@lix-js/sdk 0.12.3 → 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 +132 -6
- 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 -6
- 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 +2 -2
- package/dist/worker/factory.node.js +3 -10
- 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/lix.js
CHANGED
|
@@ -15,26 +15,44 @@ const observeFinalizer = new FinalizationRegistry(({ observe, onClose }) => {
|
|
|
15
15
|
});
|
|
16
16
|
export class Lix {
|
|
17
17
|
binding;
|
|
18
|
+
openReport;
|
|
18
19
|
closePromise;
|
|
19
20
|
#activeBranchListeners = new Set();
|
|
20
21
|
#inFlightOperations = new Set();
|
|
21
22
|
#observations = new Map();
|
|
23
|
+
#snapshotExports = new Set();
|
|
22
24
|
#nextObservationId = 0;
|
|
23
25
|
#transactionsOpening = 0;
|
|
24
26
|
#activeTransactions = 0;
|
|
25
27
|
#acceptingOperations = true;
|
|
26
28
|
constructor(binding) {
|
|
27
29
|
this.binding = binding;
|
|
30
|
+
const report = binding.openReport?.();
|
|
31
|
+
this.openReport = report
|
|
32
|
+
? Object.freeze({
|
|
33
|
+
...report,
|
|
34
|
+
...(report.migration
|
|
35
|
+
? { migration: Object.freeze({ ...report.migration }) }
|
|
36
|
+
: {}),
|
|
37
|
+
})
|
|
38
|
+
: undefined;
|
|
39
|
+
}
|
|
40
|
+
/** Opens an independent session over the same repository storage. */
|
|
41
|
+
async openAnotherSession(options = {}) {
|
|
42
|
+
assertOpenAnotherSessionOptions(options);
|
|
43
|
+
return this.#runOperation(async () => new Lix(await this.binding.openAnotherSession(options)));
|
|
28
44
|
}
|
|
29
45
|
async execute(sql, params = [], options) {
|
|
30
46
|
assertExecuteArgs("lix", sql, params, options);
|
|
31
|
-
|
|
47
|
+
const { rowMode = "object", ...bindingOptions } = options ?? {};
|
|
48
|
+
return this.#runOperation(async () => wrapExecuteResult(await this.binding.execute(sql, params.map((param, index) => toNativeValue(normalizeParam(param, index))), bindingOptions), rowMode));
|
|
32
49
|
}
|
|
33
50
|
async executeBatch(statements, options) {
|
|
34
51
|
const normalizedStatements = normalizeBatchStatements(statements, options);
|
|
52
|
+
const { rowMode = "object", ...bindingOptions } = options ?? {};
|
|
35
53
|
return this.#runOperation(async () => {
|
|
36
|
-
const results = await this.binding.executeBatch(normalizedStatements,
|
|
37
|
-
return results.map(wrapExecuteBatchResult);
|
|
54
|
+
const results = await this.binding.executeBatch(normalizedStatements, bindingOptions);
|
|
55
|
+
return results.map((result) => wrapExecuteBatchResult(result, rowMode));
|
|
38
56
|
});
|
|
39
57
|
}
|
|
40
58
|
observe(sql, params = []) {
|
|
@@ -82,8 +100,90 @@ export class Lix {
|
|
|
82
100
|
async createBranch(options) {
|
|
83
101
|
return this.#runOperation(() => this.binding.createBranch(options));
|
|
84
102
|
}
|
|
85
|
-
|
|
86
|
-
|
|
103
|
+
/** Streams a deterministic snapshot of the complete Lix. */
|
|
104
|
+
exportSnapshot() {
|
|
105
|
+
let snapshot;
|
|
106
|
+
const start = () => {
|
|
107
|
+
if (snapshot)
|
|
108
|
+
return snapshot;
|
|
109
|
+
let finish;
|
|
110
|
+
const completed = new Promise((resolve) => {
|
|
111
|
+
finish = resolve;
|
|
112
|
+
});
|
|
113
|
+
let resolveBinding;
|
|
114
|
+
let rejectBinding;
|
|
115
|
+
const binding = new Promise((resolve, reject) => {
|
|
116
|
+
resolveBinding = resolve;
|
|
117
|
+
rejectBinding = reject;
|
|
118
|
+
});
|
|
119
|
+
const operation = this.#runOperation(async () => {
|
|
120
|
+
try {
|
|
121
|
+
const exportSnapshot = this.binding.exportSnapshot;
|
|
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));
|
|
129
|
+
await completed;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
rejectBinding(error);
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
// Pull observes setup errors through `binding`; this catch only prevents
|
|
137
|
+
// the lifecycle-tracking promise from becoming an unhandled rejection.
|
|
138
|
+
void operation.catch((error) => rejectBinding(error));
|
|
139
|
+
let finished = false;
|
|
140
|
+
let cancelPromise;
|
|
141
|
+
const active = {
|
|
142
|
+
binding,
|
|
143
|
+
finish: () => {
|
|
144
|
+
if (finished)
|
|
145
|
+
return;
|
|
146
|
+
finished = true;
|
|
147
|
+
this.#snapshotExports.delete(active);
|
|
148
|
+
finish();
|
|
149
|
+
},
|
|
150
|
+
cancel: () => (cancelPromise ??= (async () => {
|
|
151
|
+
try {
|
|
152
|
+
await (await binding).cancel();
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
active.finish();
|
|
156
|
+
}
|
|
157
|
+
})()),
|
|
158
|
+
};
|
|
159
|
+
snapshot = active;
|
|
160
|
+
this.#snapshotExports.add(active);
|
|
161
|
+
return snapshot;
|
|
162
|
+
};
|
|
163
|
+
return new ReadableStream({
|
|
164
|
+
pull: async (controller) => {
|
|
165
|
+
const active = start();
|
|
166
|
+
const binding = await active.binding;
|
|
167
|
+
try {
|
|
168
|
+
const chunk = await binding.next();
|
|
169
|
+
if (chunk == null) {
|
|
170
|
+
active.finish();
|
|
171
|
+
controller.close();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
controller.enqueue(chunk);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
await active.cancel().catch(() => undefined);
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
cancel: async () => {
|
|
182
|
+
if (!snapshot)
|
|
183
|
+
return;
|
|
184
|
+
await snapshot.cancel();
|
|
185
|
+
},
|
|
186
|
+
}, { highWaterMark: 0 });
|
|
87
187
|
}
|
|
88
188
|
async undo() {
|
|
89
189
|
return this.#runOperation(() => this.binding.undo());
|
|
@@ -131,6 +231,7 @@ export class Lix {
|
|
|
131
231
|
}
|
|
132
232
|
this.#observations.clear();
|
|
133
233
|
this.closePromise = (async () => {
|
|
234
|
+
await Promise.allSettled([...this.#snapshotExports].map((snapshot) => snapshot.cancel()));
|
|
134
235
|
await Promise.allSettled([...this.#inFlightOperations]);
|
|
135
236
|
const results = await Promise.allSettled([
|
|
136
237
|
Promise.resolve().then(() => this.binding.close()),
|
|
@@ -164,6 +265,20 @@ export class Lix {
|
|
|
164
265
|
throw error;
|
|
165
266
|
}
|
|
166
267
|
}
|
|
268
|
+
function assertOpenAnotherSessionOptions(options) {
|
|
269
|
+
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
270
|
+
throw new TypeError("openAnotherSession() options must be an object");
|
|
271
|
+
}
|
|
272
|
+
for (const [name, value] of [
|
|
273
|
+
["branchId", options.branchId],
|
|
274
|
+
["accountId", options.accountId],
|
|
275
|
+
]) {
|
|
276
|
+
if (value !== undefined &&
|
|
277
|
+
(typeof value !== "string" || value.length === 0)) {
|
|
278
|
+
throw new TypeError(`openAnotherSession() ${name} must be a non-empty string`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
167
282
|
export class ObserveEvents {
|
|
168
283
|
onClose;
|
|
169
284
|
setup = {};
|
|
@@ -218,7 +333,8 @@ export class LixTransaction {
|
|
|
218
333
|
}
|
|
219
334
|
async execute(sql, params = [], options) {
|
|
220
335
|
assertExecuteArgs("lixTransaction", sql, params, options);
|
|
221
|
-
|
|
336
|
+
const { rowMode = "object", ...bindingOptions } = options ?? {};
|
|
337
|
+
return wrapExecuteResult(await this.binding.execute(sql, params.map((param, index) => toNativeValue(normalizeParam(param, index))), bindingOptions), rowMode);
|
|
222
338
|
}
|
|
223
339
|
async commit() {
|
|
224
340
|
return this.finish("transaction.commit");
|
|
@@ -271,6 +387,11 @@ function assertExecuteArgs(receiver, sql, params, options) {
|
|
|
271
387
|
typeof options.idempotencyKey !== "string") {
|
|
272
388
|
throw invalidArgument("execute", "options.idempotencyKey", "string", typeof options.idempotencyKey, receiver);
|
|
273
389
|
}
|
|
390
|
+
if (options.rowMode !== undefined &&
|
|
391
|
+
options.rowMode !== "object" &&
|
|
392
|
+
options.rowMode !== "array") {
|
|
393
|
+
throw invalidArgument("execute", "options.rowMode", '"object" | "array"', typeof options.rowMode, receiver);
|
|
394
|
+
}
|
|
274
395
|
}
|
|
275
396
|
function assertSqlArgs(operation, receiver, sql, params) {
|
|
276
397
|
if (typeof sql !== "string") {
|
|
@@ -331,6 +452,11 @@ function assertBatchOptions(options) {
|
|
|
331
452
|
typeof options.idempotencyKey !== "string") {
|
|
332
453
|
throw invalidArgument("executeBatch", "options.idempotencyKey", "string", typeof options.idempotencyKey);
|
|
333
454
|
}
|
|
455
|
+
if (options.rowMode !== undefined &&
|
|
456
|
+
options.rowMode !== "object" &&
|
|
457
|
+
options.rowMode !== "array") {
|
|
458
|
+
throw invalidArgument("lix.executeBatch", "options.rowMode", '"object" | "array"', typeof options.rowMode);
|
|
459
|
+
}
|
|
334
460
|
}
|
|
335
461
|
function withBatchStatementIndex(error, statementIndex) {
|
|
336
462
|
if (!error || typeof error !== "object")
|
package/dist/open-lix.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Lix } from "./lix.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { OpenLixOptions } from "./types.js";
|
|
3
3
|
export { Lix, LixTransaction, ObserveEvents } from "./lix.js";
|
|
4
|
-
export declare class IndexedDbStorage {
|
|
5
|
-
readonly name: string;
|
|
6
|
-
constructor(options: IndexedDbStorageOptions);
|
|
7
|
-
}
|
|
8
4
|
export declare function openLix(options?: OpenLixOptions): Promise<Lix>;
|
|
5
|
+
export declare namespace openLix {
|
|
6
|
+
function fromSnapshot(source: ReadableStream<Uint8Array> | Uint8Array, options?: OpenLixOptions): Promise<Lix>;
|
|
7
|
+
}
|
package/dist/open-lix.js
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { Lix } from "./lix.js";
|
|
2
|
-
import { isLixStorage } from "./storage-adapter.js";
|
|
2
|
+
import { isJsProviderLixStorage, isLixStorage, } from "./storage-adapter.js";
|
|
3
3
|
export { Lix, LixTransaction, ObserveEvents } from "./lix.js";
|
|
4
4
|
const openStorages = new WeakSet();
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
name;
|
|
8
|
-
constructor(options) {
|
|
9
|
-
if (!options || typeof options.name !== "string" || options.name.length === 0) {
|
|
10
|
-
throw new TypeError("IndexedDbStorage requires a non-empty name");
|
|
11
|
-
}
|
|
12
|
-
this.name = options.name;
|
|
13
|
-
}
|
|
5
|
+
export function openLix(options = {}) {
|
|
6
|
+
return openLixInternal(options);
|
|
14
7
|
}
|
|
15
|
-
|
|
8
|
+
async function openLixInternal(options, snapshot) {
|
|
16
9
|
if (!options || typeof options !== "object") {
|
|
17
10
|
throw new TypeError("openLix() options must be an object");
|
|
18
11
|
}
|
|
@@ -24,16 +17,52 @@ export async function openLix(options = {}) {
|
|
|
24
17
|
typeof options.telemetry.onSpan !== "function")) {
|
|
25
18
|
throw new TypeError("openLix() telemetry requires an onSpan callback");
|
|
26
19
|
}
|
|
20
|
+
if (options.telemetry?.parentContext !== undefined &&
|
|
21
|
+
typeof options.telemetry.parentContext !== "function") {
|
|
22
|
+
throw new TypeError("openLix() telemetry parentContext must be a context provider function");
|
|
23
|
+
}
|
|
24
|
+
if (options.onProgress !== undefined &&
|
|
25
|
+
typeof options.onProgress !== "function") {
|
|
26
|
+
throw new TypeError("openLix() onProgress must be a function");
|
|
27
|
+
}
|
|
27
28
|
if (options.server !== undefined) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
if (snapshot) {
|
|
30
|
+
throw new TypeError("openLix.fromSnapshot() does not accept server mode");
|
|
31
|
+
}
|
|
32
|
+
if (options.server.mode === "remote") {
|
|
33
|
+
const { openRemoteLixBinding } = await import("./remote/client.js");
|
|
34
|
+
if ("storage" in options && options.storage !== undefined) {
|
|
35
|
+
throw new TypeError("openLix() remote mode does not accept storage");
|
|
36
|
+
}
|
|
37
|
+
return new Lix(await openRemoteLixBinding(options.server));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const syncServer = options.server?.mode === "sync"
|
|
41
|
+
? {
|
|
42
|
+
url: new URL(options.server.url).toString(),
|
|
43
|
+
headers: options.server.headers,
|
|
44
|
+
fetch: options.server.fetch,
|
|
31
45
|
}
|
|
32
|
-
|
|
46
|
+
: undefined;
|
|
47
|
+
if (syncServer?.fetch !== undefined && typeof syncServer.fetch !== "function") {
|
|
48
|
+
throw new TypeError("openLix() sync server fetch must be a function");
|
|
49
|
+
}
|
|
50
|
+
if (syncServer?.headers !== undefined && typeof syncServer.headers !== "function") {
|
|
51
|
+
// Validate static headers before opening a worker/native runtime.
|
|
52
|
+
new Headers(syncServer.headers);
|
|
53
|
+
}
|
|
54
|
+
if (options.server !== undefined && syncServer === undefined) {
|
|
55
|
+
throw new TypeError("openLix() server mode must be 'remote' or 'sync'");
|
|
56
|
+
}
|
|
57
|
+
if (syncServer !== undefined && options.storage === undefined) {
|
|
58
|
+
throw new TypeError("openLix() sync mode requires a durability-capable storage adapter");
|
|
33
59
|
}
|
|
34
60
|
const { openLixWorkerBinding } = await import("./worker/client.js");
|
|
35
61
|
if (options.storage === undefined) {
|
|
36
|
-
return new Lix(await openLixWorkerBinding({ kind: "memory" }, undefined, options.telemetry));
|
|
62
|
+
return new Lix(await openLixWorkerBinding({ kind: "memory" }, undefined, options.telemetry, syncServer, options.onProgress, snapshot));
|
|
63
|
+
}
|
|
64
|
+
if (isJsProviderLixStorage(options.storage)) {
|
|
65
|
+
return openJsProviderStorage(options.storage, options.telemetry, syncServer, options.onProgress, snapshot);
|
|
37
66
|
}
|
|
38
67
|
if (isLixStorage(options.storage)) {
|
|
39
68
|
const storage = options.storage;
|
|
@@ -47,12 +76,13 @@ export async function openLix(options = {}) {
|
|
|
47
76
|
openStorages.delete(storage);
|
|
48
77
|
};
|
|
49
78
|
try {
|
|
50
|
-
binding = await openLixWorkerBinding(storage.lixStorage.config, disconnect, options.telemetry);
|
|
79
|
+
binding = await openLixWorkerBinding(storage.lixStorage.config, disconnect, options.telemetry, syncServer, options.onProgress, snapshot);
|
|
80
|
+
const routed = routeStorageBinding(binding);
|
|
51
81
|
storage.lixStorage.connect({
|
|
52
|
-
importFilesystemPaths: (paths) =>
|
|
53
|
-
syncDiskToLix: () =>
|
|
82
|
+
importFilesystemPaths: (paths) => routed.current().importFilesystemPaths(paths),
|
|
83
|
+
syncDiskToLix: () => routed.current().syncDiskToLix(),
|
|
54
84
|
});
|
|
55
|
-
return new Lix(binding);
|
|
85
|
+
return new Lix(routed.binding);
|
|
56
86
|
}
|
|
57
87
|
catch (error) {
|
|
58
88
|
disconnect();
|
|
@@ -60,25 +90,135 @@ export async function openLix(options = {}) {
|
|
|
60
90
|
throw error;
|
|
61
91
|
}
|
|
62
92
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
93
|
+
throw new TypeError("openLix() requires a Lix storage adapter");
|
|
94
|
+
}
|
|
95
|
+
function routeStorageBinding(root) {
|
|
96
|
+
const live = new Set();
|
|
97
|
+
const wrap = (binding) => {
|
|
98
|
+
live.add(binding);
|
|
99
|
+
return new Proxy(binding, {
|
|
100
|
+
get(target, property, receiver) {
|
|
101
|
+
if (property === "openAnotherSession") {
|
|
102
|
+
return async (options) => wrap(await target.openAnotherSession(options));
|
|
103
|
+
}
|
|
104
|
+
if (property === "close") {
|
|
105
|
+
return async () => {
|
|
106
|
+
try {
|
|
107
|
+
await target.close();
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
live.delete(target);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const value = Reflect.get(target, property, receiver);
|
|
115
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
binding: wrap(root),
|
|
121
|
+
current: () => {
|
|
122
|
+
const bindings = [...live];
|
|
123
|
+
return bindings[bindings.length - 1] ?? root;
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function openJsProviderStorage(storage, telemetry, syncServer, onProgress, snapshot) {
|
|
128
|
+
const { openLixWorkerBinding } = await import("./worker/client.js");
|
|
129
|
+
if (openStorages.has(storage))
|
|
130
|
+
throw storageAlreadyOpen();
|
|
131
|
+
openStorages.add(storage);
|
|
132
|
+
let binding;
|
|
133
|
+
try {
|
|
134
|
+
const opened = await openLixWorkerBinding({
|
|
135
|
+
kind: "jsStorage",
|
|
136
|
+
moduleUrl: storage.lixStorage.moduleUrl,
|
|
137
|
+
options: storage.lixStorage.options,
|
|
138
|
+
}, () => openStorages.delete(storage), telemetry, syncServer, onProgress, snapshot);
|
|
139
|
+
binding = opened;
|
|
140
|
+
return new Lix(opened);
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
openStorages.delete(storage);
|
|
144
|
+
await binding?.close().catch(() => undefined);
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
(function (openLix) {
|
|
149
|
+
async function fromSnapshot(source, options = {}) {
|
|
150
|
+
const prepared = prepareSnapshotSource(source);
|
|
71
151
|
try {
|
|
72
|
-
|
|
73
|
-
return new Lix(binding);
|
|
152
|
+
return await openLixInternal(options, prepared.stream);
|
|
74
153
|
}
|
|
75
154
|
catch (error) {
|
|
76
|
-
|
|
77
|
-
await binding?.close().catch(() => undefined);
|
|
155
|
+
await prepared.cancel(error);
|
|
78
156
|
throw error;
|
|
79
157
|
}
|
|
80
158
|
}
|
|
81
|
-
|
|
159
|
+
openLix.fromSnapshot = fromSnapshot;
|
|
160
|
+
})(openLix || (openLix = {}));
|
|
161
|
+
function prepareSnapshotSource(source) {
|
|
162
|
+
if (source instanceof Uint8Array) {
|
|
163
|
+
let sent = false;
|
|
164
|
+
const stream = new ReadableStream({
|
|
165
|
+
pull(controller) {
|
|
166
|
+
if (!sent) {
|
|
167
|
+
sent = true;
|
|
168
|
+
controller.enqueue(source);
|
|
169
|
+
}
|
|
170
|
+
controller.close();
|
|
171
|
+
},
|
|
172
|
+
}, { highWaterMark: 0 });
|
|
173
|
+
return {
|
|
174
|
+
stream,
|
|
175
|
+
cancel: async (reason) => {
|
|
176
|
+
await stream.cancel(reason).catch(() => undefined);
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
if (!source || typeof source.getReader !== "function") {
|
|
181
|
+
throw new TypeError("openLix.fromSnapshot() requires a ReadableStream<Uint8Array> or Uint8Array");
|
|
182
|
+
}
|
|
183
|
+
// Acquire the caller's stream before openLixInternal can start a native or
|
|
184
|
+
// worker restore. A locked source therefore fails without creating backend work.
|
|
185
|
+
const reader = source.getReader();
|
|
186
|
+
let released = false;
|
|
187
|
+
const release = () => {
|
|
188
|
+
if (released)
|
|
189
|
+
return;
|
|
190
|
+
released = true;
|
|
191
|
+
reader.releaseLock();
|
|
192
|
+
};
|
|
193
|
+
const cancel = async (reason) => {
|
|
194
|
+
if (released)
|
|
195
|
+
return;
|
|
196
|
+
try {
|
|
197
|
+
await reader.cancel(reason);
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
release();
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
const stream = new ReadableStream({
|
|
204
|
+
async pull(controller) {
|
|
205
|
+
try {
|
|
206
|
+
const result = await reader.read();
|
|
207
|
+
if (result.done) {
|
|
208
|
+
release();
|
|
209
|
+
controller.close();
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
controller.enqueue(result.value);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
release();
|
|
216
|
+
controller.error(error);
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
cancel,
|
|
220
|
+
}, { highWaterMark: 0 });
|
|
221
|
+
return { stream, cancel };
|
|
82
222
|
}
|
|
83
223
|
function storageAlreadyOpen() {
|
|
84
224
|
const error = new Error("openLix() storage is already open; close the existing Lix or create a new storage adapter");
|
package/dist/remote/client.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { LixBinding } from "../binding-types.js";
|
|
2
2
|
import type { RemoteLixServerOptions } from "../types.js";
|
|
3
|
-
import { type ServerProtocolHandshakeRequest } from "./server-protocol.js";
|
|
4
3
|
type RemoteLixClientOptions = {
|
|
5
|
-
initialActiveBranchId?:
|
|
4
|
+
initialActiveBranchId?: string;
|
|
6
5
|
};
|
|
7
6
|
export declare function openRemoteLixBinding(options: RemoteLixServerOptions, clientOptions?: RemoteLixClientOptions): Promise<LixBinding>;
|
|
8
7
|
export {};
|