turbine-orm 0.77.1 → 0.78.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 (93) hide show
  1. package/README.md +13 -9
  2. package/dist/cjs/cli/config.d.ts +7 -1
  3. package/dist/cjs/cli/config.js +11 -2
  4. package/dist/cjs/cli/destructive.d.ts +1 -1
  5. package/dist/cjs/cli/destructive.js +307 -9
  6. package/dist/cjs/cli/index.js +252 -42
  7. package/dist/cjs/cli/mcp.d.ts +23 -0
  8. package/dist/cjs/cli/mcp.js +190 -152
  9. package/dist/cjs/cli/migrate.d.ts +243 -3
  10. package/dist/cjs/cli/migrate.js +432 -43
  11. package/dist/cjs/cli/sql-statements.js +27 -0
  12. package/dist/cjs/cli/studio.d.ts +0 -1
  13. package/dist/cjs/cli/studio.js +9 -7
  14. package/dist/cjs/client.d.ts +8 -1
  15. package/dist/cjs/client.js +7 -0
  16. package/dist/cjs/connection-url.d.ts +82 -0
  17. package/dist/cjs/connection-url.js +187 -1
  18. package/dist/cjs/errors.d.ts +112 -12
  19. package/dist/cjs/errors.js +558 -114
  20. package/dist/cjs/generate.js +47 -15
  21. package/dist/cjs/index.d.ts +1 -1
  22. package/dist/cjs/introspect.d.ts +33 -0
  23. package/dist/cjs/introspect.js +54 -1
  24. package/dist/cjs/mssql.js +21 -1
  25. package/dist/cjs/nested-write.js +85 -14
  26. package/dist/cjs/pipeline-submittable.d.ts +2 -0
  27. package/dist/cjs/pipeline-submittable.js +88 -3
  28. package/dist/cjs/pipeline.js +13 -1
  29. package/dist/cjs/powdb-introspect.d.ts +5 -1
  30. package/dist/cjs/powdb-introspect.js +5 -1
  31. package/dist/cjs/powql.d.ts +14 -0
  32. package/dist/cjs/powql.js +44 -4
  33. package/dist/cjs/prisma-compat.js +95 -8
  34. package/dist/cjs/query/aggregates.js +56 -6
  35. package/dist/cjs/query/builder.d.ts +76 -13
  36. package/dist/cjs/query/builder.js +188 -58
  37. package/dist/cjs/query/compound-unique.d.ts +76 -0
  38. package/dist/cjs/query/compound-unique.js +129 -0
  39. package/dist/cjs/query/index.d.ts +1 -1
  40. package/dist/cjs/query/types.d.ts +65 -11
  41. package/dist/cjs/query/where.d.ts +85 -19
  42. package/dist/cjs/query/where.js +262 -47
  43. package/dist/cjs/query/writes.d.ts +11 -2
  44. package/dist/cjs/query/writes.js +116 -21
  45. package/dist/cjs/seed.d.ts +16 -0
  46. package/dist/cjs/seed.js +16 -0
  47. package/dist/cli/config.d.ts +7 -1
  48. package/dist/cli/config.js +11 -2
  49. package/dist/cli/destructive.d.ts +1 -1
  50. package/dist/cli/destructive.js +307 -9
  51. package/dist/cli/index.js +254 -44
  52. package/dist/cli/mcp.d.ts +23 -0
  53. package/dist/cli/mcp.js +187 -150
  54. package/dist/cli/migrate.d.ts +243 -3
  55. package/dist/cli/migrate.js +423 -45
  56. package/dist/cli/sql-statements.js +27 -0
  57. package/dist/cli/studio.d.ts +0 -1
  58. package/dist/cli/studio.js +10 -7
  59. package/dist/client.d.ts +8 -1
  60. package/dist/client.js +7 -0
  61. package/dist/connection-url.d.ts +82 -0
  62. package/dist/connection-url.js +183 -0
  63. package/dist/errors.d.ts +112 -12
  64. package/dist/errors.js +558 -114
  65. package/dist/generate.js +47 -15
  66. package/dist/index.d.ts +1 -1
  67. package/dist/introspect.d.ts +33 -0
  68. package/dist/introspect.js +53 -1
  69. package/dist/mssql.js +21 -1
  70. package/dist/nested-write.js +85 -14
  71. package/dist/pipeline-submittable.d.ts +2 -0
  72. package/dist/pipeline-submittable.js +87 -3
  73. package/dist/pipeline.js +14 -2
  74. package/dist/powdb-introspect.d.ts +5 -1
  75. package/dist/powdb-introspect.js +5 -1
  76. package/dist/powql.d.ts +14 -0
  77. package/dist/powql.js +45 -5
  78. package/dist/prisma-compat.js +96 -9
  79. package/dist/query/aggregates.js +56 -6
  80. package/dist/query/builder.d.ts +76 -13
  81. package/dist/query/builder.js +188 -58
  82. package/dist/query/compound-unique.d.ts +76 -0
  83. package/dist/query/compound-unique.js +126 -1
  84. package/dist/query/index.d.ts +1 -1
  85. package/dist/query/types.d.ts +65 -11
  86. package/dist/query/where.d.ts +85 -19
  87. package/dist/query/where.js +260 -47
  88. package/dist/query/writes.d.ts +11 -2
  89. package/dist/query/writes.js +117 -22
  90. package/dist/seed.d.ts +16 -0
  91. package/dist/seed.js +16 -0
  92. package/package.json +3 -3
  93. package/skills/turbine-orm/SKILL.md +37 -10
