@vibeorm/runtime 2.6.0 → 3.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.
Files changed (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -1
  3. package/dist/adapter-kit/adapter-lifecycle.d.ts +79 -0
  4. package/dist/adapter-kit/deferred-control.d.ts +58 -0
  5. package/dist/adapter-kit/index.d.ts +10 -3
  6. package/dist/adapter-kit/index.js +317 -24
  7. package/dist/adapter-kit/index.js.map +10 -7
  8. package/dist/adapter-kit/nested-options.d.ts +16 -2
  9. package/dist/adapter-kit/row-changes.d.ts +15 -1
  10. package/dist/adapter-kit/savepoint-gate.d.ts +17 -3
  11. package/dist/adapter-kit/transaction-budget.d.ts +23 -13
  12. package/dist/adapter-kit/transaction-outcome.d.ts +167 -0
  13. package/dist/adapter.d.ts +103 -11
  14. package/dist/client.d.ts +7 -0
  15. package/dist/codecs.d.ts +35 -0
  16. package/dist/config.d.ts +15 -0
  17. package/dist/extensions.d.ts +10 -0
  18. package/dist/find-page.d.ts +9 -2
  19. package/dist/index.d.ts +8 -4
  20. package/dist/index.js +4086 -1295
  21. package/dist/index.js.map +40 -28
  22. package/dist/keyset-iterator.d.ts +12 -2
  23. package/dist/keyset.d.ts +65 -10
  24. package/dist/lateral-projection.d.ts +31 -1
  25. package/dist/model-meta.d.ts +12 -0
  26. package/dist/nested-fold.d.ts +98 -0
  27. package/dist/nested-update-data.d.ts +11 -0
  28. package/dist/nested-writes.d.ts +38 -1
  29. package/dist/query-builder.d.ts +78 -19
  30. package/dist/read-only.d.ts +5 -0
  31. package/dist/relation-key.d.ts +50 -0
  32. package/dist/relation-loader.d.ts +13 -1
  33. package/dist/relation-plan.d.ts +16 -0
  34. package/dist/strict-args.d.ts +1 -0
  35. package/dist/upsert-fold.d.ts +77 -0
  36. package/dist/write-scope.d.ts +9 -0
  37. package/package.json +7 -5
  38. package/dist/adapter-kit/index.d.ts.map +0 -1
  39. package/dist/adapter-kit/nested-options.d.ts.map +0 -1
  40. package/dist/adapter-kit/row-changes.d.ts.map +0 -1
  41. package/dist/adapter-kit/savepoint-gate.d.ts.map +0 -1
  42. package/dist/adapter-kit/savepoints.d.ts.map +0 -1
  43. package/dist/adapter-kit/session.d.ts.map +0 -1
  44. package/dist/adapter-kit/sqlite-session.d.ts.map +0 -1
  45. package/dist/adapter-kit/transaction-budget.d.ts.map +0 -1
  46. package/dist/adapter.d.ts.map +0 -1
  47. package/dist/advisory-key.d.ts.map +0 -1
  48. package/dist/advisory-lock.d.ts.map +0 -1
  49. package/dist/bulk-upsert.d.ts.map +0 -1
  50. package/dist/client-types.d.ts.map +0 -1
  51. package/dist/client.d.ts.map +0 -1
  52. package/dist/codecs.d.ts.map +0 -1
  53. package/dist/computed.d.ts.map +0 -1
  54. package/dist/database-module.d.ts.map +0 -1
  55. package/dist/db-now.d.ts.map +0 -1
  56. package/dist/diagnostics/index.d.ts.map +0 -1
  57. package/dist/diagnostics/insight.d.ts.map +0 -1
  58. package/dist/diagnostics/plan.d.ts.map +0 -1
  59. package/dist/diagnostics/preview.d.ts.map +0 -1
  60. package/dist/diagnostics/statement-diagnostics.d.ts.map +0 -1
  61. package/dist/diagnostics/types.d.ts.map +0 -1
  62. package/dist/diagnostics/workload.d.ts.map +0 -1
  63. package/dist/extensions.d.ts.map +0 -1
  64. package/dist/find-page.d.ts.map +0 -1
  65. package/dist/index.d.ts.map +0 -1
  66. package/dist/keyset-iterator.d.ts.map +0 -1
  67. package/dist/keyset-projection.d.ts.map +0 -1
  68. package/dist/keyset.d.ts.map +0 -1
  69. package/dist/lateral-projection.d.ts.map +0 -1
  70. package/dist/model-meta.d.ts.map +0 -1
  71. package/dist/module-context.d.ts.map +0 -1
  72. package/dist/nested-writes.d.ts.map +0 -1
  73. package/dist/policy-operation.d.ts.map +0 -1
  74. package/dist/policy.d.ts.map +0 -1
  75. package/dist/query-builder.d.ts.map +0 -1
  76. package/dist/read-only.d.ts.map +0 -1
  77. package/dist/relation-key.d.ts.map +0 -1
  78. package/dist/relation-loader.d.ts.map +0 -1
  79. package/dist/relation-plan.d.ts.map +0 -1
  80. package/dist/render-cache.d.ts.map +0 -1
  81. package/dist/rls-context.d.ts.map +0 -1
  82. package/dist/rls-readiness.d.ts.map +0 -1
  83. package/dist/scoped.d.ts.map +0 -1
  84. package/dist/sql-access.d.ts.map +0 -1
  85. package/dist/sql.d.ts.map +0 -1
  86. package/dist/strict-args.d.ts.map +0 -1
  87. package/dist/telemetry/collector.d.ts.map +0 -1
  88. package/dist/telemetry/config.d.ts.map +0 -1
  89. package/dist/telemetry/fingerprint.d.ts.map +0 -1
  90. package/dist/telemetry/index.d.ts.map +0 -1
  91. package/dist/telemetry/recorder.d.ts.map +0 -1
  92. package/dist/telemetry/statement.d.ts.map +0 -1
  93. package/dist/telemetry/types.d.ts.map +0 -1
  94. package/dist/transaction-row-changes.d.ts.map +0 -1
  95. package/dist/validators.d.ts.map +0 -1
  96. package/dist/views.d.ts.map +0 -1
  97. package/dist/write-scope.d.ts.map +0 -1
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Transaction outcome reports — what a FAILED top-level transaction did and
3
+ * did not do (EPIC T).
4
+ *
5
+ * ONE copy, shared by every adapter package through the
6
+ * `@vibeorm/runtime/adapter-kit` subpath (like `transaction-budget.ts`), so the
7
+ * rule cannot drift into a per-engine difference.
8
+ *
9
+ * THE RULE
10
+ *
11
+ * The commit outcome follows from how far the adapter's OWN `COMMIT` got —
12
+ * never from the type of the error that ended the transaction:
13
+ *
14
+ * - `"not-committed"`: `COMMIT` never left the client (the callback failed, a
15
+ * deadline or a closed handle refused it, or the driver had already seen the
16
+ * connection die and refused it locally), or the engine ANSWERED it with an
17
+ * error or a ROLLBACK tag. Only this session can send `COMMIT`, and a
18
+ * server ends an open transaction when its connection closes, so a failed
19
+ * cleanup `ROLLBACK` does not change this.
20
+ * - `"unknown"`: a `COMMIT` that left the client got no answer — the
21
+ * connection was lost while it was in flight, or a client-side deadline
22
+ * stopped waiting for it. Also when the savepoint stack was lost before
23
+ * `COMMIT` (`savepoint-rollback-failed`): an implicit commit (MySQL DDL) or a
24
+ * raw `COMMIT` may already have ended the transaction.
25
+ * - `"committed"`: the engine acknowledged `COMMIT`. A successful transaction
26
+ * throws nothing, so no report is recorded for it.
27
+ *
28
+ * The cleanup is reported APART from the commit outcome: whether the cleanup
29
+ * `ROLLBACK` was acknowledged, failed or not needed, and whether the
30
+ * connection went back to the pool or was discarded.
31
+ *
32
+ * WHERE THE FACTS LIVE
33
+ *
34
+ * The error a failed transaction throws stays the SAME value — callers match
35
+ * their own errors and stable codes. The facts ride beside it in a registry
36
+ * keyed by that value, read with {@link transactionOutcomeOf}. The registry is
37
+ * a `WeakMap` held on `globalThis` under a `Symbol.for` key: the runtime's
38
+ * main entry and this subpath are separate bundles, each with its own copy of
39
+ * this module, and both must read the same map. A `WeakMap` never keeps an
40
+ * error alive and never changes the error object. Under a frozen or sealed
41
+ * `globalThis` (SES, hardened JavaScript) the key cannot be added: each copy
42
+ * then keeps a module-local map, so a report recorded by one bundle is not
43
+ * visible from the other, and the accessor returns `undefined` — the runtime
44
+ * stays importable.
45
+ *
46
+ * A CROSS-VERSION CONTRACT
47
+ *
48
+ * Two installed copies of `@vibeorm/runtime` (an adapter built against one,
49
+ * a framework reading with another) share the one global map. Each stored
50
+ * record therefore carries a `version`. The report shape is append-only:
51
+ * fields are only ever added; a change of meaning bumps the version, and a
52
+ * reader that does not know a record's version returns `undefined` ("no
53
+ * facts") rather than misreading it.
54
+ */
55
+ import { type SavepointScope } from "./savepoint-gate.ts";
56
+ import { type TransactionBudget, type TransactionOutcome } from "./transaction-budget.ts";
57
+ /**
58
+ * How far an adapter's own `COMMIT` got. The adapter moves it to `"sent"`
59
+ * IMMEDIATELY before `COMMIT` is handed to the driver, and on a failure
60
+ * classifies a sent `COMMIT` as `"answered"` (the engine replied with an error
61
+ * or a ROLLBACK tag) or `"unanswered"` (the reply was lost or abandoned). A
62
+ * `"sent"` that was never classified counts as unanswered: without an answer
63
+ * nothing proves that the write did not commit.
64
+ */
65
+ export type CommitProgress = "not-sent" | "sent" | "answered" | "unanswered";
66
+ /** What the cleanup `ROLLBACK` of a failed top-level transaction did. */
67
+ export type RollbackOutcome = "acknowledged" | "failed" | "not-needed";
68
+ /** Where the transaction's connection went after the failure. */
69
+ export type ConnectionOutcome = "returned" | "discarded";
70
+ /**
71
+ * The facts of one failed top-level transaction, read with
72
+ * {@link transactionOutcomeOf}.
73
+ *
74
+ * - `commit`: the commit outcome (see the module rule). `"not-committed"` is
75
+ * safe to retry as far as the database is concerned; `"unknown"` is not.
76
+ * - `commitSent`: whether the adapter handed its `COMMIT` to the driver.
77
+ * - `rollback`: `"acknowledged"` (the engine confirmed the cleanup
78
+ * `ROLLBACK`), `"failed"` (it was sent and failed — the connection is lost,
79
+ * or the engine refused it), `"not-needed"` (no transaction was open on the
80
+ * connection: nothing was sent yet, or the engine had already ended it
81
+ * when it answered `COMMIT`).
82
+ * - `connection`: `"returned"` to the pool (or kept, on a single-connection
83
+ * engine) or `"discarded"` (destroyed, so the server ends whatever it still
84
+ * holds when it sees the close).
85
+ */
86
+ export type TransactionOutcomeReport = {
87
+ readonly commit: FailedCommitOutcome;
88
+ readonly commitSent: boolean;
89
+ readonly rollback: RollbackOutcome;
90
+ readonly connection: ConnectionOutcome;
91
+ };
92
+ /**
93
+ * The commit outcome of a FAILED transaction. `"committed"` is never recorded:
94
+ * a transaction that committed throws nothing.
95
+ */
96
+ export type FailedCommitOutcome = Exclude<TransactionOutcome, "committed">;
97
+ /**
98
+ * Attach `report` to the value a failed top-level transaction is about to
99
+ * throw. A later report for the same value replaces the earlier one, so a
100
+ * value rethrown through several top-level transactions carries the facts of
101
+ * the LAST one it left. A primitive thrown value (a string, a number,
102
+ * `undefined`) cannot key a `WeakMap`, so nothing is recorded for it.
103
+ */
104
+ export declare function recordTransactionOutcome(params: {
105
+ error: unknown;
106
+ report: TransactionOutcomeReport;
107
+ }): void;
108
+ /**
109
+ * The facts of the failed top-level transaction that threw `error`, or
110
+ * `undefined` when there are none.
111
+ *
112
+ * `undefined` means one of: the adapter does not declare
113
+ * `transactionOutcome: "reported"`; `error` did not leave a top-level
114
+ * `transaction()` (a nested savepoint records nothing); the transaction was
115
+ * refused before it started (an invalid option, a connection that could not be
116
+ * acquired — nothing was sent); the thrown value is not an object (a
117
+ * primitive cannot key the registry — throw `Error` objects to keep the facts);
118
+ * the record was written by a runtime copy with a report version this copy
119
+ * does not know; or `globalThis` is frozen and the report was recorded by the
120
+ * other bundle (see the module doc).
121
+ */
122
+ export declare function transactionOutcomeOf(params: {
123
+ error: unknown;
124
+ }): TransactionOutcomeReport | undefined;
125
+ /** The commit outcome of a failed transaction — the ONE rule (see the module doc). */
126
+ export declare function failedCommitOutcome(params: {
127
+ commit: CommitProgress;
128
+ stateLost: boolean;
129
+ }): FailedCommitOutcome;
130
+ /**
131
+ * Close a failed top-level transaction's budget with its commit outcome (the
132
+ * rule above) and return that outcome. The first close wins: an adapter that
133
+ * closed `unknown` the moment it lost a COMMIT reply keeps that.
134
+ *
135
+ * {@link settleFailedTransaction} calls it. An adapter whose connection must
136
+ * leave BEFORE it can settle (adapter-mysql resets the session and releases the
137
+ * connection to learn where it went) calls it first, so every handle of the
138
+ * failed transaction is refused before the connection is handed back.
139
+ */
140
+ export declare function closeFailedTransactionBudget(params: {
141
+ error: unknown;
142
+ budget: TransactionBudget;
143
+ scope: SavepointScope;
144
+ commit: CommitProgress;
145
+ }): FailedCommitOutcome;
146
+ /**
147
+ * Settle a failed top-level transaction AFTER its cleanup ran: close the
148
+ * budget with the commit outcome, choose the value to throw, and record the
149
+ * facts on it. Returns that value; the adapter throws it.
150
+ *
151
+ * The value is `error` itself — the same object, the same code — except when
152
+ * a client-side deadline abandoned a COMMIT that had already left the client
153
+ * (`commit: "unanswered"` with the deadline refusal as `error`): only then is
154
+ * it {@link transactionOutcomeUnknownError}. A deadline that refused the
155
+ * COMMIT before it was sent is a known outcome (`"not-committed"`), and its own
156
+ * deadline error is rethrown even when the cleanup `ROLLBACK` failed.
157
+ */
158
+ export declare function settleFailedTransaction(params: {
159
+ error: unknown;
160
+ provider: string;
161
+ budget: TransactionBudget;
162
+ scope: SavepointScope;
163
+ commit: CommitProgress;
164
+ rollback: RollbackOutcome;
165
+ connection: ConnectionOutcome;
166
+ }): unknown;
167
+ //# sourceMappingURL=transaction-outcome.d.ts.map
package/dist/adapter.d.ts CHANGED
@@ -68,12 +68,26 @@ export type TransactionDeadline = {
68
68
  * a nested timeout is not enforceable, and a nested deadline would need an
69
69
  * independent session setting on a connection it does not own. A nested
70
70
  * savepoint instead INHERITS the top-level deadline, by reference.
71
+ *
72
+ * `accessMode: "readOnly"` opens a READ ONLY transaction in the opening
73
+ * statement itself (`BEGIN … READ ONLY` on postgres servers, `START
74
+ * TRANSACTION READ ONLY` on mysql, `SET TRANSACTION READ ONLY` right after
75
+ * PGlite's own BEGIN) — no extra round trip. A write inside it is refused by
76
+ * the engine and raises `VIBE_TRANSACTION` with `meta.reason:
77
+ * "read-only-transaction"`. sqlite adapters refuse the option with
78
+ * `VIBE_UNSUPPORTED_CAPABILITY`; a nested call refuses it like the others.
71
79
  */
72
80
  export type TransactionOptions = {
73
81
  isolationLevel?: IsolationLevel;
74
82
  timeout?: number;
75
83
  deadline?: TransactionDeadline;
84
+ accessMode?: TransactionAccessMode;
76
85
  };
86
+ /**
87
+ * Transaction access mode. Only `"readOnly"` exists: omitting the option keeps
88
+ * the engine's default (read/write), exactly as before the option existed.
89
+ */
90
+ export type TransactionAccessMode = "readOnly";
77
91
  /**
78
92
  * How far an engine's per-statement timeout actually reaches.
79
93
  *
@@ -83,6 +97,15 @@ export type TransactionOptions = {
83
97
  * forbids.
84
98
  */
85
99
  export type StatementTimeoutSupport = "all-statements" | "select-only" | "unsupported";
100
+ /**
101
+ * Whether a failed top-level `transaction()` reports its facts (EPIC T).
102
+ * `"reported"`: every object it throws once the transaction has started
103
+ * carries a `TransactionOutcomeReport`, read with `transactionOutcomeOf({ error })`
104
+ * from `@vibeorm/runtime` — the commit outcome (`not-committed` / `unknown`),
105
+ * whether COMMIT was sent, what the cleanup ROLLBACK did and whether the
106
+ * connection was returned or discarded.
107
+ */
108
+ export type TransactionOutcomeSupport = "reported";
86
109
  /** The strongest transaction-deadline guarantee an adapter can honestly deliver. */
87
110
  export type TransactionDeadlineSupport = "cancel-running-statements" | "between-statements" | "unsupported";
88
111
  /**
@@ -100,11 +123,35 @@ export type AdapterBudgetSupport = {
100
123
  readonly statementTimeout: StatementTimeoutSupport;
101
124
  /** What `TransactionOptions.deadline.enforcement` may ask for on this engine. */
102
125
  readonly transactionDeadline: TransactionDeadlineSupport;
126
+ /**
127
+ * The `TransactionOptions.accessMode` values this adapter honours in its
128
+ * opening statement. Not a timing budget, but declared here for the same
129
+ * reason as `transactionDeadline`: the runtime refuses an access mode the
130
+ * adapter does not declare with `VIBE_UNSUPPORTED_CAPABILITY` before it calls
131
+ * `transaction()`, so an adapter that predates the option (or a third-party
132
+ * one) can never open a read/write transaction for a caller who asked for a
133
+ * read-only one. Optional (additive); undeclared = none.
134
+ */
135
+ readonly accessModes?: readonly TransactionAccessMode[];
103
136
  };
104
137
  /** Surviving direct DML effects, or an honest unknown when observation is incomplete. */
105
138
  export type RowChangeCount = number | "unknown";
106
- /** Internal structured execution intent. Never accepted as an ORM/raw query argument. */
107
- export type StatementEffect = "read" | "write" | "unknown";
139
+ /**
140
+ * Internal structured execution intent. Never accepted as an ORM/raw query argument.
141
+ *
142
+ * `writeRows` (round-trip campaign EPIC 4): a data-modifying statement chain
143
+ * whose RESULT ROWS are its direct effects — one returned row per changed row.
144
+ * An adapter counts the rows it received, never the command tag: a chain's tag
145
+ * is `SELECT n`, and PGlite reports zero affected rows for any SELECT. An
146
+ * adapter that cannot count rows reports `unknown` for it.
147
+ *
148
+ * `writeTally` (round-trip campaign EPIC F): a statement chain that REPORTS its
149
+ * direct effects in the result column `ROW_CHANGES_COLUMN` (adapter-kit) — the
150
+ * rows its data-modifying steps changed, which its result rows do not show.
151
+ * An adapter sums that column over the rows it received (adapter-kit
152
+ * `statementRowChanges` with `resultRows`); one that cannot reports `unknown`.
153
+ */
154
+ export type StatementEffect = "read" | "write" | "writeRows" | "writeTally" | "unknown";
108
155
  /** Result of an unsafe/raw execution: rows plus affected-row count. */
109
156
  export type QueryResult = {
110
157
  rows: Record<string, unknown>[];
@@ -212,15 +259,45 @@ export type DatabaseAdapter = {
212
259
  * provider name. Every adapter in this repository declares it.
213
260
  */
214
261
  readonly budgets?: AdapterBudgetSupport;
262
+ /**
263
+ * Whether a round trip to this adapter's engine crosses a network
264
+ * (`"network"`: a database server, even on a local socket) or stays inside
265
+ * this process (`"in-process"`: an embedded engine such as PGlite or SQLite).
266
+ *
267
+ * The runtime folds some multi-statement calls into ONE larger statement to
268
+ * save round trips (the nested-write fold and the upsert-fallback fold). On an
269
+ * in-process engine a round trip costs nothing, so only the larger
270
+ * statement's cost would remain: there the runtime keeps the multi-statement
271
+ * path, with the same results, errors and counts.
272
+ *
273
+ * OPTIONAL, so the frozen contract stays additive — exactly like
274
+ * {@link DatabaseAdapter.budgets}. An adapter that declares nothing is treated
275
+ * as `"network"`. Callers branch on this declaration, never on a provider
276
+ * name. Transactional adapters must carry the same declaration.
277
+ */
278
+ readonly roundTrips?: "network" | "in-process";
279
+ /**
280
+ * Whether a failed top-level {@link DatabaseAdapter.transaction} records a
281
+ * `TransactionOutcomeReport` on the value it throws (EPIC T) — read it with
282
+ * `transactionOutcomeOf({ error })`. The thrown value itself is unchanged.
283
+ *
284
+ * OPTIONAL, so the frozen contract stays additive — exactly like
285
+ * {@link DatabaseAdapter.roundTrips}. Undeclared = no reports. Callers branch
286
+ * on this declaration, never on a provider name. It describes the TOP-LEVEL
287
+ * call only: a transactional handle's nested `transaction()` (a savepoint)
288
+ * records nothing, so transactional handles do not declare it.
289
+ */
290
+ readonly transactionOutcome?: TransactionOutcomeSupport;
215
291
  /**
216
292
  * Run `fn` inside a transaction; the callback receives a transactional
217
293
  * adapter with this same interface. Nested calls create savepoints. Throwing
218
294
  * rolls back (the savepoint or the whole transaction) and rethrows.
219
295
  *
220
296
  * `options` is honored on TOP-LEVEL calls only. A NESTED call refuses any
221
- * `isolationLevel` or `timeout` with `VIBE_VALIDATION` (`meta.nested:
222
- * true`), identically on every adapter: a savepoint cannot change the
223
- * isolation level of the transaction it joins, and a nested timeout is not
297
+ * `isolationLevel`, `timeout`, `deadline` or `accessMode` with
298
+ * `VIBE_VALIDATION` (`meta.nested: true`), identically on every adapter: a
299
+ * savepoint cannot change the isolation level of the transaction it joins,
300
+ * and a nested timeout is not
224
301
  * enforceable. Silently dropping the option was the pre-#3 behaviour of the
225
302
  * pg/pglite/mysql/bun adapters and is forbidden by constitution rule 4.
226
303
  */
@@ -232,14 +309,29 @@ export type DatabaseAdapter = {
232
309
  * Optional for third-party adapters; migration use refuses when unavailable.
233
310
  */
234
311
  readonly withSession?: SessionRunner;
235
- /** Eagerly open/verify connectivity (pool warm-up or first connection). */
312
+ /**
313
+ * Eagerly open/verify connectivity (pool warm-up or first connection).
314
+ * Refuses with `VIBE_ADAPTER_CLOSED` once {@link DatabaseAdapter.disconnect}
315
+ * was called. On a transaction handle it refuses with `VIBE_VALIDATION`
316
+ * (`meta: { method, inTransaction: true }`): the transaction owns the connection.
317
+ */
236
318
  connect(): Promise<void>;
237
319
  /**
238
- * Gracefully close the connections open right now. NOT terminal: every
239
- * adapter constructs its pool/connection lazily, so a query issued after
240
- * `disconnect()` transparently opens a NEW connection and succeeds — the
241
- * documented contract (symmetric with lazy construction, and with Prisma's
242
- * `$disconnect()`-then-query semantics), not an accident.
320
+ * End this adapter for good (terminal since EPIC A2). The first call seals
321
+ * the adapter synchronously: every later root call (`execute`,
322
+ * `executeUnsafe`, `transaction`, `withSession`, `connect`, …) refuses with
323
+ * `VIBE_ADAPTER_CLOSED` (`meta: { driver, state: "closing" | "closed" }`)
324
+ * and opens no pool or connection. Work admitted before the call drains
325
+ * first — a whole transaction or session callback included, whose handle
326
+ * keeps working until it returns — then the adapter closes what it OWNS,
327
+ * once; an injected pool/instance/database is never ended. Every call
328
+ * returns the same completion (a cleanup failure included). Called from
329
+ * inside one of this adapter's own running transaction/session callbacks,
330
+ * it refuses with `VIBE_TRANSACTION` (`meta.reason:
331
+ * "disconnect-in-active-callback"`) instead of waiting for itself. There is
332
+ * no timeout: stop producers and await pending work before closing. To
333
+ * connect again, create a new adapter. On a transaction handle it refuses
334
+ * with `VIBE_VALIDATION`, like `connect()`.
243
335
  */
244
336
  disconnect(): Promise<void>;
245
337
  /**
package/dist/client.d.ts CHANGED
@@ -254,6 +254,13 @@ export type DynamicClient = {
254
254
  */
255
255
  readonly $tryAdvisoryLock: (options: AdvisoryLockOptions) => Promise<boolean>;
256
256
  readonly $connect: () => Promise<void>;
257
+ /**
258
+ * Flush pending diagnostics, end the adapter for good, then flush telemetry.
259
+ * The adapter's `disconnect()` is terminal: work this client (or any client
260
+ * sharing the adapter) issues afterwards refuses with `VIBE_ADAPTER_CLOSED`,
261
+ * `$connect()` included. Stop producers and await pending ORM work first;
262
+ * to connect again, create a new adapter and client.
263
+ */
257
264
  readonly $disconnect: () => Promise<void>;
258
265
  /**
259
266
  * Field-masking views (v1 `defineView` parity, board #11) — a read-only
package/dist/codecs.d.ts CHANGED
@@ -24,6 +24,35 @@ export declare function getCodec(params: {
24
24
  dialect: Dialect;
25
25
  type: FieldType;
26
26
  }): ScalarCodec;
27
+ /**
28
+ * Field-aware routing: membership survives identity pruning despite String
29
+ * transport, and `Float @db.Real` takes the float32 codec (shortest decimal
30
+ * that round-trips through float32 — a binary-format driver widens `0.1` to
31
+ * `0.10000000149011612`), and `DateTime @db.Time`/`@db.Timetz` take the
32
+ * time-of-day codec (UTC time of day out, `1970-01-01` in).
33
+ */
34
+ /**
35
+ * Does this field hold a time of day (`DateTime @db.Time(n)` / `@db.Timetz(n)`)?
36
+ * The same rule that routes it to the time-of-day codec; membership predicates
37
+ * carry it to the dialect (`inArray.timeOfDay`).
38
+ */
39
+ export declare function isTimeOfDayField(params: {
40
+ field: FieldMeta;
41
+ }): boolean;
42
+ /**
43
+ * Is this column projected as `"col"::text AS "col"` (SELECT and RETURNING)?
44
+ * True for postgres `Float[]` and `Json[]` columns: bun:sql's text array parser
45
+ * refuses a float array holding a value postgres prints with an exponent
46
+ * (`1e-05`, `1e+15`) and a json/jsonb array holding an integer beyond int32 or
47
+ * a nested `[null]` — the whole statement fails, after a write has already
48
+ * happened on RETURNING. The array literal text is parsed by the list decoder
49
+ * below instead (`fieldDecoder`). Other list types parse fine on every driver
50
+ * and are left alone — the text path costs JS parsing.
51
+ */
52
+ export declare function projectsListAsText(params: {
53
+ dialect: Dialect;
54
+ field: FieldMeta;
55
+ }): boolean;
27
56
  /**
28
57
  * Encode one value for parameter binding. `null`/`undefined` pass through
29
58
  * untouched (SQL NULL). List fields encode element-wise; the adapter's
@@ -161,6 +190,12 @@ export type PositionalMaterializer = (row: unknown) => Record<string, unknown>;
161
190
  export declare function positionalMaterializer(params: {
162
191
  model: ModelMeta;
163
192
  columns: readonly ColRef[];
193
+ /**
194
+ * R-02: trailing slots after `columns`, kept RAW under these names — a
195
+ * nested lateral's JSON, decoded by the next level with its own model's
196
+ * codecs. Never a schema field (`__rel_<name>` is a reserved prefix).
197
+ */
198
+ passthrough?: readonly string[];
164
199
  }): PositionalMaterializer;
165
200
  /**
166
201
  * Normalize one aggregate value — the contract, tested live on PGlite:
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Runtime tunables. Internal: not exported from the package entry.
3
+ */
4
+ /** Tunables of the client runtime, grouped in one frozen object. */
5
+ export declare const RUNTIME_CONFIG: {
6
+ /**
7
+ * The nested write as ONE statement (round-trip campaign EPIC F) covers at
8
+ * most this many children; a longer list keeps today's path (parent
9
+ * statement + child statement in a transaction). EPIC F decision 3: at 1000
10
+ * children the one statement measured ~1.5× slower than the plain child
11
+ * INSERT locally; at 100 or fewer it is within ~1 ms.
12
+ */
13
+ readonly nestedFoldMaxChildren: number;
14
+ };
15
+ //# sourceMappingURL=config.d.ts.map
@@ -32,6 +32,16 @@ export type ExtensionMountContext = {
32
32
  values: readonly unknown[];
33
33
  method?: string;
34
34
  }) => Promise<Record<string, unknown>[]>;
35
+ /**
36
+ * The mount model's full row projection (`"t"."id", "t"."scores"::text AS
37
+ * "scores"`), every column qualified by `qualify`. Select this instead of
38
+ * `"t".*`: rows then hold exactly the model's columns, read the way
39
+ * `findMany` reads them — bun:sql refuses some `Float[]`/`Json[]` values
40
+ * when the driver parses the list itself.
41
+ */
42
+ readonly projection: (params: {
43
+ qualify: string;
44
+ }) => string;
35
45
  /** Compile a user `where` tree for AND-ing into extension SQL. */
36
46
  readonly compileWhere: (params: {
37
47
  where: Record<string, unknown>;
@@ -1,5 +1,5 @@
1
1
  import type { SqlDialect } from "@vibeorm/sql";
2
- import type { KeysetOrderPlan } from "./keyset.ts";
2
+ import type { KeysetOrderPlan, KeysetQueryBinding } from "./keyset.ts";
3
3
  import type { ModelMeta, RuntimeMeta } from "./model-meta.ts";
4
4
  /** One bounded keyset page. A null continuation means the lookahead found no further row. */
5
5
  export type KeysetPage<T> = {
@@ -14,7 +14,12 @@ export declare function validatePageArgs(params: {
14
14
  model: string;
15
15
  args: unknown;
16
16
  }): PageArgs;
17
- /** Compile the first page's order too; findMany alone only requires a total order with after. */
17
+ /**
18
+ * Compile the first page's order too; findMany alone only requires a total
19
+ * order with after. The binding is the query the page's tokens belong to: the
20
+ * `where` this engine compiles (any `$scoped` / `$withPolicy` predicate
21
+ * included) plus the caller's `keyset.scope`.
22
+ */
18
23
  export declare function preparePage(params: {
19
24
  meta: RuntimeMeta;
20
25
  model: ModelMeta;
@@ -22,11 +27,13 @@ export declare function preparePage(params: {
22
27
  args: PageArgs;
23
28
  }): {
24
29
  readonly plan: KeysetOrderPlan;
30
+ readonly binding: KeysetQueryBinding;
25
31
  readonly args: Record<string, unknown>;
26
32
  };
27
33
  /** Mint from the last delivered row before its hidden fields are projected away. */
28
34
  export declare function pageContinuation(params: {
29
35
  plan: KeysetOrderPlan;
36
+ binding: KeysetQueryBinding;
30
37
  rows: readonly Record<string, unknown>[];
31
38
  take: number;
32
39
  after: unknown;
package/dist/index.d.ts CHANGED
@@ -15,13 +15,17 @@ export { compileAdvisoryLock } from "./advisory-lock.ts";
15
15
  export { advisoryKeyOf } from "./advisory-key.ts";
16
16
  export { transactionRowChanges } from "./transaction-row-changes.ts";
17
17
  export type { AdvisoryLockMethod, AdvisoryLockOptions } from "./advisory-lock.ts";
18
- export type { DatabaseAdapter, IsolationLevel, QueryResult, RowChangeCount, StatementEffect, SessionRunner, SqlExecutor, TransactionOptions, } from "./adapter.ts";
18
+ export type { DatabaseAdapter, IsolationLevel, QueryResult, RowChangeCount, StatementEffect, SessionRunner, SqlExecutor, TransactionAccessMode, TransactionOptions, } from "./adapter.ts";
19
19
  export type { AdapterBudgetSupport, StatementTimeoutSupport, TransactionDeadline, TransactionDeadlineEnforcement, TransactionDeadlineSupport, } from "./adapter.ts";
20
+ export { transactionOutcomeOf } from "./adapter-kit/transaction-outcome.ts";
21
+ export type { ConnectionOutcome, RollbackOutcome, FailedCommitOutcome, TransactionOutcomeReport, } from "./adapter-kit/transaction-outcome.ts";
22
+ export type { TransactionOutcome } from "./adapter-kit/transaction-budget.ts";
23
+ export type { TransactionOutcomeSupport } from "./adapter.ts";
20
24
  export { buildRuntimeMeta, generateCuid, generateDefaultValue, generateNanoid, generateUlid, generateUuid, getFieldMeta, getModelMeta, toClientName, } from "./model-meta.ts";
21
25
  export type { ComputedFieldMeta, DefaultOrigin, ExtensionOperatorFn, FieldMeta, ModelMeta, RuntimeMeta, } from "./model-meta.ts";
22
26
  export { DIALECT_CODECS, MYSQL_CODECS, POSTGRES_CODECS, SQLITE_CODECS, decodeAggregateValue, decodeIsNoop, decodeRow, decodeRows, decodeValue, encodeValue, getCodec, } from "./codecs.ts";
23
27
  export type { CodecTable, ScalarCodec, WireFidelity } from "./codecs.ts";
24
- export { COUNT_ALIAS, buildQuery, compileOrderBy, compileSelect, compileWhere, lateralColumnAlias, resolveResultShape, } from "./query-builder.ts";
28
+ export { COUNT_ALIAS, buildQuery, compileOrderBy, compileProjection, compileSelect, compileWhere, lateralColumnAlias, resolveResultShape, } from "./query-builder.ts";
25
29
  export type { AggregateKey, AggregateSelection, AggregateSpec, BuilderClientOptions, QueryMethod, QueryPlan, RelationStrategy, } from "./query-builder.ts";
26
30
  export { DIAGNOSTIC_THRESHOLDS, PLAN_DEFAULTS, STATEMENT_DIAGNOSTICS_DEFAULTS, analyzeOperationTelemetry, createStatementDiagnostics, explainOnSession, explainOperation, explainSql, formatStatementDiagnostic, isExecutableRead, parameterTypeTag, parseDiagnosticsEnv, parsePostgresPlan, previewOperation, readWorkloadStatistics, recommendFromPlan, resolveStatementDiagnostics, summarizePlan, } from "./diagnostics/index.ts";
27
31
  export type { DiagnosticFinding, DiagnosticFindingCode, ExplainMode, ExplainSkipReason, ObservedStatement, ResolvedStatementDiagnostics, StatementDiagnostic, StatementDiagnosticPlan, StatementDiagnosticsHook, StatementDiagnosticsOptions, StatementExplainMode, IndexCandidate, IndexFacts, OperationPreview, ParsedPlan, PlanContext, PlanNode, PreviewLimitation, PreviewLimitationCode, PreviewStatement, QueryPlanReport, SlowOperation, SuspectedPattern, TableFacts, TelemetryDiagnosticReport, WorkloadAvailability, WorkloadReport, WorkloadStatement, } from "./diagnostics/index.ts";
@@ -53,8 +57,8 @@ export type { BatchResult, ClientOptions, ClientRow, DynamicClient, ModelDelegat
53
57
  export { CLIENT_MEMBER_ACCESS, DELEGATE_METHOD_ACCESS, READ_DELEGATE_METHODS, WRITE_DELEGATE_METHODS, attachReadOnly, clientMemberAccess, createDelegateMethodClassifier, delegateMethodAccess, inheritReadOnly, readOnlyRefusal, } from "./read-only.ts";
54
58
  export type { ClientMemberAccess, DelegateMethodAccess, DelegateMethodClassifier, LazyOperationBridge, } from "./read-only.ts";
55
59
  export type { KeysetPage } from "./find-page.ts";
56
- export { KEYSET_MAX_PAGE_SIZE, KEYSET_TOKEN_PREFIX, KEYSET_TOKEN_VERSION, compileKeysetOrderPlan, decodeKeysetToken, encodeKeysetToken, keysetRowIsAfter, keysetRowValues, } from "./keyset.ts";
57
- export type { KeysetDirection, KeysetNulls, KeysetOrderInput, KeysetOrderKey, KeysetOrderPlan, KeysetTimestampPrecision, KeysetValueTag, } from "./keyset.ts";
60
+ export { KEYSET_MAX_PAGE_SIZE, KEYSET_TOKEN_PREFIX, KEYSET_TOKEN_VERSION, compileKeysetOrderPlan, decodeKeysetToken, encodeKeysetToken, keysetQueryBinding, keysetRowIsAfter, keysetRowValues, } from "./keyset.ts";
61
+ export type { KeysetDirection, KeysetNulls, KeysetOrderInput, KeysetOrderKey, KeysetOrderPlan, KeysetQueryBinding, KeysetTimestampPrecision, KeysetValueTag, } from "./keyset.ts";
58
62
  export { iterateKeyset } from "./keyset-iterator.ts";
59
63
  export type { KeysetIterateOptions, KeysetIterator, KeysetPageSource } from "./keyset-iterator.ts";
60
64
  export { compileKeysetOrderInputs } from "./query-builder.ts";