dirsql 0.0.99-test.1775729890 → 0.1.2

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 ADDED
@@ -0,0 +1,45 @@
1
+ # `dirsql` (TypeScript SDK)
2
+
3
+ TypeScript SDK for `dirsql` -- napi-rs bindings wrapping the Rust core (`dirsql`).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add dirsql
9
+ ```
10
+
11
+ Requires a native build step (Rust toolchain). The native module is compiled during `pnpm build`.
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { DirSQL } from "dirsql";
17
+
18
+ const db = new DirSQL("/path/to/directory", [
19
+ {
20
+ ddl: "CREATE TABLE users (name TEXT, age INTEGER)",
21
+ glob: "data/*.json",
22
+ extract: (filePath, content) => JSON.parse(content),
23
+ },
24
+ ]);
25
+
26
+ const rows = db.query("SELECT * FROM users WHERE age > 25");
27
+ console.log(rows);
28
+ ```
29
+
30
+ ## Building
31
+
32
+ ```bash
33
+ pnpm install
34
+ pnpm build
35
+ ```
36
+
37
+ ## Testing
38
+
39
+ ```bash
40
+ pnpm test
41
+ ```
42
+
43
+ ## License
44
+
45
+ MIT
package/dirsql.node ADDED
Binary file
@@ -0,0 +1,105 @@
1
+ /** Definition of a SQL-indexed table backed by files on disk. */
2
+ export interface TableDef {
3
+ /** SQL DDL statement, e.g. `CREATE TABLE users (name TEXT, age INTEGER)`. */
4
+ ddl: string;
5
+ /** Glob pattern (relative to the DirSQL root) for files backing this table. */
6
+ glob: string;
7
+ /** Extract rows from a file's contents. Returns an array of row objects. */
8
+ extract: (filePath: string, content: string) => Record<string, unknown>[];
9
+ /** If true, reject rows with columns not declared in `ddl`. */
10
+ strict?: boolean;
11
+ }
12
+ /** A row-level event emitted by the file watcher. */
13
+ export interface RowEvent {
14
+ table: string;
15
+ action: "insert" | "update" | "delete" | "error";
16
+ row?: Record<string, unknown> | null;
17
+ oldRow?: Record<string, unknown> | null;
18
+ error?: string | null;
19
+ filePath?: string | null;
20
+ }
21
+ interface NativeDirSQL {
22
+ query(sql: string): Record<string, unknown>[];
23
+ startWatcher(): void;
24
+ pollEvents(timeoutMs: number): RowEvent[];
25
+ }
26
+ interface NativeDirSQLConstructor {
27
+ new (root: string, tables: TableDef[], ignore?: string[]): NativeDirSQL;
28
+ fromConfig(configPath: string): NativeDirSQL;
29
+ }
30
+ interface CoreModule {
31
+ DirSQL: NativeDirSQLConstructor;
32
+ }
33
+ /**
34
+ * **Test-only.** Replace the core module used by the SDK with a fake.
35
+ *
36
+ * This is an internal escape hatch for unit tests that want to mock the
37
+ * napi-rs binding layer without loading the real native binary. Passing
38
+ * `null` resets to the default (lazy native load on next access). Not
39
+ * part of the public API; do not use in application code.
40
+ */
41
+ export declare function __setCoreForTesting(fake: CoreModule | null): void;
42
+ /**
43
+ * Ephemeral SQL index over a local directory.
44
+ *
45
+ * Constructing a `DirSQL` scans `root`, matches files against each
46
+ * {@link TableDef}'s `glob`, extracts rows via `extract`, and builds an
47
+ * in-memory SQLite database. `query` / `startWatcher` / `pollEvents`
48
+ * are synchronous; {@link ready} and {@link watch} expose the same
49
+ * surface in an async-idiomatic shape so TypeScript consumers don't
50
+ * need a separate `AsyncDirSQL` class.
51
+ *
52
+ * ```ts
53
+ * const db = new DirSQL(root, tables);
54
+ * await db.ready;
55
+ * const rows = db.query("SELECT ...");
56
+ * for await (const event of db.watch()) { ... }
57
+ * ```
58
+ */
59
+ export declare class DirSQL {
60
+ /**
61
+ * Resolves once the initial directory scan has completed. Scanning
62
+ * runs synchronously inside the constructor, so this Promise is
63
+ * already resolved by the time the constructor returns; construction
64
+ * failures throw synchronously rather than surfacing here. Exposed
65
+ * as a Promise purely so consumers can write async-style code
66
+ * uniformly across SDKs.
67
+ */
68
+ readonly ready: Promise<void>;
69
+ private _inner;
70
+ constructor(root: string, tables: TableDef[], ignore?: string[]);
71
+ /**
72
+ * Load a {@link DirSQL} instance from a `.dirsql.toml` config file.
73
+ *
74
+ * The root directory is derived from the config file's parent. Tables
75
+ * are parsed using the built-in parser for each format declared in the
76
+ * config. No JS `extract` callback is required.
77
+ */
78
+ static fromConfig(configPath: string): DirSQL;
79
+ /** Execute a SQL query and return results as an array of row objects. */
80
+ query(sql: string): Record<string, unknown>[];
81
+ /**
82
+ * Start the file watcher. Must be called before {@link pollEvents}.
83
+ * Idempotent — safe to call multiple times.
84
+ */
85
+ startWatcher(): void;
86
+ /**
87
+ * Poll for file change events, blocking up to `timeoutMs` for the first
88
+ * event. Returns all events observed in the window (possibly empty).
89
+ */
90
+ pollEvents(timeoutMs: number): RowEvent[];
91
+ /**
92
+ * Watch for file change events as an async iterable.
93
+ *
94
+ * ```ts
95
+ * for await (const event of db.watch()) { ... }
96
+ * ```
97
+ *
98
+ * Starts the underlying watcher on first iteration, then polls in 200ms
99
+ * increments and yields each {@link RowEvent}. The iterator runs
100
+ * indefinitely; break out of the `for await` loop to stop.
101
+ */
102
+ watch(): AsyncGenerator<RowEvent, void, unknown>;
103
+ }
104
+ export {};
105
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../ts/index.ts"],"names":[],"mappings":"AAgBA,iEAAiE;AACjE,MAAM,WAAW,QAAQ;IACvB,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAC1E,+DAA+D;IAC/D,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAGD,UAAU,YAAY;IACpB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAC9C,YAAY,IAAI,IAAI,CAAC;IACrB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC;CAC3C;AAED,UAAU,uBAAuB;IAC/B,KAAK,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC;IACxE,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAAC;CAC9C;AAID,UAAU,UAAU;IAClB,MAAM,EAAE,uBAAuB,CAAC;CACjC;AAwBD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAEjE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,MAAM;IACjB;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9B,OAAO,CAAC,MAAM,CAAe;gBAEjB,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE;IAS/D;;;;;;OAMG;IACH,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAW7C,yEAAyE;IACzE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;IAI7C;;;OAGG;IACH,YAAY,IAAI,IAAI;IAIpB;;;OAGG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE;IAIzC;;;;;;;;;;OAUG;IACI,KAAK,IAAI,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC;CASxD"}
package/dist/index.js ADDED
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ // dirsql TypeScript SDK.
3
+ //
4
+ // The public surface is implemented in Rust via napi-rs. `pnpm build` runs
5
+ // `napi build` which produces `dirsql.node` at the package root, then
6
+ // `tsc` compiles this file to `dist/index.js` + `dist/index.d.ts`, which
7
+ // is what consumers import via the package's `main` / `types` / `exports`
8
+ // fields.
9
+ //
10
+ // The native binary lives at the package root (not in `dist/`) because
11
+ // that is where napi-rs writes it and where `napi prepublish` expects it.
12
+ // We resolve it relative to this file's location at runtime so the
13
+ // loader works whether the package is consumed via `node_modules/dirsql`
14
+ // or via a pnpm workspace self-reference from `test/`.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.DirSQL = void 0;
17
+ exports.__setCoreForTesting = __setCoreForTesting;
18
+ const node_path_1 = require("node:path");
19
+ // Lazy-loaded reference to the core module. Populated on first access
20
+ // by `loadNativeCore()`, or by `__setCoreForTesting()` for tests.
21
+ let core = null;
22
+ /**
23
+ * Load the native napi-rs binary. Resolved relative to this compiled
24
+ * module: after `tsc` emits to `dist/`, `__dirname` is `<pkg>/dist`, so
25
+ * `..` reaches the package root where napi-rs writes `dirsql.node`.
26
+ */
27
+ function loadNativeCore() {
28
+ const bindingPath = (0, node_path_1.join)(__dirname, "..", "dirsql.node");
29
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
30
+ return require(bindingPath);
31
+ }
32
+ function getCore() {
33
+ if (core === null) {
34
+ core = loadNativeCore();
35
+ }
36
+ return core;
37
+ }
38
+ /**
39
+ * **Test-only.** Replace the core module used by the SDK with a fake.
40
+ *
41
+ * This is an internal escape hatch for unit tests that want to mock the
42
+ * napi-rs binding layer without loading the real native binary. Passing
43
+ * `null` resets to the default (lazy native load on next access). Not
44
+ * part of the public API; do not use in application code.
45
+ */
46
+ function __setCoreForTesting(fake) {
47
+ core = fake;
48
+ }
49
+ /**
50
+ * Ephemeral SQL index over a local directory.
51
+ *
52
+ * Constructing a `DirSQL` scans `root`, matches files against each
53
+ * {@link TableDef}'s `glob`, extracts rows via `extract`, and builds an
54
+ * in-memory SQLite database. `query` / `startWatcher` / `pollEvents`
55
+ * are synchronous; {@link ready} and {@link watch} expose the same
56
+ * surface in an async-idiomatic shape so TypeScript consumers don't
57
+ * need a separate `AsyncDirSQL` class.
58
+ *
59
+ * ```ts
60
+ * const db = new DirSQL(root, tables);
61
+ * await db.ready;
62
+ * const rows = db.query("SELECT ...");
63
+ * for await (const event of db.watch()) { ... }
64
+ * ```
65
+ */
66
+ class DirSQL {
67
+ constructor(root, tables, ignore) {
68
+ const Ctor = getCore().DirSQL;
69
+ this._inner =
70
+ ignore === undefined
71
+ ? new Ctor(root, tables)
72
+ : new Ctor(root, tables, ignore);
73
+ this.ready = Promise.resolve();
74
+ }
75
+ /**
76
+ * Load a {@link DirSQL} instance from a `.dirsql.toml` config file.
77
+ *
78
+ * The root directory is derived from the config file's parent. Tables
79
+ * are parsed using the built-in parser for each format declared in the
80
+ * config. No JS `extract` callback is required.
81
+ */
82
+ static fromConfig(configPath) {
83
+ const instance = Object.create(DirSQL.prototype);
84
+ const writable = instance;
85
+ writable._inner = getCore().DirSQL.fromConfig(configPath);
86
+ writable.ready = Promise.resolve();
87
+ return instance;
88
+ }
89
+ /** Execute a SQL query and return results as an array of row objects. */
90
+ query(sql) {
91
+ return this._inner.query(sql);
92
+ }
93
+ /**
94
+ * Start the file watcher. Must be called before {@link pollEvents}.
95
+ * Idempotent — safe to call multiple times.
96
+ */
97
+ startWatcher() {
98
+ this._inner.startWatcher();
99
+ }
100
+ /**
101
+ * Poll for file change events, blocking up to `timeoutMs` for the first
102
+ * event. Returns all events observed in the window (possibly empty).
103
+ */
104
+ pollEvents(timeoutMs) {
105
+ return this._inner.pollEvents(timeoutMs);
106
+ }
107
+ /**
108
+ * Watch for file change events as an async iterable.
109
+ *
110
+ * ```ts
111
+ * for await (const event of db.watch()) { ... }
112
+ * ```
113
+ *
114
+ * Starts the underlying watcher on first iteration, then polls in 200ms
115
+ * increments and yields each {@link RowEvent}. The iterator runs
116
+ * indefinitely; break out of the `for await` loop to stop.
117
+ */
118
+ async *watch() {
119
+ this._inner.startWatcher();
120
+ while (true) {
121
+ const events = this._inner.pollEvents(200);
122
+ for (const event of events) {
123
+ yield event;
124
+ }
125
+ }
126
+ }
127
+ }
128
+ exports.DirSQL = DirSQL;
129
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../ts/index.ts"],"names":[],"mappings":";AAAA,yBAAyB;AACzB,EAAE;AACF,2EAA2E;AAC3E,sEAAsE;AACtE,yEAAyE;AACzE,0EAA0E;AAC1E,UAAU;AACV,EAAE;AACF,uEAAuE;AACvE,0EAA0E;AAC1E,mEAAmE;AACnE,yEAAyE;AACzE,uDAAuD;;;AA0EvD,kDAEC;AA1ED,yCAAiC;AA0CjC,sEAAsE;AACtE,kEAAkE;AAClE,IAAI,IAAI,GAAsB,IAAI,CAAC;AAEnC;;;;GAIG;AACH,SAAS,cAAc;IACrB,MAAM,WAAW,GAAG,IAAA,gBAAI,EAAC,SAAS,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;IACzD,iEAAiE;IACjE,OAAO,OAAO,CAAC,WAAW,CAAe,CAAC;AAC5C,CAAC;AAED,SAAS,OAAO;IACd,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,IAAI,GAAG,cAAc,EAAE,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,mBAAmB,CAAC,IAAuB;IACzD,IAAI,GAAG,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,MAAM;IAajB,YAAY,IAAY,EAAE,MAAkB,EAAE,MAAiB;QAC7D,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC,MAAM,CAAC;QAC9B,IAAI,CAAC,MAAM;YACT,MAAM,KAAK,SAAS;gBAClB,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;gBACxB,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IACjC,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,UAAU,CAAC,UAAkB;QAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAW,CAAC;QAC3D,MAAM,QAAQ,GAAG,QAGhB,CAAC;QACF,QAAQ,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC1D,QAAQ,CAAC,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;QACnC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,yEAAyE;IACzE,KAAK,CAAC,GAAW;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED;;;OAGG;IACH,YAAY;QACV,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;;;;;OAUG;IACH,KAAK,CAAC,CAAC,KAAK;QACV,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QAC3B,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAC3C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAjFD,wBAiFC"}
package/package.json CHANGED
@@ -1,11 +1,52 @@
1
1
  {
2
2
  "name": "dirsql",
3
- "version": "0.0.99-test.1775729890",
3
+ "version": "0.1.2",
4
4
  "description": "Ephemeral SQL index over a local directory",
5
5
  "license": "MIT",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/thekevinscott/dirsql.git"
6
+ "repository": "https://github.com/thekevinscott/dirsql",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
9
14
  },
