@nxgt/mongo-kit 0.1.4 → 0.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.
package/README.md CHANGED
@@ -218,6 +218,40 @@ definition under it; without `export`, every export that is a definition is
218
218
  taken. Two files defining the same server collection are refused. It needs
219
219
  the Bun runtime, and it is for scripts.
220
220
 
221
+ ## Errors
222
+
223
+ `KitError` is what this package refuses: a configuration, a name or a call
224
+ that cannot work. It carries a `code`, and the `database` and `key` it is
225
+ about — never a URI, which may hold a password.
226
+
227
+ ```ts
228
+ import { KitError } from '@nxgt/mongo-kit';
229
+
230
+ if (error instanceof KitError && error.code === 'CONFIG') {
231
+ console.error(`mongo: "${error.database}" is misconfigured`, error.message);
232
+ }
233
+ ```
234
+
235
+ | `KitErrorCode` | |
236
+ | --- | --- |
237
+ | `CONFIG` | `defineConfig` refused the configuration |
238
+ | `COLLISION` | a collection is wired under a name the driver's `Db` has |
239
+ | `NO_DATABASE` | `transaction(fn, { on })` named a database this kit does not hold |
240
+ | `SEVERAL_DATABASES` | `kit.db` was read on a kit that holds more than one |
241
+ | `TRANSACTION` | no client named where one is needed, or `{ on }` inside a session |
242
+ | `DERIVED` | `close()` on a kit `as`, `withSession` or a transaction derived |
243
+ | `DISCOVERY` | `discoverCollections` could not make a set of definitions |
244
+
245
+ It extends **`TypeError`**, not `Error`: each of these is a call or a
246
+ configuration written wrong, and this package threw bare `TypeError`s before
247
+ the class existed, so a `catch` that tests for `TypeError` still matches.
248
+
249
+ The collections are `@nxgt/mongo`'s, so what a *query* throws is its
250
+ `DataError` and its subclasses, unchanged. MongoDB's own refusal to connect
251
+ reaches the caller from `createKit` as the driver's error. Every code, with
252
+ the call that raises it, is in
253
+ [docs/guide/errors.md](docs/guide/errors.md).
254
+
221
255
  ## What does not compile
222
256
 
223
257
  Each is a `@ts-expect-error` case in this package's type tests.
@@ -250,7 +284,7 @@ Each is a `@ts-expect-error` case in this package's type tests.
250
284
  deployment step: it needs `dbAdmin`, and an index build is not in a
251
285
  transaction.
252
286
  - **A kit from `as` or `withSession` cannot be closed**, and `close()` on it
253
- throws: the clients are the root kit's.
287
+ throws `KitError` with the code `DERIVED`: the clients are the root kit's.
254
288
  - **`discoverCollections` runs under Bun**, has no types, and does not
255
289
  survive bundling. It is for scripts run from the repository; a Node script
256
290
  calling it gets `Bun is not defined`.
@@ -258,15 +292,33 @@ Each is a `@ts-expect-error` case in this package's type tests.
258
292
  uncallable: one call could not stamp both.
259
293
  - **`{ on }` is required at run time, not by the types**, and cannot be: two
260
294
  databases on one URI share a client and need none, so what decides is the
261
- number of *clients*. Without it, a kit holding two throws.
295
+ number of *clients*. Without it, a kit holding two throws `TRANSACTION`.
262
296
  - **A transaction body may run twice.** The driver retries it from the start
263
297
  on a transient error, so it must hold nothing that MongoDB would not roll
264
298
  back.
265
299
  - **A transaction reaches one client's databases.** With `{ on: 'main' }`,
266
300
  an operation on a database of another client carries a session that client
267
301
  does not own, and the driver refuses it.
268
- - **`kit.db` throws on a kit with several databases**, where its type is
269
- already `never`: the message names the databases to read instead.
302
+ - **`kit.db` throws `SEVERAL_DATABASES` on a kit with several databases**,
303
+ where its type is already `never`: the message names the databases to read
304
+ instead.
305
+
306
+ ## Documentation
307
+
308
+ - [Guide index](docs/README.md) — every page, and when to read it.
309
+ - [Configuration](docs/guide/configuration.md) — the databases, the
310
+ collections, and the options each is built with.
311
+ - [The `db` scope](docs/guide/db-scope.md) — the collections on the driver's
312
+ `Db`, and the kit in a request.
313
+ - [The actor, sessions and transactions](docs/guide/actor-and-transactions.md)
314
+ — `as`, `withSession` and `transaction`.
315
+ - [Syncing](docs/guide/sync.md) — the deployment step, and `dryRun`.
316
+ - [Errors](docs/guide/errors.md) — `KitError`, its codes, and what each one
317
+ is thrown by.
318
+ - [`discoverCollections`](docs/guide/discover-collections.md) — definitions
319
+ from a glob, for scripts.
320
+ - [Troubleshooting](docs/troubleshooting.md) — the errors, by their message.
321
+ - [Roadmap](docs/roadmap.md) — what is next, and what is not planned.
270
322
 
