@lix-js/sdk 0.11.0 → 0.12.1

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 (40) hide show
  1. package/README.md +48 -76
  2. package/dist/binding-types.d.ts +6 -15
  3. package/dist/binding.browser.js +18 -5
  4. package/dist/binding.node.js +5 -6
  5. package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
  6. package/dist/bundled-plugins/plugin_markdown.lixplugin +0 -0
  7. package/dist/errors.d.ts +0 -2
  8. package/dist/errors.js +0 -13
  9. package/dist/index.d.ts +3 -3
  10. package/dist/index.js +1 -1
  11. package/dist/indexeddb-backend.d.ts +19 -0
  12. package/dist/indexeddb-backend.js +121 -0
  13. package/dist/lix.d.ts +1 -4
  14. package/dist/lix.js +21 -52
  15. package/dist/open-lix.d.ts +4 -9
  16. package/dist/open-lix.js +45 -135
  17. package/dist/remote/client.d.ts +2 -3
  18. package/dist/remote/client.js +13 -21
  19. package/dist/remote/{protocol.d.ts → server-protocol.d.ts} +35 -33
  20. package/dist/remote/{protocol.js → server-protocol.js} +24 -17
  21. package/dist/storage-adapter.d.ts +30 -0
  22. package/dist/storage-adapter.js +12 -0
  23. package/dist/types.d.ts +14 -24
  24. package/dist/value.d.ts +2 -1
  25. package/dist/value.js +23 -10
  26. package/dist/wasm/lix_js_sdk.d.ts +5 -10
  27. package/dist/wasm/lix_js_sdk.js +33 -45
  28. package/dist/wasm/lix_js_sdk_bg.wasm +0 -0
  29. package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +3 -6
  30. package/dist/worker/client.d.ts +1 -12
  31. package/dist/worker/client.js +0 -161
  32. package/dist/worker/host.js +0 -23
  33. package/dist/worker/protocol.d.ts +1 -15
  34. package/package.json +8 -12
  35. package/dist/client-state.d.ts +0 -53
  36. package/dist/client-state.js +0 -315
  37. package/dist/local-storage-adapter.d.ts +0 -26
  38. package/dist/local-storage-adapter.js +0 -117
  39. package/dist/snapshot-persistence.d.ts +0 -7
  40. package/dist/snapshot-persistence.js +0 -26
