@spfn/core 0.3.0-beta.3 → 0.3.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +301 -10
  2. package/dist/app-config/index.d.ts +39 -1
  3. package/dist/app-config/index.js.map +1 -1
  4. package/dist/authz/index.js +47 -391
  5. package/dist/authz/index.js.map +1 -1
  6. package/dist/{boss-D16fO2oG.d.ts → boss-BiDCbbAQ.d.ts} +60 -7
  7. package/dist/codegen/index.d.ts +157 -16
  8. package/dist/codegen/index.js +772 -166
  9. package/dist/codegen/index.js.map +1 -1
  10. package/dist/config/index.js +4 -4
  11. package/dist/config/index.js.map +1 -1
  12. package/dist/contract/index.d.ts +39 -16
  13. package/dist/contract/index.js +147 -23
  14. package/dist/contract/index.js.map +1 -1
  15. package/dist/db/index.d.ts +230 -35
  16. package/dist/db/index.js +316 -160
  17. package/dist/db/index.js.map +1 -1
  18. package/dist/env/index.d.ts +6 -442
  19. package/dist/env/index.js +13 -16
  20. package/dist/env/index.js.map +1 -1
  21. package/dist/env/loader.js +24 -1
  22. package/dist/env/loader.js.map +1 -1
  23. package/dist/error-CIZlYJlL.d.ts +157 -0
  24. package/dist/errors/index.d.ts +18 -1
  25. package/dist/errors/index.js +47 -391
  26. package/dist/errors/index.js.map +1 -1
  27. package/dist/event/index.d.ts +5 -5
  28. package/dist/event/index.js +202 -3
  29. package/dist/event/index.js.map +1 -1
  30. package/dist/event/sse/client.d.ts +18 -4
  31. package/dist/event/sse/client.js +94 -18
  32. package/dist/event/sse/client.js.map +1 -1
  33. package/dist/event/sse/index.d.ts +18 -5
  34. package/dist/event/sse/index.js +452 -114
  35. package/dist/event/sse/index.js.map +1 -1
  36. package/dist/event/ws/client.d.ts +3 -2
  37. package/dist/event/ws/index.d.ts +4 -3
  38. package/dist/job/index.d.ts +48 -3
  39. package/dist/job/index.js +131 -52
  40. package/dist/job/index.js.map +1 -1
  41. package/dist/logger/index.js +0 -12
  42. package/dist/logger/index.js.map +1 -1
  43. package/dist/middleware/index.js +52 -397
  44. package/dist/middleware/index.js.map +1 -1
  45. package/dist/nextjs/index.d.ts +75 -14
  46. package/dist/nextjs/index.js +200 -84
  47. package/dist/nextjs/index.js.map +1 -1
  48. package/dist/nextjs/server.d.ts +46 -8
  49. package/dist/nextjs/server.js +15 -1
  50. package/dist/nextjs/server.js.map +1 -1
  51. package/dist/ops/index.d.ts +61 -42
  52. package/dist/ops/index.js +648 -97
  53. package/dist/ops/index.js.map +1 -1
  54. package/dist/registry-C2KQCh0m.d.ts +473 -0
  55. package/dist/route/index.d.ts +5 -2
  56. package/dist/route/index.js +107 -28
  57. package/dist/route/index.js.map +1 -1
  58. package/dist/route/types.d.ts +7 -1
  59. package/dist/{router-Cy7rAfmj.d.ts → route-builder-DRW-MSCJ.d.ts} +51 -126
  60. package/dist/router-C57y-vz1.d.ts +184 -0
  61. package/dist/router-CX5uVjmU.d.ts +406 -0
  62. package/dist/server/index.d.ts +130 -7
  63. package/dist/server/index.js +1174 -164
  64. package/dist/server/index.js.map +1 -1
  65. package/dist/state/client.d.ts +206 -0
  66. package/dist/state/client.js +678 -0
  67. package/dist/state/client.js.map +1 -0
  68. package/dist/state/index.d.ts +443 -0
  69. package/dist/state/index.js +644 -0
  70. package/dist/state/index.js.map +1 -0
  71. package/dist/state/react.d.ts +49 -0
  72. package/dist/state/react.js +50 -0
  73. package/dist/state/react.js.map +1 -0
  74. package/dist/surface/index.d.ts +115 -0
  75. package/dist/surface/index.js +1013 -0
  76. package/dist/surface/index.js.map +1 -0
  77. package/dist/token-manager-Ckjt2-qq.d.ts +122 -0
  78. package/dist/{types-CfYVhIQ9.d.ts → types-5Rl11_Nb.d.ts} +43 -4
  79. package/dist/types-CKH0D3Dy.d.ts +441 -0
  80. package/dist/{types-ZQODsBft.d.ts → types-CurMab2Q.d.ts} +52 -2
  81. package/dist/{types-2AbaW4Ie.d.ts → types-DncqXfWN.d.ts} +4 -3
  82. package/docs/file-upload.md +195 -333
  83. package/package.json +39 -9
  84. package/src/cache/README.md +330 -0
  85. package/src/codegen/README.md +721 -0
  86. package/src/config/README.md +333 -0
  87. package/src/contract/README.md +442 -0
  88. package/src/db/README.md +589 -0
  89. package/src/db/manager/README.md +500 -0
  90. package/src/db/schema/README.md +354 -0
  91. package/src/db/transaction/README.md +845 -0
  92. package/src/env/README.md +787 -0
  93. package/src/errors/README.md +445 -0
  94. package/src/event/README.md +994 -0
  95. package/src/job/README.md +613 -0
  96. package/src/logger/README.md +321 -0
  97. package/src/middleware/README.md +634 -0
  98. package/src/nextjs/README.md +756 -0
  99. package/src/route/README.md +763 -0
  100. package/src/security/README.md +100 -0
  101. package/src/server/README.md +704 -0
  102. package/src/state/README.md +806 -0
  103. package/dist/token-manager-BT5EnUAR.d.ts +0 -278
  104. package/dist/types-9oszaJqp.d.ts +0 -250
