turbine-orm 0.81.0 → 0.90.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/README.md +26 -25
  2. package/dist/checkout.d.ts +27 -2
  3. package/dist/checkout.js +75 -4
  4. package/dist/cjs/checkout.d.ts +27 -2
  5. package/dist/cjs/checkout.js +76 -3
  6. package/dist/cjs/cli/code-first-tags.d.ts +62 -0
  7. package/dist/cjs/cli/code-first-tags.js +124 -0
  8. package/dist/cjs/cli/compile-query.js +9 -0
  9. package/dist/cjs/cli/config.d.ts +35 -6
  10. package/dist/cjs/cli/config.js +17 -1
  11. package/dist/cjs/cli/destructive.d.ts +7 -4
  12. package/dist/cjs/cli/destructive.js +224 -20
  13. package/dist/cjs/cli/error-catalog.js +36 -0
  14. package/dist/cjs/cli/error-text.d.ts +15 -0
  15. package/dist/cjs/cli/error-text.js +40 -0
  16. package/dist/cjs/cli/index.d.ts +62 -4
  17. package/dist/cjs/cli/index.js +568 -108
  18. package/dist/cjs/cli/local-server-guard.d.ts +53 -0
  19. package/dist/cjs/cli/local-server-guard.js +119 -0
  20. package/dist/cjs/cli/local-server-output.d.ts +41 -0
  21. package/dist/cjs/cli/local-server-output.js +103 -0
  22. package/dist/cjs/cli/mcp.d.ts +8 -0
  23. package/dist/cjs/cli/mcp.js +121 -32
  24. package/dist/cjs/cli/migrate.d.ts +113 -5
  25. package/dist/cjs/cli/migrate.js +270 -21
  26. package/dist/cjs/cli/observe.d.ts +6 -1
  27. package/dist/cjs/cli/observe.js +85 -55
  28. package/dist/cjs/cli/pii-predicate-guard.d.ts +43 -23
  29. package/dist/cjs/cli/pii-predicate-guard.js +98 -37
  30. package/dist/cjs/cli/prisma-resolve.js +17 -13
  31. package/dist/cjs/cli/prisma-schema.js +12 -4
  32. package/dist/cjs/cli/studio-ui.generated.js +1 -1
  33. package/dist/cjs/cli/studio.d.ts +14 -2
  34. package/dist/cjs/cli/studio.js +244 -69
  35. package/dist/cjs/cli/ui.d.ts +1 -1
  36. package/dist/cjs/client.d.ts +558 -85
  37. package/dist/cjs/client.js +1270 -395
  38. package/dist/cjs/connection-guard.d.ts +13 -0
  39. package/dist/cjs/connection-guard.js +28 -0
  40. package/dist/cjs/connection-url.d.ts +51 -16
  41. package/dist/cjs/connection-url.js +67 -34
  42. package/dist/cjs/diagnostics.d.ts +81 -0
  43. package/dist/cjs/diagnostics.js +147 -0
  44. package/dist/cjs/dialect.d.ts +449 -20
  45. package/dist/cjs/dialect.js +117 -76
  46. package/dist/cjs/engine-config.d.ts +7 -6
  47. package/dist/cjs/errors.d.ts +126 -6
  48. package/dist/cjs/errors.js +256 -13
  49. package/dist/cjs/generate.d.ts +57 -7
  50. package/dist/cjs/generate.js +635 -279
  51. package/dist/cjs/global-filters-config.d.ts +59 -0
  52. package/dist/cjs/global-filters-config.js +367 -0
  53. package/dist/cjs/index.d.ts +9 -4
  54. package/dist/cjs/index.js +10 -2
  55. package/dist/cjs/introspect.d.ts +31 -6
  56. package/dist/cjs/introspect.js +108 -50
  57. package/dist/cjs/log-codes.d.ts +12 -0
  58. package/dist/cjs/log-codes.js +77 -0
  59. package/dist/cjs/logger.d.ts +87 -0
  60. package/dist/cjs/logger.js +98 -0
  61. package/dist/cjs/mssql.d.ts +8 -5
  62. package/dist/cjs/mssql.js +352 -65
  63. package/dist/cjs/mysql.d.ts +3 -5
  64. package/dist/cjs/mysql.js +420 -70
  65. package/dist/cjs/nested-write.d.ts +3 -0
  66. package/dist/cjs/nested-write.js +179 -114
  67. package/dist/cjs/pipeline-submittable.d.ts +12 -0
  68. package/dist/cjs/pipeline-submittable.js +118 -44
  69. package/dist/cjs/pipeline.js +21 -26
  70. package/dist/cjs/powdb-introspect.d.ts +5 -2
  71. package/dist/cjs/powdb-introspect.js +20 -15
  72. package/dist/cjs/powdb-shared.d.ts +36 -5
  73. package/dist/cjs/powdb-shared.js +67 -8
  74. package/dist/cjs/powdb.d.ts +4 -0
  75. package/dist/cjs/powdb.js +183 -51
  76. package/dist/cjs/powql.d.ts +394 -51
  77. package/dist/cjs/powql.js +1829 -284
  78. package/dist/cjs/prisma-compat.d.ts +23 -15
  79. package/dist/cjs/prisma-compat.js +507 -372
  80. package/dist/cjs/query/aggregates.d.ts +17 -1
  81. package/dist/cjs/query/aggregates.js +261 -29
  82. package/dist/cjs/query/batched-loader.d.ts +25 -6
  83. package/dist/cjs/query/batched-loader.js +103 -20
  84. package/dist/cjs/query/builder.d.ts +325 -184
  85. package/dist/cjs/query/builder.js +1452 -490
  86. package/dist/cjs/query/column-ref.d.ts +61 -0
  87. package/dist/cjs/query/column-ref.js +73 -0
  88. package/dist/cjs/query/compound-unique.d.ts +21 -0
  89. package/dist/cjs/query/compound-unique.js +98 -18
  90. package/dist/cjs/query/deferred.d.ts +53 -16
  91. package/dist/cjs/query/expr.d.ts +217 -0
  92. package/dist/cjs/query/expr.js +859 -0
  93. package/dist/cjs/query/filters.d.ts +155 -53
  94. package/dist/cjs/query/filters.js +613 -76
  95. package/dist/cjs/query/index.d.ts +2 -0
  96. package/dist/cjs/query/index.js +7 -1
  97. package/dist/cjs/query/json-value.d.ts +43 -0
  98. package/dist/cjs/query/json-value.js +59 -0
  99. package/dist/cjs/query/normalize-args.d.ts +87 -0
  100. package/dist/cjs/query/normalize-args.js +527 -0
  101. package/dist/cjs/query/option-surface.d.ts +16 -4
  102. package/dist/cjs/query/option-surface.js +57 -14
  103. package/dist/cjs/query/relation-names.d.ts +14 -0
  104. package/dist/cjs/query/relation-names.js +77 -18
  105. package/dist/cjs/query/relations.d.ts +30 -3
  106. package/dist/cjs/query/relations.js +219 -63
  107. package/dist/cjs/query/row-lock.d.ts +49 -0
  108. package/dist/cjs/query/row-lock.js +138 -0
  109. package/dist/cjs/query/sql-comment.d.ts +161 -0
  110. package/dist/cjs/query/sql-comment.js +381 -0
  111. package/dist/cjs/query/stream-idle.d.ts +132 -0
  112. package/dist/cjs/query/stream-idle.js +212 -0
  113. package/dist/cjs/query/table-client.d.ts +101 -0
  114. package/dist/cjs/query/table-client.js +74 -0
  115. package/dist/cjs/query/types.d.ts +677 -298
  116. package/dist/cjs/query/utils.d.ts +105 -6
  117. package/dist/cjs/query/utils.js +426 -19
  118. package/dist/cjs/query/warn-registry.d.ts +18 -0
  119. package/dist/cjs/query/warn-registry.js +18 -0
  120. package/dist/cjs/query/where-compile.d.ts +138 -14
  121. package/dist/cjs/query/where-compile.js +513 -29
  122. package/dist/cjs/query/where.d.ts +159 -59
  123. package/dist/cjs/query/where.js +716 -246
  124. package/dist/cjs/query/writes.d.ts +112 -50
  125. package/dist/cjs/query/writes.js +1498 -200
  126. package/dist/cjs/query-events.d.ts +4 -2
  127. package/dist/cjs/query-events.js +3 -1
  128. package/dist/cjs/realtime.d.ts +7 -3
  129. package/dist/cjs/realtime.js +13 -2
  130. package/dist/cjs/schema-builder.d.ts +55 -4
  131. package/dist/cjs/schema-builder.js +382 -18
  132. package/dist/cjs/schema-metadata.d.ts +21 -1
  133. package/dist/cjs/schema-metadata.js +29 -7
  134. package/dist/cjs/schema-sql.d.ts +75 -5
  135. package/dist/cjs/schema-sql.js +497 -45
  136. package/dist/cjs/schema.d.ts +26 -5
  137. package/dist/cjs/schema.js +110 -13
  138. package/dist/cjs/sql-placeholders.d.ts +56 -0
  139. package/dist/cjs/sql-placeholders.js +204 -0
  140. package/dist/cjs/sqlite.d.ts +75 -20
  141. package/dist/cjs/sqlite.js +593 -95
  142. package/dist/cjs/supplied-pool-types.d.ts +48 -0
  143. package/dist/cjs/supplied-pool-types.js +256 -0
  144. package/dist/cjs/transaction-control.d.ts +51 -0
  145. package/dist/cjs/transaction-control.js +316 -0
  146. package/dist/cjs/transaction-state.d.ts +342 -0
  147. package/dist/cjs/transaction-state.js +707 -0
  148. package/dist/cjs/typed-sql.d.ts +37 -3
  149. package/dist/cjs/typed-sql.js +102 -8
  150. package/dist/cli/code-first-tags.d.ts +62 -0
  151. package/dist/cli/code-first-tags.js +120 -0
  152. package/dist/cli/compile-query.js +9 -0
  153. package/dist/cli/config.d.ts +35 -6
  154. package/dist/cli/config.js +16 -1
  155. package/dist/cli/destructive.d.ts +7 -4
  156. package/dist/cli/destructive.js +224 -20
  157. package/dist/cli/error-catalog.js +36 -0
  158. package/dist/cli/error-text.d.ts +15 -0
  159. package/dist/cli/error-text.js +37 -0
  160. package/dist/cli/index.d.ts +62 -4
  161. package/dist/cli/index.js +569 -112
  162. package/dist/cli/local-server-guard.d.ts +53 -0
  163. package/dist/cli/local-server-guard.js +113 -0
  164. package/dist/cli/local-server-output.d.ts +41 -0
  165. package/dist/cli/local-server-output.js +98 -0
  166. package/dist/cli/mcp.d.ts +8 -0
  167. package/dist/cli/mcp.js +121 -34
  168. package/dist/cli/migrate.d.ts +113 -5
  169. package/dist/cli/migrate.js +261 -21
  170. package/dist/cli/observe.d.ts +6 -1
  171. package/dist/cli/observe.js +84 -54
  172. package/dist/cli/pii-predicate-guard.d.ts +43 -23
  173. package/dist/cli/pii-predicate-guard.js +100 -35
  174. package/dist/cli/prisma-resolve.js +15 -11
  175. package/dist/cli/prisma-schema.js +12 -4
  176. package/dist/cli/studio-ui.generated.js +1 -1
  177. package/dist/cli/studio.d.ts +14 -2
  178. package/dist/cli/studio.js +246 -71
  179. package/dist/cli/ui.d.ts +1 -1
  180. package/dist/client.d.ts +558 -85
  181. package/dist/client.js +1275 -400
  182. package/dist/connection-guard.d.ts +13 -0
  183. package/dist/connection-guard.js +27 -0
  184. package/dist/connection-url.d.ts +51 -16
  185. package/dist/connection-url.js +63 -34
  186. package/dist/diagnostics.d.ts +81 -0
  187. package/dist/diagnostics.js +144 -0
  188. package/dist/dialect.d.ts +449 -20
  189. package/dist/dialect.js +115 -43
  190. package/dist/engine-config.d.ts +7 -6
  191. package/dist/errors.d.ts +126 -6
  192. package/dist/errors.js +252 -12
  193. package/dist/generate.d.ts +57 -7
  194. package/dist/generate.js +635 -281
  195. package/dist/global-filters-config.d.ts +59 -0
  196. package/dist/global-filters-config.js +361 -0
  197. package/dist/index.d.ts +9 -4
  198. package/dist/index.js +4 -2
  199. package/dist/introspect.d.ts +31 -6
  200. package/dist/introspect.js +106 -50
  201. package/dist/log-codes.d.ts +12 -0
  202. package/dist/log-codes.js +74 -0
  203. package/dist/logger.d.ts +87 -0
  204. package/dist/logger.js +93 -0
  205. package/dist/mssql.d.ts +8 -5
  206. package/dist/mssql.js +354 -67
  207. package/dist/mysql.d.ts +3 -5
  208. package/dist/mysql.js +423 -73
  209. package/dist/nested-write.d.ts +3 -0
  210. package/dist/nested-write.js +177 -112
  211. package/dist/pipeline-submittable.d.ts +12 -0
  212. package/dist/pipeline-submittable.js +117 -44
  213. package/dist/pipeline.js +21 -26
  214. package/dist/powdb-introspect.d.ts +5 -2
  215. package/dist/powdb-introspect.js +21 -16
  216. package/dist/powdb-shared.d.ts +36 -5
  217. package/dist/powdb-shared.js +65 -8
  218. package/dist/powdb.d.ts +4 -0
  219. package/dist/powdb.js +183 -51
  220. package/dist/powql.d.ts +394 -51
  221. package/dist/powql.js +1836 -291
  222. package/dist/prisma-compat.d.ts +23 -15
  223. package/dist/prisma-compat.js +508 -373
  224. package/dist/query/aggregates.d.ts +17 -1
  225. package/dist/query/aggregates.js +263 -32
  226. package/dist/query/batched-loader.d.ts +25 -6
  227. package/dist/query/batched-loader.js +101 -21
  228. package/dist/query/builder.d.ts +325 -184
  229. package/dist/query/builder.js +1458 -495
  230. package/dist/query/column-ref.d.ts +61 -0
  231. package/dist/query/column-ref.js +66 -0
  232. package/dist/query/compound-unique.d.ts +21 -0
  233. package/dist/query/compound-unique.js +97 -19
  234. package/dist/query/deferred.d.ts +53 -16
  235. package/dist/query/expr.d.ts +217 -0
  236. package/dist/query/expr.js +848 -0
  237. package/dist/query/filters.d.ts +155 -53
  238. package/dist/query/filters.js +597 -72
  239. package/dist/query/index.d.ts +2 -0
  240. package/dist/query/index.js +4 -0
  241. package/dist/query/json-value.d.ts +43 -0
  242. package/dist/query/json-value.js +54 -0
  243. package/dist/query/normalize-args.d.ts +87 -0
  244. package/dist/query/normalize-args.js +517 -0
  245. package/dist/query/option-surface.d.ts +16 -4
  246. package/dist/query/option-surface.js +56 -13
  247. package/dist/query/relation-names.d.ts +14 -0
  248. package/dist/query/relation-names.js +77 -19
  249. package/dist/query/relations.d.ts +30 -3
  250. package/dist/query/relations.js +220 -67
  251. package/dist/query/row-lock.d.ts +49 -0
  252. package/dist/query/row-lock.js +131 -0
  253. package/dist/query/sql-comment.d.ts +161 -0
  254. package/dist/query/sql-comment.js +374 -0
  255. package/dist/query/stream-idle.d.ts +132 -0
  256. package/dist/query/stream-idle.js +203 -0
  257. package/dist/query/table-client.d.ts +101 -0
  258. package/dist/query/table-client.js +70 -0
  259. package/dist/query/types.d.ts +677 -298
  260. package/dist/query/utils.d.ts +105 -6
  261. package/dist/query/utils.js +414 -18
  262. package/dist/query/warn-registry.d.ts +18 -0
  263. package/dist/query/warn-registry.js +18 -0
  264. package/dist/query/where-compile.d.ts +138 -14
  265. package/dist/query/where-compile.js +508 -31
  266. package/dist/query/where.d.ts +159 -59
  267. package/dist/query/where.js +711 -248
  268. package/dist/query/writes.d.ts +112 -50
  269. package/dist/query/writes.js +1496 -202
  270. package/dist/query-events.d.ts +4 -2
  271. package/dist/query-events.js +3 -1
  272. package/dist/realtime.d.ts +7 -3
  273. package/dist/realtime.js +13 -2
  274. package/dist/schema-builder.d.ts +55 -4
  275. package/dist/schema-builder.js +381 -18
  276. package/dist/schema-metadata.d.ts +21 -1
  277. package/dist/schema-metadata.js +28 -7
  278. package/dist/schema-sql.d.ts +75 -5
  279. package/dist/schema-sql.js +494 -44
  280. package/dist/schema.d.ts +26 -5
  281. package/dist/schema.js +109 -13
  282. package/dist/sql-placeholders.d.ts +56 -0
  283. package/dist/sql-placeholders.js +200 -0
  284. package/dist/sqlite.d.ts +75 -20
  285. package/dist/sqlite.js +597 -99
  286. package/dist/supplied-pool-types.d.ts +48 -0
  287. package/dist/supplied-pool-types.js +247 -0
  288. package/dist/transaction-control.d.ts +51 -0
  289. package/dist/transaction-control.js +311 -0
  290. package/dist/transaction-state.d.ts +342 -0
  291. package/dist/transaction-state.js +696 -0
  292. package/dist/typed-sql.d.ts +37 -3
  293. package/dist/typed-sql.js +100 -8
  294. package/package.json +7 -4
  295. package/skills/turbine-orm/SKILL.md +56 -6
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ReadOnlyError = exports.UnsupportedFeatureError = exports.OptimisticLockError = exports.PipelineError = exports.ExclusionConstraintError = exports.CheckConstraintError = exports.SerializationFailureError = exports.DeadlockError = exports.NotNullViolationError = exports.ForeignKeyError = exports.UniqueConstraintError = exports.CircularRelationError = exports.MigrationError = exports.RelationError = exports.ConnectionError = exports.ValidationError = exports.TimeoutError = exports.NotFoundError = exports.REDACTED_DETAIL = exports.TurbineError = exports.TurbineErrorCode = void 0;
3
+ exports.InvariantError = exports.INVARIANT_REPORT_HINT = exports.TransactionRolledBackError = exports.ReadOnlyError = exports.UnsupportedFeatureError = exports.OptimisticLockError = exports.PipelineError = exports.ExclusionConstraintError = exports.CheckConstraintError = exports.LockNotAvailableError = exports.SerializationFailureError = exports.DeadlockError = exports.NotNullViolationError = exports.ForeignKeyError = exports.UniqueConstraintError = exports.CircularRelationError = exports.MigrationError = exports.RelationError = exports.ConnectionError = exports.ValidationError = exports.TimeoutError = exports.NotFoundError = exports.REDACTED_DETAIL = exports.TurbineError = exports.TurbineErrorCode = void 0;
4
4
  exports.registerClientErrorMessageMode = registerClientErrorMessageMode;
