@gesetz/sqlite-compat 3.0.0-rc.8

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,65 @@
1
+ # `@gesetz/sqlite-compat`
2
+
3
+ Optional SQLite cache driver for **gesetz** on runtimes without a usable
4
+ `node:sqlite` module — Node < 23.4, or Bun.
5
+
6
+ ## Why this is separate
7
+
8
+ `@gesetz/core` must stay dependency-light, so it never depends on a native
9
+ SQLite binding. It exposes a driver registry instead, and this package registers
10
+ a `better-sqlite3`-backed implementation under the `sqlite` kind.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pnpm add -D @gesetz/sqlite-compat
16
+ ```
17
+
18
+ `better-sqlite3` is a dependency of this package, so this pulls the native
19
+ module too. It is never a dependency of `@gesetz/core`.
20
+
21
+ ## Use
22
+
23
+ Import it once from `gesetz.config.ts`. The import is the entire opt-in — it
24
+ registers the driver as a side effect:
25
+
26
+ ```ts
27
+ // gesetz.config.ts
28
+ import '@gesetz/sqlite-compat';
29
+ import { defineConfig } from 'gesetz';
30
+
31
+ export default defineConfig({
32
+ rules: [
33
+ /* … */
34
+ ],
35
+ });
36
+ ```
37
+
38
+ That is the whole change — the default shared cache then works on this runtime.
39
+ (To keep the cache somewhere specific instead, set
40
+ `storage: { kind: 'sqlite', path: '…' }`.)
41
+
42
+ `gesetz check` then uses `better-sqlite3` automatically whenever `node:sqlite`
43
+ is unavailable. Driver selection is automatic and is **not** a user-facing
44
+ setting: `storage` only says *whether* and *where* to cache.
45
+
46
+ If `better-sqlite3` cannot be resolved, importing this module is a no-op and
47
+ gesetz runs without a cache.
48
+
49
+ ## API
50
+
51
+ ```ts
52
+ import { createBetterSqliteStore, registerBetterSqliteDriver } from '@gesetz/sqlite-compat';
53
+
54
+ // Register explicitly instead of relying on the import side effect.
55
+ registerBetterSqliteDriver(); // false when better-sqlite3 is not installed
56
+
57
+ // Build a store directly.
58
+ const store = await createBetterSqliteStore('/path/to/cache.db', { namespace: projectRoot });
59
+ ```
60
+
61
+ - `createBetterSqliteStore(path, options?)` — throws with an actionable message
62
+ when `better-sqlite3` cannot be resolved. `options.ctor` and `options.load`
63
+ exist for tests.
64
+ - `registerBetterSqliteDriver(load?)` — registers the driver and returns whether
65
+ it succeeded.
@@ -0,0 +1,31 @@
1
+ import { CacheStore, SqliteLikeDatabase, SqliteStoreNamespaceOptions } from "@gesetz/core";
2
+
3
+ //#region src/index.d.ts
4
+ /**
5
+ * The subset of the `better-sqlite3` constructor we use. Declared structurally
6
+ * so this package typechecks without `@types/better-sqlite3` installed.
7
+ */
8
+ interface BetterSqliteConstructor {
9
+ new (path: string): SqliteLikeDatabase;
10
+ }
11
+ /** Loads the raw `better-sqlite3` module export. Injectable for tests. */
12
+ type BetterSqliteLoader = () => unknown | Promise<unknown>;
13
+ interface CreateBetterSqliteStoreOptions extends SqliteStoreNamespaceOptions {
14
+ /** Use an already-resolved constructor instead of loading `better-sqlite3`. */
15
+ readonly ctor?: BetterSqliteConstructor | undefined;
16
+ /** Override the module loader. Intended for tests. */
17
+ readonly load?: BetterSqliteLoader | undefined;
18
+ }
19
+ /**
20
+ * Creates a cache store backed by `better-sqlite3`.
21
+ *
22
+ * Throws with an actionable message when `better-sqlite3` is not installed.
23
+ */
24
+ declare function createBetterSqliteStore(path: string, options?: CreateBetterSqliteStoreOptions): Promise<CacheStore>;
25
+ /**
26
+ * Registers the `better-sqlite3` driver with `@gesetz/core`.
27
+ * Returns false (and registers nothing) when `better-sqlite3` is unavailable.
28
+ */
29
+ declare function registerBetterSqliteDriver(load?: BetterSqliteLoader): boolean;
30
+ //#endregion
31
+ export { BetterSqliteConstructor, BetterSqliteLoader, CreateBetterSqliteStoreOptions, createBetterSqliteStore, registerBetterSqliteDriver };
package/dist/index.js ADDED
@@ -0,0 +1,86 @@
1
+ import { createRequire } from "node:module";
2
+ import { createSqliteStoreFromDatabase, registerCacheDriver } from "@gesetz/core";
3
+ //#region src/index.ts
4
+ /**
5
+ * `@gesetz/sqlite-compat` — optional SQLite cache driver for runtimes without a
6
+ * usable `node:sqlite` module (Node < 23.4, or Bun).
7
+ *
8
+ * ## Why this is a separate package
9
+ *
10
+ * `@gesetz/core` must stay dependency-light, so it never depends on a native
11
+ * SQLite binding. Instead it exposes a driver registry, and this package
12
+ * registers a `better-sqlite3`-backed implementation under the `sqlite` kind.
13
+ *
14
+ * ## Usage
15
+ *
16
+ * Install `better-sqlite3` and this package, then import it once from
17
+ * `gesetz.config.ts` — the registration is the entire opt-in:
18
+ *
19
+ * ```ts
20
+ * // gesetz.config.ts
21
+ * import '@gesetz/sqlite-compat';
22
+ * import { defineConfig } from 'gesetz';
23
+ *
24
+ * export default defineConfig({
25
+ * storage: { kind: 'sqlite', path: '.gesetz/cache.db' },
26
+ * rules: [/* … *\/],
27
+ * });
28
+ * ```
29
+ *
30
+ * `gesetz check` will then use `better-sqlite3` automatically when
31
+ * `node:sqlite` is unavailable. To force it even where `node:sqlite` exists,
32
+ * set `storage: { kind: 'sqlite', path, driver: 'compat' }`.
33
+ *
34
+ * If `better-sqlite3` cannot be resolved, importing this module is a no-op and
35
+ * gesetz falls back to the JSON cache.
36
+ */
37
+ const SQLITE_MODULE = "better-sqlite3";
38
+ /** Accepts either `module.exports = Ctor` or `{ default: Ctor }`. */
39
+ function resolveConstructor(module) {
40
+ if (typeof module === "function") return module;
41
+ if (module !== null && typeof module === "object") {
42
+ const candidate = module.default;
43
+ if (typeof candidate === "function") return candidate;
44
+ }
45
+ return null;
46
+ }
47
+ let cachedConstructor;
48
+ function loadConstructor() {
49
+ cachedConstructor ??= (() => {
50
+ try {
51
+ return resolveConstructor(createRequire(import.meta.url)(SQLITE_MODULE));
52
+ } catch {
53
+ return null;
54
+ }
55
+ })();
56
+ return cachedConstructor;
57
+ }
58
+ /**
59
+ * Creates a cache store backed by `better-sqlite3`.
60
+ *
61
+ * Throws with an actionable message when `better-sqlite3` is not installed.
62
+ */
63
+ async function createBetterSqliteStore(path, options = {}) {
64
+ const ctor = options.ctor ?? (options.load !== void 0 ? resolveConstructor(await options.load()) : loadConstructor());
65
+ if (ctor === null) throw new Error(`gesetz: ${SQLITE_MODULE} is not installed, so @gesetz/sqlite-compat cannot back the cache. Install it with: pnpm add -D ${SQLITE_MODULE}`);
66
+ return createSqliteStoreFromDatabase(new ctor(path), {
67
+ namespace: options.namespace,
68
+ ttlMs: options.ttlMs
69
+ });
70
+ }
71
+ /**
72
+ * Registers the `better-sqlite3` driver with `@gesetz/core`.
73
+ * Returns false (and registers nothing) when `better-sqlite3` is unavailable.
74
+ */
75
+ function registerBetterSqliteDriver(load = () => loadConstructor()) {
76
+ const resolved = resolveConstructor(load());
77
+ if (resolved === null) return false;
78
+ registerCacheDriver("sqlite", (path, options) => createBetterSqliteStore(path, {
79
+ ctor: resolved,
80
+ ...options ?? {}
81
+ }));
82
+ return true;
83
+ }
84
+ registerBetterSqliteDriver();
85
+ //#endregion
86
+ export { createBetterSqliteStore, registerBetterSqliteDriver };
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@gesetz/sqlite-compat",
3
+ "version": "3.0.0-rc.8",
4
+ "description": "Optional better-sqlite3 cache driver for gesetz on runtimes without node:sqlite",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ }
11
+ },
12
+ "dependencies": {
13
+ "better-sqlite3": "^13.0.0",
14
+ "@gesetz/core": "3.0.0-rc.8"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^22.0.0",
18
+ "typescript": "^5.8.0",
19
+ "vitest": "^4.0.0"
20
+ },
21
+ "types": "./dist/index.d.ts",
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "test": "vitest run",
27
+ "test:watch": "vitest",
28
+ "typecheck": "tsc --noEmit",
29
+ "build": "tsdown"
30
+ }
31
+ }