@askdb/introspect 0.3.0-beta.2 → 0.3.0-beta.20

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 (46) hide show
  1. package/README.md +75 -3
  2. package/dist/index.d.ts +3 -2
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +2 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/kit/driver.d.ts +76 -0
  7. package/dist/kit/driver.d.ts.map +1 -0
  8. package/dist/kit/driver.js +156 -0
  9. package/dist/kit/driver.js.map +1 -0
  10. package/dist/kit/filters.d.ts +29 -0
  11. package/dist/kit/filters.d.ts.map +1 -0
  12. package/dist/kit/filters.js +58 -0
  13. package/dist/kit/filters.js.map +1 -0
  14. package/dist/kit/ids.d.ts +16 -0
  15. package/dist/kit/ids.d.ts.map +1 -0
  16. package/dist/kit/ids.js +20 -0
  17. package/dist/kit/ids.js.map +1 -0
  18. package/dist/kit/index.d.ts +18 -0
  19. package/dist/kit/index.d.ts.map +1 -0
  20. package/dist/kit/index.js +18 -0
  21. package/dist/kit/index.js.map +1 -0
  22. package/dist/kit/label.d.ts +44 -0
  23. package/dist/kit/label.d.ts.map +1 -0
  24. package/dist/kit/label.js +110 -0
  25. package/dist/kit/label.js.map +1 -0
  26. package/dist/kit/provider.d.ts +57 -0
  27. package/dist/kit/provider.d.ts.map +1 -0
  28. package/dist/kit/provider.js +50 -0
  29. package/dist/kit/provider.js.map +1 -0
  30. package/dist/kit/rows.d.ts +42 -0
  31. package/dist/kit/rows.d.ts.map +1 -0
  32. package/dist/kit/rows.js +86 -0
  33. package/dist/kit/rows.js.map +1 -0
  34. package/dist/registry.d.ts +188 -0
  35. package/dist/registry.d.ts.map +1 -0
  36. package/dist/registry.js +156 -0
  37. package/dist/registry.js.map +1 -0
  38. package/dist/render/render.d.ts +27 -3
  39. package/dist/render/render.d.ts.map +1 -1
  40. package/dist/render/render.js +67 -11
  41. package/dist/render/render.js.map +1 -1
  42. package/dist/render/types.d.ts +10 -0
  43. package/dist/render/types.d.ts.map +1 -1
  44. package/dist/types.d.ts +13 -1
  45. package/dist/types.d.ts.map +1 -1
  46. package/package.json +14 -7
package/README.md CHANGED
@@ -7,13 +7,17 @@ Engine-agnostic introspection orchestrator for AskDB. Defines the `Connector` co
7
7
  ## Install
8
8
 
9
9
  ```bash
10
- pnpm add @askdb/introspect @askdb/core
10
+ # `ai` (Vercel AI SDK 6 or 7) is a required peer dependency of @askdb/core
11
+ pnpm add @askdb/introspect @askdb/core ai
11
12
  # Plus an integration package for the engine you're targeting, e.g.:
12
13
  pnpm add @askdb/postgres pg
13
- # Or for Prisma schema-file introspection:
14
- pnpm add @askdb/prisma
14
+ # Or for Prisma schema-file introspection (pnpm 11 must approve the @prisma/engines build;
15
+ # --allow-build needs pnpm 10.4 or later):
16
+ pnpm add --allow-build=@prisma/engines @askdb/prisma
15
17
  ```
16
18
 
