@ai-matrx/summon 0.0.0-stage → 0.1.0

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +380 -2
  4. package/dist/closeBinding-C6raC3qJ.d.cts +20 -0
  5. package/dist/closeBinding-C6raC3qJ.d.ts +20 -0
  6. package/dist/dialog.cjs +60 -0
  7. package/dist/dialog.cjs.map +1 -0
  8. package/dist/dialog.d.cts +16 -0
  9. package/dist/dialog.d.ts +16 -0
  10. package/dist/dialog.js +38 -0
  11. package/dist/dialog.js.map +1 -0
  12. package/dist/errors-eJrKXq33.d.cts +30 -0
  13. package/dist/errors-eJrKXq33.d.ts +30 -0
  14. package/dist/handles.cjs +411 -0
  15. package/dist/handles.cjs.map +1 -0
  16. package/dist/handles.d.cts +166 -0
  17. package/dist/handles.d.ts +166 -0
  18. package/dist/handles.js +388 -0
  19. package/dist/handles.js.map +1 -0
  20. package/dist/index.cjs +2383 -0
  21. package/dist/index.cjs.map +1 -0
  22. package/dist/index.d.cts +1259 -0
  23. package/dist/index.d.ts +1259 -0
  24. package/dist/index.js +2363 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/lite.cjs +460 -0
  27. package/dist/lite.cjs.map +1 -0
  28. package/dist/lite.d.cts +56 -0
  29. package/dist/lite.d.ts +56 -0
  30. package/dist/lite.js +444 -0
  31. package/dist/lite.js.map +1 -0
  32. package/dist/next.cjs +61 -0
  33. package/dist/next.cjs.map +1 -0
  34. package/dist/next.d.cts +5 -0
  35. package/dist/next.d.ts +5 -0
  36. package/dist/next.js +39 -0
  37. package/dist/next.js.map +1 -0
  38. package/dist/persistence-data.cjs +143 -0
  39. package/dist/persistence-data.cjs.map +1 -0
  40. package/dist/persistence-data.d.cts +72 -0
  41. package/dist/persistence-data.d.ts +72 -0
  42. package/dist/persistence-data.js +120 -0
  43. package/dist/persistence-data.js.map +1 -0
  44. package/dist/persistence.cjs +1073 -0
  45. package/dist/persistence.cjs.map +1 -0
  46. package/dist/persistence.d.cts +236 -0
  47. package/dist/persistence.d.ts +236 -0
  48. package/dist/persistence.js +1077 -0
  49. package/dist/persistence.js.map +1 -0
  50. package/dist/react.cjs +733 -0
  51. package/dist/react.cjs.map +1 -0
  52. package/dist/react.d.cts +261 -0
  53. package/dist/react.d.ts +261 -0
  54. package/dist/react.js +718 -0
  55. package/dist/react.js.map +1 -0
  56. package/dist/sheet.cjs +71 -0
  57. package/dist/sheet.cjs.map +1 -0
  58. package/dist/sheet.d.cts +17 -0
  59. package/dist/sheet.d.ts +17 -0
  60. package/dist/sheet.js +49 -0
  61. package/dist/sheet.js.map +1 -0
  62. package/dist/styles.css +78 -0
  63. package/dist/testing.cjs +132 -0
  64. package/dist/testing.cjs.map +1 -0
  65. package/dist/testing.d.cts +44 -0
  66. package/dist/testing.d.ts +44 -0
  67. package/dist/testing.js +115 -0
  68. package/dist/testing.js.map +1 -0
  69. package/dist/url.cjs +362 -0
  70. package/dist/url.cjs.map +1 -0
  71. package/dist/url.d.cts +153 -0
  72. package/dist/url.d.ts +153 -0
  73. package/dist/url.js +352 -0
  74. package/dist/url.js.map +1 -0
  75. package/dist/window-host.cjs +123 -0
  76. package/dist/window-host.cjs.map +1 -0
  77. package/dist/window-host.d.cts +72 -0
  78. package/dist/window-host.d.ts +72 -0
  79. package/dist/window-host.js +104 -0
  80. package/dist/window-host.js.map +1 -0
  81. package/dist/window.cjs +3978 -0
  82. package/dist/window.cjs.map +1 -0
  83. package/dist/window.d.cts +796 -0
  84. package/dist/window.d.ts +796 -0
  85. package/dist/window.js +4003 -0
  86. package/dist/window.js.map +1 -0
  87. package/package.json +237 -4
