@vibeorm/runtime 2.2.0 → 2.3.1

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 (43) hide show
  1. package/dist/adapter-kit/index.d.ts +6 -3
  2. package/dist/adapter-kit/index.d.ts.map +1 -1
  3. package/dist/adapter-kit/index.js +191 -32
  4. package/dist/adapter-kit/index.js.map +8 -5
  5. package/dist/adapter-kit/nested-options.d.ts +22 -0
  6. package/dist/adapter-kit/nested-options.d.ts.map +1 -0
  7. package/dist/adapter-kit/savepoint-gate.d.ts +31 -0
  8. package/dist/adapter-kit/savepoint-gate.d.ts.map +1 -1
  9. package/dist/adapter-kit/session.d.ts +9 -0
  10. package/dist/adapter-kit/session.d.ts.map +1 -0
  11. package/dist/adapter-kit/sqlite-session.d.ts +8 -0
  12. package/dist/adapter-kit/sqlite-session.d.ts.map +1 -0
  13. package/dist/adapter.d.ts +34 -27
  14. package/dist/adapter.d.ts.map +1 -1
  15. package/dist/bulk-upsert.d.ts +5 -3
  16. package/dist/bulk-upsert.d.ts.map +1 -1
  17. package/dist/client-types.d.ts +14 -0
  18. package/dist/client-types.d.ts.map +1 -0
  19. package/dist/client.d.ts.map +1 -1
  20. package/dist/codecs.d.ts +5 -0
  21. package/dist/codecs.d.ts.map +1 -1
  22. package/dist/database-module.d.ts +27 -0
  23. package/dist/database-module.d.ts.map +1 -0
  24. package/dist/diagnostics/plan.d.ts +3 -1
  25. package/dist/diagnostics/plan.d.ts.map +1 -1
  26. package/dist/diagnostics/preview.d.ts +3 -1
  27. package/dist/diagnostics/preview.d.ts.map +1 -1
  28. package/dist/diagnostics/statement-diagnostics.d.ts +10 -6
  29. package/dist/diagnostics/statement-diagnostics.d.ts.map +1 -1
  30. package/dist/index.d.ts +4 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +992 -759
  33. package/dist/index.js.map +20 -18
  34. package/dist/module-context.d.ts +20 -0
  35. package/dist/module-context.d.ts.map +1 -0
  36. package/dist/nested-writes.d.ts.map +1 -1
  37. package/dist/policy.d.ts.map +1 -1
  38. package/dist/query-builder.d.ts.map +1 -1
  39. package/dist/read-only.d.ts.map +1 -1
  40. package/dist/scoped.d.ts.map +1 -1
  41. package/dist/sql-access.d.ts +18 -2
  42. package/dist/sql-access.d.ts.map +1 -1
  43. package/package.json +3 -3
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @vibeorm/runtime/adapter-kit — the transaction-safety helpers every driver
3
- * adapter shares: savepoint naming, the savepoint lifetime gate (F14) and the
4
- * transaction budget (EPIC 6).
3
+ * adapter shares: savepoint naming, the savepoint lifetime gate (F14), the
4
+ * transaction budget (EPIC 6) and the nested-option refusal.
5
5
  *
6
6
  * ONE copy. Each adapter imports from this subpath and re-exports the helpers
7
7
  * it always offered, so a fix to the gate or the budget reaches every engine
@@ -13,8 +13,11 @@
13
13
  */
14
14
  export { createSavepointCounter, nextSavepointName } from "./savepoints.ts";
15
15
  export type { SavepointCounter } from "./savepoints.ts";
16
- export { createSavepointScope, runNestedSavepoint, runRootScope, scopeTurn } from "./savepoint-gate.ts";
16
+ export { createSavepointScope, isSavepointRollbackFailedError, runNestedSavepoint, runRootScope, savepointRollbackFailedError, scopeTurn, } from "./savepoint-gate.ts";
17
17
  export type { SavepointScope, SavepointState } from "./savepoint-gate.ts";
18
+ export { refuseNestedTransactionOptions } from "./nested-options.ts";
18
19
  export { DEFAULT_DEADLINE_CLOCK, engineStatementBudgetMs, isTransactionDeadlineError, startTransactionBudget, transactionClosedError, transactionDeadlineError, transactionOutcomeUnknownError, validateTransactionDeadline, } from "./transaction-budget.ts";
19
20
  export type { BudgetStage, DeadlineClock, TransactionBudget, TransactionOutcome } from "./transaction-budget.ts";
21
+ export { runPinnedSession } from "./session.ts";
22
+ export { runSqliteSession } from "./sqlite-session.ts";
20
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter-kit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACxG,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1E,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,8BAA8B,EAC9B,2BAA2B,GAC5B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter-kit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,EACL,oBAAoB,EACpB,8BAA8B,EAC9B,kBAAkB,EAClB,YAAY,EACZ,4BAA4B,EAC5B,SAAS,GACV,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1E,OAAO,EAAE,8BAA8B,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,8BAA8B,EAC9B,2BAA2B,GAC5B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAEjH,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -8,14 +8,21 @@ function nextSavepointName(params) {
8
8
  }
9
9
  // packages/runtime/src/adapter-kit/savepoint-gate.ts
10
10
  import { AsyncLocalStorage } from "async_hooks";
11
+ import { VibeError } from "@vibeorm/schema";
11
12
  var CURRENT = new AsyncLocalStorage;
12
13
  function createSavepointScope() {
13
- return { depth: 0, state: { counter: createSavepointCounter(), open: null } };
14
+ return { depth: 0, state: { counter: createSavepointCounter(), open: null, poisoned: null } };
14
15
  }
15
16
  function runRootScope(params) {
16
- return CURRENT.run(params.scope, params.body);
17
+ return CURRENT.run(params.scope, async () => {
18
+ assertNotPoisoned({ state: params.scope.state });
19
+ const result = await params.body();
20
+ assertNotPoisoned({ state: params.scope.state });
21
+ return result;
22
+ });
17
23
  }
18
24
  function scopeTurn(params) {
25
+ assertNotPoisoned({ state: params.scope.state });
19
26
  const open = params.scope.state.open;
20
27
  if (mayProceed({ scope: params.scope, open }))
21
28
  return;
@@ -25,28 +32,56 @@ async function runNestedSavepoint(params) {
25
32
  const { scope, execute, body } = params;
26
33
  const node = await acquire({ scope });
27
34
  try {
28
- if (execute !== undefined)
29
- await execute(`SAVEPOINT ${node.name}`);
30
- let result;
31
35
  try {
32
- result = await CURRENT.run(node.scope, () => body(node.scope));
36
+ if (execute !== undefined)
37
+ await execute(`SAVEPOINT ${node.name}`);
38
+ const result = await CURRENT.run(node.scope, () => body(node.scope));
39
+ await drainDescendants({ node });
40
+ assertNotPoisoned({ state: scope.state });
41
+ if (execute !== undefined)
42
+ await execute(`RELEASE SAVEPOINT ${node.name}`);
43
+ return result;
33
44
  } catch (error) {
34
45
  await drainDescendants({ node });
46
+ assertNotPoisoned({ state: scope.state });
35
47
  if (execute !== undefined) {
36
48
  try {
37
49
  await execute(`ROLLBACK TO SAVEPOINT ${node.name}`);
38
- } catch {}
50
+ } catch (rollbackFailure) {
51
+ const poisoned = savepointRollbackFailedError({ cause: error, rollbackFailure });
52
+ scope.state.poisoned = poisoned;
53
+ throw poisoned;
54
+ }
39
55
  }
40
56
  throw error;
41
57
  }
42
- await drainDescendants({ node });
43
- if (execute !== undefined)
44
- await execute(`RELEASE SAVEPOINT ${node.name}`);
45
- return result;
46
58
  } finally {
47
59
  closeNode({ node });
48
60
  }
49
61
  }
