@typed-sql/postgres 1.0.0-rc.0 → 1.0.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/CHANGELOG.md +71 -0
- package/README.md +31 -64
- package/dist/packages/postgres/src/pg.d.ts +12 -3
- package/dist/packages/postgres/src/pg.d.ts.map +1 -1
- package/dist/packages/postgres/src/pg.js +114 -14
- package/dist/packages/postgres/src/pg.js.map +1 -1
- package/dist/packages/postgres/src/prepared.d.ts +20 -0
- package/dist/packages/postgres/src/prepared.d.ts.map +1 -0
- package/dist/packages/postgres/src/prepared.js +47 -0
- package/dist/packages/postgres/src/prepared.js.map +1 -0
- package/dist/packages/postgres/src/runtime.d.ts +21 -3
- package/dist/packages/postgres/src/runtime.d.ts.map +1 -1
- package/dist/packages/postgres/src/runtime.js +509 -20
- package/dist/packages/postgres/src/runtime.js.map +1 -1
- package/dist/packages/postgres/src/stream.d.ts +34 -0
- package/dist/packages/postgres/src/stream.d.ts.map +1 -0
- package/dist/packages/postgres/src/stream.js +124 -0
- package/dist/packages/postgres/src/stream.js.map +1 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,76 @@
|
|
|
1
1
|
# @typed-sql/postgres
|
|
2
2
|
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 7ca256b: Release the first public typed-sql beta: exact TypeScript 7 row inference from static PostgreSQL and
|
|
8
|
+
MySQL, versioned schema introspection, application-owned drivers, config-driven grammar plugins,
|
|
9
|
+
CLI verification, editor language-server integration, versioned diagnostics, bounded parsing, and
|
|
10
|
+
real-database plus packed-tarball verification.
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- eb16de7: Add grammar-neutral stream and ordered-result type contracts, and add lazy prepared-query factories to the PostgreSQL and MySQL runtime adapters. Prepared factories retain exact query types, validate stable SQL shapes, and remain available inside nested transactions.
|
|
15
|
+
- eb16de7: Add lazy, exactly typed query streams to the PostgreSQL and MySQL runtime adapters. PostgreSQL
|
|
16
|
+
uses an application-owned optional `pg-cursor` installation for bounded cursor reads. MySQL uses
|
|
17
|
+
mysql2's execute-protocol stream and shared decoder plan. Both adapters enforce deterministic
|
|
18
|
+
cleanup, transaction ownership, and positive safe-integer batch sizes.
|
|
19
|
+
- eb16de7: Add a grammar-neutral validated query-batch type and ordered, exactly typed query batches to the
|
|
20
|
+
PostgreSQL and MySQL runtime adapters. Non-empty root batches execute sequentially on one leased
|
|
21
|
+
connection, transaction batches reuse their transaction connection, and empty batches avoid
|
|
22
|
+
connection acquisition. Batch execution preserves prepared metadata and adapter codecs, stops at
|
|
23
|
+
the first failure, and rejects transaction work that escapes its callback.
|
|
24
|
+
- b6389e4: Add an exactly typed PostgreSQL `pipeline()` capability backed by node-postgres's documented opt-in pipeline mode. Pipelines lease one client, dispatch independent queries before awaiting their results, preserve tuple order and prepared metadata, settle every in-flight query before cleanup, and integrate with transaction rollback and non-escape guarantees without changing sequential `batch()` semantics.
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- b6389e4: Cache immutable SQL rendering skeletons for prepared query factories so repeated calls only bind changing values while still rejecting structural drift before driver dispatch.
|
|
29
|
+
- eb16de7: Own in-flight transaction executions through settlement so unawaited work can never race commit, savepoint release, rollback, or connection release.
|
|
30
|
+
|
|
31
|
+
The PostgreSQL adapter now also rejects pg's client-side `query_timeout` option because it can settle before the connection is safe to reuse. Root batches discard checked-out clients after query rejection, while caught transaction query, batch, and stream failures force rollback and discard the lease. Use PostgreSQL's server-enforced `statement_timeout` for statement deadlines.
|
|
32
|
+
- eb16de7: Allow adapters to retain enriched capabilities in transaction callbacks and nested transactions
|
|
33
|
+
through a self-typed core database contract. Transaction cleanup now also preserves the original
|
|
34
|
+
operation error when rollback or connection-release cleanup fails.
|
|
35
|
+
- 1563a7a: Declare and enforce the 1.0 package stability boundary. Core SQL, compiler, schema, config, AST,
|
|
36
|
+
PostgreSQL, MySQL, and CLI packages form the stable train; the TypeScript preview bridge and
|
|
37
|
+
language server remain explicitly experimental. Freeze public entrypoints and query type contracts,
|
|
38
|
+
and remove internal compiler/type helpers from stable package-root exports before 1.0.
|
|
39
|
+
- 9dd6bc4: Finalize dialect contract version 3 with explicit identifier quoting and grammar-owned capability
|
|
40
|
+
declarations. Accept third-party snapshot dialects, validate grammar versions, and document the
|
|
41
|
+
public grammar-authoring and conformance workflow.
|
|
42
|
+
- 16e2475: Prove npm trusted publishing and provenance after the initial registry bootstrap.
|
|
43
|
+
- 642cebd: Prove and document runtime codec fidelity against live PostgreSQL and MySQL values. PostgreSQL now
|
|
44
|
+
delegates non-policy OIDs to the installed pg parser table, MySQL maps BIT to Uint8Array, and the
|
|
45
|
+
mysql2 adapter rejects pool settings that would contradict its type policy.
|
|
46
|
+
- 3e2c75c: Infer ordered query parameter tuples and let TypeScript reject interpolation values that do not
|
|
47
|
+
match their SQL context. Dialect contract version 2 adds explicit parameter analysis; unresolved
|
|
48
|
+
positions remain `unknown`. Add typed nullable predicate composition through `sql.fragment()`,
|
|
49
|
+
`sql.and()`, `sql.or()`, `sql.where()`, and `sql.append()` while preserving row and parameter tuples.
|
|
50
|
+
Direct append fragments are grammar-analyzed cumulatively against their static base, so TypeScript
|
|
51
|
+
rejects fragment interpolation values that disagree with the referenced database columns.
|
|
52
|
+
Add `sql.empty` and SQL-template-native conditional structural fragments. The compiler analyzes
|
|
53
|
+
complete branch variants, preserves literal boolean-dependent result rows, and type-checks nested
|
|
54
|
+
fragment parameters without adding a query-builder DSL. Bound independent structural expansion at
|
|
55
|
+
64 variants by default, correlate repeated conditions, merge diagnostics and fragment expectations
|
|
56
|
+
across variants, and fail closed on incompatible contexts. Share indexed catalog and conservative
|
|
57
|
+
parameter-resolution primitives across grammars, harden cooked-template scanning, and add runtime,
|
|
58
|
+
resolver, scanner, and structural performance gates.
|
|
59
|
+
- Updated dependencies [eb16de7]
|
|
60
|
+
- Updated dependencies [b6389e4]
|
|
61
|
+
- Updated dependencies [eb16de7]
|
|
62
|
+
- Updated dependencies [b6389e4]
|
|
63
|
+
- Updated dependencies [eb16de7]
|
|
64
|
+
- Updated dependencies [1563a7a]
|
|
65
|
+
- Updated dependencies [9dd6bc4]
|
|
66
|
+
- Updated dependencies [7ca256b]
|
|
67
|
+
- Updated dependencies [16e2475]
|
|
68
|
+
- Updated dependencies [69c7d87]
|
|
69
|
+
- Updated dependencies [3e2c75c]
|
|
70
|
+
- @typed-sql/core@1.0.0
|
|
71
|
+
- @typed-sql/ast@1.0.0
|
|
72
|
+
- @typed-sql/schema@1.0.0
|
|
73
|
+
|
|
3
74
|
## 1.0.0-rc.0
|
|
4
75
|
|
|
5
76
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,95 +1,62 @@
|
|
|
1
1
|
# @typed-sql/postgres
|
|
2
2
|
|
|
3
|
-
PostgreSQL grammar
|
|
4
|
-
|
|
3
|
+
The stable PostgreSQL grammar for [typed-sql](https://github.com/Lojhan/typed-sql), including
|
|
4
|
+
catalog introspection, row and parameter inference, type policy, runtime codecs, and an optional
|
|
5
|
+
application-owned `pg` adapter.
|
|
5
6
|
|
|
6
7
|
```sh
|
|
7
|
-
pnpm add @typed-sql/core
|
|
8
|
-
pnpm add -D @typed-sql/cli
|
|
8
|
+
pnpm add @typed-sql/core @typed-sql/postgres pg
|
|
9
|
+
pnpm add -D @typed-sql/cli typescript@7.0.2
|
|
9
10
|
```
|
|
10
11
|
|
|
11
|
-
`pg` is
|
|
12
|
-
|
|
13
|
-
`@typed-sql/postgres/pg`.
|
|
14
|
-
|
|
15
|
-
## Configure and generate
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
import { defineConfig } from "@typed-sql/core";
|
|
19
|
-
import { postgres, typePolicy } from "@typed-sql/postgres";
|
|
20
|
-
import { pg } from "@typed-sql/postgres/pg";
|
|
21
|
-
|
|
22
|
-
export default defineConfig({
|
|
23
|
-
dialect: postgres({ typePolicy }),
|
|
24
|
-
schema: {
|
|
25
|
-
file: "generated/db/schema.json",
|
|
26
|
-
provider: pg({
|
|
27
|
-
connectionString: () => process.env.DATABASE_URL!,
|
|
28
|
-
schemas: ["public"],
|
|
29
|
-
typePolicy,
|
|
30
|
-
}),
|
|
31
|
-
},
|
|
32
|
-
outDir: "generated/db",
|
|
33
|
-
projects: ["tsconfig.json"],
|
|
34
|
-
typePolicy,
|
|
35
|
-
});
|
|
36
|
-
```
|
|
12
|
+
`pg` is loaded only through `@typed-sql/postgres/pg`; it is not a dependency or peer dependency of
|
|
13
|
+
the grammar. Applications that stream rows also install the optional application-owned cursor:
|
|
37
14
|
|
|
38
15
|
```sh
|
|
39
|
-
pnpm
|
|
16
|
+
pnpm add pg-cursor
|
|
40
17
|
```
|
|
41
18
|
|
|
42
|
-
## Query and execute
|
|
43
|
-
|
|
44
19
|
```ts
|
|
45
20
|
import { sql, typePolicy } from "@typed-sql/postgres";
|
|
46
21
|
import { createPgDatabase } from "@typed-sql/postgres/pg";
|
|
47
22
|
|
|
48
23
|
const query = sql`
|
|
49
|
-
SELECT account.id, account.email,
|
|
24
|
+
SELECT account.id, account.email, project.budget
|
|
50
25
|
FROM users AS account
|
|
51
26
|
LEFT JOIN projects AS project ON project.owner_id = account.id
|
|
52
|
-
ORDER BY account.id
|
|
53
27
|
`;
|
|
54
28
|
|
|
55
29
|
const database = await createPgDatabase({
|
|
56
30
|
connectionString: process.env.DATABASE_URL!,
|
|
31
|
+
poolConfig: { pipeline: true },
|
|
57
32
|
typePolicy,
|
|
58
33
|
});
|
|
59
34
|
|
|
35
|
+
// pipeline() requires the application-owned pg 8.23.0 or newer.
|
|
36
|
+
|
|
60
37
|
const rows = await database.execute(query);
|
|
61
|
-
// readonly {
|
|
62
|
-
// id: bigint;
|
|
63
|
-
// email: string;
|
|
64
|
-
// status: "active" | "suspended";
|
|
65
|
-
// budget: string | null;
|
|
66
|
-
// }[]
|
|
67
|
-
```
|
|
68
38
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
39
|
+
const accountById = database.prepare("account-by-id", (id: bigint) => sql`
|
|
40
|
+
SELECT account.id, account.email
|
|
41
|
+
FROM users AS account
|
|
42
|
+
WHERE account.id = ${id}
|
|
43
|
+
`);
|
|
44
|
+
|
|
45
|
+
const [selectedAccounts, allAccounts] = await database.batch([accountById(42n), query]);
|
|
46
|
+
const [pipelinedAccount, pipelinedAll] = await database.pipeline([accountById(42n), query]);
|
|
74
47
|
|
|
75
|
-
|
|
48
|
+
for await (const account of database.stream(accountById(42n), { batchSize: 500 })) {
|
|
49
|
+
// account retains the query's inferred row type
|
|
50
|
+
}
|
|
51
|
+
```
|
|
76
52
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
| `SELECT`, `DISTINCT`, `DISTINCT ON` | Supported | Static row-shape inference. |
|
|
81
|
-
| Tables, schemas, aliases and stars | Supported | Catalog lookup, ambiguity checks and `USING` column merging. |
|
|
82
|
-
| Inner and outer joins | Supported | Outer-join nullability propagates into result columns. |
|
|
83
|
-
| CTEs and derived/correlated/scalar subqueries | Supported | Recursive CTEs and unsafe scalar/IN arity diagnose. |
|
|
84
|
-
| Grouping, aggregates and windows | Supported | Includes common aggregates, `FILTER`, named and inline windows. |
|
|
85
|
-
| Expressions, `CASE`, casts and `$n` parameters | Supported | Parameters infer from columns, casts, DML targets, ranges, limits, and catalog functions; ambiguous positions remain `unknown`. |
|
|
86
|
-
| Arrays, enums, domains, JSON and catalog functions | Supported | Known types and function name/arity are validated. |
|
|
87
|
-
| `INSERT`, `UPDATE`, `DELETE`, `RETURNING` | Supported | Commands without `RETURNING` infer `Query<never, Parameters>`. |
|
|
88
|
-
| Set operations and `WITHIN GROUP` | Not supported | Fail safely during parsing. |
|
|
89
|
-
| Dynamic SQL or identifiers | No static inference | Use runtime values and `sql.ident()` explicitly. |
|
|
53
|
+
The package root exports `sql`, `postgres`, and the PostgreSQL type policy. The `/pg` entrypoint
|
|
54
|
+
exports the schema provider and execution adapter; `/runtime` exposes driver-neutral PostgreSQL
|
|
55
|
+
rendering and codecs.
|
|
90
56
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
57
|
+
Read the [PostgreSQL grammar guide](https://github.com/Lojhan/typed-sql/blob/main/docs/dialects/postgresql.md),
|
|
58
|
+
[execution guide](https://github.com/Lojhan/typed-sql/blob/main/docs/guides/execution.md),
|
|
59
|
+
[configuration](https://github.com/Lojhan/typed-sql/blob/main/docs/getting-started/configuration.md), and
|
|
60
|
+
[database type mappings](https://github.com/Lojhan/typed-sql/blob/main/docs/reference/type-mappings.md).
|
|
94
61
|
|
|
95
62
|
MIT © typed-sql contributors
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import type { Pool as PgPool, PoolConfig } from "pg";
|
|
2
2
|
import type { PostgresSchemaSnapshot, PostgresTypePolicy } from "./index.js";
|
|
3
3
|
import { type PostgresQueryable } from "./provider.js";
|
|
4
|
-
import { type PostgresDatabase, type PostgresPoolLike } from "./runtime.js";
|
|
4
|
+
import { type PostgresDatabase, type PostgresPoolLike, type PostgresQueryConfig } from "./runtime.js";
|
|
5
|
+
export interface PgCursorConstructor {
|
|
6
|
+
new (text: string, values?: readonly unknown[], config?: {
|
|
7
|
+
readonly types?: PostgresQueryConfig["types"];
|
|
8
|
+
}): unknown;
|
|
9
|
+
}
|
|
10
|
+
export type PgCursorImporter = () => Promise<unknown>;
|
|
11
|
+
export declare function loadPgCursorDriver(importer?: PgCursorImporter): Promise<PgCursorConstructor>;
|
|
5
12
|
export interface PgOptions {
|
|
6
13
|
readonly connectionString: string | (() => string | Promise<string>);
|
|
7
|
-
readonly poolConfig?: Omit<PoolConfig, "connectionString" | "types">;
|
|
14
|
+
readonly poolConfig?: Omit<PoolConfig, "connectionString" | "query_timeout" | "types">;
|
|
8
15
|
readonly typePolicy?: PostgresTypePolicy;
|
|
9
16
|
readonly decimal?: (value: string) => unknown;
|
|
17
|
+
/** Host-injected loader for workspaces or runtimes with nonstandard package resolution. */
|
|
18
|
+
readonly cursorImporter?: PgCursorImporter;
|
|
10
19
|
}
|
|
11
20
|
export interface PgSchemaProviderOptions {
|
|
12
21
|
readonly connectionString?: string | (() => string | Promise<string>);
|
|
@@ -15,7 +24,7 @@ export interface PgSchemaProviderOptions {
|
|
|
15
24
|
readonly typePolicy?: PostgresTypePolicy;
|
|
16
25
|
}
|
|
17
26
|
export declare function loadPgDriver(importer?: () => Promise<typeof import("pg")>): Promise<typeof import("pg")>;
|
|
18
|
-
export declare function adaptPgPool(pool: PgPool): PostgresPoolLike;
|
|
27
|
+
export declare function adaptPgPool(pool: PgPool, cursorImporter?: PgCursorImporter): PostgresPoolLike;
|
|
19
28
|
export declare function createPgDatabase(options: PgOptions): Promise<PostgresDatabase>;
|
|
20
29
|
export declare function pg(options: PgSchemaProviderOptions): {
|
|
21
30
|
introspect(): Promise<PostgresSchemaSnapshot>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../../../src/pg.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,MAAM,EAAc,UAAU,EAAe,MAAM,IAAI,CAAC;AAC9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,KAAK,iBAAiB,EAA0B,MAAM,eAAe,CAAC;AAC/E,OAAO,
|
|
1
|
+
{"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../../../src/pg.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,MAAM,EAAc,UAAU,EAAe,MAAM,IAAI,CAAC;AAC9E,OAAO,KAAK,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,KAAK,iBAAiB,EAA0B,MAAM,eAAe,CAAC;AAC/E,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EAEzB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,mBAAmB;IAClC,KACE,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,EAC3B,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;KAC/C,GACA,OAAO,CAAC;CACZ;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;AAqBtD,wBAAsB,kBAAkB,CACtC,QAAQ,GAAE,gBAA0C,GACnD,OAAO,CAAC,mBAAmB,CAAC,CAY9B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACrE,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,kBAAkB,GAAG,eAAe,GAAG,OAAO,CAAC,CAAC;IACvF,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAC9C,2FAA2F;IAC3F,QAAQ,CAAC,cAAc,CAAC,EAAE,gBAAgB,CAAC;CAC5C;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CAC1C;AAED,wBAAsB,YAAY,CAChC,QAAQ,GAAE,MAAM,OAAO,CAAC,cAAc,IAAI,CAAC,CAAsB,GAChE,OAAO,CAAC,cAAc,IAAI,CAAC,CAAC,CAW9B;AAsCD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,cAAc,GAAE,gBAA0C,GACzD,gBAAgB,CAqFlB;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAcpF;AAED,wBAAgB,EAAE,CAAC,OAAO,EAAE,uBAAuB,GAAG;IAAE,UAAU,IAAI,OAAO,CAAC,sBAAsB,CAAC,CAAA;CAAE,CAiBtG"}
|
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
import { PostgresSchemaProvider } from "./provider.js";
|
|
2
2
|
import { createPostgresDatabase, } from "./runtime.js";
|
|
3
|
+
const pgCursorPackage = "pg-cursor";
|
|
4
|
+
const queryTimeoutError = "@typed-sql/postgres/pg does not accept pg query_timeout because pg can reject before the connection is ready for reuse; use PostgreSQL statement_timeout instead";
|
|
5
|
+
async function defaultPgCursorImporter() {
|
|
6
|
+
return import(pgCursorPackage);
|
|
7
|
+
}
|
|
8
|
+
function pgCursorConstructor(module) {
|
|
9
|
+
const candidate = typeof module === "object" && module !== null && "default" in module
|
|
10
|
+
? module.default
|
|
11
|
+
: module;
|
|
12
|
+
if (typeof candidate !== "function") {
|
|
13
|
+
throw new TypeError("The application-owned pg-cursor package does not export a default Cursor constructor");
|
|
14
|
+
}
|
|
15
|
+
return candidate;
|
|
16
|
+
}
|
|
17
|
+
export async function loadPgCursorDriver(importer = defaultPgCursorImporter) {
|
|
18
|
+
try {
|
|
19
|
+
return pgCursorConstructor(await importer());
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof Error && "code" in error && error.code === "ERR_MODULE_NOT_FOUND") {
|
|
23
|
+
throw new Error("@typed-sql/postgres/pg streaming requires the application-owned pg-cursor package. Install it with: pnpm add pg-cursor", { cause: error });
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
3
28
|
export async function loadPgDriver(importer = () => import("pg")) {
|
|
4
29
|
try {
|
|
5
30
|
return await importer();
|
|
@@ -20,29 +45,99 @@ async function connectionString(value) {
|
|
|
20
45
|
return resolved;
|
|
21
46
|
}
|
|
22
47
|
function validatePoolConfig(poolConfig) {
|
|
48
|
+
if (poolConfig !== undefined && "query_timeout" in poolConfig)
|
|
49
|
+
throw new TypeError(queryTimeoutError);
|
|
23
50
|
if (poolConfig !== undefined && "types" in poolConfig) {
|
|
24
51
|
throw new TypeError("@typed-sql/postgres/pg owns poolConfig.types so decoded values match typePolicy; remove that option");
|
|
25
52
|
}
|
|
26
53
|
}
|
|
54
|
+
function validateConnectionStringQueryTimeout(value) {
|
|
55
|
+
try {
|
|
56
|
+
const url = new URL(value);
|
|
57
|
+
for (const name of url.searchParams.keys()) {
|
|
58
|
+
if (name === "query_timeout")
|
|
59
|
+
throw new TypeError(queryTimeoutError);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error instanceof TypeError && error.message === queryTimeoutError)
|
|
64
|
+
throw error;
|
|
65
|
+
// Let pg report malformed or non-URL connection strings through its normal validation path.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
27
68
|
function queryConfig(config) {
|
|
28
69
|
return {
|
|
70
|
+
...(config.name === undefined ? {} : { name: config.name }),
|
|
29
71
|
text: config.text,
|
|
30
72
|
...(config.values === undefined ? {} : { values: [...config.values] }),
|
|
31
73
|
...(config.types === undefined ? {} : { types: config.types }),
|
|
32
74
|
};
|
|
33
75
|
}
|
|
34
|
-
export function adaptPgPool(pool) {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
76
|
+
export function adaptPgPool(pool, cursorImporter = defaultPgCursorImporter) {
|
|
77
|
+
const options = pool.options;
|
|
78
|
+
if (options !== undefined && "query_timeout" in options)
|
|
79
|
+
throw new TypeError(queryTimeoutError);
|
|
80
|
+
if (typeof options?.connectionString === "string")
|
|
81
|
+
validateConnectionStringQueryTimeout(options.connectionString);
|
|
82
|
+
let cursorConstructorPromise;
|
|
83
|
+
const loadCursor = () => {
|
|
84
|
+
cursorConstructorPromise ??= loadPgCursorDriver(cursorImporter);
|
|
85
|
+
return cursorConstructorPromise;
|
|
86
|
+
};
|
|
87
|
+
const wrapClient = (client) => {
|
|
88
|
+
let fatalError;
|
|
89
|
+
let rejectFatal;
|
|
90
|
+
const fatalSettlement = new Promise((_resolve, reject) => {
|
|
91
|
+
rejectFatal = reject;
|
|
92
|
+
});
|
|
93
|
+
// The promise intentionally remains pending for a healthy lease and must never be unhandled.
|
|
94
|
+
void fatalSettlement.catch(() => undefined);
|
|
95
|
+
const recordFatal = (error) => {
|
|
96
|
+
if (fatalError !== undefined)
|
|
97
|
+
return;
|
|
98
|
+
fatalError = error;
|
|
99
|
+
rejectFatal(error);
|
|
100
|
+
};
|
|
101
|
+
const onError = (error) => recordFatal(error);
|
|
102
|
+
const onEnd = () => recordFatal(new Error("The PostgreSQL connection ended while it was leased"));
|
|
103
|
+
client.on("error", onError);
|
|
104
|
+
client.on("end", onEnd);
|
|
105
|
+
return {
|
|
106
|
+
pipeline: client.pipeline,
|
|
107
|
+
async query(config) {
|
|
108
|
+
const result = typeof config === "string"
|
|
109
|
+
? await client.query(config)
|
|
110
|
+
: await client.query(queryConfig(config));
|
|
111
|
+
return { rows: result.rows };
|
|
112
|
+
},
|
|
113
|
+
async openCursor(config) {
|
|
114
|
+
const Cursor = await loadCursor();
|
|
115
|
+
// pg-cursor always parses an unnamed statement. Keep the prepared name in typed-sql's
|
|
116
|
+
// driver-neutral config, but do not pretend the native cursor can honor it.
|
|
117
|
+
const cursor = new Cursor(config.text, config.values, {
|
|
118
|
+
...(config.types === undefined ? {} : { types: config.types }),
|
|
119
|
+
});
|
|
120
|
+
const queryCursor = client.query.bind(client);
|
|
121
|
+
const nativeCursor = queryCursor(cursor);
|
|
122
|
+
return {
|
|
123
|
+
read: (rowCount) => nativeCursor.read(rowCount),
|
|
124
|
+
async close() {
|
|
125
|
+
if (fatalError !== undefined)
|
|
126
|
+
throw fatalError;
|
|
127
|
+
const nativeClose = nativeCursor.close();
|
|
128
|
+
// Keep observing the native promise even when fatal settlement wins the race.
|
|
129
|
+
void nativeClose.catch(() => undefined);
|
|
130
|
+
await Promise.race([nativeClose, fatalSettlement]);
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
release(error) {
|
|
135
|
+
client.removeListener("error", onError);
|
|
136
|
+
client.removeListener("end", onEnd);
|
|
137
|
+
client.release(error === undefined ? fatalError : error);
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
};
|
|
46
141
|
return {
|
|
47
142
|
async query(config) {
|
|
48
143
|
const result = typeof config === "string"
|
|
@@ -50,6 +145,9 @@ export function adaptPgPool(pool) {
|
|
|
50
145
|
: await pool.query(queryConfig(config));
|
|
51
146
|
return { rows: result.rows };
|
|
52
147
|
},
|
|
148
|
+
async ensureCursor() {
|
|
149
|
+
await loadCursor();
|
|
150
|
+
},
|
|
53
151
|
async connect() {
|
|
54
152
|
return wrapClient(await pool.connect());
|
|
55
153
|
},
|
|
@@ -60,11 +158,13 @@ export function adaptPgPool(pool) {
|
|
|
60
158
|
}
|
|
61
159
|
export async function createPgDatabase(options) {
|
|
62
160
|
validatePoolConfig(options.poolConfig);
|
|
161
|
+
const resolvedConnectionString = await connectionString(options.connectionString);
|
|
162
|
+
validateConnectionStringQueryTimeout(resolvedConnectionString);
|
|
63
163
|
const driver = await loadPgDriver();
|
|
64
164
|
const { Pool } = driver;
|
|
65
|
-
const pool = new Pool({ ...options.poolConfig, connectionString:
|
|
165
|
+
const pool = new Pool({ ...options.poolConfig, connectionString: resolvedConnectionString });
|
|
66
166
|
return createPostgresDatabase({
|
|
67
|
-
pool: adaptPgPool(pool),
|
|
167
|
+
pool: adaptPgPool(pool, options.cursorImporter),
|
|
68
168
|
ownsPool: true,
|
|
69
169
|
fallbackTypeParsers: driver.types,
|
|
70
170
|
...(options.typePolicy === undefined ? {} : { typePolicy: options.typePolicy }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../../../../src/pg.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EACL,sBAAsB,
|
|
1
|
+
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../../../../src/pg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Query, type QueryRenderSkeleton, type RenderedQuery, type SqlRenderer } from "@typed-sql/core";
|
|
2
|
+
export interface PostgresPreparedQueryFactory<Arguments extends readonly unknown[], Row, Params extends readonly unknown[]> {
|
|
3
|
+
(...args: Arguments): Query<Row, Params>;
|
|
4
|
+
readonly statementName: string;
|
|
5
|
+
}
|
|
6
|
+
export interface PostgresPreparedQueryMetadata {
|
|
7
|
+
readonly statementName: string;
|
|
8
|
+
readonly rendered: RenderedQuery;
|
|
9
|
+
}
|
|
10
|
+
interface PreparedStatement {
|
|
11
|
+
skeleton: QueryRenderSkeleton | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface PostgresPreparedQueryState {
|
|
14
|
+
readonly statements: Map<string, PreparedStatement>;
|
|
15
|
+
readonly queries: WeakMap<object, PostgresPreparedQueryMetadata>;
|
|
16
|
+
}
|
|
17
|
+
export declare function createPostgresPreparedQueryState(): PostgresPreparedQueryState;
|
|
18
|
+
export declare function preparePostgresQuery<Arguments extends readonly unknown[], Row, Params extends readonly unknown[]>(state: PostgresPreparedQueryState, renderer: SqlRenderer, statementName: string, factory: (...args: Arguments) => Query<Row, Params>): PostgresPreparedQueryFactory<Arguments, Row, Params>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=prepared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepared.d.ts","sourceRoot":"","sources":["../../../../src/prepared.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,mBAAmB,EACxB,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,4BAA4B,CAC3C,SAAS,SAAS,SAAS,OAAO,EAAE,EACpC,GAAG,EACH,MAAM,SAAS,SAAS,OAAO,EAAE;IAEjC,CAAC,GAAG,IAAI,EAAE,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;CAClC;AAED,UAAU,iBAAiB;IACzB,QAAQ,EAAE,mBAAmB,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACpD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;CAClE;AAED,wBAAgB,gCAAgC,IAAI,0BAA0B,CAK7E;AAQD,wBAAgB,oBAAoB,CAAC,SAAS,SAAS,SAAS,OAAO,EAAE,EAAE,GAAG,EAAE,MAAM,SAAS,SAAS,OAAO,EAAE,EAC/G,KAAK,EAAE,0BAA0B,EACjC,QAAQ,EAAE,WAAW,EACrB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,SAAS,KAAK,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,GAClD,4BAA4B,CAAC,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,CAwCtD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { bindQueryRenderSkeleton, compileQueryRenderSkeleton, } from "@typed-sql/core";
|
|
2
|
+
export function createPostgresPreparedQueryState() {
|
|
3
|
+
return {
|
|
4
|
+
statements: new Map(),
|
|
5
|
+
queries: new WeakMap(),
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
function validateStatementName(statementName) {
|
|
9
|
+
if (typeof statementName !== "string" || statementName.length === 0 || statementName.includes("\0")) {
|
|
10
|
+
throw new TypeError("Prepared statement names must be non-empty and cannot contain NUL");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function preparePostgresQuery(state, renderer, statementName, factory) {
|
|
14
|
+
validateStatementName(statementName);
|
|
15
|
+
if (state.statements.has(statementName)) {
|
|
16
|
+
throw new TypeError(`Prepared statement name ${JSON.stringify(statementName)} is already registered`);
|
|
17
|
+
}
|
|
18
|
+
const statement = { skeleton: undefined };
|
|
19
|
+
state.statements.set(statementName, statement);
|
|
20
|
+
const prepared = (...args) => {
|
|
21
|
+
const query = factory(...args);
|
|
22
|
+
const existing = state.queries.get(query);
|
|
23
|
+
if (existing !== undefined && existing.statementName !== statementName) {
|
|
24
|
+
throw new TypeError(`A query cannot use both prepared statement ${JSON.stringify(existing.statementName)} and ${JSON.stringify(statementName)}`);
|
|
25
|
+
}
|
|
26
|
+
let rendered = existing?.rendered;
|
|
27
|
+
const skeleton = statement.skeleton;
|
|
28
|
+
if (rendered === undefined) {
|
|
29
|
+
if (skeleton === undefined) {
|
|
30
|
+
const compiled = compileQueryRenderSkeleton(query, renderer);
|
|
31
|
+
statement.skeleton = compiled.skeleton;
|
|
32
|
+
rendered = compiled.rendered;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
rendered = bindQueryRenderSkeleton(query, skeleton);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (rendered === undefined) {
|
|
39
|
+
throw new TypeError(`Prepared statement ${JSON.stringify(statementName)} must always render the same SQL text and structure`);
|
|
40
|
+
}
|
|
41
|
+
if (existing === undefined)
|
|
42
|
+
state.queries.set(query, { statementName, rendered });
|
|
43
|
+
return query;
|
|
44
|
+
};
|
|
45
|
+
return Object.freeze(Object.assign(prepared, { statementName }));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=prepared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepared.js","sourceRoot":"","sources":["../../../../src/prepared.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAK3B,MAAM,iBAAiB,CAAC;AAyBzB,MAAM,UAAU,gCAAgC;IAC9C,OAAO;QACL,UAAU,EAAE,IAAI,GAAG,EAAE;QACrB,OAAO,EAAE,IAAI,OAAO,EAAE;KACvB,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,aAAqB;IAClD,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACpG,MAAM,IAAI,SAAS,CAAC,mEAAmE,CAAC,CAAC;IAC3F,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,KAAiC,EACjC,QAAqB,EACrB,aAAqB,EACrB,OAAmD;IAEnD,qBAAqB,CAAC,aAAa,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,SAAS,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC;IACxG,CAAC;IAED,MAAM,SAAS,GAAsB,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAC7D,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IAE/C,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAe,EAAsB,EAAE;QAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,aAAa,KAAK,aAAa,EAAE,CAAC;YACvE,MAAM,IAAI,SAAS,CACjB,8CAA8C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,QAAQ,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,CAC5H,CAAC;QACJ,CAAC;QAED,IAAI,QAAQ,GAAG,QAAQ,EAAE,QAAQ,CAAC;QAClC,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC;QACpC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,MAAM,QAAQ,GAAG,0BAA0B,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBAC7D,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;gBACvC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,QAAQ,GAAG,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,IAAI,SAAS,CACjB,sBAAsB,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,qDAAqD,CACzG,CAAC;QACJ,CAAC;QAED,IAAI,QAAQ,KAAK,SAAS;YAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAC;QAClF,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { type Database, type SqlRenderer } from "@typed-sql/core";
|
|
1
|
+
import { type Database, type Query, type QueryBatch, type QueryResults, type QueryStream, type SqlRenderer, type StreamOptions } from "@typed-sql/core";
|
|
2
|
+
import { type PostgresPreparedQueryFactory } from "./prepared.js";
|
|
3
|
+
import { type PostgresCursorLike } from "./stream.js";
|
|
4
|
+
export type { PostgresPreparedQueryFactory } from "./prepared.js";
|
|
5
|
+
export type { PostgresCursorLike } from "./stream.js";
|
|
2
6
|
export interface PostgresCodecPolicy {
|
|
3
7
|
readonly bigint: "bigint" | "string" | "number";
|
|
4
8
|
readonly numeric: "string" | "number" | "Decimal";
|
|
@@ -9,6 +13,7 @@ export interface PostgresTypeParserSet {
|
|
|
9
13
|
getTypeParser(oid: number, format?: string): (value: string) => unknown;
|
|
10
14
|
}
|
|
11
15
|
export interface PostgresQueryConfig {
|
|
16
|
+
readonly name?: string;
|
|
12
17
|
readonly text: string;
|
|
13
18
|
readonly values?: readonly unknown[];
|
|
14
19
|
readonly types?: PostgresTypeParserSet;
|
|
@@ -17,15 +22,28 @@ export interface PostgresQueryResult {
|
|
|
17
22
|
readonly rows: readonly Record<string, unknown>[];
|
|
18
23
|
}
|
|
19
24
|
export interface PostgresClientLike {
|
|
25
|
+
readonly pipeline?: boolean;
|
|
20
26
|
query(config: PostgresQueryConfig | string): Promise<PostgresQueryResult>;
|
|
21
|
-
|
|
27
|
+
openCursor?(config: PostgresQueryConfig): PostgresCursorLike | Promise<PostgresCursorLike>;
|
|
28
|
+
release(error?: Error | boolean): void;
|
|
22
29
|
}
|
|
23
30
|
export interface PostgresPoolLike {
|
|
24
31
|
query(config: PostgresQueryConfig | string): Promise<PostgresQueryResult>;
|
|
32
|
+
ensureCursor?(): Promise<void>;
|
|
25
33
|
connect(): Promise<PostgresClientLike>;
|
|
26
34
|
end(): Promise<void>;
|
|
27
35
|
}
|
|
28
|
-
export interface
|
|
36
|
+
export interface PostgresTransaction extends Database<PostgresTransaction> {
|
|
37
|
+
batch<const Queries extends readonly unknown[]>(queries: QueryBatch<Queries>): Promise<QueryResults<Queries>>;
|
|
38
|
+
pipeline<const Queries extends readonly unknown[]>(queries: QueryBatch<Queries>): Promise<QueryResults<Queries>>;
|
|
39
|
+
prepare<Arguments extends readonly unknown[], Row, Params extends readonly unknown[]>(statementName: string, factory: (...args: Arguments) => Query<Row, Params>): PostgresPreparedQueryFactory<Arguments, Row, Params>;
|
|
40
|
+
stream<Row, Params extends readonly unknown[]>(query: Query<Row, Params>, options?: StreamOptions): QueryStream<Row>;
|
|
41
|
+
}
|
|
42
|
+
export interface PostgresDatabase extends Database<PostgresTransaction> {
|
|
43
|
+
batch<const Queries extends readonly unknown[]>(queries: QueryBatch<Queries>): Promise<QueryResults<Queries>>;
|
|
44
|
+
pipeline<const Queries extends readonly unknown[]>(queries: QueryBatch<Queries>): Promise<QueryResults<Queries>>;
|
|
45
|
+
prepare<Arguments extends readonly unknown[], Row, Params extends readonly unknown[]>(statementName: string, factory: (...args: Arguments) => Query<Row, Params>): PostgresPreparedQueryFactory<Arguments, Row, Params>;
|
|
46
|
+
stream<Row, Params extends readonly unknown[]>(query: Query<Row, Params>, options?: StreamOptions): QueryStream<Row>;
|
|
29
47
|
close(): Promise<void>;
|
|
30
48
|
}
|
|
31
49
|
export interface PostgresDatabaseOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../src/runtime.ts"],"names":[],"mappings":"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"}
|