@flowot/nx-pn-storage-sqlite 0.3.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/lib/index.d.ts ADDED
@@ -0,0 +1,63 @@
1
+ /**
2
+ * SQLite storage backend: one database file hosts every routed unit,
3
+ * document-per-row (`key TEXT` / `value TEXT` JSON). This is a PURE LIBRARY
4
+ * (no cordis): the nx-pn host owns assembly — `new SqliteStorageBackend({ path,
5
+ * journalMode })` registers the instance under backend name `sqlite` on the
6
+ * storage hub, and on teardown unregisters first, then calls `close()`.
7
+ * @module @flowot/nx-pn-storage-sqlite
8
+ */
9
+ import type { KvFacet, StorageBackend } from '@flowot/nx-pn-storage';
10
+ import { type JournalMode } from './schema.js';
11
+ export { STORAGE_SQLITE_SCHEMA_VERSION, type JournalMode } from './schema.js';
12
+ /**
13
+ * Backend configuration. In dsh this package was a cordis plugin whose
14
+ * `Config` was validated by schemastery at load time (with `journalMode`
15
+ * defaulting to `wal`); here validation/defaulting is the caller's
16
+ * responsibility and only the plain interface remains.
17
+ */
18
+ export interface Config {
19
+ /**
20
+ * Filesystem path to the SQLite database file. The special value `:memory:`
21
+ * opens an in-process database (tests). On filesystems with POSIX modes,
22
+ * missing directories and databases are created owner-only; existing path
23
+ * modes are preserved. Filesystem setup errors other than an existing
24
+ * database fail the open. The backend does not protect confidentiality or
25
+ * integrity when another principal can replace the database entry in its
26
+ * parent directory.
27
+ */
28
+ path: string;
29
+ /**
30
+ * SQLite `journal_mode` pragma. `wal` (the default) suits local disks; pick
31
+ * a rollback-journal mode (`delete`/`truncate`/`persist`) on filesystems
32
+ * where WAL's shared-memory files do not work (network mounts). See
33
+ * {@link JournalMode}.
34
+ */
35
+ journalMode?: JournalMode;
36
+ }
37
+ /**
38
+ * The SQLite {@link StorageBackend}. Owns one `DatabaseSync` connection and
39
+ * the open-unit table; `kv.open` validates names, enforces the per-unit
40
+ * version stamp in `units`, and ensures the unit's record tables.
41
+ */
42
+ export declare class SqliteStorageBackend implements StorageBackend {
43
+ /** The key-value facet; the only shape this backend serves. */
44
+ readonly kv: KvFacet;
45
+ private readonly ready;
46
+ /** Open (or still-opening) units by name; presence is the double-open guard. */
47
+ private readonly units;
48
+ private closing;
49
+ /**
50
+ * @param config - Backend configuration.
51
+ */
52
+ constructor(config: Config);
53
+ private openUnit;
54
+ private materializeUnit;
55
+ /**
56
+ * Close every open unit and release the database. Idempotent; concurrent
57
+ * and repeated calls resolve once teardown finishes.
58
+ * @returns resolution after the medium is released.
59
+ */
60
+ close(): Promise<void>;
61
+ private doClose;
62
+ }
63
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,OAAO,EAA4B,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC9F,OAAO,EAAiC,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AAG7E,OAAO,EAAE,6BAA6B,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAA;AAE7E;;;;;GAKG;AACH,MAAM,WAAW,MAAM;IACrB;;;;;;;;OAQG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;CAC1B;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IACzD,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAoD;IAExE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAC7C,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2C;IACjE,OAAO,CAAC,OAAO,CAA2B;IAE1C;;OAEG;gBACS,MAAM,EAAE,MAAM;IAU1B,OAAO,CAAC,QAAQ;YAuBF,eAAe;IA2B7B;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAKR,OAAO;CAetB"}
package/lib/index.js ADDED
@@ -0,0 +1,107 @@
1
+ /**
2
+ * SQLite storage backend: one database file hosts every routed unit,
3
+ * document-per-row (`key TEXT` / `value TEXT` JSON). This is a PURE LIBRARY
4
+ * (no cordis): the nx-pn host owns assembly — `new SqliteStorageBackend({ path,
5
+ * journalMode })` registers the instance under backend name `sqlite` on the
6
+ * storage hub, and on teardown unregisters first, then calls `close()`.
7
+ * @module @flowot/nx-pn-storage-sqlite
8
+ */
9
+ import { StorageError, UNIT_NAME_RE } from '@flowot/nx-pn-storage';
10
+ import { openDatabase, recordTableName } from './schema.js';
11
+ import { SqliteKvUnit } from './unit.js';
12
+ export { STORAGE_SQLITE_SCHEMA_VERSION } from './schema.js';
13
+ /**
14
+ * The SQLite {@link StorageBackend}. Owns one `DatabaseSync` connection and
15
+ * the open-unit table; `kv.open` validates names, enforces the per-unit
16
+ * version stamp in `units`, and ensures the unit's record tables.
17
+ */
18
+ export class SqliteStorageBackend {
19
+ /** The key-value facet; the only shape this backend serves. */
20
+ kv = { open: descriptor => this.openUnit(descriptor) };
21
+ ready;
22
+ /** Open (or still-opening) units by name; presence is the double-open guard. */
23
+ units = new Map();
24
+ closing;
25
+ /**
26
+ * @param config - Backend configuration.
27
+ */
28
+ constructor(config) {
29
+ // The dsh loader applied the schemastery `default('wal')` before the
30
+ // constructor ran; with that loader gone, the default is applied here.
31
+ this.ready = openDatabase(config.path, config.journalMode ?? 'wal');
32
+ // Mark the rejection handled: every primitive re-awaits `ready`, so an
33
+ // open failure still surfaces to each caller; this guard only prevents an
34
+ // unhandled-rejection crash when the failure precedes the first use.
35
+ this.ready.catch(() => { });
36
+ }
37
+ openUnit(descriptor) {
38
+ if (this.closing !== undefined) {
39
+ return Promise.reject(new StorageError('closed', 'sqlite storage backend is closed'));
40
+ }
41
+ if (!UNIT_NAME_RE.test(descriptor.name)) {
42
+ return Promise.reject(new Error(`kv unit name '${descriptor.name}' violates ${UNIT_NAME_RE}`));
43
+ }
44
+ for (const table of descriptor.tables) {
45
+ if (!UNIT_NAME_RE.test(table)) {
46
+ return Promise.reject(new Error(`kv table name '${table}' in unit '${descriptor.name}' violates ${UNIT_NAME_RE}`));
47
+ }
48
+ }
49
+ if (this.units.has(descriptor.name)) {
50
+ return Promise.reject(new Error(`kv unit '${descriptor.name}' is already open (double-open is a caller bug)`));
51
+ }
52
+ // Reserve the name synchronously so a concurrent second open of the same
53
+ // name rejects instead of racing past the guard during the awaits below.
54
+ const pending = this.materializeUnit(descriptor);
55
+ this.units.set(descriptor.name, pending);
56
+ pending.catch(() => this.units.delete(descriptor.name));
57
+ return pending;
58
+ }
59
+ async materializeUnit(descriptor) {
60
+ const db = await this.ready;
61
+ const row = db.prepare('SELECT version FROM units WHERE name = ?').get(descriptor.name);
62
+ if (row === undefined) {
63
+ db.prepare('INSERT INTO units (name, version) VALUES (?, ?)').run(descriptor.name, descriptor.version);
64
+ }
65
+ else if (row.version !== descriptor.version) {
66
+ throw new StorageError('version-mismatch', `kv unit '${descriptor.name}' is stamped version ${row.version} on the medium, incompatible with descriptor version ${descriptor.version}`);
67
+ }
68
+ for (const table of descriptor.tables) {
69
+ // Both segments passed UNIT_NAME_RE, so the identifier is safe in DDL.
70
+ db.exec(`
71
+ CREATE TABLE IF NOT EXISTS "${recordTableName(descriptor.name, table)}" (
72
+ key TEXT PRIMARY KEY,
73
+ value TEXT NOT NULL
74
+ ) STRICT
75
+ `);
76
+ }
77
+ return new SqliteKvUnit(db, descriptor, () => {
78
+ this.units.delete(descriptor.name);
79
+ });
80
+ }
81
+ /**
82
+ * Close every open unit and release the database. Idempotent; concurrent
83
+ * and repeated calls resolve once teardown finishes.
84
+ * @returns resolution after the medium is released.
85
+ */
86
+ close() {
87
+ this.closing ??= this.doClose();
88
+ return this.closing;
89
+ }
90
+ async doClose() {
91
+ let db;
92
+ try {
93
+ db = await this.ready;
94
+ }
95
+ catch {
96
+ // The medium never opened; that failure already rejected the opener and
97
+ // every unit call, so there is nothing left to release here.
98
+ return;
99
+ }
100
+ for (const pending of [...this.units.values()]) {
101
+ const unit = await pending.catch(() => undefined);
102
+ await unit?.close();
103
+ }
104
+ db.close();
105
+ }
106
+ }
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Schema + open-time helpers for the SQLite storage backend: the physical
3
+ * layout version, the database open/configure sequence (permissions, pragmas,
4
+ * version stamp/reject), and the unit metadata tables. Unit record tables are
5
+ * created per descriptor in `unit.ts`.
6
+ * @module @flowot/nx-pn-storage-sqlite/schema
7
+ */
8
+ import { DatabaseSync } from 'node:sqlite';
9
+ /**
10
+ * The on-disk physical layout version, stored in `PRAGMA user_version`.
11
+ * Orthogonal to each unit's own `version` (stamped per unit in the `units`
12
+ * row). Bumped only on a breaking change to the table layout; any other
13
+ * stamped version rejects — this unreleased format has no migrations.
14
+ */
15
+ export declare const STORAGE_SQLITE_SCHEMA_VERSION = 1;
16
+ /**
17
+ * Journal modes the backend will run under. `wal` is the default; the
18
+ * rollback-journal modes (`delete`/`truncate`/`persist`) exist for
19
+ * filesystems where WAL's shared-memory files do not work (network mounts).
20
+ * `memory`/`off` are excluded: dropping journal durability silently
21
+ * contradicts the durability clause of the KV backend contract.
22
+ */
23
+ export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist';
24
+ /**
25
+ * Open the database and apply its schema and pragmas. Missing directories and
26
+ * database files are created owner-only (`:memory:` skips filesystem setup).
27
+ * A zero `user_version` is stamped with {@link STORAGE_SQLITE_SCHEMA_VERSION};
28
+ * every other non-current version rejects rather than being migrated in place.
29
+ * @param path - the SQLite database file to open, or `:memory:`.
30
+ * @param journalMode - validated journal pragma.
31
+ * @returns the open handle with pragmas applied and the unit metadata tables ensured.
32
+ */
33
+ export declare function openDatabase(path: string, journalMode: JournalMode): Promise<DatabaseSync>;
34
+ /**
35
+ * Physical table name for one unit table. Both segments are validated against
36
+ * `UNIT_NAME_RE` before reaching this, so the result is safe to interpolate
37
+ * into DDL and prepared-statement text.
38
+ * @param unit - Validated unit name.
39
+ * @param table - Validated table name.
40
+ * @returns the `u_<unit>_<table>` identifier.
41
+ */
42
+ export declare function recordTableName(unit: string, table: string): string;
43
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAK1C;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,IAAI,CAAA;AAE9C;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAA;AAsBnE;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAchG;AAmCD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE"}
package/lib/schema.js ADDED
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Schema + open-time helpers for the SQLite storage backend: the physical
3
+ * layout version, the database open/configure sequence (permissions, pragmas,
4
+ * version stamp/reject), and the unit metadata tables. Unit record tables are
5
+ * created per descriptor in `unit.ts`.
6
+ * @module @flowot/nx-pn-storage-sqlite/schema
7
+ */
8
+ import { DatabaseSync } from 'node:sqlite';
9
+ import { mkdir, open } from 'node:fs/promises';
10
+ import { dirname, resolve } from 'node:path';
11
+ import { StorageError } from '@flowot/nx-pn-storage';
12
+ /**
13
+ * The on-disk physical layout version, stored in `PRAGMA user_version`.
14
+ * Orthogonal to each unit's own `version` (stamped per unit in the `units`
15
+ * row). Bumped only on a breaking change to the table layout; any other
16
+ * stamped version rejects — this unreleased format has no migrations.
17
+ */
18
+ export const STORAGE_SQLITE_SCHEMA_VERSION = 1;
19
+ /* jscpd:ignore-start -- deliberately mirrors the session-query-sqlite open
20
+ sequence. Each package owns a distinct database identity and schema, so a
21
+ shared helper would couple otherwise independent storage providers (see the
22
+ domain KV storage Agent Note's reuse audit). */
23
+ /**
24
+ * Exclusively create a missing database file with owner-only permissions.
25
+ * Existing files retain their modes, and errors other than `EEXIST` propagate.
26
+ * `DatabaseSync` reopens by path, so this does not protect confidentiality or
27
+ * integrity when another principal can replace the database entry in its
28
+ * parent directory.
29
+ */
30
+ async function createDatabaseFile(path) {
31
+ try {
32
+ const handle = await open(path, 'wx', 0o600);
33
+ await handle.close();
34
+ }
35
+ catch (error) {
36
+ if (error.code !== 'EEXIST')
37
+ throw error;
38
+ }
39
+ }
40
+ /**
41
+ * Open the database and apply its schema and pragmas. Missing directories and
42
+ * database files are created owner-only (`:memory:` skips filesystem setup).
43
+ * A zero `user_version` is stamped with {@link STORAGE_SQLITE_SCHEMA_VERSION};
44
+ * every other non-current version rejects rather than being migrated in place.
45
+ * @param path - the SQLite database file to open, or `:memory:`.
46
+ * @param journalMode - validated journal pragma.
47
+ * @returns the open handle with pragmas applied and the unit metadata tables ensured.
48
+ */
49
+ export async function openDatabase(path, journalMode) {
50
+ const actual = path === ':memory:' ? path : resolve(path);
51
+ if (actual !== ':memory:') {
52
+ await mkdir(dirname(actual), { recursive: true, mode: 0o700 });
53
+ await createDatabaseFile(actual);
54
+ }
55
+ const db = new DatabaseSync(actual);
56
+ try {
57
+ configureDatabase(db, actual, journalMode);
58
+ return db;
59
+ }
60
+ catch (error) {
61
+ db.close();
62
+ throw error;
63
+ }
64
+ }
65
+ function configureDatabase(db, path, journalMode) {
66
+ db.exec('PRAGMA foreign_keys = ON');
67
+ // The validated union is safe to interpolate into a non-bindable PRAGMA.
68
+ db.exec(`PRAGMA journal_mode = ${journalMode.toUpperCase()}`);
69
+ // `PRAGMA user_version` always returns exactly one row { user_version }.
70
+ const { user_version: onDisk } = db.prepare('PRAGMA user_version').get();
71
+ if (onDisk !== 0 && onDisk !== STORAGE_SQLITE_SCHEMA_VERSION) {
72
+ throw new StorageError('version-mismatch', `storage database at "${path}" has schema version ${onDisk}, incompatible with this build (${STORAGE_SQLITE_SCHEMA_VERSION})`);
73
+ }
74
+ /* jscpd:ignore-end */
75
+ db.exec(`
76
+ CREATE TABLE IF NOT EXISTS units (
77
+ name TEXT PRIMARY KEY,
78
+ version INTEGER NOT NULL
79
+ ) STRICT
80
+ `);
81
+ db.exec(`
82
+ CREATE TABLE IF NOT EXISTS unit_globals (
83
+ unit TEXT PRIMARY KEY REFERENCES units(name),
84
+ value TEXT NOT NULL
85
+ ) STRICT
86
+ `);
87
+ if (onDisk === 0) {
88
+ // Stamp fresh databases LAST: the stamp asserts the layout is complete,
89
+ // so a failure above must leave the medium unstamped (a re-open after
90
+ // the obstruction is cleared retries materialization from scratch).
91
+ db.exec(`PRAGMA user_version = ${STORAGE_SQLITE_SCHEMA_VERSION}`);
92
+ }
93
+ }
94
+ /**
95
+ * Physical table name for one unit table. Both segments are validated against
96
+ * `UNIT_NAME_RE` before reaching this, so the result is safe to interpolate
97
+ * into DDL and prepared-statement text.
98
+ * @param unit - Validated unit name.
99
+ * @param table - Validated table name.
100
+ * @returns the `u_<unit>_<table>` identifier.
101
+ */
102
+ export function recordTableName(unit, table) {
103
+ return `u_${unit}_${table}`;
104
+ }
105
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEpD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAA;AAW9C;;;kDAGkD;AAClD;;;;;;GAMG;AACH,KAAK,UAAU,kBAAkB,CAAC,IAAY;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;QAC5C,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAA;IACrE,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,WAAwB;IACvE,MAAM,MAAM,GAAG,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACzD,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;QAC1B,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9D,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAA;IACnC,IAAI,CAAC;QACH,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,CAAA;QAC1C,OAAO,EAAE,CAAA;IACX,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,EAAE,CAAC,KAAK,EAAE,CAAA;QACV,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAgB,EAAE,IAAY,EAAE,WAAwB;IACjF,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;IACnC,yEAAyE;IACzE,EAAE,CAAC,IAAI,CAAC,yBAAyB,WAAW,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IAC7D,yEAAyE;IACzE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAA8B,CAAA;IACpG,IAAI,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,6BAA6B,EAAE,CAAC;QAC7D,MAAM,IAAI,YAAY,CACpB,kBAAkB,EAClB,wBAAwB,IAAI,wBAAwB,MAAM,mCAAmC,6BAA6B,GAAG,CAC9H,CAAA;IACH,CAAC;IACD,sBAAsB;IACtB,EAAE,CAAC,IAAI,CAAC;;;;;GAKP,CAAC,CAAA;IACF,EAAE,CAAC,IAAI,CAAC;;;;;GAKP,CAAC,CAAA;IACF,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;QACjB,wEAAwE;QACxE,sEAAsE;QACtE,oEAAoE;QACpE,EAAE,CAAC,IAAI,CAAC,yBAAyB,6BAA6B,EAAE,CAAC,CAAA;IACnE,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,KAAa;IACzD,OAAO,KAAK,IAAI,IAAI,KAAK,EAAE,CAAA;AAC7B,CAAC"}
package/lib/unit.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * One opened SQLite KV unit: prepared per-table statements over the
3
+ * `u_<unit>_<table>` record tables plus this unit's row in the shared
4
+ * `unit_globals` table. Each primitive is a single statement, so atomicity
5
+ * comes from SQLite itself — no explicit transactions, and no write queue
6
+ * (write ordering is the caller's responsibility per the KV contract).
7
+ * @module @flowot/nx-pn-storage-sqlite/unit
8
+ */
9
+ import type { DatabaseSync } from 'node:sqlite';
10
+ import type { KvUnit, KvUnitDescriptor } from '@flowot/nx-pn-storage';
11
+ /**
12
+ * The SQLite {@link KvUnit}. Constructed by the backend AFTER the unit's
13
+ * record tables exist; statements are prepared once here and reused for every
14
+ * primitive. Values are stored as JSON text in the `value` column.
15
+ */
16
+ export declare class SqliteKvUnit implements KvUnit {
17
+ private readonly descriptor;
18
+ private readonly onClose;
19
+ private readonly tables;
20
+ private readonly globalUpsert;
21
+ private readonly globalSelect;
22
+ private closed;
23
+ /**
24
+ * @param db - Open database handle owned by the backend (never closed here).
25
+ * @param descriptor - Validated descriptor whose record tables already exist.
26
+ * @param onClose - Backend callback releasing this unit's open-name slot.
27
+ */
28
+ constructor(db: DatabaseSync, descriptor: KvUnitDescriptor, onClose: () => void);
29
+ loadAll(): Promise<{
30
+ tables: Record<string, Record<string, unknown>>;
31
+ global: unknown;
32
+ }>;
33
+ /** Parse one stored value column, mapping bad JSON to `malformed-medium`. */
34
+ private parseValue;
35
+ putRecord(table: string, key: string, value: unknown): Promise<void>;
36
+ deleteRecord(table: string, key: string): Promise<void>;
37
+ setGlobal(value: unknown): Promise<void>;
38
+ close(): Promise<void>;
39
+ /**
40
+ * Run one synchronous primitive behind the closed guard, mapping a throw to
41
+ * a rejection so the Promise-returning contract never throws synchronously.
42
+ */
43
+ private settle;
44
+ private ensureOpen;
45
+ private statementsFor;
46
+ }
47
+ //# sourceMappingURL=unit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit.d.ts","sourceRoot":"","sources":["../src/unit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAA;AAE9D,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAUrE;;;;GAIG;AACH,qBAAa,YAAa,YAAW,MAAM;IAavC,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAb1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2B;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2B;IACxD,OAAO,CAAC,MAAM,CAAQ;IAEtB;;;;OAIG;gBAED,EAAE,EAAE,YAAY,EACC,UAAU,EAAE,gBAAgB,EAC5B,OAAO,EAAE,MAAM,IAAI;IAwBtC,OAAO,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAqBxF,6EAA6E;IAC7E,OAAO,CAAC,UAAU;IAYlB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpE,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvD,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IASxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB;;;OAGG;IACH,OAAO,CAAC,MAAM;IAWd,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,aAAa;CAOtB"}
package/lib/unit.js ADDED
@@ -0,0 +1,131 @@
1
+ /**
2
+ * One opened SQLite KV unit: prepared per-table statements over the
3
+ * `u_<unit>_<table>` record tables plus this unit's row in the shared
4
+ * `unit_globals` table. Each primitive is a single statement, so atomicity
5
+ * comes from SQLite itself — no explicit transactions, and no write queue
6
+ * (write ordering is the caller's responsibility per the KV contract).
7
+ * @module @flowot/nx-pn-storage-sqlite/unit
8
+ */
9
+ import { StorageError } from '@flowot/nx-pn-storage';
10
+ import { recordTableName } from './schema.js';
11
+ /**
12
+ * The SQLite {@link KvUnit}. Constructed by the backend AFTER the unit's
13
+ * record tables exist; statements are prepared once here and reused for every
14
+ * primitive. Values are stored as JSON text in the `value` column.
15
+ */
16
+ export class SqliteKvUnit {
17
+ descriptor;
18
+ onClose;
19
+ tables = new Map();
20
+ globalUpsert;
21
+ globalSelect;
22
+ closed = false;
23
+ /**
24
+ * @param db - Open database handle owned by the backend (never closed here).
25
+ * @param descriptor - Validated descriptor whose record tables already exist.
26
+ * @param onClose - Backend callback releasing this unit's open-name slot.
27
+ */
28
+ constructor(db, descriptor, onClose) {
29
+ this.descriptor = descriptor;
30
+ this.onClose = onClose;
31
+ for (const table of descriptor.tables) {
32
+ // Both name segments are validated against UNIT_NAME_RE by the backend,
33
+ // so the physical identifier is safe to interpolate into statement text.
34
+ const physical = recordTableName(descriptor.name, table);
35
+ this.tables.set(table, {
36
+ upsert: db.prepare(`INSERT INTO "${physical}" (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`),
37
+ remove: db.prepare(`DELETE FROM "${physical}" WHERE key = ?`),
38
+ selectAll: db.prepare(`SELECT key, value FROM "${physical}"`),
39
+ });
40
+ }
41
+ this.globalUpsert = descriptor.hasGlobal
42
+ ? db.prepare('INSERT INTO unit_globals (unit, value) VALUES (?, ?) ON CONFLICT(unit) DO UPDATE SET value = excluded.value')
43
+ : undefined;
44
+ this.globalSelect = descriptor.hasGlobal
45
+ ? db.prepare('SELECT value FROM unit_globals WHERE unit = ?')
46
+ : undefined;
47
+ }
48
+ loadAll() {
49
+ return this.settle(() => {
50
+ const tables = {};
51
+ for (const [name, statements] of this.tables) {
52
+ // Null prototype: record keys are arbitrary strings, so '__proto__'
53
+ // must land as an own property instead of mutating the prototype.
54
+ const records = Object.create(null);
55
+ for (const row of statements.selectAll.all()) {
56
+ records[row.key] = this.parseValue(row.value, `table '${name}' key '${row.key}'`);
57
+ }
58
+ tables[name] = records;
59
+ }
60
+ let global = null;
61
+ if (this.globalSelect !== undefined) {
62
+ const row = this.globalSelect.get(this.descriptor.name);
63
+ if (row !== undefined)
64
+ global = this.parseValue(row.value, 'global slot');
65
+ }
66
+ return { tables, global };
67
+ });
68
+ }
69
+ /** Parse one stored value column, mapping bad JSON to `malformed-medium`. */
70
+ parseValue(text, slot) {
71
+ try {
72
+ return JSON.parse(text);
73
+ }
74
+ catch (error) {
75
+ throw new StorageError('malformed-medium', `kv unit '${this.descriptor.name}' holds unparsable JSON at ${slot}`, { cause: error });
76
+ }
77
+ }
78
+ putRecord(table, key, value) {
79
+ return this.settle(() => {
80
+ this.statementsFor(table).upsert.run(key, JSON.stringify(value));
81
+ });
82
+ }
83
+ deleteRecord(table, key) {
84
+ return this.settle(() => {
85
+ this.statementsFor(table).remove.run(key);
86
+ });
87
+ }
88
+ setGlobal(value) {
89
+ return this.settle(() => {
90
+ if (this.globalUpsert === undefined) {
91
+ throw new Error(`kv unit '${this.descriptor.name}' declared no global slot`);
92
+ }
93
+ this.globalUpsert.run(this.descriptor.name, JSON.stringify(value));
94
+ });
95
+ }
96
+ close() {
97
+ if (!this.closed) {
98
+ this.closed = true;
99
+ this.onClose();
100
+ }
101
+ return Promise.resolve();
102
+ }
103
+ /**
104
+ * Run one synchronous primitive behind the closed guard, mapping a throw to
105
+ * a rejection so the Promise-returning contract never throws synchronously.
106
+ */
107
+ settle(operation) {
108
+ try {
109
+ this.ensureOpen();
110
+ return Promise.resolve(operation());
111
+ }
112
+ catch (error) {
113
+ // Non-Error throws can only enter through JSON.stringify propagating a
114
+ // value's own toJSON throw; wrap those, preserve every real Error.
115
+ return Promise.reject(error instanceof Error ? error : new Error(String(error)));
116
+ }
117
+ }
118
+ ensureOpen() {
119
+ if (this.closed) {
120
+ throw new StorageError('closed', `kv unit '${this.descriptor.name}' is closed`);
121
+ }
122
+ }
123
+ statementsFor(table) {
124
+ const statements = this.tables.get(table);
125
+ if (statements === undefined) {
126
+ throw new Error(`kv unit '${this.descriptor.name}' declared no table '${table}'`);
127
+ }
128
+ return statements;
129
+ }
130
+ }
131
+ //# sourceMappingURL=unit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit.js","sourceRoot":"","sources":["../src/unit.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@flowot/nx-pn-storage-sqlite",
3
+ "version": "0.3.0",
4
+ "description": "SQLite storage backend (document-per-row KV) for the nx-pn storage hub, via node:sqlite (dsh storage-family port)",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/On-DevPlan/nx-pn.git",
12
+ "directory": "packages/storage/storage-sqlite"
13
+ },
14
+ "type": "module",
15
+ "main": "./lib/index.js",
16
+ "types": "./lib/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./lib/index.d.ts",
20
+ "default": "./lib/index.js"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
24
+ "files": [
25
+ "lib",
26
+ "!lib/*.tsbuildinfo"
27
+ ],
28
+ "dependencies": {
29
+ "@flowot/nx-pn-storage": "^0.3.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^22.7.0",
33
+ "typescript": "5.6.3",
34
+ "vitest": "^3.2.4",
35
+ "vite": "^6.0.0"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -b",
39
+ "test": "vitest run",
40
+ "test:watch": "vitest",
41
+ "lint": "tsc --noEmit"
42
+ }
43
+ }