@loradb/lora-node 0.4.0 → 0.5.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 CHANGED
@@ -51,27 +51,64 @@ The initialization rule is:
51
51
  ```ts
52
52
  import { createDatabase } from "lora-node";
53
53
 
54
- const inMemory = await createDatabase(); // in-memory only
55
- const persistent = await createDatabase("./app"); // persistent: pass a directory string
54
+ const inMemory = await createDatabase(); // in-memory only
55
+ const named = await createDatabase("app"); // named in-memory
56
+ const persistent = await createDatabase("app", {
57
+ databaseDir: "./data",
58
+ }); // ./data/app.loradb
56
59
  ```
57
60
 
58
- If you want persistence, pass a **directory string** to `createDatabase(...)`.
61
+ If you want persistence, pass a `databaseDir` option to `createDatabase(...)`.
59
62
 
60
- Node also has a WAL-backed convenience overload:
63
+ Node also has an archive-backed convenience overload:
61
64
 
62
65
  ```ts
63
66
  import { createDatabase } from "lora-node";
64
67
 
65
- const db = await createDatabase("./.lora-wal"); // persistent: directory string
68
+ const db = await createDatabase("app", { databaseDir: "./data" });
66
69
  ```
67
70
 
68
- The string is treated as the WAL directory path verbatim. Relative
69
- paths resolve from the current working directory. This is a Node-only
70
- initialization convenience; the query surface, shared types, and async
71
+ The database name is validated and resolved under `databaseDir`, appending
72
+ `.loradb` to the basename when needed. Relative paths resolve from the current
73
+ working directory. This is a Node-only initialization convenience; the query surface, shared types, and async
71
74
  method signatures still match `lora-wasm`.
72
75
 
73
76
  Call `db.dispose()` when you need to release the native handle eagerly,
74
- especially before reopening the same WAL directory in the same process.
77
+ especially before reopening the same archive in the same process.
78
+
79
+ ## Snapshots
80
+
81
+ `saveSnapshot(path)` writes the current graph to a local file. It also accepts
82
+ typed formats: `"binary"` returns a Node `Buffer`, `"base64"` returns base64
83
+ text, and `{ format: "path", path }` accepts either a path string or `file:`
84
+ URL.
85
+
86
+ `loadSnapshot` accepts a `NodeSnapshotSource`: a filesystem path, `file:` URL,
87
+ HTTP(S) or `data:` URL, `Buffer`, `Uint8Array`, `ArrayBuffer`, Node
88
+ `Readable`, web `ReadableStream`, or async iterable of byte chunks.
89
+
90
+ ```ts
91
+ import { readFile } from "node:fs/promises";
92
+ import { createReadStream } from "node:fs";
93
+ import { pathToFileURL } from "node:url";
94
+ import { createDatabase } from "lora-node";
95
+
96
+ const db = await createDatabase();
97
+ await db.execute("CREATE (:Person {name: 'Alice'})");
98
+ await db.saveSnapshot("./graph.lorasnap");
99
+ const bytes = await db.saveSnapshot("binary");
100
+ const base64 = await db.saveSnapshot({ format: "base64" });
101
+
102
+ await db.loadSnapshot("./graph.lorasnap");
103
+ await db.loadSnapshot(pathToFileURL("./graph.lorasnap"));
104
+ await db.loadSnapshot(await readFile("./graph.lorasnap"));
105
+ await db.loadSnapshot(createReadStream("./graph.lorasnap"));
106
+ await db.loadSnapshot(bytes);
107
+ await db.loadSnapshot(new URL("https://example.com/graph.lorasnap"));
108
+ ```
109
+
110
+ Use `loadSnapshotFromBytes(bytes)` when you already have in-memory bytes and
111
+ want to make that intent explicit.
75
112
 
76
113
  ## Typed value model
77
114
 
@@ -139,21 +176,19 @@ identical to `lora-wasm`.
139
176
 
140
177
  ## Known limitations
141
178
 
