@syncular/client 0.15.44 → 0.15.46

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 (59) hide show
  1. package/README.md +37 -5
  2. package/dist/browser-storage-persistence.d.ts +20 -0
  3. package/dist/browser-storage-persistence.js +34 -0
  4. package/dist/bun-database.d.ts +1 -1
  5. package/dist/bun-database.js +1 -1
  6. package/dist/client.d.ts +3 -3
  7. package/dist/client.js +6 -6
  8. package/dist/database.d.ts +1 -1
  9. package/dist/devtools.d.ts +1 -1
  10. package/dist/http.d.ts +6 -2
  11. package/dist/http.js +68 -1
  12. package/dist/index.d.ts +4 -2
  13. package/dist/index.js +4 -2
  14. package/dist/invalidation.d.ts +1 -1
  15. package/dist/leader-lock.d.ts +2 -2
  16. package/dist/multi-tab.js +1 -1
  17. package/dist/naming.d.ts +1 -1
  18. package/dist/naming.js +1 -1
  19. package/dist/node-database.js +1 -1
  20. package/dist/query-guard.d.ts +1 -1
  21. package/dist/query-guard.js +1 -1
  22. package/dist/remote.d.ts +76 -0
  23. package/dist/remote.js +441 -0
  24. package/dist/schema.d.ts +3 -3
  25. package/dist/sql-tag.d.ts +1 -1
  26. package/dist/transport.d.ts +12 -1
  27. package/dist/transport.js +1 -1
  28. package/dist/wasm-database.d.ts +6 -4
  29. package/dist/wasm-database.js +13 -8
  30. package/dist/window.d.ts +1 -1
  31. package/dist/window.js +1 -1
  32. package/dist/worker-entry.js +1 -1
  33. package/dist/worker-host.d.ts +5 -5
  34. package/dist/worker-host.js +2 -2
  35. package/dist/worker-protocol.d.ts +3 -3
  36. package/dist/worker-protocol.js +1 -1
  37. package/package.json +3 -3
  38. package/src/browser-storage-persistence.ts +52 -0
  39. package/src/bun-database.ts +1 -1
  40. package/src/client.ts +6 -6
  41. package/src/database.ts +1 -1
  42. package/src/devtools.ts +1 -1
  43. package/src/http.ts +100 -8
  44. package/src/index.ts +4 -2
  45. package/src/invalidation.ts +1 -1
  46. package/src/leader-lock.ts +2 -2
  47. package/src/multi-tab.ts +1 -1
  48. package/src/naming.ts +1 -1
  49. package/src/node-database.ts +1 -1
  50. package/src/query-guard.ts +1 -1
  51. package/src/remote.ts +724 -0
  52. package/src/schema.ts +3 -3
  53. package/src/sql-tag.ts +1 -1
  54. package/src/transport.ts +20 -1
  55. package/src/wasm-database.ts +13 -8
  56. package/src/window.ts +1 -1
  57. package/src/worker-entry.ts +1 -1
  58. package/src/worker-host.ts +6 -6
  59. package/src/worker-protocol.ts +3 -3
package/src/schema.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Client schema IR (SPEC.md §2.4, §3.1) — the same shape the server
3
- * compiles, hand-written until codegen (B5) emits it. Drives local table
3
+ * compiles and is emitted by codegen. Drives local table
4
4
  * DDL, the generated row codec, mutation helpers, and the §3.3 purge
5
5
  * mapping (scope variable → local column).
6
6
  */
@@ -19,7 +19,7 @@ export interface ClientIndexSpec {
19
19
  readonly unique: boolean;
20
20
  }
21
21
 
