@ai-matrx/summon 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -1
- package/dist/index.cjs +11 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/dist/persistence.cjs +1 -1
- package/dist/persistence.cjs.map +1 -1
- package/dist/persistence.js +2 -2
- package/dist/persistence.js.map +1 -1
- package/dist/react.cjs +2 -2
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +2 -2
- package/dist/react.js.map +1 -1
- package/dist/window.cjs +25 -49
- package/dist/window.cjs.map +1 -1
- package/dist/window.js +15 -39
- package/dist/window.js.map +1 -1
- package/package.json +4 -4
package/dist/persistence.cjs
CHANGED
|
@@ -678,7 +678,7 @@ function hydrateWindowWorkspace(raw, viewport, expectedWorkspaceId) {
|
|
|
678
678
|
const sessions = ordered.map((session, index) => {
|
|
679
679
|
const restoreDefaults = (0, import_summon.getOverlayMeta)(session.overlayId)?.window?.restoreDefaults;
|
|
680
680
|
const slot = slotOf.get(session.sessionKey) ?? null;
|
|
681
|
-
const renderRect = session.state === "minimized" && slot !== null ? (0, import_summon.traySlotRect)(slot, viewport.width, viewport.height, minimized.length) : session.state === "windowed" || session.state === "maximized" ? (0, import_summon.
|
|
681
|
+
const renderRect = session.state === "minimized" && slot !== null ? (0, import_summon.traySlotRect)(slot, viewport.width, viewport.height, minimized.length) : session.state === "windowed" || session.state === "maximized" ? (0, import_summon.clampStoredRectToViewport)(session.windowedRect, viewport) : fallbackRect(viewport);
|
|
682
682
|
return {
|
|
683
683
|
...session,
|
|
684
684
|
traySlot: slot,
|
package/dist/persistence.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/persistence.ts","../src/persistence/backend.ts","../src/persistence/errors.ts","../src/persistence/keys.ts","../src/persistence/localStore.ts","../src/persistence/workspace.ts","../src/persistence/controller.ts","../src/persistence/OverlayPersistence.tsx"],"sourcesContent":["// @ai-matrx/summon/persistence — overlay persistence (R4, R6): the browser-local store\n// (localStorage mirror + IndexedDB; workspaces, leases, caps, identity isolation) and the restore\n// orchestration with the link-vs-restore race made deterministic.\nexport {\n createLocalPersistence,\n isLocalPersistence,\n DEFAULT_IDB_READ_BUDGET_MS,\n WORKSPACE_LEASE_MS,\n MAX_WORKSPACES_PER_IDENTITY,\n type LocalPersistenceOptions,\n type LocalOverlayPersistence,\n type LocalWorkspaces,\n type StorageLike,\n type LocksLike,\n} from \"./persistence/localStore\";\nexport { createIndexedDbBackend, createMemoryBackend, type KeyValueBackend } from \"./persistence/backend\";\nexport {\n PersistenceVersionConflictError,\n PersistenceLoadTimeoutError,\n isVersionConflict,\n isLoadTimeout,\n VERSION_CONFLICT_ERROR,\n LOAD_TIMEOUT_ERROR,\n} from \"./persistence/errors\";\nexport { PERSON_WORKSPACE_KEY, STATE_KEY_PREFIX, tabWorkspaceKey, stateKey, identityScopedKey } from \"./persistence/keys\";\nexport {\n serializeWindowWorkspace,\n hydrateWindowWorkspace,\n readSession,\n sanitizeJsonRecord,\n preservationFor,\n WINDOW_WORKSPACE_SCHEMA_VERSION,\n DEFAULT_WINDOW_DATA_BYTES,\n MAX_WINDOW_WORKSPACE_BYTES,\n MAX_PERSISTED_WINDOW_SESSIONS,\n type PersistedWindowWorkspace,\n type WindowPersistenceDiagnostic,\n type WindowPersistenceDiagnosticCode,\n} from \"./persistence/workspace\";\nexport {\n createOverlayPersistenceController,\n persistsComponentState,\n DEFAULT_SAVE_DEBOUNCE_MS,\n type OverlayPersistenceController,\n type OverlayPersistenceOptions,\n type PersistenceScope,\n type PersistenceStore,\n} from \"./persistence/controller\";\nexport { OverlayPersistence, useOverlayPersistence, type OverlayPersistenceProps } from \"./persistence/OverlayPersistence\";\n","/**\n * The warm tier behind the local store: a tiny async key/value interface, implemented over raw\n * IndexedDB (no Dexie) and in memory (tests, SSR, browsers without IndexedDB).\n */\n\nexport interface KeyValueBackend {\n get(key: string): Promise<unknown>;\n set(key: string, value: unknown): Promise<void>;\n delete(key: string): Promise<void>;\n /** Every key starting with `prefix`. */\n keys(prefix: string): Promise<string[]>;\n}\n\nexport function createMemoryBackend(): KeyValueBackend & { readonly data: Map<string, unknown> } {\n const data = new Map<string, unknown>();\n return {\n data,\n get: async (key) => (data.has(key) ? structuredClone(data.get(key)) : undefined),\n set: async (key, value) => {\n data.set(key, structuredClone(value));\n },\n delete: async (key) => {\n data.delete(key);\n },\n keys: async (prefix) => [...data.keys()].filter((key) => key.startsWith(prefix)),\n };\n}\n\nfunction request<T>(req: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error ?? new Error(\"IndexedDB request failed\"));\n });\n}\n\n/**\n * One object store in one database. The connection opens lazily on first use and is reused; a\n * blocked/failed open rejects every call (the local store then lives on its synchronous mirror).\n */\nexport function createIndexedDbBackend(dbName = \"ai-matrx-overlays\", storeName = \"kv\"): KeyValueBackend {\n let opening: Promise<IDBDatabase> | null = null;\n const db = (): Promise<IDBDatabase> => {\n if (opening) return opening;\n opening = new Promise<IDBDatabase>((resolve, reject) => {\n if (typeof indexedDB === \"undefined\") {\n reject(new Error(\"IndexedDB is unavailable\"));\n return;\n }\n const req = indexedDB.open(dbName, 1);\n req.onupgradeneeded = () => {\n if (!req.result.objectStoreNames.contains(storeName)) req.result.createObjectStore(storeName);\n };\n req.onsuccess = () => {\n const conn = req.result;\n // Another tab upgrading must not wedge on us; reopen lazily next time.\n conn.onversionchange = () => {\n conn.close();\n opening = null;\n };\n resolve(conn);\n };\n req.onerror = () => reject(req.error ?? new Error(\"IndexedDB open failed\"));\n req.onblocked = () => reject(new Error(\"IndexedDB open blocked\"));\n }).catch((error: unknown) => {\n opening = null;\n throw error;\n });\n return opening;\n };\n const run = async <T>(mode: IDBTransactionMode, body: (store: IDBObjectStore) => IDBRequest<T>): Promise<T> => {\n const conn = await db();\n const tx = conn.transaction(storeName, mode);\n const done =\n mode === \"readwrite\"\n ? new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error ?? new Error(\"IndexedDB transaction failed\"));\n tx.onabort = () => reject(tx.error ?? new Error(\"IndexedDB transaction aborted\"));\n })\n : Promise.resolve();\n const result = await request(body(tx.objectStore(storeName)));\n await done;\n return result;\n };\n return {\n get: (key) => run(\"readonly\", (store) => store.get(key)),\n set: async (key, value) => {\n await run(\"readwrite\", (store) => store.put(value, key));\n },\n delete: async (key) => {\n await run(\"readwrite\", (store) => store.delete(key));\n },\n keys: async (prefix) => {\n const range = IDBKeyRange.bound(prefix, `${prefix}`);\n const keys = await run(\"readonly\", (store) => store.getAllKeys(range));\n return keys.filter((key): key is string => typeof key === \"string\");\n },\n };\n}\n","/**\n * Errors every persistence store throws in the same shape. Matched by `name`, never `instanceof`:\n * each section entry may carry its own copy of this module in a built consumer.\n */\nimport type { StoredValue } from \"@ai-matrx/summon\";\n\nexport const VERSION_CONFLICT_ERROR = \"OverlayPersistenceVersionConflict\";\nexport const LOAD_TIMEOUT_ERROR = \"OverlayPersistenceLoadTimeout\";\n\n/** A save whose `expectedVersion` no longer matches the stored version. */\nexport class PersistenceVersionConflictError extends Error {\n readonly key: string;\n readonly expectedVersion: number;\n readonly currentVersion: number;\n constructor(key: string, expectedVersion: number, currentVersion: number) {\n super(`[overlays/persistence] \"${key}\" is at version ${currentVersion}, not the expected ${expectedVersion}`);\n this.name = VERSION_CONFLICT_ERROR;\n this.key = key;\n this.expectedVersion = expectedVersion;\n this.currentVersion = currentVersion;\n }\n}\n\nexport function isVersionConflict(error: unknown): error is PersistenceVersionConflictError {\n return error instanceof Error && error.name === VERSION_CONFLICT_ERROR;\n}\n\n/**\n * The fast tier missed and the slow tier did not answer within the read budget. `pending` still\n * resolves the authoritative answer: a caller keeps every automatic writer gated until it does,\n * so an unknown stored value is never overwritten.\n */\nexport class PersistenceLoadTimeoutError extends Error {\n readonly key: string;\n readonly pending: Promise<StoredValue | null>;\n constructor(key: string, budgetMs: number, pending: Promise<StoredValue | null>) {\n super(`[overlays/persistence] \"${key}\" did not load within ${budgetMs}ms`);\n this.name = LOAD_TIMEOUT_ERROR;\n this.key = key;\n this.pending = pending;\n }\n}\n\nexport function isLoadTimeout(error: unknown): error is PersistenceLoadTimeoutError {\n return error instanceof Error && error.name === LOAD_TIMEOUT_ERROR;\n}\n","/** Storage keys the orchestration writes (before identity scoping). */\nexport const PERSON_WORKSPACE_KEY = \"workspace\";\nexport const tabWorkspaceKey = (workspaceId: string): string => `workspace:${workspaceId}`;\nexport const STATE_KEY_PREFIX = \"state:\";\nexport const stateKey = (instanceKey: string): string => `${STATE_KEY_PREFIX}${instanceKey}`;\n/** `<identityKey>/<key>` for stores that are not per-person themselves. */\nexport const identityScopedKey = (identityKey: string, key: string): string => `${identityKey}/${key}`;\n","/**\n * createLocalPersistence — an OverlayPersistencePort over the browser: a synchronous localStorage\n * mirror (the fast, pagehide-safe tier) plus IndexedDB (the warm tier). Ported from matrx-frontend\n * `localWindowSessionStore.ts` + `lib/sync/persistence/*` with the same safety:\n *\n * - write ordering: the mirror is written synchronously first; IndexedDB follows in a per-key\n * queue under `navigator.locks` (cross-tab) when available. A mirror write that fails removes\n * the old mirror, so a stale value never looks authoritative.\n * - reads: a valid mirror answers at once; otherwise IndexedDB gets a 750 ms budget, after which\n * load rejects with a PersistenceLoadTimeoutError carrying the still-pending answer.\n * - per-tab workspaces (`workspaces`): sessionStorage id + 24 h lease; a duplicated tab (same\n * sessionStorage, another live document holds the lease, not a reload) gets a fresh id; an\n * index per identity caps workspaces at 5 and GC skips any workspace with a live lease.\n * - identity isolation: keys arrive scoped (`<identityKey>/<key>`); `purgeIdentity` removes\n * everything one identity stored, both tiers (the old store missed the mirror keys).\n *\n * All state lives in the store instance (no module state). Create ONE per app.\n */\nimport type { OverlayPersistencePort, StoredValue } from \"@ai-matrx/summon\";\nimport { createIndexedDbBackend, createMemoryBackend, type KeyValueBackend } from \"./backend\";\nimport { PersistenceLoadTimeoutError, PersistenceVersionConflictError } from \"./errors\";\nimport { identityScopedKey, tabWorkspaceKey } from \"./keys\";\n\nexport const DEFAULT_IDB_READ_BUDGET_MS = 750;\nexport const WORKSPACE_LEASE_MS = 24 * 60 * 60 * 1000;\nexport const MAX_WORKSPACES_PER_IDENTITY = 5;\nconst INDEX_REFRESH_MS = 60 * 1000;\nconst RECORD_VERSION = 1;\n\n/** The slice of the Web Storage API the store uses. */\nexport interface StorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n key(index: number): string | null;\n readonly length: number;\n}\n\n/** The slice of `navigator.locks` the store uses. */\nexport interface LocksLike {\n request<T>(name: string, callback: () => Promise<T>): Promise<T>;\n}\n\nexport interface LocalPersistenceOptions {\n /** Prefix of every localStorage key and the IndexedDB database name. Default \"ai-matrx.overlays\". */\n readonly namespace?: string;\n /** Warm tier. Default: IndexedDB when present, else in-memory. */\n readonly backend?: KeyValueBackend;\n /** Default: window.localStorage (absent → memory-only mirror is skipped). */\n readonly storage?: StorageLike | null;\n /** Default: window.sessionStorage. */\n readonly session?: StorageLike | null;\n /** Default: navigator.locks. */\n readonly locks?: LocksLike | null;\n readonly idbReadBudgetMs?: number;\n /** Is this document a reload? Default: the Navigation Timing entry. */\n readonly isReload?: () => boolean;\n readonly now?: () => number;\n}\n\nexport interface LocalWorkspaces {\n /** This tab's workspace id (stable across reloads, fresh for a duplicated tab). Claims its lease. */\n currentId(): string;\n /** Event-driven lease heartbeat (focus, pageshow, visible). */\n renew(workspaceId: string): void;\n /** Release the lease this document holds (pagehide). */\n release(workspaceId: string): void;\n /** Record use of a workspace for an identity; evicts the oldest beyond the cap (live leases spared). */\n index(identityKey: string, workspaceId: string): void;\n}\n\nexport interface LocalOverlayPersistence extends OverlayPersistencePort {\n readonly perPerson: false;\n readonly workspaces: LocalWorkspaces;\n list(prefix: string): Promise<readonly string[]>;\n /** Remove everything stored under one identity (both tiers). */\n purgeIdentity(identityKey: string): Promise<void>;\n /** Resolves once every queued IndexedDB write has finished (tests, shutdown). */\n idle(): Promise<void>;\n}\n\ninterface StoredRecord {\n readonly v: typeof RECORD_VERSION;\n readonly version: number;\n readonly value: unknown;\n}\n\nfunction isStoredRecord(value: unknown): value is StoredRecord {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { v?: unknown }).v === RECORD_VERSION &&\n typeof (value as { version?: unknown }).version === \"number\" &&\n \"value\" in value\n );\n}\n\nfunction randomId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") return crypto.randomUUID();\n return `tab-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;\n}\n\nconst browserStorage = (pick: \"localStorage\" | \"sessionStorage\"): StorageLike | null => {\n try {\n return typeof window === \"undefined\" ? null : window[pick];\n } catch {\n return null;\n }\n};\n\nconst defaultIsReload = (): boolean => {\n try {\n const entry = performance.getEntriesByType(\"navigation\")[0] as PerformanceNavigationTiming | undefined;\n return entry?.type === \"reload\";\n } catch {\n return false;\n }\n};\n\nexport function isLocalPersistence(port: OverlayPersistencePort | null | undefined): port is LocalOverlayPersistence {\n return Boolean(port && \"workspaces\" in port && typeof (port as { workspaces?: unknown }).workspaces === \"object\");\n}\n\nexport function createLocalPersistence(options: LocalPersistenceOptions = {}): LocalOverlayPersistence {\n const ns = options.namespace ?? \"ai-matrx.overlays\";\n const storage = options.storage === undefined ? browserStorage(\"localStorage\") : options.storage;\n const session = options.session === undefined ? browserStorage(\"sessionStorage\") : options.session;\n const locks =\n options.locks === undefined ? (typeof navigator !== \"undefined\" && navigator.locks ? (navigator.locks as unknown as LocksLike) : null) : options.locks;\n const backend = options.backend ?? (typeof indexedDB !== \"undefined\" ? createIndexedDbBackend(ns) : createMemoryBackend());\n const budgetMs = options.idbReadBudgetMs ?? DEFAULT_IDB_READ_BUDGET_MS;\n const now = options.now ?? Date.now;\n const isReload = options.isReload ?? defaultIsReload;\n const runtimeId = randomId();\n const fallbackWorkspaceId = `fallback-${runtimeId}`;\n const queues = new Map<string, Promise<void>>();\n let leased: string | null = null;\n\n const mirrorKey = (key: string) => `${ns}:${key}`;\n const leaseKey = (workspaceId: string) => `${ns}:lease:${workspaceId}`;\n const indexPrefix = (identityKey: string) => `${ns}:index:${identityKey}:`;\n\n // ── sync mirror helpers ──\n const readJson = (key: string): unknown => {\n if (!storage) return null;\n try {\n const raw = storage.getItem(key);\n return raw === null ? null : (JSON.parse(raw) as unknown);\n } catch {\n return null;\n }\n };\n const writeJson = (key: string, value: unknown): boolean => {\n if (!storage) return false;\n try {\n storage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n };\n const removeKey = (key: string): void => {\n try {\n storage?.removeItem(key);\n } catch {\n /* storage disabled: nothing to remove */\n }\n };\n const storageKeys = (prefix: string): string[] => {\n if (!storage) return [];\n const out: string[] = [];\n try {\n for (let i = 0; i < storage.length; i += 1) {\n const key = storage.key(i);\n if (key?.startsWith(prefix)) out.push(key);\n }\n } catch {\n /* enumeration failed; cleanup retries on a later save */\n }\n return out;\n };\n const readMirror = (key: string): StoredRecord | null => {\n const raw = readJson(mirrorKey(key));\n return isStoredRecord(raw) ? raw : null;\n };\n\n // ── ordered warm-tier writes ──\n const enqueue = (key: string, operation: () => Promise<void>): Promise<void> => {\n const previous = queues.get(key) ?? Promise.resolve();\n const next = previous\n .catch(() => undefined)\n .then(() => (locks ? locks.request(`${ns}:${key}`, operation) : operation()));\n queues.set(key, next);\n void next.then(\n () => {\n if (queues.get(key) === next) queues.delete(key);\n },\n () => {\n if (queues.get(key) === next) queues.delete(key);\n },\n );\n return next;\n };\n\n const readWarm = async (key: string): Promise<StoredValue | null> => {\n const raw = await backend.get(key);\n return isStoredRecord(raw) ? { value: raw.value, version: raw.version } : null;\n };\n\n // ── leases ──\n const leaseBody = (workspaceId: string): { runtimeId?: unknown; expiresAt?: unknown } | null => {\n const raw = readJson(leaseKey(workspaceId));\n return typeof raw === \"object\" && raw !== null ? (raw as { runtimeId?: unknown; expiresAt?: unknown }) : null;\n };\n const hasLiveLease = (workspaceId: string, at: number): boolean => {\n const body = leaseBody(workspaceId);\n return typeof body?.expiresAt === \"number\" && body.expiresAt > at;\n };\n const claimLease = (workspaceId: string): void => {\n if (leased && leased !== workspaceId && leaseBody(leased)?.runtimeId === runtimeId) removeKey(leaseKey(leased));\n leased = workspaceId;\n writeJson(leaseKey(workspaceId), { runtimeId, expiresAt: now() + WORKSPACE_LEASE_MS });\n };\n\n const workspaces: LocalWorkspaces = {\n currentId() {\n if (!session) {\n claimLease(fallbackWorkspaceId);\n return fallbackWorkspaceId;\n }\n try {\n const sessionKey = `${ns}:workspace-id`;\n const existing = session.getItem(sessionKey);\n const body = existing ? leaseBody(existing) : null;\n const claimedElsewhere = Boolean(\n existing &&\n !isReload() &&\n body?.runtimeId !== runtimeId &&\n typeof body?.expiresAt === \"number\" &&\n body.expiresAt > now(),\n );\n const workspaceId = existing && !claimedElsewhere ? existing : randomId();\n session.setItem(sessionKey, workspaceId);\n claimLease(workspaceId);\n return workspaceId;\n } catch {\n claimLease(fallbackWorkspaceId);\n return fallbackWorkspaceId;\n }\n },\n renew(workspaceId) {\n claimLease(workspaceId);\n },\n release(workspaceId) {\n if (leaseBody(workspaceId)?.runtimeId === runtimeId) removeKey(leaseKey(workspaceId));\n if (leased === workspaceId) leased = null;\n },\n index(identityKey, workspaceId) {\n const at = now();\n const prefix = indexPrefix(identityKey);\n const rows = storageKeys(prefix)\n .map((key) => readJson(key))\n .filter(\n (row): row is { workspaceId: string; lastUsedAt: number } =>\n typeof row === \"object\" &&\n row !== null &&\n typeof (row as { workspaceId?: unknown }).workspaceId === \"string\" &&\n typeof (row as { lastUsedAt?: unknown }).lastUsedAt === \"number\",\n );\n const current = rows.find((row) => row.workspaceId === workspaceId);\n if (current && rows.length <= MAX_WORKSPACES_PER_IDENTITY && at - current.lastUsedAt < INDEX_REFRESH_MS) return;\n const entry = { workspaceId, lastUsedAt: current && at - current.lastUsedAt < INDEX_REFRESH_MS ? current.lastUsedAt : at };\n writeJson(`${prefix}${workspaceId}`, entry);\n const ordered = [...rows.filter((row) => row.workspaceId !== workspaceId), entry].sort((a, b) => b.lastUsedAt - a.lastUsedAt);\n for (const stale of ordered.slice(MAX_WORKSPACES_PER_IDENTITY)) {\n if (hasLiveLease(stale.workspaceId, at)) continue;\n const key = identityScopedKey(identityKey, tabWorkspaceKey(stale.workspaceId));\n void enqueue(key, async () => {\n // Recheck inside the cross-tab lock: that tab may have woken since the scan.\n if (hasLiveLease(stale.workspaceId, now())) return;\n removeKey(mirrorKey(key));\n removeKey(leaseKey(stale.workspaceId));\n removeKey(`${prefix}${stale.workspaceId}`);\n await backend.delete(key);\n }).catch(() => undefined);\n }\n },\n };\n\n return {\n perPerson: false,\n workspaces,\n\n async load<T = unknown>(key: string): Promise<StoredValue<T> | null> {\n const mirror = readMirror(key);\n // The synchronous mirror is written before IndexedDB on every save: when it is valid,\n // waiting on IndexedDB adds latency without adding freshness.\n if (mirror) return { value: mirror.value as T, version: mirror.version };\n const warm = readWarm(key).catch(() => null);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<\"timeout\">((resolve) => {\n timer = setTimeout(() => resolve(\"timeout\"), budgetMs);\n });\n const first = await Promise.race([warm, timeout]);\n if (timer !== undefined) clearTimeout(timer);\n if (first === \"timeout\") throw new PersistenceLoadTimeoutError(key, budgetMs, warm);\n return first as StoredValue<T> | null;\n },\n\n async save<T = unknown>(key: string, value: T, saveOptions?: { readonly expectedVersion?: number }) {\n const current = readMirror(key)?.version ?? 0;\n const expected = saveOptions?.expectedVersion;\n if (expected !== undefined && expected !== current) throw new PersistenceVersionConflictError(key, expected, current);\n const record: StoredRecord = { v: RECORD_VERSION, version: current + 1, value };\n // Never leave a previously valid mirror looking authoritative when this newer write only\n // reaches IndexedDB (quota / disabled storage).\n if (!writeJson(mirrorKey(key), record)) removeKey(mirrorKey(key));\n await enqueue(key, () => backend.set(key, record));\n return { version: record.version };\n },\n\n async remove(key: string) {\n removeKey(mirrorKey(key));\n await enqueue(key, () => backend.delete(key));\n },\n\n async list(prefix: string) {\n const fromMirror = storageKeys(mirrorKey(prefix)).map((key) => key.slice(ns.length + 1));\n let fromWarm: string[] = [];\n try {\n fromWarm = await backend.keys(prefix);\n } catch {\n /* warm tier unavailable: the mirror is the answer */\n }\n return [...new Set([...fromMirror, ...fromWarm])].sort();\n },\n\n async purgeIdentity(identityKey: string) {\n const prefix = identityScopedKey(identityKey, \"\");\n for (const key of storageKeys(mirrorKey(prefix))) removeKey(key);\n for (const key of storageKeys(indexPrefix(identityKey))) removeKey(key);\n let warmKeys: string[] = [];\n try {\n warmKeys = await backend.keys(prefix);\n } catch {\n return;\n }\n await Promise.all(warmKeys.map((key) => enqueue(key, () => backend.delete(key))));\n },\n\n async idle() {\n await Promise.all([...queues.values()].map((q) => q.catch(() => undefined)));\n },\n };\n}\n","/**\n * The window workspace record: serialize the window manager into a compact JSON record and\n * validate a stored one back into staged sessions. Ported from matrx-frontend\n * `windowSessionSerialization.ts`; the old metadata table is now each definition's `window`\n * options in the registry.\n *\n * DEFAULT DENY: a window is saved and restored only when its definition has `window.preservation`\n * and is not `ephemeral`; only `preservation.dataKeys` of its data are kept; unknown overlay ids\n * are rejected with a diagnostic. `window.restoreDefaults` is merged UNDER saved data on restore.\n */\nimport {\n WINDOW_SESSION_SCHEMA_VERSION,\n centerRectInViewport,\n clampRectToViewport,\n defaultWindowIdFor,\n getOverlayMeta,\n traySlotRect,\n windowSessionKey,\n type AnyOverlayMeta,\n type HydratedWindowSession,\n type PersistedWindowSession,\n type WindowManagerState,\n type WindowPreservation,\n type WindowRect,\n type WindowState,\n} from \"@ai-matrx/summon\";\n\nexport const WINDOW_WORKSPACE_SCHEMA_VERSION = 1 as const;\nexport const DEFAULT_WINDOW_DATA_BYTES = 32 * 1024;\nexport const MAX_WINDOW_WORKSPACE_BYTES = 256 * 1024;\nexport const MAX_PERSISTED_WINDOW_SESSIONS = 64;\nconst MAX_ID_LENGTH = 160;\nconst MAX_LABEL_LENGTH = 512;\n\nexport interface PersistedWindowWorkspace {\n schemaVersion: typeof WINDOW_WORKSPACE_SCHEMA_VERSION;\n workspaceId: string;\n savedAt: number;\n sessions: PersistedWindowSession[];\n}\n\nexport type WindowPersistenceDiagnosticCode =\n | \"unsupported-data\"\n | \"window-data-too-large\"\n | \"workspace-too-large\"\n | \"invalid-workspace\"\n | \"invalid-session\"\n | \"unknown-overlay\"\n | \"preservation-disabled\"\n | \"state-too-large\";\n\nexport interface WindowPersistenceDiagnostic {\n level: \"warning\" | \"error\";\n code: WindowPersistenceDiagnosticCode;\n sessionKey?: string;\n message: string;\n}\n\ninterface Preserved {\n readonly meta: AnyOverlayMeta;\n readonly preservation: WindowPreservation;\n}\n\n/** The definition's preservation, or null when the window is not preserved (default deny). */\nexport function preservationFor(overlayId: string): Preserved | null {\n const meta = getOverlayMeta(overlayId);\n const preservation = meta?.window?.preservation;\n if (!meta || !preservation || meta.window?.ephemeral) return null;\n return { meta, preservation };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nconst isFiniteNumber = (value: unknown): value is number => typeof value === \"number\" && Number.isFinite(value);\n\n/** UTF-8 byte count without TextEncoder. */\nexport function utf8Bytes(value: string): number {\n let bytes = 0;\n for (const ch of value) {\n const cp = ch.codePointAt(0) ?? 0;\n bytes += cp <= 0x7f ? 1 : cp <= 0x7ff ? 2 : cp <= 0xffff ? 3 : 4;\n }\n return bytes;\n}\n\nconst isWindowState = (value: unknown): value is WindowState => value === \"windowed\" || value === \"maximized\" || value === \"minimized\";\n\nfunction readRect(value: unknown): WindowRect | null {\n if (!isRecord(value)) return null;\n const { x, y, width, height } = value;\n if (!isFiniteNumber(x) || !isFiniteNumber(y) || !isFiniteNumber(width) || !isFiniteNumber(height) || width <= 0 || height <= 0) return null;\n return { x, y, width, height };\n}\n\nexport interface JsonSanitizeResult {\n data: Record<string, unknown>;\n droppedUnsupported: boolean;\n bytes: number;\n}\n\n/**\n * Copy `allowedKeys` (all keys when `null`) into plain JSON. Functions, symbols, undefined and\n * circular references are dropped; BigInt becomes text; class instances are dropped.\n */\nexport function sanitizeJsonRecord(value: unknown, allowedKeys: readonly string[] | null): JsonSanitizeResult {\n if (!isRecord(value) || (allowedKeys && allowedKeys.length === 0)) return { data: {}, droppedUnsupported: false, bytes: 2 };\n const ancestors = new WeakSet<object>();\n let droppedUnsupported = false;\n const DROPPED = Symbol(\"dropped\");\n const copy = (item: unknown): unknown => {\n if (item === undefined || typeof item === \"function\" || typeof item === \"symbol\") {\n droppedUnsupported = true;\n return DROPPED;\n }\n if (typeof item === \"bigint\") {\n droppedUnsupported = true;\n return item.toString();\n }\n if (typeof item === \"number\" && !Number.isFinite(item)) {\n droppedUnsupported = true;\n return null;\n }\n if (item === null || typeof item !== \"object\") return item;\n if (item instanceof Date) return item.toJSON();\n if (ancestors.has(item)) {\n droppedUnsupported = true;\n return DROPPED;\n }\n ancestors.add(item);\n let result: unknown;\n if (Array.isArray(item)) {\n result = item.map((child) => {\n const copied = copy(child);\n return copied === DROPPED ? null : copied;\n });\n } else if (Object.getPrototypeOf(item) === Object.prototype || Object.getPrototypeOf(item) === null) {\n result = Object.fromEntries(\n Object.entries(item).flatMap(([key, child]) => {\n const copied = copy(child);\n return copied === DROPPED ? [] : [[key, copied]];\n }),\n );\n } else {\n droppedUnsupported = true;\n result = DROPPED;\n }\n ancestors.delete(item);\n return result;\n };\n try {\n const allowed = allowedKeys ? new Set(allowedKeys) : null;\n const selected = Object.fromEntries(Object.entries(value).filter(([key]) => !allowed || allowed.has(key)));\n ancestors.add(value);\n const copied = copy(selected);\n ancestors.delete(value);\n const json = JSON.stringify(copied === DROPPED ? {} : copied) || \"{}\";\n const parsed: unknown = JSON.parse(json);\n return { data: isRecord(parsed) ? parsed : {}, droppedUnsupported, bytes: utf8Bytes(json) };\n } catch {\n return { data: {}, droppedUnsupported: true, bytes: 2 };\n }\n}\n\nfunction invalidAllowedDataKey(data: Record<string, unknown>, preservation: WindowPreservation): string | null {\n const domains = preservation.allowedDataValues;\n if (!domains) return null;\n return Object.entries(domains).find(([key, allowed]) => !allowed.includes(data[key] as string | number | boolean | null))?.[0] ?? null;\n}\n\nfunction sessionFromWindow(\n entry: WindowManagerState[\"windows\"][string],\n savedAt: number,\n diagnostics: WindowPersistenceDiagnostic[],\n): PersistedWindowSession | null {\n const persistence = entry.persistence;\n if (!persistence || persistence.closing) return null;\n const preserved = preservationFor(persistence.overlayId);\n if (!preserved) return null;\n const sessionKey = windowSessionKey(persistence.overlayId, persistence.instanceId);\n if (persistence.instanceId.length > MAX_ID_LENGTH || entry.id.length > MAX_ID_LENGTH || entry.title.length > MAX_LABEL_LENGTH) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", sessionKey, message: `Skipped ${sessionKey}: identity or label metadata is oversized.` });\n return null;\n }\n const sanitized = sanitizeJsonRecord(persistence.data, preserved.preservation.dataKeys);\n if (sanitized.droppedUnsupported) {\n diagnostics.push({ level: \"warning\", code: \"unsupported-data\", sessionKey, message: `Dropped non-JSON window data for ${sessionKey}.` });\n }\n const maxBytes = preserved.preservation.maxDataBytes ?? DEFAULT_WINDOW_DATA_BYTES;\n const data = sanitized.bytes <= maxBytes ? sanitized.data : {};\n if (sanitized.bytes > maxBytes) {\n diagnostics.push({\n level: \"error\",\n code: \"window-data-too-large\",\n sessionKey,\n message: `Discarded ${sanitized.bytes} bytes of window data for ${sessionKey}; limit is ${maxBytes}.`,\n });\n }\n const invalidKey = invalidAllowedDataKey(sanitized.data, preserved.preservation);\n if (invalidKey) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", sessionKey, message: `Skipped ${sessionKey}: ${invalidKey} is outside its allowed domain.` });\n return null;\n }\n return {\n schemaVersion: WINDOW_SESSION_SCHEMA_VERSION,\n sessionKey,\n overlayId: persistence.overlayId,\n instanceId: persistence.instanceId,\n windowId: entry.id,\n title: entry.title,\n state: entry.state,\n windowedRect: entry.state === \"minimized\" ? (entry.preMinimizedRect ?? entry.windowed) : entry.windowed,\n traySlot: entry.state === \"minimized\" ? entry.traySlot : null,\n zIndex: entry.zIndex,\n sidebarOpen: persistence.sidebarOpen,\n sidebarSize: persistence.sidebarSize,\n data,\n savedAt,\n };\n}\n\n/** Validate one stored session against the registry (default deny). */\nexport function readSession(value: unknown, diagnostics: WindowPersistenceDiagnostic[]): PersistedWindowSession | null {\n if (!isRecord(value)) return null;\n const { overlayId, instanceId } = value;\n const rect = readRect(value.windowedRect);\n if (\n value.schemaVersion !== WINDOW_SESSION_SCHEMA_VERSION ||\n typeof overlayId !== \"string\" ||\n typeof instanceId !== \"string\" ||\n instanceId.length === 0 ||\n !rect ||\n !isWindowState(value.state)\n ) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", message: \"Ignored an invalid window preservation record.\" });\n return null;\n }\n const sessionKey = windowSessionKey(overlayId, instanceId);\n const meta = getOverlayMeta(overlayId);\n if (!meta) {\n diagnostics.push({ level: \"error\", code: \"unknown-overlay\", sessionKey, message: `Ignored unknown overlay ${overlayId}.` });\n return null;\n }\n const preserved = preservationFor(overlayId);\n if (!preserved) {\n diagnostics.push({ level: \"warning\", code: \"preservation-disabled\", sessionKey, message: `Ignored ${overlayId}: its definition does not preserve windows.` });\n return null;\n }\n if (\n (meta.instance !== \"multi\" && instanceId !== \"default\") ||\n instanceId.length > MAX_ID_LENGTH ||\n (typeof value.windowId === \"string\" && value.windowId.length > MAX_ID_LENGTH) ||\n (typeof value.title === \"string\" && value.title.length > MAX_LABEL_LENGTH)\n ) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", sessionKey, message: `Ignored invalid instance or oversized metadata for ${overlayId}.` });\n return null;\n }\n const sanitized = sanitizeJsonRecord(value.data, preserved.preservation.dataKeys);\n const missing = preserved.preservation.requiredDataKeys?.find((key) => {\n const v = sanitized.data[key];\n return v === undefined || v === null || v === \"\";\n });\n if (missing) {\n diagnostics.push({ level: \"warning\", code: \"invalid-session\", sessionKey, message: `Ignored ${overlayId}: required key ${missing} was empty.` });\n return null;\n }\n const invalidKey = invalidAllowedDataKey(sanitized.data, preserved.preservation);\n if (invalidKey) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", sessionKey, message: `Ignored ${overlayId}: ${invalidKey} is outside its allowed domain.` });\n return null;\n }\n const maxBytes = preserved.preservation.maxDataBytes ?? DEFAULT_WINDOW_DATA_BYTES;\n if (sanitized.bytes > maxBytes) {\n diagnostics.push({\n level: \"error\",\n code: \"window-data-too-large\",\n sessionKey,\n message: `Discarded ${sanitized.bytes} bytes of restored window data for ${overlayId}; limit is ${maxBytes}.`,\n });\n }\n return {\n schemaVersion: WINDOW_SESSION_SCHEMA_VERSION,\n sessionKey,\n overlayId,\n instanceId,\n windowId: typeof value.windowId === \"string\" ? value.windowId : defaultWindowIdFor(meta),\n title: typeof value.title === \"string\" ? value.title : meta.label,\n state: value.state,\n windowedRect: rect,\n traySlot: Number.isInteger(value.traySlot) && Number(value.traySlot) >= 0 ? Number(value.traySlot) : null,\n zIndex: isFiniteNumber(value.zIndex) ? value.zIndex : 1000,\n sidebarOpen: value.sidebarOpen !== false,\n sidebarSize: isFiniteNumber(value.sidebarSize) && value.sidebarSize > 0 ? value.sidebarSize : null,\n data: sanitized.bytes <= maxBytes ? sanitized.data : {},\n savedAt: isFiniteNumber(value.savedAt) ? value.savedAt : 0,\n };\n}\n\nexport function serializeWindowWorkspace(\n state: WindowManagerState,\n workspaceId: string,\n savedAt = Date.now(),\n): { workspace: PersistedWindowWorkspace; diagnostics: WindowPersistenceDiagnostic[] } {\n const diagnostics: WindowPersistenceDiagnostic[] = [];\n const live = Object.values(state.windows)\n .map((entry) => sessionFromWindow(entry, savedAt, diagnostics))\n .filter((s): s is PersistedWindowSession => s !== null);\n const liveKeys = new Set(live.map((s) => s.sessionKey));\n // Pending restores stay in the workspace until their window registers, so an early save can\n // never erase a session whose lazy chunk has not arrived.\n const pending = Object.values(state.pendingRestores)\n .filter((s) => !liveKeys.has(s.sessionKey))\n .map((s) => readSession({ ...s, savedAt }, diagnostics))\n .filter((s): s is PersistedWindowSession => s !== null);\n const all = [...live, ...pending].sort((a, b) => b.zIndex - a.zIndex || a.sessionKey.localeCompare(b.sessionKey));\n const sessions = all.slice(0, MAX_PERSISTED_WINDOW_SESSIONS).sort((a, b) => a.zIndex - b.zIndex || a.sessionKey.localeCompare(b.sessionKey));\n if (all.length > sessions.length) {\n diagnostics.push({\n level: \"error\",\n code: \"workspace-too-large\",\n message: `Window workspace exceeded ${MAX_PERSISTED_WINDOW_SESSIONS} sessions; later z-order entries were not saved.`,\n });\n }\n const workspace: PersistedWindowWorkspace = { schemaVersion: WINDOW_WORKSPACE_SCHEMA_VERSION, workspaceId, savedAt, sessions };\n const bytes = utf8Bytes(JSON.stringify(workspace));\n if (bytes > MAX_WINDOW_WORKSPACE_BYTES) {\n for (const s of sessions) s.data = {};\n diagnostics.push({\n level: \"error\",\n code: \"workspace-too-large\",\n message: `Window workspace reached ${bytes} bytes; window data was discarded while geometry was kept.`,\n });\n while (sessions.length > 0 && utf8Bytes(JSON.stringify(workspace)) > MAX_WINDOW_WORKSPACE_BYTES) sessions.pop();\n }\n return { workspace, diagnostics };\n}\n\nfunction fallbackRect(viewport: { width: number; height: number }): WindowRect {\n return centerRectInViewport({ x: 0, y: 0, width: Math.min(720, viewport.width), height: Math.min(480, viewport.height) }, viewport);\n}\n\n/**\n * Validate a stored workspace into staged sessions: rects clamped to the viewport, tray slots\n * renumbered, `restoreDefaults` merged under the saved data. `expectedWorkspaceId` (tab scope)\n * rejects a record written by another workspace.\n */\nexport function hydrateWindowWorkspace(\n raw: unknown,\n viewport: { width: number; height: number },\n expectedWorkspaceId?: string,\n): { sessions: HydratedWindowSession[]; diagnostics: WindowPersistenceDiagnostic[] } {\n const diagnostics: WindowPersistenceDiagnostic[] = [];\n if (\n !isRecord(raw) ||\n raw.schemaVersion !== WINDOW_WORKSPACE_SCHEMA_VERSION ||\n !Array.isArray(raw.sessions) ||\n typeof raw.workspaceId !== \"string\" ||\n (expectedWorkspaceId !== undefined && raw.workspaceId !== expectedWorkspaceId)\n ) {\n if (raw != null) diagnostics.push({ level: \"error\", code: \"invalid-workspace\", message: \"Ignored an invalid or unsupported window workspace.\" });\n return { sessions: [], diagnostics };\n }\n let workspaceBytes: number;\n try {\n workspaceBytes = utf8Bytes(JSON.stringify(raw));\n } catch {\n diagnostics.push({ level: \"error\", code: \"invalid-workspace\", message: \"Ignored a window workspace that could not be serialized.\" });\n return { sessions: [], diagnostics };\n }\n if (workspaceBytes > MAX_WINDOW_WORKSPACE_BYTES) {\n diagnostics.push({\n level: \"error\",\n code: \"workspace-too-large\",\n message: `Ignored a ${workspaceBytes}-byte window workspace above the ${MAX_WINDOW_WORKSPACE_BYTES}-byte limit.`,\n });\n return { sessions: [], diagnostics };\n }\n if (raw.sessions.length > MAX_PERSISTED_WINDOW_SESSIONS) {\n diagnostics.push({\n level: \"error\",\n code: \"invalid-workspace\",\n message: `Window workspace exceeded ${MAX_PERSISTED_WINDOW_SESSIONS} sessions; extras were ignored.`,\n });\n }\n const byKey = new Map<string, PersistedWindowSession>();\n for (const candidate of raw.sessions.slice(0, MAX_PERSISTED_WINDOW_SESSIONS)) {\n const session = readSession(candidate, diagnostics);\n if (!session) continue;\n const existing = byKey.get(session.sessionKey);\n if (!existing || existing.savedAt < session.savedAt || (existing.savedAt === session.savedAt && JSON.stringify(existing) < JSON.stringify(session))) {\n byKey.set(session.sessionKey, session);\n }\n }\n const ordered = [...byKey.values()].sort((a, b) => a.zIndex - b.zIndex || a.sessionKey.localeCompare(b.sessionKey));\n const minimized = ordered\n .filter((s) => s.state === \"minimized\")\n .sort((a, b) => (a.traySlot ?? Number.MAX_SAFE_INTEGER) - (b.traySlot ?? Number.MAX_SAFE_INTEGER) || a.sessionKey.localeCompare(b.sessionKey));\n const slotOf = new Map(minimized.map((s, i) => [s.sessionKey, i] as const));\n const sessions = ordered.map((session, index): HydratedWindowSession => {\n const restoreDefaults = getOverlayMeta(session.overlayId)?.window?.restoreDefaults;\n const slot = slotOf.get(session.sessionKey) ?? null;\n const renderRect =\n session.state === \"minimized\" && slot !== null\n ? traySlotRect(slot, viewport.width, viewport.height, minimized.length)\n : session.state === \"windowed\" || session.state === \"maximized\"\n ? clampRectToViewport(session.windowedRect, viewport)\n : fallbackRect(viewport);\n return {\n ...session,\n traySlot: slot,\n zIndex: 1000 + index,\n data: restoreDefaults ? { ...restoreDefaults, ...session.data } : session.data,\n renderRect,\n };\n });\n return { sessions, diagnostics };\n}\n","/**\n * The persistence orchestration, framework-free: one controller per overlays store. The React\n * component (`OverlayPersistence`) only starts and stops it.\n *\n * - identity ready → load the workspace (tab or person scope) and saved component state →\n * validate (default deny, see workspace.ts) → stage/apply → open what is not open yet.\n * - window manager / overlayState change → save debounced 250 ms; flush on pagehide, hidden\n * visibility and every close (close-lifecycle flusher). Writes stay gated until the load for\n * the CURRENT identity has applied, so an unknown stored value is never overwritten.\n * - identity change → close everything, clear staged persistence and component state, load the\n * new identity. Nothing of one identity is ever written under another.\n *\n * LINK vs RESTORE (deterministic in both orders, for the same instance):\n * the link's DATA wins, the restored GEOMETRY wins.\n * - restore after link: an instance already open keeps its data (no re-open); its saved\n * geometry is staged (window not registered yet → `registerWindow` takes the staged rect and\n * merges staged data UNDER the live data) or applied to the live window directly.\n * - link after restore: the link's open replaces the overlay's data; the staged/applied\n * geometry is untouched by an open.\n */\nimport {\n closeAllOverlays,\n clearOverlayState,\n clearWindowPersistenceState,\n hydrateOverlayState,\n hydrateWindowSessions,\n markWindowClosing,\n maximizeWindow,\n minimizeWindow,\n parseInstanceKey,\n overlaysRawActions,\n pruneStaleInstances,\n registerCloseFlusher,\n restoreWindow,\n safeViewportDims,\n getOverlayMeta,\n updateWindowRect,\n windowSessionKey,\n type HydratedWindowSession,\n type InstanceKey,\n type OverlayPersistencePort,\n type SummonPorts,\n type SummonRootState,\n type StoredValue,\n type WindowEntry,\n} from \"@ai-matrx/summon\";\nimport type { Dispatch, UnknownAction } from \"@reduxjs/toolkit\";\nimport { isLoadTimeout, isVersionConflict } from \"./errors\";\nimport { PERSON_WORKSPACE_KEY, STATE_KEY_PREFIX, identityScopedKey, stateKey, tabWorkspaceKey } from \"./keys\";\nimport { isLocalPersistence } from \"./localStore\";\nimport {\n DEFAULT_WINDOW_DATA_BYTES,\n hydrateWindowWorkspace,\n preservationFor,\n sanitizeJsonRecord,\n serializeWindowWorkspace,\n type WindowPersistenceDiagnostic,\n} from \"./workspace\";\n\nexport type PersistenceScope = \"tab\" | \"person\";\n\nexport interface OverlayPersistenceOptions {\n /**\n * `tab`: one workspace per browser tab (the local store's default). `person`: one workspace per\n * person (`workspace`) — windows follow the person across devices (the data adapter's default).\n */\n readonly scope?: PersistenceScope;\n /** Tab scope: a tab with no workspace of its own starts from the person's last one. Default true. */\n readonly seedFromPerson?: boolean;\n readonly saveDebounceMs?: number;\n /** Viewport used to clamp restored rects. Default: the sanitized window size. */\n readonly viewport?: () => { width: number; height: number };\n /** Called whenever `hydrated` flips. */\n readonly onHydratedChange?: (hydrated: boolean) => void;\n}\n\nexport interface PersistenceStore {\n getState(): SummonRootState;\n dispatch: Dispatch<UnknownAction>;\n subscribe(listener: () => void): () => void;\n}\n\nexport interface OverlayPersistenceController {\n start(): void;\n stop(): void;\n /** Save now (skips unchanged records). */\n flush(): void;\n readonly hydrated: boolean;\n}\n\nexport const DEFAULT_SAVE_DEBOUNCE_MS = 250;\nconst STALE_SWEEP_MS = 30 * 60 * 1000;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Open by registry id with plain strings (raw action; definition defaults merged underneath). */\nfunction openRegisteredOverlay(dispatch: Dispatch<UnknownAction>, overlayId: string, instanceId: string, data: unknown): void {\n const defaults = getOverlayMeta(overlayId)?.defaults;\n dispatch(overlaysRawActions.openOverlay({ overlayId, instanceId, data, ...(isRecord(defaults) ? { defaults } : {}) }));\n}\n\n/** Component state is saved for definitions with keepAlive \"restore\" or a preserved window. */\nexport function persistsComponentState(overlayId: string): boolean {\n const meta = getOverlayMeta(overlayId);\n return Boolean(meta && (meta.keepAlive === \"restore\" || preservationFor(overlayId)));\n}\n\nexport function createOverlayPersistenceController(\n store: PersistenceStore,\n ports: SummonPorts,\n options: OverlayPersistenceOptions = {},\n): OverlayPersistenceController {\n const port: OverlayPersistencePort | null = ports.persistence;\n const debounceMs = options.saveDebounceMs ?? DEFAULT_SAVE_DEBOUNCE_MS;\n const seedFromPerson = options.seedFromPerson ?? true;\n const local = isLocalPersistence(port) ? port : null;\n const scope: PersistenceScope = options.scope ?? (port?.perPerson ? \"person\" : local ? \"tab\" : \"person\");\n\n let identityKey: string | null = null;\n let generation = 0;\n let writeSafe = false;\n let hydrated = false;\n let workspaceId: string | null = null;\n let saveTimer: ReturnType<typeof setTimeout> | null = null;\n let lastWorkspaceFp: string | null = null;\n let lastSavedAt = 0;\n const versions = new Map<string, number>();\n const stateFps = new Map<string, string>();\n const chains = new Map<string, Promise<void>>();\n const closedExact = new Set<string>();\n const closedOverlay = new Set<string>();\n let closedAll = false;\n const cleanups: (() => void)[] = [];\n\n const setHydrated = (next: boolean) => {\n if (hydrated === next) return;\n hydrated = next;\n options.onHydratedChange?.(next);\n };\n\n const report = (diagnostics: readonly WindowPersistenceDiagnostic[]) => {\n for (const d of diagnostics) {\n ports.errors.capture(new Error(`[overlays/persistence:${d.code}] ${d.message}`), {\n source: \"overlay-persistence\",\n level: d.level,\n code: d.code,\n ...(d.sessionKey ? { sessionKey: d.sessionKey } : {}),\n });\n }\n };\n const fail = (where: string) => (error: unknown) => ports.errors.capture(error, { source: \"overlay-persistence\", where });\n\n const scoped = (key: string): string => (port?.perPerson || identityKey === null ? key : identityScopedKey(identityKey, key));\n const workspaceKey = (): string => (scope === \"tab\" && workspaceId ? tabWorkspaceKey(workspaceId) : PERSON_WORKSPACE_KEY);\n\n /** Serialized per key; a version conflict re-reads the version and writes once more (latest intent wins). */\n const put = (key: string, value: unknown): void => {\n if (!port) return;\n const gen = generation;\n const run = async () => {\n if (gen !== generation) return;\n const expected = versions.get(key);\n try {\n const saved = await port.save(key, value, expected === undefined ? undefined : { expectedVersion: expected });\n versions.set(key, saved.version);\n } catch (error) {\n if (!isVersionConflict(error) || gen !== generation) throw error;\n const current = await port.load(key).catch(() => null);\n const saved = await port.save(key, value, { expectedVersion: current?.version ?? 0 });\n versions.set(key, saved.version);\n }\n };\n const next = (chains.get(key) ?? Promise.resolve()).then(run).catch(fail(`save ${key}`));\n chains.set(key, next);\n };\n const drop = (key: string): void => {\n if (!port) return;\n const next = (chains.get(key) ?? Promise.resolve())\n .then(() => port.remove(key))\n .then(() => void versions.delete(key))\n .catch(fail(`remove ${key}`));\n chains.set(key, next);\n };\n\n const saveStates = (state: SummonRootState): void => {\n const present = new Set<string>();\n for (const [key, entry] of Object.entries(state.overlayState.entries)) {\n const parsed = parseInstanceKey(key);\n if (!parsed || !persistsComponentState(parsed.overlayId)) continue;\n const sanitized = sanitizeJsonRecord(entry.values, null);\n if (sanitized.bytes > DEFAULT_WINDOW_DATA_BYTES) {\n report([\n {\n level: \"error\",\n code: \"state-too-large\",\n sessionKey: key,\n message: `Saved component state of ${key} is ${sanitized.bytes} bytes; limit is ${DEFAULT_WINDOW_DATA_BYTES}. Not saved.`,\n },\n ]);\n continue;\n }\n const storageKey = scoped(stateKey(key));\n present.add(storageKey);\n const fp = JSON.stringify(sanitized.data);\n if (stateFps.get(storageKey) === fp) continue;\n stateFps.set(storageKey, fp);\n put(storageKey, sanitized.data);\n }\n for (const storageKey of [...stateFps.keys()]) {\n if (present.has(storageKey)) continue;\n stateFps.delete(storageKey);\n drop(storageKey);\n }\n };\n\n const saveNow = (): void => {\n if (saveTimer) {\n clearTimeout(saveTimer);\n saveTimer = null;\n }\n if (!port || !writeSafe || identityKey === null) return;\n const state = store.getState();\n const savedAt = Math.max(Date.now(), lastSavedAt + 1);\n const { workspace, diagnostics } = serializeWindowWorkspace(state.windowManager, workspaceId ?? PERSON_WORKSPACE_KEY, savedAt);\n report(diagnostics);\n const fp = JSON.stringify(workspace.sessions.map((s) => ({ ...s, savedAt: 0 })));\n if (fp !== lastWorkspaceFp) {\n lastWorkspaceFp = fp;\n lastSavedAt = savedAt;\n put(scoped(workspaceKey()), workspace);\n if (scope === \"tab\" && workspaceId) {\n if (seedFromPerson) put(scoped(PERSON_WORKSPACE_KEY), workspace);\n local?.workspaces.index(identityKey, workspaceId);\n }\n }\n saveStates(state);\n };\n\n const scheduleSave = () => {\n if (saveTimer) clearTimeout(saveTimer);\n saveTimer = setTimeout(() => {\n saveTimer = null;\n saveNow();\n }, debounceMs);\n };\n\n const loadValue = async (key: string): Promise<StoredValue | null> => {\n if (!port) return null;\n try {\n return await port.load(key);\n } catch (error) {\n // The fast tier missed and the warm tier is slow: wait for the real answer. Writes are\n // gated until it arrives, so nothing unknown is overwritten.\n if (isLoadTimeout(error)) return error.pending;\n throw error;\n }\n };\n\n const teardown = (): void => {\n generation += 1;\n writeSafe = false;\n setHydrated(false);\n if (saveTimer) {\n clearTimeout(saveTimer);\n saveTimer = null;\n }\n const state = store.getState();\n const identities = new Map<string, { overlayId: string; instanceId: string }>();\n for (const entry of Object.values(state.windowManager.windows)) {\n if (entry.persistence) {\n const { overlayId, instanceId } = entry.persistence;\n identities.set(windowSessionKey(overlayId, instanceId), { overlayId, instanceId });\n }\n }\n for (const session of Object.values(state.windowManager.pendingRestores)) {\n identities.set(session.sessionKey, { overlayId: session.overlayId, instanceId: session.instanceId });\n }\n for (const identity of identities.values()) store.dispatch(markWindowClosing(identity));\n store.dispatch(closeAllOverlays());\n store.dispatch(clearWindowPersistenceState());\n // keepAlive \"restore\" values survive a close by design — never into another identity.\n for (const key of Object.keys(store.getState().overlayState.entries)) store.dispatch(clearOverlayState({ key: key as InstanceKey }));\n // Account teardown closes are not the next identity's intent.\n closedExact.clear();\n closedOverlay.clear();\n closedAll = false;\n versions.clear();\n stateFps.clear();\n lastWorkspaceFp = null;\n };\n\n const liveWindowFor = (windows: Record<string, WindowEntry>, overlayId: string, instanceId: string): WindowEntry | undefined =>\n Object.values(windows).find(\n (entry) => entry.persistence?.overlayId === overlayId && entry.persistence.instanceId === instanceId && !entry.persistence.closing,\n );\n\n /** Restored geometry for a window that is already registered (the link opened it first). */\n const applyGeometry = (entry: WindowEntry, session: HydratedWindowSession, viewport: { width: number; height: number }) => {\n if (entry.state !== \"windowed\") store.dispatch(restoreWindow(entry.id));\n store.dispatch(updateWindowRect({ id: entry.id, rect: session.state === \"minimized\" ? session.windowedRect : session.renderRect }));\n if (session.state === \"maximized\") store.dispatch(maximizeWindow(entry.id));\n else if (session.state === \"minimized\") {\n store.dispatch(minimizeWindow({ id: entry.id, viewportWidth: viewport.width, viewportHeight: viewport.height }));\n }\n };\n\n const loadIdentity = async (key: string): Promise<void> => {\n if (!port) return;\n const gen = generation;\n if (scope === \"tab\" && local) workspaceId ??= local.workspaces.currentId();\n else workspaceId = null;\n\n // One-read boot: a store that can answer everything at once is asked once.\n const all = port.loadAll ? await port.loadAll() : null;\n const bootValue = async (k: string): Promise<StoredValue | null> => (all ? (all.get(k) ?? null) : loadValue(k));\n\n const ownKey = scoped(workspaceKey());\n let stored = await bootValue(ownKey);\n let expectedWorkspaceId: string | undefined = scope === \"tab\" && workspaceId ? workspaceId : undefined;\n if (stored) versions.set(ownKey, stored.version);\n // The workspace already saved under THIS key: an unchanged first snapshot writes nothing.\n // (A tab seeded from the person's workspace below has no own row yet, so it still writes.)\n let storedUnderOwnKey = stored !== null;\n if (!stored && scope === \"tab\" && seedFromPerson) {\n storedUnderOwnKey = false;\n const personKey = scoped(PERSON_WORKSPACE_KEY);\n stored = await bootValue(personKey);\n if (stored) versions.set(personKey, stored.version);\n expectedWorkspaceId = undefined;\n }\n const stateKeys = all ? [...all.keys()].sort() : port.list ? await port.list(scoped(STATE_KEY_PREFIX)) : null;\n if (gen !== generation || identityKey !== key) return;\n\n const viewport =\n options.viewport?.() ??\n (() => {\n const { vw, vh } = safeViewportDims();\n return { width: vw, height: vh };\n })();\n const result = hydrateWindowWorkspace(stored?.value ?? null, viewport, expectedWorkspaceId);\n report(result.diagnostics);\n const sessions = result.sessions.filter(\n (s) => !closedAll && !closedOverlay.has(s.overlayId) && !closedExact.has(s.sessionKey),\n );\n\n // Saved component state, loaded BEFORE any instance opens so it mounts with its values.\n const prefix = scoped(STATE_KEY_PREFIX);\n const candidates = stateKeys\n ? stateKeys.filter((k) => k.startsWith(prefix)).map((k) => k.slice(prefix.length))\n : sessions.map((s) => s.sessionKey);\n const loadedStates = await Promise.all(\n candidates.map(async (instance) => [instance, await bootValue(scoped(stateKey(instance))).catch(() => null)] as const),\n );\n if (gen !== generation || identityKey !== key) return;\n\n const before = store.getState();\n const restoredKeys = new Set(sessions.map((s) => s.sessionKey));\n const stateEntries: Record<string, { values: Record<string, unknown> }> = {};\n for (const [instance, value] of loadedStates) {\n const parsed = parseInstanceKey(instance);\n if (!parsed || !value || !isRecord(value.value)) continue;\n const storageKey = scoped(stateKey(instance));\n const meta = getOverlayMeta(parsed.overlayId);\n if (!meta || !persistsComponentState(parsed.overlayId)) continue;\n const open = before.overlays.overlays[parsed.overlayId]?.[parsed.instanceId]?.isOpen === true;\n const wanted = meta.keepAlive === \"restore\" || restoredKeys.has(instance) || open;\n if (!wanted) {\n drop(storageKey); // a preserved window that did not come back: its state is dead\n continue;\n }\n versions.set(storageKey, value.version);\n if (before.overlayState.entries[instance]) continue; // live values beat saved ones\n stateEntries[instance] = { values: value.value };\n stateFps.set(storageKey, JSON.stringify(value.value));\n }\n if (Object.keys(stateEntries).length > 0) store.dispatch(hydrateOverlayState({ entries: stateEntries }));\n\n const live: [WindowEntry, HydratedWindowSession][] = [];\n const staged: HydratedWindowSession[] = [];\n for (const session of sessions) {\n const entry = liveWindowFor(before.windowManager.windows, session.overlayId, session.instanceId);\n if (entry) live.push([entry, session]);\n else staged.push(session);\n }\n store.dispatch(hydrateWindowSessions({ sessions: staged, viewportWidth: viewport.width, viewportHeight: viewport.height }));\n for (const [entry, session] of live) applyGeometry(entry, session, viewport);\n for (const session of staged) {\n // Already open (a link got there first): its data stands; only geometry was staged.\n if (before.overlays.overlays[session.overlayId]?.[session.instanceId]?.isOpen) continue;\n openRegisteredOverlay(store.dispatch, session.overlayId, session.instanceId, session.data);\n }\n\n lastWorkspaceFp =\n stored && storedUnderOwnKey && isRecord(stored.value) && Array.isArray(stored.value.sessions)\n ? JSON.stringify((stored.value.sessions as Record<string, unknown>[]).map((s) => ({ ...s, savedAt: 0 })))\n : null;\n lastSavedAt = stored && isRecord(stored.value) && typeof stored.value.savedAt === \"number\" ? stored.value.savedAt : 0;\n writeSafe = true;\n setHydrated(true);\n // Let restored windows register, then take the normalized first snapshot (also records an\n // authoritative empty workspace on a miss).\n setTimeout(() => {\n if (gen !== generation) return;\n saveNow();\n closedExact.clear();\n closedOverlay.clear();\n closedAll = false;\n }, 0);\n };\n\n const onIdentity = (): void => {\n const current = ports.identity.current();\n if (!current.ready) {\n if (identityKey !== null) teardown();\n identityKey = null;\n return;\n }\n if (current.key === identityKey) return;\n const changed = identityKey !== null;\n if (changed) teardown();\n else generation += 1;\n identityKey = current.key;\n writeSafe = false;\n setHydrated(false);\n const key = current.key;\n // A swap waits one task so the previous identity's windows unmount before anything loads.\n const wait = changed ? new Promise<void>((resolve) => setTimeout(resolve, 0)) : Promise.resolve();\n void wait\n .then(() => loadIdentity(key))\n .catch((error: unknown) => {\n fail(\"load\")(error);\n // A failed load is a completed load: the person keeps working; writes stay gated for\n // this identity so nothing unknown is overwritten.\n if (identityKey === key) setHydrated(true);\n });\n };\n\n return {\n get hydrated() {\n return hydrated;\n },\n flush: saveNow,\n start() {\n if (!port) return;\n cleanups.push(ports.identity.subscribe(onIdentity));\n cleanups.push(\n registerCloseFlusher((event) => {\n if (writeSafe) {\n saveNow();\n return;\n }\n for (const intent of event.intents) {\n if (intent.scope === \"all\") closedAll = true;\n else if (intent.scope === \"overlay\") closedOverlay.add(intent.overlayId);\n else closedExact.add(windowSessionKey(intent.overlayId, intent.instanceId));\n }\n }),\n );\n let previous = store.getState();\n cleanups.push(\n store.subscribe(() => {\n const next = store.getState();\n const changed = next.windowManager !== previous.windowManager || next.overlayState !== previous.overlayState;\n previous = next;\n if (changed && writeSafe) scheduleSave();\n }),\n );\n if (typeof window !== \"undefined\") {\n const renew = () => {\n if (workspaceId) local?.workspaces.renew(workspaceId);\n };\n const onPageHide = () => {\n saveNow();\n if (workspaceId) local?.workspaces.release(workspaceId);\n };\n const onVisibility = () => {\n if (document.visibilityState === \"hidden\") saveNow();\n else renew();\n };\n window.addEventListener(\"pagehide\", onPageHide);\n window.addEventListener(\"pageshow\", renew);\n window.addEventListener(\"focus\", renew);\n document.addEventListener(\"visibilitychange\", onVisibility);\n const sweep = window.setInterval(() => store.dispatch(pruneStaleInstances({ olderThanMs: STALE_SWEEP_MS })), STALE_SWEEP_MS);\n cleanups.push(() => {\n window.removeEventListener(\"pagehide\", onPageHide);\n window.removeEventListener(\"pageshow\", renew);\n window.removeEventListener(\"focus\", renew);\n document.removeEventListener(\"visibilitychange\", onVisibility);\n window.clearInterval(sweep);\n });\n }\n onIdentity();\n },\n stop() {\n saveNow();\n generation += 1;\n writeSafe = false;\n if (saveTimer) clearTimeout(saveTimer);\n saveTimer = null;\n for (const cleanup of cleanups.splice(0)) cleanup();\n identityKey = null;\n },\n };\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type { SummonPorts } from \"@ai-matrx/summon\";\nimport { useSummonPorts, useSummonStore } from \"@ai-matrx/summon/react\";\nimport { createOverlayPersistenceController, type OverlayPersistenceOptions } from \"./controller\";\n\n/**\n * Turn persistence on for the nearest <SummonProvider> (reads `ports.persistence` and\n * `ports.identity`; inert when persistence is null). Mount ONCE. Returns whether the current\n * identity's saved layout has been applied.\n */\nexport function useOverlayPersistence(options: Omit<OverlayPersistenceOptions, \"onHydratedChange\"> = {}): { hydrated: boolean } {\n const store = useSummonStore();\n const ports = useSummonPorts();\n const [hydrated, setHydrated] = useState(false);\n const { scope, seedFromPerson, saveDebounceMs, viewport } = options;\n // Restart only when what persistence reads changes (the store, the persistence port, identity).\n // A host that swaps another port (the router port arrives after mount) must not re-run the boot\n // read: the controller reads the rest of the ports through this ref.\n const portsRef = useRef(ports);\n useEffect(() => {\n portsRef.current = ports;\n });\n const { persistence, identity } = ports;\n useEffect(() => {\n const view = {\n get identity() { return identity; },\n get persistence() { return persistence; },\n get router() { return portsRef.current.router; },\n get notify() { return portsRef.current.notify; },\n get errors() { return portsRef.current.errors; },\n get debug() { return portsRef.current.debug; },\n } as SummonPorts;\n const controller = createOverlayPersistenceController(store, view, {\n ...(scope === undefined ? {} : { scope }),\n ...(seedFromPerson === undefined ? {} : { seedFromPerson }),\n ...(saveDebounceMs === undefined ? {} : { saveDebounceMs }),\n ...(viewport === undefined ? {} : { viewport }),\n onHydratedChange: setHydrated,\n });\n controller.start();\n return () => controller.stop();\n }, [store, persistence, identity, scope, seedFromPerson, saveDebounceMs, viewport]);\n return { hydrated };\n}\n\nexport type OverlayPersistenceProps = Omit<OverlayPersistenceOptions, \"onHydratedChange\">;\n\n/** Component form of `useOverlayPersistence` — mount once inside <SummonProvider>. */\nexport function OverlayPersistence(props: OverlayPersistenceProps): null {\n useOverlayPersistence(props);\n return null;\n}\n"],"mappings":"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","names":["import_summon","isRecord","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/persistence.ts","../src/persistence/backend.ts","../src/persistence/errors.ts","../src/persistence/keys.ts","../src/persistence/localStore.ts","../src/persistence/workspace.ts","../src/persistence/controller.ts","../src/persistence/OverlayPersistence.tsx"],"sourcesContent":["// @ai-matrx/summon/persistence — overlay persistence (R4, R6): the browser-local store\n// (localStorage mirror + IndexedDB; workspaces, leases, caps, identity isolation) and the restore\n// orchestration with the link-vs-restore race made deterministic.\nexport {\n createLocalPersistence,\n isLocalPersistence,\n DEFAULT_IDB_READ_BUDGET_MS,\n WORKSPACE_LEASE_MS,\n MAX_WORKSPACES_PER_IDENTITY,\n type LocalPersistenceOptions,\n type LocalOverlayPersistence,\n type LocalWorkspaces,\n type StorageLike,\n type LocksLike,\n} from \"./persistence/localStore\";\nexport { createIndexedDbBackend, createMemoryBackend, type KeyValueBackend } from \"./persistence/backend\";\nexport {\n PersistenceVersionConflictError,\n PersistenceLoadTimeoutError,\n isVersionConflict,\n isLoadTimeout,\n VERSION_CONFLICT_ERROR,\n LOAD_TIMEOUT_ERROR,\n} from \"./persistence/errors\";\nexport { PERSON_WORKSPACE_KEY, STATE_KEY_PREFIX, tabWorkspaceKey, stateKey, identityScopedKey } from \"./persistence/keys\";\nexport {\n serializeWindowWorkspace,\n hydrateWindowWorkspace,\n readSession,\n sanitizeJsonRecord,\n preservationFor,\n WINDOW_WORKSPACE_SCHEMA_VERSION,\n DEFAULT_WINDOW_DATA_BYTES,\n MAX_WINDOW_WORKSPACE_BYTES,\n MAX_PERSISTED_WINDOW_SESSIONS,\n type PersistedWindowWorkspace,\n type WindowPersistenceDiagnostic,\n type WindowPersistenceDiagnosticCode,\n} from \"./persistence/workspace\";\nexport {\n createOverlayPersistenceController,\n persistsComponentState,\n DEFAULT_SAVE_DEBOUNCE_MS,\n type OverlayPersistenceController,\n type OverlayPersistenceOptions,\n type PersistenceScope,\n type PersistenceStore,\n} from \"./persistence/controller\";\nexport { OverlayPersistence, useOverlayPersistence, type OverlayPersistenceProps } from \"./persistence/OverlayPersistence\";\n","/**\n * The warm tier behind the local store: a tiny async key/value interface, implemented over raw\n * IndexedDB (no Dexie) and in memory (tests, SSR, browsers without IndexedDB).\n */\n\nexport interface KeyValueBackend {\n get(key: string): Promise<unknown>;\n set(key: string, value: unknown): Promise<void>;\n delete(key: string): Promise<void>;\n /** Every key starting with `prefix`. */\n keys(prefix: string): Promise<string[]>;\n}\n\nexport function createMemoryBackend(): KeyValueBackend & { readonly data: Map<string, unknown> } {\n const data = new Map<string, unknown>();\n return {\n data,\n get: async (key) => (data.has(key) ? structuredClone(data.get(key)) : undefined),\n set: async (key, value) => {\n data.set(key, structuredClone(value));\n },\n delete: async (key) => {\n data.delete(key);\n },\n keys: async (prefix) => [...data.keys()].filter((key) => key.startsWith(prefix)),\n };\n}\n\nfunction request<T>(req: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error ?? new Error(\"IndexedDB request failed\"));\n });\n}\n\n/**\n * One object store in one database. The connection opens lazily on first use and is reused; a\n * blocked/failed open rejects every call (the local store then lives on its synchronous mirror).\n */\nexport function createIndexedDbBackend(dbName = \"ai-matrx-overlays\", storeName = \"kv\"): KeyValueBackend {\n let opening: Promise<IDBDatabase> | null = null;\n const db = (): Promise<IDBDatabase> => {\n if (opening) return opening;\n opening = new Promise<IDBDatabase>((resolve, reject) => {\n if (typeof indexedDB === \"undefined\") {\n reject(new Error(\"IndexedDB is unavailable\"));\n return;\n }\n const req = indexedDB.open(dbName, 1);\n req.onupgradeneeded = () => {\n if (!req.result.objectStoreNames.contains(storeName)) req.result.createObjectStore(storeName);\n };\n req.onsuccess = () => {\n const conn = req.result;\n // Another tab upgrading must not wedge on us; reopen lazily next time.\n conn.onversionchange = () => {\n conn.close();\n opening = null;\n };\n resolve(conn);\n };\n req.onerror = () => reject(req.error ?? new Error(\"IndexedDB open failed\"));\n req.onblocked = () => reject(new Error(\"IndexedDB open blocked\"));\n }).catch((error: unknown) => {\n opening = null;\n throw error;\n });\n return opening;\n };\n const run = async <T>(mode: IDBTransactionMode, body: (store: IDBObjectStore) => IDBRequest<T>): Promise<T> => {\n const conn = await db();\n const tx = conn.transaction(storeName, mode);\n const done =\n mode === \"readwrite\"\n ? new Promise<void>((resolve, reject) => {\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error ?? new Error(\"IndexedDB transaction failed\"));\n tx.onabort = () => reject(tx.error ?? new Error(\"IndexedDB transaction aborted\"));\n })\n : Promise.resolve();\n const result = await request(body(tx.objectStore(storeName)));\n await done;\n return result;\n };\n return {\n get: (key) => run(\"readonly\", (store) => store.get(key)),\n set: async (key, value) => {\n await run(\"readwrite\", (store) => store.put(value, key));\n },\n delete: async (key) => {\n await run(\"readwrite\", (store) => store.delete(key));\n },\n keys: async (prefix) => {\n const range = IDBKeyRange.bound(prefix, `${prefix}`);\n const keys = await run(\"readonly\", (store) => store.getAllKeys(range));\n return keys.filter((key): key is string => typeof key === \"string\");\n },\n };\n}\n","/**\n * Errors every persistence store throws in the same shape. Matched by `name`, never `instanceof`:\n * each section entry may carry its own copy of this module in a built consumer.\n */\nimport type { StoredValue } from \"@ai-matrx/summon\";\n\nexport const VERSION_CONFLICT_ERROR = \"OverlayPersistenceVersionConflict\";\nexport const LOAD_TIMEOUT_ERROR = \"OverlayPersistenceLoadTimeout\";\n\n/** A save whose `expectedVersion` no longer matches the stored version. */\nexport class PersistenceVersionConflictError extends Error {\n readonly key: string;\n readonly expectedVersion: number;\n readonly currentVersion: number;\n constructor(key: string, expectedVersion: number, currentVersion: number) {\n super(`[overlays/persistence] \"${key}\" is at version ${currentVersion}, not the expected ${expectedVersion}`);\n this.name = VERSION_CONFLICT_ERROR;\n this.key = key;\n this.expectedVersion = expectedVersion;\n this.currentVersion = currentVersion;\n }\n}\n\nexport function isVersionConflict(error: unknown): error is PersistenceVersionConflictError {\n return error instanceof Error && error.name === VERSION_CONFLICT_ERROR;\n}\n\n/**\n * The fast tier missed and the slow tier did not answer within the read budget. `pending` still\n * resolves the authoritative answer: a caller keeps every automatic writer gated until it does,\n * so an unknown stored value is never overwritten.\n */\nexport class PersistenceLoadTimeoutError extends Error {\n readonly key: string;\n readonly pending: Promise<StoredValue | null>;\n constructor(key: string, budgetMs: number, pending: Promise<StoredValue | null>) {\n super(`[overlays/persistence] \"${key}\" did not load within ${budgetMs}ms`);\n this.name = LOAD_TIMEOUT_ERROR;\n this.key = key;\n this.pending = pending;\n }\n}\n\nexport function isLoadTimeout(error: unknown): error is PersistenceLoadTimeoutError {\n return error instanceof Error && error.name === LOAD_TIMEOUT_ERROR;\n}\n","/** Storage keys the orchestration writes (before identity scoping). */\nexport const PERSON_WORKSPACE_KEY = \"workspace\";\nexport const tabWorkspaceKey = (workspaceId: string): string => `workspace:${workspaceId}`;\nexport const STATE_KEY_PREFIX = \"state:\";\nexport const stateKey = (instanceKey: string): string => `${STATE_KEY_PREFIX}${instanceKey}`;\n/** `<identityKey>/<key>` for stores that are not per-person themselves. */\nexport const identityScopedKey = (identityKey: string, key: string): string => `${identityKey}/${key}`;\n","/**\n * createLocalPersistence — an OverlayPersistencePort over the browser: a synchronous localStorage\n * mirror (the fast, pagehide-safe tier) plus IndexedDB (the warm tier). Ported from matrx-frontend\n * `localWindowSessionStore.ts` + `lib/sync/persistence/*` with the same safety:\n *\n * - write ordering: the mirror is written synchronously first; IndexedDB follows in a per-key\n * queue under `navigator.locks` (cross-tab) when available. A mirror write that fails removes\n * the old mirror, so a stale value never looks authoritative.\n * - reads: a valid mirror answers at once; otherwise IndexedDB gets a 750 ms budget, after which\n * load rejects with a PersistenceLoadTimeoutError carrying the still-pending answer.\n * - per-tab workspaces (`workspaces`): sessionStorage id + 24 h lease; a duplicated tab (same\n * sessionStorage, another live document holds the lease, not a reload) gets a fresh id; an\n * index per identity caps workspaces at 5 and GC skips any workspace with a live lease.\n * - identity isolation: keys arrive scoped (`<identityKey>/<key>`); `purgeIdentity` removes\n * everything one identity stored, both tiers (the old store missed the mirror keys).\n *\n * All state lives in the store instance (no module state). Create ONE per app.\n */\nimport type { OverlayPersistencePort, StoredValue } from \"@ai-matrx/summon\";\nimport { createIndexedDbBackend, createMemoryBackend, type KeyValueBackend } from \"./backend\";\nimport { PersistenceLoadTimeoutError, PersistenceVersionConflictError } from \"./errors\";\nimport { identityScopedKey, tabWorkspaceKey } from \"./keys\";\n\nexport const DEFAULT_IDB_READ_BUDGET_MS = 750;\nexport const WORKSPACE_LEASE_MS = 24 * 60 * 60 * 1000;\nexport const MAX_WORKSPACES_PER_IDENTITY = 5;\nconst INDEX_REFRESH_MS = 60 * 1000;\nconst RECORD_VERSION = 1;\n\n/** The slice of the Web Storage API the store uses. */\nexport interface StorageLike {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n key(index: number): string | null;\n readonly length: number;\n}\n\n/** The slice of `navigator.locks` the store uses. */\nexport interface LocksLike {\n request<T>(name: string, callback: () => Promise<T>): Promise<T>;\n}\n\nexport interface LocalPersistenceOptions {\n /** Prefix of every localStorage key and the IndexedDB database name. Default \"ai-matrx.overlays\". */\n readonly namespace?: string;\n /** Warm tier. Default: IndexedDB when present, else in-memory. */\n readonly backend?: KeyValueBackend;\n /** Default: window.localStorage (absent → memory-only mirror is skipped). */\n readonly storage?: StorageLike | null;\n /** Default: window.sessionStorage. */\n readonly session?: StorageLike | null;\n /** Default: navigator.locks. */\n readonly locks?: LocksLike | null;\n readonly idbReadBudgetMs?: number;\n /** Is this document a reload? Default: the Navigation Timing entry. */\n readonly isReload?: () => boolean;\n readonly now?: () => number;\n}\n\nexport interface LocalWorkspaces {\n /** This tab's workspace id (stable across reloads, fresh for a duplicated tab). Claims its lease. */\n currentId(): string;\n /** Event-driven lease heartbeat (focus, pageshow, visible). */\n renew(workspaceId: string): void;\n /** Release the lease this document holds (pagehide). */\n release(workspaceId: string): void;\n /** Record use of a workspace for an identity; evicts the oldest beyond the cap (live leases spared). */\n index(identityKey: string, workspaceId: string): void;\n}\n\nexport interface LocalOverlayPersistence extends OverlayPersistencePort {\n readonly perPerson: false;\n readonly workspaces: LocalWorkspaces;\n list(prefix: string): Promise<readonly string[]>;\n /** Remove everything stored under one identity (both tiers). */\n purgeIdentity(identityKey: string): Promise<void>;\n /** Resolves once every queued IndexedDB write has finished (tests, shutdown). */\n idle(): Promise<void>;\n}\n\ninterface StoredRecord {\n readonly v: typeof RECORD_VERSION;\n readonly version: number;\n readonly value: unknown;\n}\n\nfunction isStoredRecord(value: unknown): value is StoredRecord {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { v?: unknown }).v === RECORD_VERSION &&\n typeof (value as { version?: unknown }).version === \"number\" &&\n \"value\" in value\n );\n}\n\nfunction randomId(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") return crypto.randomUUID();\n return `tab-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;\n}\n\nconst browserStorage = (pick: \"localStorage\" | \"sessionStorage\"): StorageLike | null => {\n try {\n return typeof window === \"undefined\" ? null : window[pick];\n } catch {\n return null;\n }\n};\n\nconst defaultIsReload = (): boolean => {\n try {\n const entry = performance.getEntriesByType(\"navigation\")[0] as PerformanceNavigationTiming | undefined;\n return entry?.type === \"reload\";\n } catch {\n return false;\n }\n};\n\nexport function isLocalPersistence(port: OverlayPersistencePort | null | undefined): port is LocalOverlayPersistence {\n return Boolean(port && \"workspaces\" in port && typeof (port as { workspaces?: unknown }).workspaces === \"object\");\n}\n\nexport function createLocalPersistence(options: LocalPersistenceOptions = {}): LocalOverlayPersistence {\n const ns = options.namespace ?? \"ai-matrx.overlays\";\n const storage = options.storage === undefined ? browserStorage(\"localStorage\") : options.storage;\n const session = options.session === undefined ? browserStorage(\"sessionStorage\") : options.session;\n const locks =\n options.locks === undefined ? (typeof navigator !== \"undefined\" && navigator.locks ? (navigator.locks as unknown as LocksLike) : null) : options.locks;\n const backend = options.backend ?? (typeof indexedDB !== \"undefined\" ? createIndexedDbBackend(ns) : createMemoryBackend());\n const budgetMs = options.idbReadBudgetMs ?? DEFAULT_IDB_READ_BUDGET_MS;\n const now = options.now ?? Date.now;\n const isReload = options.isReload ?? defaultIsReload;\n const runtimeId = randomId();\n const fallbackWorkspaceId = `fallback-${runtimeId}`;\n const queues = new Map<string, Promise<void>>();\n let leased: string | null = null;\n\n const mirrorKey = (key: string) => `${ns}:${key}`;\n const leaseKey = (workspaceId: string) => `${ns}:lease:${workspaceId}`;\n const indexPrefix = (identityKey: string) => `${ns}:index:${identityKey}:`;\n\n // ── sync mirror helpers ──\n const readJson = (key: string): unknown => {\n if (!storage) return null;\n try {\n const raw = storage.getItem(key);\n return raw === null ? null : (JSON.parse(raw) as unknown);\n } catch {\n return null;\n }\n };\n const writeJson = (key: string, value: unknown): boolean => {\n if (!storage) return false;\n try {\n storage.setItem(key, JSON.stringify(value));\n return true;\n } catch {\n return false;\n }\n };\n const removeKey = (key: string): void => {\n try {\n storage?.removeItem(key);\n } catch {\n /* storage disabled: nothing to remove */\n }\n };\n const storageKeys = (prefix: string): string[] => {\n if (!storage) return [];\n const out: string[] = [];\n try {\n for (let i = 0; i < storage.length; i += 1) {\n const key = storage.key(i);\n if (key?.startsWith(prefix)) out.push(key);\n }\n } catch {\n /* enumeration failed; cleanup retries on a later save */\n }\n return out;\n };\n const readMirror = (key: string): StoredRecord | null => {\n const raw = readJson(mirrorKey(key));\n return isStoredRecord(raw) ? raw : null;\n };\n\n // ── ordered warm-tier writes ──\n const enqueue = (key: string, operation: () => Promise<void>): Promise<void> => {\n const previous = queues.get(key) ?? Promise.resolve();\n const next = previous\n .catch(() => undefined)\n .then(() => (locks ? locks.request(`${ns}:${key}`, operation) : operation()));\n queues.set(key, next);\n void next.then(\n () => {\n if (queues.get(key) === next) queues.delete(key);\n },\n () => {\n if (queues.get(key) === next) queues.delete(key);\n },\n );\n return next;\n };\n\n const readWarm = async (key: string): Promise<StoredValue | null> => {\n const raw = await backend.get(key);\n return isStoredRecord(raw) ? { value: raw.value, version: raw.version } : null;\n };\n\n // ── leases ──\n const leaseBody = (workspaceId: string): { runtimeId?: unknown; expiresAt?: unknown } | null => {\n const raw = readJson(leaseKey(workspaceId));\n return typeof raw === \"object\" && raw !== null ? (raw as { runtimeId?: unknown; expiresAt?: unknown }) : null;\n };\n const hasLiveLease = (workspaceId: string, at: number): boolean => {\n const body = leaseBody(workspaceId);\n return typeof body?.expiresAt === \"number\" && body.expiresAt > at;\n };\n const claimLease = (workspaceId: string): void => {\n if (leased && leased !== workspaceId && leaseBody(leased)?.runtimeId === runtimeId) removeKey(leaseKey(leased));\n leased = workspaceId;\n writeJson(leaseKey(workspaceId), { runtimeId, expiresAt: now() + WORKSPACE_LEASE_MS });\n };\n\n const workspaces: LocalWorkspaces = {\n currentId() {\n if (!session) {\n claimLease(fallbackWorkspaceId);\n return fallbackWorkspaceId;\n }\n try {\n const sessionKey = `${ns}:workspace-id`;\n const existing = session.getItem(sessionKey);\n const body = existing ? leaseBody(existing) : null;\n const claimedElsewhere = Boolean(\n existing &&\n !isReload() &&\n body?.runtimeId !== runtimeId &&\n typeof body?.expiresAt === \"number\" &&\n body.expiresAt > now(),\n );\n const workspaceId = existing && !claimedElsewhere ? existing : randomId();\n session.setItem(sessionKey, workspaceId);\n claimLease(workspaceId);\n return workspaceId;\n } catch {\n claimLease(fallbackWorkspaceId);\n return fallbackWorkspaceId;\n }\n },\n renew(workspaceId) {\n claimLease(workspaceId);\n },\n release(workspaceId) {\n if (leaseBody(workspaceId)?.runtimeId === runtimeId) removeKey(leaseKey(workspaceId));\n if (leased === workspaceId) leased = null;\n },\n index(identityKey, workspaceId) {\n const at = now();\n const prefix = indexPrefix(identityKey);\n const rows = storageKeys(prefix)\n .map((key) => readJson(key))\n .filter(\n (row): row is { workspaceId: string; lastUsedAt: number } =>\n typeof row === \"object\" &&\n row !== null &&\n typeof (row as { workspaceId?: unknown }).workspaceId === \"string\" &&\n typeof (row as { lastUsedAt?: unknown }).lastUsedAt === \"number\",\n );\n const current = rows.find((row) => row.workspaceId === workspaceId);\n if (current && rows.length <= MAX_WORKSPACES_PER_IDENTITY && at - current.lastUsedAt < INDEX_REFRESH_MS) return;\n const entry = { workspaceId, lastUsedAt: current && at - current.lastUsedAt < INDEX_REFRESH_MS ? current.lastUsedAt : at };\n writeJson(`${prefix}${workspaceId}`, entry);\n const ordered = [...rows.filter((row) => row.workspaceId !== workspaceId), entry].sort((a, b) => b.lastUsedAt - a.lastUsedAt);\n for (const stale of ordered.slice(MAX_WORKSPACES_PER_IDENTITY)) {\n if (hasLiveLease(stale.workspaceId, at)) continue;\n const key = identityScopedKey(identityKey, tabWorkspaceKey(stale.workspaceId));\n void enqueue(key, async () => {\n // Recheck inside the cross-tab lock: that tab may have woken since the scan.\n if (hasLiveLease(stale.workspaceId, now())) return;\n removeKey(mirrorKey(key));\n removeKey(leaseKey(stale.workspaceId));\n removeKey(`${prefix}${stale.workspaceId}`);\n await backend.delete(key);\n }).catch(() => undefined);\n }\n },\n };\n\n return {\n perPerson: false,\n workspaces,\n\n async load<T = unknown>(key: string): Promise<StoredValue<T> | null> {\n const mirror = readMirror(key);\n // The synchronous mirror is written before IndexedDB on every save: when it is valid,\n // waiting on IndexedDB adds latency without adding freshness.\n if (mirror) return { value: mirror.value as T, version: mirror.version };\n const warm = readWarm(key).catch(() => null);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<\"timeout\">((resolve) => {\n timer = setTimeout(() => resolve(\"timeout\"), budgetMs);\n });\n const first = await Promise.race([warm, timeout]);\n if (timer !== undefined) clearTimeout(timer);\n if (first === \"timeout\") throw new PersistenceLoadTimeoutError(key, budgetMs, warm);\n return first as StoredValue<T> | null;\n },\n\n async save<T = unknown>(key: string, value: T, saveOptions?: { readonly expectedVersion?: number }) {\n const current = readMirror(key)?.version ?? 0;\n const expected = saveOptions?.expectedVersion;\n if (expected !== undefined && expected !== current) throw new PersistenceVersionConflictError(key, expected, current);\n const record: StoredRecord = { v: RECORD_VERSION, version: current + 1, value };\n // Never leave a previously valid mirror looking authoritative when this newer write only\n // reaches IndexedDB (quota / disabled storage).\n if (!writeJson(mirrorKey(key), record)) removeKey(mirrorKey(key));\n await enqueue(key, () => backend.set(key, record));\n return { version: record.version };\n },\n\n async remove(key: string) {\n removeKey(mirrorKey(key));\n await enqueue(key, () => backend.delete(key));\n },\n\n async list(prefix: string) {\n const fromMirror = storageKeys(mirrorKey(prefix)).map((key) => key.slice(ns.length + 1));\n let fromWarm: string[] = [];\n try {\n fromWarm = await backend.keys(prefix);\n } catch {\n /* warm tier unavailable: the mirror is the answer */\n }\n return [...new Set([...fromMirror, ...fromWarm])].sort();\n },\n\n async purgeIdentity(identityKey: string) {\n const prefix = identityScopedKey(identityKey, \"\");\n for (const key of storageKeys(mirrorKey(prefix))) removeKey(key);\n for (const key of storageKeys(indexPrefix(identityKey))) removeKey(key);\n let warmKeys: string[] = [];\n try {\n warmKeys = await backend.keys(prefix);\n } catch {\n return;\n }\n await Promise.all(warmKeys.map((key) => enqueue(key, () => backend.delete(key))));\n },\n\n async idle() {\n await Promise.all([...queues.values()].map((q) => q.catch(() => undefined)));\n },\n };\n}\n","/**\n * The window workspace record: serialize the window manager into a compact JSON record and\n * validate a stored one back into staged sessions. Ported from matrx-frontend\n * `windowSessionSerialization.ts`; the old metadata table is now each definition's `window`\n * options in the registry.\n *\n * DEFAULT DENY: a window is saved and restored only when its definition has `window.preservation`\n * and is not `ephemeral`; only `preservation.dataKeys` of its data are kept; unknown overlay ids\n * are rejected with a diagnostic. `window.restoreDefaults` is merged UNDER saved data on restore.\n */\nimport {\n WINDOW_SESSION_SCHEMA_VERSION,\n centerRectInViewport,\n clampStoredRectToViewport,\n defaultWindowIdFor,\n getOverlayMeta,\n traySlotRect,\n windowSessionKey,\n type AnyOverlayMeta,\n type HydratedWindowSession,\n type PersistedWindowSession,\n type WindowManagerState,\n type WindowPreservation,\n type WindowRect,\n type WindowState,\n} from \"@ai-matrx/summon\";\n\nexport const WINDOW_WORKSPACE_SCHEMA_VERSION = 1 as const;\nexport const DEFAULT_WINDOW_DATA_BYTES = 32 * 1024;\nexport const MAX_WINDOW_WORKSPACE_BYTES = 256 * 1024;\nexport const MAX_PERSISTED_WINDOW_SESSIONS = 64;\nconst MAX_ID_LENGTH = 160;\nconst MAX_LABEL_LENGTH = 512;\n\nexport interface PersistedWindowWorkspace {\n schemaVersion: typeof WINDOW_WORKSPACE_SCHEMA_VERSION;\n workspaceId: string;\n savedAt: number;\n sessions: PersistedWindowSession[];\n}\n\nexport type WindowPersistenceDiagnosticCode =\n | \"unsupported-data\"\n | \"window-data-too-large\"\n | \"workspace-too-large\"\n | \"invalid-workspace\"\n | \"invalid-session\"\n | \"unknown-overlay\"\n | \"preservation-disabled\"\n | \"state-too-large\";\n\nexport interface WindowPersistenceDiagnostic {\n level: \"warning\" | \"error\";\n code: WindowPersistenceDiagnosticCode;\n sessionKey?: string;\n message: string;\n}\n\ninterface Preserved {\n readonly meta: AnyOverlayMeta;\n readonly preservation: WindowPreservation;\n}\n\n/** The definition's preservation, or null when the window is not preserved (default deny). */\nexport function preservationFor(overlayId: string): Preserved | null {\n const meta = getOverlayMeta(overlayId);\n const preservation = meta?.window?.preservation;\n if (!meta || !preservation || meta.window?.ephemeral) return null;\n return { meta, preservation };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nconst isFiniteNumber = (value: unknown): value is number => typeof value === \"number\" && Number.isFinite(value);\n\n/** UTF-8 byte count without TextEncoder. */\nexport function utf8Bytes(value: string): number {\n let bytes = 0;\n for (const ch of value) {\n const cp = ch.codePointAt(0) ?? 0;\n bytes += cp <= 0x7f ? 1 : cp <= 0x7ff ? 2 : cp <= 0xffff ? 3 : 4;\n }\n return bytes;\n}\n\nconst isWindowState = (value: unknown): value is WindowState => value === \"windowed\" || value === \"maximized\" || value === \"minimized\";\n\nfunction readRect(value: unknown): WindowRect | null {\n if (!isRecord(value)) return null;\n const { x, y, width, height } = value;\n if (!isFiniteNumber(x) || !isFiniteNumber(y) || !isFiniteNumber(width) || !isFiniteNumber(height) || width <= 0 || height <= 0) return null;\n return { x, y, width, height };\n}\n\nexport interface JsonSanitizeResult {\n data: Record<string, unknown>;\n droppedUnsupported: boolean;\n bytes: number;\n}\n\n/**\n * Copy `allowedKeys` (all keys when `null`) into plain JSON. Functions, symbols, undefined and\n * circular references are dropped; BigInt becomes text; class instances are dropped.\n */\nexport function sanitizeJsonRecord(value: unknown, allowedKeys: readonly string[] | null): JsonSanitizeResult {\n if (!isRecord(value) || (allowedKeys && allowedKeys.length === 0)) return { data: {}, droppedUnsupported: false, bytes: 2 };\n const ancestors = new WeakSet<object>();\n let droppedUnsupported = false;\n const DROPPED = Symbol(\"dropped\");\n const copy = (item: unknown): unknown => {\n if (item === undefined || typeof item === \"function\" || typeof item === \"symbol\") {\n droppedUnsupported = true;\n return DROPPED;\n }\n if (typeof item === \"bigint\") {\n droppedUnsupported = true;\n return item.toString();\n }\n if (typeof item === \"number\" && !Number.isFinite(item)) {\n droppedUnsupported = true;\n return null;\n }\n if (item === null || typeof item !== \"object\") return item;\n if (item instanceof Date) return item.toJSON();\n if (ancestors.has(item)) {\n droppedUnsupported = true;\n return DROPPED;\n }\n ancestors.add(item);\n let result: unknown;\n if (Array.isArray(item)) {\n result = item.map((child) => {\n const copied = copy(child);\n return copied === DROPPED ? null : copied;\n });\n } else if (Object.getPrototypeOf(item) === Object.prototype || Object.getPrototypeOf(item) === null) {\n result = Object.fromEntries(\n Object.entries(item).flatMap(([key, child]) => {\n const copied = copy(child);\n return copied === DROPPED ? [] : [[key, copied]];\n }),\n );\n } else {\n droppedUnsupported = true;\n result = DROPPED;\n }\n ancestors.delete(item);\n return result;\n };\n try {\n const allowed = allowedKeys ? new Set(allowedKeys) : null;\n const selected = Object.fromEntries(Object.entries(value).filter(([key]) => !allowed || allowed.has(key)));\n ancestors.add(value);\n const copied = copy(selected);\n ancestors.delete(value);\n const json = JSON.stringify(copied === DROPPED ? {} : copied) || \"{}\";\n const parsed: unknown = JSON.parse(json);\n return { data: isRecord(parsed) ? parsed : {}, droppedUnsupported, bytes: utf8Bytes(json) };\n } catch {\n return { data: {}, droppedUnsupported: true, bytes: 2 };\n }\n}\n\nfunction invalidAllowedDataKey(data: Record<string, unknown>, preservation: WindowPreservation): string | null {\n const domains = preservation.allowedDataValues;\n if (!domains) return null;\n return Object.entries(domains).find(([key, allowed]) => !allowed.includes(data[key] as string | number | boolean | null))?.[0] ?? null;\n}\n\nfunction sessionFromWindow(\n entry: WindowManagerState[\"windows\"][string],\n savedAt: number,\n diagnostics: WindowPersistenceDiagnostic[],\n): PersistedWindowSession | null {\n const persistence = entry.persistence;\n if (!persistence || persistence.closing) return null;\n const preserved = preservationFor(persistence.overlayId);\n if (!preserved) return null;\n const sessionKey = windowSessionKey(persistence.overlayId, persistence.instanceId);\n if (persistence.instanceId.length > MAX_ID_LENGTH || entry.id.length > MAX_ID_LENGTH || entry.title.length > MAX_LABEL_LENGTH) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", sessionKey, message: `Skipped ${sessionKey}: identity or label metadata is oversized.` });\n return null;\n }\n const sanitized = sanitizeJsonRecord(persistence.data, preserved.preservation.dataKeys);\n if (sanitized.droppedUnsupported) {\n diagnostics.push({ level: \"warning\", code: \"unsupported-data\", sessionKey, message: `Dropped non-JSON window data for ${sessionKey}.` });\n }\n const maxBytes = preserved.preservation.maxDataBytes ?? DEFAULT_WINDOW_DATA_BYTES;\n const data = sanitized.bytes <= maxBytes ? sanitized.data : {};\n if (sanitized.bytes > maxBytes) {\n diagnostics.push({\n level: \"error\",\n code: \"window-data-too-large\",\n sessionKey,\n message: `Discarded ${sanitized.bytes} bytes of window data for ${sessionKey}; limit is ${maxBytes}.`,\n });\n }\n const invalidKey = invalidAllowedDataKey(sanitized.data, preserved.preservation);\n if (invalidKey) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", sessionKey, message: `Skipped ${sessionKey}: ${invalidKey} is outside its allowed domain.` });\n return null;\n }\n return {\n schemaVersion: WINDOW_SESSION_SCHEMA_VERSION,\n sessionKey,\n overlayId: persistence.overlayId,\n instanceId: persistence.instanceId,\n windowId: entry.id,\n title: entry.title,\n state: entry.state,\n windowedRect: entry.state === \"minimized\" ? (entry.preMinimizedRect ?? entry.windowed) : entry.windowed,\n traySlot: entry.state === \"minimized\" ? entry.traySlot : null,\n zIndex: entry.zIndex,\n sidebarOpen: persistence.sidebarOpen,\n sidebarSize: persistence.sidebarSize,\n data,\n savedAt,\n };\n}\n\n/** Validate one stored session against the registry (default deny). */\nexport function readSession(value: unknown, diagnostics: WindowPersistenceDiagnostic[]): PersistedWindowSession | null {\n if (!isRecord(value)) return null;\n const { overlayId, instanceId } = value;\n const rect = readRect(value.windowedRect);\n if (\n value.schemaVersion !== WINDOW_SESSION_SCHEMA_VERSION ||\n typeof overlayId !== \"string\" ||\n typeof instanceId !== \"string\" ||\n instanceId.length === 0 ||\n !rect ||\n !isWindowState(value.state)\n ) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", message: \"Ignored an invalid window preservation record.\" });\n return null;\n }\n const sessionKey = windowSessionKey(overlayId, instanceId);\n const meta = getOverlayMeta(overlayId);\n if (!meta) {\n diagnostics.push({ level: \"error\", code: \"unknown-overlay\", sessionKey, message: `Ignored unknown overlay ${overlayId}.` });\n return null;\n }\n const preserved = preservationFor(overlayId);\n if (!preserved) {\n diagnostics.push({ level: \"warning\", code: \"preservation-disabled\", sessionKey, message: `Ignored ${overlayId}: its definition does not preserve windows.` });\n return null;\n }\n if (\n (meta.instance !== \"multi\" && instanceId !== \"default\") ||\n instanceId.length > MAX_ID_LENGTH ||\n (typeof value.windowId === \"string\" && value.windowId.length > MAX_ID_LENGTH) ||\n (typeof value.title === \"string\" && value.title.length > MAX_LABEL_LENGTH)\n ) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", sessionKey, message: `Ignored invalid instance or oversized metadata for ${overlayId}.` });\n return null;\n }\n const sanitized = sanitizeJsonRecord(value.data, preserved.preservation.dataKeys);\n const missing = preserved.preservation.requiredDataKeys?.find((key) => {\n const v = sanitized.data[key];\n return v === undefined || v === null || v === \"\";\n });\n if (missing) {\n diagnostics.push({ level: \"warning\", code: \"invalid-session\", sessionKey, message: `Ignored ${overlayId}: required key ${missing} was empty.` });\n return null;\n }\n const invalidKey = invalidAllowedDataKey(sanitized.data, preserved.preservation);\n if (invalidKey) {\n diagnostics.push({ level: \"error\", code: \"invalid-session\", sessionKey, message: `Ignored ${overlayId}: ${invalidKey} is outside its allowed domain.` });\n return null;\n }\n const maxBytes = preserved.preservation.maxDataBytes ?? DEFAULT_WINDOW_DATA_BYTES;\n if (sanitized.bytes > maxBytes) {\n diagnostics.push({\n level: \"error\",\n code: \"window-data-too-large\",\n sessionKey,\n message: `Discarded ${sanitized.bytes} bytes of restored window data for ${overlayId}; limit is ${maxBytes}.`,\n });\n }\n return {\n schemaVersion: WINDOW_SESSION_SCHEMA_VERSION,\n sessionKey,\n overlayId,\n instanceId,\n windowId: typeof value.windowId === \"string\" ? value.windowId : defaultWindowIdFor(meta),\n title: typeof value.title === \"string\" ? value.title : meta.label,\n state: value.state,\n windowedRect: rect,\n traySlot: Number.isInteger(value.traySlot) && Number(value.traySlot) >= 0 ? Number(value.traySlot) : null,\n zIndex: isFiniteNumber(value.zIndex) ? value.zIndex : 1000,\n sidebarOpen: value.sidebarOpen !== false,\n sidebarSize: isFiniteNumber(value.sidebarSize) && value.sidebarSize > 0 ? value.sidebarSize : null,\n data: sanitized.bytes <= maxBytes ? sanitized.data : {},\n savedAt: isFiniteNumber(value.savedAt) ? value.savedAt : 0,\n };\n}\n\nexport function serializeWindowWorkspace(\n state: WindowManagerState,\n workspaceId: string,\n savedAt = Date.now(),\n): { workspace: PersistedWindowWorkspace; diagnostics: WindowPersistenceDiagnostic[] } {\n const diagnostics: WindowPersistenceDiagnostic[] = [];\n const live = Object.values(state.windows)\n .map((entry) => sessionFromWindow(entry, savedAt, diagnostics))\n .filter((s): s is PersistedWindowSession => s !== null);\n const liveKeys = new Set(live.map((s) => s.sessionKey));\n // Pending restores stay in the workspace until their window registers, so an early save can\n // never erase a session whose lazy chunk has not arrived.\n const pending = Object.values(state.pendingRestores)\n .filter((s) => !liveKeys.has(s.sessionKey))\n .map((s) => readSession({ ...s, savedAt }, diagnostics))\n .filter((s): s is PersistedWindowSession => s !== null);\n const all = [...live, ...pending].sort((a, b) => b.zIndex - a.zIndex || a.sessionKey.localeCompare(b.sessionKey));\n const sessions = all.slice(0, MAX_PERSISTED_WINDOW_SESSIONS).sort((a, b) => a.zIndex - b.zIndex || a.sessionKey.localeCompare(b.sessionKey));\n if (all.length > sessions.length) {\n diagnostics.push({\n level: \"error\",\n code: \"workspace-too-large\",\n message: `Window workspace exceeded ${MAX_PERSISTED_WINDOW_SESSIONS} sessions; later z-order entries were not saved.`,\n });\n }\n const workspace: PersistedWindowWorkspace = { schemaVersion: WINDOW_WORKSPACE_SCHEMA_VERSION, workspaceId, savedAt, sessions };\n const bytes = utf8Bytes(JSON.stringify(workspace));\n if (bytes > MAX_WINDOW_WORKSPACE_BYTES) {\n for (const s of sessions) s.data = {};\n diagnostics.push({\n level: \"error\",\n code: \"workspace-too-large\",\n message: `Window workspace reached ${bytes} bytes; window data was discarded while geometry was kept.`,\n });\n while (sessions.length > 0 && utf8Bytes(JSON.stringify(workspace)) > MAX_WINDOW_WORKSPACE_BYTES) sessions.pop();\n }\n return { workspace, diagnostics };\n}\n\nfunction fallbackRect(viewport: { width: number; height: number }): WindowRect {\n return centerRectInViewport({ x: 0, y: 0, width: Math.min(720, viewport.width), height: Math.min(480, viewport.height) }, viewport);\n}\n\n/**\n * Validate a stored workspace into staged sessions: rects clamped to the viewport, tray slots\n * renumbered, `restoreDefaults` merged under the saved data. `expectedWorkspaceId` (tab scope)\n * rejects a record written by another workspace.\n */\nexport function hydrateWindowWorkspace(\n raw: unknown,\n viewport: { width: number; height: number },\n expectedWorkspaceId?: string,\n): { sessions: HydratedWindowSession[]; diagnostics: WindowPersistenceDiagnostic[] } {\n const diagnostics: WindowPersistenceDiagnostic[] = [];\n if (\n !isRecord(raw) ||\n raw.schemaVersion !== WINDOW_WORKSPACE_SCHEMA_VERSION ||\n !Array.isArray(raw.sessions) ||\n typeof raw.workspaceId !== \"string\" ||\n (expectedWorkspaceId !== undefined && raw.workspaceId !== expectedWorkspaceId)\n ) {\n if (raw != null) diagnostics.push({ level: \"error\", code: \"invalid-workspace\", message: \"Ignored an invalid or unsupported window workspace.\" });\n return { sessions: [], diagnostics };\n }\n let workspaceBytes: number;\n try {\n workspaceBytes = utf8Bytes(JSON.stringify(raw));\n } catch {\n diagnostics.push({ level: \"error\", code: \"invalid-workspace\", message: \"Ignored a window workspace that could not be serialized.\" });\n return { sessions: [], diagnostics };\n }\n if (workspaceBytes > MAX_WINDOW_WORKSPACE_BYTES) {\n diagnostics.push({\n level: \"error\",\n code: \"workspace-too-large\",\n message: `Ignored a ${workspaceBytes}-byte window workspace above the ${MAX_WINDOW_WORKSPACE_BYTES}-byte limit.`,\n });\n return { sessions: [], diagnostics };\n }\n if (raw.sessions.length > MAX_PERSISTED_WINDOW_SESSIONS) {\n diagnostics.push({\n level: \"error\",\n code: \"invalid-workspace\",\n message: `Window workspace exceeded ${MAX_PERSISTED_WINDOW_SESSIONS} sessions; extras were ignored.`,\n });\n }\n const byKey = new Map<string, PersistedWindowSession>();\n for (const candidate of raw.sessions.slice(0, MAX_PERSISTED_WINDOW_SESSIONS)) {\n const session = readSession(candidate, diagnostics);\n if (!session) continue;\n const existing = byKey.get(session.sessionKey);\n if (!existing || existing.savedAt < session.savedAt || (existing.savedAt === session.savedAt && JSON.stringify(existing) < JSON.stringify(session))) {\n byKey.set(session.sessionKey, session);\n }\n }\n const ordered = [...byKey.values()].sort((a, b) => a.zIndex - b.zIndex || a.sessionKey.localeCompare(b.sessionKey));\n const minimized = ordered\n .filter((s) => s.state === \"minimized\")\n .sort((a, b) => (a.traySlot ?? Number.MAX_SAFE_INTEGER) - (b.traySlot ?? Number.MAX_SAFE_INTEGER) || a.sessionKey.localeCompare(b.sessionKey));\n const slotOf = new Map(minimized.map((s, i) => [s.sessionKey, i] as const));\n const sessions = ordered.map((session, index): HydratedWindowSession => {\n const restoreDefaults = getOverlayMeta(session.overlayId)?.window?.restoreDefaults;\n const slot = slotOf.get(session.sessionKey) ?? null;\n const renderRect =\n session.state === \"minimized\" && slot !== null\n ? traySlotRect(slot, viewport.width, viewport.height, minimized.length)\n : session.state === \"windowed\" || session.state === \"maximized\"\n ? clampStoredRectToViewport(session.windowedRect, viewport)\n : fallbackRect(viewport);\n return {\n ...session,\n traySlot: slot,\n zIndex: 1000 + index,\n data: restoreDefaults ? { ...restoreDefaults, ...session.data } : session.data,\n renderRect,\n };\n });\n return { sessions, diagnostics };\n}\n","/**\n * The persistence orchestration, framework-free: one controller per overlays store. The React\n * component (`OverlayPersistence`) only starts and stops it.\n *\n * - identity ready → load the workspace (tab or person scope) and saved component state →\n * validate (default deny, see workspace.ts) → stage/apply → open what is not open yet.\n * - window manager / overlayState change → save debounced 250 ms; flush on pagehide, hidden\n * visibility and every close (close-lifecycle flusher). Writes stay gated until the load for\n * the CURRENT identity has applied, so an unknown stored value is never overwritten.\n * - identity change → close everything, clear staged persistence and component state, load the\n * new identity. Nothing of one identity is ever written under another.\n *\n * LINK vs RESTORE (deterministic in both orders, for the same instance):\n * the link's DATA wins, the restored GEOMETRY wins.\n * - restore after link: an instance already open keeps its data (no re-open); its saved\n * geometry is staged (window not registered yet → `registerWindow` takes the staged rect and\n * merges staged data UNDER the live data) or applied to the live window directly.\n * - link after restore: the link's open replaces the overlay's data; the staged/applied\n * geometry is untouched by an open.\n */\nimport {\n closeAllOverlays,\n clearOverlayState,\n clearWindowPersistenceState,\n hydrateOverlayState,\n hydrateWindowSessions,\n markWindowClosing,\n maximizeWindow,\n minimizeWindow,\n parseInstanceKey,\n overlaysRawActions,\n pruneStaleInstances,\n registerCloseFlusher,\n restoreWindow,\n safeViewportDims,\n getOverlayMeta,\n updateWindowRect,\n windowSessionKey,\n type HydratedWindowSession,\n type InstanceKey,\n type OverlayPersistencePort,\n type SummonPorts,\n type SummonRootState,\n type StoredValue,\n type WindowEntry,\n} from \"@ai-matrx/summon\";\nimport type { Dispatch, UnknownAction } from \"@reduxjs/toolkit\";\nimport { isLoadTimeout, isVersionConflict } from \"./errors\";\nimport { PERSON_WORKSPACE_KEY, STATE_KEY_PREFIX, identityScopedKey, stateKey, tabWorkspaceKey } from \"./keys\";\nimport { isLocalPersistence } from \"./localStore\";\nimport {\n DEFAULT_WINDOW_DATA_BYTES,\n hydrateWindowWorkspace,\n preservationFor,\n sanitizeJsonRecord,\n serializeWindowWorkspace,\n type WindowPersistenceDiagnostic,\n} from \"./workspace\";\n\nexport type PersistenceScope = \"tab\" | \"person\";\n\nexport interface OverlayPersistenceOptions {\n /**\n * `tab`: one workspace per browser tab (the local store's default). `person`: one workspace per\n * person (`workspace`) — windows follow the person across devices (the data adapter's default).\n */\n readonly scope?: PersistenceScope;\n /** Tab scope: a tab with no workspace of its own starts from the person's last one. Default true. */\n readonly seedFromPerson?: boolean;\n readonly saveDebounceMs?: number;\n /** Viewport used to clamp restored rects. Default: the sanitized window size. */\n readonly viewport?: () => { width: number; height: number };\n /** Called whenever `hydrated` flips. */\n readonly onHydratedChange?: (hydrated: boolean) => void;\n}\n\nexport interface PersistenceStore {\n getState(): SummonRootState;\n dispatch: Dispatch<UnknownAction>;\n subscribe(listener: () => void): () => void;\n}\n\nexport interface OverlayPersistenceController {\n start(): void;\n stop(): void;\n /** Save now (skips unchanged records). */\n flush(): void;\n readonly hydrated: boolean;\n}\n\nexport const DEFAULT_SAVE_DEBOUNCE_MS = 250;\nconst STALE_SWEEP_MS = 30 * 60 * 1000;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Open by registry id with plain strings (raw action; definition defaults merged underneath). */\nfunction openRegisteredOverlay(dispatch: Dispatch<UnknownAction>, overlayId: string, instanceId: string, data: unknown): void {\n const defaults = getOverlayMeta(overlayId)?.defaults;\n dispatch(overlaysRawActions.openOverlay({ overlayId, instanceId, data, ...(isRecord(defaults) ? { defaults } : {}) }));\n}\n\n/** Component state is saved for definitions with keepAlive \"restore\" or a preserved window. */\nexport function persistsComponentState(overlayId: string): boolean {\n const meta = getOverlayMeta(overlayId);\n return Boolean(meta && (meta.keepAlive === \"restore\" || preservationFor(overlayId)));\n}\n\nexport function createOverlayPersistenceController(\n store: PersistenceStore,\n ports: SummonPorts,\n options: OverlayPersistenceOptions = {},\n): OverlayPersistenceController {\n const port: OverlayPersistencePort | null = ports.persistence;\n const debounceMs = options.saveDebounceMs ?? DEFAULT_SAVE_DEBOUNCE_MS;\n const seedFromPerson = options.seedFromPerson ?? true;\n const local = isLocalPersistence(port) ? port : null;\n const scope: PersistenceScope = options.scope ?? (port?.perPerson ? \"person\" : local ? \"tab\" : \"person\");\n\n let identityKey: string | null = null;\n let generation = 0;\n let writeSafe = false;\n let hydrated = false;\n let workspaceId: string | null = null;\n let saveTimer: ReturnType<typeof setTimeout> | null = null;\n let lastWorkspaceFp: string | null = null;\n let lastSavedAt = 0;\n const versions = new Map<string, number>();\n const stateFps = new Map<string, string>();\n const chains = new Map<string, Promise<void>>();\n const closedExact = new Set<string>();\n const closedOverlay = new Set<string>();\n let closedAll = false;\n const cleanups: (() => void)[] = [];\n\n const setHydrated = (next: boolean) => {\n if (hydrated === next) return;\n hydrated = next;\n options.onHydratedChange?.(next);\n };\n\n const report = (diagnostics: readonly WindowPersistenceDiagnostic[]) => {\n for (const d of diagnostics) {\n ports.errors.capture(new Error(`[overlays/persistence:${d.code}] ${d.message}`), {\n source: \"overlay-persistence\",\n level: d.level,\n code: d.code,\n ...(d.sessionKey ? { sessionKey: d.sessionKey } : {}),\n });\n }\n };\n const fail = (where: string) => (error: unknown) => ports.errors.capture(error, { source: \"overlay-persistence\", where });\n\n const scoped = (key: string): string => (port?.perPerson || identityKey === null ? key : identityScopedKey(identityKey, key));\n const workspaceKey = (): string => (scope === \"tab\" && workspaceId ? tabWorkspaceKey(workspaceId) : PERSON_WORKSPACE_KEY);\n\n /** Serialized per key; a version conflict re-reads the version and writes once more (latest intent wins). */\n const put = (key: string, value: unknown): void => {\n if (!port) return;\n const gen = generation;\n const run = async () => {\n if (gen !== generation) return;\n const expected = versions.get(key);\n try {\n const saved = await port.save(key, value, expected === undefined ? undefined : { expectedVersion: expected });\n versions.set(key, saved.version);\n } catch (error) {\n if (!isVersionConflict(error) || gen !== generation) throw error;\n const current = await port.load(key).catch(() => null);\n const saved = await port.save(key, value, { expectedVersion: current?.version ?? 0 });\n versions.set(key, saved.version);\n }\n };\n const next = (chains.get(key) ?? Promise.resolve()).then(run).catch(fail(`save ${key}`));\n chains.set(key, next);\n };\n const drop = (key: string): void => {\n if (!port) return;\n const next = (chains.get(key) ?? Promise.resolve())\n .then(() => port.remove(key))\n .then(() => void versions.delete(key))\n .catch(fail(`remove ${key}`));\n chains.set(key, next);\n };\n\n const saveStates = (state: SummonRootState): void => {\n const present = new Set<string>();\n for (const [key, entry] of Object.entries(state.overlayState.entries)) {\n const parsed = parseInstanceKey(key);\n if (!parsed || !persistsComponentState(parsed.overlayId)) continue;\n const sanitized = sanitizeJsonRecord(entry.values, null);\n if (sanitized.bytes > DEFAULT_WINDOW_DATA_BYTES) {\n report([\n {\n level: \"error\",\n code: \"state-too-large\",\n sessionKey: key,\n message: `Saved component state of ${key} is ${sanitized.bytes} bytes; limit is ${DEFAULT_WINDOW_DATA_BYTES}. Not saved.`,\n },\n ]);\n continue;\n }\n const storageKey = scoped(stateKey(key));\n present.add(storageKey);\n const fp = JSON.stringify(sanitized.data);\n if (stateFps.get(storageKey) === fp) continue;\n stateFps.set(storageKey, fp);\n put(storageKey, sanitized.data);\n }\n for (const storageKey of [...stateFps.keys()]) {\n if (present.has(storageKey)) continue;\n stateFps.delete(storageKey);\n drop(storageKey);\n }\n };\n\n const saveNow = (): void => {\n if (saveTimer) {\n clearTimeout(saveTimer);\n saveTimer = null;\n }\n if (!port || !writeSafe || identityKey === null) return;\n const state = store.getState();\n const savedAt = Math.max(Date.now(), lastSavedAt + 1);\n const { workspace, diagnostics } = serializeWindowWorkspace(state.windowManager, workspaceId ?? PERSON_WORKSPACE_KEY, savedAt);\n report(diagnostics);\n const fp = JSON.stringify(workspace.sessions.map((s) => ({ ...s, savedAt: 0 })));\n if (fp !== lastWorkspaceFp) {\n lastWorkspaceFp = fp;\n lastSavedAt = savedAt;\n put(scoped(workspaceKey()), workspace);\n if (scope === \"tab\" && workspaceId) {\n if (seedFromPerson) put(scoped(PERSON_WORKSPACE_KEY), workspace);\n local?.workspaces.index(identityKey, workspaceId);\n }\n }\n saveStates(state);\n };\n\n const scheduleSave = () => {\n if (saveTimer) clearTimeout(saveTimer);\n saveTimer = setTimeout(() => {\n saveTimer = null;\n saveNow();\n }, debounceMs);\n };\n\n const loadValue = async (key: string): Promise<StoredValue | null> => {\n if (!port) return null;\n try {\n return await port.load(key);\n } catch (error) {\n // The fast tier missed and the warm tier is slow: wait for the real answer. Writes are\n // gated until it arrives, so nothing unknown is overwritten.\n if (isLoadTimeout(error)) return error.pending;\n throw error;\n }\n };\n\n const teardown = (): void => {\n generation += 1;\n writeSafe = false;\n setHydrated(false);\n if (saveTimer) {\n clearTimeout(saveTimer);\n saveTimer = null;\n }\n const state = store.getState();\n const identities = new Map<string, { overlayId: string; instanceId: string }>();\n for (const entry of Object.values(state.windowManager.windows)) {\n if (entry.persistence) {\n const { overlayId, instanceId } = entry.persistence;\n identities.set(windowSessionKey(overlayId, instanceId), { overlayId, instanceId });\n }\n }\n for (const session of Object.values(state.windowManager.pendingRestores)) {\n identities.set(session.sessionKey, { overlayId: session.overlayId, instanceId: session.instanceId });\n }\n for (const identity of identities.values()) store.dispatch(markWindowClosing(identity));\n store.dispatch(closeAllOverlays());\n store.dispatch(clearWindowPersistenceState());\n // keepAlive \"restore\" values survive a close by design — never into another identity.\n for (const key of Object.keys(store.getState().overlayState.entries)) store.dispatch(clearOverlayState({ key: key as InstanceKey }));\n // Account teardown closes are not the next identity's intent.\n closedExact.clear();\n closedOverlay.clear();\n closedAll = false;\n versions.clear();\n stateFps.clear();\n lastWorkspaceFp = null;\n };\n\n const liveWindowFor = (windows: Record<string, WindowEntry>, overlayId: string, instanceId: string): WindowEntry | undefined =>\n Object.values(windows).find(\n (entry) => entry.persistence?.overlayId === overlayId && entry.persistence.instanceId === instanceId && !entry.persistence.closing,\n );\n\n /** Restored geometry for a window that is already registered (the link opened it first). */\n const applyGeometry = (entry: WindowEntry, session: HydratedWindowSession, viewport: { width: number; height: number }) => {\n if (entry.state !== \"windowed\") store.dispatch(restoreWindow(entry.id));\n store.dispatch(updateWindowRect({ id: entry.id, rect: session.state === \"minimized\" ? session.windowedRect : session.renderRect }));\n if (session.state === \"maximized\") store.dispatch(maximizeWindow(entry.id));\n else if (session.state === \"minimized\") {\n store.dispatch(minimizeWindow({ id: entry.id, viewportWidth: viewport.width, viewportHeight: viewport.height }));\n }\n };\n\n const loadIdentity = async (key: string): Promise<void> => {\n if (!port) return;\n const gen = generation;\n if (scope === \"tab\" && local) workspaceId ??= local.workspaces.currentId();\n else workspaceId = null;\n\n // One-read boot: a store that can answer everything at once is asked once.\n const all = port.loadAll ? await port.loadAll() : null;\n const bootValue = async (k: string): Promise<StoredValue | null> => (all ? (all.get(k) ?? null) : loadValue(k));\n\n const ownKey = scoped(workspaceKey());\n let stored = await bootValue(ownKey);\n let expectedWorkspaceId: string | undefined = scope === \"tab\" && workspaceId ? workspaceId : undefined;\n if (stored) versions.set(ownKey, stored.version);\n // The workspace already saved under THIS key: an unchanged first snapshot writes nothing.\n // (A tab seeded from the person's workspace below has no own row yet, so it still writes.)\n let storedUnderOwnKey = stored !== null;\n if (!stored && scope === \"tab\" && seedFromPerson) {\n storedUnderOwnKey = false;\n const personKey = scoped(PERSON_WORKSPACE_KEY);\n stored = await bootValue(personKey);\n if (stored) versions.set(personKey, stored.version);\n expectedWorkspaceId = undefined;\n }\n const stateKeys = all ? [...all.keys()].sort() : port.list ? await port.list(scoped(STATE_KEY_PREFIX)) : null;\n if (gen !== generation || identityKey !== key) return;\n\n const viewport =\n options.viewport?.() ??\n (() => {\n const { vw, vh } = safeViewportDims();\n return { width: vw, height: vh };\n })();\n const result = hydrateWindowWorkspace(stored?.value ?? null, viewport, expectedWorkspaceId);\n report(result.diagnostics);\n const sessions = result.sessions.filter(\n (s) => !closedAll && !closedOverlay.has(s.overlayId) && !closedExact.has(s.sessionKey),\n );\n\n // Saved component state, loaded BEFORE any instance opens so it mounts with its values.\n const prefix = scoped(STATE_KEY_PREFIX);\n const candidates = stateKeys\n ? stateKeys.filter((k) => k.startsWith(prefix)).map((k) => k.slice(prefix.length))\n : sessions.map((s) => s.sessionKey);\n const loadedStates = await Promise.all(\n candidates.map(async (instance) => [instance, await bootValue(scoped(stateKey(instance))).catch(() => null)] as const),\n );\n if (gen !== generation || identityKey !== key) return;\n\n const before = store.getState();\n const restoredKeys = new Set(sessions.map((s) => s.sessionKey));\n const stateEntries: Record<string, { values: Record<string, unknown> }> = {};\n for (const [instance, value] of loadedStates) {\n const parsed = parseInstanceKey(instance);\n if (!parsed || !value || !isRecord(value.value)) continue;\n const storageKey = scoped(stateKey(instance));\n const meta = getOverlayMeta(parsed.overlayId);\n if (!meta || !persistsComponentState(parsed.overlayId)) continue;\n const open = before.overlays.overlays[parsed.overlayId]?.[parsed.instanceId]?.isOpen === true;\n const wanted = meta.keepAlive === \"restore\" || restoredKeys.has(instance) || open;\n if (!wanted) {\n drop(storageKey); // a preserved window that did not come back: its state is dead\n continue;\n }\n versions.set(storageKey, value.version);\n if (before.overlayState.entries[instance]) continue; // live values beat saved ones\n stateEntries[instance] = { values: value.value };\n stateFps.set(storageKey, JSON.stringify(value.value));\n }\n if (Object.keys(stateEntries).length > 0) store.dispatch(hydrateOverlayState({ entries: stateEntries }));\n\n const live: [WindowEntry, HydratedWindowSession][] = [];\n const staged: HydratedWindowSession[] = [];\n for (const session of sessions) {\n const entry = liveWindowFor(before.windowManager.windows, session.overlayId, session.instanceId);\n if (entry) live.push([entry, session]);\n else staged.push(session);\n }\n store.dispatch(hydrateWindowSessions({ sessions: staged, viewportWidth: viewport.width, viewportHeight: viewport.height }));\n for (const [entry, session] of live) applyGeometry(entry, session, viewport);\n for (const session of staged) {\n // Already open (a link got there first): its data stands; only geometry was staged.\n if (before.overlays.overlays[session.overlayId]?.[session.instanceId]?.isOpen) continue;\n openRegisteredOverlay(store.dispatch, session.overlayId, session.instanceId, session.data);\n }\n\n lastWorkspaceFp =\n stored && storedUnderOwnKey && isRecord(stored.value) && Array.isArray(stored.value.sessions)\n ? JSON.stringify((stored.value.sessions as Record<string, unknown>[]).map((s) => ({ ...s, savedAt: 0 })))\n : null;\n lastSavedAt = stored && isRecord(stored.value) && typeof stored.value.savedAt === \"number\" ? stored.value.savedAt : 0;\n writeSafe = true;\n setHydrated(true);\n // Let restored windows register, then take the normalized first snapshot (also records an\n // authoritative empty workspace on a miss).\n setTimeout(() => {\n if (gen !== generation) return;\n saveNow();\n closedExact.clear();\n closedOverlay.clear();\n closedAll = false;\n }, 0);\n };\n\n const onIdentity = (): void => {\n const current = ports.identity.current();\n if (!current.ready) {\n if (identityKey !== null) teardown();\n identityKey = null;\n return;\n }\n if (current.key === identityKey) return;\n const changed = identityKey !== null;\n if (changed) teardown();\n else generation += 1;\n identityKey = current.key;\n writeSafe = false;\n setHydrated(false);\n const key = current.key;\n // A swap waits one task so the previous identity's windows unmount before anything loads.\n const wait = changed ? new Promise<void>((resolve) => setTimeout(resolve, 0)) : Promise.resolve();\n void wait\n .then(() => loadIdentity(key))\n .catch((error: unknown) => {\n fail(\"load\")(error);\n // A failed load is a completed load: the person keeps working; writes stay gated for\n // this identity so nothing unknown is overwritten.\n if (identityKey === key) setHydrated(true);\n });\n };\n\n return {\n get hydrated() {\n return hydrated;\n },\n flush: saveNow,\n start() {\n if (!port) return;\n cleanups.push(ports.identity.subscribe(onIdentity));\n cleanups.push(\n registerCloseFlusher((event) => {\n if (writeSafe) {\n saveNow();\n return;\n }\n for (const intent of event.intents) {\n if (intent.scope === \"all\") closedAll = true;\n else if (intent.scope === \"overlay\") closedOverlay.add(intent.overlayId);\n else closedExact.add(windowSessionKey(intent.overlayId, intent.instanceId));\n }\n }),\n );\n let previous = store.getState();\n cleanups.push(\n store.subscribe(() => {\n const next = store.getState();\n const changed = next.windowManager !== previous.windowManager || next.overlayState !== previous.overlayState;\n previous = next;\n if (changed && writeSafe) scheduleSave();\n }),\n );\n if (typeof window !== \"undefined\") {\n const renew = () => {\n if (workspaceId) local?.workspaces.renew(workspaceId);\n };\n const onPageHide = () => {\n saveNow();\n if (workspaceId) local?.workspaces.release(workspaceId);\n };\n const onVisibility = () => {\n if (document.visibilityState === \"hidden\") saveNow();\n else renew();\n };\n window.addEventListener(\"pagehide\", onPageHide);\n window.addEventListener(\"pageshow\", renew);\n window.addEventListener(\"focus\", renew);\n document.addEventListener(\"visibilitychange\", onVisibility);\n const sweep = window.setInterval(() => store.dispatch(pruneStaleInstances({ olderThanMs: STALE_SWEEP_MS })), STALE_SWEEP_MS);\n cleanups.push(() => {\n window.removeEventListener(\"pagehide\", onPageHide);\n window.removeEventListener(\"pageshow\", renew);\n window.removeEventListener(\"focus\", renew);\n document.removeEventListener(\"visibilitychange\", onVisibility);\n window.clearInterval(sweep);\n });\n }\n onIdentity();\n },\n stop() {\n saveNow();\n generation += 1;\n writeSafe = false;\n if (saveTimer) clearTimeout(saveTimer);\n saveTimer = null;\n for (const cleanup of cleanups.splice(0)) cleanup();\n identityKey = null;\n },\n };\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type { SummonPorts } from \"@ai-matrx/summon\";\nimport { useSummonPorts, useSummonStore } from \"@ai-matrx/summon/react\";\nimport { createOverlayPersistenceController, type OverlayPersistenceOptions } from \"./controller\";\n\n/**\n * Turn persistence on for the nearest <SummonProvider> (reads `ports.persistence` and\n * `ports.identity`; inert when persistence is null). Mount ONCE. Returns whether the current\n * identity's saved layout has been applied.\n */\nexport function useOverlayPersistence(options: Omit<OverlayPersistenceOptions, \"onHydratedChange\"> = {}): { hydrated: boolean } {\n const store = useSummonStore();\n const ports = useSummonPorts();\n const [hydrated, setHydrated] = useState(false);\n const { scope, seedFromPerson, saveDebounceMs, viewport } = options;\n // Restart only when what persistence reads changes (the store, the persistence port, identity).\n // A host that swaps another port (the router port arrives after mount) must not re-run the boot\n // read: the controller reads the rest of the ports through this ref.\n const portsRef = useRef(ports);\n useEffect(() => {\n portsRef.current = ports;\n });\n const { persistence, identity } = ports;\n useEffect(() => {\n const view = {\n get identity() { return identity; },\n get persistence() { return persistence; },\n get router() { return portsRef.current.router; },\n get notify() { return portsRef.current.notify; },\n get errors() { return portsRef.current.errors; },\n get debug() { return portsRef.current.debug; },\n } as SummonPorts;\n const controller = createOverlayPersistenceController(store, view, {\n ...(scope === undefined ? {} : { scope }),\n ...(seedFromPerson === undefined ? {} : { seedFromPerson }),\n ...(saveDebounceMs === undefined ? {} : { saveDebounceMs }),\n ...(viewport === undefined ? {} : { viewport }),\n onHydratedChange: setHydrated,\n });\n controller.start();\n return () => controller.stop();\n }, [store, persistence, identity, scope, seedFromPerson, saveDebounceMs, viewport]);\n return { hydrated };\n}\n\nexport type OverlayPersistenceProps = Omit<OverlayPersistenceOptions, \"onHydratedChange\">;\n\n/** Component form of `useOverlayPersistence` — mount once inside <SummonProvider>. */\nexport function OverlayPersistence(props: OverlayPersistenceProps): null {\n useOverlayPersistence(props);\n return null;\n}\n"],"mappings":"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","names":["import_summon","isRecord","import_react"]}
|
package/dist/persistence.js
CHANGED
|
@@ -348,7 +348,7 @@ function createLocalPersistence(options = {}) {
|
|
|
348
348
|
import {
|
|
349
349
|
WINDOW_SESSION_SCHEMA_VERSION,
|
|
350
350
|
centerRectInViewport,
|
|
351
|
-
|
|
351
|
+
clampStoredRectToViewport,
|
|
352
352
|
defaultWindowIdFor,
|
|
353
353
|
getOverlayMeta,
|
|
354
354
|
traySlotRect,
|
|
@@ -630,7 +630,7 @@ function hydrateWindowWorkspace(raw, viewport, expectedWorkspaceId) {
|
|
|
630
630
|
const sessions = ordered.map((session, index) => {
|
|
631
631
|
const restoreDefaults = getOverlayMeta(session.overlayId)?.window?.restoreDefaults;
|
|
632
632
|
const slot = slotOf.get(session.sessionKey) ?? null;
|
|
633
|
-
const renderRect = session.state === "minimized" && slot !== null ? traySlotRect(slot, viewport.width, viewport.height, minimized.length) : session.state === "windowed" || session.state === "maximized" ?
|
|
633
|
+
const renderRect = session.state === "minimized" && slot !== null ? traySlotRect(slot, viewport.width, viewport.height, minimized.length) : session.state === "windowed" || session.state === "maximized" ? clampStoredRectToViewport(session.windowedRect, viewport) : fallbackRect(viewport);
|
|
634
634
|
return {
|
|
635
635
|
...session,
|
|
636
636
|
traySlot: slot,
|