19
+ See [the Prisma guide](https://askdb.tools/guides/integrations/prisma/#install) for other package managers.
20
+
17
21
  ## Programmatic usage
18
22
 
19
23
  ```ts
@@ -42,6 +46,8 @@ const result = await introspect(
42
46
  );
43
47
  ```
44
48
 
49
+ To get the exact `schema.json` bytes without writing anything (for previews or drift checks), use `renderSchemaV2Body(result.schema, { schemaId, provider: result.provider, existingArtifactDir })`. It is the same function `renderToSchemaV2` writes through — including the merge that carries human-set `sensitive` flags over from an existing artifact — and it backs `askdb introspect --out`, `--print`, and `--diff`.
50
+
45
51
  ## CLI
46
52
 
47
53
  The user-facing CLI for introspection ships in the [`askdb`](https://www.npmjs.com/package/askdb) package as `askdb introspect`. `@askdb/introspect` does not provide a standalone binary.
@@ -54,3 +60,69 @@ A `Connector<TInput>` has two methods:
54
60
  - `templates?(): SqlTemplateBundle` — optional; only relevant for engines that introspect via catalog SQL.
55
61
 
56
62
  The integration package owns its own input type (e.g. `PostgresIntrospectionInput`, `PrismaIntrospectionInput`). `@askdb/introspect` does not assume a live catalog runner exists, a bundle path exists, a schema-file path exists, or a template suite exists.
63
+
64
+ ### Connector registry
65
+
66
+ Hosts that pick the engine from configuration use the connector provider registry. The example below also uses `@askdb/config` (for `getAskDbRuntimeConfig()`) and `@askdb/mysql`; install the engine packages you register, and `@askdb/config` when you resolve connections from `askdb.config.ts`. Every engine package exports an adapter: `postgresConnectorProvider`, `mysqlConnectorProvider`, `sqliteConnectorProvider`, `sqlServerConnectorProvider`, `prismaConnectorProvider`. Provider ids are open strings (`ConnectorProviderId`), so a third-party engine package can export `{ provider: "oracle", ... }` and register it the same way.
67
+
68
+ ```ts
69
+ import { getAskDbRuntimeConfig } from "@askdb/config";
70
+ import { createConnectorRegistry, introspect } from "@askdb/introspect";
71
+ import { postgresConnectorProvider } from "@askdb/postgres";
72
+ import { mysqlConnectorProvider } from "@askdb/mysql";
73
+
74
+ const registry = createConnectorRegistry([postgresConnectorProvider, mysqlConnectorProvider]);
75
+
76
+ // The adapter merges explicit values with askdb.config/env (explicit wins).
77
+ const resolved = registry.resolveConnection("mysql", { runtime: getAskDbRuntimeConfig() });
78
+ if (!resolved.ok) throw new Error(resolved.error);
79
+ console.log(`Introspecting ${resolved.sourceLabel}`); // host, port and database only
80
+
81
+ const { connector, input } = registry.createConnector({ provider: "mysql", ...resolved.connection });
82
+ await introspect(input, { outDir: "./askdb", schemaId: "shop" }, { connector });
83
+ ```
84
+
85
+ `ConnectorProviderAdapter` is `{ provider, createConnector(config), getTemplates?(), resolveConnection?(request), connectionLabelParts?(connection) }`. `resolveConnection` returns only the connection (or an error); the registry adds `sourceLabel`, which it always builds with `formatConnectionLabel` from the adapter's `connectionLabelParts` (host, port, database, or a file path). No adapter supplies label text, so `sourceLabel` is safe to display for any adapter; one without `connectionLabelParts` gets `configured <provider> connection` ([ADR 0011](https://github.com/Ygilany/AskDB/blob/main/docs/adrs/0011-connection-labels-from-parsed-parts.md)). See [Connector authoring](https://github.com/Ygilany/AskDB/blob/main/docs/integration/connectors.md#registering-with-askdb-hosts) for writing an adapter.
86
+
87
+ An engine package your users may not have installed registers as a **lazy entry**, `{ provider, load }`, where `load()` imports the package and returns its adapter. `hasProvider()` and `providers()` list it without loading. Call `await registry.load(provider)` once the engine is selected: it imports the package once, shares concurrent calls, retries after a failure, and checks the adapter's `provider`. Until then the other methods throw for that entry. The `askdb` CLI and Studio register `@askdb/prisma` this way, with `createOptionalDriverLoader` and `connectorPackageMissingMessage({ provider, packageName, allowBuilds })` for the install hint ([ADR 0008](https://github.com/Ygilany/AskDB/blob/main/docs/adrs/0008-engine-packages-and-connector-registry.md), 2026-11 amendment):
88
+
89
+ ```ts
90
+ const registry = createConnectorRegistry([
91
+ postgresConnectorProvider,
92
+ { provider: "prisma", load: async () => (await import("@askdb/prisma")).prismaConnectorProvider },
93
+ ]);
94
+ await registry.load(engine); // a no-op for an adapter object
95
+ ```
96
+
97
+ This bare `import()` surfaces Node's own module-not-found error when the package is missing. To give an install hint instead, wrap the import in `createOptionalDriverLoader`, as [Registering an engine that may not be installed](https://github.com/Ygilany/AskDB/blob/main/docs/integration/connectors.md#registering-an-engine-that-may-not-be-installed) shows.
98
+
99
+ ### Engine kit (`@askdb/introspect/kit`)
100
+
101
+ The `@askdb/introspect/kit` subpath holds the engine-agnostic helpers every first-party engine package uses, so a new engine does not copy them:
102
+
103
+ | Helper | Purpose |
104
+ | --- | --- |
105
+ | `createOptionalDriverLoader({ packageName, specifier?, importDriver, missingMessage })`, `isDriverInstalled(packageName, { resolveFrom? })`, `missingDriverMessage({ engine, packageName })`, `rethrowDriverImportError` | Lazy, cached loading of an optional driver peer (`pg`, `mysql2`, …): the engine package's own `import()` first, then the caller's project (`resolveFrom`, default `process.cwd()`). A missing peer rejects with an `AskDbError`; the failed cache slot is cleared so a later call retries. `missingDriverMessage` is the first-party engines' message (it suggests a one-off `askdb` command, which registers only those engines); a third-party engine passes its own `missingMessage`. Chain `.catch(rethrowDriverImportError)` on your `import()` so bundlers such as esbuild treat the peer as optional. |
106
+ | `compileTableFilters(patterns)`, `ambiguousFilterWarnings(patterns, qualifiedNames)` | `IntrospectionFilters.tables` glob matching (`*`, `?`) and the `ambiguous_filter` warning for patterns that match nothing. |
107
+ | `makeTableId(schema, table)`, `makeColumnId(schema, table, column)` | Schema v2 ids (`table:<schema>.<name>`, `table:<schema>.<name>#<column>`). |
108
+ | `rowsToRecords(result, { expectedColumns?, source? })`, `groupBy`, `buildOrderedGroups`, `byName`, `sortedUnique`, `mapFkAction` | Folding positional `CatalogQueryResult` rows into Schema v2 tables, constraints, and indexes. |
109
+ | `formatConnectionLabel`, `parseConnectionUrl`, `ConnectionLabelParts` | `ConnectionLabelParts` is what an adapter's `connectionLabelParts` hook returns (take the parts from your driver's own parser where it has one; `parseConnectionUrl` is a strict fallback for a standard URL). `formatConnectionLabel` is what `registry.connectionLabel()` applies to those parts: host, port and database (or a file path), else `configured <engine> connection` ([ADR 0011](https://github.com/Ygilany/AskDB/blob/main/docs/adrs/0011-connection-labels-from-parsed-parts.md)). |
110
+ | `defineLiveConnectorProvider({ provider, displayName, runtimeKey, connectionNoun, missingConnection, fromExportUnsupported?, createConnector, createRunner, connectionLabelParts })` | The full `ConnectorProviderAdapter` for an engine that only introspects through a live `CatalogQueryRunner`. `@askdb/mysql`, `@askdb/sqlite`, and `@askdb/sqlserver` use it. |
111
+ | `runtimeIntrospectionString(runtime, key)` | A non-empty string from `runtime.introspection[key]`, the per-engine values `@askdb/config` resolves (for example `postgresDatabaseUrl`). |
112
+
113
+ ```ts
114
+ import { createOptionalDriverLoader, rethrowDriverImportError } from "@askdb/introspect/kit";
115
+
116
+ const driver = createOptionalDriverLoader<typeof import("my-driver")>({
117
+ packageName: "my-driver",
118
+ // Keep the import literal in *your* package, where the peer is declared, with the
119
+ // rethrowing .catch() on it, so bundlers treat the peer as optional.
120
+ importDriver: () => import("my-driver").catch(rethrowDriverImportError),
121
+ missingMessage:
122
+ "The MyEngine connector requires the optional `my-driver` peer dependency. Install it in your project (e.g. `pnpm add my-driver`).",
123
+ });
124
+ ```
125
+
126
+ ## License
127
+
128
+ Apache-2.0 © [Yahya Gilany](https://yahyagilany.io). See [LICENSE](./LICENSE) and [NOTICE](./NOTICE).
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export type { SqlSchema, SqlNamespace, SqlTable, SqlColumn, SqlForeignKey, SqlForeignKeyAction, SqlUnique, SqlIndex, SqlCheck, SqlEnum, SqlSequence, SqlView, IntrospectionFilters, IntrospectionResult, IntrospectionWarning, SqlTemplate, SqlTemplateBundle, CatalogQueryResult, CatalogQueryRunner, Connector, } from "./types.js";
2
- export type { RenderOptions, RenderResult } from "./render/types.js";
2
+ export type { RenderOptions, RenderResult, RenderBodyOptions, RenderBodyResult, } from "./render/types.js";
3
3
  export { introspect, type IntrospectOptions, type IntrospectResult, } from "./introspect.js";
4
- export { renderToSchemaV2, toV2SchemaJson, compactPostgresType } from "./render/render.js";
4
+ export { BUILT_IN_CONNECTOR_PROVIDERS, connectorPackageMissingMessage, connectorProviderMissingMessage, createConnectorRegistry, type BuiltInConnectorProvider, type ConnectorConfig, type ConnectorConnection, type ConnectorConnectionRequest, type ConnectorConnectionResolution, type ConnectorConnectionResult, type ConnectorProviderAdapter, type ConnectorProviderAdapters, type ConnectorProviderEntry, type ConnectorProviderId, type ConnectorRegistry, type ConnectorResult, type ConnectorRuntimeConfig, type LazyConnectorProviderAdapter, } from "./registry.js";
5
+ export { renderToSchemaV2, renderSchemaV2Body, isSchemaV2Json, toV2SchemaJson, compactPostgresType, } from "./render/render.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,WAAW,EACX,OAAO,EACP,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,GACV,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,aAAa,EACb,mBAAmB,EACnB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,WAAW,EACX,OAAO,EACP,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,GACV,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,4BAA4B,EAC5B,8BAA8B,EAC9B,+BAA+B,EAC/B,uBAAuB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,6BAA6B,EAClC,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,4BAA4B,GAClC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,mBAAmB,GACpB,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export { introspect, } from "./introspect.js";
2
- export { renderToSchemaV2, toV2SchemaJson, compactPostgresType } from "./render/render.js";
2
+ export { BUILT_IN_CONNECTOR_PROVIDERS, connectorPackageMissingMessage, connectorProviderMissingMessage, createConnectorRegistry, } from "./registry.js";
3
+ export { renderToSchemaV2, renderSchemaV2Body, isSchemaV2Json, toV2SchemaJson, compactPostgresType, } from "./render/render.js";
3
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyBA,OAAO,EACL,UAAU,GAGX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA8BA,OAAO,EACL,UAAU,GAGX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,4BAA4B,EAC5B,8BAA8B,EAC9B,+BAA+B,EAC/B,uBAAuB,GAexB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,mBAAmB,GACpB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Where to resolve an optional driver peer from when the engine package itself
3
+ * cannot see it. Defaults to `process.cwd()` — the caller's project root.
4
+ */
5
+ export type DriverLoadOptions = {
6
+ resolveFrom?: string;
7
+ };
8
+ export type OptionalDriverSpec<T> = {
9
+ /** npm package name of the optional peer (e.g. `"pg"`, `"mysql2"`). */
10
+ packageName: string;
11
+ /**
12
+ * Module specifier to import when falling back to the project root. Defaults
13
+ * to `packageName`; set it for subpath entry points such as `"mysql2/promise"`.
14
+ */
15
+ specifier?: string;
16
+ /**
17
+ * Imports the driver relative to the *engine package*. Must be a literal
18
+ * `() => import("pg").catch(rethrowDriverImportError)` written in the engine package, not
19
+ * here: the peer is declared (and installed next to) the engine package, and
20
+ * bundlers only see the dependency when the import is lexically in that
21
+ * package. The `.catch()` chained on the `import()` (any handler that
22
+ * rethrows the error unchanged) is how bundlers such as esbuild tell an
23
+ * optional import from a required one; the catch inside this loader is
24
+ * invisible to them.
25
+ */
26
+ importDriver: () => Promise<T>;
27
+ /** Message of the `AskDbError` thrown when the peer cannot be resolved from anywhere. */
28
+ missingMessage: string;
29
+ };
30
+ export type OptionalDriverLoader<T> = {
31
+ /**
32
+ * Resolve the driver: first through the engine package's own import, then
33
+ * from `resolveFrom` (default `process.cwd()`). Successful loads are cached
34
+ * per `resolveFrom`; failures clear the cache slot so a later call retries
35
+ * (e.g. after the user runs `pnpm add pg`). Rejects with an `AskDbError`
36
+ * carrying `missingMessage` when the peer is missing everywhere, and with an
37
+ * `AskDbError` naming the real failure (`cause` set) when the peer is
38
+ * installed but fails to load.
39
+ *
40
+ * Node 24 and later can keep a failed package lookup until the process exits,
41
+ * so a retry may still miss a peer installed after the first attempt. When
42
+ * the peer is on disk under `resolveFrom` but Node can't resolve it, the
43
+ * `AskDbError` says to restart the process instead of to install it.
44
+ */
45
+ load(options?: DriverLoadOptions): Promise<T>;
46
+ };
47
+ /**
48
+ * Build a lazy, cached loader for an optional database-driver peer. Engine
49
+ * packages call this once at module scope, so each engine keeps its own cache.
50
+ */
51
+ export declare function createOptionalDriverLoader<T>(spec: OptionalDriverSpec<T>): OptionalDriverLoader<T>;
52
+ /**
53
+ * True when `packageName` resolves from `resolveFrom` (default `process.cwd()`).
54
+ * A cheap, synchronous capability probe — it does not load the driver.
55
+ */
56
+ export declare function isDriverInstalled(packageName: string, options?: DriverLoadOptions): boolean;
57
+ /**
58
+ * The install hint the first-party engines' built-in catalog runners throw when
59
+ * their driver peer is missing, e.g.
60
+ * `missingDriverMessage({ engine: "Postgres", packageName: "pg" })`. It
61
+ * suggests a one-off `askdb` command, and the `askdb` binary registers only the
62
+ * first-party engines, so a third-party engine writes its own `missingMessage`.
63
+ */
64
+ export declare function missingDriverMessage(input: {
65
+ engine: string;
66
+ packageName: string;
67
+ }): string;
68
+ /**
69
+ * The handler an engine chains on its driver's `import()`:
70
+ * `() => import("pg").catch(rethrowDriverImportError)`. It rethrows unchanged,
71
+ * so the loader still classifies the error; its job is to sit on the
72
+ * `import()` expression, which is how bundlers such as esbuild tell an
73
+ * optional peer from a required one.
74
+ */
75
+ export declare function rethrowDriverImportError(error: unknown): never;
76
+ //# sourceMappingURL=driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/kit/driver.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI;IAClC,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;OASG;IACH,YAAY,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/B,yFAAyF;IACzF,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI;IACpC;;;;;;;;;;;;;OAaG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC/C,CAAC;AA0DF;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC,CA0DlG;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAQ3F;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAQ3F;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAE9D"}
@@ -0,0 +1,156 @@
1
+ import { AskDbError } from "@askdb/core";
2
+ import { existsSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import { dirname, join } from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ /**
7
+ * True when `cause` (or any error in its `cause` chain) is a Node module
8
+ * resolution failure (`ERR_MODULE_NOT_FOUND` / `MODULE_NOT_FOUND`) for the
9
+ * driver itself: the specifier Node could not find (`Cannot find package 'pg'`,
10
+ * `Cannot find module 'mysql2/promise'`, or Yarn PnP's `tried to access pg`)
11
+ * must be `packageName` or `specifier`, the entry point the loader asks for
12
+ * (default `packageName`). A different missing package whose name merely
13
+ * contains it (`pg-connection-string`), a path that happens to contain it
14
+ * (`/home/mssqluser/…`), or another file of the package (`pg/lib/missing`,
15
+ * which the installed driver failed to load) does not count. Anything else is a
16
+ * real error and must surface.
17
+ */
18
+ function isModuleResolutionFailure(cause, packageName, specifier = packageName) {
19
+ if (!(cause instanceof Error))
20
+ return false;
21
+ const nestedCause = cause.cause;
22
+ if (nestedCause && nestedCause !== cause && isModuleResolutionFailure(nestedCause, packageName, specifier)) {
23
+ return true;
24
+ }
25
+ const code = cause.code;
26
+ if (code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND")
27
+ return false;
28
+ const missing =
29
+ // Node: `Cannot find package 'pg' imported from …` / `Cannot find module 'mysql2/promise'`.
30
+ /Cannot find (?:module|package) '([^']+)'/.exec(cause.message)?.[1] ??
31
+ // Yarn PnP: `… tried to access pg, but it isn't declared in its dependencies …`.
32
+ /tried to access ([^\s,]+)/.exec(cause.message)?.[1];
33
+ return missing === packageName || missing === specifier;
34
+ }
35
+ /** The driver resolves from neither the engine package nor `resolveFrom`. */
36
+ class DriverNotFoundError extends AggregateError {
37
+ }
38
+ /** Node can't resolve the driver, but it is on disk in `nodeModules` (see `OptionalDriverLoader.load`). */
39
+ class DriverUnresolvableError extends AggregateError {
40
+ nodeModules;
41
+ constructor(errors, nodeModules) {
42
+ super(errors, "Optional peer dependency is installed but does not resolve");
43
+ this.nodeModules = nodeModules;
44
+ }
45
+ }
46
+ /**
47
+ * The `node_modules` directory under `fromDir` or one of its parents that holds
48
+ * `packageName`, checked on disk rather than through Node's resolver.
49
+ */
50
+ function nodeModulesHolding(fromDir, packageName) {
51
+ for (let dir = fromDir;; dir = dirname(dir)) {
52
+ if (existsSync(join(dir, "node_modules", packageName, "package.json")))
53
+ return join(dir, "node_modules");
54
+ if (dirname(dir) === dir)
55
+ return undefined;
56
+ }
57
+ }
58
+ /**
59
+ * Build a lazy, cached loader for an optional database-driver peer. Engine
60
+ * packages call this once at module scope, so each engine keeps its own cache.
61
+ */
62
+ export function createOptionalDriverLoader(spec) {
63
+ const { packageName, importDriver, missingMessage } = spec;
64
+ const specifier = spec.specifier ?? packageName;
65
+ const cache = new Map();
66
+ async function importOptional(options) {
67
+ try {
68
+ return await importDriver();
69
+ }
70
+ catch (cause) {
71
+ if (!isModuleResolutionFailure(cause, packageName, specifier))
72
+ throw cause;
73
+ const fromDir = options?.resolveFrom ?? process.cwd();
74
+ const projectRequire = createRequire(join(fromDir, "package.json"));
75
+ let resolved;
76
+ try {
77
+ resolved = projectRequire.resolve(specifier);
78
+ }
79
+ catch (projectCause) {
80
+ if (!isModuleResolutionFailure(projectCause, packageName, specifier))
81
+ throw projectCause;
82
+ const nodeModules = nodeModulesHolding(fromDir, packageName);
83
+ if (nodeModules)
84
+ throw new DriverUnresolvableError([cause, projectCause], nodeModules);
85
+ throw new DriverNotFoundError([cause, projectCause], `Unable to resolve optional \`${packageName}\` peer dependency`);
86
+ }
87
+ // Resolved in the project: any failure from here on is the installed
88
+ // driver failing to load, never "not installed".
89
+ return (await import(pathToFileURL(resolved).href));
90
+ }
91
+ }
92
+ return {
93
+ load(options) {
94
+ const key = options?.resolveFrom;
95
+ let promise = cache.get(key);
96
+ if (!promise) {
97
+ promise = importOptional(options).catch((cause) => {
98
+ cache.delete(key);
99
+ // Only a driver that resolves nowhere gets the install hint. A driver
100
+ // that is installed but fails to load (a missing dependency of its
101
+ // own, a native build error, …) reports that failure instead.
102
+ if (cause instanceof DriverNotFoundError)
103
+ throw new AskDbError(missingMessage, cause);
104
+ if (cause instanceof DriverUnresolvableError) {
105
+ throw new AskDbError(`\`${packageName}\` is in ${cause.nodeModules}, but Node can't load it in this process. ` +
106
+ "If it was installed while the process was running, restart the process: " +
107
+ "Node 24 and later can keep a failed package lookup until the process exits.", cause);
108
+ }
109
+ const detail = cause instanceof Error ? cause.message : String(cause);
110
+ throw new AskDbError(`The optional \`${packageName}\` peer dependency failed to load: ${detail}`, cause);
111
+ });
112
+ cache.set(key, promise);
113
+ }
114
+ return promise;
115
+ },
116
+ };
117
+ }
118
+ /**
119
+ * True when `packageName` resolves from `resolveFrom` (default `process.cwd()`).
120
+ * A cheap, synchronous capability probe — it does not load the driver.
121
+ */
122
+ export function isDriverInstalled(packageName, options) {
123
+ try {
124
+ const req = createRequire(join(options?.resolveFrom ?? process.cwd(), "package.json"));
125
+ req.resolve(packageName);
126
+ return true;
127
+ }
128
+ catch {
129
+ return false;
130
+ }
131
+ }
132
+ /**
133
+ * The install hint the first-party engines' built-in catalog runners throw when
134
+ * their driver peer is missing, e.g.
135
+ * `missingDriverMessage({ engine: "Postgres", packageName: "pg" })`. It
136
+ * suggests a one-off `askdb` command, and the `askdb` binary registers only the
137
+ * first-party engines, so a third-party engine writes its own `missingMessage`.
138
+ */
139
+ export function missingDriverMessage(input) {
140
+ const { engine, packageName } = input;
141
+ return (`The built-in ${engine} catalog query runner requires the optional \`${packageName}\` peer dependency. ` +
142
+ `Install it in your project (e.g. \`pnpm add ${packageName}\`) or include it in the same one-off command ` +
143
+ `(e.g. \`pnpm dlx -p askdb -p ${packageName} askdb ...\` or \`npx -p askdb -p ${packageName} askdb ...\`). ` +
144
+ `You can also pass a custom catalog query runner to the ${engine} connector.`);
145
+ }
146
+ /**
147
+ * The handler an engine chains on its driver's `import()`:
148
+ * `() => import("pg").catch(rethrowDriverImportError)`. It rethrows unchanged,
149
+ * so the loader still classifies the error; its job is to sit on the
150
+ * `import()` expression, which is how bundlers such as esbuild tell an
151
+ * optional peer from a required one.
152
+ */
153
+ export function rethrowDriverImportError(error) {
154
+ throw error;
155
+ }
156
+ //# sourceMappingURL=driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.js","sourceRoot":"","sources":["../../src/kit/driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { IntrospectionWarning } from "../types.js";
2
+ /**
3
+ * Minimal glob matcher for `IntrospectionFilters.tables`. Patterns match
4
+ * against `"<schema>.<name>"` strings; supported wildcards:
5
+ *
6
+ * * matches any run of characters (including dots)
7
+ * ? matches a single character
8
+ *
9
+ * Brace expansion (`{a,b}`) and character classes (`[abc]`) are intentionally
10
+ * not supported — keeping the surface small avoids a glob dependency. If a
11
+ * filter looks valid but matches nothing, emit an `ambiguous_filter` warning
12
+ * (see {@link ambiguousFilterWarnings}).
13
+ */
14
+ export declare function compileGlob(pattern: string): RegExp;
15
+ export type GlobMatcher = (qualifiedName: string) => boolean;
16
+ /**
17
+ * Returns a matcher that accepts a `"<schema>.<name>"` and returns true when
18
+ * any pattern matches. When `patterns` is empty or undefined, the matcher
19
+ * always returns true (no filtering).
20
+ */
21
+ export declare function compileTableFilters(patterns: ReadonlyArray<string> | undefined): GlobMatcher;
22
+ /**
23
+ * One `ambiguous_filter` warning per declared `tables` pattern that matches
24
+ * none of the emitted objects. `qualifiedNames` are the `"<schema>.<name>"` of
25
+ * every table and view that made it into the result. Warnings keep the
26
+ * declared pattern order (duplicates included).
27
+ */
28
+ export declare function ambiguousFilterWarnings(patterns: ReadonlyArray<string> | undefined, qualifiedNames: Iterable<string>): IntrospectionWarning[];
29
+ //# sourceMappingURL=filters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../../src/kit/filters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUnD;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,GAAG,WAAW,CAI5F;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,EAC3C,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC/B,oBAAoB,EAAE,CAWxB"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Minimal glob matcher for `IntrospectionFilters.tables`. Patterns match
3
+ * against `"<schema>.<name>"` strings; supported wildcards:
4
+ *
5
+ * * matches any run of characters (including dots)
6
+ * ? matches a single character
7
+ *
8
+ * Brace expansion (`{a,b}`) and character classes (`[abc]`) are intentionally
9
+ * not supported — keeping the surface small avoids a glob dependency. If a
10
+ * filter looks valid but matches nothing, emit an `ambiguous_filter` warning
11
+ * (see {@link ambiguousFilterWarnings}).
12
+ */
13
+ export function compileGlob(pattern) {
14
+ let out = "^";
15
+ for (const ch of pattern) {
16
+ if (ch === "*")
17
+ out += ".*";
18
+ else if (ch === "?")
19
+ out += ".";
20
+ else if (/[.+^${}()|[\]\\]/.test(ch))
21
+ out += "\\" + ch;
22
+ else
23
+ out += ch;
24
+ }
25
+ out += "$";
26
+ return new RegExp(out);
27
+ }
28
+ /**
29
+ * Returns a matcher that accepts a `"<schema>.<name>"` and returns true when
30
+ * any pattern matches. When `patterns` is empty or undefined, the matcher
31
+ * always returns true (no filtering).
32
+ */
33
+ export function compileTableFilters(patterns) {
34
+ if (!patterns || patterns.length === 0)
35
+ return () => true;
36
+ const compiled = patterns.map(compileGlob);
37
+ return (qualifiedName) => compiled.some((re) => re.test(qualifiedName));
38
+ }
39
+ /**
40
+ * One `ambiguous_filter` warning per declared `tables` pattern that matches
41
+ * none of the emitted objects. `qualifiedNames` are the `"<schema>.<name>"` of
42
+ * every table and view that made it into the result. Warnings keep the
43
+ * declared pattern order (duplicates included).
44
+ */
45
+ export function ambiguousFilterWarnings(patterns, qualifiedNames) {
46
+ if (!patterns || patterns.length === 0)
47
+ return [];
48
+ const names = [...qualifiedNames];
49
+ const warnings = [];
50
+ for (const pattern of patterns) {
51
+ const re = compileGlob(pattern);
52
+ if (!names.some((name) => re.test(name))) {
53
+ warnings.push({ code: "ambiguous_filter", filter: pattern });
54
+ }
55
+ }
56
+ return warnings;
57
+ }
58
+ //# sourceMappingURL=filters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filters.js","sourceRoot":"","sources":["../../src/kit/filters.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,IAAI,GAAG,GAAG,GAAG,CAAC;IACd,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,EAAE,KAAK,GAAG;YAAE,GAAG,IAAI,IAAI,CAAC;aACvB,IAAI,EAAE,KAAK,GAAG;YAAE,GAAG,IAAI,GAAG,CAAC;aAC3B,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC;;YAClD,GAAG,IAAI,EAAE,CAAC;IACjB,CAAC;IACD,GAAG,IAAI,GAAG,CAAC;IACX,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAID;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAA2C;IAC7E,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC;IAC1D,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC3C,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CACrC,QAA2C,EAC3C,cAAgC;IAEhC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClD,MAAM,KAAK,GAAG,CAAC,GAAG,cAAc,CAAC,CAAC;IAClC,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Schema v2 ID conventions (see docs/contracts/schema-v2.md):
3
+ *
4
+ * table:<schema>.<name>
5
+ * table:<schema>.<name>#<col>
6
+ *
7
+ * The schema prefix is always included (even for `public`) so cross-schema
8
+ * tables are unambiguous and IDs survive a future move between schemas
9
+ * without colliding. The `#` separator is reserved for column suffixes.
10
+ * Engines without Postgres-style schemas use `"public"` so IDs stay stable
11
+ * across engines: SQLite always, and MySQL for the connection's own database
12
+ * (with a database list, MySQL uses each database's name instead).
13
+ */
14
+ export declare function makeTableId(schemaName: string, tableName: string): string;
15
+ export declare function makeColumnId(schemaName: string, tableName: string, columnName: string): string;
16
+ //# sourceMappingURL=ids.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/kit/ids.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE9F"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Schema v2 ID conventions (see docs/contracts/schema-v2.md):
3
+ *
4
+ * table:<schema>.<name>
5
+ * table:<schema>.<name>#<col>
6
+ *
7
+ * The schema prefix is always included (even for `public`) so cross-schema
8
+ * tables are unambiguous and IDs survive a future move between schemas
9
+ * without colliding. The `#` separator is reserved for column suffixes.
10
+ * Engines without Postgres-style schemas use `"public"` so IDs stay stable
11
+ * across engines: SQLite always, and MySQL for the connection's own database
12
+ * (with a database list, MySQL uses each database's name instead).
13
+ */
14
+ export function makeTableId(schemaName, tableName) {
15
+ return `table:${schemaName}.${tableName}`;
16
+ }
17
+ export function makeColumnId(schemaName, tableName, columnName) {
18
+ return `table:${schemaName}.${tableName}#${columnName}`;
19
+ }
20
+ //# sourceMappingURL=ids.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/kit/ids.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CAAC,UAAkB,EAAE,SAAiB;IAC/D,OAAO,SAAS,UAAU,IAAI,SAAS,EAAE,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAkB,EAAE,SAAiB,EAAE,UAAkB;IACpF,OAAO,SAAS,UAAU,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `@askdb/introspect/kit` — shared building blocks for engine integration
3
+ * packages (`@askdb/postgres`, `@askdb/mysql`, `@askdb/sqlite`,
4
+ * `@askdb/sqlserver`, `@askdb/prisma`, and third-party engines).
5
+ *
6
+ * Nothing here is engine-specific: catalog SQL, row shapes, and dialect rules
7
+ * stay in each engine package. The kit only removes the mechanical code every
8
+ * engine would otherwise copy — optional-driver loading, table-glob filters,
9
+ * Schema v2 IDs, catalog-row folding, connection labels, and the
10
+ * connector-provider adapter for live-catalog-only engines.
11
+ */
12
+ export { createOptionalDriverLoader, isDriverInstalled, missingDriverMessage, rethrowDriverImportError, type DriverLoadOptions, type OptionalDriverLoader, type OptionalDriverSpec, } from "./driver.js";
13
+ export { ambiguousFilterWarnings, compileTableFilters, type GlobMatcher, } from "./filters.js";
14
+ export { makeColumnId, makeTableId } from "./ids.js";
15
+ export { buildOrderedGroups, byName, groupBy, mapFkAction, rowsToRecords, sortedUnique, type RowsToRecordsOptions, } from "./rows.js";
16
+ export { defineLiveConnectorProvider, runtimeIntrospectionString, type LiveCatalogInput, type LiveConnectorProviderSpec, } from "./provider.js";
17
+ export { formatConnectionLabel, parseConnectionUrl, type ConnectionLabelParts, } from "./label.js";
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/kit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,0BAA0B,EAC1B,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAErD,OAAO,EACL,kBAAkB,EAClB,MAAM,EACN,OAAO,EACP,WAAW,EACX,aAAa,EACb,YAAY,EACZ,KAAK,oBAAoB,GAC1B,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,EAC1B,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,GAC/B,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,KAAK,oBAAoB,GAC1B,MAAM,YAAY,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `@askdb/introspect/kit` — shared building blocks for engine integration
3
+ * packages (`@askdb/postgres`, `@askdb/mysql`, `@askdb/sqlite`,
4
+ * `@askdb/sqlserver`, `@askdb/prisma`, and third-party engines).
5
+ *
6
+ * Nothing here is engine-specific: catalog SQL, row shapes, and dialect rules
7
+ * stay in each engine package. The kit only removes the mechanical code every
8
+ * engine would otherwise copy — optional-driver loading, table-glob filters,
9
+ * Schema v2 IDs, catalog-row folding, connection labels, and the
10
+ * connector-provider adapter for live-catalog-only engines.
11
+ */
12
+ export { createOptionalDriverLoader, isDriverInstalled, missingDriverMessage, rethrowDriverImportError, } from "./driver.js";
13
+ export { ambiguousFilterWarnings, compileTableFilters, } from "./filters.js";
14
+ export { makeColumnId, makeTableId } from "./ids.js";
15
+ export { buildOrderedGroups, byName, groupBy, mapFkAction, rowsToRecords, sortedUnique, } from "./rows.js";
16
+ export { defineLiveConnectorProvider, runtimeIntrospectionString, } from "./provider.js";
17
+ export { formatConnectionLabel, parseConnectionUrl, } from "./label.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/kit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,0BAA0B,EAC1B,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,GAIzB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,EACvB,mBAAmB,GAEpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAErD,OAAO,EACL,kBAAkB,EAClB,MAAM,EACN,OAAO,EACP,WAAW,EACX,aAAa,EACb,YAAY,GAEb,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,GAG3B,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,qBAAqB,EACrB,kBAAkB,GAEnB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Connection labels: the credential-free text shown for a configured database
3
+ * connection (Studio's `GET /api/introspect/status` `sourceLabel`).
4
+ *
5
+ * A label is built only from parts an engine's parser extracted cleanly — host,
6
+ * port, database, or a SQLite file path — and only when each part passes the
7
+ * allowlist below. No other substring of the input is ever copied. Input that
8
+ * does not parse cleanly, or a part that fails its allowlist, becomes
9
+ * `configured <engine> connection`. Nothing here masks: see
10
+ * docs/adrs/0011-connection-labels-from-parsed-parts.md for why.
11
+ */
12
+ /** What an engine's parser may hand to `formatConnectionLabel`. */
13
+ export type ConnectionLabelParts = {
14
+ host?: string;
15
+ port?: string;
16
+ database?: string;
17
+ } | {
18
+ file: string;
19
+ };
20
+ /**
21
+ * Build a connection label from parsed parts: `<engine>://host[:port][/database]`
22
+ * for network engines, the path itself for a file. Returns
23
+ * `configured <engine> connection` when `parts` is `undefined` (the input did
24
+ * not parse) or any part fails its allowlist. The shape is checked at runtime
25
+ * too, because a plain-JS adapter can return anything: a value that isn't a
26
+ * plain object (a string, an array, a `URL`), or a part that isn't a string,
27
+ * also gets the fallback instead of throwing.
28
+ */
29
+ export declare function formatConnectionLabel(engine: string, parts: ConnectionLabelParts | undefined): string;
30
+ /**
31
+ * Parse a standard `scheme://[user[:password]@]host[:port][/database][?query]`
32
+ * connection URL (Postgres, MySQL, SQL Server `mssql://`) into label parts.
33
+ * Userinfo and the query string are never returned. Returns `undefined` —
34
+ * so the label falls back — when:
35
+ *
36
+ * - the scheme is not one of `schemes` (so `jdbc:postgresql://…`, a quoted
37
+ * URL, and `postgres:/…` all fall back);
38
+ * - the input contains whitespace, a control character, or a `#`;
39
+ * - an `@` appears after the authority (a password containing `/`, `?` or `#`
40
+ * cut the authority short, so where it ends is unknown);
41
+ * - the host is not a single `host[:port]`, or the path has more than one segment.
42
+ */
43
+ export declare function parseConnectionUrl(input: string, schemes: readonly string[]): ConnectionLabelParts | undefined;
44
+ //# sourceMappingURL=label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../src/kit/label.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,mEAAmE;AACnE,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AASrB;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,oBAAoB,GAAG,SAAS,GACtC,MAAM,CAmBR;AAWD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,oBAAoB,GAAG,SAAS,CAiBlC"}