22
- /** One client-local contentful FTS5 projection (RFC 0005). */
22
+ /** One client-local contentful FTS5 projection. */
23
23
  export interface ClientFtsIndexSpec {
24
24
  readonly name: string;
25
25
  readonly columns: readonly string[];
@@ -63,7 +63,7 @@ export interface CompiledClientTable {
63
63
  /**
64
64
  * Scope variable → the pattern's literal prefix (§3.1). A stored-scope
65
65
  * value `v` for this variable has scope key `prefix:v` — the invalidation
66
- * vocabulary (TODO 3.1 / DESIGN-eviction I2) and the delta-routing key.
66
+ * vocabulary and the delta-routing key.
67
67
  */
68
68
  readonly scopePrefixByVariable: ReadonlyMap<string, string>;
69
69
  /** Local secondary indexes to create on the mirror table (declaration
package/src/sql-tag.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The `sql` tagged template — the raw tier's composition helper
3
- * (DESIGN-queries.md I4). Structural injection safety: an interpolated
3
+ * Structural injection safety: an interpolated
4
4
  * value can only ever become a `?` bind parameter; SQL text can only enter
5
5
  * through the literal template, `sql.ident()` (allowlist-gated) or a loud
6
6
  * `sql.raw()`. This helper is deliberately dumb plumbing and stays that
package/src/transport.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Transport seams (REVISE B3): request/response bytes, segment download,
2
+ * Transport seams: request/response bytes, segment download,
3
3
  * and the realtime attach surface matching §8's client side. Tests use
4
4
  * loopback implementations that call the server library directly — the
5
5
  * loopback doctrine; HTTP/WebSocket bindings live in `./http`.
@@ -8,6 +8,25 @@
8
8
  /** One combined push+pull round trip: SSP2 request bytes → response bytes. */
9
9
  export type SyncTransport = (request: Uint8Array) => Promise<Uint8Array>;
10
10
 
11
+ /** One registered authoritative query or command request. */
12
+ export type RemoteOperationTransport = (
13
+ request: Uint8Array,
14
+ ) => Promise<Uint8Array>;
15
+
16
+ export interface RemoteOperationRealtimeHandlers {
17
+ onMessage(bytes: Uint8Array): void;
18
+ onClose?(): void;
19
+ }
20
+
21
+ export interface RemoteOperationRealtimeSocket {
22
+ send(bytes: Uint8Array): void;
23
+ close(): void;
24
+ }
25
+
26
+ export type RemoteOperationRealtimeConnector = (
27
+ handlers: RemoteOperationRealtimeHandlers,
28
+ ) => RemoteOperationRealtimeSocket | Promise<RemoteOperationRealtimeSocket>;
29
+
11
30
  export interface SegmentFetchRequest {
12
31
  readonly segmentId: string;
13
32
  readonly table: string;
@@ -1,8 +1,8 @@
1
1
  /**
2
- * `ClientDatabase` on @sqlite.org/sqlite-wasm (Direction decision 2,
3
- * 2026-07-03). Two modes, no ladder between them:
2
+ * `ClientDatabase` on @sqlite.org/sqlite-wasm. Two modes, no ladder between
3
+ * them:
4
4
  *
5
- * - `openPersistentWasmDatabase(name)` — THE persistent browser mode:
5
+ * - `openPersistentWasmDatabase(name)` — THE reload-persistent browser mode:
6
6
  * OPFS via the `opfs-sahpool` VFS, restricted to Web Worker contexts
7
7
  * because the whole client core runs in a worker by design. SAHPool
8
8
  * needs **no COOP/COEP headers and no SharedArrayBuffer** (it is built
@@ -10,7 +10,10 @@
10
10
  * proxy — the COOP/COEP requirement documented by sqlite-wasm applies
11
11
  * only to `oo1.OpfsDb`, which this binding no longer uses). Browsers
12
12
  * without OPFS are unsupported (support floor ~2023+): the factory
13
- * fails loud. Never IndexedDB, never a silent in-memory fallback.
13
+ * fails loud. Never IndexedDB, never a silent in-memory fallback. The
14
+ * browser's separate origin-eviction policy is exposed from the root package
15
+ * by `checkBrowserStoragePersistence` and
16
+ * `requestBrowserStoragePersistence`.
14
17
  * - `openWasmDatabase()` — EXPLICIT ephemeral: an in-memory database for
15
18
  * tests, demos and SSR. Nothing survives a reload, on purpose.
16
19
  *
@@ -184,7 +187,7 @@ function initSqlite3(): Promise<Sqlite3Static> {
184
187
  * EXPLICIT ephemeral mode: an in-memory sqlite-wasm database. For tests,
185
188
  * demos and SSR only — nothing persists. The persistent mode is
186
189
  * `openPersistentWasmDatabase` inside a worker; there is no fallback from
187
- * one to the other (Direction decision 2).
190
+ * one to the other.
188
191
  */
189
192
  export async function openWasmDatabase(): Promise<ClientDatabase> {
190
193
  const sqlite3 = await initSqlite3();
@@ -238,14 +241,16 @@ function opfsSahPoolError(error: unknown, directory: string): ClientSyncError {
238
241
  }
239
242
 
240
243
  /**
241
- * THE persistent browser mode: a named database on OPFS via the
244
+ * THE reload-persistent browser mode: a named database on OPFS via the
242
245
  * `opfs-sahpool` VFS. Worker-context only — not because SAHPool requires
243
246
  * it (it uses `FileSystemSyncAccessHandle`, no `Atomics.wait`, and could
244
247
  * technically run on the main thread), but because the persistent mode IS
245
- * whole-core-in-a-worker (REVISE Direction decision 2, 2026-07-03) and
248
+ * whole-core-in-a-worker and
246
249
  * this factory enforces that decision. No COOP/COEP headers required.
247
250
  *
248
- * Support floor: no OPFS → a loud `ClientSyncError`, never a fallback.
251
+ * Support floor: no OPFS → a loud `ClientSyncError`, never a fallback. This
252
+ * factory cannot request eviction-resistant origin storage because that API
253
+ * belongs to the page's Window context.
249
254
  */
250
255
  export async function openPersistentWasmDatabase(
251
256
  name: string,
package/src/window.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Windowed subscriptions (SPEC.md §4.8 / DESIGN-eviction.md W1).
2
+ * Windowed subscriptions (SPEC.md §4.8).
3
3
  *
4
4
  * A window is a partial local replica keyed by scope VALUES: the client
5
5
  * holds rows for a chosen set of units (one scope value each) of a window
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Worker-side bootstrap (Direction decision 2): constructs the WHOLE
2
+ * Worker-side bootstrap: constructs the WHOLE
3
3
  * client core — SyncClient + transports + realtime + SQLite — inside the
4
4
  * worker and serves the `worker-protocol` RPC over postMessage.
5
5
  *
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Main-thread side of the worker mode (Direction decision 2) and the
3
- * multi-tab topology (TODO 3.2, REVISE B3).
2
+ * Main-thread side of the worker mode and the
3
+ * multi-tab topology.
4
4
  *
5
5
  * `createSyncClientHandle` acquires the Web Locks leader lock and, when it
6
6
  * wins, spawns the worker running the WHOLE core — so exactly one core runs
@@ -8,7 +8,7 @@
8
8
  * holding the lock). The returned {@link SyncClientHandle} is a thin, fully
9
9
  * async proxy over the `worker-protocol` RPC.
10
10
  *
11
- * Multi-tab is the DEFAULT (RFC 0002 §2.4 the follower path is
11
+ * Multi-tab is the DEFAULT. The follower path is
12
12
  * conformance-covered): a tab that LOSES the election becomes a FOLLOWER
13
13
  * (`role === 'follower'`) that proxies every call to the leader tab over a
14
14
  * BroadcastChannel (see `multi-tab.ts`). When the leader tab closes, its
@@ -181,7 +181,7 @@ export interface SyncClientHandleConfig {
181
181
  /** Shared by default; isolated derives the database/lock/channel tuple. */
182
182
  readonly replica?: BrowserReplicaMode;
183
183
  /**
184
- * Multi-tab followers (TODO 3.2). On by default: a tab that loses the
184
+ * Multi-tab followers. On by default: a tab that loses the
185
185
  * leader election becomes a FOLLOWER that proxies to the leader over a
186
186
  * BroadcastChannel, and contests + promotes when the leader closes. Set
187
187
  * false for the single-tab contract — the loser is a dead
@@ -318,7 +318,7 @@ export class SyncClientHandle {
318
318
  this.#diagnostics = internals.diagnostics;
319
319
  this.#roleListeners = internals.roleListeners ?? new Set();
320
320
  this.#leadershipListeners = internals.leadershipListeners ?? new Set();
321
- // RFC 0002 §3.2: console introspection a no-op outside a dev page.
321
+ // Console introspection is a no-op outside a dev page.
322
322
  this.#devtoolsUnregister = registerDevtools({
323
323
  kind: 'handle',
324
324
  ref: this,
@@ -401,7 +401,7 @@ export class SyncClientHandle {
401
401
  }
402
402
 
403
403
  /**
404
- * TODO 3.1 / I1: subscribe to fine-grained invalidation the identical
404
+ * Subscribe to fine-grained invalidation. The identical
405
405
  * surface as `SyncClient.onInvalidate`, so React bindings target one
406
406
  * interface across direct, worker-leader, and follower modes. Returns an
407
407
  * unsubscribe function.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The worker RPC protocol (Direction decision 2, 2026-07-03): the whole
2
+ * The worker RPC protocol: the whole
3
3
  * client core runs in a Web Worker; the UI thread talks to it through
4
4
  * this thin, multiplexed postMessage protocol. Exactly SIX message types
5
5
  * (`init`, `call`, `ready`, `result`, `error`, `event`) — every logical
@@ -63,7 +63,7 @@ import type { WindowBase } from './window';
63
63
  // Client-local error codes (never wire codes; §10 stays server-owned)
64
64
  // ---------------------------------------------------------------------------
65
65
 
66
- /** The handle exists but this tab lost the leader election (TODO 3.2). */
66
+ /** The handle exists but this tab lost the leader election. */
67
67
  export const NOT_LEADER_CODE = 'client.not_leader';
68
68
  /** The worker (or its RPC channel) failed outside protocol semantics. */
69
69
  export const WORKER_FAILED_CODE = 'client.worker_failed';
@@ -76,7 +76,7 @@ export const WORKER_RESTART_REQUIRED_CODE = 'client.worker_restart_required';
76
76
 
77
77
  export type WorkerDatabaseInit =
78
78
  | {
79
- /** THE persistent mode: opfs-sahpool, named database. */
79
+ /** Reload-persistent OPFS mode; origin eviction policy stays page-owned. */
80
80
  readonly mode: 'persistent';
81
81
  readonly name: string;
82
82
  /** Optional pool directory override (default `.syncular/<name>`). */