62
+ function savepointRollbackFailedError(params) {
63
+ const { cause, rollbackFailure } = params;
64
+ const rollbackErrorCode = rollbackFailure instanceof VibeError ? rollbackFailure.code : undefined;
65
+ return new VibeError({
66
+ code: "VIBE_TRANSACTION",
67
+ message: "a nested transaction failed and the ROLLBACK TO SAVEPOINT that should have undone it failed too \u2014 " + "the savepoint stack no longer describes this connection, so the commit state of the whole transaction " + "is UNKNOWN and no further statement is accepted on any of its handles. The top-level transaction is " + "being rolled back; nothing is retried automatically.",
68
+ meta: {
69
+ reason: "savepoint-rollback-failed",
70
+ outcome: "unknown",
71
+ rollbackFailed: true,
72
+ ...rollbackErrorCode === undefined ? {} : { rollbackErrorCode }
73
+ },
74
+ cause
75
+ });
76
+ }
77
+ function isSavepointRollbackFailedError(error) {
78
+ const reason = error?.meta?.reason;
79
+ return reason === "savepoint-rollback-failed";
80
+ }
81
+ function assertNotPoisoned(params) {
82
+ if (params.state.poisoned !== null)
83
+ throw params.state.poisoned;
84
+ }
50
85
  function mayProceed(params) {
51
86
  const { scope, open } = params;
52
87
  if (open === null)
@@ -59,6 +94,7 @@ function mayProceed(params) {
59
94
  }
60
95
  async function waitForTurn(params) {
61
96
  for (;; ) {
97
+ assertNotPoisoned({ state: params.scope.state });
62
98
  const open = params.scope.state.open;
63
99
  if (open === null || mayProceed({ scope: params.scope, open }))
64
100
  return;
@@ -68,6 +104,7 @@ async function waitForTurn(params) {
68
104
  async function acquire(params) {
69
105
  const { scope } = params;
70
106
  for (;; ) {
107
+ assertNotPoisoned({ state: scope.state });
71
108
  const open = scope.state.open;
72
109
  if (mayProceed({ scope, open }))
73
110
  return pushNode({ scope, parent: open });
@@ -109,8 +146,36 @@ async function drainDescendants(params) {
109
146
  await open.settled;
110
147
  }
111
148
  }
149
+ // packages/runtime/src/adapter-kit/nested-options.ts
150
+ import { VibeError as VibeError2 } from "@vibeorm/schema";
151
+ function refuseNestedTransactionOptions(params) {
152
+ const { options, provider } = params;
153
+ if (options === undefined)
154
+ return;
155
+ const passed = [];
156
+ if (options.isolationLevel !== undefined)
157
+ passed.push("isolationLevel");
158
+ if (options.timeout !== undefined)
159
+ passed.push("timeout");
160
+ if (options.deadline !== undefined)
161
+ passed.push("deadline");
162
+ if (passed.length === 0)
163
+ return;
164
+ const meta = { provider, nested: true };
165
+ if (options.isolationLevel !== undefined)
166
+ meta.isolationLevel = options.isolationLevel;
167
+ if (options.timeout !== undefined)
168
+ meta.timeout = options.timeout;
169
+ if (options.deadline !== undefined)
170
+ meta.deadline = options.deadline;
171
+ throw new VibeError2({
172
+ code: "VIBE_VALIDATION",
173
+ message: `nested transactions run as savepoints and cannot honor ${passed.join(" or ")} \u2014 a savepoint cannot change the isolation level of the transaction it joins, a nested timeout is not enforceable, and a nested deadline would need its own session setting on a connection it does not own (it inherits the top-level one instead); pass options on the top-level $transaction`,
174
+ meta
175
+ });
176
+ }
112
177
  // packages/runtime/src/adapter-kit/transaction-budget.ts
113
- import { VibeError } from "@vibeorm/schema";
178
+ import { VibeError as VibeError3 } from "@vibeorm/schema";
114
179
  var DEFAULT_DEADLINE_CLOCK = () => Date.now();
115
180
  function validateTransactionDeadline(params) {
116
181
  const { options, support, provider } = params;
@@ -118,14 +183,14 @@ function validateTransactionDeadline(params) {
118
183
  if (deadline === undefined)
119
184
  return;
120
185
  if (support === "unsupported") {
121
- throw new VibeError({
186
+ throw new VibeError3({
122
187
  code: "VIBE_UNSUPPORTED_CAPABILITY",
123
188
  message: `${provider} cannot enforce a transaction deadline \u2014 remove the \`deadline\` option`,
124
189
  meta: { provider, feature: "transactionDeadline", supported: support }
125
190
  });
126
191
  }
127
192
  if (!Number.isInteger(deadline.totalMs) || deadline.totalMs <= 0) {
128
- throw new VibeError({
193
+ throw new VibeError3({
129
194
  code: "VIBE_VALIDATION",
130
195
  message: `transaction deadline \`totalMs\` must be a positive integer of milliseconds, received ${String(deadline.totalMs)}`,
131
196
  meta: { provider, feature: "transactionDeadline", totalMs: deadline.totalMs }
@@ -133,7 +198,7 @@ function validateTransactionDeadline(params) {
133
198
  }
134
199
  const requested = deadline.enforcement ?? "between-statements";
135
200
  if (requested === "cancel-running-statements" && support !== "cancel-running-statements") {
136
- throw new VibeError({
201
+ throw new VibeError3({
137
202
  code: "VIBE_UNSUPPORTED_CAPABILITY",
138
203
  message: `${provider} cannot cancel a statement that is already running, so the requested ` + "`cancel-running-statements` deadline guarantee is refused rather than silently downgraded \u2014 " + 'ask for "between-statements" if a budget checked between statements is enough',
139
204
  meta: { provider, feature: "transactionDeadline", requested, supported: support }
@@ -194,7 +259,7 @@ function engineStatementBudgetMs(params) {
194
259
  function transactionDeadlineError(params) {
195
260
  const { provider, stage, totalMs, overdueMs } = params;
196
261
  const what = stage === "commit" ? "the transaction was rolled back instead of committed" : "the statement was never sent and the transaction is being rolled back";
197
- return new VibeError({
262
+ return new VibeError3({
198
263
  code: "VIBE_TRANSACTION",
199
264
  message: `transaction deadline of ${totalMs} ms expired ${Math.max(0, Math.round(overdueMs))} ms ago \u2014 ${what}. ` + "Nothing is retried automatically: work the callback did outside the database may already have happened.",
200
265
  meta: { provider, reason: "transaction-deadline", stage, totalMs, overdueMs: Math.max(0, Math.round(overdueMs)) }
@@ -202,7 +267,7 @@ function transactionDeadlineError(params) {
202
267
  }
203
268
  function transactionClosedError(params) {
204
269
  const { provider, outcome, stage } = params;
205
- return new VibeError({
270
+ return new VibeError3({
206
271
  code: "VIBE_TRANSACTION",
207
272
  message: `this transaction has already finished (${outcome}), so its client can no longer be used \u2014 ` + "a handle kept past the end of `$transaction` would run outside the transaction, on a connection " + "that now belongs to someone else",
208
273
  meta: { provider, reason: "transaction-closed", outcome, stage }
@@ -210,7 +275,7 @@ function transactionClosedError(params) {
210
275
  }
211
276
  function transactionOutcomeUnknownError(params) {
212
277
  const { provider, totalMs, cause } = params;
213
- return new VibeError({
278
+ return new VibeError3({
214
279
  code: "VIBE_TRANSACTION",
215
280
  message: `transaction deadline of ${totalMs} ms expired and the rollback that should have cleaned up failed \u2014 ` + "the commit state of this transaction is UNKNOWN. It is not retried automatically; inspect the data " + "before deciding.",
216
281
  meta: {
@@ -227,21 +292,115 @@ function isTransactionDeadlineError(error) {
227
292
  const reason = error?.meta?.reason;
228
293
  return reason === "transaction-deadline";
229
294
  }
295
+ // packages/runtime/src/adapter-kit/session.ts
296
+ import { VibeError as VibeError4 } from "@vibeorm/schema";
297
+ function runPinnedSession(params) {
298
+ let active = true;
299
+ let lost;
300
+ let tail = Promise.resolve();
301
+ const executor = (query) => {
302
+ const result = tail.then(async () => {
303
+ if (lost !== undefined)
304
+ throw lost;
305
+ if (!active)
306
+ throw new VibeError4({
307
+ code: "VIBE_ADAPTER",
308
+ message: "The reserved database session has finished; acquire a new session before executing SQL.",
309
+ meta: { reason: "session-closed" }
310
+ });
311
+ return params.execute(query).catch((cause) => {
312
+ if (params.isLost(cause)) {
313
+ lost = new VibeError4({
314
+ code: "VIBE_ADAPTER",
315
+ message: "The reserved database session was lost. No further SQL will be sent; inspect migration progress before retrying.",
316
+ meta: { reason: "session-lost", outcome: "unknown" },
317
+ cause
318
+ });
319
+ throw lost;
320
+ }
321
+ throw cause;
322
+ });
323
+ });
324
+ tail = result.then(() => {
325
+ return;
326
+ }, () => {
327
+ return;
328
+ });
329
+ return result;
330
+ };
331
+ return Promise.resolve().then(() => params.run(executor)).then(async (result) => {
332
+ active = false;
333
+ await tail;
334
+ if (lost !== undefined)
335
+ throw lost;
336
+ return result;
337
+ }).finally(async () => {
338
+ active = false;
339
+ await tail;
340
+ await params.release();
341
+ });
342
+ }
343
+ // packages/runtime/src/adapter-kit/sqlite-session.ts
344
+ import { VibeError as VibeError5 } from "@vibeorm/schema";
345
+ import { SQLITE_SESSION_SQL } from "@vibeorm/sql";
346
+ async function runSqliteSession(params) {
347
+ if (params.inTransaction())
348
+ throw new VibeError5({
349
+ code: "VIBE_TRANSACTION",
350
+ message: "A migration session cannot borrow a SQLite connection with an open transaction.",
351
+ meta: { reason: "session-in-transaction" }
352
+ });
353
+ const rows = await params.execute({ text: SQLITE_SESSION_SQL.lockingMode, values: [] });
354
+ const mode = rows[0]?.locking_mode;
355
+ if (mode !== "normal" && mode !== "exclusive")
356
+ throw new VibeError5({
357
+ code: "VIBE_ADAPTER",
358
+ message: "SQLite did not report its locking mode; no migration was started.",
359
+ meta: { reason: "session-lock-mode" }
360
+ });
361
+ await params.execute({ text: SQLITE_SESSION_SQL.exclusive });
362
+ return Promise.resolve().then(async () => {
363
+ await params.execute({ text: SQLITE_SESSION_SQL.acquire });
364
+ await params.execute({ text: SQLITE_SESSION_SQL.commit });
365
+ return runPinnedSession({
366
+ execute: params.execute,
367
+ run: params.run,
368
+ isLost: () => false,
369
+ release: async () => {
370
+ if (params.inTransaction())
371
+ await params.execute({ text: SQLITE_SESSION_SQL.rollback });
372
+ }
373
+ });
374
+ }).finally(async () => {
375
+ if (params.inTransaction())
376
+ await params.execute({ text: SQLITE_SESSION_SQL.rollback });
377
+ await params.execute({ text: SQLITE_SESSION_SQL.foreignKeysOn });
378
+ if (mode === "normal") {
379
+ await params.execute({ text: SQLITE_SESSION_SQL.normal });
380
+ await params.execute({ text: SQLITE_SESSION_SQL.touch, values: [] });
381
+ }
382
+ });
383
+ }
230
384
  export {
231
- validateTransactionDeadline,
232
- transactionOutcomeUnknownError,
233
- transactionDeadlineError,
234
- transactionClosedError,
235
- startTransactionBudget,
236
- scopeTurn,
237
- runRootScope,
238
- runNestedSavepoint,
239
- nextSavepointName,
240
- isTransactionDeadlineError,
241
- engineStatementBudgetMs,
242
- createSavepointScope,
385
+ DEFAULT_DEADLINE_CLOCK,
243
386
  createSavepointCounter,
244
- DEFAULT_DEADLINE_CLOCK
387
+ createSavepointScope,
388
+ engineStatementBudgetMs,
389
+ isSavepointRollbackFailedError,
390
+ isTransactionDeadlineError,
391
+ nextSavepointName,
392
+ refuseNestedTransactionOptions,
393
+ runNestedSavepoint,
394
+ runPinnedSession,
395
+ runRootScope,
396
+ runSqliteSession,
397
+ savepointRollbackFailedError,
398
+ scopeTurn,
399
+ startTransactionBudget,
400
+ transactionClosedError,
401
+ transactionDeadlineError,
402
+ transactionOutcomeUnknownError,
403
+ validateTransactionDeadline
245
404
  };
246
405
 
247
- //# debugId=90A5C246EB2BA1E264756E2164756E21
406
+ //# debugId=F41DD3D472C2858864756E2164756E21
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/adapter-kit/savepoints.ts", "../src/adapter-kit/savepoint-gate.ts", "../src/adapter-kit/transaction-budget.ts"],
3
+ "sources": ["../src/adapter-kit/savepoints.ts", "../src/adapter-kit/savepoint-gate.ts", "../src/adapter-kit/nested-options.ts", "../src/adapter-kit/transaction-budget.ts", "../src/adapter-kit/session.ts", "../src/adapter-kit/sqlite-session.ts"],
4
4
  "sourcesContent": [
5
5
  "/**\n * Savepoint naming for nested transactions.\n *\n * v1 lesson (LEARNINGS.md): the counter is shared **by reference** across every\n * adapter created for one top-level transaction, so sibling and deeply nested\n * savepoints can never collide on a name.\n */\n\n/** Mutable counter shared by reference across one top-level transaction. */\nexport type SavepointCounter = { n: number };\n\n/** Fresh counter — one per top-level transaction. */\nexport function createSavepointCounter(): SavepointCounter {\n return { n: 0 };\n}\n\n/**\n * Allocate the next savepoint name (`vibeorm_sp_0`, `vibeorm_sp_1`, …) and\n * advance the shared counter. The name is an identifier by construction, so it\n * is safe to interpolate into `SAVEPOINT` / `RELEASE` / `ROLLBACK TO` SQL.\n */\nexport function nextSavepointName(params: { counter: SavepointCounter }): string {\n return `vibeorm_sp_${params.counter.n++}`;\n}\n",
6
- "/**\n * Savepoint lifetimes inside one top-level transaction (F14).\n *\n * A savepoint stack lives on ONE connection: `ROLLBACK TO SAVEPOINT s` undoes\n * everything done after `s`, including work a LATER savepoint already released.\n * Two `transaction()` callbacks opened from the same handle and overlapping in\n * time therefore share that one stack, and the earlier one's rollback silently\n * erases the later one's already committed work. Unique savepoint names do not\n * help — the names never collided, the lifetimes did.\n *\n * The rule enforced here, on every handle of a transaction:\n *\n * > A handle runs when nothing deeper than itself is open. Otherwise it waits\n * > for the innermost open savepoint to settle — unless the call is being made\n * > from INSIDE that savepoint's own callback, which is genuine nesting and\n * > proceeds immediately.\n *\n * The \"from inside\" test is an {@link AsyncLocalStorage} lookup, so the common\n * nesting shapes never wait on themselves: a child opened from its parent's\n * callback, and the parent handle used from within an open child's callback,\n * both proceed. Only genuinely concurrent siblings serialize.\n *\n * Not covered: a callback that awaits a sibling it did not start. That\n * arrangement asks for two savepoints to be open at once, which is exactly what\n * loses work; it now blocks instead. Deliberate — see the notes for this fix.\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { type SavepointCounter, createSavepointCounter, nextSavepointName } from \"./savepoints.ts\";\n\n// ─── Types ────────────────────────────────────────────────────────\n\n/**\n * One handle's position in the savepoint stack of a top-level transaction.\n * `state` is shared by reference across every handle of that transaction.\n */\nexport type SavepointScope = {\n /** Physical savepoint depth; 0 is the top-level transaction itself. */\n readonly depth: number;\n /** Shared state: name allocation plus the innermost open savepoint. */\n readonly state: SavepointState;\n};\n\n/** Mutable state shared by every scope of one top-level transaction. */\nexport type SavepointState = {\n /** Savepoint name counter (shared, so names never collide). */\n readonly counter: SavepointCounter;\n /** The innermost savepoint currently open, or `null` when none is. */\n open: OpenSavepoint | null;\n};\n\n/** An open savepoint: its handle, its name, and when it finished. */\ntype OpenSavepoint = {\n readonly scope: SavepointScope;\n readonly name: string;\n readonly parent: OpenSavepoint | null;\n readonly settled: Promise<void>;\n readonly settle: () => void;\n};\n\n/**\n * The savepoint whose callback the current async context is running inside.\n * This is the discriminator between genuine nesting (proceed) and an\n * overlapping sibling (wait).\n */\nconst CURRENT = new AsyncLocalStorage<SavepointScope>();\n\n// ─── Public API ───────────────────────────────────────────────────\n\n/** Fresh scope for one top-level transaction: depth 0, nothing open. */\nexport function createSavepointScope(): SavepointScope {\n return { depth: 0, state: { counter: createSavepointCounter(), open: null } };\n}\n\n/**\n * Run a top-level transaction callback inside its scope's async context, so\n * nested calls made from it can be told apart from calls made inside an open\n * child.\n */\nexport function runRootScope<T>(params: { scope: SavepointScope; body: () => Promise<T> }): Promise<T> {\n return CURRENT.run(params.scope, params.body);\n}\n\n/**\n * The wait a statement on `scope` owes before it may run, or `undefined` when\n * it may run now. Returning `undefined` keeps the uncontended path — nothing\n * deeper open — free of an extra promise and microtask.\n */\nexport function scopeTurn(params: { scope: SavepointScope }): Promise<void> | undefined {\n const open = params.scope.state.open;\n if (mayProceed({ scope: params.scope, open })) return undefined;\n return waitForTurn({ scope: params.scope });\n}\n\n/**\n * Open a nested savepoint under `scope`, run `body` inside it and release it —\n * rolling back to it if `body` throws, exactly as before this gate existed.\n *\n * `execute` runs the savepoint control SQL (already wrapped in the adapter's\n * own driver-error mapping). Omit it when the driver manages the savepoint\n * itself (bun:sql's `savepoint()`), in which case only the lifetime is gated.\n */\nexport async function runNestedSavepoint<T>(params: {\n readonly scope: SavepointScope;\n readonly execute?: (statement: string) => Promise<unknown> | unknown;\n readonly body: (scope: SavepointScope) => Promise<T>;\n}): Promise<T> {\n const { scope, execute, body } = params;\n const node = await acquire({ scope });\n try {\n if (execute !== undefined) await execute(`SAVEPOINT ${node.name}`);\n let result: T;\n try {\n result = await CURRENT.run(node.scope, () => body(node.scope));\n } catch (error) {\n // A descendant the callback started but never awaited must finish before\n // this savepoint may be rolled back — releasing out of order corrupts\n // the stack.\n await drainDescendants({ node });\n if (execute !== undefined) {\n // Best effort: never mask the original failure with a rollback failure.\n try {\n await execute(`ROLLBACK TO SAVEPOINT ${node.name}`);\n } catch {\n /* rollback is best-effort */\n }\n }\n throw error;\n }\n await drainDescendants({ node });\n if (execute !== undefined) await execute(`RELEASE SAVEPOINT ${node.name}`);\n return result;\n } finally {\n closeNode({ node });\n }\n}\n\n// ─── Internals ────────────────────────────────────────────────────\n\n/** Whether `scope` may act while `open` is the innermost open savepoint. */\nfunction mayProceed(params: { scope: SavepointScope; open: OpenSavepoint | null }): boolean {\n const { scope, open } = params;\n if (open === null) return true;\n // This handle IS the innermost open savepoint.\n if (open.scope === scope) return true;\n // This handle's own savepoint has already closed (a retained child handle):\n // it can only act at the connection's current depth, and waiting for a\n // shallower savepoint it does not own would never resolve.\n if (open.scope.depth < scope.depth) return true;\n // Genuine nesting: the call is being made from inside the open callback.\n return CURRENT.getStore() === open.scope;\n}\n\nasync function waitForTurn(params: { scope: SavepointScope }): Promise<void> {\n for (;;) {\n const open = params.scope.state.open;\n if (open === null || mayProceed({ scope: params.scope, open })) return;\n await open.settled;\n }\n}\n\n/**\n * Wait for this handle's turn and take it in the SAME synchronous step — the\n * check and the push must not be separated by an await, or two waiters woken\n * together would both open a savepoint.\n */\nasync function acquire(params: { scope: SavepointScope }): Promise<OpenSavepoint> {\n const { scope } = params;\n for (;;) {\n const open = scope.state.open;\n if (mayProceed({ scope, open })) return pushNode({ scope, parent: open });\n // `mayProceed` returns true for a null `open`, so this is never null here.\n await (open as OpenSavepoint).settled;\n }\n}\n\nfunction pushNode(params: { scope: SavepointScope; parent: OpenSavepoint | null }): OpenSavepoint {\n const { scope, parent } = params;\n const state = scope.state;\n let settle: () => void = () => undefined;\n const settled = new Promise<void>((resolve) => {\n settle = () => resolve();\n });\n // Physical depth follows the connection's stack, not the handle that opened\n // it: a savepoint opened from an outer handle inside a child's callback still\n // nests inside that child.\n const node: OpenSavepoint = {\n scope: { depth: (parent === null ? 0 : parent.scope.depth) + 1, state },\n name: nextSavepointName({ counter: state.counter }),\n parent,\n settled,\n settle,\n };\n state.open = node;\n return node;\n}\n\nfunction closeNode(params: { node: OpenSavepoint }): void {\n const { node } = params;\n const state = node.scope.state;\n if (state.open === node) state.open = node.parent;\n node.settle();\n}\n\n/** Wait out savepoints a callback opened below this node and never awaited. */\nasync function drainDescendants(params: { node: OpenSavepoint }): Promise<void> {\n const state = params.node.scope.state;\n for (;;) {\n const open = state.open;\n if (open === null || open === params.node || open.scope.depth <= params.node.scope.depth) return;\n await open.settled;\n }\n}\n",
7
- "/**\n * Transaction budgets — the total-deadline clock and the handle-closure gate.\n *\n * ONE copy, shared by every adapter package through the\n * `@vibeorm/runtime/adapter-kit` subpath (like `savepoint-gate.ts`), so a\n * change here reaches all engines at once — a per-adapter copy would drift\n * into a silent per-engine behaviour difference.\n *\n * WHAT A DEADLINE IS, AND IS NOT\n *\n * `TransactionOptions.timeout` is unchanged: a PER-STATEMENT engine-side bound.\n * `TransactionOptions.deadline` is new and different — a TOTAL wall-clock bound\n * on one top-level transaction. Its clock starts immediately before `BEGIN` is\n * sent, so connection acquisition (which has its own budget on the pooled\n * adapters) is deliberately NOT counted.\n *\n * Enforcement is never `Promise.race` over a statement that keeps running:\n *\n * - `\"between-statements\"` (the default, and all six adapters can deliver it):\n * before every statement, every nested `transaction()` and the `COMMIT`, an\n * expired budget refuses. The statement is never sent and the transaction is\n * rolled back. A statement ALREADY IN FLIGHT is not interrupted.\n * - `\"cancel-running-statements\"` (postgres servers only): additionally hands\n * the engine the remaining budget as `statement_timeout`, so the SERVER\n * cancels an over-long statement. An adapter that cannot do this refuses the\n * request outright rather than quietly delivering the weaker level.\n *\n * JavaScript cannot forcibly stop a running callback. A callback that keeps\n * going past the deadline finds its later database calls refused; work it does\n * outside the database (an HTTP call, an SMS) is not stopped and cannot be.\n * There is no automatic retry: a deadline failure is terminal for that\n * transaction, because external side effects may already have happened.\n */\n\nimport { VibeError } from \"@vibeorm/schema\";\nimport type {\n TransactionDeadlineEnforcement,\n TransactionDeadlineSupport,\n TransactionOptions,\n} from \"../adapter.ts\";\n\n// ─── Types ────────────────────────────────────────────────────────\n\n/** Where a budget check happened, reported as `meta.stage`. */\nexport type BudgetStage = \"statement\" | \"nested\" | \"commit\";\n\n/**\n * What is known about a finished transaction. `\"unknown\"` is a first-class\n * outcome, not a failure to decide: when a rollback itself fails the commit\n * state genuinely cannot be asserted, and claiming \"rolled back\" would be a lie.\n */\nexport type TransactionOutcome = \"committed\" | \"rolled-back\" | \"unknown\";\n\n/** Wall clock, injectable so tests are deterministic instead of sleep-timed. */\nexport type DeadlineClock = () => number;\n\n/** The ambient clock, used whenever no seam is injected. */\nexport const DEFAULT_DEADLINE_CLOCK: DeadlineClock = (): number => Date.now();\n\n/**\n * One top-level transaction's budget. Nested savepoint handles share this\n * object BY REFERENCE — they never get an independent clock, connection or\n * session setting.\n */\nexport type TransactionBudget = {\n /** The enforcement level in force, or `null` when no deadline was requested. */\n readonly enforcement: TransactionDeadlineEnforcement | null;\n /** The requested total budget in milliseconds, or `null` when none was. */\n readonly totalMs: number | null;\n /** Existing per-statement limit, independent of the total deadline. Zero disables it. */\n readonly statementTimeoutMs: number | null;\n /** Milliseconds left (never negative), or `null` when no deadline is set. */\n remainingMs(): number | null;\n /** True only when a deadline is set and has passed. */\n expired(): boolean;\n /** Refuse a closed handle or an expired budget. Called BEFORE anything is sent. */\n assertUsable(params: { stage: BudgetStage }): void;\n /** Record the terminal outcome; the first call wins and later ones are ignored. */\n close(params: { outcome: TransactionOutcome }): void;\n /** The recorded outcome, or `null` while the transaction is still open. */\n readonly outcome: TransactionOutcome | null;\n};\n\n// ─── Validation (before BEGIN, before any write) ──────────────────\n\n/**\n * Check `options.deadline` against what this adapter can honestly deliver.\n * Called BEFORE `BEGIN` — a budget this engine cannot honour must never leave\n * a transaction open behind it.\n *\n * @throws VibeError `VIBE_VALIDATION` when `totalMs` is not a positive integer.\n * @throws VibeError `VIBE_UNSUPPORTED_CAPABILITY` when the requested\n * `enforcement` is stronger than `support` — refused, never silently degraded.\n */\nexport function validateTransactionDeadline(params: {\n options?: TransactionOptions;\n support: TransactionDeadlineSupport;\n provider: string;\n}): void {\n const { options, support, provider } = params;\n const deadline = options?.deadline;\n if (deadline === undefined) return;\n\n if (support === \"unsupported\") {\n throw new VibeError({\n code: \"VIBE_UNSUPPORTED_CAPABILITY\",\n message: `${provider} cannot enforce a transaction deadline — remove the \\`deadline\\` option`,\n meta: { provider, feature: \"transactionDeadline\", supported: support },\n });\n }\n\n if (!Number.isInteger(deadline.totalMs) || deadline.totalMs <= 0) {\n throw new VibeError({\n code: \"VIBE_VALIDATION\",\n message: `transaction deadline \\`totalMs\\` must be a positive integer of milliseconds, received ${String(deadline.totalMs)}`,\n meta: { provider, feature: \"transactionDeadline\", totalMs: deadline.totalMs },\n });\n }\n\n const requested: TransactionDeadlineEnforcement = deadline.enforcement ?? \"between-statements\";\n if (requested === \"cancel-running-statements\" && support !== \"cancel-running-statements\") {\n throw new VibeError({\n code: \"VIBE_UNSUPPORTED_CAPABILITY\",\n message:\n `${provider} cannot cancel a statement that is already running, so the requested ` +\n \"`cancel-running-statements` deadline guarantee is refused rather than silently downgraded — \" +\n 'ask for \"between-statements\" if a budget checked between statements is enough',\n meta: { provider, feature: \"transactionDeadline\", requested, supported: support },\n });\n }\n}\n\n// ─── The budget ───────────────────────────────────────────────────\n\n/**\n * Start the clock for one top-level transaction. Call it immediately before\n * `BEGIN`; {@link validateTransactionDeadline} must already have run.\n */\nexport function startTransactionBudget(params: {\n options?: TransactionOptions;\n provider: string;\n clock?: DeadlineClock;\n}): TransactionBudget {\n const { options, provider } = params;\n const clock = params.clock ?? DEFAULT_DEADLINE_CLOCK;\n const deadline = options?.deadline;\n const totalMs = deadline === undefined ? null : deadline.totalMs;\n const enforcement: TransactionDeadlineEnforcement | null =\n deadline === undefined ? null : (deadline.enforcement ?? \"between-statements\");\n const expiresAt = totalMs === null ? null : clock() + totalMs;\n let outcome: TransactionOutcome | null = null;\n\n const budget: TransactionBudget = {\n enforcement,\n totalMs,\n statementTimeoutMs: options?.timeout ?? null,\n remainingMs(): number | null {\n return expiresAt === null ? null : Math.max(0, expiresAt - clock());\n },\n expired(): boolean {\n return expiresAt !== null && clock() >= expiresAt;\n },\n assertUsable(assertParams: { stage: BudgetStage }): void {\n if (outcome !== null) {\n throw transactionClosedError({ provider, outcome, stage: assertParams.stage });\n }\n if (expiresAt !== null && clock() >= expiresAt) {\n throw transactionDeadlineError({\n provider,\n stage: assertParams.stage,\n totalMs: totalMs as number,\n overdueMs: clock() - expiresAt,\n });\n }\n },\n close(closeParams: { outcome: TransactionOutcome }): void {\n if (outcome === null) outcome = closeParams.outcome;\n },\n get outcome(): TransactionOutcome | null {\n return outcome;\n },\n };\n return budget;\n}\n\n/**\n * The engine-side bound for the NEXT statement, or `null` when the caller did\n * not buy `\"cancel-running-statements\"`. Floored at 1 ms: on postgres `0` means\n * \"no limit\", so a spent budget must never be handed over as a zero.\n */\nexport function engineStatementBudgetMs(params: { budget: TransactionBudget }): number | null {\n const { budget } = params;\n if (budget.enforcement !== \"cancel-running-statements\") return null;\n const remaining = budget.remainingMs();\n if (remaining === null) return null;\n const totalBound = Math.max(1, Math.ceil(remaining));\n return budget.statementTimeoutMs !== null && budget.statementTimeoutMs > 0\n ? Math.min(totalBound, budget.statementTimeoutMs) : totalBound;\n}\n\n// ─── Errors ───────────────────────────────────────────────────────\n\n/**\n * The refusal an expired budget raises. `VIBE_TRANSACTION` with a stable\n * `meta.reason` — no SQL text, no parameter values, no credentials.\n */\nexport function transactionDeadlineError(params: {\n provider: string;\n stage: BudgetStage;\n totalMs: number;\n overdueMs: number;\n}): VibeError {\n const { provider, stage, totalMs, overdueMs } = params;\n const what =\n stage === \"commit\"\n ? \"the transaction was rolled back instead of committed\"\n : \"the statement was never sent and the transaction is being rolled back\";\n return new VibeError({\n code: \"VIBE_TRANSACTION\",\n message:\n `transaction deadline of ${totalMs} ms expired ${Math.max(0, Math.round(overdueMs))} ms ago — ${what}. ` +\n \"Nothing is retried automatically: work the callback did outside the database may already have happened.\",\n meta: { provider, reason: \"transaction-deadline\", stage, totalMs, overdueMs: Math.max(0, Math.round(overdueMs)) },\n });\n}\n\n/**\n * The refusal an ESCAPED transaction handle raises — a transactional adapter\n * kept past the end of its transaction. Without this it would run on a\n * connection that is back in the pool, outside any transaction.\n */\nexport function transactionClosedError(params: {\n provider: string;\n outcome: TransactionOutcome;\n stage: BudgetStage;\n}): VibeError {\n const { provider, outcome, stage } = params;\n return new VibeError({\n code: \"VIBE_TRANSACTION\",\n message:\n `this transaction has already finished (${outcome}), so its client can no longer be used — ` +\n \"a handle kept past the end of `$transaction` would run outside the transaction, on a connection \" +\n \"that now belongs to someone else\",\n meta: { provider, reason: \"transaction-closed\", outcome, stage },\n });\n}\n\n/**\n * The stable typed outcome for \"the deadline expired and the rollback that was\n * supposed to clean up failed too\". Promising a rollback here would be false;\n * promising a retry would be worse.\n *\n * `cause` is the CAUSAL error (the deadline refusal), so the reason the\n * transaction was being abandoned survives. The rollback failure itself is\n * reported only as `meta.rollbackFailed`: a raw driver failure can carry\n * statement text, and this error is meant to be logged.\n */\nexport function transactionOutcomeUnknownError(params: {\n provider: string;\n totalMs: number;\n cause: unknown;\n}): VibeError {\n const { provider, totalMs, cause } = params;\n return new VibeError({\n code: \"VIBE_TRANSACTION\",\n message:\n `transaction deadline of ${totalMs} ms expired and the rollback that should have cleaned up failed — ` +\n \"the commit state of this transaction is UNKNOWN. It is not retried automatically; inspect the data \" +\n \"before deciding.\",\n meta: {\n provider,\n reason: \"transaction-outcome-unknown\",\n outcome: \"unknown\",\n totalMs,\n rollbackFailed: true,\n },\n cause,\n });\n}\n\n/** Whether `error` is this module's deadline refusal (used to pick the cleanup path). */\nexport function isTransactionDeadlineError(error: unknown): boolean {\n const reason = (error as { meta?: { reason?: unknown } } | null)?.meta?.reason;\n return reason === \"transaction-deadline\";\n}\n"
6
+ "/**\n * Savepoint lifetimes inside one top-level transaction (F14).\n *\n * A savepoint stack lives on ONE connection: `ROLLBACK TO SAVEPOINT s` undoes\n * everything done after `s`, including work a LATER savepoint already released.\n * Two `transaction()` callbacks opened from the same handle and overlapping in\n * time therefore share that one stack, and the earlier one's rollback silently\n * erases the later one's already committed work. Unique savepoint names do not\n * help — the names never collided, the lifetimes did.\n *\n * The rule enforced here, on every handle of a transaction:\n *\n * > A handle runs when nothing deeper than itself is open. Otherwise it waits\n * > for the innermost open savepoint to settle — unless the call is being made\n * > from INSIDE that savepoint's own callback, which is genuine nesting and\n * > proceeds immediately.\n *\n * The \"from inside\" test is an {@link AsyncLocalStorage} lookup, so the common\n * nesting shapes never wait on themselves: a child opened from its parent's\n * callback, and the parent handle used from within an open child's callback,\n * both proceed. Only genuinely concurrent siblings serialize.\n *\n * Not covered: a callback that awaits a sibling it did not start. That\n * arrangement asks for two savepoints to be open at once, which is exactly what\n * loses work; it now blocks instead. Deliberate — see the notes for this fix.\n *\n * A FAILED `ROLLBACK TO SAVEPOINT` poisons the whole transaction. When the\n * engine cannot undo a savepoint — InnoDB has already rolled the entire\n * transaction back after a deadlock, an implicit-commit DDL cleared every\n * savepoint, the connection dropped — the transaction's outcome is unknown and\n * no handle of it may send another statement: a parent callback that caught\n * the nested error and \"continued\" would otherwise run in autocommit and the\n * final COMMIT would succeed vacuously. Every later turn refuses with the same\n * typed error.\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { VibeError } from \"@vibeorm/schema\";\nimport { type SavepointCounter, createSavepointCounter, nextSavepointName } from \"./savepoints.ts\";\n\n// ─── Types ────────────────────────────────────────────────────────\n\n/**\n * One handle's position in the savepoint stack of a top-level transaction.\n * `state` is shared by reference across every handle of that transaction.\n */\nexport type SavepointScope = {\n /** Physical savepoint depth; 0 is the top-level transaction itself. */\n readonly depth: number;\n /** Shared state: name allocation plus the innermost open savepoint. */\n readonly state: SavepointState;\n};\n\n/** Mutable state shared by every scope of one top-level transaction. */\nexport type SavepointState = {\n /** Savepoint name counter (shared, so names never collide). */\n readonly counter: SavepointCounter;\n /** The innermost savepoint currently open, or `null` when none is. */\n open: OpenSavepoint | null;\n /**\n * Set once a `ROLLBACK TO SAVEPOINT` has failed: the savepoint stack no\n * longer describes the connection, so every later statement and nested\n * savepoint on ANY handle of this transaction is refused with this error.\n */\n poisoned: VibeError | null;\n};\n\n/** An open savepoint: its handle, its name, and when it finished. */\ntype OpenSavepoint = {\n readonly scope: SavepointScope;\n readonly name: string;\n readonly parent: OpenSavepoint | null;\n readonly settled: Promise<void>;\n readonly settle: () => void;\n};\n\n/**\n * The savepoint whose callback the current async context is running inside.\n * This is the discriminator between genuine nesting (proceed) and an\n * overlapping sibling (wait).\n */\nconst CURRENT = new AsyncLocalStorage<SavepointScope>();\n\n// ─── Public API ───────────────────────────────────────────────────\n\n/** Fresh scope for one top-level transaction: depth 0, nothing open. */\nexport function createSavepointScope(): SavepointScope {\n return { depth: 0, state: { counter: createSavepointCounter(), open: null, poisoned: null } };\n}\n\n/**\n * Run a top-level transaction callback inside its scope's async context, so\n * nested calls made from it can be told apart from calls made inside an open\n * child.\n */\nexport function runRootScope<T>(params: { scope: SavepointScope; body: () => Promise<T> }): Promise<T> {\n return CURRENT.run(params.scope, async () => {\n assertNotPoisoned({ state: params.scope.state });\n const result = await params.body();\n // Adapters commit after this resolves. Catching a nested failure must not\n // allow a poisoned transaction to report successful completion.\n assertNotPoisoned({ state: params.scope.state });\n return result;\n });\n}\n\n/**\n * The wait a statement on `scope` owes before it may run, or `undefined` when\n * it may run now. Returning `undefined` keeps the uncontended path — nothing\n * deeper open — free of an extra promise and microtask.\n */\nexport function scopeTurn(params: { scope: SavepointScope }): Promise<void> | undefined {\n assertNotPoisoned({ state: params.scope.state });\n const open = params.scope.state.open;\n if (mayProceed({ scope: params.scope, open })) return undefined;\n return waitForTurn({ scope: params.scope });\n}\n\n/**\n * Open a nested savepoint under `scope`, run `body` inside it and release it —\n * rolling back to it if `body` throws, exactly as before this gate existed.\n *\n * `execute` runs the savepoint control SQL (already wrapped in the adapter's\n * own driver-error mapping). Omit it when the driver manages the savepoint\n * itself (bun:sql's `savepoint()`), in which case only the lifetime is gated.\n */\nexport async function runNestedSavepoint<T>(params: {\n readonly scope: SavepointScope;\n readonly execute?: (statement: string) => Promise<unknown> | unknown;\n readonly body: (scope: SavepointScope) => Promise<T>;\n}): Promise<T> {\n const { scope, execute, body } = params;\n const node = await acquire({ scope });\n try {\n try {\n if (execute !== undefined) await execute(`SAVEPOINT ${node.name}`);\n const result = await CURRENT.run(node.scope, () => body(node.scope));\n await drainDescendants({ node });\n assertNotPoisoned({ state: scope.state });\n if (execute !== undefined) await execute(`RELEASE SAVEPOINT ${node.name}`);\n return result;\n } catch (error) {\n // A descendant the callback started but never awaited must finish before\n // this savepoint may be rolled back — releasing out of order corrupts\n // the stack.\n await drainDescendants({ node });\n assertNotPoisoned({ state: scope.state });\n if (execute !== undefined) {\n try {\n await execute(`ROLLBACK TO SAVEPOINT ${node.name}`);\n } catch (rollbackFailure) {\n // The savepoint could not be undone, so the connection's real state is\n // unknown. Poison the transaction (every handle, every later turn) and\n // surface THAT, with the body failure as the cause — rethrowing the\n // body error alone would let the parent callback continue.\n const poisoned = savepointRollbackFailedError({ cause: error, rollbackFailure });\n scope.state.poisoned = poisoned;\n throw poisoned;\n }\n }\n throw error;\n }\n } finally {\n closeNode({ node });\n }\n}\n\n// ─── Errors ───────────────────────────────────────────────────────\n\n/**\n * The refusal raised when `ROLLBACK TO SAVEPOINT` itself fails, and repeated\n * for every later statement on the poisoned transaction. `VIBE_TRANSACTION`\n * with `meta.reason = \"savepoint-rollback-failed\"` and `meta.outcome =\n * \"unknown\"`; `cause` is the body failure that triggered the rollback. The\n * rollback failure's own code (when it is a `VibeError`) rides along as\n * `meta.rollbackErrorCode` — its message is not copied, because a raw driver\n * failure can carry statement text and this error is meant to be logged.\n */\nexport function savepointRollbackFailedError(params: { cause: unknown; rollbackFailure: unknown }): VibeError {\n const { cause, rollbackFailure } = params;\n const rollbackErrorCode =\n rollbackFailure instanceof VibeError ? rollbackFailure.code : undefined;\n return new VibeError({\n code: \"VIBE_TRANSACTION\",\n message:\n \"a nested transaction failed and the ROLLBACK TO SAVEPOINT that should have undone it failed too — \" +\n \"the savepoint stack no longer describes this connection, so the commit state of the whole transaction \" +\n \"is UNKNOWN and no further statement is accepted on any of its handles. The top-level transaction is \" +\n \"being rolled back; nothing is retried automatically.\",\n meta: {\n reason: \"savepoint-rollback-failed\",\n outcome: \"unknown\",\n rollbackFailed: true,\n ...(rollbackErrorCode === undefined ? {} : { rollbackErrorCode }),\n },\n cause,\n });\n}\n\n/** Whether `error` is this module's poison refusal (used to pick the cleanup path). */\nexport function isSavepointRollbackFailedError(error: unknown): boolean {\n const reason = (error as { meta?: { reason?: unknown } } | null)?.meta?.reason;\n return reason === \"savepoint-rollback-failed\";\n}\n\n// ─── Internals ────────────────────────────────────────────────────\n\nfunction assertNotPoisoned(params: { state: SavepointState }): void {\n if (params.state.poisoned !== null) throw params.state.poisoned;\n}\n\n/** Whether `scope` may act while `open` is the innermost open savepoint. */\nfunction mayProceed(params: { scope: SavepointScope; open: OpenSavepoint | null }): boolean {\n const { scope, open } = params;\n if (open === null) return true;\n // This handle IS the innermost open savepoint.\n if (open.scope === scope) return true;\n // This handle's own savepoint has already closed (a retained child handle):\n // it can only act at the connection's current depth, and waiting for a\n // shallower savepoint it does not own would never resolve.\n if (open.scope.depth < scope.depth) return true;\n // Genuine nesting: the call is being made from inside the open callback.\n return CURRENT.getStore() === open.scope;\n}\n\nasync function waitForTurn(params: { scope: SavepointScope }): Promise<void> {\n for (;;) {\n assertNotPoisoned({ state: params.scope.state });\n const open = params.scope.state.open;\n if (open === null || mayProceed({ scope: params.scope, open })) return;\n await open.settled;\n }\n}\n\n/**\n * Wait for this handle's turn and take it in the SAME synchronous step — the\n * check and the push must not be separated by an await, or two waiters woken\n * together would both open a savepoint.\n */\nasync function acquire(params: { scope: SavepointScope }): Promise<OpenSavepoint> {\n const { scope } = params;\n for (;;) {\n assertNotPoisoned({ state: scope.state });\n const open = scope.state.open;\n if (mayProceed({ scope, open })) return pushNode({ scope, parent: open });\n // `mayProceed` returns true for a null `open`, so this is never null here.\n await (open as OpenSavepoint).settled;\n }\n}\n\nfunction pushNode(params: { scope: SavepointScope; parent: OpenSavepoint | null }): OpenSavepoint {\n const { scope, parent } = params;\n const state = scope.state;\n let settle: () => void = () => undefined;\n const settled = new Promise<void>((resolve) => {\n settle = () => resolve();\n });\n // Physical depth follows the connection's stack, not the handle that opened\n // it: a savepoint opened from an outer handle inside a child's callback still\n // nests inside that child.\n const node: OpenSavepoint = {\n scope: { depth: (parent === null ? 0 : parent.scope.depth) + 1, state },\n name: nextSavepointName({ counter: state.counter }),\n parent,\n settled,\n settle,\n };\n state.open = node;\n return node;\n}\n\nfunction closeNode(params: { node: OpenSavepoint }): void {\n const { node } = params;\n const state = node.scope.state;\n if (state.open === node) state.open = node.parent;\n node.settle();\n}\n\n/** Wait out savepoints a callback opened below this node and never awaited. */\nasync function drainDescendants(params: { node: OpenSavepoint }): Promise<void> {\n const state = params.node.scope.state;\n for (;;) {\n const open = state.open;\n if (open === null || open === params.node || open.scope.depth <= params.node.scope.depth) return;\n await open.settled;\n }\n}\n",
7
+ "/**\n * The nested-transaction option contract — ONE copy, shared by every adapter\n * through `@vibeorm/runtime/adapter-kit` (CORE-B-03). It used to live as six\n * hand-synchronised copies, one per adapter; a fourth option would have had\n * to be refused six times.\n */\n\nimport { VibeError } from \"@vibeorm/schema\";\nimport type { TransactionOptions } from \"../adapter.ts\";\n\n/**\n * Refuse options on a NESTED `transaction()` call — the same contract on every\n * adapter (see the `DatabaseAdapter.transaction` JSDoc in `adapter.ts`): a\n * nested transaction is a SAVEPOINT, and a savepoint can neither change the\n * isolation level of the transaction it joins, enforce its own timeout, nor\n * carry its own deadline. Silently dropping the option hid exactly that.\n *\n * @throws VibeError `VIBE_VALIDATION` when `isolationLevel`, `timeout` or\n * `deadline` is present (an `undefined` or empty options object is accepted).\n */\nexport function refuseNestedTransactionOptions(params: {\n options?: TransactionOptions;\n provider: string;\n}): void {\n const { options, provider } = params;\n if (options === undefined) return;\n\n const passed: string[] = [];\n if (options.isolationLevel !== undefined) passed.push(\"isolationLevel\");\n if (options.timeout !== undefined) passed.push(\"timeout\");\n if (options.deadline !== undefined) passed.push(\"deadline\");\n if (passed.length === 0) return;\n\n const meta: Record<string, unknown> = { provider, nested: true };\n if (options.isolationLevel !== undefined) meta.isolationLevel = options.isolationLevel;\n if (options.timeout !== undefined) meta.timeout = options.timeout;\n if (options.deadline !== undefined) meta.deadline = options.deadline;\n\n throw new VibeError({\n code: \"VIBE_VALIDATION\",\n message: `nested transactions run as savepoints and cannot honor ${passed.join(\" or \")} — a savepoint cannot change the isolation level of the transaction it joins, a nested timeout is not enforceable, and a nested deadline would need its own session setting on a connection it does not own (it inherits the top-level one instead); pass options on the top-level $transaction`,\n meta,\n });\n}\n",
8
+ "/**\n * Transaction budgets — the total-deadline clock and the handle-closure gate.\n *\n * ONE copy, shared by every adapter package through the\n * `@vibeorm/runtime/adapter-kit` subpath (like `savepoint-gate.ts`), so a\n * change here reaches all engines at once — a per-adapter copy would drift\n * into a silent per-engine behaviour difference.\n *\n * WHAT A DEADLINE IS, AND IS NOT\n *\n * `TransactionOptions.timeout` is unchanged: a PER-STATEMENT engine-side bound.\n * `TransactionOptions.deadline` is new and different — a TOTAL wall-clock bound\n * on one top-level transaction. Its clock starts immediately before `BEGIN` is\n * sent, so connection acquisition (which has its own budget on the pooled\n * adapters) is deliberately NOT counted.\n *\n * Enforcement is never `Promise.race` over a statement that keeps running:\n *\n * - `\"between-statements\"` (the default, and all six adapters can deliver it):\n * before every statement, every nested `transaction()` and the `COMMIT`, an\n * expired budget refuses. The statement is never sent and the transaction is\n * rolled back. A statement ALREADY IN FLIGHT is not interrupted.\n * - `\"cancel-running-statements\"` (postgres servers only): additionally hands\n * the engine the remaining budget as `statement_timeout`, so the SERVER\n * cancels an over-long statement. An adapter that cannot do this refuses the\n * request outright rather than quietly delivering the weaker level.\n *\n * JavaScript cannot forcibly stop a running callback. A callback that keeps\n * going past the deadline finds its later database calls refused; work it does\n * outside the database (an HTTP call, an SMS) is not stopped and cannot be.\n * There is no automatic retry: a deadline failure is terminal for that\n * transaction, because external side effects may already have happened.\n */\n\nimport { VibeError } from \"@vibeorm/schema\";\nimport type {\n TransactionDeadlineEnforcement,\n TransactionDeadlineSupport,\n TransactionOptions,\n} from \"../adapter.ts\";\n\n// ─── Types ────────────────────────────────────────────────────────\n\n/** Where a budget check happened, reported as `meta.stage`. */\nexport type BudgetStage = \"statement\" | \"nested\" | \"commit\";\n\n/**\n * What is known about a finished transaction. `\"unknown\"` is a first-class\n * outcome, not a failure to decide: when a rollback itself fails the commit\n * state genuinely cannot be asserted, and claiming \"rolled back\" would be a lie.\n */\nexport type TransactionOutcome = \"committed\" | \"rolled-back\" | \"unknown\";\n\n/** Wall clock, injectable so tests are deterministic instead of sleep-timed. */\nexport type DeadlineClock = () => number;\n\n/** The ambient clock, used whenever no seam is injected. */\nexport const DEFAULT_DEADLINE_CLOCK: DeadlineClock = (): number => Date.now();\n\n/**\n * One top-level transaction's budget. Nested savepoint handles share this\n * object BY REFERENCE — they never get an independent clock, connection or\n * session setting.\n */\nexport type TransactionBudget = {\n /** The enforcement level in force, or `null` when no deadline was requested. */\n readonly enforcement: TransactionDeadlineEnforcement | null;\n /** The requested total budget in milliseconds, or `null` when none was. */\n readonly totalMs: number | null;\n /** Existing per-statement limit, independent of the total deadline. Zero disables it. */\n readonly statementTimeoutMs: number | null;\n /** Milliseconds left (never negative), or `null` when no deadline is set. */\n remainingMs(): number | null;\n /** True only when a deadline is set and has passed. */\n expired(): boolean;\n /** Refuse a closed handle or an expired budget. Called BEFORE anything is sent. */\n assertUsable(params: { stage: BudgetStage }): void;\n /** Record the terminal outcome; the first call wins and later ones are ignored. */\n close(params: { outcome: TransactionOutcome }): void;\n /** The recorded outcome, or `null` while the transaction is still open. */\n readonly outcome: TransactionOutcome | null;\n};\n\n// ─── Validation (before BEGIN, before any write) ──────────────────\n\n/**\n * Check `options.deadline` against what this adapter can honestly deliver.\n * Called BEFORE `BEGIN` — a budget this engine cannot honour must never leave\n * a transaction open behind it.\n *\n * @throws VibeError `VIBE_VALIDATION` when `totalMs` is not a positive integer.\n * @throws VibeError `VIBE_UNSUPPORTED_CAPABILITY` when the requested\n * `enforcement` is stronger than `support` — refused, never silently degraded.\n */\nexport function validateTransactionDeadline(params: {\n options?: TransactionOptions;\n support: TransactionDeadlineSupport;\n provider: string;\n}): void {\n const { options, support, provider } = params;\n const deadline = options?.deadline;\n if (deadline === undefined) return;\n\n if (support === \"unsupported\") {\n throw new VibeError({\n code: \"VIBE_UNSUPPORTED_CAPABILITY\",\n message: `${provider} cannot enforce a transaction deadline — remove the \\`deadline\\` option`,\n meta: { provider, feature: \"transactionDeadline\", supported: support },\n });\n }\n\n if (!Number.isInteger(deadline.totalMs) || deadline.totalMs <= 0) {\n throw new VibeError({\n code: \"VIBE_VALIDATION\",\n message: `transaction deadline \\`totalMs\\` must be a positive integer of milliseconds, received ${String(deadline.totalMs)}`,\n meta: { provider, feature: \"transactionDeadline\", totalMs: deadline.totalMs },\n });\n }\n\n const requested: TransactionDeadlineEnforcement = deadline.enforcement ?? \"between-statements\";\n if (requested === \"cancel-running-statements\" && support !== \"cancel-running-statements\") {\n throw new VibeError({\n code: \"VIBE_UNSUPPORTED_CAPABILITY\",\n message:\n `${provider} cannot cancel a statement that is already running, so the requested ` +\n \"`cancel-running-statements` deadline guarantee is refused rather than silently downgraded — \" +\n 'ask for \"between-statements\" if a budget checked between statements is enough',\n meta: { provider, feature: \"transactionDeadline\", requested, supported: support },\n });\n }\n}\n\n// ─── The budget ───────────────────────────────────────────────────\n\n/**\n * Start the clock for one top-level transaction. Call it immediately before\n * `BEGIN`; {@link validateTransactionDeadline} must already have run.\n */\nexport function startTransactionBudget(params: {\n options?: TransactionOptions;\n provider: string;\n clock?: DeadlineClock;\n}): TransactionBudget {\n const { options, provider } = params;\n const clock = params.clock ?? DEFAULT_DEADLINE_CLOCK;\n const deadline = options?.deadline;\n const totalMs = deadline === undefined ? null : deadline.totalMs;\n const enforcement: TransactionDeadlineEnforcement | null =\n deadline === undefined ? null : (deadline.enforcement ?? \"between-statements\");\n const expiresAt = totalMs === null ? null : clock() + totalMs;\n let outcome: TransactionOutcome | null = null;\n\n const budget: TransactionBudget = {\n enforcement,\n totalMs,\n statementTimeoutMs: options?.timeout ?? null,\n remainingMs(): number | null {\n return expiresAt === null ? null : Math.max(0, expiresAt - clock());\n },\n expired(): boolean {\n return expiresAt !== null && clock() >= expiresAt;\n },\n assertUsable(assertParams: { stage: BudgetStage }): void {\n if (outcome !== null) {\n throw transactionClosedError({ provider, outcome, stage: assertParams.stage });\n }\n if (expiresAt !== null && clock() >= expiresAt) {\n throw transactionDeadlineError({\n provider,\n stage: assertParams.stage,\n totalMs: totalMs as number,\n overdueMs: clock() - expiresAt,\n });\n }\n },\n close(closeParams: { outcome: TransactionOutcome }): void {\n if (outcome === null) outcome = closeParams.outcome;\n },\n get outcome(): TransactionOutcome | null {\n return outcome;\n },\n };\n return budget;\n}\n\n/**\n * The engine-side bound for the NEXT statement, or `null` when the caller did\n * not buy `\"cancel-running-statements\"`. Floored at 1 ms: on postgres `0` means\n * \"no limit\", so a spent budget must never be handed over as a zero.\n */\nexport function engineStatementBudgetMs(params: { budget: TransactionBudget }): number | null {\n const { budget } = params;\n if (budget.enforcement !== \"cancel-running-statements\") return null;\n const remaining = budget.remainingMs();\n if (remaining === null) return null;\n const totalBound = Math.max(1, Math.ceil(remaining));\n return budget.statementTimeoutMs !== null && budget.statementTimeoutMs > 0\n ? Math.min(totalBound, budget.statementTimeoutMs) : totalBound;\n}\n\n// ─── Errors ───────────────────────────────────────────────────────\n\n/**\n * The refusal an expired budget raises. `VIBE_TRANSACTION` with a stable\n * `meta.reason` — no SQL text, no parameter values, no credentials.\n */\nexport function transactionDeadlineError(params: {\n provider: string;\n stage: BudgetStage;\n totalMs: number;\n overdueMs: number;\n}): VibeError {\n const { provider, stage, totalMs, overdueMs } = params;\n const what =\n stage === \"commit\"\n ? \"the transaction was rolled back instead of committed\"\n : \"the statement was never sent and the transaction is being rolled back\";\n return new VibeError({\n code: \"VIBE_TRANSACTION\",\n message:\n `transaction deadline of ${totalMs} ms expired ${Math.max(0, Math.round(overdueMs))} ms ago — ${what}. ` +\n \"Nothing is retried automatically: work the callback did outside the database may already have happened.\",\n meta: { provider, reason: \"transaction-deadline\", stage, totalMs, overdueMs: Math.max(0, Math.round(overdueMs)) },\n });\n}\n\n/**\n * The refusal an ESCAPED transaction handle raises — a transactional adapter\n * kept past the end of its transaction. Without this it would run on a\n * connection that is back in the pool, outside any transaction.\n */\nexport function transactionClosedError(params: {\n provider: string;\n outcome: TransactionOutcome;\n stage: BudgetStage;\n}): VibeError {\n const { provider, outcome, stage } = params;\n return new VibeError({\n code: \"VIBE_TRANSACTION\",\n message:\n `this transaction has already finished (${outcome}), so its client can no longer be used — ` +\n \"a handle kept past the end of `$transaction` would run outside the transaction, on a connection \" +\n \"that now belongs to someone else\",\n meta: { provider, reason: \"transaction-closed\", outcome, stage },\n });\n}\n\n/**\n * The stable typed outcome for \"the deadline expired and the rollback that was\n * supposed to clean up failed too\". Promising a rollback here would be false;\n * promising a retry would be worse.\n *\n * `cause` is the CAUSAL error (the deadline refusal), so the reason the\n * transaction was being abandoned survives. The rollback failure itself is\n * reported only as `meta.rollbackFailed`: a raw driver failure can carry\n * statement text, and this error is meant to be logged.\n */\nexport function transactionOutcomeUnknownError(params: {\n provider: string;\n totalMs: number;\n cause: unknown;\n}): VibeError {\n const { provider, totalMs, cause } = params;\n return new VibeError({\n code: \"VIBE_TRANSACTION\",\n message:\n `transaction deadline of ${totalMs} ms expired and the rollback that should have cleaned up failed — ` +\n \"the commit state of this transaction is UNKNOWN. It is not retried automatically; inspect the data \" +\n \"before deciding.\",\n meta: {\n provider,\n reason: \"transaction-outcome-unknown\",\n outcome: \"unknown\",\n totalMs,\n rollbackFailed: true,\n },\n cause,\n });\n}\n\n/** Whether `error` is this module's deadline refusal (used to pick the cleanup path). */\nexport function isTransactionDeadlineError(error: unknown): boolean {\n const reason = (error as { meta?: { reason?: unknown } } | null)?.meta?.reason;\n return reason === \"transaction-deadline\";\n}\n",
9
+ "import { VibeError } from \"@vibeorm/schema\";\nimport type { SqlExecutor } from \"../adapter.ts\";\n\n/** Own one physical session until the callback and dispatched work have settled. */\nexport function runPinnedSession<T>(params: {\n readonly execute: SqlExecutor;\n readonly run: (executor: SqlExecutor) => Promise<T>;\n readonly release: () => Promise<void>;\n readonly isLost: (error: unknown) => boolean;\n}): Promise<T> {\n let active = true;\n let lost: VibeError | undefined;\n let tail: Promise<void> = Promise.resolve();\n const executor: SqlExecutor = (query) => {\n const result = tail.then(async () => {\n if (lost !== undefined) throw lost;\n if (!active) throw new VibeError({\n code: \"VIBE_ADAPTER\",\n message: \"The reserved database session has finished; acquire a new session before executing SQL.\",\n meta: { reason: \"session-closed\" },\n });\n return params.execute(query).catch((cause: unknown) => {\n if (params.isLost(cause)) {\n lost = new VibeError({\n code: \"VIBE_ADAPTER\",\n message: \"The reserved database session was lost. No further SQL will be sent; inspect migration progress before retrying.\",\n meta: { reason: \"session-lost\", outcome: \"unknown\" },\n cause,\n });\n throw lost;\n }\n throw cause;\n });\n });\n tail = result.then(() => undefined, () => undefined);\n return result;\n };\n return Promise.resolve().then(() => params.run(executor)).then(async (result) => {\n active = false;\n await tail;\n if (lost !== undefined) throw lost;\n return result;\n }).finally(async () => {\n active = false;\n await tail;\n await params.release();\n });\n}\n",
10
+ "import { VibeError } from \"@vibeorm/schema\";\nimport { SQLITE_SESSION_SQL } from \"@vibeorm/sql\";\nimport type { SqlExecutor } from \"../adapter.ts\";\nimport { runPinnedSession } from \"./session.ts\";\n\n/** Hold SQLite's native file lock across transaction boundaries, then restore it. */\nexport async function runSqliteSession<T>(params: {\n readonly execute: SqlExecutor;\n readonly run: (executor: SqlExecutor) => Promise<T>;\n readonly inTransaction: () => boolean;\n}): Promise<T> {\n if (params.inTransaction()) throw new VibeError({\n code: \"VIBE_TRANSACTION\",\n message: \"A migration session cannot borrow a SQLite connection with an open transaction.\",\n meta: { reason: \"session-in-transaction\" },\n });\n const rows = await params.execute({ text: SQLITE_SESSION_SQL.lockingMode, values: [] });\n const mode = rows[0]?.locking_mode;\n if (mode !== \"normal\" && mode !== \"exclusive\") throw new VibeError({\n code: \"VIBE_ADAPTER\",\n message: \"SQLite did not report its locking mode; no migration was started.\",\n meta: { reason: \"session-lock-mode\" },\n });\n await params.execute({ text: SQLITE_SESSION_SQL.exclusive });\n return Promise.resolve().then(async () => {\n // The transaction acquires the file lock; EXCLUSIVE retains it after COMMIT.\n await params.execute({ text: SQLITE_SESSION_SQL.acquire });\n await params.execute({ text: SQLITE_SESSION_SQL.commit });\n return runPinnedSession({\n execute: params.execute,\n run: params.run,\n isLost: () => false, // The captured native handle never reconnects.\n release: async () => {\n if (params.inTransaction()) await params.execute({ text: SQLITE_SESSION_SQL.rollback });\n },\n });\n }).finally(async () => {\n if (params.inTransaction()) await params.execute({ text: SQLITE_SESSION_SQL.rollback });\n await params.execute({ text: SQLITE_SESSION_SQL.foreignKeysOn });\n if (mode === \"normal\") {\n await params.execute({ text: SQLITE_SESSION_SQL.normal });\n // NORMAL alone does not release the lock: SQLite requires a database read.\n await params.execute({ text: SQLITE_SESSION_SQL.touch, values: [] });\n }\n });\n}\n"
8
11
  ],
9
- "mappings": "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",
10
- "debugId": "90A5C246EB2BA1E264756E2164756E21",
12
+ "mappings": "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",
13
+ "debugId": "F41DD3D472C2858864756E2164756E21",
11
14
  "names": []
12
15
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The nested-transaction option contract — ONE copy, shared by every adapter
3
+ * through `@vibeorm/runtime/adapter-kit` (CORE-B-03). It used to live as six
4
+ * hand-synchronised copies, one per adapter; a fourth option would have had
5
+ * to be refused six times.
6
+ */
7
+ import type { TransactionOptions } from "../adapter.ts";
8
+ /**
9
+ * Refuse options on a NESTED `transaction()` call — the same contract on every
10
+ * adapter (see the `DatabaseAdapter.transaction` JSDoc in `adapter.ts`): a
11
+ * nested transaction is a SAVEPOINT, and a savepoint can neither change the
12
+ * isolation level of the transaction it joins, enforce its own timeout, nor
13
+ * carry its own deadline. Silently dropping the option hid exactly that.
14
+ *
15
+ * @throws VibeError `VIBE_VALIDATION` when `isolationLevel`, `timeout` or
16
+ * `deadline` is present (an `undefined` or empty options object is accepted).
17
+ */
18
+ export declare function refuseNestedTransactionOptions(params: {
19
+ options?: TransactionOptions;
20
+ provider: string;
21
+ }): void;
22
+ //# sourceMappingURL=nested-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nested-options.d.ts","sourceRoot":"","sources":["../../src/adapter-kit/nested-options.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAoBP"}
@@ -23,7 +23,17 @@
23
23
  * Not covered: a callback that awaits a sibling it did not start. That
24
24
  * arrangement asks for two savepoints to be open at once, which is exactly what
25
25
  * loses work; it now blocks instead. Deliberate — see the notes for this fix.
26
+ *
27
+ * A FAILED `ROLLBACK TO SAVEPOINT` poisons the whole transaction. When the
28
+ * engine cannot undo a savepoint — InnoDB has already rolled the entire
29
+ * transaction back after a deadlock, an implicit-commit DDL cleared every
30
+ * savepoint, the connection dropped — the transaction's outcome is unknown and
31
+ * no handle of it may send another statement: a parent callback that caught
32
+ * the nested error and "continued" would otherwise run in autocommit and the
33
+ * final COMMIT would succeed vacuously. Every later turn refuses with the same
34
+ * typed error.
26
35
  */
36
+ import { VibeError } from "@vibeorm/schema";
27
37
  import { type SavepointCounter } from "./savepoints.ts";
28
38
  /**
29
39
  * One handle's position in the savepoint stack of a top-level transaction.
@@ -41,6 +51,12 @@ export type SavepointState = {
41
51
  readonly counter: SavepointCounter;
42
52
  /** The innermost savepoint currently open, or `null` when none is. */
43
53
  open: OpenSavepoint | null;
54
+ /**
55
+ * Set once a `ROLLBACK TO SAVEPOINT` has failed: the savepoint stack no
56
+ * longer describes the connection, so every later statement and nested
57
+ * savepoint on ANY handle of this transaction is refused with this error.
58
+ */
59
+ poisoned: VibeError | null;
44
60
  };
45
61
  /** An open savepoint: its handle, its name, and when it finished. */
46
62
  type OpenSavepoint = {
@@ -82,5 +98,20 @@ export declare function runNestedSavepoint<T>(params: {
82
98
  readonly execute?: (statement: string) => Promise<unknown> | unknown;
83
99
  readonly body: (scope: SavepointScope) => Promise<T>;
84
100
  }): Promise<T>;
101
+ /**
102
+ * The refusal raised when `ROLLBACK TO SAVEPOINT` itself fails, and repeated
103
+ * for every later statement on the poisoned transaction. `VIBE_TRANSACTION`
104
+ * with `meta.reason = "savepoint-rollback-failed"` and `meta.outcome =
105
+ * "unknown"`; `cause` is the body failure that triggered the rollback. The
106
+ * rollback failure's own code (when it is a `VibeError`) rides along as
107
+ * `meta.rollbackErrorCode` — its message is not copied, because a raw driver
108
+ * failure can carry statement text and this error is meant to be logged.
109
+ */
110
+ export declare function savepointRollbackFailedError(params: {
111
+ cause: unknown;
112
+ rollbackFailure: unknown;
113
+ }): VibeError;
114
+ /** Whether `error` is this module's poison refusal (used to pick the cleanup path). */
115
+ export declare function isSavepointRollbackFailedError(error: unknown): boolean;
85
116
  export {};
86
117
  //# sourceMappingURL=savepoint-gate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"savepoint-gate.d.ts","sourceRoot":"","sources":["../../src/adapter-kit/savepoint-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,KAAK,gBAAgB,EAA6C,MAAM,iBAAiB,CAAC;AAInG;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;CAChC,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,sEAAsE;IACtE,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,qEAAqE;AACrE,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AAWF,wEAAwE;AACxE,wBAAgB,oBAAoB,IAAI,cAAc,CAErD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAErG;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAItF;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE;IAClD,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACrE,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACtD,GAAG,OAAO,CAAC,CAAC,CAAC,CA6Bb"}
1
+ {"version":3,"file":"savepoint-gate.d.ts","sourceRoot":"","sources":["../../src/adapter-kit/savepoint-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,KAAK,gBAAgB,EAA6C,MAAM,iBAAiB,CAAC;AAInG;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;CAChC,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,cAAc,GAAG;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,sEAAsE;IACtE,IAAI,EAAE,aAAa,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,EAAE,SAAS,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,qEAAqE;AACrE,KAAK,aAAa,GAAG;IACnB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AAWF,wEAAwE;AACxE,wBAAgB,oBAAoB,IAAI,cAAc,CAErD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,CAAA;CAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CASrG;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,cAAc,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAKtF;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE;IAClD,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACrE,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACtD,GAAG,OAAO,CAAC,CAAC,CAAC,CAmCb;AAID;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,eAAe,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAmB5G;AAED,uFAAuF;AACvF,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGtE"}
@@ -0,0 +1,9 @@
1
+ import type { SqlExecutor } from "../adapter.ts";
2
+ /** Own one physical session until the callback and dispatched work have settled. */
3
+ export declare function runPinnedSession<T>(params: {
4
+ readonly execute: SqlExecutor;
5
+ readonly run: (executor: SqlExecutor) => Promise<T>;
6
+ readonly release: () => Promise<void>;
7
+ readonly isLost: (error: unknown) => boolean;
8
+ }): Promise<T>;
9
+ //# sourceMappingURL=session.d.ts.map