turbine-orm 0.49.0 → 0.50.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 (157) hide show
  1. package/README.md +122 -39
  2. package/dist/cjs/adapters/cockroachdb.d.ts +39 -0
  3. package/dist/cjs/adapters/index.d.ts +110 -0
  4. package/dist/cjs/adapters/yugabytedb.d.ts +51 -0
  5. package/dist/cjs/cli/config.d.ts +181 -0
  6. package/dist/cjs/cli/config.js +32 -6
  7. package/dist/cjs/cli/destructive.d.ts +38 -0
  8. package/dist/cjs/cli/index.d.ts +359 -0
  9. package/dist/cjs/cli/index.js +228 -56
  10. package/dist/cjs/cli/loader.d.ts +61 -0
  11. package/dist/cjs/cli/mcp.d.ts +42 -0
  12. package/dist/cjs/cli/migrate.d.ts +356 -0
  13. package/dist/cjs/cli/migrate.js +131 -40
  14. package/dist/cjs/cli/observe-ui.d.ts +1 -0
  15. package/dist/cjs/cli/observe-ui.js +14 -5
  16. package/dist/cjs/cli/observe.d.ts +25 -0
  17. package/dist/cjs/cli/observe.js +49 -12
  18. package/dist/cjs/cli/pii-tags.d.ts +53 -0
  19. package/dist/cjs/cli/prisma-report.d.ts +33 -0
  20. package/dist/cjs/cli/prisma-report.js +73 -0
  21. package/dist/cjs/cli/prisma-resolve.d.ts +106 -0
  22. package/dist/cjs/cli/prisma-resolve.js +1 -0
  23. package/dist/cjs/cli/prisma-schema.d.ts +176 -0
  24. package/dist/cjs/cli/prisma-schema.js +82 -4
  25. package/dist/cjs/cli/rate-limit.d.ts +32 -0
  26. package/dist/cjs/cli/rate-limit.js +45 -0
  27. package/dist/cjs/cli/studio-demo.d.ts +43 -0
  28. package/dist/cjs/cli/studio-ui.generated.d.ts +1 -0
  29. package/dist/cjs/cli/studio.d.ts +207 -0
  30. package/dist/cjs/cli/studio.js +136 -71
  31. package/dist/cjs/cli/ui.d.ts +73 -0
  32. package/dist/cjs/cli/ui.js +51 -9
  33. package/dist/cjs/client.d.ts +837 -0
  34. package/dist/cjs/client.js +3 -0
  35. package/dist/cjs/dialect.d.ts +516 -0
  36. package/dist/cjs/dialect.js +37 -12
  37. package/dist/cjs/errors.d.ts +370 -0
  38. package/dist/cjs/generate.d.ts +137 -0
  39. package/dist/cjs/generate.js +39 -6
  40. package/dist/cjs/index-advisor.d.ts +153 -0
  41. package/dist/cjs/index-stats.d.ts +384 -0
  42. package/dist/cjs/index.d.ts +55 -0
  43. package/dist/cjs/index.js +7 -2
  44. package/dist/cjs/introspect.d.ts +269 -0
  45. package/dist/cjs/mssql.d.ts +232 -0
  46. package/dist/cjs/mssql.js +6 -0
  47. package/dist/cjs/mysql.d.ts +173 -0
  48. package/dist/cjs/mysql.js +16 -0
  49. package/dist/cjs/nested-write.d.ts +96 -0
  50. package/dist/cjs/nested-write.js +414 -24
  51. package/dist/cjs/observe.d.ts +115 -0
  52. package/dist/cjs/optional-peer-import.d.cts +72 -0
  53. package/dist/cjs/pipeline-submittable.d.ts +93 -0
  54. package/dist/cjs/pipeline.d.ts +71 -0
  55. package/dist/cjs/powdb-introspect.d.ts +84 -0
  56. package/dist/cjs/powdb.d.ts +931 -0
  57. package/dist/cjs/powdb.js +106 -21
  58. package/dist/cjs/powql.d.ts +592 -0
  59. package/dist/cjs/powql.js +42 -6
  60. package/dist/cjs/prisma-compat.d.ts +283 -0
  61. package/dist/cjs/prisma-compat.js +167 -9
  62. package/dist/cjs/query/aggregates.d.ts +92 -0
  63. package/dist/cjs/query/aggregates.js +7 -3
  64. package/dist/cjs/query/batched-loader.d.ts +193 -0
  65. package/dist/cjs/query/builder.d.ts +849 -0
  66. package/dist/cjs/query/builder.js +571 -65
  67. package/dist/cjs/query/compound-unique.d.ts +51 -0
  68. package/dist/cjs/query/deferred.d.ts +223 -0
  69. package/dist/cjs/query/filters.d.ts +201 -0
  70. package/dist/cjs/query/index.d.ts +14 -0
  71. package/dist/cjs/query/index.js +6 -1
  72. package/dist/cjs/query/relations.d.ts +609 -0
  73. package/dist/cjs/query/relations.js +693 -46
  74. package/dist/cjs/query/types.d.ts +1300 -0
  75. package/dist/cjs/query/utils.d.ts +209 -0
  76. package/dist/cjs/query/utils.js +208 -1
  77. package/dist/cjs/query/warn-registry.d.ts +68 -0
  78. package/dist/cjs/query/warn-registry.js +9 -0
  79. package/dist/cjs/query/where-compile.d.ts +139 -0
  80. package/dist/cjs/query/where.d.ts +548 -0
  81. package/dist/cjs/query/where.js +58 -22
  82. package/dist/cjs/query/writes.d.ts +172 -0
  83. package/dist/cjs/query/writes.js +105 -12
  84. package/dist/cjs/realtime.d.ts +70 -0
  85. package/dist/cjs/schema-builder.d.ts +354 -0
  86. package/dist/cjs/schema-metadata.d.ts +83 -0
  87. package/dist/cjs/schema-sql.d.ts +217 -0
  88. package/dist/cjs/schema-sql.js +23 -5
  89. package/dist/cjs/schema.d.ts +356 -0
  90. package/dist/cjs/schema.js +125 -0
  91. package/dist/cjs/seed.d.ts +15 -0
  92. package/dist/cjs/serverless.d.ts +142 -0
  93. package/dist/cjs/sqlite.d.ts +143 -0
  94. package/dist/cjs/sqlite.js +4 -0
  95. package/dist/cjs/typed-sql.d.ts +102 -0
  96. package/dist/cli/config.d.ts +18 -4
  97. package/dist/cli/config.js +31 -6
  98. package/dist/cli/index.d.ts +123 -0
  99. package/dist/cli/index.js +223 -58
  100. package/dist/cli/migrate.d.ts +59 -10
  101. package/dist/cli/migrate.js +128 -41
  102. package/dist/cli/observe-ui.d.ts +1 -1
  103. package/dist/cli/observe-ui.js +14 -5
  104. package/dist/cli/observe.d.ts +7 -1
  105. package/dist/cli/observe.js +48 -12
  106. package/dist/cli/prisma-report.d.ts +14 -0
  107. package/dist/cli/prisma-report.js +72 -0
  108. package/dist/cli/prisma-resolve.d.ts +6 -0
  109. package/dist/cli/prisma-resolve.js +1 -0
  110. package/dist/cli/prisma-schema.d.ts +62 -2
  111. package/dist/cli/prisma-schema.js +81 -4
  112. package/dist/cli/rate-limit.d.ts +32 -0
  113. package/dist/cli/rate-limit.js +40 -0
  114. package/dist/cli/studio.d.ts +5 -5
  115. package/dist/cli/studio.js +135 -70
  116. package/dist/cli/ui.d.ts +1 -1
  117. package/dist/cli/ui.js +51 -9
  118. package/dist/client.d.ts +40 -0
  119. package/dist/client.js +3 -0
  120. package/dist/dialect.d.ts +17 -1
  121. package/dist/dialect.js +37 -12
  122. package/dist/generate.js +40 -7
  123. package/dist/index.d.ts +1 -1
  124. package/dist/index.js +1 -1
  125. package/dist/mssql.js +6 -0
  126. package/dist/mysql.js +16 -0
  127. package/dist/nested-write.d.ts +2 -0
  128. package/dist/nested-write.js +415 -25
  129. package/dist/powdb.d.ts +4 -2
  130. package/dist/powdb.js +106 -21
  131. package/dist/powql.d.ts +5 -0
  132. package/dist/powql.js +42 -6
  133. package/dist/prisma-compat.d.ts +2 -0
  134. package/dist/prisma-compat.js +166 -8
  135. package/dist/query/aggregates.js +7 -3
  136. package/dist/query/builder.d.ts +292 -21
  137. package/dist/query/builder.js +570 -64
  138. package/dist/query/deferred.d.ts +39 -0
  139. package/dist/query/index.d.ts +1 -1
  140. package/dist/query/index.js +1 -1
  141. package/dist/query/relations.d.ts +173 -5
  142. package/dist/query/relations.js +688 -47
  143. package/dist/query/types.d.ts +123 -39
  144. package/dist/query/utils.d.ts +116 -0
  145. package/dist/query/utils.js +198 -0
  146. package/dist/query/warn-registry.d.ts +9 -0
  147. package/dist/query/warn-registry.js +9 -0
  148. package/dist/query/where.d.ts +38 -1
  149. package/dist/query/where.js +58 -23
  150. package/dist/query/writes.d.ts +42 -1
  151. package/dist/query/writes.js +104 -13
  152. package/dist/schema-sql.d.ts +14 -0
  153. package/dist/schema-sql.js +23 -5
  154. package/dist/schema.d.ts +38 -0
  155. package/dist/schema.js +123 -0
  156. package/dist/sqlite.js +4 -0
  157. package/package.json +77 -28
