@lix-js/sdk 0.15.1 → 0.16.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 +99 -7
- package/dist/binding-types.d.ts +11 -1
- package/dist/binding.browser.d.ts +2 -0
- package/dist/binding.browser.js +11 -1
- package/dist/binding.node.d.ts +2 -0
- package/dist/binding.node.js +9 -3
- package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
- package/dist/bundled-plugins/plugin_markdown.lixplugin +0 -0
- package/dist/hosted-lix.d.ts +5 -0
- package/dist/hosted-lix.js +36 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/lix.d.ts +9 -2
- package/dist/lix.js +41 -18
- package/dist/open-lix.js +10 -13
- package/dist/remote/client.d.ts +2 -2
- package/dist/remote/client.js +0 -3
- package/dist/storage-adapter.d.ts +0 -4
- package/dist/types.d.ts +97 -22
- package/dist/wasm/lix_js_sdk.d.ts +24 -3
- package/dist/wasm/lix_js_sdk.js +124 -34
- package/dist/wasm/lix_js_sdk_bg.wasm +0 -0
- package/dist/wasm/lix_js_sdk_bg.wasm.d.ts +13 -3
- package/dist/worker/client.d.ts +5 -2
- package/dist/worker/client.js +14 -0
- package/dist/worker/host.js +32 -15
- package/dist/worker/protocol.d.ts +17 -0
- package/package.json +5 -9
- package/dist/remote/server-protocol.d.ts +0 -185
- package/dist/remote/server-protocol.js +0 -417
package/README.md
CHANGED
|
@@ -22,10 +22,51 @@ console.log(result.rows[0]?.message);
|
|
|
22
22
|
await lix.close();
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Hosted lifecycle
|
|
26
|
+
|
|
27
|
+
`openLix()` selects execution from the supplied locations:
|
|
28
|
+
|
|
29
|
+
| Options | Behavior |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| Neither | Fresh in-memory repository |
|
|
32
|
+
| `storage` | Local repository, initialized if empty |
|
|
33
|
+
| `server` | Execute against an existing hosted repository |
|
|
34
|
+
| `storage` and `server` | Local reads and writes with background synchronization |
|
|
35
|
+
|
|
36
|
+
Creation and deletion are explicit server operations:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { createLix, deleteLix, openLix } from "@lix-js/sdk";
|
|
40
|
+
|
|
41
|
+
const repository = await createLix({
|
|
42
|
+
server: { url: "https://example.com", headers: getAuthHeaders },
|
|
43
|
+
from: localLix, // Omit to create an empty repository.
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const remote = await openLix({
|
|
47
|
+
server: { url: repository.url, headers: getAuthHeaders },
|
|
48
|
+
});
|
|
49
|
+
await remote.close();
|
|
50
|
+
await deleteLix({ server: { url: repository.url, headers: getAuthHeaders } });
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`from` captures a consistent repository snapshot, including history and untracked
|
|
54
|
+
rows. The source remains open. Creation returns `{ id, url }`, not a session.
|
|
55
|
+
Use the same optional `idempotencyKey` when retrying creation after an uncertain
|
|
56
|
+
response. Deletion removes the hosted repository and leaves local copies intact. Opening
|
|
57
|
+
or synchronizing never implicitly creates a missing hosted repository.
|
|
58
|
+
|
|
59
|
+
Browser creation from a local repository requires Fetch request streaming.
|
|
60
|
+
Browsers without that support return `LIX_UNSUPPORTED_OPERATION`; Lix does not
|
|
61
|
+
buffer the complete repository as a fallback. Browser Fetch may also require an
|
|
62
|
+
HTTP/2 or HTTP/3 connection for streaming uploads. Empty creation and remote
|
|
63
|
+
execution do not require streaming uploads.
|
|
64
|
+
|
|
25
65
|
## Synchronized local repositories
|
|
26
66
|
|
|
27
|
-
|
|
28
|
-
|
|
67
|
+
Combine storage with a server to keep a synchronized local replica. Reads and
|
|
68
|
+
writes execute locally; background synchronization exchanges changes with the
|
|
69
|
+
server:
|
|
29
70
|
|
|
30
71
|
```ts
|
|
31
72
|
import { openLix } from "@lix-js/sdk";
|
|
@@ -34,7 +75,6 @@ import { OpfsStorage } from "@lix-js/storage-opfs";
|
|
|
34
75
|
const lix = await openLix({
|
|
35
76
|
storage: new OpfsStorage({ name: "acme" }),
|
|
36
77
|
server: {
|
|
37
|
-
mode: "sync",
|
|
38
78
|
url: "https://example.com/lix/01936f4e-7b6c-7c3d-8f9a-123456789abc",
|
|
39
79
|
headers: async () => ({
|
|
40
80
|
Authorization: `Bearer ${await accessToken()}`,
|
|
@@ -43,11 +83,59 @@ const lix = await openLix({
|
|
|
43
83
|
});
|
|
44
84
|
```
|
|
45
85
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
86
|
+
A successful mutation confirms a local commit; it does not confirm server
|
|
87
|
+
acceptance. Pending commits upload in the background. Cached reads and local
|
|
88
|
+
writes work offline; older history and binary content load when needed.
|
|
49
89
|
See [Collaboration and Sync](https://lix.dev/docs/collaboration-and-sync).
|
|
50
90
|
|
|
91
|
+
### Upgrading a local replica
|
|
92
|
+
|
|
93
|
+
Keep the same storage name across SDK upgrades. For a supported older synchronized
|
|
94
|
+
replica, Lix preserves its existing storage generation and bootstraps a separate
|
|
95
|
+
generation from the same authoritative repository and account. The replacement
|
|
96
|
+
becomes active only after bootstrap and validation succeed. Pending work and
|
|
97
|
+
local-only rows remain in the preserved generation; they do not block opening the
|
|
98
|
+
current server state. An upgrade requires a server connection and enough local
|
|
99
|
+
storage for both generations.
|
|
100
|
+
|
|
101
|
+
Recovery is explicit and separate from opening:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const sources = await lix.replicaRecoverySources();
|
|
105
|
+
for (const source of sources.filter((source) => source.recoveryRequired)) {
|
|
106
|
+
const exported = await lix.exportReplicaRecovery(source.id);
|
|
107
|
+
// Save exported as JSON when the user requests a portable recovery copy.
|
|
108
|
+
console.log(exported.unresolved);
|
|
109
|
+
|
|
110
|
+
const receipt = await lix.recoverReplica(source.id);
|
|
111
|
+
// Present these separate branches for review; the active branch is unchanged.
|
|
112
|
+
console.log(receipt.branchIds, receipt.restoredRows, receipt.unresolved);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`exportReplicaRecovery()` captures available logical rows, blob contents, and
|
|
117
|
+
original branch/checkpoint coordinates. `recoverReplica()` restores supported
|
|
118
|
+
tracked rows into separate recovery branches. It does not automatically publish
|
|
119
|
+
local-only rows or merge recovered work into the active branch. Inspect
|
|
120
|
+
`unresolved`: original history and any unavailable content remain in the retained
|
|
121
|
+
source. A recovery receipt describes local restoration, not a server durability
|
|
122
|
+
acknowledgement. Neither operation deletes the retained generation, and retries
|
|
123
|
+
reuse recovery branch receipts rather than overwriting previously recovered work.
|
|
124
|
+
|
|
125
|
+
Recovery export currently allows up to 100,000 logical rows across all branches,
|
|
126
|
+
64 MiB per blob, and 128 MiB of blob content in total. Unfinished upload parts
|
|
127
|
+
have a separate 128 MiB content budget. A row-limit or upload-limit error leaves
|
|
128
|
+
the source intact; omitted blob content is identified in `unresolved`. Exported
|
|
129
|
+
JSON can be larger than these content budgets because binary data uses base64.
|
|
130
|
+
This recovery file is not a complete repository backup.
|
|
131
|
+
|
|
132
|
+
These methods require a local storage-backed handle; remote-only handles reject
|
|
133
|
+
with `LIX_ERROR_LOCAL_STORAGE_REQUIRED`. Do not clear browser storage to resolve
|
|
134
|
+
upgrade or recovery errors. Browser storage eviction or an unsupported old format
|
|
135
|
+
can still require external recovery; retaining bytes alone is not proof that all
|
|
136
|
+
work has been recovered. Standalone and authoritative repositories continue to
|
|
137
|
+
use history-preserving format migrations.
|
|
138
|
+
|
|
51
139
|
## Remote repositories
|
|
52
140
|
|
|
53
141
|
Use the same Lix client as a thin client against a hosted repository:
|
|
@@ -55,7 +143,6 @@ Use the same Lix client as a thin client against a hosted repository:
|
|
|
55
143
|
```ts
|
|
56
144
|
const lix = await openLix({
|
|
57
145
|
server: {
|
|
58
|
-
mode: "remote",
|
|
59
146
|
url: "https://example.com/lix/01936f4e-7b6c-7c3d-8f9a-123456789abc",
|
|
60
147
|
headers: async () => ({
|
|
61
148
|
Authorization: `Bearer ${await accessToken()}`,
|
|
@@ -161,6 +248,11 @@ const merge = await lix.mergeBranch({ sourceBranchId: draft.id });
|
|
|
161
248
|
|
|
162
249
|
## Transactions
|
|
163
250
|
|
|
251
|
+
`beginTransaction()` captures the current branch and account in an independent
|
|
252
|
+
transaction context. Use `tx.execute()` for transaction work; its reads see staged
|
|
253
|
+
writes. Ordinary reads and observers on `lix` continue to see committed data while
|
|
254
|
+
the transaction is open. Commit or roll back before closing `lix`.
|
|
255
|
+
|
|
164
256
|
```ts
|
|
165
257
|
const tx = await lix.beginTransaction();
|
|
166
258
|
|
package/dist/binding-types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CreateBranchOptions, CreateBranchReceipt, UndoReceipt, RedoReceipt, ExecuteOptions, LixBatchOptions, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, SwitchBranchOptions, SwitchBranchReceipt, LixTelemetrySpan, LixTelemetryParentContext, LixOpenProgress, LixOpenReport, OpenAnotherSessionOptions, ResultColumn } from "./types.js";
|
|
1
|
+
import type { CommitSpan, CreateBranchOptions, CreateBranchReceipt, UndoReceipt, RedoReceipt, ExecuteOptions, LixBatchOptions, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, SwitchBranchOptions, SwitchBranchReceipt, LixTelemetrySpan, LixTelemetryParentContext, LixOpenProgress, LixOpenReport, ReplicaRecoverySource, ReplicaRecoveryExport, ReplicaRecoveryReceipt, OpenAnotherSessionOptions, ResultColumn } from "./types.js";
|
|
2
2
|
import type { NativeLixValue } from "./value.js";
|
|
3
3
|
import type { LixStorageProvider } from "./storage-adapter.js";
|
|
4
4
|
export type SyncServerBindingOptions = {
|
|
@@ -18,6 +18,7 @@ export type BindingExecuteResult = {
|
|
|
18
18
|
message: string;
|
|
19
19
|
hint?: string;
|
|
20
20
|
}>;
|
|
21
|
+
commit?: CommitSpan;
|
|
21
22
|
};
|
|
22
23
|
export type BindingObserveEvent = {
|
|
23
24
|
sequence: number;
|
|
@@ -41,6 +42,7 @@ export type BindingBatchStatement = {
|
|
|
41
42
|
label?: string;
|
|
42
43
|
};
|
|
43
44
|
export type LixBinding = {
|
|
45
|
+
createHosted?(server: HostedServerBindingOptions): Promise<import("./types.js").HostedLix>;
|
|
44
46
|
openReport?(): LixOpenReport | undefined;
|
|
45
47
|
setTelemetryParent(parent?: TelemetryParentContext): void;
|
|
46
48
|
openAnotherSession(options: OpenAnotherSessionOptions): Promise<LixBinding>;
|
|
@@ -48,6 +50,9 @@ export type LixBinding = {
|
|
|
48
50
|
executeBatch(statements: BindingBatchStatement[], options?: LixBatchOptions): Promise<BindingExecuteResult[]>;
|
|
49
51
|
observe(sql: string, params: BindingParam[]): Promise<ObserveEventsBinding>;
|
|
50
52
|
beginTransaction(): Promise<LixTransactionBinding>;
|
|
53
|
+
replicaRecoverySources(): Promise<ReplicaRecoverySource[]>;
|
|
54
|
+
exportReplicaRecovery(id: string): Promise<ReplicaRecoveryExport>;
|
|
55
|
+
recoverReplica(id: string): Promise<ReplicaRecoveryReceipt>;
|
|
51
56
|
activeBranchId(): Promise<string>;
|
|
52
57
|
activeAccountId(): Promise<string>;
|
|
53
58
|
createBranch(options: CreateBranchOptions): Promise<CreateBranchReceipt>;
|
|
@@ -88,3 +93,8 @@ export type LixStorageConfig = {
|
|
|
88
93
|
path: string;
|
|
89
94
|
syncAllFiles: boolean;
|
|
90
95
|
};
|
|
96
|
+
export type HostedServerBindingOptions = {
|
|
97
|
+
idempotencyKey?: string;
|
|
98
|
+
url: string;
|
|
99
|
+
headers: [string, string][];
|
|
100
|
+
};
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import type { LixStorageConfig, LixBinding, SyncServerBindingOptions, TelemetryDispatch, TelemetryParentContext, OpenProgressDispatch } from "./binding-types.js";
|
|
2
2
|
export declare function openLixBinding(storage: LixStorageConfig, telemetry?: TelemetryDispatch, telemetryParent?: TelemetryParentContext, server?: SyncServerBindingOptions, openProgress?: OpenProgressDispatch, snapshot?: ReadableStream<Uint8Array>): Promise<LixBinding>;
|
|
3
|
+
export declare function createHostedBinding(server: import("./binding-types.js").HostedServerBindingOptions): Promise<import("./types.js").HostedLix>;
|
|
4
|
+
export declare function deleteHostedBinding(server: import("./binding-types.js").HostedServerBindingOptions): Promise<void>;
|
package/dist/binding.browser.js
CHANGED
|
@@ -2,7 +2,9 @@ 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 { openJsStorage, openJsStorageFromSnapshot, openMemory, openMemoryFromSnapshot,
|
|
5
|
+
import { createHosted, deleteHosted, openJsStorage, openJsStorageFromSnapshot, openMemory, openMemoryFromSnapshot,
|
|
6
|
+
// @ts-ignore Generated by build:wasm and absent in source-only checks.
|
|
7
|
+
} from "./wasm/lix_js_sdk.js";
|
|
6
8
|
export async function openLixBinding(storage, telemetry, telemetryParent, server, openProgress, snapshot) {
|
|
7
9
|
await initializeWasm();
|
|
8
10
|
switch (storage.kind) {
|
|
@@ -32,3 +34,11 @@ export async function openLixBinding(storage, telemetry, telemetryParent, server
|
|
|
32
34
|
throw new Error("FilesystemStorage is only available in Node.js");
|
|
33
35
|
}
|
|
34
36
|
}
|
|
37
|
+
export async function createHostedBinding(server) {
|
|
38
|
+
await initializeWasm();
|
|
39
|
+
return createHosted(server);
|
|
40
|
+
}
|
|
41
|
+
export async function deleteHostedBinding(server) {
|
|
42
|
+
await initializeWasm();
|
|
43
|
+
await deleteHosted(server);
|
|
44
|
+
}
|
package/dist/binding.node.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { LixStorageConfig, LixBinding, SyncServerBindingOptions, TelemetryDispatch, TelemetryParentContext, OpenProgressDispatch } from "./binding-types.js";
|
|
2
2
|
export declare function openLixBinding(storage: LixStorageConfig, telemetry?: TelemetryDispatch, telemetryParent?: TelemetryParentContext, server?: SyncServerBindingOptions, openProgress?: OpenProgressDispatch, snapshot?: ReadableStream<Uint8Array>): Promise<LixBinding>;
|
|
3
3
|
export declare function openNativeLixBinding(storage: LixStorageConfig, telemetry?: TelemetryDispatch, telemetryParent?: TelemetryParentContext, server?: SyncServerBindingOptions, openProgress?: OpenProgressDispatch, snapshot?: ReadableStream<Uint8Array>): Promise<LixBinding>;
|
|
4
|
+
export declare function createHostedBinding(server: import("./binding-types.js").HostedServerBindingOptions): Promise<import("./types.js").HostedLix>;
|
|
5
|
+
export declare function deleteHostedBinding(server: import("./binding-types.js").HostedServerBindingOptions): Promise<void>;
|
package/dist/binding.node.js
CHANGED
|
@@ -62,7 +62,7 @@ class NativeAddonUnavailableError extends Error {
|
|
|
62
62
|
this.name = "NativeAddonUnavailableError";
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
function
|
|
65
|
+
function loadAddon() {
|
|
66
66
|
if (addon)
|
|
67
67
|
return addon;
|
|
68
68
|
if (addonLoadError)
|
|
@@ -114,7 +114,7 @@ export async function openNativeLixBinding(storage, telemetry, telemetryParent,
|
|
|
114
114
|
: undefined;
|
|
115
115
|
switch (storage.kind) {
|
|
116
116
|
case "memory": {
|
|
117
|
-
const nativeAddon =
|
|
117
|
+
const nativeAddon = loadAddon();
|
|
118
118
|
const nativeTelemetry = telemetry
|
|
119
119
|
? (spanJson) => telemetry(JSON.parse(spanJson))
|
|
120
120
|
: undefined;
|
|
@@ -130,7 +130,7 @@ export async function openNativeLixBinding(storage, telemetry, telemetryParent,
|
|
|
130
130
|
case "jsStorage":
|
|
131
131
|
throw new Error("JavaScript storage providers are only available in browsers");
|
|
132
132
|
case "filesystem": {
|
|
133
|
-
const nativeAddon =
|
|
133
|
+
const nativeAddon = loadAddon();
|
|
134
134
|
const nativeTelemetry = telemetry
|
|
135
135
|
? (spanJson) => telemetry(JSON.parse(spanJson))
|
|
136
136
|
: undefined;
|
|
@@ -145,3 +145,9 @@ export async function openNativeLixBinding(storage, telemetry, telemetryParent,
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
+
export async function createHostedBinding(server) {
|
|
149
|
+
return loadAddon().createHosted(server.url, server.headers, server.idempotencyKey);
|
|
150
|
+
}
|
|
151
|
+
export async function deleteHostedBinding(server) {
|
|
152
|
+
await loadAddon().deleteHosted(server.url, server.headers);
|
|
153
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CreateLixOptions, DeleteLixOptions, HostedLix } from "./types.js";
|
|
2
|
+
/** Creates a hosted repository, optionally from a consistent snapshot of a local Lix. */
|
|
3
|
+
export declare function createLix(options: CreateLixOptions): Promise<HostedLix>;
|
|
4
|
+
/** Deletes the hosted repository. Local replicas are not deleted. */
|
|
5
|
+
export declare function deleteLix(options: DeleteLixOptions): Promise<void>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createHostedFromLix } from "./lix.js";
|
|
2
|
+
import { hostedLixWorkerOperation } from "./worker/client.js";
|
|
3
|
+
async function resolveServer(server) {
|
|
4
|
+
if (!server || typeof server !== "object")
|
|
5
|
+
throw new TypeError("A server is required");
|
|
6
|
+
if ("fetch" in server && server.fetch !== undefined)
|
|
7
|
+
throw new TypeError("hosted lifecycle does not accept a custom fetch");
|
|
8
|
+
if ("mode" in server)
|
|
9
|
+
throw new TypeError("server.mode was removed");
|
|
10
|
+
const url = new URL(server.url).toString();
|
|
11
|
+
const headers = new Headers(typeof server.headers === "function"
|
|
12
|
+
? await server.headers()
|
|
13
|
+
: server.headers);
|
|
14
|
+
const entries = [];
|
|
15
|
+
headers.forEach((value, key) => entries.push([key, value]));
|
|
16
|
+
return { url, headers: entries };
|
|
17
|
+
}
|
|
18
|
+
/** Creates a hosted repository, optionally from a consistent snapshot of a local Lix. */
|
|
19
|
+
export async function createLix(options) {
|
|
20
|
+
if (options.from !== undefined) {
|
|
21
|
+
return createHostedFromLix(options.from, async () => ({
|
|
22
|
+
...(await resolveServer(options.server)),
|
|
23
|
+
idempotencyKey: options.idempotencyKey,
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
const server = await resolveServer(options.server);
|
|
27
|
+
return hostedLixWorkerOperation({
|
|
28
|
+
kind: "hosted.create",
|
|
29
|
+
server: { ...server, idempotencyKey: options.idempotencyKey },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Deletes the hosted repository. Local replicas are not deleted. */
|
|
33
|
+
export async function deleteLix(options) {
|
|
34
|
+
const server = await resolveServer(options.server);
|
|
35
|
+
await hostedLixWorkerOperation({ kind: "hosted.delete", server });
|
|
36
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export type { LixStorage, LixStorageBound, LixStorageChangeWatch, LixStorageComm
|
|
|
3
3
|
export { LixStorageError } from "./storage-adapter.js";
|
|
4
4
|
export { bundledPluginArchives, type BundledPluginArchive, } from "./bundled-plugins.js";
|
|
5
5
|
export { Value } from "./value.js";
|
|
6
|
-
export type { CreateBranchOptions, CreateBranchReceipt, RedoReceipt, ExecuteOptions, ExecuteResult, ExecuteBatchResult, LixBatchOptions, LixBatchStatement, JsonValue, LixValue, ResultArrayRow, ResultColumn, ResultColumnType, ResultObjectRow, ResultRow, MergeBranchOptions, MergeBranchOutcome, MergeBranchPreview, MergeBranchReceipt, MergeChangeStats, MergeConflict, MergeConflictSide, ObserveEvent, OpenLixOptions, OpenAnotherSessionOptions, LixTelemetryOptions, LixTelemetryParentContext, LixTelemetrySpan, LixTelemetrySpanLink, LixOpenMigrationReport, LixOpenPhase, LixOpenProgress, LixOpenProgressOptions, LixOpenReport, RemoteLixFetch,
|
|
6
|
+
export type { CreateBranchOptions, CreateBranchReceipt, RedoReceipt, CommitSpan, ExecuteOptions, ExecuteResult, ExecuteBatchResult, LixBatchOptions, LixBatchStatement, JsonValue, LixValue, ResultArrayRow, ResultColumn, ResultColumnType, ResultObjectRow, ResultRow, MergeBranchOptions, MergeBranchOutcome, MergeBranchPreview, MergeBranchReceipt, MergeChangeStats, MergeConflict, MergeConflictSide, ObserveEvent, OpenLixOptions, OpenAnotherSessionOptions, LixTelemetryOptions, LixTelemetryParentContext, LixTelemetrySpan, LixTelemetrySpanLink, LixOpenMigrationReport, LixOpenPhase, LixOpenProgress, LixOpenProgressOptions, LixOpenReport, ReplicaRecoverySource, ReplicaRecoveryRow, ReplicaRecoveryBranch, ReplicaRecoveryBlob, ReplicaRecoveryFile, ReplicaRecoveryExport, ReplicaRecoveryReceipt, RemoteLixFetch, LixServerOptions, HostedLix, CreateLixOptions, DeleteLixOptions, UndoReceipt, SqlParam, SwitchBranchOptions, SwitchBranchReceipt, } from "./types.js";
|
|
7
|
+
export { createLix, deleteLix } from "./hosted-lix.js";
|
package/dist/index.js
CHANGED
|
@@ -2,3 +2,4 @@ export { Lix, LixTransaction, ObserveEvents, openLix } from "./open-lix.js";
|
|
|
2
2
|
export { LixStorageError } from "./storage-adapter.js";
|
|
3
3
|
export { bundledPluginArchives, } from "./bundled-plugins.js";
|
|
4
4
|
export { Value } from "./value.js";
|
|
5
|
+
export { createLix, deleteLix } from "./hosted-lix.js";
|
package/dist/lix.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { LixBinding, LixTransactionBinding, ObserveEventsBinding } from "./binding-types.js";
|
|
2
|
-
import type { CreateBranchOptions, CreateBranchReceipt, RedoReceipt, ExecuteOptions, ExecuteResult, ExecuteBatchResult, LixBatchOptions, LixBatchStatement, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, ObserveEvent, OpenAnotherSessionOptions, LixOpenReport, SqlParam, ResultArrayRow, ResultObjectRow, ResultRow, SwitchBranchOptions, SwitchBranchReceipt, UndoReceipt } from "./types.js";
|
|
2
|
+
import type { CreateBranchOptions, CreateBranchReceipt, RedoReceipt, ExecuteOptions, ExecuteResult, ExecuteBatchResult, LixBatchOptions, LixBatchStatement, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, ObserveEvent, OpenAnotherSessionOptions, LixOpenReport, ReplicaRecoverySource, ReplicaRecoveryExport, ReplicaRecoveryReceipt, SqlParam, ResultArrayRow, ResultObjectRow, ResultRow, SwitchBranchOptions, SwitchBranchReceipt, UndoReceipt } from "./types.js";
|
|
3
|
+
/** @internal Used by createLix without adding another method to Lix. */
|
|
4
|
+
export declare function createHostedFromLix(lix: Lix, server: () => Promise<import("./binding-types.js").HostedServerBindingOptions>): Promise<import("./types.js").HostedLix>;
|
|
3
5
|
export declare class Lix {
|
|
4
6
|
#private;
|
|
5
7
|
private readonly binding;
|
|
@@ -24,6 +26,12 @@ export declare class Lix {
|
|
|
24
26
|
executeBatch(statements: readonly LixBatchStatement[], options?: LixBatchOptions): Promise<readonly ExecuteBatchResult<ResultRow>[]>;
|
|
25
27
|
observe(sql: string, params?: SqlParam[]): ObserveEvents;
|
|
26
28
|
beginTransaction(): Promise<LixTransaction>;
|
|
29
|
+
/** Lists preserved generations belonging to this local repository. */
|
|
30
|
+
replicaRecoverySources(): Promise<ReplicaRecoverySource[]>;
|
|
31
|
+
/** Exports retained work without deleting or changing its source. */
|
|
32
|
+
exportReplicaRecovery(id: string): Promise<ReplicaRecoveryExport>;
|
|
33
|
+
/** Restores supported rows onto separate recovery branches; preserves the source. */
|
|
34
|
+
recoverReplica(id: string): Promise<ReplicaRecoveryReceipt>;
|
|
27
35
|
activeBranchId(): Promise<string>;
|
|
28
36
|
activeAccountId(): Promise<string>;
|
|
29
37
|
/** Subscribes to successful branch switches made through this Lix handle. */
|
|
@@ -50,7 +58,6 @@ export declare class ObserveEvents {
|
|
|
50
58
|
export declare class LixTransaction {
|
|
51
59
|
private readonly binding;
|
|
52
60
|
private readonly onFinish;
|
|
53
|
-
private finishPromise;
|
|
54
61
|
private finished;
|
|
55
62
|
constructor(binding: LixTransactionBinding, onFinish?: () => void);
|
|
56
63
|
execute(sql: string, params: SqlParam[] | undefined, options: ExecuteOptions & {
|
package/dist/lix.js
CHANGED
|
@@ -13,6 +13,14 @@ const observeFinalizer = new FinalizationRegistry(({ observe, onClose }) => {
|
|
|
13
13
|
events?.close();
|
|
14
14
|
});
|
|
15
15
|
});
|
|
16
|
+
const hostedCreators = new WeakMap();
|
|
17
|
+
/** @internal Used by createLix without adding another method to Lix. */
|
|
18
|
+
export function createHostedFromLix(lix, server) {
|
|
19
|
+
const create = hostedCreators.get(lix);
|
|
20
|
+
if (!create)
|
|
21
|
+
throw new TypeError("createLix() from must be an open local Lix");
|
|
22
|
+
return create(server);
|
|
23
|
+
}
|
|
16
24
|
export class Lix {
|
|
17
25
|
binding;
|
|
18
26
|
openReport;
|
|
@@ -27,6 +35,11 @@ export class Lix {
|
|
|
27
35
|
#acceptingOperations = true;
|
|
28
36
|
constructor(binding) {
|
|
29
37
|
this.binding = binding;
|
|
38
|
+
hostedCreators.set(this, (server) => this.#runOperation(async () => {
|
|
39
|
+
if (!binding.createHosted)
|
|
40
|
+
throw new TypeError("createLix() from requires a local Lix");
|
|
41
|
+
return binding.createHosted(await server());
|
|
42
|
+
}));
|
|
30
43
|
const report = binding.openReport?.();
|
|
31
44
|
this.openReport = report
|
|
32
45
|
? Object.freeze({
|
|
@@ -82,6 +95,18 @@ export class Lix {
|
|
|
82
95
|
}
|
|
83
96
|
});
|
|
84
97
|
}
|
|
98
|
+
/** Lists preserved generations belonging to this local repository. */
|
|
99
|
+
async replicaRecoverySources() {
|
|
100
|
+
return this.#runOperation(() => this.binding.replicaRecoverySources());
|
|
101
|
+
}
|
|
102
|
+
/** Exports retained work without deleting or changing its source. */
|
|
103
|
+
async exportReplicaRecovery(id) {
|
|
104
|
+
return this.#runOperation(() => this.binding.exportReplicaRecovery(id));
|
|
105
|
+
}
|
|
106
|
+
/** Restores supported rows onto separate recovery branches; preserves the source. */
|
|
107
|
+
async recoverReplica(id) {
|
|
108
|
+
return this.#runOperation(() => this.binding.recoverReplica(id));
|
|
109
|
+
}
|
|
85
110
|
async activeBranchId() {
|
|
86
111
|
return this.#runOperation(() => this.binding.activeBranchId());
|
|
87
112
|
}
|
|
@@ -317,7 +342,6 @@ export class ObserveEvents {
|
|
|
317
342
|
export class LixTransaction {
|
|
318
343
|
binding;
|
|
319
344
|
onFinish;
|
|
320
|
-
finishPromise;
|
|
321
345
|
finished = false;
|
|
322
346
|
constructor(binding, onFinish = () => undefined) {
|
|
323
347
|
this.binding = binding;
|
|
@@ -325,6 +349,8 @@ export class LixTransaction {
|
|
|
325
349
|
transactionFinalizer.register(this, { transaction: binding, onFinish: this.onFinish }, this);
|
|
326
350
|
}
|
|
327
351
|
async execute(sql, params = [], options) {
|
|
352
|
+
if (this.finished)
|
|
353
|
+
throw transactionClosedError();
|
|
328
354
|
assertExecuteArgs("lixTransaction", sql, params, options);
|
|
329
355
|
const { rowMode = "object", ...bindingOptions } = options ?? {};
|
|
330
356
|
return wrapExecuteResult(await this.binding.execute(sql, params.map((param, index) => toNativeValue(normalizeParam(param, index))), bindingOptions), rowMode);
|
|
@@ -338,24 +364,21 @@ export class LixTransaction {
|
|
|
338
364
|
async finish(kind) {
|
|
339
365
|
if (this.finished)
|
|
340
366
|
throw transactionClosedError();
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
})();
|
|
367
|
+
// The first terminal call owns the handle immediately. In particular,
|
|
368
|
+
// a concurrent rollback must never report a pending commit's success.
|
|
369
|
+
this.finished = true;
|
|
370
|
+
try {
|
|
371
|
+
if (kind === "transaction.commit")
|
|
372
|
+
await this.binding.commit();
|
|
373
|
+
else
|
|
374
|
+
await this.binding.rollback();
|
|
375
|
+
}
|
|
376
|
+
finally {
|
|
377
|
+
// Keep the parent transaction lease until the binding settles. A
|
|
378
|
+
// terminal call consumes the handle even when it reports an error.
|
|
379
|
+
transactionFinalizer.unregister(this);
|
|
380
|
+
this.onFinish();
|
|
357
381
|
}
|
|
358
|
-
await this.finishPromise;
|
|
359
382
|
}
|
|
360
383
|
}
|
|
361
384
|
function transactionClosedError() {
|
package/dist/open-lix.js
CHANGED
|
@@ -26,37 +26,34 @@ async function openLixInternal(options, snapshot) {
|
|
|
26
26
|
throw new TypeError("openLix() onProgress must be a function");
|
|
27
27
|
}
|
|
28
28
|
if (options.server !== undefined) {
|
|
29
|
+
if ("mode" in options.server)
|
|
30
|
+
throw new TypeError("server.mode was removed; provide storage for synchronization or omit it for remote execution");
|
|
29
31
|
if (snapshot) {
|
|
30
32
|
throw new TypeError("openLix.fromSnapshot() does not accept server mode");
|
|
31
33
|
}
|
|
32
|
-
if (options.
|
|
34
|
+
if (options.storage === undefined) {
|
|
35
|
+
if (options.telemetry !== undefined || options.onProgress !== undefined)
|
|
36
|
+
throw new TypeError("remote execution does not accept local telemetry or onProgress");
|
|
33
37
|
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
38
|
return new Lix(await openRemoteLixBinding(options.server));
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
|
-
const syncServer = options.server
|
|
41
|
+
const syncServer = options.server !== undefined && options.storage !== undefined
|
|
41
42
|
? {
|
|
42
43
|
url: new URL(options.server.url).toString(),
|
|
43
44
|
headers: options.server.headers,
|
|
44
45
|
fetch: options.server.fetch,
|
|
45
46
|
}
|
|
46
47
|
: undefined;
|
|
47
|
-
if (syncServer?.fetch !== undefined &&
|
|
48
|
+
if (syncServer?.fetch !== undefined &&
|
|
49
|
+
typeof syncServer.fetch !== "function") {
|
|
48
50
|
throw new TypeError("openLix() sync server fetch must be a function");
|
|
49
51
|
}
|
|
50
|
-
if (syncServer?.headers !== undefined &&
|
|
52
|
+
if (syncServer?.headers !== undefined &&
|
|
53
|
+
typeof syncServer.headers !== "function") {
|
|
51
54
|
// Validate static headers before opening a worker/native runtime.
|
|
52
55
|
new Headers(syncServer.headers);
|
|
53
56
|
}
|
|
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");
|
|
59
|
-
}
|
|
60
57
|
const { openLixWorkerBinding } = await import("./worker/client.js");
|
|
61
58
|
if (options.storage === undefined) {
|
|
62
59
|
const binding = await openLixWorkerBinding({ kind: "memory" }, undefined, options.telemetry, syncServer, options.onProgress, snapshot);
|
package/dist/remote/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LixBinding } from "../binding-types.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { LixServerOptions } from "../types.js";
|
|
3
3
|
type RemoteLixClientOptions = {
|
|
4
4
|
initialActiveBranchId?: string;
|
|
5
5
|
};
|
|
6
|
-
export declare function openRemoteLixBinding(options:
|
|
6
|
+
export declare function openRemoteLixBinding(options: LixServerOptions, clientOptions?: RemoteLixClientOptions): Promise<LixBinding>;
|
|
7
7
|
export {};
|
package/dist/remote/client.js
CHANGED
|
@@ -6,9 +6,6 @@ export async function openRemoteLixBinding(options, clientOptions = {}) {
|
|
|
6
6
|
if (!options || typeof options !== "object") {
|
|
7
7
|
throw new TypeError("openLix() remote server must be an object");
|
|
8
8
|
}
|
|
9
|
-
if (options.mode !== "remote") {
|
|
10
|
-
throw new TypeError("openLix() remote server mode must be 'remote'");
|
|
11
|
-
}
|
|
12
9
|
const remoteFetch = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
13
10
|
if (typeof remoteFetch !== "function") {
|
|
14
11
|
throw new TypeError("openLix() remote mode requires fetch");
|
|
@@ -98,10 +98,6 @@ export type LixStoragePrecondition = {
|
|
|
98
98
|
kind: "rangeEmpty";
|
|
99
99
|
space: LixStorageSpace;
|
|
100
100
|
range: LixStorageKeyRange;
|
|
101
|
-
} | {
|
|
102
|
-
kind: "branchEquals";
|
|
103
|
-
refKey: Uint8Array;
|
|
104
|
-
expected: Uint8Array;
|
|
105
101
|
};
|
|
106
102
|
export type LixStorageGetManyRequest = {
|
|
107
103
|
space: LixStorageSpace;
|