package/dist/types.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- export type LocalFilesystemOptions = {
2
- path: string;
3
- lixDir?: string;
4
- syncAllFiles: boolean;
1
+ export type IndexedDbStorageOptions = {
2
+ /**
3
+ * Identifies one persistent Lix database within the current origin.
4
+ * A database name can be opened by only one Lix handle at a time.
5
+ */
6
+ name: string;
5
7
  };
6
8
  export type RemoteLixFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
7
9
  export type RemoteLixServerOptions = {
@@ -21,27 +23,12 @@ export type LixTelemetrySpan = {
21
23
  export type LixTelemetryOptions = {
22
24
  onSpan(span: LixTelemetrySpan): void;
23
25
  };
24
- /**
25
- * Persists opaque Lix snapshots under SDK-provided namespaces.
26
- *
27
- * Implementations must treat snapshots as bytes owned by Lix. The namespace
28
- * selects one logical Lix and allows a single adapter to persist more than one
29
- * instance without collisions.
30
- */
31
- export interface LixSnapshotStorage {
32
- load(namespace: string): Promise<Uint8Array | undefined>;
33
- save(namespace: string, snapshot: Uint8Array): Promise<void>;
34
- }
35
26
  export type OpenLixOptions = {
36
- storage?: import("./open-lix.js").LocalFilesystem | LixSnapshotStorage;
27
+ storage?: import("./storage-adapter.js").LixStorage | import("./open-lix.js").IndexedDbStorage;
37
28
  server?: never;
38
29
  telemetry?: LixTelemetryOptions;
39
30
  } | {
40
- /**
41
- * Optional client-local storage. In remote mode workspace SQL remains on
42
- * the server; only `lix.clientState` is stored here.
43
- */
44
- storage?: LixSnapshotStorage;
31
+ storage?: never;
45
32
  server: RemoteLixServerOptions;
46
33
  telemetry?: never;
47
34
  };
@@ -61,8 +48,11 @@ export type LixValue = {
61
48
  kind: "text";
62
49
  value: string;
63
50
  } | {
64
- kind: "json";
51
+ kind: "jsonb";
65
52
  value: JsonValue;
53
+ } | {
54
+ kind: "timestamptz";
55
+ value: string;
66
56
  } | {
67
57
  kind: "blob";
68
58
  value: Uint8Array;
@@ -188,9 +178,9 @@ export type MergeChangeStats = {
188
178
  removed: number;
189
179
  };
190
180
  export type MergeConflict = {
191
- kind: "sameEntityChanged";
181
+ kind: "sameRowChanged";
192
182
  schemaKey: string;
193
- entityPk: unknown;
183
+ rowPk: unknown;
194
184
  fileId: string | null;
195
185
  target: MergeConflictSide;
196
186
  source: MergeConflictSide;
package/dist/value.d.ts CHANGED
@@ -8,7 +8,8 @@ export declare class Value {
8
8
  static integer(value: number): Value;
9
9
  static real(value: number): Value;
10
10
  static text(value: string): Value;
11
- static json(value: JsonValue): Value;
11
+ static jsonb(value: JsonValue): Value;
12
+ static timestamptz(value: string): Value;
12
13
  static blob(value: Uint8Array): Value;
13
14
  static from(value: SqlParam): Value;
14
15
  static _fromNative(value: LixValue): Value;
package/dist/value.js CHANGED
@@ -2,9 +2,9 @@ import { invalidParam } from "./errors.js";
2
2
  export class Value {
3
3
  kind;
4
4
  #raw;
5
- constructor(raw) {
5
+ constructor(raw, clone = true) {
6
6
  validateExplicitValue(raw);
7
- this.#raw = cloneValue(raw);
7
+ this.#raw = clone ? cloneValue(raw) : raw;
8
8
  this.kind = this.#raw.kind;
9
9
  }
10
10
  static null() {
@@ -22,8 +22,11 @@ export class Value {
22
22
  static text(value) {
23
23
  return new Value({ kind: "text", value });
24
24
  }
25
- static json(value) {
26
- return new Value({ kind: "json", value });
25
+ static jsonb(value) {
26
+ return new Value({ kind: "jsonb", value });
27
+ }
28
+ static timestamptz(value) {
29
+ return new Value({ kind: "timestamptz", value });
27
30
  }
28
31
  static blob(value) {
29
32
  return new Value({ kind: "blob", value });
@@ -32,7 +35,11 @@ export class Value {
32
35
  return new Value(normalizeParam(value));
33
36
  }
34
37
  static _fromNative(value) {
35
- return new Value(value);
38
+ // Native execute results are newly materialized for this result set. Keep
39
+ // the native value as-is and defer the defensive copy until toJS(). This
40
+ // avoids cloning every structured result once during row wrapping and
41
+ // again when callers read it.
42
+ return new Value(value, false);
36
43
  }
37
44
  _toNative() {
38
45
  return toNativeValue(this.#raw);
@@ -101,7 +108,7 @@ export function normalizeParam(value, index = 0, seen = new WeakSet()) {
101
108
  throw invalidParam(index, "typed array SQL parameters must be Uint8Array", value.constructor.name);
102
109
  }
103
110
  assertJsonSerializable(value, seen, index);
104
- return { kind: "json", value };
111
+ return { kind: "jsonb", value };
105
112
  }
106
113
  throw invalidParam(index, `${typeof value} is not a valid SQL parameter`, typeof value);
107
114
  }
@@ -113,7 +120,8 @@ function unwrapValue(value) {
113
120
  case "integer":
114
121
  case "real":
115
122
  case "text":
116
- case "json":
123
+ case "timestamptz":
124
+ case "jsonb":
117
125
  return cloneJsonValue(value.value);
118
126
  case "blob":
119
127
  return new Uint8Array(value.value);
@@ -193,9 +201,14 @@ function validateExplicitValue(value) {
193
201
  throw invalidParam(0, "string SQL parameters must be well-formed UTF-16", "string");
194
202
  }
195
203
  return;
196
- case "json":
204
+ case "jsonb":
197
205
  assertJsonSerializable(value.value, new WeakSet(), 0);
198
206
  return;
207
+ case "timestamptz":
208
+ if (typeof value.value === "string" && !Number.isNaN(Date.parse(value.value))) {
209
+ return;
210
+ }
211
+ break;
199
212
  case "blob":
200
213
  if (value.value instanceof Uint8Array)
201
214
  return;
@@ -209,8 +222,8 @@ function cloneValue(value) {
209
222
  if (value.kind === "blob") {
210
223
  return { kind: "blob", value: new Uint8Array(value.value) };
211
224
  }
212
- if (value.kind === "json") {
213
- return { kind: "json", value: cloneJsonValue(value.value) };
225
+ if (value.kind === "jsonb") {
226
+ return { kind: "jsonb", value: cloneJsonValue(value.value) };
214
227
  }
215
228
  return value;
216
229
  }
@@ -8,10 +8,6 @@ export class WasmLix {
8
8
  activeAccountId(): Promise<string>;
9
9
  activeBranchId(): Promise<string>;
10
10
  beginTransaction(): Promise<WasmLixTransaction>;
11
- clientStateDelete(key: string): Promise<void>;
12
- clientStateEntries(): Promise<any>;
13
- clientStateGet(key: string): Promise<any>;
14
- clientStateSet(key: string, value: any): Promise<void>;
15
11
  close(): Promise<void>;
16
12
  createBranch(options: any): Promise<any>;
17
13
  createCheckpoint(): Promise<any>;
@@ -43,6 +39,8 @@ export class WasmObserveEvents {
43
39
  next(): Promise<any>;
44
40
  }
45
41
 
42
+ export function openIndexedDb(backend: any, telemetry_dispatch?: Function | null): Promise<WasmLix>;
43
+
46
44
  export function openMemory(telemetry_dispatch?: Function | null): Promise<WasmLix>;
47
45
 
48
46
  export function openMemoryFromSnapshot(telemetry_dispatch?: Function | null, snapshot?: Uint8Array | null): Promise<WasmLix>;
@@ -56,16 +54,13 @@ export interface InitOutput {
56
54
  readonly __wbg_wasmlix_free: (a: number, b: number) => void;
57
55
  readonly __wbg_wasmlixtransaction_free: (a: number, b: number) => void;
58
56
  readonly __wbg_wasmobserveevents_free: (a: number, b: number) => void;
57
+ readonly openIndexedDb: (a: number, b: number) => number;
59
58
  readonly openMemory: (a: number) => number;
60
59
  readonly openMemoryFromSnapshot: (a: number, b: number, c: number) => number;
61
60
  readonly parseSqlScript: (a: number, b: number, c: number, d: number) => void;
62
61
  readonly wasmlix_activeAccountId: (a: number) => number;
63
62
  readonly wasmlix_activeBranchId: (a: number) => number;
64
63
  readonly wasmlix_beginTransaction: (a: number) => number;
65
- readonly wasmlix_clientStateDelete: (a: number, b: number, c: number) => number;
66
- readonly wasmlix_clientStateEntries: (a: number) => number;
67
- readonly wasmlix_clientStateGet: (a: number, b: number, c: number) => number;
68
- readonly wasmlix_clientStateSet: (a: number, b: number, c: number, d: number) => number;
69
64
  readonly wasmlix_close: (a: number) => number;
70
65
  readonly wasmlix_createBranch: (a: number, b: number) => number;
71
66
  readonly wasmlix_createCheckpoint: (a: number) => number;
@@ -83,8 +78,8 @@ export interface InitOutput {
83
78
  readonly wasmlixtransaction_rollback: (a: number) => number;
84
79
  readonly wasmobserveevents_close: (a: number) => void;
85
80
  readonly wasmobserveevents_next: (a: number) => number;
86
- readonly __wasm_bindgen_func_elem_122229: (a: number, b: number, c: number, d: number) => void;
87
- readonly __wasm_bindgen_func_elem_122231: (a: number, b: number, c: number, d: number) => void;
81
+ readonly __wasm_bindgen_func_elem_119237: (a: number, b: number, c: number, d: number) => void;
82
+ readonly __wasm_bindgen_func_elem_119239: (a: number, b: number, c: number, d: number) => void;
88
83
  readonly __wbindgen_export: (a: number, b: number) => number;
89
84
  readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
90
85
  readonly __wbindgen_export3: (a: number) => void;
@@ -38,44 +38,6 @@ export class WasmLix {
38
38
  const ret = wasm.wasmlix_beginTransaction(this.__wbg_ptr);
39
39
  return takeObject(ret);
40
40
  }
41
- /**
42
- * @param {string} key
43
- * @returns {Promise<void>}
44
- */
45
- clientStateDelete(key) {
46
- const ptr0 = passStringToWasm0(key, wasm.__wbindgen_export, wasm.__wbindgen_export2);
47
- const len0 = WASM_VECTOR_LEN;
48
- const ret = wasm.wasmlix_clientStateDelete(this.__wbg_ptr, ptr0, len0);
49
- return takeObject(ret);
50
- }
51
- /**
52
- * @returns {Promise<any>}
53
- */
54
- clientStateEntries() {
55
- const ret = wasm.wasmlix_clientStateEntries(this.__wbg_ptr);
56
- return takeObject(ret);
57
- }
58
- /**
59
- * @param {string} key
60
- * @returns {Promise<any>}
61
- */
62
- clientStateGet(key) {
63
- const ptr0 = passStringToWasm0(key, wasm.__wbindgen_export, wasm.__wbindgen_export2);
64
- const len0 = WASM_VECTOR_LEN;
65
- const ret = wasm.wasmlix_clientStateGet(this.__wbg_ptr, ptr0, len0);
66
- return takeObject(ret);
67
- }
68
- /**
69
- * @param {string} key
70
- * @param {any} value
71
- * @returns {Promise<void>}
72
- */
73
- clientStateSet(key, value) {
74
- const ptr0 = passStringToWasm0(key, wasm.__wbindgen_export, wasm.__wbindgen_export2);
75
- const len0 = WASM_VECTOR_LEN;
76
- const ret = wasm.wasmlix_clientStateSet(this.__wbg_ptr, ptr0, len0, addHeapObject(value));
77
- return takeObject(ret);
78
- }
79
41
  /**
80
42
  * @returns {Promise<void>}
81
43
  */
@@ -254,6 +216,16 @@ export class WasmObserveEvents {
254
216
  }
255
217
  if (Symbol.dispose) WasmObserveEvents.prototype[Symbol.dispose] = WasmObserveEvents.prototype.free;
256
218
 
219
+ /**
220
+ * @param {any} backend
221
+ * @param {Function | null} [telemetry_dispatch]
222
+ * @returns {Promise<WasmLix>}
223
+ */
224
+ export function openIndexedDb(backend, telemetry_dispatch) {
225
+ const ret = wasm.openIndexedDb(addHeapObject(backend), isLikeNone(telemetry_dispatch) ? 0 : addHeapObject(telemetry_dispatch));
226
+ return takeObject(ret);
227
+ }
228
+
257
229
  /**
258
230
  * @param {Function | null} [telemetry_dispatch]
259
231
  * @returns {Promise<WasmLix>}
@@ -390,6 +362,10 @@ function __wbg_get_imports() {
390
362
  __wbg__wbg_cb_unref_61db23ac97f16c31: function(arg0) {
391
363
  getObject(arg0)._wbg_cb_unref();
392
364
  },
365
+ __wbg_applyChanges_e055d59b63743afd: function(arg0, arg1) {
366
+ const ret = getObject(arg0).applyChanges(takeObject(arg1));
367
+ return addHeapObject(ret);
368
+ },
393
369
  __wbg_call_8a89609d89f6608a: function() { return handleError(function (arg0, arg1) {
394
370
  const ret = getObject(arg0).call(getObject(arg1));
395
371
  return addHeapObject(ret);
@@ -398,6 +374,10 @@ function __wbg_get_imports() {
398
374
  const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
399
375
  return addHeapObject(ret);
400
376
  }, arguments); },
377
+ __wbg_close_93c7ea4f94bb464a: function(arg0) {
378
+ const ret = getObject(arg0).close();
379
+ return addHeapObject(ret);
380
+ },
401
381
  __wbg_done_60cf307fcc680536: function(arg0) {
402
382
  const ret = getObject(arg0).done;
403
383
  return ret;
@@ -501,6 +481,10 @@ function __wbg_get_imports() {
501
481
  const ret = getObject(arg0).length;
502
482
  return ret;
503
483
  },
484
+ __wbg_loadEntries_7336ebc0a13d5ac7: function(arg0) {
485
+ const ret = getObject(arg0).loadEntries();
486
+ return addHeapObject(ret);
487
+ },
504
488
  __wbg_new_0_445c13a750296eb6: function() {
505
489
  const ret = new Date();
506
490
  return addHeapObject(ret);
@@ -536,7 +520,7 @@ function __wbg_get_imports() {
536
520
  const a = state0.a;
537
521
  state0.a = 0;
538
522
  try {
539
- return __wasm_bindgen_func_elem_122231(a, state0.b, arg0, arg1);
523
+ return __wasm_bindgen_func_elem_119239(a, state0.b, arg0, arg1);
540
524
  } finally {
541
525
  state0.a = a;
542
526
  }
@@ -625,6 +609,10 @@ function __wbg_get_imports() {
625
609
  const ret = typeof window === 'undefined' ? null : window;
626
610
  return isLikeNone(ret) ? 0 : addHeapObject(ret);
627
611
  },
612
+ __wbg_then_18f476d590e58992: function(arg0, arg1, arg2) {
613
+ const ret = getObject(arg0).then(getObject(arg1), getObject(arg2));
614
+ return addHeapObject(ret);
615
+ },
628
616
  __wbg_then_ac7b025999b52837: function(arg0, arg1) {
629
617
  const ret = getObject(arg0).then(getObject(arg1));
630
618
  return addHeapObject(ret);
@@ -646,8 +634,8 @@ function __wbg_get_imports() {
646
634
  return addHeapObject(ret);
647
635
  },
648
636
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
649
- // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 30525, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
650
- const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_122229);
637
+ // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 28427, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
638
+ const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_119237);
651
639
  return addHeapObject(ret);
652
640
  },
653
641
  __wbindgen_cast_0000000000000002: function(arg0) {
@@ -696,10 +684,10 @@ function __wbg_get_imports() {
696
684
  };
697
685
  }
698
686
 
699
- function __wasm_bindgen_func_elem_122229(arg0, arg1, arg2) {
687
+ function __wasm_bindgen_func_elem_119237(arg0, arg1, arg2) {
700
688
  try {
701
689
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
702
- wasm.__wasm_bindgen_func_elem_122229(retptr, arg0, arg1, addHeapObject(arg2));
690
+ wasm.__wasm_bindgen_func_elem_119237(retptr, arg0, arg1, addHeapObject(arg2));
703
691
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
704
692
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
705
693
  if (r1) {
@@ -710,8 +698,8 @@ function __wasm_bindgen_func_elem_122229(arg0, arg1, arg2) {
710
698
  }
711
699
  }
712
700
 
713
- function __wasm_bindgen_func_elem_122231(arg0, arg1, arg2, arg3) {
714
- wasm.__wasm_bindgen_func_elem_122231(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
701
+ function __wasm_bindgen_func_elem_119239(arg0, arg1, arg2, arg3) {
702
+ wasm.__wasm_bindgen_func_elem_119239(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
715
703
  }
716
704
 
717
705
  const WasmLixFinalization = (typeof FinalizationRegistry === 'undefined')
Binary file
@@ -4,16 +4,13 @@ export const memory: WebAssembly.Memory;
4
4
  export const __wbg_wasmlix_free: (a: number, b: number) => void;
5
5
  export const __wbg_wasmlixtransaction_free: (a: number, b: number) => void;
6
6
  export const __wbg_wasmobserveevents_free: (a: number, b: number) => void;
7
+ export const openIndexedDb: (a: number, b: number) => number;
7
8
  export const openMemory: (a: number) => number;
8
9
  export const openMemoryFromSnapshot: (a: number, b: number, c: number) => number;
9
10
  export const parseSqlScript: (a: number, b: number, c: number, d: number) => void;
10
11
  export const wasmlix_activeAccountId: (a: number) => number;
11
12
  export const wasmlix_activeBranchId: (a: number) => number;
12
13
  export const wasmlix_beginTransaction: (a: number) => number;
13
- export const wasmlix_clientStateDelete: (a: number, b: number, c: number) => number;
14
- export const wasmlix_clientStateEntries: (a: number) => number;
15
- export const wasmlix_clientStateGet: (a: number, b: number, c: number) => number;
16
- export const wasmlix_clientStateSet: (a: number, b: number, c: number, d: number) => number;
17
14
  export const wasmlix_close: (a: number) => number;
18
15
  export const wasmlix_createBranch: (a: number, b: number) => number;
19
16
  export const wasmlix_createCheckpoint: (a: number) => number;
@@ -31,8 +28,8 @@ export const wasmlixtransaction_execute: (a: number, b: number, c: number, d: nu
31
28
  export const wasmlixtransaction_rollback: (a: number) => number;
32
29
  export const wasmobserveevents_close: (a: number) => void;
33
30
  export const wasmobserveevents_next: (a: number) => number;
34
- export const __wasm_bindgen_func_elem_122229: (a: number, b: number, c: number, d: number) => void;
35
- export const __wasm_bindgen_func_elem_122231: (a: number, b: number, c: number, d: number) => void;
31
+ export const __wasm_bindgen_func_elem_119237: (a: number, b: number, c: number, d: number) => void;
32
+ export const __wasm_bindgen_func_elem_119239: (a: number, b: number, c: number, d: number) => void;
36
33
  export const __wbindgen_export: (a: number, b: number) => number;
37
34
  export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
38
35
  export const __wbindgen_export3: (a: number) => void;
@@ -1,20 +1,9 @@
1
1
  import type { LixBinding, LixStorageConfig } from "../binding-types.js";
2
- import type { LixSnapshotStorage, LixTelemetryOptions } from "../types.js";
2
+ import type { LixTelemetryOptions } from "../types.js";
3
3
  import { type WorkerConnection, type WorkerNotification, type WorkerOperation } from "./protocol.js";
4
4
  export declare function openLixWorker(storage: LixStorageConfig, onDisposed?: () => void, telemetry?: LixTelemetryOptions): Promise<LixWorkerClient>;
5
5
  /** Opens the local worker transport behind the semantic Lix binding. */
6
6
  export declare function openLixWorkerBinding(storage: LixStorageConfig, onDisposed?: () => void, telemetry?: LixTelemetryOptions): Promise<LixBinding>;
7
- export type OpenPersistentLixWorkerBindingOptions = {
8
- storage: LixSnapshotStorage;
9
- namespace: string;
10
- telemetry?: LixTelemetryOptions;
11
- };
12
- /**
13
- * Opens a browser memory binding from an opaque snapshot and persists a fresh
14
- * snapshot after every successful mutation. This is an internal composition
15
- * seam for public storage adapters; it does not route workspace operations.
16
- */
17
- export declare function openPersistentLixWorkerBinding(options: OpenPersistentLixWorkerBindingOptions): Promise<LixBinding>;
18
7
  export declare class LixWorkerClient {
19
8
  private readonly connection;
20
9
  private nextRequestId;
@@ -1,5 +1,4 @@
1
1
  import { createWorkerConnection, openDirectLixBinding } from "#worker-factory";
2
- import { snapshotPersistenceAfterCommitError } from "../snapshot-persistence.js";
3
2
  import { deserializeWorkerError, } from "./protocol.js";
4
3
  const MAX_IDLE_WORKERS = 1;
5
4
  // The common serial reopen path retains one worker so its prepared plugin cache
@@ -64,43 +63,6 @@ export async function openLixWorkerBinding(storage, onDisposed, telemetry) {
64
63
  const client = await openLixWorker(storage, onDisposed, telemetry);
65
64
  return workerBinding(client);
66
65
  }
67
- /**
68
- * Opens a browser memory binding from an opaque snapshot and persists a fresh
69
- * snapshot after every successful mutation. This is an internal composition
70
- * seam for public storage adapters; it does not route workspace operations.
71
- */
72
- export async function openPersistentLixWorkerBinding(options) {
73
- if (!options || typeof options !== "object") {
74
- throw new TypeError("openPersistentLixWorkerBinding() options must be an object");
75
- }
76
- if (!options.storage ||
77
- typeof options.storage.load !== "function" ||
78
- typeof options.storage.save !== "function") {
79
- throw new TypeError("openPersistentLixWorkerBinding() storage must implement load() and save()");
80
- }
81
- if (typeof options.namespace !== "string" || options.namespace.length === 0) {
82
- throw new TypeError("openPersistentLixWorkerBinding() namespace must be a non-empty string");
83
- }
84
- const snapshot = await options.storage.load(options.namespace);
85
- if (snapshot !== undefined && !(snapshot instanceof Uint8Array)) {
86
- throw new TypeError("Snapshot storage load() must return a Uint8Array");
87
- }
88
- const binding = await openLixWorkerBinding({
89
- kind: "memory",
90
- ...(snapshot === undefined ? {} : { snapshot }),
91
- }, undefined, options.telemetry);
92
- const persistent = persistentSnapshotBinding(binding, options.storage, options.namespace);
93
- if (snapshot === undefined) {
94
- try {
95
- await persistent.persist();
96
- }
97
- catch (error) {
98
- await binding.close().catch(() => undefined);
99
- throw error;
100
- }
101
- }
102
- return persistent.binding;
103
- }
104
66
  function workerBinding(client) {
105
67
  let closed = false;
106
68
  const request = (operation) => {
@@ -131,10 +93,6 @@ function workerBinding(client) {
131
93
  },
132
94
  activeBranchId: () => request({ kind: "activeBranchId" }),
133
95
  activeAccountId: () => request({ kind: "activeAccountId" }),
134
- clientStateEntries: () => request({ kind: "clientState.entries" }),
135
- clientStateGet: (key) => request({ kind: "clientState.get", key }),
136
- clientStateSet: (key, value) => request({ kind: "clientState.set", key, value }),
137
- clientStateDelete: (key) => request({ kind: "clientState.delete", key }),
138
96
  createBranch: (options) => request({ kind: "createBranch", options }),
139
97
  createCheckpoint: () => request({ kind: "createCheckpoint" }),
140
98
  undo: () => request({ kind: "undo" }),
@@ -144,7 +102,6 @@ function workerBinding(client) {
144
102
  mergeBranchPreview: (options) => request({ kind: "mergeBranchPreview", options }),
145
103
  mergeBranch: (options) => request({ kind: "mergeBranch", options }),
146
104
  syncDiskToLix: () => request({ kind: "syncDiskToLix" }),
147
- exportSnapshot: () => request({ kind: "exportSnapshot" }),
148
105
  close: async () => {
149
106
  if (closed)
150
107
  return;
@@ -154,124 +111,6 @@ function workerBinding(client) {
154
111
  },
155
112
  };
156
113
  }
157
- function persistentSnapshotBinding(binding, storage, namespace) {
158
- let persistenceTail = Promise.resolve();
159
- let closePromise;
160
- let bindingClosed = false;
161
- const persist = () => {
162
- const operation = persistenceTail.then(async () => {
163
- const exportSnapshot = binding.exportSnapshot;
164
- if (!exportSnapshot) {
165
- throw new Error("The open Lix binding does not support snapshot export");
166
- }
167
- const snapshot = await exportSnapshot.call(binding);
168
- await storage.save(namespace, snapshot);
169
- });
170
- persistenceTail = operation.catch(() => undefined);
171
- return operation;
172
- };
173
- const afterMutation = async (operation) => {
174
- const result = await operation;
175
- try {
176
- await persist();
177
- }
178
- catch (error) {
179
- // The Rust transaction is already committed. Preserve that fact so
180
- // synchronous facades can reflect the live session value while still
181
- // reporting that durability failed.
182
- throw snapshotPersistenceAfterCommitError(error);
183
- }
184
- return result;
185
- };
186
- const persistentBinding = {
187
- execute: (sql, params, executeOptions) => afterMutation(binding.execute(sql, params, executeOptions)),
188
- executeBatch: (statements, batchOptions) => afterMutation(binding.executeBatch(statements, batchOptions)),
189
- observe: (sql, params) => binding.observe(sql, params),
190
- beginTransaction: async () => {
191
- const transaction = await binding.beginTransaction();
192
- return {
193
- execute: (sql, params, executeOptions) => transaction.execute(sql, params, executeOptions),
194
- commit: () => afterMutation(transaction.commit()),
195
- rollback: () => transaction.rollback(),
196
- };
197
- },
198
- activeBranchId: () => binding.activeBranchId(),
199
- activeAccountId: () => binding.activeAccountId(),
200
- clientStateEntries: () => {
201
- const method = binding.clientStateEntries;
202
- if (!method)
203
- return Promise.reject(clientStateUnsupportedError());
204
- return method.call(binding);
205
- },
206
- clientStateGet: (key) => {
207
- const method = binding.clientStateGet;
208
- if (!method)
209
- return Promise.reject(clientStateUnsupportedError());
210
- return method.call(binding, key);
211
- },
212
- clientStateSet: (key, value) => {
213
- const method = binding.clientStateSet;
214
- if (!method)
215
- return Promise.reject(clientStateUnsupportedError());
216
- return afterMutation(method.call(binding, key, value));
217
- },
218
- clientStateDelete: (key) => {
219
- const method = binding.clientStateDelete;
220
- if (!method)
221
- return Promise.reject(clientStateUnsupportedError());
222
- return afterMutation(method.call(binding, key));
223
- },
224
- createBranch: (branchOptions) => afterMutation(binding.createBranch(branchOptions)),
225
- createCheckpoint: () => afterMutation(binding.createCheckpoint()),
226
- undo: () => afterMutation(binding.undo()),
227
- redo: () => afterMutation(binding.redo()),
228
- switchBranch: (branchOptions) => afterMutation(binding.switchBranch(branchOptions)),
229
- importFilesystemPaths: (paths) => afterMutation(binding.importFilesystemPaths(paths)),
230
- mergeBranchPreview: (branchOptions) => binding.mergeBranchPreview(branchOptions),
231
- mergeBranch: (branchOptions) => afterMutation(binding.mergeBranch(branchOptions)),
232
- syncDiskToLix: () => afterMutation(binding.syncDiskToLix()),
233
- exportSnapshot: () => {
234
- const exportSnapshot = binding.exportSnapshot;
235
- if (!exportSnapshot) {
236
- return Promise.reject(new Error("The open Lix binding does not support snapshot export"));
237
- }
238
- return exportSnapshot.call(binding);
239
- },
240
- close: () => {
241
- if (closePromise)
242
- return closePromise;
243
- closePromise = (async () => {
244
- let persistenceError;
245
- try {
246
- await persist();
247
- }
248
- catch (error) {
249
- persistenceError = error;
250
- }
251
- await binding.close();
252
- bindingClosed = true;
253
- if (persistenceError !== undefined)
254
- throw persistenceError;
255
- })();
256
- void closePromise.catch((error) => {
257
- if (!bindingClosed && isActiveTransactionCloseError(error)) {
258
- closePromise = undefined;
259
- }
260
- });
261
- return closePromise;
262
- },
263
- };
264
- return { binding: persistentBinding, persist };
265
- }
266
- function isActiveTransactionCloseError(error) {
267
- return (typeof error === "object" &&
268
- error !== null &&
269
- "code" in error &&
270
- error.code === "LIX_INVALID_TRANSACTION_STATE");
271
- }
272
- function clientStateUnsupportedError() {
273
- return new Error("The open Lix binding does not support typed client state");
274
- }
275
114
  function workerTransactionBinding(request, transactionId) {
276
115
  return {
277
116
  execute: (sql, params, options) => request({
@@ -89,14 +89,6 @@ export function startWorkerHost(endpoint) {
89
89
  return requiredLix().activeBranchId();
90
90
  case "activeAccountId":
91
91
  return requiredLix().activeAccountId();
92
- case "clientState.entries":
93
- return requiredClientStateMethod("clientStateEntries")();
94
- case "clientState.get":
95
- return requiredClientStateMethod("clientStateGet")(operation.key);
96
- case "clientState.set":
97
- return requiredClientStateMethod("clientStateSet")(operation.key, operation.value);
98
- case "clientState.delete":
99
- return requiredClientStateMethod("clientStateDelete")(operation.key);
100
92
  case "createBranch":
101
93
  return requiredLix().createBranch(operation.options);
102
94
  case "createCheckpoint":
@@ -115,14 +107,6 @@ export function startWorkerHost(endpoint) {
115
107
  return requiredLix().importFilesystemPaths(operation.paths);
116
108
  case "syncDiskToLix":
117
109
  return requiredLix().syncDiskToLix();
118
- case "exportSnapshot": {
119
- const lix = requiredLix();
120
- const exportSnapshot = lix.exportSnapshot;
121
- if (!exportSnapshot) {
122
- throw workerStateError("The open Lix storage does not support snapshot export");
123
- }
124
- return exportSnapshot.call(lix);
125
- }
126
110
  case "observe": {
127
111
  const events = await requiredLix().observe(operation.sql, operation.params);
128
112
  const observeId = nextObserveId++;
@@ -154,13 +138,6 @@ export function startWorkerHost(endpoint) {
154
138
  throw workerStateError("Lix worker is closed");
155
139
  return lix;
156
140
  }
157
- function requiredClientStateMethod(key) {
158
- const method = requiredLix()[key];
159
- if (!method) {
160
- throw workerStateError("The open Lix binding does not support typed client state");
161
- }
162
- return method.bind(requiredLix());
163
- }
164
141
  function requiredTransaction(transactionId) {
165
142
  const transaction = transactions.get(transactionId);
166
143
  if (!transaction) {