@@ -90,10 +90,36 @@ export interface PrismaEnum {
90
90
  map?: string;
91
91
  line: number;
92
92
  }
93
+ /**
94
+ * A connection-string value inside a `datasource` block: either a literal
95
+ * string (`url = "postgres://..."`) or an `env("NAME")` indirection.
96
+ */
97
+ export type PrismaConnectionValue = {
98
+ kind: 'literal';
99
+ value: string;
100
+ } | {
101
+ kind: 'env';
102
+ variable: string;
103
+ };
104
+ /** A parsed `datasource` block. Only the connection keys are retained. */
105
+ export interface PrismaDatasource {
106
+ /** Block name (`datasource db { ... }` -> `db`). */
107
+ name: string;
108
+ /** `provider = "postgresql"`, when declared as a literal. */
109
+ provider?: string;
110
+ /** `url = ...`, when declared as a literal or an `env(...)` call. */
111
+ url?: PrismaConnectionValue;
112
+ /** `directUrl = ...` (Prisma's non-pooled connection), same forms as `url`. */
113
+ directUrl?: PrismaConnectionValue;
114
+ /** 1-based source line of the block header. */
115
+ line: number;
116
+ }
93
117
  /** The full parse result. */
94
118
  export interface PrismaSchemaAst {
95
119
  models: PrismaModel[];
96
120
  enums: PrismaEnum[];
121
+ /** Parsed `datasource` blocks, in source order. */
122
+ datasources: PrismaDatasource[];
97
123
  /** Non-fatal notes: skipped/unknown blocks and attributes. */
98
124
  warnings: string[];
99
125
  }
