turbine-orm 0.49.0 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +122 -39
  2. package/dist/cjs/adapters/cockroachdb.d.ts +39 -0
  3. package/dist/cjs/adapters/index.d.ts +110 -0
  4. package/dist/cjs/adapters/yugabytedb.d.ts +51 -0
  5. package/dist/cjs/cli/config.d.ts +181 -0
  6. package/dist/cjs/cli/config.js +32 -6
  7. package/dist/cjs/cli/destructive.d.ts +38 -0
  8. package/dist/cjs/cli/index.d.ts +359 -0
  9. package/dist/cjs/cli/index.js +228 -56
  10. package/dist/cjs/cli/loader.d.ts +61 -0
  11. package/dist/cjs/cli/mcp.d.ts +42 -0
  12. package/dist/cjs/cli/migrate.d.ts +356 -0
  13. package/dist/cjs/cli/migrate.js +131 -40
  14. package/dist/cjs/cli/observe-ui.d.ts +1 -0
  15. package/dist/cjs/cli/observe-ui.js +14 -5
  16. package/dist/cjs/cli/observe.d.ts +25 -0
  17. package/dist/cjs/cli/observe.js +49 -12
  18. package/dist/cjs/cli/pii-tags.d.ts +53 -0
  19. package/dist/cjs/cli/prisma-report.d.ts +33 -0
  20. package/dist/cjs/cli/prisma-report.js +73 -0
  21. package/dist/cjs/cli/prisma-resolve.d.ts +106 -0
  22. package/dist/cjs/cli/prisma-resolve.js +1 -0
  23. package/dist/cjs/cli/prisma-schema.d.ts +176 -0
  24. package/dist/cjs/cli/prisma-schema.js +82 -4
  25. package/dist/cjs/cli/rate-limit.d.ts +32 -0
  26. package/dist/cjs/cli/rate-limit.js +45 -0
  27. package/dist/cjs/cli/studio-demo.d.ts +43 -0
  28. package/dist/cjs/cli/studio-ui.generated.d.ts +1 -0
  29. package/dist/cjs/cli/studio.d.ts +207 -0
  30. package/dist/cjs/cli/studio.js +136 -71
  31. package/dist/cjs/cli/ui.d.ts +73 -0
  32. package/dist/cjs/cli/ui.js +51 -9
  33. package/dist/cjs/client.d.ts +837 -0
  34. package/dist/cjs/client.js +3 -0
  35. package/dist/cjs/dialect.d.ts +516 -0
  36. package/dist/cjs/dialect.js +37 -12
  37. package/dist/cjs/errors.d.ts +370 -0
  38. package/dist/cjs/generate.d.ts +137 -0
  39. package/dist/cjs/generate.js +39 -6
  40. package/dist/cjs/index-advisor.d.ts +153 -0
  41. package/dist/cjs/index-stats.d.ts +384 -0
  42. package/dist/cjs/index.d.ts +55 -0
  43. package/dist/cjs/index.js +7 -2
  44. package/dist/cjs/introspect.d.ts +269 -0
  45. package/dist/cjs/mssql.d.ts +232 -0
  46. package/dist/cjs/mssql.js +6 -0
  47. package/dist/cjs/mysql.d.ts +173 -0
  48. package/dist/cjs/mysql.js +16 -0
  49. package/dist/cjs/nested-write.d.ts +96 -0
  50. package/dist/cjs/nested-write.js +414 -24
  51. package/dist/cjs/observe.d.ts +115 -0
  52. package/dist/cjs/optional-peer-import.d.cts +72 -0
  53. package/dist/cjs/pipeline-submittable.d.ts +93 -0
  54. package/dist/cjs/pipeline.d.ts +71 -0
  55. package/dist/cjs/powdb-introspect.d.ts +84 -0
  56. package/dist/cjs/powdb.d.ts +931 -0
  57. package/dist/cjs/powdb.js +106 -21
  58. package/dist/cjs/powql.d.ts +592 -0
  59. package/dist/cjs/powql.js +42 -6
  60. package/dist/cjs/prisma-compat.d.ts +283 -0
  61. package/dist/cjs/prisma-compat.js +167 -9
  62. package/dist/cjs/query/aggregates.d.ts +92 -0
  63. package/dist/cjs/query/aggregates.js +7 -3
  64. package/dist/cjs/query/batched-loader.d.ts +193 -0
  65. package/dist/cjs/query/builder.d.ts +849 -0
  66. package/dist/cjs/query/builder.js +571 -65
  67. package/dist/cjs/query/compound-unique.d.ts +51 -0
  68. package/dist/cjs/query/deferred.d.ts +223 -0
  69. package/dist/cjs/query/filters.d.ts +201 -0
  70. package/dist/cjs/query/index.d.ts +14 -0
  71. package/dist/cjs/query/index.js +6 -1
  72. package/dist/cjs/query/relations.d.ts +609 -0
  73. package/dist/cjs/query/relations.js +693 -46
  74. package/dist/cjs/query/types.d.ts +1300 -0
  75. package/dist/cjs/query/utils.d.ts +209 -0
  76. package/dist/cjs/query/utils.js +208 -1
  77. package/dist/cjs/query/warn-registry.d.ts +68 -0
  78. package/dist/cjs/query/warn-registry.js +9 -0
  79. package/dist/cjs/query/where-compile.d.ts +139 -0
  80. package/dist/cjs/query/where.d.ts +548 -0
  81. package/dist/cjs/query/where.js +58 -22
  82. package/dist/cjs/query/writes.d.ts +172 -0
  83. package/dist/cjs/query/writes.js +105 -12
  84. package/dist/cjs/realtime.d.ts +70 -0
  85. package/dist/cjs/schema-builder.d.ts +354 -0
  86. package/dist/cjs/schema-metadata.d.ts +83 -0
  87. package/dist/cjs/schema-sql.d.ts +217 -0
  88. package/dist/cjs/schema-sql.js +23 -5
  89. package/dist/cjs/schema.d.ts +356 -0
  90. package/dist/cjs/schema.js +125 -0
  91. package/dist/cjs/seed.d.ts +15 -0
  92. package/dist/cjs/serverless.d.ts +142 -0
  93. package/dist/cjs/sqlite.d.ts +143 -0
  94. package/dist/cjs/sqlite.js +4 -0
  95. package/dist/cjs/typed-sql.d.ts +102 -0
  96. package/dist/cli/config.d.ts +18 -4
  97. package/dist/cli/config.js +31 -6
  98. package/dist/cli/index.d.ts +123 -0
  99. package/dist/cli/index.js +223 -58
  100. package/dist/cli/migrate.d.ts +59 -10
  101. package/dist/cli/migrate.js +128 -41
  102. package/dist/cli/observe-ui.d.ts +1 -1
  103. package/dist/cli/observe-ui.js +14 -5
  104. package/dist/cli/observe.d.ts +7 -1
  105. package/dist/cli/observe.js +48 -12
  106. package/dist/cli/prisma-report.d.ts +14 -0
  107. package/dist/cli/prisma-report.js +72 -0
  108. package/dist/cli/prisma-resolve.d.ts +6 -0
  109. package/dist/cli/prisma-resolve.js +1 -0
  110. package/dist/cli/prisma-schema.d.ts +62 -2
  111. package/dist/cli/prisma-schema.js +81 -4
  112. package/dist/cli/rate-limit.d.ts +32 -0
  113. package/dist/cli/rate-limit.js +40 -0
  114. package/dist/cli/studio.d.ts +5 -5
  115. package/dist/cli/studio.js +135 -70
  116. package/dist/cli/ui.d.ts +1 -1
  117. package/dist/cli/ui.js +51 -9
  118. package/dist/client.d.ts +40 -0
  119. package/dist/client.js +3 -0
  120. package/dist/dialect.d.ts +17 -1
  121. package/dist/dialect.js +37 -12
  122. package/dist/generate.js +40 -7
  123. package/dist/index.d.ts +1 -1
  124. package/dist/index.js +1 -1
  125. package/dist/mssql.js +6 -0
  126. package/dist/mysql.js +16 -0
  127. package/dist/nested-write.d.ts +2 -0
  128. package/dist/nested-write.js +415 -25
  129. package/dist/powdb.d.ts +4 -2
  130. package/dist/powdb.js +106 -21
  131. package/dist/powql.d.ts +5 -0
  132. package/dist/powql.js +42 -6
  133. package/dist/prisma-compat.d.ts +2 -0
  134. package/dist/prisma-compat.js +166 -8
  135. package/dist/query/aggregates.js +7 -3
  136. package/dist/query/builder.d.ts +292 -21
  137. package/dist/query/builder.js +570 -64
  138. package/dist/query/deferred.d.ts +39 -0
  139. package/dist/query/index.d.ts +1 -1
  140. package/dist/query/index.js +1 -1
  141. package/dist/query/relations.d.ts +173 -5
  142. package/dist/query/relations.js +688 -47
  143. package/dist/query/types.d.ts +123 -39
  144. package/dist/query/utils.d.ts +116 -0
  145. package/dist/query/utils.js +198 -0
  146. package/dist/query/warn-registry.d.ts +9 -0
  147. package/dist/query/warn-registry.js +9 -0
  148. package/dist/query/where.d.ts +38 -1
  149. package/dist/query/where.js +58 -23
  150. package/dist/query/writes.d.ts +42 -1
  151. package/dist/query/writes.js +104 -13
  152. package/dist/schema-sql.d.ts +14 -0
  153. package/dist/schema-sql.js +23 -5
  154. package/dist/schema.d.ts +38 -0
  155. package/dist/schema.js +123 -0
  156. package/dist/sqlite.js +4 -0
  157. package/package.json +77 -28
