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
@@ -16,6 +16,8 @@ exports.DEFAULT_EXCLUDED_TABLES = void 0;
16
16
  exports.pgConfActionToReferential = pgConfActionToReferential;
17
17
  exports.applyTableFilters = applyTableFilters;
18
18
  exports.defaultExcludedTablesPresent = defaultExcludedTablesPresent;
19
+ exports.printableCatalogName = printableCatalogName;
20
+ exports.nullRecord = nullRecord;
19
21
  exports.assertSafeCatalogIdentifier = assertSafeCatalogIdentifier;
20
22
  exports.assertSafeCatalogSchema = assertSafeCatalogSchema;
21
23
  exports.introspect = introspect;
@@ -38,6 +40,7 @@ exports.deriveEngineRelations = deriveEngineRelations;
38
40
  const _pg_1 = __importDefault(require("pg"));
39
41
  const dialect_js_1 = require("./dialect.js");
40
42
  const errors_js_1 = require("./errors.js");
43
+ const logger_js_1 = require("./logger.js");
41
44
  const schema_js_1 = require("./schema.js");
42
45
  /**
43
46
  * Map a `pg_constraint.confdeltype` / `confupdtype` character to a
@@ -356,6 +359,58 @@ function defaultExcludedTablesPresent(names, options = {}) {
356
359
  */
357
360
  // biome-ignore lint/suspicious/noControlCharactersInRegex: detecting control characters is this pattern's purpose
358
361
  const UNSAFE_CATALOG_CHARS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
362
+ /**
363
+ * Characters that must not reach a terminal or a log verbatim: everything in
364
+ * {@link UNSAFE_CATALOG_CHARS} (an ESC starts an ANSI sequence, a carriage
365
+ * return overwrites the line), plus the bidirectional controls that reorder how
366
+ * a name is displayed without changing what it is.
367
+ */
368
+ // biome-ignore lint/suspicious/noControlCharactersInRegex: neutralizing control characters is this pattern's purpose
369
+ const TERMINAL_UNSAFE_CHARS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029\u200e\u200f\u202a-\u202e\u2066-\u2069]/g;
370
+ /**
371
+ * A catalog name made safe to PRINT. Every diagnostic that quotes a table,
372
+ * column, enum, relation or constraint name goes through this, because Postgres
373
+ * lets anyone with CREATE privilege pick any characters for those, and an
374
+ * unescaped name in an error message is a way to write escape sequences to the
375
+ * developer's terminal. Control and bidi characters become visible escapes
376
+ * (`\n`, `\u001b`); everything else, including non-ASCII letters, is untouched.
377
+ */
378
+ function printableCatalogName(name) {
379
+ return name.replace(TERMINAL_UNSAFE_CHARS, (ch) => {
380
+ if (ch === '\n')
381
+ return '\\n';
382
+ if (ch === '\r')
383
+ return '\\r';
384
+ if (ch === '\t')
385
+ return '\\t';
386
+ return `\\u${ch.charCodeAt(0).toString(16).padStart(4, '0')}`;
387
+ });
388
+ }
389
+ /**
390
+ * An empty record for something keyed by catalog names. Prototype-less on
391
+ * purpose: a plain `{}` turns a table named `__proto__` into a prototype
392
+ * assignment (the table silently disappears), and makes `enums['constructor']`
393
+ * truthy before any enum was ever added.
394
+ */
395
+ function nullRecord() {
396
+ return Object.create(null);
397
+ }
398
+ /**
399
+ * The TypeScript type for a catalog type name. A user-defined type can be named
400
+ * after an `Object.prototype` member (`toString`, `constructor`, `valueOf`),
401
+ * which a plain-object type table answers with a function instead of nothing, so
402
+ * that case is pinned to `unknown` here, before any type table is consulted,
403
+ * rather than emitted as function source. `lookup` is the dialect's own mapping
404
+ * for every other name.
405
+ */
406
+ function tsTypeForCatalogType(typeName, nullable, lookup = schema_js_1.pgTypeToTs) {
407
+ const isArray = typeName.startsWith('_');
408
+ if ((isArray ? typeName.slice(1) : typeName) in Object.prototype) {
409
+ const unknownType = isArray ? 'unknown[]' : 'unknown';
410
+ return nullable ? `${unknownType} | null` : unknownType;
411
+ }
412
+ return lookup(typeName, nullable);
413
+ }
359
414
  /**
360
415
  * Refuse one catalog identifier carrying a character from
361
416
  * {@link UNSAFE_CATALOG_CHARS}. `subject` names the object in the error.
@@ -365,7 +420,7 @@ function assertSafeCatalogIdentifier(name, subject) {
365
420
  if (match === null)
366
421
  return;
367
422
  const code = match[0].charCodeAt(0).toString(16).padStart(4, '0');
368
- throw new errors_js_1.ValidationError(`Refusing to introspect ${subject}: its name contains the control character U+${code.toUpperCase()} ` +
423
+ throw new errors_js_1.ValidationError(`Refusing to introspect ${printableCatalogName(subject)}: its name contains the control character U+${code.toUpperCase()} ` +
369
424
  `at position ${match.index}. Such a name cannot be safely emitted into generated code, SQL comments, or ` +
370
425
  `tooling output. Rename the database object, or exclude it from introspection.`);
371
426
  }
@@ -425,14 +480,15 @@ function assertSafeCatalogSchema(schema) {
425
480
  /**
426
481
  * Introspect a database into {@link SchemaMetadata}, routing through the active
427
482
  * dialect's {@link Dialect.introspector} so each engine can override the catalog
428
- * SQL. PostgreSQL is driven by {@link introspectPostgresCatalog}.
483
+ * SQL. A dialect with none, PostgreSQL included, is read by
484
+ * {@link introspectPostgresCatalog}.
429
485
  */
