@syncular/client 0.1.2 → 0.2.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 (233) hide show
  1. package/README.md +227 -709
  2. package/dist/apply.d.ts +80 -0
  3. package/dist/apply.js +301 -0
  4. package/dist/blob.d.ts +127 -0
  5. package/dist/blob.js +201 -0
  6. package/dist/bun-database.d.ts +22 -0
  7. package/dist/bun-database.js +61 -0
  8. package/dist/client.d.ts +320 -69
  9. package/dist/client.js +1627 -163
  10. package/dist/content-type.d.ts +2 -0
  11. package/dist/content-type.js +2 -0
  12. package/dist/database.d.ts +35 -80
  13. package/dist/database.js +32 -947
  14. package/dist/encryption.d.ts +47 -0
  15. package/dist/encryption.js +75 -0
  16. package/dist/errors.d.ts +8 -22
  17. package/dist/errors.js +10 -207
  18. package/dist/http.d.ts +32 -0
  19. package/dist/http.js +196 -0
  20. package/dist/index.d.ts +28 -16
  21. package/dist/index.js +25 -12
  22. package/dist/invalidation.d.ts +69 -0
  23. package/dist/invalidation.js +84 -0
  24. package/dist/leader-lock.d.ts +28 -0
  25. package/dist/leader-lock.js +38 -0
  26. package/dist/multi-tab.d.ts +134 -0
  27. package/dist/multi-tab.js +399 -0
  28. package/dist/node-database.d.ts +41 -0
  29. package/dist/node-database.js +133 -0
  30. package/dist/outbox.d.ts +56 -0
  31. package/dist/outbox.js +140 -0
  32. package/dist/schema.d.ts +107 -0
  33. package/dist/schema.js +267 -0
  34. package/dist/state.d.ts +40 -0
  35. package/dist/state.js +77 -0
  36. package/dist/transport.d.ts +44 -0
  37. package/dist/transport.js +7 -0
  38. package/dist/wasm-database.d.ts +30 -0
  39. package/dist/wasm-database.js +170 -0
  40. package/dist/window.d.ts +64 -0
  41. package/dist/window.js +0 -0
  42. package/dist/worker-entry.d.ts +16 -2
  43. package/dist/worker-entry.js +300 -456
  44. package/dist/worker-host.d.ts +174 -0
  45. package/dist/worker-host.js +536 -0
  46. package/dist/worker-protocol.d.ts +173 -61
  47. package/dist/worker-protocol.js +7 -16
  48. package/package.json +45 -112
  49. package/src/apply.ts +435 -0
  50. package/src/blob.ts +333 -0
  51. package/src/bun-database.ts +75 -0
  52. package/src/client.ts +2247 -277
  53. package/src/content-type.ts +2 -0
  54. package/src/database.ts +63 -1389
  55. package/src/encryption.ts +123 -0
  56. package/src/errors.ts +11 -265
  57. package/src/http.ts +254 -0
  58. package/src/index.ts +25 -20
  59. package/src/invalidation.ts +128 -0
  60. package/src/leader-lock.ts +68 -0
  61. package/src/multi-tab.ts +550 -0
  62. package/src/node-database.ts +180 -0
  63. package/src/outbox.ts +206 -0
  64. package/src/schema.ts +397 -0
  65. package/src/state.ts +126 -0
  66. package/src/transport.ts +52 -0
  67. package/src/wasm-database.ts +279 -0
  68. package/src/window.ts +0 -0
  69. package/src/worker-entry.ts +391 -545
  70. package/src/worker-host.ts +800 -0
  71. package/src/worker-protocol.ts +204 -99
  72. package/dist/auth-leases.d.ts +0 -11
  73. package/dist/auth-leases.d.ts.map +0 -1
  74. package/dist/auth-leases.js +0 -140
  75. package/dist/auth-leases.js.map +0 -1
  76. package/dist/blob-limits.d.ts +0 -15
  77. package/dist/blob-limits.d.ts.map +0 -1
  78. package/dist/blob-limits.js +0 -66
  79. package/dist/blob-limits.js.map +0 -1
  80. package/dist/bridge-client.d.ts +0 -69
  81. package/dist/bridge-client.d.ts.map +0 -1
  82. package/dist/bridge-client.js +0 -282
  83. package/dist/bridge-client.js.map +0 -1
  84. package/dist/client-config.d.ts +0 -6
  85. package/dist/client-config.d.ts.map +0 -1
  86. package/dist/client-config.js +0 -18
  87. package/dist/client-config.js.map +0 -1
  88. package/dist/client.d.ts.map +0 -1
  89. package/dist/client.js.map +0 -1
  90. package/dist/command-history.d.ts +0 -35
  91. package/dist/command-history.d.ts.map +0 -1
  92. package/dist/command-history.js +0 -378
  93. package/dist/command-history.js.map +0 -1
  94. package/dist/console-diagnostics.d.ts +0 -33
  95. package/dist/console-diagnostics.d.ts.map +0 -1
  96. package/dist/console-diagnostics.js +0 -496
  97. package/dist/console-diagnostics.js.map +0 -1
  98. package/dist/crdt-yjs/index.d.ts +0 -4
  99. package/dist/crdt-yjs/index.d.ts.map +0 -1
  100. package/dist/crdt-yjs/index.js +0 -4
  101. package/dist/crdt-yjs/index.js.map +0 -1
  102. package/dist/crdt-yjs/webview-host-facade.d.ts +0 -126
  103. package/dist/crdt-yjs/webview-host-facade.d.ts.map +0 -1
  104. package/dist/crdt-yjs/webview-host-facade.js +0 -284
  105. package/dist/crdt-yjs/webview-host-facade.js.map +0 -1
  106. package/dist/crdt-yjs/yjs-document-field-adapter.d.ts +0 -153
  107. package/dist/crdt-yjs/yjs-document-field-adapter.d.ts.map +0 -1
  108. package/dist/crdt-yjs/yjs-document-field-adapter.js +0 -406
  109. package/dist/crdt-yjs/yjs-document-field-adapter.js.map +0 -1
  110. package/dist/crdt-yjs/yjs-prosemirror-bridge.d.ts +0 -73
  111. package/dist/crdt-yjs/yjs-prosemirror-bridge.d.ts.map +0 -1
  112. package/dist/crdt-yjs/yjs-prosemirror-bridge.js +0 -169
  113. package/dist/crdt-yjs/yjs-prosemirror-bridge.js.map +0 -1
  114. package/dist/database.d.ts.map +0 -1
  115. package/dist/database.js.map +0 -1
  116. package/dist/diagnostics.d.ts +0 -10
  117. package/dist/diagnostics.d.ts.map +0 -1
  118. package/dist/diagnostics.js +0 -83
  119. package/dist/diagnostics.js.map +0 -1
  120. package/dist/errors.d.ts.map +0 -1
  121. package/dist/errors.js.map +0 -1
  122. package/dist/generated-bridge.d.ts +0 -365
  123. package/dist/generated-bridge.d.ts.map +0 -1
  124. package/dist/generated-bridge.js +0 -250
  125. package/dist/generated-bridge.js.map +0 -1
  126. package/dist/index.d.ts.map +0 -1
  127. package/dist/index.js.map +0 -1
  128. package/dist/mutations.d.ts +0 -72
  129. package/dist/mutations.d.ts.map +0 -1
  130. package/dist/mutations.js +0 -63
  131. package/dist/mutations.js.map +0 -1
  132. package/dist/network.d.ts +0 -3
  133. package/dist/network.d.ts.map +0 -1
  134. package/dist/network.js +0 -17
  135. package/dist/network.js.map +0 -1
  136. package/dist/react/index.d.ts +0 -169
  137. package/dist/react/index.d.ts.map +0 -1
  138. package/dist/react/index.js +0 -628
  139. package/dist/react/index.js.map +0 -1
  140. package/dist/react-native/index.d.ts +0 -35
  141. package/dist/react-native/index.d.ts.map +0 -1
  142. package/dist/react-native/index.js +0 -49
  143. package/dist/react-native/index.js.map +0 -1
  144. package/dist/runtime-contract.d.ts +0 -13
  145. package/dist/runtime-contract.d.ts.map +0 -1
  146. package/dist/runtime-contract.js +0 -24
  147. package/dist/runtime-contract.js.map +0 -1
  148. package/dist/rust-client.d.ts +0 -106
  149. package/dist/rust-client.d.ts.map +0 -1
  150. package/dist/rust-client.js +0 -938
  151. package/dist/rust-client.js.map +0 -1
  152. package/dist/sentry.d.ts +0 -35
  153. package/dist/sentry.d.ts.map +0 -1
  154. package/dist/sentry.js +0 -155
  155. package/dist/sentry.js.map +0 -1
  156. package/dist/sql-safety.d.ts +0 -3
  157. package/dist/sql-safety.d.ts.map +0 -1
  158. package/dist/sql-safety.js +0 -62
  159. package/dist/sql-safety.js.map +0 -1
  160. package/dist/syncular-runtime-artifacts.json +0 -61
  161. package/dist/tauri/index.d.ts +0 -35
  162. package/dist/tauri/index.d.ts.map +0 -1
  163. package/dist/tauri/index.js +0 -114
  164. package/dist/tauri/index.js.map +0 -1
  165. package/dist/types.d.ts +0 -1096
  166. package/dist/types.d.ts.map +0 -1
  167. package/dist/types.js +0 -2
  168. package/dist/types.js.map +0 -1
  169. package/dist/wasm/.syncular-wasm-profile +0 -1
  170. package/dist/wasm/syncular-runtime-artifact.json +0 -21
  171. package/dist/wasm/syncular.d.ts +0 -207
  172. package/dist/wasm/syncular.js +0 -2341
  173. package/dist/wasm/syncular_bg.wasm +0 -0
  174. package/dist/wasm/syncular_bg.wasm.d.ts +0 -97
  175. package/dist/wasm-bindings/runtime-contract.d.ts +0 -22
  176. package/dist/wasm-bindings/runtime-contract.d.ts.map +0 -1
  177. package/dist/wasm-bindings/runtime-contract.js +0 -112
  178. package/dist/wasm-bindings/runtime-contract.js.map +0 -1
  179. package/dist/wasm-core/.syncular-wasm-profile +0 -1
  180. package/dist/wasm-core/syncular-runtime-artifact.json +0 -17
  181. package/dist/wasm-core/syncular.d.ts +0 -162
  182. package/dist/wasm-core/syncular.js +0 -1847
  183. package/dist/wasm-core/syncular_bg.wasm +0 -0
  184. package/dist/wasm-core/syncular_bg.wasm.d.ts +0 -77
  185. package/dist/wasm-perf/.syncular-wasm-profile +0 -1
  186. package/dist/wasm-perf/syncular-runtime-artifact.json +0 -21
  187. package/dist/wasm-perf/syncular.d.ts +0 -207
  188. package/dist/wasm-perf/syncular.js +0 -2341
  189. package/dist/wasm-perf/syncular_bg.wasm +0 -0
  190. package/dist/wasm-perf/syncular_bg.wasm.d.ts +0 -97
  191. package/dist/wasm-runtime.d.ts +0 -23
  192. package/dist/wasm-runtime.d.ts.map +0 -1
  193. package/dist/wasm-runtime.js +0 -69
  194. package/dist/wasm-runtime.js.map +0 -1
  195. package/dist/worker-client.d.ts +0 -123
  196. package/dist/worker-client.d.ts.map +0 -1
  197. package/dist/worker-client.js +0 -1735
  198. package/dist/worker-client.js.map +0 -1
  199. package/dist/worker-entry.d.ts.map +0 -1
  200. package/dist/worker-entry.js.map +0 -1
  201. package/dist/worker-protocol.d.ts.map +0 -1
  202. package/dist/worker-protocol.js.map +0 -1
  203. package/dist/worker-realtime.d.ts +0 -39
  204. package/dist/worker-realtime.d.ts.map +0 -1
  205. package/dist/worker-realtime.js +0 -677
  206. package/dist/worker-realtime.js.map +0 -1
  207. package/src/auth-leases.ts +0 -251
  208. package/src/blob-limits.ts +0 -98
  209. package/src/bridge-client.ts +0 -512
  210. package/src/client-config.ts +0 -29
  211. package/src/command-history.ts +0 -623
  212. package/src/console-diagnostics.ts +0 -617
  213. package/src/crdt-yjs/index.ts +0 -3
  214. package/src/crdt-yjs/webview-host-facade.ts +0 -477
  215. package/src/crdt-yjs/yjs-document-field-adapter.ts +0 -733
  216. package/src/crdt-yjs/yjs-prosemirror-bridge.ts +0 -272
  217. package/src/diagnostics.ts +0 -116
  218. package/src/generated-bridge.ts +0 -741
  219. package/src/mutations.ts +0 -168
  220. package/src/network.ts +0 -32
  221. package/src/react/index.ts +0 -1036
  222. package/src/react-native/index.ts +0 -152
  223. package/src/runtime-contract.ts +0 -48
  224. package/src/rust-client.ts +0 -1491
  225. package/src/sentry.ts +0 -215
  226. package/src/sql-safety.ts +0 -61
  227. package/src/tauri/index.ts +0 -211
  228. package/src/types.ts +0 -1397
  229. package/src/wasm-bindings/generated-wasm-bindings.d.ts +0 -70
  230. package/src/wasm-bindings/runtime-contract.ts +0 -158
  231. package/src/wasm-runtime.ts +0 -145
  232. package/src/worker-client.ts +0 -2289
  233. package/src/worker-realtime.ts +0 -843
