@vibeorm/adapter-pglite 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIhE;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CA2B9E,CAAC;AAEH,4EAA4E;AAC5E,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEnE,CAAC;AAYH;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAKlF;AAID;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CA0B1E;AAED,wEAAwE;AACxE,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMnE"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIhE;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAqC9E,CAAC;AAEH,4EAA4E;AAC5E,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMnE,CAAC;AAYH;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAKlF;AAID;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CA0B1E;AAED,wEAAwE;AACxE,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMnE"}
package/dist/index.d.ts CHANGED
@@ -65,9 +65,9 @@ export { PGLITE_SQLSTATE_ERROR_CODES, PGLITE_SQLSTATE_REASONS, mapPgliteDriverEr
65
65
  export { PgliteArrayParam, serializeParams, serializeParamsRaw, toPgArrayLiteral } from "./params.ts";
66
66
  export { createOperationQueue } from "./queue.ts";
67
67
  export type { OperationQueue } from "./queue.ts";
68
- export { createSavepointCounter, nextSavepointName } from "./savepoints.ts";
69
- export type { SavepointCounter } from "./savepoints.ts";
68
+ export { createSavepointCounter, nextSavepointName } from "@vibeorm/runtime/adapter-kit";
69
+ export type { SavepointCounter } from "@vibeorm/runtime/adapter-kit";
70
70
  export { ISOLATION_LEVEL_SQL, refuseNestedTransactionOptions, setIsolationLevelStatement, } from "./transaction-sql.ts";
71
- export { DEFAULT_DEADLINE_CLOCK, engineStatementBudgetMs, isTransactionDeadlineError, startTransactionBudget, transactionClosedError, transactionDeadlineError, transactionOutcomeUnknownError, validateTransactionDeadline, } from "./transaction-budget.ts";
72
- export type { BudgetStage, DeadlineClock, TransactionBudget, TransactionOutcome } from "./transaction-budget.ts";
71
+ export { DEFAULT_DEADLINE_CLOCK, engineStatementBudgetMs, isTransactionDeadlineError, startTransactionBudget, transactionClosedError, transactionDeadlineError, transactionOutcomeUnknownError, validateTransactionDeadline, } from "@vibeorm/runtime/adapter-kit";
72
+ export type { BudgetStage, DeadlineClock, TransactionBudget, TransactionOutcome } from "@vibeorm/runtime/adapter-kit";
73
73
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAEV,eAAe,EAIhB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAA8B,MAAM,sBAAsB,CAAC;AAoBpG,yCAAyC;AACzC,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAClC;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC,CAAC;AAsGF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,eAAe,CA0R7E;AAID,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACtG,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EACL,mBAAmB,EACnB,8BAA8B,EAC9B,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC1B,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,8BAA8B,EAC9B,2BAA2B,GAC5B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAEV,eAAe,EAIhB,MAAM,kBAAkB,CAAC;AAY1B,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAA8B,MAAM,sBAAsB,CAAC;AAQpG,yCAAyC;AACzC,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAClC;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC,CAAC;AAsGF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,eAAe,CA0R7E;AAID,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACtG,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACzF,YAAY,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,8BAA8B,EAC9B,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAE9B,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,24 +2,39 @@
2
2
  var __require = import.meta.require;
3
3
 
4
4
  // packages/adapter-pglite/src/index.ts
5
- import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
6
- import { VibeError as VibeError5 } from "@vibeorm/schema";
5
+ import { AsyncLocalStorage } from "async_hooks";
6
+ import { VibeError as VibeError4 } from "@vibeorm/schema";
7
+ import {
8
+ createSavepointScope,
9
+ runNestedSavepoint,
10
+ runRootScope,
11
+ scopeTurn,
12
+ startTransactionBudget,
13
+ validateTransactionDeadline
14
+ } from "@vibeorm/runtime/adapter-kit";
7
15
 
8
16
  // packages/adapter-pglite/src/errors.ts
9
17
  import { VibeError } from "@vibeorm/schema";
10
18
  var PGLITE_SQLSTATE_ERROR_CODES = Object.freeze({
19
+ "23P01": "VIBE_EXCLUSION_VIOLATION",
11
20
  "23505": "VIBE_UNIQUE_VIOLATION",
12
21
  "23503": "VIBE_FK_VIOLATION",
22
+ "23001": "VIBE_FK_VIOLATION",
13
23
  "23502": "VIBE_VALIDATION",
14
24
  "23514": "VIBE_VALIDATION",
15
25
  "22P02": "VIBE_VALIDATION",
16
26
  "42501": "VIBE_PERMISSION_DENIED",
17
27
  "40001": "VIBE_TRANSACTION",
28
+ "55P03": "VIBE_LOCK_NOT_AVAILABLE",
18
29
  "40P01": "VIBE_TRANSACTION",
19
30
  "57014": "VIBE_TRANSACTION"
20
31
  });
21
32
  var PGLITE_SQLSTATE_REASONS = Object.freeze({
22
- "57014": "timeout"
33
+ "23P01": "exclusion-violation",
34
+ "57014": "timeout",
35
+ "55P03": "lock-not-available",
36
+ "40P01": "deadlock",
37
+ "40001": "serialization-failure"
23
38
  });
24
39
  var SQLSTATE_PATTERN = /^[0-9A-Z]{5}$/;
25
40
  function readStringField(params) {
@@ -142,241 +157,8 @@ function createOperationQueue() {
142
157
  };
143
158
  }
144
159
 
145
- // packages/adapter-pglite/src/savepoint-gate.ts
146
- import { AsyncLocalStorage } from "async_hooks";
147
-
148
- // packages/adapter-pglite/src/savepoints.ts
149
- function createSavepointCounter() {
150
- return { n: 0 };
151
- }
152
- function nextSavepointName(params) {
153
- return `vibeorm_sp_${params.counter.n++}`;
154
- }
155
-
156
- // packages/adapter-pglite/src/savepoint-gate.ts
157
- var CURRENT = new AsyncLocalStorage;
158
- function createSavepointScope() {
159
- return { depth: 0, state: { counter: createSavepointCounter(), open: null } };
160
- }
161
- function runRootScope(params) {
162
- return CURRENT.run(params.scope, params.body);
163
- }
164
- function scopeTurn(params) {
165
- const open = params.scope.state.open;
166
- if (mayProceed({ scope: params.scope, open }))
167
- return;
168
- return waitForTurn({ scope: params.scope });
169
- }
170
- async function runNestedSavepoint(params) {
171
- const { scope, execute, body } = params;
172
- const node = await acquire({ scope });
173
- try {
174
- if (execute !== undefined)
175
- await execute(`SAVEPOINT ${node.name}`);
176
- let result;
177
- try {
178
- result = await CURRENT.run(node.scope, () => body(node.scope));
179
- } catch (error) {
180
- await drainDescendants({ node });
181
- if (execute !== undefined) {
182
- try {
183
- await execute(`ROLLBACK TO SAVEPOINT ${node.name}`);
184
- } catch {}
185
- }
186
- throw error;
187
- }
188
- await drainDescendants({ node });
189
- if (execute !== undefined)
190
- await execute(`RELEASE SAVEPOINT ${node.name}`);
191
- return result;
192
- } finally {
193
- closeNode({ node });
194
- }
195
- }
196
- function mayProceed(params) {
197
- const { scope, open } = params;
198
- if (open === null)
199
- return true;
200
- if (open.scope === scope)
201
- return true;
202
- if (open.scope.depth < scope.depth)
203
- return true;
204
- return CURRENT.getStore() === open.scope;
205
- }
206
- async function waitForTurn(params) {
207
- for (;; ) {
208
- const open = params.scope.state.open;
209
- if (open === null || mayProceed({ scope: params.scope, open }))
210
- return;
211
- await open.settled;
212
- }
213
- }
214
- async function acquire(params) {
215
- const { scope } = params;
216
- for (;; ) {
217
- const open = scope.state.open;
218
- if (mayProceed({ scope, open }))
219
- return pushNode({ scope, parent: open });
220
- await open.settled;
221
- }
222
- }
223
- function pushNode(params) {
224
- const { scope, parent } = params;
225
- const state = scope.state;
226
- let settle = () => {
227
- return;
228
- };
229
- const settled = new Promise((resolve) => {
230
- settle = () => resolve();
231
- });
232
- const node = {
233
- scope: { depth: (parent === null ? 0 : parent.scope.depth) + 1, state },
234
- name: nextSavepointName({ counter: state.counter }),
235
- parent,
236
- settled,
237
- settle
238
- };
239
- state.open = node;
240
- return node;
241
- }
242
- function closeNode(params) {
243
- const { node } = params;
244
- const state = node.scope.state;
245
- if (state.open === node)
246
- state.open = node.parent;
247
- node.settle();
248
- }
249
- async function drainDescendants(params) {
250
- const state = params.node.scope.state;
251
- for (;; ) {
252
- const open = state.open;
253
- if (open === null || open === params.node || open.scope.depth <= params.node.scope.depth)
254
- return;
255
- await open.settled;
256
- }
257
- }
258
-
259
- // packages/adapter-pglite/src/transaction-budget.ts
260
- import { VibeError as VibeError3 } from "@vibeorm/schema";
261
- var DEFAULT_DEADLINE_CLOCK = () => Date.now();
262
- function validateTransactionDeadline(params) {
263
- const { options, support, provider } = params;
264
- const deadline = options?.deadline;
265
- if (deadline === undefined)
266
- return;
267
- if (support === "unsupported") {
268
- throw new VibeError3({
269
- code: "VIBE_UNSUPPORTED_CAPABILITY",
270
- message: `${provider} cannot enforce a transaction deadline \u2014 remove the \`deadline\` option`,
271
- meta: { provider, feature: "transactionDeadline", supported: support }
272
- });
273
- }
274
- if (!Number.isInteger(deadline.totalMs) || deadline.totalMs <= 0) {
275
- throw new VibeError3({
276
- code: "VIBE_VALIDATION",
277
- message: `transaction deadline \`totalMs\` must be a positive integer of milliseconds, received ${String(deadline.totalMs)}`,
278
- meta: { provider, feature: "transactionDeadline", totalMs: deadline.totalMs }
279
- });
280
- }
281
- const requested = deadline.enforcement ?? "between-statements";
282
- if (requested === "cancel-running-statements" && support !== "cancel-running-statements") {
283
- throw new VibeError3({
284
- code: "VIBE_UNSUPPORTED_CAPABILITY",
285
- 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',
286
- meta: { provider, feature: "transactionDeadline", requested, supported: support }
287
- });
288
- }
289
- }
290
- function startTransactionBudget(params) {
291
- const { options, provider } = params;
292
- const clock = params.clock ?? DEFAULT_DEADLINE_CLOCK;
293
- const deadline = options?.deadline;
294
- const totalMs = deadline === undefined ? null : deadline.totalMs;
295
- const enforcement = deadline === undefined ? null : deadline.enforcement ?? "between-statements";
296
- const expiresAt = totalMs === null ? null : clock() + totalMs;
297
- let outcome = null;
298
- const budget = {
299
- enforcement,
300
- totalMs,
301
- statementTimeoutMs: options?.timeout ?? null,
302
- remainingMs() {
303
- return expiresAt === null ? null : Math.max(0, expiresAt - clock());
304
- },
305
- expired() {
306
- return expiresAt !== null && clock() >= expiresAt;
307
- },
308
- assertUsable(assertParams) {
309
- if (outcome !== null) {
310
- throw transactionClosedError({ provider, outcome, stage: assertParams.stage });
311
- }
312
- if (expiresAt !== null && clock() >= expiresAt) {
313
- throw transactionDeadlineError({
314
- provider,
315
- stage: assertParams.stage,
316
- totalMs,
317
- overdueMs: clock() - expiresAt
318
- });
319
- }
320
- },
321
- close(closeParams) {
322
- if (outcome === null)
323
- outcome = closeParams.outcome;
324
- },
325
- get outcome() {
326
- return outcome;
327
- }
328
- };
329
- return budget;
330
- }
331
- function engineStatementBudgetMs(params) {
332
- const { budget } = params;
333
- if (budget.enforcement !== "cancel-running-statements")
334
- return null;
335
- const remaining = budget.remainingMs();
336
- if (remaining === null)
337
- return null;
338
- const totalBound = Math.max(1, Math.ceil(remaining));
339
- return budget.statementTimeoutMs !== null && budget.statementTimeoutMs > 0 ? Math.min(totalBound, budget.statementTimeoutMs) : totalBound;
340
- }
341
- function transactionDeadlineError(params) {
342
- const { provider, stage, totalMs, overdueMs } = params;
343
- const what = stage === "commit" ? "the transaction was rolled back instead of committed" : "the statement was never sent and the transaction is being rolled back";
344
- return new VibeError3({
345
- code: "VIBE_TRANSACTION",
346
- 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.",
347
- meta: { provider, reason: "transaction-deadline", stage, totalMs, overdueMs: Math.max(0, Math.round(overdueMs)) }
348
- });
349
- }
350
- function transactionClosedError(params) {
351
- const { provider, outcome, stage } = params;
352
- return new VibeError3({
353
- code: "VIBE_TRANSACTION",
354
- 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",
355
- meta: { provider, reason: "transaction-closed", outcome, stage }
356
- });
357
- }
358
- function transactionOutcomeUnknownError(params) {
359
- const { provider, totalMs, cause } = params;
360
- return new VibeError3({
361
- code: "VIBE_TRANSACTION",
362
- 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.",
363
- meta: {
364
- provider,
365
- reason: "transaction-outcome-unknown",
366
- outcome: "unknown",
367
- totalMs,
368
- rollbackFailed: true
369
- },
370
- cause
371
- });
372
- }
373
- function isTransactionDeadlineError(error) {
374
- const reason = error?.meta?.reason;
375
- return reason === "transaction-deadline";
376
- }
377
-
378
160
  // packages/adapter-pglite/src/transaction-sql.ts
379
- import { VibeError as VibeError4 } from "@vibeorm/schema";
161
+ import { VibeError as VibeError3 } from "@vibeorm/schema";
380
162
  var ISOLATION_LEVEL_SQL = Object.freeze({
381
163
  ReadCommitted: "READ COMMITTED",
382
164
  RepeatableRead: "REPEATABLE READ",
@@ -405,7 +187,7 @@ function refuseNestedTransactionOptions(params) {
405
187
  meta.timeout = options.timeout;
406
188
  if (options.deadline !== undefined)
407
189
  meta.deadline = options.deadline;
408
- throw new VibeError4({
190
+ throw new VibeError3({
409
191
  code: "VIBE_VALIDATION",
410
192
  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`,
411
193
  meta
@@ -413,6 +195,17 @@ function refuseNestedTransactionOptions(params) {
413
195
  }
414
196
 
415
197
  // packages/adapter-pglite/src/index.ts
198
+ import { createSavepointCounter, nextSavepointName } from "@vibeorm/runtime/adapter-kit";
199
+ import {
200
+ DEFAULT_DEADLINE_CLOCK,
201
+ engineStatementBudgetMs,
202
+ isTransactionDeadlineError,
203
+ startTransactionBudget as startTransactionBudget2,
204
+ transactionClosedError,
205
+ transactionDeadlineError,
206
+ transactionOutcomeUnknownError,
207
+ validateTransactionDeadline as validateTransactionDeadline2
208
+ } from "@vibeorm/runtime/adapter-kit";
416
209
  var TIMESTAMP_OID = 1114;
417
210
  var TIMESTAMP_ARRAY_OID = 1115;
418
211
  var ZONE_LESS_TEXT = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d{1,6})?$/;
@@ -454,7 +247,7 @@ var BUDGETS = Object.freeze({
454
247
  });
455
248
  function pgliteAdapter(options) {
456
249
  if (options?.pglite !== undefined && options.extensions !== undefined) {
457
- throw new VibeError5({
250
+ throw new VibeError4({
458
251
  code: "VIBE_CONFIG",
459
252
  message: "pgliteAdapter: `extensions` applies to an instance the adapter CREATES \u2014 a provided `pglite` instance was already constructed with its own extensions; pass one or the other",
460
253
  meta: { provider: PROVIDER }
@@ -462,10 +255,10 @@ function pgliteAdapter(options) {
462
255
  }
463
256
  const queue = createOperationQueue();
464
257
  const ownsInstance = options?.pglite === undefined;
465
- const txContext = new AsyncLocalStorage2;
258
+ const txContext = new AsyncLocalStorage;
466
259
  function assertNotInsideTransaction() {
467
260
  if (txContext.getStore() === true) {
468
- throw new VibeError5({
261
+ throw new VibeError4({
469
262
  code: "VIBE_TRANSACTION",
470
263
  message: "root client used inside a transaction callback \u2014 use the tx client the callback receives; the root connection would deadlock behind the open transaction",
471
264
  meta: { provider: PROVIDER }
@@ -566,7 +359,7 @@ function pgliteAdapter(options) {
566
359
  async transaction(fn, transactionOptions) {
567
360
  assertNotInsideTransaction();
568
361
  if (transactionOptions?.timeout !== undefined) {
569
- throw new VibeError5({
362
+ throw new VibeError4({
570
363
  code: "VIBE_UNSUPPORTED_CAPABILITY",
571
364
  message: "pglite cannot enforce a transaction timeout: the single-threaded WASM build accepts statement_timeout but never cancels a running statement \u2014 remove the option, or use a postgres server adapter where it is genuinely enforced",
572
365
  meta: { provider: PROVIDER, feature: "transactionTimeout", timeout: transactionOptions.timeout }
@@ -628,12 +421,12 @@ function pgliteAdapter(options) {
628
421
  };
629
422
  }
630
423
  export {
631
- validateTransactionDeadline,
424
+ validateTransactionDeadline2 as validateTransactionDeadline,
632
425
  transactionOutcomeUnknownError,
633
426
  transactionDeadlineError,
634
427
  transactionClosedError,
635
428
  toPgArrayLiteral,
636
- startTransactionBudget,
429
+ startTransactionBudget2 as startTransactionBudget,
637
430
  setIsolationLevelStatement,
638
431
  serializeParamsRaw,
639
432
  serializeParams,
@@ -653,4 +446,4 @@ export {
653
446
  DEFAULT_DEADLINE_CLOCK
654
447
  };
655
448
 
656
- //# debugId=E854C74C7D9581BE64756E2164756E21
449
+ //# debugId=2AB293AB4718A69464756E2164756E21
package/dist/index.js.map CHANGED
@@ -1,17 +1,14 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/index.ts", "../src/errors.ts", "../src/params.ts", "../src/queue.ts", "../src/savepoint-gate.ts", "../src/savepoints.ts", "../src/transaction-budget.ts", "../src/transaction-sql.ts"],
3
+ "sources": ["../src/index.ts", "../src/errors.ts", "../src/params.ts", "../src/queue.ts", "../src/transaction-sql.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * @vibeorm/adapter-pglite — PGlite (in-process PostgreSQL, WASM) adapter for\n * VibeORM v2.\n *\n * PGlite is a *single* embedded connection, so this adapter serializes every\n * operation through one queue — including whole transactions, which hold the\n * queue until they commit or roll back. That makes concurrent client calls safe\n * without a pool, and makes an in-memory instance an honest postgres target for\n * tests (no Docker).\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { VibeError } from \"@vibeorm/schema\";\nimport type {\n AdapterBudgetSupport,\n DatabaseAdapter,\n QueryResult,\n TransactionOptions,\n WireFidelity,\n} from \"@vibeorm/runtime\";\nimport type { Dialect, Provider } from \"@vibeorm/schema\";\nimport type { Extensions, PGliteInterface, ParserOptions, Transaction } from \"@electric-sql/pglite\";\nimport { mapPgliteDriverError, runMapped } from \"./errors.ts\";\nimport { PgliteArrayParam, serializeParams, serializeParamsRaw } from \"./params.ts\";\nimport { createOperationQueue } from \"./queue.ts\";\nimport {\n createSavepointScope,\n runNestedSavepoint,\n runRootScope,\n scopeTurn,\n type SavepointScope,\n} from \"./savepoint-gate.ts\";\nimport {\n startTransactionBudget,\n type TransactionBudget,\n validateTransactionDeadline,\n} from \"./transaction-budget.ts\";\nimport { refuseNestedTransactionOptions, setIsolationLevelStatement } from \"./transaction-sql.ts\";\n\n// ─── Options ──────────────────────────────────────────────────────\n\n/** Options for {@link pgliteAdapter}. */\nexport type PgliteAdapterOptions = {\n /**\n * Directory to persist the database in. Omit for a fresh in-memory database —\n * the usual choice for tests. Prefixes PGlite understands (`idb://`,\n * `memory://`) work here too.\n */\n readonly dataDir?: string;\n /**\n * An already-created PGlite instance to run on (sharing one database across\n * adapters, or reusing a warm instance between test files). The adapter never\n * closes an instance it did not create, so `disconnect()` is a no-op then.\n */\n readonly pglite?: PGliteInterface;\n /**\n * PGlite extension bundles to load into the instance the ADAPTER creates —\n * `{ vector }` from `@electric-sql/pglite-pgvector`, `pg_trgm` from\n * `@electric-sql/pglite/contrib/pg_trgm`, … The bundles still come from\n * their own packages; this option removes the need to construct PGlite\n * yourself just to attach them. Mutually exclusive with `pglite` (that\n * instance was already constructed with its extensions) — passing both\n * throws `VIBE_CONFIG`.\n */\n readonly extensions?: Extensions;\n};\n\n// ─── Internals ────────────────────────────────────────────────────\n\n/** Anything that runs SQL: the PGlite instance itself or an open transaction. */\ntype Queryable = Pick<Transaction, \"query\" | \"exec\">;\n\n// ─── UTC zone-less timestamps ─────────────────────────────────────\n\n/** `timestamp without time zone` and its array form. */\nconst TIMESTAMP_OID = 1114;\nconst TIMESTAMP_ARRAY_OID = 1115;\n\n/** PGlite's text output for a zone-less timestamp: `2026-03-08 19:38:08.538`. */\nconst ZONE_LESS_TEXT = /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,6})?$/;\n\n/**\n * Zone-less timestamp text read as **UTC** — the codec table's\n * `parseDateTimeText` rule (@vibeorm/sql) applied at the driver level, because\n * PGlite hands these columns to the ORM as `Date` objects already\n * (`wire.dateTime: \"native\"` prunes the codec decode). PGlite's own parser is\n * `new Date(text)`, which ECMA-262 reads as host-LOCAL time — while PGlite\n * SERIALIZES a `Date` parameter as UTC (`toISOString()`), so a value did not\n * even round-trip on a non-UTC host. `date` is unaffected (date-only text is\n * UTC midnight under ECMA-262 already). Anything outside the plain form keeps\n * PGlite's parser.\n */\nfunction parseTimestampAsUtc(value: string): unknown {\n if (ZONE_LESS_TEXT.test(value)) {\n const parsed = new Date(`${value.replace(\" \", \"T\").replace(/(\\.\\d{3})\\d+$/, \"$1\")}Z`);\n if (!Number.isNaN(parsed.getTime())) return parsed;\n }\n return new Date(value);\n}\n\nlet utcParsers: ParserOptions | null = null;\n\n/**\n * Per-query parsers (`QueryOptions.parsers`) — never `instance.parsers`, which\n * a caller-supplied instance shares with everyone else. The array parser is\n * PGlite's own (`types.arrayParser`), resolved lazily from the same dynamic\n * import `getInstance` uses, so the WASM module is never loaded just to build\n * this table.\n */\nasync function getUtcParsers(): Promise<ParserOptions> {\n if (utcParsers !== null) return utcParsers;\n const { types } = await import(\"@electric-sql/pglite\");\n utcParsers = {\n [TIMESTAMP_OID]: parseTimestampAsUtc,\n [TIMESTAMP_ARRAY_OID]: (text: string): unknown => types.arrayParser(text, parseTimestampAsUtc, TIMESTAMP_ARRAY_OID),\n };\n return utcParsers;\n}\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 PGlite has passed it back out of `transaction()`.\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\nconst DIALECT: Dialect = \"postgres\";\nconst PROVIDER: Provider = \"pglite\";\n\n/**\n * pglite wire (board #30, live-verified on both execute paths): timestamptz →\n * `Date`, json/jsonb → parsed values, int4/float8 → numbers. (int8 arrives as\n * a native `bigint` here — the BigInt codec passes it through; not declared.)\n */\nconst WIRE: WireFidelity = Object.freeze({ dateTime: \"native\", json: \"parsed\", numbers: \"native\" } as const);\n\n/**\n * Timing budgets this adapter genuinely enforces (EPIC 6).\n *\n * - `acquireTimeout: false` — one in-process WASM instance behind a queue.\n * There is no pool to exhaust.\n * - `statementTimeout: \"unsupported\"` — **PGlite ACCEPTING `statement_timeout`\n * is not support.** The single-threaded WASM build reports the setting back\n * via SHOW and never fires it (board #2, live-verified: `pg_sleep(2)` under a\n * 100 ms timeout runs to completion), which is why the `timeout` option is\n * refused outright below.\n * - `transactionDeadline: \"between-statements\"` — the budget is checked before\n * each statement and before the commit, which PGlite CAN honour because those\n * checks happen in JavaScript. It is not cancellation, for the same\n * single-threaded reason, so `\"cancel-running-statements\"` is refused.\n */\nconst BUDGETS: AdapterBudgetSupport = Object.freeze({\n acquireTimeout: false,\n statementTimeout: \"unsupported\",\n transactionDeadline: \"between-statements\",\n} as const);\n\n// ─── Adapter ──────────────────────────────────────────────────────\n\n/**\n * Create a VibeORM adapter backed by PGlite.\n *\n * @example In-memory database (tests)\n * ```ts\n * const adapter = pgliteAdapter();\n * await adapter.executeUnsafe({ text: `CREATE TABLE \"User\" (\"id\" serial primary key)` });\n * ```\n *\n * @example Persistent database, or a shared instance\n * ```ts\n * const adapter = pgliteAdapter({ dataDir: \"./.pglite\" });\n * const shared = pgliteAdapter({ pglite: existingInstance });\n * ```\n *\n * `disconnect()` closes an instance the adapter created; a later call opens a\n * fresh one (lazy reconnect, matching the pool-backed adapters). With no\n * `dataDir` that fresh instance is a new, empty in-memory database.\n *\n * @example Bundled extensions (pgvector) without hand-constructing PGlite\n * ```ts\n * import { vector } from \"@electric-sql/pglite-pgvector\";\n * const adapter = pgliteAdapter({ dataDir: \"./.pglite\", extensions: { vector } });\n * ```\n */\nexport function pgliteAdapter(options?: PgliteAdapterOptions): DatabaseAdapter {\n if (options?.pglite !== undefined && options.extensions !== undefined) {\n throw new VibeError({\n code: \"VIBE_CONFIG\",\n message:\n \"pgliteAdapter: `extensions` applies to an instance the adapter CREATES — a provided `pglite` instance was already constructed with its own extensions; pass one or the other\",\n meta: { provider: PROVIDER },\n });\n }\n const queue = createOperationQueue();\n const ownsInstance = options?.pglite === undefined;\n\n /**\n * Deadlock guard (review F6): PGlite is a single connection, and a whole\n * transaction holds the operation queue — so a ROOT-adapter call issued from\n * inside a `transaction()` callback would queue behind the very transaction\n * it is running in and hang forever. The callback runs inside this context;\n * root entry points refuse instead of deadlocking. The tx-bound adapter\n * bypasses the queue and stays fully usable.\n */\n const txContext = new AsyncLocalStorage<true>();\n\n function assertNotInsideTransaction(): void {\n if (txContext.getStore() === true) {\n throw new VibeError({\n code: \"VIBE_TRANSACTION\",\n message:\n \"root client used inside a transaction callback — use the tx client the callback receives; the root connection would deadlock behind the open transaction\",\n meta: { provider: PROVIDER },\n });\n }\n }\n\n let instance: PGliteInterface | null = options?.pglite ?? null;\n let pending: Promise<PGliteInterface> | null = null;\n\n async function getInstance(): Promise<PGliteInterface> {\n if (instance !== null) return instance;\n if (pending === null) {\n pending = runMapped(async () => {\n const { PGlite } = await import(\"@electric-sql/pglite\");\n const created = new PGlite({\n ...(options?.dataDir === undefined ? {} : { dataDir: options.dataDir }),\n ...(options?.extensions === undefined ? {} : { extensions: options.extensions }),\n });\n await created.waitReady;\n return created;\n });\n }\n try {\n instance = await pending;\n return instance;\n } catch (error) {\n // Let the next caller retry instead of caching the failure forever.\n pending = null;\n throw error;\n }\n }\n\n async function runExecute(params: {\n queryable: Queryable;\n text: string;\n values: unknown[];\n }): Promise<Record<string, unknown>[]> {\n const values = serializeParams({ values: params.values });\n const parsers = utcParsers ?? (await getUtcParsers());\n const result = await runMapped(() =>\n params.queryable.query<Record<string, unknown>>(params.text, values, { parsers }),\n );\n return result.rows;\n }\n\n /**\n * Raw path. Without parameters the statement goes through `exec()` (simple\n * protocol) so multi-statement DDL — what @vibeorm/migrate emits — runs as\n * one call; with parameters it goes through the extended protocol.\n */\n async function runExecuteUnsafe(params: {\n queryable: Queryable;\n text: string;\n values?: unknown[];\n }): Promise<QueryResult> {\n const parsers = utcParsers ?? (await getUtcParsers());\n if (params.values === undefined) {\n const results = await runMapped(() => params.queryable.exec(params.text, { parsers }));\n const last = results.at(-1);\n return { rows: last?.rows ?? [], affectedRows: last?.affectedRows ?? 0 };\n }\n const values = serializeParamsRaw({ values: params.values });\n const result = await runMapped(() =>\n params.queryable.query<Record<string, unknown>>(params.text, values, { parsers }),\n );\n return { rows: result.rows, affectedRows: result.affectedRows ?? 0 };\n }\n\n /**\n * Adapter bound to an open transaction. It never re-enters the queue — the\n * enclosing `transaction()` call already owns the connection — and nested\n * `transaction()` calls become savepoints whose LIFETIMES are serialized by\n * the savepoint gate (F14): overlapping siblings would share one savepoint\n * stack, and the earlier one's rollback would erase the later one's work.\n */\n function createTransactionAdapter(params: {\n tx: Transaction;\n scope: SavepointScope;\n budget: TransactionBudget;\n }): DatabaseAdapter {\n const { tx, scope, budget } = params;\n\n return {\n dialect: DIALECT,\n provider: PROVIDER,\n wire: WIRE,\n budgets: BUDGETS,\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 return runExecute({ queryable: tx, ...execParams });\n },\n\n async executeUnsafe(execParams) {\n const turn = scopeTurn({ scope });\n if (turn !== undefined) await turn;\n budget.assertUsable({ stage: \"statement\" });\n return runExecuteUnsafe({ queryable: tx, ...execParams });\n },\n\n async transaction<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 return runNestedSavepoint({\n scope,\n execute: (statement) => runMapped(() => tx.query(statement)),\n // The child shares the ROOT budget by reference: a savepoint never\n // gets an independent clock or session setting.\n body: (child) => fn(createTransactionAdapter({ tx, scope: child, budget })),\n });\n },\n\n async connect(): Promise<void> {\n // Already connected — this adapter is bound to an open transaction.\n },\n\n async disconnect(): Promise<void> {\n // The database outlives the transaction; closing here would be wrong.\n },\n\n formatArrayParam(values: unknown[]): unknown {\n return new PgliteArrayParam(values);\n },\n };\n }\n\n return {\n dialect: DIALECT,\n provider: PROVIDER,\n wire: WIRE,\n budgets: BUDGETS,\n\n async execute(params) {\n assertNotInsideTransaction();\n // The instance is acquired INSIDE the queue (F15): capturing it first and\n // enqueueing after let a `disconnect()` issued in between overtake this\n // statement and close the instance out from under it.\n return queue.run(async () => runExecute({ queryable: await getInstance(), ...params }));\n },\n\n async executeUnsafe(params) {\n assertNotInsideTransaction();\n return queue.run(async () => runExecuteUnsafe({ queryable: await getInstance(), ...params }));\n },\n\n async transaction<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n transactionOptions?: TransactionOptions,\n ): Promise<T> {\n assertNotInsideTransaction();\n // Dialect honesty (constitution rule 4, board #2): PGlite ACCEPTS\n // `SET LOCAL statement_timeout` and even reports it back via SHOW, but\n // never FIRES it — the single-threaded WASM build has no timer interrupt\n // to cancel a running statement (live-verified: `pg_sleep(2)` under a\n // 100ms timeout runs to completion). A timeout the engine cannot enforce\n // is refused at the earliest knowable moment instead of becoming a\n // silent no-op; the postgres SERVER adapters honor the same option for\n // real (SQLSTATE 57014 → VIBE_TRANSACTION, meta.reason \"timeout\").\n if (transactionOptions?.timeout !== undefined) {\n throw new VibeError({\n code: \"VIBE_UNSUPPORTED_CAPABILITY\",\n message:\n \"pglite cannot enforce a transaction timeout: the single-threaded WASM build accepts statement_timeout but never cancels a running statement — remove the option, or use a postgres server adapter where it is genuinely enforced\",\n meta: { provider: PROVIDER, feature: \"transactionTimeout\", timeout: transactionOptions.timeout },\n });\n }\n // Same earliest-moment rule for the deadline: a budget this engine\n // cannot honour is refused before the transaction is ever opened.\n validateTransactionDeadline({\n options: transactionOptions,\n support: BUDGETS.transactionDeadline,\n provider: PROVIDER,\n });\n const scope = createSavepointScope();\n\n return queue.run(async () => {\n const db = await getInstance();\n // The deadline clock starts here — after the queue turn, immediately\n // before PGlite opens the transaction.\n const budget = startTransactionBudget({ options: transactionOptions, provider: PROVIDER });\n try {\n const result = await db.transaction(async (tx) => {\n if (transactionOptions?.isolationLevel !== undefined) {\n await tx.query(\n setIsolationLevelStatement({ isolationLevel: transactionOptions.isolationLevel }),\n );\n }\n try {\n const value = await txContext.run(true, () =>\n runRootScope({ scope, body: () => fn(createTransactionAdapter({ tx, scope, budget })) }),\n );\n // An expired budget must never commit. PGlite commits when this\n // callback returns, so the refusal has to be thrown from INSIDE\n // it — which makes PGlite roll back, exactly as intended.\n budget.assertUsable({ stage: \"commit\" });\n return value;\n } catch (error) {\n throw new CallbackError(error);\n }\n });\n budget.close({ outcome: \"committed\" });\n return result;\n } catch (error) {\n // PGlite owns this transaction's rollback and performs it in-process\n // before control returns here, so the outcome is known.\n budget.close({ outcome: \"rolled-back\" });\n // The callback's own failure propagates untouched; PGlite has already\n // rolled the transaction back by the time it reaches us.\n if (error instanceof CallbackError) throw error.inner;\n throw mapPgliteDriverError({ error });\n }\n });\n },\n\n async connect(): Promise<void> {\n await getInstance();\n },\n\n /**\n * ONE ordered lifecycle (F15): the reference is cleared and the instance\n * closed INSIDE the queue, so work this adapter already accepted completes\n * on the instance it was accepted against instead of being overtaken by the\n * close. Lazy reconnect is unchanged — a later call creates a fresh\n * instance (with no `dataDir`, a new empty one).\n *\n * Refuses inside a transaction callback for the same reason the other entry\n * points do: the close would queue behind the transaction that is waiting\n * for it. Before this guard that call hung forever.\n */\n async disconnect(): Promise<void> {\n assertNotInsideTransaction();\n if (!ownsInstance) return;\n await queue.run(async () => {\n if (instance === null) {\n pending = null;\n return;\n }\n const closing = instance;\n instance = null;\n pending = null;\n await runMapped(() => closing.close());\n });\n },\n\n formatArrayParam(values: unknown[]): unknown {\n return new PgliteArrayParam(values);\n },\n };\n}\n\n// ─── Re-exports (driver-error table, markers, helpers) ────────────\n\nexport {\n PGLITE_SQLSTATE_ERROR_CODES,\n PGLITE_SQLSTATE_REASONS,\n mapPgliteDriverError,\n pgliteErrorSqlstate,\n} from \"./errors.ts\";\nexport { PgliteArrayParam, serializeParams, serializeParamsRaw, toPgArrayLiteral } from \"./params.ts\";\nexport { createOperationQueue } from \"./queue.ts\";\nexport type { OperationQueue } from \"./queue.ts\";\nexport { createSavepointCounter, nextSavepointName } from \"./savepoints.ts\";\nexport type { SavepointCounter } from \"./savepoints.ts\";\nexport {\n ISOLATION_LEVEL_SQL,\n refuseNestedTransactionOptions,\n setIsolationLevelStatement,\n} 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",
6
- "/**\n * Driver-error mapping for PGlite.\n *\n * PGlite runs the real PostgreSQL error protocol in-process, so its errors\n * carry the same SQLSTATE (`code`) plus `constraint` / `table` / `column` as a\n * server would. Constitution rule 5: only `VibeError` 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 maps to `VIBE_ADAPTER`.\n */\nexport const PGLITE_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 PGLITE_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 PGlite error. Failures raised by PGlite itself\n * (closed database, WASM init) carry no SQLSTATE and yield `undefined`.\n */\nexport function pgliteErrorSqlstate(params: { error: unknown }): string | undefined {\n const { error } = params;\n if (error === null || typeof error !== \"object\") return undefined;\n const code = readStringField({ source: error as Record<string, unknown>, key: \"code\" });\n return code !== undefined && SQLSTATE_PATTERN.test(code) ? code : undefined;\n}\n\n// ─── Mapping ──────────────────────────────────────────────────────\n\n/**\n * Map any error thrown by PGlite 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 mapPgliteDriverError(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 = pgliteErrorSqlstate({ error });\n const code: VibeErrorCode =\n (sqlstate === undefined ? undefined : PGLITE_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 : PGLITE_SQLSTATE_REASONS[sqlstate];\n if (reason !== undefined) meta.reason = reason;\n\n const message =\n readStringField({ source, key: \"message\" }) ??\n (typeof error === \"string\" ? error : \"unknown pglite 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 mapPgliteDriverError({ error });\n }\n}\n",
5
+ "/**\n * @vibeorm/adapter-pglite — PGlite (in-process PostgreSQL, WASM) adapter for\n * VibeORM v2.\n *\n * PGlite is a *single* embedded connection, so this adapter serializes every\n * operation through one queue — including whole transactions, which hold the\n * queue until they commit or roll back. That makes concurrent client calls safe\n * without a pool, and makes an in-memory instance an honest postgres target for\n * tests (no Docker).\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { VibeError } from \"@vibeorm/schema\";\nimport type {\n AdapterBudgetSupport,\n DatabaseAdapter,\n QueryResult,\n TransactionOptions,\n WireFidelity,\n} from \"@vibeorm/runtime\";\nimport {\n createSavepointScope,\n runNestedSavepoint,\n runRootScope,\n type SavepointScope,\n scopeTurn,\n startTransactionBudget,\n type TransactionBudget,\n validateTransactionDeadline,\n} from \"@vibeorm/runtime/adapter-kit\";\nimport type { Dialect, Provider } from \"@vibeorm/schema\";\nimport type { Extensions, PGliteInterface, ParserOptions, Transaction } from \"@electric-sql/pglite\";\nimport { mapPgliteDriverError, runMapped } from \"./errors.ts\";\nimport { PgliteArrayParam, serializeParams, serializeParamsRaw } from \"./params.ts\";\nimport { createOperationQueue } from \"./queue.ts\";\nimport { refuseNestedTransactionOptions, setIsolationLevelStatement } from \"./transaction-sql.ts\";\n\n// ─── Options ──────────────────────────────────────────────────────\n\n/** Options for {@link pgliteAdapter}. */\nexport type PgliteAdapterOptions = {\n /**\n * Directory to persist the database in. Omit for a fresh in-memory database —\n * the usual choice for tests. Prefixes PGlite understands (`idb://`,\n * `memory://`) work here too.\n */\n readonly dataDir?: string;\n /**\n * An already-created PGlite instance to run on (sharing one database across\n * adapters, or reusing a warm instance between test files). The adapter never\n * closes an instance it did not create, so `disconnect()` is a no-op then.\n */\n readonly pglite?: PGliteInterface;\n /**\n * PGlite extension bundles to load into the instance the ADAPTER creates —\n * `{ vector }` from `@electric-sql/pglite-pgvector`, `pg_trgm` from\n * `@electric-sql/pglite/contrib/pg_trgm`, … The bundles still come from\n * their own packages; this option removes the need to construct PGlite\n * yourself just to attach them. Mutually exclusive with `pglite` (that\n * instance was already constructed with its extensions) — passing both\n * throws `VIBE_CONFIG`.\n */\n readonly extensions?: Extensions;\n};\n\n// ─── Internals ────────────────────────────────────────────────────\n\n/** Anything that runs SQL: the PGlite instance itself or an open transaction. */\ntype Queryable = Pick<Transaction, \"query\" | \"exec\">;\n\n// ─── UTC zone-less timestamps ─────────────────────────────────────\n\n/** `timestamp without time zone` and its array form. */\nconst TIMESTAMP_OID = 1114;\nconst TIMESTAMP_ARRAY_OID = 1115;\n\n/** PGlite's text output for a zone-less timestamp: `2026-03-08 19:38:08.538`. */\nconst ZONE_LESS_TEXT = /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,6})?$/;\n\n/**\n * Zone-less timestamp text read as **UTC** — the codec table's\n * `parseDateTimeText` rule (@vibeorm/sql) applied at the driver level, because\n * PGlite hands these columns to the ORM as `Date` objects already\n * (`wire.dateTime: \"native\"` prunes the codec decode). PGlite's own parser is\n * `new Date(text)`, which ECMA-262 reads as host-LOCAL time — while PGlite\n * SERIALIZES a `Date` parameter as UTC (`toISOString()`), so a value did not\n * even round-trip on a non-UTC host. `date` is unaffected (date-only text is\n * UTC midnight under ECMA-262 already). Anything outside the plain form keeps\n * PGlite's parser.\n */\nfunction parseTimestampAsUtc(value: string): unknown {\n if (ZONE_LESS_TEXT.test(value)) {\n const parsed = new Date(`${value.replace(\" \", \"T\").replace(/(\\.\\d{3})\\d+$/, \"$1\")}Z`);\n if (!Number.isNaN(parsed.getTime())) return parsed;\n }\n return new Date(value);\n}\n\nlet utcParsers: ParserOptions | null = null;\n\n/**\n * Per-query parsers (`QueryOptions.parsers`) — never `instance.parsers`, which\n * a caller-supplied instance shares with everyone else. The array parser is\n * PGlite's own (`types.arrayParser`), resolved lazily from the same dynamic\n * import `getInstance` uses, so the WASM module is never loaded just to build\n * this table.\n */\nasync function getUtcParsers(): Promise<ParserOptions> {\n if (utcParsers !== null) return utcParsers;\n const { types } = await import(\"@electric-sql/pglite\");\n utcParsers = {\n [TIMESTAMP_OID]: parseTimestampAsUtc,\n [TIMESTAMP_ARRAY_OID]: (text: string): unknown => types.arrayParser(text, parseTimestampAsUtc, TIMESTAMP_ARRAY_OID),\n };\n return utcParsers;\n}\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 PGlite has passed it back out of `transaction()`.\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\nconst DIALECT: Dialect = \"postgres\";\nconst PROVIDER: Provider = \"pglite\";\n\n/**\n * pglite wire (board #30, live-verified on both execute paths): timestamptz →\n * `Date`, json/jsonb → parsed values, int4/float8 → numbers. (int8 arrives as\n * a native `bigint` here — the BigInt codec passes it through; not declared.)\n */\nconst WIRE: WireFidelity = Object.freeze({ dateTime: \"native\", json: \"parsed\", numbers: \"native\" } as const);\n\n/**\n * Timing budgets this adapter genuinely enforces (EPIC 6).\n *\n * - `acquireTimeout: false` — one in-process WASM instance behind a queue.\n * There is no pool to exhaust.\n * - `statementTimeout: \"unsupported\"` — **PGlite ACCEPTING `statement_timeout`\n * is not support.** The single-threaded WASM build reports the setting back\n * via SHOW and never fires it (board #2, live-verified: `pg_sleep(2)` under a\n * 100 ms timeout runs to completion), which is why the `timeout` option is\n * refused outright below.\n * - `transactionDeadline: \"between-statements\"` — the budget is checked before\n * each statement and before the commit, which PGlite CAN honour because those\n * checks happen in JavaScript. It is not cancellation, for the same\n * single-threaded reason, so `\"cancel-running-statements\"` is refused.\n */\nconst BUDGETS: AdapterBudgetSupport = Object.freeze({\n acquireTimeout: false,\n statementTimeout: \"unsupported\",\n transactionDeadline: \"between-statements\",\n} as const);\n\n// ─── Adapter ──────────────────────────────────────────────────────\n\n/**\n * Create a VibeORM adapter backed by PGlite.\n *\n * @example In-memory database (tests)\n * ```ts\n * const adapter = pgliteAdapter();\n * await adapter.executeUnsafe({ text: `CREATE TABLE \"User\" (\"id\" serial primary key)` });\n * ```\n *\n * @example Persistent database, or a shared instance\n * ```ts\n * const adapter = pgliteAdapter({ dataDir: \"./.pglite\" });\n * const shared = pgliteAdapter({ pglite: existingInstance });\n * ```\n *\n * `disconnect()` closes an instance the adapter created; a later call opens a\n * fresh one (lazy reconnect, matching the pool-backed adapters). With no\n * `dataDir` that fresh instance is a new, empty in-memory database.\n *\n * @example Bundled extensions (pgvector) without hand-constructing PGlite\n * ```ts\n * import { vector } from \"@electric-sql/pglite-pgvector\";\n * const adapter = pgliteAdapter({ dataDir: \"./.pglite\", extensions: { vector } });\n * ```\n */\nexport function pgliteAdapter(options?: PgliteAdapterOptions): DatabaseAdapter {\n if (options?.pglite !== undefined && options.extensions !== undefined) {\n throw new VibeError({\n code: \"VIBE_CONFIG\",\n message:\n \"pgliteAdapter: `extensions` applies to an instance the adapter CREATES — a provided `pglite` instance was already constructed with its own extensions; pass one or the other\",\n meta: { provider: PROVIDER },\n });\n }\n const queue = createOperationQueue();\n const ownsInstance = options?.pglite === undefined;\n\n /**\n * Deadlock guard (review F6): PGlite is a single connection, and a whole\n * transaction holds the operation queue — so a ROOT-adapter call issued from\n * inside a `transaction()` callback would queue behind the very transaction\n * it is running in and hang forever. The callback runs inside this context;\n * root entry points refuse instead of deadlocking. The tx-bound adapter\n * bypasses the queue and stays fully usable.\n */\n const txContext = new AsyncLocalStorage<true>();\n\n function assertNotInsideTransaction(): void {\n if (txContext.getStore() === true) {\n throw new VibeError({\n code: \"VIBE_TRANSACTION\",\n message:\n \"root client used inside a transaction callback — use the tx client the callback receives; the root connection would deadlock behind the open transaction\",\n meta: { provider: PROVIDER },\n });\n }\n }\n\n let instance: PGliteInterface | null = options?.pglite ?? null;\n let pending: Promise<PGliteInterface> | null = null;\n\n async function getInstance(): Promise<PGliteInterface> {\n if (instance !== null) return instance;\n if (pending === null) {\n pending = runMapped(async () => {\n const { PGlite } = await import(\"@electric-sql/pglite\");\n const created = new PGlite({\n ...(options?.dataDir === undefined ? {} : { dataDir: options.dataDir }),\n ...(options?.extensions === undefined ? {} : { extensions: options.extensions }),\n });\n await created.waitReady;\n return created;\n });\n }\n try {\n instance = await pending;\n return instance;\n } catch (error) {\n // Let the next caller retry instead of caching the failure forever.\n pending = null;\n throw error;\n }\n }\n\n async function runExecute(params: {\n queryable: Queryable;\n text: string;\n values: unknown[];\n }): Promise<Record<string, unknown>[]> {\n const values = serializeParams({ values: params.values });\n const parsers = utcParsers ?? (await getUtcParsers());\n const result = await runMapped(() =>\n params.queryable.query<Record<string, unknown>>(params.text, values, { parsers }),\n );\n return result.rows;\n }\n\n /**\n * Raw path. Without parameters the statement goes through `exec()` (simple\n * protocol) so multi-statement DDL — what @vibeorm/migrate emits — runs as\n * one call; with parameters it goes through the extended protocol.\n */\n async function runExecuteUnsafe(params: {\n queryable: Queryable;\n text: string;\n values?: unknown[];\n }): Promise<QueryResult> {\n const parsers = utcParsers ?? (await getUtcParsers());\n if (params.values === undefined) {\n const results = await runMapped(() => params.queryable.exec(params.text, { parsers }));\n const last = results.at(-1);\n return { rows: last?.rows ?? [], affectedRows: last?.affectedRows ?? 0 };\n }\n const values = serializeParamsRaw({ values: params.values });\n const result = await runMapped(() =>\n params.queryable.query<Record<string, unknown>>(params.text, values, { parsers }),\n );\n return { rows: result.rows, affectedRows: result.affectedRows ?? 0 };\n }\n\n /**\n * Adapter bound to an open transaction. It never re-enters the queue — the\n * enclosing `transaction()` call already owns the connection — and nested\n * `transaction()` calls become savepoints whose LIFETIMES are serialized by\n * the savepoint gate (F14): overlapping siblings would share one savepoint\n * stack, and the earlier one's rollback would erase the later one's work.\n */\n function createTransactionAdapter(params: {\n tx: Transaction;\n scope: SavepointScope;\n budget: TransactionBudget;\n }): DatabaseAdapter {\n const { tx, scope, budget } = params;\n\n return {\n dialect: DIALECT,\n provider: PROVIDER,\n wire: WIRE,\n budgets: BUDGETS,\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 return runExecute({ queryable: tx, ...execParams });\n },\n\n async executeUnsafe(execParams) {\n const turn = scopeTurn({ scope });\n if (turn !== undefined) await turn;\n budget.assertUsable({ stage: \"statement\" });\n return runExecuteUnsafe({ queryable: tx, ...execParams });\n },\n\n async transaction<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 return runNestedSavepoint({\n scope,\n execute: (statement) => runMapped(() => tx.query(statement)),\n // The child shares the ROOT budget by reference: a savepoint never\n // gets an independent clock or session setting.\n body: (child) => fn(createTransactionAdapter({ tx, scope: child, budget })),\n });\n },\n\n async connect(): Promise<void> {\n // Already connected — this adapter is bound to an open transaction.\n },\n\n async disconnect(): Promise<void> {\n // The database outlives the transaction; closing here would be wrong.\n },\n\n formatArrayParam(values: unknown[]): unknown {\n return new PgliteArrayParam(values);\n },\n };\n }\n\n return {\n dialect: DIALECT,\n provider: PROVIDER,\n wire: WIRE,\n budgets: BUDGETS,\n\n async execute(params) {\n assertNotInsideTransaction();\n // The instance is acquired INSIDE the queue (F15): capturing it first and\n // enqueueing after let a `disconnect()` issued in between overtake this\n // statement and close the instance out from under it.\n return queue.run(async () => runExecute({ queryable: await getInstance(), ...params }));\n },\n\n async executeUnsafe(params) {\n assertNotInsideTransaction();\n return queue.run(async () => runExecuteUnsafe({ queryable: await getInstance(), ...params }));\n },\n\n async transaction<T>(\n fn: (txAdapter: DatabaseAdapter) => Promise<T>,\n transactionOptions?: TransactionOptions,\n ): Promise<T> {\n assertNotInsideTransaction();\n // Dialect honesty (constitution rule 4, board #2): PGlite ACCEPTS\n // `SET LOCAL statement_timeout` and even reports it back via SHOW, but\n // never FIRES it — the single-threaded WASM build has no timer interrupt\n // to cancel a running statement (live-verified: `pg_sleep(2)` under a\n // 100ms timeout runs to completion). A timeout the engine cannot enforce\n // is refused at the earliest knowable moment instead of becoming a\n // silent no-op; the postgres SERVER adapters honor the same option for\n // real (SQLSTATE 57014 → VIBE_TRANSACTION, meta.reason \"timeout\").\n if (transactionOptions?.timeout !== undefined) {\n throw new VibeError({\n code: \"VIBE_UNSUPPORTED_CAPABILITY\",\n message:\n \"pglite cannot enforce a transaction timeout: the single-threaded WASM build accepts statement_timeout but never cancels a running statement — remove the option, or use a postgres server adapter where it is genuinely enforced\",\n meta: { provider: PROVIDER, feature: \"transactionTimeout\", timeout: transactionOptions.timeout },\n });\n }\n // Same earliest-moment rule for the deadline: a budget this engine\n // cannot honour is refused before the transaction is ever opened.\n validateTransactionDeadline({\n options: transactionOptions,\n support: BUDGETS.transactionDeadline,\n provider: PROVIDER,\n });\n const scope = createSavepointScope();\n\n return queue.run(async () => {\n const db = await getInstance();\n // The deadline clock starts here — after the queue turn, immediately\n // before PGlite opens the transaction.\n const budget = startTransactionBudget({ options: transactionOptions, provider: PROVIDER });\n try {\n const result = await db.transaction(async (tx) => {\n if (transactionOptions?.isolationLevel !== undefined) {\n await tx.query(\n setIsolationLevelStatement({ isolationLevel: transactionOptions.isolationLevel }),\n );\n }\n try {\n const value = await txContext.run(true, () =>\n runRootScope({ scope, body: () => fn(createTransactionAdapter({ tx, scope, budget })) }),\n );\n // An expired budget must never commit. PGlite commits when this\n // callback returns, so the refusal has to be thrown from INSIDE\n // it — which makes PGlite roll back, exactly as intended.\n budget.assertUsable({ stage: \"commit\" });\n return value;\n } catch (error) {\n throw new CallbackError(error);\n }\n });\n budget.close({ outcome: \"committed\" });\n return result;\n } catch (error) {\n // PGlite owns this transaction's rollback and performs it in-process\n // before control returns here, so the outcome is known.\n budget.close({ outcome: \"rolled-back\" });\n // The callback's own failure propagates untouched; PGlite has already\n // rolled the transaction back by the time it reaches us.\n if (error instanceof CallbackError) throw error.inner;\n throw mapPgliteDriverError({ error });\n }\n });\n },\n\n async connect(): Promise<void> {\n await getInstance();\n },\n\n /**\n * ONE ordered lifecycle (F15): the reference is cleared and the instance\n * closed INSIDE the queue, so work this adapter already accepted completes\n * on the instance it was accepted against instead of being overtaken by the\n * close. Lazy reconnect is unchanged — a later call creates a fresh\n * instance (with no `dataDir`, a new empty one).\n *\n * Refuses inside a transaction callback for the same reason the other entry\n * points do: the close would queue behind the transaction that is waiting\n * for it. Before this guard that call hung forever.\n */\n async disconnect(): Promise<void> {\n assertNotInsideTransaction();\n if (!ownsInstance) return;\n await queue.run(async () => {\n if (instance === null) {\n pending = null;\n return;\n }\n const closing = instance;\n instance = null;\n pending = null;\n await runMapped(() => closing.close());\n });\n },\n\n formatArrayParam(values: unknown[]): unknown {\n return new PgliteArrayParam(values);\n },\n };\n}\n\n// ─── Re-exports (driver-error table, markers, helpers) ────────────\n\nexport {\n PGLITE_SQLSTATE_ERROR_CODES,\n PGLITE_SQLSTATE_REASONS,\n mapPgliteDriverError,\n pgliteErrorSqlstate,\n} from \"./errors.ts\";\nexport { PgliteArrayParam, serializeParams, serializeParamsRaw, toPgArrayLiteral } from \"./params.ts\";\nexport { createOperationQueue } from \"./queue.ts\";\nexport type { OperationQueue } from \"./queue.ts\";\nexport { createSavepointCounter, nextSavepointName } from \"@vibeorm/runtime/adapter-kit\";\nexport type { SavepointCounter } from \"@vibeorm/runtime/adapter-kit\";\nexport {\n ISOLATION_LEVEL_SQL,\n refuseNestedTransactionOptions,\n setIsolationLevelStatement,\n} 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
+ "/**\n * Driver-error mapping for PGlite.\n *\n * PGlite runs the real PostgreSQL error protocol in-process, so its errors\n * carry the same SQLSTATE (`code`) plus `constraint` / `table` / `column` as a\n * server would. Constitution rule 5: only `VibeError` 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 maps to `VIBE_ADAPTER`.\n */\nexport const PGLITE_SQLSTATE_ERROR_CODES: Readonly<Record<string, VibeErrorCode>> = Object.freeze({\n /** exclusion_violation */\n \"23P01\": \"VIBE_EXCLUSION_VIOLATION\",\n /** unique_violation */\n \"23505\": \"VIBE_UNIQUE_VIOLATION\",\n /** foreign_key_violation */\n \"23503\": \"VIBE_FK_VIOLATION\",\n /** restrict_violation — PostgreSQL 18+ ON DELETE/UPDATE RESTRICT */\n \"23001\": \"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 /**\n * lock_not_available. PGlite has ONE session, so nothing can contend with the\n * caller — the mapping exists for parity with the server adapters (identical\n * PostgreSQL SQLSTATEs), not because this engine is expected to raise it.\n */\n \"55P03\": \"VIBE_LOCK_NOT_AVAILABLE\",\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 PGLITE_SQLSTATE_REASONS: Readonly<Record<string, string>> = Object.freeze({\n \"23P01\": \"exclusion-violation\",\n \"57014\": \"timeout\",\n \"55P03\": \"lock-not-available\",\n \"40P01\": \"deadlock\",\n \"40001\": \"serialization-failure\",\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 PGlite error. Failures raised by PGlite itself\n * (closed database, WASM init) carry no SQLSTATE and yield `undefined`.\n */\nexport function pgliteErrorSqlstate(params: { error: unknown }): string | undefined {\n const { error } = params;\n if (error === null || typeof error !== \"object\") return undefined;\n const code = readStringField({ source: error as Record<string, unknown>, key: \"code\" });\n return code !== undefined && SQLSTATE_PATTERN.test(code) ? code : undefined;\n}\n\n// ─── Mapping ──────────────────────────────────────────────────────\n\n/**\n * Map any error thrown by PGlite 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 mapPgliteDriverError(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 = pgliteErrorSqlstate({ error });\n const code: VibeErrorCode =\n (sqlstate === undefined ? undefined : PGLITE_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 : PGLITE_SQLSTATE_REASONS[sqlstate];\n if (reason !== undefined) meta.reason = reason;\n\n const message =\n readStringField({ source, key: \"message\" }) ??\n (typeof error === \"string\" ? error : \"unknown pglite 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 mapPgliteDriverError({ error });\n }\n}\n",
7
7
  "/**\n * Parameter serialization for PGlite.\n *\n * PGlite takes JS arrays natively for the array types it knows, but it picks a\n * parameter serializer from the BACKEND-INFERRED type OID and falls back to\n * `String(value)` for anything else — so a scalar list bound against a column\n * of a custom type (a native `enum`, i.e. every `Role[]` / `role IN (…)` query)\n * reached the server as `ADMIN,MODERATOR` and was rejected with `malformed\n * array literal`. ORM-path scalar lists are therefore rendered as PostgreSQL\n * array literals here, exactly like the bun:sql adapter does\n * (`@vibeorm/adapter-bun`'s `toPgArrayLiteral`); the server then coerces the\n * literal to whichever array type the statement needs (`text[]`, `int[]`,\n * `timestamptz[]`, `\"Role\"[]`).\n *\n * The ORM path and the raw path still split the same way (LEARNINGS.md): the\n * ORM path cannot tell a `jsonb` value that happens to be an array from a\n * scalar-list parameter, so it JSON-stringifies plain arrays and only treats\n * values tagged with {@link PgliteArrayParam} as scalar lists; the raw path\n * passes plain JS arrays straight through to the driver.\n */\n\nimport { VibeError } from \"@vibeorm/schema\";\n\n// ─── Scalar-list marker ───────────────────────────────────────────\n\n/**\n * Opaque token returned by `pgliteAdapter().formatArrayParam` marking a value\n * as a PostgreSQL array parameter (rather than a JSON value that happens to be\n * an array). The wrapped array is rendered as an array literal on the way out.\n */\nexport class PgliteArrayParam {\n /** The untouched scalar-list values. */\n readonly values: unknown[];\n\n constructor(values: unknown[]) {\n this.values = values;\n }\n}\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 — the same element\n * rules as `@vibeorm/adapter-bun`'s `toPgArrayLiteral` (kept per-adapter: an\n * array literal is driver transport, not SQL text):\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 (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\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: \"pglite\" },\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/** True for values PGlite must receive verbatim (dates, binary, primitives, null). */\nfunction isDriverNativeValue(value: unknown): boolean {\n return (\n value === null ||\n value === undefined ||\n typeof value !== \"object\" ||\n value instanceof Date ||\n ArrayBuffer.isView(value) ||\n value instanceof ArrayBuffer\n );\n}\n\n/**\n * ORM hot path: render scalar-list markers as array literals, JSON-stringify\n * plain objects **and** plain arrays (they can only be `json`/`jsonb` values at\n * this point).\n */\nexport function serializeParams(params: { values: readonly unknown[] }): unknown[] {\n return params.values.map((value) => {\n if (value instanceof PgliteArrayParam) return toPgArrayLiteral(value.values);\n if (isDriverNativeValue(value)) return value;\n return JSON.stringify(value);\n });\n}\n\n/**\n * Raw path (`$queryRaw*` / `$executeRaw*` / DDL): identical to\n * {@link serializeParams} except that plain JS arrays pass straight through, so\n * `db.$queryRawUnsafe('… WHERE \"id\" = ANY($1)', [1, 2, 3])` matches rows.\n */\nexport function serializeParamsRaw(params: { values: readonly unknown[] }): unknown[] {\n return params.values.map((value) => {\n if (value instanceof PgliteArrayParam) return toPgArrayLiteral(value.values);\n if (Array.isArray(value)) return value;\n if (isDriverNativeValue(value)) return value;\n return JSON.stringify(value);\n });\n}\n",
8
8
  "/**\n * Operation queue for PGlite.\n *\n * PGlite is a single embedded PostgreSQL connection: two overlapping\n * operations would interleave on the same wire, and an interleaved statement\n * inside a transaction would silently join that transaction. Every adapter\n * entry point therefore runs through one serial chain — including whole\n * `transaction()` calls, which occupy the chain until they commit or roll back.\n */\n\n/** A serial chain: jobs run one at a time, in the order they were queued. */\nexport type OperationQueue = {\n /** Queue `job`, resolving with its result once every earlier job has settled. */\n run<T>(job: () => Promise<T>): Promise<T>;\n};\n\n/** Create an empty operation queue. */\nexport function createOperationQueue(): OperationQueue {\n let tail: Promise<unknown> = Promise.resolve();\n\n return {\n run<T>(job: () => Promise<T>): Promise<T> {\n // Run after the previous job settles, whether it resolved or rejected.\n const result = tail.then(job, job);\n // Keep the chain alive: a rejected job must not reject every later job.\n tail = result.then(\n () => undefined,\n () => undefined,\n );\n return result;\n },\n };\n}\n",
9
- "/**\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",
10
- "/**\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",
11
- "/**\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",
12
9
  "/**\n * Transaction-control SQL text (postgres dialect, PGlite flavour).\n *\n * PGlite issues its own `BEGIN` inside `pglite.transaction(cb)`, so isolation\n * is set with `SET TRANSACTION …` as the first statement of the callback rather\n * than as a `BEGIN` clause.\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/**\n * `SET TRANSACTION ISOLATION LEVEL <level>` — valid only as the first statement\n * of an open transaction, which is where the adapter issues it.\n */\nexport function setIsolationLevelStatement(params: { isolationLevel: IsolationLevel }): string {\n return `SET TRANSACTION ISOLATION LEVEL ${ISOLATION_LEVEL_SQL[params.isolationLevel]}`;\n}\n\n// NOTE (board #2): this module deliberately has NO statementTimeoutStatement.\n// PGlite accepts `SET LOCAL statement_timeout` and reports it back via SHOW,\n// but the single-threaded WASM build never fires it (live-verified:\n// `pg_sleep(2)` under a 100ms timeout runs to completion) — so the adapter\n// refuses the `timeout` option outright with VIBE_UNSUPPORTED_CAPABILITY\n// instead of rendering SQL that silently does nothing.\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"
13
10
  ],
14
- "mappings": "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",
15
- "debugId": "E854C74C7D9581BE64756E2164756E21",
11
+ "mappings": "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",
12
+ "debugId": "2AB293AB4718A69464756E2164756E21",
16
13
  "names": []
17
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeorm/adapter-pglite",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "PGlite (in-process Postgres) adapter for VibeORM v2",
5
5
  "keywords": [
6
6
  "orm",
@@ -44,8 +44,8 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@electric-sql/pglite": "^0.3.0 || ^0.4.0 || ^0.5.0",
47
- "@vibeorm/runtime": "2.0.1",
48
- "@vibeorm/schema": "2.0.0"
47
+ "@vibeorm/runtime": "2.1.0",
48
+ "@vibeorm/schema": "2.1.0"
49
49
  },
50
50
  "publishConfig": {
51
51
  "access": "public"
@@ -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"}
@@ -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
@@ -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"}