@lix-js/sdk 0.16.1 → 0.17.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 (71) hide show
  1. package/README.md +162 -44
  2. package/dist/binding-types.d.ts +15 -5
  3. package/dist/binding.browser.d.ts +2 -0
  4. package/dist/binding.browser.js +14 -4
  5. package/dist/binding.node-wasm.d.ts +1 -1
  6. package/dist/binding.node-wasm.js +5 -3
  7. package/dist/binding.node.d.ts +2 -0
  8. package/dist/binding.node.js +34 -8
  9. package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
  10. package/dist/bundled-plugins/plugin_markdown.lixplugin +0 -0
  11. package/dist/compatibility.d.ts +6 -0
  12. package/dist/compatibility.js +6 -0
  13. package/dist/component-host/dispatch.d.ts +12 -0
  14. package/dist/component-host/dispatch.js +364 -0
  15. package/dist/component-host/index.d.ts +15 -0
  16. package/dist/component-host/index.js +84 -0
  17. package/dist/component-host/instrument.d.ts +6 -0
  18. package/dist/component-host/instrument.js +260 -0
  19. package/dist/conversion-provider.d.ts +4 -0
  20. package/dist/conversion-provider.js +20 -0
  21. package/dist/hosted-lix.js +1 -1
  22. package/dist/http-transport.d.ts +25 -0
  23. package/dist/http-transport.js +162 -0
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.js +1 -0
  26. package/dist/lix.d.ts +14 -9
  27. package/dist/lix.js +44 -9
  28. package/dist/migration-binding.browser.d.ts +33 -0
  29. package/dist/migration-binding.browser.js +46 -0
  30. package/dist/migration-binding.node.d.ts +6 -0
  31. package/dist/migration-binding.node.js +5 -0
  32. package/dist/migration-wasm/lix_js_sdk.d.ts +271 -0
  33. package/dist/migration-wasm/lix_js_sdk.js +1852 -0
  34. package/dist/migration-wasm/lix_js_sdk_bg.wasm +4 -0
  35. package/dist/migration-wasm/lix_js_sdk_bg.wasm.d.ts +101 -0
  36. package/dist/migration.d.ts +23 -0
  37. package/dist/migration.js +55 -0
  38. package/dist/open-lix.js +29 -18
  39. package/dist/open-progress.d.ts +10 -0
  40. package/dist/open-progress.js +59 -0
  41. package/dist/remote/client.d.ts +2 -1
  42. package/dist/remote/client.js +11 -1
  43. package/dist/result.d.ts +4 -3
  44. package/dist/result.js +3 -4
  45. package/dist/storage-adapter.d.ts +7 -1
  46. package/dist/storage-ownership.d.ts +5 -0
  47. package/dist/storage-ownership.js +4 -0
  48. package/dist/types.d.ts +65 -31
  49. package/dist/wasm/lix_js_sdk.d.ts +45 -16
  50. package/dist/wasm/lix_js_sdk.js +214 -60
  51. package/dist/wasm/lix_js_sdk_bg.wasm +2 -2
  52. package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +17 -9
  53. package/dist/worker/client.d.ts +12 -3
  54. package/dist/worker/client.js +95 -81
  55. package/dist/worker/durable-local-admission.d.ts +20 -0
  56. package/dist/worker/durable-local-admission.js +87 -0
  57. package/dist/worker/entry.shared.browser.d.ts +1 -0
  58. package/dist/worker/entry.shared.browser.js +211 -0
  59. package/dist/worker/factory.browser.d.ts +2 -0
  60. package/dist/worker/factory.browser.js +65 -1
  61. package/dist/worker/factory.node.d.ts +1 -0
  62. package/dist/worker/factory.node.js +3 -0
  63. package/dist/worker/host.d.ts +4 -2
  64. package/dist/worker/host.js +86 -32
  65. package/dist/worker/protocol.d.ts +25 -8
  66. package/dist/worker/protocol.js +25 -7
  67. package/dist/worker/shared-admission.d.ts +26 -0
  68. package/dist/worker/shared-admission.js +116 -0
  69. package/dist/worker/shared-engine.d.ts +34 -0
  70. package/dist/worker/shared-engine.js +194 -0
  71. package/package.json +21 -9
package/README.md CHANGED
@@ -22,16 +22,57 @@ console.log(result.rows[0]?.message);
22
22
  await lix.close();