@@ -0,0 +1,30 @@
1
+ import { type ClientDatabase } from './database.js';
2
+ /**
3
+ * EXPLICIT ephemeral mode: an in-memory sqlite-wasm database. For tests,
4
+ * demos and SSR only — nothing persists. The persistent mode is
5
+ * `openPersistentWasmDatabase` inside a worker; there is no fallback from
6
+ * one to the other (Direction decision 2).
7
+ */
8
+ export declare function openWasmDatabase(): Promise<ClientDatabase>;
9
+ export interface PersistentWasmDatabaseOptions {
10
+ /**
11
+ * OPFS directory holding this database's SAH pool (default
12
+ * `.syncular/<name>`). One pool per concurrent user: the sahpool VFS
13
+ * forbids two live instances on the same directory, so two cores on one
14
+ * origin (e.g. the demo's two panes) need distinct names/directories.
15
+ */
16
+ readonly directory?: string;
17
+ /** Initial SAH pool capacity (sqlite-wasm default: 6). */
18
+ readonly initialCapacity?: number;
19
+ }
20
+ /**
21
+ * THE persistent browser mode: a named database on OPFS via the
22
+ * `opfs-sahpool` VFS. Worker-context only — not because SAHPool requires
23
+ * it (it uses `FileSystemSyncAccessHandle`, no `Atomics.wait`, and could
24
+ * technically run on the main thread), but because the persistent mode IS
25
+ * whole-core-in-a-worker (REVISE Direction decision 2, 2026-07-03) and
26
+ * this factory enforces that decision. No COOP/COEP headers required.
27
+ *
28
+ * Support floor: no OPFS → a loud `ClientSyncError`, never a fallback.
29
+ */
30
+ export declare function openPersistentWasmDatabase(name: string, options?: PersistentWasmDatabaseOptions): Promise<ClientDatabase>;
@@ -0,0 +1,170 @@
1
+ /**
2
+ * `ClientDatabase` on @sqlite.org/sqlite-wasm (Direction decision 2,
3
+ * 2026-07-03). Two modes, no ladder between them:
4
+ *
5
+ * - `openPersistentWasmDatabase(name)` — THE persistent browser mode:
6
+ * OPFS via the `opfs-sahpool` VFS, restricted to Web Worker contexts
7
+ * because the whole client core runs in a worker by design. SAHPool
8
+ * needs **no COOP/COEP headers and no SharedArrayBuffer** (it is built
9
+ * on `FileSystemSyncAccessHandle`, not the Atomics-based `opfs` VFS
10
+ * proxy — the COOP/COEP requirement documented by sqlite-wasm applies
11
+ * only to `oo1.OpfsDb`, which this binding no longer uses). Browsers
12
+ * without OPFS are unsupported (support floor ~2023+): the factory
13
+ * fails loud. Never IndexedDB, never a silent in-memory fallback.
14
+ * - `openWasmDatabase()` — EXPLICIT ephemeral: an in-memory database for
15
+ * tests, demos and SSR. Nothing survives a reload, on purpose.
16
+ *
17
+ * A thin binding over the sqlite3 `oo1` API: opening is async (wasm
18
+ * init), everything after is synchronous like every other
19
+ * `ClientDatabase`. Browser-only — exercised by the demo, never imported
20
+ * by bun tests (subpath export `@syncular/client/wasm`).
21
+ */
22
+ import sqlite3InitModule from '@sqlite.org/sqlite-wasm';
23
+ import { assertImageAlias, runTransaction, } from './database.js';
24
+ import { ClientSyncError } from './errors.js';
25
+ function coerceParams(params) {
26
+ return params.map((value) => {
27
+ if (typeof value === 'boolean')
28
+ return value ? 1 : 0;
29
+ return value;
30
+ });
31
+ }
32
+ class WasmClientDatabase {
33
+ #db;
34
+ #sqlite3;
35
+ #tx = { depth: 0 };
36
+ constructor(db, sqlite3) {
37
+ this.#db = db;
38
+ this.#sqlite3 = sqlite3;
39
+ }
40
+ exec(sql, params = []) {
41
+ this.#db.exec({
42
+ sql,
43
+ ...(params.length > 0 ? { bind: coerceParams(params) } : {}),
44
+ rowMode: 'object',
45
+ resultRows: [],
46
+ });
47
+ }
48
+ query(sql, params = []) {
49
+ const resultRows = [];
50
+ this.#db.exec({
51
+ sql,
52
+ ...(params.length > 0 ? { bind: coerceParams(params) } : {}),
53
+ rowMode: 'object',
54
+ resultRows,
55
+ });
56
+ return resultRows;
57
+ }
58
+ transaction(fn) {
59
+ return runTransaction(this.#tx, (sql) => this.exec(sql), fn);
60
+ }
61
+ /**
62
+ * §5.3 image import at near-file-copy speed: attach an empty in-memory
63
+ * schema, then `sqlite3_deserialize` the image bytes into it (the
64
+ * documented sqlite-wasm import path — no OPFS round-trip, no SQL-level
65
+ * row shuttling before the single INSERT…SELECT the caller runs).
66
+ */
67
+ withSqliteImage(bytes, alias, fn) {
68
+ assertImageAlias(alias);
69
+ const pointer = this.#db.pointer;
70
+ if (pointer === undefined) {
71
+ throw new ClientSyncError('sync.invalid_request', 'sqlite-wasm database exposes no native handle for image import');
72
+ }
73
+ const { capi, wasm } = this.#sqlite3;
74
+ this.exec(`ATTACH ':memory:' AS ${alias}`);
75
+ try {
76
+ const data = wasm.allocFromTypedArray(bytes);
77
+ const rc = capi.sqlite3_deserialize(pointer, alias, data, bytes.length, bytes.length,
78
+ // FREEONCLOSE: sqlite owns the allocation; READONLY: images are
79
+ // immutable inputs (§5.1).
80
+ capi.SQLITE_DESERIALIZE_FREEONCLOSE | capi.SQLITE_DESERIALIZE_READONLY);
81
+ if (rc !== 0) {
82
+ throw new ClientSyncError('sync.invalid_request', `sqlite3_deserialize failed with code ${rc} (§5.3)`);
83
+ }
84
+ return fn();
85
+ }
86
+ finally {
87
+ this.exec(`DETACH ${alias}`);
88
+ }
89
+ }
90
+ close() {
91
+ this.#db.close();
92
+ }
93
+ }
94
+ let sqlite3Init;
95
+ function initSqlite3() {
96
+ if (sqlite3Init === undefined) {
97
+ const init = sqlite3InitModule;
98
+ sqlite3Init = init({
99
+ print: () => { },
100
+ printErr: () => { },
101
+ });
102
+ }
103
+ return sqlite3Init;
104
+ }
105
+ /**
106
+ * EXPLICIT ephemeral mode: an in-memory sqlite-wasm database. For tests,
107
+ * demos and SSR only — nothing persists. The persistent mode is
108
+ * `openPersistentWasmDatabase` inside a worker; there is no fallback from
109
+ * one to the other (Direction decision 2).
110
+ */
111
+ export async function openWasmDatabase() {
112
+ const sqlite3 = await initSqlite3();
113
+ return new WasmClientDatabase(new sqlite3.oo1.DB(':memory:', 'c'), sqlite3);
114
+ }
115
+ function inWorkerContext() {
116
+ const scope = globalThis;
117
+ return (typeof scope.WorkerGlobalScope === 'function' &&
118
+ globalThis instanceof scope.WorkerGlobalScope);
119
+ }
120
+ /** One registered VFS per pool directory, reused across opens. */
121
+ const sahPools = new Map();
122
+ /**
123
+ * THE persistent browser mode: a named database on OPFS via the
124
+ * `opfs-sahpool` VFS. Worker-context only — not because SAHPool requires
125
+ * it (it uses `FileSystemSyncAccessHandle`, no `Atomics.wait`, and could
126
+ * technically run on the main thread), but because the persistent mode IS
127
+ * whole-core-in-a-worker (REVISE Direction decision 2, 2026-07-03) and
128
+ * this factory enforces that decision. No COOP/COEP headers required.
129
+ *
130
+ * Support floor: no OPFS → a loud `ClientSyncError`, never a fallback.
131
+ */
132
+ export async function openPersistentWasmDatabase(name, options) {
133
+ if (!/^[A-Za-z0-9._-]+$/.test(name)) {
134
+ throw new ClientSyncError('sync.invalid_request', `invalid persistent database name ${JSON.stringify(name)}`);
135
+ }
136
+ if (!inWorkerContext()) {
137
+ throw new ClientSyncError('sync.invalid_request', 'openPersistentWasmDatabase() must run inside a Web Worker: the ' +
138
+ 'persistent mode is whole-core-in-a-worker by design (Direction ' +
139
+ 'decision 2, 2026-07-03). Use the worker handle from the main ' +
140
+ 'thread, or openWasmDatabase() for explicitly ephemeral state.');
141
+ }
142
+ const storage = globalThis.navigator?.storage;
143
+ if (typeof storage?.getDirectory !== 'function') {
144
+ throw new ClientSyncError('sync.invalid_request', 'OPFS is unavailable in this browser — the syncular support floor ' +
145
+ 'requires OPFS (~2023+ browsers). There is no IndexedDB or ' +
146
+ 'in-memory fallback for persistent mode.');
147
+ }
148
+ const sqlite3 = await initSqlite3();
149
+ const directory = options?.directory ?? `.syncular/${name}`;
150
+ let pool = sahPools.get(directory);
151
+ if (pool === undefined) {
152
+ pool = sqlite3
153
+ .installOpfsSAHPoolVfs({
154
+ // VFS registration names must be unique per directory.
155
+ name: `syncular-sahpool-${directory.replace(/[^A-Za-z0-9]+/g, '-')}`,
156
+ directory,
157
+ ...(options?.initialCapacity !== undefined
158
+ ? { initialCapacity: options.initialCapacity }
159
+ : {}),
160
+ })
161
+ .catch((error) => {
162
+ sahPools.delete(directory);
163
+ throw new ClientSyncError('sync.invalid_request', 'opfs-sahpool VFS failed to initialize (is OPFS available, and ' +
164
+ `is another live instance using directory ${JSON.stringify(directory)}?): ${String(error)}`);
165
+ });
166
+ sahPools.set(directory, pool);
167
+ }
168
+ const util = await pool;
169
+ return new WasmClientDatabase(new util.OpfsSAHPoolDb(`/${name}.db`), sqlite3);
170
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Windowed subscriptions (SPEC.md §4.8 / DESIGN-eviction.md W1).
3
+ *
4
+ * A window is a partial local replica keyed by scope VALUES: the client
5
+ * holds rows for a chosen set of units (one scope value each) of a window
6
+ * BASE (a table + one scope variable + the fixed remainder of the scope
7
+ * map). Windowing is a set-difference on §4 subscriptions — never a
8
+ * mutation of one — so it needs zero wire or server changes.
9
+ *
10
+ * This module owns the registry bookkeeping and the deterministic
11
+ * per-unit subscription-id derivation (§4.1 guidance). The eviction that
12
+ * fuses with a shrink (E1–E4) lives on the client, which holds the DB
13
+ * transaction and the invalidation choke point.
14
+ */
15
+ import { type ScopeMap } from '@syncular/core';
16
+ import type { ClientDatabase } from './database.js';
17
+ /**
18
+ * A window base: one table, one variable whose values are the window
19
+ * units, and any FIXED scopes every unit shares (other variables pinned
20
+ * to a constant set). `params` is host-opaque, carried onto every unit's
21
+ * subscription verbatim.
22
+ */
23
+ export interface WindowBase {
24
+ readonly table: string;
25
+ /** The scope variable whose values are the window units. */
26
+ readonly variable: string;
27
+ /** Scopes shared by every unit (other variables), if any. */
28
+ readonly fixedScopes?: ScopeMap;
29
+ readonly params?: string;
30
+ }
31
+ /** A live unit in the registry: its value and the subscription it drives. */
32
+ export interface WindowUnit {
33
+ readonly unit: string;
34
+ readonly subId: string;
35
+ }
36
+ /**
37
+ * A stable, server-opaque key for a window base — table + variable +
38
+ * canonical fixed scopes. Two `setWindow` calls with the same base
39
+ * address the same registry rows.
40
+ */
41
+ export declare function windowBaseKey(base: WindowBase): string;
42
+ /** The full requested scope map for one unit (fixed scopes + the unit). */
43
+ export declare function unitScopes(base: WindowBase, unit: string): ScopeMap;
44
+ /**
45
+ * Deterministic per-unit subscription id (§4.1 guidance):
46
+ * `w:<table>:<sha256(canonical scope map, §11.2)[0..16]>`. Ids are echoed
47
+ * not interpreted by the server (§4.1), so the exact hash is pure client
48
+ * convention; SHA-256 matches the SPEC's worked example.
49
+ */
50
+ export declare function deriveSubId(base: WindowBase, unit: string): Promise<string>;
51
+ /** Live units for a base, ordered by unit value. */
52
+ export declare function loadWindowUnits(db: ClientDatabase, baseKey: string): WindowUnit[];
53
+ export declare function insertWindowUnit(db: ClientDatabase, baseKey: string, unit: string, subId: string): void;
54
+ export declare function deleteWindowUnit(db: ClientDatabase, baseKey: string, unit: string): void;
55
+ /** Is a single scope value windowed-in for this base? (the oracle, I3) */
56
+ export declare function isUnitLive(db: ClientDatabase, baseKey: string, unit: string): boolean;
57
+ export interface PendingEviction {
58
+ readonly subId: string;
59
+ readonly table: string;
60
+ readonly effective: ScopeMap;
61
+ }
62
+ export declare function savePendingEviction(db: ClientDatabase, subId: string, table: string, effective: ScopeMap): void;
63
+ export declare function deletePendingEviction(db: ClientDatabase, subId: string): void;
64
+ export declare function loadPendingEvictions(db: ClientDatabase): PendingEviction[];
package/dist/window.js ADDED
Binary file
@@ -1,2 +1,16 @@
1
- export {};
2
- //# sourceMappingURL=worker-entry.d.ts.map
1
+ import type { ClientDatabase } from './database.js';
2
+ import type { RealtimeConnector, SegmentDownloader, SyncTransport } from './transport.js';
3
+ import { type WorkerInitConfig } from './worker-protocol.js';
4
+ export interface SyncWorkerOverrides {
5
+ /** Database factory indirection: tests inject bun:sqlite here. */
6
+ readonly openDatabase?: (config: WorkerInitConfig) => Promise<ClientDatabase> | ClientDatabase;
7
+ readonly createTransport?: (config: WorkerInitConfig) => SyncTransport;
8
+ readonly createSegments?: (config: WorkerInitConfig) => SegmentDownloader | undefined;
9
+ readonly createRealtime?: (config: WorkerInitConfig, clientId: string) => RealtimeConnector | undefined;
10
+ }
11
+ /**
12
+ * Register the RPC server on the current worker scope. Call this once
13
+ * from a worker entry script; the main-thread handle drives everything
14
+ * else through `init`/`call` messages.
15
+ */
16
+ export declare function startSyncWorker(overrides?: SyncWorkerOverrides): void;