flotilla/src/app/session.ts

99 lines
3 KiB
TypeScript
Raw Normal View History

2026-07-28 16:16:26 +00:00
import type {ClientOptions} from "@pomade/core"
import type {Wallet} from "@welshman/util"
import {nip01, nip07, nip46, nip55, pomade, toSession} from "@welshman/app"
import type {Session} from "@welshman/app"
2026-08-06 15:43:57 +00:00
import {getTestEvents, maybeGetTestSession} from "@lib/test/session"
2026-07-28 16:16:26 +00:00
import {app, login, session} from "@app/core"
import {wallet} from "@app/lightning"
import {kv, ss, storage} from "@app/storage"
2026-06-08 21:14:40 +00:00
import {deactivateCurrentPomadeSession} from "@app/pomade"
import {Push} from "@app/push"
2026-03-05 22:20:20 +00:00
// Sessions were a Record keyed by an active pubkey, so convert one rather than logging people out.
2026-07-28 16:16:26 +00:00
type LegacySession = {
method: string
pubkey: string
secret?: string
signer?: string
email?: string
clientOptions?: ClientOptions
handler?: {pubkey: string; relays: string[]}
wallet?: Wallet
}
const toCurrentSession = (legacy: LegacySession): Session | undefined => {
switch (legacy.method) {
case "nip01":
return legacy.secret ? toSession(nip01, {secret: legacy.secret}) : undefined
case "nip07":
return toSession(nip07, {})
case "nip46":
return legacy.secret && legacy.handler
? toSession(nip46, {
clientSecret: legacy.secret,
signerPubkey: legacy.handler.pubkey,
relays: legacy.handler.relays,
})
: undefined
case "nip55":
return legacy.signer
? toSession(nip55, {pubkey: legacy.pubkey, signer: legacy.signer})
: undefined
case "pomade":
return legacy.clientOptions && legacy.email
? toSession(pomade, {clientOptions: legacy.clientOptions, email: legacy.email})
: undefined
}
}
const readLegacySession = async () => {
const pubkey = await kv.get<string>("pubkey")
const sessions = await ss.get<Record<string, LegacySession>>("sessions")
const legacy = pubkey ? sessions?.[pubkey] : undefined
if (legacy?.wallet) {
wallet.set(legacy.wallet)
}
return legacy ? toCurrentSession(legacy) : undefined
}
// The session derives from the app's user, so read it back at startup and persist it on a change.
2026-07-28 16:16:26 +00:00
export const restoreSession = async () => {
// Test-only: an injected window.__TEST_SESSION__ wins over storage and is stripped from production.
2026-08-06 15:43:57 +00:00
const testSession = import.meta.env.DEV ? maybeGetTestSession() : undefined
const $session = testSession ?? (await ss.get<Session>("session")) ?? (await readLegacySession())
2026-07-28 16:16:26 +00:00
if ($session) {
await login($session)
}
// Storage loads with Repository.load, which clears the repository, so these wait for it.
2026-08-06 15:43:57 +00:00
if (testSession) {
await storage.get()?.ready
for (const event of getTestEvents()) {
app.get().repository.publish(event)
}
}
2026-07-28 16:16:26 +00:00
return session.subscribe($session => {
if ($session) {
ss.set("session", $session)
}
})
}
2026-03-05 22:20:20 +00:00
export const logout = async () => {
await deactivateCurrentPomadeSession()
2026-03-05 22:20:20 +00:00
await Push.disable()
await kv.clear()
2026-03-24 00:51:51 +00:00
await ss.clear()
2026-07-28 16:16:26 +00:00
await storage.get()?.clear()
2026-03-05 22:20:20 +00:00
2026-07-28 16:16:26 +00:00
app.get().cleanup()
2026-03-05 22:20:20 +00:00
localStorage.clear()
window.location.href = "/"
}