@prisma-next/cli 0.16.0-dev.3 → 0.16.0-dev.31
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 +44 -45
- package/dist/cli.mjs +13 -13
- package/dist/{client-KuBQftxz.mjs → client-B1UjQc_x.mjs} +50 -58
- package/dist/client-B1UjQc_x.mjs.map +1 -0
- package/dist/{command-helpers-Cpq44aVa.mjs → command-helpers-D-jBl0Qt.mjs} +16 -8
- package/dist/command-helpers-D-jBl0Qt.mjs.map +1 -0
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +8 -6
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +11 -12
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +14 -15
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +1 -1
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +13 -13
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +4 -2
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +1 -1
- package/dist/commands/migration-graph.d.mts +1 -1
- package/dist/commands/migration-graph.mjs +4 -4
- package/dist/commands/migration-list.d.mts +1 -1
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +1 -1
- package/dist/commands/migration-log.d.mts +1 -1
- package/dist/commands/migration-log.mjs +1 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +16 -40
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +3 -4
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.mjs +5 -5
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +1 -1
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +13 -18
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/commands/telemetry/index.mjs +1 -1
- package/dist/contract-at-errors-DvZ_DzJK.mjs +36 -0
- package/dist/contract-at-errors-DvZ_DzJK.mjs.map +1 -0
- package/dist/{contract-emit-CgnXSANN.mjs → contract-emit-BT46Mu8Q.mjs} +3 -3
- package/dist/{contract-emit-CgnXSANN.mjs.map → contract-emit-BT46Mu8Q.mjs.map} +1 -1
- package/dist/{contract-emit-cJQBlvGb.mjs → contract-emit-hVdlaF2U.mjs} +6 -7
- package/dist/{contract-emit-cJQBlvGb.mjs.map → contract-emit-hVdlaF2U.mjs.map} +1 -1
- package/dist/{contract-enrichment-gn9sWbPw.mjs → contract-enrichment-JUhLv-BX.mjs} +8 -8
- package/dist/{contract-enrichment-gn9sWbPw.mjs.map → contract-enrichment-JUhLv-BX.mjs.map} +1 -1
- package/dist/{contract-infer-Cg8evbeg.mjs → contract-infer-DpqTQECL.mjs} +3 -3
- package/dist/{contract-infer-Cg8evbeg.mjs.map → contract-infer-DpqTQECL.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-D_3VeHVb.mjs → contract-space-aggregate-loader-CNd-ZB6C.mjs} +14 -14
- package/dist/contract-space-aggregate-loader-CNd-ZB6C.mjs.map +1 -0
- package/dist/{db-verify-BEclUzki.mjs → db-verify-FEN6k1m7.mjs} +10 -8
- package/dist/db-verify-FEN6k1m7.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +4 -4
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.d.mts +2 -1
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +61 -21
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{format-DAUAZqPt.mjs → format-DI5qVr22.mjs} +8 -7
- package/dist/format-DI5qVr22.mjs.map +1 -0
- package/dist/{framework-components-CnbUbiJw.mjs → framework-components-C4XACYNB.mjs} +3 -3
- package/dist/framework-components-C4XACYNB.mjs.map +1 -0
- package/dist/{init-C3JhkHg-.mjs → init-ClrRkbwd.mjs} +77 -67
- package/dist/init-ClrRkbwd.mjs.map +1 -0
- package/dist/{inspect-live-schema-CX7EA5C3.mjs → inspect-live-schema-C0Rgdtw_.mjs} +4 -4
- package/dist/{inspect-live-schema-CX7EA5C3.mjs.map → inspect-live-schema-C0Rgdtw_.mjs.map} +1 -1
- package/dist/{migration-check-MHT3w7_v.mjs → migration-check-zEkHpPDT.mjs} +58 -30
- package/dist/migration-check-zEkHpPDT.mjs.map +1 -0
- package/dist/{migration-command-scaffold-CRyYrHZ9.mjs → migration-command-scaffold-CkNsp9g1.mjs} +4 -4
- package/dist/{migration-command-scaffold-CRyYrHZ9.mjs.map → migration-command-scaffold-CkNsp9g1.mjs.map} +1 -1
- package/dist/{migration-graph-command-render-B83xrnNy.mjs → migration-graph-command-render-DEwFpx-w.mjs} +5 -4
- package/dist/migration-graph-command-render-DEwFpx-w.mjs.map +1 -0
- package/dist/{migration-list-BAKujUjh.mjs → migration-list-BkafFVXS.mjs} +6 -6
- package/dist/migration-list-BkafFVXS.mjs.map +1 -0
- package/dist/{migration-log-C_xam2HZ.mjs → migration-log-BxhAtbhA.mjs} +5 -5
- package/dist/{migration-log-C_xam2HZ.mjs.map → migration-log-BxhAtbhA.mjs.map} +1 -1
- package/dist/{migration-path-target-DpPTsRCg.mjs → migration-path-target-B5HkjSTO.mjs} +2 -2
- package/dist/{migration-path-target-DpPTsRCg.mjs.map → migration-path-target-B5HkjSTO.mjs.map} +1 -1
- package/dist/{migration-plan-CreSVtWZ.mjs → migration-plan-Bk2pbPQH.mjs} +64 -74
- package/dist/migration-plan-Bk2pbPQH.mjs.map +1 -0
- package/dist/{migration-status-YgEvXf-u.mjs → migration-status-BzlARseq.mjs} +13 -12
- package/dist/migration-status-BzlARseq.mjs.map +1 -0
- package/dist/{output-mEQ74_nd.mjs → output-DWNYqZGc.mjs} +5 -6
- package/dist/output-DWNYqZGc.mjs.map +1 -0
- package/dist/{ref-advancement-BkXlikCA.mjs → ref-advancement-BCz7X7qJ.mjs} +13 -6
- package/dist/ref-advancement-BCz7X7qJ.mjs.map +1 -0
- package/dist/{telemetry-DVr6RFnq.mjs → telemetry-BbniBUbP.mjs} +2 -2
- package/dist/{telemetry-DVr6RFnq.mjs.map → telemetry-BbniBUbP.mjs.map} +1 -1
- package/dist/{types-D4r_HI9-.d.mts → types-DgXprE3w.d.mts} +3 -3
- package/dist/types-DgXprE3w.d.mts.map +1 -0
- package/dist/{verify-CgDVZjhc.mjs → verify-BSaNeaSL.mjs} +2 -2
- package/dist/{verify-CgDVZjhc.mjs.map → verify-BSaNeaSL.mjs.map} +1 -1
- package/package.json +21 -21
- package/src/commands/db-init.ts +5 -3
- package/src/commands/db-sign.ts +9 -7
- package/src/commands/db-update.ts +18 -9
- package/src/commands/db-verify.ts +4 -4
- package/src/commands/format.ts +1 -1
- package/src/commands/init/hygiene-gitattributes.ts +37 -21
- package/src/commands/init/init.ts +6 -6
- package/src/commands/init/output.ts +4 -5
- package/src/commands/init/probe-db.ts +9 -2
- package/src/commands/init/reinit-cleanup.ts +16 -17
- package/src/commands/init/templates/render.ts +2 -1
- package/src/commands/inspect-live-schema.ts +1 -1
- package/src/commands/migrate.ts +6 -5
- package/src/commands/migration-check.ts +72 -34
- package/src/commands/migration-list.ts +1 -5
- package/src/commands/migration-log.ts +1 -1
- package/src/commands/migration-new.ts +17 -41
- package/src/commands/migration-plan.ts +64 -88
- package/src/commands/migration-show.ts +2 -2
- package/src/commands/migration-status.ts +6 -7
- package/src/commands/ref.ts +19 -14
- package/src/control-api/client.ts +43 -25
- package/src/control-api/contract-enrichment.ts +7 -7
- package/src/control-api/operations/contract-emit.ts +2 -3
- package/src/control-api/operations/db-init.ts +3 -3
- package/src/control-api/operations/db-run.ts +8 -7
- package/src/control-api/operations/db-update.ts +2 -2
- package/src/control-api/operations/db-verify.ts +4 -4
- package/src/control-api/operations/format.ts +5 -4
- package/src/control-api/operations/migrate.ts +6 -5
- package/src/control-api/operations/run-migration.ts +2 -1
- package/src/control-api/types.ts +1 -1
- package/src/load-ts-contract.ts +81 -16
- package/src/utils/cli-errors.ts +15 -7
- package/src/utils/combine-verify-results.ts +2 -1
- package/src/utils/command-helpers.ts +15 -5
- package/src/utils/contract-at-errors.ts +13 -22
- package/src/utils/contract-space-aggregate-loader.ts +8 -8
- package/src/utils/contract-space-seed-phase.ts +11 -9
- package/src/utils/extension-pack-inputs.ts +8 -8
- package/src/utils/formatters/migration-graph-grid-layout.ts +2 -1
- package/src/utils/formatters/migration-graph-labels.ts +1 -2
- package/src/utils/formatters/migration-list-data-column.ts +1 -2
- package/src/utils/framework-components.ts +9 -9
- package/src/utils/integrity-violation-to-check-failure.ts +3 -3
- package/src/utils/migration-command-scaffold.ts +1 -1
- package/src/utils/plan-resolution.ts +7 -10
- package/src/utils/ref-advancement.ts +22 -3
- package/dist/client-KuBQftxz.mjs.map +0 -1
- package/dist/command-helpers-Cpq44aVa.mjs.map +0 -1
- package/dist/contract-at-errors-D9gEjYtg.mjs +0 -42
- package/dist/contract-at-errors-D9gEjYtg.mjs.map +0 -1
- package/dist/contract-space-aggregate-loader-D_3VeHVb.mjs.map +0 -1
- package/dist/db-verify-BEclUzki.mjs.map +0 -1
- package/dist/format-DAUAZqPt.mjs.map +0 -1
- package/dist/framework-components-CnbUbiJw.mjs.map +0 -1
- package/dist/init-C3JhkHg-.mjs.map +0 -1
- package/dist/migration-check-MHT3w7_v.mjs.map +0 -1
- package/dist/migration-graph-command-render-B83xrnNy.mjs.map +0 -1
- package/dist/migration-list-BAKujUjh.mjs.map +0 -1
- package/dist/migration-plan-CreSVtWZ.mjs.map +0 -1
- package/dist/migration-status-YgEvXf-u.mjs.map +0 -1
- package/dist/output-mEQ74_nd.mjs.map +0 -1
- package/dist/ref-advancement-BkXlikCA.mjs.map +0 -1
- package/dist/types-D4r_HI9-.d.mts.map +0 -1
- package/src/control-api/errors.ts +0 -9
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
LedgerEntryRecord,
|
|
5
5
|
} from '@prisma-next/contract/types';
|
|
6
6
|
import { emit as emitContractArtifacts } from '@prisma-next/emitter';
|
|
7
|
+
import { CliStructuredError } from '@prisma-next/errors/control';
|
|
7
8
|
import type { AuthoringPslBlockDescriptorNamespace } from '@prisma-next/framework-components/authoring';
|
|
8
9
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
9
10
|
import type {
|
|
@@ -27,13 +28,13 @@ import {
|
|
|
27
28
|
hasSchemaView,
|
|
28
29
|
} from '@prisma-next/framework-components/control';
|
|
29
30
|
import type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';
|
|
30
|
-
|
|
31
31
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
32
|
+
import { InternalError } from '@prisma-next/utils/internal-error';
|
|
32
33
|
import { notOk, ok } from '@prisma-next/utils/result';
|
|
34
|
+
import { structuredError } from '@prisma-next/utils/structured-error';
|
|
33
35
|
|
|
34
36
|
import { assertFrameworkComponentsCompatible } from '../utils/framework-components';
|
|
35
37
|
import { enrichContract } from './contract-enrichment';
|
|
36
|
-
import { ContractValidationError } from './errors';
|
|
37
38
|
import { executeDbInit } from './operations/db-init';
|
|
38
39
|
import { executeDbUpdate } from './operations/db-update';
|
|
39
40
|
import { type ExecuteDbVerifyResult, executeDbVerify } from './operations/db-verify';
|
|
@@ -103,7 +104,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
103
104
|
target: this.options.target,
|
|
104
105
|
adapter: this.options.adapter,
|
|
105
106
|
driver: this.options.driver,
|
|
106
|
-
|
|
107
|
+
extensions: this.options.extensions,
|
|
107
108
|
});
|
|
108
109
|
|
|
109
110
|
this.familyInstance = this.options.family.create(this.stack);
|
|
@@ -112,7 +113,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
112
113
|
const rawComponents = [
|
|
113
114
|
this.options.target,
|
|
114
115
|
this.options.adapter,
|
|
115
|
-
...(this.options.
|
|
116
|
+
...(this.options.extensions ?? []),
|
|
116
117
|
];
|
|
117
118
|
this.frameworkComponents = assertFrameworkComponentsCompatible(
|
|
118
119
|
this.options.family.familyId,
|
|
@@ -128,20 +129,25 @@ class ControlClientImpl implements ControlClient {
|
|
|
128
129
|
this.init();
|
|
129
130
|
|
|
130
131
|
if (this.driver) {
|
|
131
|
-
throw new
|
|
132
|
+
throw new CliStructuredError(
|
|
133
|
+
'DRIVER.ALREADY_CONNECTED',
|
|
134
|
+
'Already connected. Call close() before reconnecting.',
|
|
135
|
+
);
|
|
132
136
|
}
|
|
133
137
|
|
|
134
138
|
// Resolve connection: argument > default from options
|
|
135
139
|
const resolvedConnection = connection ?? this.defaultConnection;
|
|
136
140
|
if (resolvedConnection === undefined) {
|
|
137
|
-
throw new
|
|
141
|
+
throw new CliStructuredError(
|
|
142
|
+
'CONFIG.DB_CONNECTION_REQUIRED',
|
|
138
143
|
'No connection provided. Pass a connection to connect() or provide a default connection when creating the client.',
|
|
139
144
|
);
|
|
140
145
|
}
|
|
141
146
|
|
|
142
147
|
// Check for driver descriptor
|
|
143
148
|
if (!this.stack?.driver) {
|
|
144
|
-
throw new
|
|
149
|
+
throw new CliStructuredError(
|
|
150
|
+
'CONFIG.DRIVER_REQUIRED',
|
|
145
151
|
'Driver is not configured. Pass a driver descriptor when creating the control client to enable database operations.',
|
|
146
152
|
);
|
|
147
153
|
}
|
|
@@ -167,7 +173,8 @@ class ControlClientImpl implements ControlClient {
|
|
|
167
173
|
private buildControlAdapter(): ControlAdapterInstance<string, string> {
|
|
168
174
|
this.init();
|
|
169
175
|
if (!this.stack?.adapter) {
|
|
170
|
-
throw new
|
|
176
|
+
throw new CliStructuredError(
|
|
177
|
+
'MIGRATION.TARGET_UNSUPPORTED',
|
|
171
178
|
`Target "${this.options.target.targetId}" requires an adapter for migrations`,
|
|
172
179
|
);
|
|
173
180
|
}
|
|
@@ -188,7 +195,10 @@ class ControlClientImpl implements ControlClient {
|
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
if (!this.driver || !this.familyInstance || !this.frameworkComponents) {
|
|
191
|
-
throw new
|
|
198
|
+
throw new CliStructuredError(
|
|
199
|
+
'DRIVER.NOT_CONNECTED',
|
|
200
|
+
'Not connected. Call connect(connection) first.',
|
|
201
|
+
);
|
|
192
202
|
}
|
|
193
203
|
return {
|
|
194
204
|
driver: this.driver,
|
|
@@ -229,7 +239,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
229
239
|
contract = familyInstance.deserializeContract(options.contract);
|
|
230
240
|
} catch (error) {
|
|
231
241
|
const message = error instanceof Error ? error.message : String(error);
|
|
232
|
-
throw
|
|
242
|
+
throw structuredError('CONTRACT.VALIDATION_FAILED', message, { cause: error });
|
|
233
243
|
}
|
|
234
244
|
|
|
235
245
|
// Emit verify span
|
|
@@ -282,7 +292,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
282
292
|
contract = familyInstance.deserializeContract(options.contract);
|
|
283
293
|
} catch (error) {
|
|
284
294
|
const message = error instanceof Error ? error.message : String(error);
|
|
285
|
-
throw
|
|
295
|
+
throw structuredError('CONTRACT.VALIDATION_FAILED', message, { cause: error });
|
|
286
296
|
}
|
|
287
297
|
|
|
288
298
|
// Emit schemaVerify span
|
|
@@ -336,7 +346,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
336
346
|
contract = familyInstance.deserializeContract(options.contract);
|
|
337
347
|
} catch (error) {
|
|
338
348
|
const message = error instanceof Error ? error.message : String(error);
|
|
339
|
-
throw
|
|
349
|
+
throw structuredError('CONTRACT.VALIDATION_FAILED', message, { cause: error });
|
|
340
350
|
}
|
|
341
351
|
|
|
342
352
|
// Emit sign span
|
|
@@ -381,7 +391,10 @@ class ControlClientImpl implements ControlClient {
|
|
|
381
391
|
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
382
392
|
|
|
383
393
|
if (!hasMigrations(this.options.target)) {
|
|
384
|
-
throw new
|
|
394
|
+
throw new CliStructuredError(
|
|
395
|
+
'MIGRATION.TARGET_UNSUPPORTED',
|
|
396
|
+
`Target "${this.options.target.targetId}" does not support migrations`,
|
|
397
|
+
);
|
|
385
398
|
}
|
|
386
399
|
|
|
387
400
|
const adapter = this.buildControlAdapter();
|
|
@@ -391,7 +404,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
391
404
|
contract = familyInstance.deserializeContract(options.contract);
|
|
392
405
|
} catch (error) {
|
|
393
406
|
const message = error instanceof Error ? error.message : String(error);
|
|
394
|
-
throw
|
|
407
|
+
throw structuredError('CONTRACT.VALIDATION_FAILED', message, { cause: error });
|
|
395
408
|
}
|
|
396
409
|
|
|
397
410
|
return executeDbInit({
|
|
@@ -404,7 +417,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
404
417
|
frameworkComponents,
|
|
405
418
|
migrationsDir: options.migrationsDir,
|
|
406
419
|
targetId: this.options.target.targetId,
|
|
407
|
-
|
|
420
|
+
extensions: this.options.extensions ?? [],
|
|
408
421
|
...ifDefined('onProgress', onProgress),
|
|
409
422
|
});
|
|
410
423
|
}
|
|
@@ -415,7 +428,10 @@ class ControlClientImpl implements ControlClient {
|
|
|
415
428
|
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
416
429
|
|
|
417
430
|
if (!hasMigrations(this.options.target)) {
|
|
418
|
-
throw new
|
|
431
|
+
throw new CliStructuredError(
|
|
432
|
+
'MIGRATION.TARGET_UNSUPPORTED',
|
|
433
|
+
`Target "${this.options.target.targetId}" does not support migrations`,
|
|
434
|
+
);
|
|
419
435
|
}
|
|
420
436
|
|
|
421
437
|
const adapter = this.buildControlAdapter();
|
|
@@ -425,7 +441,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
425
441
|
contract = familyInstance.deserializeContract(options.contract);
|
|
426
442
|
} catch (error) {
|
|
427
443
|
const message = error instanceof Error ? error.message : String(error);
|
|
428
|
-
throw
|
|
444
|
+
throw structuredError('CONTRACT.VALIDATION_FAILED', message, { cause: error });
|
|
429
445
|
}
|
|
430
446
|
|
|
431
447
|
return executeDbUpdate({
|
|
@@ -438,7 +454,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
438
454
|
frameworkComponents,
|
|
439
455
|
migrationsDir: options.migrationsDir,
|
|
440
456
|
targetId: this.options.target.targetId,
|
|
441
|
-
|
|
457
|
+
extensions: this.options.extensions ?? [],
|
|
442
458
|
...ifDefined('acceptDataLoss', options.acceptDataLoss),
|
|
443
459
|
...ifDefined('onProgress', onProgress),
|
|
444
460
|
});
|
|
@@ -455,7 +471,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
455
471
|
contract: options.contract,
|
|
456
472
|
migrationsDir: options.migrationsDir,
|
|
457
473
|
targetId: this.options.target.targetId,
|
|
458
|
-
|
|
474
|
+
extensions: this.options.extensions ?? [],
|
|
459
475
|
frameworkComponents,
|
|
460
476
|
mode: options.strict ? 'strict' : 'lenient',
|
|
461
477
|
skipSchema: options.skipSchema,
|
|
@@ -490,7 +506,10 @@ class ControlClientImpl implements ControlClient {
|
|
|
490
506
|
const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();
|
|
491
507
|
|
|
492
508
|
if (!hasMigrations(this.options.target)) {
|
|
493
|
-
throw new
|
|
509
|
+
throw new CliStructuredError(
|
|
510
|
+
'MIGRATION.TARGET_UNSUPPORTED',
|
|
511
|
+
`Target "${this.options.target.targetId}" does not support migrations`,
|
|
512
|
+
);
|
|
494
513
|
}
|
|
495
514
|
|
|
496
515
|
let contract: Contract;
|
|
@@ -498,7 +517,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
498
517
|
contract = familyInstance.deserializeContract(options.contract);
|
|
499
518
|
} catch (error) {
|
|
500
519
|
const message = error instanceof Error ? error.message : String(error);
|
|
501
|
-
throw
|
|
520
|
+
throw structuredError('CONTRACT.VALIDATION_FAILED', message, { cause: error });
|
|
502
521
|
}
|
|
503
522
|
|
|
504
523
|
return executeMigrate({
|
|
@@ -508,7 +527,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
508
527
|
migrations: this.options.target.migrations,
|
|
509
528
|
frameworkComponents,
|
|
510
529
|
migrationsDir: options.migrationsDir,
|
|
511
|
-
|
|
530
|
+
extensions: this.options.extensions ?? [],
|
|
512
531
|
targetId: this.options.target.targetId,
|
|
513
532
|
...ifDefined('refHash', options.refHash),
|
|
514
533
|
...ifDefined('refInvariants', options.refInvariants),
|
|
@@ -593,7 +612,7 @@ class ControlClientImpl implements ControlClient {
|
|
|
593
612
|
this.init();
|
|
594
613
|
|
|
595
614
|
if (!this.familyInstance) {
|
|
596
|
-
throw new
|
|
615
|
+
throw new InternalError('Family instance was not initialized. This is a bug.');
|
|
597
616
|
}
|
|
598
617
|
|
|
599
618
|
let contractRaw: unknown;
|
|
@@ -607,9 +626,8 @@ class ControlClientImpl implements ControlClient {
|
|
|
607
626
|
try {
|
|
608
627
|
const stack = this.stack!;
|
|
609
628
|
const sourceContext = {
|
|
610
|
-
|
|
629
|
+
composedExtensions: stack.extensions.map((p) => p.id),
|
|
611
630
|
composedExtensionContracts: stack.extensionContracts,
|
|
612
|
-
scalarTypeDescriptors: stack.scalarTypeDescriptors,
|
|
613
631
|
authoringContributions: stack.authoringContributions,
|
|
614
632
|
codecLookup: stack.codecLookup,
|
|
615
633
|
controlMutationDefaults: stack.controlMutationDefaults,
|
|
@@ -65,21 +65,21 @@ export function enrichContract(
|
|
|
65
65
|
): Contract {
|
|
66
66
|
const mergedCapabilities = mergeCapabilityMatrices(ir.capabilities, components);
|
|
67
67
|
|
|
68
|
-
const
|
|
68
|
+
const extensionsMeta: Record<string, unknown> = {};
|
|
69
69
|
for (const component of components) {
|
|
70
70
|
if (component.kind === 'extension') {
|
|
71
|
-
|
|
71
|
+
extensionsMeta[component.id] = extractExtensionPackMeta(component);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const
|
|
76
|
-
Object.keys(
|
|
77
|
-
? { ...ir.
|
|
78
|
-
: ir.
|
|
75
|
+
const extensions =
|
|
76
|
+
Object.keys(extensionsMeta).length > 0
|
|
77
|
+
? { ...ir.extensions, ...extensionsMeta }
|
|
78
|
+
: ir.extensions;
|
|
79
79
|
|
|
80
80
|
return {
|
|
81
81
|
...ir,
|
|
82
82
|
capabilities: sortDeepTyped(mergedCapabilities),
|
|
83
|
-
|
|
83
|
+
extensions: sortDeepTyped(extensions),
|
|
84
84
|
};
|
|
85
85
|
}
|
|
@@ -195,9 +195,8 @@ export async function executeContractEmit(
|
|
|
195
195
|
const stack = createControlStack(config);
|
|
196
196
|
|
|
197
197
|
const sourceContext = {
|
|
198
|
-
|
|
198
|
+
composedExtensions: stack.extensions.map((p) => p.id),
|
|
199
199
|
composedExtensionContracts: stack.extensionContracts,
|
|
200
|
-
scalarTypeDescriptors: stack.scalarTypeDescriptors,
|
|
201
200
|
authoringContributions: stack.authoringContributions,
|
|
202
201
|
codecLookup: stack.codecLookup,
|
|
203
202
|
controlMutationDefaults: stack.controlMutationDefaults,
|
|
@@ -231,7 +230,7 @@ export async function executeContractEmit(
|
|
|
231
230
|
let emitResult: Awaited<ReturnType<typeof emit>>;
|
|
232
231
|
try {
|
|
233
232
|
const familyInstance = config.family.create(stack);
|
|
234
|
-
const rawComponents = [config.target, config.adapter, ...(config.
|
|
233
|
+
const rawComponents = [config.target, config.adapter, ...(config.extensions ?? [])];
|
|
235
234
|
const frameworkComponents = assertFrameworkComponentsCompatible(
|
|
236
235
|
config.family.familyId,
|
|
237
236
|
config.target.targetId,
|
|
@@ -25,7 +25,7 @@ import { executeRun } from './db-run';
|
|
|
25
25
|
* 3. The runner's `execute` applies the per-space plans
|
|
26
26
|
* inside one outer transaction.
|
|
27
27
|
*
|
|
28
|
-
* `
|
|
28
|
+
* `extensions` mirrors `Config.extensions` (descriptor list).
|
|
29
29
|
* The loader (sub-spec § Loader) is the sole descriptor-import boundary.
|
|
30
30
|
*/
|
|
31
31
|
export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extends string> {
|
|
@@ -55,7 +55,7 @@ export interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extend
|
|
|
55
55
|
* routes through the same loader → planner → runner pipeline with no
|
|
56
56
|
* extension spaces in the aggregate.
|
|
57
57
|
*/
|
|
58
|
-
readonly
|
|
58
|
+
readonly extensions?: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
59
59
|
/** Optional progress callback for observing operation progress */
|
|
60
60
|
readonly onProgress?: OnControlProgress;
|
|
61
61
|
}
|
|
@@ -80,7 +80,7 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
|
|
|
80
80
|
frameworkComponents: options.frameworkComponents,
|
|
81
81
|
migrationsDir: options.migrationsDir,
|
|
82
82
|
targetId: options.targetId,
|
|
83
|
-
|
|
83
|
+
extensions: options.extensions ?? [],
|
|
84
84
|
policy: { allowedOperationClasses: ['additive'] },
|
|
85
85
|
action: 'dbInit',
|
|
86
86
|
...ifDefined('onProgress', options.onProgress),
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from '@prisma-next/migration-tools/aggregate';
|
|
25
25
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
26
26
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
27
|
+
import { InternalError } from '@prisma-next/utils/internal-error';
|
|
27
28
|
import { notOk, ok } from '@prisma-next/utils/result';
|
|
28
29
|
import { CliStructuredError } from '../../utils/cli-errors';
|
|
29
30
|
import {
|
|
@@ -80,7 +81,7 @@ export interface ExecuteRunOptions<TFamilyId extends string, TTargetId extends s
|
|
|
80
81
|
>;
|
|
81
82
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
82
83
|
readonly migrationsDir: string;
|
|
83
|
-
readonly
|
|
84
|
+
readonly extensions: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
84
85
|
readonly targetId: TTargetId;
|
|
85
86
|
readonly policy: MigrationOperationPolicy;
|
|
86
87
|
readonly action: 'dbInit' | 'dbUpdate';
|
|
@@ -119,7 +120,7 @@ export async function executeRun<TFamilyId extends string, TTargetId extends str
|
|
|
119
120
|
migrations,
|
|
120
121
|
frameworkComponents,
|
|
121
122
|
migrationsDir,
|
|
122
|
-
|
|
123
|
+
extensions,
|
|
123
124
|
targetId,
|
|
124
125
|
policy,
|
|
125
126
|
action,
|
|
@@ -131,7 +132,7 @@ export async function executeRun<TFamilyId extends string, TTargetId extends str
|
|
|
131
132
|
targetId,
|
|
132
133
|
migrationsDir,
|
|
133
134
|
appContract: contract,
|
|
134
|
-
|
|
135
|
+
extensions,
|
|
135
136
|
deserializeContract: (json) => familyInstance.deserializeContract(json),
|
|
136
137
|
};
|
|
137
138
|
const loaded = await buildContractSpaceAggregate(loadInputs);
|
|
@@ -200,7 +201,7 @@ export async function executeRun<TFamilyId extends string, TTargetId extends str
|
|
|
200
201
|
// `destination` is the storage hash users see in CLI output.
|
|
201
202
|
const appResolution = orderedResolutions.find((r) => r.spaceId === aggregate.app.spaceId);
|
|
202
203
|
if (!appResolution) {
|
|
203
|
-
throw new
|
|
204
|
+
throw new InternalError(
|
|
204
205
|
'Aggregate planner returned no plan for the app space — the planner is supposed to always emit one.',
|
|
205
206
|
);
|
|
206
207
|
}
|
|
@@ -283,7 +284,7 @@ function aggregatePlannerWarnings(
|
|
|
283
284
|
* Compare the live `_prisma_marker` rows against the aggregate's
|
|
284
285
|
* declared contract spaces. Any marker row whose `space` is not a space of
|
|
285
286
|
* the aggregate is an "orphan" — typically a marker left behind by
|
|
286
|
-
* an extension that was removed from `
|
|
287
|
+
* an extension that was removed from `extensions` without first
|
|
287
288
|
* cleaning up its on-disk migrations / database tables.
|
|
288
289
|
*
|
|
289
290
|
* Returns a {@link CliStructuredError} envelope (code
|
|
@@ -319,8 +320,8 @@ function detectOrphanMarkers(
|
|
|
319
320
|
.map((s) => `"${s}"`)
|
|
320
321
|
.join(
|
|
321
322
|
', ',
|
|
322
|
-
)}) that are not declared in the project's \`
|
|
323
|
-
fix: 'Either re-declare the missing extension(s) in `
|
|
323
|
+
)}) that are not declared in the project's \`extensions\`. The aggregate pipeline refuses to advance markers it cannot account for.`,
|
|
324
|
+
fix: 'Either re-declare the missing extension(s) in `extensions` (so the aggregate owns them again), or remove the orphan marker row(s) from `_prisma_marker` once you have confirmed the corresponding tables can be safely retired.',
|
|
324
325
|
docsUrl: 'https://pris.ly/contract-spaces',
|
|
325
326
|
meta: {
|
|
326
327
|
violations: orphans.map((spaceId) => ({ kind: 'orphanMarker', spaceId })),
|
|
@@ -40,7 +40,7 @@ export interface ExecuteDbUpdateOptions<TFamilyId extends string, TTargetId exte
|
|
|
40
40
|
readonly acceptDataLoss?: boolean;
|
|
41
41
|
readonly migrationsDir: string;
|
|
42
42
|
readonly targetId: TTargetId;
|
|
43
|
-
readonly
|
|
43
|
+
readonly extensions?: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
44
44
|
readonly onProgress?: OnControlProgress;
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -65,7 +65,7 @@ export async function executeDbUpdate<TFamilyId extends string, TTargetId extend
|
|
|
65
65
|
frameworkComponents: options.frameworkComponents,
|
|
66
66
|
migrationsDir: options.migrationsDir,
|
|
67
67
|
targetId: options.targetId,
|
|
68
|
-
|
|
68
|
+
extensions: options.extensions ?? [],
|
|
69
69
|
policy: DB_UPDATE_POLICY,
|
|
70
70
|
action: 'dbUpdate' as const,
|
|
71
71
|
...ifDefined('onProgress', options.onProgress),
|
|
@@ -50,7 +50,7 @@ export interface ExecuteDbVerifyOptions<TFamilyId extends string, TTargetId exte
|
|
|
50
50
|
readonly contract: Contract;
|
|
51
51
|
readonly migrationsDir: string;
|
|
52
52
|
readonly targetId: TTargetId;
|
|
53
|
-
readonly
|
|
53
|
+
readonly extensions: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
54
54
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
55
55
|
readonly mode: 'strict' | 'lenient';
|
|
56
56
|
readonly skipSchema: boolean;
|
|
@@ -149,7 +149,7 @@ function buildLoadInputs<TFamilyId extends string, TTargetId extends string>(
|
|
|
149
149
|
targetId: options.targetId,
|
|
150
150
|
migrationsDir: options.migrationsDir,
|
|
151
151
|
appContract: options.contract,
|
|
152
|
-
|
|
152
|
+
extensions: options.extensions,
|
|
153
153
|
deserializeContract: (json) => options.familyInstance.deserializeContract(json),
|
|
154
154
|
};
|
|
155
155
|
}
|
|
@@ -349,7 +349,7 @@ function mapMarkerCheckFailures(
|
|
|
349
349
|
violations.push({
|
|
350
350
|
kind: 'orphanMarker',
|
|
351
351
|
spaceId: orphan.spaceId,
|
|
352
|
-
remediation: `Add the corresponding extension to \`
|
|
352
|
+
remediation: `Add the corresponding extension to \`extensions\` in \`prisma-next.config.ts\`, or delete the orphan marker row for "${orphan.spaceId}".`,
|
|
353
353
|
});
|
|
354
354
|
}
|
|
355
355
|
if (violations.length === 0) return null;
|
|
@@ -359,7 +359,7 @@ function mapMarkerCheckFailures(
|
|
|
359
359
|
? 'Contract-space verifier found a violation'
|
|
360
360
|
: `Contract-space verifier found violations (${violations.length})`;
|
|
361
361
|
return new CliStructuredError('MIGRATION.CONTRACT_SPACE_VIOLATION', summary, {
|
|
362
|
-
why: `The on-disk \`migrations/\` directory, the \`
|
|
362
|
+
why: `The on-disk \`migrations/\` directory, the \`extensions\` declaration, and the live database marker rows are not in agreement.\n${lines.join('\n')}`,
|
|
363
363
|
fix: violations[0]?.remediation ?? 'Review and reconcile the violations listed above.',
|
|
364
364
|
docsUrl: 'https://pris.ly/contract-spaces',
|
|
365
365
|
meta: { violations },
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { EOL } from 'node:os';
|
|
3
3
|
import { loadConfig } from '@prisma-next/config-loader';
|
|
4
|
-
import { type FormatOptions, format
|
|
4
|
+
import { type FormatOptions, format } from '@prisma-next/psl-parser/format';
|
|
5
5
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
6
|
+
import { isStructuredError } from '@prisma-next/utils/structured-error';
|
|
6
7
|
import { CliStructuredError, errorRuntime, errorUnexpected } from '../../utils/cli-errors';
|
|
7
8
|
|
|
8
9
|
export interface FormatOperationOptions {
|
|
@@ -41,7 +42,7 @@ export async function executeFormat(
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
const source = config.contract?.source;
|
|
44
|
-
if (source?.
|
|
45
|
+
if (source?.format !== 'psl') {
|
|
45
46
|
return ok({ formatted: false });
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -71,12 +72,12 @@ export async function executeFormat(
|
|
|
71
72
|
try {
|
|
72
73
|
formatted = format(contents, formatOptions);
|
|
73
74
|
} catch (error) {
|
|
74
|
-
if (error
|
|
75
|
+
if (isStructuredError(error) && error.code === 'PSL.PARSE_FAILED') {
|
|
75
76
|
return notOk(
|
|
76
77
|
errorRuntime('Cannot format PSL with parse errors', {
|
|
77
78
|
why: error.message,
|
|
78
79
|
fix: 'Fix the parse errors in your schema and try again.',
|
|
79
|
-
meta: { diagnostics: error.diagnostics },
|
|
80
|
+
meta: { diagnostics: error.meta?.['diagnostics'] },
|
|
80
81
|
}),
|
|
81
82
|
);
|
|
82
83
|
}
|
|
@@ -24,6 +24,7 @@ import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
|
24
24
|
import { errorNoInvariantPath } from '@prisma-next/migration-tools/errors';
|
|
25
25
|
import { findPathWithDecision } from '@prisma-next/migration-tools/migration-graph';
|
|
26
26
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
27
|
+
import { InternalError } from '@prisma-next/utils/internal-error';
|
|
27
28
|
import { notOk, ok } from '@prisma-next/utils/result';
|
|
28
29
|
import {
|
|
29
30
|
type BuildAggregateInputs,
|
|
@@ -60,7 +61,7 @@ export interface ExecuteMigrateOptions<TFamilyId extends string, TTargetId exten
|
|
|
60
61
|
>;
|
|
61
62
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;
|
|
62
63
|
readonly migrationsDir: string;
|
|
63
|
-
readonly
|
|
64
|
+
readonly extensions: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
64
65
|
readonly targetId: TTargetId;
|
|
65
66
|
/**
|
|
66
67
|
* Optional app-space ref override. When provided, the app space's
|
|
@@ -122,7 +123,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
122
123
|
migrations,
|
|
123
124
|
frameworkComponents,
|
|
124
125
|
migrationsDir,
|
|
125
|
-
|
|
126
|
+
extensions,
|
|
126
127
|
targetId,
|
|
127
128
|
refHash,
|
|
128
129
|
refInvariants,
|
|
@@ -134,7 +135,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
134
135
|
targetId,
|
|
135
136
|
migrationsDir,
|
|
136
137
|
appContract: contract,
|
|
137
|
-
|
|
138
|
+
extensions,
|
|
138
139
|
deserializeContract: (json) => familyInstance.deserializeContract(json),
|
|
139
140
|
};
|
|
140
141
|
const loaded = await buildContractSpaceAggregate(loadInputs);
|
|
@@ -247,7 +248,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
247
248
|
.map((spaceId) => {
|
|
248
249
|
const entry = perSpacePlans.get(spaceId) ?? atHeadResolutions.get(spaceId);
|
|
249
250
|
if (entry === undefined) {
|
|
250
|
-
throw new
|
|
251
|
+
throw new InternalError(`Unreachable: missing per-space plan for "${spaceId}"`);
|
|
251
252
|
}
|
|
252
253
|
return { spaceId, entry };
|
|
253
254
|
});
|
|
@@ -306,7 +307,7 @@ export async function executeMigrate<TFamilyId extends string, TTargetId extends
|
|
|
306
307
|
}
|
|
307
308
|
const entry = atHeadResolutions.get(spaceId);
|
|
308
309
|
if (entry === undefined) {
|
|
309
|
-
throw new
|
|
310
|
+
throw new InternalError(`Unreachable: missing per-space plan for "${spaceId}"`);
|
|
310
311
|
}
|
|
311
312
|
return { spaceId, entry };
|
|
312
313
|
});
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
} from '@prisma-next/framework-components/control';
|
|
13
13
|
import type { ContractSpaceAggregate, PerSpacePlan } from '@prisma-next/migration-tools/aggregate';
|
|
14
14
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
15
|
+
import { InternalError } from '@prisma-next/utils/internal-error';
|
|
15
16
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
16
17
|
import type { OnControlProgress, PerSpaceExecutionEntry } from '../types';
|
|
17
18
|
|
|
@@ -243,7 +244,7 @@ export function collectOrdered(
|
|
|
243
244
|
return applyOrder.map((spaceId) => {
|
|
244
245
|
const entry = perSpace.get(spaceId);
|
|
245
246
|
if (!entry) {
|
|
246
|
-
throw new
|
|
247
|
+
throw new InternalError(`planner output missing per-space plan for "${spaceId}"`);
|
|
247
248
|
}
|
|
248
249
|
return { spaceId, entry };
|
|
249
250
|
});
|
package/src/control-api/types.ts
CHANGED
|
@@ -52,7 +52,7 @@ export interface ControlClientOptions {
|
|
|
52
52
|
// biome-ignore lint/suspicious/noExplicitAny: required for contravariance in driver.create()
|
|
53
53
|
readonly driver?: ControlDriverDescriptor<any, any, any, any>;
|
|
54
54
|
// biome-ignore lint/suspicious/noExplicitAny: required for contravariance in extension.create()
|
|
55
|
-
readonly
|
|
55
|
+
readonly extensions?: ReadonlyArray<ControlExtensionDescriptor<any, any, any>>;
|
|
56
56
|
/**
|
|
57
57
|
* Optional default connection for auto-connect.
|
|
58
58
|
* When provided, operations will auto-connect if not already connected.
|