@@ -0,0 +1,236 @@
1
+ import { OverlayPersistencePort, PersistedWindowSession, HydratedWindowSession, AnyOverlayMeta, WindowPreservation, WindowManagerState, SummonRootState, SummonPorts } from '@ai-matrx/summon';
2
+ export { L as LOAD_TIMEOUT_ERROR, a as PersistenceLoadTimeoutError, P as PersistenceVersionConflictError, V as VERSION_CONFLICT_ERROR, b as isLoadTimeout, i as isVersionConflict } from './errors-eJrKXq33.js';
3
+ import { Dispatch, UnknownAction } from '@reduxjs/toolkit';
4
+
5
+ /**
6
+ * The warm tier behind the local store: a tiny async key/value interface, implemented over raw
7
+ * IndexedDB (no Dexie) and in memory (tests, SSR, browsers without IndexedDB).
8
+ */
9
+ interface KeyValueBackend {
10
+ get(key: string): Promise<unknown>;
11
+ set(key: string, value: unknown): Promise<void>;
12
+ delete(key: string): Promise<void>;
13
+ /** Every key starting with `prefix`. */
14
+ keys(prefix: string): Promise<string[]>;
15
+ }
16
+ declare function createMemoryBackend(): KeyValueBackend & {
17
+ readonly data: Map<string, unknown>;
18
+ };
19
+ /**
20
+ * One object store in one database. The connection opens lazily on first use and is reused; a
21
+ * blocked/failed open rejects every call (the local store then lives on its synchronous mirror).
22
+ */
23
+ declare function createIndexedDbBackend(dbName?: string, storeName?: string): KeyValueBackend;
24
+
25
+ /**
26
+ * createLocalPersistence — an OverlayPersistencePort over the browser: a synchronous localStorage
27
+ * mirror (the fast, pagehide-safe tier) plus IndexedDB (the warm tier). Ported from matrx-frontend
28
+ * `localWindowSessionStore.ts` + `lib/sync/persistence/*` with the same safety:
29
+ *
30
+ * - write ordering: the mirror is written synchronously first; IndexedDB follows in a per-key
31
+ * queue under `navigator.locks` (cross-tab) when available. A mirror write that fails removes
32
+ * the old mirror, so a stale value never looks authoritative.
33
+ * - reads: a valid mirror answers at once; otherwise IndexedDB gets a 750 ms budget, after which
34
+ * load rejects with a PersistenceLoadTimeoutError carrying the still-pending answer.
35
+ * - per-tab workspaces (`workspaces`): sessionStorage id + 24 h lease; a duplicated tab (same
36
+ * sessionStorage, another live document holds the lease, not a reload) gets a fresh id; an
37
+ * index per identity caps workspaces at 5 and GC skips any workspace with a live lease.
38
+ * - identity isolation: keys arrive scoped (`<identityKey>/<key>`); `purgeIdentity` removes
39
+ * everything one identity stored, both tiers (the old store missed the mirror keys).
40
+ *
41
+ * All state lives in the store instance (no module state). Create ONE per app.
42
+ */
43
+
44
+ declare const DEFAULT_IDB_READ_BUDGET_MS = 750;
45
+ declare const WORKSPACE_LEASE_MS: number;
46
+ declare const MAX_WORKSPACES_PER_IDENTITY = 5;
47
+ /** The slice of the Web Storage API the store uses. */
48
+ interface StorageLike {
49
+ getItem(key: string): string | null;
50
+ setItem(key: string, value: string): void;
51
+ removeItem(key: string): void;
52
+ key(index: number): string | null;
53
+ readonly length: number;
54
+ }
55
+ /** The slice of `navigator.locks` the store uses. */
56
+ interface LocksLike {
57
+ request<T>(name: string, callback: () => Promise<T>): Promise<T>;
58
+ }
59
+ interface LocalPersistenceOptions {
60
+ /** Prefix of every localStorage key and the IndexedDB database name. Default "ai-matrx.overlays". */
61
+ readonly namespace?: string;
62
+ /** Warm tier. Default: IndexedDB when present, else in-memory. */
63
+ readonly backend?: KeyValueBackend;
64
+ /** Default: window.localStorage (absent → memory-only mirror is skipped). */
65
+ readonly storage?: StorageLike | null;
66
+ /** Default: window.sessionStorage. */
67
+ readonly session?: StorageLike | null;
68
+ /** Default: navigator.locks. */
69
+ readonly locks?: LocksLike | null;
70
+ readonly idbReadBudgetMs?: number;
71
+ /** Is this document a reload? Default: the Navigation Timing entry. */
72
+ readonly isReload?: () => boolean;
73
+ readonly now?: () => number;
74
+ }
75
+ interface LocalWorkspaces {
76
+ /** This tab's workspace id (stable across reloads, fresh for a duplicated tab). Claims its lease. */
77
+ currentId(): string;
78
+ /** Event-driven lease heartbeat (focus, pageshow, visible). */
79
+ renew(workspaceId: string): void;
80
+ /** Release the lease this document holds (pagehide). */
81
+ release(workspaceId: string): void;
82
+ /** Record use of a workspace for an identity; evicts the oldest beyond the cap (live leases spared). */
83
+ index(identityKey: string, workspaceId: string): void;
84
+ }
85
+ interface LocalOverlayPersistence extends OverlayPersistencePort {
86
+ readonly perPerson: false;
87
+ readonly workspaces: LocalWorkspaces;
88
+ list(prefix: string): Promise<readonly string[]>;
89
+ /** Remove everything stored under one identity (both tiers). */
90
+ purgeIdentity(identityKey: string): Promise<void>;
91
+ /** Resolves once every queued IndexedDB write has finished (tests, shutdown). */
92
+ idle(): Promise<void>;
93
+ }
94
+ declare function isLocalPersistence(port: OverlayPersistencePort | null | undefined): port is LocalOverlayPersistence;
95
+ declare function createLocalPersistence(options?: LocalPersistenceOptions): LocalOverlayPersistence;
96
+
97
+ /** Storage keys the orchestration writes (before identity scoping). */
98
+ declare const PERSON_WORKSPACE_KEY = "workspace";
99
+ declare const tabWorkspaceKey: (workspaceId: string) => string;
100
+ declare const STATE_KEY_PREFIX = "state:";
101
+ declare const stateKey: (instanceKey: string) => string;
102
+ /** `<identityKey>/<key>` for stores that are not per-person themselves. */
103
+ declare const identityScopedKey: (identityKey: string, key: string) => string;
104
+
105
+ /**
106
+ * The window workspace record: serialize the window manager into a compact JSON record and
107
+ * validate a stored one back into staged sessions. Ported from matrx-frontend
108
+ * `windowSessionSerialization.ts`; the old metadata table is now each definition's `window`
109
+ * options in the registry.
110
+ *
111
+ * DEFAULT DENY: a window is saved and restored only when its definition has `window.preservation`
112
+ * and is not `ephemeral`; only `preservation.dataKeys` of its data are kept; unknown overlay ids
113
+ * are rejected with a diagnostic. `window.restoreDefaults` is merged UNDER saved data on restore.
114
+ */
115
+
116
+ declare const WINDOW_WORKSPACE_SCHEMA_VERSION: 1;
117
+ declare const DEFAULT_WINDOW_DATA_BYTES: number;
118
+ declare const MAX_WINDOW_WORKSPACE_BYTES: number;
119
+ declare const MAX_PERSISTED_WINDOW_SESSIONS = 64;
120
+ interface PersistedWindowWorkspace {
121
+ schemaVersion: typeof WINDOW_WORKSPACE_SCHEMA_VERSION;
122
+ workspaceId: string;
123
+ savedAt: number;
124
+ sessions: PersistedWindowSession[];
125
+ }
126
+ type WindowPersistenceDiagnosticCode = "unsupported-data" | "window-data-too-large" | "workspace-too-large" | "invalid-workspace" | "invalid-session" | "unknown-overlay" | "preservation-disabled" | "state-too-large";
127
+ interface WindowPersistenceDiagnostic {
128
+ level: "warning" | "error";
129
+ code: WindowPersistenceDiagnosticCode;
130
+ sessionKey?: string;
131
+ message: string;
132
+ }
133
+ interface Preserved {
134
+ readonly meta: AnyOverlayMeta;
135
+ readonly preservation: WindowPreservation;
136
+ }
137
+ /** The definition's preservation, or null when the window is not preserved (default deny). */
138
+ declare function preservationFor(overlayId: string): Preserved | null;
139
+ interface JsonSanitizeResult {
140
+ data: Record<string, unknown>;
141
+ droppedUnsupported: boolean;
142
+ bytes: number;
143
+ }
144
+ /**
145
+ * Copy `allowedKeys` (all keys when `null`) into plain JSON. Functions, symbols, undefined and
146
+ * circular references are dropped; BigInt becomes text; class instances are dropped.
147
+ */
148
+ declare function sanitizeJsonRecord(value: unknown, allowedKeys: readonly string[] | null): JsonSanitizeResult;
149
+ /** Validate one stored session against the registry (default deny). */
150
+ declare function readSession(value: unknown, diagnostics: WindowPersistenceDiagnostic[]): PersistedWindowSession | null;
151
+ declare function serializeWindowWorkspace(state: WindowManagerState, workspaceId: string, savedAt?: number): {
152
+ workspace: PersistedWindowWorkspace;
153
+ diagnostics: WindowPersistenceDiagnostic[];
154
+ };
155
+ /**
156
+ * Validate a stored workspace into staged sessions: rects clamped to the viewport, tray slots
157
+ * renumbered, `restoreDefaults` merged under the saved data. `expectedWorkspaceId` (tab scope)
158
+ * rejects a record written by another workspace.
159
+ */
160
+ declare function hydrateWindowWorkspace(raw: unknown, viewport: {
161
+ width: number;
162
+ height: number;
163
+ }, expectedWorkspaceId?: string): {
164
+ sessions: HydratedWindowSession[];
165
+ diagnostics: WindowPersistenceDiagnostic[];
166
+ };
167
+
168
+ /**
169
+ * The persistence orchestration, framework-free: one controller per overlays store. The React
170
+ * component (`OverlayPersistence`) only starts and stops it.
171
+ *
172
+ * - identity ready → load the workspace (tab or person scope) and saved component state →
173
+ * validate (default deny, see workspace.ts) → stage/apply → open what is not open yet.
174
+ * - window manager / overlayState change → save debounced 250 ms; flush on pagehide, hidden
175
+ * visibility and every close (close-lifecycle flusher). Writes stay gated until the load for
176
+ * the CURRENT identity has applied, so an unknown stored value is never overwritten.
177
+ * - identity change → close everything, clear staged persistence and component state, load the
178
+ * new identity. Nothing of one identity is ever written under another.
179
+ *
180
+ * LINK vs RESTORE (deterministic in both orders, for the same instance):
181
+ * the link's DATA wins, the restored GEOMETRY wins.
182
+ * - restore after link: an instance already open keeps its data (no re-open); its saved
183
+ * geometry is staged (window not registered yet → `registerWindow` takes the staged rect and
184
+ * merges staged data UNDER the live data) or applied to the live window directly.
185
+ * - link after restore: the link's open replaces the overlay's data; the staged/applied
186
+ * geometry is untouched by an open.
187
+ */
188
+
189
+ type PersistenceScope = "tab" | "person";
190
+ interface OverlayPersistenceOptions {
191
+ /**
192
+ * `tab`: one workspace per browser tab (the local store's default). `person`: one workspace per
193
+ * person (`workspace`) — windows follow the person across devices (the data adapter's default).
194
+ */
195
+ readonly scope?: PersistenceScope;
196
+ /** Tab scope: a tab with no workspace of its own starts from the person's last one. Default true. */
197
+ readonly seedFromPerson?: boolean;
198
+ readonly saveDebounceMs?: number;
199
+ /** Viewport used to clamp restored rects. Default: the sanitized window size. */
200
+ readonly viewport?: () => {
201
+ width: number;
202
+ height: number;
203
+ };
204
+ /** Called whenever `hydrated` flips. */
205
+ readonly onHydratedChange?: (hydrated: boolean) => void;
206
+ }
207
+ interface PersistenceStore {
208
+ getState(): SummonRootState;
209
+ dispatch: Dispatch<UnknownAction>;
210
+ subscribe(listener: () => void): () => void;
211
+ }
212
+ interface OverlayPersistenceController {
213
+ start(): void;
214
+ stop(): void;
215
+ /** Save now (skips unchanged records). */
216
+ flush(): void;
217
+ readonly hydrated: boolean;
218
+ }
219
+ declare const DEFAULT_SAVE_DEBOUNCE_MS = 250;
220
+ /** Component state is saved for definitions with keepAlive "restore" or a preserved window. */
221
+ declare function persistsComponentState(overlayId: string): boolean;
222
+ declare function createOverlayPersistenceController(store: PersistenceStore, ports: SummonPorts, options?: OverlayPersistenceOptions): OverlayPersistenceController;
223
+
224
+ /**
225
+ * Turn persistence on for the nearest <SummonProvider> (reads `ports.persistence` and
226
+ * `ports.identity`; inert when persistence is null). Mount ONCE. Returns whether the current
227
+ * identity's saved layout has been applied.
228
+ */
229
+ declare function useOverlayPersistence(options?: Omit<OverlayPersistenceOptions, "onHydratedChange">): {
230
+ hydrated: boolean;
231
+ };
232
+ type OverlayPersistenceProps = Omit<OverlayPersistenceOptions, "onHydratedChange">;
233
+ /** Component form of `useOverlayPersistence` — mount once inside <SummonProvider>. */
234
+ declare function OverlayPersistence(props: OverlayPersistenceProps): null;
235
+
236
+ export { DEFAULT_IDB_READ_BUDGET_MS, DEFAULT_SAVE_DEBOUNCE_MS, DEFAULT_WINDOW_DATA_BYTES, type KeyValueBackend, type LocalOverlayPersistence, type LocalPersistenceOptions, type LocalWorkspaces, type LocksLike, MAX_PERSISTED_WINDOW_SESSIONS, MAX_WINDOW_WORKSPACE_BYTES, MAX_WORKSPACES_PER_IDENTITY, OverlayPersistence, type OverlayPersistenceController, type OverlayPersistenceOptions, type OverlayPersistenceProps, PERSON_WORKSPACE_KEY, type PersistedWindowWorkspace, type PersistenceScope, type PersistenceStore, STATE_KEY_PREFIX, type StorageLike, WINDOW_WORKSPACE_SCHEMA_VERSION, WORKSPACE_LEASE_MS, type WindowPersistenceDiagnostic, type WindowPersistenceDiagnosticCode, createIndexedDbBackend, createLocalPersistence, createMemoryBackend, createOverlayPersistenceController, hydrateWindowWorkspace, identityScopedKey, isLocalPersistence, persistsComponentState, preservationFor, readSession, sanitizeJsonRecord, serializeWindowWorkspace, stateKey, tabWorkspaceKey, useOverlayPersistence };