@@ -102,13 +128,47 @@ export declare class PrismaParseError extends Error {
102
128
  readonly line: number;
103
129
  constructor(message: string, line: number);
104
130
  }
131
+ /** Where a datasource connection string was resolved from. */
132
+ export interface ResolvedPrismaDatasourceUrl {
133
+ /** The connection string itself. */
134
+ url: string;
135
+ /** Datasource block name it came from. */
136
+ datasource: string;
137
+ /** Which key supplied it. */
138
+ key: 'url' | 'directUrl';
139
+ /** The environment variable read, when the value was an `env(...)` call. */
140
+ variable?: string;
141
+ }
142
+ /** Result of {@link resolvePrismaDatasourceUrl}. */
143
+ export interface PrismaDatasourceUrlLookup {
144
+ /** The first usable connection string found, if any. */
145
+ resolved?: ResolvedPrismaDatasourceUrl;
146
+ /**
147
+ * Environment variable names the schema declares via `env(...)` that were
148
+ * unset or empty, in lookup order. Surfaced in the no-URL error so the user
149
+ * sees exactly which variable the schema asked for.
150
+ */
151
+ missingVariables: string[];
152
+ }
153
+ /**
154
+ * Resolve the connection string a `schema.prisma` declares, reading `env(...)`
155
+ * indirections out of the supplied environment (pure: the environment is an
156
+ * argument, never `process.env` directly).
157
+ *
158
+ * Per datasource block, `url` is preferred and `directUrl` is the fallback:
159
+ * `url` is what Prisma itself uses for everything but migrations, and a pooled
160
+ * `url` introspects the same catalog as its direct twin.
161
+ */
162
+ export declare function resolvePrismaDatasourceUrl(ast: Pick<PrismaSchemaAst, 'datasources'>, env: Record<string, string | undefined>): PrismaDatasourceUrlLookup;
105
163
  /**
106
164
  * Parse a `schema.prisma` source string into a {@link PrismaSchemaAst}.
107
165
  *
108
166
  * Understands: model / view / type / enum blocks; field lines with `@map`,
109
167
  * `@id`, `@unique`, `@default`, `@updatedAt`, `@ignore`, `@relation`; and block
110
- * attributes `@@map`, `@@id`, `@@unique`, `@@index`, `@@schema`. Unknown
111
- * attributes and blocks are skipped into {@link PrismaSchemaAst.warnings}.
168
+ * attributes `@@map`, `@@id`, `@@unique`, `@@index`, `@@schema`; plus the
169
+ * `provider` / `url` / `directUrl` keys of each `datasource` block (see
170
+ * {@link resolvePrismaDatasourceUrl}). Unknown attributes and blocks are
171
+ * skipped into {@link PrismaSchemaAst.warnings}.
112
172
  *
113
173
  * @throws {@link PrismaParseError} on an unterminated block/paren/string or a
114
174
  * structurally broken `@@id` / `@@unique` / `@@map`.
@@ -432,6 +432,78 @@ function parseEnumBody(block, src) {
432
432
  }
433
433
  return en;
434
434
  }
435
+ /**
436
+ * Parse a `datasource` block value: a quoted literal, or an `env("NAME")` call.
437
+ * Returns null for any other form (e.g. an interpolated expression), which the
438
+ * caller records as "declared but not usable" rather than guessing.
439
+ */
440
+ function parseConnectionValue(raw) {
441
+ if (/^"(?:[^"\\]|\\.)*"$/.test(raw))
442
+ return { kind: 'literal', value: unquote(raw) };
443
+ const envCall = raw.match(/^env\(\s*("(?:[^"\\]|\\.)*")\s*\)$/);
444
+ if (envCall) {
445
+ const variable = unquote(envCall[1]);
446
+ return variable ? { kind: 'env', variable } : null;
447
+ }
448
+ return null;
449
+ }
450
+ /**
451
+ * Parse a `datasource` block. Only `provider`, `url`, and `directUrl` are kept;
452
+ * every other key (`shadowDatabaseUrl`, `relationMode`, `extensions`, ...) is
453
+ * irrelevant to name mapping and skipped silently, as before.
454
+ */
455
+ function parseDatasourceBody(block, src) {
456
+ const ds = { name: block.name, line: block.headerLine };
457
+ for (const { text } of bodyLines(block.body, block.bodyOffset, src)) {
458
+ const m = text.match(/^([A-Za-z_]\w*)\s*=\s*(.+)$/);
459
+ if (!m)
460
+ continue;
461
+ const key = m[1];
462
+ const raw = m[2].trim();
463
+ if (key === 'provider') {
464
+ const value = parseConnectionValue(raw);
465
+ if (value?.kind === 'literal')
466
+ ds.provider = value.value;
467
+ }
468
+ else if (key === 'url' || key === 'directUrl') {
469
+ const value = parseConnectionValue(raw);
470
+ if (value)
471
+ ds[key] = value;
472
+ }
473
+ }
474
+ return ds;
475
+ }
476
+ /**
477
+ * Resolve the connection string a `schema.prisma` declares, reading `env(...)`
478
+ * indirections out of the supplied environment (pure: the environment is an
479
+ * argument, never `process.env` directly).
480
+ *
481
+ * Per datasource block, `url` is preferred and `directUrl` is the fallback:
482
+ * `url` is what Prisma itself uses for everything but migrations, and a pooled
483
+ * `url` introspects the same catalog as its direct twin.
484
+ */
485
+ export function resolvePrismaDatasourceUrl(ast, env) {
486
+ const missingVariables = [];
487
+ for (const ds of ast.datasources) {
488
+ for (const key of ['url', 'directUrl']) {
489
+ const value = ds[key];
490
+ if (!value)
491
+ continue;
492
+ if (value.kind === 'literal') {
493
+ if (value.value)
494
+ return { resolved: { url: value.value, datasource: ds.name, key }, missingVariables };
495
+ continue;
496
+ }
497
+ const fromEnv = env[value.variable];
498
+ if (fromEnv) {
499
+ return { resolved: { url: fromEnv, datasource: ds.name, key, variable: value.variable }, missingVariables };
500
+ }
501
+ if (!missingVariables.includes(value.variable))
502
+ missingVariables.push(value.variable);
503
+ }
504
+ }
505
+ return { missingVariables };
506
+ }
435
507
  // ---------------------------------------------------------------------------