10
- "main": "index.js"
11
- }
15
+ "files": [
16
+ "dist/",
17
+ "dirsql.node"
18
+ ],
19
+ "napi": {
20
+ "binaryName": "dirsql",
21
+ "triples": {}
22
+ },
23
+ "scripts": {
24
+ "artifacts": "napi artifacts",
25
+ "build": "napi build --release && tsc",
26
+ "build:debug": "napi build && tsc",
27
+ "prepublishOnly": "napi prepublish -t npm",
28
+ "test": "vitest run",
29
+ "test:unit": "vitest run --dir src --passWithNoTests",
30
+ "test:integration": "vitest run --dir test --passWithNoTests",
31
+ "coverage": "vitest run --coverage",
32
+ "lint": "biome check .",
33
+ "lint:fix": "biome check --write .",
34
+ "format": "biome format --write .",
35
+ "format:check": "biome format ."
36
+ },
37
+ "devDependencies": {
38
+ "@biomejs/biome": "^1.9.0",
39
+ "@napi-rs/cli": "^3.0.0",
40
+ "@types/node": "^22.0.0",
41
+ "typescript": "^5.8.0",
42
+ "vitest": "^3.1.1",
43
+ "@vitest/coverage-v8": "^3.1.1"
44
+ },
45
+ "pnpm": {
46
+ "onlyBuiltDependencies": [
47
+ "@biomejs/biome",
48
+ "esbuild"
49
+ ]
50
+ },
51
+ "optionalDependencies": {}
52
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Kevin Scott
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/index.js DELETED
@@ -1,5 +0,0 @@
1
- "use strict";
2
-
3
- module.exports = {
4
- message: "dirsql TypeScript SDK is not yet implemented. See https://github.com/thekevinscott/dirsql for status.",
5
- };