5
5
  exports.errorMessageModesDiverged = errorMessageModesDiverged;
6
6
  exports.runWithErrorMessageMode = runWithErrorMessageMode;
@@ -39,6 +39,8 @@ exports.TurbineErrorCode = {
39
39
  EXCLUSION_VIOLATION: 'TURBINE_E016',
40
40
  UNSUPPORTED_FEATURE: 'TURBINE_E017',
41
41
  READ_ONLY: 'TURBINE_E018',
42
+ TRANSACTION_ROLLED_BACK: 'TURBINE_E019',
43
+ INVARIANT_VIOLATION: 'TURBINE_E020',
42
44
  };
43
45
  /**
44
46
  * The docs page anchor for a code: `TURBINE_E003` -> `.../errors#e003`.
@@ -622,12 +624,14 @@ function renderWhereForMessage(where, mode) {
622
624
  * `[TURBINE_E001] findUniqueOrThrow on "users" found no record matching where: {"id":1}`
623
625
  *
624
626
  * The full `where` object, `table`, and `operation` are always available as
625
- * structured properties on the error instance regardless of mode.
627
+ * structured properties on the error instance regardless of mode. `where`
628
+ * carries the caller's raw values, so under 'safe' it is NON-ENUMERABLE:
629
+ * `err.where` reads it, while `JSON.stringify`, `util.inspect` and error
630
+ * serializers that copy own enumerable fields leave it out.
626
631
  */
