@lix-js/sdk 0.16.0 → 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 (73) hide show
  1. package/README.md +187 -22
  2. package/dist/binding-types.d.ts +20 -6
  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 +20 -10
  27. package/dist/lix.js +68 -23
  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 -5
  46. package/dist/storage-ownership.d.ts +5 -0
  47. package/dist/storage-ownership.js +4 -0
  48. package/dist/types.d.ts +132 -22
  49. package/dist/wasm/lix_js_sdk.d.ts +57 -16
  50. package/dist/wasm/lix_js_sdk.js +268 -60
  51. package/dist/wasm/lix_js_sdk_bg.wasm +2 -2
  52. package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +23 -9
  53. package/dist/worker/client.d.ts +12 -3
  54. package/dist/worker/client.js +98 -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 +92 -32
  65. package/dist/worker/protocol.d.ts +33 -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 -13
  72. package/dist/remote/server-protocol.d.ts +0 -185
  73. package/dist/remote/server-protocol.js +0 -417
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` | Synchronized local reads; mutations execute on the server |
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 read replica.
68
- Certified current-state reads can execute locally; mutations execute on 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()}`,
@@ -83,12 +126,121 @@ const lix = await openLix({
83
126
  });
84
127
  ```
85
128
 
86
- A successful mutation confirms server acceptance. The local replica receives
87
- the resulting certified state automatically; older history and binary content
88
- load when needed. Connected mutations require the server, and cached reads may
89
- also need fresh server certification.
129
+ A successful mutation confirms a local commit; it does not confirm server
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
+
90
149
  See [Collaboration and Sync](https://lix.dev/docs/collaboration-and-sync).
91
150
 
151
+ ### Upgrading a local replica
152
+
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:
179
+
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:
192
+
193
+ ```ts
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();
206
+ }
207
+ ```
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
+
215
+ `exportReplicaRecovery()` captures available logical rows, blob contents, and
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.
229
+
230
+ Recovery export currently allows up to 100,000 logical rows across all branches,
231
+ 64 MiB per blob, and 128 MiB of blob content in total. Unfinished upload parts
232
+ have a separate 128 MiB content budget. A row-limit or upload-limit error leaves
233
+ the source intact; omitted blob content is identified in `unresolved`. Exported
234
+ JSON can be larger than these content budgets because binary data uses base64.
235
+ This recovery file is not a complete repository backup.
236
+
237
+ These methods require a local storage-backed handle; remote-only handles reject
238
+ with `LIX_ERROR_LOCAL_STORAGE_REQUIRED`. Do not clear browser storage to resolve
239
+ upgrade or recovery errors. Browser storage eviction or an unsupported old format
240
+ can still require external recovery; retaining bytes alone is not proof that all
241
+ work has been recovered. Standalone and authoritative repositories continue to
242
+ use history-preserving format migrations.
243
+
92
244
  ## Remote repositories
93
245
 
94
246
  Use the same Lix client as a thin client against a hosted repository:
@@ -116,7 +268,8 @@ files.close();
116
268
  await lix.close();
117
269
  ```
118
270
 
119
- 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
120
273
  open a local engine. Dynamic headers are resolved for every request and
121
274
  observation reconnect. An injected `fetch` can route requests through a service
122
275
  binding or another authorized server-side transport.
