@askdb/introspect 0.3.0-beta.16 → 0.3.0-beta.18
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 +54 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/kit/driver.d.ts +71 -0
- package/dist/kit/driver.d.ts.map +1 -0
- package/dist/kit/driver.js +127 -0
- package/dist/kit/driver.js.map +1 -0
- package/dist/kit/filters.d.ts +29 -0
- package/dist/kit/filters.d.ts.map +1 -0
- package/dist/kit/filters.js +58 -0
- package/dist/kit/filters.js.map +1 -0
- package/dist/kit/ids.d.ts +16 -0
- package/dist/kit/ids.d.ts.map +1 -0
- package/dist/kit/ids.js +20 -0
- package/dist/kit/ids.js.map +1 -0
- package/dist/kit/index.d.ts +18 -0
- package/dist/kit/index.d.ts.map +1 -0
- package/dist/kit/index.js +18 -0
- package/dist/kit/index.js.map +1 -0
- package/dist/kit/label.d.ts +44 -0
- package/dist/kit/label.d.ts.map +1 -0
- package/dist/kit/label.js +110 -0
- package/dist/kit/label.js.map +1 -0
- package/dist/kit/provider.d.ts +57 -0
- package/dist/kit/provider.d.ts.map +1 -0
- package/dist/kit/provider.js +50 -0
- package/dist/kit/provider.js.map +1 -0
- package/dist/kit/rows.d.ts +42 -0
- package/dist/kit/rows.d.ts.map +1 -0
- package/dist/kit/rows.js +86 -0
- package/dist/kit/rows.js.map +1 -0
- package/dist/registry.d.ts +144 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +91 -0
- package/dist/registry.js.map +1 -0
- package/dist/render/render.d.ts +23 -1
- package/dist/render/render.d.ts.map +1 -1
- package/dist/render/render.js +45 -7
- package/dist/render/render.js.map +1 -1
- package/dist/render/types.d.ts +10 -0
- package/dist/render/types.d.ts.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -7,7 +7,8 @@ Engine-agnostic introspection orchestrator for AskDB. Defines the `Connector` co
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
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
14
|
# Or for Prisma schema-file introspection:
|
|
@@ -42,6 +43,8 @@ const result = await introspect(
|
|
|
42
43
|
);
|
|
43
44
|
```
|
|
44
45
|
|
|
46
|
+
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`.
|
|
47
|
+
|
|
45
48
|
## CLI
|
|
46
49
|
|
|
47
50
|
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.
|
|
@@ -55,6 +58,56 @@ A `Connector<TInput>` has two methods:
|
|
|
55
58
|
|
|
56
59
|
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.
|
|
57
60
|
|
|
61
|
+
### Connector registry
|
|
62
|
+
|
|
63
|
+
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.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { getAskDbRuntimeConfig } from "@askdb/config";
|
|
67
|
+
import { createConnectorRegistry, introspect } from "@askdb/introspect";
|
|
68
|
+
import { postgresConnectorProvider } from "@askdb/postgres";
|
|
69
|
+
import { mysqlConnectorProvider } from "@askdb/mysql";
|
|
70
|
+
|
|
71
|
+
const registry = createConnectorRegistry([postgresConnectorProvider, mysqlConnectorProvider]);
|
|
72
|
+
|
|
73
|
+
// The adapter merges explicit values with askdb.config/env (explicit wins).
|
|
74
|
+
const resolved = registry.resolveConnection("mysql", { runtime: getAskDbRuntimeConfig() });
|
|
75
|
+
if (!resolved.ok) throw new Error(resolved.error);
|
|
76
|
+
console.log(`Introspecting ${resolved.sourceLabel}`); // host, port and database only
|
|
77
|
+
|
|
78
|
+
const { connector, input } = registry.createConnector({ provider: "mysql", ...resolved.connection });
|
|
79
|
+
await introspect(input, { outDir: "./askdb", schemaId: "shop" }, { connector });
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`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](../../docs/adrs/0011-connection-labels-from-parsed-parts.md)). See [Connector authoring](../../docs/integration/connectors.md#registering-with-askdb-hosts) for writing an adapter.
|
|
83
|
+
|
|
84
|
+
### Engine kit (`@askdb/introspect/kit`)
|
|
85
|
+
|
|
86
|
+
The `@askdb/introspect/kit` subpath holds the engine-agnostic helpers every first-party engine package uses, so a new engine does not copy them:
|
|
87
|
+
|
|
88
|
+
| Helper | Purpose |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `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. |
|
|
91
|
+
| `compileTableFilters(patterns)`, `ambiguousFilterWarnings(patterns, qualifiedNames)` | `IntrospectionFilters.tables` glob matching (`*`, `?`) and the `ambiguous_filter` warning for patterns that match nothing. |
|
|
92
|
+
| `makeTableId(schema, table)`, `makeColumnId(schema, table, column)` | Schema v2 ids (`table:<schema>.<name>`, `table:<schema>.<name>#<column>`). |
|
|
93
|
+
| `rowsToRecords(result, { expectedColumns?, source? })`, `groupBy`, `buildOrderedGroups`, `byName`, `sortedUnique`, `mapFkAction` | Folding positional `CatalogQueryResult` rows into Schema v2 tables, constraints, and indexes. |
|
|
94
|
+
| `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](../../docs/adrs/0011-connection-labels-from-parsed-parts.md)). |
|
|
95
|
+
| `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. |
|
|
96
|
+
| `runtimeIntrospectionString(runtime, key)` | A non-empty string from `runtime.introspection[key]`, the per-engine values `@askdb/config` resolves (for example `postgresDatabaseUrl`). |
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { createOptionalDriverLoader, rethrowDriverImportError } from "@askdb/introspect/kit";
|
|
100
|
+
|
|
101
|
+
const driver = createOptionalDriverLoader<typeof import("my-driver")>({
|
|
102
|
+
packageName: "my-driver",
|
|
103
|
+
// Keep the import literal in *your* package, where the peer is declared, with the
|
|
104
|
+
// rethrowing .catch() on it, so bundlers treat the peer as optional.
|
|
105
|
+
importDriver: () => import("my-driver").catch(rethrowDriverImportError),
|
|
106
|
+
missingMessage:
|
|
107
|
+
"The MyEngine connector requires the optional `my-driver` peer dependency. Install it in your project (e.g. `pnpm add my-driver`).",
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
58
111
|
## License
|
|
59
112
|
|
|
60
113
|
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 {
|
|
4
|
+
export { BUILT_IN_CONNECTOR_PROVIDERS, connectorProviderMissingMessage, createConnectorRegistry, type BuiltInConnectorProvider, type ConnectorConfig, type ConnectorConnection, type ConnectorConnectionRequest, type ConnectorConnectionResolution, type ConnectorConnectionResult, type ConnectorProviderAdapter, type ConnectorProviderAdapters, type ConnectorProviderId, type ConnectorRegistry, type ConnectorResult, type ConnectorRuntimeConfig, } from "./registry.js";
|
|
5
|
+
export { renderToSchemaV2, renderSchemaV2Body, isSchemaV2Json, toV2SchemaJson, compactPostgresType, } from "./render/render.js";
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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,+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,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC5B,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 {
|
|
2
|
+
export { BUILT_IN_CONNECTOR_PROVIDERS, 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":"
|
|
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,+BAA+B,EAC/B,uBAAuB,GAaxB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,mBAAmB,GACpB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
load(options?: DriverLoadOptions): Promise<T>;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Build a lazy, cached loader for an optional database-driver peer. Engine
|
|
44
|
+
* packages call this once at module scope, so each engine keeps its own cache.
|
|
45
|
+
*/
|
|
46
|
+
export declare function createOptionalDriverLoader<T>(spec: OptionalDriverSpec<T>): OptionalDriverLoader<T>;
|
|
47
|
+
/**
|
|
48
|
+
* True when `packageName` resolves from `resolveFrom` (default `process.cwd()`).
|
|
49
|
+
* A cheap, synchronous capability probe — it does not load the driver.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isDriverInstalled(packageName: string, options?: DriverLoadOptions): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* The install hint the first-party engines' built-in catalog runners throw when
|
|
54
|
+
* their driver peer is missing, e.g.
|
|
55
|
+
* `missingDriverMessage({ engine: "Postgres", packageName: "pg" })`. It
|
|
56
|
+
* suggests a one-off `askdb` command, and the `askdb` binary registers only the
|
|
57
|
+
* first-party engines, so a third-party engine writes its own `missingMessage`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function missingDriverMessage(input: {
|
|
60
|
+
engine: string;
|
|
61
|
+
packageName: string;
|
|
62
|
+
}): string;
|
|
63
|
+
/**
|
|
64
|
+
* The handler an engine chains on its driver's `import()`:
|
|
65
|
+
* `() => import("pg").catch(rethrowDriverImportError)`. It rethrows unchanged,
|
|
66
|
+
* so the loader still classifies the error; its job is to sit on the
|
|
67
|
+
* `import()` expression, which is how bundlers such as esbuild tell an
|
|
68
|
+
* optional peer from a required one.
|
|
69
|
+
*/
|
|
70
|
+
export declare function rethrowDriverImportError(error: unknown): never;
|
|
71
|
+
//# sourceMappingURL=driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/kit/driver.ts"],"names":[],"mappings":"AAKA;;;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;;;;;;;;OAQG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC/C,CAAC;AAqCF;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,CAAC,CAgDlG;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,127 @@
|
|
|
1
|
+
import { AskDbError } from "@askdb/core";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
/**
|
|
6
|
+
* True when `cause` (or any error in its `cause` chain) is a Node module
|
|
7
|
+
* resolution failure (`ERR_MODULE_NOT_FOUND` / `MODULE_NOT_FOUND`) for the
|
|
8
|
+
* driver itself: the specifier Node could not find (`Cannot find package 'pg'`,
|
|
9
|
+
* `Cannot find module 'mysql2/promise'`, or Yarn PnP's `tried to access pg`)
|
|
10
|
+
* must be `packageName` or `specifier`, the entry point the loader asks for
|
|
11
|
+
* (default `packageName`). A different missing package whose name merely
|
|
12
|
+
* contains it (`pg-connection-string`), a path that happens to contain it
|
|
13
|
+
* (`/home/mssqluser/…`), or another file of the package (`pg/lib/missing`,
|
|
14
|
+
* which the installed driver failed to load) does not count. Anything else is a
|
|
15
|
+
* real error and must surface.
|
|
16
|
+
*/
|
|
17
|
+
function isModuleResolutionFailure(cause, packageName, specifier = packageName) {
|
|
18
|
+
if (!(cause instanceof Error))
|
|
19
|
+
return false;
|
|
20
|
+
const nestedCause = cause.cause;
|
|
21
|
+
if (nestedCause && nestedCause !== cause && isModuleResolutionFailure(nestedCause, packageName, specifier)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
const code = cause.code;
|
|
25
|
+
if (code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND")
|
|
26
|
+
return false;
|
|
27
|
+
const missing =
|
|
28
|
+
// Node: `Cannot find package 'pg' imported from …` / `Cannot find module 'mysql2/promise'`.
|
|
29
|
+
/Cannot find (?:module|package) '([^']+)'/.exec(cause.message)?.[1] ??
|
|
30
|
+
// Yarn PnP: `… tried to access pg, but it isn't declared in its dependencies …`.
|
|
31
|
+
/tried to access ([^\s,]+)/.exec(cause.message)?.[1];
|
|
32
|
+
return missing === packageName || missing === specifier;
|
|
33
|
+
}
|
|
34
|
+
/** The driver resolves from neither the engine package nor `resolveFrom`. */
|
|
35
|
+
class DriverNotFoundError extends AggregateError {
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build a lazy, cached loader for an optional database-driver peer. Engine
|
|
39
|
+
* packages call this once at module scope, so each engine keeps its own cache.
|
|
40
|
+
*/
|
|
41
|
+
export function createOptionalDriverLoader(spec) {
|
|
42
|
+
const { packageName, importDriver, missingMessage } = spec;
|
|
43
|
+
const specifier = spec.specifier ?? packageName;
|
|
44
|
+
const cache = new Map();
|
|
45
|
+
async function importOptional(options) {
|
|
46
|
+
try {
|
|
47
|
+
return await importDriver();
|
|
48
|
+
}
|
|
49
|
+
catch (cause) {
|
|
50
|
+
if (!isModuleResolutionFailure(cause, packageName, specifier))
|
|
51
|
+
throw cause;
|
|
52
|
+
const fromDir = options?.resolveFrom ?? process.cwd();
|
|
53
|
+
const projectRequire = createRequire(join(fromDir, "package.json"));
|
|
54
|
+
let resolved;
|
|
55
|
+
try {
|
|
56
|
+
resolved = projectRequire.resolve(specifier);
|
|
57
|
+
}
|
|
58
|
+
catch (projectCause) {
|
|
59
|
+
if (!isModuleResolutionFailure(projectCause, packageName, specifier))
|
|
60
|
+
throw projectCause;
|
|
61
|
+
throw new DriverNotFoundError([cause, projectCause], `Unable to resolve optional \`${packageName}\` peer dependency`);
|
|
62
|
+
}
|
|
63
|
+
// Resolved in the project: any failure from here on is the installed
|
|
64
|
+
// driver failing to load, never "not installed".
|
|
65
|
+
return (await import(pathToFileURL(resolved).href));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
load(options) {
|
|
70
|
+
const key = options?.resolveFrom;
|
|
71
|
+
let promise = cache.get(key);
|
|
72
|
+
if (!promise) {
|
|
73
|
+
promise = importOptional(options).catch((cause) => {
|
|
74
|
+
cache.delete(key);
|
|
75
|
+
// Only a driver that resolves nowhere gets the install hint. A driver
|
|
76
|
+
// that is installed but fails to load (a missing dependency of its
|
|
77
|
+
// own, a native build error, …) reports that failure instead.
|
|
78
|
+
if (cause instanceof DriverNotFoundError)
|
|
79
|
+
throw new AskDbError(missingMessage, cause);
|
|
80
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
81
|
+
throw new AskDbError(`The optional \`${packageName}\` peer dependency failed to load: ${detail}`, cause);
|
|
82
|
+
});
|
|
83
|
+
cache.set(key, promise);
|
|
84
|
+
}
|
|
85
|
+
return promise;
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* True when `packageName` resolves from `resolveFrom` (default `process.cwd()`).
|
|
91
|
+
* A cheap, synchronous capability probe — it does not load the driver.
|
|
92
|
+
*/
|
|
93
|
+
export function isDriverInstalled(packageName, options) {
|
|
94
|
+
try {
|
|
95
|
+
const req = createRequire(join(options?.resolveFrom ?? process.cwd(), "package.json"));
|
|
96
|
+
req.resolve(packageName);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The install hint the first-party engines' built-in catalog runners throw when
|
|
105
|
+
* their driver peer is missing, e.g.
|
|
106
|
+
* `missingDriverMessage({ engine: "Postgres", packageName: "pg" })`. It
|
|
107
|
+
* suggests a one-off `askdb` command, and the `askdb` binary registers only the
|
|
108
|
+
* first-party engines, so a third-party engine writes its own `missingMessage`.
|
|
109
|
+
*/
|
|
110
|
+
export function missingDriverMessage(input) {
|
|
111
|
+
const { engine, packageName } = input;
|
|
112
|
+
return (`The built-in ${engine} catalog query runner requires the optional \`${packageName}\` peer dependency. ` +
|
|
113
|
+
`Install it in your project (e.g. \`pnpm add ${packageName}\`) or include it in the same one-off command ` +
|
|
114
|
+
`(e.g. \`pnpm dlx -p askdb -p ${packageName} askdb ...\` or \`npx -p askdb -p ${packageName} askdb ...\`). ` +
|
|
115
|
+
`You can also pass a custom catalog query runner to the ${engine} connector.`);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* The handler an engine chains on its driver's `import()`:
|
|
119
|
+
* `() => import("pg").catch(rethrowDriverImportError)`. It rethrows unchanged,
|
|
120
|
+
* so the loader still classifies the error; its job is to sit on the
|
|
121
|
+
* `import()` expression, which is how bundlers such as esbuild tell an
|
|
122
|
+
* optional peer from a required one.
|
|
123
|
+
*/
|
|
124
|
+
export function rethrowDriverImportError(error) {
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
//# 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"}
|
package/dist/kit/ids.js
ADDED
|
@@ -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"}
|