@lix-js/sdk 0.6.2 → 0.7.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 +21 -6
- package/dist/bundled-plugins/plugin_csv.lixplugin +0 -0
- package/dist/bundled-plugins/plugin_md_v2.lixplugin +0 -0
- package/dist/bundled-plugins.d.ts +6 -0
- package/dist/bundled-plugins.js +33 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/dist/open-lix.d.ts +22 -1
- package/dist/open-lix.js +49 -6
- package/dist/types.d.ts +9 -1
- package/package.json +10 -6
package/README.md
CHANGED
|
@@ -17,9 +17,15 @@ const lix = await openLix({
|
|
|
17
17
|
backend: new SqliteBackend({ path: "app.lix" }),
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
await lix.
|
|
20
|
+
await lix.execute(
|
|
21
|
+
"INSERT INTO lix_file (path, data) VALUES ($1, $2) ON CONFLICT (path) DO UPDATE SET data = excluded.data",
|
|
22
|
+
["/hello.txt", new TextEncoder().encode("world")],
|
|
23
|
+
);
|
|
21
24
|
|
|
22
|
-
const
|
|
25
|
+
const result = await lix.execute("SELECT data FROM lix_file WHERE path = $1", [
|
|
26
|
+
"/hello.txt",
|
|
27
|
+
]);
|
|
28
|
+
const bytes = result.rows[0]?.value("data").asBytes();
|
|
23
29
|
|
|
24
30
|
console.log(bytes && new TextDecoder().decode(bytes));
|
|
25
31
|
|
|
@@ -33,7 +39,10 @@ const main = await lix.activeBranchId();
|
|
|
33
39
|
const draft = await lix.createBranch({ name: "Draft" });
|
|
34
40
|
|
|
35
41
|
await lix.switchBranch({ branchId: draft.id });
|
|
36
|
-
await lix.
|
|
42
|
+
await lix.execute(
|
|
43
|
+
"INSERT INTO lix_file (path, data) VALUES ($1, $2) ON CONFLICT (path) DO UPDATE SET data = excluded.data",
|
|
44
|
+
["/status.txt", new TextEncoder().encode("draft")],
|
|
45
|
+
);
|
|
37
46
|
|
|
38
47
|
await lix.switchBranch({ branchId: main });
|
|
39
48
|
const preview = await lix.mergeBranchPreview({ sourceBranchId: draft.id });
|
|
@@ -46,8 +55,14 @@ const merge = await lix.mergeBranch({ sourceBranchId: draft.id });
|
|
|
46
55
|
const tx = await lix.beginTransaction();
|
|
47
56
|
|
|
48
57
|
try {
|
|
49
|
-
await tx.
|
|
50
|
-
|
|
58
|
+
await tx.execute(
|
|
59
|
+
"INSERT INTO lix_file (path, data) VALUES ($1, $2) ON CONFLICT (path) DO UPDATE SET data = excluded.data",
|
|
60
|
+
["/a.txt", new TextEncoder().encode("1")],
|
|
61
|
+
);
|
|
62
|
+
await tx.execute(
|
|
63
|
+
"INSERT INTO lix_file (path, data) VALUES ($1, $2) ON CONFLICT (path) DO UPDATE SET data = excluded.data",
|
|
64
|
+
["/b.txt", new TextEncoder().encode("2")],
|
|
65
|
+
);
|
|
51
66
|
await tx.commit();
|
|
52
67
|
} catch (error) {
|
|
53
68
|
await tx.rollback();
|
|
@@ -57,7 +72,7 @@ try {
|
|
|
57
72
|
|
|
58
73
|
## Notes
|
|
59
74
|
|
|
60
|
-
- `openLix()` opens a fresh in-memory Lix. Pass `new SqliteBackend({ path })`
|
|
75
|
+
- `openLix()` opens a fresh in-memory Lix. Pass `new SqliteBackend({ path })` for a raw SQLite `.lix` file, or `new FsBackend({ path })` for a filesystem workspace directory backed by `<path>/.lix/.internal/db.sqlite`.
|
|
61
76
|
- The SDK is Node/native only right now; it is not browser-compatible.
|
|
62
77
|
- The package is ESM-only.
|
|
63
78
|
- The native addon is built from Rust and loaded by the TypeScript wrapper.
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
const BUNDLED_PLUGIN_MANIFEST = [
|
|
3
|
+
{
|
|
4
|
+
key: "plugin_md_v2",
|
|
5
|
+
fileName: "plugin_md_v2.lixplugin",
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
key: "plugin_csv",
|
|
9
|
+
fileName: "plugin_csv.lixplugin",
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
export async function bundledPluginArchives() {
|
|
13
|
+
return await Promise.all(BUNDLED_PLUGIN_MANIFEST.map(async (plugin) => ({
|
|
14
|
+
key: plugin.key,
|
|
15
|
+
fileName: plugin.fileName,
|
|
16
|
+
archiveBytes: await readBundledArchive(plugin.fileName),
|
|
17
|
+
})));
|
|
18
|
+
}
|
|
19
|
+
async function readBundledArchive(fileName) {
|
|
20
|
+
const urls = [
|
|
21
|
+
new URL(`./bundled-plugins/${fileName}`, import.meta.url),
|
|
22
|
+
new URL(`../dist/bundled-plugins/${fileName}`, import.meta.url),
|
|
23
|
+
];
|
|
24
|
+
for (const url of urls) {
|
|
25
|
+
try {
|
|
26
|
+
return new Uint8Array(await readFile(url));
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Try the next build/source layout.
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return new Uint8Array(await readFile(urls[0]));
|
|
33
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { Lix, LixTransaction, openLix, SqliteBackend } from "./open-lix.js";
|
|
1
|
+
export { FsBackend, Lix, LixTransaction, ObserveEvents, openLix, SqliteBackend, } from "./open-lix.js";
|
|
2
|
+
export { bundledPluginArchives, type BundledPluginArchive, } from "./bundled-plugins.js";
|
|
2
3
|
export { Row } from "./result.js";
|
|
3
4
|
export { Value } from "./value.js";
|
|
4
|
-
export type { CreateBranchOptions, CreateBranchReceipt, ExecuteResult, JsonValue, LixValue, MergeBranchOptions, MergeBranchOutcome, MergeBranchPreview, MergeBranchReceipt, MergeChangeStats, MergeConflict, MergeConflictSide, OpenLixOptions, SqlParam, SqliteBackendOptions, SwitchBranchOptions, SwitchBranchReceipt, } from "./types.js";
|
|
5
|
+
export type { CreateBranchOptions, CreateBranchReceipt, ExecuteResult, FsBackendOptions, JsonValue, LixValue, MergeBranchOptions, MergeBranchOutcome, MergeBranchPreview, MergeBranchReceipt, MergeChangeStats, MergeConflict, MergeConflictSide, ObserveEvent, OpenLixOptions, SqlParam, SqliteBackendOptions, SwitchBranchOptions, SwitchBranchReceipt, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { Lix, LixTransaction, openLix, SqliteBackend } from "./open-lix.js";
|
|
1
|
+
export { FsBackend, Lix, LixTransaction, ObserveEvents, openLix, SqliteBackend, } from "./open-lix.js";
|
|
2
|
+
export { bundledPluginArchives, } from "./bundled-plugins.js";
|
|
2
3
|
export { Row } from "./result.js";
|
|
3
4
|
export { Value } from "./value.js";
|
package/dist/open-lix.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { wrapExecuteResult } from "./result.js";
|
|
2
2
|
import { toNativeValue } from "./value.js";
|
|
3
|
-
import type { CreateBranchOptions, CreateBranchReceipt, ExecuteResult, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, OpenLixOptions, SqlParam, SqliteBackendOptions, SwitchBranchOptions, SwitchBranchReceipt } from "./types.js";
|
|
3
|
+
import type { CreateBranchOptions, CreateBranchReceipt, ExecuteResult, FsBackendOptions, MergeBranchOptions, MergeBranchPreview, MergeBranchReceipt, ObserveEvent, OpenLixOptions, SqlParam, SqliteBackendOptions, SwitchBranchOptions, SwitchBranchReceipt } from "./types.js";
|
|
4
4
|
type NativeExecuteResult = Parameters<typeof wrapExecuteResult>[0];
|
|
5
|
+
type NativeObserveEvent = {
|
|
6
|
+
sequence: number;
|
|
7
|
+
mutationSequence: number;
|
|
8
|
+
rows: NativeExecuteResult;
|
|
9
|
+
};
|
|
5
10
|
type NativeParam = ReturnType<typeof toNativeValue>;
|
|
6
11
|
type NativeLix = {
|
|
7
12
|
execute(sql: string, params: NativeParam[]): NativeExecuteResult;
|
|
13
|
+
observe(sql: string, params: NativeParam[]): NativeObserveEvents;
|
|
8
14
|
beginTransaction(): NativeLixTransaction;
|
|
9
15
|
activeBranchId(): string;
|
|
10
16
|
createBranch(options: CreateBranchOptions): CreateBranchReceipt;
|
|
@@ -18,15 +24,24 @@ type NativeLixTransaction = {
|
|
|
18
24
|
commit(): void;
|
|
19
25
|
rollback(): void;
|
|
20
26
|
};
|
|
27
|
+
type NativeObserveEvents = {
|
|
28
|
+
next(): Promise<NativeObserveEvent | null | undefined>;
|
|
29
|
+
close(): void;
|
|
30
|
+
};
|
|
21
31
|
export declare class SqliteBackend {
|
|
22
32
|
readonly path: string;
|
|
23
33
|
constructor(options: SqliteBackendOptions);
|
|
24
34
|
}
|
|
35
|
+
export declare class FsBackend {
|
|
36
|
+
readonly path: string;
|
|
37
|
+
constructor(options: FsBackendOptions);
|
|
38
|
+
}
|
|
25
39
|
export declare function openLix(options?: OpenLixOptions): Promise<Lix>;
|
|
26
40
|
export declare class Lix {
|
|
27
41
|
private readonly native;
|
|
28
42
|
constructor(native: NativeLix);
|
|
29
43
|
execute(sql: string, params?: SqlParam[]): Promise<ExecuteResult>;
|
|
44
|
+
observe(sql: string, params?: SqlParam[]): ObserveEvents;
|
|
30
45
|
beginTransaction(): Promise<LixTransaction>;
|
|
31
46
|
activeBranchId(): Promise<string>;
|
|
32
47
|
createBranch(options: CreateBranchOptions): Promise<CreateBranchReceipt>;
|
|
@@ -35,6 +50,12 @@ export declare class Lix {
|
|
|
35
50
|
mergeBranch(options: MergeBranchOptions): Promise<MergeBranchReceipt>;
|
|
36
51
|
close(): Promise<void>;
|
|
37
52
|
}
|
|
53
|
+
export declare class ObserveEvents {
|
|
54
|
+
private readonly native;
|
|
55
|
+
constructor(native: NativeObserveEvents);
|
|
56
|
+
next(): Promise<ObserveEvent | undefined>;
|
|
57
|
+
close(): void;
|
|
58
|
+
}
|
|
38
59
|
export declare class LixTransaction {
|
|
39
60
|
private readonly native;
|
|
40
61
|
constructor(native: NativeLixTransaction);
|
package/dist/open-lix.js
CHANGED
|
@@ -5,12 +5,25 @@ import { normalizeParam, toNativeValue } from "./value.js";
|
|
|
5
5
|
export class SqliteBackend {
|
|
6
6
|
path;
|
|
7
7
|
constructor(options) {
|
|
8
|
-
if (!options ||
|
|
8
|
+
if (!options ||
|
|
9
|
+
typeof options.path !== "string" ||
|
|
10
|
+
options.path.length === 0) {
|
|
9
11
|
throw new TypeError("SqliteBackend requires a non-empty path");
|
|
10
12
|
}
|
|
11
13
|
this.path = options.path;
|
|
12
14
|
}
|
|
13
15
|
}
|
|
16
|
+
export class FsBackend {
|
|
17
|
+
path;
|
|
18
|
+
constructor(options) {
|
|
19
|
+
if (!options ||
|
|
20
|
+
typeof options.path !== "string" ||
|
|
21
|
+
options.path.length === 0) {
|
|
22
|
+
throw new TypeError("FsBackend requires a non-empty path");
|
|
23
|
+
}
|
|
24
|
+
this.path = options.path;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
14
27
|
export async function openLix(options = {}) {
|
|
15
28
|
if (!options || typeof options !== "object") {
|
|
16
29
|
throw new TypeError("openLix() options must be an object");
|
|
@@ -18,10 +31,13 @@ export async function openLix(options = {}) {
|
|
|
18
31
|
if (options.backend === undefined) {
|
|
19
32
|
return new Lix(addon.Lix.openMemory());
|
|
20
33
|
}
|
|
21
|
-
if (
|
|
22
|
-
|
|
34
|
+
if (options.backend instanceof SqliteBackend) {
|
|
35
|
+
return new Lix(addon.Lix.openSqlite(options.backend.path));
|
|
36
|
+
}
|
|
37
|
+
if (options.backend instanceof FsBackend) {
|
|
38
|
+
return new Lix(addon.Lix.openFs(options.backend.path));
|
|
23
39
|
}
|
|
24
|
-
|
|
40
|
+
throw new TypeError("openLix() requires { backend: new SqliteBackend({ path }) } or { backend: new FsBackend({ path }) }");
|
|
25
41
|
}
|
|
26
42
|
export class Lix {
|
|
27
43
|
native;
|
|
@@ -32,6 +48,10 @@ export class Lix {
|
|
|
32
48
|
assertExecuteArgs("lix", sql, params);
|
|
33
49
|
return wrapExecuteResult(this.native.execute(sql, params.map((param, index) => toNativeValue(normalizeParam(param, index)))));
|
|
34
50
|
}
|
|
51
|
+
observe(sql, params = []) {
|
|
52
|
+
assertSqlArgs("observe", "lix", sql, params);
|
|
53
|
+
return new ObserveEvents(this.native.observe(sql, params.map((param, index) => toNativeValue(normalizeParam(param, index)))));
|
|
54
|
+
}
|
|
35
55
|
async beginTransaction() {
|
|
36
56
|
return new LixTransaction(this.native.beginTransaction());
|
|
37
57
|
}
|
|
@@ -56,6 +76,26 @@ export class Lix {
|
|
|
56
76
|
return this.native.close();
|
|
57
77
|
}
|
|
58
78
|
}
|
|
79
|
+
export class ObserveEvents {
|
|
80
|
+
native;
|
|
81
|
+
constructor(native) {
|
|
82
|
+
this.native = native;
|
|
83
|
+
}
|
|
84
|
+
async next() {
|
|
85
|
+
const event = await this.native.next();
|
|
86
|
+
if (event == null) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
sequence: event.sequence,
|
|
91
|
+
mutationSequence: event.mutationSequence,
|
|
92
|
+
result: wrapExecuteResult(event.rows),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
close() {
|
|
96
|
+
this.native.close();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
59
99
|
export class LixTransaction {
|
|
60
100
|
native;
|
|
61
101
|
constructor(native) {
|
|
@@ -73,10 +113,13 @@ export class LixTransaction {
|
|
|
73
113
|
}
|
|
74
114
|
}
|
|
75
115
|
function assertExecuteArgs(receiver, sql, params) {
|
|
116
|
+
assertSqlArgs("execute", receiver, sql, params);
|
|
117
|
+
}
|
|
118
|
+
function assertSqlArgs(operation, receiver, sql, params) {
|
|
76
119
|
if (typeof sql !== "string") {
|
|
77
|
-
throw invalidArgument(
|
|
120
|
+
throw invalidArgument(operation, "sql", "string", typeof sql, receiver);
|
|
78
121
|
}
|
|
79
122
|
if (!Array.isArray(params)) {
|
|
80
|
-
throw invalidArgument(
|
|
123
|
+
throw invalidArgument(operation, "params", "array", typeof params, receiver);
|
|
81
124
|
}
|
|
82
125
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export type SqliteBackendOptions = {
|
|
2
2
|
path: string;
|
|
3
3
|
};
|
|
4
|
+
export type FsBackendOptions = {
|
|
5
|
+
path: string;
|
|
6
|
+
};
|
|
4
7
|
export type OpenLixOptions = {
|
|
5
|
-
backend?: import("./open-lix.js").SqliteBackend;
|
|
8
|
+
backend?: import("./open-lix.js").SqliteBackend | import("./open-lix.js").FsBackend;
|
|
6
9
|
};
|
|
7
10
|
export type LixValue = {
|
|
8
11
|
kind: "null";
|
|
@@ -40,6 +43,11 @@ export type ExecuteResult = {
|
|
|
40
43
|
hint?: string;
|
|
41
44
|
}>;
|
|
42
45
|
};
|
|
46
|
+
export type ObserveEvent = {
|
|
47
|
+
sequence: number;
|
|
48
|
+
mutationSequence: number;
|
|
49
|
+
result: ExecuteResult;
|
|
50
|
+
};
|
|
43
51
|
export type RowLike = {
|
|
44
52
|
get(column: string): unknown;
|
|
45
53
|
value(column: string): ValueLike;
|
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.7.0",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"repository": {
|
|
@@ -18,22 +18,26 @@
|
|
|
18
18
|
"dist"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"build": "npm run build:native && npm run build:ts",
|
|
21
|
+
"build": "npm run build:native && npm run build:ts && npm run build:plugins",
|
|
22
22
|
"build:native": "node ./scripts/build-native.js",
|
|
23
|
+
"build:plugins": "node ./scripts/build-bundled-plugins.js",
|
|
23
24
|
"prepare:native-package": "node ./scripts/prepare-native-package.js",
|
|
24
25
|
"build:ts": "tsc -p tsconfig.json",
|
|
25
26
|
"test": "npm run build && vitest run",
|
|
26
27
|
"typecheck": "tsc -p tsconfig.test.json --noEmit"
|
|
27
28
|
},
|
|
28
29
|
"optionalDependencies": {
|
|
29
|
-
"@lix-js/sdk-darwin-arm64": "0.
|
|
30
|
-
"@lix-js/sdk-linux-arm64": "0.
|
|
31
|
-
"@lix-js/sdk-linux-x64": "0.
|
|
32
|
-
"@lix-js/sdk-win32-x64": "0.
|
|
30
|
+
"@lix-js/sdk-darwin-arm64": "0.7.0",
|
|
31
|
+
"@lix-js/sdk-linux-arm64": "0.7.0",
|
|
32
|
+
"@lix-js/sdk-linux-x64": "0.7.0",
|
|
33
|
+
"@lix-js/sdk-win32-x64": "0.7.0"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@types/node": "^24.10.2",
|
|
36
37
|
"typescript": "^5.5.4",
|
|
37
38
|
"vitest": "^4.0.18"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"fflate": "^0.8.3"
|
|
38
42
|
}
|
|
39
43
|
}
|