23
23
  ```
24
24
 
25
+ For compiled plugin downloads, installation, updates, and uninstalling, see
26
+ [Installing and managing plugins](../../docs/plugins.md).
27
+
25
28
  ## Hosted lifecycle
26
29
 
27
- `openLix()` selects execution from the supplied locations:
30
+ ### Automatic upgrades and progress
31
+
32
+ Opening a supported older hosted repository automatically upgrades it on the
33
+ server. The SDK waits inside `openLix()`; applications do not implement migration
34
+ or retry logic. Concurrent opens share the server's upgrade operation.
35
+
36
+ Use `onProgress` to display status in either remote or partial-replica mode.
37
+ Authority upgrades emit `scope: "authority"` and `phase: "migrating"`, followed
38
+ by opening and completion. The source format and work totals may be unknown:
39
+ show “Upgrading repository” with an indeterminate indicator instead of inventing
40
+ a percentage. Progress callbacks are observational and cannot change the result
41
+ of opening.
42
+
43
+ ### Compatibility metadata
44
+
45
+ Raw HTTP integrations can obtain this SDK's protocol versions without loading
46
+ the engine:
47
+
48
+ ```ts
49
+ import { compatibility } from "@lix-js/sdk/compatibility";
50
+
51
+ const headers = {
52
+ "Lix-Server-Protocol-Version": String(compatibility.serverProtocolVersion),
53
+ "Lix-Sync-Protocol-Version": String(compatibility.syncProtocolVersion),
54
+ };
55
+ ```
56
+
57
+ The object also includes `storageFormatVersion`. It is generated from the Rust
58
+ engine constants during the SDK build. Source-checkout CI can use
59
+ `node scripts/compatibility.mjs` before building the SDK.
60
+
61
+ ### Execution modes
62
+
63
+ `openLix()` selects execution from storage and the explicit server mode:
28
64
 
29
65
  | Options | Behavior |
30
66
  | --- | --- |
31
67
  | Neither | Fresh in-memory repository |
32
68
  | `storage` | Local repository, initialized if empty |
33
- | `server` | Execute against an existing hosted repository |
34
- | `storage` and `server` | Local reads and writes with background synchronization |
69
+ | `server`, mode omitted or `"remote"` | Execute SQL remotely against an existing hosted repository; no local storage |
70
+ | `storage` and `server.mode: "partial_replica"` | Partial replica with on-demand sync; reads and writes whose dependencies are resident execute locally |
71
+
72
+ `server.mode` defaults to `"remote"`. Supplying storage requires explicitly opting
73
+ into `"partial_replica"`; remote mode rejects storage. Partial-replica mode requires
74
+ storage. These are the only supported server modes. `"replica"` may be added later;
75
+ the former `"sync"` mode is not an alias.
35
76
 
36
77
  Creation and deletion are explicit server operations:
37
78
 
@@ -64,9 +105,10 @@ execution do not require streaming uploads.
64
105
 
65
106
  ## Synchronized local repositories
66
107
 
67
- Combine storage with a server to keep a synchronized local replica. Reads and
68
- writes execute locally; background synchronization exchanges changes with the
69
- server:
108
+ Provide storage and set `server.mode: "partial_replica"` to create a
109
+ **partial replica with on-demand sync**. Opening loads bounded metadata. SQL fetches missing native inputs on
110
+ demand and retains them locally; background synchronization updates the loaded
111
+ working set:
70
112
 
71
113
  ```ts
72
114
  import { openLix } from "@lix-js/sdk";