627
632
  class NotFoundError extends TurbineError {
628
633
  static CODE = exports.TurbineErrorCode.NOT_FOUND;
629
634
  table;
630
- where;
631
635
  operation;
632
636
  constructor(input) {
633
637
  // Back-compat: string argument (or undefined), replicate legacy behavior.
@@ -654,7 +658,12 @@ class NotFoundError extends TurbineError {
654
658
  super(exports.TurbineErrorCode.NOT_FOUND, message, { cause });
655
659
  this.name = 'NotFoundError';
656
660
  this.table = table;
657
- this.where = where;
661
+ Object.defineProperty(this, 'where', {
662
+ value: where,
663
+ enumerable: currentErrorMessageMode() === 'verbose',
664
+ writable: false,
665
+ configurable: true,
666
+ });
658
667
  this.operation = operation;
659
668
  }
660
669
  }
@@ -663,18 +672,22 @@ exports.NotFoundError = NotFoundError;
663
672
  class TimeoutError extends TurbineError {
664
673
  static CODE = exports.TurbineErrorCode.TIMEOUT;
665
674
  timeoutMs;
675
+ /** Whether the interrupted statement can have taken effect. See {@link TimeoutOutcome}. */
676
+ outcome;
666
677
  /**
667
678
  * @param timeoutMs the client-side timeout budget in ms. Pass `0` when the
668
679
  * duration is unknown (e.g. a server-side `statement_timeout` cancellation
669
680
  * surfaced via `wrapPgError`, where Turbine did not set the deadline).
670
681
  * @param context human label for the operation ("Query", "Transaction").
671
682
  * @param options optional `message` override and pg `cause` to preserve, used
672
- * when wrapping a driver error rather than a client-side timer expiry.
683
+ * when wrapping a driver error rather than a client-side timer expiry, and
684
+ * the `outcome` (default `'unknown'`, the only answer that is never wrong).
673
685
  */
674
686
  constructor(timeoutMs, context = 'Query', options) {
675
687
  super(exports.TurbineErrorCode.TIMEOUT, options?.message ?? `${context} timed out after ${timeoutMs}ms`, options);
676
688
  this.name = 'TimeoutError';
677
689
  this.timeoutMs = timeoutMs;
690
+ this.outcome = options?.outcome ?? 'unknown';
678
691
  }
679
692
  }
680
693
  exports.TimeoutError = TimeoutError;
@@ -975,6 +988,75 @@ class SerializationFailureError extends TurbineError {
975
988
  }
976
989
  }