430
486
  async function introspect(options) {
431
487
  const dialect = options.dialect ?? dialect_js_1.postgresDialect;
432
488
  const introspector = dialect.introspector;
433
489
  const schema = introspector
434
490
  ? await introspector.introspect(options)
435
- : // Dialects without an introspector fall back to the Postgres catalog reader.
491
+ : // PostgreSQL, and any dialect without an introspector, reads the Postgres catalog.
436
492
  await introspectPostgresCatalog(options);
437
493
  // Applied here rather than inside each introspector so every engine gets it.
438
494
  const renamed = options.relationNames ? applyRelationRenames(schema, options.relationNames) : schema;
@@ -458,18 +514,18 @@ async function introspect(options) {
458
514
  * means the call sites it was supposed to fix break at runtime instead.
459
515
  */
460
516
  function applyRelationRenames(schema, renames) {
461
- const tables = { ...schema.tables };
517
+ const tables = Object.assign(nullRecord(), schema.tables);
462
518
  for (const [table, mapping] of Object.entries(renames)) {
463
- const meta = tables[table];
519
+ const meta = Object.hasOwn(tables, table) ? tables[table] : undefined;
464
520
  if (!meta) {
465
- throw new errors_js_1.ValidationError(`relationNames: unknown table "${table}". Known tables: ${Object.keys(tables).join(', ')}.`);
521
+ throw new errors_js_1.ValidationError(`relationNames: unknown table "${printableCatalogName(table)}". Known tables: ${Object.keys(tables).map(printableCatalogName).join(', ')}.`);
466
522
  }
467
- const relations = { ...meta.relations };
523
+ const relations = Object.assign(nullRecord(), meta.relations);
468
524
  const columnFields = new Set(Object.values(meta.columnMap));
469
525
  for (const [from, to] of Object.entries(mapping)) {
470
526
  if (!Object.hasOwn(relations, from)) {
471
- throw new errors_js_1.ValidationError(`relationNames: table "${table}" has no relation "${from}". ` +
472
- `Derived relations: ${Object.keys(relations).join(', ') || '(none)'}.`);
527
+ throw new errors_js_1.ValidationError(`relationNames: table "${printableCatalogName(table)}" has no relation "${printableCatalogName(from)}". ` +
528
+ `Derived relations: ${Object.keys(relations).map(printableCatalogName).join(', ') || '(none)'}.`);
473
529
  }
474
530
  if (from === to)
475
531
  continue;
@@ -522,21 +578,21 @@ function assertDistinctColumnFields(tableName, columns) {
522
578
  for (const [field, names] of columnsByField) {
523
579
  if (names.length < 2)
524
580
  continue;
525
- const quoted = names.map((n) => `"${n}"`);
581
+ const quoted = names.map((n) => `"${printableCatalogName(n)}"`);
526
582
  const list = `${quoted.slice(0, -1).join(', ')} and ${quoted[quoted.length - 1]}`;
527
- collisions.push(`columns ${list} ${names.length === 2 ? 'both' : 'all'} resolve to the field "${field}"`);
583
+ collisions.push(`columns ${list} ${names.length === 2 ? 'both' : 'all'} resolve to the field "${printableCatalogName(field)}"`);
528
584
  }
529
585
  if (collisions.length === 0)
530
586
  return;
531
- throw new errors_js_1.ValidationError(`Field collision on table "${tableName}": ${collisions.join('; ')}. A client addresses one column per field, ` +
587
+ throw new errors_js_1.ValidationError(`Field collision on table "${printableCatalogName(tableName)}": ${collisions.join('; ')}. A client addresses one column per field, ` +
532
588
  'so reads would fold the colliding columns into one property and a write to that field would reach only ' +
533
589
  'one of them. Rename one of the columns, or set `keepColumnNames: true` in turbine.config.ts ' +
534
590
  '(`turbine generate --keep-column-names`) so every field is its raw column name.');
535
591
  }
536
592
  /**
537
593
  * PostgreSQL catalog introspector: reads information_schema + pg_catalog and
538
- * produces {@link SchemaMetadata}. This is the implementation wrapped by
539
- * `postgresDialect.introspector`; call {@link introspect} for dialect routing.
594
+ * produces {@link SchemaMetadata}. {@link introspect} calls it for PostgreSQL;
595
+ * call {@link introspect} for dialect routing.
540
596
  */
541
597
  async function introspectPostgresCatalog(options) {
542
598
  const schema = options.schema ?? 'public';
@@ -609,8 +665,7 @@ async function introspectPostgresCatalog(options) {
609
665
  field: options.keepColumnNames ? row.column_name : (0, schema_js_1.snakeToCamel)(row.column_name),
610
666
  dialectType,
611
667
  pgType: dialectType,
612
- tsType: dialect.typeToTypeScript?.(isArray ? dialectType : baseType, isNullable) ??
613
- (0, schema_js_1.pgTypeToTs)(isArray ? dialectType : baseType, isNullable),
668
+ tsType: tsTypeForCatalogType(isArray ? dialectType : baseType, isNullable, dialect.typeToTypeScript?.bind(dialect) ?? schema_js_1.pgTypeToTs),
614
669
  nullable: isNullable,
615
670
  hasDefault: row.column_default !== null,
616
671
  // Server-generated = a sequence default (serial/BIGSERIAL → nextval(…))
@@ -706,9 +761,9 @@ async function introspectPostgresCatalog(options) {
706
761
  });
707
762
  }
708
763
  // ----- Collect enums -----
709
- const enums = {};
764
+ const enums = nullRecord();
710
765
  for (const row of enumResult.rows) {
711
- if (!enums[row.typname])
766
+ if (!Object.hasOwn(enums, row.typname))
712
767
  enums[row.typname] = [];
713
768
  enums[row.typname].push(row.enumlabel);
714
769
  }
@@ -754,9 +809,9 @@ async function introspectPostgresCatalog(options) {
754
809
  }
755
810
  const foreignKeys = Array.from(fkGroups.values());
756
811
  if (crossSchemaRefs.length > 0) {
757
- console.warn(`[turbine] Skipped ${crossSchemaRefs.length} foreign key(s) referencing a table outside schema "${schema}": ` +
758
- `${crossSchemaRefs.join(', ')}. Generated clients address tables by bare name within one schema, so no ` +
759
- `relation is emitted for these. Introspect the other schema separately, or add the target table to this one.`);
812
+ (0, logger_js_1.logTo)(options.logger ?? logger_js_1.consoleLogger, 'warn', `Skipped ${crossSchemaRefs.length} foreign key(s) referencing a table outside schema "${printableCatalogName(schema)}": ` +
813
+ `${crossSchemaRefs.map(printableCatalogName).join(', ')}. Generated clients address tables by bare name within one schema, so no ` +
814
+ `relation is emitted for these. Introspect the other schema separately, or add the target table to this one.`, { code: 'introspect-cross-schema-fk', schema, references: crossSchemaRefs.length });
760
815
  }
761
816
  // Referential actions (ON DELETE / ON UPDATE) per constraint. Keyed
762
817
  // "<table>::<constraint>" because the NAME alone is not unique (the same
@@ -789,16 +844,17 @@ async function introspectPostgresCatalog(options) {
789
844
  enums,
790
845
  fkActions,
791
846
  legacyToManyUniques: options.legacyToManyUniques,
847
+ ...(options.logger !== undefined ? { logger: options.logger } : {}),
792
848
  });
793
849
  // ----- Assemble TableMetadata for each table -----
794
- const tables = {};
850
+ const tables = nullRecord();
795
851
  for (const tableName of tableNames) {
796
852
  const columns = columnsByTable.get(tableName) ?? [];
797
- const columnMap = {};
798
- const reverseColumnMap = {};
853
+ const columnMap = nullRecord();
854
+ const reverseColumnMap = nullRecord();
799
855
  const dateColumns = new Set();
800
- const dialectTypes = {};
801
- const pgTypes = {};
856
+ const dialectTypes = nullRecord();
857
+ const pgTypes = nullRecord();
802
858
  const allColumns = [];
803
859
  for (const col of columns) {
804
860
  columnMap[col.field] = col.name;
@@ -822,7 +878,7 @@ async function introspectPostgresCatalog(options) {
822
878
  allColumns,
823
879
  primaryKey: pkByTable.get(tableName) ?? [],
824
880
  uniqueColumns: uniqueByTable.get(tableName) ?? [],
825
- relations: relationsByTable.get(tableName) ?? {},
881
+ relations: relationsByTable.get(tableName) ?? nullRecord(),
826
882
  indexes: indexesByTable.get(tableName) ?? [],
827
883
  checks: checksByTable.get(tableName) ?? [],
828
884
  ...(viewNameSet.has(tableName) ? { isView: true } : {}),
@@ -1209,13 +1265,13 @@ function detectUniqueForeignKeySets(pkByTable, uniqueByTable, indexesByTable) {
1209
1265
  * colliding name would otherwise shadow a column field and generate types
1210
1266
  * that fail `tsc --strict` (TS2430/TS2322).
1211
1267
  */
1212
- function resolveRelationNameCollision(candidate, taken, table, source) {
1268
+ function resolveRelationNameCollision(candidate, taken, table, source, logger) {
1213
1269
  if (!taken.has(candidate))
1214
1270
  return candidate;
1215
1271
  let name = `${candidate}Rel`;
1216
1272
  for (let i = 2; taken.has(name); i++)
1217
1273
  name = `${candidate}Rel${i}`;
1218
- console.warn(`[turbine] Relation name "${candidate}" on table "${table}" (from ${source}) collides with an existing column or relation, using "${name}" instead.`);
1274
+ (0, logger_js_1.logTo)(logger, 'warn', printableCatalogName(`Relation name "${candidate}" on table "${table}" (from ${source}) collides with an existing column or relation, using "${name}" instead.`), { code: 'introspect-relation-renamed', table, relation: name, wanted: candidate });
1219
1275
  return name;
1220
1276
  }
1221
1277
  /**
@@ -1257,7 +1313,7 @@ function resolveRelationNameCollision(candidate, taken, table, source) {
1257
1313
  * engine introspectors and `defineSchema` path do) to keep every reverse
1258
1314
  * relation `hasMany`.
1259
1315
  */
1260
- function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActions, unknownTypedFieldsByTable, uniqueSetsByTable) {
1316
+ function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActions, unknownTypedFieldsByTable, uniqueSetsByTable, logger = logger_js_1.consoleLogger) {
1261
1317
  // Count FKs per (source, target) pair for disambiguation.
1262
1318
  const fkCounts = new Map();
1263
1319
  for (const fk of foreignKeys) {
@@ -1293,18 +1349,19 @@ function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActio
1293
1349
  const taken = takenFor(table);
1294
1350
  if (!taken.has(legacy))
1295
1351
  return legacy;
1296
- // Historical json/jsonb shadow: previously worked at runtime AND compiled
1297
- // (tsType `unknown` absorbs the relation payload). Keep the name, warn -
1298
- // typeSafeRelations() keeps the generated type layer sound.
1352
+ // A relation named like a json/jsonb column keeps that name: it works at
1353
+ // runtime and compiles (the column's `unknown` type absorbs the relation
1354
+ // payload). Keep it and warn; typeSafeRelations() keeps the generated types
1355
+ // sound.
1299
1356
  if (!assignedFor(table).has(legacy) && unknownTypedFieldsByTable?.get(table)?.has(legacy)) {
1300
- console.warn(`[turbine] Relation "${legacy}" on table "${table}" (from ${source}) shadows the json/jsonb column ` +
1357
+ (0, logger_js_1.logTo)(logger, 'warn', printableCatalogName(`Relation "${legacy}" on table "${table}" (from ${source}) shadows the json/jsonb column ` +
1301
1358
  `"${legacy}", keeping the historical name for runtime compatibility; the relation is omitted from ` +
1302
- `the generated types. Rename the column to expose it.`);
1359
+ `the generated types. Rename the column to expose it.`), { code: 'introspect-relation-shadows-json', table, relation: legacy });
1303
1360
  return legacy;
1304
1361
  }
1305
1362
  if (modern !== null && modern !== legacy && !taken.has(modern))
1306
1363
  return modern;
1307
- return resolveRelationNameCollision(modern ?? legacy, taken, table, source);
1364
+ return resolveRelationNameCollision(modern ?? legacy, taken, table, source, logger);
1308
1365
  };
1309
1366
  for (const fk of foreignKeys) {
1310
1367
  const pairKey = `${fk.sourceTable}→${fk.targetTable}`;
@@ -1353,7 +1410,7 @@ function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActio
1353
1410
  if (actions?.onUpdate && actions.onUpdate !== 'no action')
1354
1411
  actionFields.onUpdate = actions.onUpdate;
1355
1412
  if (!relationsByTable.has(fk.sourceTable))
1356
- relationsByTable.set(fk.sourceTable, {});
1413
+ relationsByTable.set(fk.sourceTable, nullRecord());
1357
1414
  relationsByTable.get(fk.sourceTable)[belongsToName] = {
1358
1415
  type: 'belongsTo',
1359
1416
  name: belongsToName,
@@ -1394,7 +1451,7 @@ function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActio
1394
1451
  takenFor(fk.targetTable).add(reverseName);
1395
1452
  assignedFor(fk.targetTable).add(reverseName);
1396
1453
  if (!relationsByTable.has(fk.targetTable))
1397
- relationsByTable.set(fk.targetTable, {});
1454
+ relationsByTable.set(fk.targetTable, nullRecord());
1398
1455
  relationsByTable.get(fk.targetTable)[reverseName] = {
1399
1456
  type: reverseType,
1400
1457
  name: reverseName,
@@ -1433,7 +1490,7 @@ function buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, fkActio
1433
1490
  * - a shadowed concrete-typed column → deterministic `Rel` suffix + warn
1434
1491
  * instead of silently dropping the relation.
1435
1492
  */
1436
- function addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, columnNamesByTable, relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, uniqueIndexColsByTable) {
1493
+ function addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, columnNamesByTable, relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, uniqueIndexColsByTable, logger = logger_js_1.consoleLogger) {
1437
1494
  for (const tableName of tableNames) {
1438
1495
  // FKs whose source is this table, both must be single-column.
1439
1496
  const tableFks = foreignKeys.filter((fk) => fk.sourceTable === tableName);
@@ -1479,22 +1536,22 @@ function addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, columnNa
1479
1536
  const targetTbl = other.targetTable; // B
1480
1537
  let relName = (0, schema_js_1.snakeToCamel)(targetTbl); // plural table name → e.g. "tags"
1481
1538
  if (!relationsByTable.has(sourceTbl))
1482
- relationsByTable.set(sourceTbl, {});
1539
+ relationsByTable.set(sourceTbl, nullRecord());
1483
1540
  const existing = relationsByTable.get(sourceTbl);
1484
1541
  // Additive-only: never clobber an existing relation name.
1485
- if (existing[relName])
1542
+ if (Object.hasOwn(existing, relName))
1486
1543
  return;
1487
1544
  const columnFields = columnFieldsByTable?.get(sourceTbl);
1488
1545
  if (columnFields?.has(relName)) {
1489
1546
  if (unknownTypedFieldsByTable?.get(sourceTbl)?.has(relName)) {
1490
- // Historical json/jsonb shadow, worked at runtime, compiled fine.
1491
- console.warn(`[turbine] Relation "${relName}" on table "${sourceTbl}" (junction ${tableName}) shadows the ` +
1547
+ // Same json/jsonb shadow as above: keep the name and warn.
1548
+ (0, logger_js_1.logTo)(logger, 'warn', printableCatalogName(`Relation "${relName}" on table "${sourceTbl}" (junction ${tableName}) shadows the ` +
1492
1549
  `json/jsonb column "${relName}", keeping the historical name for runtime compatibility; ` +
1493
- `the relation is omitted from the generated types.`);
1550
+ `the relation is omitted from the generated types.`), { code: 'introspect-relation-shadows-json', table: sourceTbl, relation: relName });
1494
1551
  }
1495
1552
  else {
1496
1553
  const taken = new Set([...columnFields, ...Object.keys(existing)]);
1497
- relName = resolveRelationNameCollision(relName, taken, sourceTbl, `junction ${tableName}`);
1554
+ relName = resolveRelationNameCollision(relName, taken, sourceTbl, `junction ${tableName}`, logger);
1498
1555
  }
1499
1556
  }
1500
1557
  existing[relName] = {
@@ -1558,7 +1615,8 @@ function deriveCatalogRelations(inputs) {
1558
1615
  const uniqueSetsByTable = inputs.legacyToManyUniques
1559
1616
  ? undefined
1560
1617
  : detectUniqueForeignKeySets(pkByTable, uniqueByTable, indexesByTable);
1561
- const relationsByTable = buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, inputs.fkActions, unknownTypedFieldsByTable, uniqueSetsByTable);
1618
+ const logger = inputs.logger ?? logger_js_1.consoleLogger;
1619
+ const relationsByTable = buildRelationsFromForeignKeys(foreignKeys, columnFieldsByTable, inputs.fkActions, unknownTypedFieldsByTable, uniqueSetsByTable, logger);
1562
1620
  // Prisma's implicit m2m junctions have no primary key (just a two-column
1563
1621
  // UNIQUE index over the FK columns), so pass the introspected two-column
1564
1622
  // unique indexes as the fallback junction-key source.
@@ -1587,7 +1645,7 @@ function deriveCatalogRelations(inputs) {
1587
1645
  if (twoColUniques.length > 0)
1588
1646
  uniqueIndexColsByTable.set(tbl, twoColUniques);
1589
1647
  }
1590
- addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, new Map(Array.from(columnsByTable, ([tbl, cols]) => [tbl, cols.map((c) => c.name)])), relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, uniqueIndexColsByTable);
1648
+ addAutoManyToManyRelations(tableNames, foreignKeys, pkByTable, new Map(Array.from(columnsByTable, ([tbl, cols]) => [tbl, cols.map((c) => c.name)])), relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, uniqueIndexColsByTable, logger);
1591
1649
  return relationsByTable;
1592
1650
  }
1593
1651
  /**
@@ -1599,7 +1657,7 @@ function deriveCatalogRelations(inputs) {
1599
1657
  * relation names for the same logical schema (the engines previously carried
1600
1658
  * stale copies of a retired naming scheme).
1601
1659
  */
1602
- function deriveEngineRelations(tableNames, foreignKeys, pkByTable, columnsByTable) {
1660
+ function deriveEngineRelations(tableNames, foreignKeys, pkByTable, columnsByTable, logger = logger_js_1.consoleLogger) {
1603
1661
  const tableSet = new Set(tableNames);
1604
1662
  const fks = foreignKeys.filter((fk) => tableSet.has(fk.sourceTable) && tableSet.has(fk.targetTable));
1605
1663
  const columnFieldsByTable = new Map();
@@ -1608,7 +1666,7 @@ function deriveEngineRelations(tableNames, foreignKeys, pkByTable, columnsByTabl
1608
1666
  columnFieldsByTable.set(tbl, new Set(cols.map((c) => c.field)));
1609
1667
  unknownTypedFieldsByTable.set(tbl, new Set(cols.filter((c) => isUnknownTsType(c.tsType)).map((c) => c.field)));
1610
1668
  }
1611
- const relationsByTable = buildRelationsFromForeignKeys(fks, columnFieldsByTable, undefined, unknownTypedFieldsByTable);
1612
- addAutoManyToManyRelations(tableNames, fks, pkByTable, new Map(Array.from(columnsByTable, ([tbl, cols]) => [tbl, cols.map((c) => c.name)])), relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable);
1669
+ const relationsByTable = buildRelationsFromForeignKeys(fks, columnFieldsByTable, undefined, unknownTypedFieldsByTable, undefined, logger);
1670
+ addAutoManyToManyRelations(tableNames, fks, pkByTable, new Map(Array.from(columnsByTable, ([tbl, cols]) => [tbl, cols.map((c) => c.name)])), relationsByTable, columnFieldsByTable, unknownTypedFieldsByTable, undefined, logger);
1613
1671
  return relationsByTable;
1614
1672
  }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * turbine-orm, every `code` a Turbine log line can carry.
3
+ *
4
+ * A log line's TEXT is not a stable contract; its `code` is. This list is the
5
+ * whole set. Library code imports it as a TYPE only (see `TurbineLogCode` in
6
+ * logger.ts), so an emitter cannot use a code that is not here and the list
7
+ * itself never reaches a bundle. The tests import the runtime array: one test
8
+ * per code, and a source scan that fails on a code nothing emits.
9
+ */
10
+ export declare const LOG_CODES: readonly ["unknown-config-key", "plan-cache-mode-ignored", "prepared-statements-on-pooler", "connection-option-ignored", "pool-error", "query-listener-error", "pool-listener-error", "replica-close-error", "external-pool", "pool-created", "replicas-configured", "pipeline", "raw-sql", "transaction-committed", "transaction-rolled-back", "listen", "notify", "connection-verified", "disconnect-skipped", "pool-disconnected", "typed-sql", "listen-reconnecting", "listen-lost", "parser-overwrite", "untyped-columns", "unordered-page", "auto-strategy", "deep-with", "flatten-blocked", "redundant-sort-term", "unknown-query-option", "unlimited-find-many", "temporal-infinity", "cache-mismatch", "stream-idle-timeout", "sql-comment-dropped", "relation-payload-json", "flatten-fallback", "unindexed-relation", "prisma-compat-unknown-option", "prisma-compat-native-spelling", "prisma-map-stale", "prisma-compat-junction-collision", "powdb-link-collision", "powdb-link-drift", "powdb-introspect-no-primary-key", "introspect-cross-schema-fk", "introspect-relation-renamed", "introspect-relation-shadows-json", "generate-relation-shadows-column"];
11
+ /** A stable, machine-readable log line id. */
12
+ export type TurbineLogCode = (typeof LOG_CODES)[number];
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOG_CODES = void 0;
4
+ /**
5
+ * turbine-orm, every `code` a Turbine log line can carry.
6
+ *
7
+ * A log line's TEXT is not a stable contract; its `code` is. This list is the
8
+ * whole set. Library code imports it as a TYPE only (see `TurbineLogCode` in
9
+ * logger.ts), so an emitter cannot use a code that is not here and the list
10
+ * itself never reaches a bundle. The tests import the runtime array: one test
11
+ * per code, and a source scan that fails on a code nothing emits.
12
+ */
13
+ exports.LOG_CODES = [
14
+ // client.ts, construction (always on)
15
+ 'unknown-config-key',
16
+ 'plan-cache-mode-ignored',
17
+ 'prepared-statements-on-pooler',
18
+ 'connection-option-ignored',
19
+ // client.ts, runtime errors
20
+ 'pool-error',
21
+ 'query-listener-error',
22
+ 'pool-listener-error',
23
+ 'replica-close-error',
24
+ // client.ts, `logging: true` lifecycle lines
25
+ 'external-pool',
26
+ 'pool-created',
27
+ 'replicas-configured',
28
+ 'pipeline',
29
+ 'raw-sql',
30
+ 'transaction-committed',
31
+ 'transaction-rolled-back',
32
+ 'listen',
33
+ 'notify',
34
+ 'connection-verified',
35
+ 'disconnect-skipped',
36
+ 'pool-disconnected',
37
+ // typed-sql.ts
38
+ 'typed-sql',
39
+ // realtime.ts
40
+ 'listen-reconnecting',
41
+ 'listen-lost',
42
+ // query/utils.ts, a pg type parser replaced (client construction, always on)
43
+ 'parser-overwrite',
44
+ // query/builder.ts, query/utils.ts, query/option-surface.ts: per-query advice
45
+ 'untyped-columns',
46
+ 'unordered-page',
47
+ 'auto-strategy',
48
+ 'deep-with',
49
+ 'flatten-blocked',
50
+ 'redundant-sort-term',
51
+ 'unknown-query-option',
52
+ // query/builder.ts, always on
53
+ 'unlimited-find-many',
54
+ 'temporal-infinity',
55
+ 'cache-mismatch',
56
+ 'stream-idle-timeout',
57
+ // query/sql-comment.ts, always on (a sqlComment.dynamic value left out)
58
+ 'sql-comment-dropped',
59
+ // query/relations.ts, per-query advice
60
+ 'relation-payload-json',
61
+ 'flatten-fallback',
62
+ 'unindexed-relation',
63
+ // prisma-compat.ts
64
+ 'prisma-compat-unknown-option',
65
+ 'prisma-compat-native-spelling',
66
+ 'prisma-map-stale',
67
+ 'prisma-compat-junction-collision',
68
+ // powdb.ts, powdb-introspect.ts
69
+ 'powdb-link-collision',
70
+ 'powdb-link-drift',
71
+ 'powdb-introspect-no-primary-key',
72
+ // introspect.ts, generate.ts
73
+ 'introspect-cross-schema-fk',
74
+ 'introspect-relation-renamed',
75
+ 'introspect-relation-shadows-json',
76
+ 'generate-relation-shadows-column',
77
+ ];
@@ -0,0 +1,87 @@
1
+ /**
2
+ * turbine-orm, the pluggable logger.
3
+ *
4
+ * Every line Turbine writes goes through a {@link TurbineLogger}: the client's
5
+ * `logger` option, or {@link consoleLogger} when none is set. Each line is a
6
+ * human message plus a {@link TurbineLogEntry} whose `code` is stable and
7
+ * machine-readable; the message text is not a stable contract.
8
+ *
9
+ * No log line carries a bound parameter value or a row value, whatever
10
+ * `logQueryParams` says: that option governs `$on('query')` events only. An
11
+ * entry about a where clause names its keys, never its values.
12
+ *
13
+ * This module and `seed.ts` (a CLI-driven runner) are the only library modules
14
+ * that call `console` directly; a source scan fails the build on another.
15
+ */
16
+ import type { ResolvedDiagnostics } from './diagnostics.js';
17
+ import type { TurbineLogCode } from './log-codes.js';
18
+ export type { TurbineLogCode } from './log-codes.js';
19
+ /** The structured half of a log line. */
20
+ export interface TurbineLogEntry {
21
+ /** Stable, machine-readable id of the line, e.g. `'pool-error'`, `'unknown-config-key'`. */
22
+ code: string;
23
+ /** The table the line is about, when there is one. */
24
+ table?: string;
25
+ /** The operation the line is about (`'findMany'`, `'$transaction'`), when there is one. */
26
+ operation?: string;
27
+ /** The error the line reports, when it reports one. */
28
+ error?: unknown;
29
+ [field: string]: unknown;
30
+ }
31
+ /**
32
+ * Where Turbine's log lines go. Every method is optional, and a missing method
33
+ * drops that level, so `{}` silences Turbine entirely. The argument order,
34
+ * `(message, entry)`, matches `console` and winston; pino and bunyan take
35
+ * `(object, message)` and need a two-line adapter.
36
+ *
37
+ * A method that throws is ignored: logging never fails the operation that
38
+ * logged.
39
+ */
40
+ export interface TurbineLogger {
41
+ debug?(message: string, entry: TurbineLogEntry): void;
42
+ info?(message: string, entry: TurbineLogEntry): void;
43
+ warn?(message: string, entry: TurbineLogEntry): void;
44
+ error?(message: string, entry: TurbineLogEntry): void;
45
+ }
46
+ /** One of the four {@link TurbineLogger} levels. */
47
+ export type TurbineLogLevel = 'debug' | 'info' | 'warn' | 'error';
48
+ /**
49
+ * The logger a client uses when `logger` is not set. `console` is looked up
50
+ * on every call, not captured, so anything that replaces `console.warn` (a
51
+ * test, an APM agent) sees Turbine's lines.
52
+ */
53
+ export declare const consoleLogger: TurbineLogger;
54
+ /**
55
+ * Validate the `logger` option: unset means {@link consoleLogger}; otherwise an
56
+ * object whose `debug` / `info` / `warn` / `error` members, where present, are
57
+ * functions. Other members are ignored, so a pino, winston or console object is
58
+ * accepted as it is. Throws `ValidationError` (E003) otherwise.
59
+ */
60
+ export declare function resolveLogger(logger: unknown): TurbineLogger;
61
+ /** An entry as Turbine's own emitters build it: the code is one of {@link TurbineLogCode}. */
62
+ export interface InternalLogEntry extends TurbineLogEntry {
63
+ code: TurbineLogCode;
64
+ }
65
+ /**
66
+ * Send one line to `logger` at `level`. A logger without that level drops it;
67
+ * a logger that throws is ignored. Called as a method, so a class-based
68
+ * logger keeps its `this`.
69
+ *
70
+ * Callers build `message` only once they know the line is wanted (behind the
71
+ * `logging` flag, the advice gate, or the warn-once registry), so a silenced
72
+ * line costs nothing.
73
+ */
74
+ export declare function logTo(logger: TurbineLogger, level: TurbineLogLevel, message: string, entry: InternalLogEntry): void;
75
+ /**
76
+ * What a client hands to code that wraps it (prisma-compat) or runs on its
77
+ * behalf: its logger and its resolved diagnostics.
78
+ */
79
+ export interface ClientLogContext {
80
+ readonly logger: TurbineLogger;
81
+ readonly diagnostics: ResolvedDiagnostics;
82
+ }
83
+ /**
84
+ * The key a `TurbineClient` exposes its {@link ClientLogContext} under.
85
+ * `Symbol.for`, so an ESM and a CJS copy of the package agree on it.
86
+ */
87
+ export declare const CLIENT_LOG_CONTEXT: unique symbol;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * turbine-orm, the pluggable logger.
4
+ *
5
+ * Every line Turbine writes goes through a {@link TurbineLogger}: the client's
6
+ * `logger` option, or {@link consoleLogger} when none is set. Each line is a
7
+ * human message plus a {@link TurbineLogEntry} whose `code` is stable and
8
+ * machine-readable; the message text is not a stable contract.
9
+ *
10
+ * No log line carries a bound parameter value or a row value, whatever
11
+ * `logQueryParams` says: that option governs `$on('query')` events only. An
12
+ * entry about a where clause names its keys, never its values.
13
+ *
14
+ * This module and `seed.ts` (a CLI-driven runner) are the only library modules
15
+ * that call `console` directly; a source scan fails the build on another.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.CLIENT_LOG_CONTEXT = exports.consoleLogger = void 0;
19
+ exports.resolveLogger = resolveLogger;
20
+ exports.logTo = logTo;
21
+ const errors_js_1 = require("./errors.js");
22
+ const LEVELS = ['debug', 'info', 'warn', 'error'];
23
+ /**
24
+ * What the default logger prints for one line: `[turbine] <message>`, plus the
25
+ * entry's error as a second argument when the message ends with a colon. Such
26
+ * a message names a failure and the error completes it (`Query listener error:`
27
+ * followed by the error and its stack); every other message is complete on its
28
+ * own and already carries what it needs from the error.
29
+ */
30
+ function consoleArgs(message, entry) {
31
+ // turbine-prefix-ok: this line only ever reaches the console.* calls in consoleLogger, never an Error.
32
+ const line = `[turbine] ${message}`;
33
+ return entry.error !== undefined && message.endsWith(':') ? [line, entry.error] : [line];
34
+ }
35
+ /**
36
+ * The logger a client uses when `logger` is not set. `console` is looked up
37
+ * on every call, not captured, so anything that replaces `console.warn` (a
38
+ * test, an APM agent) sees Turbine's lines.
39
+ */
40
+ exports.consoleLogger = Object.freeze({
41
+ debug(message, entry) {
42
+ console.log(...consoleArgs(message, entry));
43
+ },
44
+ info(message, entry) {
45
+ console.info(...consoleArgs(message, entry));
46
+ },
47
+ warn(message, entry) {
48
+ console.warn(...consoleArgs(message, entry));
49
+ },
50
+ error(message, entry) {
51
+ console.error(...consoleArgs(message, entry));
52
+ },
53
+ });
54
+ /**
55
+ * Validate the `logger` option: unset means {@link consoleLogger}; otherwise an
56
+ * object whose `debug` / `info` / `warn` / `error` members, where present, are
57
+ * functions. Other members are ignored, so a pino, winston or console object is
58
+ * accepted as it is. Throws `ValidationError` (E003) otherwise.
59
+ */
60
+ function resolveLogger(logger) {
61
+ if (logger === undefined)
62
+ return exports.consoleLogger;
63
+ if ((typeof logger !== 'object' && typeof logger !== 'function') || logger === null || Array.isArray(logger)) {
64
+ throw new errors_js_1.ValidationError(`Invalid logger option: expected an object with optional debug, info, warn and error methods, got ${logger === null ? 'null' : Array.isArray(logger) ? 'an array' : typeof logger}. Pass {} to silence Turbine, or leave the option unset for console.`);
65
+ }
66
+ for (const level of LEVELS) {
67
+ const member = logger[level];
68
+ if (member !== undefined && typeof member !== 'function') {
69
+ throw new errors_js_1.ValidationError(`Invalid logger option: logger.${level} must be a function (message, entry) or absent, got ${typeof member}.`);
70
+ }
71
+ }
72
+ return logger;
73
+ }
74
+ /**
75
+ * Send one line to `logger` at `level`. A logger without that level drops it;
76
+ * a logger that throws is ignored. Called as a method, so a class-based
77
+ * logger keeps its `this`.
78
+ *
79
+ * Callers build `message` only once they know the line is wanted (behind the
80
+ * `logging` flag, the advice gate, or the warn-once registry), so a silenced
81
+ * line costs nothing.
82
+ */
83
+ function logTo(logger, level, message, entry) {
84
+ const method = logger[level];
85
+ if (typeof method !== 'function')
86
+ return;
87
+ try {
88
+ method.call(logger, message, entry);
89
+ }
90
+ catch {
91
+ // A logging failure must never become the caller's failure.
92
+ }
93
+ }
94
+ /**
95
+ * The key a `TurbineClient` exposes its {@link ClientLogContext} under.
96
+ * `Symbol.for`, so an ESM and a CJS copy of the package agree on it.
97
+ */
98
+ exports.CLIENT_LOG_CONTEXT = Symbol.for('turbine-orm.clientLogContext');