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.
- package/README.md +26 -25
- package/dist/checkout.d.ts +27 -2
- package/dist/checkout.js +75 -4
- package/dist/cjs/checkout.d.ts +27 -2
- package/dist/cjs/checkout.js +76 -3
- package/dist/cjs/cli/code-first-tags.d.ts +62 -0
- package/dist/cjs/cli/code-first-tags.js +124 -0
- package/dist/cjs/cli/compile-query.js +9 -0
- package/dist/cjs/cli/config.d.ts +35 -6
- package/dist/cjs/cli/config.js +17 -1
- package/dist/cjs/cli/destructive.d.ts +7 -4
- package/dist/cjs/cli/destructive.js +224 -20
- package/dist/cjs/cli/error-catalog.js +36 -0
- package/dist/cjs/cli/error-text.d.ts +15 -0
- package/dist/cjs/cli/error-text.js +40 -0
- package/dist/cjs/cli/index.d.ts +62 -4
- package/dist/cjs/cli/index.js +568 -108
- package/dist/cjs/cli/local-server-guard.d.ts +53 -0
- package/dist/cjs/cli/local-server-guard.js +119 -0
- package/dist/cjs/cli/local-server-output.d.ts +41 -0
- package/dist/cjs/cli/local-server-output.js +103 -0
- package/dist/cjs/cli/mcp.d.ts +8 -0
- package/dist/cjs/cli/mcp.js +121 -32
- package/dist/cjs/cli/migrate.d.ts +113 -5
- package/dist/cjs/cli/migrate.js +270 -21
- package/dist/cjs/cli/observe.d.ts +6 -1
- package/dist/cjs/cli/observe.js +85 -55
- package/dist/cjs/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cjs/cli/pii-predicate-guard.js +98 -37
- package/dist/cjs/cli/prisma-resolve.js +17 -13
- package/dist/cjs/cli/prisma-schema.js +12 -4
- package/dist/cjs/cli/studio-ui.generated.js +1 -1
- package/dist/cjs/cli/studio.d.ts +14 -2
- package/dist/cjs/cli/studio.js +244 -69
- package/dist/cjs/cli/ui.d.ts +1 -1
- package/dist/cjs/client.d.ts +558 -85
- package/dist/cjs/client.js +1270 -395
- package/dist/cjs/connection-guard.d.ts +13 -0
- package/dist/cjs/connection-guard.js +28 -0
- package/dist/cjs/connection-url.d.ts +51 -16
- package/dist/cjs/connection-url.js +67 -34
- package/dist/cjs/diagnostics.d.ts +81 -0
- package/dist/cjs/diagnostics.js +147 -0
- package/dist/cjs/dialect.d.ts +449 -20
- package/dist/cjs/dialect.js +117 -76
- package/dist/cjs/engine-config.d.ts +7 -6
- package/dist/cjs/errors.d.ts +126 -6
- package/dist/cjs/errors.js +256 -13
- package/dist/cjs/generate.d.ts +57 -7
- package/dist/cjs/generate.js +635 -279
- package/dist/cjs/global-filters-config.d.ts +59 -0
- package/dist/cjs/global-filters-config.js +367 -0
- package/dist/cjs/index.d.ts +9 -4
- package/dist/cjs/index.js +10 -2
- package/dist/cjs/introspect.d.ts +31 -6
- package/dist/cjs/introspect.js +108 -50
- package/dist/cjs/log-codes.d.ts +12 -0
- package/dist/cjs/log-codes.js +77 -0
- package/dist/cjs/logger.d.ts +87 -0
- package/dist/cjs/logger.js +98 -0
- package/dist/cjs/mssql.d.ts +8 -5
- package/dist/cjs/mssql.js +352 -65
- package/dist/cjs/mysql.d.ts +3 -5
- package/dist/cjs/mysql.js +420 -70
- package/dist/cjs/nested-write.d.ts +3 -0
- package/dist/cjs/nested-write.js +179 -114
- package/dist/cjs/pipeline-submittable.d.ts +12 -0
- package/dist/cjs/pipeline-submittable.js +118 -44
- package/dist/cjs/pipeline.js +21 -26
- package/dist/cjs/powdb-introspect.d.ts +5 -2
- package/dist/cjs/powdb-introspect.js +20 -15
- package/dist/cjs/powdb-shared.d.ts +36 -5
- package/dist/cjs/powdb-shared.js +67 -8
- package/dist/cjs/powdb.d.ts +4 -0
- package/dist/cjs/powdb.js +183 -51
- package/dist/cjs/powql.d.ts +394 -51
- package/dist/cjs/powql.js +1829 -284
- package/dist/cjs/prisma-compat.d.ts +23 -15
- package/dist/cjs/prisma-compat.js +507 -372
- package/dist/cjs/query/aggregates.d.ts +17 -1
- package/dist/cjs/query/aggregates.js +261 -29
- package/dist/cjs/query/batched-loader.d.ts +25 -6
- package/dist/cjs/query/batched-loader.js +103 -20
- package/dist/cjs/query/builder.d.ts +325 -184
- package/dist/cjs/query/builder.js +1452 -490
- package/dist/cjs/query/column-ref.d.ts +61 -0
- package/dist/cjs/query/column-ref.js +73 -0
- package/dist/cjs/query/compound-unique.d.ts +21 -0
- package/dist/cjs/query/compound-unique.js +98 -18
- package/dist/cjs/query/deferred.d.ts +53 -16
- package/dist/cjs/query/expr.d.ts +217 -0
- package/dist/cjs/query/expr.js +859 -0
- package/dist/cjs/query/filters.d.ts +155 -53
- package/dist/cjs/query/filters.js +613 -76
- package/dist/cjs/query/index.d.ts +2 -0
- package/dist/cjs/query/index.js +7 -1
- package/dist/cjs/query/json-value.d.ts +43 -0
- package/dist/cjs/query/json-value.js +59 -0
- package/dist/cjs/query/normalize-args.d.ts +87 -0
- package/dist/cjs/query/normalize-args.js +527 -0
- package/dist/cjs/query/option-surface.d.ts +16 -4
- package/dist/cjs/query/option-surface.js +57 -14
- package/dist/cjs/query/relation-names.d.ts +14 -0
- package/dist/cjs/query/relation-names.js +77 -18
- package/dist/cjs/query/relations.d.ts +30 -3
- package/dist/cjs/query/relations.js +219 -63
- package/dist/cjs/query/row-lock.d.ts +49 -0
- package/dist/cjs/query/row-lock.js +138 -0
- package/dist/cjs/query/sql-comment.d.ts +161 -0
- package/dist/cjs/query/sql-comment.js +381 -0
- package/dist/cjs/query/stream-idle.d.ts +132 -0
- package/dist/cjs/query/stream-idle.js +212 -0
- package/dist/cjs/query/table-client.d.ts +101 -0
- package/dist/cjs/query/table-client.js +74 -0
- package/dist/cjs/query/types.d.ts +677 -298
- package/dist/cjs/query/utils.d.ts +105 -6
- package/dist/cjs/query/utils.js +426 -19
- package/dist/cjs/query/warn-registry.d.ts +18 -0
- package/dist/cjs/query/warn-registry.js +18 -0
- package/dist/cjs/query/where-compile.d.ts +138 -14
- package/dist/cjs/query/where-compile.js +513 -29
- package/dist/cjs/query/where.d.ts +159 -59
- package/dist/cjs/query/where.js +716 -246
- package/dist/cjs/query/writes.d.ts +112 -50
- package/dist/cjs/query/writes.js +1498 -200
- package/dist/cjs/query-events.d.ts +4 -2
- package/dist/cjs/query-events.js +3 -1
- package/dist/cjs/realtime.d.ts +7 -3
- package/dist/cjs/realtime.js +13 -2
- package/dist/cjs/schema-builder.d.ts +55 -4
- package/dist/cjs/schema-builder.js +382 -18
- package/dist/cjs/schema-metadata.d.ts +21 -1
- package/dist/cjs/schema-metadata.js +29 -7
- package/dist/cjs/schema-sql.d.ts +75 -5
- package/dist/cjs/schema-sql.js +497 -45
- package/dist/cjs/schema.d.ts +26 -5
- package/dist/cjs/schema.js +110 -13
- package/dist/cjs/sql-placeholders.d.ts +56 -0
- package/dist/cjs/sql-placeholders.js +204 -0
- package/dist/cjs/sqlite.d.ts +75 -20
- package/dist/cjs/sqlite.js +593 -95
- package/dist/cjs/supplied-pool-types.d.ts +48 -0
- package/dist/cjs/supplied-pool-types.js +256 -0
- package/dist/cjs/transaction-control.d.ts +51 -0
- package/dist/cjs/transaction-control.js +316 -0
- package/dist/cjs/transaction-state.d.ts +342 -0
- package/dist/cjs/transaction-state.js +707 -0
- package/dist/cjs/typed-sql.d.ts +37 -3
- package/dist/cjs/typed-sql.js +102 -8
- package/dist/cli/code-first-tags.d.ts +62 -0
- package/dist/cli/code-first-tags.js +120 -0
- package/dist/cli/compile-query.js +9 -0
- package/dist/cli/config.d.ts +35 -6
- package/dist/cli/config.js +16 -1
- package/dist/cli/destructive.d.ts +7 -4
- package/dist/cli/destructive.js +224 -20
- package/dist/cli/error-catalog.js +36 -0
- package/dist/cli/error-text.d.ts +15 -0
- package/dist/cli/error-text.js +37 -0
- package/dist/cli/index.d.ts +62 -4
- package/dist/cli/index.js +569 -112
- package/dist/cli/local-server-guard.d.ts +53 -0
- package/dist/cli/local-server-guard.js +113 -0
- package/dist/cli/local-server-output.d.ts +41 -0
- package/dist/cli/local-server-output.js +98 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +121 -34
- package/dist/cli/migrate.d.ts +113 -5
- package/dist/cli/migrate.js +261 -21
- package/dist/cli/observe.d.ts +6 -1
- package/dist/cli/observe.js +84 -54
- package/dist/cli/pii-predicate-guard.d.ts +43 -23
- package/dist/cli/pii-predicate-guard.js +100 -35
- package/dist/cli/prisma-resolve.js +15 -11
- package/dist/cli/prisma-schema.js +12 -4
- package/dist/cli/studio-ui.generated.js +1 -1
- package/dist/cli/studio.d.ts +14 -2
- package/dist/cli/studio.js +246 -71
- package/dist/cli/ui.d.ts +1 -1
- package/dist/client.d.ts +558 -85
- package/dist/client.js +1275 -400
- package/dist/connection-guard.d.ts +13 -0
- package/dist/connection-guard.js +27 -0
- package/dist/connection-url.d.ts +51 -16
- package/dist/connection-url.js +63 -34
- package/dist/diagnostics.d.ts +81 -0
- package/dist/diagnostics.js +144 -0
- package/dist/dialect.d.ts +449 -20
- package/dist/dialect.js +115 -43
- package/dist/engine-config.d.ts +7 -6
- package/dist/errors.d.ts +126 -6
- package/dist/errors.js +252 -12
- package/dist/generate.d.ts +57 -7
- package/dist/generate.js +635 -281
- package/dist/global-filters-config.d.ts +59 -0
- package/dist/global-filters-config.js +361 -0
- package/dist/index.d.ts +9 -4
- package/dist/index.js +4 -2
- package/dist/introspect.d.ts +31 -6
- package/dist/introspect.js +106 -50
- package/dist/log-codes.d.ts +12 -0
- package/dist/log-codes.js +74 -0
- package/dist/logger.d.ts +87 -0
- package/dist/logger.js +93 -0
- package/dist/mssql.d.ts +8 -5
- package/dist/mssql.js +354 -67
- package/dist/mysql.d.ts +3 -5
- package/dist/mysql.js +423 -73
- package/dist/nested-write.d.ts +3 -0
- package/dist/nested-write.js +177 -112
- package/dist/pipeline-submittable.d.ts +12 -0
- package/dist/pipeline-submittable.js +117 -44
- package/dist/pipeline.js +21 -26
- package/dist/powdb-introspect.d.ts +5 -2
- package/dist/powdb-introspect.js +21 -16
- package/dist/powdb-shared.d.ts +36 -5
- package/dist/powdb-shared.js +65 -8
- package/dist/powdb.d.ts +4 -0
- package/dist/powdb.js +183 -51
- package/dist/powql.d.ts +394 -51
- package/dist/powql.js +1836 -291
- package/dist/prisma-compat.d.ts +23 -15
- package/dist/prisma-compat.js +508 -373
- package/dist/query/aggregates.d.ts +17 -1
- package/dist/query/aggregates.js +263 -32
- package/dist/query/batched-loader.d.ts +25 -6
- package/dist/query/batched-loader.js +101 -21
- package/dist/query/builder.d.ts +325 -184
- package/dist/query/builder.js +1458 -495
- package/dist/query/column-ref.d.ts +61 -0
- package/dist/query/column-ref.js +66 -0
- package/dist/query/compound-unique.d.ts +21 -0
- package/dist/query/compound-unique.js +97 -19
- package/dist/query/deferred.d.ts +53 -16
- package/dist/query/expr.d.ts +217 -0
- package/dist/query/expr.js +848 -0
- package/dist/query/filters.d.ts +155 -53
- package/dist/query/filters.js +597 -72
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.js +4 -0
- package/dist/query/json-value.d.ts +43 -0
- package/dist/query/json-value.js +54 -0
- package/dist/query/normalize-args.d.ts +87 -0
- package/dist/query/normalize-args.js +517 -0
- package/dist/query/option-surface.d.ts +16 -4
- package/dist/query/option-surface.js +56 -13
- package/dist/query/relation-names.d.ts +14 -0
- package/dist/query/relation-names.js +77 -19
- package/dist/query/relations.d.ts +30 -3
- package/dist/query/relations.js +220 -67
- package/dist/query/row-lock.d.ts +49 -0
- package/dist/query/row-lock.js +131 -0
- package/dist/query/sql-comment.d.ts +161 -0
- package/dist/query/sql-comment.js +374 -0
- package/dist/query/stream-idle.d.ts +132 -0
- package/dist/query/stream-idle.js +203 -0
- package/dist/query/table-client.d.ts +101 -0
- package/dist/query/table-client.js +70 -0
- package/dist/query/types.d.ts +677 -298
- package/dist/query/utils.d.ts +105 -6
- package/dist/query/utils.js +414 -18
- package/dist/query/warn-registry.d.ts +18 -0
- package/dist/query/warn-registry.js +18 -0
- package/dist/query/where-compile.d.ts +138 -14
- package/dist/query/where-compile.js +508 -31
- package/dist/query/where.d.ts +159 -59
- package/dist/query/where.js +711 -248
- package/dist/query/writes.d.ts +112 -50
- package/dist/query/writes.js +1496 -202
- package/dist/query-events.d.ts +4 -2
- package/dist/query-events.js +3 -1
- package/dist/realtime.d.ts +7 -3
- package/dist/realtime.js +13 -2
- package/dist/schema-builder.d.ts +55 -4
- package/dist/schema-builder.js +381 -18
- package/dist/schema-metadata.d.ts +21 -1
- package/dist/schema-metadata.js +28 -7
- package/dist/schema-sql.d.ts +75 -5
- package/dist/schema-sql.js +494 -44
- package/dist/schema.d.ts +26 -5
- package/dist/schema.js +109 -13
- package/dist/sql-placeholders.d.ts +56 -0
- package/dist/sql-placeholders.js +200 -0
- package/dist/sqlite.d.ts +75 -20
- package/dist/sqlite.js +597 -99
- package/dist/supplied-pool-types.d.ts +48 -0
- package/dist/supplied-pool-types.js +247 -0
- package/dist/transaction-control.d.ts +51 -0
- package/dist/transaction-control.js +311 -0
- package/dist/transaction-state.d.ts +342 -0
- package/dist/transaction-state.js +696 -0
- package/dist/typed-sql.d.ts +37 -3
- package/dist/typed-sql.js +100 -8
- package/package.json +7 -4
- package/skills/turbine-orm/SKILL.md +56 -6
|
@@ -58,6 +58,19 @@ export interface CheckoutGuard extends ConnectionGuard {
|
|
|
58
58
|
* event (an engine shim) is left alone.
|
|
59
59
|
*/
|
|
60
60
|
export declare function absorbCheckedOutErrors(pool: unknown): void;
|
|
61
|
+
export interface CheckoutWatch {
|
|
62
|
+
/** Connections currently checked out of the pool, in checkout order. */
|
|
63
|
+
readonly checkedOut: ReadonlySet<object>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Track which connections of a pool Turbine owns are checked out, from
|
|
67
|
+
* pg-pool's public `acquire` / `release` / `remove` events, and call `onLost`
|
|
68
|
+
* once per connection that fails WHILE checked out (an idle connection's
|
|
69
|
+
* failure is pg-pool's own `'error'` event). Used for the client's
|
|
70
|
+
* `connectionLost` event and for force-closing what `disconnect({ timeoutMs })`
|
|
71
|
+
* is still waiting on. A pool without those events is left alone.
|
|
72
|
+
*/
|
|
73
|
+
export declare function watchCheckouts(pool: unknown, onLost?: (err: Error) => void): CheckoutWatch;
|
|
61
74
|
/**
|
|
62
75
|
* Guard a connection for as long as the caller holds it. Use {@link guardCheckout}
|
|
63
76
|
* for a pooled checkout; this form is for a client whose whole lifetime the
|
package/dist/connection-guard.js
CHANGED
|
@@ -46,6 +46,33 @@ export function absorbCheckedOutErrors(pool) {
|
|
|
46
46
|
client.on?.('error', () => { });
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Track which connections of a pool Turbine owns are checked out, from
|
|
51
|
+
* pg-pool's public `acquire` / `release` / `remove` events, and call `onLost`
|
|
52
|
+
* once per connection that fails WHILE checked out (an idle connection's
|
|
53
|
+
* failure is pg-pool's own `'error'` event). Used for the client's
|
|
54
|
+
* `connectionLost` event and for force-closing what `disconnect({ timeoutMs })`
|
|
55
|
+
* is still waiting on. A pool without those events is left alone.
|
|
56
|
+
*/
|
|
57
|
+
export function watchCheckouts(pool, onLost) {
|
|
58
|
+
const checkedOut = new Set();
|
|
59
|
+
const emitter = pool;
|
|
60
|
+
if (typeof emitter.on !== 'function')
|
|
61
|
+
return { checkedOut };
|
|
62
|
+
const reported = new WeakSet();
|
|
63
|
+
emitter.on('acquire', (client) => checkedOut.add(client));
|
|
64
|
+
emitter.on('release', (_err, client) => checkedOut.delete(client));
|
|
65
|
+
emitter.on('remove', (client) => checkedOut.delete(client));
|
|
66
|
+
emitter.on('connect', (client) => {
|
|
67
|
+
client.on?.('error', (err) => {
|
|
68
|
+
if (!checkedOut.has(client) || reported.has(client))
|
|
69
|
+
return;
|
|
70
|
+
reported.add(client);
|
|
71
|
+
onLost?.(err);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
return { checkedOut };
|
|
75
|
+
}
|
|
49
76
|
/**
|
|
50
77
|
* Guard a connection for as long as the caller holds it. Use {@link guardCheckout}
|
|
51
78
|
* for a pooled checkout; this form is for a client whose whole lifetime the
|
package/dist/connection-url.d.ts
CHANGED
|
@@ -107,12 +107,33 @@ export interface PoolerDetection {
|
|
|
107
107
|
* blocks a legitimate database, so precision wins and the caller is expected to
|
|
108
108
|
* offer an override.
|
|
109
109
|
*/
|
|
110
|
-
export declare function detectPooler(connectionString: string): PoolerDetection;
|
|
110
|
+
export declare function detectPooler(connectionString: string, environment?: PgEnvironmentTarget): PoolerDetection;
|
|
111
|
+
/**
|
|
112
|
+
* The `PGHOST` / `PGPORT` values a connection target falls back to. node-postgres
|
|
113
|
+
* reads a field from the connection string or the config first and the
|
|
114
|
+
* environment only when that leaves it unset, so a string that names no port (or
|
|
115
|
+
* no host) is still connecting to wherever these point.
|
|
116
|
+
*/
|
|
117
|
+
export interface PgEnvironmentTarget {
|
|
118
|
+
readonly host?: string | undefined;
|
|
119
|
+
readonly port?: string | undefined;
|
|
120
|
+
}
|
|
121
|
+
/** `target` with the host and port it leaves unset taken from `environment`, the way node-postgres does. */
|
|
122
|
+
export declare function fillTargetFromEnvironment(target: ConnectionTarget, environment: PgEnvironmentTarget): ConnectionTarget;
|
|
123
|
+
/** {@link detectPooler} for a target that is already parsed. */
|
|
124
|
+
export declare function detectPoolerTarget(target: ConnectionTarget): PoolerDetection;
|
|
111
125
|
export interface PoolerRefusalOptions {
|
|
112
126
|
/** The command being refused, e.g. `turbine doctor`. */
|
|
113
127
|
command: string;
|
|
114
128
|
/** The flag that overrides the refusal, e.g. `--allow-pooler`. */
|
|
115
129
|
allowFlag: string;
|
|
130
|
+
/**
|
|
131
|
+
* Why THIS command cannot use a pooler, in place of the default paragraph
|
|
132
|
+
* (written for `doctor`: session state, session-scoped views, the read bound).
|
|
133
|
+
* Lines are printed as given, between the endpoint and the advice to use the
|
|
134
|
+
* direct endpoint.
|
|
135
|
+
*/
|
|
136
|
+
explanation?: readonly string[];
|
|
116
137
|
}
|
|
117
138
|
/**
|
|
118
139
|
* The lines a command prints when it refuses a pooler endpoint.
|
|
@@ -158,6 +179,30 @@ export interface ConnectionOptionsConfig {
|
|
|
158
179
|
* a value that can carry a space can carry a second `-c`.
|
|
159
180
|
*/
|
|
160
181
|
export declare function withStatementTimeoutOption(config: ConnectionOptionsConfig, statementTimeoutMs: number): ConnectionOptionsConfig;
|
|
182
|
+
/**
|
|
183
|
+
* The `-c statement_timeout=<ms>` startup setting, or `null` when the value is
|
|
184
|
+
* not a non-negative safe integer (see the injection note on
|
|
185
|
+
* {@link withStatementTimeoutOption}). No unit suffix: the GUC's default unit
|
|
186
|
+
* is milliseconds.
|
|
187
|
+
*/
|
|
188
|
+
export declare function statementTimeoutSetting(statementTimeoutMs: number): string | null;
|
|
189
|
+
/**
|
|
190
|
+
* `config` with one `-c name=value` startup setting appended to its libpq
|
|
191
|
+
* `options`, in whichever place pg will read them from: an `options` query
|
|
192
|
+
* parameter already on the connection string wins over the `options` field,
|
|
193
|
+
* and the field falls back to `PGOPTIONS` only while it is unset, so both are
|
|
194
|
+
* read first and appended to rather than replaced.
|
|
195
|
+
*
|
|
196
|
+
* `setting` is emitted verbatim. The caller must have built it from a closed
|
|
197
|
+
* set or a narrowed number: the `options` string is split on whitespace, so a
|
|
198
|
+
* caller-controlled value could carry a second `-c`.
|
|
199
|
+
*/
|
|
200
|
+
export declare function withStartupSetting<T extends {
|
|
201
|
+
connectionString?: string;
|
|
202
|
+
options?: string;
|
|
203
|
+
}>(config: T, setting: string): T & {
|
|
204
|
+
options?: string;
|
|
205
|
+
};
|
|
161
206
|
/**
|
|
162
207
|
* `connectionString` with `setting` appended to an existing `options` query
|
|
163
208
|
* parameter, or `null` when it carries none (in which case the caller uses the
|
|
@@ -170,22 +215,12 @@ export declare function withStatementTimeoutOption(config: ConnectionOptionsConf
|
|
|
170
215
|
* password is not parseable by pg either, so there is no shape this handles
|
|
171
216
|
* differently from the driver.
|
|
172
217
|
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* is worth keeping because it was wrong in an instructive way: importing it
|
|
176
|
-
* from `client.ts` adds an import edge from a module ~100 test processes load,
|
|
177
|
-
* and this file's merged coverage read 40% while measuring 100% in isolation,
|
|
178
|
-
* which moved the aggregate gate 75.48% -> 75.03% against a 75% floor. The
|
|
179
|
-
* conclusion drawn was that the refactor cost the gate's headroom.
|
|
180
|
-
*
|
|
181
|
-
* The 40% was a c8 merge defect, not an import cost: c8's V8-level merge is not
|
|
182
|
-
* monotonic, and once the report merges at the istanbul level instead this file
|
|
183
|
-
* reads 100% with the edge in place (see `//merge-bug` in .c8rc.json). So the
|
|
184
|
-
* duplication was paying for an artifact, and the two copies are now one.
|
|
218
|
+
* Used by {@link withStartupSetting} (the client's pool configuration) and
|
|
219
|
+
* {@link withSearchPathOption}.
|
|
185
220
|
*
|
|
186
|
-
* Keep this module import-free
|
|
187
|
-
*
|
|
188
|
-
*
|
|
221
|
+
* Keep this module import-free: `query/` and `cli/` both reach it, and an
|
|
222
|
+
* edge back to `client.ts` would be the cycle `scripts/check-import-cycles.mjs`
|
|
223
|
+
* exists to refuse.
|
|
189
224
|
*/
|
|
190
225
|
export declare function mergeConnectionStringOptions(connectionString: string, setting: string): string | null;
|
|
191
226
|
/**
|
package/dist/connection-url.js
CHANGED
|
@@ -106,8 +106,22 @@ function noPooler(target) {
|
|
|
106
106
|
* blocks a legitimate database, so precision wins and the caller is expected to
|
|
107
107
|
* offer an override.
|
|
108
108
|
*/
|
|
109
|
-
export function detectPooler(connectionString) {
|
|
110
|
-
const
|
|
109
|
+
export function detectPooler(connectionString, environment) {
|
|
110
|
+
const parsed = parseConnectionTarget(connectionString);
|
|
111
|
+
return detectPoolerTarget(environment === undefined ? parsed : fillTargetFromEnvironment(parsed, environment));
|
|
112
|
+
}
|
|
113
|
+
/** `target` with the host and port it leaves unset taken from `environment`, the way node-postgres does. */
|
|
114
|
+
export function fillTargetFromEnvironment(target, environment) {
|
|
115
|
+
const host = target.host ?? (environment.host ? environment.host.trim().toLowerCase() || null : null);
|
|
116
|
+
let port = target.port;
|
|
117
|
+
if (port === null && environment.port) {
|
|
118
|
+
const parsed = Number.parseInt(environment.port, 10);
|
|
119
|
+
port = Number.isInteger(parsed) ? parsed : null;
|
|
120
|
+
}
|
|
121
|
+
return { host, port };
|
|
122
|
+
}
|
|
123
|
+
/** {@link detectPooler} for a target that is already parsed. */
|
|
124
|
+
export function detectPoolerTarget(target) {
|
|
111
125
|
if (target.host !== null) {
|
|
112
126
|
for (const label of target.host.split('.')) {
|
|
113
127
|
for (const token of label.split(/[-_]/)) {
|
|
@@ -160,6 +174,21 @@ function deriveDirectHost(host, token) {
|
|
|
160
174
|
});
|
|
161
175
|
return changed ? rewritten.join('.') : null;
|
|
162
176
|
}
|
|
177
|
+
/** Why `turbine doctor` refuses a pooler; the paragraph {@link poolerRefusalMessage} prints by default. */
|
|
178
|
+
const DEFAULT_POOLER_EXPLANATION = [
|
|
179
|
+
'A transaction pooler (PgBouncer, a Neon "-pooler" endpoint, Supabase\'s pooler) does not',
|
|
180
|
+
'give a client its own server backend. It multiplexes many clients onto a few shared',
|
|
181
|
+
'backends and reuses one as soon as a transaction ends, so:',
|
|
182
|
+
'',
|
|
183
|
+
' 1. Session state is not private. Anything this command sets on the session can be left',
|
|
184
|
+
' behind for another client, and whatever an earlier client left behind can be in',
|
|
185
|
+
' force for this one. That is how a "read-only guardrail" becomes an outage.',
|
|
186
|
+
' 2. Session-scoped views describe the wrong session. pg_prepared_statements, which this',
|
|
187
|
+
' report tells you to read to confirm a cached plan, belongs to whichever backend',
|
|
188
|
+
' answered, not to your application.',
|
|
189
|
+
' 3. The read bounds may not apply. This command asks for its statement_timeout as a',
|
|
190
|
+
' connection parameter, and a pooler is free to drop or reject one.',
|
|
191
|
+
];
|
|
163
192
|
/**
|
|
164
193
|
* The lines a command prints when it refuses a pooler endpoint.
|
|
165
194
|
*
|
|
@@ -177,18 +206,7 @@ export function poolerRefusalMessage(detection, options) {
|
|
|
177
206
|
` Endpoint: ${where}${detection.port === null ? '' : `:${detection.port}`}`,
|
|
178
207
|
` Detected: ${what}`,
|
|
179
208
|
'',
|
|
180
|
-
|
|
181
|
-
'give a client its own server backend. It multiplexes many clients onto a few shared',
|
|
182
|
-
'backends and reuses one as soon as a transaction ends, so:',
|
|
183
|
-
'',
|
|
184
|
-
' 1. Session state is not private. Anything this command sets on the session can be left',
|
|
185
|
-
' behind for another client, and whatever an earlier client left behind can be in',
|
|
186
|
-
' force for this one. That is how a "read-only guardrail" becomes an outage.',
|
|
187
|
-
' 2. Session-scoped views describe the wrong session. pg_prepared_statements, which this',
|
|
188
|
-
' report tells you to read to confirm a cached plan, belongs to whichever backend',
|
|
189
|
-
' answered, not to your application.',
|
|
190
|
-
' 3. The read bounds may not apply. This command asks for its statement_timeout as a',
|
|
191
|
-
' connection parameter, and a pooler is free to drop or reject one.',
|
|
209
|
+
...(options.explanation ?? DEFAULT_POOLER_EXPLANATION),
|
|
192
210
|
'',
|
|
193
211
|
'Use the DIRECT (non-pooled) endpoint for the same database instead.',
|
|
194
212
|
];
|
|
@@ -233,12 +251,33 @@ export function poolerRefusalMessage(detection, options) {
|
|
|
233
251
|
* a value that can carry a space can carry a second `-c`.
|
|
234
252
|
*/
|
|
235
253
|
export function withStatementTimeoutOption(config, statementTimeoutMs) {
|
|
254
|
+
const setting = statementTimeoutSetting(statementTimeoutMs);
|
|
255
|
+
return setting === null ? config : withStartupSetting(config, setting);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* The `-c statement_timeout=<ms>` startup setting, or `null` when the value is
|
|
259
|
+
* not a non-negative safe integer (see the injection note on
|
|
260
|
+
* {@link withStatementTimeoutOption}). No unit suffix: the GUC's default unit
|
|
261
|
+
* is milliseconds.
|
|
262
|
+
*/
|
|
263
|
+
export function statementTimeoutSetting(statementTimeoutMs) {
|
|
236
264
|
if (!Number.isSafeInteger(statementTimeoutMs) || statementTimeoutMs < 0)
|
|
237
|
-
return
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
265
|
+
return null;
|
|
266
|
+
return `-c statement_timeout=${statementTimeoutMs}`;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* `config` with one `-c name=value` startup setting appended to its libpq
|
|
270
|
+
* `options`, in whichever place pg will read them from: an `options` query
|
|
271
|
+
* parameter already on the connection string wins over the `options` field,
|
|
272
|
+
* and the field falls back to `PGOPTIONS` only while it is unset, so both are
|
|
273
|
+
* read first and appended to rather than replaced.
|
|
274
|
+
*
|
|
275
|
+
* `setting` is emitted verbatim. The caller must have built it from a closed
|
|
276
|
+
* set or a narrowed number: the `options` string is split on whitespace, so a
|
|
277
|
+
* caller-controlled value could carry a second `-c`.
|
|
278
|
+
*/
|
|
279
|
+
export function withStartupSetting(config, setting) {
|
|
280
|
+
const merged = config.connectionString ? mergeConnectionStringOptions(config.connectionString, setting) : null;
|
|
242
281
|
if (merged !== null)
|
|
243
282
|
return { ...config, connectionString: merged };
|
|
244
283
|
const existing = config.options || (typeof process !== 'undefined' ? process.env?.PGOPTIONS : undefined);
|
|
@@ -256,22 +295,12 @@ export function withStatementTimeoutOption(config, statementTimeoutMs) {
|
|
|
256
295
|
* password is not parseable by pg either, so there is no shape this handles
|
|
257
296
|
* differently from the driver.
|
|
258
297
|
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
* is worth keeping because it was wrong in an instructive way: importing it
|
|
262
|
-
* from `client.ts` adds an import edge from a module ~100 test processes load,
|
|
263
|
-
* and this file's merged coverage read 40% while measuring 100% in isolation,
|
|
264
|
-
* which moved the aggregate gate 75.48% -> 75.03% against a 75% floor. The
|
|
265
|
-
* conclusion drawn was that the refactor cost the gate's headroom.
|
|
266
|
-
*
|
|
267
|
-
* The 40% was a c8 merge defect, not an import cost: c8's V8-level merge is not
|
|
268
|
-
* monotonic, and once the report merges at the istanbul level instead this file
|
|
269
|
-
* reads 100% with the edge in place (see `//merge-bug` in .c8rc.json). So the
|
|
270
|
-
* duplication was paying for an artifact, and the two copies are now one.
|
|
298
|
+
* Used by {@link withStartupSetting} (the client's pool configuration) and
|
|
299
|
+
* {@link withSearchPathOption}.
|
|
271
300
|
*
|
|
272
|
-
* Keep this module import-free
|
|
273
|
-
*
|
|
274
|
-
*
|
|
301
|
+
* Keep this module import-free: `query/` and `cli/` both reach it, and an
|
|
302
|
+
* edge back to `client.ts` would be the cycle `scripts/check-import-cycles.mjs`
|
|
303
|
+
* exists to refuse.
|
|
275
304
|
*/
|
|
276
305
|
export function mergeConnectionStringOptions(connectionString, setting) {
|
|
277
306
|
const q = connectionString.indexOf('?');
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm, the `diagnostics` switch.
|
|
3
|
+
*
|
|
4
|
+
* One client option decides what Turbine checks and says about itself at run
|
|
5
|
+
* time: per-query advice (unknown options, unordered pages, deep `with`,
|
|
6
|
+
* strategy notes, missing FK indexes, redundant sort terms) and the SQL-cache
|
|
7
|
+
* self-check. It is resolved ONCE, when a client is constructed, and travels to
|
|
8
|
+
* every query interface the client builds, so no hot path reads `process.env`.
|
|
9
|
+
*
|
|
10
|
+
* This module is the only place in the library (outside `cli/`) that reads
|
|
11
|
+
* `NODE_ENV` or the two `TURBINE_*` cache-check variables; a source scan
|
|
12
|
+
* (`fleet-diagnostics-env-scan.test.ts`) fails the build on a second reader.
|
|
13
|
+
*
|
|
14
|
+
* Zero imports besides errors.ts, so client.ts, query/ and the engines can all
|
|
15
|
+
* depend on it without a new cycle.
|
|
16
|
+
*/
|
|
17
|
+
/** `'development'`: advice on, cache self-check on every hit. `'production'`: both off. */
|
|
18
|
+
export type DiagnosticsMode = 'development' | 'production';
|
|
19
|
+
/** The SQL-cache self-check: rebuild on every cache hit, a sampled fraction of hits, or never. */
|
|
20
|
+
export type CacheCheckMode = 'every-hit' | 'off' | {
|
|
21
|
+
readonly sample: number;
|
|
22
|
+
};
|
|
23
|
+
/** Per-part overrides for {@link DiagnosticsConfig}. Unset parts follow the mode. */
|
|
24
|
+
export interface DiagnosticsOptions {
|
|
25
|
+
/**
|
|
26
|
+
* Per-query advice: unknown query options, unordered pages, deep `with`
|
|
27
|
+
* trees, relation-strategy notes, missing FK indexes, redundant sort terms.
|
|
28
|
+
* Default: on in development, off in production.
|
|
29
|
+
*/
|
|
30
|
+
advice?: boolean | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* SQL-cache self-check. `'every-hit'` rebuilds the SQL on each cache hit
|
|
33
|
+
* and compares; `{ sample }` compares that fraction of hits, in `(0, 1]`;
|
|
34
|
+
* `'off'` never compares. Default: `'every-hit'` in development, `'off'` in
|
|
35
|
+
* production. A mismatch means Turbine has a bug, and throws.
|
|
36
|
+
*/
|
|
37
|
+
cacheCheck?: CacheCheckMode | undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The `diagnostics` client option: a mode, or per-part overrides on top of
|
|
41
|
+
* one. When no mode is given it comes from `NODE_ENV`, read once when the
|
|
42
|
+
* client is constructed: `'production'` when `NODE_ENV` is `'production'` (or
|
|
43
|
+
* when there is no `process` at all, as on an edge runtime), else
|
|
44
|
+
* `'development'`.
|
|
45
|
+
*/
|
|
46
|
+
export type DiagnosticsConfig = DiagnosticsMode | (DiagnosticsOptions & {
|
|
47
|
+
mode?: DiagnosticsMode | undefined;
|
|
48
|
+
});
|
|
49
|
+
/** What a client actually runs with. Frozen; built only by {@link resolveDiagnostics}. */
|
|
50
|
+
export interface ResolvedDiagnostics {
|
|
51
|
+
readonly mode: DiagnosticsMode;
|
|
52
|
+
/** Whether per-query advice is emitted. */
|
|
53
|
+
readonly advice: boolean;
|
|
54
|
+
readonly cacheCheck: CacheCheckMode;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The environment variables this module reads. `null` in their place means
|
|
58
|
+
* there is no `process` to read (an edge runtime), which resolves to
|
|
59
|
+
* production.
|
|
60
|
+
*/
|
|
61
|
+
export interface DiagnosticsEnv {
|
|
62
|
+
NODE_ENV?: string | undefined;
|
|
63
|
+
TURBINE_DISABLE_CACHE_CHECK?: string | undefined;
|
|
64
|
+
TURBINE_CACHE_CHECK_SAMPLE?: string | undefined;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the `diagnostics` option, once, at client construction.
|
|
68
|
+
*
|
|
69
|
+
* Precedence for each part: the explicit option, then (for `cacheCheck` only)
|
|
70
|
+
* the legacy `TURBINE_DISABLE_CACHE_CHECK` / `TURBINE_CACHE_CHECK_SAMPLE`
|
|
71
|
+
* variables, then the mode's default. The mode itself is the option's, else
|
|
72
|
+
* `NODE_ENV`'s.
|
|
73
|
+
*
|
|
74
|
+
* Throws `ValidationError` (E003) for an unknown mode, an unknown key, a
|
|
75
|
+
* non-boolean `advice`, or a `sample` outside `(0, 1]`. A value this function
|
|
76
|
+
* returned is handed back by reference.
|
|
77
|
+
*
|
|
78
|
+
* @param env - The environment to read; defaults to `process.env`. Tests pass
|
|
79
|
+
* one explicitly; `null` stands for a runtime with no `process`.
|
|
80
|
+
*/
|
|
81
|
+
export declare function resolveDiagnostics(config?: unknown, env?: DiagnosticsEnv | null): ResolvedDiagnostics;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* turbine-orm, the `diagnostics` switch.
|
|
3
|
+
*
|
|
4
|
+
* One client option decides what Turbine checks and says about itself at run
|
|
5
|
+
* time: per-query advice (unknown options, unordered pages, deep `with`,
|
|
6
|
+
* strategy notes, missing FK indexes, redundant sort terms) and the SQL-cache
|
|
7
|
+
* self-check. It is resolved ONCE, when a client is constructed, and travels to
|
|
8
|
+
* every query interface the client builds, so no hot path reads `process.env`.
|
|
9
|
+
*
|
|
10
|
+
* This module is the only place in the library (outside `cli/`) that reads
|
|
11
|
+
* `NODE_ENV` or the two `TURBINE_*` cache-check variables; a source scan
|
|
12
|
+
* (`fleet-diagnostics-env-scan.test.ts`) fails the build on a second reader.
|
|
13
|
+
*
|
|
14
|
+
* Zero imports besides errors.ts, so client.ts, query/ and the engines can all
|
|
15
|
+
* depend on it without a new cycle.
|
|
16
|
+
*/
|
|
17
|
+
import { ValidationError } from './errors.js';
|
|
18
|
+
const MODES = ['development', 'production'];
|
|
19
|
+
const OPTION_KEYS = new Set(['mode', 'advice', 'cacheCheck']);
|
|
20
|
+
/**
|
|
21
|
+
* Marks objects {@link resolveDiagnostics} built, so resolving a resolved value
|
|
22
|
+
* hands it back by reference. A `TransactionClient` builds a query interface
|
|
23
|
+
* per table per transaction from the client's options; re-resolving there would
|
|
24
|
+
* put the environment reads back on a per-transaction path.
|
|
25
|
+
*/
|
|
26
|
+
const resolvedSet = new WeakSet();
|
|
27
|
+
/**
|
|
28
|
+
* Read the variables once. Every read is guarded: no `process` (edge runtimes)
|
|
29
|
+
* and no `process.env` (some sandboxes) both mean "no environment".
|
|
30
|
+
*/
|
|
31
|
+
function readEnv() {
|
|
32
|
+
if (typeof process === 'undefined' || process.env === undefined)
|
|
33
|
+
return null;
|
|
34
|
+
const env = process.env;
|
|
35
|
+
return {
|
|
36
|
+
NODE_ENV: env.NODE_ENV,
|
|
37
|
+
TURBINE_DISABLE_CACHE_CHECK: env.TURBINE_DISABLE_CACHE_CHECK,
|
|
38
|
+
TURBINE_CACHE_CHECK_SAMPLE: env.TURBINE_CACHE_CHECK_SAMPLE,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function invalid(detail) {
|
|
42
|
+
return new ValidationError(`Invalid diagnostics option: ${detail}. Expected 'development', 'production', or ` +
|
|
43
|
+
"{ mode?, advice?: boolean, cacheCheck?: 'every-hit' | 'off' | { sample: number in (0, 1] } }.");
|
|
44
|
+
}
|
|
45
|
+
function checkSample(value) {
|
|
46
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0 || value > 1) {
|
|
47
|
+
throw invalid(`cacheCheck.sample must be a number in (0, 1], got ${describe(value)}`);
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
function describe(value) {
|
|
52
|
+
if (typeof value === 'string')
|
|
53
|
+
return JSON.stringify(value);
|
|
54
|
+
if (typeof value === 'number' || typeof value === 'boolean' || value === null || value === undefined) {
|
|
55
|
+
return String(value);
|
|
56
|
+
}
|
|
57
|
+
return Array.isArray(value) ? 'an array' : `a ${typeof value}`;
|
|
58
|
+
}
|
|
59
|
+
function resolveCacheCheck(value) {
|
|
60
|
+
if (value === 'every-hit' || value === 'off')
|
|
61
|
+
return value;
|
|
62
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
63
|
+
const keys = Object.keys(value);
|
|
64
|
+
if (keys.length !== 1 || keys[0] !== 'sample') {
|
|
65
|
+
throw invalid(`cacheCheck object takes exactly one key, sample; got { ${keys.join(', ')} }`);
|
|
66
|
+
}
|
|
67
|
+
return Object.freeze({ sample: checkSample(value.sample) });
|
|
68
|
+
}
|
|
69
|
+
throw invalid(`cacheCheck ${describe(value)}`);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The legacy cache-check variables, under an explicit `cacheCheck`.
|
|
73
|
+
* `TURBINE_DISABLE_CACHE_CHECK=1` turns the check off in any mode. In
|
|
74
|
+
* production mode, `TURBINE_CACHE_CHECK_SAMPLE` sets a sample rate: a rate of
|
|
75
|
+
* 1 or more checks every hit, and 0, a negative or an unparseable value leaves
|
|
76
|
+
* the check off, as these variables always behaved. Development mode already
|
|
77
|
+
* checks every hit, so the sample variable is not read there.
|
|
78
|
+
*/
|
|
79
|
+
function legacyCacheCheck(mode, env) {
|
|
80
|
+
if (env === null)
|
|
81
|
+
return undefined;
|
|
82
|
+
if (env.TURBINE_DISABLE_CACHE_CHECK === '1')
|
|
83
|
+
return 'off';
|
|
84
|
+
if (mode !== 'production' || env.TURBINE_CACHE_CHECK_SAMPLE === undefined)
|
|
85
|
+
return undefined;
|
|
86
|
+
const rate = Number.parseFloat(env.TURBINE_CACHE_CHECK_SAMPLE);
|
|
87
|
+
if (!Number.isFinite(rate) || rate <= 0)
|
|
88
|
+
return 'off';
|
|
89
|
+
return Object.freeze({ sample: Math.min(rate, 1) });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Resolve the `diagnostics` option, once, at client construction.
|
|
93
|
+
*
|
|
94
|
+
* Precedence for each part: the explicit option, then (for `cacheCheck` only)
|
|
95
|
+
* the legacy `TURBINE_DISABLE_CACHE_CHECK` / `TURBINE_CACHE_CHECK_SAMPLE`
|
|
96
|
+
* variables, then the mode's default. The mode itself is the option's, else
|
|
97
|
+
* `NODE_ENV`'s.
|
|
98
|
+
*
|
|
99
|
+
* Throws `ValidationError` (E003) for an unknown mode, an unknown key, a
|
|
100
|
+
* non-boolean `advice`, or a `sample` outside `(0, 1]`. A value this function
|
|
101
|
+
* returned is handed back by reference.
|
|
102
|
+
*
|
|
103
|
+
* @param env - The environment to read; defaults to `process.env`. Tests pass
|
|
104
|
+
* one explicitly; `null` stands for a runtime with no `process`.
|
|
105
|
+
*/
|
|
106
|
+
export function resolveDiagnostics(config, env = readEnv()) {
|
|
107
|
+
if (typeof config === 'object' && config !== null && resolvedSet.has(config)) {
|
|
108
|
+
return config;
|
|
109
|
+
}
|
|
110
|
+
let options = {};
|
|
111
|
+
if (typeof config === 'string') {
|
|
112
|
+
if (!MODES.includes(config))
|
|
113
|
+
throw invalid(`unknown mode ${describe(config)}`);
|
|
114
|
+
options = { mode: config };
|
|
115
|
+
}
|
|
116
|
+
else if (typeof config === 'object' && config !== null && !Array.isArray(config)) {
|
|
117
|
+
for (const key of Object.keys(config)) {
|
|
118
|
+
if (!OPTION_KEYS.has(key))
|
|
119
|
+
throw invalid(`unknown key "${key}"`);
|
|
120
|
+
}
|
|
121
|
+
options = config;
|
|
122
|
+
if (options.mode !== undefined && !MODES.includes(options.mode)) {
|
|
123
|
+
throw invalid(`unknown mode ${describe(options.mode)}`);
|
|
124
|
+
}
|
|
125
|
+
if (options.advice !== undefined && typeof options.advice !== 'boolean') {
|
|
126
|
+
throw invalid(`advice must be a boolean, got ${describe(options.advice)}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else if (config !== undefined && config !== null) {
|
|
130
|
+
throw invalid(describe(config));
|
|
131
|
+
}
|
|
132
|
+
const mode = options.mode ??
|
|
133
|
+
(env === null || env.NODE_ENV === 'production' ? 'production' : 'development');
|
|
134
|
+
const cacheCheck = options.cacheCheck !== undefined
|
|
135
|
+
? resolveCacheCheck(options.cacheCheck)
|
|
136
|
+
: (legacyCacheCheck(mode, env) ?? (mode === 'production' ? 'off' : 'every-hit'));
|
|
137
|
+
const resolved = Object.freeze({
|
|
138
|
+
mode,
|
|
139
|
+
advice: options.advice ?? mode === 'development',
|
|
140
|
+
cacheCheck,
|
|
141
|
+
});
|
|
142
|
+
resolvedSet.add(resolved);
|
|
143
|
+
return resolved;
|
|
144
|
+
}
|