@@ -397,27 +397,6 @@ declare function getDatabaseInfo(): {
397
397
  providerKind?: string;
398
398
  };
399
399
 
400
- /**
401
- * Reconnect Trigger — Query-error driven pool rebuild
402
- *
403
- * Complements the periodic health check with a fast-path: when application
404
- * queries start failing with connection-level errors, we do not wait up to
405
- * DB_HEALTH_CHECK_INTERVAL (default 60s) to notice. A sliding-window counter
406
- * trips a force-reconnect as soon as the failure rate crosses a threshold.
407
- *
408
- * Why this exists:
409
- * - postgres.js transparently drops dead sockets and opens new ones on the
410
- * next query. A single `SELECT 1` on the periodic interval can therefore
411
- * false-pass while user-facing queries keep hitting the remaining dead
412
- * sockets in the pool.
413
- * - This module observes real query errors and, when it sees a burst of
414
- * connection-level failures, calls triggerForceReconnect() which performs
415
- * the same atomic-swap rebuild as the health check.
416
- *
417
- * Configuration (env vars, hardcoded defaults):
418
- * - DB_RECONNECT_ERROR_THRESHOLD (default 3): errors needed in window
419
- * - DB_RECONNECT_ERROR_WINDOW_MS (default 10000): sliding window size
420
- */
421
400
  /**
422
401
  * Determine whether an error looks like a pool/connection failure
423
402
  *
@@ -505,7 +484,7 @@ declare function checkConnection(client: Sql): Promise<boolean>;
505
484
  interface DrizzleConfigOptions {
506
485
  /** Database connection URL (defaults to process.env.DATABASE_URL) */
507
486
  databaseUrl?: string;