977
990
  exports.SerializationFailureError = SerializationFailureError;
991
+ /** Marks a {@link LockNotAvailableError} across copies of this module (it shares E013 with its parent). */
992
+ const LOCK_NOT_AVAILABLE_BRAND = Symbol.for('turbine-orm.lockNotAvailable');
993
+ /**
994
+ * A row lock could not be taken. A locking read with `noWait` found a row
995
+ * locked by another transaction (PostgreSQL 55P03, MySQL 3572), or a lock wait
996
+ * outlasted the server's lock timeout (PostgreSQL 55P03 under `lock_timeout`,
997
+ * MySQL 1205, SQL Server 1222).
998
+ *
999
+ * A {@link SerializationFailureError}: same code (E013) and `isRetryable`, so
1000
+ * code that already retries E013 retries this too. Retry after a backoff, or
1001
+ * read with `skipLocked` to move on to the rows that are free.
1002
+ *
1003
+ * On PostgreSQL the failed statement aborts the transaction it ran in. To keep
1004
+ * the outer transaction alive, take the lock in a nested `tx.$transaction(...)`
1005
+ * (a savepoint) and catch the error outside it.
1006
+ */
1007
+ class LockNotAvailableError extends SerializationFailureError {
1008
+ constructor(opts = {}) {
1009
+ const { cause } = opts;
1010
+ let message = opts.message;
1011
+ if (!message) {
1012
+ const driverMessage = cause?.message;
1013
+ message =
1014
+ `Row lock not available${driverMessage ? `: ${driverMessage}` : ''}. Another transaction holds the lock. ` +
1015
+ 'Retry after a backoff, or read with skipLocked to take only the rows that are free.';
1016
+ }
1017
+ super({ message, cause });
1018
+ this.name = 'LockNotAvailableError';
1019
+ Object.defineProperty(this, LOCK_NOT_AVAILABLE_BRAND, {
1020
+ value: true,
1021
+ enumerable: false,
1022
+ writable: false,
1023
+ configurable: false,
1024
+ });
1025
+ }
1026
+ /**
1027
+ * `instanceof` across two copies of this module. The code alone cannot tell
1028
+ * this class from its parent (both E013), so another copy's instance must
1029
+ * also carry this class's own brand. A caller's subclass answers only for
1030
+ * its own instances, as {@link TurbineError[Symbol.hasInstance]} does.
1031
+ */
1032
+ static [Symbol.hasInstance](value) {
1033
+ // biome-ignore lint/complexity/noThisInStatic: the receiver may be a caller's subclass, see TurbineError
1034
+ // biome-ignore lint/complexity/noUselessThisAlias: one alias carries one suppression
1035
+ const cls = this;
1036
+ if (Function.prototype[Symbol.hasInstance].call(cls, value))
1037
+ return true;
1038
+ if (cls !== LockNotAvailableError)
1039
+ return false;
1040
+ return (SerializationFailureError[Symbol.hasInstance](value) &&
1041
+ value[LOCK_NOT_AVAILABLE_BRAND] === true);
1042
+ }
1043
+ }
1044
+ exports.LockNotAvailableError = LockNotAvailableError;
1045
+ /**
1046
+ * A lock that could not be taken: PostgreSQL 55P03 (`NOWAIT`, or
1047
+ * `lock_timeout`), MySQL 3572 (`NOWAIT`) and 1205 (lock wait timeout), SQL
1048
+ * Server 1222 (lock request timeout). The MySQL and SQL Server shapes arrive
1049
+ * with `.code` already set to 40001 by their engine modules, so the driver's
1050
+ * own number decides.
1051
+ */
1052
+ function isLockNotAvailableError(err, code) {
1053
+ if (code === '55P03' || code === 'ER_LOCK_NOWAIT')
1054
+ return true;
1055
+ const e = err;
1056
+ if (e.errno === 3572)
1057
+ return true;
1058
+ return code === '40001' && (e.errno === 1205 || e.number === 1222);
1059
+ }
978
1060
  /** Thrown when a CHECK constraint is violated (pg code 23514) */
