@lix-js/sdk 0.14.0 → 0.15.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.
- package/README.md +14 -0
- package/dist/binding-types.d.ts +1 -1
- package/dist/binding.browser.js +2 -10
- package/dist/binding.node-wasm.js +2 -8
- package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
- package/dist/bundled-plugins/plugin_markdown.lixplugin +0 -0
- package/dist/lix.js +1 -8
- package/dist/open-lix.js +2 -1
- package/dist/remote/client.js +5 -23
- package/dist/types.d.ts +3 -3
- package/dist/wasm/lix_js_sdk.d.ts +7 -5
- package/dist/wasm/lix_js_sdk.js +41 -34
- package/dist/wasm/lix_js_sdk_bg.wasm +0 -0
- package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +4 -3
- package/dist/wasm-init.d.ts +2 -0
- package/dist/wasm-init.js +23 -0
- package/dist/worker/client.d.ts +4 -0
- package/dist/worker/client.js +86 -3
- package/dist/worker/host.d.ts +2 -1
- package/dist/worker/host.js +128 -16
- package/dist/worker/protocol.d.ts +30 -3
- package/package.json +5 -5
- package/dist/browser-wasm-init.d.ts +0 -14
- package/dist/browser-wasm-init.js +0 -16
package/README.md
CHANGED
|
@@ -85,6 +85,20 @@ Remote server sessions are branch-pinned, so switching one client does not
|
|
|
85
85
|
switch another client. Browser-local application state belongs to the
|
|
86
86
|
application rather than the remote Lix handle.
|
|
87
87
|
|
|
88
|
+
Remote handles support branch creation, merge preview and merge through the
|
|
89
|
+
server's Rust engine. `openAnotherSession()` inherits the active branch unless
|
|
90
|
+
one is supplied, retains the authenticated account, and returns an independent
|
|
91
|
+
handle with the same operations—including streaming `exportSnapshot()`. Snapshot
|
|
92
|
+
export covers the complete repository, not only the active branch. Cancelling
|
|
93
|
+
the returned stream releases the HTTP request.
|
|
94
|
+
|
|
95
|
+
Internally, local and connected-sync bindings call `Lix`; remote bindings call
|
|
96
|
+
the Rust protocol client. Both implement the required Rust session operation
|
|
97
|
+
contract, and the WASM bindings share SQL and branch-operation forwarding and
|
|
98
|
+
value conversion. Host-specific storage, telemetry, stream, and actor cleanup
|
|
99
|
+
remain in the bindings. This does not make network availability or authentication
|
|
100
|
+
constraints identical to an offline local engine.
|
|
101
|
+
|
|
88
102
|
Filesystem sync uses native Node.js dependencies:
|
|
89
103
|
|
|
90
104
|
```ts
|
package/dist/binding-types.d.ts
CHANGED
|
@@ -58,7 +58,7 @@ export type LixBinding = {
|
|
|
58
58
|
mergeBranchPreview(options: MergeBranchOptions): Promise<MergeBranchPreview>;
|
|
59
59
|
mergeBranch(options: MergeBranchOptions): Promise<MergeBranchReceipt>;
|
|
60
60
|
syncDiskToLix(): Promise<void>;
|
|
61
|
-
exportSnapshot
|
|
61
|
+
exportSnapshot(): SnapshotExportBinding;
|
|
62
62
|
close(): Promise<void>;
|
|
63
63
|
};
|
|
64
64
|
export type LixTransactionBinding = {
|
package/dist/binding.browser.js
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { initializeWasm } from "./wasm-init.js";
|
|
2
2
|
import { restoreSnapshot } from "./snapshot-restore.js";
|
|
3
3
|
// Generated before TypeScript compilation and emitted beside this module.
|
|
4
4
|
// @ts-ignore Generated by build:wasm and absent in source-only checks.
|
|
5
|
-
import
|
|
6
|
-
let wasmInitialized;
|
|
7
|
-
function initializeWasm() {
|
|
8
|
-
if (wasmInitialized !== undefined)
|
|
9
|
-
return wasmInitialized;
|
|
10
|
-
const initialization = initializeBrowserWasm(initWasm, new URL("./wasm/lix_js_sdk_bg.wasm", import.meta.url));
|
|
11
|
-
wasmInitialized = initialization;
|
|
12
|
-
return wasmInitialized;
|
|
13
|
-
}
|
|
5
|
+
import { openJsStorage, openJsStorageFromSnapshot, openMemory, openMemoryFromSnapshot, } from "./wasm/lix_js_sdk.js";
|
|
14
6
|
export async function openLixBinding(storage, telemetry, telemetryParent, server, openProgress, snapshot) {
|
|
15
7
|
await initializeWasm();
|
|
16
8
|
switch (storage.kind) {
|
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
1
|
import { restoreSnapshot } from "./snapshot-restore.js";
|
|
2
|
+
import { initializeWasm } from "./wasm-init.js";
|
|
3
3
|
// Generated before TypeScript compilation and emitted beside this module.
|
|
4
4
|
// @ts-ignore Generated by build:wasm and absent in source-only checks.
|
|
5
|
-
import
|
|
6
|
-
let wasmInitialized;
|
|
7
|
-
function initializeWasm() {
|
|
8
|
-
return (wasmInitialized ??= initWasm({
|
|
9
|
-
module_or_path: readFile(new URL("./wasm/lix_js_sdk_bg.wasm", import.meta.url)),
|
|
10
|
-
}));
|
|
11
|
-
}
|
|
5
|
+
import { openMemory, openMemoryFromSnapshot } from "./wasm/lix_js_sdk.js";
|
|
12
6
|
export async function openMemoryWasmBinding(telemetry, telemetryParent, openProgress, snapshot) {
|
|
13
7
|
await initializeWasm();
|
|
14
8
|
if (snapshot) {
|
|
Binary file
|
|
Binary file
|
package/dist/lix.js
CHANGED
|
@@ -118,14 +118,7 @@ export class Lix {
|
|
|
118
118
|
});
|
|
119
119
|
const operation = this.#runOperation(async () => {
|
|
120
120
|
try {
|
|
121
|
-
|
|
122
|
-
if (!exportSnapshot) {
|
|
123
|
-
const error = new Error("snapshot export is not available for remote Lix handles");
|
|
124
|
-
error.name = "LixError";
|
|
125
|
-
error.code = "LIX_UNSUPPORTED_STORAGE";
|
|
126
|
-
throw error;
|
|
127
|
-
}
|
|
128
|
-
resolveBinding(exportSnapshot.call(this.binding));
|
|
121
|
+
resolveBinding(this.binding.exportSnapshot());
|
|
129
122
|
await completed;
|
|
130
123
|
}
|
|
131
124
|
catch (error) {
|
package/dist/open-lix.js
CHANGED
|
@@ -59,7 +59,8 @@ async function openLixInternal(options, snapshot) {
|
|
|
59
59
|
}
|
|
60
60
|
const { openLixWorkerBinding } = await import("./worker/client.js");
|
|
61
61
|
if (options.storage === undefined) {
|
|
62
|
-
|
|
62
|
+
const binding = await openLixWorkerBinding({ kind: "memory" }, undefined, options.telemetry, syncServer, options.onProgress, snapshot);
|
|
63
|
+
return new Lix(binding);
|
|
63
64
|
}
|
|
64
65
|
if (isJsProviderLixStorage(options.storage)) {
|
|
65
66
|
return openJsProviderStorage(options.storage, options.telemetry, syncServer, options.onProgress, snapshot);
|
package/dist/remote/client.js
CHANGED
|
@@ -1,26 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { initializeWasm } from "../wasm-init.js";
|
|
2
2
|
// Generated before TypeScript compilation and emitted beside the JS SDK.
|
|
3
3
|
// @ts-ignore Generated by build:wasm and absent in source-only checks.
|
|
4
|
-
import
|
|
5
|
-
let wasmInitialized;
|
|
6
|
-
function initializeWasm() {
|
|
7
|
-
if (wasmInitialized !== undefined)
|
|
8
|
-
return wasmInitialized;
|
|
9
|
-
let initialization;
|
|
10
|
-
if (typeof process !== "undefined" && process.versions?.node) {
|
|
11
|
-
initialization = import("node:fs/promises").then(({ readFile }) => initWasm({
|
|
12
|
-
module_or_path: readFile(new URL("../wasm/lix_js_sdk_bg.wasm", import.meta.url)),
|
|
13
|
-
}), (error) => {
|
|
14
|
-
wasmInitialized = undefined;
|
|
15
|
-
throw error;
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
initialization = initializeBrowserWasm(initWasm, new URL("../wasm/lix_js_sdk_bg.wasm", import.meta.url));
|
|
20
|
-
}
|
|
21
|
-
wasmInitialized = initialization;
|
|
22
|
-
return wasmInitialized;
|
|
23
|
-
}
|
|
4
|
+
import { openRemote } from "../wasm/lix_js_sdk.js";
|
|
24
5
|
export async function openRemoteLixBinding(options, clientOptions = {}) {
|
|
25
6
|
if (!options || typeof options !== "object") {
|
|
26
7
|
throw new TypeError("openLix() remote server must be an object");
|
|
@@ -41,9 +22,10 @@ export async function openRemoteLixBinding(options, clientOptions = {}) {
|
|
|
41
22
|
clientOptions.initialActiveBranchId.length === 0) {
|
|
42
23
|
throw new TypeError("initialActiveBranchId must be a non-empty string");
|
|
43
24
|
}
|
|
44
|
-
const
|
|
25
|
+
const locator = connectionUrl(options.url);
|
|
26
|
+
const protocolLocator = locator.toString();
|
|
45
27
|
await initializeWasm();
|
|
46
|
-
return openRemote(protocolLocator, remoteFetch, options.headers, clientOptions.initialActiveBranchId);
|
|
28
|
+
return await openRemote(protocolLocator, remoteFetch, options.headers, clientOptions.initialActiveBranchId);
|
|
47
29
|
}
|
|
48
30
|
function connectionUrl(value) {
|
|
49
31
|
let locator;
|
package/dist/types.d.ts
CHANGED
|
@@ -184,9 +184,9 @@ export type ObserveEvent = {
|
|
|
184
184
|
sequence: number;
|
|
185
185
|
mutationSequence: number;
|
|
186
186
|
/**
|
|
187
|
-
* The current result of the observed query. Remote
|
|
188
|
-
*
|
|
189
|
-
*
|
|
187
|
+
* The current result of the observed query. Remote rows and
|
|
188
|
+
* `mutationSequence` come from the same authoritative observation frame;
|
|
189
|
+
* reconnect frames are coalesced when their rows are unchanged.
|
|
190
190
|
*/
|
|
191
191
|
result: ExecuteResult;
|
|
192
192
|
};
|
|
@@ -55,9 +55,10 @@ export class WasmRemoteLix {
|
|
|
55
55
|
createBranch(options: any): Promise<any>;
|
|
56
56
|
execute(sql: string, params: any, options?: any | null): Promise<any>;
|
|
57
57
|
executeBatch(statements: any, options?: any | null): Promise<any>;
|
|
58
|
+
exportSnapshot(): WasmSnapshotExport;
|
|
58
59
|
importFilesystemPaths(_paths: any): Promise<void>;
|
|
59
|
-
mergeBranch(
|
|
60
|
-
mergeBranchPreview(
|
|
60
|
+
mergeBranch(options: any): Promise<any>;
|
|
61
|
+
mergeBranchPreview(options: any): Promise<any>;
|
|
61
62
|
observe(sql: string, params: any): Promise<WasmRemoteObserveEvents>;
|
|
62
63
|
openAnotherSession(options: any): Promise<WasmRemoteLix>;
|
|
63
64
|
redo(): Promise<any>;
|
|
@@ -162,6 +163,7 @@ export interface InitOutput {
|
|
|
162
163
|
readonly wasmremotelix_createBranch: (a: number, b: number) => number;
|
|
163
164
|
readonly wasmremotelix_execute: (a: number, b: number, c: number, d: number, e: number) => number;
|
|
164
165
|
readonly wasmremotelix_executeBatch: (a: number, b: number, c: number) => number;
|
|
166
|
+
readonly wasmremotelix_exportSnapshot: (a: number) => number;
|
|
165
167
|
readonly wasmremotelix_importFilesystemPaths: (a: number, b: number) => number;
|
|
166
168
|
readonly wasmremotelix_mergeBranch: (a: number, b: number) => number;
|
|
167
169
|
readonly wasmremotelix_mergeBranchPreview: (a: number, b: number) => number;
|
|
@@ -184,9 +186,9 @@ export interface InitOutput {
|
|
|
184
186
|
readonly wasmsnapshotrestore_finish: (a: number) => number;
|
|
185
187
|
readonly wasmsnapshotrestore_isComplete: (a: number) => number;
|
|
186
188
|
readonly wasmsnapshotrestore_write: (a: number, b: number, c: number) => number;
|
|
187
|
-
readonly
|
|
188
|
-
readonly
|
|
189
|
-
readonly
|
|
189
|
+
readonly __wasm_bindgen_func_elem_92636: (a: number, b: number, c: number, d: number) => void;
|
|
190
|
+
readonly __wasm_bindgen_func_elem_92638: (a: number, b: number, c: number, d: number) => void;
|
|
191
|
+
readonly __wasm_bindgen_func_elem_16813: (a: number, b: number) => void;
|
|
190
192
|
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
191
193
|
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
192
194
|
readonly __wbindgen_export3: (a: number) => void;
|
package/dist/wasm/lix_js_sdk.js
CHANGED
|
@@ -356,6 +356,13 @@ export class WasmRemoteLix {
|
|
|
356
356
|
const ret = wasm.wasmremotelix_executeBatch(this.__wbg_ptr, addHeapObject(statements), isLikeNone(options) ? 0 : addHeapObject(options));
|
|
357
357
|
return takeObject(ret);
|
|
358
358
|
}
|
|
359
|
+
/**
|
|
360
|
+
* @returns {WasmSnapshotExport}
|
|
361
|
+
*/
|
|
362
|
+
exportSnapshot() {
|
|
363
|
+
const ret = wasm.wasmremotelix_exportSnapshot(this.__wbg_ptr);
|
|
364
|
+
return WasmSnapshotExport.__wrap(ret);
|
|
365
|
+
}
|
|
359
366
|
/**
|
|
360
367
|
* @param {any} _paths
|
|
361
368
|
* @returns {Promise<void>}
|
|
@@ -365,19 +372,19 @@ export class WasmRemoteLix {
|
|
|
365
372
|
return takeObject(ret);
|
|
366
373
|
}
|
|
367
374
|
/**
|
|
368
|
-
* @param {any}
|
|
375
|
+
* @param {any} options
|
|
369
376
|
* @returns {Promise<any>}
|
|
370
377
|
*/
|
|
371
|
-
mergeBranch(
|
|
372
|
-
const ret = wasm.wasmremotelix_mergeBranch(this.__wbg_ptr, addHeapObject(
|
|
378
|
+
mergeBranch(options) {
|
|
379
|
+
const ret = wasm.wasmremotelix_mergeBranch(this.__wbg_ptr, addHeapObject(options));
|
|
373
380
|
return takeObject(ret);
|
|
374
381
|
}
|
|
375
382
|
/**
|
|
376
|
-
* @param {any}
|
|
383
|
+
* @param {any} options
|
|
377
384
|
* @returns {Promise<any>}
|
|
378
385
|
*/
|
|
379
|
-
mergeBranchPreview(
|
|
380
|
-
const ret = wasm.wasmremotelix_mergeBranchPreview(this.__wbg_ptr, addHeapObject(
|
|
386
|
+
mergeBranchPreview(options) {
|
|
387
|
+
const ret = wasm.wasmremotelix_mergeBranchPreview(this.__wbg_ptr, addHeapObject(options));
|
|
381
388
|
return takeObject(ret);
|
|
382
389
|
}
|
|
383
390
|
/**
|
|
@@ -760,19 +767,19 @@ function __wbg_get_imports() {
|
|
|
760
767
|
__wbg__wbg_cb_unref_61db23ac97f16c31: function(arg0) {
|
|
761
768
|
getObject(arg0)._wbg_cb_unref();
|
|
762
769
|
},
|
|
763
|
-
|
|
770
|
+
__wbg_acquireSession_4217826058465f0a: function(arg0) {
|
|
764
771
|
const ret = getObject(arg0).acquireSession();
|
|
765
772
|
return addHeapObject(ret);
|
|
766
773
|
},
|
|
767
|
-
|
|
774
|
+
__wbg_beginRead_94ff94b93b664ae5: function(arg0, arg1) {
|
|
768
775
|
const ret = getObject(arg0).beginRead(takeObject(arg1));
|
|
769
776
|
return addHeapObject(ret);
|
|
770
777
|
},
|
|
771
|
-
|
|
778
|
+
__wbg_beginScan_51d1ffb7b76bed05: function(arg0, arg1, arg2, arg3) {
|
|
772
779
|
const ret = getObject(arg0).beginScan(takeObject(arg1), takeObject(arg2), takeObject(arg3));
|
|
773
780
|
return addHeapObject(ret);
|
|
774
781
|
},
|
|
775
|
-
|
|
782
|
+
__wbg_beginWrite_57e757a92c7a162f: function(arg0, arg1) {
|
|
776
783
|
const ret = getObject(arg0).beginWrite(takeObject(arg1));
|
|
777
784
|
return addHeapObject(ret);
|
|
778
785
|
},
|
|
@@ -788,18 +795,18 @@ function __wbg_get_imports() {
|
|
|
788
795
|
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
|
|
789
796
|
return addHeapObject(ret);
|
|
790
797
|
}, arguments); },
|
|
791
|
-
|
|
798
|
+
__wbg_changed_58ce3f6384cfabf1: function(arg0) {
|
|
792
799
|
const ret = getObject(arg0).changed();
|
|
793
800
|
return addHeapObject(ret);
|
|
794
801
|
},
|
|
795
|
-
|
|
802
|
+
__wbg_close_48f18a70bd365447: function(arg0) {
|
|
796
803
|
getObject(arg0).close();
|
|
797
804
|
},
|
|
798
|
-
|
|
805
|
+
__wbg_close_c5652a29ac52dc7a: function(arg0) {
|
|
799
806
|
const ret = getObject(arg0).close();
|
|
800
807
|
return addHeapObject(ret);
|
|
801
808
|
},
|
|
802
|
-
|
|
809
|
+
__wbg_commit_abef9a20db94a24b: function(arg0) {
|
|
803
810
|
const ret = getObject(arg0).commit();
|
|
804
811
|
return addHeapObject(ret);
|
|
805
812
|
},
|
|
@@ -807,11 +814,11 @@ function __wbg_get_imports() {
|
|
|
807
814
|
const ret = Reflect.construct(getObject(arg0), getObject(arg1));
|
|
808
815
|
return addHeapObject(ret);
|
|
809
816
|
}, arguments); },
|
|
810
|
-
|
|
817
|
+
__wbg_deleteMany_fba03247e38ecd66: function(arg0, arg1, arg2) {
|
|
811
818
|
const ret = getObject(arg0).deleteMany(takeObject(arg1), takeObject(arg2));
|
|
812
819
|
return addHeapObject(ret);
|
|
813
820
|
},
|
|
814
|
-
|
|
821
|
+
__wbg_deleteRange_d3f785b237515ef2: function(arg0, arg1, arg2) {
|
|
815
822
|
const ret = getObject(arg0).deleteRange(takeObject(arg1), takeObject(arg2));
|
|
816
823
|
return addHeapObject(ret);
|
|
817
824
|
},
|
|
@@ -838,7 +845,7 @@ function __wbg_get_imports() {
|
|
|
838
845
|
const ret = Array.from(getObject(arg0));
|
|
839
846
|
return addHeapObject(ret);
|
|
840
847
|
},
|
|
841
|
-
|
|
848
|
+
__wbg_getMany_274d167fafd6553d: function(arg0, arg1) {
|
|
842
849
|
const ret = getObject(arg0).getMany(takeObject(arg1));
|
|
843
850
|
return addHeapObject(ret);
|
|
844
851
|
},
|
|
@@ -963,7 +970,7 @@ function __wbg_get_imports() {
|
|
|
963
970
|
const a = state0.a;
|
|
964
971
|
state0.a = 0;
|
|
965
972
|
try {
|
|
966
|
-
return
|
|
973
|
+
return __wasm_bindgen_func_elem_92638(a, state0.b, arg0, arg1);
|
|
967
974
|
} finally {
|
|
968
975
|
state0.a = a;
|
|
969
976
|
}
|
|
@@ -993,7 +1000,7 @@ function __wbg_get_imports() {
|
|
|
993
1000
|
const a = state0.a;
|
|
994
1001
|
state0.a = 0;
|
|
995
1002
|
try {
|
|
996
|
-
return
|
|
1003
|
+
return __wasm_bindgen_func_elem_92638(a, state0.b, arg0, arg1);
|
|
997
1004
|
} finally {
|
|
998
1005
|
state0.a = a;
|
|
999
1006
|
}
|
|
@@ -1004,7 +1011,7 @@ function __wbg_get_imports() {
|
|
|
1004
1011
|
state0.a = 0;
|
|
1005
1012
|
}
|
|
1006
1013
|
},
|
|
1007
|
-
|
|
1014
|
+
__wbg_nextPage_2c82fda0921c8144: function(arg0, arg1) {
|
|
1008
1015
|
const ret = getObject(arg0).nextPage(arg1 >>> 0);
|
|
1009
1016
|
return addHeapObject(ret);
|
|
1010
1017
|
},
|
|
@@ -1043,7 +1050,7 @@ function __wbg_get_imports() {
|
|
|
1043
1050
|
const ret = getObject(arg0).push(getObject(arg1));
|
|
1044
1051
|
return ret;
|
|
1045
1052
|
},
|
|
1046
|
-
|
|
1053
|
+
__wbg_putMany_232f0878d2013b1a: function(arg0, arg1, arg2) {
|
|
1047
1054
|
const ret = getObject(arg0).putMany(takeObject(arg1), takeObject(arg2));
|
|
1048
1055
|
return addHeapObject(ret);
|
|
1049
1056
|
},
|
|
@@ -1054,7 +1061,7 @@ function __wbg_get_imports() {
|
|
|
1054
1061
|
const ret = getObject(arg0).queueMicrotask;
|
|
1055
1062
|
return addHeapObject(ret);
|
|
1056
1063
|
},
|
|
1057
|
-
|
|
1064
|
+
__wbg_replaceMany_79fe2cff87eae447: function(arg0, arg1, arg2) {
|
|
1058
1065
|
const ret = getObject(arg0).replaceMany(takeObject(arg1), takeObject(arg2));
|
|
1059
1066
|
return addHeapObject(ret);
|
|
1060
1067
|
},
|
|
@@ -1062,7 +1069,7 @@ function __wbg_get_imports() {
|
|
|
1062
1069
|
const ret = Promise.resolve(getObject(arg0));
|
|
1063
1070
|
return addHeapObject(ret);
|
|
1064
1071
|
},
|
|
1065
|
-
|
|
1072
|
+
__wbg_rollback_ff9a2e1df7d86a27: function(arg0) {
|
|
1066
1073
|
const ret = getObject(arg0).rollback();
|
|
1067
1074
|
return addHeapObject(ret);
|
|
1068
1075
|
},
|
|
@@ -1146,18 +1153,18 @@ function __wbg_get_imports() {
|
|
|
1146
1153
|
const ret = WasmRemoteObserveEvents.__wrap(arg0);
|
|
1147
1154
|
return addHeapObject(ret);
|
|
1148
1155
|
},
|
|
1149
|
-
|
|
1156
|
+
__wbg_watchForChanges_6e168a3d435984ae: function(arg0) {
|
|
1150
1157
|
const ret = getObject(arg0).watchForChanges();
|
|
1151
1158
|
return addHeapObject(ret);
|
|
1152
1159
|
},
|
|
1153
1160
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
1154
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx:
|
|
1155
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
1161
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 21338, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
1162
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_92636);
|
|
1156
1163
|
return addHeapObject(ret);
|
|
1157
1164
|
},
|
|
1158
1165
|
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
1159
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx:
|
|
1160
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
1166
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1647, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
|
1167
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_16813);
|
|
1161
1168
|
return addHeapObject(ret);
|
|
1162
1169
|
},
|
|
1163
1170
|
__wbindgen_cast_0000000000000003: function(arg0) {
|
|
@@ -1206,14 +1213,14 @@ function __wbg_get_imports() {
|
|
|
1206
1213
|
};
|
|
1207
1214
|
}
|
|
1208
1215
|
|
|
1209
|
-
function
|
|
1210
|
-
wasm.
|
|
1216
|
+
function __wasm_bindgen_func_elem_16813(arg0, arg1) {
|
|
1217
|
+
wasm.__wasm_bindgen_func_elem_16813(arg0, arg1);
|
|
1211
1218
|
}
|
|
1212
1219
|
|
|
1213
|
-
function
|
|
1220
|
+
function __wasm_bindgen_func_elem_92636(arg0, arg1, arg2) {
|
|
1214
1221
|
try {
|
|
1215
1222
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
1216
|
-
wasm.
|
|
1223
|
+
wasm.__wasm_bindgen_func_elem_92636(retptr, arg0, arg1, addHeapObject(arg2));
|
|
1217
1224
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
1218
1225
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
1219
1226
|
if (r1) {
|
|
@@ -1224,8 +1231,8 @@ function __wasm_bindgen_func_elem_92059(arg0, arg1, arg2) {
|
|
|
1224
1231
|
}
|
|
1225
1232
|
}
|
|
1226
1233
|
|
|
1227
|
-
function
|
|
1228
|
-
wasm.
|
|
1234
|
+
function __wasm_bindgen_func_elem_92638(arg0, arg1, arg2, arg3) {
|
|
1235
|
+
wasm.__wasm_bindgen_func_elem_92638(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
|
1229
1236
|
}
|
|
1230
1237
|
|
|
1231
1238
|
const WasmLixFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
Binary file
|
|
@@ -46,6 +46,7 @@ export const wasmremotelix_close: (a: number) => number;
|
|
|
46
46
|
export const wasmremotelix_createBranch: (a: number, b: number) => number;
|
|
47
47
|
export const wasmremotelix_execute: (a: number, b: number, c: number, d: number, e: number) => number;
|
|
48
48
|
export const wasmremotelix_executeBatch: (a: number, b: number, c: number) => number;
|
|
49
|
+
export const wasmremotelix_exportSnapshot: (a: number) => number;
|
|
49
50
|
export const wasmremotelix_importFilesystemPaths: (a: number, b: number) => number;
|
|
50
51
|
export const wasmremotelix_mergeBranch: (a: number, b: number) => number;
|
|
51
52
|
export const wasmremotelix_mergeBranchPreview: (a: number, b: number) => number;
|
|
@@ -68,9 +69,9 @@ export const wasmsnapshotrestore_cancel: (a: number) => number;
|
|
|
68
69
|
export const wasmsnapshotrestore_finish: (a: number) => number;
|
|
69
70
|
export const wasmsnapshotrestore_isComplete: (a: number) => number;
|
|
70
71
|
export const wasmsnapshotrestore_write: (a: number, b: number, c: number) => number;
|
|
71
|
-
export const
|
|
72
|
-
export const
|
|
73
|
-
export const
|
|
72
|
+
export const __wasm_bindgen_func_elem_92636: (a: number, b: number, c: number, d: number) => void;
|
|
73
|
+
export const __wasm_bindgen_func_elem_92638: (a: number, b: number, c: number, d: number) => void;
|
|
74
|
+
export const __wasm_bindgen_func_elem_16813: (a: number, b: number) => void;
|
|
74
75
|
export const __wbindgen_export: (a: number, b: number) => number;
|
|
75
76
|
export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
76
77
|
export const __wbindgen_export3: (a: number) => void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Generated before TypeScript compilation and emitted beside this module.
|
|
2
|
+
// @ts-ignore Generated by build:wasm and absent in source-only checks.
|
|
3
|
+
import initWasm from "./wasm/lix_js_sdk.js";
|
|
4
|
+
let wasmInitialized;
|
|
5
|
+
/** All local and remote bindings share the same Wasm module in this realm. */
|
|
6
|
+
export function initializeWasm() {
|
|
7
|
+
return (wasmInitialized ??= loadWasm());
|
|
8
|
+
}
|
|
9
|
+
async function loadWasm() {
|
|
10
|
+
const moduleUrl = new URL("./wasm/lix_js_sdk_bg.wasm", import.meta.url);
|
|
11
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
12
|
+
const { readFile } = await import("node:fs/promises");
|
|
13
|
+
return initWasm({ module_or_path: await readFile(moduleUrl) });
|
|
14
|
+
}
|
|
15
|
+
// Chromium can abort a consumer when workers cold-load the same large
|
|
16
|
+
// response concurrently. Hold the cross-realm lock until compilation ends
|
|
17
|
+
// so later workers can consume the completed immutable HTTP cache entry.
|
|
18
|
+
const lockManager = globalThis.navigator?.locks;
|
|
19
|
+
const run = () => initWasm({ module_or_path: moduleUrl });
|
|
20
|
+
if (!lockManager)
|
|
21
|
+
return run();
|
|
22
|
+
return lockManager.request(`lix:browser-wasm:${moduleUrl.href}`, { mode: "exclusive" }, run);
|
|
23
|
+
}
|
package/dist/worker/client.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export declare class LixWorkerClient {
|
|
|
29
29
|
private onProgress?;
|
|
30
30
|
openReport: LixOpenReport | undefined;
|
|
31
31
|
private readonly syncFetchControllers;
|
|
32
|
+
private readonly syncFetchStreams;
|
|
32
33
|
constructor(connection?: WorkerConnection);
|
|
33
34
|
get isDisposed(): boolean;
|
|
34
35
|
allocateSnapshotInputId(): number;
|
|
@@ -41,6 +42,9 @@ export declare class LixWorkerClient {
|
|
|
41
42
|
private handleWorkerEvent;
|
|
42
43
|
private resolveSyncHeaders;
|
|
43
44
|
private resolveSyncFetch;
|
|
45
|
+
private resolveSyncFetchStreamPull;
|
|
46
|
+
private cancelSyncFetch;
|
|
47
|
+
private finishSyncFetchStream;
|
|
44
48
|
private handleFatal;
|
|
45
49
|
private rejectPending;
|
|
46
50
|
}
|
package/dist/worker/client.js
CHANGED
|
@@ -368,6 +368,7 @@ export class LixWorkerClient {
|
|
|
368
368
|
onProgress;
|
|
369
369
|
openReport;
|
|
370
370
|
syncFetchControllers = new Map();
|
|
371
|
+
syncFetchStreams = new Map();
|
|
371
372
|
constructor(connection = createWorkerConnection()) {
|
|
372
373
|
this.connection = connection;
|
|
373
374
|
connection.onMessage((message) => this.handleMessage(message));
|
|
@@ -401,6 +402,10 @@ export class LixWorkerClient {
|
|
|
401
402
|
for (const controller of this.syncFetchControllers.values())
|
|
402
403
|
controller.abort();
|
|
403
404
|
this.syncFetchControllers.clear();
|
|
405
|
+
for (const reader of this.syncFetchStreams.values()) {
|
|
406
|
+
void reader?.cancel().catch(() => undefined);
|
|
407
|
+
}
|
|
408
|
+
this.syncFetchStreams.clear();
|
|
404
409
|
onDisposed?.();
|
|
405
410
|
}
|
|
406
411
|
request(operation, sessionId = 0) {
|
|
@@ -493,9 +498,11 @@ export class LixWorkerClient {
|
|
|
493
498
|
case "sync.fetch":
|
|
494
499
|
void this.resolveSyncFetch(message.requestId, message.request);
|
|
495
500
|
break;
|
|
501
|
+
case "sync.fetch.stream.pull":
|
|
502
|
+
void this.resolveSyncFetchStreamPull(message.requestId);
|
|
503
|
+
break;
|
|
496
504
|
case "sync.fetch.cancel":
|
|
497
|
-
this.
|
|
498
|
-
this.syncFetchControllers.delete(message.requestId);
|
|
505
|
+
this.cancelSyncFetch(message.requestId);
|
|
499
506
|
break;
|
|
500
507
|
}
|
|
501
508
|
}
|
|
@@ -532,6 +539,7 @@ export class LixWorkerClient {
|
|
|
532
539
|
}
|
|
533
540
|
const controller = new AbortController();
|
|
534
541
|
this.syncFetchControllers.set(requestId, controller);
|
|
542
|
+
let retainedStream = false;
|
|
535
543
|
try {
|
|
536
544
|
const response = await fetcher(request.url, {
|
|
537
545
|
method: request.method,
|
|
@@ -542,6 +550,29 @@ export class LixWorkerClient {
|
|
|
542
550
|
credentials: request.credentials,
|
|
543
551
|
signal: controller.signal,
|
|
544
552
|
});
|
|
553
|
+
if (this.syncFetchControllers.get(requestId) !== controller ||
|
|
554
|
+
controller.signal.aborted) {
|
|
555
|
+
await response.body?.cancel().catch(() => undefined);
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
if (request.responseMode === "stream") {
|
|
559
|
+
this.syncFetchStreams.set(requestId, response.body?.getReader());
|
|
560
|
+
retainedStream = true;
|
|
561
|
+
this.notify({
|
|
562
|
+
kind: "sync.fetch.result",
|
|
563
|
+
requestId,
|
|
564
|
+
result: {
|
|
565
|
+
ok: true,
|
|
566
|
+
response: {
|
|
567
|
+
status: response.status,
|
|
568
|
+
statusText: response.statusText,
|
|
569
|
+
headers: headerEntries(response.headers),
|
|
570
|
+
streaming: true,
|
|
571
|
+
},
|
|
572
|
+
},
|
|
573
|
+
});
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
545
576
|
const body = await readSyncResponseBody(response, request.responseLimit, controller);
|
|
546
577
|
this.notify({
|
|
547
578
|
kind: "sync.fetch.result",
|
|
@@ -567,9 +598,61 @@ export class LixWorkerClient {
|
|
|
567
598
|
}
|
|
568
599
|
}
|
|
569
600
|
finally {
|
|
570
|
-
|
|
601
|
+
if (!retainedStream)
|
|
602
|
+
this.syncFetchControllers.delete(requestId);
|
|
571
603
|
}
|
|
572
604
|
}
|
|
605
|
+
async resolveSyncFetchStreamPull(requestId) {
|
|
606
|
+
if (!this.syncFetchStreams.has(requestId))
|
|
607
|
+
return;
|
|
608
|
+
const reader = this.syncFetchStreams.get(requestId);
|
|
609
|
+
try {
|
|
610
|
+
const result = reader ? await reader.read() : { done: true };
|
|
611
|
+
if (!this.syncFetchStreams.has(requestId) ||
|
|
612
|
+
this.syncFetchStreams.get(requestId) !== reader ||
|
|
613
|
+
this.syncFetchControllers.get(requestId)?.signal.aborted) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
this.notify({
|
|
617
|
+
kind: "sync.fetch.stream.result",
|
|
618
|
+
requestId,
|
|
619
|
+
result: result.done
|
|
620
|
+
? { ok: true, done: true }
|
|
621
|
+
: { ok: true, done: false, chunk: result.value.slice() },
|
|
622
|
+
});
|
|
623
|
+
if (result.done) {
|
|
624
|
+
reader?.releaseLock();
|
|
625
|
+
this.finishSyncFetchStream(requestId);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
catch (error) {
|
|
629
|
+
const controller = this.syncFetchControllers.get(requestId);
|
|
630
|
+
if (!controller?.signal.aborted) {
|
|
631
|
+
this.notify({
|
|
632
|
+
kind: "sync.fetch.stream.result",
|
|
633
|
+
requestId,
|
|
634
|
+
result: { ok: false, error: serializeWorkerError(error) },
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
try {
|
|
638
|
+
reader?.releaseLock();
|
|
639
|
+
}
|
|
640
|
+
catch {
|
|
641
|
+
// A cancellation can leave the read pending until its rejection settles.
|
|
642
|
+
}
|
|
643
|
+
this.finishSyncFetchStream(requestId);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
cancelSyncFetch(requestId) {
|
|
647
|
+
this.syncFetchControllers.get(requestId)?.abort();
|
|
648
|
+
const reader = this.syncFetchStreams.get(requestId);
|
|
649
|
+
void reader?.cancel().catch(() => undefined);
|
|
650
|
+
this.finishSyncFetchStream(requestId);
|
|
651
|
+
}
|
|
652
|
+
finishSyncFetchStream(requestId) {
|
|
653
|
+
this.syncFetchStreams.delete(requestId);
|
|
654
|
+
this.syncFetchControllers.delete(requestId);
|
|
655
|
+
}
|
|
573
656
|
handleFatal(error) {
|
|
574
657
|
if (this.disposed)
|
|
575
658
|
return;
|
package/dist/worker/host.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { openLixBinding } from "#binding";
|
|
1
2
|
import { type WorkerHostEndpoint, type WorkerSyncFetchResponse } from "./protocol.js";
|
|
2
|
-
export declare function startWorkerHost(endpoint: WorkerHostEndpoint): void;
|
|
3
|
+
export declare function startWorkerHost(endpoint: WorkerHostEndpoint, openBinding?: typeof openLixBinding): void;
|
|
3
4
|
export declare function responseFromSyncFetch(resolved: WorkerSyncFetchResponse): Response;
|
package/dist/worker/host.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { openLixBinding } from "#binding";
|
|
2
2
|
import { deserializeWorkerError, serializeWorkerError, } from "./protocol.js";
|
|
3
|
-
export function startWorkerHost(endpoint) {
|
|
3
|
+
export function startWorkerHost(endpoint, openBinding = openLixBinding) {
|
|
4
4
|
const sessions = new Map();
|
|
5
5
|
let nextSessionId = 1;
|
|
6
6
|
let nextTransactionId = 1;
|
|
@@ -13,6 +13,8 @@ export function startWorkerHost(endpoint) {
|
|
|
13
13
|
let nextSyncRequestId = 1;
|
|
14
14
|
const pendingSyncHeaders = new Map();
|
|
15
15
|
const pendingSyncFetch = new Map();
|
|
16
|
+
const pendingSyncStreamPulls = new Map();
|
|
17
|
+
const syncStreamCleanup = new Map();
|
|
16
18
|
let finiteQueue = Promise.resolve();
|
|
17
19
|
endpoint.onMessage((message) => {
|
|
18
20
|
if (!("id" in message)) {
|
|
@@ -46,6 +48,15 @@ export function startWorkerHost(endpoint) {
|
|
|
46
48
|
}
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
51
|
+
if (message.operation.kind === "observe") {
|
|
52
|
+
const operation = message.operation;
|
|
53
|
+
// Observation setup is metadata-only. Keeping it behind the global
|
|
54
|
+
// finite-operation queue lets an authority mutation that is waiting for
|
|
55
|
+
// local publication block a newly mounted server-first History query.
|
|
56
|
+
// The live `next()` lane is already independent for the same reason.
|
|
57
|
+
void respond(message, () => handleObserveRegistration(message.sessionId, operation.sql, operation.params));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
49
60
|
finiteQueue = finiteQueue.then(async () => {
|
|
50
61
|
try {
|
|
51
62
|
await respond(message, async () => {
|
|
@@ -108,8 +119,35 @@ export function startWorkerHost(endpoint) {
|
|
|
108
119
|
pending.reject(deserializeWorkerError(message.result.error));
|
|
109
120
|
break;
|
|
110
121
|
}
|
|
122
|
+
case "sync.fetch.stream.result": {
|
|
123
|
+
const pending = pendingSyncStreamPulls.get(message.requestId);
|
|
124
|
+
pendingSyncStreamPulls.delete(message.requestId);
|
|
125
|
+
if (!pending)
|
|
126
|
+
break;
|
|
127
|
+
if (!message.result.ok) {
|
|
128
|
+
const error = deserializeWorkerError(message.result.error);
|
|
129
|
+
pending.controller.error(error);
|
|
130
|
+
pending.reject(error);
|
|
131
|
+
finishSyncStream(message.requestId);
|
|
132
|
+
}
|
|
133
|
+
else if (message.result.done) {
|
|
134
|
+
pending.controller.close();
|
|
135
|
+
pending.resolve();
|
|
136
|
+
finishSyncStream(message.requestId);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
pending.controller.enqueue(message.result.chunk);
|
|
140
|
+
pending.resolve();
|
|
141
|
+
}
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
111
144
|
}
|
|
112
145
|
}
|
|
146
|
+
function finishSyncStream(requestId) {
|
|
147
|
+
const cleanup = syncStreamCleanup.get(requestId);
|
|
148
|
+
syncStreamCleanup.delete(requestId);
|
|
149
|
+
cleanup?.();
|
|
150
|
+
}
|
|
113
151
|
async function respond(request, operation) {
|
|
114
152
|
try {
|
|
115
153
|
const value = await operation();
|
|
@@ -133,7 +171,7 @@ export function startWorkerHost(endpoint) {
|
|
|
133
171
|
? undefined
|
|
134
172
|
: requiredSnapshotInput(operation.snapshotId).readable;
|
|
135
173
|
try {
|
|
136
|
-
const opened = await
|
|
174
|
+
const opened = await openBinding(operation.storage, operation.telemetryEnabled
|
|
137
175
|
? (span) => endpoint.postMessage({ kind: "telemetry", span })
|
|
138
176
|
: undefined, telemetryParent, createSyncServerBridge(operation.server), operation.progressEnabled
|
|
139
177
|
? (progress) => endpoint.postMessage({ kind: "open.progress", progress })
|
|
@@ -216,12 +254,8 @@ export function startWorkerHost(endpoint) {
|
|
|
216
254
|
throw workerStateError("snapshot pulls bypass the finite operation queue");
|
|
217
255
|
case "exportSnapshot.cancel":
|
|
218
256
|
throw workerStateError("snapshot cancellation bypasses the finite operation queue");
|
|
219
|
-
case "observe":
|
|
220
|
-
|
|
221
|
-
const observeId = nextObserveId++;
|
|
222
|
-
observations.set(observeId, events);
|
|
223
|
-
return observeId;
|
|
224
|
-
}
|
|
257
|
+
case "observe":
|
|
258
|
+
throw workerStateError("observe must use the observation lane");
|
|
225
259
|
case "close": {
|
|
226
260
|
const openLix = requiredLix(sessionId);
|
|
227
261
|
await openLix.close();
|
|
@@ -296,14 +330,17 @@ export function startWorkerHost(endpoint) {
|
|
|
296
330
|
};
|
|
297
331
|
}
|
|
298
332
|
async function bridgeFetch(input, init) {
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
333
|
+
const extension = init;
|
|
334
|
+
const streaming = extension?.lixResponseStream === true;
|
|
335
|
+
const responseLimit = extension?.lixResponseLimit;
|
|
336
|
+
if (!streaming &&
|
|
337
|
+
(typeof responseLimit !== "number" ||
|
|
338
|
+
!Number.isSafeInteger(responseLimit) ||
|
|
339
|
+
responseLimit <= 0)) {
|
|
303
340
|
throw new TypeError("Browser sync fetch has no valid response limit");
|
|
304
341
|
}
|
|
305
342
|
const requestId = nextSyncRequestId++;
|
|
306
|
-
const
|
|
343
|
+
const requestBase = {
|
|
307
344
|
url: typeof input === "string"
|
|
308
345
|
? input
|
|
309
346
|
: input instanceof URL
|
|
@@ -313,8 +350,14 @@ export function startWorkerHost(endpoint) {
|
|
|
313
350
|
headers: headerEntries(init?.headers),
|
|
314
351
|
body: serializableBody(init?.body),
|
|
315
352
|
credentials: init?.credentials,
|
|
316
|
-
responseLimit,
|
|
317
353
|
};
|
|
354
|
+
const request = streaming
|
|
355
|
+
? { ...requestBase, responseMode: "stream" }
|
|
356
|
+
: {
|
|
357
|
+
...requestBase,
|
|
358
|
+
responseMode: "buffered",
|
|
359
|
+
responseLimit: responseLimit,
|
|
360
|
+
};
|
|
318
361
|
const response = new Promise((resolve, reject) => {
|
|
319
362
|
pendingSyncFetch.set(requestId, { resolve, reject });
|
|
320
363
|
endpoint.postMessage({ kind: "sync.fetch", requestId, request });
|
|
@@ -324,20 +367,77 @@ export function startWorkerHost(endpoint) {
|
|
|
324
367
|
pendingSyncFetch.delete(requestId);
|
|
325
368
|
if (pending) {
|
|
326
369
|
pending.reject(new DOMException("The operation was aborted", "AbortError"));
|
|
327
|
-
endpoint.postMessage({ kind: "sync.fetch.cancel", requestId });
|
|
328
370
|
}
|
|
371
|
+
const pull = pendingSyncStreamPulls.get(requestId);
|
|
372
|
+
pendingSyncStreamPulls.delete(requestId);
|
|
373
|
+
if (pull) {
|
|
374
|
+
const error = new DOMException("The operation was aborted", "AbortError");
|
|
375
|
+
pull.controller.error(error);
|
|
376
|
+
pull.reject(error);
|
|
377
|
+
}
|
|
378
|
+
endpoint.postMessage({ kind: "sync.fetch.cancel", requestId });
|
|
379
|
+
finishSyncStream(requestId);
|
|
329
380
|
};
|
|
330
381
|
if (init?.signal?.aborted)
|
|
331
382
|
abort();
|
|
332
383
|
else
|
|
333
384
|
init?.signal?.addEventListener("abort", abort, { once: true });
|
|
385
|
+
let streamEstablished = false;
|
|
334
386
|
try {
|
|
335
387
|
const resolved = await response;
|
|
388
|
+
if (resolved.streaming) {
|
|
389
|
+
const signal = init?.signal;
|
|
390
|
+
if (signal?.aborted) {
|
|
391
|
+
abort();
|
|
392
|
+
throw new DOMException("The operation was aborted", "AbortError");
|
|
393
|
+
}
|
|
394
|
+
if (resolved.status === 204 ||
|
|
395
|
+
resolved.status === 205 ||
|
|
396
|
+
resolved.status === 304) {
|
|
397
|
+
endpoint.postMessage({ kind: "sync.fetch.cancel", requestId });
|
|
398
|
+
return new Response(null, {
|
|
399
|
+
status: resolved.status,
|
|
400
|
+
statusText: resolved.statusText,
|
|
401
|
+
headers: resolved.headers,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
syncStreamCleanup.set(requestId, () => signal?.removeEventListener("abort", abort));
|
|
405
|
+
const body = new ReadableStream({
|
|
406
|
+
pull: (controller) => new Promise((resolve, reject) => {
|
|
407
|
+
pendingSyncStreamPulls.set(requestId, {
|
|
408
|
+
controller,
|
|
409
|
+
resolve,
|
|
410
|
+
reject,
|
|
411
|
+
});
|
|
412
|
+
endpoint.postMessage({
|
|
413
|
+
kind: "sync.fetch.stream.pull",
|
|
414
|
+
requestId,
|
|
415
|
+
});
|
|
416
|
+
}),
|
|
417
|
+
cancel: abort,
|
|
418
|
+
});
|
|
419
|
+
const streamedResponse = new Response(body, {
|
|
420
|
+
status: resolved.status,
|
|
421
|
+
statusText: resolved.statusText,
|
|
422
|
+
headers: resolved.headers,
|
|
423
|
+
});
|
|
424
|
+
streamEstablished = true;
|
|
425
|
+
return streamedResponse;
|
|
426
|
+
}
|
|
336
427
|
return responseFromSyncFetch(resolved);
|
|
337
428
|
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
if (streaming && !streamEstablished) {
|
|
431
|
+
endpoint.postMessage({ kind: "sync.fetch.cancel", requestId });
|
|
432
|
+
finishSyncStream(requestId);
|
|
433
|
+
}
|
|
434
|
+
throw error;
|
|
435
|
+
}
|
|
338
436
|
finally {
|
|
339
|
-
init?.signal?.removeEventListener("abort", abort);
|
|
340
437
|
pendingSyncFetch.delete(requestId);
|
|
438
|
+
if (!streamEstablished) {
|
|
439
|
+
init?.signal?.removeEventListener("abort", abort);
|
|
440
|
+
}
|
|
341
441
|
}
|
|
342
442
|
}
|
|
343
443
|
async function handleObserveNext(observeId, telemetryParent) {
|
|
@@ -347,6 +447,15 @@ export function startWorkerHost(endpoint) {
|
|
|
347
447
|
events.setTelemetryParent(telemetryParent);
|
|
348
448
|
return events.next();
|
|
349
449
|
}
|
|
450
|
+
async function handleObserveRegistration(sessionId, sql, params) {
|
|
451
|
+
// Do not touch the mutable Lix telemetry carrier here: it belongs to the
|
|
452
|
+
// serialized finite lane. Each `observe.next` supplies telemetry directly
|
|
453
|
+
// to its observation binding.
|
|
454
|
+
const events = await requiredLix(sessionId).observe(sql, params);
|
|
455
|
+
const observeId = nextObserveId++;
|
|
456
|
+
observations.set(observeId, events);
|
|
457
|
+
return observeId;
|
|
458
|
+
}
|
|
350
459
|
function requiredLix(sessionId) {
|
|
351
460
|
const lix = sessions.get(sessionId);
|
|
352
461
|
if (!lix)
|
|
@@ -364,6 +473,9 @@ export function startWorkerHost(endpoint) {
|
|
|
364
473
|
}
|
|
365
474
|
}
|
|
366
475
|
export function responseFromSyncFetch(resolved) {
|
|
476
|
+
if (resolved.streaming) {
|
|
477
|
+
throw new TypeError("Streaming sync responses require the worker stream bridge");
|
|
478
|
+
}
|
|
367
479
|
const body = resolved.status === 204 ||
|
|
368
480
|
resolved.status === 205 ||
|
|
369
481
|
resolved.status === 304
|
|
@@ -12,14 +12,23 @@ export type WorkerSyncFetchRequest = {
|
|
|
12
12
|
headers: [string, string][];
|
|
13
13
|
body?: string | Uint8Array;
|
|
14
14
|
credentials?: RequestCredentials;
|
|
15
|
+
} & ({
|
|
16
|
+
responseMode: "buffered";
|
|
15
17
|
responseLimit: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
+
} | {
|
|
19
|
+
responseMode: "stream";
|
|
20
|
+
});
|
|
21
|
+
type WorkerSyncFetchResponseHead = {
|
|
18
22
|
status: number;
|
|
19
23
|
statusText: string;
|
|
20
24
|
headers: [string, string][];
|
|
21
|
-
body: Uint8Array;
|
|
22
25
|
};
|
|
26
|
+
export type WorkerSyncFetchResponse = WorkerSyncFetchResponseHead & ({
|
|
27
|
+
streaming: true;
|
|
28
|
+
} | {
|
|
29
|
+
streaming?: false;
|
|
30
|
+
body: Uint8Array;
|
|
31
|
+
});
|
|
23
32
|
export type WorkerRequest = {
|
|
24
33
|
id: number;
|
|
25
34
|
sessionId: number;
|
|
@@ -138,6 +147,20 @@ export type WorkerNotification = {
|
|
|
138
147
|
ok: false;
|
|
139
148
|
error: SerializedWorkerError;
|
|
140
149
|
};
|
|
150
|
+
} | {
|
|
151
|
+
kind: "sync.fetch.stream.result";
|
|
152
|
+
requestId: number;
|
|
153
|
+
result: {
|
|
154
|
+
ok: true;
|
|
155
|
+
done: true;
|
|
156
|
+
} | {
|
|
157
|
+
ok: true;
|
|
158
|
+
done: false;
|
|
159
|
+
chunk: Uint8Array;
|
|
160
|
+
} | {
|
|
161
|
+
ok: false;
|
|
162
|
+
error: SerializedWorkerError;
|
|
163
|
+
};
|
|
141
164
|
};
|
|
142
165
|
export type WorkerInput = WorkerRequest | WorkerNotification;
|
|
143
166
|
export type WorkerConnection = {
|
|
@@ -181,9 +204,13 @@ export type WorkerResponse = {
|
|
|
181
204
|
kind: "sync.fetch";
|
|
182
205
|
requestId: number;
|
|
183
206
|
request: WorkerSyncFetchRequest;
|
|
207
|
+
} | {
|
|
208
|
+
kind: "sync.fetch.stream.pull";
|
|
209
|
+
requestId: number;
|
|
184
210
|
} | {
|
|
185
211
|
kind: "sync.fetch.cancel";
|
|
186
212
|
requestId: number;
|
|
187
213
|
};
|
|
188
214
|
export declare function serializeWorkerError(error: unknown): SerializedWorkerError;
|
|
189
215
|
export declare function deserializeWorkerError(error: SerializedWorkerError): Error;
|
|
216
|
+
export {};
|
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.15.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"typecheck": "tsc -p tsconfig.test.json --noEmit"
|
|
50
50
|
},
|
|
51
51
|
"optionalDependencies": {
|
|
52
|
-
"@lix-js/sdk-darwin-arm64": "0.
|
|
53
|
-
"@lix-js/sdk-linux-arm64": "0.
|
|
54
|
-
"@lix-js/sdk-linux-x64": "0.
|
|
55
|
-
"@lix-js/sdk-win32-x64": "0.
|
|
52
|
+
"@lix-js/sdk-darwin-arm64": "0.15.1",
|
|
53
|
+
"@lix-js/sdk-linux-arm64": "0.15.1",
|
|
54
|
+
"@lix-js/sdk-linux-x64": "0.15.1",
|
|
55
|
+
"@lix-js/sdk-win32-x64": "0.15.1"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@vitest/browser-playwright": "4.1.10",
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
type WasmInitializer = (options: {
|
|
2
|
-
module_or_path: URL;
|
|
3
|
-
}) => Promise<unknown>;
|
|
4
|
-
/**
|
|
5
|
-
* Initializes one fingerprinted Wasm asset without racing the browser's shared
|
|
6
|
-
* HTTP cache across tabs.
|
|
7
|
-
*
|
|
8
|
-
* Chromium can abort one consumer when separate workers cold-load the same
|
|
9
|
-
* large response concurrently. The lock lasts only for the initial streaming
|
|
10
|
-
* compilation. Once it releases, later workers consume the completed immutable
|
|
11
|
-
* cache entry and compile independently.
|
|
12
|
-
*/
|
|
13
|
-
export declare function initializeBrowserWasm(initialize: WasmInitializer, moduleUrl: URL): Promise<unknown>;
|
|
14
|
-
export {};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Initializes one fingerprinted Wasm asset without racing the browser's shared
|
|
3
|
-
* HTTP cache across tabs.
|
|
4
|
-
*
|
|
5
|
-
* Chromium can abort one consumer when separate workers cold-load the same
|
|
6
|
-
* large response concurrently. The lock lasts only for the initial streaming
|
|
7
|
-
* compilation. Once it releases, later workers consume the completed immutable
|
|
8
|
-
* cache entry and compile independently.
|
|
9
|
-
*/
|
|
10
|
-
export function initializeBrowserWasm(initialize, moduleUrl) {
|
|
11
|
-
const lockManager = globalThis.navigator.locks;
|
|
12
|
-
const run = () => initialize({ module_or_path: moduleUrl });
|
|
13
|
-
if (!lockManager)
|
|
14
|
-
return run();
|
|
15
|
-
return lockManager.request(`lix:browser-wasm:${moduleUrl.href}`, { mode: "exclusive" }, run);
|
|
16
|
-
}
|