@vibeorm/adapter-bun 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -244
- package/dist/index.js.map +4 -7
- package/package.json +3 -3
- package/dist/savepoint-gate.d.ts +0 -86
- package/dist/savepoint-gate.d.ts.map +0 -1
- package/dist/savepoints.d.ts +0 -22
- package/dist/savepoints.d.ts.map +0 -1
- package/dist/transaction-budget.d.ts +0 -144
- package/dist/transaction-budget.d.ts.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -53,12 +53,12 @@ export { BUN_SQLSTATE_ERROR_CODES, BUN_SQLSTATE_REASONS, bunErrorSqlstate, mapBu
|
|
|
53
53
|
export { serializeParams, serializeParamsRaw, toPgArrayLiteral } from "./params.ts";
|
|
54
54
|
export { applyStartupOptions, buildStartupOptions } from "./connection-url.ts";
|
|
55
55
|
export type { PlanCacheMode } from "./connection-url.ts";
|
|
56
|
-
export { createSavepointCounter, nextSavepointName } from "
|
|
57
|
-
export type { SavepointCounter } from "
|
|
56
|
+
export { createSavepointCounter, nextSavepointName } from "@vibeorm/runtime/adapter-kit";
|
|
57
|
+
export type { SavepointCounter } from "@vibeorm/runtime/adapter-kit";
|
|
58
58
|
export { createTemplateCache, templateChunks } from "./template-cache.ts";
|
|
59
59
|
export type { TemplateCache } from "./template-cache.ts";
|
|
60
60
|
export { ISOLATION_LEVEL_SQL, beginStatement, classifyRawTransactionControl, refuseNestedTransactionOptions, statementTimeoutStatement, } from "./transaction-sql.ts";
|
|
61
61
|
export type { RawTransactionControl } from "./transaction-sql.ts";
|
|
62
|
-
export { DEFAULT_DEADLINE_CLOCK, engineStatementBudgetMs, isTransactionDeadlineError, startTransactionBudget, transactionClosedError, transactionDeadlineError, transactionOutcomeUnknownError, validateTransactionDeadline, } from "
|
|
63
|
-
export type { BudgetStage, DeadlineClock, TransactionBudget, TransactionOutcome } from "
|
|
62
|
+
export { DEFAULT_DEADLINE_CLOCK, engineStatementBudgetMs, isTransactionDeadlineError, startTransactionBudget, transactionClosedError, transactionDeadlineError, transactionOutcomeUnknownError, validateTransactionDeadline, } from "@vibeorm/runtime/adapter-kit";
|
|
63
|
+
export type { BudgetStage, DeadlineClock, TransactionBudget, TransactionOutcome } from "@vibeorm/runtime/adapter-kit";
|
|
64
64
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAEV,eAAe,EAIhB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAEV,eAAe,EAIhB,MAAM,kBAAkB,CAAC;AAe1B,OAAO,EAA4C,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAuEnG,sCAAsC;AACtC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,oGAAoG;IACpG,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IACtC,2EAA2E;IAC3E,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,uFAAuF;IACvF,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;CACxC,CAAC;AA+CF;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,eAAe,CA0bvE;AAgBD,OAAO,EACL,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACzF,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1E,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,6BAA6B,EAC7B,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,8BAA8B,EAC9B,2BAA2B,GAC5B,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
// packages/adapter-bun/src/index.ts
|
|
3
3
|
var {SQL } = globalThis.Bun;
|
|
4
4
|
import { postgresDialect, renderDiagnostic } from "@vibeorm/sql";
|
|
5
|
+
import {
|
|
6
|
+
createSavepointScope,
|
|
7
|
+
engineStatementBudgetMs,
|
|
8
|
+
isTransactionDeadlineError,
|
|
9
|
+
runNestedSavepoint,
|
|
10
|
+
runRootScope,
|
|
11
|
+
scopeTurn,
|
|
12
|
+
startTransactionBudget,
|
|
13
|
+
transactionOutcomeUnknownError,
|
|
14
|
+
validateTransactionDeadline
|
|
15
|
+
} from "@vibeorm/runtime/adapter-kit";
|
|
5
16
|
|
|
6
17
|
// packages/adapter-bun/src/connection-url.ts
|
|
7
18
|
import { VibeError } from "@vibeorm/schema";
|
|
@@ -148,241 +159,8 @@ function serializeParamsRaw(params) {
|
|
|
148
159
|
});
|
|
149
160
|
}
|
|
150
161
|
|
|
151
|
-
// packages/adapter-bun/src/transaction-budget.ts
|
|
152
|
-
import { VibeError as VibeError4 } from "@vibeorm/schema";
|
|
153
|
-
var DEFAULT_DEADLINE_CLOCK = () => Date.now();
|
|
154
|
-
function validateTransactionDeadline(params) {
|
|
155
|
-
const { options, support, provider } = params;
|
|
156
|
-
const deadline = options?.deadline;
|
|
157
|
-
if (deadline === undefined)
|
|
158
|
-
return;
|
|
159
|
-
if (support === "unsupported") {
|
|
160
|
-
throw new VibeError4({
|
|
161
|
-
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
162
|
-
message: `${provider} cannot enforce a transaction deadline \u2014 remove the \`deadline\` option`,
|
|
163
|
-
meta: { provider, feature: "transactionDeadline", supported: support }
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
if (!Number.isInteger(deadline.totalMs) || deadline.totalMs <= 0) {
|
|
167
|
-
throw new VibeError4({
|
|
168
|
-
code: "VIBE_VALIDATION",
|
|
169
|
-
message: `transaction deadline \`totalMs\` must be a positive integer of milliseconds, received ${String(deadline.totalMs)}`,
|
|
170
|
-
meta: { provider, feature: "transactionDeadline", totalMs: deadline.totalMs }
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
const requested = deadline.enforcement ?? "between-statements";
|
|
174
|
-
if (requested === "cancel-running-statements" && support !== "cancel-running-statements") {
|
|
175
|
-
throw new VibeError4({
|
|
176
|
-
code: "VIBE_UNSUPPORTED_CAPABILITY",
|
|
177
|
-
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',
|
|
178
|
-
meta: { provider, feature: "transactionDeadline", requested, supported: support }
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
function startTransactionBudget(params) {
|
|
183
|
-
const { options, provider } = params;
|
|
184
|
-
const clock = params.clock ?? DEFAULT_DEADLINE_CLOCK;
|
|
185
|
-
const deadline = options?.deadline;
|
|
186
|
-
const totalMs = deadline === undefined ? null : deadline.totalMs;
|
|
187
|
-
const enforcement = deadline === undefined ? null : deadline.enforcement ?? "between-statements";
|
|
188
|
-
const expiresAt = totalMs === null ? null : clock() + totalMs;
|
|
189
|
-
let outcome = null;
|
|
190
|
-
const budget = {
|
|
191
|
-
enforcement,
|
|
192
|
-
totalMs,
|
|
193
|
-
statementTimeoutMs: options?.timeout ?? null,
|
|
194
|
-
remainingMs() {
|
|
195
|
-
return expiresAt === null ? null : Math.max(0, expiresAt - clock());
|
|
196
|
-
},
|
|
197
|
-
expired() {
|
|
198
|
-
return expiresAt !== null && clock() >= expiresAt;
|
|
199
|
-
},
|
|
200
|
-
assertUsable(assertParams) {
|
|
201
|
-
if (outcome !== null) {
|
|
202
|
-
throw transactionClosedError({ provider, outcome, stage: assertParams.stage });
|
|
203
|
-
}
|
|
204
|
-
if (expiresAt !== null && clock() >= expiresAt) {
|
|
205
|
-
throw transactionDeadlineError({
|
|
206
|
-
provider,
|
|
207
|
-
stage: assertParams.stage,
|
|
208
|
-
totalMs,
|
|
209
|
-
overdueMs: clock() - expiresAt
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
close(closeParams) {
|
|
214
|
-
if (outcome === null)
|
|
215
|
-
outcome = closeParams.outcome;
|
|
216
|
-
},
|
|
217
|
-
get outcome() {
|
|
218
|
-
return outcome;
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
return budget;
|
|
222
|
-
}
|
|
223
|
-
function engineStatementBudgetMs(params) {
|
|
224
|
-
const { budget } = params;
|
|
225
|
-
if (budget.enforcement !== "cancel-running-statements")
|
|
226
|
-
return null;
|
|
227
|
-
const remaining = budget.remainingMs();
|
|
228
|
-
if (remaining === null)
|
|
229
|
-
return null;
|
|
230
|
-
const totalBound = Math.max(1, Math.ceil(remaining));
|
|
231
|
-
return budget.statementTimeoutMs !== null && budget.statementTimeoutMs > 0 ? Math.min(totalBound, budget.statementTimeoutMs) : totalBound;
|
|
232
|
-
}
|
|
233
|
-
function transactionDeadlineError(params) {
|
|
234
|
-
const { provider, stage, totalMs, overdueMs } = params;
|
|
235
|
-
const what = stage === "commit" ? "the transaction was rolled back instead of committed" : "the statement was never sent and the transaction is being rolled back";
|
|
236
|
-
return new VibeError4({
|
|
237
|
-
code: "VIBE_TRANSACTION",
|
|
238
|
-
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.",
|
|
239
|
-
meta: { provider, reason: "transaction-deadline", stage, totalMs, overdueMs: Math.max(0, Math.round(overdueMs)) }
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
function transactionClosedError(params) {
|
|
243
|
-
const { provider, outcome, stage } = params;
|
|
244
|
-
return new VibeError4({
|
|
245
|
-
code: "VIBE_TRANSACTION",
|
|
246
|
-
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",
|
|
247
|
-
meta: { provider, reason: "transaction-closed", outcome, stage }
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
function transactionOutcomeUnknownError(params) {
|
|
251
|
-
const { provider, totalMs, cause } = params;
|
|
252
|
-
return new VibeError4({
|
|
253
|
-
code: "VIBE_TRANSACTION",
|
|
254
|
-
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.",
|
|
255
|
-
meta: {
|
|
256
|
-
provider,
|
|
257
|
-
reason: "transaction-outcome-unknown",
|
|
258
|
-
outcome: "unknown",
|
|
259
|
-
totalMs,
|
|
260
|
-
rollbackFailed: true
|
|
261
|
-
},
|
|
262
|
-
cause
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
function isTransactionDeadlineError(error) {
|
|
266
|
-
const reason = error?.meta?.reason;
|
|
267
|
-
return reason === "transaction-deadline";
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// packages/adapter-bun/src/savepoint-gate.ts
|
|
271
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
272
|
-
|
|
273
|
-
// packages/adapter-bun/src/savepoints.ts
|
|
274
|
-
function createSavepointCounter() {
|
|
275
|
-
return { n: 0 };
|
|
276
|
-
}
|
|
277
|
-
function nextSavepointName(params) {
|
|
278
|
-
return `vibeorm_sp_${params.counter.n++}`;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// packages/adapter-bun/src/savepoint-gate.ts
|
|
282
|
-
var CURRENT = new AsyncLocalStorage;
|
|
283
|
-
function createSavepointScope() {
|
|
284
|
-
return { depth: 0, state: { counter: createSavepointCounter(), open: null } };
|
|
285
|
-
}
|
|
286
|
-
function runRootScope(params) {
|
|
287
|
-
return CURRENT.run(params.scope, params.body);
|
|
288
|
-
}
|
|
289
|
-
function scopeTurn(params) {
|
|
290
|
-
const open = params.scope.state.open;
|
|
291
|
-
if (mayProceed({ scope: params.scope, open }))
|
|
292
|
-
return;
|
|
293
|
-
return waitForTurn({ scope: params.scope });
|
|
294
|
-
}
|
|
295
|
-
async function runNestedSavepoint(params) {
|
|
296
|
-
const { scope, execute, body } = params;
|
|
297
|
-
const node = await acquire({ scope });
|
|
298
|
-
try {
|
|
299
|
-
if (execute !== undefined)
|
|
300
|
-
await execute(`SAVEPOINT ${node.name}`);
|
|
301
|
-
let result;
|
|
302
|
-
try {
|
|
303
|
-
result = await CURRENT.run(node.scope, () => body(node.scope));
|
|
304
|
-
} catch (error) {
|
|
305
|
-
await drainDescendants({ node });
|
|
306
|
-
if (execute !== undefined) {
|
|
307
|
-
try {
|
|
308
|
-
await execute(`ROLLBACK TO SAVEPOINT ${node.name}`);
|
|
309
|
-
} catch {}
|
|
310
|
-
}
|
|
311
|
-
throw error;
|
|
312
|
-
}
|
|
313
|
-
await drainDescendants({ node });
|
|
314
|
-
if (execute !== undefined)
|
|
315
|
-
await execute(`RELEASE SAVEPOINT ${node.name}`);
|
|
316
|
-
return result;
|
|
317
|
-
} finally {
|
|
318
|
-
closeNode({ node });
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
function mayProceed(params) {
|
|
322
|
-
const { scope, open } = params;
|
|
323
|
-
if (open === null)
|
|
324
|
-
return true;
|
|
325
|
-
if (open.scope === scope)
|
|
326
|
-
return true;
|
|
327
|
-
if (open.scope.depth < scope.depth)
|
|
328
|
-
return true;
|
|
329
|
-
return CURRENT.getStore() === open.scope;
|
|
330
|
-
}
|
|
331
|
-
async function waitForTurn(params) {
|
|
332
|
-
for (;; ) {
|
|
333
|
-
const open = params.scope.state.open;
|
|
334
|
-
if (open === null || mayProceed({ scope: params.scope, open }))
|
|
335
|
-
return;
|
|
336
|
-
await open.settled;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
async function acquire(params) {
|
|
340
|
-
const { scope } = params;
|
|
341
|
-
for (;; ) {
|
|
342
|
-
const open = scope.state.open;
|
|
343
|
-
if (mayProceed({ scope, open }))
|
|
344
|
-
return pushNode({ scope, parent: open });
|
|
345
|
-
await open.settled;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
function pushNode(params) {
|
|
349
|
-
const { scope, parent } = params;
|
|
350
|
-
const state = scope.state;
|
|
351
|
-
let settle = () => {
|
|
352
|
-
return;
|
|
353
|
-
};
|
|
354
|
-
const settled = new Promise((resolve) => {
|
|
355
|
-
settle = () => resolve();
|
|
356
|
-
});
|
|
357
|
-
const node = {
|
|
358
|
-
scope: { depth: (parent === null ? 0 : parent.scope.depth) + 1, state },
|
|
359
|
-
name: nextSavepointName({ counter: state.counter }),
|
|
360
|
-
parent,
|
|
361
|
-
settled,
|
|
362
|
-
settle
|
|
363
|
-
};
|
|
364
|
-
state.open = node;
|
|
365
|
-
return node;
|
|
366
|
-
}
|
|
367
|
-
function closeNode(params) {
|
|
368
|
-
const { node } = params;
|
|
369
|
-
const state = node.scope.state;
|
|
370
|
-
if (state.open === node)
|
|
371
|
-
state.open = node.parent;
|
|
372
|
-
node.settle();
|
|
373
|
-
}
|
|
374
|
-
async function drainDescendants(params) {
|
|
375
|
-
const state = params.node.scope.state;
|
|
376
|
-
for (;; ) {
|
|
377
|
-
const open = state.open;
|
|
378
|
-
if (open === null || open === params.node || open.scope.depth <= params.node.scope.depth)
|
|
379
|
-
return;
|
|
380
|
-
await open.settled;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
162
|
// packages/adapter-bun/src/template-cache.ts
|
|
385
|
-
import { VibeError as
|
|
163
|
+
import { VibeError as VibeError4 } from "@vibeorm/schema";
|
|
386
164
|
function isIdentChar(char) {
|
|
387
165
|
if (char === undefined)
|
|
388
166
|
return false;
|
|
@@ -488,7 +266,7 @@ function bindTemplateValues(params) {
|
|
|
488
266
|
const { text, indices, values } = params;
|
|
489
267
|
return indices.map((placeholder) => {
|
|
490
268
|
if (placeholder < 1 || placeholder > values.length) {
|
|
491
|
-
throw new
|
|
269
|
+
throw new VibeError4({
|
|
492
270
|
code: "VIBE_VALIDATION",
|
|
493
271
|
message: `bun:sql prepared statement references $${placeholder} but only ${values.length} parameter(s) were given`,
|
|
494
272
|
meta: { text, placeholder, provided: values.length }
|
|
@@ -525,7 +303,7 @@ function createTemplateCache(params) {
|
|
|
525
303
|
}
|
|
526
304
|
|
|
527
305
|
// packages/adapter-bun/src/transaction-sql.ts
|
|
528
|
-
import { VibeError as
|
|
306
|
+
import { VibeError as VibeError5 } from "@vibeorm/schema";
|
|
529
307
|
var ISOLATION_LEVEL_SQL = Object.freeze({
|
|
530
308
|
ReadCommitted: "READ COMMITTED",
|
|
531
309
|
RepeatableRead: "REPEATABLE READ",
|
|
@@ -538,7 +316,7 @@ function beginStatement(params) {
|
|
|
538
316
|
function statementTimeoutStatement(params) {
|
|
539
317
|
const { timeout } = params;
|
|
540
318
|
if (!Number.isInteger(timeout) || timeout < 0) {
|
|
541
|
-
throw new
|
|
319
|
+
throw new VibeError5({
|
|
542
320
|
code: "VIBE_VALIDATION",
|
|
543
321
|
message: `transaction timeout must be a non-negative integer of milliseconds, received ${String(timeout)}`,
|
|
544
322
|
meta: { timeout }
|
|
@@ -575,7 +353,7 @@ function refuseNestedTransactionOptions(params) {
|
|
|
575
353
|
meta.timeout = options.timeout;
|
|
576
354
|
if (options.deadline !== undefined)
|
|
577
355
|
meta.deadline = options.deadline;
|
|
578
|
-
throw new
|
|
356
|
+
throw new VibeError5({
|
|
579
357
|
code: "VIBE_VALIDATION",
|
|
580
358
|
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`,
|
|
581
359
|
meta
|
|
@@ -583,6 +361,18 @@ function refuseNestedTransactionOptions(params) {
|
|
|
583
361
|
}
|
|
584
362
|
|
|
585
363
|
// packages/adapter-bun/src/index.ts
|
|
364
|
+
import { createSavepointCounter, nextSavepointName } from "@vibeorm/runtime/adapter-kit";
|
|
365
|
+
import {
|
|
366
|
+
DEFAULT_DEADLINE_CLOCK,
|
|
367
|
+
engineStatementBudgetMs as engineStatementBudgetMs2,
|
|
368
|
+
isTransactionDeadlineError as isTransactionDeadlineError2,
|
|
369
|
+
startTransactionBudget as startTransactionBudget2,
|
|
370
|
+
transactionClosedError,
|
|
371
|
+
transactionDeadlineError,
|
|
372
|
+
transactionOutcomeUnknownError as transactionOutcomeUnknownError2,
|
|
373
|
+
validateTransactionDeadline as validateTransactionDeadline2
|
|
374
|
+
} from "@vibeorm/runtime/adapter-kit";
|
|
375
|
+
|
|
586
376
|
class CallbackError extends Error {
|
|
587
377
|
inner;
|
|
588
378
|
constructor(inner) {
|
|
@@ -892,21 +682,21 @@ function readAffectedRows(params) {
|
|
|
892
682
|
return rows.length;
|
|
893
683
|
}
|
|
894
684
|
export {
|
|
895
|
-
validateTransactionDeadline,
|
|
896
|
-
transactionOutcomeUnknownError,
|
|
685
|
+
validateTransactionDeadline2 as validateTransactionDeadline,
|
|
686
|
+
transactionOutcomeUnknownError2 as transactionOutcomeUnknownError,
|
|
897
687
|
transactionDeadlineError,
|
|
898
688
|
transactionClosedError,
|
|
899
689
|
toPgArrayLiteral,
|
|
900
690
|
templateChunks,
|
|
901
691
|
statementTimeoutStatement,
|
|
902
|
-
startTransactionBudget,
|
|
692
|
+
startTransactionBudget2 as startTransactionBudget,
|
|
903
693
|
serializeParamsRaw,
|
|
904
694
|
serializeParams,
|
|
905
695
|
refuseNestedTransactionOptions,
|
|
906
696
|
nextSavepointName,
|
|
907
697
|
mapBunDriverError,
|
|
908
|
-
isTransactionDeadlineError,
|
|
909
|
-
engineStatementBudgetMs,
|
|
698
|
+
isTransactionDeadlineError2 as isTransactionDeadlineError,
|
|
699
|
+
engineStatementBudgetMs2 as engineStatementBudgetMs,
|
|
910
700
|
createTemplateCache,
|
|
911
701
|
createSavepointCounter,
|
|
912
702
|
classifyRawTransactionControl,
|
|
@@ -921,4 +711,4 @@ export {
|
|
|
921
711
|
BUN_SQLSTATE_ERROR_CODES
|
|
922
712
|
};
|
|
923
713
|
|
|
924
|
-
//# debugId=
|
|
714
|
+
//# debugId=70944EEE52F737AB64756E2164756E21
|
package/dist/index.js.map
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/connection-url.ts", "../src/errors.ts", "../src/params.ts", "../src/
|
|
3
|
+
"sources": ["../src/index.ts", "../src/connection-url.ts", "../src/errors.ts", "../src/params.ts", "../src/template-cache.ts", "../src/transaction-sql.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * @vibeorm/adapter-bun — bun:sql (PostgreSQL) adapter for VibeORM v2.\n *\n * Uses Bun's built-in SQL driver and its internal connection pool. Owns\n * optional prepared statements (synthetic tagged templates), transactions\n * (nested → savepoints), array-literal parameter formatting and driver-error\n * mapping. Only `VibeError` ever escapes.\n */\n\nimport { SQL } from \"bun\";\nimport { postgresDialect, renderDiagnostic } from \"@vibeorm/sql\";\nimport type {\n AdapterBudgetSupport,\n DatabaseAdapter,\n QueryResult,\n TransactionOptions,\n WireFidelity,\n} from \"@vibeorm/runtime\";\nimport type { Dialect, Provider } from \"@vibeorm/schema\";\nimport { applyStartupOptions, buildStartupOptions, type PlanCacheMode } from \"./connection-url.ts\";\nimport { mapBunDriverError, runMapped } from \"./errors.ts\";\nimport { serializeParams, serializeParamsRaw, toPgArrayLiteral } from \"./params.ts\";\nimport {\n engineStatementBudgetMs,\n isTransactionDeadlineError,\n startTransactionBudget,\n type TransactionBudget,\n transactionOutcomeUnknownError,\n validateTransactionDeadline,\n} from \"./transaction-budget.ts\";\nimport {\n createSavepointScope,\n runNestedSavepoint,\n runRootScope,\n scopeTurn,\n type SavepointScope,\n} from \"./savepoint-gate.ts\";\nimport { bindTemplateValues, createTemplateCache } from \"./template-cache.ts\";\nimport {\n beginStatement,\n classifyRawTransactionControl,\n refuseNestedTransactionOptions,\n statementTimeoutStatement,\n} from \"./transaction-sql.ts\";\n\n// ─── Minimal bun:sql surface ──────────────────────────────────────\n\n/**\n * What bun:sql resolves a query to: the row array, with driver metadata\n * (`count`, `command`) attached as properties.\n */\ntype BunRows = Record<string, unknown>[] & { count?: number; affectedRows?: number };\n\n/** Anything that executes SQL through bun:sql. */\ntype BunExecutor = {\n (strings: TemplateStringsArray, ...values: unknown[]): Promise<BunRows>;\n unsafe(text: string, values?: unknown[]): Promise<BunRows>;\n};\n\n/**\n * The handle passed to `sql.begin(cb)`. Modern bun:sql exposes `savepoint(fn)`\n * for sub-transactions; `begin()` throws inside a transaction (\"use\n * savepoint() instead\"), so it is never called here. Older builds lack\n * `savepoint`, which is why it is optional and probed at runtime.\n */\ntype BunTransaction = BunExecutor & {\n savepoint?: <T>(fn: (sp: BunTransaction) => Promise<T>) => Promise<T>;\n};\n\n/** A connection checked out with `sql.reserve()` — no `savepoint`, must be released. */\ntype BunReserved = BunExecutor & { release(): void };\n\n/** The pool-level bun:sql client. */\ntype BunInstance = BunExecutor & {\n begin<T>(fn: (tx: BunTransaction) => Promise<T>): Promise<T>;\n reserve(): Promise<BunReserved>;\n close(): Promise<void>;\n};\n\n/** Any bun:sql handle the adapter can be built on top of. */\ntype BunSource = BunInstance | BunReserved | BunTransaction;\n\n/**\n * Whether a handle is the pool (can open a real transaction) or is already\n * inside one (must nest through savepoints).\n */\ntype ParentMode = \"pool\" | \"tx\";\n\n/**\n * Wrapper that marks an error as \"thrown by the user's transaction callback\",\n * so it can be rethrown untouched instead of being mapped as a driver failure\n * after bun:sql has passed it back out of `begin()` / `savepoint()`.\n */\nclass CallbackError extends Error {\n readonly inner: unknown;\n\n constructor(inner: unknown) {\n super(\"vibeorm: transaction callback failed\");\n this.name = \"CallbackError\";\n this.inner = inner;\n }\n}\n\n// ─── Options ──────────────────────────────────────────────────────\n\n/** Options for {@link bunAdapter}. */\nexport type BunAdapterOptions = {\n /** PostgreSQL connection URL. Defaults to `process.env.DATABASE_URL`, then bun's `PG*` env vars. */\n readonly url?: string;\n /** Maximum pooled connections (default 10). */\n readonly max?: number;\n /**\n * Pool-wide `statement_timeout` in milliseconds, sent as a startup parameter\n * so every connection inherits it. A per-transaction `timeout` overrides it\n * for that transaction.\n */\n readonly statementTimeout?: number;\n /**\n * Milliseconds to wait for a connection to be established. Passed to bun:sql\n * as `connectionTimeout` (which expects **seconds**; converted here).\n */\n readonly connectionTimeout?: number;\n /**\n * Execute ORM-path queries as tagged templates, creating named prepared\n * statements (default false). Saves planning time but lets PostgreSQL fall\n * back to a generic plan after ~5 executions — leave off unless profiling\n * says otherwise. bun:sql's `prepare: false` constructor option is never set\n * (it triggers a known bun:sql performance regression).\n */\n readonly preparedStatements?: boolean;\n /** Maximum entries in the synthetic template cache (default 1000, LRU). */\n readonly stmtCacheMax?: number;\n /** PostgreSQL `plan_cache_mode` for every connection (default `force_custom_plan`). */\n readonly planCacheMode?: PlanCacheMode;\n};\n\n// ─── Adapter ──────────────────────────────────────────────────────\n\nconst DIALECT: Dialect = \"postgres\";\nconst PROVIDER: Provider = \"postgresql\";\n\n/**\n * bun:sql wire (board #30, live-verified on both execute paths): timestamptz\n * → `Date`, int4/float8 → numbers. (int8 arrives as a string — BigInt\n * decoding is real work and never pruned.)\n *\n * The `json` half is NOT a constant, because bun:sql's answer changed between\n * Bun versions and this package supports a range of them: on Bun 1.3.14 the\n * tagged-template path parsed json/jsonb while `sql.unsafe` did not (board\n * #34 — declaring \"parsed\" there made the runtime prune the Json decoder and\n * leak raw strings), and on Bun 1.4.1 BOTH paths parse (leaving \"text\" makes\n * the guarded decode re-parse a stored top-level JSON string: `\"123\"` becomes\n * the number 123, `\"hello\"` throws). Either constant is wrong on one of those\n * runtimes, so the adapter OBSERVES its own driver once instead of guessing —\n * see {@link probeJsonWire}. {@link WIRE_TEXT} is the conservative claim it\n * starts from and keeps if the probe cannot run.\n */\n/**\n * Timing budgets this adapter genuinely enforces (EPIC 6).\n *\n * - `acquireTimeout: true` — {@link BunAdapterOptions.connectionTimeout} maps\n * to bun:sql's own `connectionTimeout` (\"maximum time to wait for a\n * connection to become available\"). Declared as a capability; the effective\n * value is whatever the option is set to.\n * - `statementTimeout: \"all-statements\"` — a real PostgreSQL server, so\n * `statement_timeout` cancels ANY over-long statement, writes included.\n * - `transactionDeadline: \"cancel-running-statements\"` — the remaining budget\n * is handed to the SERVER before each statement, so the database itself stops\n * work that would outlive the deadline.\n */\nconst BUDGETS: AdapterBudgetSupport = Object.freeze({\n acquireTimeout: true,\n statementTimeout: \"all-statements\",\n transactionDeadline: \"cancel-running-statements\",\n} as const);\n\nconst WIRE_TEXT: WireFidelity = Object.freeze({ dateTime: \"native\", json: \"text\", numbers: \"native\" } as const);\n\n/** The same wire, for a driver observed to hand back parsed json. */\nconst WIRE_PARSED: WireFidelity = Object.freeze({ dateTime: \"native\", json: \"parsed\", numbers: \"native\" } as const);\n\n/**\n * Create a VibeORM adapter backed by bun:sql.\n *\n * @example\n * ```ts\n * const adapter = bunAdapter({ url: process.env.DATABASE_URL, max: 10 });\n * await adapter.connect();\n * const rows = await adapter.execute({ text: 'SELECT * FROM \"User\" WHERE \"id\" = $1', values: [1] });\n * ```\n */\nexport function bunAdapter(options?: BunAdapterOptions): DatabaseAdapter {\n const usePrepared = options?.preparedStatements ?? false;\n const templates = createTemplateCache({ max: options?.stmtCacheMax ?? 1000 });\n\n /**\n * The wire claim this adapter currently makes. Starts conservative and is\n * replaced at most once, by {@link probeJsonWire}'s observation. Every handle\n * this factory builds — pool, transaction, savepoint, reserved session —\n * reads this one variable, so a transaction can never disagree with its\n * parent (the contract requires transactional adapters to carry the same\n * declaration).\n */\n let activeWire: WireFidelity = WIRE_TEXT;\n let wireSettled = false;\n let wireProbe: Promise<void> | null = null;\n\n let instance: BunInstance | null = null;\n\n /**\n * The reserved connection of an OPEN raw transaction — session affinity for\n * the raw path. @vibeorm/migrate wraps transactional DDL in literal `BEGIN`\n * / `COMMIT` / `ROLLBACK` sent through `executeUnsafe`; bun:sql refuses\n * transaction control through `sql.unsafe()` on a pooled instance\n * (`ERR_POSTGRES_UNSAFE_TRANSACTION`), so a pure `BEGIN` reserves one\n * connection, every raw statement until the matching `COMMIT`/`ROLLBACK`\n * rides it, and the close releases it. The ORM path (`execute`) and\n * `transaction()` stay on the pool — they never participate in a raw\n * transaction. Concurrent raw transactions on one adapter are unsupported\n * (they were driver-refused before this pinning existed).\n */\n let rawSession: BunReserved | null = null;\n\n function getSql(): BunInstance {\n if (instance !== null) return instance;\n\n const sqlOptions: Record<string, unknown> = { max: options?.max ?? 10 };\n if (options?.connectionTimeout !== undefined) {\n // bun:sql expects seconds; the VibeORM surface is milliseconds everywhere.\n sqlOptions.connectionTimeout = Math.max(1, Math.ceil(options.connectionTimeout / 1000));\n }\n\n const startupOptions = buildStartupOptions({\n planCacheMode: options?.planCacheMode ?? \"force_custom_plan\",\n statementTimeout: options?.statementTimeout,\n });\n const baseUrl = options?.url ?? process.env.DATABASE_URL;\n const url =\n baseUrl === undefined || startupOptions === undefined\n ? baseUrl\n : applyStartupOptions({ url: baseUrl, startupOptions });\n\n // Without a URL, bun:sql falls back to PG* environment variables (startup\n // options cannot be attached in that case).\n instance =\n url === undefined\n ? (new SQL(sqlOptions) as unknown as BunInstance)\n : (new SQL(url, sqlOptions) as unknown as BunInstance);\n return instance;\n }\n\n /**\n * Ask THIS driver, once, whether it parses json on the path the ORM reads\n * rows over — the same `execute` path, prepared or unsafe as configured, so\n * the answer describes the traffic the claim is applied to.\n *\n * Runs on the handle that is already in hand (pool, transaction or reserved\n * session): a `SELECT` is harmless inside a transaction, and probing the pool\n * from inside one could deadlock an adapter configured with `max: 1`.\n * Failure is not fatal — the conservative `WIRE_TEXT` claim stands, the\n * caller's own statement reports the real error, and the probe never runs\n * again.\n */\n async function probeJsonWire(source: BunExecutor): Promise<void> {\n const probe = renderDiagnostic({ dialect: postgresDialect, query: \"postgresJsonWire\" });\n try {\n const rows = usePrepared\n ? await source(templates.getTemplate({ text: probe.text }).template)\n : await source.unsafe(probe.text, []);\n const probed = rows[0]?.probe;\n if (typeof probed === \"object\" && probed !== null) activeWire = WIRE_PARSED;\n } catch {\n /* undeclared beats wrongly declared — keep WIRE_TEXT */\n } finally {\n wireSettled = true;\n }\n }\n\n async function runExecute(params: {\n source: BunExecutor;\n text: string;\n values: unknown[];\n }): Promise<Record<string, unknown>[]> {\n // One extra round trip on the first ORM query of this adapter's life; a\n // single boolean test on every one after it. It must complete BEFORE the\n // first rows are handed back, because the runtime reads `wire` to build\n // that read's decode plan.\n if (!wireSettled) {\n wireProbe ??= probeJsonWire(params.source);\n await wireProbe;\n }\n const values = serializeParams({ values: params.values });\n if (usePrepared) {\n // F19: a tagged template binds POSITIONALLY, one value per gap — so the\n // values follow the placeholder ORDER found in the text (`$2, $1` binds\n // backwards otherwise, and a repeated `$1` needs its value twice).\n const prepared = templates.getTemplate({ text: params.text });\n const bound = bindTemplateValues({ text: params.text, indices: prepared.indices, values });\n return runMapped(() => params.source(prepared.template, ...bound));\n }\n return runMapped(() => params.source.unsafe(params.text, values));\n }\n\n async function runExecuteUnsafe(params: {\n source: BunExecutor;\n text: string;\n values?: unknown[];\n }): Promise<QueryResult> {\n const values = params.values === undefined ? undefined : serializeParamsRaw({ values: params.values });\n const rows = await runMapped(() => params.source.unsafe(params.text, values));\n return { rows, affectedRows: readAffectedRows({ rows }) };\n }\n\n /**\n * Build the adapter facade over any bun:sql handle. `parentMode` decides\n * whether a nested `transaction()` opens a real transaction or a savepoint;\n * `scope` is shared by reference across one top-level transaction, and the\n * savepoint gate serializes overlapping sibling savepoints (F14) on BOTH the\n * driver-managed and the manual path.\n */\n function createAdapter(params: {\n source: BunSource;\n parentMode: ParentMode;\n scope: SavepointScope;\n /** The enclosing transaction's budget; absent on the pool-level adapter. */\n budget?: TransactionBudget;\n }): DatabaseAdapter {\n const { source, parentMode, scope, budget } = params;\n\n /**\n * Hand the SERVER the remaining budget before a statement runs, when the\n * caller bought `\"cancel-running-statements\"`. `SET LOCAL` is\n * transaction-scoped, so PostgreSQL reverts it at COMMIT/ROLLBACK and the\n * connection goes back to the pool with its session settings intact. One\n * extra round trip per statement, only while a deadline is active.\n */\n async function applyEngineBudget(): Promise<void> {\n if (budget === undefined) return;\n const ms = engineStatementBudgetMs({ budget });\n if (ms === null) return;\n await runMapped(() => (source as BunTransaction).unsafe(statementTimeoutStatement({ timeout: ms })));\n }\n\n /** Nested transaction: a savepoint on the connection we are already on. */\n async function transactionViaSavepoint<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n nestedOptions?: TransactionOptions,\n ): Promise<T> {\n refuseNestedTransactionOptions({ options: nestedOptions, provider: PROVIDER });\n budget?.assertUsable({ stage: \"nested\" });\n const transactional = source as BunTransaction;\n\n // Modern bun:sql: the in-transaction handle drives savepoints itself —\n // the gate then owns only the LIFETIME, not the SQL. Captured before the\n // callback because narrowing does not reach into a nested closure.\n const driverSavepoint = transactional.savepoint?.bind(transactional);\n if (driverSavepoint !== undefined) {\n return runNestedSavepoint({\n scope,\n body: async (child) => {\n try {\n return await driverSavepoint(async (savepointSql) => {\n const nested = createAdapter({\n source: savepointSql,\n parentMode: \"tx\",\n scope: child,\n });\n try {\n return await fn(nested);\n } catch (error) {\n throw new CallbackError(error);\n }\n });\n } catch (error) {\n if (error instanceof CallbackError) throw error.inner;\n throw mapBunDriverError({ error });\n }\n },\n });\n }\n\n // Reserved connections (and older bun:sql) expose no savepoint helper —\n // drive SAVEPOINT / RELEASE / ROLLBACK TO by hand.\n return runNestedSavepoint({\n scope,\n execute: (statement) => runMapped(() => transactional.unsafe(statement)),\n // The child shares the ROOT budget by reference: a savepoint never gets\n // an independent clock or session setting.\n body: (child) =>\n fn(createAdapter({ source: transactional, parentMode: \"tx\", scope: child, budget })),\n });\n }\n\n /** Top-level transaction on the pool. */\n async function transactionViaPool<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n transactionOptions?: TransactionOptions,\n ): Promise<T> {\n const pool = source as BunInstance;\n\n // Refuse an unsupportable budget before any connection is taken.\n validateTransactionDeadline({\n options: transactionOptions,\n support: BUDGETS.transactionDeadline,\n provider: PROVIDER,\n });\n\n // Fast path: bun:sql drives BEGIN/COMMIT itself. A DEADLINE opts out of\n // it deliberately — the clock must start after the connection is in hand,\n // and only the reserved path below gives that seam.\n if (\n transactionOptions?.isolationLevel === undefined &&\n transactionOptions?.timeout === undefined &&\n transactionOptions?.deadline === undefined\n ) {\n // A budget with no deadline: it still closes the handle at the end, so\n // an escaped transaction client cannot run on a pooled connection.\n const budget = startTransactionBudget({ provider: PROVIDER });\n try {\n const result = await pool.begin(async (txSql) => {\n const txScope = createSavepointScope();\n const txAdapter = createAdapter({\n source: txSql,\n parentMode: \"tx\",\n scope: txScope,\n budget,\n });\n try {\n return await runRootScope({ scope: txScope, body: () => fn(txAdapter) });\n } catch (error) {\n throw new CallbackError(error);\n }\n });\n budget.close({ outcome: \"committed\" });\n return result;\n } catch (error) {\n // bun:sql owns this transaction's rollback and has already performed\n // it by the time control reaches here.\n budget.close({ outcome: \"rolled-back\" });\n if (error instanceof CallbackError) throw error.inner;\n throw mapBunDriverError({ error });\n }\n }\n\n // Options path: reserve one connection and drive the transaction by hand,\n // because bun:sql's begin() takes no isolation/timeout options.\n const timeoutText =\n transactionOptions.timeout === undefined\n ? undefined\n : statementTimeoutStatement({ timeout: transactionOptions.timeout });\n const reserved = await runMapped(() => pool.reserve());\n // The deadline clock starts HERE: the connection is reserved, so waiting\n // for it is not charged against the caller's transaction budget.\n const budget = startTransactionBudget({ options: transactionOptions, provider: PROVIDER });\n try {\n await runMapped(() =>\n reserved.unsafe(beginStatement({ isolationLevel: transactionOptions.isolationLevel })),\n );\n if (timeoutText !== undefined) await runMapped(() => reserved.unsafe(timeoutText));\n const txScope = createSavepointScope();\n const txAdapter = createAdapter({\n source: reserved,\n parentMode: \"tx\",\n scope: txScope,\n budget,\n });\n const result = await runRootScope({ scope: txScope, body: () => fn(txAdapter) });\n // An expired budget must never commit, however the callback ended.\n budget.assertUsable({ stage: \"commit\" });\n await runMapped(() => reserved.unsafe(\"COMMIT\"));\n budget.close({ outcome: \"committed\" });\n return result;\n } catch (error) {\n try {\n await reserved.unsafe(\"ROLLBACK\");\n budget.close({ outcome: \"rolled-back\" });\n } catch {\n // The rollback that should have cleaned up failed: the commit state is\n // genuinely unknown. `SET LOCAL` reverts with the transaction, but\n // this session's transaction state can no longer be asserted.\n budget.close({ outcome: \"unknown\" });\n if (budget.totalMs !== null && isTransactionDeadlineError(error)) {\n throw transactionOutcomeUnknownError({\n provider: PROVIDER,\n totalMs: budget.totalMs,\n cause: error,\n });\n }\n }\n throw error;\n } finally {\n reserved.release();\n }\n }\n\n return {\n dialect: DIALECT,\n provider: PROVIDER,\n budgets: BUDGETS,\n get wire(): WireFidelity {\n return activeWire;\n },\n\n async execute(execParams) {\n const turn = scopeTurn({ scope });\n if (turn !== undefined) await turn;\n // After the turn, not before: waiting for a sibling savepoint spends\n // the same budget the statement is about to run against.\n budget?.assertUsable({ stage: \"statement\" });\n await applyEngineBudget();\n return runExecute({ source, ...execParams });\n },\n\n async executeUnsafe(execParams) {\n const turn = scopeTurn({ scope });\n if (turn !== undefined) await turn;\n budget?.assertUsable({ stage: \"statement\" });\n await applyEngineBudget();\n return runExecuteUnsafe({ source, ...execParams });\n },\n\n async transaction<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n transactionOptions?: TransactionOptions,\n ): Promise<T> {\n return parentMode === \"pool\"\n ? transactionViaPool(fn, transactionOptions)\n : transactionViaSavepoint(fn, transactionOptions);\n },\n\n async connect(): Promise<void> {\n if (parentMode !== \"pool\") return;\n const reserved = await runMapped(() => (source as BunInstance).reserve());\n reserved.release();\n },\n\n async disconnect(): Promise<void> {\n if (parentMode !== \"pool\") return;\n await runMapped(() => (source as BunInstance).close());\n instance = null;\n },\n\n formatArrayParam(values: unknown[]): unknown {\n return toPgArrayLiteral(values);\n },\n };\n }\n\n /** Pool-level facade — the bun:sql client is created on first use. */\n function poolAdapter(): DatabaseAdapter {\n return createAdapter({\n source: getSql(),\n parentMode: \"pool\",\n scope: createSavepointScope(),\n });\n }\n\n return {\n dialect: DIALECT,\n provider: PROVIDER,\n budgets: BUDGETS,\n get wire(): WireFidelity {\n return activeWire;\n },\n\n async execute(params) {\n return poolAdapter().execute(params);\n },\n\n async executeUnsafe(params) {\n const control = classifyRawTransactionControl({ text: params.text });\n if (rawSession !== null) {\n if (control === \"close\") {\n const session = rawSession;\n rawSession = null;\n try {\n return await runExecuteUnsafe({ source: session, ...params });\n } finally {\n session.release();\n }\n }\n // A nested raw BEGIN lands here too — postgres treats it as a warning\n // no-op on the open session, exactly like a single connection would.\n return runExecuteUnsafe({ source: rawSession, ...params });\n }\n if (control === \"open\") {\n const reserved = await runMapped(() => getSql().reserve());\n try {\n const result = await runExecuteUnsafe({ source: reserved, ...params });\n rawSession = reserved;\n return result;\n } catch (error) {\n reserved.release();\n throw error;\n }\n }\n return poolAdapter().executeUnsafe(params);\n },\n\n async transaction<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n transactionOptions?: TransactionOptions,\n ): Promise<T> {\n return poolAdapter().transaction(fn, transactionOptions);\n },\n\n async connect(): Promise<void> {\n return poolAdapter().connect();\n },\n\n async disconnect(): Promise<void> {\n if (rawSession !== null) {\n // An abandoned raw transaction must not leak an in-transaction\n // connection; roll it back best-effort before the pool closes.\n const session = rawSession;\n rawSession = null;\n try {\n await session.unsafe(\"ROLLBACK\");\n } catch {\n /* the pool is closing; the session is going away regardless */\n }\n session.release();\n }\n if (instance === null) return;\n const closing = instance;\n instance = null;\n await runMapped(() => closing.close());\n },\n\n formatArrayParam(values: unknown[]): unknown {\n return toPgArrayLiteral(values);\n },\n };\n}\n\n/**\n * Rows affected by a bun:sql statement: the driver attaches `count` (and, on\n * some versions, `affectedRows`) to the returned array; otherwise the number of\n * returned rows is the best available answer.\n */\nfunction readAffectedRows(params: { rows: BunRows }): number {\n const { rows } = params;\n if (typeof rows.count === \"number\") return rows.count;\n if (typeof rows.affectedRows === \"number\") return rows.affectedRows;\n return rows.length;\n}\n\n// ─── Re-exports (driver-error table, params, helpers) ─────────────\n\nexport {\n BUN_SQLSTATE_ERROR_CODES,\n BUN_SQLSTATE_REASONS,\n bunErrorSqlstate,\n mapBunDriverError,\n} from \"./errors.ts\";\nexport { serializeParams, serializeParamsRaw, toPgArrayLiteral } from \"./params.ts\";\nexport { applyStartupOptions, buildStartupOptions } from \"./connection-url.ts\";\nexport type { PlanCacheMode } from \"./connection-url.ts\";\nexport { createSavepointCounter, nextSavepointName } from \"./savepoints.ts\";\nexport type { SavepointCounter } from \"./savepoints.ts\";\nexport { createTemplateCache, templateChunks } from \"./template-cache.ts\";\nexport type { TemplateCache } from \"./template-cache.ts\";\nexport {\n ISOLATION_LEVEL_SQL,\n beginStatement,\n classifyRawTransactionControl,\n refuseNestedTransactionOptions,\n statementTimeoutStatement,\n} from \"./transaction-sql.ts\";\nexport type { RawTransactionControl } from \"./transaction-sql.ts\";\n// ─── EPIC 6: transaction budgets ──────────────────────────────────\nexport {\n DEFAULT_DEADLINE_CLOCK,\n engineStatementBudgetMs,\n isTransactionDeadlineError,\n startTransactionBudget,\n transactionClosedError,\n transactionDeadlineError,\n transactionOutcomeUnknownError,\n validateTransactionDeadline,\n} from \"./transaction-budget.ts\";\nexport type { BudgetStage, DeadlineClock, TransactionBudget, TransactionOutcome } from \"./transaction-budget.ts\";\n",
|
|
5
|
+
"/**\n * @vibeorm/adapter-bun — bun:sql (PostgreSQL) adapter for VibeORM v2.\n *\n * Uses Bun's built-in SQL driver and its internal connection pool. Owns\n * optional prepared statements (synthetic tagged templates), transactions\n * (nested → savepoints), array-literal parameter formatting and driver-error\n * mapping. Only `VibeError` ever escapes.\n */\n\nimport { SQL } from \"bun\";\nimport { postgresDialect, renderDiagnostic } from \"@vibeorm/sql\";\nimport type {\n AdapterBudgetSupport,\n DatabaseAdapter,\n QueryResult,\n TransactionOptions,\n WireFidelity,\n} from \"@vibeorm/runtime\";\nimport {\n createSavepointScope,\n engineStatementBudgetMs,\n isTransactionDeadlineError,\n runNestedSavepoint,\n runRootScope,\n type SavepointScope,\n scopeTurn,\n startTransactionBudget,\n type TransactionBudget,\n transactionOutcomeUnknownError,\n validateTransactionDeadline,\n} from \"@vibeorm/runtime/adapter-kit\";\nimport type { Dialect, Provider } from \"@vibeorm/schema\";\nimport { applyStartupOptions, buildStartupOptions, type PlanCacheMode } from \"./connection-url.ts\";\nimport { mapBunDriverError, runMapped } from \"./errors.ts\";\nimport { serializeParams, serializeParamsRaw, toPgArrayLiteral } from \"./params.ts\";\nimport { bindTemplateValues, createTemplateCache } from \"./template-cache.ts\";\nimport {\n beginStatement,\n classifyRawTransactionControl,\n refuseNestedTransactionOptions,\n statementTimeoutStatement,\n} from \"./transaction-sql.ts\";\n\n// ─── Minimal bun:sql surface ──────────────────────────────────────\n\n/**\n * What bun:sql resolves a query to: the row array, with driver metadata\n * (`count`, `command`) attached as properties.\n */\ntype BunRows = Record<string, unknown>[] & { count?: number; affectedRows?: number };\n\n/** Anything that executes SQL through bun:sql. */\ntype BunExecutor = {\n (strings: TemplateStringsArray, ...values: unknown[]): Promise<BunRows>;\n unsafe(text: string, values?: unknown[]): Promise<BunRows>;\n};\n\n/**\n * The handle passed to `sql.begin(cb)`. Modern bun:sql exposes `savepoint(fn)`\n * for sub-transactions; `begin()` throws inside a transaction (\"use\n * savepoint() instead\"), so it is never called here. Older builds lack\n * `savepoint`, which is why it is optional and probed at runtime.\n */\ntype BunTransaction = BunExecutor & {\n savepoint?: <T>(fn: (sp: BunTransaction) => Promise<T>) => Promise<T>;\n};\n\n/** A connection checked out with `sql.reserve()` — no `savepoint`, must be released. */\ntype BunReserved = BunExecutor & { release(): void };\n\n/** The pool-level bun:sql client. */\ntype BunInstance = BunExecutor & {\n begin<T>(fn: (tx: BunTransaction) => Promise<T>): Promise<T>;\n reserve(): Promise<BunReserved>;\n close(): Promise<void>;\n};\n\n/** Any bun:sql handle the adapter can be built on top of. */\ntype BunSource = BunInstance | BunReserved | BunTransaction;\n\n/**\n * Whether a handle is the pool (can open a real transaction) or is already\n * inside one (must nest through savepoints).\n */\ntype ParentMode = \"pool\" | \"tx\";\n\n/**\n * Wrapper that marks an error as \"thrown by the user's transaction callback\",\n * so it can be rethrown untouched instead of being mapped as a driver failure\n * after bun:sql has passed it back out of `begin()` / `savepoint()`.\n */\nclass CallbackError extends Error {\n readonly inner: unknown;\n\n constructor(inner: unknown) {\n super(\"vibeorm: transaction callback failed\");\n this.name = \"CallbackError\";\n this.inner = inner;\n }\n}\n\n// ─── Options ──────────────────────────────────────────────────────\n\n/** Options for {@link bunAdapter}. */\nexport type BunAdapterOptions = {\n /** PostgreSQL connection URL. Defaults to `process.env.DATABASE_URL`, then bun's `PG*` env vars. */\n readonly url?: string;\n /** Maximum pooled connections (default 10). */\n readonly max?: number;\n /**\n * Pool-wide `statement_timeout` in milliseconds, sent as a startup parameter\n * so every connection inherits it. A per-transaction `timeout` overrides it\n * for that transaction.\n */\n readonly statementTimeout?: number;\n /**\n * Milliseconds to wait for a connection to be established. Passed to bun:sql\n * as `connectionTimeout` (which expects **seconds**; converted here).\n */\n readonly connectionTimeout?: number;\n /**\n * Execute ORM-path queries as tagged templates, creating named prepared\n * statements (default false). Saves planning time but lets PostgreSQL fall\n * back to a generic plan after ~5 executions — leave off unless profiling\n * says otherwise. bun:sql's `prepare: false` constructor option is never set\n * (it triggers a known bun:sql performance regression).\n */\n readonly preparedStatements?: boolean;\n /** Maximum entries in the synthetic template cache (default 1000, LRU). */\n readonly stmtCacheMax?: number;\n /** PostgreSQL `plan_cache_mode` for every connection (default `force_custom_plan`). */\n readonly planCacheMode?: PlanCacheMode;\n};\n\n// ─── Adapter ──────────────────────────────────────────────────────\n\nconst DIALECT: Dialect = \"postgres\";\nconst PROVIDER: Provider = \"postgresql\";\n\n/**\n * bun:sql wire (board #30, live-verified on both execute paths): timestamptz\n * → `Date`, int4/float8 → numbers. (int8 arrives as a string — BigInt\n * decoding is real work and never pruned.)\n *\n * The `json` half is NOT a constant, because bun:sql's answer changed between\n * Bun versions and this package supports a range of them: on Bun 1.3.14 the\n * tagged-template path parsed json/jsonb while `sql.unsafe` did not (board\n * #34 — declaring \"parsed\" there made the runtime prune the Json decoder and\n * leak raw strings), and on Bun 1.4.1 BOTH paths parse (leaving \"text\" makes\n * the guarded decode re-parse a stored top-level JSON string: `\"123\"` becomes\n * the number 123, `\"hello\"` throws). Either constant is wrong on one of those\n * runtimes, so the adapter OBSERVES its own driver once instead of guessing —\n * see {@link probeJsonWire}. {@link WIRE_TEXT} is the conservative claim it\n * starts from and keeps if the probe cannot run.\n */\n/**\n * Timing budgets this adapter genuinely enforces (EPIC 6).\n *\n * - `acquireTimeout: true` — {@link BunAdapterOptions.connectionTimeout} maps\n * to bun:sql's own `connectionTimeout` (\"maximum time to wait for a\n * connection to become available\"). Declared as a capability; the effective\n * value is whatever the option is set to.\n * - `statementTimeout: \"all-statements\"` — a real PostgreSQL server, so\n * `statement_timeout` cancels ANY over-long statement, writes included.\n * - `transactionDeadline: \"cancel-running-statements\"` — the remaining budget\n * is handed to the SERVER before each statement, so the database itself stops\n * work that would outlive the deadline.\n */\nconst BUDGETS: AdapterBudgetSupport = Object.freeze({\n acquireTimeout: true,\n statementTimeout: \"all-statements\",\n transactionDeadline: \"cancel-running-statements\",\n} as const);\n\nconst WIRE_TEXT: WireFidelity = Object.freeze({ dateTime: \"native\", json: \"text\", numbers: \"native\" } as const);\n\n/** The same wire, for a driver observed to hand back parsed json. */\nconst WIRE_PARSED: WireFidelity = Object.freeze({ dateTime: \"native\", json: \"parsed\", numbers: \"native\" } as const);\n\n/**\n * Create a VibeORM adapter backed by bun:sql.\n *\n * @example\n * ```ts\n * const adapter = bunAdapter({ url: process.env.DATABASE_URL, max: 10 });\n * await adapter.connect();\n * const rows = await adapter.execute({ text: 'SELECT * FROM \"User\" WHERE \"id\" = $1', values: [1] });\n * ```\n */\nexport function bunAdapter(options?: BunAdapterOptions): DatabaseAdapter {\n const usePrepared = options?.preparedStatements ?? false;\n const templates = createTemplateCache({ max: options?.stmtCacheMax ?? 1000 });\n\n /**\n * The wire claim this adapter currently makes. Starts conservative and is\n * replaced at most once, by {@link probeJsonWire}'s observation. Every handle\n * this factory builds — pool, transaction, savepoint, reserved session —\n * reads this one variable, so a transaction can never disagree with its\n * parent (the contract requires transactional adapters to carry the same\n * declaration).\n */\n let activeWire: WireFidelity = WIRE_TEXT;\n let wireSettled = false;\n let wireProbe: Promise<void> | null = null;\n\n let instance: BunInstance | null = null;\n\n /**\n * The reserved connection of an OPEN raw transaction — session affinity for\n * the raw path. @vibeorm/migrate wraps transactional DDL in literal `BEGIN`\n * / `COMMIT` / `ROLLBACK` sent through `executeUnsafe`; bun:sql refuses\n * transaction control through `sql.unsafe()` on a pooled instance\n * (`ERR_POSTGRES_UNSAFE_TRANSACTION`), so a pure `BEGIN` reserves one\n * connection, every raw statement until the matching `COMMIT`/`ROLLBACK`\n * rides it, and the close releases it. The ORM path (`execute`) and\n * `transaction()` stay on the pool — they never participate in a raw\n * transaction. Concurrent raw transactions on one adapter are unsupported\n * (they were driver-refused before this pinning existed).\n */\n let rawSession: BunReserved | null = null;\n\n function getSql(): BunInstance {\n if (instance !== null) return instance;\n\n const sqlOptions: Record<string, unknown> = { max: options?.max ?? 10 };\n if (options?.connectionTimeout !== undefined) {\n // bun:sql expects seconds; the VibeORM surface is milliseconds everywhere.\n sqlOptions.connectionTimeout = Math.max(1, Math.ceil(options.connectionTimeout / 1000));\n }\n\n const startupOptions = buildStartupOptions({\n planCacheMode: options?.planCacheMode ?? \"force_custom_plan\",\n statementTimeout: options?.statementTimeout,\n });\n const baseUrl = options?.url ?? process.env.DATABASE_URL;\n const url =\n baseUrl === undefined || startupOptions === undefined\n ? baseUrl\n : applyStartupOptions({ url: baseUrl, startupOptions });\n\n // Without a URL, bun:sql falls back to PG* environment variables (startup\n // options cannot be attached in that case).\n instance =\n url === undefined\n ? (new SQL(sqlOptions) as unknown as BunInstance)\n : (new SQL(url, sqlOptions) as unknown as BunInstance);\n return instance;\n }\n\n /**\n * Ask THIS driver, once, whether it parses json on the path the ORM reads\n * rows over — the same `execute` path, prepared or unsafe as configured, so\n * the answer describes the traffic the claim is applied to.\n *\n * Runs on the handle that is already in hand (pool, transaction or reserved\n * session): a `SELECT` is harmless inside a transaction, and probing the pool\n * from inside one could deadlock an adapter configured with `max: 1`.\n * Failure is not fatal — the conservative `WIRE_TEXT` claim stands, the\n * caller's own statement reports the real error, and the probe never runs\n * again.\n */\n async function probeJsonWire(source: BunExecutor): Promise<void> {\n const probe = renderDiagnostic({ dialect: postgresDialect, query: \"postgresJsonWire\" });\n try {\n const rows = usePrepared\n ? await source(templates.getTemplate({ text: probe.text }).template)\n : await source.unsafe(probe.text, []);\n const probed = rows[0]?.probe;\n if (typeof probed === \"object\" && probed !== null) activeWire = WIRE_PARSED;\n } catch {\n /* undeclared beats wrongly declared — keep WIRE_TEXT */\n } finally {\n wireSettled = true;\n }\n }\n\n async function runExecute(params: {\n source: BunExecutor;\n text: string;\n values: unknown[];\n }): Promise<Record<string, unknown>[]> {\n // One extra round trip on the first ORM query of this adapter's life; a\n // single boolean test on every one after it. It must complete BEFORE the\n // first rows are handed back, because the runtime reads `wire` to build\n // that read's decode plan.\n if (!wireSettled) {\n wireProbe ??= probeJsonWire(params.source);\n await wireProbe;\n }\n const values = serializeParams({ values: params.values });\n if (usePrepared) {\n // F19: a tagged template binds POSITIONALLY, one value per gap — so the\n // values follow the placeholder ORDER found in the text (`$2, $1` binds\n // backwards otherwise, and a repeated `$1` needs its value twice).\n const prepared = templates.getTemplate({ text: params.text });\n const bound = bindTemplateValues({ text: params.text, indices: prepared.indices, values });\n return runMapped(() => params.source(prepared.template, ...bound));\n }\n return runMapped(() => params.source.unsafe(params.text, values));\n }\n\n async function runExecuteUnsafe(params: {\n source: BunExecutor;\n text: string;\n values?: unknown[];\n }): Promise<QueryResult> {\n const values = params.values === undefined ? undefined : serializeParamsRaw({ values: params.values });\n const rows = await runMapped(() => params.source.unsafe(params.text, values));\n return { rows, affectedRows: readAffectedRows({ rows }) };\n }\n\n /**\n * Build the adapter facade over any bun:sql handle. `parentMode` decides\n * whether a nested `transaction()` opens a real transaction or a savepoint;\n * `scope` is shared by reference across one top-level transaction, and the\n * savepoint gate serializes overlapping sibling savepoints (F14) on BOTH the\n * driver-managed and the manual path.\n */\n function createAdapter(params: {\n source: BunSource;\n parentMode: ParentMode;\n scope: SavepointScope;\n /** The enclosing transaction's budget; absent on the pool-level adapter. */\n budget?: TransactionBudget;\n }): DatabaseAdapter {\n const { source, parentMode, scope, budget } = params;\n\n /**\n * Hand the SERVER the remaining budget before a statement runs, when the\n * caller bought `\"cancel-running-statements\"`. `SET LOCAL` is\n * transaction-scoped, so PostgreSQL reverts it at COMMIT/ROLLBACK and the\n * connection goes back to the pool with its session settings intact. One\n * extra round trip per statement, only while a deadline is active.\n */\n async function applyEngineBudget(): Promise<void> {\n if (budget === undefined) return;\n const ms = engineStatementBudgetMs({ budget });\n if (ms === null) return;\n await runMapped(() => (source as BunTransaction).unsafe(statementTimeoutStatement({ timeout: ms })));\n }\n\n /** Nested transaction: a savepoint on the connection we are already on. */\n async function transactionViaSavepoint<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n nestedOptions?: TransactionOptions,\n ): Promise<T> {\n refuseNestedTransactionOptions({ options: nestedOptions, provider: PROVIDER });\n budget?.assertUsable({ stage: \"nested\" });\n const transactional = source as BunTransaction;\n\n // Modern bun:sql: the in-transaction handle drives savepoints itself —\n // the gate then owns only the LIFETIME, not the SQL. Captured before the\n // callback because narrowing does not reach into a nested closure.\n const driverSavepoint = transactional.savepoint?.bind(transactional);\n if (driverSavepoint !== undefined) {\n return runNestedSavepoint({\n scope,\n body: async (child) => {\n try {\n return await driverSavepoint(async (savepointSql) => {\n const nested = createAdapter({\n source: savepointSql,\n parentMode: \"tx\",\n scope: child,\n });\n try {\n return await fn(nested);\n } catch (error) {\n throw new CallbackError(error);\n }\n });\n } catch (error) {\n if (error instanceof CallbackError) throw error.inner;\n throw mapBunDriverError({ error });\n }\n },\n });\n }\n\n // Reserved connections (and older bun:sql) expose no savepoint helper —\n // drive SAVEPOINT / RELEASE / ROLLBACK TO by hand.\n return runNestedSavepoint({\n scope,\n execute: (statement) => runMapped(() => transactional.unsafe(statement)),\n // The child shares the ROOT budget by reference: a savepoint never gets\n // an independent clock or session setting.\n body: (child) =>\n fn(createAdapter({ source: transactional, parentMode: \"tx\", scope: child, budget })),\n });\n }\n\n /** Top-level transaction on the pool. */\n async function transactionViaPool<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n transactionOptions?: TransactionOptions,\n ): Promise<T> {\n const pool = source as BunInstance;\n\n // Refuse an unsupportable budget before any connection is taken.\n validateTransactionDeadline({\n options: transactionOptions,\n support: BUDGETS.transactionDeadline,\n provider: PROVIDER,\n });\n\n // Fast path: bun:sql drives BEGIN/COMMIT itself. A DEADLINE opts out of\n // it deliberately — the clock must start after the connection is in hand,\n // and only the reserved path below gives that seam.\n if (\n transactionOptions?.isolationLevel === undefined &&\n transactionOptions?.timeout === undefined &&\n transactionOptions?.deadline === undefined\n ) {\n // A budget with no deadline: it still closes the handle at the end, so\n // an escaped transaction client cannot run on a pooled connection.\n const budget = startTransactionBudget({ provider: PROVIDER });\n try {\n const result = await pool.begin(async (txSql) => {\n const txScope = createSavepointScope();\n const txAdapter = createAdapter({\n source: txSql,\n parentMode: \"tx\",\n scope: txScope,\n budget,\n });\n try {\n return await runRootScope({ scope: txScope, body: () => fn(txAdapter) });\n } catch (error) {\n throw new CallbackError(error);\n }\n });\n budget.close({ outcome: \"committed\" });\n return result;\n } catch (error) {\n // bun:sql owns this transaction's rollback and has already performed\n // it by the time control reaches here.\n budget.close({ outcome: \"rolled-back\" });\n if (error instanceof CallbackError) throw error.inner;\n throw mapBunDriverError({ error });\n }\n }\n\n // Options path: reserve one connection and drive the transaction by hand,\n // because bun:sql's begin() takes no isolation/timeout options.\n const timeoutText =\n transactionOptions.timeout === undefined\n ? undefined\n : statementTimeoutStatement({ timeout: transactionOptions.timeout });\n const reserved = await runMapped(() => pool.reserve());\n // The deadline clock starts HERE: the connection is reserved, so waiting\n // for it is not charged against the caller's transaction budget.\n const budget = startTransactionBudget({ options: transactionOptions, provider: PROVIDER });\n try {\n await runMapped(() =>\n reserved.unsafe(beginStatement({ isolationLevel: transactionOptions.isolationLevel })),\n );\n if (timeoutText !== undefined) await runMapped(() => reserved.unsafe(timeoutText));\n const txScope = createSavepointScope();\n const txAdapter = createAdapter({\n source: reserved,\n parentMode: \"tx\",\n scope: txScope,\n budget,\n });\n const result = await runRootScope({ scope: txScope, body: () => fn(txAdapter) });\n // An expired budget must never commit, however the callback ended.\n budget.assertUsable({ stage: \"commit\" });\n await runMapped(() => reserved.unsafe(\"COMMIT\"));\n budget.close({ outcome: \"committed\" });\n return result;\n } catch (error) {\n try {\n await reserved.unsafe(\"ROLLBACK\");\n budget.close({ outcome: \"rolled-back\" });\n } catch {\n // The rollback that should have cleaned up failed: the commit state is\n // genuinely unknown. `SET LOCAL` reverts with the transaction, but\n // this session's transaction state can no longer be asserted.\n budget.close({ outcome: \"unknown\" });\n if (budget.totalMs !== null && isTransactionDeadlineError(error)) {\n throw transactionOutcomeUnknownError({\n provider: PROVIDER,\n totalMs: budget.totalMs,\n cause: error,\n });\n }\n }\n throw error;\n } finally {\n reserved.release();\n }\n }\n\n return {\n dialect: DIALECT,\n provider: PROVIDER,\n budgets: BUDGETS,\n get wire(): WireFidelity {\n return activeWire;\n },\n\n async execute(execParams) {\n const turn = scopeTurn({ scope });\n if (turn !== undefined) await turn;\n // After the turn, not before: waiting for a sibling savepoint spends\n // the same budget the statement is about to run against.\n budget?.assertUsable({ stage: \"statement\" });\n await applyEngineBudget();\n return runExecute({ source, ...execParams });\n },\n\n async executeUnsafe(execParams) {\n const turn = scopeTurn({ scope });\n if (turn !== undefined) await turn;\n budget?.assertUsable({ stage: \"statement\" });\n await applyEngineBudget();\n return runExecuteUnsafe({ source, ...execParams });\n },\n\n async transaction<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n transactionOptions?: TransactionOptions,\n ): Promise<T> {\n return parentMode === \"pool\"\n ? transactionViaPool(fn, transactionOptions)\n : transactionViaSavepoint(fn, transactionOptions);\n },\n\n async connect(): Promise<void> {\n if (parentMode !== \"pool\") return;\n const reserved = await runMapped(() => (source as BunInstance).reserve());\n reserved.release();\n },\n\n async disconnect(): Promise<void> {\n if (parentMode !== \"pool\") return;\n await runMapped(() => (source as BunInstance).close());\n instance = null;\n },\n\n formatArrayParam(values: unknown[]): unknown {\n return toPgArrayLiteral(values);\n },\n };\n }\n\n /** Pool-level facade — the bun:sql client is created on first use. */\n function poolAdapter(): DatabaseAdapter {\n return createAdapter({\n source: getSql(),\n parentMode: \"pool\",\n scope: createSavepointScope(),\n });\n }\n\n return {\n dialect: DIALECT,\n provider: PROVIDER,\n budgets: BUDGETS,\n get wire(): WireFidelity {\n return activeWire;\n },\n\n async execute(params) {\n return poolAdapter().execute(params);\n },\n\n async executeUnsafe(params) {\n const control = classifyRawTransactionControl({ text: params.text });\n if (rawSession !== null) {\n if (control === \"close\") {\n const session = rawSession;\n rawSession = null;\n try {\n return await runExecuteUnsafe({ source: session, ...params });\n } finally {\n session.release();\n }\n }\n // A nested raw BEGIN lands here too — postgres treats it as a warning\n // no-op on the open session, exactly like a single connection would.\n return runExecuteUnsafe({ source: rawSession, ...params });\n }\n if (control === \"open\") {\n const reserved = await runMapped(() => getSql().reserve());\n try {\n const result = await runExecuteUnsafe({ source: reserved, ...params });\n rawSession = reserved;\n return result;\n } catch (error) {\n reserved.release();\n throw error;\n }\n }\n return poolAdapter().executeUnsafe(params);\n },\n\n async transaction<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n transactionOptions?: TransactionOptions,\n ): Promise<T> {\n return poolAdapter().transaction(fn, transactionOptions);\n },\n\n async connect(): Promise<void> {\n return poolAdapter().connect();\n },\n\n async disconnect(): Promise<void> {\n if (rawSession !== null) {\n // An abandoned raw transaction must not leak an in-transaction\n // connection; roll it back best-effort before the pool closes.\n const session = rawSession;\n rawSession = null;\n try {\n await session.unsafe(\"ROLLBACK\");\n } catch {\n /* the pool is closing; the session is going away regardless */\n }\n session.release();\n }\n if (instance === null) return;\n const closing = instance;\n instance = null;\n await runMapped(() => closing.close());\n },\n\n formatArrayParam(values: unknown[]): unknown {\n return toPgArrayLiteral(values);\n },\n };\n}\n\n/**\n * Rows affected by a bun:sql statement: the driver attaches `count` (and, on\n * some versions, `affectedRows`) to the returned array; otherwise the number of\n * returned rows is the best available answer.\n */\nfunction readAffectedRows(params: { rows: BunRows }): number {\n const { rows } = params;\n if (typeof rows.count === \"number\") return rows.count;\n if (typeof rows.affectedRows === \"number\") return rows.affectedRows;\n return rows.length;\n}\n\n// ─── Re-exports (driver-error table, params, helpers) ─────────────\n\nexport {\n BUN_SQLSTATE_ERROR_CODES,\n BUN_SQLSTATE_REASONS,\n bunErrorSqlstate,\n mapBunDriverError,\n} from \"./errors.ts\";\nexport { serializeParams, serializeParamsRaw, toPgArrayLiteral } from \"./params.ts\";\nexport { applyStartupOptions, buildStartupOptions } from \"./connection-url.ts\";\nexport type { PlanCacheMode } from \"./connection-url.ts\";\nexport { createSavepointCounter, nextSavepointName } from \"@vibeorm/runtime/adapter-kit\";\nexport type { SavepointCounter } from \"@vibeorm/runtime/adapter-kit\";\nexport { createTemplateCache, templateChunks } from \"./template-cache.ts\";\nexport type { TemplateCache } from \"./template-cache.ts\";\nexport {\n ISOLATION_LEVEL_SQL,\n beginStatement,\n classifyRawTransactionControl,\n refuseNestedTransactionOptions,\n statementTimeoutStatement,\n} from \"./transaction-sql.ts\";\nexport type { RawTransactionControl } from \"./transaction-sql.ts\";\n// ─── EPIC 6: transaction budgets (shared, @vibeorm/runtime/adapter-kit) ───\nexport {\n DEFAULT_DEADLINE_CLOCK,\n engineStatementBudgetMs,\n isTransactionDeadlineError,\n startTransactionBudget,\n transactionClosedError,\n transactionDeadlineError,\n transactionOutcomeUnknownError,\n validateTransactionDeadline,\n} from \"@vibeorm/runtime/adapter-kit\";\nexport type { BudgetStage, DeadlineClock, TransactionBudget, TransactionOutcome } from \"@vibeorm/runtime/adapter-kit\";\n",
|
|
6
6
|
"/**\n * Connection-URL handling for bun:sql.\n *\n * Per-connection PostgreSQL settings (`plan_cache_mode`, `statement_timeout`)\n * travel in the `options` startup parameter, which the server parses for\n * `-c key=value` pairs — so every connection in bun's internal pool inherits\n * them without a per-query round trip.\n *\n * v1 lesson (LEARNINGS.md): bun:sql forwards *unrecognised* URL parameters to\n * the server as runtime configuration, so a libpq client-side option such as\n * `connect_timeout` must never be put in the URL (PostgreSQL rejects it as an\n * unrecognised configuration parameter). Connection timeouts use bun:sql's\n * `connectionTimeout` constructor option instead.\n */\n\nimport { VibeError } from \"@vibeorm/schema\";\n\n/**\n * PostgreSQL plan-cache behaviour for the implicit prepared statements bun:sql\n * creates. `force_custom_plan` replans with the real parameter values (≈0.1 ms\n * per query) and keeps index selection optimal on range/LIKE/skewed filters —\n * `auto` lets PostgreSQL switch to a generic plan after ~5 executions.\n */\nexport type PlanCacheMode = \"auto\" | \"force_custom_plan\" | \"force_generic_plan\";\n\n/**\n * Build the `options` startup string, or `undefined` when nothing needs setting.\n *\n * @throws VibeError `VIBE_VALIDATION` when `statementTimeout` is not a\n * non-negative integer — the value ends up inside the startup string verbatim.\n */\nexport function buildStartupOptions(params: {\n planCacheMode: PlanCacheMode;\n statementTimeout?: number;\n}): string | undefined {\n const { planCacheMode, statementTimeout } = params;\n const parts: string[] = [];\n if (planCacheMode !== \"auto\") parts.push(`-c plan_cache_mode=${planCacheMode}`);\n if (statementTimeout !== undefined) {\n if (!Number.isInteger(statementTimeout) || statementTimeout < 0) {\n throw new VibeError({\n code: \"VIBE_VALIDATION\",\n message: `statementTimeout must be a non-negative integer of milliseconds, received ${String(statementTimeout)}`,\n meta: { statementTimeout },\n });\n }\n parts.push(`-c statement_timeout=${statementTimeout}`);\n }\n return parts.length === 0 ? undefined : parts.join(\" \");\n}\n\n/** Append the `options` startup parameter to a connection URL. */\nexport function applyStartupOptions(params: { url: string; startupOptions: string }): string {\n const { url, startupOptions } = params;\n const separator = url.includes(\"?\") ? \"&\" : \"?\";\n return `${url}${separator}options=${encodeURIComponent(startupOptions)}`;\n}\n",
|
|
7
7
|
"/**\n * Driver-error mapping for `bun:sql`.\n *\n * bun:sql raises `SQL.PostgresError` for server failures and for client-side\n * problems alike. Server failures carry the PostgreSQL SQLSTATE — depending on\n * the Bun version on `code` or on `errno` — while client-side failures use a\n * `ERR_POSTGRES_*` identifier in `code`. Both shapes are read here, so the\n * mapping is stable across Bun versions. Constitution rule 5: only `VibeError`\n * escapes the adapter.\n */\n\nimport { VibeError, type VibeErrorCode } from \"@vibeorm/schema\";\n\n// ─── SQLSTATE table ───────────────────────────────────────────────\n\n/**\n * PostgreSQL SQLSTATE → stable VibeError code. Frozen and mirrored by tests;\n * anything absent from this table (including every `ERR_POSTGRES_*` connection\n * or auth failure) maps to `VIBE_ADAPTER`.\n */\nexport const BUN_SQLSTATE_ERROR_CODES: Readonly<Record<string, VibeErrorCode>> = Object.freeze({\n /** unique_violation */\n \"23505\": \"VIBE_UNIQUE_VIOLATION\",\n /** foreign_key_violation */\n \"23503\": \"VIBE_FK_VIOLATION\",\n /** not_null_violation */\n \"23502\": \"VIBE_VALIDATION\",\n /** check_violation */\n \"23514\": \"VIBE_VALIDATION\",\n /**\n * invalid_text_representation — a value the server cannot parse into the\n * column's type (out-of-range enum value, `\"abc\"` for an integer). Bad input,\n * so the same code sqlite reports for its enum CHECK violation.\n */\n \"22P02\": \"VIBE_VALIDATION\",\n /**\n * insufficient_privilege — a denied table/column privilege, and the SQLSTATE a\n * native row-level-security policy raises when its WITH CHECK refuses a write.\n * Callers identify it by this code, never by message text.\n */\n \"42501\": \"VIBE_PERMISSION_DENIED\",\n /** serialization_failure */\n \"40001\": \"VIBE_TRANSACTION\",\n /** deadlock_detected */\n \"40P01\": \"VIBE_TRANSACTION\",\n /** query_canceled — statement_timeout fired */\n \"57014\": \"VIBE_TRANSACTION\",\n});\n\n/** SQLSTATEs that additionally explain themselves through `meta.reason`. */\nexport const BUN_SQLSTATE_REASONS: Readonly<Record<string, string>> = Object.freeze({\n \"57014\": \"timeout\",\n});\n\n// ─── Reading driver errors ────────────────────────────────────────\n\n/** A PostgreSQL SQLSTATE is exactly five digits/uppercase letters (e.g. `40P01`). */\nconst SQLSTATE_PATTERN = /^[0-9A-Z]{5}$/;\n\nfunction readStringField(params: { source: Record<string, unknown>; key: string }): string | undefined {\n const value = params.source[params.key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/**\n * Extract the SQLSTATE from a bun:sql error, accepting it on either `code` or\n * `errno`. `ERR_POSTGRES_*` identifiers are not SQLSTATEs and yield `undefined`.\n */\nexport function bunErrorSqlstate(params: { error: unknown }): string | undefined {\n const { error } = params;\n if (error === null || typeof error !== \"object\") return undefined;\n const source = error as Record<string, unknown>;\n for (const key of [\"code\", \"errno\"]) {\n const value = readStringField({ source, key });\n if (value !== undefined && SQLSTATE_PATTERN.test(value)) return value;\n }\n return undefined;\n}\n\n// ─── Mapping ──────────────────────────────────────────────────────\n\n/**\n * Map any error thrown by bun:sql onto a `VibeError`.\n *\n * A `VibeError` passes through unchanged, so an error raised deeper inside the\n * ORM (or by a nested adapter call) is never re-wrapped.\n */\nexport function mapBunDriverError(params: { error: unknown }): VibeError {\n const { error } = params;\n if (error instanceof VibeError) return error;\n\n const source: Record<string, unknown> =\n error !== null && typeof error === \"object\" ? (error as Record<string, unknown>) : {};\n const sqlstate = bunErrorSqlstate({ error });\n const code: VibeErrorCode =\n (sqlstate === undefined ? undefined : BUN_SQLSTATE_ERROR_CODES[sqlstate]) ?? \"VIBE_ADAPTER\";\n\n const meta: Record<string, unknown> = {};\n if (sqlstate !== undefined) meta.sqlstate = sqlstate;\n const constraint = readStringField({ source, key: \"constraint\" });\n if (constraint !== undefined) meta.constraint = constraint;\n const table = readStringField({ source, key: \"table\" });\n if (table !== undefined) meta.table = table;\n const column = readStringField({ source, key: \"column\" });\n if (column !== undefined) meta.column = column;\n const reason = sqlstate === undefined ? undefined : BUN_SQLSTATE_REASONS[sqlstate];\n if (reason !== undefined) meta.reason = reason;\n // Keep bun's own identifier when it is not a SQLSTATE — it is the only clue\n // a connection/auth/protocol failure carries.\n const driverCode = readStringField({ source, key: \"code\" });\n if (driverCode !== undefined && driverCode !== sqlstate) meta.driverCode = driverCode;\n\n const message =\n readStringField({ source, key: \"message\" }) ??\n (typeof error === \"string\" ? error : \"unknown bun:sql driver error\");\n\n return new VibeError({ code, message, meta, cause: error });\n}\n\n/** Run a driver call, mapping anything it throws onto a `VibeError`. */\nexport async function runMapped<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n throw mapBunDriverError({ error });\n }\n}\n",
|
|
8
8
|
"/**\n * Parameter serialization for bun:sql.\n *\n * Verified against Bun 1.3 (re-verified on 1.3.14; `tests/live.test.ts` and\n * the notes below):\n * - a plain object or array bound to a `json`/`jsonb` column is JSON-encoded by\n * bun:sql itself — encoding it here as well double-encodes it and stores a\n * JSON *string* (`jsonb_typeof` = `\"string\"`), so the ORM path must not touch it;\n * - a plain JS array bound to a scalar-list column (`text[]`, `int[]`) is NOT\n * turned into a PostgreSQL array literal by bun:sql — it arrives as `a,b` and\n * the server rejects it with `malformed array literal`. Scalar lists therefore\n * have to be pre-rendered with {@link toPgArrayLiteral}, which is exactly what\n * the adapter's `formatArrayParam` returns.\n *\n * Hence the split (LEARNINGS.md): the ORM path passes values through (scalar\n * lists already arrived as literal strings), while the raw path renders plain JS\n * arrays as array literals so `db.$queryRawUnsafe('… = ANY($1)', [1, 2, 3])`\n * matches rows.\n */\n\nimport { VibeError } from \"@vibeorm/schema\";\n\n// ─── PostgreSQL array literals ────────────────────────────────────\n\n/** Quote and escape one array element: `\"` and `\\` are the special characters. */\nfunction quoteElement(value: string): string {\n return `\"${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * Render a JS array as a PostgreSQL array literal string.\n *\n * Element handling:\n * - `null` / `undefined` → unquoted `NULL`\n * - `number` / `bigint` / `boolean` → unquoted primitive\n * - `Date` → quoted ISO-8601 (PostgreSQL cannot parse `String(date)`)\n * - `string` → quoted, with `\"` and `\\` escaped (so commas, braces and quotes\n * inside an element are safe)\n * - any other object, **including a nested array** → quoted `JSON.stringify`,\n * which is what a `Json[]` scalar list needs (PostgreSQL scalar lists are\n * one-dimensional, so a nested array is a JSON value, not a matrix)\n * - binary (`Uint8Array` / `ArrayBuffer`) → unsupported, throws\n *\n * @throws VibeError `VIBE_VALIDATION` for binary elements.\n */\nexport function toPgArrayLiteral(values: readonly unknown[]): string {\n const elements = values.map((value) => {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"number\" || typeof value === \"bigint\" || typeof value === \"boolean\") {\n return String(value);\n }\n if (value instanceof Date) return quoteElement(value.toISOString());\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {\n throw new VibeError({\n code: \"VIBE_VALIDATION\",\n message: \"binary values are not supported inside a postgres array literal\",\n meta: { driver: \"bun:sql\" },\n });\n }\n if (typeof value === \"string\") return quoteElement(value);\n if (typeof value === \"object\") return quoteElement(JSON.stringify(value));\n return quoteElement(String(value));\n });\n return `{${elements.join(\",\")}}`;\n}\n\n// ─── Serialization ────────────────────────────────────────────────\n\n/**\n * `Date` → UTC ISO-8601 text (`2026-03-08T19:38:08.538Z`), the same spelling\n * the array literal above uses.\n *\n * bun:sql serializes a `Date` by the parameter's RESOLVED postgres type\n * (LEARNINGS): fine for `timestamp`/`timestamptz` (UTC text), but a `date`\n * parameter gets `Date#toString()` — `Sun Mar 08 2026 23:30:00 GMT+0000\n * (Coordinated Universal Time)` — which the server rejects in every host TZ\n * (live on Bun 1.4.3: `invalid input syntax for type date` under UTC, `time\n * zone \"gmt-0400\" not recognized` under America/New_York). The ISO text\n * parses for all three, and pins the UTC wall-clock contract the codec table\n * and the other postgres adapters share. Dates the ISO form cannot spell\n * (invalid, BC, beyond year 9999) keep the driver's serializer.\n */\nexport function serializeDate(params: { value: Date }): unknown {\n const { value } = params;\n if (Number.isNaN(value.getTime())) return value;\n const year = value.getUTCFullYear();\n if (year < 1 || year > 9999) return value;\n return value.toISOString();\n}\n\n/**\n * ORM hot path: pass every value straight to bun:sql, except `Date`\n * ({@link serializeDate}).\n *\n * Scalar lists already arrived as array-literal strings from\n * `formatArrayParam`, and bun:sql JSON-encodes objects and arrays for\n * `json`/`jsonb` columns by itself — re-encoding here would store a\n * double-encoded JSON string.\n */\nexport function serializeParams(params: { values: readonly unknown[] }): unknown[] {\n return params.values.map((value) => (value instanceof Date ? serializeDate({ value }) : value));\n}\n\n/**\n * Raw path: render plain JS arrays as PostgreSQL array literals so\n * `db.$queryRawUnsafe('… WHERE \"id\" = ANY($1)', [1, 2, 3])` matches rows;\n * everything else (objects included) goes to bun:sql untouched.\n *\n * Trade-off (v1 lesson): binding a JS array **into** a `jsonb` column from a raw\n * query means calling `JSON.stringify` yourself.\n */\nexport function serializeParamsRaw(params: { values: readonly unknown[] }): unknown[] {\n return params.values.map((value) => {\n if (Array.isArray(value)) return toPgArrayLiteral(value);\n if (value instanceof Date) return serializeDate({ value });\n return value;\n });\n}\n",
|
|
9
|
-
"/**\n * Transaction budgets — the total-deadline clock and the handle-closure gate.\n *\n * BYTE-IDENTICAL in all six adapter packages, exactly like `savepoint-gate.ts`:\n * adapters depend on `@vibeorm/runtime` for TYPES only, so a shared value\n * module there would invert the dependency direction, and `@vibeorm/schema` is\n * the IR package, not a home for a transaction clock. Keep the six copies in\n * lockstep — a divergence here is 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 type {\n TransactionDeadlineEnforcement,\n TransactionDeadlineSupport,\n TransactionOptions,\n} from \"@vibeorm/runtime\";\nimport { VibeError } from \"@vibeorm/schema\";\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",
|
|
10
|
-
"/**\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",
|
|
11
|
-
"/**\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",
|
|
12
9
|
"/**\n * Synthetic tagged-template cache — bun:sql's prepared-statement path.\n *\n * bun:sql only creates a *named* prepared statement (one PostgreSQL keeps a\n * plan for) when the query arrives as a tagged template. Generated SQL is a\n * plain string, so with `preparedStatements: true` the adapter turns each SQL\n * text into a synthetic `TemplateStringsArray` — split at its `$1`, `$2`, …\n * placeholders — and reuses that same object identity for every execution.\n *\n * A tagged template binds its values POSITIONALLY, one per gap, so the split\n * has to keep two things a plain `text.split(/\\$\\d+/)` throws away (F19):\n *\n * - **which** placeholder each gap is. `SELECT $2, $1` has to bind\n * `values[1]` then `values[0]`, and a repeated `$1` needs its value bound at\n * every occurrence — otherwise the statement silently returns other rows, or\n * reaches the server with too few parameters and fails to parse.\n * - **where** a `$n` is not a placeholder at all: inside a string literal, a\n * quoted identifier, a line or block comment, or a dollar-quoted body. A\n * split there tears the literal apart and produces invalid SQL.\n *\n * The cache is LRU-bounded so a long-running process never grows it without\n * limit.\n */\n\nimport { VibeError } from \"@vibeorm/schema\";\n\n/** A SQL text split for bun:sql, with the placeholder index behind each gap. */\nexport type PreparedTemplate = {\n /** The synthetic template; stable by identity so bun:sql can cache its plan. */\n readonly template: TemplateStringsArray;\n /** 1-based `$n` for each gap, in TEXT order (`SELECT $2, $1` → `[2, 1]`). */\n readonly indices: readonly number[];\n};\n\n/** LRU map from SQL text to the synthetic template used to execute it. */\nexport type TemplateCache = {\n /** Template for `text`, creating one on first sight. Stable by identity. */\n getTemplate(params: { text: string }): PreparedTemplate;\n /** Number of texts currently held — diagnostics and tests. */\n size(): number;\n};\n\n// ─── Scanning ─────────────────────────────────────────────────────\n\n/** Is this character part of an unquoted SQL identifier? */\nfunction isIdentChar(char: string | undefined): boolean {\n if (char === undefined) return false;\n return /[A-Za-z0-9_]/.test(char);\n}\n\n/**\n * Index just past a quoted run starting at `start` (`'…'` or `\"…\"`). A doubled\n * quote (`''`, `\"\"`) continues the run — postgres' own escape. A backslash\n * escapes the next character ONLY in an `E'…'` string; with the default\n * `standard_conforming_strings = on` a backslash inside an ordinary literal is\n * just a backslash, and treating it as an escape would run past the literal's\n * real end.\n */\nfunction skipQuoted(text: string, start: number, quote: string): number {\n const escaping =\n quote === \"'\" && (text[start - 1] === \"e\" || text[start - 1] === \"E\") && !isIdentChar(text[start - 2]);\n let index = start + 1;\n while (index < text.length) {\n const char = text[index];\n if (escaping && char === \"\\\\\") {\n index += 2;\n continue;\n }\n if (char === quote) {\n if (text[index + 1] === quote) {\n index += 2;\n continue;\n }\n return index + 1;\n }\n index += 1;\n }\n return text.length; // unterminated — the driver reports it, not this scanner\n}\n\n/** Index just past a block comment, honouring postgres' nesting. */\nfunction skipBlockComment(text: string, start: number): number {\n let depth = 0;\n let index = start;\n while (index < text.length) {\n if (text[index] === \"/\" && text[index + 1] === \"*\") {\n depth += 1;\n index += 2;\n continue;\n }\n if (text[index] === \"*\" && text[index + 1] === \"/\") {\n depth -= 1;\n index += 2;\n if (depth === 0) return index;\n continue;\n }\n index += 1;\n }\n return text.length;\n}\n\n/**\n * Index just past a dollar-quoted body (`$$…$$`, `$tag$…$tag$`) starting at\n * `start`, or `-1` when no dollar quote opens there. `$1` never matches: a tag\n * has to start with a letter or underscore.\n */\nfunction skipDollarQuoted(text: string, start: number): number {\n const opener = /^\\$(?:[A-Za-z_][A-Za-z0-9_]*)?\\$/.exec(text.slice(start));\n if (opener === null) return -1;\n const tag = opener[0];\n const close = text.indexOf(tag, start + tag.length);\n return close === -1 ? text.length : close + tag.length;\n}\n\n/**\n * Split `text` at its real `$n` placeholders. `chunks.length` is always\n * `indices.length + 1`, which is exactly the shape a tagged template needs.\n */\nexport function scanPlaceholders(params: { text: string }): PreparedTemplate {\n const { text } = params;\n const chunks: string[] = [];\n const indices: number[] = [];\n let chunkStart = 0;\n let index = 0;\n\n while (index < text.length) {\n const char = text[index];\n if (char === \"'\" || char === '\"') {\n index = skipQuoted(text, index, char);\n continue;\n }\n if (char === \"-\" && text[index + 1] === \"-\") {\n const newline = text.indexOf(\"\\n\", index);\n index = newline === -1 ? text.length : newline + 1;\n continue;\n }\n if (char === \"/\" && text[index + 1] === \"*\") {\n index = skipBlockComment(text, index);\n continue;\n }\n if (char === \"$\") {\n const dollarEnd = skipDollarQuoted(text, index);\n if (dollarEnd !== -1) {\n index = dollarEnd;\n continue;\n }\n let digits = index + 1;\n while (digits < text.length && text[digits] !== undefined && /[0-9]/.test(text[digits] as string)) digits += 1;\n if (digits > index + 1) {\n chunks.push(text.slice(chunkStart, index));\n indices.push(Number(text.slice(index + 1, digits)));\n chunkStart = digits;\n index = digits;\n continue;\n }\n }\n index += 1;\n }\n\n chunks.push(text.slice(chunkStart));\n const template = Object.assign(chunks, { raw: chunks }) as unknown as TemplateStringsArray;\n return { template, indices };\n}\n\n/**\n * Split a SQL text on `$n` placeholders into the literal chunks around them.\n *\n * Kept for callers that only want the chunks; it is quote-, comment- and\n * dollar-quote-aware through {@link scanPlaceholders}, so `'$1'` inside a\n * string literal is NOT a split point.\n */\nexport function templateChunks(params: { text: string }): string[] {\n return [...scanPlaceholders(params).template];\n}\n\n// ─── Binding ──────────────────────────────────────────────────────\n\n/**\n * The values to hand a synthetic template, in gap order: `$n` picks\n * `values[n - 1]`, a repeated placeholder repeats its value.\n *\n * A `$n` with no matching value is REFUSED (`VIBE_VALIDATION`) rather than\n * bound to `undefined` — misbinding is exactly the failure mode F19 records.\n */\nexport function bindTemplateValues(params: {\n text: string;\n indices: readonly number[];\n values: readonly unknown[];\n}): unknown[] {\n const { text, indices, values } = params;\n return indices.map((placeholder) => {\n if (placeholder < 1 || placeholder > values.length) {\n throw new VibeError({\n code: \"VIBE_VALIDATION\",\n message: `bun:sql prepared statement references $${placeholder} but only ${values.length} parameter(s) were given`,\n meta: { text, placeholder, provided: values.length },\n });\n }\n return values[placeholder - 1];\n });\n}\n\n// ─── Cache ────────────────────────────────────────────────────────\n\n/**\n * Create a template cache holding at most `max` texts (least recently used\n * evicted first).\n */\nexport function createTemplateCache(params: { max: number }): TemplateCache {\n const { max } = params;\n const templates = new Map<string, PreparedTemplate>();\n\n return {\n getTemplate(templateParams: { text: string }): PreparedTemplate {\n const { text } = templateParams;\n const existing = templates.get(text);\n if (existing !== undefined) {\n // Re-insert to mark most-recently-used.\n templates.delete(text);\n templates.set(text, existing);\n return existing;\n }\n const prepared = scanPlaceholders({ text });\n if (templates.size >= max) {\n const oldest = templates.keys().next().value;\n if (oldest !== undefined) templates.delete(oldest);\n }\n templates.set(text, prepared);\n return prepared;\n },\n\n size(): number {\n return templates.size;\n },\n };\n}\n",
|
|
13
10
|
"/**\n * Transaction-control SQL text (postgres dialect, bun:sql flavour).\n *\n * Used by the reserved-connection path, which issues `BEGIN` itself so that\n * isolation level and statement timeout can be applied — bun:sql's\n * `sql.begin(fn)` fast path takes no such options.\n */\n\nimport type { IsolationLevel, TransactionOptions } from \"@vibeorm/runtime\";\nimport { VibeError } from \"@vibeorm/schema\";\n\n/** VibeORM isolation level → PostgreSQL isolation level keyword. */\nexport const ISOLATION_LEVEL_SQL: Readonly<Record<IsolationLevel, string>> = Object.freeze({\n ReadCommitted: \"READ COMMITTED\",\n RepeatableRead: \"REPEATABLE READ\",\n Serializable: \"SERIALIZABLE\",\n});\n\n/** `BEGIN`, with an `ISOLATION LEVEL` clause when the caller asked for one. */\nexport function beginStatement(params: { isolationLevel?: IsolationLevel }): string {\n const { isolationLevel } = params;\n return isolationLevel === undefined\n ? \"BEGIN\"\n : `BEGIN ISOLATION LEVEL ${ISOLATION_LEVEL_SQL[isolationLevel]}`;\n}\n\n/**\n * `SET LOCAL statement_timeout = <ms>` — transaction-scoped, so PostgreSQL\n * cancels an over-long statement with SQLSTATE 57014 (mapped to\n * `VIBE_TRANSACTION` with `meta.reason = \"timeout\"`).\n *\n * @throws VibeError `VIBE_VALIDATION` when the timeout is not a non-negative\n * integer — the value is interpolated into SQL, so it is never trusted blindly.\n */\nexport function statementTimeoutStatement(params: { timeout: number }): string {\n const { timeout } = params;\n if (!Number.isInteger(timeout) || timeout < 0) {\n throw new VibeError({\n code: \"VIBE_VALIDATION\",\n message: `transaction timeout must be a non-negative integer of milliseconds, received ${String(timeout)}`,\n meta: { timeout },\n });\n }\n return `SET LOCAL statement_timeout = ${timeout}`;\n}\n\n// ─── Raw transaction control (session affinity) ─────────────────\n\n/** How a raw statement steers the adapter's session-affine raw transaction. */\nexport type RawTransactionControl = \"open\" | \"close\" | null;\n\nconst RAW_OPEN_PATTERN: RegExp = /^\\s*(?:begin|start\\s+transaction)\\b[^;]*;?\\s*$/i;\nconst RAW_CLOSE_PATTERN: RegExp = /^\\s*(?:commit|end|rollback|abort)(?:\\s+(?:transaction|work))?\\s*;?\\s*$/i;\n\n/**\n * Classify a raw statement as transaction control.\n *\n * @vibeorm/migrate drives transactional DDL by sending literal `BEGIN` /\n * `COMMIT` / `ROLLBACK` through its stateless `SqlExecutor` — sound only when\n * every statement in between rides the SAME connection. The adapter uses this\n * to pin one connection for the whole raw transaction (\"open\" reserves,\n * \"close\" releases). On a pooled bun:sql instance an unpinned `BEGIN` is\n * refused outright by the driver (`ERR_POSTGRES_UNSAFE_TRANSACTION`); other\n * pool drivers would only work by checkout luck.\n *\n * Deliberately strict: only PURE single-statement control text matches\n * (`BEGIN`, `BEGIN ISOLATION LEVEL …;`, `COMMIT`, `ROLLBACK WORK`, `END`,\n * `ABORT`). Compound scripts, `ROLLBACK TO SAVEPOINT`, two-phase\n * `COMMIT PREPARED` and `COMMIT AND CHAIN` (which keeps a transaction open)\n * never engage the pinning.\n */\nexport function classifyRawTransactionControl(params: { text: string }): RawTransactionControl {\n if (RAW_OPEN_PATTERN.test(params.text)) return \"open\";\n if (RAW_CLOSE_PATTERN.test(params.text)) return \"close\";\n return null;\n}\n\n// ─── Nested transaction options (the cross-adapter contract) ──────\n\n/**\n * Refuse options on a NESTED `transaction()` call — the same contract on every\n * adapter (see the `DatabaseAdapter.transaction` JSDoc in @vibeorm/runtime):\n * a nested transaction is a SAVEPOINT, and a savepoint can neither change the\n * isolation level of the transaction it joins nor enforce its own timeout.\n * Silently dropping the option (the pre-#3 behaviour) hid exactly that.\n *\n * @throws VibeError `VIBE_VALIDATION` when `isolationLevel` or `timeout` is\n * 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"
|
|
14
11
|
],
|
|
15
|
-
"mappings": "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",
|
|
16
|
-
"debugId": "
|
|
12
|
+
"mappings": "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",
|
|
13
|
+
"debugId": "70944EEE52F737AB64756E2164756E21",
|
|
17
14
|
"names": []
|
|
18
15
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeorm/adapter-bun",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "bun:sql (Postgres) adapter for VibeORM v2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"orm",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"bun": ">=1.2.0"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@vibeorm/runtime": "2.0.
|
|
44
|
+
"@vibeorm/runtime": "2.0.2",
|
|
45
45
|
"@vibeorm/schema": "2.0.0",
|
|
46
|
-
"@vibeorm/sql": "2.0.
|
|
46
|
+
"@vibeorm/sql": "2.0.2"
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public"
|
package/dist/savepoint-gate.d.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Savepoint lifetimes inside one top-level transaction (F14).
|
|
3
|
-
*
|
|
4
|
-
* A savepoint stack lives on ONE connection: `ROLLBACK TO SAVEPOINT s` undoes
|
|
5
|
-
* everything done after `s`, including work a LATER savepoint already released.
|
|
6
|
-
* Two `transaction()` callbacks opened from the same handle and overlapping in
|
|
7
|
-
* time therefore share that one stack, and the earlier one's rollback silently
|
|
8
|
-
* erases the later one's already committed work. Unique savepoint names do not
|
|
9
|
-
* help — the names never collided, the lifetimes did.
|
|
10
|
-
*
|
|
11
|
-
* The rule enforced here, on every handle of a transaction:
|
|
12
|
-
*
|
|
13
|
-
* > A handle runs when nothing deeper than itself is open. Otherwise it waits
|
|
14
|
-
* > for the innermost open savepoint to settle — unless the call is being made
|
|
15
|
-
* > from INSIDE that savepoint's own callback, which is genuine nesting and
|
|
16
|
-
* > proceeds immediately.
|
|
17
|
-
*
|
|
18
|
-
* The "from inside" test is an {@link AsyncLocalStorage} lookup, so the common
|
|
19
|
-
* nesting shapes never wait on themselves: a child opened from its parent's
|
|
20
|
-
* callback, and the parent handle used from within an open child's callback,
|
|
21
|
-
* both proceed. Only genuinely concurrent siblings serialize.
|
|
22
|
-
*
|
|
23
|
-
* Not covered: a callback that awaits a sibling it did not start. That
|
|
24
|
-
* arrangement asks for two savepoints to be open at once, which is exactly what
|
|
25
|
-
* loses work; it now blocks instead. Deliberate — see the notes for this fix.
|
|
26
|
-
*/
|
|
27
|
-
import { type SavepointCounter } from "./savepoints.ts";
|
|
28
|
-
/**
|
|
29
|
-
* One handle's position in the savepoint stack of a top-level transaction.
|
|
30
|
-
* `state` is shared by reference across every handle of that transaction.
|
|
31
|
-
*/
|
|
32
|
-
export type SavepointScope = {
|
|
33
|
-
/** Physical savepoint depth; 0 is the top-level transaction itself. */
|
|
34
|
-
readonly depth: number;
|
|
35
|
-
/** Shared state: name allocation plus the innermost open savepoint. */
|
|
36
|
-
readonly state: SavepointState;
|
|
37
|
-
};
|
|
38
|
-
/** Mutable state shared by every scope of one top-level transaction. */
|
|
39
|
-
export type SavepointState = {
|
|
40
|
-
/** Savepoint name counter (shared, so names never collide). */
|
|
41
|
-
readonly counter: SavepointCounter;
|
|
42
|
-
/** The innermost savepoint currently open, or `null` when none is. */
|
|
43
|
-
open: OpenSavepoint | null;
|
|
44
|
-
};
|
|
45
|
-
/** An open savepoint: its handle, its name, and when it finished. */
|
|
46
|
-
type OpenSavepoint = {
|
|
47
|
-
readonly scope: SavepointScope;
|
|
48
|
-
readonly name: string;
|
|
49
|
-
readonly parent: OpenSavepoint | null;
|
|
50
|
-
readonly settled: Promise<void>;
|
|
51
|
-
readonly settle: () => void;
|
|
52
|
-
};
|
|
53
|
-
/** Fresh scope for one top-level transaction: depth 0, nothing open. */
|
|
54
|
-
export declare function createSavepointScope(): SavepointScope;
|
|
55
|
-
/**
|
|
56
|
-
* Run a top-level transaction callback inside its scope's async context, so
|
|
57
|
-
* nested calls made from it can be told apart from calls made inside an open
|
|
58
|
-
* child.
|
|
59
|
-
*/
|
|
60
|
-
export declare function runRootScope<T>(params: {
|
|
61
|
-
scope: SavepointScope;
|
|
62
|
-
body: () => Promise<T>;
|
|
63
|
-
}): Promise<T>;
|
|
64
|
-
/**
|
|
65
|
-
* The wait a statement on `scope` owes before it may run, or `undefined` when
|
|
66
|
-
* it may run now. Returning `undefined` keeps the uncontended path — nothing
|
|
67
|
-
* deeper open — free of an extra promise and microtask.
|
|
68
|
-
*/
|
|
69
|
-
export declare function scopeTurn(params: {
|
|
70
|
-
scope: SavepointScope;
|
|
71
|
-
}): Promise<void> | undefined;
|
|
72
|
-
/**
|
|
73
|
-
* Open a nested savepoint under `scope`, run `body` inside it and release it —
|
|
74
|
-
* rolling back to it if `body` throws, exactly as before this gate existed.
|
|
75
|
-
*
|
|
76
|
-
* `execute` runs the savepoint control SQL (already wrapped in the adapter's
|
|
77
|
-
* own driver-error mapping). Omit it when the driver manages the savepoint
|
|
78
|
-
* itself (bun:sql's `savepoint()`), in which case only the lifetime is gated.
|
|
79
|
-
*/
|
|
80
|
-
export declare function runNestedSavepoint<T>(params: {
|
|
81
|
-
readonly scope: SavepointScope;
|
|
82
|
-
readonly execute?: (statement: string) => Promise<unknown> | unknown;
|
|
83
|
-
readonly body: (scope: SavepointScope) => Promise<T>;
|
|
84
|
-
}): Promise<T>;
|
|
85
|
-
export {};
|
|
86
|
-
//# sourceMappingURL=savepoint-gate.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"savepoint-gate.d.ts","sourceRoot":"","sources":["../src/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"}
|
package/dist/savepoints.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Savepoint naming for nested transactions.
|
|
3
|
-
*
|
|
4
|
-
* v1 lesson (LEARNINGS.md): the counter is shared **by reference** across every
|
|
5
|
-
* adapter created for one top-level transaction, so sibling and deeply nested
|
|
6
|
-
* savepoints can never collide on a name.
|
|
7
|
-
*/
|
|
8
|
-
/** Mutable counter shared by reference across one top-level transaction. */
|
|
9
|
-
export type SavepointCounter = {
|
|
10
|
-
n: number;
|
|
11
|
-
};
|
|
12
|
-
/** Fresh counter — one per top-level transaction. */
|
|
13
|
-
export declare function createSavepointCounter(): SavepointCounter;
|
|
14
|
-
/**
|
|
15
|
-
* Allocate the next savepoint name (`vibeorm_sp_0`, `vibeorm_sp_1`, …) and
|
|
16
|
-
* advance the shared counter. The name is an identifier by construction, so it
|
|
17
|
-
* is safe to interpolate into `SAVEPOINT` / `RELEASE` / `ROLLBACK TO` SQL.
|
|
18
|
-
*/
|
|
19
|
-
export declare function nextSavepointName(params: {
|
|
20
|
-
counter: SavepointCounter;
|
|
21
|
-
}): string;
|
|
22
|
-
//# sourceMappingURL=savepoints.d.ts.map
|
package/dist/savepoints.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"savepoints.d.ts","sourceRoot":"","sources":["../src/savepoints.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GAAG;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C,qDAAqD;AACrD,wBAAgB,sBAAsB,IAAI,gBAAgB,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,gBAAgB,CAAA;CAAE,GAAG,MAAM,CAE/E"}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Transaction budgets — the total-deadline clock and the handle-closure gate.
|
|
3
|
-
*
|
|
4
|
-
* BYTE-IDENTICAL in all six adapter packages, exactly like `savepoint-gate.ts`:
|
|
5
|
-
* adapters depend on `@vibeorm/runtime` for TYPES only, so a shared value
|
|
6
|
-
* module there would invert the dependency direction, and `@vibeorm/schema` is
|
|
7
|
-
* the IR package, not a home for a transaction clock. Keep the six copies in
|
|
8
|
-
* lockstep — a divergence here is a silent per-engine behaviour difference.
|
|
9
|
-
*
|
|
10
|
-
* WHAT A DEADLINE IS, AND IS NOT
|
|
11
|
-
*
|
|
12
|
-
* `TransactionOptions.timeout` is unchanged: a PER-STATEMENT engine-side bound.
|
|
13
|
-
* `TransactionOptions.deadline` is new and different — a TOTAL wall-clock bound
|
|
14
|
-
* on one top-level transaction. Its clock starts immediately before `BEGIN` is
|
|
15
|
-
* sent, so connection acquisition (which has its own budget on the pooled
|
|
16
|
-
* adapters) is deliberately NOT counted.
|
|
17
|
-
*
|
|
18
|
-
* Enforcement is never `Promise.race` over a statement that keeps running:
|
|
19
|
-
*
|
|
20
|
-
* - `"between-statements"` (the default, and all six adapters can deliver it):
|
|
21
|
-
* before every statement, every nested `transaction()` and the `COMMIT`, an
|
|
22
|
-
* expired budget refuses. The statement is never sent and the transaction is
|
|
23
|
-
* rolled back. A statement ALREADY IN FLIGHT is not interrupted.
|
|
24
|
-
* - `"cancel-running-statements"` (postgres servers only): additionally hands
|
|
25
|
-
* the engine the remaining budget as `statement_timeout`, so the SERVER
|
|
26
|
-
* cancels an over-long statement. An adapter that cannot do this refuses the
|
|
27
|
-
* request outright rather than quietly delivering the weaker level.
|
|
28
|
-
*
|
|
29
|
-
* JavaScript cannot forcibly stop a running callback. A callback that keeps
|
|
30
|
-
* going past the deadline finds its later database calls refused; work it does
|
|
31
|
-
* outside the database (an HTTP call, an SMS) is not stopped and cannot be.
|
|
32
|
-
* There is no automatic retry: a deadline failure is terminal for that
|
|
33
|
-
* transaction, because external side effects may already have happened.
|
|
34
|
-
*/
|
|
35
|
-
import type { TransactionDeadlineEnforcement, TransactionDeadlineSupport, TransactionOptions } from "@vibeorm/runtime";
|
|
36
|
-
import { VibeError } from "@vibeorm/schema";
|
|
37
|
-
/** Where a budget check happened, reported as `meta.stage`. */
|
|
38
|
-
export type BudgetStage = "statement" | "nested" | "commit";
|
|
39
|
-
/**
|
|
40
|
-
* What is known about a finished transaction. `"unknown"` is a first-class
|
|
41
|
-
* outcome, not a failure to decide: when a rollback itself fails the commit
|
|
42
|
-
* state genuinely cannot be asserted, and claiming "rolled back" would be a lie.
|
|
43
|
-
*/
|
|
44
|
-
export type TransactionOutcome = "committed" | "rolled-back" | "unknown";
|
|
45
|
-
/** Wall clock, injectable so tests are deterministic instead of sleep-timed. */
|
|
46
|
-
export type DeadlineClock = () => number;
|
|
47
|
-
/** The ambient clock, used whenever no seam is injected. */
|
|
48
|
-
export declare const DEFAULT_DEADLINE_CLOCK: DeadlineClock;
|
|
49
|
-
/**
|
|
50
|
-
* One top-level transaction's budget. Nested savepoint handles share this
|
|
51
|
-
* object BY REFERENCE — they never get an independent clock, connection or
|
|
52
|
-
* session setting.
|
|
53
|
-
*/
|
|
54
|
-
export type TransactionBudget = {
|
|
55
|
-
/** The enforcement level in force, or `null` when no deadline was requested. */
|
|
56
|
-
readonly enforcement: TransactionDeadlineEnforcement | null;
|
|
57
|
-
/** The requested total budget in milliseconds, or `null` when none was. */
|
|
58
|
-
readonly totalMs: number | null;
|
|
59
|
-
/** Existing per-statement limit, independent of the total deadline. Zero disables it. */
|
|
60
|
-
readonly statementTimeoutMs: number | null;
|
|
61
|
-
/** Milliseconds left (never negative), or `null` when no deadline is set. */
|
|
62
|
-
remainingMs(): number | null;
|
|
63
|
-
/** True only when a deadline is set and has passed. */
|
|
64
|
-
expired(): boolean;
|
|
65
|
-
/** Refuse a closed handle or an expired budget. Called BEFORE anything is sent. */
|
|
66
|
-
assertUsable(params: {
|
|
67
|
-
stage: BudgetStage;
|
|
68
|
-
}): void;
|
|
69
|
-
/** Record the terminal outcome; the first call wins and later ones are ignored. */
|
|
70
|
-
close(params: {
|
|
71
|
-
outcome: TransactionOutcome;
|
|
72
|
-
}): void;
|
|
73
|
-
/** The recorded outcome, or `null` while the transaction is still open. */
|
|
74
|
-
readonly outcome: TransactionOutcome | null;
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Check `options.deadline` against what this adapter can honestly deliver.
|
|
78
|
-
* Called BEFORE `BEGIN` — a budget this engine cannot honour must never leave
|
|
79
|
-
* a transaction open behind it.
|
|
80
|
-
*
|
|
81
|
-
* @throws VibeError `VIBE_VALIDATION` when `totalMs` is not a positive integer.
|
|
82
|
-
* @throws VibeError `VIBE_UNSUPPORTED_CAPABILITY` when the requested
|
|
83
|
-
* `enforcement` is stronger than `support` — refused, never silently degraded.
|
|
84
|
-
*/
|
|
85
|
-
export declare function validateTransactionDeadline(params: {
|
|
86
|
-
options?: TransactionOptions;
|
|
87
|
-
support: TransactionDeadlineSupport;
|
|
88
|
-
provider: string;
|
|
89
|
-
}): void;
|
|
90
|
-
/**
|
|
91
|
-
* Start the clock for one top-level transaction. Call it immediately before
|
|
92
|
-
* `BEGIN`; {@link validateTransactionDeadline} must already have run.
|
|
93
|
-
*/
|
|
94
|
-
export declare function startTransactionBudget(params: {
|
|
95
|
-
options?: TransactionOptions;
|
|
96
|
-
provider: string;
|
|
97
|
-
clock?: DeadlineClock;
|
|
98
|
-
}): TransactionBudget;
|
|
99
|
-
/**
|
|
100
|
-
* The engine-side bound for the NEXT statement, or `null` when the caller did
|
|
101
|
-
* not buy `"cancel-running-statements"`. Floored at 1 ms: on postgres `0` means
|
|
102
|
-
* "no limit", so a spent budget must never be handed over as a zero.
|
|
103
|
-
*/
|
|
104
|
-
export declare function engineStatementBudgetMs(params: {
|
|
105
|
-
budget: TransactionBudget;
|
|
106
|
-
}): number | null;
|
|
107
|
-
/**
|
|
108
|
-
* The refusal an expired budget raises. `VIBE_TRANSACTION` with a stable
|
|
109
|
-
* `meta.reason` — no SQL text, no parameter values, no credentials.
|
|
110
|
-
*/
|
|
111
|
-
export declare function transactionDeadlineError(params: {
|
|
112
|
-
provider: string;
|
|
113
|
-
stage: BudgetStage;
|
|
114
|
-
totalMs: number;
|
|
115
|
-
overdueMs: number;
|
|
116
|
-
}): VibeError;
|
|
117
|
-
/**
|
|
118
|
-
* The refusal an ESCAPED transaction handle raises — a transactional adapter
|
|
119
|
-
* kept past the end of its transaction. Without this it would run on a
|
|
120
|
-
* connection that is back in the pool, outside any transaction.
|
|
121
|
-
*/
|
|
122
|
-
export declare function transactionClosedError(params: {
|
|
123
|
-
provider: string;
|
|
124
|
-
outcome: TransactionOutcome;
|
|
125
|
-
stage: BudgetStage;
|
|
126
|
-
}): VibeError;
|
|
127
|
-
/**
|
|
128
|
-
* The stable typed outcome for "the deadline expired and the rollback that was
|
|
129
|
-
* supposed to clean up failed too". Promising a rollback here would be false;
|
|
130
|
-
* promising a retry would be worse.
|
|
131
|
-
*
|
|
132
|
-
* `cause` is the CAUSAL error (the deadline refusal), so the reason the
|
|
133
|
-
* transaction was being abandoned survives. The rollback failure itself is
|
|
134
|
-
* reported only as `meta.rollbackFailed`: a raw driver failure can carry
|
|
135
|
-
* statement text, and this error is meant to be logged.
|
|
136
|
-
*/
|
|
137
|
-
export declare function transactionOutcomeUnknownError(params: {
|
|
138
|
-
provider: string;
|
|
139
|
-
totalMs: number;
|
|
140
|
-
cause: unknown;
|
|
141
|
-
}): VibeError;
|
|
142
|
-
/** Whether `error` is this module's deadline refusal (used to pick the cleanup path). */
|
|
143
|
-
export declare function isTransactionDeadlineError(error: unknown): boolean;
|
|
144
|
-
//# sourceMappingURL=transaction-budget.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-budget.d.ts","sourceRoot":"","sources":["../src/transaction-budget.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EACV,8BAA8B,EAC9B,0BAA0B,EAC1B,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,+DAA+D;AAC/D,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE5D;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;AAEzE,gFAAgF;AAChF,MAAM,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC;AAEzC,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,aAAwC,CAAC;AAE9E;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,gFAAgF;IAChF,QAAQ,CAAC,WAAW,EAAE,8BAA8B,GAAG,IAAI,CAAC;IAC5D,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,yFAAyF;IACzF,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,6EAA6E;IAC7E,WAAW,IAAI,MAAM,GAAG,IAAI,CAAC;IAC7B,uDAAuD;IACvD,OAAO,IAAI,OAAO,CAAC;IACnB,mFAAmF;IACnF,YAAY,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE,GAAG,IAAI,CAAC;IACnD,mFAAmF;IACnF,KAAK,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,kBAAkB,CAAA;KAAE,GAAG,IAAI,CAAC;IACrD,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAC7C,CAAC;AAIF;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,OAAO,EAAE,0BAA0B,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAgCP;AAID;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,GAAG,iBAAiB,CAyCpB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CAQ5F;AAID;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,SAAS,CAaZ;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,KAAK,EAAE,WAAW,CAAC;CACpB,GAAG,SAAS,CAUZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,SAAS,CAiBZ;AAED,yFAAyF;AACzF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGlE"}
|