979
1061
  class CheckConstraintError extends TurbineError {
980
1062
  static CODE = exports.TurbineErrorCode.CHECK_VIOLATION;
@@ -1146,24 +1228,114 @@ class ReadOnlyError extends TurbineError {
1146
1228
  * fail-fast flag), so NOTHING can write here and writes must route to the
1147
1229
  * primary. `'rbac'`: the database is writable but THIS connection's role may
1148
1230
  * not write (per-connection permission), so re-authenticating may suffice.
1231
+ * `'transaction'`: the transaction is read-only (`$transaction({ readOnly:
1232
+ * true })`, `BEGIN READ ONLY`, or a read replica, where every transaction
1233
+ * is), so the write belongs in a read-write transaction on the primary.
1149
1234
  */
1150
1235
  reason;
1151
1236
  /**
1152
1237
  * @param detail human-readable description of the refused write (the engine
1153
- * message, or a local fail-fast description). A "route writes to a writable
1154
- * primary" hint is always appended.
1238
+ * message, or a local fail-fast description). A hint naming where the
1239
+ * write belongs is always appended.
1155
1240
  * @param options optional driver `cause` to preserve when wrapping a refusal,
1156
1241
  * and the refusal `reason` (default `'snapshot'`).
1157
1242
  */
1158
1243
  constructor(detail, options) {
1159
- super(exports.TurbineErrorCode.READ_ONLY, `${detail} Route writes to a writable primary.`, {
1244
+ const reason = options?.reason ?? 'snapshot';
1245
+ super(exports.TurbineErrorCode.READ_ONLY, `${detail} ${READ_ONLY_HINTS[reason]}`, {
1160
1246
  cause: options?.cause,
1161
1247
  });
1162
1248
  this.name = 'ReadOnlyError';
1163
- this.reason = options?.reason ?? 'snapshot';
1249
+ this.reason = reason;
1164
1250
  }
1165
1251
  }
1166
1252
  exports.ReadOnlyError = ReadOnlyError;
1253
+ const READ_ONLY_HINTS = {
1254
+ snapshot: 'Route writes to a writable primary.',
1255
+ rbac: 'Route writes to a writable primary.',
1256
+ transaction: 'Run the write in a read-write transaction (not `readOnly: true` or BEGIN READ ONLY) on the primary, ' +
1257
+ 'not a read replica.',
1258
+ };
1259
+ /**
1260
+ * Thrown when work the caller expected to be saved was rolled back instead:
1261
+ * a `$transaction` or `transaction()` whose COMMIT the server answered with
1262
+ * ROLLBACK, a transaction that cannot commit because a statement inside it was
1263
+ * cut short by its `timeout`, or a nested `tx.$transaction(...)` block that
1264
+ * could not be kept for the same reasons.
1265
+ *
1266
+ * PostgreSQL aborts a transaction at its first error. Catching that error
1267
+ * inside the callback does not undo the abort, so the callback returns, the
1268
+ * COMMIT ends as a ROLLBACK, and none of the transaction's writes are saved.
1269
+ * The first failure is attached as `cause`. Nothing was committed, so the
1270
+ * whole transaction can be run again once the cause is dealt with; to keep the
1271
+ * rest of the work after an expected failure, run the statement that can fail
1272
+ * in its own nested `tx.$transaction(...)`.
1273
+ *
1274
+ * NOT retryable on its own: the failure that caused it is not known to be
1275
+ * transient. When that first failure WAS a deadlock or a serialization
1276
+ * conflict, the retryable class (`DeadlockError`, `SerializationFailureError`)
1277
+ * is thrown instead, so `$retry` re-runs the transaction.
1278
+ */
1279
+ class TransactionRolledBackError extends TurbineError {
1280
+ static CODE = exports.TurbineErrorCode.TRANSACTION_ROLLED_BACK;
1281
+ /**
1282
+ * @param message what was rolled back and how to keep the work next time.
1283
+ * @param options the first failure inside the transaction, as `cause`.
1284
+ */
1285
+ constructor(message, options) {
1286
+ super(exports.TurbineErrorCode.TRANSACTION_ROLLED_BACK, message, options);
1287
+ this.name = 'TransactionRolledBackError';
1288
+ }
1289
+ }
1290
+ exports.TransactionRolledBackError = TransactionRolledBackError;
1291
+ /**
1292
+ * The sentence every {@link InvariantError} message ends with, before the docs
1293
+ * link. Exported so a test can assert it without restating it.
1294
+ */
1295
+ exports.INVARIANT_REPORT_HINT = 'This is a bug in turbine-orm, not in your code. Please report it at ' +
1296
+ 'https://github.com/zvndev/turbine-orm/issues with this message.';
1297
+ /**
1298
+ * Turbine detected a bug in itself: a branch that no argument can reach was
1299
+ * reached, or two internal paths that must agree did not (the SQL-template
1300
+ * cache's build and param-collect paths, for example).
1301
+ *
1302
+ * Not caused by the arguments, so rewriting the call is not the fix, and not
1303
+ * retryable: the same call fails the same way. `invariant` is a stable id for
1304
+ * the broken rule (`'sql-cache-lockstep'`, `'sql-cache-param-count'`, ...), so
1305
+ * a report or an alert can group on it. The message names no row or parameter
1306
+ * value.
1307
+ *
1308
+ * Thrown in place of executing a statement Turbine knows is wrong, which is
1309
+ * what makes the checks behind it safe to run in production.
1310
+ */
1311
+ class InvariantError extends TurbineError {
1312
+ static CODE = exports.TurbineErrorCode.INVARIANT_VIOLATION;
1313
+ /** Stable id of the broken invariant, e.g. `'sql-cache-lockstep'`. */
1314
+ invariant;
1315
+ /**
1316
+ * @param invariant stable id of the broken rule.
1317
+ * @param message what disagreed, with no row or parameter value in it. The
1318
+ * report hint is appended once.
1319
+ * @param options the error that exposed the broken rule, as `cause`.
1320
+ */
1321
+ constructor(invariant, message, options) {
1322
+ const body = message.includes(exports.INVARIANT_REPORT_HINT) ? message : `${message} ${exports.INVARIANT_REPORT_HINT}`;
1323
+ super(exports.TurbineErrorCode.INVARIANT_VIOLATION, body, options);
1324
+ this.name = 'InvariantError';
1325
+ this.invariant = invariant;
1326
+ }
1327
+ }
1328
+ exports.InvariantError = InvariantError;
1329
+ /**
1330
+ * A write refused because its transaction is read-only: PostgreSQL SQLSTATE
1331
+ * 25006, or MySQL's error 1792 (which carries the same SQLSTATE).
1332
+ */
1333
+ function isReadOnlyTransactionError(err, code) {
1334
+ if (code === '25006' || code === 'ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION')
1335
+ return true;
1336
+ const e = err;
1337
+ return e.errno === 1792 && e.sqlState === '25006';
1338
+ }
1167
1339
  /**
1168
1340
  * Parse column names out of a pg `detail` string like:
1169
1341
  * "Key (email)=(foo@bar) already exists."
@@ -1195,6 +1367,11 @@ const CONNECTION_ERROR_CODES = new Set([
1195
1367
  '08006', // connection_failure
1196
1368
  '08007', // transaction_resolution_unknown
1197
1369
  '08P01', // protocol_violation
1370
+ // A named prepared statement met a server connection that did not prepare it
1371
+ // (26000) or already holds it (42P05). Turbine names its own statements, so
1372
+ // the usual cause is a transaction-pooling endpoint switching backends.
1373
+ '42P05', // duplicate_prepared_statement
1374
+ '26000', // invalid_sql_statement_name
1198
1375
  // pg SQLSTATE class 28: the server answered and REFUSED us. These are the
1199
1376
  // most common first-run failures there are (wrong password, a pg_hba rule
1200
1377
  // that does not cover this user/host), and they used to fall through
@@ -1214,6 +1391,11 @@ const CONNECTION_ERROR_CODES = new Set([
1214
1391
  '57P01', // admin_shutdown
1215
1392
  '57P02', // crash_shutdown
1216
1393
  '57P03', // cannot_connect_now
1394
+ // The server ended a session that sat idle inside an open transaction past
1395
+ // idle_in_transaction_session_timeout (a FATAL: the connection is gone).
1396
+ // A cursor stream sets that limit on its own transaction, see
1397
+ // query/stream-idle.ts, so this is how a frozen process's stream ends.
1398
+ '25P03', // idle_in_transaction_session_timeout
1217
1399
  // Node driver-level socket errors (surface on err.code too)
1218
1400
  'ECONNREFUSED',
1219
1401
  'ECONNRESET',
@@ -1253,6 +1435,11 @@ const PG_CONNECTION_LOSS_MESSAGES = new Set([
1253
1435
  'Connection terminated',
1254
1436
  'Connection terminated due to connection timeout',
1255
1437
  ]);
1438
+ /** pg-pool's own words for a checkout that waited longer than `connectionTimeoutMillis`. */
1439
+ const PG_POOL_CHECKOUT_TIMEOUT_MESSAGE = 'timeout exceeded when trying to connect';
1440
+ const POOL_CHECKOUT_TIMEOUT_HINT = "Timed out waiting for a free connection from the pool. Something is holding connections for longer than the pool's " +
1441
+ 'connection timeout: long transactions or streams, or a query on the outer client inside a `$transaction` ' +
1442
+ 'callback, which needs a second connection (use `tx` there). Raise the pool size if the load is genuine.';
1256
1443
  /** The follow-on errors pg raises for a query sent to a client already known to be dead. */
1257
1444
  const PG_NOT_QUERYABLE_MESSAGES = new Set([
1258
1445
  'Client has encountered a connection error and is not queryable',
@@ -1311,6 +1498,11 @@ function isStaleConnectionError(err) {
1311
1498
  }
1312
1499
  const CONNECTION_LOSS_HINT = 'The server or the network closed it (a restart, failover, idle timeout, compute suspend, or ' +
1313
1500
  'pg_terminate_backend). The pool discards the connection, so retrying the operation opens a fresh one.';
1501
+ const PREPARED_STATEMENT_POOLER_HINT = 'A named prepared statement met a server connection that did not prepare it, or that already holds it. A ' +
1502
+ 'transaction-pooling endpoint (PgBouncer in transaction mode, a managed "-pooler" host, port 6432 or 6543) ' +
1503
+ 'gives each transaction to a different server connection, which is the usual cause. Connect to the direct ' +
1504
+ 'endpoint, set `preparedStatements: false`, or turn on prepared-statement support in the pooler (PgBouncer ' +
1505
+ '1.21 or later, `max_prepared_statements` above 0).';
1314
1506
  /**
1315
1507
  * Actionable next step per connection-class code, appended to the driver's own
1316
1508
  * message. The driver message states WHAT happened ("password authentication
@@ -1320,11 +1512,18 @@ const CONNECTION_LOSS_HINT = 'The server or the network closed it (a restart, fa
1320
1512
  * A code with no entry here simply gets no hint appended.
1321
1513
  */
1322
1514
  const CONNECTION_ERROR_HINTS = {
1515
+ '42P05': PREPARED_STATEMENT_POOLER_HINT,
1516
+ '26000': PREPARED_STATEMENT_POOLER_HINT,
1323
1517
  '28P01': 'The server rejected the credentials. Check the password in your connection string (or DATABASE_URL), including any URL-encoding of special characters.',
1324
1518
  '28000': "The server refused this user/host combination. Check the user name and the server's pg_hba.conf rules for the client address.",
1325
1519
  '3D000': 'The database named in the connection string does not exist. Check the path segment after the host, and create the database if needed.',
1326
1520
  '53300': "The server has no free connection slots. Lower `poolSize` or raise the server's max_connections.",
1327
1521
  '57P03': 'The server is still starting up (or shutting down) and is not accepting connections yet.',
1522
+ '25P03': 'The server ended the session because it sat idle inside an open transaction for longer than ' +
1523
+ '`idle_in_transaction_session_timeout`. A cursor stream sets that limit to its idle timeout plus 10 s, so for ' +
1524
+ 'a stream this means the process ran nothing for that long (a frozen serverless instance, a blocked event ' +
1525
+ 'loop); for a transaction, that the callback awaited something else for longer than the server allows. The ' +
1526
+ 'connection is discarded and the pool opens a fresh one.',
1328
1527
  ECONNREFUSED: 'Nothing is listening on that host and port. Check the server is running and the port is right.',
1329
1528
  ENOTFOUND: 'The host in the connection string could not be resolved. Check the host name, and that the connection string itself is well formed.',
1330
1529
  EAI_AGAIN: 'DNS lookup for the host failed temporarily. Check network/DNS availability, then retry.',
@@ -1556,9 +1755,13 @@ function scrubUnclassifiedServerError(err, code) {
1556
1755
  * 23P01 (exclusion_violation) -> ExclusionConstraintError
1557
1756
  * 40P01 (deadlock_detected) -> DeadlockError (retryable)
1558
1757
  * 40001 (serialization_failure) -> SerializationFailureError (retryable)
1758
+ * 55P03 (lock_not_available) -> LockNotAvailableError (retryable, E013); also
1759
+ * MySQL 3572 / 1205 and SQL Server 1222
1559
1760
  * 57014 (query_canceled) -> TimeoutError (server-side statement_timeout)
1560
1761
  * 28P01 / 28000 (auth refused) -> ConnectionError, with a remediation hint
1561
1762
  * 3D000 (no such database) -> ConnectionError, with a remediation hint
1763
+ * 42P05 / 26000 (prepared statement name clash or miss, a transaction-mode
1764
+ * pooler) -> ConnectionError, with a remediation hint
1562
1765
  * connection-class codes -> ConnectionError (see CONNECTION_ERROR_CODES)
1563
1766
  * 22xxx (data exception) -> ValidationError naming the column (when the
1564
1767
  * server did) and the SQLSTATE; driver text
@@ -1587,8 +1790,26 @@ function wrapPgError(err) {
1587
1790
  if (err instanceof Error && PG_CONNECTION_LOSS_MESSAGES.has(err.message)) {
1588
1791
  return new ConnectionError(`Database connection lost: ${err.message}. ${CONNECTION_LOSS_HINT}`, { cause: err });
1589
1792
  }
1793
+ // pg-pool's checkout timeout carries no code either. A pool Turbine owns
1794
+ // types it at checkout (checkout.ts); this covers a caller's own pg.Pool.
1795
+ if (err instanceof Error && err.message === PG_POOL_CHECKOUT_TIMEOUT_MESSAGE) {
1796
+ return new ConnectionError(POOL_CHECKOUT_TIMEOUT_HINT, { cause: err });
1797
+ }
1590
1798
  return err;
1591
1799
  }
1800
+ if (isReadOnlyTransactionError(err, e.code)) {
1801
+ const pgMessage = typeof e.message === 'string' && e.message.length > 0 ? e.message : 'write refused';
1802
+ return new ReadOnlyError(`${pgMessage} (SQLSTATE 25006).`, { cause: err, reason: 'transaction' });
1803
+ }
1804
+ if (isLockNotAvailableError(err, e.code))
1805
+ return new LockNotAvailableError({ cause: err });
1806
+ // A protocol violation answered with ERROR rather than FATAL concerns one
1807
+ // message, and the connection stays usable. The common cause is a Buffer
1808
+ // bound to a column that is not bytea: node-postgres sends a Buffer as
1809
+ // binary data, which the server cannot read as an integer or a date.
1810
+ if (e.code === '08P01' && e.severity === 'ERROR') {
1811
+ return wrapValueBearingPgError(err, e, 'Invalid input', 'a bound value could not be read as the type the statement expects', ' A Buffer is sent as binary data and fits only a bytea column; pass a number, string or Date for any other type.');
1812
+ }
1592
1813
  switch (e.code) {
1593
1814
  case '23505': {
1594
1815
  const cols = e.detail ? parseColumnsFromDetail(e.detail) : undefined;
@@ -1633,13 +1854,27 @@ function wrapPgError(err) {
1633
1854
  cause: err,
1634
1855
  });
1635
1856
  case '57014':
1636
- // query_canceled: a server-side statement_timeout cancelled the query.
1637
- // Turbine did not set the deadline (that lives in Postgres config), so
1638
- // there is no client-side budget to report → timeoutMs = 0.
1857
+ // query_canceled: the statement was stopped, so it made no change. A
1858
+ // cancel request (what Turbine sends when a query or transaction
1859
+ // `timeout` expires) reads "due to user request"; anything else is the
1860
+ // server's own statement_timeout.
1639
1861
  return new TimeoutError(0, 'Query', {
1640
- message: 'Query canceled by server-side statement_timeout',
1862
+ message: typeof e.message === 'string' && /user request/i.test(e.message)
1863
+ ? 'Query cancelled on the server by a cancel request, which Turbine sends when a query or ' +
1864
+ 'transaction `timeout` expires. It made no change.'
1865
+ : 'Query canceled by server-side statement_timeout',
1641
1866
  cause: err,
1867
+ outcome: 'not-executed',
1642
1868
  });
1869
+ case '25P02':
1870
+ // in_failed_sql_transaction: a statement sent after an earlier one failed. Turbine's own
1871
+ // transactions refuse it first, with the failure attached (transaction-state.ts); this is
1872
+ // the driver's answer on a path that sent it anyway (a connection used outside Turbine).
1873
+ return new TransactionRolledBackError('A statement was sent after an earlier statement in the same transaction failed. PostgreSQL ignores ' +
1874
+ 'every statement after a failure until the transaction, or the savepoint it ran in, is rolled back, ' +
1875
+ 'so nothing more can be saved in it. Catching the error does not undo the abort: let it leave the ' +
1876
+ 'transaction, or run the statement that can fail in its own nested `tx.$transaction(...)`, which ' +
1877
+ 'rolls back only that savepoint. The earlier failure is the error that statement threw.', { cause: err });
1643
1878
  default:
1644
1879
  if (CONNECTION_ERROR_CODES.has(e.code)) {
1645
1880
  const pgMessage = typeof e.message === 'string' && e.message.length > 0 ? e.message : undefined;
@@ -1662,6 +1897,14 @@ function wrapPgError(err) {
1662
1897
  : DATA_EXCEPTION_FALLBACK;
1663
1898
  return wrapValueBearingPgError(err, e, subject, phrase);
1664
1899
  }
1900
+ // 42883: no operator or function for these argument types, e.g. a bigint
1901
+ // column compared with text. PostgreSQL's message names types, never
1902
+ // values, so it is kept in both modes.
1903
+ if (e.code === '42883') {
1904
+ const pgMessage = typeof e.message === 'string' && e.message.length > 0 ? `${e.message} ` : '';
1905
+ return new ValidationError(`${pgMessage}(SQLSTATE 42883). A value of one type was compared with or passed to something that takes ` +
1906
+ "another, usually a value bound to a column of a different type. Pass a value of the column's type.", { cause: err, sqlstate: e.code });
1907
+ }
1665
1908
  // 42601 is any syntax error. Only the to_tsquery parse failure is a
1666
1909
  // caller-input problem Turbine can name (the `search` operator), so the
1667
1910
  // message text is the discriminator; every other 42601 takes the generic
@@ -8,10 +8,36 @@
8
8
  *
9
9
  * Output goes to the specified directory (default: ./generated/turbine/).
10
10
  */
11
- import { type PrismaCompatMap, type SchemaMetadata } from './schema.js';
11
+ import { type TurbineLogger } from './logger.js';
12
+ import { type ColumnMetadata, type PrismaCompatMap, type SchemaMetadata } from './schema.js';
13
+ /**
14
+ * Per-column TypeScript overrides from {@link GenerateOptions.columnTypes},
15
+ * keyed by database table name, then database column name.
16
+ */
17
+ type ColumnTypeOverrides = ReadonlyMap<string, ReadonlyMap<string, string>>;
18
+ /**
19
+ * Resolve the TypeScript type for a column, mapping enum-typed columns to their
20
+ * generated string-literal union (PascalCase enum name) instead of the
21
+ * `unknown` that {@link pgTypeToTs} yields for user-defined types. A
22
+ * `columnTypes` override replaces the type outright (nullability is still
23
+ * added). Falls back to the introspected `col.tsType` for everything else.
24
+ */
25
+ export declare function columnTsType(col: ColumnMetadata, enums: Record<string, string[]>, override?: string): string;
26
+ /**
27
+ * Validate {@link GenerateOptions.columnTypes} against the schema and index it.
28
+ * A key naming no table or column is a `ValidationError`, not a silent no-op,
29
+ * since an override that applies to nothing leaves the column typed `unknown`.
30
+ */
31
+ export declare function resolveColumnTypeOverrides(schema: SchemaMetadata, columnTypes: Readonly<Record<string, string>> | undefined): ColumnTypeOverrides | undefined;
12
32
  export interface GenerateOptions {
13
33
  /** The introspected schema to generate from */
14
34
  schema: SchemaMetadata;
35
+ /**
36
+ * Where generation notes go (a relation omitted from the generated types
37
+ * because it shadows a column). Defaults to the console logger. Never
38
+ * affects the generated files.
39
+ */
40
+ logger?: TurbineLogger;
15
41
  /** Output directory (default: './generated/turbine') */
16
42
  outDir?: string;
17
43
  /** Redact connection string from generated comments */
@@ -36,6 +62,10 @@ export interface GenerateOptions {
36
62
  *
37
63
  * - `'js'`: always `./types.js` (required by NodeNext `tsc` and by
38
64
  * tsc-compiled ESM run on Node; the pre-0.41 behavior).
65
+ * - `'ts'`: always `./types.ts`, so Node's native type stripping can run the
66
+ * generated files directly (`node app.ts`). A type checker needs
67
+ * `allowImportingTsExtensions` or `rewriteRelativeImportExtensions` to
68
+ * accept it. `'auto'` never picks this.
39
69
  * - `'none'`: always `./types` (correct for bundlers / `moduleResolution
40
70
  * bundler | node10`: webpack, Next.js/SWC, Vite/esbuild).
41
71
  * - `'auto'` (default): walk up from `outDir` to the nearest `tsconfig.json`
@@ -44,7 +74,7 @@ export interface GenerateOptions {
44
74
  * neither is, and fall back to `'.js'` when the tsconfig is missing,
45
75
  * unparseable, or ambiguous (so NodeNext consumers can never regress).
46
76
  */
47
- importExtension?: 'js' | 'none' | 'auto';
77
+ importExtension?: 'js' | 'ts' | 'none' | 'auto';
48
78
  /**
49
79
  * Rewrite generated column FIELD names to the raw database column names
50
80
  * (snake_case) instead of camelCase (F4). Opt-in; when unset the output is
@@ -54,18 +84,36 @@ export interface GenerateOptions {
54
84
  * names are unaffected.
55
85
  */
56
86
  keepColumnNames?: boolean;
87
+ /**
88
+ * TypeScript types for specific columns, keyed `"<table>.<column>"` with
89
+ * database names. The value is emitted as written into the row type and the
90
+ * `*Create` / `*Update` input types (`| null` is added for a nullable
91
+ * column), so a json/jsonb column can carry its real shape instead of
92
+ * `unknown`:
93
+ *
94
+ * columnTypes: { 'users.settings': "import('../src/settings.js').Settings" }
95
+ *
96
+ * A relative `import()` resolves from the output directory. The type is a
97
+ * compile-time claim: nothing checks stored values against it. A key naming
98
+ * no table or column is an error.
99
+ */
100
+ columnTypes?: Readonly<Record<string, string>>;
57
101
  }
58
102
  /** Per-file generator options (subset of {@link GenerateOptions} the emitters need). */
59
103
  export interface GenerateFileOptions {
60
104
  /** Omit the `Generated at:` header line for reproducible output. */
61
105
  noTimestamp?: boolean;
62
106
  /**
63
- * Resolved sibling-import extension for `generateIndex` (`'.js'` or `''`).
107
+ * Resolved sibling-import extension for `generateIndex` (`'.js'`, `'.ts'` or `''`).
64
108
  * Defaults to `'.js'` when unset so direct callers stay byte-stable.
65
109
  */
66
110
  importExt?: string;
67
111
  /** Human-readable resolved import mode, recorded as a comment in `index.ts`. */
68
112
  importMode?: string;
113
+ /** {@link GenerateOptions.columnTypes}; validated against the schema by the emitter. */
114
+ columnTypes?: Readonly<Record<string, string>>;
115
+ /** {@link GenerateOptions.logger}. */
116
+ logger?: TurbineLogger;
69
117
  }
70
118
  export declare function generate(options: GenerateOptions): {
71
119
  outDir: string;
@@ -77,12 +125,13 @@ export declare function generate(options: GenerateOptions): {
77
125
  * mode label for the generated comment.
78
126
  *
79
127
  * - `'js'` → `.js`
128
+ * - `'ts'` → `.ts`
80
129
  * - `'none'` → `''`
81
130
  * - `'auto'` → tsconfig-driven ({@link detectTsconfigExtension}); falls back
82
131
  * to `.js` (the pre-0.41 default) when detection is uncertain, so NodeNext
83
132
  * consumers can never regress.
84
133
  */
85
- export declare function resolveImportExtension(outDir: string, requested: 'js' | 'none' | 'auto'): {
134
+ export declare function resolveImportExtension(outDir: string, requested: 'js' | 'ts' | 'none' | 'auto'): {
86
135
  ext: string;
87
136
  mode: string;
88
137
  };
@@ -137,10 +186,10 @@ export declare function isEmittableIdentifier(name: string): boolean;
137
186
  export declare function assertEmittableSchema(schema: SchemaMetadata): void;
138
187
  /**
139
188
  * Generate the contents of `types.ts` (entity interfaces, *Create / *Update,
140
- * and *Relations brand-field interfaces). Exported so tests can pin the
141
- * generator output without writing files to disk.
189
+ * *Relations brand-field interfaces, and the write input types). Exported so
190
+ * tests can pin the generator output without writing files to disk.
142
191
  */
143
- export declare function generateTypes(schema: SchemaMetadata, options?: GenerateFileOptions): string;
192
+ export declare function generateTypes(input: SchemaMetadata, options?: GenerateFileOptions): string;
144
193
  /**
145
194
  * Generate the contents of `zod.ts`. Emits, per table, `XSchema` (the full
146
195
  * row), `XCreateSchema` (PK/defaulted/nullable columns optional, STORED
@@ -161,3 +210,4 @@ export declare function generateIndex(schema: SchemaMetadata, options?: Generate
161
210
  * stable input regenerates byte-identical output under `noTimestamp`.
162
211
  */
163
212
  export declare function generatePrismaMap(map: PrismaCompatMap, options?: GenerateFileOptions): string;
213
+ export {};