← Public packages
@kentcdodds/audible
Personal Audible library app — browser re-auth, library, wishlist, NAS archive stub.
src/auth-session.ts
87 lines · 2.1 KB · TypeScript/**
* In-flight OpenID+PKCE session state in packageStorage (verifier + locale + serial).
*/
import { packageStorage } from 'kody:runtime'
export type AuthSession = {
authSessionId: string
codeVerifier: string
locale: string
serial: string
withUsername: boolean
createdAt: string
}
const PREFIX = 'auth-session:'
const MAX_AGE_MS = 30 * 60 * 1000
function keyFor(id: string) {
return `${PREFIX}${id}`
}
export async function saveAuthSession(session: AuthSession): Promise<void> {
await packageStorage().set(keyFor(session.authSessionId), session)
}
export async function loadAuthSession(
authSessionId: string,
): Promise<AuthSession | null> {
const id = authSessionId?.trim()
if (!id) return null
try {
const raw = await packageStorage().get(keyFor(id))
if (raw == null) return null
const session =
typeof raw === 'string'
? (JSON.parse(raw) as AuthSession)
: (raw as AuthSession)
if (!session?.codeVerifier || !session?.serial) return null
const created = Date.parse(session.createdAt || '')
if (created && Date.now() - created > MAX_AGE_MS) {
await deleteAuthSession(id)
return null
}
return session
} catch {
return null
}
}
export async function deleteAuthSession(authSessionId: string): Promise<void> {
try {
const storage = packageStorage() as {
delete?: (key: string) => Promise<unknown>
set: (key: string, value: unknown) => Promise<unknown>
}
if (typeof storage.delete === 'function') {
await storage.delete(keyFor(authSessionId))
} else {
await storage.set(keyFor(authSessionId), null)
}
} catch {
// best-effort cleanup
}
}
const SCOPE_KEY = 'audibleAuthSecretScope'
export async function rememberAuthSecretScope(
scope: 'package' | 'user',
): Promise<void> {
await packageStorage().set(SCOPE_KEY, scope)
}
export async function loadAuthSecretScope(): Promise<'package' | 'user' | null> {
try {
const raw = await packageStorage().get(SCOPE_KEY)
if (raw === 'package' || raw === 'user') return raw
if (typeof raw === 'string') {
const parsed = JSON.parse(raw)
if (parsed === 'package' || parsed === 'user') return parsed
}
} catch {
// ignore
}
return null
}