@mailwoman/sqlite 10.0.0 → 10.2.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.
Files changed (64) hide show
  1. package/lib/batched.ts +7 -13
  2. package/lib/client.ts +18 -45
  3. package/lib/database-schema.ts +13 -20
  4. package/lib/driver.ts +2 -2
  5. package/lib/index.ts +6 -5
  6. package/lib/introspection.ts +15 -8
  7. package/lib/lookup.ts +77 -0
  8. package/lib/schema-columns.ts +43 -19
  9. package/lib/sealed/build.ts +18 -29
  10. package/lib/sealed/db.ts +74 -53
  11. package/lib/{sealed/index.ts → sealed.ts} +13 -8
  12. package/out/batched.d.ts +7 -13
  13. package/out/batched.d.ts.map +1 -1
  14. package/out/batched.js +3 -5
  15. package/out/batched.js.map +1 -1
  16. package/out/client.d.ts +13 -40
  17. package/out/client.d.ts.map +1 -1
  18. package/out/client.js +12 -20
  19. package/out/client.js.map +1 -1
  20. package/out/database-schema.d.ts +12 -20
  21. package/out/database-schema.d.ts.map +1 -1
  22. package/out/database-schema.js +1 -14
  23. package/out/database-schema.js.map +1 -1
  24. package/out/{dialect/index.d.ts → dialect.d.ts} +1 -1
  25. package/out/dialect.d.ts.map +1 -0
  26. package/out/{dialect/index.js → dialect.js} +1 -1
  27. package/out/dialect.js.map +1 -0
  28. package/out/driver.js +2 -2
  29. package/out/driver.js.map +1 -1
  30. package/out/index.d.ts +6 -5
  31. package/out/index.d.ts.map +1 -1
  32. package/out/index.js +6 -5
  33. package/out/index.js.map +1 -1
  34. package/out/introspection.d.ts +15 -8
  35. package/out/introspection.d.ts.map +1 -1
  36. package/out/introspection.js +15 -8
  37. package/out/introspection.js.map +1 -1
  38. package/out/lookup.d.ts +49 -0
  39. package/out/lookup.d.ts.map +1 -0
  40. package/out/lookup.js +55 -0
  41. package/out/lookup.js.map +1 -0
  42. package/out/schema-columns.d.ts +42 -19
  43. package/out/schema-columns.d.ts.map +1 -1
  44. package/out/schema-columns.js +14 -17
  45. package/out/schema-columns.js.map +1 -1
  46. package/out/sealed/build.d.ts +14 -25
  47. package/out/sealed/build.d.ts.map +1 -1
  48. package/out/sealed/build.js +2 -15
  49. package/out/sealed/build.js.map +1 -1
  50. package/out/sealed/db.d.ts +51 -35
  51. package/out/sealed/db.d.ts.map +1 -1
  52. package/out/sealed/db.js +63 -43
  53. package/out/sealed/db.js.map +1 -1
  54. package/out/{sealed/index.d.ts → sealed.d.ts} +13 -9
  55. package/out/sealed.d.ts.map +1 -0
  56. package/out/{sealed/index.js → sealed.js} +11 -8
  57. package/out/sealed.js.map +1 -0
  58. package/out/tsconfig.test.tsbuildinfo +1 -1
  59. package/package.json +16 -105
  60. package/out/dialect/index.d.ts.map +0 -1
  61. package/out/dialect/index.js.map +0 -1
  62. package/out/sealed/index.d.ts.map +0 -1
  63. package/out/sealed/index.js.map +0 -1
  64. /package/lib/{dialect/index.ts → dialect.ts} +0 -0
package/lib/sealed/db.ts CHANGED
@@ -3,36 +3,41 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * The sealed-artifact invariant: every SQLite DB a build produces is a READ-ONLY asset. `sealDatabase`
6
+ * The sealed-artifact invariant: every SQLite DB a build produces is a read-only asset. `sealDatabase`
7
7
  * is the last step of every builder — checkpoint, freeze the journal, chmod 0444. `openBuiltClient`