436
508
  // Entry point
437
509
  // ---------------------------------------------------------------------------
@@ -440,15 +512,17 @@ function parseEnumBody(block, src) {
440
512
  *
441
513
  * Understands: model / view / type / enum blocks; field lines with `@map`,
442
514
  * `@id`, `@unique`, `@default`, `@updatedAt`, `@ignore`, `@relation`; and block
443
- * attributes `@@map`, `@@id`, `@@unique`, `@@index`, `@@schema`. Unknown
444
- * attributes and blocks are skipped into {@link PrismaSchemaAst.warnings}.
515
+ * attributes `@@map`, `@@id`, `@@unique`, `@@index`, `@@schema`; plus the
516
+ * `provider` / `url` / `directUrl` keys of each `datasource` block (see
517
+ * {@link resolvePrismaDatasourceUrl}). Unknown attributes and blocks are
518
+ * skipped into {@link PrismaSchemaAst.warnings}.
445
519
  *
446
520
  * @throws {@link PrismaParseError} on an unterminated block/paren/string or a
447
521
  * structurally broken `@@id` / `@@unique` / `@@map`.
448
522
  */
449
523
  export function parsePrismaSchema(source) {
450
524
  const src = stripComments(source);
451
- const ast = { models: [], enums: [], warnings: [] };
525
+ const ast = { models: [], enums: [], datasources: [], warnings: [] };
452
526
  for (const block of scanBlocks(src)) {
453
527
  switch (block.keyword) {
454
528
  case 'model':
@@ -467,8 +541,11 @@ export function parsePrismaSchema(source) {
467
541
  ast.enums.push(parseEnumBody(block, src));
468
542
  break;
469
543
  case 'datasource':
544
+ // Not a table, but it declares the connection string the CLI can reuse.
545
+ ast.datasources.push(parseDatasourceBody(block, src));
546
+ break;
470
547
  case 'generator':
471
- // Configuration blocks - irrelevant to name mapping.
548
+ // Configuration block - irrelevant to name mapping.
472
549
  break;
473
550
  default:
474
551
  ast.warnings.push(`Skipped unsupported block "${block.keyword} ${block.name}".`);
@@ -0,0 +1,32 @@
1
+ /**
2
+ * turbine-orm CLI: fixed-window rate limiter
3
+ *
4
+ * A pure leaf module (same role as `cli/destructive.ts`): no imports beyond a
5
+ * Node type, no I/O, no state of its own. Both local servers, Studio and
6
+ * Observe, throttle through it so they behave identically without either one
7
+ * importing the other. Studio in particular statically pulls in the embedded
8
+ * UI, the demo store, PII redaction and QueryInterface, none of which Observe
9
+ * has any use for.
10
+ */
11
+ import type { IncomingMessage } from 'node:http';
12
+ export declare const RATE_LIMIT_WINDOW_MS = 60000;
13
+ export declare const RATE_LIMIT_MAX_REQUESTS = 100;
14
+ /**
15
+ * Bucket identity for one caller. These are loopback tools with a single shared
16
+ * token, so the remote address is the only thing that distinguishes one client
17
+ * from another; requests with no socket (in-process dispatch) share one key.
18
+ */
19
+ export declare function callerKey(req: IncomingMessage): string;
20
+ export interface RateLimitResult {
21
+ allowed: boolean;
22
+ resetAt: number;
23
+ }
24
+ /**
25
+ * Fixed-window counter. `limiter` is the caller's own state map (each server
26
+ * owns one, so exhausting one server's budget never touches the other's) and
27
+ * `token` is the bucket key, not a credential.
28
+ */
29
+ export declare function checkRateLimit(limiter: Map<string, {
30
+ count: number;
31
+ resetAt: number;
32
+ }>, token: string): RateLimitResult;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * turbine-orm CLI: fixed-window rate limiter
3
+ *
4
+ * A pure leaf module (same role as `cli/destructive.ts`): no imports beyond a
5
+ * Node type, no I/O, no state of its own. Both local servers, Studio and
6
+ * Observe, throttle through it so they behave identically without either one
7
+ * importing the other. Studio in particular statically pulls in the embedded
8
+ * UI, the demo store, PII redaction and QueryInterface, none of which Observe
9
+ * has any use for.
10
+ */
11
+ export const RATE_LIMIT_WINDOW_MS = 60_000; // 60 seconds
12
+ export const RATE_LIMIT_MAX_REQUESTS = 100;
13
+ /**
14
+ * Bucket identity for one caller. These are loopback tools with a single shared
15
+ * token, so the remote address is the only thing that distinguishes one client
16
+ * from another; requests with no socket (in-process dispatch) share one key.
17
+ */
18
+ export function callerKey(req) {
19
+ return req.socket?.remoteAddress ?? 'unknown';
20
+ }
21
+ /**
22
+ * Fixed-window counter. `limiter` is the caller's own state map (each server
23
+ * owns one, so exhausting one server's budget never touches the other's) and
24
+ * `token` is the bucket key, not a credential.
25
+ */
26
+ export function checkRateLimit(limiter, token) {
27
+ const now = Date.now();
28
+ const entry = limiter.get(token);
29
+ if (!entry || now >= entry.resetAt) {
30
+ // Start a new window
31
+ const resetAt = now + RATE_LIMIT_WINDOW_MS;
32
+ limiter.set(token, { count: 1, resetAt });
33
+ return { allowed: true, resetAt };
34
+ }
35
+ entry.count++;
36
+ if (entry.count > RATE_LIMIT_MAX_REQUESTS) {
37
+ return { allowed: false, resetAt: entry.resetAt };
38
+ }
39
+ return { allowed: true, resetAt: entry.resetAt };
40
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * turbine-orm CLI Studio
2
+ * turbine-orm CLI: Studio
3
3
  *
4
4
  * A local web UI for browsing databases, exploring relations, and composing
5
5
  * queries visually. ORM-native since v0.19: there is no raw-SQL input surface.
@@ -90,7 +90,7 @@ export interface StudioHandle {
90
90
  } | null;
91
91
  /** Random per-process session token the UI sends via cookie. */
92
92
  authToken: string;
93
- /** Full URL including `?token=...` safe to print for the user. */
93
+ /** Full URL including `?token=...`, safe to print for the user. */
94
94
  url: string;
95
95
  }
96
96
  export interface StudioContext {
@@ -106,12 +106,12 @@ export interface StudioContext {
106
106
  options: StudioOptions;
107
107
  authToken: string;
108
108
  stateDir: string;
109
- /** Resolved statement timeout (adapter-aware) parameterized SQL + values. */
109
+ /** Resolved statement timeout (adapter-aware): parameterized SQL + values. */
110
110
  statementTimeout: {
111
111
  sql: string;
112
112
  params: unknown[];
113
113
  };
114
- /** Rate limiter state tracks requests per authenticated session. */
114
+ /** Rate limiter state: tracks requests per authenticated session. */
115
115
  rateLimiter: Map<string, {
116
116
  count: number;
117
117
  resetAt: number;
@@ -190,7 +190,7 @@ interface SavedQuery {
190
190
  id: string;
191
191
  table: string;
192
192
  name: string;
193
- /** Studio only saves visual-builder queries there is no raw-SQL surface. */
193
+ /** Studio only saves visual-builder queries: there is no raw-SQL surface. */
194
194
  kind: 'builder';
195
195
  args?: unknown;
196
196
  createdAt: string;