@@ -0,0 +1,931 @@
1
+ /**
2
+ * turbine-orm/powdb — Turbine's PowDB / PowQL backend.
3
+ *
4
+ * PowDB is a single-node embedded database with its own query language, **PowQL**
5
+ * (not SQL), reached over `@zvndev/powdb-client`'s binary TCP protocol. PowDB is a
6
+ * different shape than the SQL engines, so this module does NOT route through the
7
+ * SQL `Dialect` / `QueryInterface`: it ships a parallel {@link PowqlInterface} that
8
+ * generates PowQL, plugged into `TurbineClient` via the `queryInterfaceFactory`
9
+ * seam. The four SQL engines are untouched.
10
+ *
11
+ * PowDB realities shape the design (all verified firsthand against a live
12
+ * `powdb-server` / the embedded addon, see `docs/internal/strategy/powdb-parity-matrix.md`):
13
+ * - **`RETURNING` (since 0.7.0)** — `create/createMany/update/delete` append the
14
+ * trailing `returning` keyword (`RETURNING *`, all columns) and read the
15
+ * affected rows back in one round-trip. `upsert` is the lone exception (its
16
+ * statement rejects `returning`) and reselects by primary key.
17
+ * - **No generated IDs** — the app must supply every value → Turbine generates a
18
+ * client-side UUID for the primary key when it has a default.
19
+ * - **`uuid`/`datetime`/`bytes` columns can't hold client-supplied values** (no
20
+ * literal, no working cast on the wire) → Turbine maps everything onto the four
21
+ * writable types (`str`/`int`/`float`/`bool`); `Date` → `int` epoch micros;
22
+ * `string` PKs hold UUID strings.
23
+ * - **No JSON aggregation / link navigation** — single-query nested `with` is
24
+ * impossible → it degrades to batched N+1 loaders (Phase B).
25
+ * - **Single global write lock; no savepoints/isolation** — nested
26
+ * transactions / isolation / vector / LISTEN-NOTIFY / RLS throw.
27
+ * Independent concurrent `db.$transaction` calls do NOT throw: they queue
28
+ * FIFO on a pool-level gate and run one at a time (see {@link PowdbTxGate}).
29
+ * Only a *re-entrant* transaction — a `db.$transaction` opened from inside
30
+ * an active transaction callback's async context, which queueing would
31
+ * deadlock — fails fast with E017.
32
+ * - **The wire protocol pipelines** — `@zvndev/powdb-client` writes each
33
+ * request frame immediately and matches replies FIFO, so multiple queries
34
+ * may be in flight on one connection. {@link PowdbPool}'s checked-out
35
+ * clients advertise `supportsPipelining`, which lets the batch
36
+ * `$transaction([...])` overload dispatch all statements in one write
37
+ * burst (~1 round trip) instead of one round trip per statement.
38
+ *
39
+ * `@zvndev/powdb-client` is an **optional peer dependency** loaded by dynamic
40
+ * import; `npm i turbine-orm` still pulls only `pg`.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { turbinePowDB } from 'turbine-orm/powdb';
45
+ * import { SCHEMA } from './generated/turbine/metadata.js';
46
+ *
47
+ * const db = await turbinePowDB({ host: '127.0.0.1', port: 5433 }, SCHEMA);
48
+ * const user = await db.table('users').create({ data: { name: 'Ada' } }); // UUID id auto-generated
49
+ * const found = await db.table('users').findMany({ where: { name: 'Ada' }, limit: 10 });
50
+ * await db.disconnect();
51
+ * ```
52
+ *
53
+ * @module
54
+ */
55
+ import { type PgCompatPool, type PgCompatPoolClient, TurbineClient, type TurbineConfig } from './client.js';
56
+ import { type Dialect } from './dialect.js';
57
+ import type { PowdbExec } from './powdb-introspect.js';
58
+ import { type ColumnMetadata, type SchemaMetadata, type TableMetadata } from './schema.js';
59
+ /**
60
+ * Capability descriptor for PowDB. PowQL generation is owned by
61
+ * {@link PowqlInterface} (not the SQL `Dialect`), so this dialect exists only to
62
+ * drive `TurbineClient`'s capability gating and transaction keywords:
63
+ * - `supports*` flags are all `false` for the Postgres-only features, so
64
+ * `$listen`/`$notify`, RLS `sessionContext`/`$withSession`, and pgvector
65
+ * throw a clear {@link UnsupportedFeatureError} (E017) at the client surface
66
+ * instead of emitting SQL that PowDB cannot parse.
67
+ * - `begin`/`commit`/`rollback` are lowercase PowQL keywords (verified on the
68
+ * wire) so a single-level `$transaction` works.
69
+ * - PowDB has a single global write lock and supports neither savepoints nor
70
+ * nested/concurrent transactions. The `savepoint*` keywords therefore throw
71
+ * {@link UnsupportedFeatureError} (E017): a nested `tx.$transaction` emits a
72
+ * savepoint synchronously (before any DB call) and so fails fast with a
73
+ * clear typed error instead of leaking PowDB's cryptic `Parse(... 'sp_1')`.
74
+ * The pool-level transaction gate (see {@link PowdbTxGate}) handles the
75
+ * other shapes: a fresh top-level `db.$transaction` opened inside an
76
+ * already-open one throws E017 before it can deadlock on the write lock,
77
+ * while INDEPENDENT concurrent `db.$transaction` calls queue FIFO and run
78
+ * one at a time instead of failing.
79
+ * Isolation levels remain Phase B.
80
+ */
81
+ export declare const powdbDialect: Dialect;
82
+ /** A single value PowDB accepts as a positional `$N` parameter. */
83
+ type PowdbParam = string | number | bigint | boolean | null;
84
+ /**
85
+ * Marker wrapper for a value bound to a `float` column. The networked driver
86
+ * unwraps it to the plain number (the wire param is unchanged), but the
87
+ * *embedded* literal encoder reads it to emit a float-form PowQL literal (`42`
88
+ * → `42.0`) so an integer-valued float column stays unambiguously a float.
89
+ * Constructed in {@link PowqlInterface.param}.
90
+ */
91
+ export declare class PowdbFloatParam {
92
+ readonly value: number;
93
+ constructor(value: number);
94
+ }
95
+ /**
96
+ * Marker wrapper for a JS object/array bound to a `json` document column. Both
97
+ * transports serialize `value` with `JSON.stringify` and send the text as a
98
+ * `str` param / string literal, exactly how the PowDB docs insert a json
99
+ * document (the engine validates it as JSON text and stores the canonical
100
+ * binary form). Constructed in {@link PowqlInterface.param} when the target
101
+ * column is `json` and the value is a non-null object/array; a JS string
102
+ * written to a json column passes through RAW (same contract as pg jsonb,
103
+ * pass `'"x"'` to store the JSON string `"x"`), and `null` stays `null`.
104
+ */
105
+ export declare class PowdbJsonParam {
106
+ readonly value: unknown;
107
+ readonly column?: string | undefined;
108
+ /** `column` is diagnostic only: it names the target column when serialization fails. */
109
+ constructor(value: unknown, column?: string | undefined);
110
+ }
111
+ /** The four shapes a PowQL result takes over the legacy string wire. */
112
+ type PowdbResult = {
113
+ kind: 'rows';
114
+ columns: string[];
115
+ rows: string[][];
116
+ } | {
117
+ kind: 'scalar';
118
+ value: string;
119
+ } | {
120
+ kind: 'ok';
121
+ affected: bigint;
122
+ } | {
123
+ kind: 'message';
124
+ message: string;
125
+ };
126
+ /**
127
+ * Local structural mirror of `@zvndev/powdb-client`'s `WireValue` (the lossless
128
+ * typed cell of the native wire surface). Defined here rather than imported so
129
+ * the optional peer's types never leak into Turbine's published `.d.ts` (a
130
+ * consumer without the peer installed must still `tsc` cleanly, same rule as
131
+ * every other optional-peer type in this module). `empty` = an unset value
132
+ * (distinct, for a json column, from a JSON-null document, which is
133
+ * `{ type: 'json', value: null }`).
134
+ */
135
+ type PowdbWireValue = {
136
+ type: 'empty';
137
+ } | {
138
+ type: 'int';
139
+ value: bigint;
140
+ } | {
141
+ type: 'float';
142
+ value: number;
143
+ } | {
144
+ type: 'bool';
145
+ value: boolean;
146
+ } | {
147
+ type: 'str';
148
+ value: string;
149
+ } | {
150
+ type: 'datetime';
151
+ value: bigint;
152
+ } | {
153
+ type: 'uuid';
154
+ value: Uint8Array;
155
+ } | {
156
+ type: 'bytes';
157
+ value: Uint8Array;
158
+ } | {
159
+ type: 'json';
160
+ value: unknown;
161
+ pj1?: Uint8Array;
162
+ };
163
+ /** The native (lossless typed) result shape, mirroring `RawNativeQueryResult`. */
164
+ type PowdbRawNativeResult = {
165
+ kind: 'rows';
166
+ columns: string[];
167
+ rows: PowdbWireValue[][];
168
+ } | {
169
+ kind: 'scalar';
170
+ value: PowdbWireValue;
171
+ } | {
172
+ kind: 'ok';
173
+ affected: bigint;
174
+ } | {
175
+ kind: 'message';
176
+ message: string;
177
+ };
178
+ interface PowdbClient {
179
+ readonly serverVersion: string;
180
+ query(query: string, params?: PowdbParam[], opts?: {
181
+ signal?: AbortSignal;
182
+ }): Promise<PowdbResult>;
183
+ /**
184
+ * Lossless typed wire surface (client ≥ 0.13, server ≥ 0.13). Optional: an
185
+ * older client omits it, so every call site feature-detects
186
+ * `typeof c.queryNativeRaw === 'function'` before using it and falls back to
187
+ * {@link query}. It NEVER retries as a legacy query, replaying an ambiguous
188
+ * mutation is unsafe, so its use is additionally version-gated server-side.
189
+ */
190
+ queryNativeRaw?(query: string, params?: PowdbParam[], opts?: {
191
+ signal?: AbortSignal;
192
+ }): Promise<PowdbRawNativeResult>;
193
+ close(): Promise<void>;
194
+ }
195
+ interface PowdbClientPool {
196
+ acquire(): Promise<PowdbClient>;
197
+ release(c: PowdbClient): void;
198
+ destroy(c: PowdbClient): void;
199
+ withClient<T>(fn: (c: PowdbClient) => Promise<T>): Promise<T>;
200
+ close(): Promise<void>;
201
+ }
202
+ interface PowdbModule {
203
+ Client: {
204
+ connect(opts: PowdbConnOptions): Promise<PowdbClient>;
205
+ };
206
+ Pool: new (opts: PowdbConnOptions & {
207
+ max?: number;
208
+ }) => PowdbClientPool;
209
+ isPowDBError?(err: unknown): err is {
210
+ code: string;
211
+ message: string;
212
+ };
213
+ }
214
+ /** Connection options for {@link turbinePowDB} — host/port, not a connection string. */
215
+ export interface PowdbConnOptions {
216
+ host: string;
217
+ port: number;
218
+ dbName?: string;
219
+ user?: string;
220
+ password?: string | null;
221
+ connectTimeoutMs?: number;
222
+ tls?: boolean;
223
+ }
224
+ /** Minimum PowDB server version the networked transport requires. */
225
+ export declare const MIN_POWDB_VERSION = "0.7.0";
226
+ /**
227
+ * Parse a `powdb://[user[:pass]@]host[:port][/db]` connection string into
228
+ * {@link PowdbConnOptions} (consistency with `turbineMysql`/`turbineMssql`,
229
+ * which accept a URL). Defaults: host `127.0.0.1`, port `5433`.
230
+ */
231
+ export declare function parsePowdbUrl(connectionString: string): PowdbConnOptions;
232
+ /**
233
+ * Fail fast if a networked PowDB server is older than {@link MIN_POWDB_VERSION}.
234
+ * Turbine's write path relies on the trailing `returning` keyword and the
235
+ * int→float coercion fix, both of which landed in 0.7.0. Embedded exposes no
236
+ * version method, so this is networked-only (the embedded peer is pinned ^0.7.0
237
+ * at install time). A non-semver / empty version string is tolerated (we cannot
238
+ * prove it is too old).
239
+ */
240
+ export declare function assertSupportedPowdbVersion(version: string | undefined): void;
241
+ /**
242
+ * Feature capabilities of a bound PowDB connection. Resolved once (from the
243
+ * probed server version on the networked transport, or the addon package
244
+ * version on embedded) and carried on the pool so {@link PowqlInterface} can
245
+ * gate PowQL features that only exist on newer engines, an old engine gets a
246
+ * typed {@link UnsupportedFeatureError} (E017) with a version hint instead of a
247
+ * raw PowQL parse error.
248
+ */
249
+ export interface PowdbCapabilities {
250
+ /** Best-known engine version (e.g. `'0.13.0'`), or `null` when unknowable. */
251
+ engineVersion: string | null;
252
+ /** ≥ 0.12: `json` column type, `->` path filters / ordering / grouping. */
253
+ jsonDocs: boolean;
254
+ /** ≥ 0.13: `alter T add index (.col->seg)` expression indexes. */
255
+ docFieldIndexes: boolean;
256
+ /** ≥ 0.10: `schema` / `describe` introspection statements. */
257
+ introspection: boolean;
258
+ /** ≥ 0.13: server-side joins, hash-accelerated and bounded. */
259
+ serverJoins: boolean;
260
+ /**
261
+ * ≥ 0.18: nested projections (shaped results) — a projection field may be a
262
+ * whole correlated child query returning a per-parent JSON array. When set,
263
+ * eligible `with` clauses compile into the parent statement instead of the
264
+ * batched loaders.
265
+ */
266
+ nestedProjections: boolean;
267
+ /**
268
+ * ≥ 0.19: entity links (`link` DDL, scalar/block traversal). Capability is
269
+ * recognized (probe-only), but query generation deliberately does NOT consume
270
+ * links yet: turbine keeps composing its own nested projections (see the
271
+ * PowDB engine page for the rationale). Declaring a link permanently upgrades
272
+ * the on-disk catalog to v7, so this stays FALSE in ALL_POWDB_CAPABILITIES.
273
+ */
274
+ entityLinks: boolean;
275
+ /**
276
+ * ≥ 0.19.1: link INTROSPECTION, the `schema links` listing statement and the
277
+ * appended link rows in `describe <T>`. Only meaningful when probed (there is
278
+ * no query-generation flip behind it), so it stays FALSE in
279
+ * ALL_POWDB_CAPABILITIES like the other probe-only gates. Floored at the PATCH
280
+ * 0.19.1: the listing statement shipped there, not in 0.19.0.
281
+ */
282
+ linkIntrospection: boolean;
283
+ /**
284
+ * ≥ 0.19.1: scalar to-one link PATHS in query generation. Floored at the PATCH
285
+ * 0.19.1 (never 0.19.0) because 0.19.0 had silent-wrong-results link bugs
286
+ * (bare-dotted-path split, wrong aggregates over links) that make traversal
287
+ * unsafe; 0.19.1 turned those into hard errors. This flag flips real query
288
+ * generation (a to-one `with` whose child carries bigint/bytes compiles to
289
+ * link-path projections instead of a loader), so it stays FALSE in
290
+ * ALL_POWDB_CAPABILITIES: it must only light up behind a real version probe.
291
+ */
292
+ linkPaths: boolean;
293
+ /** Networked only: server ≥ 0.13 AND the client exposes `queryNativeRaw`. */
294
+ nativeRaw: boolean;
295
+ }
296
+ /** The feature-gate capability keys (everything except the version/nativeRaw metadata). */
297
+ type PowdbFeatureKey = 'jsonDocs' | 'docFieldIndexes' | 'introspection' | 'serverJoins' | 'nestedProjections' | 'entityLinks' | 'linkIntrospection' | 'linkPaths';
298
+ /**
299
+ * Trusted-caller default: every FEATURE gate on, engine version unknown. Used
300
+ * for a directly-constructed {@link PowdbPool} / {@link PowdbEmbeddedPool} that
301
+ * did not go through {@link turbinePowDB}'s version probe (e.g. an injected
302
+ * pool, or a unit-test pool). `nativeRaw` stays OFF here because it flips the
303
+ * actual wire path and must only be enabled after a real server-version probe,
304
+ * never inferred from a bare construction. `nestedProjections` stays OFF for
305
+ * the same reason: it changes the generated PowQL for every `with` query, and
306
+ * an unprobed engine below 0.18 would reject the syntax outright.
307
+ * `entityLinks` stays OFF for a stronger reason still: declaring a link
308
+ * one-way-upgrades the on-disk catalog to v7 and locks out pre-0.19 binaries,
309
+ * so it must only ever light up behind a real version probe.
310
+ * `linkIntrospection` / `linkPaths` stay OFF for the same probe-only discipline:
311
+ * `linkPaths` flips real query generation (a to-one `with` compiling to link
312
+ * projections), and `linkIntrospection` is only meaningful once genuinely
313
+ * probed, so both must come from a real version resolution, never a bare
314
+ * construction.
315
+ */
316
+ export declare const ALL_POWDB_CAPABILITIES: PowdbCapabilities;
317
+ /**
318
+ * Derive {@link PowdbCapabilities} from an engine version string. A non-semver /
319
+ * unknown version turns every gate OFF (the E017 hint then tells the caller to
320
+ * upgrade or pass `assumeEngineVersion`). `nativeRaw` requires BOTH the client
321
+ * to expose `queryNativeRaw` (passed in) AND server ≥ 0.13.
322
+ */
323
+ export declare function capabilitiesFromVersion(version: string | undefined | null, opts?: {
324
+ hasNativeRaw?: boolean;
325
+ }): PowdbCapabilities;
326
+ /**
327
+ * Throw a version-hinting {@link UnsupportedFeatureError} (E017) when a gated
328
+ * PowQL feature is used on an engine that does not support it. Keeps old engines
329
+ * getting clean typed errors instead of raw PowQL parse failures.
330
+ */
331
+ export declare function requireCapability(caps: PowdbCapabilities, key: PowdbFeatureKey, feature: string): void;
332
+ /**
333
+ * PowQL column types Turbine emits: the four writable scalars plus PowDB's
334
+ * native `json` document type (added to the map in the 0.12/0.13 parity round,
335
+ * see {@link isJsonColumn}). A `json` column stores a canonical binary document
336
+ * (sorted keys, int/float distinction preserved) that Turbine writes as a JSON
337
+ * string literal and reads back by parsing the canonical JSON text.
338
+ */
339
+ export type PowqlType = 'str' | 'int' | 'float' | 'bool' | 'json';
340
+ /**
341
+ * Does this column map to PowDB's native `json` document type? A Postgres
342
+ * `json`/`jsonb` type (via `dialectType`/`pgType`) is authoritative; otherwise
343
+ * the tsType heuristic (`Record<…>`, `object`, `unknown`, an object/array
344
+ * literal) that the four scalar branches do not claim. Array columns never map
345
+ * to json, a PowDB array only exists INSIDE a json document, so a Postgres
346
+ * array column has no PowDB shape and still throws in {@link powqlColumnType}.
347
+ */
348
+ export declare function isJsonColumn(col: ColumnMetadata): boolean;
349
+ /**
350
+ * Map a Turbine column to the PowQL DDL type used in `defineSchema` →
351
+ * `type T { … }`. Turbine never emits PowDB's `uuid`/`datetime`/`bytes` types,
352
+ * which cannot hold client-supplied values on the wire (no literal, no cast):
353
+ * - `Date` → `int` (epoch micros) - `boolean` → `bool`
354
+ * - integral `number`/`bigint` → `int` - fractional `number` → `float`
355
+ * - JSON / object columns → `json` (native PowDB document type, ≥ 0.12)
356
+ * - everything else (incl. UUID/PK strings) → `str`
357
+ * Array (non-json) and bytes columns throw, they have no PowDB equivalent.
358
+ */
359
+ export declare function powqlColumnType(col: ColumnMetadata): PowqlType;
360
+ /**
361
+ * Generate PowQL DDL (`type T { … }`) for every table in a schema. Used to
362
+ * provision a PowDB database from a code-first `defineSchema`/`SchemaMetadata`
363
+ * (PowDB has no migration runner yet). The primary key column is declared
364
+ * `required unique`; non-nullable columns are `required`. A server-generated
365
+ * column ({@link ColumnMetadata.isGenerated}) that maps to PowQL `int` gets the
366
+ * `auto` modifier, so PowDB assigns a monotonic id on insert and Turbine stops
367
+ * synthesizing a client-side value for it.
368
+ */
369
+ /**
370
+ * PowQL reserved words — the v0.10 lexer keyword table from POWQL.md's
371
+ * "Reserved Words and Quoting" section, including the v0.10 additions
372
+ * `schema` and `describe`. Keyword matching is case-sensitive in the lexer,
373
+ * so only the exact lowercase form collides.
374
+ */
375
+ export declare const POWQL_KEYWORDS: ReadonlySet<string>;
376
+ /**
377
+ * Backtick-quote an identifier when PowQL would otherwise lex it as a keyword
378
+ * (or when it contains characters outside the bare-identifier grammar).
379
+ * Applied only in bare-identifier positions — DDL type/field names, index DDL,
380
+ * and `insert`/`update`/`upsert` assignment targets. Dotted references
381
+ * (`.col` in filters/projections/ordering) bypass keyword lookup on every
382
+ * engine version and deliberately stay bare for ≤0.9 compatibility. Backticks
383
+ * parse on PowDB ≥ 0.10; on older engines these names were already parse
384
+ * errors when emitted bare, so quoting is strictly an improvement.
385
+ */
386
+ export declare function quotePowqlIdent(name: string): string;
387
+ /**
388
+ * Options for {@link powqlSchemaDDL}. Additive: with no options the DDL is
389
+ * emitted unconditionally (pure-function callers / tests); pass `capabilities`
390
+ * to gate engine-version-specific features (json columns, and, since the
391
+ * 0.13 parity round, doc-field expression indexes) behind the connection's
392
+ * real capabilities. Doc-field expression index declarations plug into the
393
+ * per-table `indexes` surface consumed here without further signature churn.
394
+ */
395
+ export interface PowqlSchemaDDLOptions {
396
+ capabilities?: PowdbCapabilities;
397
+ /**
398
+ * Emit `link Owner.name -> Target on local = target` declarations (PowDB entity
399
+ * links, >= 0.19) for every single-column hasMany / hasOne / belongsTo relation
400
+ * in the metadata, appended after the `type` / index statements. Default
401
+ * `false`: links are opt-in. Composite-key relations and m2m junctions are
402
+ * skipped (a link is single-column only); a relation whose name collides with a
403
+ * column on the owner is skipped with a one-time warning (the engine hard-errors
404
+ * on such a collision). When `capabilities` is also supplied it must pass the
405
+ * `entityLinks` gate, else this throws a typed E017.
406
+ *
407
+ * ONE-WAY DOOR: the FIRST `link` a database ever executes permanently upgrades
408
+ * its on-disk catalog to format v7; pre-0.19 PowDB binaries / addons can then no
409
+ * longer open that data directory. A database that never declares a link stays
410
+ * on its current catalog format. The DDL is create-only (no `if not exists`, no
411
+ * drop spelling), so an apply layer must existence-check first (see
412
+ * {@link applyPowdbLinks}).
413
+ */
414
+ emitLinks?: boolean;
415
+ }
416
+ /**
417
+ * One entity link Turbine wants declared for a relation: `link owner.name ->
418
+ * target on localKey = targetKey`. Cardinality is NOT part of the DDL (PowDB
419
+ * derives to-one vs to-many from whether `targetKey` is unique on `target` at
420
+ * declare time), so a belongsTo and its reverse hasMany both round-trip to the
421
+ * same shape from opposite owners.
422
+ */
423
+ export interface PowdbDesiredLink {
424
+ owner: string;
425
+ name: string;
426
+ target: string;
427
+ localKey: string;
428
+ targetKey: string;
429
+ }
430
+ /**
431
+ * Derive the entity links Turbine would declare from a schema's relations. One
432
+ * link per single-column hasMany / hasOne / belongsTo relation, owned by the
433
+ * relation's `from` table:
434
+ * - belongsTo Order->User: `Order.user -> User on user_id = id`
435
+ * (localKey = the FK on the owner, targetKey = the referenced key on target).
436
+ * - hasMany User->Order: `User.orders -> Order on id = user_id`
437
+ * (localKey = the referenced key on the owner, targetKey = the FK on the child).
438
+ * Composite-key relations and m2m junctions are skipped (links are single-column;
439
+ * a junction cannot be inferred from links). A relation whose name collides with
440
+ * a column on the owner is skipped and reported through `onCollision` (the caller
441
+ * decides whether to warn). Pure: no capability gate, no side effects.
442
+ */
443
+ export declare function deriveDesiredLinks(schema: SchemaMetadata, onCollision?: (owner: string, name: string) => void): PowdbDesiredLink[];
444
+ /** Render one {@link PowdbDesiredLink} as its create-only `link ...` DDL statement. */
445
+ export declare function powdbLinkStatement(link: PowdbDesiredLink): string;
446
+ export declare function powqlSchemaDDL(schema: SchemaMetadata, opts?: PowqlSchemaDDLOptions): string[];
447
+ /**
448
+ * Existence-checked apply of entity-link DDL against a LIVE PowDB database.
449
+ * Because link DDL is create-only (no `if not exists`, redeclaring is an error,
450
+ * and there is no drop spelling), an apply layer must diff against the live
451
+ * catalog first: this reads the `schema links` listing, then executes only the
452
+ * links that are genuinely missing.
453
+ *
454
+ * - a desired link already declared with the SAME endpoints → skipped (idempotent);
455
+ * - a link declared with the same owner + name but DIFFERENT endpoints → skipped
456
+ * with a one-time warning (never dropped/replaced: there is no drop DDL, and a
457
+ * silent replace would be a destructive schema change);
458
+ * - a name/column collision on the owner → skipped (deriveDesiredLinks warns).
459
+ *
460
+ * Requires the `entityLinks` + `linkIntrospection` capabilities when `capabilities`
461
+ * is supplied (the listing statement is 0.19.1+). Returns the statements executed.
462
+ * `exec` runs one PowQL statement (embedded `db.raw` / a networked query shim); it
463
+ * must return rows keyed by column name for the `schema links` read.
464
+ */
465
+ export declare function applyPowdbLinks(exec: PowdbExec, schema: SchemaMetadata, options?: {
466
+ capabilities?: PowdbCapabilities;
467
+ }): Promise<string[]>;
468
+ /**
469
+ * Coerce a single PowDB wire string into the JS value its column type implies.
470
+ * Every PowDB value arrives as a string; NULL arrives as the bareword `"null"`.
471
+ * Metadata resolves the `"null"` ambiguity for nullable non-string columns.
472
+ */
473
+ export declare function coerceValue(raw: string, col: ColumnMetadata): unknown;
474
+ /**
475
+ * Coerce a single cell that arrived over the NATIVE typed wire (decoded from a
476
+ * {@link PowdbWireValue}, so already a JS `bigint`/`number`/`boolean`/`string`/
477
+ * `NativeJson`/`Uint8Array`/`null`, never a bare `"null"` string). Unlike
478
+ * {@link coerceValue} this NEVER collapses the string `"null"` to `null`: an
479
+ * absent value already decoded to `null` (from the `empty` cell), so a genuine
480
+ * str `"null"` stays the string `"null"` (fixes the legacy-wire wart on the
481
+ * native transport). `datetime`-shaped cells (int micros) become `Date`; a
482
+ * bigint on a `number` column follows the int8 safe-integer policy.
483
+ */
484
+ export declare function coerceNativeValue(value: unknown, col: ColumnMetadata): unknown;
485
+ /**
486
+ * Map one raw PowDB row into a typed entity (camelCase fields, coerced values).
487
+ * Only the columns present in `raw` are emitted, so partial `select`
488
+ * projections round-trip unchanged. `native` selects the coercion policy: the
489
+ * default `false` handles the legacy string wire (every cell is a string, via
490
+ * {@link coerceValue}); `true` handles the native typed wire, where non-string
491
+ * cells arrive pre-typed and go through {@link coerceNativeValue} (see F3).
492
+ * Callers on the native transport pass `this.pool.capabilities.nativeRaw`.
493
+ */
494
+ export declare function rowToEntity(raw: Record<string, unknown>, meta: TableMetadata, native?: boolean): Record<string, unknown>;
495
+ /**
496
+ * Translate a PowDB error into a typed Turbine error. Handles BOTH transports,
497
+ * whose error shapes differ:
498
+ * - **networked** (`@zvndev/powdb-client`) tags errors with a *semantic*
499
+ * `.code` (`connect_failed`, `timeout`, `query_failed`, …);
500
+ * - **embedded** (`@zvndev/powdb-embedded` napi addon) tags EVERY error
501
+ * `code:'GenericFailure'`, so the class can only be recovered from the
502
+ * message text (`Execution("column 'email' is required …")`,
503
+ * `Execution("type mismatch …")`, `Parse(…)`, `StorageError(…)`).
504
+ *
505
+ * So we always run the unique-constraint and message-shape checks first (they
506
+ * fire for both transports and extract detail like constraint / column names),
507
+ * then classify by the typed wire error class (`.wireErrorClass`, networked
508
+ * server >= 0.17 — accurate even when the server sanitized the message text),
509
+ * then fall through to the networked `.code` switch.
510
+ */
511
+ export declare function wrapPowdbError(err: unknown): Error;
512
+ /**
513
+ * True when `err` is the stale-wire-frame {@link ConnectionError} produced by
514
+ * {@link wrapPowdbError} (its `.cause` is a `protocol_error` PowDBError, or the
515
+ * message carries the invalid-state signature). The opt-in read retry
516
+ * (`retryStaleReads`, evaluated in {@link PowqlInterface}'s exec seam) uses this
517
+ * to decide whether a first-statement READ may be replayed once on a fresh
518
+ * connection; writes are NEVER retried (an ambiguous mutation reply is unsafe
519
+ * to replay, matching the client's own native-path policy).
520
+ */
521
+ export declare function isStaleFramePowdbError(err: unknown): boolean;
522
+ type QueryArg = string | {
523
+ name?: string;
524
+ text: string;
525
+ values?: unknown[];
526
+ };
527
+ /**
528
+ * Default cap (ms) on how long a `begin` may wait in the FIFO queue for
529
+ * PowDB's single global write lock before failing with a typed
530
+ * {@link TimeoutError} (E002). Prevents silent starvation behind a wedged
531
+ * transaction. Override via `transactionQueueTimeoutMs`
532
+ * ({@link TurbinePowdbOptions} / {@link PowdbPoolOptions}); `0` or `Infinity`
533
+ * waits without limit.
534
+ */
535
+ export declare const DEFAULT_TX_QUEUE_TIMEOUT_MS = 30000;
536
+ /** Tuning options shared by {@link PowdbPool} and {@link PowdbEmbeddedPool}. */
537
+ export interface PowdbPoolOptions {
538
+ /**
539
+ * Max time (ms) a concurrent transaction's `begin` may wait in the FIFO
540
+ * queue for the single-writer lock before failing with a
541
+ * {@link TimeoutError}. Default {@link DEFAULT_TX_QUEUE_TIMEOUT_MS};
542
+ * `0` / `Infinity` = wait without limit. Note this is a separate surface
543
+ * from `$transaction`'s `timeout` option, which only covers the callback
544
+ * *after* the transaction has begun.
545
+ */
546
+ transactionQueueTimeoutMs?: number;
547
+ /**
548
+ * Feature capabilities of the bound connection. Set by {@link turbinePowDB}
549
+ * from the probed engine version; defaults to {@link ALL_POWDB_CAPABILITIES}
550
+ * (feature gates on, `nativeRaw` off, engine version unknown) for a
551
+ * directly-constructed pool: a "trusted caller".
552
+ */
553
+ capabilities?: PowdbCapabilities;
554
+ /**
555
+ * Opt in to replaying a first-statement READ once, on a fresh connection,
556
+ * when it fails with the stale-wire-frame {@link ConnectionError} (see
557
+ * {@link isStaleFramePowdbError}). Networked only; writes and mid-transaction
558
+ * statements are NEVER retried. Read by {@link PowqlInterface}'s exec seam.
559
+ * Default `false` (typed-error-only).
560
+ */
561
+ retryStaleReads?: boolean;
562
+ /**
563
+ * Mark this pool read-only: {@link PowqlInterface}'s exec seam then fails a
564
+ * write (or a tx-control `begin`) fast with a {@link ReadOnlyError} (E018)
565
+ * before it reaches the wire. An `{ embedded, readonly: true }` target forces
566
+ * this true; a networked pool bound to a read-only role can also set it so
567
+ * writes are rejected locally instead of round-tripping to the engine's
568
+ * refusal. Default `false`.
569
+ */
570
+ readonly?: boolean;
571
+ }
572
+ /**
573
+ * A {@link PgCompatPool} backed by a `@zvndev/powdb-client` `Pool`. The query
574
+ * `text` is **PowQL**, not SQL ({@link PowqlInterface} generates it). On the
575
+ * legacy string wire cells come back as strings; when `capabilities.nativeRaw`
576
+ * is set (server ≥ 0.13 + a client exposing `queryNativeRaw`) this pool routes
577
+ * through the typed native wire instead, so cells arrive pre-typed (a json int
578
+ * as `bigint`, etc.) and each result is tagged with the wire that served it
579
+ * ({@link PowdbTaggedResult}). Per-column JS coercion still happens in
580
+ * `PowqlInterface` (it owns the schema metadata), keyed on that per-result tag.
581
+ */
582
+ export declare class PowdbPool implements PgCompatPool {
583
+ readonly pool: PowdbClientPool;
584
+ private readonly toParam;
585
+ private closed;
586
+ /**
587
+ * Pool-level single-writer gate. PowDB holds one global write lock, so at
588
+ * most one transaction may be open across the whole pool. Concurrent
589
+ * `begin`s queue FIFO on the gate (instead of checking out a second
590
+ * connection and blocking on the lock forever — the networked hang);
591
+ * re-entrant `begin`s throw E017 (see {@link PowdbTxGate}).
592
+ */
593
+ private readonly txGate;
594
+ /** Hold taken by a `begin` issued via `query()` directly (no checked-out client). */
595
+ private poolHold;
596
+ /**
597
+ * Clients currently checked out via {@link connect}. The driver pool's
598
+ * `close()` only closes IDLE clients (checked-out ones are documented as the
599
+ * caller's responsibility), so {@link end} destroys these explicitly;
600
+ * otherwise a `disconnect()` racing an unreleased connection would leave a
601
+ * live socket holding the process open until the server's idle timeout.
602
+ */
603
+ private readonly checkedOut;
604
+ /** Feature capabilities of the bound server (probed version + native-wire feature-detect). */
605
+ readonly capabilities: PowdbCapabilities;
606
+ /** Opt-in first-statement-read replay on a stale wire frame (read by {@link PowqlInterface}). */
607
+ readonly retryStaleReads: boolean;
608
+ /**
609
+ * True when the caller marked this pool read-only (`readonly: true`). Read by
610
+ * {@link PowqlInterface}'s exec seam to fail writes fast with E018 before the
611
+ * wire; the engine's own read-only-role refusal (mapped by
612
+ * {@link wrapPowdbError}) is the backstop for raw / injected paths.
613
+ */
614
+ readonly readonly: boolean;
615
+ constructor(pool: PowdbClientPool, toParam?: (v: unknown, i: number) => PowdbParam, options?: PowdbPoolOptions);
616
+ /**
617
+ * Run one statement on `c`, choosing the lossless native typed wire when the
618
+ * server supports it (`capabilities.nativeRaw`) AND this client exposes
619
+ * `queryNativeRaw` (a defensive per-call feature-detect, so a heterogeneous
620
+ * injected pool cannot crash). Otherwise the legacy string wire, unchanged.
621
+ */
622
+ private runOnClient;
623
+ query(text: QueryArg, values?: unknown[]): Promise<any>;
624
+ /**
625
+ * Typed guard mirroring {@link PowdbEmbeddedPool}: after `end()` the driver
626
+ * pool throws a raw `Error('pool closed')` that {@link wrapPowdbError}
627
+ * cannot classify — surface the same ConnectionError on both transports.
628
+ */
629
+ private assertOpen;
630
+ connect(): Promise<PgCompatPoolClient>;
631
+ end(): Promise<void>;
632
+ }
633
+ /** The embedded addon's result shape (matches {@link PowdbResult} but with optional fields). */
634
+ interface EmbeddedQueryResult {
635
+ kind: string;
636
+ columns?: string[];
637
+ rows?: string[][];
638
+ value?: string;
639
+ affected?: bigint;
640
+ message?: string;
641
+ }
642
+ /**
643
+ * The embedded addon's native typed result (`@zvndev/powdb-embedded` ≥ 0.14).
644
+ * Mirrors {@link PowdbRawNativeResult}, the same tagged {@link PowdbWireValue}
645
+ * cells (embedded `bytes` arrive as a `Buffer`, which IS a `Uint8Array`, so the
646
+ * decode path is unchanged), including the `message` kind for DDL / status
647
+ * replies, which {@link adaptNativeResult}'s default branch handles at runtime.
648
+ */
649
+ type EmbeddedNativeResult = PowdbRawNativeResult;
650
+ /** A single in-process embedded database handle (`@zvndev/powdb-embedded`). */
651
+ interface EmbeddedDatabase {
652
+ query(powql: string): EmbeddedQueryResult;
653
+ querySql(sql: string): EmbeddedQueryResult;
654
+ queryReadonly(powql: string): EmbeddedQueryResult;
655
+ isPoisoned(): boolean;
656
+ /** WAL durability selector — `@zvndev/powdb-embedded` ≥ 0.7.1. */
657
+ setSyncMode?(mode: string): void;
658
+ /**
659
+ * Lossless typed native wire (`@zvndev/powdb-embedded` ≥ 0.14). All optional
660
+ * and feature-detected: an older addon omits them, so {@link PowdbEmbeddedPool}
661
+ * falls back to {@link materializePowql} + {@link query}. `queryWithParams`
662
+ * binds positional `$N` params as {@link PowdbParam} values (the NativeParam
663
+ * union) instead of materializing literals.
664
+ */
665
+ queryNative?(powql: string): EmbeddedNativeResult;
666
+ queryReadonlyNative?(powql: string): EmbeddedNativeResult;
667
+ queryWithParams?(powql: string, params: PowdbParam[]): EmbeddedNativeResult;
668
+ /** Checkpoint-flushing close (`@zvndev/powdb-embedded` ≥ 0.14). Optional (feature-detected). */
669
+ close?(): void;
670
+ }
671
+ interface EmbeddedModule {
672
+ Database: {
673
+ open(dir: string): EmbeddedDatabase;
674
+ /** Open with a per-query memory budget — `@zvndev/powdb-embedded` ≥ 0.7.1. */
675
+ openWithMemoryLimit?(dir: string, limitBytes: number): EmbeddedDatabase;
676
+ /**
677
+ * Open a read-only handle for snapshot serving (`@zvndev/powdb-embedded` ≥
678
+ * 0.14). Optional (feature-detected); a write through such a handle is
679
+ * refused with `readonly mode: statement requires a writer …` (→ E018).
680
+ */
681
+ openReadOnly?(dir: string): EmbeddedDatabase;
682
+ openReadOnlyWithMemoryLimit?(dir: string, limitBytes: number): EmbeddedDatabase;
683
+ };
684
+ }
685
+ /**
686
+ * Encode a JS value as a **PowQL literal** for the embedded driver, which takes
687
+ * no params array — `$N` placeholders must be materialized into the query text.
688
+ *
689
+ * This is the single place Turbine builds PowQL text from a value, so it is the
690
+ * security-critical surface. String encoding matches PowDB's lexer
691
+ * (`crates/query/src/lexer.rs`) exactly: a string literal is `"…"`, and inside
692
+ * it the lexer recognizes only the escapes `\"`, `\\`, `\n`, `\t` (any other
693
+ * `\x` drops the backslash and keeps `x`; every non-`\`/non-`"` char — raw
694
+ * newlines, CR, unicode — is taken literally). So we escape `\` → `\\` and
695
+ * `"` → `\"` (the only breakout vectors), render `\n`/`\t` as their recognized
696
+ * escapes, and leave everything else raw. Verified against the real engine:
697
+ * quotes, backslashes, `$N`, `"); drop … --`, raw CR, and emoji all round-trip
698
+ * as data and cannot break out of the literal or inject a second statement.
699
+ */
700
+ export declare function encodePowqlLiteral(value: unknown, position?: string): string;
701
+ /**
702
+ * The newest PowDB engine LINE (major.minor) whose lexer escape handling
703
+ * {@link encodePowqlString} is VERIFIED against by reading
704
+ * `crates/query/src/lexer.rs`. The legacy materialize path
705
+ * ({@link materializePowql}) inlines encoded string literals directly into query
706
+ * text, so it is only injection-safe while the lexer recognizes exactly the
707
+ * escape set the escaper emits (`\"`, `\\`, `\n`, `\t`, everything else raw). If
708
+ * a future engine line teaches the lexer new escapes (e.g. `\u`, `\x`), a string
709
+ * that the escaper leaves raw could be re-interpreted by the lexer and break out
710
+ * of the literal, turning the fallback into an injection primitive.
711
+ *
712
+ * CONTRACT: bump this ceiling ONLY after re-verifying the escape handling in
713
+ * `crates/query/src/lexer.rs` for the newer line AND confirming
714
+ * {@link encodePowqlString} still escapes every breakout vector the lexer
715
+ * recognizes. The legacy path guards on this value (see
716
+ * {@link PowdbEmbeddedPool.exec}): an embedded addon whose engine line exceeds
717
+ * the ceiling yet still routes through the string wire is refused rather than
718
+ * materialized.
719
+ *
720
+ * Verification for the 0.19 line: `crates/query/src/lexer.rs` is byte-identical
721
+ * between v0.18.0 and v0.19.0 (empty git diff), and `link` was already a lexer
722
+ * keyword at 0.18.0. The 0.19 entity-links surface adds new STATEMENTS built from
723
+ * pre-existing tokens, so the tokenization / escape surface this ceiling guards is
724
+ * unmoved. The 0.19.1 link-introspection / link-path round is likewise lexer-neutral:
725
+ * `git diff v0.19.0 v0.19.1 -- crates/query/src/lexer.rs` is empty (the bare-dotted-path
726
+ * hard error is parser-level, not tokenization), so this ceiling stays `'0.19'`. The
727
+ * guard in {@link PowdbEmbeddedPool.exec} compares major.minor only, so `'0.19'`
728
+ * already covers every 0.19.x patch — no bump is needed for 0.19.1.
729
+ */
730
+ export declare const POWQL_LEXER_TESTED_CEILING = "0.19";
731
+ /**
732
+ * Substitute every `$N` placeholder in a generator-produced PowQL template with
733
+ * the encoded literal of `params[N-1]`. Safe because the template is produced by
734
+ * {@link PowqlInterface} and contains **no** user string literals — the only
735
+ * `$<digits>` tokens are genuine positional placeholders, so a single scan
736
+ * cannot accidentally rewrite a `$N` that is itself part of a value (values are
737
+ * params, never inlined into the template by the generator).
738
+ */
739
+ export declare function materializePowql(powql: string, params: unknown[]): string;
740
+ /**
741
+ * A {@link PgCompatPool} backed by an in-process `@zvndev/powdb-embedded`
742
+ * `Database`. On the addon's typed native wire (≥ 0.14, when
743
+ * `capabilities.nativeRaw` is set) this pool binds positional `$N` params via
744
+ * `queryWithParams` and decodes the typed cells, exactly like the networked
745
+ * transport. On an older addon (no `queryWithParams`) it falls back to the
746
+ * legacy string wire, which takes **no params array** (its `query(powql)`
747
+ * accepts only a string), so each positional `$N` is materialized into a PowQL
748
+ * literal via {@link materializePowql} before the text is handed to the engine.
749
+ * One handle, single connection: transaction keywords (`begin`/`commit`/
750
+ * `rollback`) are issued serially as ordinary queries.
751
+ */
752
+ export declare class PowdbEmbeddedPool implements PgCompatPool {
753
+ private readonly db;
754
+ private closed;
755
+ /**
756
+ * Single-writer gate. The embedded engine is one handle with one global
757
+ * write lock — only one transaction may be open at a time. A re-entrant
758
+ * `begin` (a fresh top-level `db.$transaction` opened inside an open one's
759
+ * callback) would otherwise hit PowDB's raw "already in a transaction"
760
+ * parse error; the gate surfaces a typed E017 instead, while INDEPENDENT
761
+ * concurrent transactions queue FIFO and run one at a time. (Nested
762
+ * `tx.$transaction` is caught earlier still, by the savepoint override in
763
+ * {@link powdbDialect}.)
764
+ */
765
+ private readonly txGate;
766
+ /** Hold taken by a `begin` issued via `query()` directly (no checked-out client). */
767
+ private readonly poolHoldRef;
768
+ /**
769
+ * Feature capabilities of the embedded engine (resolved from the addon
770
+ * package version). `nativeRaw` is true when the addon is ≥ 0.14 and the
771
+ * opened handle exposes `queryWithParams` (the typed native wire); an older
772
+ * addon has no such method, so it stays false and the legacy string wire is
773
+ * used.
774
+ */
775
+ readonly capabilities: PowdbCapabilities;
776
+ /** Carried for surface uniformity with {@link PowdbPool}; inert on embedded (no protocol_error frames). */
777
+ readonly retryStaleReads: boolean;
778
+ /**
779
+ * True when this pool was opened read-only (an `{ embedded, readonly: true }`
780
+ * target, or a directly-constructed pool passed `readonly: true`). Read by
781
+ * {@link PowqlInterface}'s exec seam to fail writes fast with E018 before the
782
+ * wire; the engine's own refusal (mapped by {@link wrapPowdbError}) is the
783
+ * backstop for raw / injected paths.
784
+ */
785
+ readonly readonly: boolean;
786
+ constructor(db: EmbeddedDatabase, options?: PowdbPoolOptions);
787
+ /** Run the PowQL on the in-process engine, choosing the native or legacy wire. */
788
+ private exec;
789
+ /**
790
+ * Run one statement, gating transaction control. `holdRef` scopes the gate
791
+ * hold to whoever issued the `begin` (the pool itself or one checked-out
792
+ * client), so finishing a transaction can never release a slot a different
793
+ * transaction is holding.
794
+ */
795
+ private run;
796
+ query(text: QueryArg, values?: unknown[]): Promise<any>;
797
+ connect(): Promise<PgCompatPoolClient>;
798
+ end(): Promise<void>;
799
+ }
800
+ export { introspectPowdbDatabase, type PowdbExec, type PowdbIntrospectOptions, } from './powdb-introspect.js';
801
+ export { PowqlInterface } from './powql.js';
802
+ /** Options for {@link turbinePowDB}. */
803
+ export interface TurbinePowdbOptions extends Pick<TurbineConfig, 'logging' | 'defaultLimit' | 'warnOnUnlimited' | 'relationLoadStrategy'> {
804
+ /**
805
+ * Client-level default `with`-relation load strategy. On PowDB the default is
806
+ * the batched N+1 loaders; setting `'join'` opts INTO native PowQL server-side
807
+ * joins for eligible top-level relations (ineligible ones, e.g. a paged parent
808
+ * or a nested `with`, fall back to the loaders per-relation and silently). A
809
+ * per-query `relationLoadStrategy` arg still overrides this. Requires an engine
810
+ * that advertises `serverJoins` (PowDB ≥ 0.13); a per-query `'join'` on an
811
+ * older engine throws E017, a client-level default silently falls back.
812
+ */
813
+ relationLoadStrategy?: TurbineConfig['relationLoadStrategy'];
814
+ /** Max pooled connections (default 10). Networked transport only. */
815
+ connectionLimit?: number;
816
+ /**
817
+ * Max time (ms) a concurrent `$transaction` waits in the FIFO queue for
818
+ * PowDB's single global write lock before failing with a typed
819
+ * `TimeoutError` (default {@link DEFAULT_TX_QUEUE_TIMEOUT_MS} = 30 000;
820
+ * `0` / `Infinity` = wait without limit). Independent concurrent
821
+ * transactions queue and run one at a time; only a re-entrant
822
+ * `db.$transaction` (opened inside an active transaction callback) throws
823
+ * E017 — queueing that shape would deadlock.
824
+ *
825
+ * Ignored when you inject an already-constructed {@link PowdbPool} (it carries
826
+ * its own {@link PowdbPoolOptions}); set it on that pool's constructor instead.
827
+ */
828
+ transactionQueueTimeoutMs?: number;
829
+ /**
830
+ * Opt in to replaying a first-statement READ once (on a fresh connection)
831
+ * when it fails with the stale-wire-frame {@link ConnectionError} that a
832
+ * request can hit after a long idle gap. Networked only; WRITES and any
833
+ * statement inside a transaction are NEVER retried (an ambiguous mutation
834
+ * reply is unsafe to replay). Default `false`: the error is surfaced typed
835
+ * so the caller can decide. See the retry recipe in the docs.
836
+ *
837
+ * Ignored when you inject an already-constructed {@link PowdbPool} (it carries
838
+ * its own {@link PowdbPoolOptions}); set it on that pool's constructor instead.
839
+ */
840
+ retryStaleReads?: boolean;
841
+ /**
842
+ * Override the detected engine version used for capability gating. For exotic
843
+ * deployments and injected pools whose version cannot be probed (a non-semver
844
+ * server string, or an addon whose package.json cannot be resolved): pass
845
+ * e.g. `'0.13.0'` to unlock the features that version supports. Without it, an
846
+ * undetectable version turns every version-gated feature OFF (with a hinting
847
+ * E017).
848
+ */
849
+ assumeEngineVersion?: string;
850
+ /**
851
+ * Mark the client read-only: a write (or a transaction `begin`) fails fast
852
+ * locally with a {@link ReadOnlyError} (E018) before it reaches the wire,
853
+ * rather than round-tripping to the engine's refusal. Works on both
854
+ * transports (a networked pool bound to a read-only role, or an embedded
855
+ * handle). An `{ embedded, readonly: true }` target implies this. Default
856
+ * `false`.
857
+ *
858
+ * Ignored when you inject an already-constructed {@link PowdbPool} (it carries
859
+ * its own {@link PowdbPoolOptions}); set it on that pool's constructor instead.
860
+ */
861
+ readonly?: boolean;
862
+ /**
863
+ * Driver-module injection for the networked target forms (URL / host+port):
864
+ * bypasses the dynamic `import('@zvndev/powdb-client')` and uses this object
865
+ * as the driver module instead. Intended for tests (a fake pool that counts
866
+ * connections) and advanced embedding; everyday callers never set it.
867
+ */
868
+ powdbClientModule?: PowdbModule;
869
+ /**
870
+ * Driver-module injection for the **embedded** target form (`{ embedded }`):
871
+ * bypasses the dynamic `import('@zvndev/powdb-embedded')` and uses this object
872
+ * as the addon module instead. Intended for tests (a fake `Database` factory
873
+ * that records how the handle was opened) and advanced embedding; everyday
874
+ * callers never set it. The symmetric counterpart to {@link powdbClientModule}.
875
+ */
876
+ powdbEmbeddedModule?: EmbeddedModule;
877
+ }
878
+ /**
879
+ * Selects the **embedded** transport — an in-process `@zvndev/powdb-embedded`
880
+ * database at the given data directory (no server, no socket). The value is the
881
+ * data dir path. Preview: Full-durability checkpoint-bound; built binaries ship
882
+ * for macOS (arm64/x64) and Unix-glibc only (Intel-mac/musl/Windows fall back to
883
+ * a from-source `npm run build`).
884
+ *
885
+ * @example
886
+ * ```ts
887
+ * const db = await turbinePowDB({ embedded: '/var/data/app.powdb' }, SCHEMA);
888
+ * // Faster writes (fsync off the commit path, bounded-loss) — requires addon >= 0.7.1:
889
+ * const fast = await turbinePowDB({ embedded: '/var/data/app.powdb', syncMode: 'normal' }, SCHEMA);
890
+ * ```
891
+ */
892
+ export interface TurbinePowdbEmbeddedTarget {
893
+ embedded: string;
894
+ /**
895
+ * WAL durability for the embedded engine (requires `@zvndev/powdb-embedded` ≥ 0.7.1):
896
+ * `'full'` (default — fsync per commit), `'normal'` (fsync off the commit path,
897
+ * ~15–40× faster writes, bounded loss on OS crash/power loss), `'off'` (bench-only).
898
+ */
899
+ syncMode?: 'full' | 'normal' | 'off';
900
+ /** Per-query memory budget in bytes (requires `@zvndev/powdb-embedded` ≥ 0.7.1). */
901
+ memoryLimit?: number;
902
+ /**
903
+ * Open the data directory read-only for snapshot serving (requires
904
+ * `@zvndev/powdb-embedded` ≥ 0.14: `openReadOnly` / `openReadOnlyWithMemoryLimit`).
905
+ * A write through a read-only handle is refused by the engine with
906
+ * `readonly mode: statement requires a writer …` (→ {@link ReadOnlyError}, E018),
907
+ * and Turbine additionally fails writes fast locally (this implies the pool's
908
+ * `readonly` flag). Meaningless together with `syncMode` (a read-only engine
909
+ * never writes), setting both throws a {@link ValidationError}.
910
+ */
911
+ readonly?: boolean;
912
+ }
913
+ /**
914
+ * Bind Turbine to PowDB. `target` is one of:
915
+ * - a `powdb://[user[:pass]@]host[:port][/db]` connection string → a
916
+ * **networked** `@zvndev/powdb-client` pool (consistency with
917
+ * `turbineMysql`/`turbineMssql`);
918
+ * - a host/port options object → a **networked** `@zvndev/powdb-client` pool;
919
+ * - an `{ embedded: <data-dir> }` object → an in-process
920
+ * `@zvndev/powdb-embedded` database (no server);
921
+ * - an already-constructed `@zvndev/powdb-client` `Pool` or {@link PowdbPool}
922
+ * (injection — you own its lifecycle and `disconnect()` is a no-op).
923
+ *
924
+ * On the networked transport the server version is probed and a clear
925
+ * {@link ConnectionError} is thrown if it is older than {@link MIN_POWDB_VERSION}
926
+ * (the `returning` keyword / int->float coercion fix Turbine relies on).
927
+ *
928
+ * Resolves to a `TurbineClient` whose `table()` accessors generate **PowQL** via
929
+ * {@link PowqlInterface}. The SQL `Dialect` is not involved.
930
+ */
931
+ export declare function turbinePowDB(target: string | PowdbConnOptions | PowdbClientPool | PowdbPool | TurbinePowdbEmbeddedTarget, schema: SchemaMetadata, options?: TurbinePowdbOptions): Promise<TurbineClient>;