142
- - **Concurrent writes.** Each `execute()` hops through the threadpool and
143
- serialises on the store mutex inside Rust, so concurrent read/read and
144
- read/write traffic works. Firing many concurrent write queries against
145
- the same `Database` (e.g. 2 000 parallel `CREATE`s via `Promise.all`)
146
- can expose races in the underlying engine — treat the mutex as
147
- per-operation, not per-query. Prefer `await`-in-a-loop or a single
148
- batched query for heavy write workloads.
179
+ - **Concurrent writes.** Each `execute()` hops through the threadpool; read
180
+ queries can share the store read lock, while writes serialize on the store
181
+ write lock. Firing many concurrent write queries against the same
182
+ `Database` (e.g. 2 000 parallel `CREATE`s via `Promise.all`) works but
183
+ queues behind that write lock. Prefer `await`-in-a-loop or a single batched
184
+ query for heavy write workloads.
149
185
  - **I64 precision.** Integer values above `Number.MAX_SAFE_INTEGER`
150
186
  (2^53) are returned as JS `number` and lose precision. A `bigint`-aware
151
187
  path would require extending the value serializer.
152
188
  - **Cancellation.** The napi `Task` abstraction does not support
153
189
  cancellation once dispatched; a runaway query runs to completion.
154
190
  - **WAL surface.** This first Node persistence slice only exposes
155
- WAL-backed initialization via `createDatabase(walDir)`. Checkpoint,
191
+ archive-backed initialization via `createDatabase(name, { databaseDir })`. Checkpoint,
156
192
  truncate, status, and sync-mode controls are not exposed yet.
157
- - **WAL directory ownership.** A WAL directory can only be open by one
158
- live handle at a time. Dispose the first handle before reopening the
159
- same directory.
193
+ - **Archive ownership.** One archive can only be open by one live handle at a
194
+ time. Dispose the first handle before reopening the same database.
package/dist/index.d.ts CHANGED
@@ -8,10 +8,12 @@
8
8
  * shapes defined in the shared TS contract (`crates/shared-ts/types.ts`).
9
9
  *
10
10
  * **Initialization is async-only.** The canonical entry point is
11
- * `createDatabase(...)`, optionally with a WAL directory path. There is no
11
+ * `createDatabase(...)`, optionally with archive-backed persistence. There is no
12
12
  * synchronous constructor. See the docs at
13
13
  * https://loradb.com/docs/getting-started/node for the full rationale.
14
14
  */
15
+ import { Buffer } from "node:buffer";
16
+ import { Readable } from "node:stream";
15
17
  import type { LoraParams, LoraValue, QueryResult } from "./types.js";
16
18
  declare const NativeDatabase: typeof import("./native.js").Database;
17
19
  export * from "./types.js";
@@ -27,17 +29,41 @@ export interface SnapshotMeta {
27
29
  relationshipCount: number;
28
30
  walLsn: number | null;
29
31
  }
32
+ export type NodeSnapshotChunk = string | Uint8Array | ArrayBuffer | Buffer;
33
+ export type NodeSnapshotSource = string | URL | Uint8Array | ArrayBuffer | Buffer | Readable | ReadableStream<NodeSnapshotChunk> | AsyncIterable<NodeSnapshotChunk>;
34
+ export type NodeSnapshotSaveFormat = "binary" | "base64";
35
+ export type NodeSnapshotSaveOptions = {
36
+ format: "path";
37
+ path: string | URL;
38
+ } | {
39
+ format: NodeSnapshotSaveFormat;
40
+ };
41
+ export type NodeSnapshotSaveTarget = string | URL | NodeSnapshotSaveFormat | NodeSnapshotSaveOptions;
42
+ export interface CreateDatabaseOptions {
43
+ databaseDir?: string;
44
+ }
45
+ export type TransactionMode = "read_write" | "read_only" | "readwrite" | "readonly" | "rw" | "ro";
46
+ export interface TransactionStatement {
47
+ query: string;
48
+ params?: LoraParams | null;
49
+ }
50
+ export interface RowStream<T extends Record<string, LoraValue> = Record<string, LoraValue>> extends AsyncIterableIterator<T> {
51
+ columns(): string[];
52
+ toArray(): Promise<T[]>;
53
+ close(): void;
54
+ }
30
55
  /**
31
56
  * Lora graph database instance.
32
57
  *
33
58
  * Obtained exclusively via `createDatabase()`. There is no public
34
59
  * constructor and no synchronous factory. With no args the instance is
35
- * purely in-memory; with a WAL directory path it replays committed WAL
36
- * state from disk before serving queries.
60
+ * purely in-memory; with a database name and `databaseDir` it replays committed
61
+ * WAL state from the serialized `.loradb` path under `databaseDir` before
62
+ * serving queries.
37
63
  *
38
64
  * Instances are independent — each owns its own in-memory graph. Multiple
39
- * concurrent `execute()` calls against one instance run one at a time
40
- * (serialised on the store mutex) but none of them block the event loop.
65
+ * concurrent read-only `execute()` calls against one instance can share
66
+ * the store read lock; writes serialize without blocking the event loop.
41
67
  */