@@ -28,12 +28,40 @@ export declare const TurbineErrorCode: {
28
28
  export type TurbineErrorCode = (typeof TurbineErrorCode)[keyof typeof TurbineErrorCode];
29
29
  /** Base error class for all Turbine errors */
30
30
  export declare class TurbineError extends Error {
31
+ /**
32
+ * The code every instance of this class passes to `super()`, declared once
33
+ * per subclass on the line above the constructor that names it, so the two
34
+ * are read together. It exists for {@link TurbineError[Symbol.hasInstance]}:
35
+ * a subclass recognises a branded error from another copy of this module
36
+ * when the codes agree. `undefined` here on the base class, which therefore
37
+ * recognises any branded error.
38
+ *
39
+ * A static per class rather than a class-to-code map because the code is
40
+ * already written once per class; this puts the second mention next to the
41
+ * first instead of in a table at the bottom of the file, and a unit test
42
+ * asserts the two agree for every exported class.
43
+ */
44
+ static readonly CODE: TurbineErrorCode | undefined;
31
45
  readonly code: TurbineErrorCode;
32
46
  /** Docs page for this code, e.g. `https://turbineorm.dev/errors#e003`. */
33
47
  readonly docsUrl: string;
34
48
  constructor(code: TurbineErrorCode, message: string, options?: {
35
49
  cause?: unknown;
36
50
  });
51
+ /**
52
+ * `instanceof` that survives two copies of this module in one process.
53
+ *
54
+ * The ordinary prototype-chain answer is taken first, so a single-copy
55
+ * process behaves exactly as before, user subclasses included. Only when that
56
+ * says no is the brand consulted: a branded object is an instance of the base
57
+ * class outright, and of a coded subclass when its `code` equals that class's
58
+ * {@link CODE}. The `hasOwn` guard restricts the code match to classes that
59
+ * declare their own CODE, i.e. the ones in this module: a user subclass such
60
+ * as `class MyError extends ValidationError {}` inherits E003 without
61
+ * declaring it, and every ValidationError must not become an instance of the
62
+ * user's narrower class.
63
+ */
64
+ static [Symbol.hasInstance](value: unknown): boolean;
37
65
  }
38
66
  /**
39
67
  * Controls whether NotFoundError messages include the actual `where` values
@@ -91,17 +119,28 @@ export declare function runWithErrorMessageMode<R>(mode: ErrorMessageMode, fn: (
91
119
  * clause (e.g. `where: {"id":1,"email":"alice@x.com"}`).
92
120
  *
93
121
  * SCOPE, stated precisely because the useful version of this contract is the
94
- * one that is true. 'safe' mode redacts row values from the surfaces Turbine
95
- * OWNS: its own error messages, and the `detail` field of a driver error it
96
- * wraps and attaches as `.cause` (see redactCauseForMode).
97
- *
98
- * It is NOT a blanket guarantee that no row value can be reached from a thrown
99
- * error. A driver error whose SQLSTATE {@link wrapPgError} does not classify is
100
- * returned UNCHANGED, and some of those carry a value in the `message` field
101
- * itself, where nothing can be removed without destroying the diagnosis:
102
- * `22P02 invalid input syntax for type integer: "alice@example.com"` is the
103
- * common one. Treat 'safe' mode as removing Turbine's own contribution to the
104
- * leak, not as a log-scrubbing boundary.
122
+ * one that is true. 'safe' mode redacts row and parameter values from every
123
+ * error Turbine raises or wraps:
124
+ * - its own messages;
125
+ * - the `detail`, `hint`, `where` (the CONTEXT field, which carries the bound
126
+ * PARAMETERS when `log_parameter_max_length_on_error` is non-zero) and
127
+ * `internalQuery` fields of a driver error it attaches as `.cause`, and of
128
+ * the error it hands back. See {@link VALUE_BEARING_FIELDS} for what puts a
129
+ * value in each of them;
130
+ * - the driver MESSAGE where that is what carries the value, so `22P02
131
+ * invalid input syntax for type integer: "alice@example.com"` becomes a
132
+ * ValidationError whose safe-mode text names the column and the SQLSTATE
133
+ * and nothing else (see {@link wrapPgError});
134
+ * - the message of a PostgreSQL server error whose SQLSTATE wrapPgError has
135
+ * no class for AND whose SQLSTATE class can hold a value in its message
136
+ * text (`P0001`, say, whose text the function author wrote), replaced by a
137
+ * sentence naming the SQLSTATE and saying the text was withheld. A class
138
+ * whose grammar is written over schema object names keeps its text, because
139
+ * withholding what cannot leak protects nothing: see
140
+ * {@link messageTextIsValueFree}.
141
+ * It is not a log-scrubbing boundary for errors that never pass through
142
+ * Turbine, and an unclassified NATIVE error code from one of the non-Postgres
143
+ * engines is left to that engine's own classifier.
105
144
  */
106
145
  export declare function setErrorMessageMode(mode: ErrorMessageMode): void;
107
146
  /**
@@ -162,6 +201,7 @@ export declare function describeTargetForMessage(target: unknown): string;
162
201
  * structured properties on the error instance regardless of mode.
163
202
  */
164
203
  export declare class NotFoundError extends TurbineError {
204
+ static readonly CODE: "TURBINE_E001";
165
205
  readonly table?: string;
166
206
  readonly where?: unknown;
167
207
  readonly operation?: string;
@@ -175,6 +215,7 @@ export declare class NotFoundError extends TurbineError {
175
215
  }
176
216
  /** Thrown when a query or transaction exceeds the configured timeout */
177
217
  export declare class TimeoutError extends TurbineError {
218
+ static readonly CODE: "TURBINE_E002";
178
219
  readonly timeoutMs: number;
179
220
  /**
180
221
  * @param timeoutMs the client-side timeout budget in ms. Pass `0` when the
@@ -191,6 +232,23 @@ export declare class TimeoutError extends TurbineError {
191
232
  }
192
233
  /** Thrown when query arguments fail validation (unknown column, invalid operator, etc.) */
193
234
  export declare class ValidationError extends TurbineError {
235
+ static readonly CODE: "TURBINE_E003";
236
+ /**
237
+ * For an E003 that wraps a PostgreSQL data exception (SQLSTATE class 22) or a
238
+ * `search` operand `to_tsquery` rejected (42601): the column the server named,
239
+ * when it named one, and the SQLSTATE that classified the error. Undefined
240
+ * for validation Turbine performed itself, which never reaches the server.
241
+ */
242
+ readonly column?: string;
243
+ readonly sqlstate?: string;
244
+ /**
245
+ * The driver's own text for a wrapped data exception. PostgreSQL puts the
246
+ * offending VALUE in that text (`invalid input syntax for type integer:
247
+ * "alice@example.com"`), so under `errorMessages: 'safe'` this is
248
+ * {@link REDACTED_DETAIL} and under `'verbose'` the driver text in full, the
249
+ * same split the constraint classes apply to `.cause.detail`.
250
+ */
251
+ readonly detail?: string;
194
252
  /**
195
253
  * `options.cause` is for the engines, not for the query builder. Turbine's own
196
254
  * E003s are raised from validation it performed itself, so there is nothing
@@ -202,10 +260,14 @@ export declare class ValidationError extends TurbineError {
202
260
  */
203
261
  constructor(message: string, options?: {
204
262
  cause?: unknown;
263
+ column?: string;
264
+ sqlstate?: string;
265
+ detail?: string;
205
266
  });
206
267
  }
207
268
  /** Thrown when a database connection fails */
208
269
  export declare class ConnectionError extends TurbineError {
270
+ static readonly CODE: "TURBINE_E004";
209
271
  /**
210
272
  * The driver code that produced this error: a Postgres SQLSTATE (`28P01`
211
273
  * wrong password, `3D000` no such database, `08006` connection failure, ...)
@@ -254,19 +316,23 @@ export declare class ConnectionError extends TurbineError {
254
316
  export declare function malformedConnectionStringMessage(engine: string, example: string): string;
255
317
  /** Thrown when a relation reference is invalid */
256
318
  export declare class RelationError extends TurbineError {
319
+ static readonly CODE: "TURBINE_E005";
257
320
  constructor(message: string);
258
321
  }
259
322
  /** Thrown when a migration operation fails */
260
323
  export declare class MigrationError extends TurbineError {
324
+ static readonly CODE: "TURBINE_E006";
261
325
  constructor(message: string);
262
326
  }
263
327
  /** Thrown when circular relation nesting is detected */
264
328
  export declare class CircularRelationError extends TurbineError {
329
+ static readonly CODE: "TURBINE_E007";
265
330
  readonly path: string[];
266
331
  constructor(path: string[]);
267
332
  }
268
333
  /** Thrown when a UNIQUE constraint is violated (pg code 23505) */
269
334
  export declare class UniqueConstraintError extends TurbineError {
335
+ static readonly CODE: "TURBINE_E008";
270
336
  readonly constraint?: string;
271
337
  readonly columns?: string[];
272
338
  readonly table?: string;
@@ -280,6 +346,7 @@ export declare class UniqueConstraintError extends TurbineError {
280
346
  }
281
347
  /** Thrown when a FOREIGN KEY constraint is violated (pg code 23503) */
282
348
  export declare class ForeignKeyError extends TurbineError {
349
+ static readonly CODE: "TURBINE_E009";
283
350
  readonly constraint?: string;
284
351
  readonly table?: string;
285
352
  constructor(opts?: {
@@ -291,6 +358,7 @@ export declare class ForeignKeyError extends TurbineError {
291
358
  }
292
359
  /** Thrown when a NOT NULL constraint is violated (pg code 23502) */
293
360
  export declare class NotNullViolationError extends TurbineError {
361
+ static readonly CODE: "TURBINE_E010";
294
362
  readonly column?: string;
295
363
  readonly table?: string;
296
364
  constructor(opts?: {
@@ -317,6 +385,7 @@ export declare class NotNullViolationError extends TurbineError {
317
385
  * ```
318
386
  */
319
387
  export declare class DeadlockError extends TurbineError {
388
+ static readonly CODE: "TURBINE_E012";
320
389
  /** Marks this error as safe to retry */
321
390
  readonly isRetryable: true;
322
391
  readonly constraint?: string;
@@ -344,6 +413,7 @@ export declare class DeadlockError extends TurbineError {
344
413
  * ```
345
414
  */
346
415
  export declare class SerializationFailureError extends TurbineError {
416
+ static readonly CODE: "TURBINE_E013";
347
417
  /** Marks this error as safe to retry */
348
418
  readonly isRetryable: true;
349
419
  constructor(opts?: {
@@ -353,6 +423,7 @@ export declare class SerializationFailureError extends TurbineError {
353
423
  }
354
424
  /** Thrown when a CHECK constraint is violated (pg code 23514) */
355
425
  export declare class CheckConstraintError extends TurbineError {
426
+ static readonly CODE: "TURBINE_E011";
356
427
  readonly constraint?: string;
357
428
  readonly table?: string;
358
429
  constructor(opts?: {
@@ -363,6 +434,7 @@ export declare class CheckConstraintError extends TurbineError {
363
434
  });
364
435
  }
365
436
  export declare class ExclusionConstraintError extends TurbineError {
437
+ static readonly CODE: "TURBINE_E016";
366
438
  readonly constraint?: string;
367
439
  readonly table?: string;
368
440
  constructor(opts?: {
@@ -401,6 +473,7 @@ export type PipelineResultSlot = {
401
473
  * ```
402
474
  */
403
475
  export declare class PipelineError extends TurbineError {
476
+ static readonly CODE: "TURBINE_E014";
404
477
  /** Per-query results: each slot is either `{status:'ok', value}` or `{status:'error', error}` */
405
478
  readonly results: PipelineResultSlot[];
406
479
  /** Zero-based index of the first query that failed */
@@ -416,9 +489,19 @@ export declare class PipelineError extends TurbineError {
416
489
  });
417
490
  }
418
491
  export declare class OptimisticLockError extends TurbineError {
492
+ static readonly CODE: "TURBINE_E015";
419
493
  readonly table: string;
420
494
  readonly versionField: string;
421
495
  readonly expectedVersion: unknown;
496
+ /**
497
+ * The comparison that failed, value included: `expected version = 3`.
498
+ * Populated in both modes, like `expectedVersion` itself; only the MESSAGE
499
+ * withholds the value under `errorMessages: 'safe'`. `optimisticLock` accepts
500
+ * any column as the version field (an `updated_at` timestamp, an etag
501
+ * string), so the value is a stored cell like any other, and the message
502
+ * treats it the way the constraint classes treat `detail`.
503
+ */
504
+ readonly detail: string;
422
505
  constructor(opts: {
423
506
  table: string;
424
507
  versionField: string;
@@ -432,6 +515,7 @@ export declare class OptimisticLockError extends TurbineError {
432
515
  * clear `unsupported on <engine>` message instead of generating broken SQL.
433
516
  */
434
517
  export declare class UnsupportedFeatureError extends TurbineError {
518
+ static readonly CODE: "TURBINE_E017";
435
519
  readonly feature: string;
436
520
  readonly dialect: string;
437
521
  constructor(feature: string, dialect: string, hint?: string);
@@ -451,6 +535,7 @@ export declare class UnsupportedFeatureError extends TurbineError {
451
535
  * identically; route it to a writable primary instead.
452
536
  */
453
537
  export declare class ReadOnlyError extends TurbineError {
538
+ static readonly CODE: "TURBINE_E018";
454
539
  /**
455
540
  * Why the write was refused. `'snapshot'`: the database itself is read-only
456
541
  * (snapshot serving, an embedded `readonly: true` open, or the client-level
@@ -473,7 +558,6 @@ export declare class ReadOnlyError extends TurbineError {
473
558
  }
474
559
  /**
475
560
  * Translate a pg driver error into a typed Turbine error.
476
- * If the error doesn't match a known constraint code, returns it unchanged.
477
561
  *
478
562
  * Maps:
479
563
  * 23505 (unique_violation) -> UniqueConstraintError
@@ -487,6 +571,22 @@ export declare class ReadOnlyError extends TurbineError {
487
571
  * 28P01 / 28000 (auth refused) -> ConnectionError, with a remediation hint
488
572
  * 3D000 (no such database) -> ConnectionError, with a remediation hint
489
573
  * connection-class codes -> ConnectionError (see CONNECTION_ERROR_CODES)
574
+ * 22xxx (data exception) -> ValidationError naming the column (when the
575
+ * server did) and the SQLSTATE; driver text
576
+ * on `.detail`, redacted in 'safe' mode
577
+ * 42601 from to_tsquery -> ValidationError with a `search` hint
578
+ * any other server SQLSTATE -> 'safe' mode: a clone keeping the SQLSTATE
579
+ * on `.code` and repeating it on `.sqlstate`,
580
+ * with the value-bearing fields redacted, the
581
+ * driver message kept when the SQLSTATE
582
+ * class's grammar cannot hold a row value and
583
+ * withheld when it can, and the original on
584
+ * `.cause` under the same rules (see
585
+ * scrubUnclassifiedServerError);
586
+ * 'verbose' mode: returned unchanged
587
+ *
588
+ * Anything that is not a PostgreSQL server error (no SQLSTATE-shaped code, or
589
+ * no `severity`) is returned unchanged whatever the mode: see isPgServerError.
490
590
  *
491
591
  * The original pg error is preserved as `.cause` on the wrapped error.
492
592
  */