@lix-js/sdk 0.12.2 → 0.14.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 +40 -10
- package/dist/binding-types.d.ts +37 -9
- package/dist/binding.browser.d.ts +2 -2
- package/dist/binding.browser.js +25 -10
- package/dist/binding.node-wasm.d.ts +2 -2
- package/dist/binding.node-wasm.js +8 -4
- package/dist/binding.node.d.ts +3 -3
- package/dist/binding.node.js +70 -13
- package/dist/browser-wasm-init.d.ts +14 -0
- package/dist/browser-wasm-init.js +16 -0
- package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
- package/dist/bundled-plugins/plugin_markdown.lixplugin +0 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/lix.d.ts +27 -5
- package/dist/lix.js +135 -12
- package/dist/open-lix.d.ts +4 -5
- package/dist/open-lix.js +173 -33
- package/dist/remote/client.d.ts +1 -2
- package/dist/remote/client.js +58 -1151
- package/dist/remote/server-protocol.d.ts +5 -6
- package/dist/remote/server-protocol.js +40 -9
- package/dist/result.d.ts +6 -13
- package/dist/result.js +9 -35
- package/dist/snapshot-restore.d.ts +6 -0
- package/dist/snapshot-restore.js +101 -0
- package/dist/storage-adapter.d.ts +175 -19
- package/dist/storage-adapter.js +21 -0
- package/dist/types.d.ts +101 -31
- package/dist/value.d.ts +1 -0
- package/dist/value.js +8 -0
- package/dist/wasm/lix_js_sdk.d.ts +119 -24
- package/dist/wasm/lix_js_sdk.js +599 -78
- package/dist/wasm/lix_js_sdk_bg.wasm +0 -0
- package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +47 -6
- package/dist/worker/client.d.ts +27 -5
- package/dist/worker/client.js +458 -45
- package/dist/worker/factory.browser.d.ts +2 -2
- package/dist/worker/factory.node.d.ts +3 -2
- package/dist/worker/factory.node.js +18 -12
- package/dist/worker/host.d.ts +2 -1
- package/dist/worker/host.js +283 -37
- package/dist/worker/protocol.d.ts +80 -3
- package/package.json +6 -10
- package/dist/indexeddb-backend.d.ts +0 -19
- package/dist/indexeddb-backend.js +0 -121
- package/dist/remote/sse.d.ts +0 -12
- package/dist/remote/sse.js +0 -87
- package/dist/workerd.d.ts +0 -25
- package/dist/workerd.js +0 -35
package/dist/worker/host.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { type WorkerHostEndpoint } from "./protocol.js";
|
|
1
|
+
import { type WorkerHostEndpoint, type WorkerSyncFetchResponse } from "./protocol.js";
|
|
2
2
|
export declare function startWorkerHost(endpoint: WorkerHostEndpoint): void;
|
|
3
|
+
export declare function responseFromSyncFetch(resolved: WorkerSyncFetchResponse): Response;
|
package/dist/worker/host.js
CHANGED
|
@@ -1,24 +1,66 @@
|
|
|
1
1
|
import { openLixBinding } from "#binding";
|
|
2
|
-
import { serializeWorkerError, } from "./protocol.js";
|
|
2
|
+
import { deserializeWorkerError, serializeWorkerError, } from "./protocol.js";
|
|
3
3
|
export function startWorkerHost(endpoint) {
|
|
4
|
-
|
|
4
|
+
const sessions = new Map();
|
|
5
|
+
let nextSessionId = 1;
|
|
5
6
|
let nextTransactionId = 1;
|
|
6
7
|
let nextObserveId = 1;
|
|
7
8
|
const transactions = new Map();
|
|
8
9
|
const observations = new Map();
|
|
10
|
+
let nextSnapshotExportId = 1;
|
|
11
|
+
const snapshotExports = new Map();
|
|
12
|
+
const snapshotInputs = new Map();
|
|
13
|
+
let nextSyncRequestId = 1;
|
|
14
|
+
const pendingSyncHeaders = new Map();
|
|
15
|
+
const pendingSyncFetch = new Map();
|
|
9
16
|
let finiteQueue = Promise.resolve();
|
|
10
17
|
endpoint.onMessage((message) => {
|
|
11
18
|
if (!("id" in message)) {
|
|
12
19
|
handleNotification(message);
|
|
13
20
|
return;
|
|
14
21
|
}
|
|
15
|
-
if (message.operation.kind === "
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
if (message.operation.kind === "openSnapshot.write" ||
|
|
23
|
+
message.operation.kind === "openSnapshot.finish") {
|
|
24
|
+
const operation = message.operation;
|
|
25
|
+
void respond(message, () => handleSnapshotInput(operation));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (message.operation.kind === "open" &&
|
|
29
|
+
message.operation.snapshotId !== undefined) {
|
|
30
|
+
ensureSnapshotInput(message.operation.snapshotId);
|
|
31
|
+
}
|
|
32
|
+
if (message.operation.kind === "observe.next" ||
|
|
33
|
+
message.operation.kind === "exportSnapshot.next" ||
|
|
34
|
+
message.operation.kind === "exportSnapshot.cancel") {
|
|
35
|
+
if (message.operation.kind === "observe.next") {
|
|
36
|
+
const observeId = message.operation.observeId;
|
|
37
|
+
void respond(message, () => handleObserveNext(observeId, message.telemetryParent));
|
|
38
|
+
}
|
|
39
|
+
else if (message.operation.kind === "exportSnapshot.next") {
|
|
40
|
+
const exportId = message.operation.exportId;
|
|
41
|
+
void respond(message, () => handleSnapshotNext(exportId));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const exportId = message.operation.exportId;
|
|
45
|
+
void respond(message, () => handleSnapshotCancel(exportId));
|
|
46
|
+
}
|
|
18
47
|
return;
|
|
19
48
|
}
|
|
20
49
|
finiteQueue = finiteQueue.then(async () => {
|
|
21
|
-
|
|
50
|
+
try {
|
|
51
|
+
await respond(message, async () => {
|
|
52
|
+
if (message.operation.kind !== "open") {
|
|
53
|
+
requiredLix(message.sessionId).setTelemetryParent(message.telemetryParent);
|
|
54
|
+
}
|
|
55
|
+
return handleFiniteOperation(message.sessionId, message.operation, message.telemetryParent);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
// The mutable FFI carrier is safe only within this serialized
|
|
60
|
+
// operation. Clear it before another request or background task
|
|
61
|
+
// can accidentally inherit a stale remote parent.
|
|
62
|
+
(sessions.get(message.sessionId) ?? sessions.get(0))?.setTelemetryParent();
|
|
63
|
+
}
|
|
22
64
|
});
|
|
23
65
|
});
|
|
24
66
|
function handleNotification(message) {
|
|
@@ -29,6 +71,13 @@ export function startWorkerHost(endpoint) {
|
|
|
29
71
|
events?.close();
|
|
30
72
|
break;
|
|
31
73
|
}
|
|
74
|
+
case "openSnapshot.cancel": {
|
|
75
|
+
const input = snapshotInputs.get(message.snapshotId);
|
|
76
|
+
snapshotInputs.delete(message.snapshotId);
|
|
77
|
+
if (input)
|
|
78
|
+
void input.writer.abort().catch(() => undefined);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
32
81
|
case "transaction.abandon":
|
|
33
82
|
finiteQueue = finiteQueue.then(async () => {
|
|
34
83
|
const transaction = transactions.get(message.transactionId);
|
|
@@ -37,6 +86,28 @@ export function startWorkerHost(endpoint) {
|
|
|
37
86
|
await transaction.rollback().catch(() => undefined);
|
|
38
87
|
});
|
|
39
88
|
break;
|
|
89
|
+
case "sync.headers.result": {
|
|
90
|
+
const pending = pendingSyncHeaders.get(message.requestId);
|
|
91
|
+
pendingSyncHeaders.delete(message.requestId);
|
|
92
|
+
if (!pending)
|
|
93
|
+
break;
|
|
94
|
+
if (message.result.ok)
|
|
95
|
+
pending.resolve(message.result.headers);
|
|
96
|
+
else
|
|
97
|
+
pending.reject(deserializeWorkerError(message.result.error));
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case "sync.fetch.result": {
|
|
101
|
+
const pending = pendingSyncFetch.get(message.requestId);
|
|
102
|
+
pendingSyncFetch.delete(message.requestId);
|
|
103
|
+
if (!pending)
|
|
104
|
+
break;
|
|
105
|
+
if (message.result.ok)
|
|
106
|
+
pending.resolve(message.result.response);
|
|
107
|
+
else
|
|
108
|
+
pending.reject(deserializeWorkerError(message.result.error));
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
40
111
|
}
|
|
41
112
|
}
|
|
42
113
|
async function respond(request, operation) {
|
|
@@ -52,21 +123,45 @@ export function startWorkerHost(endpoint) {
|
|
|
52
123
|
});
|
|
53
124
|
}
|
|
54
125
|
}
|
|
55
|
-
async function handleFiniteOperation(operation) {
|
|
126
|
+
async function handleFiniteOperation(sessionId, operation, telemetryParent) {
|
|
56
127
|
switch (operation.kind) {
|
|
57
128
|
case "open":
|
|
58
|
-
if (
|
|
129
|
+
if (sessions.size > 0)
|
|
59
130
|
throw workerStateError("Lix worker is already open");
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
131
|
+
{
|
|
132
|
+
const snapshot = operation.snapshotId === undefined
|
|
133
|
+
? undefined
|
|
134
|
+
: requiredSnapshotInput(operation.snapshotId).readable;
|
|
135
|
+
try {
|
|
136
|
+
const opened = await openLixBinding(operation.storage, operation.telemetryEnabled
|
|
137
|
+
? (span) => endpoint.postMessage({ kind: "telemetry", span })
|
|
138
|
+
: undefined, telemetryParent, createSyncServerBridge(operation.server), operation.progressEnabled
|
|
139
|
+
? (progress) => endpoint.postMessage({ kind: "open.progress", progress })
|
|
140
|
+
: undefined, snapshot);
|
|
141
|
+
sessions.set(0, opened);
|
|
142
|
+
return opened.openReport?.();
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
if (operation.snapshotId !== undefined) {
|
|
146
|
+
snapshotInputs.delete(operation.snapshotId);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
case "openSnapshot.write":
|
|
151
|
+
case "openSnapshot.finish":
|
|
152
|
+
throw workerStateError("snapshot input uses the restore lane");
|
|
153
|
+
case "openAnotherSession": {
|
|
154
|
+
const opened = await requiredLix(sessionId).openAnotherSession(operation.options);
|
|
155
|
+
const openedSessionId = nextSessionId++;
|
|
156
|
+
sessions.set(openedSessionId, opened);
|
|
157
|
+
return openedSessionId;
|
|
158
|
+
}
|
|
64
159
|
case "execute":
|
|
65
|
-
return requiredLix().execute(operation.sql, operation.params, operation.options);
|
|
160
|
+
return requiredLix(sessionId).execute(operation.sql, operation.params, operation.options);
|
|
66
161
|
case "executeBatch":
|
|
67
|
-
return requiredLix().executeBatch(operation.statements, operation.options);
|
|
162
|
+
return requiredLix(sessionId).executeBatch(operation.statements, operation.options);
|
|
68
163
|
case "beginTransaction": {
|
|
69
|
-
const transaction = await requiredLix().beginTransaction();
|
|
164
|
+
const transaction = await requiredLix(sessionId).beginTransaction();
|
|
70
165
|
const transactionId = nextTransactionId++;
|
|
71
166
|
transactions.set(transactionId, transaction);
|
|
72
167
|
return transactionId;
|
|
@@ -86,56 +181,176 @@ export function startWorkerHost(endpoint) {
|
|
|
86
181
|
return undefined;
|
|
87
182
|
}
|
|
88
183
|
case "activeBranchId":
|
|
89
|
-
return requiredLix().activeBranchId();
|
|
184
|
+
return requiredLix(sessionId).activeBranchId();
|
|
90
185
|
case "activeAccountId":
|
|
91
|
-
return requiredLix().activeAccountId();
|
|
186
|
+
return requiredLix(sessionId).activeAccountId();
|
|
92
187
|
case "createBranch":
|
|
93
|
-
return requiredLix().createBranch(operation.options);
|
|
94
|
-
case "createCheckpoint":
|
|
95
|
-
return requiredLix().createCheckpoint();
|
|
188
|
+
return requiredLix(sessionId).createBranch(operation.options);
|
|
96
189
|
case "undo":
|
|
97
|
-
return requiredLix().undo();
|
|
190
|
+
return requiredLix(sessionId).undo();
|
|
98
191
|
case "redo":
|
|
99
|
-
return requiredLix().redo();
|
|
192
|
+
return requiredLix(sessionId).redo();
|
|
100
193
|
case "switchBranch":
|
|
101
|
-
return requiredLix().switchBranch(operation.options);
|
|
194
|
+
return requiredLix(sessionId).switchBranch(operation.options);
|
|
102
195
|
case "mergeBranchPreview":
|
|
103
|
-
return requiredLix().mergeBranchPreview(operation.options);
|
|
196
|
+
return requiredLix(sessionId).mergeBranchPreview(operation.options);
|
|
104
197
|
case "mergeBranch":
|
|
105
|
-
return requiredLix().mergeBranch(operation.options);
|
|
198
|
+
return requiredLix(sessionId).mergeBranch(operation.options);
|
|
106
199
|
case "importFilesystemPaths":
|
|
107
|
-
return requiredLix().importFilesystemPaths(operation.paths);
|
|
200
|
+
return requiredLix(sessionId).importFilesystemPaths(operation.paths);
|
|
108
201
|
case "syncDiskToLix":
|
|
109
|
-
return requiredLix().syncDiskToLix();
|
|
202
|
+
return requiredLix(sessionId).syncDiskToLix();
|
|
203
|
+
case "exportSnapshot":
|
|
204
|
+
{
|
|
205
|
+
const binding = requiredLix(sessionId);
|
|
206
|
+
const exportSnapshot = binding.exportSnapshot;
|
|
207
|
+
if (!exportSnapshot) {
|
|
208
|
+
throw workerStateError("this Lix binding cannot export snapshots");
|
|
209
|
+
}
|
|
210
|
+
const snapshot = exportSnapshot.call(binding);
|
|
211
|
+
const exportId = nextSnapshotExportId++;
|
|
212
|
+
snapshotExports.set(exportId, snapshot);
|
|
213
|
+
return exportId;
|
|
214
|
+
}
|
|
215
|
+
case "exportSnapshot.next":
|
|
216
|
+
throw workerStateError("snapshot pulls bypass the finite operation queue");
|
|
217
|
+
case "exportSnapshot.cancel":
|
|
218
|
+
throw workerStateError("snapshot cancellation bypasses the finite operation queue");
|
|
110
219
|
case "observe": {
|
|
111
|
-
const events = await requiredLix().observe(operation.sql, operation.params);
|
|
220
|
+
const events = await requiredLix(sessionId).observe(operation.sql, operation.params);
|
|
112
221
|
const observeId = nextObserveId++;
|
|
113
222
|
observations.set(observeId, events);
|
|
114
223
|
return observeId;
|
|
115
224
|
}
|
|
116
225
|
case "close": {
|
|
117
|
-
const openLix = requiredLix();
|
|
226
|
+
const openLix = requiredLix(sessionId);
|
|
118
227
|
await openLix.close();
|
|
119
|
-
|
|
120
|
-
events.close();
|
|
121
|
-
observations.clear();
|
|
122
|
-
transactions.clear();
|
|
123
|
-
lix = undefined;
|
|
228
|
+
sessions.delete(sessionId);
|
|
124
229
|
return undefined;
|
|
125
230
|
}
|
|
126
231
|
case "observe.next":
|
|
127
232
|
throw workerStateError("observe.next must use the observation lane");
|
|
128
233
|
}
|
|
129
234
|
}
|
|
130
|
-
async function
|
|
235
|
+
async function handleSnapshotNext(exportId) {
|
|
236
|
+
const snapshot = snapshotExports.get(exportId);
|
|
237
|
+
if (!snapshot)
|
|
238
|
+
return undefined;
|
|
239
|
+
try {
|
|
240
|
+
const chunk = await snapshot.next();
|
|
241
|
+
if (chunk == null)
|
|
242
|
+
snapshotExports.delete(exportId);
|
|
243
|
+
return chunk ?? undefined;
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
snapshotExports.delete(exportId);
|
|
247
|
+
await Promise.resolve(snapshot.cancel()).catch(() => undefined);
|
|
248
|
+
throw error;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async function handleSnapshotCancel(exportId) {
|
|
252
|
+
const snapshot = snapshotExports.get(exportId);
|
|
253
|
+
snapshotExports.delete(exportId);
|
|
254
|
+
if (snapshot)
|
|
255
|
+
await snapshot.cancel();
|
|
256
|
+
}
|
|
257
|
+
function ensureSnapshotInput(snapshotId) {
|
|
258
|
+
if (snapshotInputs.has(snapshotId))
|
|
259
|
+
return;
|
|
260
|
+
const stream = new TransformStream(undefined, { highWaterMark: 0 }, { highWaterMark: 0 });
|
|
261
|
+
snapshotInputs.set(snapshotId, {
|
|
262
|
+
readable: stream.readable,
|
|
263
|
+
writer: stream.writable.getWriter(),
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function requiredSnapshotInput(snapshotId) {
|
|
267
|
+
const input = snapshotInputs.get(snapshotId);
|
|
268
|
+
if (!input)
|
|
269
|
+
throw workerStateError("snapshot restore input is closed");
|
|
270
|
+
return input;
|
|
271
|
+
}
|
|
272
|
+
async function handleSnapshotInput(operation) {
|
|
273
|
+
const input = requiredSnapshotInput(operation.snapshotId);
|
|
274
|
+
if (operation.kind === "openSnapshot.write") {
|
|
275
|
+
await input.writer.write(operation.chunk);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
await input.writer.close();
|
|
279
|
+
}
|
|
280
|
+
function createSyncServerBridge(server) {
|
|
281
|
+
if (!server)
|
|
282
|
+
return undefined;
|
|
283
|
+
return {
|
|
284
|
+
url: server.url,
|
|
285
|
+
headers: server.headers ?? [],
|
|
286
|
+
headerProvider: server.dynamicHeaders
|
|
287
|
+
? () => {
|
|
288
|
+
const requestId = nextSyncRequestId++;
|
|
289
|
+
return new Promise((resolve, reject) => {
|
|
290
|
+
pendingSyncHeaders.set(requestId, { resolve, reject });
|
|
291
|
+
endpoint.postMessage({ kind: "sync.headers", requestId });
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
: undefined,
|
|
295
|
+
fetch: server.customFetch ? bridgeFetch : undefined,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
async function bridgeFetch(input, init) {
|
|
299
|
+
const responseLimit = init?.lixResponseLimit;
|
|
300
|
+
if (typeof responseLimit !== "number" ||
|
|
301
|
+
!Number.isSafeInteger(responseLimit) ||
|
|
302
|
+
responseLimit <= 0) {
|
|
303
|
+
throw new TypeError("Browser sync fetch has no valid response limit");
|
|
304
|
+
}
|
|
305
|
+
const requestId = nextSyncRequestId++;
|
|
306
|
+
const request = {
|
|
307
|
+
url: typeof input === "string"
|
|
308
|
+
? input
|
|
309
|
+
: input instanceof URL
|
|
310
|
+
? input.toString()
|
|
311
|
+
: input.url,
|
|
312
|
+
method: init?.method ?? "GET",
|
|
313
|
+
headers: headerEntries(init?.headers),
|
|
314
|
+
body: serializableBody(init?.body),
|
|
315
|
+
credentials: init?.credentials,
|
|
316
|
+
responseLimit,
|
|
317
|
+
};
|
|
318
|
+
const response = new Promise((resolve, reject) => {
|
|
319
|
+
pendingSyncFetch.set(requestId, { resolve, reject });
|
|
320
|
+
endpoint.postMessage({ kind: "sync.fetch", requestId, request });
|
|
321
|
+
});
|
|
322
|
+
const abort = () => {
|
|
323
|
+
const pending = pendingSyncFetch.get(requestId);
|
|
324
|
+
pendingSyncFetch.delete(requestId);
|
|
325
|
+
if (pending) {
|
|
326
|
+
pending.reject(new DOMException("The operation was aborted", "AbortError"));
|
|
327
|
+
endpoint.postMessage({ kind: "sync.fetch.cancel", requestId });
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
if (init?.signal?.aborted)
|
|
331
|
+
abort();
|
|
332
|
+
else
|
|
333
|
+
init?.signal?.addEventListener("abort", abort, { once: true });
|
|
334
|
+
try {
|
|
335
|
+
const resolved = await response;
|
|
336
|
+
return responseFromSyncFetch(resolved);
|
|
337
|
+
}
|
|
338
|
+
finally {
|
|
339
|
+
init?.signal?.removeEventListener("abort", abort);
|
|
340
|
+
pendingSyncFetch.delete(requestId);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async function handleObserveNext(observeId, telemetryParent) {
|
|
131
344
|
const events = observations.get(observeId);
|
|
132
345
|
if (!events)
|
|
133
346
|
return undefined;
|
|
347
|
+
events.setTelemetryParent(telemetryParent);
|
|
134
348
|
return events.next();
|
|
135
349
|
}
|
|
136
|
-
function requiredLix() {
|
|
350
|
+
function requiredLix(sessionId) {
|
|
351
|
+
const lix = sessions.get(sessionId);
|
|
137
352
|
if (!lix)
|
|
138
|
-
throw workerStateError("Lix
|
|
353
|
+
throw workerStateError("Lix session is closed");
|
|
139
354
|
return lix;
|
|
140
355
|
}
|
|
141
356
|
function requiredTransaction(transactionId) {
|
|
@@ -148,9 +363,40 @@ export function startWorkerHost(endpoint) {
|
|
|
148
363
|
return transaction;
|
|
149
364
|
}
|
|
150
365
|
}
|
|
366
|
+
export function responseFromSyncFetch(resolved) {
|
|
367
|
+
const body = resolved.status === 204 ||
|
|
368
|
+
resolved.status === 205 ||
|
|
369
|
+
resolved.status === 304
|
|
370
|
+
? null
|
|
371
|
+
: resolved.body.slice().buffer;
|
|
372
|
+
return new Response(body, {
|
|
373
|
+
status: resolved.status,
|
|
374
|
+
statusText: resolved.statusText,
|
|
375
|
+
headers: resolved.headers,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
151
378
|
function workerStateError(message) {
|
|
152
379
|
const error = new Error(message);
|
|
153
380
|
error.name = "LixError";
|
|
154
381
|
error.code = "LIX_ERROR_CLOSED";
|
|
155
382
|
return error;
|
|
156
383
|
}
|
|
384
|
+
function headerEntries(headers) {
|
|
385
|
+
const entries = [];
|
|
386
|
+
new Headers(headers).forEach((value, name) => entries.push([name, value]));
|
|
387
|
+
return entries;
|
|
388
|
+
}
|
|
389
|
+
function serializableBody(body) {
|
|
390
|
+
if (body === undefined || body === null)
|
|
391
|
+
return undefined;
|
|
392
|
+
if (typeof body === "string")
|
|
393
|
+
return body;
|
|
394
|
+
if (body instanceof Uint8Array)
|
|
395
|
+
return body;
|
|
396
|
+
if (body instanceof ArrayBuffer)
|
|
397
|
+
return new Uint8Array(body);
|
|
398
|
+
if (ArrayBuffer.isView(body)) {
|
|
399
|
+
return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
|
|
400
|
+
}
|
|
401
|
+
throw new TypeError("Browser sync fetch body is not structured-cloneable");
|
|
402
|
+
}
|
|
@@ -1,13 +1,48 @@
|
|
|
1
1
|
import type { BindingBatchStatement, BindingParam, LixStorageConfig } from "../binding-types.js";
|
|
2
|
-
import type { CreateBranchOptions, ExecuteOptions, LixBatchOptions, MergeBranchOptions, SwitchBranchOptions, LixTelemetrySpan } from "../types.js";
|
|
2
|
+
import type { CreateBranchOptions, ExecuteOptions, LixBatchOptions, MergeBranchOptions, SwitchBranchOptions, LixTelemetrySpan, LixTelemetryParentContext, LixOpenProgress, OpenAnotherSessionOptions } from "../types.js";
|
|
3
|
+
export type WorkerSyncServerOptions = {
|
|
4
|
+
url: string;
|
|
5
|
+
headers?: [string, string][];
|
|
6
|
+
dynamicHeaders: boolean;
|
|
7
|
+
customFetch: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type WorkerSyncFetchRequest = {
|
|
10
|
+
url: string;
|
|
11
|
+
method: string;
|
|
12
|
+
headers: [string, string][];
|
|
13
|
+
body?: string | Uint8Array;
|
|
14
|
+
credentials?: RequestCredentials;
|
|
15
|
+
responseLimit: number;
|
|
16
|
+
};
|
|
17
|
+
export type WorkerSyncFetchResponse = {
|
|
18
|
+
status: number;
|
|
19
|
+
statusText: string;
|
|
20
|
+
headers: [string, string][];
|
|
21
|
+
body: Uint8Array;
|
|
22
|
+
};
|
|
3
23
|
export type WorkerRequest = {
|
|
4
24
|
id: number;
|
|
25
|
+
sessionId: number;
|
|
26
|
+
telemetryParent?: LixTelemetryParentContext;
|
|
5
27
|
operation: WorkerOperation;
|
|
6
28
|
};
|
|
7
29
|
export type WorkerOperation = {
|
|
8
30
|
kind: "open";
|
|
9
31
|
storage: LixStorageConfig;
|
|
10
32
|
telemetryEnabled: boolean;
|
|
33
|
+
progressEnabled: boolean;
|
|
34
|
+
snapshotId?: number;
|
|
35
|
+
server?: WorkerSyncServerOptions;
|
|
36
|
+
} | {
|
|
37
|
+
kind: "openSnapshot.write";
|
|
38
|
+
snapshotId: number;
|
|
39
|
+
chunk: Uint8Array;
|
|
40
|
+
} | {
|
|
41
|
+
kind: "openSnapshot.finish";
|
|
42
|
+
snapshotId: number;
|
|
43
|
+
} | {
|
|
44
|
+
kind: "openAnotherSession";
|
|
45
|
+
options: OpenAnotherSessionOptions;
|
|
11
46
|
} | {
|
|
12
47
|
kind: "execute";
|
|
13
48
|
sql: string;
|
|
@@ -38,8 +73,6 @@ export type WorkerOperation = {
|
|
|
38
73
|
} | {
|
|
39
74
|
kind: "createBranch";
|
|
40
75
|
options: CreateBranchOptions;
|
|
41
|
-
} | {
|
|
42
|
-
kind: "createCheckpoint";
|
|
43
76
|
} | {
|
|
44
77
|
kind: "undo";
|
|
45
78
|
} | {
|
|
@@ -58,6 +91,14 @@ export type WorkerOperation = {
|
|
|
58
91
|
paths: string[];
|
|
59
92
|
} | {
|
|
60
93
|
kind: "syncDiskToLix";
|
|
94
|
+
} | {
|
|
95
|
+
kind: "exportSnapshot";
|
|
96
|
+
} | {
|
|
97
|
+
kind: "exportSnapshot.next";
|
|
98
|
+
exportId: number;
|
|
99
|
+
} | {
|
|
100
|
+
kind: "exportSnapshot.cancel";
|
|
101
|
+
exportId: number;
|
|
61
102
|
} | {
|
|
62
103
|
kind: "observe";
|
|
63
104
|
sql: string;
|
|
@@ -74,6 +115,29 @@ export type WorkerNotification = {
|
|
|
74
115
|
} | {
|
|
75
116
|
kind: "observe.close";
|
|
76
117
|
observeId: number;
|
|
118
|
+
} | {
|
|
119
|
+
kind: "openSnapshot.cancel";
|
|
120
|
+
snapshotId: number;
|
|
121
|
+
} | {
|
|
122
|
+
kind: "sync.headers.result";
|
|
123
|
+
requestId: number;
|
|
124
|
+
result: {
|
|
125
|
+
ok: true;
|
|
126
|
+
headers: [string, string][];
|
|
127
|
+
} | {
|
|
128
|
+
ok: false;
|
|
129
|
+
error: SerializedWorkerError;
|
|
130
|
+
};
|
|
131
|
+
} | {
|
|
132
|
+
kind: "sync.fetch.result";
|
|
133
|
+
requestId: number;
|
|
134
|
+
result: {
|
|
135
|
+
ok: true;
|
|
136
|
+
response: WorkerSyncFetchResponse;
|
|
137
|
+
} | {
|
|
138
|
+
ok: false;
|
|
139
|
+
error: SerializedWorkerError;
|
|
140
|
+
};
|
|
77
141
|
};
|
|
78
142
|
export type WorkerInput = WorkerRequest | WorkerNotification;
|
|
79
143
|
export type WorkerConnection = {
|
|
@@ -107,6 +171,19 @@ export type WorkerResponse = {
|
|
|
107
171
|
} | {
|
|
108
172
|
kind: "telemetry";
|
|
109
173
|
span: LixTelemetrySpan;
|
|
174
|
+
} | {
|
|
175
|
+
kind: "open.progress";
|
|
176
|
+
progress: LixOpenProgress;
|
|
177
|
+
} | {
|
|
178
|
+
kind: "sync.headers";
|
|
179
|
+
requestId: number;
|
|
180
|
+
} | {
|
|
181
|
+
kind: "sync.fetch";
|
|
182
|
+
requestId: number;
|
|
183
|
+
request: WorkerSyncFetchRequest;
|
|
184
|
+
} | {
|
|
185
|
+
kind: "sync.fetch.cancel";
|
|
186
|
+
requestId: number;
|
|
110
187
|
};
|
|
111
188
|
export declare function serializeWorkerError(error: unknown): SerializedWorkerError;
|
|
112
189
|
export declare function deserializeWorkerError(error: SerializedWorkerError): Error;
|
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.14.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -12,11 +12,6 @@
|
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
13
|
"default": "./dist/index.js"
|
|
14
14
|
},
|
|
15
|
-
"./workerd": {
|
|
16
|
-
"types": "./dist/workerd.d.ts",
|
|
17
|
-
"workerd": "./dist/workerd.js",
|
|
18
|
-
"default": "./dist/workerd.js"
|
|
19
|
-
},
|
|
20
15
|
"./server-protocol": {
|
|
21
16
|
"types": "./dist/remote/server-protocol.d.ts",
|
|
22
17
|
"default": "./dist/remote/server-protocol.js"
|
|
@@ -43,6 +38,7 @@
|
|
|
43
38
|
"build:wasm:dev": "LIX_WASM_PROFILE=dev node ./scripts/build-wasm.js",
|
|
44
39
|
"build:plugins": "node ./scripts/build-bundled-plugins.js",
|
|
45
40
|
"benchmark:plugin-reopen": "node ./scripts/benchmark-plugin-reopen.mjs",
|
|
41
|
+
"benchmark:storage-boundary": "LIX_WASM_STORAGE_BENCH=1 npm run build:browser && LIX_WASM_STORAGE_BENCH=1 vitest run --config vitest.browser.config.ts src/storage-bridge.bench.browser.test.ts",
|
|
46
42
|
"clean": "node ./scripts/clean.js",
|
|
47
43
|
"prepare:native-package": "node ./scripts/prepare-native-package.js",
|
|
48
44
|
"build:ts": "tsc -p tsconfig.json",
|
|
@@ -53,10 +49,10 @@
|
|
|
53
49
|
"typecheck": "tsc -p tsconfig.test.json --noEmit"
|
|
54
50
|
},
|
|
55
51
|
"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.
|
|
52
|
+
"@lix-js/sdk-darwin-arm64": "0.14.0",
|
|
53
|
+
"@lix-js/sdk-linux-arm64": "0.14.0",
|
|
54
|
+
"@lix-js/sdk-linux-x64": "0.14.0",
|
|
55
|
+
"@lix-js/sdk-win32-x64": "0.14.0"
|
|
60
56
|
},
|
|
61
57
|
"devDependencies": {
|
|
62
58
|
"@vitest/browser-playwright": "4.1.10",
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
type IndexedDbEntry = {
|
|
2
|
-
key: Uint8Array;
|
|
3
|
-
value: Uint8Array;
|
|
4
|
-
};
|
|
5
|
-
type IndexedDbChanges = {
|
|
6
|
-
deletes: Uint8Array[];
|
|
7
|
-
puts: IndexedDbEntry[];
|
|
8
|
-
strictDurability: boolean;
|
|
9
|
-
};
|
|
10
|
-
/** Internal worker-local bridge used by the WASM IndexedDB storage adapter. */
|
|
11
|
-
export declare class IndexedDbBackend {
|
|
12
|
-
#private;
|
|
13
|
-
private constructor();
|
|
14
|
-
static open(name: string): Promise<IndexedDbBackend>;
|
|
15
|
-
loadEntries(): Promise<IndexedDbEntry[]>;
|
|
16
|
-
applyChanges(changes: IndexedDbChanges): Promise<void>;
|
|
17
|
-
close(): Promise<void>;
|
|
18
|
-
}
|
|
19
|
-
export {};
|