8
- * (`@mailwoman/sqlite/sealed`) is how anything opens a data artifact; a write-mode open of a sealed
9
- * file throws a NAMED error pointing at the rebuild command instead of a cryptic SQLITE_READONLY. Unsealing is deliberate and
10
- * manual (`chmod u+w`), never programmatic — rebuild, don't mutate.
11
- *
12
- * `swapDatabaseIntoPlace` is the other half of that invariant — the atomic publish step AGENTS.md
13
- * specifies in prose ("build it successfully, then move the previous version to a temp directory,
14
- * and then move the new version into place"). It lives here because this module already owns the
15
- * built-artifact lifecycle, and because a rule the project states in prose and implements more than
16
- * once in code should be a function.
8
+ * (`@mailwoman/sqlite/sealed`) is how anything opens a data artifact. a write-mode open of a sealed
9
+ * file throws a descriptive error pointing at the rebuild command instead of a cryptic SQLITE_READONLY.
10
+ * A caller can restore write permission only with manual `chmod u+w`; the program never changes permissions.
11
+ * Rebuild the artifact to make changes.
12
+ *
13
+ * `swapDatabaseIntoPlace` is the atomic publish step agents.md
14
+ * specifies in prose ("build it successfully. Move the previous version to a temp directory.
15
+ * Move the new version into place."). It lives here because this module already owns the
16
+ * built-artifact lifecycle. A rule stated in project prose and implemented by several builders belongs in a
17
+ * shared function.
17
18
  */
18
19
 
19
20
  import type { DatabaseSync } from "node:sqlite"
20
21
 
21
- import { pathExists, statPath } from "@mailwoman/core/fs/readers"
22
+ import { pathExists, statPath } from "@mailwoman/core/fs/readers/stat"
22
23
  import { changeMode, movePath, removePath, removePathIfPresent } from "@mailwoman/core/fs/writers"
23
- import { basename } from "path-ts"
24
+ import { basename, type PathBuilderLike } from "path-ts"
24
25
 
25
26
  /**
26
- * The one capability {@link assertDatabaseIntegrity} needs. Narrowing to it rather than naming a handle type lets a
27
- * `DatabaseClient` satisfy the parameter with no import and no cast.
27
+ * The one capability {@link assertDatabaseIntegrity} needs.
28
+ *
29
+ * A narrow callback type lets a `DatabaseClient` satisfy the parameter with no import and no cast.
28
30
  */
29
31
  type IntegrityProbe = Pick<DatabaseSync, "prepare">
30
32
 
31
33
  /**
32
- * `node:sqlite` via {@link process.getBuiltinModule} — invisible to bundlers. A static import here would ride the
33
- * `@mailwoman/core/utils` barrel into every consumer, and the docs' plugin loader (which transpiles `docusaurus.config`
34
- * imports) can't resolve `node:sqlite` (CI: "Cannot find module 'sqlite'"). The builtin accessor keeps `node:sqlite`
35
- * out of the static import graph with zero resolve surface.
34
+ * `node:sqlite` via {@link process.getBuiltinModule} — invisible to bundlers.
35
+ *
36
+ * A static import here would ride the `@mailwoman/core/utils` barrel into every consumer.
37
+ * The docs' plugin loader transpiles `docusaurus.config` imports and cannot resolve
38
+ * `node:sqlite` (CI: "Cannot find module 'sqlite'").
39
+ *
40
+ * The builtin accessor keeps `node:sqlite` out of the static import graph with zero resolve surface.
36
41
  */
37
42
  function sqlite(): typeof import("node:sqlite") {
38
43
  return process.getBuiltinModule("node:sqlite")
@@ -42,7 +47,7 @@ function sqlite(): typeof import("node:sqlite") {
42
47
  * A write-mode open was attempted on a sealed (0444) data artifact.
43
48
  */
44
49
  export class SealedArtifactError extends Error {
45
- constructor(path: string) {
50
+ constructor(path: PathBuilderLike) {
46
51
  super(
47
52
  `${basename(path)} is a sealed read-only artifact — rebuild it via \`mailwoman gazetteer build …\`, ` +
48
53
  `don't mutate it. (Deliberate unseal: chmod u+w — but prefer a rebuild.)`
@@ -53,17 +58,20 @@ export class SealedArtifactError extends Error {
53
58
  }
54
59
 
55
60
  /**
56
- * True when the artifact exists and carries no write bits (the sealed state {@link sealDatabase} leaves).
61
+ * True when the artifact exists and has no write bits (the sealed state {@link sealDatabase} leaves).
57
62
  */
58
- export async function isSealed(path: string): Promise<boolean> {
63
+ export async function isSealed(path: PathBuilderLike): Promise<boolean> {
59
64
  return (await pathExists(path)) && ((await statPath(path)).mode & 0o222) === 0
60
65
  }
61
66
 
62
67
  /**
63
- * Finalize a built DB: WAL-checkpoint → `journal_mode = DELETE` → remove `-wal`/`-shm` sidecars → `chmod 0o444`.
64
- * Idempotent. Throws if the checkpoint cannot complete (another writer holds the DB).
68
+ * Finalize a built DB: WAL-checkpoint → `journal_mode = delete` → remove
69
+ * `-wal`/`-shm` sidecars → `chmod 0o444`.
70
+ *
71
+ * Idempotent.
72
+ * Throws if the checkpoint cannot complete (another writer holds the DB).
65
73
  */
66
- export async function sealDatabase(path: string): Promise<void> {
74
+ export async function sealDatabase(path: PathBuilderLike): Promise<void> {
67
75
  // A previously sealed artifact needs the write bit back for the journal-mode switch.
68
76
  if (await isSealed(path)) {
69
77
  await changeMode(path, 0o644)
@@ -72,7 +80,7 @@ export async function sealDatabase(path: string): Promise<void> {
72
80
  let mode: { journal_mode: string }
73
81
 
74
82
  {
75
- using db = new (sqlite().DatabaseSync)(path)
83
+ using db = new (sqlite().DatabaseSync)(path.toString())
76
84
  const checkpoint = db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get() as { busy: number }
77
85
 
78
86
  if (checkpoint.busy !== 0) {
@@ -98,14 +106,18 @@ export async function sealDatabase(path: string): Promise<void> {
98
106
  /**
99
107
  * Verify a freshly-built database is not corrupt, immediately before it is sealed and published.
100
108
  *
101
- * Belongs beside {@link sealDatabase} for the same reason `swapDatabaseIntoPlace` does: the check is part of the
102
- * built-artifact lifecycle, and every builder was running it from its own copy. `integrity_check` answers with the
103
- * single row `{ integrity_check: "ok" }` on a healthy file and one row per problem otherwise, so only the first matters
104
- * — a builder that reads the column and compares it to `"ok"` has done the whole check.
109
+ * Belongs beside {@link sealDatabase} for the same reason `swapDatabaseIntoPlace` does.
110
+ * The check is part of the built-artifact lifecycle.
111
+ *
112
+ * Every builder previously ran its own copy.
113
+ * `integrity_check` answers with the single row `{ integrity_check: "ok" }` on a healthy file
114
+ * and one row per problem otherwise, so only the first matters.
115
+ *
116
+ * A builder that reads the column and compares it to `"ok"` has done the whole check.
105
117
  *
106
118
  * @throws When the database reports anything other than `ok`, naming the artifact and what SQLite said.
107
119
  */
108
- export function assertDatabaseIntegrity(db: IntegrityProbe, artifact: string): void {
120
+ export function assertDatabaseIntegrity(db: IntegrityProbe, artifact: PathBuilderLike): void {
109
121
  const row = db.prepare("PRAGMA integrity_check").get() as { integrity_check: string } | undefined
110
122
  const verdict = row?.integrity_check
111
123
 
@@ -115,55 +127,64 @@ export function assertDatabaseIntegrity(db: IntegrityProbe, artifact: string): v
115
127
  }
116
128
 
117
129
  /**
118
- * Refuse a write-mode open of a sealed artifact, naming the rebuild command instead of letting SQLite answer
119
- * `SQLITE_READONLY`.
130
+ * Refuse a write-mode open of a sealed artifact, naming the rebuild command
131
+ * instead of letting SQLite answer `SQLITE_READONLY`.
120
132
  *
121
- * The open itself lives in `@mailwoman/sqlite/sealed` — `openBuiltClient`, which every caller uses. This half stays
122
- * here because it is a filesystem predicate, and because this module reaches `node:sqlite` through
123
- * {@link process.getBuiltinModule} to keep the `@mailwoman/core/utils` barrel free of it.
133
+ * The open itself lives in `@mailwoman/sqlite/sealed`.
134
+ * `openBuiltClient`, which every caller uses.
135
+ *
136
+ * This half stays here because it is a filesystem predicate.
137
+ * This module reaches `node:sqlite` through {@link process.getBuiltinModule} to
138
+ * keep the `@mailwoman/core/utils` barrel free of it.
124
139
  *
125
140
  * @throws {SealedArtifactError} When `path` is sealed.
126
141
  */
127
- export async function assertUnsealedForWrite(path: string): Promise<void> {
142
+ export async function assertUnsealedForWrite(path: PathBuilderLike): Promise<void> {
128
143
  if (await isSealed(path)) throw new SealedArtifactError(path)
129
144
  }
130
145
 
131
146
  /**
132
147
  * Atomically move a freshly-built database into its published location.
133
148
  *
134
- * The build writes to a temp path, so a mid-build crash never leaves a half-written DB at `finalPath`. This moves any
135
- * prior version aside, slots the new one in, then drops the old — the previous file stays intact until the replacement
136
- * is committed, and the `-wal`/`-shm` siblings of BOTH paths are cleared so a stale journal can never be paired with a
137
- * new main file.
149
+ * The build writes to a temp path, so a mid-build crash never leaves a half-written DB at `finalPath`.
150
+ * This moves any prior version aside, slots the new one in, then drops the old.
151
+ *
152
+ * The previous file stays intact until the replacement is committed.
153
+ * The function clears the `-wal` and `-shm` siblings of both paths, so a stale
154
+ * journal cannot pair with a new main file.
138
155
  *
139
- * Sealing (`sealDatabase`) happens on the temp file BEFORE the swap: a sealed artifact is what gets published, and 0444
140
- * does not prevent a rename.
156
+ * The code seals (`sealDatabase`) the temp file before the swap.
157
+ * The published artifact is sealed.
158
+ * Mode 0444 still permits a rename.
141
159
  */
142
- export async function swapDatabaseIntoPlace(tmpPath: string, finalPath: string): Promise<void> {
143
- const aside = `${finalPath}.old-${process.pid}`
160
+ export async function swapDatabaseIntoPlace(tmpPath: PathBuilderLike, finalPath: PathBuilderLike): Promise<void> {
161
+ const tmpPathString = tmpPath.toString()
162
+ const finalPathString = finalPath.toString()
163
+ const aside = `${finalPathString}.old-${process.pid}`
144
164
 
145
- if (await pathExists(finalPath)) {
146
- await movePath(finalPath, aside)
165
+ if (await pathExists(finalPathString)) {
166
+ await movePath(finalPathString, aside)
147
167
  }
148
168
 
149
169
  for (const sfx of ["-wal", "-shm"]) {
150
- await removePathIfPresent(finalPath + sfx)
170
+ await removePathIfPresent(finalPathString + sfx)
151
171
  }
152
172
 
153
173
  try {
154
- await movePath(tmpPath, finalPath)
174
+ await movePath(tmpPathString, finalPathString)
155
175
  } catch (error) {
156
- // The prior version is already aside at this point — a failed forward rename must not leave
157
- // the slot empty while a restorable artifact sits one rename away.
158
- if ((await pathExists(aside)) && !(await pathExists(finalPath))) {
159
- await movePath(aside, finalPath)
176
+ // The prior version is already aside at this point.
177
+ // A failed forward rename must not leave the slot empty while a restorable
178
+ // artifact sits one rename away.
179
+ if ((await pathExists(aside)) && !(await pathExists(finalPathString))) {
180
+ await movePath(aside, finalPathString)
160
181
  }
161
182
 
162
183
  throw error
163
184
  }
164
185
 
165
186
  for (const sfx of ["-wal", "-shm"]) {
166
- await removePathIfPresent(tmpPath + sfx)
187
+ await removePathIfPresent(tmpPathString + sfx)
167
188
  }
168
189
 
169
190
  await removePathIfPresent(aside)
@@ -3,29 +3,34 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Opening a built data artifact.
6
+ * Open a built data artifact.
7
7
  *
8
8
  * This is the other half of the sealed-artifact invariant in `../utils/sealed-db.ts`: that module owns the
9
9
  * filesystem side (seal, unseal-refusal, atomic swap) and stays free of a static `node:sqlite` import, because it
10
- * rides the `@mailwoman/core/utils` barrel into consumers that cannot resolve one. The open lives here, where
10
+ * flows through the `@mailwoman/core/utils` barrel into consumers that cannot resolve one. The open lives here, where
11
11
  * `DatabaseClient` is already imported and the cost is paid. The open is asynchronous: the write branch awaits the
12
12
  * seal check against the filesystem before the handle is constructed.
13
13
  */
14
14
 
15
+ import type { PathBuilderLike } from "path-ts"
16
+
15
17
  import { DatabaseClient } from "#client"
16
18
  import type { Database } from "#database-schema"
17
19
  import { assertUnsealedForWrite } from "#sealed/db"
18
20
 
19
21
  /**
20
- * Open a built data artifact. Read-only by default; `write: true` is for builders working on UNsealed staging, and
21
- * throws `SealedArtifactError` against a sealed file.
22
+ * Open a built data artifact.
23
+ *
24
+ * Read-only by default.
25
+ * Builders set `write: true` when working on UNsealed staging.
26
+ * A sealed file raises `SealedArtifactError`.
22
27
  *
23
- * Together with `new DatabaseClient(path)` this is the whole set of ways a connection comes into being. `DatabaseSync`
24
- * is constructed in exactly one place, inside `DatabaseClient`, so no caller holds a raw handle and no database ends up
25
- * described by two schemas.
28
+ * Together with `new DatabaseClient(path)` this is the whole set of ways a connection comes into being.
29
+ * `DatabaseSync` is constructed in exactly one place, inside `DatabaseClient`,
30
+ * so no caller holds a raw handle and no database ends up described by two schemas.
26
31
  */
27
32
  export async function openBuiltClient<DB = Database>(
28
- path: string,
33
+ path: PathBuilderLike,
29
34
  opts: { write?: boolean } = {}
30
35
  ): Promise<DatabaseClient<DB>> {
31
36
  if (opts.write) {
package/out/batched.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Batched bulk-write transactions — the `COMMIT`/`BEGIN` cadence every streaming ingest repeats around its
6
+ * Batched bulk-write transactions — the `commit`/`begin` cadence every streaming ingest repeats around its
7
7
  * raw prepared-statement loop.
8
8
  */
9
9
  /**
@@ -11,26 +11,20 @@
11
11
  */
12
12
  export interface BatchedTransaction {
13
13
  /**
14
- * Record one written row. Every `rowsPerCommit` rows the open transaction is committed and a new one opened; answers
15
- * `true` on the call that committed, so a caller can hang a progress report off the boundary.
14
+ * Record one written row, committing and reopening the transaction every `rowsPerCommit`
15
+ * rows and answering `true` on the call that committed.
16
16
  */
17
17
  rowWritten(): boolean;
18
- /**
19
- * Commit the open transaction — the ordinary end of an ingest loop.
20
- */
21
18
  commit(): void;
22
19
  /**
23
- * Best-effort `ROLLBACK`, and it must never replace the real error: a build runs with the journal off (nothing is
24
- * ever published without the swap), so SQLite may refuse to unwind. What matters is that the caller sees WHY the
25
- * ingest stopped, not that a scratch file was tidied.
20
+ * Best-effort `rollback` that must never replace the real error, so the caller
21
+ * still sees why the ingest stopped.
26
22
  */
27
23
  rollbackQuietly(): void;
28
24
  }
29
25
  /**
30
- * Open a transaction that commits and reopens itself every `rowsPerCommit` written rows.
31
- *
32
- * The batch size is the caller's: a geometry table whose rows carry a blob wants a smaller transaction than a
33
- * fixed-width staging table, because a larger one grows the write-ahead file without improving throughput.
26
+ * Open a transaction that commits and reopens itself every `rowsPerCommit` written rows,
27
+ * with the batch size left to the caller.
34
28
  */
35
29
  export declare function beginBatched(database: {
36
30
  exec(sql: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"batched.d.ts","sourceRoot":"","sources":["../lib/batched.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAA;IACrB;;OAEG;IACH,MAAM,IAAI,IAAI,CAAA;IACd;;;;OAIG;IACH,eAAe,IAAI,IAAI,CAAA;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,QAAQ,EAAE;IAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACrC,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GAChC,kBAAkB,CA6BpB"}
1
+ {"version":3,"file":"batched.d.ts","sourceRoot":"","sources":["../lib/batched.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC;;;OAGG;IACH,UAAU,IAAI,OAAO,CAAA;IACrB,MAAM,IAAI,IAAI,CAAA;IACd;;;OAGG;IACH,eAAe,IAAI,IAAI,CAAA;CACvB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC3B,QAAQ,EAAE;IAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACrC,OAAO,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GAChC,kBAAkB,CA6BpB"}
package/out/batched.js CHANGED
@@ -3,14 +3,12 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Batched bulk-write transactions — the `COMMIT`/`BEGIN` cadence every streaming ingest repeats around its
6
+ * Batched bulk-write transactions — the `commit`/`begin` cadence every streaming ingest repeats around its
7
7
  * raw prepared-statement loop.
8
8
  */
9
9
  /**
10
- * Open a transaction that commits and reopens itself every `rowsPerCommit` written rows.
11
- *
12
- * The batch size is the caller's: a geometry table whose rows carry a blob wants a smaller transaction than a
13
- * fixed-width staging table, because a larger one grows the write-ahead file without improving throughput.
10
+ * Open a transaction that commits and reopens itself every `rowsPerCommit` written rows,
11
+ * with the batch size left to the caller.
14
12
  */
15
13
  export function beginBatched(database, options) {
16
14
  let pending = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"batched.js","sourceRoot":"","sources":["../lib/batched.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAuBH;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC3B,QAAqC,EACrC,OAAkC;IAElC,IAAI,OAAO,GAAG,CAAC,CAAA;IAEf,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAEtB,OAAO;QACN,UAAU;YACT,OAAO,EAAE,CAAA;YAET,IAAI,OAAO,GAAG,OAAO,CAAC,aAAa;gBAAE,OAAO,KAAK,CAAA;YAEjD,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACvB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAEtB,OAAO,GAAG,CAAC,CAAA;YAEX,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,MAAM;YACL,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACxB,CAAC;QACD,eAAe;YACd,IAAI,CAAC;gBACJ,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACR,6CAA6C;YAC9C,CAAC;QACF,CAAC;KACD,CAAA;AACF,CAAC"}
1
+ {"version":3,"file":"batched.js","sourceRoot":"","sources":["../lib/batched.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAmBH;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC3B,QAAqC,EACrC,OAAkC;IAElC,IAAI,OAAO,GAAG,CAAC,CAAA;IAEf,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAEtB,OAAO;QACN,UAAU;YACT,OAAO,EAAE,CAAA;YAET,IAAI,OAAO,GAAG,OAAO,CAAC,aAAa;gBAAE,OAAO,KAAK,CAAA;YAEjD,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACvB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAEtB,OAAO,GAAG,CAAC,CAAA;YAEX,OAAO,IAAI,CAAA;QACZ,CAAC;QACD,MAAM;YACL,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACxB,CAAC;QACD,eAAe;YACd,IAAI,CAAC;gBACJ,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACR,6CAA6C;YAC9C,CAAC;QACF,CAAC;KACD,CAAA;AACF,CAAC"}
package/out/client.d.ts CHANGED
@@ -8,79 +8,52 @@ import { Kysely, type KyselyConfig } from "kysely";
8
8
  import { type PathBuilderLike } from "path-ts";
9
9
  import type { Database } from "#database-schema";
10
10
  import type { SqliteDialectConfig } from "#dialect/config";
11
- /**
12
- * A SQLite client for one database file: a Kysely query builder over `node:sqlite`, plus the two raw statements Kysely
13
- * cannot express.
14
- *
15
- * The client opens the file. A caller says which file and which schema; it never builds the connection itself.
16
- *
17
- * ```ts
18
- * using kdb = new DatabaseClient<MySchema>("db.sqlite", { readOnly: true })
19
- * ```
20
- *
21
- * Handing that job to callers is what let one database be described by two schemas — the type argument here and a
22
- * second one on the handle — with nothing to make them agree. It also split ownership: `SqliteDriver.destroy()` closes
23
- * whatever connection it was given, so a shared handle has two owners and the first `destroy()` closes it under the
24
- * other. One construction gives one schema, one owner, and a lifetime `using` can end.
25
- *
26
- * `exec` and `prepare` reach the same connection for the work Kysely does not model. See `core/db/schema.ts`.
27
- */
28
11
  /**
29
12
  * A connection's non-Kysely surface: the statements Kysely does not model, plus ending the connection.
30
13
  *
31
- * Schema-agnostic by construction — none of these members mentions `DB` — so a `DatabaseClient<AnySchema>` satisfies it
32
- * and a helper need not name its caller's schema. That matters because Kysely is INVARIANT in `DB`: a parameter typed
33
- * `DatabaseClient` (the empty default) would reject every real client. This is the narrowing the
34
- * `mailwoman/no-database-handle-cast` rule prescribes, applied to the raw side.
14
+ * Schema-agnostic because Kysely is invariant in `DB`: a parameter typed
15
+ * `DatabaseClient` would reject every real client.
35
16
  */
36
17
  export type RawStatements = Pick<DatabaseClient, "exec" | "prepare" | "function" | "destroy"> & Disposable;
18
+ /**
19
+ * A SQLite client for one database file: a Kysely query builder over `node:sqlite`,
20
+ * plus the two raw statements Kysely cannot express.
21
+ */
37
22
  export declare class DatabaseClient<DB = Database> extends Kysely<DB> implements Disposable {
38
23
  #private;
39
24
  /**
40
- * A memory-only database, for tests and other ephemeral work. The connection is open until the client is disposed.
25
+ * A memory-only database, for tests and other ephemeral work.
41
26
  */
42
27
  static temp<DB = Database>(): DatabaseClient<DB>;
43
28
  constructor(location: PathBuilderLike, options?: DatabaseSyncOptions, config?: Partial<KyselyConfig>);
44
29
  constructor(database: DatabaseSync, config?: Partial<KyselyConfig>);
45
30
  constructor(dialectConfig: SqliteDialectConfig, config?: Partial<KyselyConfig>);
46
31
  /**
47
- * Run a statement Kysely does not model: `PRAGMA`, `VACUUM`, `ANALYZE`, `ATTACH`, FTS5 virtual-table DDL.
48
- *
49
- * Not to be confused with Kysely's `execute()`, which runs a compiled query. This one takes SQL text and returns
50
- * nothing.
32
+ * Run a statement Kysely does not model: `pragma`, `vacuum`, `analyze`, `attach`, FTS5 virtual-table DDL.
51
33
  */
52
34
  exec(sql: string): void;
53
35
  /**
54
36
  * A prepared statement on this client's connection, for the bulk-write path.
55
- *
56
- * Kysely compiles per call, which a positional insert loop over millions of rows cannot afford. Reach for this only
57
- * there and in the other cases `AGENTS.md` lists as deliberately raw; everything cold goes through the query builder,
58
- * where the schema is checked.
59
37
  */
60
38
  prepare(sql: string): StatementSync;
61
39
  /**
62
40
  * Register a user-defined SQL function on this client's connection, callable from any statement it runs.
63
41
  *
64
- * SQLite resolves the name at statement-compile time, so registration must precede the first query that uses it.
42
+ * SQLite resolves the name at statement-compile time, so registration must
43
+ * precede the first query that uses it.
65
44
  */
66
45
  function(name: string, options: FunctionOptions, fn: (...args: SQLOutputValue[]) => SQLInputValue): void;
67
46
  function(name: string, fn: (...args: SQLOutputValue[]) => SQLInputValue): void;
68
47
  /**
69
48
  * End the connection at scope exit, synchronously.
70
49
  *
71
- * `destroy()` is Kysely's teardown and returns a promise, which `Symbol.dispose` cannot await — calling it here would
72
- * return with the file still open, and the next thing to touch that path (a `sealDatabase`, a reader expecting a
73
- * finalized statement) would see a connection that should have been gone. `node:sqlite`'s `close()` is synchronous,
74
- * so `using` closes the file before the scope ends.
75
- *
76
- * Kysely's own driver state is not unwound here. It holds this one connection and nothing else, and a query issued
77
- * afterwards fails on the closed handle rather than on a pool that thinks it is alive.
50
+ * `destroy()` returns a promise, so `Symbol.dispose` cannot call it.
51
+ * `node:sqlite`'s `close()` is synchronous.
78
52
  */
79
53
  [Symbol.dispose](): void;
80
54
  }
81
55
  /**
82
- * The `node:sqlite` types a caller needs when it holds a statement or binds a value. Re-exported so nothing has to
83
- * reach past this package for them.
56
+ * The `node:sqlite` types a caller needs when it holds a statement or binds a value.
84
57
  */
85
58
  export type { DatabaseSyncOptions, SQLInputValue, SQLOutputValue, StatementSync } from "node:sqlite";
86
59
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../lib/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACN,YAAY,EACZ,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAA;AAClD,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,SAAS,CAAA;AAE3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAG1D;;;;;;;;;;;;;;;;GAgBG;AACH;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC,GAAG,UAAU,CAAA;AAE1G,qBAAa,cAAc,CAAC,EAAE,GAAG,QAAQ,CAAE,SAAQ,MAAM,CAAC,EAAE,CAAE,YAAW,UAAU;;IAClF;;OAEG;IACH,OAAc,IAAI,CAAC,EAAE,GAAG,QAAQ,KAAK,cAAc,CAAC,EAAE,CAAC,CAEtD;IAID,YAAY,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAC;IACrG,YAAY,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAC;IACnE,YAAY,aAAa,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAC;IAuC/E;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEtB;IAED;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAElC;IAED;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,EAAE,KAAK,aAAa,GAAG,IAAI,CAAA;IACxG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,EAAE,KAAK,aAAa,GAAG,IAAI,CAAA;IAe9E;;;;;;;;;;OAUG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAEvB;CACD;AAED;;;GAGG;AACH,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../lib/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACN,YAAY,EACZ,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAA;AAClD,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,SAAS,CAAA;AAE3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEhD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAE1D;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC,GAAG,UAAU,CAAA;AAE1G;;;GAGG;AACH,qBAAa,cAAc,CAAC,EAAE,GAAG,QAAQ,CAAE,SAAQ,MAAM,CAAC,EAAE,CAAE,YAAW,UAAU;;IAClF;;OAEG;IACH,OAAc,IAAI,CAAC,EAAE,GAAG,QAAQ,KAAK,cAAc,CAAC,EAAE,CAAC,CAEtD;IAID,YAAY,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAC;IACrG,YAAY,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAC;IACnE,YAAY,aAAa,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EAAC;IAuC/E;;OAEG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEtB;IAED;;OAEG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAElC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,EAAE,KAAK,aAAa,GAAG,IAAI,CAAA;IACxG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,EAAE,KAAK,aAAa,GAAG,IAAI,CAAA;IAe9E;;;;;OAKG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAEvB;CACD;AAED;;GAEG;AACH,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA"}
package/out/client.js CHANGED
@@ -6,10 +6,14 @@
6
6
  import { DatabaseSync, } from "node:sqlite";
7
7
  import { Kysely } from "kysely";
8
8
  import { PathBuilder } from "path-ts";
9
- import { SqliteDialect } from "#dialect/index";
9
+ import { SqliteDialect } from "#dialect";
10
+ /**
11
+ * A SQLite client for one database file: a Kysely query builder over `node:sqlite`,
12
+ * plus the two raw statements Kysely cannot express.
13
+ */
10
14
  export class DatabaseClient extends Kysely {
11
15
  /**
12
- * A memory-only database, for tests and other ephemeral work. The connection is open until the client is disposed.
16
+ * A memory-only database, for tests and other ephemeral work.
13
17
  */
14
18
  static temp() {
15
19
  return new DatabaseClient(":memory:");
@@ -21,10 +25,10 @@ export class DatabaseClient extends Kysely {
21
25
  if (typeof source === "string" || source instanceof PathBuilder) {
22
26
  const location = source.toString();
23
27
  const options = optionsOrConfig;
24
- // node:sqlite checks the argument count, not the value: `new DatabaseSync(path, undefined)` throws.
28
+ // node:sqlite checks the argument count rather than the value: `new DatabaseSync(path, undefined)` throws.
25
29
  const openArgs = options ? [location, options] : [location];
26
30
  database = new DatabaseSync(...openArgs);
27
- kyselyConfig = config;
31
+ kyselyConfig = config ?? null;
28
32
  }
29
33
  else {
30
34
  const dialectConfig = "database" in source ? source : { database: source };
@@ -33,7 +37,7 @@ export class DatabaseClient extends Kysely {
33
37
  "`prepare` with nothing to reach. Pass the database path instead.");
34
38
  }
35
39
  database = dialectConfig.database;
36
- kyselyConfig = optionsOrConfig;
40
+ kyselyConfig = optionsOrConfig ?? null;
37
41
  }
38
42
  super({
39
43
  ...kyselyConfig,
@@ -42,20 +46,13 @@ export class DatabaseClient extends Kysely {
42
46
  this.#database = database;
43
47
  }
44
48
  /**
45
- * Run a statement Kysely does not model: `PRAGMA`, `VACUUM`, `ANALYZE`, `ATTACH`, FTS5 virtual-table DDL.
46
- *
47
- * Not to be confused with Kysely's `execute()`, which runs a compiled query. This one takes SQL text and returns
48
- * nothing.
49
+ * Run a statement Kysely does not model: `pragma`, `vacuum`, `analyze`, `attach`, FTS5 virtual-table DDL.
49
50
  */
50
51
  exec(sql) {
51
52
  this.#database.exec(sql);
52
53
  }
53
54
  /**
54
55
  * A prepared statement on this client's connection, for the bulk-write path.
55
- *
56
- * Kysely compiles per call, which a positional insert loop over millions of rows cannot afford. Reach for this only
57
- * there and in the other cases `AGENTS.md` lists as deliberately raw; everything cold goes through the query builder,
58
- * where the schema is checked.
59
56
  */
60
57
  prepare(sql) {
61
58
  return this.#database.prepare(sql);
@@ -70,13 +67,8 @@ export class DatabaseClient extends Kysely {
70
67
  /**
71
68
  * End the connection at scope exit, synchronously.
72
69
  *
73
- * `destroy()` is Kysely's teardown and returns a promise, which `Symbol.dispose` cannot await — calling it here would
74
- * return with the file still open, and the next thing to touch that path (a `sealDatabase`, a reader expecting a
75
- * finalized statement) would see a connection that should have been gone. `node:sqlite`'s `close()` is synchronous,
76
- * so `using` closes the file before the scope ends.
77
- *
78
- * Kysely's own driver state is not unwound here. It holds this one connection and nothing else, and a query issued
79
- * afterwards fails on the closed handle rather than on a pool that thinks it is alive.
70
+ * `destroy()` returns a promise, so `Symbol.dispose` cannot call it.
71
+ * `node:sqlite`'s `close()` is synchronous.
80
72
  */
81
73
  [Symbol.dispose]() {
82
74
  this.#database[Symbol.dispose]();
package/out/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../lib/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACN,YAAY,GAMZ,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,MAAM,EAAqB,MAAM,QAAQ,CAAA;AAClD,OAAO,EAAE,WAAW,EAAwB,MAAM,SAAS,CAAA;AAI3D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AA6B9C,MAAM,OAAO,cAA8B,SAAQ,MAAU;IAC5D;;OAEG;IACI,MAAM,CAAC,IAAI;QACjB,OAAO,IAAI,cAAc,CAAK,UAAU,CAAC,CAAA;IAC1C,CAAC;IAEQ,SAAS,CAAc;IAKhC,YACC,MAA4D,EAC5D,eAA6D,EAC7D,MAA8B;QAE9B,IAAI,QAAsB,CAAA;QAC1B,IAAI,YAA+C,CAAA;QAEnD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,YAAY,WAAW,EAAE,CAAC;YACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;YAClC,MAAM,OAAO,GAAG,eAAkD,CAAA;YAClE,oGAAoG;YACpG,MAAM,QAAQ,GAAmC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;YAE3F,QAAQ,GAAG,IAAI,YAAY,CAAC,GAAG,QAAQ,CAAC,CAAA;YACxC,YAAY,GAAG,MAAM,CAAA;QACtB,CAAC;aAAM,CAAC;YACP,MAAM,aAAa,GAAG,UAAU,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;YAE1E,IAAI,OAAO,aAAa,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;gBAClD,MAAM,IAAI,SAAS,CAClB,kGAAkG;oBACjG,kEAAkE,CACnE,CAAA;YACF,CAAC;YAED,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAA;YACjC,YAAY,GAAG,eAAoD,CAAA;QACpE,CAAC;QAED,KAAK,CAAC;YACL,GAAG,YAAY;YACf,OAAO,EAAE,IAAI,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC;SACxC,CAAC,CAAA;QAEF,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA;IAC1B,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,GAAW;QACf,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,GAAW;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACnC,CAAC;IASD,QAAQ,CACP,IAAY,EACZ,WAA6E,EAC7E,EAAiD;QAEjD,IAAI,OAAO,WAAW,KAAK,UAAU,EAAE,CAAC;YACvC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;YAE1C,OAAM;QACP,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,EAAG,CAAC,CAAA;IAChD,CAAC;IAED;;;;;;;;;;OAUG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC;QACf,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAA;IACjC,CAAC;CACD"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../lib/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACN,YAAY,GAMZ,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,MAAM,EAAqB,MAAM,QAAQ,CAAA;AAClD,OAAO,EAAE,WAAW,EAAwB,MAAM,SAAS,CAAA;AAG3D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAWxC;;;GAGG;AACH,MAAM,OAAO,cAA8B,SAAQ,MAAU;IAC5D;;OAEG;IACI,MAAM,CAAC,IAAI;QACjB,OAAO,IAAI,cAAc,CAAK,UAAU,CAAC,CAAA;IAC1C,CAAC;IAEQ,SAAS,CAAc;IAKhC,YACC,MAA4D,EAC5D,eAA6D,EAC7D,MAA8B;QAE9B,IAAI,QAAsB,CAAA;QAC1B,IAAI,YAA0C,CAAA;QAE9C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,YAAY,WAAW,EAAE,CAAC;YACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;YAClC,MAAM,OAAO,GAAG,eAAkD,CAAA;YAClE,2GAA2G;YAC3G,MAAM,QAAQ,GAAmC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;YAE3F,QAAQ,GAAG,IAAI,YAAY,CAAC,GAAG,QAAQ,CAAC,CAAA;YACxC,YAAY,GAAG,MAAM,IAAI,IAAI,CAAA;QAC9B,CAAC;aAAM,CAAC;YACP,MAAM,aAAa,GAAG,UAAU,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;YAE1E,IAAI,OAAO,aAAa,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;gBAClD,MAAM,IAAI,SAAS,CAClB,kGAAkG;oBACjG,kEAAkE,CACnE,CAAA;YACF,CAAC;YAED,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAA;YACjC,YAAY,GAAI,eAAqD,IAAI,IAAI,CAAA;QAC9E,CAAC;QAED,KAAK,CAAC;YACL,GAAG,YAAY;YACf,OAAO,EAAE,IAAI,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC;SACxC,CAAC,CAAA;QAEF,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAA;IAC1B,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,GAAW;QACf,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,GAAW;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACnC,CAAC;IAUD,QAAQ,CACP,IAAY,EACZ,WAA6E,EAC7E,EAAiD;QAEjD,IAAI,OAAO,WAAW,KAAK,UAAU,EAAE,CAAC;YACvC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;YAE1C,OAAM;QACP,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,EAAG,CAAC,CAAA;IAChD,CAAC;IAED;;;;;OAKG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC;QACf,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAA;IACjC,CAAC;CACD"}
@@ -3,28 +3,20 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Shared `Database` typing for the Kysely client at `core/kysley/client.ts`.
7
- *
8
- * This file intentionally ships an empty schema. Consumers that want compile-time table typing
9
- * should extend `Kysely<TheirSchema>` directly rather than baking a schema into core — the WOF
10
- * resolver (Phase 4.2), corpus adapters, and any future consumer all touch different tables.
11
- *
12
- * The exported `Database` interface exists so `client.ts` has a target for `Kysely<Database>` and
13
- * the boilerplate compiles without forcing a concrete schema commitment.
14
- *
15
- * IT IS THE DEFAULT, NOT THE ONLY OPTION, and reading it as the only option is how `as never` gets written. Every
16
- * table name typed against `Record<string, never>` IS `never`, so `insertInto("poi")` cannot compile and a caller
17
- * who believes no alternative exists casts — which disarms not just that one check but every type-level guarantee
18
- * anyone later adds to the table (#1757 has the worked case: a branded key column whose check a neighbouring
19
- * `as never` had already defeated).
6
+ * Default schema type for {@link DatabaseClient}; consumers supply their own table schema.
20
7
  */
21
8
  /**
22
- * Empty schema marker, and the DEFAULT type argument only.
23
- *
24
- * Consumers declare their own schema interface and pass it directly: `new Kysely<MySchema>({…})` or `new
25
- * DatabaseClient<MySchema>(…)`. `DatabaseClient<DB = Database>` is generic today, so this is available now — the
26
- * sentence here once deferred it to "Phase 4.2 work", which had already landed, and a reader who believed that had no
27
- * option but to cast.
9
+ * Empty schema marker used only as the generic default.
28
10
  */
29
11
  export type Database = Record<string, never>;
12
+ /**
13
+ * A `meta` table of key-value pairs: provenance, license and build statistics stored
14
+ * with the database rather than in a document that can drift from it.
15
+ *
16
+ * Its keys are specific to the builder.
17
+ */
18
+ export interface KeyValueMetaTable {
19
+ key: string;
20
+ value: string | null;
21
+ }
30
22
  //# sourceMappingURL=database-schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"database-schema.d.ts","sourceRoot":"","sources":["../lib/database-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA"}
1
+ {"version":3,"file":"database-schema.d.ts","sourceRoot":"","sources":["../lib/database-schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB"}
@@ -3,20 +3,7 @@
3
3
  * @license AGPL-3.0
4
4
  * @author Teffen Ellis, et al.
5
5
  *
6
- * Shared `Database` typing for the Kysely client at `core/kysley/client.ts`.
7
- *
8
- * This file intentionally ships an empty schema. Consumers that want compile-time table typing
9
- * should extend `Kysely<TheirSchema>` directly rather than baking a schema into core — the WOF
10
- * resolver (Phase 4.2), corpus adapters, and any future consumer all touch different tables.
11
- *
12
- * The exported `Database` interface exists so `client.ts` has a target for `Kysely<Database>` and
13
- * the boilerplate compiles without forcing a concrete schema commitment.
14
- *
15
- * IT IS THE DEFAULT, NOT THE ONLY OPTION, and reading it as the only option is how `as never` gets written. Every
16
- * table name typed against `Record<string, never>` IS `never`, so `insertInto("poi")` cannot compile and a caller
17
- * who believes no alternative exists casts — which disarms not just that one check but every type-level guarantee
18
- * anyone later adds to the table (#1757 has the worked case: a branded key column whose check a neighbouring
19
- * `as never` had already defeated).
6
+ * Default schema type for {@link DatabaseClient}; consumers supply their own table schema.
20
7
  */
21
8
  export {};
22
9
  //# sourceMappingURL=database-schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"database-schema.js","sourceRoot":"","sources":["../lib/database-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG"}
1
+ {"version":3,"file":"database-schema.js","sourceRoot":"","sources":["../lib/database-schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -36,4 +36,4 @@ export declare class SqliteDialect implements Dialect {
36
36
  createAdapter(): DialectAdapter;
37
37
  createIntrospector(db: Kysely<unknown>): DatabaseIntrospector;
38
38
  }
39
- //# sourceMappingURL=index.d.ts.map
39
+ //# sourceMappingURL=dialect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialect.d.ts","sourceRoot":"","sources":["../lib/dialect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAIN,KAAK,oBAAoB,EACzB,KAAK,OAAO,EACZ,KAAK,cAAc,EACnB,KAAK,MAAM,EACX,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAG1D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,aAAc,YAAW,OAAO;IAC5C,SAAS,CAAC,MAAM,EAAE,mBAAmB,CAAA;IAErC,YAAY,MAAM,EAAE,mBAAmB,EAEtC;IAED,YAAY,IAAI,MAAM,CAErB;IAED,mBAAmB,IAAI,aAAa,CAEnC;IAED,aAAa,IAAI,cAAc,CAE9B;IAED,kBAAkB,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,oBAAoB,CAE5D;CACD"}
@@ -46,4 +46,4 @@ export class SqliteDialect {
46
46
  return new SqliteIntrospector(db);
47
47
  }
48
48
  }
49
- //# sourceMappingURL=index.js.map
49
+ //# sourceMappingURL=dialect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialect.js","sourceRoot":"","sources":["../lib/dialect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACN,aAAa,EACb,kBAAkB,EAClB,mBAAmB,GAOnB,MAAM,QAAQ,CAAA;AAGf,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,aAAa;IACf,MAAM,CAAqB;IAErC,YAAY,MAA2B;QACtC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAA;IAC3C,CAAC;IAED,YAAY;QACX,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACrC,CAAC;IAED,mBAAmB;QAClB,OAAO,IAAI,mBAAmB,EAAE,CAAA;IACjC,CAAC;IAED,aAAa;QACZ,OAAO,IAAI,aAAa,EAAE,CAAA;IAC3B,CAAC;IAED,kBAAkB,CAAC,EAAmB;QACrC,OAAO,IAAI,kBAAkB,CAAC,EAAE,CAAC,CAAA;IAClC,CAAC;CACD"}