@lix-js/sdk 0.8.4 → 0.10.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 (49) hide show
  1. package/README.md +105 -22
  2. package/dist/binding-types.d.ts +21 -2
  3. package/dist/binding.browser.d.ts +2 -2
  4. package/dist/binding.browser.js +3 -3
  5. package/dist/binding.node.d.ts +2 -2
  6. package/dist/binding.node.js +18 -4
  7. package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
  8. package/dist/bundled-plugins/plugin_markdown.lixplugin +0 -0
  9. package/dist/bundled-plugins.js +2 -2
  10. package/dist/client-state.d.ts +53 -0
  11. package/dist/client-state.js +318 -0
  12. package/dist/index.d.ts +2 -1
  13. package/dist/lix.d.ts +47 -0
  14. package/dist/lix.js +378 -0
  15. package/dist/local-storage-adapter.d.ts +26 -0
  16. package/dist/local-storage-adapter.js +117 -0
  17. package/dist/open-lix.d.ts +3 -34
  18. package/dist/open-lix.js +99 -170
  19. package/dist/remote/client.d.ts +9 -0
  20. package/dist/remote/client.js +1150 -0
  21. package/dist/remote/protocol.d.ts +178 -0
  22. package/dist/remote/protocol.js +367 -0
  23. package/dist/remote/sse.d.ts +12 -0
  24. package/dist/remote/sse.js +87 -0
  25. package/dist/snapshot-persistence.d.ts +7 -0
  26. package/dist/snapshot-persistence.js +26 -0
  27. package/dist/types.d.ts +68 -1
  28. package/dist/wasm/lix_js_sdk.d.ts +22 -4
  29. package/dist/wasm/lix_js_sdk.js +96 -17
  30. package/dist/wasm/lix_js_sdk_bg.wasm +0 -0
  31. package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +11 -2
  32. package/dist/worker/client.d.ts +23 -4
  33. package/dist/worker/client.js +329 -11
  34. package/dist/worker/factory.browser.d.ts +2 -0
  35. package/dist/worker/factory.browser.js +2 -0
  36. package/dist/worker/factory.node.d.ts +2 -0
  37. package/dist/worker/factory.node.js +5 -0
  38. package/dist/worker/host.js +36 -2
  39. package/dist/worker/protocol.d.ts +32 -2
  40. package/dist/workerd.js +1 -3
  41. package/package.json +19 -16
  42. package/dist/bundled-plugins/plugin_md_v2.lixplugin +0 -0
  43. package/dist/jco/js-component-bindgen-component.core.wasm +0 -0
  44. package/dist/jco/js-component-bindgen-component.core2.wasm +0 -0
  45. package/dist/jco/js-component-bindgen-component.js +0 -13662
  46. package/dist/jco-transpile.browser.d.ts +0 -14
  47. package/dist/jco-transpile.browser.js +0 -22
  48. package/dist/plugin-runtime.d.ts +0 -45
  49. package/dist/plugin-runtime.js +0 -124
@@ -1,9 +1,22 @@
1
- import { createWorkerConnection } from "#worker-factory";
1
+ import { createWorkerConnection, openDirectLixBinding } from "#worker-factory";
2
+ import { snapshotPersistenceAfterCommitError } from "../snapshot-persistence.js";
2
3
  import { deserializeWorkerError, } from "./protocol.js";
