diff --git a/cmd/crossposting-service/di/inject_application.go b/cmd/crossposting-service/di/inject_application.go index eff96eb..f05f59e 100644 --- a/cmd/crossposting-service/di/inject_application.go +++ b/cmd/crossposting-service/di/inject_application.go @@ -22,4 +22,5 @@ var applicationSet = wire.NewSet( app.NewLinkPublicKeyHandler, app.NewGetTwitterAccountDetailsHandler, app.NewLogoutHandler, + app.NewUnlinkPublicKeyHandler, ) diff --git a/cmd/crossposting-service/di/wire_gen.go b/cmd/crossposting-service/di/wire_gen.go index bfcd668..e9bcc87 100644 --- a/cmd/crossposting-service/di/wire_gen.go +++ b/cmd/crossposting-service/di/wire_gen.go @@ -62,6 +62,7 @@ func BuildService(contextContext context.Context, configConfig config.Config) (S loginOrRegisterHandler := app.NewLoginOrRegisterHandler(genericTransactionProvider, idGenerator, idGenerator, logger, prometheusPrometheus) logoutHandler := app.NewLogoutHandler(genericTransactionProvider, logger, prometheusPrometheus) linkPublicKeyHandler := app.NewLinkPublicKeyHandler(genericTransactionProvider, logger, prometheusPrometheus) + unlinkPublicKeyHandler := app.NewUnlinkPublicKeyHandler(genericTransactionProvider, logger, prometheusPrometheus) application := app.Application{ GetSessionAccount: getSessionAccountHandler, GetAccountPublicKeys: getAccountPublicKeysHandler, @@ -69,6 +70,7 @@ func BuildService(contextContext context.Context, configConfig config.Config) (S LoginOrRegister: loginOrRegisterHandler, Logout: logoutHandler, LinkPublicKey: linkPublicKeyHandler, + UnlinkPublicKey: unlinkPublicKeyHandler, } frontendFileSystem, err := frontend.NewFrontendFileSystem() if err != nil { diff --git a/frontend/nos-crossposting-service-frontend/src/assets/delete.svg b/frontend/nos-crossposting-service-frontend/src/assets/delete.svg new file mode 100644 index 0000000..136699b --- /dev/null +++ b/frontend/nos-crossposting-service-frontend/src/assets/delete.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/nos-crossposting-service-frontend/src/components/Button.vue b/frontend/nos-crossposting-service-frontend/src/components/Button.vue index 4c86705..66a9db2 100644 --- a/frontend/nos-crossposting-service-frontend/src/components/Button.vue +++ b/frontend/nos-crossposting-service-frontend/src/components/Button.vue @@ -16,7 +16,9 @@ export default class Button extends Vue { disabled!: boolean; onClick(event: Event): void { - this.$emit('click', event) + if (!this.disabled) { + this.$emit('buttonClick', event) + } } } diff --git a/frontend/nos-crossposting-service-frontend/src/services/APIService.ts b/frontend/nos-crossposting-service-frontend/src/services/APIService.ts index df7d546..233b833 100644 --- a/frontend/nos-crossposting-service-frontend/src/services/APIService.ts +++ b/frontend/nos-crossposting-service-frontend/src/services/APIService.ts @@ -4,6 +4,7 @@ import {Mutation, State} from '@/store'; import {PublicKeys} from "@/dto/PublicKeys"; import {AddPublicKeyRequest} from "@/dto/AddPublicKeyRequest"; import {Store} from "vuex"; +import {PublicKey} from "@/dto/PublicKey"; export class APIService { @@ -23,15 +24,20 @@ export class APIService { } publicKeys(): Promise> { - const url = `/api/public-keys`; + const url = `/api/current-user/public-keys`; return this.axios.get(url); } addPublicKey(req: AddPublicKeyRequest): Promise> { - const url = `/api/public-keys`; + const url = `/api/current-user/public-keys`; return this.axios.post(url, req); } + deletePublicKey(publicKey: PublicKey): Promise> { + const url = `/api/current-user/public-keys/${publicKey.npub}`; + return this.axios.delete(url); + } + logoutCurrentUser(): Promise { return new Promise((resolve, reject) => { this.logout() diff --git a/frontend/nos-crossposting-service-frontend/src/views/HomeView.vue b/frontend/nos-crossposting-service-frontend/src/views/HomeView.vue index 54acb35..44a40f6 100644 --- a/frontend/nos-crossposting-service-frontend/src/views/HomeView.vue +++ b/frontend/nos-crossposting-service-frontend/src/views/HomeView.vue @@ -4,7 +4,9 @@
- 1. Link your X account: +
+ 1. Link your X account: +
@@ -12,14 +14,30 @@
- 1. Logged in as +
+ 1. Logged in as +
- 2. Your nostr identities: +
+ 2. Your nostr identities: +
+
@@ -30,8 +48,12 @@
  • + + +
    {{ publicKey.npub }}
    - +
@@ -39,7 +61,7 @@
@@ -60,6 +82,7 @@ import Input from "@/components/Input.vue"; import Button from "@/components/Button.vue"; import Checkmark from "@/components/Checkmark.vue"; import {Mutation} from "@/store"; +import {PublicKey} from "@/dto/PublicKey"; @Options({ @@ -79,6 +102,8 @@ export default class HomeView extends Vue { publicKeys: PublicKeys | null = null; npub = ""; + editingPublicKeys = false; + publicKeysToRemove: PublicKey[] = []; get loadingUser(): boolean { return this.store.state.user === undefined; @@ -93,7 +118,7 @@ export default class HomeView extends Vue { } @Watch('user') - watchUser(oldUser: CurrentUser, newUser: CurrentUser): void { + watchUser(newUser: CurrentUser): void { if (newUser) { this.reloadPublicKeys(); } else { @@ -101,10 +126,41 @@ export default class HomeView extends Vue { } } + startEditingPublicKeys(): void { + this.publicKeysToRemove = []; + this.editingPublicKeys = true; + } + + endEditingPublicKeys(): void { + for (const publicKey of this.publicKeysToRemove) { + this.apiService.deletePublicKey(publicKey) + .catch(() => + this.store.commit(Mutation.PushNotificationError, "Error removing a public key.") + ); + } + + this.publicKeysToRemove = []; + this.editingPublicKeys = false; + this.reloadPublicKeys(); + } + + scheduleDelete(publicKey: PublicKey): void { + const index = this.publicKeys?.publicKeys?.indexOf(publicKey); + if (index !== undefined && index >= 0) { + this.publicKeys?.publicKeys?.splice(index, 1); + // force vue update + this.publicKeys = { + publicKeys: [...this.publicKeys?.publicKeys || []], + } + } + this.publicKeysToRemove.push(publicKey); + } + addPublicKey(): void { this.apiService.addPublicKey(new AddPublicKeyRequest(this.npub)) .then(() => { this.npub = ""; + this.cancelEditingPublicKeysWithoutReloading(); this.reloadPublicKeys(); }) .catch(() => { @@ -112,6 +168,12 @@ export default class HomeView extends Vue { }); } + private cancelEditingPublicKeysWithoutReloading(): void { + this.publicKeysToRemove = []; + this.editingPublicKeys = false; + this.reloadPublicKeys(); + } + private reloadPublicKeys(): void { this.publicKeys = null; this.apiService.publicKeys() @@ -132,7 +194,33 @@ export default class HomeView extends Vue { .step { font-size: 28px; margin-top: 2em; - font-weight: 700; + display: flex; + + .text { + font-weight: 700; + } + + .actions { + padding: 0; + margin: 0 0 0 1em; + display: flex; + color: #F08508; + list-style-type: none; + + li { + padding: 0; + margin: 0; + + a { + text-decoration: none; + + &:hover { + cursor: pointer; + color: #fff; + } + } + } + } } .link-npub-form, .public-keys-wrapper { @@ -178,6 +266,16 @@ button { text-overflow: ellipsis; } } + + .delete-public-key-button { + display: block; + cursor: pointer; + margin-right: .5em; + + img { + display: block; + } + } } .link-npub-form { diff --git a/go.mod b/go.mod index fc206c7..32dab86 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/dghubble/oauth1 v0.7.2 github.com/g8rswimmer/go-twitter/v2 v2.1.5 github.com/google/wire v0.5.0 + github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/go-multierror v1.1.1 github.com/klaidas/go-oauth1 v0.0.0-20190306224042-169193bf805e diff --git a/go.sum b/go.sum index b9d7786..4e644ae 100644 --- a/go.sum +++ b/go.sum @@ -97,6 +97,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= diff --git a/service/adapters/sqlite/public_key_repository.go b/service/adapters/sqlite/public_key_repository.go index d017fa9..18d97be 100644 --- a/service/adapters/sqlite/public_key_repository.go +++ b/service/adapters/sqlite/public_key_repository.go @@ -34,6 +34,21 @@ func (m *PublicKeyRepository) Save(linkedPublicKey *domain.LinkedPublicKey) erro return nil } +func (m *PublicKeyRepository) Delete(accountID accounts.AccountID, publicKey domain.PublicKey) error { + _, err := m.tx.Exec(` +DELETE FROM public_keys +WHERE account_id = $1 AND public_key = $2 +`, + accountID.String(), + publicKey.Hex(), + ) + if err != nil { + return errors.Wrap(err, "error executing the delete query") + } + + return nil +} + func (m *PublicKeyRepository) List() ([]*domain.LinkedPublicKey, error) { rows, err := m.tx.Query(` SELECT account_id, public_key, created_at diff --git a/service/adapters/sqlite/public_key_repository_test.go b/service/adapters/sqlite/public_key_repository_test.go index 4425461..8513caa 100644 --- a/service/adapters/sqlite/public_key_repository_test.go +++ b/service/adapters/sqlite/public_key_repository_test.go @@ -120,3 +120,84 @@ func TestPublicKeyRepository_ListByPublicKeyReturnsOnlyRelevantData(t *testing.T }) require.NoError(t, err) } + +func TestPublicKeyRepository_DeletingNonExistentKeyDoesNotReturnAnError(t *testing.T) { + ctx := fixtures.TestContext(t) + adapters := NewTestAdapters(ctx, t) + + err := adapters.TransactionProvider.Transact(ctx, func(ctx context.Context, adapters sqlite.TestAdapters) error { + err := adapters.PublicKeyRepository.Delete(fixtures.SomeAccountID(), fixtures.SomePublicKey()) + require.NoError(t, err) + + return nil + }) + require.NoError(t, err) +} + +func TestPublicKeyRepository_DeletingPublicKeysDeletesThem(t *testing.T) { + ctx := fixtures.TestContext(t) + adapters := NewTestAdapters(ctx, t) + + accountID := fixtures.SomeAccountID() + twitterID := fixtures.SomeTwitterID() + + account, err := accounts.NewAccount(accountID, twitterID) + require.NoError(t, err) + + err = adapters.TransactionProvider.Transact(ctx, func(ctx context.Context, adapters sqlite.TestAdapters) error { + err = adapters.AccountRepository.Save(account) + require.NoError(t, err) + + return nil + }) + require.NoError(t, err) + + createdAt := time.Now() + publicKey1 := fixtures.SomePublicKey() + publicKey2 := fixtures.SomePublicKey() + + linkedPublicKey1, err := domain.NewLinkedPublicKey(accountID, publicKey1, createdAt) + require.NoError(t, err) + + linkedPublicKey2, err := domain.NewLinkedPublicKey(accountID, publicKey2, createdAt) + require.NoError(t, err) + + err = adapters.TransactionProvider.Transact(ctx, func(ctx context.Context, adapters sqlite.TestAdapters) error { + err = adapters.PublicKeyRepository.Save(linkedPublicKey1) + require.NoError(t, err) + + err = adapters.PublicKeyRepository.Save(linkedPublicKey2) + require.NoError(t, err) + + return nil + }) + require.NoError(t, err) + + err = adapters.TransactionProvider.Transact(ctx, func(ctx context.Context, adapters sqlite.TestAdapters) error { + results, err := adapters.PublicKeyRepository.ListByAccountID(accountID) + require.NoError(t, err) + + require.Len(t, results, 2) + + return nil + }) + require.NoError(t, err) + + err = adapters.TransactionProvider.Transact(ctx, func(ctx context.Context, adapters sqlite.TestAdapters) error { + err := adapters.PublicKeyRepository.Delete(accountID, publicKey1) + require.NoError(t, err) + + return nil + }) + require.NoError(t, err) + + err = adapters.TransactionProvider.Transact(ctx, func(ctx context.Context, adapters sqlite.TestAdapters) error { + results, err := adapters.PublicKeyRepository.ListByAccountID(accountID) + require.NoError(t, err) + + require.Len(t, results, 1) + + return nil + }) + require.NoError(t, err) +} diff --git a/service/app/app.go b/service/app/app.go index e29a1aa..6d38c87 100644 --- a/service/app/app.go +++ b/service/app/app.go @@ -45,6 +45,7 @@ type SessionRepository interface { type PublicKeyRepository interface { Save(linkedPublicKey *domain.LinkedPublicKey) error + Delete(accountID accounts.AccountID, publicKey domain.PublicKey) error List() ([]*domain.LinkedPublicKey, error) ListByPublicKey(publicKey domain.PublicKey) ([]*domain.LinkedPublicKey, error) ListByAccountID(accountID accounts.AccountID) ([]*domain.LinkedPublicKey, error) @@ -104,6 +105,7 @@ type Application struct { LoginOrRegister *LoginOrRegisterHandler Logout *LogoutHandler LinkPublicKey *LinkPublicKeyHandler + UnlinkPublicKey *UnlinkPublicKeyHandler } type ReceivedEvent struct { diff --git a/service/app/handler_unlink_public_key.go b/service/app/handler_unlink_public_key.go new file mode 100644 index 0000000..73305d8 --- /dev/null +++ b/service/app/handler_unlink_public_key.go @@ -0,0 +1,53 @@ +package app + +import ( + "context" + + "github.com/boreq/errors" + "github.com/planetary-social/nos-crossposting-service/internal/logging" + "github.com/planetary-social/nos-crossposting-service/service/domain" + "github.com/planetary-social/nos-crossposting-service/service/domain/accounts" +) + +type UnlinkPublicKey struct { + accountID accounts.AccountID + publicKey domain.PublicKey +} + +func NewUnlinkPublicKey(accountID accounts.AccountID, publicKey domain.PublicKey) UnlinkPublicKey { + return UnlinkPublicKey{accountID: accountID, publicKey: publicKey} +} + +type UnlinkPublicKeyHandler struct { + transactionProvider TransactionProvider + logger logging.Logger + metrics Metrics +} + +func NewUnlinkPublicKeyHandler( + transactionProvider TransactionProvider, + logger logging.Logger, + metrics Metrics, +) *UnlinkPublicKeyHandler { + return &UnlinkPublicKeyHandler{ + transactionProvider: transactionProvider, + logger: logger.New("unlinkPublicKeyHandler"), + metrics: metrics, + } +} + +func (h *UnlinkPublicKeyHandler) Handle(ctx context.Context, cmd UnlinkPublicKey) (err error) { + defer h.metrics.StartApplicationCall("unlinkPublicKey").End(&err) + + if err := h.transactionProvider.Transact(ctx, func(ctx context.Context, adapters Adapters) error { + if err := adapters.PublicKeys.Delete(cmd.accountID, cmd.publicKey); err != nil { + return errors.Wrap(err, "error deleting the linked publicm key") + } + + return nil + }); err != nil { + return errors.Wrap(err, "transaction error") + } + + return nil +} diff --git a/service/ports/http/frontend/css/app.d3a92ac3.css b/service/ports/http/frontend/css/app.0e9aeef4.css similarity index 74% rename from service/ports/http/frontend/css/app.d3a92ac3.css rename to service/ports/http/frontend/css/app.0e9aeef4.css index be24525..65cd112 100644 --- a/service/ports/http/frontend/css/app.d3a92ac3.css +++ b/service/ports/http/frontend/css/app.0e9aeef4.css @@ -1 +1 @@ -a[data-v-5ac017a3]{padding:15px;border-radius:10px;background-color:#fff;color:#19072c;font-size:24px;display:flex;align-items:center;font-weight:700;cursor:pointer}a .icon[data-v-5ac017a3]{margin-left:10px}header[data-v-41f23fd0]{display:flex;flex-flow:row nowrap;align-items:center}header .logo[data-v-41f23fd0]{display:block}header nav[data-v-41f23fd0]{font-size:24px;font-weight:600;flex:1;text-align:right}header nav ul[data-v-41f23fd0]{margin:0;padding:0;list-style-type:none}header nav ul li[data-v-41f23fd0]{display:inline-block;margin:0;padding:0 1em}header nav ul li[data-v-41f23fd0]:last-child{padding-right:0}header nav ul li[data-v-41f23fd0]:first-child{padding-left:0}header nav ul li a[data-v-41f23fd0]{color:#9379bf;text-decoration:none}header nav ul li a[data-v-41f23fd0]:hover{color:#fff}header .logout-button[data-v-41f23fd0]{margin-left:1em}@media screen and (max-width:1200px){header[data-v-41f23fd0]{flex-flow:column nowrap;text-align:center}header nav[data-v-41f23fd0]{margin:1em 0;text-align:center}header nav ul li[data-v-41f23fd0]{display:block;padding:.5em 0}header .logout-button[data-v-41f23fd0]{margin:1em 0}}.notifications[data-v-11301b3e]{margin:0;padding:0}.notifications .notification[data-v-11301b3e]{list-style-type:none;padding:1em;margin:1em;border-radius:10px;color:#fff;overflow:hidden;display:flex;flex-flow:row nowrap;align-items:center}.notifications .notification .text[data-v-11301b3e]{flex:1}.notifications .notification .button[data-v-11301b3e]{cursor:pointer}.notifications .notification.error[data-v-11301b3e]{background-color:#ef6155}.notifications .notification.success[data-v-11301b3e]{background-color:#2ecc71}@font-face{font-family:Clarity City;font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/ClarityCity-Regular.58b3eff6.otf) format("opentype")}@font-face{font-family:Clarity City;font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/ClarityCity-Medium.e68a804b.otf) format("opentype")}@font-face{font-family:Clarity City;font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/ClarityCity-SemiBold.41fce741.otf) format("opentype")}@font-face{font-family:Clarity City;font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/ClarityCity-Bold.952112b9.otf) format("opentype")}body,html{padding:0;margin:0;color:#fff;min-height:100vh;font-family:Clarity City,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}html{background:linear-gradient(#160f24,#281945)}body{background-image:url(/img/background.4c146daa.svg);background-position:100%;background-repeat:no-repeat;background-size:auto 100%}#app .wrapper{padding:4em}#app .wrapper .content{padding:0 4em}@media screen and (max-width:1200px){#app .wrapper .content{padding:0}}.explanation[data-v-5ace9f54]{text-align:left;margin:10em 0;max-width:700px}.explanation .large[data-v-5ace9f54]{font-size:60px;line-height:84px;font-weight:700;margin-bottom:.5em}.explanation .small[data-v-5ace9f54]{color:#9379bf;font-size:26px;font-weight:500;line-height:36px}@media screen and (max-width:1200px){.explanation[data-v-5ace9f54]{max-width:none}}a[data-v-58fab459]{display:inline-block;margin:1.5em 0;padding:5px;border-radius:10px;background:linear-gradient(#f08508,#f43f75)}a .img-wrapper[data-v-58fab459]{padding:1em 2em;background-color:#170d2b}a .img-wrapper img[data-v-58fab459]{display:block;margin:0 auto;height:52px}a:hover .img-wrapper[data-v-58fab459]{background-color:transparent}.current-user[data-v-bf1931c6]{display:grid;grid-template-columns:auto 50px;grid-template-rows:auto;grid-template-areas:"user-info checkmark";align-items:center;margin:1.5em 0}.current-user .user-info[data-v-bf1931c6]{grid-area:user-info;border-radius:10px;display:grid;grid-template-columns:auto 1fr auto;grid-template-rows:auto;grid-template-areas:"image name logout-button" "image username logout-button";align-items:center;border:3px solid #9379bf;gap:5px 20px;padding:20px;background-color:#2a1b45}.current-user .user-info .image[data-v-bf1931c6]{grid-area:image;border-radius:75px;height:75px}.current-user .user-info .name[data-v-bf1931c6],.current-user .user-info .username[data-v-bf1931c6]{font-size:28px;font-style:normal}.current-user .user-info .username[data-v-bf1931c6]{grid-area:username;font-weight:500;color:#9379bf}.current-user .user-info .name[data-v-bf1931c6]{grid-area:name;font-weight:700;color:#fff}.current-user .user-info .logout-button[data-v-bf1931c6]{grid-area:logout-button;cursor:pointer}.current-user .checkmark[data-v-bf1931c6]{grid-area:checkmark;padding:0 15px}input[data-v-a3a07d36]{border-radius:10px;border:3px solid #fff;padding:30px;background-color:#1b122d;font-weight:700;font-size:32px;line-height:32px;color:#fff}input[data-v-a3a07d36]::-moz-placeholder{color:#fff}input[data-v-a3a07d36]::placeholder{color:#fff}input.disabled[data-v-a3a07d36]{cursor:not-allowed;background-color:#342255;border-color:hsla(0,0%,100%,.15)}input.disabled[data-v-a3a07d36]::-moz-placeholder{color:hsla(0,0%,100%,.25)}input.disabled[data-v-a3a07d36]::placeholder{color:hsla(0,0%,100%,.25)}button[data-v-6881488a]{background-image:linear-gradient(180deg,#f08508,#f43f75);padding:33px;border:0;border-radius:10px;color:#fff;font-size:32px;font-weight:700;text-shadow:0 2px 2px rgba(0,0,0,.25)}button[data-v-6881488a]:hover{cursor:pointer}button.disabled[data-v-6881488a]{cursor:not-allowed}.step[data-v-6df21b34]{font-size:28px;margin-top:2em;font-weight:700}.link-npub-form[data-v-6df21b34],.public-keys-wrapper[data-v-6df21b34]{margin:28px 0}button[data-v-6df21b34]{margin-left:1em}.current-user[data-v-6df21b34]{width:550px}.public-keys[data-v-6df21b34]{list-style-type:none;font-size:28px;margin:0;padding:0}.public-keys li[data-v-6df21b34]{margin:1em 0;padding:0;color:#9379bf;font-style:normal;font-weight:700;display:flex;align-items:center;flex-flow:row nowrap}.public-keys li[data-v-6df21b34]:first-child{margin-top:0}.public-keys li[data-v-6df21b34]:last-child{margin-bottom:0}.public-keys li .npub[data-v-6df21b34]{width:300px;overflow:hidden;text-overflow:ellipsis}.link-npub-form[data-v-6df21b34]{display:flex}.link-npub-form .input[data-v-6df21b34]{width:500px}@media screen and (max-width:1200px){.current-user[data-v-6df21b34]{width:100%}.log-in-with-twitter-button[data-v-6df21b34]{display:block}.link-npub-form[data-v-6df21b34]{display:flex;flex-flow:column nowrap}.link-npub-form .input[data-v-6df21b34]{width:auto}.link-npub-form .button[data-v-6df21b34]{width:auto;margin:1em 0}} \ No newline at end of file +a[data-v-5ac017a3]{padding:15px;border-radius:10px;background-color:#fff;color:#19072c;font-size:24px;display:flex;align-items:center;font-weight:700;cursor:pointer}a .icon[data-v-5ac017a3]{margin-left:10px}header[data-v-41f23fd0]{display:flex;flex-flow:row nowrap;align-items:center}header .logo[data-v-41f23fd0]{display:block}header nav[data-v-41f23fd0]{font-size:24px;font-weight:600;flex:1;text-align:right}header nav ul[data-v-41f23fd0]{margin:0;padding:0;list-style-type:none}header nav ul li[data-v-41f23fd0]{display:inline-block;margin:0;padding:0 1em}header nav ul li[data-v-41f23fd0]:last-child{padding-right:0}header nav ul li[data-v-41f23fd0]:first-child{padding-left:0}header nav ul li a[data-v-41f23fd0]{color:#9379bf;text-decoration:none}header nav ul li a[data-v-41f23fd0]:hover{color:#fff}header .logout-button[data-v-41f23fd0]{margin-left:1em}@media screen and (max-width:1200px){header[data-v-41f23fd0]{flex-flow:column nowrap;text-align:center}header nav[data-v-41f23fd0]{margin:1em 0;text-align:center}header nav ul li[data-v-41f23fd0]{display:block;padding:.5em 0}header .logout-button[data-v-41f23fd0]{margin:1em 0}}.notifications[data-v-11301b3e]{margin:0;padding:0}.notifications .notification[data-v-11301b3e]{list-style-type:none;padding:1em;margin:1em;border-radius:10px;color:#fff;overflow:hidden;display:flex;flex-flow:row nowrap;align-items:center}.notifications .notification .text[data-v-11301b3e]{flex:1}.notifications .notification .button[data-v-11301b3e]{cursor:pointer}.notifications .notification.error[data-v-11301b3e]{background-color:#ef6155}.notifications .notification.success[data-v-11301b3e]{background-color:#2ecc71}@font-face{font-family:Clarity City;font-style:normal;font-weight:400;font-display:swap;src:url(/fonts/ClarityCity-Regular.58b3eff6.otf) format("opentype")}@font-face{font-family:Clarity City;font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/ClarityCity-Medium.e68a804b.otf) format("opentype")}@font-face{font-family:Clarity City;font-style:normal;font-weight:600;font-display:swap;src:url(/fonts/ClarityCity-SemiBold.41fce741.otf) format("opentype")}@font-face{font-family:Clarity City;font-style:normal;font-weight:700;font-display:swap;src:url(/fonts/ClarityCity-Bold.952112b9.otf) format("opentype")}body,html{padding:0;margin:0;color:#fff;min-height:100vh;font-family:Clarity City,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}html{background:linear-gradient(#160f24,#281945)}body{background-image:url(/img/background.4c146daa.svg);background-position:100%;background-repeat:no-repeat;background-size:auto 100%}#app .wrapper{padding:4em}#app .wrapper .content{padding:0 4em}@media screen and (max-width:1200px){#app .wrapper .content{padding:0}}.explanation[data-v-5ace9f54]{text-align:left;margin:10em 0;max-width:700px}.explanation .large[data-v-5ace9f54]{font-size:60px;line-height:84px;font-weight:700;margin-bottom:.5em}.explanation .small[data-v-5ace9f54]{color:#9379bf;font-size:26px;font-weight:500;line-height:36px}@media screen and (max-width:1200px){.explanation[data-v-5ace9f54]{max-width:none}}a[data-v-58fab459]{display:inline-block;margin:1.5em 0;padding:5px;border-radius:10px;background:linear-gradient(#f08508,#f43f75)}a .img-wrapper[data-v-58fab459]{padding:1em 2em;background-color:#170d2b}a .img-wrapper img[data-v-58fab459]{display:block;margin:0 auto;height:52px}a:hover .img-wrapper[data-v-58fab459]{background-color:transparent}.current-user[data-v-bf1931c6]{display:grid;grid-template-columns:auto 50px;grid-template-rows:auto;grid-template-areas:"user-info checkmark";align-items:center;margin:1.5em 0}.current-user .user-info[data-v-bf1931c6]{grid-area:user-info;border-radius:10px;display:grid;grid-template-columns:auto 1fr auto;grid-template-rows:auto;grid-template-areas:"image name logout-button" "image username logout-button";align-items:center;border:3px solid #9379bf;gap:5px 20px;padding:20px;background-color:#2a1b45}.current-user .user-info .image[data-v-bf1931c6]{grid-area:image;border-radius:75px;height:75px}.current-user .user-info .name[data-v-bf1931c6],.current-user .user-info .username[data-v-bf1931c6]{font-size:28px;font-style:normal}.current-user .user-info .username[data-v-bf1931c6]{grid-area:username;font-weight:500;color:#9379bf}.current-user .user-info .name[data-v-bf1931c6]{grid-area:name;font-weight:700;color:#fff}.current-user .user-info .logout-button[data-v-bf1931c6]{grid-area:logout-button;cursor:pointer}.current-user .checkmark[data-v-bf1931c6]{grid-area:checkmark;padding:0 15px}input[data-v-a3a07d36]{border-radius:10px;border:3px solid #fff;padding:30px;background-color:#1b122d;font-weight:700;font-size:32px;line-height:32px;color:#fff}input[data-v-a3a07d36]::-moz-placeholder{color:#fff}input[data-v-a3a07d36]::placeholder{color:#fff}input.disabled[data-v-a3a07d36]{cursor:not-allowed;background-color:#342255;border-color:hsla(0,0%,100%,.15)}input.disabled[data-v-a3a07d36]::-moz-placeholder{color:hsla(0,0%,100%,.25)}input.disabled[data-v-a3a07d36]::placeholder{color:hsla(0,0%,100%,.25)}button[data-v-59245c60]{background-image:linear-gradient(180deg,#f08508,#f43f75);padding:33px;border:0;border-radius:10px;color:#fff;font-size:32px;font-weight:700;text-shadow:0 2px 2px rgba(0,0,0,.25)}button[data-v-59245c60]:hover{cursor:pointer}button.disabled[data-v-59245c60]{cursor:not-allowed}.step[data-v-28506258]{font-size:28px;margin-top:2em;display:flex}.step .text[data-v-28506258]{font-weight:700}.step .actions[data-v-28506258]{padding:0;margin:0 0 0 1em;display:flex;color:#f08508;list-style-type:none}.step .actions li[data-v-28506258]{padding:0;margin:0}.step .actions li a[data-v-28506258]{text-decoration:none}.step .actions li a[data-v-28506258]:hover{cursor:pointer;color:#fff}.link-npub-form[data-v-28506258],.public-keys-wrapper[data-v-28506258]{margin:28px 0}button[data-v-28506258]{margin-left:1em}.current-user[data-v-28506258]{width:550px}.public-keys[data-v-28506258]{list-style-type:none;font-size:28px;margin:0;padding:0}.public-keys li[data-v-28506258]{margin:1em 0;padding:0;color:#9379bf;font-style:normal;font-weight:700;display:flex;align-items:center;flex-flow:row nowrap}.public-keys li[data-v-28506258]:first-child{margin-top:0}.public-keys li[data-v-28506258]:last-child{margin-bottom:0}.public-keys li .npub[data-v-28506258]{width:300px;overflow:hidden;text-overflow:ellipsis}.public-keys .delete-public-key-button[data-v-28506258]{display:block;cursor:pointer;margin-right:.5em}.public-keys .delete-public-key-button img[data-v-28506258]{display:block}.link-npub-form[data-v-28506258]{display:flex}.link-npub-form .input[data-v-28506258]{width:500px}@media screen and (max-width:1200px){.current-user[data-v-28506258]{width:100%}.log-in-with-twitter-button[data-v-28506258]{display:block}.link-npub-form[data-v-28506258]{display:flex;flex-flow:column nowrap}.link-npub-form .input[data-v-28506258]{width:auto}.link-npub-form .button[data-v-28506258]{width:auto;margin:1em 0}} \ No newline at end of file diff --git a/service/ports/http/frontend/img/delete.0ed4aa0d.svg b/service/ports/http/frontend/img/delete.0ed4aa0d.svg new file mode 100644 index 0000000..136699b --- /dev/null +++ b/service/ports/http/frontend/img/delete.0ed4aa0d.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/service/ports/http/frontend/index.html b/service/ports/http/frontend/index.html index c474855..d06e881 100644 --- a/service/ports/http/frontend/index.html +++ b/service/ports/http/frontend/index.html @@ -1 +1 @@ -X Connect
\ No newline at end of file +X Connect
\ No newline at end of file diff --git a/service/ports/http/frontend/js/app.5e6ad394.js b/service/ports/http/frontend/js/app.5e6ad394.js deleted file mode 100644 index 189c68c..0000000 --- a/service/ports/http/frontend/js/app.5e6ad394.js +++ /dev/null @@ -1,2 +0,0 @@ -(function(){"use strict";var e={4362:function(e,t,r){var o=r(9242),n=r(3396);const s={class:"wrapper"},i={class:"content"};function c(e,t,r,o,c,a){const l=(0,n.up)("Header"),u=(0,n.up)("Notifications"),d=(0,n.up)("router-view");return(0,n.wg)(),(0,n.iD)("div",s,[(0,n.Wm)(l),(0,n._)("div",i,[(0,n.Wm)(u),(0,n.Wm)(d)])])}var a,l=r(7327),u=r(6520),d=r(65),f=r(4161);class p{constructor(e,t){(0,l.Z)(this,"style",void 0),(0,l.Z)(this,"text",void 0),this.style=e,this.text=t}}(function(e){e["SetUser"]="setUser",e["PushNotificationError"]="pushNotificationError",e["DismissNotification"]="dismissNotification"})(a||(a={}));var h=(0,d.MT)({state:{user:void 0,notifications:[]},getters:{},mutations:{[a.SetUser](e,t){e.user=t},[a.PushNotificationError](e,t){e.notifications?.push(new p("error",t))},[a.DismissNotification](e,t){e.notifications?.splice(t,1)}},actions:{},modules:{}});class v{constructor(e){(0,l.Z)(this,"store",void 0),(0,l.Z)(this,"axios",f.Z.create()),this.store=e}currentUser(){const e="/api/current-user";return this.axios.get(e)}logout(){const e="/api/current-user";return this.axios.delete(e)}publicKeys(){const e="/api/public-keys";return this.axios.get(e)}addPublicKey(e){const t="/api/public-keys";return this.axios.post(t,e)}logoutCurrentUser(){return new Promise(((e,t)=>{this.logout().then((()=>{this.store.commit(a.SetUser,null),e()}),(e=>{t(e)}))}))}refreshCurrentUser(){return new Promise(((e,t)=>{this.currentUser().then((t=>{this.store.commit(a.SetUser,t.data.user),e(t.data)}),(e=>{t(e)}))}))}}var g=r.p+"img/logo.79c97fb0.svg";const b=e=>((0,n.dD)("data-v-41f23fd0"),e=e(),(0,n.Cn)(),e),y=b((()=>(0,n._)("a",{class:"logo",href:"/"},[(0,n._)("img",{src:g})],-1))),m=b((()=>(0,n._)("nav",null,[(0,n._)("ul",null,[(0,n._)("li",null,[(0,n._)("a",{href:"https://nos.social"},"Download Nos")]),(0,n._)("li",null,[(0,n._)("a",{href:"https://github.com/planetary-social/nos-crossposting-service"},"Source code")])])],-1)));function w(e,t,r,o,s,i){const c=(0,n.up)("LogoutButton");return(0,n.wg)(),(0,n.iD)("header",null,[y,m,e.userIsLoggedIn?((0,n.wg)(),(0,n.j4)(c,{key:0})):(0,n.kq)("",!0)])}var _=r.p+"img/logout_on_light.d9f6b5e8.svg";const k=e=>((0,n.dD)("data-v-5ac017a3"),e=e(),(0,n.Cn)(),e),D=k((()=>(0,n._)("div",{class:"label"}," Logout ",-1))),R=k((()=>(0,n._)("img",{class:"icon",src:_},null,-1))),O=[D,R];function P(e,t,r,o,s,i){return(0,n.wg)(),(0,n.iD)("a",{class:"logout-button",onClick:t[0]||(t[0]=(...t)=>e.logout&&e.logout(...t))},O)}var j=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let Z=class extends u.w3{constructor(...e){super(...e),(0,l.Z)(this,"apiService",new v((0,d.oR)())),(0,l.Z)(this,"store",(0,d.oR)())}logout(){this.apiService.logoutCurrentUser().catch((()=>{this.store.commit(a.PushNotificationError,"Error logging out the user.")}))}};Z=j([(0,u.Ei)({})],Z);var x=Z,C=r(89);const E=(0,C.Z)(x,[["render",P],["__scopeId","data-v-5ac017a3"]]);var U=E,I=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let K=class extends u.w3{constructor(...e){super(...e),(0,l.Z)(this,"store",(0,d.oR)())}get userIsLoggedIn(){return!!this.store.state.user}};K=I([(0,u.Ei)({components:{LogoutButton:U}})],K);var N=K;const S=(0,C.Z)(N,[["render",w],["__scopeId","data-v-41f23fd0"]]);var L=S,W=r(7139);const B={class:"notifications"},V={class:"text"},q=["onClick"];function z(e,t,r,o,s,i){return(0,n.wg)(),(0,n.iD)("ul",B,[((0,n.wg)(!0),(0,n.iD)(n.HY,null,(0,n.Ko)(e.notifications,((t,r)=>((0,n.wg)(),(0,n.iD)("li",{class:(0,W.C_)(["notification",[t.style]]),key:r},[(0,n._)("div",V,(0,W.zw)(t.text),1),(0,n._)("div",{class:"button",onClick:t=>e.dismiss(r)}," X ",8,q)],2)))),128))])}var T=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let X=class extends u.w3{constructor(...e){super(...e),(0,l.Z)(this,"store",(0,d.oR)())}get notifications(){return this.store.state.notifications}dismiss(e){this.store.commit(a.DismissNotification,e)}};X=T([(0,u.Ei)({components:{}})],X);var H=X;const Y=(0,C.Z)(H,[["render",z],["__scopeId","data-v-11301b3e"]]);var M=Y,$=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let A=class extends u.w3{constructor(...e){super(...e),(0,l.Z)(this,"apiService",new v((0,d.oR)())),(0,l.Z)(this,"store",(0,d.oR)())}created(){this.apiService.refreshCurrentUser().catch((()=>{this.store.commit(a.PushNotificationError,"Error loading the user.")}))}};A=$([(0,u.Ei)({components:{Notifications:M,Header:L}})],A);var F=A;const G=(0,C.Z)(F,[["render",c]]);var J=G,Q=r(2483);const ee=e=>((0,n.dD)("data-v-6df21b34"),e=e(),(0,n.Cn)(),e),te={class:"home"},re={key:0},oe=ee((()=>(0,n._)("div",{class:"step"}," 1. Link your X account: ",-1))),ne={key:1},se=ee((()=>(0,n._)("div",{class:"step"}," 1. Logged in as ",-1))),ie=ee((()=>(0,n._)("div",{class:"step"}," 2. Your nostr identities: ",-1))),ce={key:2,class:"public-keys-wrapper"},ae={key:0},le={key:1,class:"public-keys"},ue={class:"npub"},de={class:"link-npub-form"};function fe(e,t,r,o,s,i){const c=(0,n.up)("Explanation"),a=(0,n.up)("LogInWithTwitterButton"),l=(0,n.up)("CurrentUser"),u=(0,n.up)("Checkmark"),d=(0,n.up)("Input"),f=(0,n.up)("Button");return(0,n.wg)(),(0,n.iD)("div",te,[(0,n.Wm)(c),e.loadingUser||e.user?(0,n.kq)("",!0):((0,n.wg)(),(0,n.iD)("div",re,[oe,(0,n.Wm)(a)])),!e.loadingUser&&e.user?((0,n.wg)(),(0,n.iD)("div",ne,[se,(0,n.Wm)(l,{user:e.user},null,8,["user"])])):(0,n.kq)("",!0),ie,!e.loadingUser&&e.user?((0,n.wg)(),(0,n.iD)("div",ce,[e.publicKeys?(0,n.kq)("",!0):((0,n.wg)(),(0,n.iD)("div",ae," Loading public keys... ")),e.publicKeys&&e.publicKeys.publicKeys?.length>0?((0,n.wg)(),(0,n.iD)("ul",le,[((0,n.wg)(!0),(0,n.iD)(n.HY,null,(0,n.Ko)(e.publicKeys.publicKeys,(e=>((0,n.wg)(),(0,n.iD)("li",{key:e.npub},[(0,n._)("div",ue,(0,W.zw)(e.npub),1),(0,n.Wm)(u)])))),128))])):(0,n.kq)("",!0)])):(0,n.kq)("",!0),(0,n._)("div",de,[(0,n.Wm)(d,{placeholder:"Paste your npub address",modelValue:e.npub,"onUpdate:modelValue":t[0]||(t[0]=t=>e.npub=t),disabled:e.formDisabled},null,8,["modelValue","disabled"]),(0,n.Wm)(f,{text:"Add",onClick:e.addPublicKey,disabled:e.formDisabled},null,8,["onClick","disabled"])])])}var pe=r(4815);const he=e=>((0,n.dD)("data-v-5ace9f54"),e=e(),(0,n.Cn)(),e),ve={class:"explanation"},ge=he((()=>(0,n._)("div",{class:"large"}," Start posting your Nostr content on X ",-1))),be=he((()=>(0,n._)("div",{class:"small"}," Log in to your X account and add your Nostr identities so that everything you publish on Nostr will be mirrored on X ",-1))),ye=[ge,be];function me(e,t,r,o,s,i){return(0,n.wg)(),(0,n.iD)("div",ve,ye)}var we=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let _e=class extends u.w3{};_e=we([(0,u.Ei)({})],_e);var ke=_e;const De=(0,C.Z)(ke,[["render",me],["__scopeId","data-v-5ace9f54"]]);var Re=De,Oe=r.p+"img/login_with_x.b3cda31f.svg";const Pe=e=>((0,n.dD)("data-v-58fab459"),e=e(),(0,n.Cn)(),e),je={href:"/login",class:"log-in-with-twitter-button"},Ze=Pe((()=>(0,n._)("div",{class:"img-wrapper"},[(0,n._)("img",{src:Oe})],-1))),xe=[Ze];function Ce(e,t,r,o,s,i){return(0,n.wg)(),(0,n.iD)("a",je,xe)}var Ee=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let Ue=class extends u.w3{};Ue=Ee([(0,u.Ei)({})],Ue);var Ie=Ue;const Ke=(0,C.Z)(Ie,[["render",Ce],["__scopeId","data-v-58fab459"]]);var Ne=Ke,Se=r.p+"img/logout_on_dark.2eaec2bd.svg";const Le=e=>((0,n.dD)("data-v-bf1931c6"),e=e(),(0,n.Cn)(),e),We={class:"current-user"},Be={class:"user-info"},Ve=["src"],qe={class:"name"},ze={class:"username"},Te=Le((()=>(0,n._)("img",{src:Se},null,-1))),Xe=[Te];function He(e,t,r,o,s,i){const c=(0,n.up)("Checkmark");return(0,n.wg)(),(0,n.iD)("div",We,[(0,n._)("div",Be,[(0,n._)("img",{class:"image",src:e.user?.twitterProfileImageURL},null,8,Ve),(0,n._)("div",qe,(0,W.zw)(e.user.twitterName),1),(0,n._)("div",ze,"@"+(0,W.zw)(e.user.twitterUsername),1),(0,n._)("a",{class:"logout-button",onClick:t[0]||(t[0]=(...t)=>e.logout&&e.logout(...t))},Xe)]),(0,n.Wm)(c)])}class Ye{constructor(){(0,l.Z)(this,"accountID",void 0),(0,l.Z)(this,"twitterID",void 0),(0,l.Z)(this,"twitterName",void 0),(0,l.Z)(this,"twitterUsername",void 0),(0,l.Z)(this,"twitterProfileImageURL",void 0)}}var Me=r.p+"img/checkmark.3921dcf8.svg";const $e={class:"checkmark",src:Me};function Ae(e,t,r,o,s,i){return(0,n.wg)(),(0,n.iD)("img",$e)}var Fe=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let Ge=class extends u.w3{};Ge=Fe([(0,u.Ei)({})],Ge);var Je=Ge;const Qe=(0,C.Z)(Je,[["render",Ae]]);var et=Qe,tt=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let rt=class extends u.w3{constructor(...e){super(...e),(0,l.Z)(this,"user",void 0),(0,l.Z)(this,"apiService",new v((0,d.oR)())),(0,l.Z)(this,"store",(0,d.oR)())}logout(){this.apiService.logoutCurrentUser().catch((()=>{this.store.commit(a.PushNotificationError,"Error logging out the user.")}))}};rt=tt([(0,u.Ei)({components:{Checkmark:et},props:{user:Ye}})],rt);var ot=rt;const nt=(0,C.Z)(ot,[["render",He],["__scopeId","data-v-bf1931c6"]]);var st=nt;class it{constructor(e){(0,l.Z)(this,"npub",void 0),this.npub=e}}const ct=["placeholder","value","disabled"];function at(e,t,r,o,s,i){return(0,n.wg)(),(0,n.iD)("input",{type:"text",placeholder:e.placeholder,value:e.modelValue,class:(0,W.C_)(["input",{disabled:e.disabled}]),onInput:t[0]||(t[0]=(...t)=>e.onInput&&e.onInput(...t)),disabled:e.disabled},null,42,ct)}var lt=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let ut=class extends u.w3{constructor(...e){super(...e),(0,l.Z)(this,"placeholder",void 0),(0,l.Z)(this,"modelValue",void 0),(0,l.Z)(this,"disabled",void 0)}onInput(e){this.$emit("update:modelValue",e.target.value)}};ut=lt([(0,u.Ei)({props:{placeholder:String,modelValue:String,disabled:Boolean},emits:["update:modelValue"]})],ut);var dt=ut;const ft=(0,C.Z)(dt,[["render",at],["__scopeId","data-v-a3a07d36"]]);var pt=ft;function ht(e,t,r,o,s,i){return(0,n.wg)(),(0,n.iD)("button",{onClick:t[0]||(t[0]=(...t)=>e.onClick&&e.onClick(...t)),class:(0,W.C_)({button:!0,disabled:e.disabled})},(0,W.zw)(e.text),3)}var vt=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let gt=class extends u.w3{constructor(...e){super(...e),(0,l.Z)(this,"text",void 0),(0,l.Z)(this,"disabled",void 0)}onClick(e){this.$emit("click",e)}};gt=vt([(0,u.Ei)({props:{text:String,disabled:Boolean}})],gt);var bt=gt;const yt=(0,C.Z)(bt,[["render",ht],["__scopeId","data-v-6881488a"]]);var mt=yt,wt=function(e,t,r,o){var n,s=arguments.length,i=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,r):o;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)i=Reflect.decorate(e,t,r,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(i=(s<3?n(i):s>3?n(t,r,i):n(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};let _t=class extends u.w3{constructor(...e){super(...e),(0,l.Z)(this,"apiService",new v((0,d.oR)())),(0,l.Z)(this,"store",(0,d.oR)()),(0,l.Z)(this,"publicKeys",null),(0,l.Z)(this,"npub","")}get loadingUser(){return void 0===this.store.state.user}get user(){return this.store.state.user}get formDisabled(){return this.loadingUser||!this.user}watchUser(e,t){t?this.reloadPublicKeys():this.publicKeys={publicKeys:[]}}addPublicKey(){this.apiService.addPublicKey(new it(this.npub)).then((()=>{this.npub="",this.reloadPublicKeys()})).catch((()=>{this.store.commit(a.PushNotificationError,"Error adding the public key.")}))}reloadPublicKeys(){this.publicKeys=null,this.apiService.publicKeys().then((e=>{this.publicKeys=e.data})).catch((e=>{e.response&&401===e.response.status||this.store.commit(a.PushNotificationError,"Error loading the public keys.")}))}};wt([(0,pe.RL)("user")],_t.prototype,"watchUser",null),_t=wt([(0,u.Ei)({components:{Checkmark:et,Button:mt,CurrentUser:st,LogInWithTwitterButton:Ne,Explanation:Re,Input:pt}})],_t);var kt=_t;const Dt=(0,C.Z)(kt,[["render",fe],["__scopeId","data-v-6df21b34"]]);var Rt=Dt;const Ot=[{path:"/",name:"home",component:Rt}],Pt=(0,Q.p7)({history:(0,Q.PO)("/"),routes:Ot});var jt=Pt;(0,o.ri)(J).use(h).use(jt).mount("#app")}},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var s=t[o]={exports:{}};return e[o].call(s.exports,s,s.exports,r),s.exports}r.m=e,function(){var e=[];r.O=function(t,o,n,s){if(!o){var i=1/0;for(u=0;u=s)&&Object.keys(r.O).every((function(e){return r.O[e](o[a])}))?o.splice(a--,1):(c=!1,s0&&e[u-1][2]>s;u--)e[u]=e[u-1];e[u]=[o,n,s]}}(),function(){r.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return r.d(t,{a:t}),t}}(),function(){r.d=function(e,t){for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})}}(),function(){r.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"===typeof window)return window}}()}(),function(){r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}}(),function(){r.p="/"}(),function(){var e={143:0};r.O.j=function(t){return 0===e[t]};var t=function(t,o){var n,s,i=o[0],c=o[1],a=o[2],l=0;if(i.some((function(t){return 0!==e[t]}))){for(n in c)r.o(c,n)&&(r.m[n]=c[n]);if(a)var u=a(r)}for(t&&t(o);l\n
\n
\n
\n \n \n
\n
\n\n\n\n\n\n","import {createStore} from 'vuex'\nimport {User} from \"@/dto/User\";\n\nclass Notification {\n constructor(\n public style: string,\n public text: string,\n ) {\n }\n}\n\nexport enum Mutation {\n SetUser = 'setUser',\n PushNotificationError = 'pushNotificationError',\n DismissNotification = 'dismissNotification',\n}\n\nexport class State {\n user?: User;\n notifications?: Notification[];\n}\n\nexport default createStore({\n state: {\n user: undefined,\n notifications: [],\n },\n getters: {},\n mutations: {\n [Mutation.SetUser](state: State, user: User): void {\n state.user = user;\n },\n [Mutation.PushNotificationError](state: State, text: string): void {\n state.notifications?.push(new Notification('error', text));\n },\n [Mutation.DismissNotification](state: State, index: number): void {\n state.notifications?.splice(index, 1);\n },\n },\n actions: {},\n modules: {}\n})\n","import axios, {AxiosResponse} from 'axios';\nimport {CurrentUser} from \"@/dto/CurrentUser\";\nimport {Mutation, State} from '@/store';\nimport {PublicKeys} from \"@/dto/PublicKeys\";\nimport {AddPublicKeyRequest} from \"@/dto/AddPublicKeyRequest\";\nimport {Store} from \"vuex\";\n\nexport class APIService {\n\n private readonly axios = axios.create();\n\n constructor(private store: Store) {\n }\n\n private currentUser(): Promise> {\n const url = `/api/current-user`;\n return this.axios.get(url);\n }\n\n private logout(): Promise> {\n const url = `/api/current-user`;\n return this.axios.delete(url);\n }\n\n publicKeys(): Promise> {\n const url = `/api/public-keys`;\n return this.axios.get(url);\n }\n\n addPublicKey(req: AddPublicKeyRequest): Promise> {\n const url = `/api/public-keys`;\n return this.axios.post(url, req);\n }\n\n logoutCurrentUser(): Promise {\n return new Promise((resolve, reject) => {\n this.logout()\n .then(\n () => {\n this.store.commit(Mutation.SetUser, null);\n resolve();\n },\n error => {\n reject(error);\n },\n );\n });\n }\n\n refreshCurrentUser(): Promise {\n return new Promise((resolve, reject) => {\n this.currentUser()\n .then(\n response => {\n this.store.commit(Mutation.SetUser, response.data.user);\n resolve(response.data);\n },\n error => {\n reject(error);\n },\n );\n });\n }\n}","import { createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\nimport _imports_0 from '../assets/logo.svg'\n\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-41f23fd0\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"a\", {\n class: \"logo\",\n href: \"/\"\n}, [\n /*#__PURE__*/_createElementVNode(\"img\", { src: _imports_0 })\n], -1))\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"nav\", null, [\n /*#__PURE__*/_createElementVNode(\"ul\", null, [\n /*#__PURE__*/_createElementVNode(\"li\", null, [\n /*#__PURE__*/_createElementVNode(\"a\", { href: \"https://nos.social\" }, \"Download Nos\")\n ]),\n /*#__PURE__*/_createElementVNode(\"li\", null, [\n /*#__PURE__*/_createElementVNode(\"a\", { href: \"https://github.com/planetary-social/nos-crossposting-service\" }, \"Source code\")\n ])\n ])\n], -1))\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_LogoutButton = _resolveComponent(\"LogoutButton\")!\n\n return (_openBlock(), _createElementBlock(\"header\", null, [\n _hoisted_1,\n _hoisted_2,\n (_ctx.userIsLoggedIn)\n ? (_openBlock(), _createBlock(_component_LogoutButton, { key: 0 }))\n : _createCommentVNode(\"\", true)\n ]))\n}","\n\n\n\n\n","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\nimport _imports_0 from '../assets/logout_on_light.svg'\n\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-5ac017a3\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"label\" }, \" Logout \", -1))\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"img\", {\n class: \"icon\",\n src: _imports_0\n}, null, -1))\nconst _hoisted_3 = [\n _hoisted_1,\n _hoisted_2\n]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"a\", {\n class: \"logout-button\",\n onClick: _cache[0] || (_cache[0] = \n//@ts-ignore\n(...args) => (_ctx.logout && _ctx.logout(...args)))\n }, _hoisted_3))\n}","\n\n\n\n\n","import { render } from \"./LogoutButton.vue?vue&type=template&id=5ac017a3&scoped=true&ts=true\"\nimport script from \"./LogoutButton.vue?vue&type=script&lang=ts\"\nexport * from \"./LogoutButton.vue?vue&type=script&lang=ts\"\n\nimport \"./LogoutButton.vue?vue&type=style&index=0&id=5ac017a3&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-5ac017a3\"]])\n\nexport default __exports__","import { render } from \"./Header.vue?vue&type=template&id=41f23fd0&scoped=true&ts=true\"\nimport script from \"./Header.vue?vue&type=script&lang=ts\"\nexport * from \"./Header.vue?vue&type=script&lang=ts\"\n\nimport \"./Header.vue?vue&type=style&index=0&id=41f23fd0&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-41f23fd0\"]])\n\nexport default __exports__","import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, toDisplayString as _toDisplayString, createElementVNode as _createElementVNode, normalizeClass as _normalizeClass, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-11301b3e\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"notifications\" }\nconst _hoisted_2 = { class: \"text\" }\nconst _hoisted_3 = [\"onClick\"]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"ul\", _hoisted_1, [\n (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.notifications, (notification, index) => {\n return (_openBlock(), _createElementBlock(\"li\", {\n class: _normalizeClass([\"notification\", [notification.style]]),\n key: index\n }, [\n _createElementVNode(\"div\", _hoisted_2, _toDisplayString(notification.text), 1),\n _createElementVNode(\"div\", {\n class: \"button\",\n onClick: ($event: any) => (_ctx.dismiss(index))\n }, \" X \", 8, _hoisted_3)\n ], 2))\n }), 128))\n ]))\n}","\n\n\n\n\n","import { render } from \"./Notifications.vue?vue&type=template&id=11301b3e&scoped=true&ts=true\"\nimport script from \"./Notifications.vue?vue&type=script&lang=ts\"\nexport * from \"./Notifications.vue?vue&type=script&lang=ts\"\n\nimport \"./Notifications.vue?vue&type=style&index=0&id=11301b3e&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-11301b3e\"]])\n\nexport default __exports__","import { render } from \"./App.vue?vue&type=template&id=ea67d5b6&ts=true\"\nimport script from \"./App.vue?vue&type=script&lang=ts\"\nexport * from \"./App.vue?vue&type=script&lang=ts\"\n\nimport \"./App.vue?vue&type=style&index=0&id=ea67d5b6&lang=scss\"\n\nimport exportComponent from \"../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render]])\n\nexport default __exports__","import { resolveComponent as _resolveComponent, createVNode as _createVNode, createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode, renderList as _renderList, Fragment as _Fragment, toDisplayString as _toDisplayString, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-6df21b34\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"home\" }\nconst _hoisted_2 = { key: 0 }\nconst _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"step\" }, \" 1. Link your X account: \", -1))\nconst _hoisted_4 = { key: 1 }\nconst _hoisted_5 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"step\" }, \" 1. Logged in as \", -1))\nconst _hoisted_6 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"step\" }, \" 2. Your nostr identities: \", -1))\nconst _hoisted_7 = {\n key: 2,\n class: \"public-keys-wrapper\"\n}\nconst _hoisted_8 = { key: 0 }\nconst _hoisted_9 = {\n key: 1,\n class: \"public-keys\"\n}\nconst _hoisted_10 = { class: \"npub\" }\nconst _hoisted_11 = { class: \"link-npub-form\" }\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_Explanation = _resolveComponent(\"Explanation\")!\n const _component_LogInWithTwitterButton = _resolveComponent(\"LogInWithTwitterButton\")!\n const _component_CurrentUser = _resolveComponent(\"CurrentUser\")!\n const _component_Checkmark = _resolveComponent(\"Checkmark\")!\n const _component_Input = _resolveComponent(\"Input\")!\n const _component_Button = _resolveComponent(\"Button\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n _createVNode(_component_Explanation),\n (!_ctx.loadingUser && !_ctx.user)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_2, [\n _hoisted_3,\n _createVNode(_component_LogInWithTwitterButton)\n ]))\n : _createCommentVNode(\"\", true),\n (!_ctx.loadingUser && _ctx.user)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_4, [\n _hoisted_5,\n _createVNode(_component_CurrentUser, { user: _ctx.user }, null, 8, [\"user\"])\n ]))\n : _createCommentVNode(\"\", true),\n _hoisted_6,\n (!_ctx.loadingUser && _ctx.user)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_7, [\n (!_ctx.publicKeys)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_8, \" Loading public keys... \"))\n : _createCommentVNode(\"\", true),\n (_ctx.publicKeys && _ctx.publicKeys.publicKeys?.length > 0)\n ? (_openBlock(), _createElementBlock(\"ul\", _hoisted_9, [\n (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.publicKeys.publicKeys, (publicKey) => {\n return (_openBlock(), _createElementBlock(\"li\", {\n key: publicKey.npub\n }, [\n _createElementVNode(\"div\", _hoisted_10, _toDisplayString(publicKey.npub), 1),\n _createVNode(_component_Checkmark)\n ]))\n }), 128))\n ]))\n : _createCommentVNode(\"\", true)\n ]))\n : _createCommentVNode(\"\", true),\n _createElementVNode(\"div\", _hoisted_11, [\n _createVNode(_component_Input, {\n placeholder: \"Paste your npub address\",\n modelValue: _ctx.npub,\n \"onUpdate:modelValue\": _cache[0] || (_cache[0] = ($event: any) => ((_ctx.npub) = $event)),\n disabled: _ctx.formDisabled\n }, null, 8, [\"modelValue\", \"disabled\"]),\n _createVNode(_component_Button, {\n text: \"Add\",\n onClick: _ctx.addPublicKey,\n disabled: _ctx.formDisabled\n }, null, 8, [\"onClick\", \"disabled\"])\n ])\n ]))\n}","\n\n\n\n\n","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-5ace9f54\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"explanation\" }\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"large\" }, \" Start posting your Nostr content on X \", -1))\nconst _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"small\" }, \" Log in to your X account and add your Nostr identities so that everything you publish on Nostr will be mirrored on X \", -1))\nconst _hoisted_4 = [\n _hoisted_2,\n _hoisted_3\n]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, _hoisted_4))\n}","\n\n\n\n\n","import { render } from \"./Explanation.vue?vue&type=template&id=5ace9f54&scoped=true&ts=true\"\nimport script from \"./Explanation.vue?vue&type=script&lang=ts\"\nexport * from \"./Explanation.vue?vue&type=script&lang=ts\"\n\nimport \"./Explanation.vue?vue&type=style&index=0&id=5ace9f54&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-5ace9f54\"]])\n\nexport default __exports__","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\nimport _imports_0 from '../assets/login_with_x.svg'\n\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-58fab459\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = {\n href: \"/login\",\n class: \"log-in-with-twitter-button\"\n}\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"img-wrapper\" }, [\n /*#__PURE__*/_createElementVNode(\"img\", { src: _imports_0 })\n], -1))\nconst _hoisted_3 = [\n _hoisted_2\n]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"a\", _hoisted_1, _hoisted_3))\n}","\n\n\n\n\n","import { render } from \"./LogInWithTwitterButton.vue?vue&type=template&id=58fab459&scoped=true&ts=true\"\nimport script from \"./LogInWithTwitterButton.vue?vue&type=script&lang=ts\"\nexport * from \"./LogInWithTwitterButton.vue?vue&type=script&lang=ts\"\n\nimport \"./LogInWithTwitterButton.vue?vue&type=style&index=0&id=58fab459&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-58fab459\"]])\n\nexport default __exports__","import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, resolveComponent as _resolveComponent, createVNode as _createVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\nimport _imports_0 from '../assets/logout_on_dark.svg'\n\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-bf1931c6\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"current-user\" }\nconst _hoisted_2 = { class: \"user-info\" }\nconst _hoisted_3 = [\"src\"]\nconst _hoisted_4 = { class: \"name\" }\nconst _hoisted_5 = { class: \"username\" }\nconst _hoisted_6 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"img\", { src: _imports_0 }, null, -1))\nconst _hoisted_7 = [\n _hoisted_6\n]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_Checkmark = _resolveComponent(\"Checkmark\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n _createElementVNode(\"div\", _hoisted_2, [\n _createElementVNode(\"img\", {\n class: \"image\",\n src: _ctx.user?.twitterProfileImageURL\n }, null, 8, _hoisted_3),\n _createElementVNode(\"div\", _hoisted_4, _toDisplayString(_ctx.user.twitterName), 1),\n _createElementVNode(\"div\", _hoisted_5, \"@\" + _toDisplayString(_ctx.user.twitterUsername), 1),\n _createElementVNode(\"a\", {\n class: \"logout-button\",\n onClick: _cache[0] || (_cache[0] = \n//@ts-ignore\n(...args) => (_ctx.logout && _ctx.logout(...args)))\n }, _hoisted_7)\n ]),\n _createVNode(_component_Checkmark)\n ]))\n}","\n\n\n\n\n","export class User {\n accountID?: string;\n twitterID?: number;\n twitterName?: string;\n twitterUsername?: string;\n twitterProfileImageURL?: string;\n}","import { openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\nimport _imports_0 from '../assets/checkmark.svg'\n\n\nconst _hoisted_1 = {\n class: \"checkmark\",\n src: _imports_0\n}\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"img\", _hoisted_1))\n}","\n\n\n","import { render } from \"./Checkmark.vue?vue&type=template&id=4ebda3e8&ts=true\"\nimport script from \"./Checkmark.vue?vue&type=script&lang=ts\"\nexport * from \"./Checkmark.vue?vue&type=script&lang=ts\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render]])\n\nexport default __exports__","import { render } from \"./CurrentUser.vue?vue&type=template&id=bf1931c6&scoped=true&ts=true\"\nimport script from \"./CurrentUser.vue?vue&type=script&lang=ts\"\nexport * from \"./CurrentUser.vue?vue&type=script&lang=ts\"\n\nimport \"./CurrentUser.vue?vue&type=style&index=0&id=bf1931c6&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-bf1931c6\"]])\n\nexport default __exports__","export class AddPublicKeyRequest {\n npub: string;\n\n constructor(npub: string) {\n this.npub = npub\n }\n}","import { normalizeClass as _normalizeClass, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-a3a07d36\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = [\"placeholder\", \"value\", \"disabled\"]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"input\", {\n type: \"text\",\n placeholder: _ctx.placeholder,\n value: _ctx.modelValue,\n class: _normalizeClass([\"input\", { disabled: _ctx.disabled }]),\n onInput: _cache[0] || (_cache[0] = \n//@ts-ignore\n(...args) => (_ctx.onInput && _ctx.onInput(...args))),\n disabled: _ctx.disabled\n }, null, 42, _hoisted_1))\n}","\n\n\n\n\n","import { render } from \"./Input.vue?vue&type=template&id=a3a07d36&scoped=true&ts=true\"\nimport script from \"./Input.vue?vue&type=script&lang=ts\"\nexport * from \"./Input.vue?vue&type=script&lang=ts\"\n\nimport \"./Input.vue?vue&type=style&index=0&id=a3a07d36&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-a3a07d36\"]])\n\nexport default __exports__","import { toDisplayString as _toDisplayString, normalizeClass as _normalizeClass, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"button\", {\n onClick: _cache[0] || (_cache[0] = \n//@ts-ignore\n(...args) => (_ctx.onClick && _ctx.onClick(...args))),\n class: _normalizeClass({ button: true, disabled: _ctx.disabled })\n }, _toDisplayString(_ctx.text), 3))\n}","\n\n\n\n\n","import { render } from \"./Button.vue?vue&type=template&id=6881488a&scoped=true&ts=true\"\nimport script from \"./Button.vue?vue&type=script&lang=ts\"\nexport * from \"./Button.vue?vue&type=script&lang=ts\"\n\nimport \"./Button.vue?vue&type=style&index=0&id=6881488a&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-6881488a\"]])\n\nexport default __exports__","import { render } from \"./HomeView.vue?vue&type=template&id=6df21b34&scoped=true&ts=true\"\nimport script from \"./HomeView.vue?vue&type=script&lang=ts\"\nexport * from \"./HomeView.vue?vue&type=script&lang=ts\"\n\nimport \"./HomeView.vue?vue&type=style&index=0&id=6df21b34&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-6df21b34\"]])\n\nexport default __exports__","import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'\nimport HomeView from '../views/HomeView.vue'\n\nconst routes: Array = [\n {\n path: '/',\n name: 'home',\n component: HomeView\n },\n]\n\nconst router = createRouter({\n history: createWebHistory(process.env.BASE_URL),\n routes\n})\n\nexport default router\n","import { createApp } from 'vue'\nimport App from './App.vue'\nimport router from './router'\nimport store from './store'\n\ncreateApp(App).use(store).use(router).mount('#app')\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","var deferred = [];\n__webpack_require__.O = function(result, chunkIds, fn, priority) {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar chunkIds = deferred[i][0];\n\t\tvar fn = deferred[i][1];\n\t\tvar priority = deferred[i][2];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every(function(key) { return __webpack_require__.O[key](chunkIds[j]); })) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","__webpack_require__.p = \"/\";","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t143: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = function(chunkId) { return installedChunks[chunkId] === 0; };\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = function(parentChunkLoadingFunction, data) {\n\tvar chunkIds = data[0];\n\tvar moreModules = data[1];\n\tvar runtime = data[2];\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some(function(id) { return installedChunks[id] !== 0; })) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunknos_crossposting_service_frontend\"] = self[\"webpackChunknos_crossposting_service_frontend\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [998], function() { return __webpack_require__(4362); })\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n"],"names":["_hoisted_1","class","_hoisted_2","render","_ctx","_cache","$props","$setup","$data","$options","_component_Header","_resolveComponent","_component_Notifications","_component_router_view","_openBlock","_createElementBlock","_createVNode","_createElementVNode","Mutation","Notification","constructor","style","text","_defineProperty","createStore","state","user","undefined","notifications","getters","mutations","SetUser","PushNotificationError","push","DismissNotification","index","splice","actions","modules","APIService","store","axios","create","currentUser","url","this","get","logout","delete","publicKeys","addPublicKey","req","post","logoutCurrentUser","Promise","resolve","reject","then","commit","error","refreshCurrentUser","response","data","_withScopeId","n","_pushScopeId","_popScopeId","href","src","_imports_0","_component_LogoutButton","userIsLoggedIn","_createBlock","key","_createCommentVNode","_hoisted_3","onClick","args","LogOutButton","Vue","useStore","apiService","catch","__decorate","Options","__exports__","Header","components","LogoutButton","_Fragment","_renderList","notification","_normalizeClass","_toDisplayString","$event","dismiss","Notifications","App","created","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_component_Explanation","_component_LogInWithTwitterButton","_component_CurrentUser","_component_Checkmark","_component_Input","_component_Button","loadingUser","length","publicKey","npub","placeholder","modelValue","disabled","formDisabled","Explanation","LogInWithTwitterButton","twitterProfileImageURL","twitterName","twitterUsername","User","Checkmark","CurrentUser","props","AddPublicKeyRequest","type","value","onInput","Input","event","$emit","target","String","Boolean","emits","button","Button","HomeView","watchUser","oldUser","newUser","reloadPublicKeys","status","Watch","routes","path","name","component","router","createRouter","history","createWebHistory","process","createApp","use","mount","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","exports","module","__webpack_modules__","call","m","deferred","O","result","chunkIds","fn","priority","notFulfilled","Infinity","i","fulfilled","j","Object","keys","every","r","getter","__esModule","d","a","definition","o","defineProperty","enumerable","g","globalThis","Function","e","window","obj","prop","prototype","hasOwnProperty","p","installedChunks","chunkId","webpackJsonpCallback","parentChunkLoadingFunction","moreModules","runtime","some","id","chunkLoadingGlobal","self","forEach","bind","__webpack_exports__"],"sourceRoot":""} \ No newline at end of file diff --git a/service/ports/http/frontend/js/app.5ea5ba64.js b/service/ports/http/frontend/js/app.5ea5ba64.js new file mode 100644 index 0000000..34f5e88 --- /dev/null +++ b/service/ports/http/frontend/js/app.5ea5ba64.js @@ -0,0 +1,2 @@ +(function(){"use strict";var e={1110:function(e,t,i){var r=i(9242),o=i(3396);const s={class:"wrapper"},n={class:"content"};function c(e,t,i,r,c,l){const u=(0,o.up)("Header"),a=(0,o.up)("Notifications"),d=(0,o.up)("router-view");return(0,o.wg)(),(0,o.iD)("div",s,[(0,o.Wm)(u),(0,o._)("div",n,[(0,o.Wm)(a),(0,o.Wm)(d)])])}var l,u=i(7327),a=i(6520),d=i(65),p=i(4161);class f{constructor(e,t){(0,u.Z)(this,"style",void 0),(0,u.Z)(this,"text",void 0),this.style=e,this.text=t}}(function(e){e["SetUser"]="setUser",e["PushNotificationError"]="pushNotificationError",e["DismissNotification"]="dismissNotification"})(l||(l={}));var h=(0,d.MT)({state:{user:void 0,notifications:[]},getters:{},mutations:{[l.SetUser](e,t){e.user=t},[l.PushNotificationError](e,t){e.notifications?.push(new f("error",t))},[l.DismissNotification](e,t){e.notifications?.splice(t,1)}},actions:{},modules:{}});class g{constructor(e){(0,u.Z)(this,"store",void 0),(0,u.Z)(this,"axios",p.Z.create()),this.store=e}currentUser(){const e="/api/current-user";return this.axios.get(e)}logout(){const e="/api/current-user";return this.axios.delete(e)}publicKeys(){const e="/api/current-user/public-keys";return this.axios.get(e)}addPublicKey(e){const t="/api/current-user/public-keys";return this.axios.post(t,e)}deletePublicKey(e){const t=`/api/current-user/public-keys/${e.npub}`;return this.axios.delete(t)}logoutCurrentUser(){return new Promise(((e,t)=>{this.logout().then((()=>{this.store.commit(l.SetUser,null),e()}),(e=>{t(e)}))}))}refreshCurrentUser(){return new Promise(((e,t)=>{this.currentUser().then((t=>{this.store.commit(l.SetUser,t.data.user),e(t.data)}),(e=>{t(e)}))}))}}var v=i.p+"img/logo.79c97fb0.svg";const b=e=>((0,o.dD)("data-v-41f23fd0"),e=e(),(0,o.Cn)(),e),y=b((()=>(0,o._)("a",{class:"logo",href:"/"},[(0,o._)("img",{src:v})],-1))),m=b((()=>(0,o._)("nav",null,[(0,o._)("ul",null,[(0,o._)("li",null,[(0,o._)("a",{href:"https://nos.social"},"Download Nos")]),(0,o._)("li",null,[(0,o._)("a",{href:"https://github.com/planetary-social/nos-crossposting-service"},"Source code")])])],-1)));function w(e,t,i,r,s,n){const c=(0,o.up)("LogoutButton");return(0,o.wg)(),(0,o.iD)("header",null,[y,m,e.userIsLoggedIn?((0,o.wg)(),(0,o.j4)(c,{key:0})):(0,o.kq)("",!0)])}var _=i.p+"img/logout_on_light.d9f6b5e8.svg";const k=e=>((0,o.dD)("data-v-5ac017a3"),e=e(),(0,o.Cn)(),e),P=k((()=>(0,o._)("div",{class:"label"}," Logout ",-1))),K=k((()=>(0,o._)("img",{class:"icon",src:_},null,-1))),R=[P,K];function D(e,t,i,r,s,n){return(0,o.wg)(),(0,o.iD)("a",{class:"logout-button",onClick:t[0]||(t[0]=(...t)=>e.logout&&e.logout(...t))},R)}var O=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let Z=class extends a.w3{constructor(...e){super(...e),(0,u.Z)(this,"apiService",new g((0,d.oR)())),(0,u.Z)(this,"store",(0,d.oR)())}logout(){this.apiService.logoutCurrentUser().catch((()=>{this.store.commit(l.PushNotificationError,"Error logging out the user.")}))}};Z=O([(0,a.Ei)({})],Z);var j=Z,x=i(89);const E=(0,x.Z)(j,[["render",D],["__scopeId","data-v-5ac017a3"]]);var C=E,U=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let I=class extends a.w3{constructor(...e){super(...e),(0,u.Z)(this,"store",(0,d.oR)())}get userIsLoggedIn(){return!!this.store.state.user}};I=U([(0,a.Ei)({components:{LogoutButton:C}})],I);var N=I;const S=(0,x.Z)(N,[["render",w],["__scopeId","data-v-41f23fd0"]]);var L=S,W=i(7139);const T={class:"notifications"},q={class:"text"},B=["onClick"];function V(e,t,i,r,s,n){return(0,o.wg)(),(0,o.iD)("ul",T,[((0,o.wg)(!0),(0,o.iD)(o.HY,null,(0,o.Ko)(e.notifications,((t,i)=>((0,o.wg)(),(0,o.iD)("li",{class:(0,W.C_)(["notification",[t.style]]),key:i},[(0,o._)("div",q,(0,W.zw)(t.text),1),(0,o._)("div",{class:"button",onClick:t=>e.dismiss(i)}," X ",8,B)],2)))),128))])}var z=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let X=class extends a.w3{constructor(...e){super(...e),(0,u.Z)(this,"store",(0,d.oR)())}get notifications(){return this.store.state.notifications}dismiss(e){this.store.commit(l.DismissNotification,e)}};X=z([(0,a.Ei)({components:{}})],X);var H=X;const Y=(0,x.Z)(H,[["render",V],["__scopeId","data-v-11301b3e"]]);var $=Y,M=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let A=class extends a.w3{constructor(...e){super(...e),(0,u.Z)(this,"apiService",new g((0,d.oR)())),(0,u.Z)(this,"store",(0,d.oR)())}created(){this.apiService.refreshCurrentUser().catch((()=>{this.store.commit(l.PushNotificationError,"Error loading the user.")}))}};A=M([(0,a.Ei)({components:{Notifications:$,Header:L}})],A);var F=A;const G=(0,x.Z)(F,[["render",c]]);var J=G,Q=i(2483),ee=i.p+"img/delete.0ed4aa0d.svg";const te=e=>((0,o.dD)("data-v-28506258"),e=e(),(0,o.Cn)(),e),ie={class:"home"},re={key:0},oe=te((()=>(0,o._)("div",{class:"step"},[(0,o._)("div",{class:"text"}," 1. Link your X account: ")],-1))),se={key:1},ne=te((()=>(0,o._)("div",{class:"step"},[(0,o._)("div",{class:"text"}," 1. Logged in as ")],-1))),ce={class:"step"},le=te((()=>(0,o._)("div",{class:"text"}," 2. Your nostr identities: ",-1))),ue={class:"actions"},ae={key:0},de={key:1},pe={key:2,class:"public-keys-wrapper"},fe={key:0},he={key:1,class:"public-keys"},ge=["onClick"],ve=te((()=>(0,o._)("img",{src:ee},null,-1))),be=[ve],ye={class:"npub"},me={class:"link-npub-form"};function we(e,t,i,r,s,n){const c=(0,o.up)("Explanation"),l=(0,o.up)("LogInWithTwitterButton"),u=(0,o.up)("CurrentUser"),a=(0,o.up)("Checkmark"),d=(0,o.up)("Input"),p=(0,o.up)("Button");return(0,o.wg)(),(0,o.iD)("div",ie,[(0,o.Wm)(c),e.loadingUser||e.user?(0,o.kq)("",!0):((0,o.wg)(),(0,o.iD)("div",re,[oe,(0,o.Wm)(l)])),!e.loadingUser&&e.user?((0,o.wg)(),(0,o.iD)("div",se,[ne,(0,o.Wm)(u,{user:e.user},null,8,["user"])])):(0,o.kq)("",!0),(0,o._)("div",ce,[le,(0,o._)("ul",ue,[e.publicKeys&&e.publicKeys.publicKeys?.length>0&&!e.editingPublicKeys?((0,o.wg)(),(0,o.iD)("li",ae,[(0,o._)("a",{onClick:t[0]||(t[0]=(...t)=>e.startEditingPublicKeys&&e.startEditingPublicKeys(...t))}," Edit ")])):(0,o.kq)("",!0),e.editingPublicKeys?((0,o.wg)(),(0,o.iD)("li",de,[(0,o._)("a",{onClick:t[1]||(t[1]=(...t)=>e.endEditingPublicKeys&&e.endEditingPublicKeys(...t))}," Done ")])):(0,o.kq)("",!0)])]),!e.loadingUser&&e.user?((0,o.wg)(),(0,o.iD)("div",pe,[e.publicKeys?(0,o.kq)("",!0):((0,o.wg)(),(0,o.iD)("div",fe," Loading public keys... ")),e.publicKeys&&e.publicKeys.publicKeys?.length>0?((0,o.wg)(),(0,o.iD)("ul",he,[((0,o.wg)(!0),(0,o.iD)(o.HY,null,(0,o.Ko)(e.publicKeys.publicKeys,(t=>((0,o.wg)(),(0,o.iD)("li",{key:t.npub},[e.editingPublicKeys?((0,o.wg)(),(0,o.iD)("a",{key:0,onClick:i=>e.scheduleDelete(t),class:"delete-public-key-button"},be,8,ge)):(0,o.kq)("",!0),(0,o._)("div",ye,(0,W.zw)(t.npub),1),e.editingPublicKeys?(0,o.kq)("",!0):((0,o.wg)(),(0,o.j4)(a,{key:1}))])))),128))])):(0,o.kq)("",!0)])):(0,o.kq)("",!0),(0,o._)("div",me,[(0,o.Wm)(d,{placeholder:"Paste your npub address",modelValue:e.npub,"onUpdate:modelValue":t[2]||(t[2]=t=>e.npub=t),disabled:e.formDisabled},null,8,["modelValue","disabled"]),(0,o.Wm)(p,{text:"Add",onButtonClick:e.addPublicKey,disabled:e.formDisabled},null,8,["onButtonClick","disabled"])])])}i(7658);var _e=i(4815);const ke=e=>((0,o.dD)("data-v-5ace9f54"),e=e(),(0,o.Cn)(),e),Pe={class:"explanation"},Ke=ke((()=>(0,o._)("div",{class:"large"}," Start posting your Nostr content on X ",-1))),Re=ke((()=>(0,o._)("div",{class:"small"}," Log in to your X account and add your Nostr identities so that everything you publish on Nostr will be mirrored on X ",-1))),De=[Ke,Re];function Oe(e,t,i,r,s,n){return(0,o.wg)(),(0,o.iD)("div",Pe,De)}var Ze=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let je=class extends a.w3{};je=Ze([(0,a.Ei)({})],je);var xe=je;const Ee=(0,x.Z)(xe,[["render",Oe],["__scopeId","data-v-5ace9f54"]]);var Ce=Ee,Ue=i.p+"img/login_with_x.b3cda31f.svg";const Ie=e=>((0,o.dD)("data-v-58fab459"),e=e(),(0,o.Cn)(),e),Ne={href:"/login",class:"log-in-with-twitter-button"},Se=Ie((()=>(0,o._)("div",{class:"img-wrapper"},[(0,o._)("img",{src:Ue})],-1))),Le=[Se];function We(e,t,i,r,s,n){return(0,o.wg)(),(0,o.iD)("a",Ne,Le)}var Te=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let qe=class extends a.w3{};qe=Te([(0,a.Ei)({})],qe);var Be=qe;const Ve=(0,x.Z)(Be,[["render",We],["__scopeId","data-v-58fab459"]]);var ze=Ve,Xe=i.p+"img/logout_on_dark.2eaec2bd.svg";const He=e=>((0,o.dD)("data-v-bf1931c6"),e=e(),(0,o.Cn)(),e),Ye={class:"current-user"},$e={class:"user-info"},Me=["src"],Ae={class:"name"},Fe={class:"username"},Ge=He((()=>(0,o._)("img",{src:Xe},null,-1))),Je=[Ge];function Qe(e,t,i,r,s,n){const c=(0,o.up)("Checkmark");return(0,o.wg)(),(0,o.iD)("div",Ye,[(0,o._)("div",$e,[(0,o._)("img",{class:"image",src:e.user?.twitterProfileImageURL},null,8,Me),(0,o._)("div",Ae,(0,W.zw)(e.user.twitterName),1),(0,o._)("div",Fe,"@"+(0,W.zw)(e.user.twitterUsername),1),(0,o._)("a",{class:"logout-button",onClick:t[0]||(t[0]=(...t)=>e.logout&&e.logout(...t))},Je)]),(0,o.Wm)(c)])}class et{constructor(){(0,u.Z)(this,"accountID",void 0),(0,u.Z)(this,"twitterID",void 0),(0,u.Z)(this,"twitterName",void 0),(0,u.Z)(this,"twitterUsername",void 0),(0,u.Z)(this,"twitterProfileImageURL",void 0)}}var tt=i.p+"img/checkmark.3921dcf8.svg";const it={class:"checkmark",src:tt};function rt(e,t,i,r,s,n){return(0,o.wg)(),(0,o.iD)("img",it)}var ot=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let st=class extends a.w3{};st=ot([(0,a.Ei)({})],st);var nt=st;const ct=(0,x.Z)(nt,[["render",rt]]);var lt=ct,ut=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let at=class extends a.w3{constructor(...e){super(...e),(0,u.Z)(this,"user",void 0),(0,u.Z)(this,"apiService",new g((0,d.oR)())),(0,u.Z)(this,"store",(0,d.oR)())}logout(){this.apiService.logoutCurrentUser().catch((()=>{this.store.commit(l.PushNotificationError,"Error logging out the user.")}))}};at=ut([(0,a.Ei)({components:{Checkmark:lt},props:{user:et}})],at);var dt=at;const pt=(0,x.Z)(dt,[["render",Qe],["__scopeId","data-v-bf1931c6"]]);var ft=pt;class ht{constructor(e){(0,u.Z)(this,"npub",void 0),this.npub=e}}const gt=["placeholder","value","disabled"];function vt(e,t,i,r,s,n){return(0,o.wg)(),(0,o.iD)("input",{type:"text",placeholder:e.placeholder,value:e.modelValue,class:(0,W.C_)(["input",{disabled:e.disabled}]),onInput:t[0]||(t[0]=(...t)=>e.onInput&&e.onInput(...t)),disabled:e.disabled},null,42,gt)}var bt=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let yt=class extends a.w3{constructor(...e){super(...e),(0,u.Z)(this,"placeholder",void 0),(0,u.Z)(this,"modelValue",void 0),(0,u.Z)(this,"disabled",void 0)}onInput(e){this.$emit("update:modelValue",e.target.value)}};yt=bt([(0,a.Ei)({props:{placeholder:String,modelValue:String,disabled:Boolean},emits:["update:modelValue"]})],yt);var mt=yt;const wt=(0,x.Z)(mt,[["render",vt],["__scopeId","data-v-a3a07d36"]]);var _t=wt;function kt(e,t,i,r,s,n){return(0,o.wg)(),(0,o.iD)("button",{onClick:t[0]||(t[0]=(...t)=>e.onClick&&e.onClick(...t)),class:(0,W.C_)({button:!0,disabled:e.disabled})},(0,W.zw)(e.text),3)}var Pt=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let Kt=class extends a.w3{constructor(...e){super(...e),(0,u.Z)(this,"text",void 0),(0,u.Z)(this,"disabled",void 0)}onClick(e){this.disabled||this.$emit("buttonClick",e)}};Kt=Pt([(0,a.Ei)({props:{text:String,disabled:Boolean}})],Kt);var Rt=Kt;const Dt=(0,x.Z)(Rt,[["render",kt],["__scopeId","data-v-59245c60"]]);var Ot=Dt,Zt=function(e,t,i,r){var o,s=arguments.length,n=s<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"===typeof Reflect&&"function"===typeof Reflect.decorate)n=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(o=e[c])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};let jt=class extends a.w3{constructor(...e){super(...e),(0,u.Z)(this,"apiService",new g((0,d.oR)())),(0,u.Z)(this,"store",(0,d.oR)()),(0,u.Z)(this,"publicKeys",null),(0,u.Z)(this,"npub",""),(0,u.Z)(this,"editingPublicKeys",!1),(0,u.Z)(this,"publicKeysToRemove",[])}get loadingUser(){return void 0===this.store.state.user}get user(){return this.store.state.user}get formDisabled(){return this.loadingUser||!this.user}watchUser(e){e?this.reloadPublicKeys():this.publicKeys={publicKeys:[]}}startEditingPublicKeys(){this.publicKeysToRemove=[],this.editingPublicKeys=!0}endEditingPublicKeys(){for(const e of this.publicKeysToRemove)this.apiService.deletePublicKey(e).catch((()=>this.store.commit(l.PushNotificationError,"Error removing a public key.")));this.publicKeysToRemove=[],this.editingPublicKeys=!1,this.reloadPublicKeys()}scheduleDelete(e){const t=this.publicKeys?.publicKeys?.indexOf(e);void 0!==t&&t>=0&&(this.publicKeys?.publicKeys?.splice(t,1),this.publicKeys={publicKeys:[...this.publicKeys?.publicKeys||[]]}),this.publicKeysToRemove.push(e)}addPublicKey(){this.apiService.addPublicKey(new ht(this.npub)).then((()=>{this.npub="",this.cancelEditingPublicKeysWithoutReloading(),this.reloadPublicKeys()})).catch((()=>{this.store.commit(l.PushNotificationError,"Error adding the public key.")}))}cancelEditingPublicKeysWithoutReloading(){this.publicKeysToRemove=[],this.editingPublicKeys=!1,this.reloadPublicKeys()}reloadPublicKeys(){this.publicKeys=null,this.apiService.publicKeys().then((e=>{this.publicKeys=e.data})).catch((e=>{e.response&&401===e.response.status||this.store.commit(l.PushNotificationError,"Error loading the public keys.")}))}};Zt([(0,_e.RL)("user")],jt.prototype,"watchUser",null),jt=Zt([(0,a.Ei)({components:{Checkmark:lt,Button:Ot,CurrentUser:ft,LogInWithTwitterButton:ze,Explanation:Ce,Input:_t}})],jt);var xt=jt;const Et=(0,x.Z)(xt,[["render",we],["__scopeId","data-v-28506258"]]);var Ct=Et;const Ut=[{path:"/",name:"home",component:Ct}],It=(0,Q.p7)({history:(0,Q.PO)("/"),routes:Ut});var Nt=It;(0,r.ri)(J).use(h).use(Nt).mount("#app")}},t={};function i(r){var o=t[r];if(void 0!==o)return o.exports;var s=t[r]={exports:{}};return e[r].call(s.exports,s,s.exports,i),s.exports}i.m=e,function(){var e=[];i.O=function(t,r,o,s){if(!r){var n=1/0;for(a=0;a=s)&&Object.keys(i.O).every((function(e){return i.O[e](r[l])}))?r.splice(l--,1):(c=!1,s0&&e[a-1][2]>s;a--)e[a]=e[a-1];e[a]=[r,o,s]}}(),function(){i.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return i.d(t,{a:t}),t}}(),function(){i.d=function(e,t){for(var r in t)i.o(t,r)&&!i.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})}}(),function(){i.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"===typeof window)return window}}()}(),function(){i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}}(),function(){i.p="/"}(),function(){var e={143:0};i.O.j=function(t){return 0===e[t]};var t=function(t,r){var o,s,n=r[0],c=r[1],l=r[2],u=0;if(n.some((function(t){return 0!==e[t]}))){for(o in c)i.o(c,o)&&(i.m[o]=c[o]);if(l)var a=l(i)}for(t&&t(r);u\n
\n
\n
\n \n \n
\n
\n\n\n\n\n\n","import {createStore} from 'vuex'\nimport {User} from \"@/dto/User\";\n\nclass Notification {\n constructor(\n public style: string,\n public text: string,\n ) {\n }\n}\n\nexport enum Mutation {\n SetUser = 'setUser',\n PushNotificationError = 'pushNotificationError',\n DismissNotification = 'dismissNotification',\n}\n\nexport class State {\n user?: User;\n notifications?: Notification[];\n}\n\nexport default createStore({\n state: {\n user: undefined,\n notifications: [],\n },\n getters: {},\n mutations: {\n [Mutation.SetUser](state: State, user: User): void {\n state.user = user;\n },\n [Mutation.PushNotificationError](state: State, text: string): void {\n state.notifications?.push(new Notification('error', text));\n },\n [Mutation.DismissNotification](state: State, index: number): void {\n state.notifications?.splice(index, 1);\n },\n },\n actions: {},\n modules: {}\n})\n","import axios, {AxiosResponse} from 'axios';\nimport {CurrentUser} from \"@/dto/CurrentUser\";\nimport {Mutation, State} from '@/store';\nimport {PublicKeys} from \"@/dto/PublicKeys\";\nimport {AddPublicKeyRequest} from \"@/dto/AddPublicKeyRequest\";\nimport {Store} from \"vuex\";\nimport {PublicKey} from \"@/dto/PublicKey\";\n\nexport class APIService {\n\n private readonly axios = axios.create();\n\n constructor(private store: Store) {\n }\n\n private currentUser(): Promise> {\n const url = `/api/current-user`;\n return this.axios.get(url);\n }\n\n private logout(): Promise> {\n const url = `/api/current-user`;\n return this.axios.delete(url);\n }\n\n publicKeys(): Promise> {\n const url = `/api/current-user/public-keys`;\n return this.axios.get(url);\n }\n\n addPublicKey(req: AddPublicKeyRequest): Promise> {\n const url = `/api/current-user/public-keys`;\n return this.axios.post(url, req);\n }\n\n deletePublicKey(publicKey: PublicKey): Promise> {\n const url = `/api/current-user/public-keys/${publicKey.npub}`;\n return this.axios.delete(url);\n }\n\n logoutCurrentUser(): Promise {\n return new Promise((resolve, reject) => {\n this.logout()\n .then(\n () => {\n this.store.commit(Mutation.SetUser, null);\n resolve();\n },\n error => {\n reject(error);\n },\n );\n });\n }\n\n refreshCurrentUser(): Promise {\n return new Promise((resolve, reject) => {\n this.currentUser()\n .then(\n response => {\n this.store.commit(Mutation.SetUser, response.data.user);\n resolve(response.data);\n },\n error => {\n reject(error);\n },\n );\n });\n }\n}","import { createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\nimport _imports_0 from '../assets/logo.svg'\n\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-41f23fd0\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"a\", {\n class: \"logo\",\n href: \"/\"\n}, [\n /*#__PURE__*/_createElementVNode(\"img\", { src: _imports_0 })\n], -1))\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"nav\", null, [\n /*#__PURE__*/_createElementVNode(\"ul\", null, [\n /*#__PURE__*/_createElementVNode(\"li\", null, [\n /*#__PURE__*/_createElementVNode(\"a\", { href: \"https://nos.social\" }, \"Download Nos\")\n ]),\n /*#__PURE__*/_createElementVNode(\"li\", null, [\n /*#__PURE__*/_createElementVNode(\"a\", { href: \"https://github.com/planetary-social/nos-crossposting-service\" }, \"Source code\")\n ])\n ])\n], -1))\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_LogoutButton = _resolveComponent(\"LogoutButton\")!\n\n return (_openBlock(), _createElementBlock(\"header\", null, [\n _hoisted_1,\n _hoisted_2,\n (_ctx.userIsLoggedIn)\n ? (_openBlock(), _createBlock(_component_LogoutButton, { key: 0 }))\n : _createCommentVNode(\"\", true)\n ]))\n}","\n\n\n\n\n","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\nimport _imports_0 from '../assets/logout_on_light.svg'\n\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-5ac017a3\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"label\" }, \" Logout \", -1))\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"img\", {\n class: \"icon\",\n src: _imports_0\n}, null, -1))\nconst _hoisted_3 = [\n _hoisted_1,\n _hoisted_2\n]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"a\", {\n class: \"logout-button\",\n onClick: _cache[0] || (_cache[0] = \n//@ts-ignore\n(...args) => (_ctx.logout && _ctx.logout(...args)))\n }, _hoisted_3))\n}","\n\n\n\n\n","import { render } from \"./LogoutButton.vue?vue&type=template&id=5ac017a3&scoped=true&ts=true\"\nimport script from \"./LogoutButton.vue?vue&type=script&lang=ts\"\nexport * from \"./LogoutButton.vue?vue&type=script&lang=ts\"\n\nimport \"./LogoutButton.vue?vue&type=style&index=0&id=5ac017a3&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-5ac017a3\"]])\n\nexport default __exports__","import { render } from \"./Header.vue?vue&type=template&id=41f23fd0&scoped=true&ts=true\"\nimport script from \"./Header.vue?vue&type=script&lang=ts\"\nexport * from \"./Header.vue?vue&type=script&lang=ts\"\n\nimport \"./Header.vue?vue&type=style&index=0&id=41f23fd0&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-41f23fd0\"]])\n\nexport default __exports__","import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, toDisplayString as _toDisplayString, createElementVNode as _createElementVNode, normalizeClass as _normalizeClass, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-11301b3e\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"notifications\" }\nconst _hoisted_2 = { class: \"text\" }\nconst _hoisted_3 = [\"onClick\"]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"ul\", _hoisted_1, [\n (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.notifications, (notification, index) => {\n return (_openBlock(), _createElementBlock(\"li\", {\n class: _normalizeClass([\"notification\", [notification.style]]),\n key: index\n }, [\n _createElementVNode(\"div\", _hoisted_2, _toDisplayString(notification.text), 1),\n _createElementVNode(\"div\", {\n class: \"button\",\n onClick: ($event: any) => (_ctx.dismiss(index))\n }, \" X \", 8, _hoisted_3)\n ], 2))\n }), 128))\n ]))\n}","\n\n\n\n\n","import { render } from \"./Notifications.vue?vue&type=template&id=11301b3e&scoped=true&ts=true\"\nimport script from \"./Notifications.vue?vue&type=script&lang=ts\"\nexport * from \"./Notifications.vue?vue&type=script&lang=ts\"\n\nimport \"./Notifications.vue?vue&type=style&index=0&id=11301b3e&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-11301b3e\"]])\n\nexport default __exports__","import { render } from \"./App.vue?vue&type=template&id=ea67d5b6&ts=true\"\nimport script from \"./App.vue?vue&type=script&lang=ts\"\nexport * from \"./App.vue?vue&type=script&lang=ts\"\n\nimport \"./App.vue?vue&type=style&index=0&id=ea67d5b6&lang=scss\"\n\nimport exportComponent from \"../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render]])\n\nexport default __exports__","import { resolveComponent as _resolveComponent, createVNode as _createVNode, createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode, renderList as _renderList, Fragment as _Fragment, toDisplayString as _toDisplayString, createBlock as _createBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\nimport _imports_0 from '../assets/delete.svg'\n\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-28506258\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"home\" }\nconst _hoisted_2 = { key: 0 }\nconst _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"step\" }, [\n /*#__PURE__*/_createElementVNode(\"div\", { class: \"text\" }, \" 1. Link your X account: \")\n], -1))\nconst _hoisted_4 = { key: 1 }\nconst _hoisted_5 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"step\" }, [\n /*#__PURE__*/_createElementVNode(\"div\", { class: \"text\" }, \" 1. Logged in as \")\n], -1))\nconst _hoisted_6 = { class: \"step\" }\nconst _hoisted_7 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"text\" }, \" 2. Your nostr identities: \", -1))\nconst _hoisted_8 = { class: \"actions\" }\nconst _hoisted_9 = { key: 0 }\nconst _hoisted_10 = { key: 1 }\nconst _hoisted_11 = {\n key: 2,\n class: \"public-keys-wrapper\"\n}\nconst _hoisted_12 = { key: 0 }\nconst _hoisted_13 = {\n key: 1,\n class: \"public-keys\"\n}\nconst _hoisted_14 = [\"onClick\"]\nconst _hoisted_15 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"img\", { src: _imports_0 }, null, -1))\nconst _hoisted_16 = [\n _hoisted_15\n]\nconst _hoisted_17 = { class: \"npub\" }\nconst _hoisted_18 = { class: \"link-npub-form\" }\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_Explanation = _resolveComponent(\"Explanation\")!\n const _component_LogInWithTwitterButton = _resolveComponent(\"LogInWithTwitterButton\")!\n const _component_CurrentUser = _resolveComponent(\"CurrentUser\")!\n const _component_Checkmark = _resolveComponent(\"Checkmark\")!\n const _component_Input = _resolveComponent(\"Input\")!\n const _component_Button = _resolveComponent(\"Button\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n _createVNode(_component_Explanation),\n (!_ctx.loadingUser && !_ctx.user)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_2, [\n _hoisted_3,\n _createVNode(_component_LogInWithTwitterButton)\n ]))\n : _createCommentVNode(\"\", true),\n (!_ctx.loadingUser && _ctx.user)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_4, [\n _hoisted_5,\n _createVNode(_component_CurrentUser, { user: _ctx.user }, null, 8, [\"user\"])\n ]))\n : _createCommentVNode(\"\", true),\n _createElementVNode(\"div\", _hoisted_6, [\n _hoisted_7,\n _createElementVNode(\"ul\", _hoisted_8, [\n (_ctx.publicKeys && _ctx.publicKeys.publicKeys?.length > 0 && !_ctx.editingPublicKeys)\n ? (_openBlock(), _createElementBlock(\"li\", _hoisted_9, [\n _createElementVNode(\"a\", {\n onClick: _cache[0] || (_cache[0] = \n//@ts-ignore\n(...args) => (_ctx.startEditingPublicKeys && _ctx.startEditingPublicKeys(...args)))\n }, \" Edit \")\n ]))\n : _createCommentVNode(\"\", true),\n (_ctx.editingPublicKeys)\n ? (_openBlock(), _createElementBlock(\"li\", _hoisted_10, [\n _createElementVNode(\"a\", {\n onClick: _cache[1] || (_cache[1] = \n//@ts-ignore\n(...args) => (_ctx.endEditingPublicKeys && _ctx.endEditingPublicKeys(...args)))\n }, \" Done \")\n ]))\n : _createCommentVNode(\"\", true)\n ])\n ]),\n (!_ctx.loadingUser && _ctx.user)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_11, [\n (!_ctx.publicKeys)\n ? (_openBlock(), _createElementBlock(\"div\", _hoisted_12, \" Loading public keys... \"))\n : _createCommentVNode(\"\", true),\n (_ctx.publicKeys && _ctx.publicKeys.publicKeys?.length > 0)\n ? (_openBlock(), _createElementBlock(\"ul\", _hoisted_13, [\n (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.publicKeys.publicKeys, (publicKey) => {\n return (_openBlock(), _createElementBlock(\"li\", {\n key: publicKey.npub\n }, [\n (_ctx.editingPublicKeys)\n ? (_openBlock(), _createElementBlock(\"a\", {\n key: 0,\n onClick: ($event: any) => (_ctx.scheduleDelete(publicKey)),\n class: \"delete-public-key-button\"\n }, _hoisted_16, 8, _hoisted_14))\n : _createCommentVNode(\"\", true),\n _createElementVNode(\"div\", _hoisted_17, _toDisplayString(publicKey.npub), 1),\n (!_ctx.editingPublicKeys)\n ? (_openBlock(), _createBlock(_component_Checkmark, { key: 1 }))\n : _createCommentVNode(\"\", true)\n ]))\n }), 128))\n ]))\n : _createCommentVNode(\"\", true)\n ]))\n : _createCommentVNode(\"\", true),\n _createElementVNode(\"div\", _hoisted_18, [\n _createVNode(_component_Input, {\n placeholder: \"Paste your npub address\",\n modelValue: _ctx.npub,\n \"onUpdate:modelValue\": _cache[2] || (_cache[2] = ($event: any) => ((_ctx.npub) = $event)),\n disabled: _ctx.formDisabled\n }, null, 8, [\"modelValue\", \"disabled\"]),\n _createVNode(_component_Button, {\n text: \"Add\",\n onButtonClick: _ctx.addPublicKey,\n disabled: _ctx.formDisabled\n }, null, 8, [\"onButtonClick\", \"disabled\"])\n ])\n ]))\n}","\n\n\n\n\n","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-5ace9f54\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"explanation\" }\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"large\" }, \" Start posting your Nostr content on X \", -1))\nconst _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"small\" }, \" Log in to your X account and add your Nostr identities so that everything you publish on Nostr will be mirrored on X \", -1))\nconst _hoisted_4 = [\n _hoisted_2,\n _hoisted_3\n]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, _hoisted_4))\n}","\n\n\n\n\n","import { render } from \"./Explanation.vue?vue&type=template&id=5ace9f54&scoped=true&ts=true\"\nimport script from \"./Explanation.vue?vue&type=script&lang=ts\"\nexport * from \"./Explanation.vue?vue&type=script&lang=ts\"\n\nimport \"./Explanation.vue?vue&type=style&index=0&id=5ace9f54&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-5ace9f54\"]])\n\nexport default __exports__","import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\nimport _imports_0 from '../assets/login_with_x.svg'\n\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-58fab459\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = {\n href: \"/login\",\n class: \"log-in-with-twitter-button\"\n}\nconst _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"div\", { class: \"img-wrapper\" }, [\n /*#__PURE__*/_createElementVNode(\"img\", { src: _imports_0 })\n], -1))\nconst _hoisted_3 = [\n _hoisted_2\n]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"a\", _hoisted_1, _hoisted_3))\n}","\n\n\n\n\n","import { render } from \"./LogInWithTwitterButton.vue?vue&type=template&id=58fab459&scoped=true&ts=true\"\nimport script from \"./LogInWithTwitterButton.vue?vue&type=script&lang=ts\"\nexport * from \"./LogInWithTwitterButton.vue?vue&type=script&lang=ts\"\n\nimport \"./LogInWithTwitterButton.vue?vue&type=style&index=0&id=58fab459&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-58fab459\"]])\n\nexport default __exports__","import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, resolveComponent as _resolveComponent, createVNode as _createVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\nimport _imports_0 from '../assets/logout_on_dark.svg'\n\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-bf1931c6\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = { class: \"current-user\" }\nconst _hoisted_2 = { class: \"user-info\" }\nconst _hoisted_3 = [\"src\"]\nconst _hoisted_4 = { class: \"name\" }\nconst _hoisted_5 = { class: \"username\" }\nconst _hoisted_6 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode(\"img\", { src: _imports_0 }, null, -1))\nconst _hoisted_7 = [\n _hoisted_6\n]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n const _component_Checkmark = _resolveComponent(\"Checkmark\")!\n\n return (_openBlock(), _createElementBlock(\"div\", _hoisted_1, [\n _createElementVNode(\"div\", _hoisted_2, [\n _createElementVNode(\"img\", {\n class: \"image\",\n src: _ctx.user?.twitterProfileImageURL\n }, null, 8, _hoisted_3),\n _createElementVNode(\"div\", _hoisted_4, _toDisplayString(_ctx.user.twitterName), 1),\n _createElementVNode(\"div\", _hoisted_5, \"@\" + _toDisplayString(_ctx.user.twitterUsername), 1),\n _createElementVNode(\"a\", {\n class: \"logout-button\",\n onClick: _cache[0] || (_cache[0] = \n//@ts-ignore\n(...args) => (_ctx.logout && _ctx.logout(...args)))\n }, _hoisted_7)\n ]),\n _createVNode(_component_Checkmark)\n ]))\n}","\n\n\n\n\n","export class User {\n accountID?: string;\n twitterID?: number;\n twitterName?: string;\n twitterUsername?: string;\n twitterProfileImageURL?: string;\n}","import { openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\nimport _imports_0 from '../assets/checkmark.svg'\n\n\nconst _hoisted_1 = {\n class: \"checkmark\",\n src: _imports_0\n}\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"img\", _hoisted_1))\n}","\n\n\n","import { render } from \"./Checkmark.vue?vue&type=template&id=4ebda3e8&ts=true\"\nimport script from \"./Checkmark.vue?vue&type=script&lang=ts\"\nexport * from \"./Checkmark.vue?vue&type=script&lang=ts\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render]])\n\nexport default __exports__","import { render } from \"./CurrentUser.vue?vue&type=template&id=bf1931c6&scoped=true&ts=true\"\nimport script from \"./CurrentUser.vue?vue&type=script&lang=ts\"\nexport * from \"./CurrentUser.vue?vue&type=script&lang=ts\"\n\nimport \"./CurrentUser.vue?vue&type=style&index=0&id=bf1931c6&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-bf1931c6\"]])\n\nexport default __exports__","export class AddPublicKeyRequest {\n npub: string;\n\n constructor(npub: string) {\n this.npub = npub\n }\n}","import { normalizeClass as _normalizeClass, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from \"vue\"\n\nconst _withScopeId = n => (_pushScopeId(\"data-v-a3a07d36\"),n=n(),_popScopeId(),n)\nconst _hoisted_1 = [\"placeholder\", \"value\", \"disabled\"]\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"input\", {\n type: \"text\",\n placeholder: _ctx.placeholder,\n value: _ctx.modelValue,\n class: _normalizeClass([\"input\", { disabled: _ctx.disabled }]),\n onInput: _cache[0] || (_cache[0] = \n//@ts-ignore\n(...args) => (_ctx.onInput && _ctx.onInput(...args))),\n disabled: _ctx.disabled\n }, null, 42, _hoisted_1))\n}","\n\n\n\n\n","import { render } from \"./Input.vue?vue&type=template&id=a3a07d36&scoped=true&ts=true\"\nimport script from \"./Input.vue?vue&type=script&lang=ts\"\nexport * from \"./Input.vue?vue&type=script&lang=ts\"\n\nimport \"./Input.vue?vue&type=style&index=0&id=a3a07d36&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-a3a07d36\"]])\n\nexport default __exports__","import { toDisplayString as _toDisplayString, normalizeClass as _normalizeClass, openBlock as _openBlock, createElementBlock as _createElementBlock } from \"vue\"\n\nexport function render(_ctx: any,_cache: any,$props: any,$setup: any,$data: any,$options: any) {\n return (_openBlock(), _createElementBlock(\"button\", {\n onClick: _cache[0] || (_cache[0] = \n//@ts-ignore\n(...args) => (_ctx.onClick && _ctx.onClick(...args))),\n class: _normalizeClass({ button: true, disabled: _ctx.disabled })\n }, _toDisplayString(_ctx.text), 3))\n}","\n\n\n\n\n","import { render } from \"./Button.vue?vue&type=template&id=59245c60&scoped=true&ts=true\"\nimport script from \"./Button.vue?vue&type=script&lang=ts\"\nexport * from \"./Button.vue?vue&type=script&lang=ts\"\n\nimport \"./Button.vue?vue&type=style&index=0&id=59245c60&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-59245c60\"]])\n\nexport default __exports__","import { render } from \"./HomeView.vue?vue&type=template&id=28506258&scoped=true&ts=true\"\nimport script from \"./HomeView.vue?vue&type=script&lang=ts\"\nexport * from \"./HomeView.vue?vue&type=script&lang=ts\"\n\nimport \"./HomeView.vue?vue&type=style&index=0&id=28506258&scoped=true&lang=scss\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-28506258\"]])\n\nexport default __exports__","import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'\nimport HomeView from '../views/HomeView.vue'\n\nconst routes: Array = [\n {\n path: '/',\n name: 'home',\n component: HomeView\n },\n]\n\nconst router = createRouter({\n history: createWebHistory(process.env.BASE_URL),\n routes\n})\n\nexport default router\n","import { createApp } from 'vue'\nimport App from './App.vue'\nimport router from './router'\nimport store from './store'\n\ncreateApp(App).use(store).use(router).mount('#app')\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","var deferred = [];\n__webpack_require__.O = function(result, chunkIds, fn, priority) {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar chunkIds = deferred[i][0];\n\t\tvar fn = deferred[i][1];\n\t\tvar priority = deferred[i][2];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every(function(key) { return __webpack_require__.O[key](chunkIds[j]); })) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","__webpack_require__.p = \"/\";","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t143: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = function(chunkId) { return installedChunks[chunkId] === 0; };\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = function(parentChunkLoadingFunction, data) {\n\tvar chunkIds = data[0];\n\tvar moreModules = data[1];\n\tvar runtime = data[2];\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some(function(id) { return installedChunks[id] !== 0; })) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunknos_crossposting_service_frontend\"] = self[\"webpackChunknos_crossposting_service_frontend\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [998], function() { return __webpack_require__(1110); })\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n"],"names":["_hoisted_1","class","_hoisted_2","render","_ctx","_cache","$props","$setup","$data","$options","_component_Header","_resolveComponent","_component_Notifications","_component_router_view","_openBlock","_createElementBlock","_createVNode","_createElementVNode","Mutation","Notification","constructor","style","text","_defineProperty","createStore","state","user","undefined","notifications","getters","mutations","SetUser","PushNotificationError","push","DismissNotification","index","splice","actions","modules","APIService","store","axios","create","currentUser","url","this","get","logout","delete","publicKeys","addPublicKey","req","post","deletePublicKey","publicKey","npub","logoutCurrentUser","Promise","resolve","reject","then","commit","error","refreshCurrentUser","response","data","_withScopeId","n","_pushScopeId","_popScopeId","href","src","_imports_0","_component_LogoutButton","userIsLoggedIn","_createBlock","key","_createCommentVNode","_hoisted_3","onClick","args","LogOutButton","Vue","useStore","apiService","catch","__decorate","Options","__exports__","Header","components","LogoutButton","_Fragment","_renderList","notification","_normalizeClass","_toDisplayString","$event","dismiss","Notifications","App","created","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_component_Explanation","_component_LogInWithTwitterButton","_component_CurrentUser","_component_Checkmark","_component_Input","_component_Button","loadingUser","length","editingPublicKeys","startEditingPublicKeys","endEditingPublicKeys","scheduleDelete","placeholder","modelValue","disabled","formDisabled","onButtonClick","Explanation","LogInWithTwitterButton","twitterProfileImageURL","twitterName","twitterUsername","User","Checkmark","CurrentUser","props","AddPublicKeyRequest","type","value","onInput","Input","event","$emit","target","String","Boolean","emits","button","Button","HomeView","watchUser","newUser","reloadPublicKeys","publicKeysToRemove","indexOf","cancelEditingPublicKeysWithoutReloading","status","Watch","routes","path","name","component","router","createRouter","history","createWebHistory","process","createApp","use","mount","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","exports","module","__webpack_modules__","call","m","deferred","O","result","chunkIds","fn","priority","notFulfilled","Infinity","i","fulfilled","j","Object","keys","every","r","getter","__esModule","d","a","definition","o","defineProperty","enumerable","g","globalThis","Function","e","window","obj","prop","prototype","hasOwnProperty","p","installedChunks","chunkId","webpackJsonpCallback","parentChunkLoadingFunction","moreModules","runtime","some","id","chunkLoadingGlobal","self","forEach","bind","__webpack_exports__"],"sourceRoot":""} \ No newline at end of file diff --git a/service/ports/http/http.go b/service/ports/http/http.go index f425e83..a831526 100644 --- a/service/ports/http/http.go +++ b/service/ports/http/http.go @@ -13,6 +13,7 @@ import ( "github.com/dghubble/gologin/v2/twitter" "github.com/dghubble/oauth1" twitterOAuth1 "github.com/dghubble/oauth1/twitter" + "github.com/gorilla/mux" "github.com/planetary-social/nos-crossposting-service/internal" "github.com/planetary-social/nos-crossposting-service/internal/logging" "github.com/planetary-social/nos-crossposting-service/service/app" @@ -22,7 +23,9 @@ import ( "github.com/planetary-social/nos-crossposting-service/service/ports/http/frontend" ) -const loginCallbackPath = `/login-callback` +const ( + loginCallbackPath = "/login-callback" +) type Server struct { conf config.Config @@ -46,8 +49,6 @@ func NewServer( } func (s *Server) ListenAndServe(ctx context.Context) error { - mux := s.createMux() - var listenConfig net.ListenConfig listener, err := listenConfig.Listen(ctx, "tcp", s.conf.ListenAddress()) if err != nil { @@ -66,10 +67,11 @@ func (s *Server) ListenAndServe(ctx context.Context) error { } }() - return http.Serve(listener, mux) + m := s.createMux() + return http.Serve(listener, m) } -func (s *Server) createMux() *http.ServeMux { +func (s *Server) createMux() *mux.Router { config := &oauth1.Config{ ConsumerKey: s.conf.TwitterKey(), ConsumerSecret: s.conf.TwitterKeySecret(), @@ -77,14 +79,14 @@ func (s *Server) createMux() *http.ServeMux { Endpoint: twitterOAuth1.AuthorizeEndpoint, } - mux := http.NewServeMux() - mux.Handle("/", http.FileServer(s.frontendFileSystem)) - mux.Handle("/login", twitter.LoginHandler(config, nil)) - mux.HandleFunc("/api/current-user", rest.Wrap(s.apiCurrentUser)) - mux.HandleFunc("/api/public-keys", rest.Wrap(s.apiPublicKeys)) - mux.Handle(loginCallbackPath, twitter.CallbackHandler(config, s.issueSession(), nil)) - - return mux + m := mux.NewRouter() + m.Handle("/login", twitter.LoginHandler(config, nil)) + m.HandleFunc("/api/current-user", rest.Wrap(s.apiCurrentUser)) + m.HandleFunc("/api/current-user/public-keys", rest.Wrap(s.apiPublicKeys)) + m.HandleFunc("/api/current-user/public-keys/{npub}", rest.Wrap(s.apiPublicKeysDelete)) + m.Handle(loginCallbackPath, twitter.CallbackHandler(config, s.issueSession(), nil)) + m.NotFoundHandler = http.FileServer(s.frontendFileSystem) + return m } func (s *Server) twitterLoginCallbackURL() string { @@ -275,6 +277,33 @@ func (s *Server) apiPublicKeysAdd(r *http.Request) rest.RestResponse { return rest.NewResponse(nil) } +func (s *Server) apiPublicKeysDelete(r *http.Request) rest.RestResponse { + vars := mux.Vars(r) + + publicKey, err := domain.NewPublicKeyFromNpub(vars["npub"]) + if err != nil { + s.logger.Error().WithError(err).Message("error creating a public key") + return rest.ErrBadRequest + } + + account, err := s.getAccountFromRequest(r) + if err != nil { + s.logger.Error().WithError(err).Message("error getting account from request") + return rest.ErrInternalServerError + } + + if account == nil { + return rest.ErrUnauthorized + } + + if err := s.app.UnlinkPublicKey.Handle(r.Context(), app.NewUnlinkPublicKey(account.AccountID(), publicKey)); err != nil { + s.logger.Error().WithError(err).Message("error deleting a public key") + return rest.ErrInternalServerError + } + + return rest.NewResponse(nil) +} + func (s *Server) getAccountFromRequest(r *http.Request) (*accounts.Account, error) { sessionID, err := GetSessionIDFromCookie(r) if err != nil {