42
68
  declare class DatabaseImpl {
43
69
  #private;
@@ -48,6 +74,24 @@ declare class DatabaseImpl {
48
74
  * with a narrowed `code` (`LORA_ERROR` / `INVALID_PARAMS`).
49
75
  */
50
76
  execute<T extends Record<string, LoraValue> = Record<string, LoraValue>>(query: string, params?: LoraParams): Promise<QueryResult<T>>;
77
+ /**
78
+ * Return an async row iterator for a query.
79
+ *
80
+ * The binding exposes the same `for await` shape as the Rust stream API.
81
+ * Rows are materialized by the native `execute()` promise today, then
82
+ * yielded one at a time to JS consumers.
83
+ */
84
+ stream<T extends Record<string, LoraValue> = Record<string, LoraValue>>(query: string, params?: LoraParams): RowStream<T>;
85
+ /** Alias for `stream()`, useful when naming the row-level API explicitly. */
86
+ rows<T extends Record<string, LoraValue> = Record<string, LoraValue>>(query: string, params?: LoraParams): RowStream<T>;
87
+ /**
88
+ * Execute a statement batch inside one native transaction.
89
+ *
90
+ * Results are returned in statement order. If any statement fails, the
91
+ * native transaction is dropped before commit and all prior writes in the
92
+ * batch are rolled back.
93
+ */
94
+ transaction<T extends Record<string, LoraValue> = Record<string, LoraValue>>(statements: TransactionStatement[], mode?: TransactionMode): Promise<Array<QueryResult<T>>>;
51
95
  /** Drop every node and relationship. Constant-time under the hood. */
52
96
  clear(): Promise<void>;
53
97
  /** Number of nodes currently in the graph. */
@@ -57,26 +101,31 @@ declare class DatabaseImpl {
57
101
  /**
58
102
  * Release the native database handle. Idempotent.
59
103
  *
60
- * Call this when a WAL-backed database needs to be reopened in the same
104
+ * Call this when an archive-backed database needs to be reopened in the same
61
105
  * process. New operations after disposal reject with `database is closed`.
62
106
  */
63
107
  dispose(): void;
64
- /**
65
- * Save the graph to a snapshot file. Writes atomically via a `.tmp` +
66
- * rename dance — the target path is only replaced once the full payload
67
- * has been written and fsync'd.
68
- *
69
- * Synchronous in the native layer (point-in-time consistency requires
70
- * holding the store mutex for the duration of the save); the returned
71
- * Promise resolves immediately once the save returns.
72
- */
73
- saveSnapshot(path: string): Promise<SnapshotMeta>;
108
+ saveSnapshot(format: "binary"): Promise<Buffer>;
109
+ saveSnapshot(format: "base64"): Promise<string>;
110
+ saveSnapshot(path: string | URL): Promise<SnapshotMeta>;
111
+ saveSnapshot(options: {
112
+ format: "binary";
113
+ }): Promise<Buffer>;
114
+ saveSnapshot(options: {
115
+ format: "base64";
116
+ }): Promise<string>;
117
+ saveSnapshot(options: {
118
+ format: "path";
119
+ path: string | URL;
120
+ }): Promise<SnapshotMeta>;
121
+ saveSnapshotToBytes(): Promise<Buffer>;
74
122
  /**
75
123
  * Replace the current graph state with a snapshot loaded from `path`.
76
- * Concurrent `execute()` calls block on the store mutex until the load
77
- * completes.
124
+ * Concurrent `execute()` calls block on the store write lock until the
125
+ * load completes.
78
126
  */
79
- loadSnapshot(path: string): Promise<SnapshotMeta>;
127
+ loadSnapshot(source: NodeSnapshotSource): Promise<SnapshotMeta>;
128
+ loadSnapshotFromBytes(bytes: Uint8Array | ArrayBuffer | Buffer): Promise<SnapshotMeta>;
80
129
  }
81
130
  /**
82
131
  * Public type for a LoraDB instance.
@@ -113,15 +162,18 @@ export type Database = DatabaseImpl;
113
162
  * ```ts
114
163
  * import { createDatabase } from "lora-node";
115
164
  *
116
- * const inMemory = await createDatabase(); // in-memory
117
- * const persistent = await createDatabase("./app"); // persistent: pass a directory string
165
+ * const inMemory = await createDatabase(); // in-memory
166
+ * const named = await createDatabase("app"); // named in-memory
167
+ * const persistent = await createDatabase("app", {
168
+ * databaseDir: "./data",
169
+ * }); // ./data/app.loradb
118
170
  * ```
119
171
  *
120
- * If you want persistence, pass a directory string. The string is treated
121
- * as a WAL directory path verbatim. Relative paths resolve from the
122
- * current working directory.
172
+ * If you want persistence, pass `databaseDir`. The database name is validated
173
+ * and resolved under `databaseDir`, appending `.loradb` to the basename when
174
+ * needed. Relative paths resolve from the current working directory.
123
175
  *
124
176
  * Each call returns an independent graph — no shared state between instances.
125
177
  */
126
- export declare function createDatabase(walDir?: string): Promise<Database>;
178
+ export declare function createDatabase(databaseName?: string, options?: CreateDatabaseOptions): Promise<Database>;
127
179
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../ts/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,SAAS,EACT,WAAW,EACZ,MAAM,YAAY,CAAC;AAOpB,QAAA,MAAM,cAAc,EAAE,cAAc,aAAa,EAAE,QAA0B,CAAC;AAE9E,cAAc,YAAY,CAAC;AAE3B;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,cAAM,YAAY;;gBAGJ,KAAK,EAAE,YAAY,CAAC,OAAO,cAAc,CAAC;IAItD;;;;OAIG;IACG,OAAO,CACX,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAC/D,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAS9D,sEAAsE;IAChE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,8CAA8C;IACxC,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAQlC,sDAAsD;IAChD,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ1C;;;;;OAKG;IACH,OAAO,IAAI,IAAI;IAQf;;;;;;;;OAQG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAQvD;;;;OAIG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAOxD;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,QAAQ,GAAG,YAAY,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAQvE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../ts/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * shapes defined in the shared TS contract (`crates/shared-ts/types.ts`).
10
10
  *
11
11
  * **Initialization is async-only.** The canonical entry point is
12
- * `createDatabase(...)`, optionally with a WAL directory path. There is no
12
+ * `createDatabase(...)`, optionally with archive-backed persistence. There is no
13
13
  * synchronous constructor. See the docs at
14
14
  * https://loradb.com/docs/getting-started/node for the full rationale.
15
15
  */
@@ -32,23 +32,190 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
32
32
  };
33
33
  Object.defineProperty(exports, "__esModule", { value: true });
34
34
  exports.createDatabase = createDatabase;
35
+ const node_buffer_1 = require("node:buffer");
36
+ const node_stream_1 = require("node:stream");
37
+ const node_url_1 = require("node:url");
35
38
  const types_js_1 = require("./types.js");
36
39
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
37
40
  // @ts-ignore - resolved at runtime via native.js loader
38
41
  const native_js_1 = __importDefault(require("./native.js"));
39
42
  const NativeDatabase = native_js_1.default.Database;
40
43
  __exportStar(require("./types.js"), exports);
44
+ class NativeRowStream {
45
+ #inner;
46
+ #streamId;
47
+ #closed = false;
48
+ constructor(inner, streamId) {
49
+ this.#inner = inner;
50
+ this.#streamId = streamId;
51
+ }
52
+ [Symbol.asyncIterator]() {
53
+ return this;
54
+ }
55
+ columns() {
56
+ try {
57
+ return this.#inner.streamColumns(this.#streamId);
58
+ }
59
+ catch (err) {
60
+ throw (0, types_js_1.wrapError)(err);
61
+ }
62
+ }
63
+ async next() {
64
+ if (this.#closed) {
65
+ return { done: true, value: undefined };
66
+ }
67
+ try {
68
+ const row = this.#inner.streamNext(this.#streamId);
69
+ if (row === null) {
70
+ this.#closed = true;
71
+ return { done: true, value: undefined };
72
+ }
73
+ return { done: false, value: row };
74
+ }
75
+ catch (err) {
76
+ this.#closed = true;
77
+ throw (0, types_js_1.wrapError)(err);
78
+ }
79
+ }
80
+ async return() {
81
+ this.close();
82
+ return { done: true, value: undefined };
83
+ }
84
+ async toArray() {
85
+ const rows = [];
86
+ for (;;) {
87
+ const next = await this.next();
88
+ if (next.done) {
89
+ return rows;
90
+ }
91
+ rows.push(next.value);
92
+ }
93
+ }
94
+ close() {
95
+ if (this.#closed)
96
+ return;
97
+ this.#closed = true;
98
+ try {
99
+ this.#inner.streamClose(this.#streamId);
100
+ }
101
+ catch (err) {
102
+ throw (0, types_js_1.wrapError)(err);
103
+ }
104
+ }
105
+ }
106
+ function isFetchUrl(url) {
107
+ return url.protocol === "http:" || url.protocol === "https:" || url.protocol === "data:";
108
+ }
109
+ function stringToUrl(value) {
110
+ try {
111
+ return new URL(value);
112
+ }
113
+ catch {
114
+ return null;
115
+ }
116
+ }
117
+ function bytesToUint8Array(bytes) {
118
+ if (bytes instanceof Uint8Array) {
119
+ return bytes;
120
+ }
121
+ return new Uint8Array(bytes);
122
+ }
123
+ function snapshotChunkToBuffer(chunk) {
124
+ return typeof chunk === "string"
125
+ ? node_buffer_1.Buffer.from(chunk)
126
+ : node_buffer_1.Buffer.from(bytesToUint8Array(chunk));
127
+ }
128
+ function resolveNodeSnapshotPath(path) {
129
+ if (path instanceof URL) {
130
+ if (path.protocol !== "file:") {
131
+ throw new Error(`LORA_ERROR: unsupported snapshot save URL protocol '${path.protocol}'`);
132
+ }
133
+ return (0, node_url_1.fileURLToPath)(path);
134
+ }
135
+ return path;
136
+ }
137
+ async function fetchSnapshotBytes(url) {
138
+ const res = await fetch(url);
139
+ if (!res.ok) {
140
+ throw new Error(`LORA_ERROR: snapshot fetch failed (${res.status} ${res.statusText})`);
141
+ }
142
+ return node_buffer_1.Buffer.from(await res.arrayBuffer());
143
+ }
144
+ function isReadableStream(source) {
145
+ return typeof source.getReader === "function";
146
+ }
147
+ function isAsyncIterable(source) {
148
+ return typeof source[Symbol.asyncIterator] === "function";
149
+ }
150
+ async function readableStreamToBuffer(stream) {
151
+ const reader = stream.getReader();
152
+ const chunks = [];
153
+ try {
154
+ for (;;) {
155
+ const { done, value } = await reader.read();
156
+ if (done) {
157
+ return node_buffer_1.Buffer.concat(chunks);
158
+ }
159
+ chunks.push(snapshotChunkToBuffer(value));
160
+ }
161
+ }
162
+ finally {
163
+ reader.releaseLock();
164
+ }
165
+ }
166
+ async function asyncIterableToBuffer(stream) {
167
+ const chunks = [];
168
+ for await (const chunk of stream) {
169
+ chunks.push(snapshotChunkToBuffer(chunk));
170
+ }
171
+ return node_buffer_1.Buffer.concat(chunks);
172
+ }
173
+ async function resolveNodeSnapshotSource(source) {
174
+ if (source instanceof URL) {
175
+ if (source.protocol === "file:") {
176
+ return (0, node_url_1.fileURLToPath)(source);
177
+ }
178
+ if (isFetchUrl(source)) {
179
+ return fetchSnapshotBytes(source);
180
+ }
181
+ throw new Error(`LORA_ERROR: unsupported snapshot URL protocol '${source.protocol}'`);
182
+ }
183
+ if (typeof source === "string") {
184
+ const url = stringToUrl(source);
185
+ if (!url) {
186
+ return source;
187
+ }
188
+ if (url.protocol === "file:") {
189
+ return (0, node_url_1.fileURLToPath)(url);
190
+ }
191
+ if (isFetchUrl(url)) {
192
+ return fetchSnapshotBytes(url);
193
+ }
194
+ return source;
195
+ }
196
+ if (isReadableStream(source)) {
197
+ return readableStreamToBuffer(source);
198
+ }
199
+ if (source instanceof node_stream_1.Readable) {
200
+ return asyncIterableToBuffer(source);
201
+ }
202
+ if (isAsyncIterable(source)) {
203
+ return asyncIterableToBuffer(source);
204
+ }
205
+ return node_buffer_1.Buffer.from(bytesToUint8Array(source));
206
+ }
41
207
  /**
42
208
  * Lora graph database instance.
43
209
  *
44
210
  * Obtained exclusively via `createDatabase()`. There is no public
45
211
  * constructor and no synchronous factory. With no args the instance is
46
- * purely in-memory; with a WAL directory path it replays committed WAL
47
- * state from disk before serving queries.
212
+ * purely in-memory; with a database name and `databaseDir` it replays committed
213
+ * WAL state from the serialized `.loradb` path under `databaseDir` before
214
+ * serving queries.
48
215
  *
49
216
  * Instances are independent — each owns its own in-memory graph. Multiple
50
- * concurrent `execute()` calls against one instance run one at a time
51
- * (serialised on the store mutex) but none of them block the event loop.
217
+ * concurrent read-only `execute()` calls against one instance can share
218
+ * the store read lock; writes serialize without blocking the event loop.
52
219
  */
53
220
  class DatabaseImpl {
54
221
  #inner;
@@ -69,6 +236,41 @@ class DatabaseImpl {
69
236
  throw (0, types_js_1.wrapError)(err);
70
237
  }
71
238
  }
239
+ /**
240
+ * Return an async row iterator for a query.
241
+ *
242
+ * The binding exposes the same `for await` shape as the Rust stream API.
243
+ * Rows are materialized by the native `execute()` promise today, then
244
+ * yielded one at a time to JS consumers.
245
+ */
246
+ stream(query, params) {
247
+ try {
248
+ const streamId = this.#inner.openStream(query, params ?? null);
249
+ return new NativeRowStream(this.#inner, streamId);
250
+ }
251
+ catch (err) {
252
+ throw (0, types_js_1.wrapError)(err);
253
+ }
254
+ }
255
+ /** Alias for `stream()`, useful when naming the row-level API explicitly. */
256
+ rows(query, params) {
257
+ return this.stream(query, params);
258
+ }
259
+ /**
260
+ * Execute a statement batch inside one native transaction.
261
+ *
262
+ * Results are returned in statement order. If any statement fails, the
263
+ * native transaction is dropped before commit and all prior writes in the
264
+ * batch are rolled back.
265
+ */
266
+ async transaction(statements, mode = "read_write") {
267
+ try {
268
+ return (await this.#inner.transaction(statements, mode));
269
+ }
270
+ catch (err) {
271
+ throw (0, types_js_1.wrapError)(err);
272
+ }
273
+ }
72
274
  /** Drop every node and relationship. Constant-time under the hood. */
73
275
  async clear() {
74
276
  try {
@@ -99,7 +301,7 @@ class DatabaseImpl {
99
301
  /**
100
302
  * Release the native database handle. Idempotent.
101
303
  *
102
- * Call this when a WAL-backed database needs to be reopened in the same
304
+ * Call this when an archive-backed database needs to be reopened in the same
103
305
  * process. New operations after disposal reject with `database is closed`.
104
306
  */
105
307
  dispose() {
@@ -111,17 +313,44 @@ class DatabaseImpl {
111
313
  }
112
314
  }
113
315
  /**
114
- * Save the graph to a snapshot file. Writes atomically via a `.tmp` +
115
- * rename dance — the target path is only replaced once the full payload
116
- * has been written and fsync'd.
316
+ * Save the graph as a snapshot.
117
317
  *
118
- * Synchronous in the native layer (point-in-time consistency requires
119
- * holding the store mutex for the duration of the save); the returned
120
- * Promise resolves immediately once the save returns.
318
+ * - `saveSnapshot(path)` and `saveSnapshot({ format: "path", path })`
319
+ * write atomically to a local file and return `SnapshotMeta`.
320
+ * - `saveSnapshot("binary")` / `{ format: "binary" }` return a `Buffer`.
321
+ * - `saveSnapshot("base64")` / `{ format: "base64" }` return base64 text.
121
322
  */
122
- async saveSnapshot(path) {
323
+ async saveSnapshot(target) {
324
+ try {
325
+ if (target === "binary" || (typeof target === "object"
326
+ && !(target instanceof URL)
327
+ && target.format === "binary")) {
328
+ return this.saveSnapshotToBytes();
329
+ }
330
+ if (target === "base64" || (typeof target === "object"
331
+ && !(target instanceof URL)
332
+ && target.format === "base64")) {
333
+ return (await this.saveSnapshotToBytes()).toString("base64");
334
+ }
335
+ let path;
336
+ if (typeof target === "object" && !(target instanceof URL)) {
337
+ if (target.format !== "path") {
338
+ throw new Error(`LORA_ERROR: unsupported snapshot save format '${target.format}'`);
339
+ }
340
+ path = target.path;
341
+ }
342
+ else {
343
+ path = target;
344
+ }
345
+ return this.#inner.saveSnapshot(resolveNodeSnapshotPath(path));
346
+ }
347
+ catch (err) {
348
+ throw (0, types_js_1.wrapError)(err);
349
+ }
350
+ }
351
+ async saveSnapshotToBytes() {
123
352
  try {
124
- return this.#inner.saveSnapshot(path);
353
+ return this.#inner.saveSnapshotToBytes();
125
354
  }
126
355
  catch (err) {
127
356
  throw (0, types_js_1.wrapError)(err);
@@ -129,12 +358,24 @@ class DatabaseImpl {
129
358
  }
130
359
  /**
131
360
  * Replace the current graph state with a snapshot loaded from `path`.
132
- * Concurrent `execute()` calls block on the store mutex until the load
133
- * completes.
361
+ * Concurrent `execute()` calls block on the store write lock until the
362
+ * load completes.
134
363
  */
135
- async loadSnapshot(path) {
364
+ async loadSnapshot(source) {
365
+ try {
366
+ const resolved = await resolveNodeSnapshotSource(source);
367
+ if (typeof resolved === "string") {
368
+ return this.#inner.loadSnapshot(resolved);
369
+ }
370
+ return this.#inner.loadSnapshotFromBytes(resolved);
371
+ }
372
+ catch (err) {
373
+ throw (0, types_js_1.wrapError)(err);
374
+ }
375
+ }
376
+ async loadSnapshotFromBytes(bytes) {
136
377
  try {
137
- return this.#inner.loadSnapshot(path);
378
+ return this.#inner.loadSnapshotFromBytes(node_buffer_1.Buffer.from(bytesToUint8Array(bytes)));
138
379
  }
139
380
  catch (err) {
140
381
  throw (0, types_js_1.wrapError)(err);
@@ -163,19 +404,24 @@ class DatabaseImpl {
163
404
  * ```ts
164
405
  * import { createDatabase } from "lora-node";
165
406
  *
166
- * const inMemory = await createDatabase(); // in-memory
167
- * const persistent = await createDatabase("./app"); // persistent: pass a directory string
407
+ * const inMemory = await createDatabase(); // in-memory
408
+ * const named = await createDatabase("app"); // named in-memory
409
+ * const persistent = await createDatabase("app", {
410
+ * databaseDir: "./data",
411
+ * }); // ./data/app.loradb
168
412
  * ```
169
413
  *
170
- * If you want persistence, pass a directory string. The string is treated
171
- * as a WAL directory path verbatim. Relative paths resolve from the
172
- * current working directory.
414
+ * If you want persistence, pass `databaseDir`. The database name is validated
415
+ * and resolved under `databaseDir`, appending `.loradb` to the basename when
416
+ * needed. Relative paths resolve from the current working directory.
173
417
  *
174
418
  * Each call returns an independent graph — no shared state between instances.
175
419
  */
176
- async function createDatabase(walDir) {
420
+ async function createDatabase(databaseName, options = {}) {
177
421
  try {
178
- return new DatabaseImpl(walDir === undefined ? new NativeDatabase() : new NativeDatabase(walDir));
422
+ return new DatabaseImpl(databaseName === undefined
423
+ ? new NativeDatabase()
424
+ : new NativeDatabase(databaseName, options.databaseDir ?? null));
179
425
  }
180
426
  catch (err) {
181
427
  throw (0, types_js_1.wrapError)(err);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../ts/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../ts/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loradb/lora-node",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Node.js / TypeScript bindings for the Lora in-memory graph database",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "LoraDB, Inc.",
@@ -89,10 +89,10 @@
89
89
  "vitest": "^2.1.1"
90
90
  },
91
91
  "optionalDependencies": {
92
- "@loradb/lora-node-linux-x64-gnu": "0.4.0",
93
- "@loradb/lora-node-linux-arm64-gnu": "0.4.0",
94
- "@loradb/lora-node-darwin-x64": "0.4.0",
95
- "@loradb/lora-node-darwin-arm64": "0.4.0",
96
- "@loradb/lora-node-win32-x64-msvc": "0.4.0"
92
+ "@loradb/lora-node-linux-x64-gnu": "0.5.1",
93
+ "@loradb/lora-node-linux-arm64-gnu": "0.5.1",
94
+ "@loradb/lora-node-darwin-x64": "0.5.1",
95
+ "@loradb/lora-node-darwin-arm64": "0.5.1",
96
+ "@loradb/lora-node-win32-x64-msvc": "0.5.1"
97
97
  }
98
98
  }
package/ts/native.d.ts CHANGED
@@ -19,18 +19,33 @@ export interface NativeSnapshotMeta {
19
19
  }
20
20
 
21
21
  export declare class Database {
22
- constructor(walDir?: string | null);
22
+ constructor(databaseName?: string | null, databaseDir?: string | null);
23
23
  /** Non-blocking: runs on the libuv threadpool, returns a Promise. */
24
24
  execute(
25
25
  query: string,
26
26
  params?: Record<string, unknown> | null,
27
27
  ): Promise<NativeQueryResult>;
28
+ openStream(
29
+ query: string,
30
+ params?: Record<string, unknown> | null,
31
+ ): number;
32
+ streamColumns(streamId: number): string[];
33
+ streamNext(streamId: number): Record<string, unknown> | null;
34
+ streamClose(streamId: number): void;
35
+ transaction(
36
+ statements: Array<{ query: string; params?: Record<string, unknown> | null }>,
37
+ mode?: "read_write" | "read_only" | "readwrite" | "readonly" | "rw" | "ro" | null,
38
+ ): Promise<NativeQueryResult[]>;
28
39
  clear(): void;
29
40
  nodeCount(): number;
30
41
  relationshipCount(): number;
31
42
  dispose(): void;
32
- /** Atomic save. Synchronous under the store mutex. */
43
+ /** Atomic save. Synchronous under the store read lock. */
33
44
  saveSnapshot(path: string): NativeSnapshotMeta;
45
+ /** Serialize the current graph into snapshot bytes. */
46
+ saveSnapshotToBytes(): Buffer;
34
47
  /** Replace the current graph with the snapshot at `path`. */
35
48
  loadSnapshot(path: string): NativeSnapshotMeta;
49
+ /** Replace the current graph with snapshot bytes. */
50
+ loadSnapshotFromBytes(bytes: Uint8Array | Buffer): NativeSnapshotMeta;
36
51
  }