@@ -75,6 +117,7 @@ import { OpfsStorage } from "@lix-js/storage-opfs";
75
117
  const lix = await openLix({
76
118
  storage: new OpfsStorage({ name: "acme" }),
77
119
  server: {
120
+ mode: "partial_replica",
78
121
  url: "https://example.com/lix/01936f4e-7b6c-7c3d-8f9a-123456789abc",
79
122
  headers: async () => ({
80
123
  Authorization: `Bearer ${await accessToken()}`,
@@ -84,43 +127,105 @@ const lix = await openLix({
84
127
  ```
85
128
 
86
129
  A successful mutation confirms a local commit; it does not confirm server
87
- acceptance. Pending commits upload in the background. Cached reads and local
88
- writes work offline; older history and binary content load when needed.
130
+ acceptance. Pending commits upload in the background. Covered reads and writes
131
+ whose dependencies are resident work offline, with immediate local visibility.
132
+ A statement requiring missing inputs needs a connection; missing data is never
133
+ silently treated as an empty result. Current data means the coherently applied
134
+ server state plus pending local writes.
135
+
136
+ Prefetch a view on hover using the same ordinary SELECT it will display:
137
+
138
+ ```ts
139
+ const sql = "SELECT content FROM lix_file WHERE path=$1";
140
+ const params = ["/notes.txt"];
141
+ await lix.execute(sql, params); // On hover: fetch missing read inputs.
142
+ const result = await lix.execute(sql, params); // On open: resident reads stay local.
143
+ ```
144
+
145
+ Use ordinary `execute()` for mutations. Reading a file does not promise that every
146
+ later write's validation or commit dependencies are resident; cold operations can
147
+ fetch additional inputs while connected.
148
+
89
149
  See [Collaboration and Sync](https://lix.dev/docs/collaboration-and-sync).
90
150
 
91
151
  ### Upgrading a local replica
92
152
 
93
- Keep the same storage name across SDK upgrades. For a supported older synchronized
94
- replica, Lix preserves its existing storage generation and bootstraps a separate
95
- generation from the same authoritative repository and account. The replacement
96
- becomes active only after bootstrap and validation succeed. Pending work and
97
- local-only rows remain in the preserved generation; they do not block opening the
98
- current server state. An upgrade requires a server connection and enough local
99
- storage for both generations.
153
+ Keep the same storage name across SDK upgrades. Opening an existing full replica
154
+ with `server.mode: "partial_replica"` requires an explicit conversion; normal opening does not download a
155
+ replacement repository. Run conversion while the storage has no open Lix handle:
156
+
157
+ ```ts
158
+ import { convertReplicaToPartial, openLix } from "@lix-js/sdk";
159
+
160
+ const storage = new OpfsStorage({ name: "acme" });
161
+ const server = {
162
+ mode: "partial_replica" as const,
163
+ url: "https://example.com/lix/01936f4e-7b6c-7c3d-8f9a-123456789abc",
164
+ headers: async () => ({ Authorization: `Bearer ${await accessToken()}` }),
165
+ };
166
+ await convertReplicaToPartial({ storage, server });
167
+ const lix = await openLix({ storage, server });
168
+ ```
169
+
170
+ Conversion authenticates the repository and account, preserves the original
171
+ storage generation, and publishes a separate partial replica only after its
172
+ required reconciliation and validation succeed. It can require time and extra
173
+ storage; measure it separately from ordinary opening. Unsupported pending work
174
+ returns an error with the original source preserved. Do not clear storage to
175
+ bypass that error.
176
+
177
+ If authority cleanup is interrupted after conversion, retry it explicitly while
178
+ storage is closed. Ordinary opening does not scan migration journals:
100
179
 
101
- Recovery is explicit and separate from opening:
180
+ ```ts
181
+ import { retryReplicaMigrationCleanup } from "@lix-js/sdk";
182
+ const completed = await retryReplicaMigrationCleanup({ storage, server });
183
+ ```
184
+
185
+ This returns the number of newly completed cleanup records; repeating a
186
+ successful cleanup returns zero. It preserves the active replica and retained
187
+ source generation.
188
+
189
+ For retained pre-native sources, explicit format migration can succeed while
190
+ partial conversion reports that recovery is required. Open the resulting local
191
+ recovery repository without `server`, then inspect and restore retained work:
102
192
 
103
193
  ```ts
104
- const sources = await lix.replicaRecoverySources();
105
- for (const source of sources.filter((source) => source.recoveryRequired)) {
106
- const exported = await lix.exportReplicaRecovery(source.id);
107
- // Save exported as JSON when the user requests a portable recovery copy.
108
- console.log(exported.unresolved);
109
-
110
- const receipt = await lix.recoverReplica(source.id);
111
- // Present these separate branches for review; the active branch is unchanged.
112
- console.log(receipt.branchIds, receipt.restoredRows, receipt.unresolved);
194
+ const recovery = await openLix({ storage });
195
+ try {
196
+ const sources = await recovery.replicaRecoverySources();
197
+ for (const source of sources.filter((source) => source.recoveryRequired)) {
198
+ const exported = await recovery.exportReplicaRecovery(source.id);
199
+ console.log(exported.unresolved); // Save a portable copy when needed.
200
+
201
+ const receipt = await recovery.recoverReplicaWithServer(source.id, server);
202
+ console.log(receipt.branchIds, receipt.restoredRows, receipt.unresolved);
203
+ }
204
+ } finally {
205
+ await recovery.close();
113
206
  }
114
207
  ```
115
208
 
209
+ `recoverReplicaWithServer()` authenticates the same repository and account and
210
+ fetches missing recovery history or chunks explicitly. It does not start a
211
+ background sync worker or upload restored branches. Dynamic headers and custom
212
+ fetch remain scoped to this operation in the browser. The native Node binding
213
+ supports headers and rejects custom fetch.
214
+
116
215
  `exportReplicaRecovery()` captures available logical rows, blob contents, and
117
- original branch/checkpoint coordinates. `recoverReplica()` restores supported
118
- tracked rows into separate recovery branches. It does not automatically publish
119
- local-only rows or merge recovered work into the active branch. Inspect
120
- `unresolved`: original history and any unavailable content remain in the retained
121
- source. A recovery receipt describes local restoration, not a server durability
122
- acknowledgement. Neither operation deletes the retained generation, and retries
123
- reuse recovery branch receipts rather than overwriting previously recovered work.
216
+ original branch/checkpoint coordinates. `recoverReplica()` performs local
217
+ restoration; its server variant can hydrate missing dependencies. Both restore
218
+ supported tracked rows into separate recovery branches without inheriting
219
+ unrelated active-branch rows. Inspect `unresolved`: unavailable history/content
220
+ and local-only rows remain in the retained source. Neither operation deletes
221
+ that source, and retries reuse durable recovery receipts.
222
+
223
+ A recovery receipt confirms local restoration, not server acceptance or
224
+ eligibility for partial conversion. Conversion of every retained pending branch
225
+ is still a release gate: restored additional branches and unresolved retained
226
+ sources must not be silently discarded or marked acknowledged. The current
227
+ selected-branch native reconciliation path does not establish that broader
228
+ migration guarantee.
124
229
 
125
230
  Recovery export currently allows up to 100,000 logical rows across all branches,
126
231
  64 MiB per blob, and 128 MiB of blob content in total. Unfinished upload parts
@@ -163,7 +268,8 @@ files.close();
163
268
  await lix.close();
164
269
  ```
165
270
 
166
- Without `storage`, remote mode uses the server for all persistence and does not
271
+ Remote mode is the default when `server.mode` is omitted. It rejects `storage`,
272
+ uses the server for all persistence and does not
167
273
  open a local engine. Dynamic headers are resolved for every request and
168
274
  observation reconnect. An injected `fetch` can route requests through a service
169
275
  binding or another authorized server-side transport.
@@ -290,18 +396,30 @@ try {
290
396
  - The package is ESM-only.
291
397
  - The package uses conditional ESM imports internally: Node.js resolves the
292
398
  native N-API binding, while browsers and other runtimes resolve the portable
293
- WebAssembly binding. Vite follows this split without consumer configuration.
399
+ WebAssembly binding. Vite resolves these conditional imports automatically.
400
+ Configure Vite to emit ES module workers because the Component compiler uses
401
+ top-level await:
402
+
403
+ ```js
404
+ // vite.config.js
405
+ export default { worker: { format: "es" } };
406
+ ```
294
407
  - If the native addon cannot load in Node.js, in-memory Lix instances fall back
295
- to the bundled WebAssembly engine. Filesystem storage and Component API v1
296
- plugin execution still require the native addon.
408
+ to the bundled WebAssembly engine. Filesystem storage still requires the native addon.
297
409
  - Every browser `openLix()` owns one dedicated worker, so database work does
298
410
  not block the page's main thread. Node.js uses the native binding's actor.
299
- - Node.js executes installed Component API v1 plugins with the Rust SDK's
300
- Wasmtime runtime. The browser binding currently opens without a component
301
- runtime: it can use ordinary Lix storage and SQL, but does not
302
- execute installed plugins. A browser Component host is a separate follow-up.
411
+ - Node.js and browsers execute installed Component API v2 plugins through the
412
+ same JavaScript Component host. The host adapts Component interfaces to the
413
+ platform's built-in WebAssembly runtime and connects them to Lix's shared Rust
414
+ host resources. Node.js retains its native engine and filesystem adapter;
415
+ the browser engine runs inside its dedicated worker.
416
+ - Components are compiled on first use. Each file actor gets an isolated guest
417
+ instance. Guest functions and loops check execution deadlines, and core memory
418
+ declarations are capped before instantiation. Unsupported memory forms are
419
+ rejected rather than executed without limits.
303
420
  - A page Content Security Policy only needs to permit the package's same-origin
304
- worker. WebAssembly compilation happens inside that worker, so the required
421
+ worker. Component bindings are generated as data URL modules and WebAssembly
422
+ compilation happens inside that worker, so the required
305
423
  permission can be scoped to the worker script's HTTP response instead of
306
424
  being allowed by the document:
307
425
 
@@ -310,11 +428,11 @@ try {
310
428
  Content-Security-Policy: default-src 'self'; script-src 'self'; worker-src 'self'
311
429
 
312
430
  # Lix worker response (Vite emits assets/entry.browser-<hash>.js)
313
- Content-Security-Policy: default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; connect-src 'self'
431
+ Content-Security-Policy: default-src 'none'; script-src 'self' data: 'wasm-unsafe-eval'; connect-src 'self'
314
432
  ```
315
433
 
316
434
  Hosts that apply one policy to every response can use
317
- `script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'` globally
435
+ `script-src 'self' data: 'wasm-unsafe-eval'; worker-src 'self'` globally
318
436
  instead. Worker-scoped headers keep those permissions out of the page.
319
437
 
320
438
  - SQL parameters use normal JavaScript values: `string`, finite `number`, `boolean`, `Uint8Array`, `null`, JSON-compatible arrays, and JSON-compatible plain objects.
@@ -334,7 +452,7 @@ npm run test:browser
334
452
 
335
453
  `npm run test:browser:production` additionally packs the SDK, installs the
336
454
  tarball into a minimal Vite app, makes a production build, and exercises SQL
337
- plus bundled-plugin archive loading in Chromium. It runs with both
455
+ plus bundled-plugin installation and CSV row extraction in Chromium. It runs with both
338
456
  worker-scoped and global strict CSP headers.
339
457
 
340
458
  Use `npm run build:wasm:dev` while iterating on the Rust bridge when release
@@ -1,3 +1,4 @@
1
+ import type { HttpTransport } from "./http-transport.js";
1
2
  import type { CommitSpan, CreateBranchOptions, CreateBranchReceipt, UndoReceipt, RedoReceipt, ExecuteOptions, LixBatchOptions, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, SwitchBranchOptions, SwitchBranchReceipt, LixTelemetrySpan, LixTelemetryParentContext, LixOpenProgress, LixOpenReport, ReplicaRecoverySource, ReplicaRecoveryExport, ReplicaRecoveryReceipt, OpenAnotherSessionOptions, ResultColumn } from "./types.js";
2
3
  import type { NativeLixValue } from "./value.js";
3
4
  import type { LixStorageProvider } from "./storage-adapter.js";
@@ -5,7 +6,7 @@ export type SyncServerBindingOptions = {
5
6
  url: string;
6
7
  headers: [string, string][];
7
8
  headerProvider?: () => Promise<[string, string][]>;
8
- fetch?: typeof fetch;
9
+ transport?: HttpTransport;
9
10
  };
10
11
  export type BindingExecuteResult = {
11
12
  statementIndex?: number;
@@ -45,14 +46,19 @@ export type LixBinding = {
45
46
  createHosted?(server: HostedServerBindingOptions): Promise<import("./types.js").HostedLix>;
46
47
  openReport?(): LixOpenReport | undefined;
47
48
  setTelemetryParent(parent?: TelemetryParentContext): void;
48
- openAnotherSession(options: OpenAnotherSessionOptions): Promise<LixBinding>;
49
+ openAnotherSession(options: OpenAnotherSessionOptions, telemetry?: TelemetryDispatch): Promise<LixBinding>;
49
50
  execute(sql: string, params: BindingParam[], options?: ExecuteOptions): Promise<BindingExecuteResult>;
50
- executeBatch(statements: BindingBatchStatement[], options?: LixBatchOptions): Promise<BindingExecuteResult[]>;
51
+ executeBatch(statements: BindingBatchStatement[], options?: LixBatchOptions): Promise<{
52
+ results: BindingExecuteResult[];
53
+ commit?: CommitSpan | null;
54
+ }>;
51
55
  observe(sql: string, params: BindingParam[]): Promise<ObserveEventsBinding>;
52
56
  beginTransaction(): Promise<LixTransactionBinding>;
53
57
  replicaRecoverySources(): Promise<ReplicaRecoverySource[]>;
54
58
  exportReplicaRecovery(id: string): Promise<ReplicaRecoveryExport>;
55
59
  recoverReplica(id: string): Promise<ReplicaRecoveryReceipt>;
60
+ recoverReplicaWithServer(id: string, server: SyncServerBindingOptions): Promise<ReplicaRecoveryReceipt>;
61
+ syncHealth(): Promise<import("./types.js").SyncHealth>;
56
62
  activeBranchId(): Promise<string>;
57
63
  activeAccountId(): Promise<string>;
58
64
  createBranch(options: CreateBranchOptions): Promise<CreateBranchReceipt>;
@@ -68,7 +74,9 @@ export type LixBinding = {
68
74
  };
69
75
  export type LixTransactionBinding = {
70
76
  execute(sql: string, params: BindingParam[], options?: ExecuteOptions): Promise<BindingExecuteResult>;
71
- commit(): Promise<void>;
77
+ commit(): Promise<{
78
+ commit?: CommitSpan | null;
79
+ }>;
72
80
  rollback(): Promise<void>;
73
81
  };
74
82
  export type ObserveEventsBinding = {
@@ -83,6 +91,8 @@ export type LixStorageProviderModule = {
83
91
  createLixStorageProvider(options: unknown): Promise<LixStorageProvider>;
84
92
  };
85
93
  export type LixStorageConfig = {
94
+ durability?: import("./types.js").Durability;
95
+ } & ({
86
96
  kind: "memory";
87
97
  } | {
88
98
  kind: "jsStorage";
@@ -92,7 +102,7 @@ export type LixStorageConfig = {
92
102
  kind: "filesystem";
93
103
  path: string;
94
104
  syncAllFiles: boolean;
95
- };
105
+ });
96
106
  export type HostedServerBindingOptions = {
97
107
  idempotencyKey?: string;
98
108
  url: string;
@@ -2,3 +2,5 @@ import type { LixStorageConfig, LixBinding, SyncServerBindingOptions, TelemetryD
2
2
  export declare function openLixBinding(storage: LixStorageConfig, telemetry?: TelemetryDispatch, telemetryParent?: TelemetryParentContext, server?: SyncServerBindingOptions, openProgress?: OpenProgressDispatch, snapshot?: ReadableStream<Uint8Array>): Promise<LixBinding>;
3
3
  export declare function createHostedBinding(server: import("./binding-types.js").HostedServerBindingOptions): Promise<import("./types.js").HostedLix>;
4
4
  export declare function deleteHostedBinding(server: import("./binding-types.js").HostedServerBindingOptions): Promise<void>;
5
+ export declare function convertReplicaBinding(storage: LixStorageConfig, server: SyncServerBindingOptions, branchId?: string): Promise<void>;
6
+ export declare function retryReplicaMigrationCleanupBinding(storage: LixStorageConfig, server: SyncServerBindingOptions): Promise<number>;
@@ -1,3 +1,4 @@
1
+ import { createComponentDispatch } from "./component-host/dispatch.js";
1
2
  import { initializeWasm } from "./wasm-init.js";
2
3
  import { restoreSnapshot } from "./snapshot-restore.js";
3
4
  // Generated before TypeScript compilation and emitted beside this module.
@@ -7,11 +8,12 @@ import { createHosted, deleteHosted, openJsStorage, openJsStorageFromSnapshot, o
7
8
  } from "./wasm/lix_js_sdk.js";
8
9
  export async function openLixBinding(storage, telemetry, telemetryParent, server, openProgress, snapshot) {
9
10
  await initializeWasm();
11
+ const componentDispatch = createComponentDispatch();
10
12
  switch (storage.kind) {
11
13
  case "memory":
12
14
  return (snapshot
13
- ? restoreSnapshot(snapshot, openMemoryFromSnapshot(telemetry, telemetryParent, openProgress))
14
- : openMemory(telemetry, telemetryParent, server, openProgress));
15
+ ? restoreSnapshot(snapshot, openMemoryFromSnapshot(telemetry, telemetryParent, openProgress, componentDispatch, storage.durability))
16
+ : openMemory(telemetry, telemetryParent, server, openProgress, componentDispatch, storage.durability));
15
17
  case "jsStorage": {
16
18
  const module = (await import(
17
19
  /* @vite-ignore */ storage.moduleUrl));
@@ -21,8 +23,8 @@ export async function openLixBinding(storage, telemetry, telemetryParent, server
21
23
  const provider = await module.createLixStorageProvider(storage.options);
22
24
  try {
23
25
  const binding = (await (snapshot
24
- ? restoreSnapshot(snapshot, openJsStorageFromSnapshot(provider, telemetry, telemetryParent, openProgress))
25
- : openJsStorage(provider, telemetry, telemetryParent, server, openProgress)));
26
+ ? restoreSnapshot(snapshot, openJsStorageFromSnapshot(provider, telemetry, telemetryParent, openProgress, componentDispatch, storage.durability))
27
+ : openJsStorage(provider, telemetry, telemetryParent, server, openProgress, componentDispatch, storage.durability)));
26
28
  return binding;
27
29
  }
28
30
  catch (error) {
@@ -42,3 +44,11 @@ export async function deleteHostedBinding(server) {
42
44
  await initializeWasm();
43
45
  await deleteHosted(server);
44
46
  }
47
+ export async function convertReplicaBinding(storage, server, branchId) {
48
+ const migration = await import("./migration-binding.browser.js");
49
+ return migration.convertReplicaBinding(storage, server, branchId);
50
+ }
51
+ export async function retryReplicaMigrationCleanupBinding(storage, server) {
52
+ const migration = await import("./migration-binding.browser.js");
53
+ return migration.retryReplicaMigrationCleanupBinding(storage, server);
54
+ }
@@ -1,2 +1,2 @@
1
1
  import type { LixBinding, TelemetryDispatch, TelemetryParentContext, OpenProgressDispatch } from "./binding-types.js";
2
- export declare function openMemoryWasmBinding(telemetry?: TelemetryDispatch, telemetryParent?: TelemetryParentContext, openProgress?: OpenProgressDispatch, snapshot?: ReadableStream<Uint8Array>): Promise<LixBinding>;
2
+ export declare function openMemoryWasmBinding(telemetry?: TelemetryDispatch, telemetryParent?: TelemetryParentContext, openProgress?: OpenProgressDispatch, snapshot?: ReadableStream<Uint8Array>, durability?: import("./types.js").Durability): Promise<LixBinding>;
@@ -1,12 +1,14 @@
1
+ import { createComponentDispatch } from "./component-host/dispatch.js";
1
2
  import { restoreSnapshot } from "./snapshot-restore.js";
2
3
  import { initializeWasm } from "./wasm-init.js";
3
4
  // Generated before TypeScript compilation and emitted beside this module.
4
5
  // @ts-ignore Generated by build:wasm and absent in source-only checks.
5
6
  import { openMemory, openMemoryFromSnapshot } from "./wasm/lix_js_sdk.js";
6
- export async function openMemoryWasmBinding(telemetry, telemetryParent, openProgress, snapshot) {
7
+ export async function openMemoryWasmBinding(telemetry, telemetryParent, openProgress, snapshot, durability) {
7
8
  await initializeWasm();
9
+ const componentDispatch = createComponentDispatch();
8
10
  if (snapshot) {
9
- return restoreSnapshot(snapshot, openMemoryFromSnapshot(telemetry, telemetryParent, openProgress));
11
+ return restoreSnapshot(snapshot, openMemoryFromSnapshot(telemetry, telemetryParent, openProgress, componentDispatch, durability));
10
12
  }
11
- return openMemory(telemetry, telemetryParent, undefined, openProgress);
13
+ return openMemory(telemetry, telemetryParent, undefined, openProgress, componentDispatch, durability);
12
14
  }
@@ -3,3 +3,5 @@ export declare function openLixBinding(storage: LixStorageConfig, telemetry?: Te
3
3
  export declare function openNativeLixBinding(storage: LixStorageConfig, telemetry?: TelemetryDispatch, telemetryParent?: TelemetryParentContext, server?: SyncServerBindingOptions, openProgress?: OpenProgressDispatch, snapshot?: ReadableStream<Uint8Array>): Promise<LixBinding>;
4
4
  export declare function createHostedBinding(server: import("./binding-types.js").HostedServerBindingOptions): Promise<import("./types.js").HostedLix>;
5
5
  export declare function deleteHostedBinding(server: import("./binding-types.js").HostedServerBindingOptions): Promise<void>;
6
+ export declare function convertReplicaBinding(storage: LixStorageConfig, server: SyncServerBindingOptions, branchId?: string): Promise<void>;
7
+ export declare function retryReplicaMigrationCleanupBinding(storage: LixStorageConfig, server: SyncServerBindingOptions): Promise<number>;
@@ -1,3 +1,4 @@
1
+ import { createComponentDispatch } from "./component-host/dispatch.js";
1
2
  import { existsSync } from "node:fs";
2
3
  import { createRequire } from "node:module";
3
4
  import { fileURLToPath } from "node:url";
@@ -19,6 +20,14 @@ function normalizeNativeBinding(binding) {
19
20
  if (property === "setTelemetryParent") {
20
21
  return (parent) => target.setTelemetryParent(parent === undefined ? undefined : JSON.stringify(parent));
21
22
  }
23
+ if (property === "recoverReplicaWithServer") {
24
+ return async (id, server) => {
25
+ if (server.transport)
26
+ throw new Error("Custom fetch is unsupported for native recovery");
27
+ const headers = server.headerProvider ? await server.headerProvider() : server.headers;
28
+ return target.recoverReplicaWithServer(id, server.url, headers);
29
+ };
30
+ }
22
31
  if (property === "observe") {
23
32
  return async (sql, params) => normalizeNativeObserveEvents(await target.observe(sql, params));
24
33
  }
@@ -91,7 +100,7 @@ export async function openLixBinding(storage, telemetry, telemetryParent, server
91
100
  }
92
101
  try {
93
102
  const { openMemoryWasmBinding } = await import("./binding.node-wasm.js");
94
- return await openMemoryWasmBinding(telemetry, telemetryParent, openProgress, snapshot);
103
+ return await openMemoryWasmBinding(telemetry, telemetryParent, openProgress, snapshot, storage.durability);
95
104
  }
96
105
  catch (wasmError) {
97
106
  throw new AggregateError([nativeError, wasmError], "Failed to open in-memory Lix with either the native or WebAssembly binding.");
@@ -99,7 +108,7 @@ export async function openLixBinding(storage, telemetry, telemetryParent, server
99
108
  }
100
109
  }
101
110
  export async function openNativeLixBinding(storage, telemetry, telemetryParent, server, openProgress, snapshot) {
102
- if (server?.fetch) {
111
+ if (server?.transport) {
103
112
  throw new TypeError("Custom sync fetch is only supported by the browser worker");
104
113
  }
105
114
  const nativeOpenProgress = openProgress
@@ -112,6 +121,7 @@ export async function openNativeLixBinding(storage, telemetry, telemetryParent,
112
121
  }
113
122
  }
114
123
  : undefined;
124
+ const componentDispatch = createComponentDispatch();
115
125
  switch (storage.kind) {
116
126
  case "memory": {
117
127
  const nativeAddon = loadAddon();
@@ -119,13 +129,13 @@ export async function openNativeLixBinding(storage, telemetry, telemetryParent,
119
129
  ? (spanJson) => telemetry(JSON.parse(spanJson))
120
130
  : undefined;
121
131
  if (snapshot) {
122
- const restore = nativeAddon.Lix.openMemoryFromSnapshot(nativeTelemetry, telemetryParent ? JSON.stringify(telemetryParent) : undefined, nativeOpenProgress);
132
+ const restore = nativeAddon.Lix.openMemoryFromSnapshot(nativeTelemetry, telemetryParent ? JSON.stringify(telemetryParent) : undefined, nativeOpenProgress, componentDispatch, storage.durability);
123
133
  return normalizeNativeBinding(await restoreSnapshot(snapshot, restore));
124
134
  }
125
135
  if (nativeTelemetry) {
126
- return normalizeNativeBinding(await nativeAddon.Lix.openMemory(nativeTelemetry, telemetryParent ? JSON.stringify(telemetryParent) : undefined, server?.url, server?.headers, nativeOpenProgress));
136
+ return normalizeNativeBinding(await nativeAddon.Lix.openMemory(nativeTelemetry, telemetryParent ? JSON.stringify(telemetryParent) : undefined, server?.url, server?.headers, nativeOpenProgress, componentDispatch, storage.durability));
127
137
  }
128
- return normalizeNativeBinding(await nativeAddon.Lix.openMemory(undefined, undefined, server?.url, server?.headers, nativeOpenProgress));
138
+ return normalizeNativeBinding(await nativeAddon.Lix.openMemory(undefined, undefined, server?.url, server?.headers, nativeOpenProgress, componentDispatch, storage.durability));
129
139
  }
130
140
  case "jsStorage":
131
141
  throw new Error("JavaScript storage providers are only available in browsers");
@@ -135,13 +145,13 @@ export async function openNativeLixBinding(storage, telemetry, telemetryParent,
135
145
  ? (spanJson) => telemetry(JSON.parse(spanJson))
136
146
  : undefined;
137
147
  if (snapshot) {
138
- const restore = nativeAddon.Lix.openFilesystemStorageFromSnapshot(storage.path, storage.syncAllFiles, nativeTelemetry, telemetryParent ? JSON.stringify(telemetryParent) : undefined, nativeOpenProgress);
148
+ const restore = nativeAddon.Lix.openFilesystemStorageFromSnapshot(storage.path, storage.syncAllFiles, nativeTelemetry, telemetryParent ? JSON.stringify(telemetryParent) : undefined, nativeOpenProgress, componentDispatch, storage.durability);
139
149
  return normalizeNativeBinding(await restoreSnapshot(snapshot, restore));
140
150
  }
141
151
  if (nativeTelemetry) {
142
- return normalizeNativeBinding(await nativeAddon.Lix.openFilesystemStorage(storage.path, storage.syncAllFiles, nativeTelemetry, telemetryParent ? JSON.stringify(telemetryParent) : undefined, server?.url, server?.headers, nativeOpenProgress));
152
+ return normalizeNativeBinding(await nativeAddon.Lix.openFilesystemStorage(storage.path, storage.syncAllFiles, nativeTelemetry, telemetryParent ? JSON.stringify(telemetryParent) : undefined, server?.url, server?.headers, nativeOpenProgress, componentDispatch, storage.durability));
143
153
  }
144
- return normalizeNativeBinding(await nativeAddon.Lix.openFilesystemStorage(storage.path, storage.syncAllFiles, undefined, undefined, server?.url, server?.headers, nativeOpenProgress));
154
+ return normalizeNativeBinding(await nativeAddon.Lix.openFilesystemStorage(storage.path, storage.syncAllFiles, undefined, undefined, server?.url, server?.headers, nativeOpenProgress, componentDispatch, storage.durability));
145
155
  }
146
156
  }
147
157
  }
@@ -151,3 +161,19 @@ export async function createHostedBinding(server) {
151
161
  export async function deleteHostedBinding(server) {
152
162
  await loadAddon().deleteHosted(server.url, server.headers);
153
163
  }
164
+ export async function convertReplicaBinding(storage, server, branchId) {
165
+ if (storage.kind !== "filesystem")
166
+ throw new TypeError("Node conversion requires FilesystemStorage");
167
+ if (server.transport)
168
+ throw new TypeError("Custom sync fetch is only supported in browsers");
169
+ const headers = server.headerProvider ? await server.headerProvider() : server.headers;
170
+ await (await import("./migration-binding.node.js")).loadMigrationAddon().convertFilesystemReplicaToPartial(storage.path, storage.syncAllFiles, server.url, headers, branchId);
171
+ }
172
+ export async function retryReplicaMigrationCleanupBinding(storage, server) {
173
+ if (storage.kind !== "filesystem")
174
+ throw new TypeError("Node migration cleanup requires FilesystemStorage");
175
+ if (server.transport)
176
+ throw new TypeError("Custom sync fetch is only supported in browsers");
177
+ const headers = server.headerProvider ? await server.headerProvider() : server.headers;
178
+ return (await import("./migration-binding.node.js")).loadMigrationAddon().retryFilesystemReplicaMigrationCleanup(storage.path, storage.syncAllFiles, server.url, headers);
179
+ }
@@ -0,0 +1,6 @@
1
+ /** Compatibility versions of the engine shipped with this SDK. */
2
+ export declare const compatibility: Readonly<{
3
+ serverProtocolVersion: number;
4
+ syncProtocolVersion: number;
5
+ storageFormatVersion: number;
6
+ }>;
@@ -0,0 +1,6 @@
1
+ // Generated from the canonical Rust engine constants. No binding is loaded.
2
+ export const compatibility = Object.freeze({
3
+ "serverProtocolVersion": 11,
4
+ "syncProtocolVersion": 17,
5
+ "storageFormatVersion": 81
6
+ });
@@ -0,0 +1,12 @@
1
+ export type ComponentRequest = {
2
+ operation: string;
3
+ data: string;
4
+ bytes?: Uint8Array;
5
+ host?: {
6
+ call(method: string, argumentsJson: string): string;
7
+ free?(): void;
8
+ };
9
+ };
10
+ export type ComponentDispatch = (request: ComponentRequest) => Promise<string>;
11
+ /** One isolated handle registry per engine runtime, shared by Node and browsers. */
12
+ export declare function createComponentDispatch(): (request: ComponentRequest) => Promise<string>;