/** * accounts — a framework-agnostic store for the current identity id. * * The identity a session acts as is established when its wallet is imported; the * SDK is told who that is via the current-identity call. This small store just * persists that id (in an injected storage) so it survives reloads and a second * device, re-opening the same wallet, lands on the same identity. It carries no * notion of a login step, a password, or a username — only an opaque identity id. * * Framework-agnostic on purpose: no React, no DOM assumption beyond an optional * storage. A consumer's React `Context`/`Provider` wraps `useState` around * {@link IdentityStore.set}/{@link IdentityStore.clear}. The lib does not force a * React dependency. Removed against real NextGraph, where the wallet session is * the source of the identity id. */ /** localStorage key holding the current identity id. */ export const ACCOUNT_STORAGE_KEY = "ng-eventually.account.id"; /** * Minimal storage contract (a subset of the Web `Storage` interface). The * consumer injects one — `window.localStorage` in a browser, a fake in tests — * so this stays framework/DOM-agnostic. When none is available (SSR, no * `window`), pass `null` and the store degrades to in-memory-null (no persist). */ export interface VirtualUserStorage { getItem(key: string): string | null; setItem(key: string, value: string): void; removeItem(key: string): void; } /** * The persisted current identity id. A tiny store around an injected * {@link VirtualUserStorage}. It holds no framework state; the consumer's Provider * mirrors `get()` into framework state and re-reads after `set`/`clear`. */ export class IdentityStore { private readonly storage: VirtualUserStorage | null; private readonly key: string; constructor(storage: VirtualUserStorage | null, key: string = ACCOUNT_STORAGE_KEY) { this.storage = storage; this.key = key; } /** The current identity id. null = no identity set yet. */ get(): string | null { if (!this.storage) return null; try { return this.storage.getItem(this.key); } catch { return null; } } /** * Persist the (trimmed) identity id. An empty/blank value is ignored and the * previous id is kept (returns the resulting id, or null). No NextGraph call. */ set(id: string): string | null { const clean = id.trim(); if (!clean) return this.get(); if (this.storage) { try { this.storage.setItem(this.key, clean); } catch { /* ignore — staging, no security */ } } return clean; } /** Clear the persisted identity id. No NextGraph call. */ clear(): void { if (this.storage) { try { this.storage.removeItem(this.key); } catch { /* ignore */ } } } } /** * Convenience factory using `globalThis.localStorage` when present, else a * null (non-persisting) store — so the same call is safe in browser and SSR. */ export function browserIdentityStore(key: string = ACCOUNT_STORAGE_KEY): IdentityStore { const ls = typeof globalThis !== "undefined" && (globalThis as { localStorage?: VirtualUserStorage }).localStorage ? (globalThis as { localStorage: VirtualUserStorage }).localStorage : null; return new IdentityStore(ls, key); }