diff --git a/package.json b/package.json index b2ae9edc..6f32adcd 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "@getalby/lightning-tools": "^6.1.0", "@getalby/sdk": "^5.1.2", "@noble/curves": "^1.9.7", - "@pomade/core": "^0.1.1", + "@pomade/core": "^0.2.0", "@poppanator/sveltekit-svg": "^4.2.1", "@sveltejs/adapter-static": "^3.0.10", "@tiptap/core": "^2.27.2", @@ -65,16 +65,16 @@ "@types/throttle-debounce": "^5.0.2", "@vite-pwa/assets-generator": "^0.2.6", "@vite-pwa/sveltekit": "^0.6.8", - "@welshman/app": "^0.8.7", - "@welshman/content": "^0.8.7", - "@welshman/editor": "^0.8.7", - "@welshman/feeds": "^0.8.7", - "@welshman/lib": "^0.8.7", - "@welshman/net": "^0.8.7", - "@welshman/router": "^0.8.7", - "@welshman/signer": "^0.8.7", - "@welshman/store": "^0.8.7", - "@welshman/util": "^0.8.7", + "@welshman/app": "^0.8.8", + "@welshman/content": "^0.8.8", + "@welshman/editor": "^0.8.8", + "@welshman/feeds": "^0.8.8", + "@welshman/lib": "^0.8.8", + "@welshman/net": "^0.8.8", + "@welshman/router": "^0.8.8", + "@welshman/signer": "^0.8.8", + "@welshman/store": "^0.8.8", + "@welshman/util": "^0.8.8", "compressorjs-next": "^1.1.2", "daisyui": "^4.12.24", "date-picker-svelte": "^2.17.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d447fc03..98946c21 100644 Binary files a/pnpm-lock.yaml and b/pnpm-lock.yaml differ diff --git a/src/app/components/LogIn.svelte b/src/app/components/LogIn.svelte index 3b3768cf..ca4b5a9a 100644 --- a/src/app/components/LogIn.svelte +++ b/src/app/components/LogIn.svelte @@ -34,7 +34,6 @@ const onSuccess = async (session: Session) => { addSession(session) - pushToast({message: "Successfully logged in!"}) setChecked("*") clearModals() } diff --git a/src/app/components/LogInEmail.svelte b/src/app/components/LogInEmail.svelte index d63f9566..133b2778 100644 --- a/src/app/components/LogInEmail.svelte +++ b/src/app/components/LogInEmail.svelte @@ -20,6 +20,7 @@ import {pushModal, clearModals} from "@app/util/modal" import {setChecked} from "@app/util/notifications" import {pushToast} from "@app/util/toast" + import {deleteOldPomadeSessions} from "@app/core/commands" interface Props { email?: string @@ -51,7 +52,7 @@ if (res.ok && clientOptions) { loginWithPomade(clientOptions.group.group_pk.slice(2), email, clientOptions) - pushToast({message: "Successfully logged in!"}) + deleteOldPomadeSessions() setChecked("*") clearModals() } else { diff --git a/src/app/components/LogInKey.svelte b/src/app/components/LogInKey.svelte index 38a6e507..3a31e58d 100644 --- a/src/app/components/LogInKey.svelte +++ b/src/app/components/LogInKey.svelte @@ -57,7 +57,6 @@ } loginWithNip01(secret) - pushToast({message: "Successfully logged in!"}) setChecked("*") clearModals() } catch (e) { diff --git a/src/app/components/LogInOTPConfirm.svelte b/src/app/components/LogInOTPConfirm.svelte index 532d70ae..b6cf823c 100644 --- a/src/app/components/LogInOTPConfirm.svelte +++ b/src/app/components/LogInOTPConfirm.svelte @@ -17,6 +17,7 @@ import {setChecked} from "@app/util/notifications" import {pushToast} from "@app/util/toast" import {POMADE_SIGNERS} from "@app/core/state" + import {deleteOldPomadeSessions} from "@app/core/commands" type Props = { email: string @@ -63,7 +64,7 @@ if (res.ok && clientOptions) { loginWithPomade(clientOptions.group.group_pk.slice(2), email, clientOptions) - pushToast({message: "Successfully logged in!"}) + deleteOldPomadeSessions() setChecked("*") clearModals() } else { diff --git a/src/app/components/LogOut.svelte b/src/app/components/LogOut.svelte index 39981013..762f9107 100644 --- a/src/app/components/LogOut.svelte +++ b/src/app/components/LogOut.svelte @@ -9,8 +9,7 @@ import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalTitle from "@lib/components/ModalTitle.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" - import {Push} from "@app/util/notifications" - import {kv, db} from "@app/core/storage" + import {logout} from "@app/util/logout" const back = () => history.back() @@ -18,13 +17,7 @@ loading = true try { - await Push.disable() - await kv.clear() - await db.clear() - - localStorage.clear() - - window.location.href = "/" + await logout() } catch (e) { console.error(e) loading = false diff --git a/src/app/components/PomadeSessions.svelte b/src/app/components/PomadeSessions.svelte index 6567b462..e710c2a2 100644 --- a/src/app/components/PomadeSessions.svelte +++ b/src/app/components/PomadeSessions.svelte @@ -1,51 +1,30 @@ @@ -93,28 +72,46 @@
Other Sessions {#each sessions as sessionItem (sessionItem.client)} -
-
- {sessionItem.client.slice(0, 8)} -
-
- Created {formatDate(sessionItem.created_at)} -
-
- Last active: {formatDate(sessionItem.last_activity)} -
+
+
+
+ Session {sessionItem.client.slice(0, 8)} + + {#if sessionItem.deactivated_at} + Deactivated + {/if} + +
+
+ + {#if menuClient === sessionItem.client} + + + + {/if} +
+
+
+
+ Created {formatDate(sessionItem.created_at)} +
+
+ Active {formatDate(sessionItem.last_activity)}
-
{/each}
diff --git a/src/app/components/ProfileDelete.svelte b/src/app/components/ProfileDelete.svelte index 870bef08..282fb0d5 100644 --- a/src/app/components/ProfileDelete.svelte +++ b/src/app/components/ProfileDelete.svelte @@ -23,9 +23,8 @@ import Modal from "@lib/components/Modal.svelte" import ModalBody from "@lib/components/ModalBody.svelte" import {INDEXER_RELAYS, PLATFORM_NAME, userSpaceUrls} from "@app/core/state" - import {kv, db} from "@app/core/storage" import {pushToast} from "@app/util/toast" - import {Push} from "@app/util/notifications" + import {logout} from "@app/util/logout" let progress: number | undefined = $state(undefined) let confirmText = $state("") @@ -88,13 +87,7 @@ await sleep(2000) // Goodbye forever! - await Push.disable() - await kv.clear() - await db.clear() - - localStorage.clear() - - window.location.href = "/" + await logout() } const confirm = async () => { diff --git a/src/app/components/SignUpEmail.svelte b/src/app/components/SignUpEmail.svelte index 7f53072c..8fd919f9 100644 --- a/src/app/components/SignUpEmail.svelte +++ b/src/app/components/SignUpEmail.svelte @@ -18,7 +18,7 @@ import ModalSubtitle from "@lib/components/ModalSubtitle.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" import SignUpEmailConfirm from "@app/components/SignUpEmailConfirm.svelte" - import {pushToast} from "@app/util/toast" + import {pushToast, popToast} from "@app/util/toast" import {pushModal} from "@app/util/modal" type Props = { @@ -40,6 +40,11 @@ loading = true try { + const toastId = pushToast({ + timeout: 60_000, + message: "Creating your account, please wait...", + }) + const secret = getKey("signup.secret")! const {clientOptions, ...registerRes} = await Client.register(2, 3, secret) @@ -74,6 +79,7 @@ setKey("signup.email", email) setKey("signup.clientOptions", clientOptions) + popToast(toastId) pushModal(SignUpEmailConfirm, {next}) } catch (e) { console.error(e) diff --git a/src/app/core/commands.ts b/src/app/core/commands.ts index 2ea604a8..5e749d9b 100644 --- a/src/app/core/commands.ts +++ b/src/app/core/commands.ts @@ -1,6 +1,8 @@ import {nwc} from "@getalby/sdk" import * as nip19 from "nostr-tools/nip19" import {get, derived} from "svelte/store" +import {Client} from "@pomade/core" +import type {SessionItem} from "@pomade/core" import { first, sha256, @@ -71,6 +73,7 @@ import { waitForThunkError, getPubkeyRelays, userBlossomServerList, + isPomadeSession, getThunkError, } from "@welshman/app" import {compressFile} from "@lib/html" @@ -699,3 +702,58 @@ export const updateProfile = async ({ await publishThunk({event, relays}).complete } + +// Pomade + +export type PomadeSessionWithPeers = SessionItem & {peers: string[]} + +export const loadOtherPomadeSessions = async () => { + const $session = get(session) + + if (isPomadeSession($session)) { + const client = new Client($session.clientOptions) + const result = await client.listSessions() + const pubkey = await client.getPubkey() + + if (result.ok) { + // Group sessions by client pubkey and collect peers + const sessionMap = new Map() + + for (const message of result.messages) { + if (!message.res?.items) continue + + for (const item of message.res.items) { + if (item.client === pubkey) { + continue + } + + const existing = sessionMap.get(item.client) + + if (existing) { + existing.peers.push(message.url) + } else { + sessionMap.set(item.client, {...item, peers: [message.url]}) + } + } + } + + return Array.from(sessionMap.values()) + } + } + + return [] +} + +export const deleteOldPomadeSessions = async () => { + const $session = get(session) + + if (isPomadeSession($session)) { + const client = new Client($session.clientOptions) + + for (const item of await loadOtherPomadeSessions()) { + if (item.deactivated_at) { + await client.deleteSession(item.client, item.peers) + } + } + } +} diff --git a/src/app/util/logout.ts b/src/app/util/logout.ts new file mode 100644 index 00000000..b3b25fe6 --- /dev/null +++ b/src/app/util/logout.ts @@ -0,0 +1,25 @@ +import {get} from "svelte/store" +import {Client} from "@pomade/core" +import {getPubkey} from "@welshman/util" +import {session, isPomadeSession} from "@welshman/app" +import {kv, db} from "@app/core/storage" +import {Push} from "@app/util/notifications" + +export const logout = async () => { + const $session = get(session) + + if ($session && isPomadeSession($session)) { + await new Client($session.clientOptions).deactivateSession( + getPubkey($session.clientOptions.secret), + $session.clientOptions.peers, + ) + } + + await Push.disable() + await kv.clear() + await db.clear() + + localStorage.clear() + + window.location.href = "/" +}