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.
- package/README.md +122 -39
- package/dist/cjs/adapters/cockroachdb.d.ts +39 -0
- package/dist/cjs/adapters/index.d.ts +110 -0
- package/dist/cjs/adapters/yugabytedb.d.ts +51 -0
- package/dist/cjs/cli/config.d.ts +181 -0
- package/dist/cjs/cli/config.js +32 -6
- package/dist/cjs/cli/destructive.d.ts +38 -0
- package/dist/cjs/cli/index.d.ts +359 -0
- package/dist/cjs/cli/index.js +228 -56
- package/dist/cjs/cli/loader.d.ts +61 -0
- package/dist/cjs/cli/mcp.d.ts +42 -0
- package/dist/cjs/cli/migrate.d.ts +356 -0
- package/dist/cjs/cli/migrate.js +131 -40
- package/dist/cjs/cli/observe-ui.d.ts +1 -0
- package/dist/cjs/cli/observe-ui.js +14 -5
- package/dist/cjs/cli/observe.d.ts +25 -0
- package/dist/cjs/cli/observe.js +49 -12
- package/dist/cjs/cli/pii-tags.d.ts +53 -0
- package/dist/cjs/cli/prisma-report.d.ts +33 -0
- package/dist/cjs/cli/prisma-report.js +73 -0
- package/dist/cjs/cli/prisma-resolve.d.ts +106 -0
- package/dist/cjs/cli/prisma-resolve.js +1 -0
- package/dist/cjs/cli/prisma-schema.d.ts +176 -0
- package/dist/cjs/cli/prisma-schema.js +82 -4
- package/dist/cjs/cli/rate-limit.d.ts +32 -0
- package/dist/cjs/cli/rate-limit.js +45 -0
- package/dist/cjs/cli/studio-demo.d.ts +43 -0
- package/dist/cjs/cli/studio-ui.generated.d.ts +1 -0
- package/dist/cjs/cli/studio.d.ts +207 -0
- package/dist/cjs/cli/studio.js +136 -71
- package/dist/cjs/cli/ui.d.ts +73 -0
- package/dist/cjs/cli/ui.js +51 -9
- package/dist/cjs/client.d.ts +837 -0
- package/dist/cjs/client.js +3 -0
- package/dist/cjs/dialect.d.ts +516 -0
- package/dist/cjs/dialect.js +37 -12
- package/dist/cjs/errors.d.ts +370 -0
- package/dist/cjs/generate.d.ts +137 -0
- package/dist/cjs/generate.js +39 -6
- package/dist/cjs/index-advisor.d.ts +153 -0
- package/dist/cjs/index-stats.d.ts +384 -0
- package/dist/cjs/index.d.ts +55 -0
- package/dist/cjs/index.js +7 -2
- package/dist/cjs/introspect.d.ts +269 -0
- package/dist/cjs/mssql.d.ts +232 -0
- package/dist/cjs/mssql.js +6 -0
- package/dist/cjs/mysql.d.ts +173 -0
- package/dist/cjs/mysql.js +16 -0
- package/dist/cjs/nested-write.d.ts +96 -0
- package/dist/cjs/nested-write.js +414 -24
- package/dist/cjs/observe.d.ts +115 -0
- package/dist/cjs/optional-peer-import.d.cts +72 -0
- package/dist/cjs/pipeline-submittable.d.ts +93 -0
- package/dist/cjs/pipeline.d.ts +71 -0
- package/dist/cjs/powdb-introspect.d.ts +84 -0
- package/dist/cjs/powdb.d.ts +931 -0
- package/dist/cjs/powdb.js +106 -21
- package/dist/cjs/powql.d.ts +592 -0
- package/dist/cjs/powql.js +42 -6
- package/dist/cjs/prisma-compat.d.ts +283 -0
- package/dist/cjs/prisma-compat.js +167 -9
- package/dist/cjs/query/aggregates.d.ts +92 -0
- package/dist/cjs/query/aggregates.js +7 -3
- package/dist/cjs/query/batched-loader.d.ts +193 -0
- package/dist/cjs/query/builder.d.ts +849 -0
- package/dist/cjs/query/builder.js +571 -65
- package/dist/cjs/query/compound-unique.d.ts +51 -0
- package/dist/cjs/query/deferred.d.ts +223 -0
- package/dist/cjs/query/filters.d.ts +201 -0
- package/dist/cjs/query/index.d.ts +14 -0
- package/dist/cjs/query/index.js +6 -1
- package/dist/cjs/query/relations.d.ts +609 -0
- package/dist/cjs/query/relations.js +693 -46
- package/dist/cjs/query/types.d.ts +1300 -0
- package/dist/cjs/query/utils.d.ts +209 -0
- package/dist/cjs/query/utils.js +208 -1
- package/dist/cjs/query/warn-registry.d.ts +68 -0
- package/dist/cjs/query/warn-registry.js +9 -0
- package/dist/cjs/query/where-compile.d.ts +139 -0
- package/dist/cjs/query/where.d.ts +548 -0
- package/dist/cjs/query/where.js +58 -22
- package/dist/cjs/query/writes.d.ts +172 -0
- package/dist/cjs/query/writes.js +105 -12
- package/dist/cjs/realtime.d.ts +70 -0
- package/dist/cjs/schema-builder.d.ts +354 -0
- package/dist/cjs/schema-metadata.d.ts +83 -0
- package/dist/cjs/schema-sql.d.ts +217 -0
- package/dist/cjs/schema-sql.js +23 -5
- package/dist/cjs/schema.d.ts +356 -0
- package/dist/cjs/schema.js +125 -0
- package/dist/cjs/seed.d.ts +15 -0
- package/dist/cjs/serverless.d.ts +142 -0
- package/dist/cjs/sqlite.d.ts +143 -0
- package/dist/cjs/sqlite.js +4 -0
- package/dist/cjs/typed-sql.d.ts +102 -0
- package/dist/cli/config.d.ts +18 -4
- package/dist/cli/config.js +31 -6
- package/dist/cli/index.d.ts +123 -0
- package/dist/cli/index.js +223 -58
- package/dist/cli/migrate.d.ts +59 -10
- package/dist/cli/migrate.js +128 -41
- package/dist/cli/observe-ui.d.ts +1 -1
- package/dist/cli/observe-ui.js +14 -5
- package/dist/cli/observe.d.ts +7 -1
- package/dist/cli/observe.js +48 -12
- package/dist/cli/prisma-report.d.ts +14 -0
- package/dist/cli/prisma-report.js +72 -0
- package/dist/cli/prisma-resolve.d.ts +6 -0
- package/dist/cli/prisma-resolve.js +1 -0
- package/dist/cli/prisma-schema.d.ts +62 -2
- package/dist/cli/prisma-schema.js +81 -4
- package/dist/cli/rate-limit.d.ts +32 -0
- package/dist/cli/rate-limit.js +40 -0
- package/dist/cli/studio.d.ts +5 -5
- package/dist/cli/studio.js +135 -70
- package/dist/cli/ui.d.ts +1 -1
- package/dist/cli/ui.js +51 -9
- package/dist/client.d.ts +40 -0
- package/dist/client.js +3 -0
- package/dist/dialect.d.ts +17 -1
- package/dist/dialect.js +37 -12
- package/dist/generate.js +40 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mssql.js +6 -0
- package/dist/mysql.js +16 -0
- package/dist/nested-write.d.ts +2 -0
- package/dist/nested-write.js +415 -25
- package/dist/powdb.d.ts +4 -2
- package/dist/powdb.js +106 -21
- package/dist/powql.d.ts +5 -0
- package/dist/powql.js +42 -6
- package/dist/prisma-compat.d.ts +2 -0
- package/dist/prisma-compat.js +166 -8
- package/dist/query/aggregates.js +7 -3
- package/dist/query/builder.d.ts +292 -21
- package/dist/query/builder.js +570 -64
- package/dist/query/deferred.d.ts +39 -0
- package/dist/query/index.d.ts +1 -1
- package/dist/query/index.js +1 -1
- package/dist/query/relations.d.ts +173 -5
- package/dist/query/relations.js +688 -47
- package/dist/query/types.d.ts +123 -39
- package/dist/query/utils.d.ts +116 -0
- package/dist/query/utils.js +198 -0
- package/dist/query/warn-registry.d.ts +9 -0
- package/dist/query/warn-registry.js +9 -0
- package/dist/query/where.d.ts +38 -1
- package/dist/query/where.js +58 -23
- package/dist/query/writes.d.ts +42 -1
- package/dist/query/writes.js +104 -13
- package/dist/schema-sql.d.ts +14 -0
- package/dist/schema-sql.js +23 -5
- package/dist/schema.d.ts +38 -0
- package/dist/schema.js +123 -0
- package/dist/sqlite.js +4 -0
- 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
|
|
111
|
-
*
|
|
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
|
|
444
|
-
*
|
|
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
|
|
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
|
+
}
|
package/dist/cli/studio.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* turbine-orm CLI
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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;
|