3
- export async function openLixWorker(storage, onDisposed) {
4
- const client = new LixWorkerClient(onDisposed);
4
+ const MAX_IDLE_WORKERS = 1;
5
+ // The common serial reopen path retains one worker so its prepared plugin cache
6
+ // survives close(). Concurrent opens still receive isolated workers.
7
+ const idleWorkers = [];
8
+ export async function openLixWorker(storage, onDisposed, telemetry) {
9
+ let client = idleWorkers.pop();
10
+ while (client?.isDisposed)
11
+ client = idleWorkers.pop();
12
+ client ??= new LixWorkerClient();
13
+ client.beginLease(onDisposed, telemetry);
5
14
  try {
6
- await client.request({ kind: "open", storage });
15
+ await client.request({
16
+ kind: "open",
17
+ storage,
18
+ telemetryEnabled: telemetry !== undefined,
19
+ });
7
20
  return client;
8
21
  }
9
22
  catch (error) {
@@ -11,21 +24,317 @@ export async function openLixWorker(storage, onDisposed) {
11
24
  throw error;
12
25
  }
13
26
  }
27
+ /** Opens the local worker transport behind the semantic Lix binding. */
28
+ export async function openLixWorkerBinding(storage, onDisposed, telemetry) {
29
+ if (openDirectLixBinding) {
30
+ const telemetryDispatch = telemetry
31
+ ? (span) => {
32
+ try {
33
+ telemetry.onSpan(span);
34
+ }
35
+ catch {
36
+ // Telemetry is observational and must not fail engine commands.
37
+ }
38
+ }
39
+ : undefined;
40
+ const binding = await openDirectLixBinding(storage, telemetryDispatch);
41
+ if (!onDisposed)
42
+ return binding;
43
+ let disposed = false;
44
+ return new Proxy(binding, {
45
+ get(target, property, receiver) {
46
+ if (property === "close") {
47
+ return async () => {
48
+ try {
49
+ await target.close();
50
+ }
51
+ finally {
52
+ if (!disposed) {
53
+ disposed = true;
54
+ onDisposed();
55
+ }
56
+ }
57
+ };
58
+ }
59
+ const value = Reflect.get(target, property, receiver);
60
+ return typeof value === "function" ? value.bind(target) : value;
61
+ },
62
+ });
63
+ }
64
+ const client = await openLixWorker(storage, onDisposed, telemetry);
65
+ return workerBinding(client);
66
+ }
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
+ function workerBinding(client) {
105
+ let closed = false;
106
+ const request = (operation) => {
107
+ if (closed)
108
+ return Promise.reject(workerClosedError());
109
+ return client.request(operation);
110
+ };
111
+ const notify = (notification) => {
112
+ if (!closed)
113
+ client.notify(notification);
114
+ };
115
+ return {
116
+ execute: (sql, params, options) => request({ kind: "execute", sql, params, options }),
117
+ executeBatch: (statements, options) => request({ kind: "executeBatch", statements, options }),
118
+ observe: async (sql, params) => {
119
+ const observeId = await request({
120
+ kind: "observe",
121
+ sql,
122
+ params,
123
+ });
124
+ return workerObserveBinding(request, notify, observeId);
125
+ },
126
+ beginTransaction: async () => {
127
+ const transactionId = await request({
128
+ kind: "beginTransaction",
129
+ });
130
+ return workerTransactionBinding(request, transactionId);
131
+ },
132
+ activeBranchId: () => request({ kind: "activeBranchId" }),
133
+ 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
+ createBranch: (options) => request({ kind: "createBranch", options }),
139
+ createCheckpoint: () => request({ kind: "createCheckpoint" }),
140
+ undo: () => request({ kind: "undo" }),
141
+ redo: () => request({ kind: "redo" }),
142
+ switchBranch: (options) => request({ kind: "switchBranch", options }),
143
+ importFilesystemPaths: (paths) => request({ kind: "importFilesystemPaths", paths }),
144
+ mergeBranchPreview: (options) => request({ kind: "mergeBranchPreview", options }),
145
+ mergeBranch: (options) => request({ kind: "mergeBranch", options }),
146
+ syncDiskToLix: () => request({ kind: "syncDiskToLix" }),
147
+ exportSnapshot: () => request({ kind: "exportSnapshot" }),
148
+ close: async () => {
149
+ if (closed)
150
+ return;
151
+ await request({ kind: "close" });
152
+ closed = true;
153
+ await releaseWorker(client);
154
+ },
155
+ };
156
+ }
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
+ function workerTransactionBinding(request, transactionId) {
276
+ return {
277
+ execute: (sql, params, options) => request({
278
+ kind: "transaction.execute",
279
+ transactionId,
280
+ sql,
281
+ params,
282
+ options,
283
+ }),
284
+ commit: () => request({ kind: "transaction.commit", transactionId }),
285
+ rollback: () => request({ kind: "transaction.rollback", transactionId }),
286
+ };
287
+ }
288
+ function workerObserveBinding(request, notify, observeId) {
289
+ return {
290
+ next: () => request({ kind: "observe.next", observeId }),
291
+ close: () => notify({ kind: "observe.close", observeId }),
292
+ };
293
+ }
294
+ async function releaseWorker(client) {
295
+ client.endLease();
296
+ if (!client.isDisposed && idleWorkers.length < MAX_IDLE_WORKERS) {
297
+ idleWorkers.push(client);
298
+ return;
299
+ }
300
+ await client.terminate();
301
+ }
14
302
  export class LixWorkerClient {
15
- onDisposed;
16
303
  connection;
17
304
  nextRequestId = 1;
18
305
  pending = new Map();
19
306
  disposed = false;
20
- constructor(onDisposed, connection = createWorkerConnection()) {
21
- this.onDisposed = onDisposed;
307
+ leased = false;
308
+ onDisposed;
309
+ telemetry;
310
+ constructor(connection = createWorkerConnection()) {
22
311
  this.connection = connection;
23
312
  connection.onMessage((message) => this.handleMessage(message));
24
313
  connection.onFatal((error) => this.handleFatal(error));
25
314
  }
315
+ get isDisposed() {
316
+ return this.disposed;
317
+ }
318
+ beginLease(onDisposed, telemetry) {
319
+ if (this.disposed || this.leased)
320
+ throw workerClosedError();
321
+ this.leased = true;
322
+ this.onDisposed = onDisposed;
323
+ this.telemetry = telemetry;
324
+ }
325
+ endLease() {
326
+ if (!this.leased)
327
+ return;
328
+ this.leased = false;
329
+ const onDisposed = this.onDisposed;
330
+ this.onDisposed = undefined;
331
+ this.telemetry = undefined;
332
+ onDisposed?.();
333
+ }
26
334
  request(operation) {
27
- if (this.disposed)
335
+ if (this.disposed || !this.leased) {
28
336
  return Promise.reject(workerClosedError());
337
+ }
29
338
  const id = this.nextRequestId++;
30
339
  if (this.pending.size === 0)
31
340
  this.connection.ref();
@@ -46,7 +355,7 @@ export class LixWorkerClient {
46
355
  });
47
356
  }
48
357
  notify(notification) {
49
- if (this.disposed)
358
+ if (this.disposed || !this.leased)
50
359
  return;
51
360
  try {
52
361
  this.connection.postMessage(notification);
@@ -64,10 +373,19 @@ export class LixWorkerClient {
64
373
  await this.connection.terminate();
65
374
  }
66
375
  finally {
67
- this.onDisposed?.();
376
+ this.endLease();
68
377
  }
69
378
  }
70
379
  handleMessage(message) {
380
+ if ("kind" in message) {
381
+ try {
382
+ this.telemetry?.onSpan(message.span);
383
+ }
384
+ catch {
385
+ // Telemetry callbacks are isolated from Lix operation results.
386
+ }
387
+ return;
388
+ }
71
389
  const pending = this.pending.get(message.id);
72
390
  if (!pending)
73
391
  return;
@@ -87,7 +405,7 @@ export class LixWorkerClient {
87
405
  fatal.name = "LixError";
88
406
  fatal.code ??= "LIX_WORKER_TERMINATED";
89
407
  this.rejectPending(fatal);
90
- this.onDisposed?.();
408
+ this.endLease();
91
409
  }
92
410
  rejectPending(error) {
93
411
  for (const pending of this.pending.values())
@@ -1,2 +1,4 @@
1
+ import type { LixBinding, LixStorageConfig, TelemetryDispatch } from "../binding-types.js";
1
2
  import type { WorkerConnection } from "./protocol.js";
3
+ export declare const openDirectLixBinding: undefined | ((storage: LixStorageConfig, telemetry?: TelemetryDispatch) => Promise<LixBinding>);
2
4
  export declare function createWorkerConnection(): WorkerConnection;
@@ -1,4 +1,6 @@
1
1
  /// <reference lib="webworker" />
2
+ // Browser/Wasm execution stays off the main thread.
3
+ export const openDirectLixBinding = undefined;
2
4
  export function createWorkerConnection() {
3
5
  const worker = new Worker(new URL("./entry.browser.js", import.meta.url), {
4
6
  type: "module",
@@ -1,2 +1,4 @@
1
+ import type { LixBinding, LixStorageConfig, TelemetryDispatch } from "../binding-types.js";
1
2
  import type { WorkerConnection } from "./protocol.js";
2
3
  export declare function createWorkerConnection(): WorkerConnection;
4
+ export declare const openDirectLixBinding: (storage: LixStorageConfig, telemetry?: TelemetryDispatch) => Promise<LixBinding>;
@@ -1,4 +1,5 @@
1
1
  import { Worker } from "node:worker_threads";
2
+ import { openLixBinding } from "../binding.node.js";
2
3
  export function createWorkerConnection() {
3
4
  const worker = new Worker(new URL("./entry.node.js", import.meta.url), {
4
5
  name: "lix",
@@ -33,3 +34,7 @@ export function createWorkerConnection() {
33
34
  },
34
35
  };
35
36
  }
37
+ /// Native Lix already owns a dedicated serialized engine actor. Routing it
38
+ /// through a second JavaScript worker adds two message-port hops per query
39
+ /// without adding isolation or concurrency.
40
+ export const openDirectLixBinding = (storage, telemetry) => openLixBinding(storage, telemetry);
@@ -1,5 +1,4 @@
1
1
  import { openLixBinding } from "#binding";
2
- import { createPluginRuntimeDispatch } from "../plugin-runtime.js";
3
2
  import { serializeWorkerError, } from "./protocol.js";
4
3
  export function startWorkerHost(endpoint) {
5
4
  let lix;
@@ -58,10 +57,14 @@ export function startWorkerHost(endpoint) {
58
57
  case "open":
59
58
  if (lix)
60
59
  throw workerStateError("Lix worker is already open");
61
- lix = await openLixBinding(operation.storage, createPluginRuntimeDispatch());
60
+ lix = await openLixBinding(operation.storage, operation.telemetryEnabled
61
+ ? (span) => endpoint.postMessage({ kind: "telemetry", span })
62
+ : undefined);
62
63
  return undefined;
63
64
  case "execute":
64
65
  return requiredLix().execute(operation.sql, operation.params, operation.options);
66
+ case "executeBatch":
67
+ return requiredLix().executeBatch(operation.statements, operation.options);
65
68
  case "beginTransaction": {
66
69
  const transaction = await requiredLix().beginTransaction();
67
70
  const transactionId = nextTransactionId++;
@@ -84,8 +87,24 @@ export function startWorkerHost(endpoint) {
84
87
  }
85
88
  case "activeBranchId":
86
89
  return requiredLix().activeBranchId();
90
+ case "activeAccountId":
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);
87
100
  case "createBranch":
88
101
  return requiredLix().createBranch(operation.options);
102
+ case "createCheckpoint":
103
+ return requiredLix().createCheckpoint();
104
+ case "undo":
105
+ return requiredLix().undo();
106
+ case "redo":
107
+ return requiredLix().redo();
89
108
  case "switchBranch":
90
109
  return requiredLix().switchBranch(operation.options);
91
110
  case "mergeBranchPreview":
@@ -96,6 +115,14 @@ export function startWorkerHost(endpoint) {
96
115
  return requiredLix().importFilesystemPaths(operation.paths);
97
116
  case "syncDiskToLix":
98
117
  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
+ }
99
126
  case "observe": {
100
127
  const events = await requiredLix().observe(operation.sql, operation.params);
101
128
  const observeId = nextObserveId++;
@@ -127,6 +154,13 @@ export function startWorkerHost(endpoint) {
127
154
  throw workerStateError("Lix worker is closed");
128
155
  return lix;
129
156
  }
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
+ }
130
164
  function requiredTransaction(transactionId) {
131
165
  const transaction = transactions.get(transactionId);
132
166
  if (!transaction) {
@@ -1,5 +1,5 @@
1
- import type { BindingParam, LixStorageConfig } from "../binding-types.js";
2
- import type { CreateBranchOptions, ExecuteOptions, MergeBranchOptions, SwitchBranchOptions } from "../types.js";
1
+ import type { BindingBatchStatement, BindingParam, LixStorageConfig } from "../binding-types.js";
2
+ import type { CreateBranchOptions, ExecuteOptions, JsonValue, LixBatchOptions, MergeBranchOptions, SwitchBranchOptions, LixTelemetrySpan } from "../types.js";
3
3
  export type WorkerRequest = {
4
4
  id: number;
5
5
  operation: WorkerOperation;
@@ -7,11 +7,16 @@ export type WorkerRequest = {
7
7
  export type WorkerOperation = {
8
8
  kind: "open";
9
9
  storage: LixStorageConfig;
10
+ telemetryEnabled: boolean;
10
11
  } | {
11
12
  kind: "execute";
12
13
  sql: string;
13
14
  params: BindingParam[];
14
15
  options?: ExecuteOptions;
16
+ } | {
17
+ kind: "executeBatch";
18
+ statements: BindingBatchStatement[];
19
+ options?: LixBatchOptions;
15
20
  } | {
16
21
  kind: "beginTransaction";
17
22
  } | {
@@ -28,9 +33,29 @@ export type WorkerOperation = {
28
33
  transactionId: number;
29
34
  } | {
30
35
  kind: "activeBranchId";
36
+ } | {
37
+ kind: "activeAccountId";
38
+ } | {
39
+ kind: "clientState.entries";
40
+ } | {
41
+ kind: "clientState.get";
42
+ key: string;
43
+ } | {
44
+ kind: "clientState.set";
45
+ key: string;
46
+ value: JsonValue;
47
+ } | {
48
+ kind: "clientState.delete";
49
+ key: string;
31
50
  } | {
32
51
  kind: "createBranch";
33
52
  options: CreateBranchOptions;
53
+ } | {
54
+ kind: "createCheckpoint";
55
+ } | {
56
+ kind: "undo";
57
+ } | {
58
+ kind: "redo";
34
59
  } | {
35
60
  kind: "switchBranch";
36
61
  options: SwitchBranchOptions;
@@ -45,6 +70,8 @@ export type WorkerOperation = {
45
70
  paths: string[];
46
71
  } | {
47
72
  kind: "syncDiskToLix";
73
+ } | {
74
+ kind: "exportSnapshot";
48
75
  } | {
49
76
  kind: "observe";
50
77
  sql: string;
@@ -91,6 +118,9 @@ export type WorkerResponse = {
91
118
  id: number;
92
119
  ok: false;
93
120
  error: SerializedWorkerError;
121
+ } | {
122
+ kind: "telemetry";
123
+ span: LixTelemetrySpan;
94
124
  };
95
125
  export declare function serializeWorkerError(error: unknown): SerializedWorkerError;
96
126
  export declare function deserializeWorkerError(error: SerializedWorkerError): Error;
package/dist/workerd.js CHANGED
@@ -31,7 +31,5 @@ export async function openMemoryLix(options = {}) {
31
31
  throw new TypeError("openMemoryLix() snapshot must be a Uint8Array");
32
32
  }
33
33
  initializeWasm();
34
- return openMemoryFromSnapshot(async () => {
35
- throw new Error("Lix plugin execution is unavailable in Workerd");
36
- }, options.snapshot);
34
+ return openMemoryFromSnapshot(undefined, options.snapshot);
37
35
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lix-js/sdk",
3
3
  "type": "module",
4
- "version": "0.8.4",
4
+ "version": "0.10.0",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -16,6 +16,14 @@
16
16
  "types": "./dist/workerd.d.ts",
17
17
  "workerd": "./dist/workerd.js",
18
18
  "default": "./dist/workerd.js"
19
+ },
20
+ "./remote-protocol": {
21
+ "types": "./dist/remote/protocol.d.ts",
22
+ "default": "./dist/remote/protocol.js"
23
+ },
24
+ "./local-storage-adapter": {
25
+ "types": "./dist/local-storage-adapter.d.ts",
26
+ "default": "./dist/local-storage-adapter.js"
19
27
  }
20
28
  },
21
29
  "imports": {
@@ -23,10 +31,6 @@
23
31
  "node": "./dist/binding.node.js",
24
32
  "default": "./dist/binding.browser.js"
25
33
  },
26
- "#jco-transpile": {
27
- "node": "@bytecodealliance/jco-transpile",
28
- "default": "./dist/jco-transpile.browser.js"
29
- },
30
34
  "#worker-factory": {
31
35
  "node": "./dist/worker/factory.node.js",
32
36
  "default": "./dist/worker/factory.browser.js"
@@ -36,13 +40,13 @@
36
40
  "dist"
37
41
  ],
38
42
  "scripts": {
39
- "build": "npm run clean && npm run build:native && npm run build:wasm && npm run build:ts && npm run build:jco-browser && npm run build:plugins",
40
- "build:browser": "npm run clean && npm run build:wasm && npm run build:ts && npm run build:jco-browser && npm run build:plugins",
41
- "build:jco-browser": "node ./scripts/build-jco-browser.js",
43
+ "build": "npm run clean && npm run build:native && npm run build:wasm && npm run build:ts && npm run build:plugins",
44
+ "build:browser": "npm run clean && npm run build:wasm && npm run build:ts && npm run build:plugins",
42
45
  "build:native": "node ./scripts/build-native.js",
43
46
  "build:wasm": "node ./scripts/build-wasm.js",
44
47
  "build:wasm:dev": "LIX_WASM_PROFILE=dev node ./scripts/build-wasm.js",
45
48
  "build:plugins": "node ./scripts/build-bundled-plugins.js",
49
+ "benchmark:plugin-reopen": "node ./scripts/benchmark-plugin-reopen.mjs",
46
50
  "clean": "node ./scripts/clean.js",
47
51
  "prepare:native-package": "node ./scripts/prepare-native-package.js",
48
52
  "build:ts": "tsc -p tsconfig.json",
@@ -53,21 +57,20 @@
53
57
  "typecheck": "tsc -p tsconfig.test.json --noEmit"
54
58
  },
55
59
  "optionalDependencies": {
56
- "@lix-js/sdk-darwin-arm64": "0.8.4",
57
- "@lix-js/sdk-linux-arm64": "0.8.4",
58
- "@lix-js/sdk-linux-x64": "0.8.4",
59
- "@lix-js/sdk-win32-x64": "0.8.4"
60
+ "@lix-js/sdk-darwin-arm64": "0.10.0",
61
+ "@lix-js/sdk-linux-arm64": "0.10.0",
62
+ "@lix-js/sdk-linux-x64": "0.10.0",
63
+ "@lix-js/sdk-win32-x64": "0.10.0"
60
64
  },
61
65
  "devDependencies": {
62
- "@vitest/browser-playwright": "4.0.18",
66
+ "@vitest/browser-playwright": "4.1.10",
63
67
  "@types/node": "^24.10.2",
64
68
  "playwright": "1.57.0",
65
69
  "typescript": "^5.5.4",
66
- "vitest": "^4.0.18"
70
+ "vite": "8.1.4",
71
+ "vitest": "4.1.10"
67
72
  },
68
73
  "dependencies": {
69
- "@bytecodealliance/jco-transpile": "0.4.2",
70
- "@bytecodealliance/preview2-shim": "0.19.0",
71
74
  "fflate": "^0.8.3"
72
75
  }
73
76
  }