@lix-js/sdk 0.8.3 → 0.9.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.
- package/README.md +82 -16
- package/dist/binding-types.d.ts +18 -2
- package/dist/binding.browser.d.ts +2 -2
- package/dist/binding.browser.js +3 -3
- package/dist/binding.node.d.ts +2 -2
- package/dist/binding.node.js +10 -4
- package/dist/bundled-plugins/plugin_csv_v2.lixplugin +0 -0
- package/dist/bundled-plugins/plugin_markdown_incremental_v2.lixplugin +0 -0
- package/dist/bundled-plugins.js +4 -4
- package/dist/client-state.d.ts +40 -0
- package/dist/client-state.js +178 -0
- package/dist/index.d.ts +2 -1
- package/dist/lix.d.ts +44 -0
- package/dist/lix.js +369 -0
- package/dist/local-storage-adapter.d.ts +26 -0
- package/dist/local-storage-adapter.js +117 -0
- package/dist/open-lix.d.ts +3 -34
- package/dist/open-lix.js +103 -170
- package/dist/remote/client.d.ts +8 -0
- package/dist/remote/client.js +1036 -0
- package/dist/remote/protocol.d.ts +166 -0
- package/dist/remote/protocol.js +362 -0
- package/dist/remote/sse.d.ts +12 -0
- package/dist/remote/sse.js +87 -0
- package/dist/snapshot-persistence.d.ts +7 -0
- package/dist/snapshot-persistence.js +26 -0
- package/dist/types.d.ts +58 -1
- package/dist/wasm/lix_js_sdk.d.ts +19 -4
- package/dist/wasm/lix_js_sdk.js +98 -17
- package/dist/wasm/lix_js_sdk_bg.wasm +0 -0
- package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +9 -2
- package/dist/worker/client.d.ts +23 -4
- package/dist/worker/client.js +287 -10
- package/dist/worker/host.js +30 -2
- package/dist/worker/protocol.d.ts +26 -2
- package/dist/workerd.d.ts +10 -0
- package/dist/workerd.js +7 -4
- package/package.json +19 -16
- package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
- package/dist/bundled-plugins/plugin_md_v2.lixplugin +0 -0
- package/dist/jco/js-component-bindgen-component.core.wasm +0 -0
- package/dist/jco/js-component-bindgen-component.core2.wasm +0 -0
- package/dist/jco/js-component-bindgen-component.js +0 -13662
- package/dist/jco-transpile.browser.d.ts +0 -14
- package/dist/jco-transpile.browser.js +0 -22
- package/dist/plugin-runtime.d.ts +0 -45
- package/dist/plugin-runtime.js +0 -124
package/dist/worker/client.js
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
import { createWorkerConnection } from "#worker-factory";
|
|
2
|
+
import { snapshotPersistenceAfterCommitError } from "../snapshot-persistence.js";
|
|
2
3
|
import { deserializeWorkerError, } from "./protocol.js";
|
|
3
|
-
|
|
4
|
-
|
|
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({
|
|
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,276 @@ 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
|
+
const client = await openLixWorker(storage, onDisposed, telemetry);
|
|
30
|
+
return workerBinding(client);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Opens a browser memory binding from an opaque snapshot and persists a fresh
|
|
34
|
+
* snapshot after every successful mutation. This is an internal composition
|
|
35
|
+
* seam for public storage adapters; it does not route workspace operations.
|
|
36
|
+
*/
|
|
37
|
+
export async function openPersistentLixWorkerBinding(options) {
|
|
38
|
+
if (!options || typeof options !== "object") {
|
|
39
|
+
throw new TypeError("openPersistentLixWorkerBinding() options must be an object");
|
|
40
|
+
}
|
|
41
|
+
if (!options.storage ||
|
|
42
|
+
typeof options.storage.load !== "function" ||
|
|
43
|
+
typeof options.storage.save !== "function") {
|
|
44
|
+
throw new TypeError("openPersistentLixWorkerBinding() storage must implement load() and save()");
|
|
45
|
+
}
|
|
46
|
+
if (typeof options.namespace !== "string" || options.namespace.length === 0) {
|
|
47
|
+
throw new TypeError("openPersistentLixWorkerBinding() namespace must be a non-empty string");
|
|
48
|
+
}
|
|
49
|
+
const snapshot = await options.storage.load(options.namespace);
|
|
50
|
+
if (snapshot !== undefined && !(snapshot instanceof Uint8Array)) {
|
|
51
|
+
throw new TypeError("Snapshot storage load() must return a Uint8Array");
|
|
52
|
+
}
|
|
53
|
+
const binding = await openLixWorkerBinding({
|
|
54
|
+
kind: "memory",
|
|
55
|
+
...(snapshot === undefined ? {} : { snapshot }),
|
|
56
|
+
}, undefined, options.telemetry);
|
|
57
|
+
const persistent = persistentSnapshotBinding(binding, options.storage, options.namespace);
|
|
58
|
+
if (snapshot === undefined) {
|
|
59
|
+
try {
|
|
60
|
+
await persistent.persist();
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
await binding.close().catch(() => undefined);
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return persistent.binding;
|
|
68
|
+
}
|
|
69
|
+
function workerBinding(client) {
|
|
70
|
+
let closed = false;
|
|
71
|
+
const request = (operation) => {
|
|
72
|
+
if (closed)
|
|
73
|
+
return Promise.reject(workerClosedError());
|
|
74
|
+
return client.request(operation);
|
|
75
|
+
};
|
|
76
|
+
const notify = (notification) => {
|
|
77
|
+
if (!closed)
|
|
78
|
+
client.notify(notification);
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
execute: (sql, params, options) => request({ kind: "execute", sql, params, options }),
|
|
82
|
+
executeBatch: (statements, options) => request({ kind: "executeBatch", statements, options }),
|
|
83
|
+
observe: async (sql, params) => {
|
|
84
|
+
const observeId = await request({
|
|
85
|
+
kind: "observe",
|
|
86
|
+
sql,
|
|
87
|
+
params,
|
|
88
|
+
});
|
|
89
|
+
return workerObserveBinding(request, notify, observeId);
|
|
90
|
+
},
|
|
91
|
+
beginTransaction: async () => {
|
|
92
|
+
const transactionId = await request({
|
|
93
|
+
kind: "beginTransaction",
|
|
94
|
+
});
|
|
95
|
+
return workerTransactionBinding(request, transactionId);
|
|
96
|
+
},
|
|
97
|
+
activeBranchId: () => request({ kind: "activeBranchId" }),
|
|
98
|
+
clientStateEntries: () => request({ kind: "clientState.entries" }),
|
|
99
|
+
clientStateGet: (key) => request({ kind: "clientState.get", key }),
|
|
100
|
+
clientStateSet: (key, value) => request({ kind: "clientState.set", key, value }),
|
|
101
|
+
clientStateDelete: (key) => request({ kind: "clientState.delete", key }),
|
|
102
|
+
createBranch: (options) => request({ kind: "createBranch", options }),
|
|
103
|
+
createCheckpoint: () => request({ kind: "createCheckpoint" }),
|
|
104
|
+
switchBranch: (options) => request({ kind: "switchBranch", options }),
|
|
105
|
+
importFilesystemPaths: (paths) => request({ kind: "importFilesystemPaths", paths }),
|
|
106
|
+
mergeBranchPreview: (options) => request({ kind: "mergeBranchPreview", options }),
|
|
107
|
+
mergeBranch: (options) => request({ kind: "mergeBranch", options }),
|
|
108
|
+
syncDiskToLix: () => request({ kind: "syncDiskToLix" }),
|
|
109
|
+
exportSnapshot: () => request({ kind: "exportSnapshot" }),
|
|
110
|
+
close: async () => {
|
|
111
|
+
if (closed)
|
|
112
|
+
return;
|
|
113
|
+
await request({ kind: "close" });
|
|
114
|
+
closed = true;
|
|
115
|
+
await releaseWorker(client);
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function persistentSnapshotBinding(binding, storage, namespace) {
|
|
120
|
+
let persistenceTail = Promise.resolve();
|
|
121
|
+
let closePromise;
|
|
122
|
+
let bindingClosed = false;
|
|
123
|
+
const persist = () => {
|
|
124
|
+
const operation = persistenceTail.then(async () => {
|
|
125
|
+
const exportSnapshot = binding.exportSnapshot;
|
|
126
|
+
if (!exportSnapshot) {
|
|
127
|
+
throw new Error("The open Lix binding does not support snapshot export");
|
|
128
|
+
}
|
|
129
|
+
const snapshot = await exportSnapshot.call(binding);
|
|
130
|
+
await storage.save(namespace, snapshot);
|
|
131
|
+
});
|
|
132
|
+
persistenceTail = operation.catch(() => undefined);
|
|
133
|
+
return operation;
|
|
134
|
+
};
|
|
135
|
+
const afterMutation = async (operation) => {
|
|
136
|
+
const result = await operation;
|
|
137
|
+
try {
|
|
138
|
+
await persist();
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
// The Rust transaction is already committed. Preserve that fact so
|
|
142
|
+
// synchronous facades can reflect the live session value while still
|
|
143
|
+
// reporting that durability failed.
|
|
144
|
+
throw snapshotPersistenceAfterCommitError(error);
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
};
|
|
148
|
+
const persistentBinding = {
|
|
149
|
+
execute: (sql, params, executeOptions) => afterMutation(binding.execute(sql, params, executeOptions)),
|
|
150
|
+
executeBatch: (statements, batchOptions) => afterMutation(binding.executeBatch(statements, batchOptions)),
|
|
151
|
+
observe: (sql, params) => binding.observe(sql, params),
|
|
152
|
+
beginTransaction: async () => {
|
|
153
|
+
const transaction = await binding.beginTransaction();
|
|
154
|
+
return {
|
|
155
|
+
execute: (sql, params, executeOptions) => transaction.execute(sql, params, executeOptions),
|
|
156
|
+
commit: () => afterMutation(transaction.commit()),
|
|
157
|
+
rollback: () => transaction.rollback(),
|
|
158
|
+
};
|
|
159
|
+
},
|
|
160
|
+
activeBranchId: () => binding.activeBranchId(),
|
|
161
|
+
clientStateEntries: () => {
|
|
162
|
+
const method = binding.clientStateEntries;
|
|
163
|
+
if (!method)
|
|
164
|
+
return Promise.reject(clientStateUnsupportedError());
|
|
165
|
+
return method.call(binding);
|
|
166
|
+
},
|
|
167
|
+
clientStateGet: (key) => {
|
|
168
|
+
const method = binding.clientStateGet;
|
|
169
|
+
if (!method)
|
|
170
|
+
return Promise.reject(clientStateUnsupportedError());
|
|
171
|
+
return method.call(binding, key);
|
|
172
|
+
},
|
|
173
|
+
clientStateSet: (key, value) => {
|
|
174
|
+
const method = binding.clientStateSet;
|
|
175
|
+
if (!method)
|
|
176
|
+
return Promise.reject(clientStateUnsupportedError());
|
|
177
|
+
return afterMutation(method.call(binding, key, value));
|
|
178
|
+
},
|
|
179
|
+
clientStateDelete: (key) => {
|
|
180
|
+
const method = binding.clientStateDelete;
|
|
181
|
+
if (!method)
|
|
182
|
+
return Promise.reject(clientStateUnsupportedError());
|
|
183
|
+
return afterMutation(method.call(binding, key));
|
|
184
|
+
},
|
|
185
|
+
createBranch: (branchOptions) => afterMutation(binding.createBranch(branchOptions)),
|
|
186
|
+
createCheckpoint: () => afterMutation(binding.createCheckpoint()),
|
|
187
|
+
switchBranch: (branchOptions) => afterMutation(binding.switchBranch(branchOptions)),
|
|
188
|
+
importFilesystemPaths: (paths) => afterMutation(binding.importFilesystemPaths(paths)),
|
|
189
|
+
mergeBranchPreview: (branchOptions) => binding.mergeBranchPreview(branchOptions),
|
|
190
|
+
mergeBranch: (branchOptions) => afterMutation(binding.mergeBranch(branchOptions)),
|
|
191
|
+
syncDiskToLix: () => afterMutation(binding.syncDiskToLix()),
|
|
192
|
+
exportSnapshot: () => {
|
|
193
|
+
const exportSnapshot = binding.exportSnapshot;
|
|
194
|
+
if (!exportSnapshot) {
|
|
195
|
+
return Promise.reject(new Error("The open Lix binding does not support snapshot export"));
|
|
196
|
+
}
|
|
197
|
+
return exportSnapshot.call(binding);
|
|
198
|
+
},
|
|
199
|
+
close: () => {
|
|
200
|
+
if (closePromise)
|
|
201
|
+
return closePromise;
|
|
202
|
+
closePromise = (async () => {
|
|
203
|
+
let persistenceError;
|
|
204
|
+
try {
|
|
205
|
+
await persist();
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
persistenceError = error;
|
|
209
|
+
}
|
|
210
|
+
await binding.close();
|
|
211
|
+
bindingClosed = true;
|
|
212
|
+
if (persistenceError !== undefined)
|
|
213
|
+
throw persistenceError;
|
|
214
|
+
})();
|
|
215
|
+
void closePromise.catch((error) => {
|
|
216
|
+
if (!bindingClosed && isActiveTransactionCloseError(error)) {
|
|
217
|
+
closePromise = undefined;
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
return closePromise;
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
return { binding: persistentBinding, persist };
|
|
224
|
+
}
|
|
225
|
+
function isActiveTransactionCloseError(error) {
|
|
226
|
+
return (typeof error === "object" &&
|
|
227
|
+
error !== null &&
|
|
228
|
+
"code" in error &&
|
|
229
|
+
error.code === "LIX_INVALID_TRANSACTION_STATE");
|
|
230
|
+
}
|
|
231
|
+
function clientStateUnsupportedError() {
|
|
232
|
+
return new Error("The open Lix binding does not support typed client state");
|
|
233
|
+
}
|
|
234
|
+
function workerTransactionBinding(request, transactionId) {
|
|
235
|
+
return {
|
|
236
|
+
execute: (sql, params, options) => request({
|
|
237
|
+
kind: "transaction.execute",
|
|
238
|
+
transactionId,
|
|
239
|
+
sql,
|
|
240
|
+
params,
|
|
241
|
+
options,
|
|
242
|
+
}),
|
|
243
|
+
commit: () => request({ kind: "transaction.commit", transactionId }),
|
|
244
|
+
rollback: () => request({ kind: "transaction.rollback", transactionId }),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
function workerObserveBinding(request, notify, observeId) {
|
|
248
|
+
return {
|
|
249
|
+
next: () => request({ kind: "observe.next", observeId }),
|
|
250
|
+
close: () => notify({ kind: "observe.close", observeId }),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
async function releaseWorker(client) {
|
|
254
|
+
client.endLease();
|
|
255
|
+
if (!client.isDisposed && idleWorkers.length < MAX_IDLE_WORKERS) {
|
|
256
|
+
idleWorkers.push(client);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
await client.terminate();
|
|
260
|
+
}
|
|
14
261
|
export class LixWorkerClient {
|
|
15
|
-
onDisposed;
|
|
16
262
|
connection;
|
|
17
263
|
nextRequestId = 1;
|
|
18
264
|
pending = new Map();
|
|
19
265
|
disposed = false;
|
|
20
|
-
|
|
21
|
-
|
|
266
|
+
leased = false;
|
|
267
|
+
onDisposed;
|
|
268
|
+
telemetry;
|
|
269
|
+
constructor(connection = createWorkerConnection()) {
|
|
22
270
|
this.connection = connection;
|
|
23
271
|
connection.onMessage((message) => this.handleMessage(message));
|
|
24
272
|
connection.onFatal((error) => this.handleFatal(error));
|
|
25
273
|
}
|
|
274
|
+
get isDisposed() {
|
|
275
|
+
return this.disposed;
|
|
276
|
+
}
|
|
277
|
+
beginLease(onDisposed, telemetry) {
|
|
278
|
+
if (this.disposed || this.leased)
|
|
279
|
+
throw workerClosedError();
|
|
280
|
+
this.leased = true;
|
|
281
|
+
this.onDisposed = onDisposed;
|
|
282
|
+
this.telemetry = telemetry;
|
|
283
|
+
}
|
|
284
|
+
endLease() {
|
|
285
|
+
if (!this.leased)
|
|
286
|
+
return;
|
|
287
|
+
this.leased = false;
|
|
288
|
+
const onDisposed = this.onDisposed;
|
|
289
|
+
this.onDisposed = undefined;
|
|
290
|
+
this.telemetry = undefined;
|
|
291
|
+
onDisposed?.();
|
|
292
|
+
}
|
|
26
293
|
request(operation) {
|
|
27
|
-
if (this.disposed)
|
|
294
|
+
if (this.disposed || !this.leased) {
|
|
28
295
|
return Promise.reject(workerClosedError());
|
|
296
|
+
}
|
|
29
297
|
const id = this.nextRequestId++;
|
|
30
298
|
if (this.pending.size === 0)
|
|
31
299
|
this.connection.ref();
|
|
@@ -46,7 +314,7 @@ export class LixWorkerClient {
|
|
|
46
314
|
});
|
|
47
315
|
}
|
|
48
316
|
notify(notification) {
|
|
49
|
-
if (this.disposed)
|
|
317
|
+
if (this.disposed || !this.leased)
|
|
50
318
|
return;
|
|
51
319
|
try {
|
|
52
320
|
this.connection.postMessage(notification);
|
|
@@ -64,10 +332,19 @@ export class LixWorkerClient {
|
|
|
64
332
|
await this.connection.terminate();
|
|
65
333
|
}
|
|
66
334
|
finally {
|
|
67
|
-
this.
|
|
335
|
+
this.endLease();
|
|
68
336
|
}
|
|
69
337
|
}
|
|
70
338
|
handleMessage(message) {
|
|
339
|
+
if ("kind" in message) {
|
|
340
|
+
try {
|
|
341
|
+
this.telemetry?.onSpan(message.span);
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
// Telemetry callbacks are isolated from Lix operation results.
|
|
345
|
+
}
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
71
348
|
const pending = this.pending.get(message.id);
|
|
72
349
|
if (!pending)
|
|
73
350
|
return;
|
|
@@ -87,7 +364,7 @@ export class LixWorkerClient {
|
|
|
87
364
|
fatal.name = "LixError";
|
|
88
365
|
fatal.code ??= "LIX_WORKER_TERMINATED";
|
|
89
366
|
this.rejectPending(fatal);
|
|
90
|
-
this.
|
|
367
|
+
this.endLease();
|
|
91
368
|
}
|
|
92
369
|
rejectPending(error) {
|
|
93
370
|
for (const pending of this.pending.values())
|
package/dist/worker/host.js
CHANGED
|
@@ -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,
|
|
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,18 @@ export function startWorkerHost(endpoint) {
|
|
|
84
87
|
}
|
|
85
88
|
case "activeBranchId":
|
|
86
89
|
return requiredLix().activeBranchId();
|
|
90
|
+
case "clientState.entries":
|
|
91
|
+
return requiredClientStateMethod("clientStateEntries")();
|
|
92
|
+
case "clientState.get":
|
|
93
|
+
return requiredClientStateMethod("clientStateGet")(operation.key);
|
|
94
|
+
case "clientState.set":
|
|
95
|
+
return requiredClientStateMethod("clientStateSet")(operation.key, operation.value);
|
|
96
|
+
case "clientState.delete":
|
|
97
|
+
return requiredClientStateMethod("clientStateDelete")(operation.key);
|
|
87
98
|
case "createBranch":
|
|
88
99
|
return requiredLix().createBranch(operation.options);
|
|
100
|
+
case "createCheckpoint":
|
|
101
|
+
return requiredLix().createCheckpoint();
|
|
89
102
|
case "switchBranch":
|
|
90
103
|
return requiredLix().switchBranch(operation.options);
|
|
91
104
|
case "mergeBranchPreview":
|
|
@@ -96,6 +109,14 @@ export function startWorkerHost(endpoint) {
|
|
|
96
109
|
return requiredLix().importFilesystemPaths(operation.paths);
|
|
97
110
|
case "syncDiskToLix":
|
|
98
111
|
return requiredLix().syncDiskToLix();
|
|
112
|
+
case "exportSnapshot": {
|
|
113
|
+
const lix = requiredLix();
|
|
114
|
+
const exportSnapshot = lix.exportSnapshot;
|
|
115
|
+
if (!exportSnapshot) {
|
|
116
|
+
throw workerStateError("The open Lix storage does not support snapshot export");
|
|
117
|
+
}
|
|
118
|
+
return exportSnapshot.call(lix);
|
|
119
|
+
}
|
|
99
120
|
case "observe": {
|
|
100
121
|
const events = await requiredLix().observe(operation.sql, operation.params);
|
|
101
122
|
const observeId = nextObserveId++;
|
|
@@ -127,6 +148,13 @@ export function startWorkerHost(endpoint) {
|
|
|
127
148
|
throw workerStateError("Lix worker is closed");
|
|
128
149
|
return lix;
|
|
129
150
|
}
|
|
151
|
+
function requiredClientStateMethod(key) {
|
|
152
|
+
const method = requiredLix()[key];
|
|
153
|
+
if (!method) {
|
|
154
|
+
throw workerStateError("The open Lix binding does not support typed client state");
|
|
155
|
+
}
|
|
156
|
+
return method.bind(requiredLix());
|
|
157
|
+
}
|
|
130
158
|
function requiredTransaction(transactionId) {
|
|
131
159
|
const transaction = transactions.get(transactionId);
|
|
132
160
|
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,23 @@ export type WorkerOperation = {
|
|
|
28
33
|
transactionId: number;
|
|
29
34
|
} | {
|
|
30
35
|
kind: "activeBranchId";
|
|
36
|
+
} | {
|
|
37
|
+
kind: "clientState.entries";
|
|
38
|
+
} | {
|
|
39
|
+
kind: "clientState.get";
|
|
40
|
+
key: string;
|
|
41
|
+
} | {
|
|
42
|
+
kind: "clientState.set";
|
|
43
|
+
key: string;
|
|
44
|
+
value: JsonValue;
|
|
45
|
+
} | {
|
|
46
|
+
kind: "clientState.delete";
|
|
47
|
+
key: string;
|
|
31
48
|
} | {
|
|
32
49
|
kind: "createBranch";
|
|
33
50
|
options: CreateBranchOptions;
|
|
51
|
+
} | {
|
|
52
|
+
kind: "createCheckpoint";
|
|
34
53
|
} | {
|
|
35
54
|
kind: "switchBranch";
|
|
36
55
|
options: SwitchBranchOptions;
|
|
@@ -45,6 +64,8 @@ export type WorkerOperation = {
|
|
|
45
64
|
paths: string[];
|
|
46
65
|
} | {
|
|
47
66
|
kind: "syncDiskToLix";
|
|
67
|
+
} | {
|
|
68
|
+
kind: "exportSnapshot";
|
|
48
69
|
} | {
|
|
49
70
|
kind: "observe";
|
|
50
71
|
sql: string;
|
|
@@ -91,6 +112,9 @@ export type WorkerResponse = {
|
|
|
91
112
|
id: number;
|
|
92
113
|
ok: false;
|
|
93
114
|
error: SerializedWorkerError;
|
|
115
|
+
} | {
|
|
116
|
+
kind: "telemetry";
|
|
117
|
+
span: LixTelemetrySpan;
|
|
94
118
|
};
|
|
95
119
|
export declare function serializeWorkerError(error: unknown): SerializedWorkerError;
|
|
96
120
|
export declare function deserializeWorkerError(error: SerializedWorkerError): Error;
|
package/dist/workerd.d.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import type { LixBinding } from "./binding-types.js";
|
|
2
|
+
export type SqlScriptPlan = {
|
|
3
|
+
statements: SqlScriptStatement[];
|
|
4
|
+
};
|
|
5
|
+
export type SqlScriptStatement = {
|
|
6
|
+
sql: string;
|
|
7
|
+
paramStart: number;
|
|
8
|
+
paramEnd: number;
|
|
9
|
+
};
|
|
2
10
|
export interface OpenMemoryLixOptions {
|
|
3
11
|
snapshot?: Uint8Array;
|
|
4
12
|
}
|
|
5
13
|
export interface WorkerdLixBinding extends LixBinding {
|
|
6
14
|
exportSnapshot(): Promise<Uint8Array>;
|
|
7
15
|
}
|
|
16
|
+
/** Parses SQL using the same DataFusion dialect and transaction policy as Lix. */
|
|
17
|
+
export declare function parseSqlScript(sql: string, providedParamCount: number): SqlScriptPlan;
|
|
8
18
|
/**
|
|
9
19
|
* Opens an in-memory Lix binding directly in a Cloudflare Worker isolate.
|
|
10
20
|
*
|
package/dist/workerd.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @ts-expect-error Generated by build:wasm.
|
|
3
3
|
import wasmModule from "./wasm/lix_js_sdk_bg.wasm";
|
|
4
4
|
// @ts-expect-error Generated by build:wasm.
|
|
5
|
-
import { initSync, openMemoryFromSnapshot } from "./wasm/lix_js_sdk.js";
|
|
5
|
+
import { initSync, openMemoryFromSnapshot, parseSqlScript as parseSqlScriptBinding } from "./wasm/lix_js_sdk.js";
|
|
6
6
|
let initialized = false;
|
|
7
7
|
function initializeWasm() {
|
|
8
8
|
if (initialized)
|
|
@@ -10,6 +10,11 @@ function initializeWasm() {
|
|
|
10
10
|
initSync({ module: wasmModule });
|
|
11
11
|
initialized = true;
|
|
12
12
|
}
|
|
13
|
+
/** Parses SQL using the same DataFusion dialect and transaction policy as Lix. */
|
|
14
|
+
export function parseSqlScript(sql, providedParamCount) {
|
|
15
|
+
initializeWasm();
|
|
16
|
+
return parseSqlScriptBinding(sql, providedParamCount);
|
|
17
|
+
}
|
|
13
18
|
/**
|
|
14
19
|
* Opens an in-memory Lix binding directly in a Cloudflare Worker isolate.
|
|
15
20
|
*
|
|
@@ -26,7 +31,5 @@ export async function openMemoryLix(options = {}) {
|
|
|
26
31
|
throw new TypeError("openMemoryLix() snapshot must be a Uint8Array");
|
|
27
32
|
}
|
|
28
33
|
initializeWasm();
|
|
29
|
-
return openMemoryFromSnapshot(
|
|
30
|
-
throw new Error("Lix plugin execution is unavailable in Workerd");
|
|
31
|
-
}, options.snapshot);
|
|
34
|
+
return openMemoryFromSnapshot(undefined, options.snapshot);
|
|
32
35
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lix-js/sdk",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.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:
|
|
40
|
-
"build:browser": "npm run clean && npm run build:wasm && npm run build:ts && npm run build:
|
|
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.
|
|
57
|
-
"@lix-js/sdk-linux-arm64": "0.
|
|
58
|
-
"@lix-js/sdk-linux-x64": "0.
|
|
59
|
-
"@lix-js/sdk-win32-x64": "0.
|
|
60
|
+
"@lix-js/sdk-darwin-arm64": "0.9.0",
|
|
61
|
+
"@lix-js/sdk-linux-arm64": "0.9.0",
|
|
62
|
+
"@lix-js/sdk-linux-x64": "0.9.0",
|
|
63
|
+
"@lix-js/sdk-win32-x64": "0.9.0"
|
|
60
64
|
},
|
|
61
65
|
"devDependencies": {
|
|
62
|
-
"@vitest/browser-playwright": "4.
|
|
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
|
-
"
|
|
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
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|