@lix-js/sdk 0.10.0 → 0.11.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 +2 -3
- package/dist/binding-types.d.ts +3 -3
- package/dist/binding.browser.js +1 -1
- package/dist/binding.node.js +0 -5
- package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
- package/dist/bundled-plugins/plugin_markdown.lixplugin +0 -0
- package/dist/client-state.js +2 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/lix.d.ts +2 -2
- package/dist/lix.js +7 -2
- package/dist/open-lix.d.ts +1 -5
- package/dist/open-lix.js +1 -18
- package/dist/remote/client.js +38 -3
- package/dist/remote/protocol.d.ts +6 -0
- package/dist/remote/protocol.js +12 -0
- package/dist/result.d.ts +2 -1
- package/dist/result.js +12 -0
- package/dist/types.d.ts +12 -4
- package/dist/wasm/lix_js_sdk.d.ts +2 -2
- package/dist/wasm/lix_js_sdk.js +7 -7
- package/dist/wasm/lix_js_sdk_bg.wasm +0 -0
- package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +2 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ server switch into a rejected operation. Explicit `lix.clientState.set()` and
|
|
|
88
88
|
Rust transaction has already committed, `get()` continues to expose that live
|
|
89
89
|
session value; a later successful snapshot save can make it durable.
|
|
90
90
|
|
|
91
|
-
Filesystem sync
|
|
91
|
+
Filesystem sync uses native Node.js dependencies:
|
|
92
92
|
|
|
93
93
|
```ts
|
|
94
94
|
import { LocalFilesystem, openLix } from "@lix-js/sdk";
|
|
@@ -175,11 +175,10 @@ try {
|
|
|
175
175
|
- `openLix()` opens a fresh in-memory Lix. Pass `new LocalFilesystem({ path, syncAllFiles: true })` for a filesystem workspace directory backed by `<path>/.lix/.internal/rocksdb`.
|
|
176
176
|
- Pass `new LocalFilesystem({ path, lixDir, syncAllFiles: true })` for filesystem sync with repository metadata in an external `.lix` directory and no workspace `.lix` directory.
|
|
177
177
|
- Pass `syncAllFiles: false` to start filesystem sync with no regular workspace files, then call `storage.importPaths(["notes/today.md"])` on the `LocalFilesystem` instance to sync selected files. Imported paths are exact workspace-relative file paths, not directories or globs.
|
|
178
|
-
- Use `new SQLite({ path })` when a single SQLite-backed `.lix` file is the application document itself, for example when defining a new file format and using Lix as the application's file format.
|
|
179
178
|
- In browsers, local mode and remote mode with client storage load the Rust
|
|
180
179
|
engine as WebAssembly. Supplying a snapshot storage adapter persists that
|
|
181
180
|
local Lix; in remote mode, the local engine contains only client state.
|
|
182
|
-
- `LocalFilesystem`
|
|
181
|
+
- `LocalFilesystem` is Node.js-only. Constructing it is safe in
|
|
183
182
|
shared code, but passing one to `openLix()` in a browser throws an error.
|
|
184
183
|
- The package is ESM-only.
|
|
185
184
|
- The package uses conditional ESM imports internally: Node.js resolves the
|
package/dist/binding-types.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { CreateBranchOptions, CreateBranchReceipt, CreateCheckpointReceipt, UndoReceipt, RedoReceipt, ExecuteOptions, LixBatchOptions, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, SwitchBranchOptions, SwitchBranchReceipt, LixTelemetrySpan, JsonValue } from "./types.js";
|
|
2
2
|
import type { NativeLixValue } from "./value.js";
|
|
3
3
|
export type BindingExecuteResult = {
|
|
4
|
+
statementIndex?: number;
|
|
5
|
+
label?: string;
|
|
4
6
|
columns: string[];
|
|
5
7
|
rows: NativeLixValue[][];
|
|
6
8
|
rowsAffected: number;
|
|
@@ -19,6 +21,7 @@ export type BindingParam = NativeLixValue;
|
|
|
19
21
|
export type BindingBatchStatement = {
|
|
20
22
|
sql: string;
|
|
21
23
|
params: BindingParam[];
|
|
24
|
+
label?: string;
|
|
22
25
|
};
|
|
23
26
|
export type LixBinding = {
|
|
24
27
|
execute(sql: string, params: BindingParam[], options?: ExecuteOptions): Promise<BindingExecuteResult>;
|
|
@@ -60,9 +63,6 @@ export type TelemetryDispatch = (span: LixTelemetrySpan) => void;
|
|
|
60
63
|
export type LixStorageConfig = {
|
|
61
64
|
kind: "memory";
|
|
62
65
|
snapshot?: Uint8Array;
|
|
63
|
-
} | {
|
|
64
|
-
kind: "sqlite";
|
|
65
|
-
path: string;
|
|
66
66
|
} | {
|
|
67
67
|
kind: "localFilesystem";
|
|
68
68
|
path: string;
|
package/dist/binding.browser.js
CHANGED
|
@@ -7,7 +7,7 @@ function initializeWasm() {
|
|
|
7
7
|
}
|
|
8
8
|
export async function openLixBinding(storage, telemetry) {
|
|
9
9
|
if (storage.kind !== "memory") {
|
|
10
|
-
throw new Error(
|
|
10
|
+
throw new Error("LocalFilesystem is only available in Node.js");
|
|
11
11
|
}
|
|
12
12
|
await initializeWasm();
|
|
13
13
|
return openMemoryFromSnapshot(telemetry, storage.snapshot);
|
package/dist/binding.node.js
CHANGED
|
@@ -51,11 +51,6 @@ export function openLixBinding(storage, telemetry) {
|
|
|
51
51
|
if (nativeTelemetry)
|
|
52
52
|
return addon.Lix.openMemory(nativeTelemetry);
|
|
53
53
|
return addon.Lix.openMemory();
|
|
54
|
-
case "sqlite":
|
|
55
|
-
if (nativeTelemetry) {
|
|
56
|
-
return addon.Lix.openSQLite(storage.path, nativeTelemetry);
|
|
57
|
-
}
|
|
58
|
-
return addon.Lix.openSQLite(storage.path);
|
|
59
54
|
case "localFilesystem":
|
|
60
55
|
if (nativeTelemetry) {
|
|
61
56
|
return addon.Lix.openLocalFilesystem(storage.path, storage.lixDir, storage.syncAllFiles, nativeTelemetry);
|
|
Binary file
|
|
Binary file
|
package/dist/client-state.js
CHANGED
|
@@ -271,14 +271,11 @@ function decodeStoredClientState(snapshot) {
|
|
|
271
271
|
const header = new TextEncoder().encode(STORED_CLIENT_STATE_HEADER);
|
|
272
272
|
if (snapshot.length < header.length ||
|
|
273
273
|
header.some((byte, index) => snapshot[index] !== byte)) {
|
|
274
|
-
|
|
275
|
-
// compatibility is intentionally not provided: start with empty state and
|
|
276
|
-
// replace it on the next write.
|
|
277
|
-
return new Map();
|
|
274
|
+
throw new Error("Stored Lix client state header is invalid");
|
|
278
275
|
}
|
|
279
276
|
let parsed;
|
|
280
277
|
try {
|
|
281
|
-
parsed = JSON.parse(new TextDecoder().decode(snapshot.subarray(header.length)));
|
|
278
|
+
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(snapshot.subarray(header.length)));
|
|
282
279
|
}
|
|
283
280
|
catch (error) {
|
|
284
281
|
throw new Error("Stored Lix client state is invalid", { cause: error });
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { LocalFilesystem, Lix, LixTransaction, ObserveEvents, openLix,
|
|
1
|
+
export { LocalFilesystem, Lix, LixTransaction, ObserveEvents, openLix, } from "./open-lix.js";
|
|
2
2
|
export { bundledPluginArchives, type BundledPluginArchive, } from "./bundled-plugins.js";
|
|
3
3
|
export { Row } from "./result.js";
|
|
4
4
|
export { Value } from "./value.js";
|
|
5
5
|
export type { LixClientState } from "./client-state.js";
|
|
6
|
-
export type { CreateBranchOptions, CreateBranchReceipt, CreateCheckpointReceipt, RedoReceipt, ExecuteOptions, ExecuteResult, LixBatchOptions, LixBatchStatement, LocalFilesystemOptions, JsonValue, LixValue, MergeBranchOptions, MergeBranchOutcome, MergeBranchPreview, MergeBranchReceipt, MergeChangeStats, MergeConflict, MergeConflictSide, ObserveEvent, OpenLixOptions, LixTelemetryOptions, LixTelemetrySpan, LixSnapshotStorage, RemoteLixFetch, RemoteLixServerOptions, UndoReceipt, SqlParam,
|
|
6
|
+
export type { CreateBranchOptions, CreateBranchReceipt, CreateCheckpointReceipt, RedoReceipt, ExecuteOptions, ExecuteResult, LixBatchOptions, LixBatchStatement, LocalFilesystemOptions, JsonValue, LixValue, MergeBranchOptions, MergeBranchOutcome, MergeBranchPreview, MergeBranchReceipt, MergeChangeStats, MergeConflict, MergeConflictSide, ObserveEvent, OpenLixOptions, LixTelemetryOptions, LixTelemetrySpan, LixSnapshotStorage, RemoteLixFetch, RemoteLixServerOptions, UndoReceipt, SqlParam, SwitchBranchOptions, SwitchBranchReceipt, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { LocalFilesystem, Lix, LixTransaction, ObserveEvents, openLix,
|
|
1
|
+
export { LocalFilesystem, Lix, LixTransaction, ObserveEvents, openLix, } from "./open-lix.js";
|
|
2
2
|
export { bundledPluginArchives, } from "./bundled-plugins.js";
|
|
3
3
|
export { Row } from "./result.js";
|
|
4
4
|
export { Value } from "./value.js";
|
package/dist/lix.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type LixClientState, type ManagedClientState } from "./client-state.js";
|
|
2
2
|
import type { LixBinding, LixTransactionBinding, ObserveEventsBinding } from "./binding-types.js";
|
|
3
|
-
import type { CreateBranchOptions, CreateBranchReceipt, CreateCheckpointReceipt, RedoReceipt, ExecuteOptions, ExecuteResult, LixBatchOptions, LixBatchStatement, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, ObserveEvent, SqlParam, SwitchBranchOptions, SwitchBranchReceipt, UndoReceipt } from "./types.js";
|
|
3
|
+
import type { CreateBranchOptions, CreateBranchReceipt, CreateCheckpointReceipt, RedoReceipt, ExecuteOptions, ExecuteResult, ExecuteBatchResult, LixBatchOptions, LixBatchStatement, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, ObserveEvent, SqlParam, SwitchBranchOptions, SwitchBranchReceipt, UndoReceipt } from "./types.js";
|
|
4
4
|
export declare class Lix {
|
|
5
5
|
#private;
|
|
6
6
|
private readonly binding;
|
|
@@ -9,7 +9,7 @@ export declare class Lix {
|
|
|
9
9
|
readonly clientState: LixClientState;
|
|
10
10
|
constructor(binding: LixBinding, managedClientState?: ManagedClientState | undefined);
|
|
11
11
|
execute(sql: string, params?: SqlParam[], options?: ExecuteOptions): Promise<ExecuteResult>;
|
|
12
|
-
executeBatch(statements: readonly LixBatchStatement[], options?: LixBatchOptions): Promise<readonly
|
|
12
|
+
executeBatch(statements: readonly LixBatchStatement[], options?: LixBatchOptions): Promise<readonly ExecuteBatchResult[]>;
|
|
13
13
|
observe(sql: string, params?: SqlParam[]): ObserveEvents;
|
|
14
14
|
beginTransaction(): Promise<LixTransaction>;
|
|
15
15
|
activeBranchId(): Promise<string>;
|
package/dist/lix.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { invalidArgument } from "./errors.js";
|
|
2
2
|
import { ACTIVE_BRANCH_CLIENT_STATE_KEY, unavailableClientState, } from "./client-state.js";
|
|
3
|
-
import { normalizeOptionals, wrapExecuteResult } from "./result.js";
|
|
3
|
+
import { normalizeOptionals, wrapExecuteBatchResult, wrapExecuteResult, } from "./result.js";
|
|
4
4
|
import { isSnapshotPersistenceAfterCommitError } from "./snapshot-persistence.js";
|
|
5
5
|
import { normalizeParam, toNativeValue } from "./value.js";
|
|
6
6
|
const transactionFinalizer = new FinalizationRegistry(({ transaction, onFinish }) => {
|
|
@@ -50,7 +50,7 @@ export class Lix {
|
|
|
50
50
|
const normalizedStatements = normalizeBatchStatements(statements, options);
|
|
51
51
|
return this.#runOperation(async () => {
|
|
52
52
|
const results = await this.binding.executeBatch(normalizedStatements, options);
|
|
53
|
-
return results.map(
|
|
53
|
+
return results.map(wrapExecuteBatchResult);
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
observe(sql, params = []) {
|
|
@@ -336,9 +336,14 @@ function normalizeBatchStatements(statements, options) {
|
|
|
336
336
|
if (!Array.isArray(params)) {
|
|
337
337
|
throw invalidArgument("executeBatch", `statements[${statementIndex}].params`, "array", typeof params);
|
|
338
338
|
}
|
|
339
|
+
if (statement.label !== undefined &&
|
|
340
|
+
typeof statement.label !== "string") {
|
|
341
|
+
throw invalidArgument("executeBatch", `statements[${statementIndex}].label`, "string", typeof statement.label);
|
|
342
|
+
}
|
|
339
343
|
return {
|
|
340
344
|
sql: statement.sql,
|
|
341
345
|
params: params.map((param, parameterIndex) => toNativeValue(normalizeParam(param, parameterIndex))),
|
|
346
|
+
...(statement.label === undefined ? {} : { label: statement.label }),
|
|
342
347
|
};
|
|
343
348
|
}
|
|
344
349
|
catch (error) {
|
package/dist/open-lix.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { Lix } from "./lix.js";
|
|
2
|
-
import type { LocalFilesystemOptions, OpenLixOptions
|
|
2
|
+
import type { LocalFilesystemOptions, OpenLixOptions } from "./types.js";
|
|
3
3
|
export { Lix, LixTransaction, ObserveEvents } from "./lix.js";
|
|
4
|
-
export declare class SQLite {
|
|
5
|
-
readonly path: string;
|
|
6
|
-
constructor(options: SQLiteOptions);
|
|
7
|
-
}
|
|
8
4
|
export declare class LocalFilesystem {
|
|
9
5
|
readonly path: string;
|
|
10
6
|
readonly lixDir: string | undefined;
|
package/dist/open-lix.js
CHANGED
|
@@ -2,17 +2,6 @@ import { localFilesystemAlreadyOpen, localFilesystemNotOpen, } from "./errors.js
|
|
|
2
2
|
import { ACTIVE_ACCOUNT_CLIENT_STATE_KEY, ACTIVE_BRANCH_CLIENT_STATE_KEY, openClientState, openStoredClientState, } from "./client-state.js";
|
|
3
3
|
import { Lix } from "./lix.js";
|
|
4
4
|
export { Lix, LixTransaction, ObserveEvents } from "./lix.js";
|
|
5
|
-
export class SQLite {
|
|
6
|
-
path;
|
|
7
|
-
constructor(options) {
|
|
8
|
-
if (!options ||
|
|
9
|
-
typeof options.path !== "string" ||
|
|
10
|
-
options.path.length === 0) {
|
|
11
|
-
throw new TypeError("SQLite requires a non-empty path");
|
|
12
|
-
}
|
|
13
|
-
this.path = options.path;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
5
|
const openLocalFilesystems = new WeakMap();
|
|
17
6
|
export class LocalFilesystem {
|
|
18
7
|
path;
|
|
@@ -119,12 +108,6 @@ export async function openLix(options = {}) {
|
|
|
119
108
|
if (options.storage === undefined) {
|
|
120
109
|
return new Lix(await openLixWorkerBinding({ kind: "memory" }, undefined, options.telemetry));
|
|
121
110
|
}
|
|
122
|
-
if (options.storage instanceof SQLite) {
|
|
123
|
-
return new Lix(await openLixWorkerBinding({
|
|
124
|
-
kind: "sqlite",
|
|
125
|
-
path: options.storage.path,
|
|
126
|
-
}, undefined, options.telemetry));
|
|
127
|
-
}
|
|
128
111
|
if (options.storage instanceof LocalFilesystem) {
|
|
129
112
|
const storage = options.storage;
|
|
130
113
|
if (openLocalFilesystems.has(storage)) {
|
|
@@ -162,7 +145,7 @@ export async function openLix(options = {}) {
|
|
|
162
145
|
throw error;
|
|
163
146
|
}
|
|
164
147
|
}
|
|
165
|
-
throw new TypeError("openLix() requires storage to be
|
|
148
|
+
throw new TypeError("openLix() requires storage to be LocalFilesystem or a Lix snapshot storage adapter");
|
|
166
149
|
}
|
|
167
150
|
function isSnapshotStorage(value) {
|
|
168
151
|
return (typeof value === "object" &&
|
package/dist/remote/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decodeExecuteResult, decodeHandshake, decodeObserveEvent, encodeWireValue, errorFromResponseBody, protocolError, record, REMOTE_PROTOCOL_PATH, remoteError, } from "./protocol.js";
|
|
1
|
+
import { decodeExecuteBatchResult, decodeExecuteResult, decodeHandshake, decodeObserveEvent, encodeWireValue, errorFromResponseBody, protocolError, record, REMOTE_PROTOCOL_PATH, remoteError, } from "./protocol.js";
|
|
2
2
|
import { readSseEvents } from "./sse.js";
|
|
3
3
|
const OBSERVE_RETRY_BASE_MS = 100;
|
|
4
4
|
const OBSERVE_RETRY_MAX_MS = 5_000;
|
|
@@ -73,6 +73,7 @@ class RemoteLixBinding {
|
|
|
73
73
|
this.#initialActiveAccountId = clientOptions.initialActiveAccountId;
|
|
74
74
|
this.#observationHub = new RemoteObservationHub({
|
|
75
75
|
openStream: (subscriptions, signal) => this.#requestObserveStream(subscriptions, signal),
|
|
76
|
+
refreshObservation: (subscription) => this.#refreshObservation(subscription),
|
|
76
77
|
});
|
|
77
78
|
}
|
|
78
79
|
async open() {
|
|
@@ -119,10 +120,12 @@ class RemoteLixBinding {
|
|
|
119
120
|
const snapshot = statements.map((statement) => ({
|
|
120
121
|
sql: statement.sql,
|
|
121
122
|
params: snapshotParams(statement.params),
|
|
123
|
+
...(statement.label === undefined ? {} : { label: statement.label }),
|
|
122
124
|
}));
|
|
123
125
|
return this.#enqueue(async () => {
|
|
124
126
|
const preparedStatements = await Promise.all(snapshot.map(async (statement, statementIndex) => ({
|
|
125
127
|
sql: statement.sql,
|
|
128
|
+
label: statement.label,
|
|
126
129
|
prepared: await this.#prepareParams(statement.params, (paramIndex) => requestBlobSlot("batch", statement.sql, paramIndex, statementIndex)),
|
|
127
130
|
})));
|
|
128
131
|
const cacheBlobs = preparedStatements.some((statement) => statement.prepared.cacheBlobs);
|
|
@@ -133,6 +136,9 @@ class RemoteLixBinding {
|
|
|
133
136
|
body: JSON.stringify({
|
|
134
137
|
statements: preparedStatements.map((statement) => ({
|
|
135
138
|
sql: statement.sql,
|
|
139
|
+
...(statement.label === undefined
|
|
140
|
+
? {}
|
|
141
|
+
: { label: statement.label }),
|
|
136
142
|
params: full
|
|
137
143
|
? statement.prepared.fullParams()
|
|
138
144
|
: statement.prepared.params,
|
|
@@ -145,7 +151,7 @@ class RemoteLixBinding {
|
|
|
145
151
|
if (!Array.isArray(value)) {
|
|
146
152
|
throw protocolError("execute batch response must be an array");
|
|
147
153
|
}
|
|
148
|
-
const results = value.map(
|
|
154
|
+
const results = value.map(decodeExecuteBatchResult);
|
|
149
155
|
this.#commitRequestBlobBases(preparedStatements.flatMap((statement) => statement.prepared.cacheUpdates));
|
|
150
156
|
return results;
|
|
151
157
|
});
|
|
@@ -442,6 +448,18 @@ class RemoteLixBinding {
|
|
|
442
448
|
throw remoteError("LIX_REMOTE_UNAVAILABLE", "The remote Lix observation stream is unavailable", { details: { cause: errorMessage(cause) } });
|
|
443
449
|
}
|
|
444
450
|
}
|
|
451
|
+
async #refreshObservation(subscription) {
|
|
452
|
+
return this.#enqueue(async () => {
|
|
453
|
+
const value = await this.#requestJson("execute", {
|
|
454
|
+
method: "POST",
|
|
455
|
+
body: JSON.stringify({
|
|
456
|
+
sql: subscription.sql,
|
|
457
|
+
params: subscription.params,
|
|
458
|
+
}),
|
|
459
|
+
});
|
|
460
|
+
return decodeExecuteResult(value);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
445
463
|
async #prepareParams(params, slot) {
|
|
446
464
|
const prepared = await Promise.all(params.map(async (param, index) => {
|
|
447
465
|
if (param.kind !== "blob" ||
|
|
@@ -661,6 +679,7 @@ function copyArrayBuffer(bytes) {
|
|
|
661
679
|
}
|
|
662
680
|
class RemoteObservationHub {
|
|
663
681
|
#openStream;
|
|
682
|
+
#refreshObservation;
|
|
664
683
|
#observations = new Map();
|
|
665
684
|
#nextObservationId = 0;
|
|
666
685
|
#controller;
|
|
@@ -672,6 +691,7 @@ class RemoteObservationHub {
|
|
|
672
691
|
#closed = false;
|
|
673
692
|
constructor(options) {
|
|
674
693
|
this.#openStream = options.openStream;
|
|
694
|
+
this.#refreshObservation = options.refreshObservation;
|
|
675
695
|
}
|
|
676
696
|
observe(sql, params) {
|
|
677
697
|
const id = `observe-${++this.#nextObservationId}`;
|
|
@@ -743,6 +763,7 @@ class RemoteObservationHub {
|
|
|
743
763
|
if (!this.#isCurrent(generation, controller))
|
|
744
764
|
return;
|
|
745
765
|
streamOpened = true;
|
|
766
|
+
const initialSubscriptions = new Set(this.#observations.keys());
|
|
746
767
|
if (!response.ok) {
|
|
747
768
|
if (isRetryableObserveStatus(response.status)) {
|
|
748
769
|
void response.body?.cancel();
|
|
@@ -781,7 +802,21 @@ class RemoteObservationHub {
|
|
|
781
802
|
const transportDelta = payload.delta !== undefined;
|
|
782
803
|
const event = decodeObserveEvent(payload, transportBases.get(subscriptionId));
|
|
783
804
|
transportBases.set(subscriptionId, event);
|
|
784
|
-
|
|
805
|
+
if (initialSubscriptions.delete(subscriptionId)) {
|
|
806
|
+
// The first frame after opening (including a reconnect) is a
|
|
807
|
+
// synchronization point, not an authoritative snapshot. The
|
|
808
|
+
// remote runtime may have observed the stream before its
|
|
809
|
+
// external-storage watcher caught up. Reconcile through the
|
|
810
|
+
// normal execute endpoint before publishing it to consumers.
|
|
811
|
+
const rows = await this.#refreshObservation(observation.request());
|
|
812
|
+
observation.accept({
|
|
813
|
+
...event,
|
|
814
|
+
rows,
|
|
815
|
+
}, false);
|
|
816
|
+
}
|
|
817
|
+
else {
|
|
818
|
+
observation.accept(event, transportDelta);
|
|
819
|
+
}
|
|
785
820
|
this.#retryAttempt = 0;
|
|
786
821
|
}
|
|
787
822
|
catch (error) {
|
|
@@ -55,6 +55,7 @@ export type RemoteExecuteBatchRequest = {
|
|
|
55
55
|
statements: Array<{
|
|
56
56
|
sql: string;
|
|
57
57
|
params: WireRequestValue[];
|
|
58
|
+
label?: string;
|
|
58
59
|
}>;
|
|
59
60
|
options?: {
|
|
60
61
|
originKey?: string;
|
|
@@ -71,6 +72,10 @@ export type RemoteExecuteResponse = {
|
|
|
71
72
|
hint?: string;
|
|
72
73
|
}>;
|
|
73
74
|
};
|
|
75
|
+
export type RemoteExecuteBatchResponse = RemoteExecuteResponse & {
|
|
76
|
+
statementIndex: number;
|
|
77
|
+
label?: string;
|
|
78
|
+
};
|
|
74
79
|
export type RemoteObserveRequest = {
|
|
75
80
|
sql: string;
|
|
76
81
|
params: WireValue[];
|
|
@@ -156,6 +161,7 @@ export type RemoteMultiplexObserveErrorEvent = RemoteObserveErrorEvent & {
|
|
|
156
161
|
};
|
|
157
162
|
export declare function encodeWireValue(value: NativeLixValue): WireValue;
|
|
158
163
|
export declare function decodeExecuteResult(value: unknown): BindingExecuteResult;
|
|
164
|
+
export declare function decodeExecuteBatchResult(value: unknown): BindingExecuteResult;
|
|
159
165
|
export declare function decodeHandshake(value: unknown): RemoteHandshake;
|
|
160
166
|
export declare function decodeObserveEvent(value: unknown, base?: BindingObserveEvent): BindingObserveEvent;
|
|
161
167
|
export declare function remoteError(code: string, message: string, options?: {
|
package/dist/remote/protocol.js
CHANGED
|
@@ -57,6 +57,18 @@ export function decodeExecuteResult(value) {
|
|
|
57
57
|
});
|
|
58
58
|
return { columns, rows, rowsAffected: result.rowsAffected, notices };
|
|
59
59
|
}
|
|
60
|
+
export function decodeExecuteBatchResult(value) {
|
|
61
|
+
const result = record(value, "execute batch result");
|
|
62
|
+
const statementIndex = nonNegativeSafeInteger(result.statementIndex, "execute batch result statementIndex");
|
|
63
|
+
if (result.label !== undefined && typeof result.label !== "string") {
|
|
64
|
+
throw protocolError("execute batch result label must be a string when present");
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
...decodeExecuteResult(value),
|
|
68
|
+
statementIndex,
|
|
69
|
+
...(result.label === undefined ? {} : { label: result.label }),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
60
72
|
export function decodeHandshake(value) {
|
|
61
73
|
const handshake = record(value, "remote handshake");
|
|
62
74
|
if (handshake.protocolVersion !== REMOTE_PROTOCOL_VERSION) {
|
package/dist/result.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type NativeLixValue, Value } from "./value.js";
|
|
2
|
-
import type { ExecuteResult, LixValue } from "./types.js";
|
|
2
|
+
import type { ExecuteBatchResult, ExecuteResult, LixValue } from "./types.js";
|
|
3
3
|
export declare class Row {
|
|
4
4
|
private readonly columns;
|
|
5
5
|
private readonly values;
|
|
@@ -14,5 +14,6 @@ type NativeExecuteResult = Omit<ExecuteResult, "rows"> & {
|
|
|
14
14
|
rows: NativeLixValue[][];
|
|
15
15
|
};
|
|
16
16
|
export declare function wrapExecuteResult(result: NativeExecuteResult): ExecuteResult;
|
|
17
|
+
export declare function wrapExecuteBatchResult(result: NativeExecuteResult): ExecuteBatchResult;
|
|
17
18
|
export declare function normalizeOptionals<T>(value: T): T;
|
|
18
19
|
export {};
|
package/dist/result.js
CHANGED
|
@@ -36,6 +36,18 @@ export function wrapExecuteResult(result) {
|
|
|
36
36
|
rows: result.rows.map((row) => Row.fromRaw(result.columns, row.map(fromNativeValue))),
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
export function wrapExecuteBatchResult(result) {
|
|
40
|
+
const statementIndex = result.statementIndex;
|
|
41
|
+
if (typeof statementIndex !== "number" ||
|
|
42
|
+
!Number.isSafeInteger(statementIndex) ||
|
|
43
|
+
statementIndex < 0) {
|
|
44
|
+
throw new Error("executeBatch result is missing a valid statementIndex");
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
...wrapExecuteResult(result),
|
|
48
|
+
statementIndex,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
39
51
|
export function normalizeOptionals(value) {
|
|
40
52
|
if (Array.isArray(value))
|
|
41
53
|
return value.map(normalizeOptionals);
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
export type SQLiteOptions = {
|
|
2
|
-
path: string;
|
|
3
|
-
};
|
|
4
1
|
export type LocalFilesystemOptions = {
|
|
5
2
|
path: string;
|
|
6
3
|
lixDir?: string;
|
|
@@ -36,7 +33,7 @@ export interface LixSnapshotStorage {
|
|
|
36
33
|
save(namespace: string, snapshot: Uint8Array): Promise<void>;
|
|
37
34
|
}
|
|
38
35
|
export type OpenLixOptions = {
|
|
39
|
-
storage?: import("./open-lix.js").
|
|
36
|
+
storage?: import("./open-lix.js").LocalFilesystem | LixSnapshotStorage;
|
|
40
37
|
server?: never;
|
|
41
38
|
telemetry?: LixTelemetryOptions;
|
|
42
39
|
} | {
|
|
@@ -86,6 +83,7 @@ export type ExecuteOptions = {
|
|
|
86
83
|
export type LixBatchStatement = {
|
|
87
84
|
sql: string;
|
|
88
85
|
params?: readonly SqlParam[];
|
|
86
|
+
label?: string;
|
|
89
87
|
};
|
|
90
88
|
export type LixBatchOptions = {
|
|
91
89
|
originKey?: string;
|
|
@@ -93,6 +91,8 @@ export type LixBatchOptions = {
|
|
|
93
91
|
idempotencyKey?: string;
|
|
94
92
|
};
|
|
95
93
|
export type ExecuteResult = {
|
|
94
|
+
statementIndex?: number;
|
|
95
|
+
label?: string;
|
|
96
96
|
columns: string[];
|
|
97
97
|
rows: RowLike[];
|
|
98
98
|
rowsAffected: number;
|
|
@@ -102,9 +102,17 @@ export type ExecuteResult = {
|
|
|
102
102
|
hint?: string;
|
|
103
103
|
}>;
|
|
104
104
|
};
|
|
105
|
+
export type ExecuteBatchResult = ExecuteResult & {
|
|
106
|
+
statementIndex: number;
|
|
107
|
+
};
|
|
105
108
|
export type ObserveEvent = {
|
|
106
109
|
sequence: number;
|
|
107
110
|
mutationSequence: number;
|
|
111
|
+
/**
|
|
112
|
+
* The current result of the observed query. Remote observations reconcile
|
|
113
|
+
* the first frame of every stream through execute before publishing it, so
|
|
114
|
+
* reconnects cannot expose a stale server snapshot to consumers.
|
|
115
|
+
*/
|
|
108
116
|
result: ExecuteResult;
|
|
109
117
|
};
|
|
110
118
|
export type RowLike = {
|
|
@@ -83,8 +83,8 @@ export interface InitOutput {
|
|
|
83
83
|
readonly wasmlixtransaction_rollback: (a: number) => number;
|
|
84
84
|
readonly wasmobserveevents_close: (a: number) => void;
|
|
85
85
|
readonly wasmobserveevents_next: (a: number) => number;
|
|
86
|
-
readonly
|
|
87
|
-
readonly
|
|
86
|
+
readonly __wasm_bindgen_func_elem_122229: (a: number, b: number, c: number, d: number) => void;
|
|
87
|
+
readonly __wasm_bindgen_func_elem_122231: (a: number, b: number, c: number, d: number) => void;
|
|
88
88
|
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
89
89
|
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
90
90
|
readonly __wbindgen_export3: (a: number) => void;
|
package/dist/wasm/lix_js_sdk.js
CHANGED
|
@@ -536,7 +536,7 @@ function __wbg_get_imports() {
|
|
|
536
536
|
const a = state0.a;
|
|
537
537
|
state0.a = 0;
|
|
538
538
|
try {
|
|
539
|
-
return
|
|
539
|
+
return __wasm_bindgen_func_elem_122231(a, state0.b, arg0, arg1);
|
|
540
540
|
} finally {
|
|
541
541
|
state0.a = a;
|
|
542
542
|
}
|
|
@@ -646,8 +646,8 @@ function __wbg_get_imports() {
|
|
|
646
646
|
return addHeapObject(ret);
|
|
647
647
|
},
|
|
648
648
|
__wbindgen_cast_0000000000000001: function(arg0, arg1) {
|
|
649
|
-
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx:
|
|
650
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
649
|
+
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 30525, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
650
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_122229);
|
|
651
651
|
return addHeapObject(ret);
|
|
652
652
|
},
|
|
653
653
|
__wbindgen_cast_0000000000000002: function(arg0) {
|
|
@@ -696,10 +696,10 @@ function __wbg_get_imports() {
|
|
|
696
696
|
};
|
|
697
697
|
}
|
|
698
698
|
|
|
699
|
-
function
|
|
699
|
+
function __wasm_bindgen_func_elem_122229(arg0, arg1, arg2) {
|
|
700
700
|
try {
|
|
701
701
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
702
|
-
wasm.
|
|
702
|
+
wasm.__wasm_bindgen_func_elem_122229(retptr, arg0, arg1, addHeapObject(arg2));
|
|
703
703
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
704
704
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
705
705
|
if (r1) {
|
|
@@ -710,8 +710,8 @@ function __wasm_bindgen_func_elem_120695(arg0, arg1, arg2) {
|
|
|
710
710
|
}
|
|
711
711
|
}
|
|
712
712
|
|
|
713
|
-
function
|
|
714
|
-
wasm.
|
|
713
|
+
function __wasm_bindgen_func_elem_122231(arg0, arg1, arg2, arg3) {
|
|
714
|
+
wasm.__wasm_bindgen_func_elem_122231(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
|
715
715
|
}
|
|
716
716
|
|
|
717
717
|
const WasmLixFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
Binary file
|
|
@@ -31,8 +31,8 @@ export const wasmlixtransaction_execute: (a: number, b: number, c: number, d: nu
|
|
|
31
31
|
export const wasmlixtransaction_rollback: (a: number) => number;
|
|
32
32
|
export const wasmobserveevents_close: (a: number) => void;
|
|
33
33
|
export const wasmobserveevents_next: (a: number) => number;
|
|
34
|
-
export const
|
|
35
|
-
export const
|
|
34
|
+
export const __wasm_bindgen_func_elem_122229: (a: number, b: number, c: number, d: number) => void;
|
|
35
|
+
export const __wasm_bindgen_func_elem_122231: (a: number, b: number, c: number, d: number) => void;
|
|
36
36
|
export const __wbindgen_export: (a: number, b: number) => number;
|
|
37
37
|
export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
38
38
|
export const __wbindgen_export3: (a: number) => void;
|
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.11.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -57,10 +57,10 @@
|
|
|
57
57
|
"typecheck": "tsc -p tsconfig.test.json --noEmit"
|
|
58
58
|
},
|
|
59
59
|
"optionalDependencies": {
|
|
60
|
-
"@lix-js/sdk-darwin-arm64": "0.
|
|
61
|
-
"@lix-js/sdk-linux-arm64": "0.
|
|
62
|
-
"@lix-js/sdk-linux-x64": "0.
|
|
63
|
-
"@lix-js/sdk-win32-x64": "0.
|
|
60
|
+
"@lix-js/sdk-darwin-arm64": "0.11.0",
|
|
61
|
+
"@lix-js/sdk-linux-arm64": "0.11.0",
|
|
62
|
+
"@lix-js/sdk-linux-x64": "0.11.0",
|
|
63
|
+
"@lix-js/sdk-win32-x64": "0.11.0"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@vitest/browser-playwright": "4.1.10",
|