271
323
  ## License
272
324
 
@@ -1 +1 @@
1
- {"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/config/checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,uBAAuB,CAU7E;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAC5B,WAAW,EAAE,MAAM,GACjB,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAAE,CAKrC;AA6BD,6EAA6E;AAC7E,wBAAgB,aAAa,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,GAC5B,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAAE,CA8DrC"}
1
+ {"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../src/config/checks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,uBAAuB,CAU7E;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAC5B,WAAW,EAAE,MAAM,GACjB,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAAE,CAKrC;AAsCD,6EAA6E;AAC7E,wBAAgB,aAAa,CAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,cAAc,CAAC,MAAM,CAAC,GAC5B,CAAC,MAAM,EAAE,uBAAuB,CAAC,EAAE,CA6DrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"define-config.d.ts","sourceRoot":"","sources":["../../src/config/define-config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,OAAO,EAEP,SAAS,EACT,cAAc,EACd,MAAM,SAAS,CAAC;AAuBjB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,YAAY,CAAC,KAAK,CAAC,CAAC,SAAS,cAAc,EAC1D,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACpB,SAAS,CAAC,CAAC,CAAC,CAQd"}
1
+ {"version":3,"file":"define-config.d.ts","sourceRoot":"","sources":["../../src/config/define-config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,OAAO,EAEP,SAAS,EACT,cAAc,EACd,MAAM,SAAS,CAAC;AAmCjB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,YAAY,CAAC,KAAK,CAAC,CAAC,SAAS,cAAc,EAC1D,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACpB,SAAS,CAAC,CAAC,CAAC,CAQd"}
@@ -1 +1 @@
1
- {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAG3D,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC/B,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,mBAAmB,CACxC,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAiCpC"}
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAI3D,4DAA4D;AAC5D,MAAM,WAAW,eAAe;IAC/B,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,mBAAmB,CACxC,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAqCpC"}
@@ -0,0 +1,41 @@
1
+ /** What the kit refused, as a string a caller can switch on. */
2
+ export type KitErrorCode =
3
+ /** The configuration object itself is wrong, and nothing connected. */
4
+ 'CONFIG'
5
+ /** A collection is wired under a name that is a member of the driver's `Db`. */
6
+ | 'COLLISION'
7
+ /** A database was read by a name this kit does not hold. */
8
+ | 'NO_DATABASE'
9
+ /** `kit.db` was read on a kit that holds more than one database. */
10
+ | 'SEVERAL_DATABASES'
11
+ /** A transaction that cannot be opened: no client named, or already in one. */
12
+ | 'TRANSACTION'
13
+ /** `close()` on a kit that `as`, `withSession` or a transaction derived. */
14
+ | 'DERIVED'
15
+ /** `discoverCollections` could not make a set of definitions from a glob. */
16
+ | 'DISCOVERY';
17
+ export interface KitErrorOptions {
18
+ /** The database it is about, when one is named. */
19
+ database?: string | undefined;
20
+ /** The config key, the collection key or the path it is about. */
21
+ key?: string | undefined;
22
+ cause?: unknown;
23
+ }
24
+ /**
25
+ * What this package refuses, with a code beside the sentence.
26
+ *
27
+ * It extends `TypeError` rather than `Error`, unlike `DataError`,
28
+ * `RedisError` and `S3Error`: every one of these is a call or a
29
+ * configuration written wrong, which is what `TypeError` means, and this
30
+ * package threw bare `TypeError`s before it existed. Extending one keeps
31
+ * every `catch` that tests for `TypeError` working, and adds a `code` to
32
+ * switch on instead of matching the message text.
33
+ */
34
+ export declare class KitError extends TypeError {
35
+ name: string;
36
+ readonly code: KitErrorCode;
37
+ readonly database: string | undefined;
38
+ readonly key: string | undefined;
39
+ constructor(code: KitErrorCode, message: string, options?: KitErrorOptions);
40
+ }
41
+ //# sourceMappingURL=kit-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kit-error.d.ts","sourceRoot":"","sources":["../../src/errors/kit-error.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,MAAM,YAAY;AACvB,uEAAuE;AACrE,QAAQ;AACV,gFAAgF;GAC9E,WAAW;AACb,4DAA4D;GAC1D,aAAa;AACf,oEAAoE;GAClE,mBAAmB;AACrB,+EAA+E;GAC7E,aAAa;AACf,4EAA4E;GAC1E,SAAS;AACX,6EAA6E;GAC3E,WAAW,CAAC;AAEf,MAAM,WAAW,eAAe;IAC/B,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,qBAAa,QAAS,SAAQ,SAAS;IAC7B,IAAI,SAAc;IAC3B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;gBAErB,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe;CAM1E"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { defineConfig } from './config/define-config';
2
2
  export type { CollectionsIn, CollectionsOf, DatabaseConfig, DbName, KitCollectionOptions, KitConfig, KitConfigInput, NoCollision, ReservedName, Unwired, } from './config/types';
3
3
  export { type DiscoverOptions, discoverCollections } from './discover';
4
+ export { KitError, type KitErrorCode, type KitErrorOptions, } from './errors/kit-error';
4
5
  export { createKit } from './kit/create-kit';
5
6
  export type { DbScope, KitActor, KitOf, KitTransactionOptions, MongoKit, SoleScope, } from './kit/types';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,MAAM,EACN,oBAAoB,EACpB,SAAS,EACT,cAAc,EACd,WAAW,EACX,YAAY,EACZ,OAAO,GACP,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,YAAY,EACX,OAAO,EACP,QAAQ,EACR,KAAK,EACL,qBAAqB,EACrB,QAAQ,EACR,SAAS,GACT,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EACX,aAAa,EACb,aAAa,EACb,cAAc,EACd,MAAM,EACN,oBAAoB,EACpB,SAAS,EACT,cAAc,EACd,WAAW,EACX,YAAY,EACZ,OAAO,GACP,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EACN,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,eAAe,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,YAAY,EACX,OAAO,EACP,QAAQ,EACR,KAAK,EACL,qBAAqB,EACrB,QAAQ,EACR,SAAS,GACT,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,14 @@
1
+ // src/errors/kit-error.ts
2
+ class KitError extends TypeError {
3
+ constructor(code, message, options) {
4
+ super(message, { cause: options?.cause });
5
+ this.name = "KitError";
6
+ this.code = code;
7
+ this.database = options?.database;
8
+ this.key = options?.key;
9
+ }
10
+ }
11
+
1
12
  // src/config/checks.ts
2
13
  function isDefinition(value) {
3
14
  if (typeof value !== "object" || value === null)
@@ -8,65 +19,67 @@ function isDefinition(value) {
8
19
  function definitionsOf(collections) {
9
20
  return Object.entries(collections).filter((entry) => isDefinition(entry[1]));
10
21
  }
11
- var refuse = (where, said) => {
12
- throw new TypeError(`defineConfig: ${where} ${said}`);
22
+ var refuse = (name, said, key) => {
23
+ throw new KitError("CONFIG", `defineConfig: database "${name}" ${said}`, {
24
+ database: name,
25
+ key
26
+ });
13
27
  };
14
28
  var OWNED = ["db", "session", "actor", "autoSync"];
15
- function checkOwned(where, what, options) {
29
+ function checkOwned(name, what, options, forKey) {
16
30
  if (typeof options !== "object" || options === null)
17
31
  return;
18
32
  for (const key of OWNED) {
19
33
  if (key in options) {
20
- refuse(where, `has "${key}" in ${what}, which the kit decides: ` + "a database is named by its key, `as` and `withSession` carry the " + "actor and the session, and `autoSync` is the database's");
34
+ refuse(name, `has "${key}" in ${what}, which the kit decides: ` + "a database is named by its key, `as` and `withSession` carry the " + "actor and the session, and `autoSync` is the database's", forKey);
21
35
  }
22
36
  }
23
37
  }
24
38
  function checkDatabase(name, config) {
25
- const where = `database "${name}"`;
26
39
  if (typeof config !== "object" || config === null) {
27
- refuse(where, "is not a configuration object");
40
+ refuse(name, "is not a configuration object");
28
41
  }
29
42
  const hasUri = config.uri !== undefined;
30
43
  const hasClient = config.client !== undefined;
31
44
  if (hasUri === hasClient) {
32
- refuse(where, hasUri ? "has both a uri and a client: pass the one it should use" : "has neither a uri nor a client");
45
+ refuse(name, hasUri ? "has both a uri and a client: pass the one it should use" : "has neither a uri nor a client");
33
46
  }
34
47
  if (hasUri && (typeof config.uri !== "string" || config.uri === "")) {
35
- refuse(where, "has a uri that is not a string");
48
+ refuse(name, "has a uri that is not a string");
36
49
  }
37
50
  if (hasClient && typeof config.client?.db !== "function") {
38
- refuse(where, "has a client that is not a MongoClient");
51
+ refuse(name, "has a client that is not a MongoClient");
39
52
  }
40
53
  if (hasClient && config.clientOptions !== undefined) {
41
- refuse(where, "has client options beside a client it did not open: pass them where the client is made");
54
+ refuse(name, "has client options beside a client it did not open: pass them where the client is made");
42
55
  }
43
56
  if (config.database !== undefined && config.database === "") {
44
- refuse(where, "has an empty database name");
57
+ refuse(name, "has an empty database name");
45
58
  }
46
59
  if (typeof config.collections !== "object" || config.collections === null) {
47
- refuse(where, "has no collections object");
60
+ refuse(name, "has no collections object");
48
61
  }
49
62
  const definitions = definitionsOf(config.collections);
50
63
  if (definitions.length === 0) {
51
- refuse(where, "has a collections object with no definition in it: pass the module, as in `import * as collections`");
64
+ refuse(name, "has a collections object with no definition in it: pass the module, as in `import * as collections`");
52
65
  }
53
66
  const byName = new Map;
54
67
  for (const [key, definition] of definitions) {
55
68
  const seen = byName.get(definition.name);
56
69
  if (seen !== undefined) {
57
- refuse(where, `wires "${seen}" and "${key}" to the same collection, "${definition.name}"`);
70
+ refuse(name, `wires "${seen}" and "${key}" to the same collection, "${definition.name}"`);
58
71
  }
59
72
  byName.set(definition.name, key);
60
73
  }
61
74
  const keys = new Set(definitions.map(([key]) => key));
62
75
  for (const key of Object.keys(config.optionsFor ?? {})) {
63
76
  if (!keys.has(key)) {
64
- refuse(where, `has options for "${key}", which it does not wire`);
77
+ refuse(name, `has options for "${key}", which it does not wire`, key);
65
78
  }
66
79
  }
67
- checkOwned(where, "options", config.options);
80
+ checkOwned(name, "options", config.options);
68
81
  for (const [key, options] of Object.entries(config.optionsFor ?? {})) {
69
- checkOwned(where, `the options of "${key}"`, options);
82
+ checkOwned(name, `the options of "${key}"`, options, key);
70
83
  }
71
84
  return definitions;
72
85
  }
@@ -74,18 +87,18 @@ function checkDatabase(name, config) {
74
87
  // src/config/define-config.ts
75
88
  function databasesOf(config) {
76
89
  if (typeof config !== "object" || config === null) {
77
- throw new TypeError("defineConfig: a configuration object is required");
90
+ throw new KitError("CONFIG", "defineConfig: a configuration object is required");
78
91
  }
79
92
  if (!("databases" in config)) {
80
93
  return { default: config };
81
94
  }
82
95
  const { databases } = config;
83
96
  if (typeof databases !== "object" || databases === null) {
84
- throw new TypeError("defineConfig: databases is not an object");
97
+ throw new KitError("CONFIG", "defineConfig: databases must be an object of databases by name, " + "as `{ databases: { main: … } }`. One database is the " + "configuration itself, and names itself with `database`.");
85
98
  }
86
99
  const names = Object.keys(databases);
87
100
  if (names.length === 0) {
88
- throw new TypeError("defineConfig: databases names none");
101
+ throw new KitError("CONFIG", "defineConfig: databases names none. Give it at least one, " + "as `{ databases: { main: … } }`.");
89
102
  }
90
103
  return databases;
91
104
  }
@@ -102,7 +115,7 @@ function defineConfig(config) {
102
115
  async function discoverCollections(options) {
103
116
  const { glob, cwd = process.cwd(), export: name } = options;
104
117
  if (typeof glob !== "string" || glob === "") {
105
- throw new TypeError("discoverCollections: a glob is required");
118
+ throw new KitError("DISCOVERY", "discoverCollections: a glob is required");
106
119
  }
107
120
  const paths = await Array.fromAsync(new Bun.Glob(glob).scan({ cwd }));
108
121
  const found = [];
@@ -111,12 +124,12 @@ async function discoverCollections(options) {
111
124
  const module = await import(`${cwd}/${path}`);
112
125
  const definitions = name === undefined ? definitionsOf(module) : isDefinition(module[name]) ? [[name, module[name]]] : [];
113
126
  if (name !== undefined && definitions.length === 0) {
114
- throw new TypeError(`discoverCollections: ${path} exports no definition named "${name}"`);
127
+ throw new KitError("DISCOVERY", `discoverCollections: ${path} exports no definition named "${name}"`, { key: path });
115
128
  }
116
129
  for (const [, definition] of definitions) {
117
130
  const seen = byName.get(definition.name);
118
131
  if (seen !== undefined && seen !== path) {
119
- throw new TypeError(`discoverCollections: ${seen} and ${path} both define the collection "${definition.name}"`);
132
+ throw new KitError("DISCOVERY", `discoverCollections: ${seen} and ${path} both define the collection "${definition.name}"`, { key: path });
120
133
  }
121
134
  byName.set(definition.name, path);
122
135
  found.push(definition);
@@ -140,7 +153,7 @@ function derived(ctx, change) {
140
153
  function databaseOf(ctx, name) {
141
154
  const found = ctx.databases.find((database) => database.name === name);
142
155
  if (!found) {
143
- throw new TypeError(`This kit has no database "${name}": it has ${ctx.databases.map((database) => `"${database.name}"`).join(", ")}.`);
156
+ throw new KitError("NO_DATABASE", `This kit has no database "${name}": it has ${ctx.databases.map((database) => `"${database.name}"`).join(", ")}.`, { database: name });
144
157
  }
145
158
  return found;
146
159
  }
@@ -208,13 +221,13 @@ function clientFor(ctx, on) {
208
221
  const [only] = clients;
209
222
  if (clients.size === 1 && only)
210
223
  return only;
211
- throw new TypeError("transaction: this kit holds more than one client, and a transaction " + "lives on one. Name the database it runs on, as `{ on: 'main' }`.");
224
+ throw new KitError("TRANSACTION", "transaction: this kit holds more than one client, and a transaction " + "lives on one. Name the database it runs on, as `{ on: 'main' }`.");
212
225
  }
213
226
  function hostFor(ctx, on) {
214
227
  if (!ctx.session)
215
228
  return clientFor(ctx, on);
216
229
  if (on !== undefined) {
217
- throw new TypeError("transaction: this kit is already in a session, which this call " + "joins, so `on` has no client left to choose.");
230
+ throw new KitError("TRANSACTION", "transaction: this kit is already in a session, which this call " + "joins, so `on` has no client left to choose.");
218
231
  }
219
232
  return ctx.session;
220
233
  }
@@ -228,7 +241,7 @@ async function transact(ctx, build, fn, options) {
228
241
  // src/kit/derive.ts
229
242
  async function closeKit(ctx) {
230
243
  if (!ctx.root) {
231
- throw new TypeError("close: this kit came from `as`, `withSession` or a transaction. " + "Close the kit `createKit` returned — the clients are shared.");
244
+ throw new KitError("DERIVED", "close: this kit came from `as`, `withSession` or a transaction. " + "Close the kit `createKit` returned — the clients are shared.");
232
245
  }
233
246
  for (const database of ctx.databases) {
234
247
  await database.connection?.close();
@@ -260,7 +273,7 @@ function kitOf(ctx) {
260
273
  get db() {
261
274
  const [only] = ctx.databases;
262
275
  if (ctx.databases.length !== 1 || !only) {
263
- throw new TypeError("kit.db: this kit has several databases. Read the one you mean, " + `as \`kit.databases.${ctx.databases[0]?.name ?? "main"}\`.`);
276
+ throw new KitError("SEVERAL_DATABASES", "kit.db: this kit has several databases. Read the one you mean, " + `as \`kit.databases.${ctx.databases[0]?.name ?? "main"}\`.`);
264
277
  }
265
278
  return scopeFor(only.name);
266
279
  },
@@ -312,7 +325,7 @@ async function open(config) {
312
325
  function checkCollisions(name, db, keys) {
313
326
  for (const key of keys) {
314
327
  if (key in db) {
315
- throw new TypeError(`createKit: database "${name}" wires a collection under "${key}", ` + "which is a member of the driver's Db: it would be unreachable. " + "Export that definition under another name.");
328
+ throw new KitError("COLLISION", `createKit: database "${name}" wires a collection under "${key}", ` + "which is a member of the driver's Db: it would be unreachable. " + "Export that definition under another name.", { database: name, key });
316
329
  }
317
330
  }
318
331
  }
@@ -350,10 +363,11 @@ async function createKit(config) {
350
363
  return kitOf(ctx);
351
364
  }
352
365
  export {
366
+ KitError,
353
367
  createKit,
354
368
  defineConfig,
355
369
  discoverCollections
356
370
  };
357
371
 
358
- //# debugId=00B9BBA5C20F9E8D64756E2164756E21
372
+ //# debugId=D45C9A203331820F64756E2164756E21
359
373
  //# sourceMappingURL=index.js.map