508
- /** Schema files glob pattern or array of patterns (defaults to './src/server/entities/\*\*\/*.ts') */
487
+ /** Schema entry file(s), directories or glob pattern(s). Default: './src/server/entities/\*\*\/*.ts', or the registry `DRIZZLE_SCHEMA_PATH` (./src/server/entities/config.ts) when that scan finds no entity file; `schemaRegistry` reports the registry when both exist */
509
488
  schema?: string | string[];
510
489
  /** Migration output directory (defaults to './src/server/drizzle') */
511
490
  out?: string;
@@ -521,8 +500,6 @@ interface DrizzleConfigOptions {
521
500
  expandGlobs?: boolean;
522
501
  /** PostgreSQL schema filter for push/introspect commands */
523
502
  schemaFilter?: string[];
524
- /** Auto-detect PostgreSQL schemas from entity files (requires expandGlobs: true) */
525
- autoDetectSchemas?: boolean;
526
503
  /** Migration prefix strategy (default: 'timestamp') */
527
504
  migrationPrefix?: 'index' | 'timestamp' | 'unix' | 'none';
528
505
  }
@@ -551,6 +528,8 @@ declare function detectDialect(url: string): 'postgresql' | 'mysql' | 'sqlite';
551
528
  */
552
529
  declare function getDrizzleConfig(options?: DrizzleConfigOptions): {
553
530
  schema: string | string[];
531
+ schemaSource: string;
532
+ schemaRegistry: string | undefined;
554
533
  out: string;
555
534
  dialect: "postgresql" | "mysql" | "sqlite";
556
535
  dbCredentials: {
@@ -562,6 +541,8 @@ declare function getDrizzleConfig(options?: DrizzleConfigOptions): {
562
541
  schemaFilter?: undefined;
563
542
  } | {
564
543
  schema: string | string[];
544
+ schemaSource: string;
545
+ schemaRegistry: string | undefined;
565
546
  out: string;
566
547
  dialect: "postgresql" | "mysql" | "sqlite";
567
548
  dbCredentials: {
@@ -573,10 +554,29 @@ declare function getDrizzleConfig(options?: DrizzleConfigOptions): {
573
554
  };
574
555
  };
575
556
  /**
576
- * Generate drizzle.config.ts file content
557
+ * The schema fields a rendered drizzle.config.ts needs
558
+ */
559
+ interface RenderableDrizzleConfig {
560
+ schema: string | string[];
561
+ out: string;
562
+ dialect: string;
563
+ dbCredentials: Record<string, unknown>;
564
+ schemaFilter?: string[];
565
+ migrations?: Record<string, unknown>;
566
+ }
567
+ /**
568
+ * Render an already-resolved config as drizzle.config.ts source, schema
569
+ * paths made absolute for Drizzle Studio
577
570
  *
578
- * @param options - Configuration options
579
- * @returns File content as string
571
+ * @param config - Result of getDrizzleConfig, possibly with the schema replaced
572
+ * @param cwd - Base for relative schema paths (default: process.cwd())
573
+ */
574
+ declare function renderDrizzleConfig(config: RenderableDrizzleConfig, cwd?: string): string;
575
+ /**
576
+ * Generate drizzle.config.ts source from options: resolve the config, then render it
577
+ *
578
+ * @param options - Configuration options (see getDrizzleConfig)
579
+ * @returns drizzle.config.ts source
580
580
  */
581
581
  declare function generateDrizzleConfigFile(options?: DrizzleConfigOptions): string;
582
582
 
@@ -1139,6 +1139,23 @@ type TransactionDB<TDatabase extends DrizzleDatabase = DefaultDatabase> = Databa
1139
1139
  * afterCommit callback type
1140
1140
  */
1141
1141
  type AfterCommitCallback = () => void | Promise<void>;
1142
+ /**
1143
+ * beforeCommit callback type
1144
+ */
1145
+ type BeforeCommitCallback = () => void | Promise<void>;
1146
+ /**
1147
+ * afterRollback callback type
1148
+ */
1149
+ type AfterRollbackCallback = () => void | Promise<void>;
1150
+ /**
1151
+ * Serializes the savepoint frames opened directly off one transaction context
1152
+ *
1153
+ * @see createNestedFrameGate
1154
+ */
1155
+ type NestedFrameGate = {
1156
+ /** Run `frame` once every frame queued before it on this context has finished */
1157
+ run<T>(frame: () => Promise<T>): Promise<T>;
1158
+ };
1142
1159
  /**
1143
1160
  * Transaction context stored in AsyncLocalStorage
1144
1161
  */
@@ -1148,8 +1165,14 @@ type TransactionContext<TDatabase extends DrizzleDatabase = DrizzleDatabase> = {
1148
1165
  /** Unique transaction ID for logging and tracing */
1149
1166
  txId: string;
1150
1167
  level: number;
1151
- /** Callbacks to execute after root transaction commits */
1168
+ /** beforeCommit callbacks registered in THIS frame (root or savepoint) */
1169
+ beforeCommitCallbacks: BeforeCommitCallback[];
1170
+ /** afterCommit callbacks registered in THIS frame (root or savepoint) */
1152
1171
  afterCommitCallbacks: AfterCommitCallback[];
1172
+ /** afterRollback callbacks registered in THIS frame (root or savepoint) */
1173
+ afterRollbackCallbacks: AfterRollbackCallback[];
1174
+ /** Serializes the savepoint frames opened directly off THIS context */
1175
+ nestedFrames: NestedFrameGate;
1153
1176
  };
1154
1177
  /**
1155
1178
  * Get current transaction object and metadata from AsyncLocalStorage
@@ -1181,13 +1204,18 @@ callback: () => Promise<T>): Promise<T>;
1181
1204
  *
1182
1205
  * - Inside a transaction: queued and executed after root transaction commits
1183
1206
  * - Outside a transaction: executed immediately (already "committed")
1184
- * - Nested transactions: callbacks bubble up to root transaction
1207
+ * - Nested transactions: the callback belongs to the savepoint that registered
1208
+ * it. It reaches the root only if that savepoint (and every one around it)
1209
+ * resolved; a savepoint that rolls back drops it, even when the root commits
1210
+ * - A hook registered after its frame (root or savepoint) has settled is
1211
+ * dropped: the frame's queue was handed on, or discarded, when it settled.
1212
+ * Register hooks in the awaited call chain, not from detached work
1185
1213
  * - Callbacks run outside transaction context (new connection for DB access)
1186
1214
  * - Errors are logged but never thrown (commit already succeeded)
1187
1215
  *
1188
1216
  * @example
1189
1217
  * ```typescript
1190
- * import { onAfterCommit } from '@spfn/core/db/transaction';
1218
+ * import { onAfterCommit } from '@spfn/core/db';
1191
1219
  *
1192
1220
  * async function submit(spaceId: string, chatId: string)
1193
1221
  * {
@@ -1201,6 +1229,100 @@ callback: () => Promise<T>): Promise<T>;
1201
1229
  * ```
1202
1230
  */
1203
1231
  declare function onAfterCommit(callback: AfterCommitCallback): void;
1232
+ /**
1233
+ * Register a callback to run just before the current transaction commits
1234
+ *
1235
+ * - Inside a transaction: queued and executed after the root callback resolves,
1236
+ * while the transaction is still open — the callback MAY run statements and
1237
+ * they are part of the same commit
1238
+ * - Outside a transaction: executed immediately with a WARNING (same rationale as
1239
+ * onAfterCommit — there is nothing left to commit), and the abort semantics
1240
+ * below do not apply: there is no transaction for a throw to roll back
1241
+ * - Nested transactions: the callback belongs to the savepoint that registered
1242
+ * it. A savepoint that resolved hands it to the root, where it still runs
1243
+ * before the root's COMMIT (never at the savepoint); one that rolls back
1244
+ * drops it, and the root commits without it
1245
+ * - A hook registered after its frame (root or savepoint) has settled is
1246
+ * dropped: the frame's queue was handed on, or discarded, when it settled.
1247
+ * Register hooks in the awaited call chain, not from detached work
1248
+ * - Callbacks run in registration order, inside the transaction context
1249
+ * (getTransaction() returns the live tx)
1250
+ * - The queue is snapshot before the pass, so a callback registered BY a
1251
+ * beforeCommit callback does not run for this commit — it would otherwise
1252
+ * grow the queue mid-iteration and loop forever inside the open transaction
1253
+ * - A throw ABORTS: later callbacks are skipped, the transaction rolls back,
1254
+ * the error propagates to the caller, and afterRollback callbacks fire
1255
+ *
1256
+ * @example
1257
+ * ```typescript
1258
+ * import { runInTransaction, onBeforeCommit } from '@spfn/core/db';
1259
+ *
1260
+ * async function transfer(fromId: string, toId: string, amount: number)
1261
+ * {
1262
+ * // The transaction is what gives the check teeth — registered outside one,
1263
+ * // the callback runs immediately and its throw aborts nothing.
1264
+ * await runInTransaction(async () =>
1265
+ * {
1266
+ * await accountRepo.debit(fromId, amount);
1267
+ * await accountRepo.credit(toId, amount);
1268
+ *
1269
+ * // Last-moment invariant check: a throw here rolls the whole transfer back.
1270
+ * onBeforeCommit(() => assertNoNegativeBalance(fromId));
1271
+ * });
1272
+ * }
1273
+ * ```
1274
+ */
1275
+ declare function onBeforeCommit(callback: BeforeCommitCallback): void;
1276
+ /**
1277
+ * Register a callback to run after the current transaction rolled back
1278
+ *
1279
+ * - Inside a transaction: queued and executed once the work registered with it
1280
+ * is rolled back, before the causing error leaves runInTransaction / the
1281
+ * middleware
1282
+ * - Outside a transaction: no-op with a warning — there is no rollback to wait for
1283
+ * - Nested transactions: the callback belongs to the savepoint that registered
1284
+ * it. If that savepoint rolls back, the callback runs right then, awaited
1285
+ * before the error leaves the nested runInTransaction, and never again — the
1286
+ * root's own afterRollback callbacks do not run when the root commits. If the
1287
+ * savepoint resolved, the callback passes to the root and runs only if the
1288
+ * root rolls back
1289
+ * - After a ROOT rollback, callbacks run outside any transaction context (new
1290
+ * connection for DB access). After a SAVEPOINT rollback the root is still
1291
+ * open: getTransactionContext() is the parent's, so DB work in the callback
1292
+ * joins the parent transaction and commits or rolls back with it
1293
+ * - A statement that FAILS in a savepoint's callback aborts the parent
1294
+ * transaction: the error is logged and swallowed here, but the root's next
1295
+ * statement then fails with 25P02 (current transaction is aborted). If the
1296
+ * root runs none, its COMMIT fails with the callback's error. Either way,
1297
+ * everything the root wrote rolls back. A compensation may call
1298
+ * runInTransaction itself — that opens a savepoint on the parent, which
1299
+ * contains such a failure — and hooks it registers belong to the parent
1300
+ * - A hook registered after its frame (root or savepoint) has settled is
1301
+ * dropped: the frame's queue was handed on, or discarded, when it settled.
1302
+ * Register hooks in the awaited call chain, not from detached work
1303
+ * - Errors are logged but never thrown: the original error keeps propagating
1304
+ * unchanged, never replaced by a callback failure
1305
+ *
1306
+ * @example
1307
+ * ```typescript
1308
+ * import { runInTransaction, onAfterRollback } from '@spfn/core/db';
1309
+ *
1310
+ * async function importAvatar(userId: string, file: Blob)
1311
+ * {
1312
+ * // Upload first: external I/O never belongs inside the transaction.
1313
+ * const key = await objectStore.put(file);
1314
+ *
1315
+ * await runInTransaction(async () =>
1316
+ * {
1317
+ * await userRepo.updateAvatar(userId, key);
1318
+ *
1319
+ * // The upload cannot roll back on its own — undo it if the write never lands.
1320
+ * onAfterRollback(() => objectStore.delete(key));
1321
+ * });
1322
+ * }
1323
+ * ```
1324
+ */
1325
+ declare function onAfterRollback(callback: AfterRollbackCallback): void;
1204
1326
 
1205
1327
  /**
1206
1328
  * Transaction middleware options
@@ -1245,6 +1367,21 @@ interface TransactionalOptions {
1245
1367
  * @default 30000 (30s) or TRANSACTION_IDLE_TIMEOUT environment variable
1246
1368
  */
1247
1369
  idleTimeout?: number;
1370
+ /**
1371
+ * Run in an independent transaction instead of joining an ambient one.
1372
+ *
1373
+ * Only bites when the middleware itself runs nested — a sub-app mounted
1374
+ * under a route that already applied `Transactional()`, or a handler invoked
1375
+ * from inside `runInTransaction`. By default that inner run takes a SAVEPOINT
1376
+ * on the outer transaction; `requiresNew: true` gives it a real `BEGIN` on a
1377
+ * second pooled connection, with its own timeouts and its own hook queues.
1378
+ *
1379
+ * See `RunInTransactionOptions.requiresNew` for the pool and self-deadlock
1380
+ * costs — they apply here unchanged.
1381
+ *
1382
+ * @default false
1383
+ */
1384
+ requiresNew?: boolean;
1248
1385
  }
1249
1386
  /**
1250
1387
  * Transaction middleware for Hono routes
@@ -1282,6 +1419,9 @@ interface TransactionalOptions {
1282
1419
  * - Success: Auto-commit
1283
1420
  * - Error: Auto-rollback
1284
1421
  * - Detects context.error to trigger rollback
1422
+ * - Hooks: this delegates to runInTransaction, so onBeforeCommit, onAfterCommit
1423
+ * and onAfterRollback behave exactly as they do there. afterRollback callbacks
1424
+ * have already run by the time the error reaches the conversion below.
1285
1425
  *
1286
1426
  * 📊 Transaction logging:
1287
1427
  * - Auto-logs transaction start/commit/rollback
@@ -1317,8 +1457,12 @@ interface RunInTransactionOptions {
1317
1457
  * - `timeout: undefined` - Uses default (30s or TRANSACTION_TIMEOUT env var)
1318
1458
  * - `timeout: N` - Sets timeout to N milliseconds (1 to 2147483647)
1319
1459
  *
1320
- * Note: Timeout is only applied to root transactions. Nested transactions
1321
- * (SAVEPOINTs) inherit the timeout from the outer transaction.
1460
+ * Note: Timeout is only applied to root transactions. A nested call takes a
1461
+ * SAVEPOINT on the outer transaction's connection, where the outer
1462
+ * transaction's `SET LOCAL statement_timeout` is already in force — so the
1463
+ * nested call genuinely inherits it, and its own `timeout` is ignored (a
1464
+ * warning is logged when the caller passed one explicitly). A
1465
+ * `requiresNew: true` call is a root and gets its own.
1322
1466
  *
1323
1467
  * @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable
1324
1468
  *
@@ -1355,6 +1499,48 @@ interface RunInTransactionOptions {
1355
1499
  * @default 'transaction'
1356
1500
  */
1357
1501
  context?: string;
1502
+ /**
1503
+ * Run in an independent transaction instead of joining an ambient one.
1504
+ *
1505
+ * By default a call made while another transaction is open takes a SAVEPOINT
1506
+ * on that transaction's connection: its writes commit or roll back with the
1507
+ * outer transaction. `requiresNew: true` opens a real `BEGIN` on a SECOND
1508
+ * pooled connection instead, so the work commits on its own and survives an
1509
+ * outer rollback — an audit trail or a failed-attempt record, for example.
1510
+ *
1511
+ * Being a root transaction, it gets its own `statement_timeout`,
1512
+ * `idle_in_transaction_session_timeout`, and its OWN hook queues:
1513
+ * `onBeforeCommit` / `onAfterCommit` / `onAfterRollback` registered inside it
1514
+ * fire on ITS outcome, not the outer transaction's.
1515
+ *
1516
+ * Two costs, both consequences of the second connection:
1517
+ * - It holds a second connection for its whole duration, so it counts twice
1518
+ * against the pool. Keep it short and don't fan it out.
1519
+ * - It cannot see the outer transaction's uncommitted writes, and it BLOCKS
1520
+ * on any row the outer transaction has locked. Since the outer transaction
1521
+ * is waiting for this call to return, that block is a self-deadlock that
1522
+ * only `statement_timeout` breaks. Never touch rows the outer transaction
1523
+ * wrote.
1524
+ *
1525
+ * @default false
1526
+ *
1527
+ * @example
1528
+ * ```typescript
1529
+ * await runInTransaction(async () =>
1530
+ * {
1531
+ * await orderRepo.create(order);
1532
+ *
1533
+ * // Lands even if the order below rolls the outer transaction back.
1534
+ * await runInTransaction(
1535
+ * () => auditRepo.record('order.attempted', order.id),
1536
+ * { requiresNew: true },
1537
+ * );
1538
+ *
1539
+ * await inventoryRepo.reserve(order.items); // may throw
1540
+ * });
1541
+ * ```
1542
+ */
1543
+ requiresNew?: boolean;
1358
1544
  }
1359
1545
  /**
1360
1546
  * Run a callback function within a database transaction
@@ -1366,6 +1552,15 @@ interface RunInTransactionOptions {
1366
1552
  * - Warns about slow transactions
1367
1553
  * - Enforces timeout if configured
1368
1554
  *
1555
+ * Called with a transaction already open on the async call chain, it takes a
1556
+ * SAVEPOINT on that transaction rather than opening an independent one: the work
1557
+ * runs on the same connection, sees the outer transaction's uncommitted writes,
1558
+ * and commits with it. A throw that the caller catches unwinds to the SAVEPOINT
1559
+ * and leaves the outer transaction healthy; a throw that propagates rolls the
1560
+ * whole thing back. Nested calls off one transaction are serialized — see
1561
+ * `openTransaction` — so `Promise.all` over them runs them one at a time. Pass
1562
+ * `requiresNew: true` for an independent transaction on its own connection.
1563
+ *
1369
1564
  * Errors are propagated to the caller without modification.
1370
1565
  * Caller is responsible for error handling and conversion.
1371
1566
  *
@@ -1680,11 +1875,11 @@ declare function count<T extends PgTable>(table: T, where?: WhereObject<InferSel
1680
1875
  *
1681
1876
  * @example With Transactions
1682
1877
  * ```typescript
1683
- * import { runWithTransaction } from '@spfn/core/db';
1878
+ * import { runInTransaction } from '@spfn/core/db';
1684
1879
  *
1685
1880
  * const userRepo = new UserRepository();
1686
1881
  *
1687
- * await runWithTransaction(async () => {
1882
+ * await runInTransaction(async () => {
1688
1883
  * // Both db and readDb automatically use the transaction context
1689
1884
  * const user = await userRepo.create({ name: 'John' });
1690
1885
  * await userRepo.findById(user.id); // Uses same transaction
@@ -2006,4 +2201,4 @@ declare abstract class BaseRepository<TRelations extends AnyRelations = EmptyRel
2006
2201
  protected _count<T extends PgTable>(table: T, where?: Record<string, any> | SQL | undefined): Promise<number>;
2007
2202
  }
2008
2203
 
2009
- export { type AfterCommitCallback, BaseRepository, type DatabaseClients, type DatabaseInitOptions, type DatabaseOptions, type DatabaseProvider, type DatabaseTransaction, type DefaultDatabase, type DrizzleConfigOptions, type DrizzleDatabase, type FunctionMigrationEntry, type FunctionMigrationInfo, type MigrationStatus, type MigrationStatusDb, type MigrationTargetStatus, PROJECT_MIGRATIONS_TABLE, PROJECT_TARGET_NAME, type PoolConfig, RUN_MIGRATIONS_HINT, type RepositoryDatabase, RepositoryError, type RetryConfig, type RunInTransactionOptions, type TransactionContext, type TransactionDB, Transactional, type TransactionalOptions, auditFields, checkConnection, closeDatabase, collectMigrationStatus, count, countPendingMigrations, create, createDatabaseConnection, createDatabaseFromEnv, createMany, createSchema, deleteMany, deleteOne, detectDialect, discoverFunctionMigrations, enumText, filterPendingEntries, findMany, findOne, forceReconnectDatabase, foreignKey, formatPendingMigrations, fromPostgresError, functionMigrationsTable, generateDrizzleConfigFile, getDatabase, getDatabaseInfo, getDrizzleConfig, getSchemaInfo, getTransaction, getTransactionContext, hasMigrationTargets, id, initDatabase, isConnectionLevelError, migrationTargets, onAfterCommit, optionalForeignKey, packageNameToSchema, pendingMigrationTargets, pendingMigrationsSummary, projectMigrationsDir, publishingFields, readMigrationEntries, reportDatabaseError, resetConnectionErrorCounter, runInTransaction, runWithTransaction, setDatabase, setDatabaseProvider, softDelete, timestamps, typedJsonb, updateMany, updateOne, upsert, utcTimestamp, uuid, verificationTimestamp };
2204
+ export { type AfterCommitCallback, type AfterRollbackCallback, BaseRepository, type BeforeCommitCallback, type DatabaseClients, type DatabaseInitOptions, type DatabaseOptions, type DatabaseProvider, type DatabaseTransaction, type DefaultDatabase, type DrizzleConfigOptions, type DrizzleDatabase, type FunctionMigrationEntry, type FunctionMigrationInfo, type MigrationStatus, type MigrationStatusDb, type MigrationTargetStatus, type NestedFrameGate, PROJECT_MIGRATIONS_TABLE, PROJECT_TARGET_NAME, type PoolConfig, RUN_MIGRATIONS_HINT, type RenderableDrizzleConfig, type RepositoryDatabase, RepositoryError, type RetryConfig, type RunInTransactionOptions, type TransactionContext, type TransactionDB, Transactional, type TransactionalOptions, auditFields, checkConnection, closeDatabase, collectMigrationStatus, count, countPendingMigrations, create, createDatabaseConnection, createDatabaseFromEnv, createMany, createSchema, deleteMany, deleteOne, detectDialect, discoverFunctionMigrations, enumText, filterPendingEntries, findMany, findOne, forceReconnectDatabase, foreignKey, formatPendingMigrations, fromPostgresError, functionMigrationsTable, generateDrizzleConfigFile, getDatabase, getDatabaseInfo, getDrizzleConfig, getSchemaInfo, getTransaction, getTransactionContext, hasMigrationTargets, id, initDatabase, isConnectionLevelError, migrationTargets, onAfterCommit, onAfterRollback, onBeforeCommit, optionalForeignKey, packageNameToSchema, pendingMigrationTargets, pendingMigrationsSummary, projectMigrationsDir, publishingFields, readMigrationEntries, renderDrizzleConfig, reportDatabaseError, resetConnectionErrorCounter, runInTransaction, runWithTransaction, setDatabase, setDatabaseProvider, softDelete, timestamps, typedJsonb, updateMany, updateOne, upsert, utcTimestamp, uuid, verificationTimestamp };