@@ -243,18 +396,30 @@ try {
243
396
  - The package is ESM-only.
244
397
  - The package uses conditional ESM imports internally: Node.js resolves the
245
398
  native N-API binding, while browsers and other runtimes resolve the portable
246
- 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
+ ```
247
407
  - If the native addon cannot load in Node.js, in-memory Lix instances fall back
248
- to the bundled WebAssembly engine. Filesystem storage and Component API v1
249
- plugin execution still require the native addon.
408
+ to the bundled WebAssembly engine. Filesystem storage still requires the native addon.
250
409
  - Every browser `openLix()` owns one dedicated worker, so database work does
251
410
  not block the page's main thread. Node.js uses the native binding's actor.
252
- - Node.js executes installed Component API v1 plugins with the Rust SDK's
253
- Wasmtime runtime. The browser binding currently opens without a component
254
- runtime: it can use ordinary Lix storage and SQL, but does not
255
- 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.
256
420
  - A page Content Security Policy only needs to permit the package's same-origin
257
- 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
258
423
  permission can be scoped to the worker script's HTTP response instead of
259
424
  being allowed by the document:
260
425
 
@@ -263,11 +428,11 @@ try {
263
428
  Content-Security-Policy: default-src 'self'; script-src 'self'; worker-src 'self'
264
429
 
265
430
  # Lix worker response (Vite emits assets/entry.browser-<hash>.js)
266
- 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'
267
432
  ```
268
433
 
269
434
  Hosts that apply one policy to every response can use
270
- `script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'` globally
435
+ `script-src 'self' data: 'wasm-unsafe-eval'; worker-src 'self'` globally
271
436
  instead. Worker-scoped headers keep those permissions out of the page.
272
437
 
273
438
  - SQL parameters use normal JavaScript values: `string`, finite `number`, `boolean`, `Uint8Array`, `null`, JSON-compatible arrays, and JSON-compatible plain objects.
@@ -287,7 +452,7 @@ npm run test:browser
287
452
 
288
453
  `npm run test:browser:production` additionally packs the SDK, installs the
289
454
  tarball into a minimal Vite app, makes a production build, and exercises SQL
290
- 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
291
456
  worker-scoped and global strict CSP headers.
292
457
 
293
458
  Use `npm run build:wasm:dev` while iterating on the Rust bridge when release
@@ -1,11 +1,12 @@
1
- import type { CreateBranchOptions, CreateBranchReceipt, UndoReceipt, RedoReceipt, ExecuteOptions, LixBatchOptions, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, SwitchBranchOptions, SwitchBranchReceipt, LixTelemetrySpan, LixTelemetryParentContext, LixOpenProgress, LixOpenReport, OpenAnotherSessionOptions, ResultColumn } from "./types.js";
1
+ import type { HttpTransport } from "./http-transport.js";
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";
4
5
  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;
@@ -18,6 +19,7 @@ export type BindingExecuteResult = {
18
19
  message: string;
19
20
  hint?: string;
20
21
  }>;
22
+ commit?: CommitSpan;
21
23
  };
22
24
  export type BindingObserveEvent = {
23
25
  sequence: number;
@@ -44,11 +46,19 @@ export type LixBinding = {
44
46
  createHosted?(server: HostedServerBindingOptions): Promise<import("./types.js").HostedLix>;
45
47
  openReport?(): LixOpenReport | undefined;
46
48
  setTelemetryParent(parent?: TelemetryParentContext): void;
47
- openAnotherSession(options: OpenAnotherSessionOptions): Promise<LixBinding>;
49
+ openAnotherSession(options: OpenAnotherSessionOptions, telemetry?: TelemetryDispatch): Promise<LixBinding>;
48
50
  execute(sql: string, params: BindingParam[], options?: ExecuteOptions): Promise<BindingExecuteResult>;
49
- executeBatch(statements: BindingBatchStatement[], options?: LixBatchOptions): Promise<BindingExecuteResult[]>;
51
+ executeBatch(statements: BindingBatchStatement[], options?: LixBatchOptions): Promise<{
52
+ results: BindingExecuteResult[];
53
+ commit?: CommitSpan | null;
54
+ }>;
50
55
  observe(sql: string, params: BindingParam[]): Promise<ObserveEventsBinding>;
51
56
  beginTransaction(): Promise<LixTransactionBinding>;
57
+ replicaRecoverySources(): Promise<ReplicaRecoverySource[]>;
58
+ exportReplicaRecovery(id: string): Promise<ReplicaRecoveryExport>;
59
+ recoverReplica(id: string): Promise<ReplicaRecoveryReceipt>;
60
+ recoverReplicaWithServer(id: string, server: SyncServerBindingOptions): Promise<ReplicaRecoveryReceipt>;
61
+ syncHealth(): Promise<import("./types.js").SyncHealth>;
52
62
  activeBranchId(): Promise<string>;
53
63
  activeAccountId(): Promise<string>;
54
64
  createBranch(options: CreateBranchOptions): Promise<CreateBranchReceipt>;
@@ -64,7 +74,9 @@ export type LixBinding = {
64
74
  };
65
75
  export type LixTransactionBinding = {
66
76
  execute(sql: string, params: BindingParam[], options?: ExecuteOptions): Promise<BindingExecuteResult>;
67
- commit(): Promise<void>;
77
+ commit(): Promise<{
78
+ commit?: CommitSpan | null;
79
+ }>;
68
80
  rollback(): Promise<void>;
69
81
  };
70
82
  export type ObserveEventsBinding = {
@@ -79,6 +91,8 @@ export type LixStorageProviderModule = {
79
91
  createLixStorageProvider(options: unknown): Promise<LixStorageProvider>;
80
92
  };
81
93
  export type LixStorageConfig = {
94
+ durability?: import("./types.js").Durability;
95
+ } & ({
82
96
  kind: "memory";
83
97
  } | {
84
98
  kind: "jsStorage";
@@ -88,7 +102,7 @@ export type LixStorageConfig = {
88
102
  kind: "filesystem";
89
103
  path: string;
90
104
  syncAllFiles: boolean;
91
- };
105
+ });
92
106
  export type HostedServerBindingOptions = {
93
107
  idempotencyKey?: string;
94
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>;