@prisma-next/cli 0.15.0 → 0.16.0-dev.2
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/dist/cli.d.mts +1 -1
- package/dist/cli.mjs +13 -13
- package/dist/{client-DigVI8zX.mjs → client-KuBQftxz.mjs} +67 -36
- package/dist/client-KuBQftxz.mjs.map +1 -0
- package/dist/{command-helpers-CUoKYTlG.mjs → command-helpers-Cpq44aVa.mjs} +21 -5
- package/dist/command-helpers-Cpq44aVa.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts +0 -1
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.d.mts +0 -1
- package/dist/commands/contract-infer.d.mts.map +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts +0 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +6 -6
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.d.mts +0 -1
- package/dist/commands/db-schema.d.mts.map +1 -1
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-sign.d.mts +0 -1
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +4 -4
- package/dist/commands/db-update.d.mts +0 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +5 -5
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.d.mts +0 -1
- package/dist/commands/db-verify.d.mts.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +1 -2
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +5 -5
- package/dist/commands/migration-check.d.mts +1 -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 +2 -3
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +3 -3
- package/dist/commands/migration-list.d.mts +2 -3
- 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 +2 -3
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +1 -1
- package/dist/commands/migration-new.d.mts +0 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +3 -3
- package/dist/commands/migration-plan.d.mts +0 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +0 -1
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +3 -3
- package/dist/commands/migration-status.d.mts +2 -3
- 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 -2
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +2 -2
- package/dist/commands/telemetry/index.d.mts +0 -1
- package/dist/commands/telemetry/index.d.mts.map +1 -1
- package/dist/commands/telemetry/index.mjs +1 -1
- package/dist/{contract-at-errors-D8CNDD7g.mjs → contract-at-errors-D9gEjYtg.mjs} +2 -2
- package/dist/{contract-at-errors-D8CNDD7g.mjs.map → contract-at-errors-D9gEjYtg.mjs.map} +1 -1
- package/dist/{contract-emit-wgqrOXUI.mjs → contract-emit-CgnXSANN.mjs} +3 -3
- package/dist/{contract-emit-wgqrOXUI.mjs.map → contract-emit-CgnXSANN.mjs.map} +1 -1
- package/dist/{contract-emit-sYrqzsdN.mjs → contract-emit-cJQBlvGb.mjs} +3 -3
- package/dist/{contract-emit-sYrqzsdN.mjs.map → contract-emit-cJQBlvGb.mjs.map} +1 -1
- package/dist/{contract-infer-6SQnnVj7.mjs → contract-infer-Cg8evbeg.mjs} +3 -3
- package/dist/{contract-infer-6SQnnVj7.mjs.map → contract-infer-Cg8evbeg.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-DpB4x97a.mjs → contract-space-aggregate-loader-D_3VeHVb.mjs} +14 -15
- package/dist/contract-space-aggregate-loader-D_3VeHVb.mjs.map +1 -0
- package/dist/{db-verify-CEsG5Gek.mjs → db-verify-BEclUzki.mjs} +6 -7
- package/dist/db-verify-BEclUzki.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +1 -2
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.d.mts +0 -1
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +2 -2
- package/dist/exports/init-output.d.mts +1 -0
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/{format-CjongNb1.mjs → format-DAUAZqPt.mjs} +2 -2
- package/dist/{format-CjongNb1.mjs.map → format-DAUAZqPt.mjs.map} +1 -1
- package/dist/{framework-components-BbnM1RYm.mjs → framework-components-CnbUbiJw.mjs} +2 -2
- package/dist/{framework-components-BbnM1RYm.mjs.map → framework-components-CnbUbiJw.mjs.map} +1 -1
- package/dist/global-flags-BpoOYtNZ.d.mts.map +1 -1
- package/dist/{init-D8YFfaD6.mjs → init-C3JhkHg-.mjs} +33 -46
- package/dist/init-C3JhkHg-.mjs.map +1 -0
- package/dist/{inspect-live-schema-CEt_ztBJ.mjs → inspect-live-schema-CX7EA5C3.mjs} +3 -3
- package/dist/{inspect-live-schema-CEt_ztBJ.mjs.map → inspect-live-schema-CX7EA5C3.mjs.map} +1 -1
- package/dist/{migration-check-ByeQHOhK.mjs → migration-check-VqN-iTcx.mjs} +25 -24
- package/dist/migration-check-VqN-iTcx.mjs.map +1 -0
- package/dist/migration-cli.d.mts +0 -1
- package/dist/migration-cli.d.mts.map +1 -1
- package/dist/migration-cli.mjs +3 -3
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-CJO3tjiR.mjs → migration-command-scaffold-CRyYrHZ9.mjs} +3 -3
- package/dist/{migration-command-scaffold-CJO3tjiR.mjs.map → migration-command-scaffold-CRyYrHZ9.mjs.map} +1 -1
- package/dist/{migration-list-DTYM8xvm.mjs → migration-list-BAKujUjh.mjs} +3 -3
- package/dist/{migration-list-DTYM8xvm.mjs.map → migration-list-BAKujUjh.mjs.map} +1 -1
- package/dist/{migration-log-qZ8LpQIl.mjs → migration-log-C_xam2HZ.mjs} +3 -3
- package/dist/{migration-log-qZ8LpQIl.mjs.map → migration-log-C_xam2HZ.mjs.map} +1 -1
- package/dist/{migration-path-target-DmNwsDgs.mjs → migration-path-target-DpPTsRCg.mjs} +2 -2
- package/dist/{migration-path-target-DmNwsDgs.mjs.map → migration-path-target-DpPTsRCg.mjs.map} +1 -1
- package/dist/{migration-plan-CfPrB80t.mjs → migration-plan-CreSVtWZ.mjs} +6 -6
- package/dist/migration-plan-CreSVtWZ.mjs.map +1 -0
- package/dist/{migration-status-DRuS-rP5.mjs → migration-status-DYErXpyF.mjs} +6 -5
- package/dist/{migration-status-DRuS-rP5.mjs.map → migration-status-DYErXpyF.mjs.map} +1 -1
- package/dist/schemas-CeGMYFYX.d.mts.map +1 -1
- package/dist/{telemetry-DHBBq5wT.mjs → telemetry-DVr6RFnq.mjs} +2 -2
- package/dist/{telemetry-DHBBq5wT.mjs.map → telemetry-DVr6RFnq.mjs.map} +1 -1
- package/dist/{terminal-ui-DGRNFWna.d.mts → terminal-ui-BN4QOsm5.d.mts} +1 -2
- package/dist/terminal-ui-BN4QOsm5.d.mts.map +1 -0
- package/dist/{types-DFoqNIcQ.d.mts → types-D4r_HI9-.d.mts} +8 -4
- package/dist/types-D4r_HI9-.d.mts.map +1 -0
- package/dist/{verify-DDCb0R2r.mjs → verify-CgDVZjhc.mjs} +9 -8
- package/dist/verify-CgDVZjhc.mjs.map +1 -0
- package/package.json +25 -25
- package/src/commands/db-init.ts +3 -3
- package/src/commands/db-update.ts +1 -1
- package/src/commands/db-verify.ts +2 -3
- package/src/commands/init/errors.ts +62 -58
- package/src/commands/init/init.ts +29 -26
- package/src/commands/migration-check.ts +7 -7
- package/src/commands/migration-plan.ts +1 -1
- package/src/control-api/operations/db-run.ts +4 -4
- package/src/control-api/operations/db-verify.ts +12 -9
- package/src/control-api/operations/migrate.ts +70 -26
- package/src/control-api/types.ts +4 -1
- package/src/migration-cli.ts +5 -5
- package/src/utils/cli-errors.ts +15 -2
- package/src/utils/combine-verify-results.ts +1 -1
- package/src/utils/contract-space-aggregate-loader.ts +12 -13
- package/src/utils/formatters/errors.ts +24 -3
- package/src/utils/formatters/verify.ts +7 -6
- package/src/utils/integrity-violation-to-check-failure.ts +14 -14
- package/src/utils/result-handler.ts +4 -2
- package/dist/client-DigVI8zX.mjs.map +0 -1
- package/dist/command-helpers-CUoKYTlG.mjs.map +0 -1
- package/dist/contract-space-aggregate-loader-DpB4x97a.mjs.map +0 -1
- package/dist/db-verify-CEsG5Gek.mjs.map +0 -1
- package/dist/init-D8YFfaD6.mjs.map +0 -1
- package/dist/migration-check-ByeQHOhK.mjs.map +0 -1
- package/dist/migration-plan-CfPrB80t.mjs.map +0 -1
- package/dist/terminal-ui-DGRNFWna.d.mts.map +0 -1
- package/dist/types-DFoqNIcQ.d.mts.map +0 -1
- package/dist/verify-DDCb0R2r.mjs.map +0 -1
package/src/utils/cli-errors.ts
CHANGED
|
@@ -287,7 +287,18 @@ export function errorPathUnreachable(failure: MigrateFailure): CliStructuredErro
|
|
|
287
287
|
// Plan-then-apply recovery. The planner destination is the missing edge's
|
|
288
288
|
// target; `migration plan --to` (built for arbitrary targets) makes this a
|
|
289
289
|
// real command, so the diagnostic that sends you here is now honest.
|
|
290
|
+
//
|
|
291
|
+
// Never-planned spaces have an EMPTY migration graph, and contract-ref
|
|
292
|
+
// resolution only resolves full hashes against graph nodes — a
|
|
293
|
+
// `--to <hash>` remediation would reject its own input. `migration plan`
|
|
294
|
+
// without `--to` targets the working contract (the same contract the app
|
|
295
|
+
// space's synthesized head ref carries), so the bare form is the one that
|
|
296
|
+
// runs verbatim.
|
|
297
|
+
const neverPlanned = meta['kind'] === 'neverPlanned';
|
|
290
298
|
const planCommand = (() => {
|
|
299
|
+
if (neverPlanned) {
|
|
300
|
+
return 'prisma-next migration plan --name <slug>';
|
|
301
|
+
}
|
|
291
302
|
if (planFromHash !== null && targetHash !== null) {
|
|
292
303
|
return `prisma-next migration plan --from ${planFromHash} --to ${targetHash} --name <slug>`;
|
|
293
304
|
}
|
|
@@ -300,7 +311,9 @@ export function errorPathUnreachable(failure: MigrateFailure): CliStructuredErro
|
|
|
300
311
|
return 'prisma-next migration plan';
|
|
301
312
|
})();
|
|
302
313
|
const applyCommand =
|
|
303
|
-
targetHash !== null
|
|
314
|
+
targetHash !== null && !neverPlanned
|
|
315
|
+
? `prisma-next migrate --to ${targetHash}`
|
|
316
|
+
: 'prisma-next migrate';
|
|
304
317
|
return errorRuntime(failure.summary, {
|
|
305
318
|
why:
|
|
306
319
|
failure.why ??
|
|
@@ -347,7 +360,7 @@ export function mapMigrationToolsError(error: MigrationToolsError): CliStructure
|
|
|
347
360
|
* Shared "needs a live database" precondition for read verbs that consult the
|
|
348
361
|
* marker/ledger (`migration log`, `migration status`). A command needs both a
|
|
349
362
|
* connection string and a control-plane driver; either missing yields the same
|
|
350
|
-
* `
|
|
363
|
+
* `CONFIG.DB_CONNECTION_REQUIRED` envelope with `meta.missingFlags` (canonical long-form flags
|
|
351
364
|
* per CLI Style Guide §Errors) so callers can react programmatically. Returns
|
|
352
365
|
* `null` when both are present.
|
|
353
366
|
*/
|
|
@@ -78,7 +78,7 @@ export function combineVerifyResults(
|
|
|
78
78
|
return {
|
|
79
79
|
result: {
|
|
80
80
|
ok,
|
|
81
|
-
...(ok ? {} : { code: appResult.code ?? '
|
|
81
|
+
...(ok ? {} : { code: appResult.code ?? 'CONTRACT.MARKER_REQUIRED' }),
|
|
82
82
|
summary,
|
|
83
83
|
contract: appResult.contract,
|
|
84
84
|
target: appResult.target,
|
|
@@ -20,7 +20,7 @@ import { toDeclaredExtensionsFromRaw } from './extension-pack-inputs';
|
|
|
20
20
|
|
|
21
21
|
const CONTRACT_SPACES_DOCS_URL = 'https://pris.ly/contract-spaces';
|
|
22
22
|
|
|
23
|
-
function
|
|
23
|
+
function contractSpaceViolationError(
|
|
24
24
|
summary: string,
|
|
25
25
|
options: {
|
|
26
26
|
readonly why: string;
|
|
@@ -28,8 +28,7 @@ function contractSpaceError5002(
|
|
|
28
28
|
readonly violations: readonly IntegrityViolation[];
|
|
29
29
|
},
|
|
30
30
|
): CliStructuredError {
|
|
31
|
-
return new CliStructuredError('
|
|
32
|
-
domain: 'MIG',
|
|
31
|
+
return new CliStructuredError('MIGRATION.CONTRACT_SPACE_VIOLATION', summary, {
|
|
33
32
|
why: options.why,
|
|
34
33
|
fix: options.fix,
|
|
35
34
|
docsUrl: CONTRACT_SPACES_DOCS_URL,
|
|
@@ -38,7 +37,7 @@ function contractSpaceError5002(
|
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
/**
|
|
41
|
-
* Build the `
|
|
40
|
+
* Build the `MIGRATION.CONTRACT_SPACE_VIOLATION` structured-error envelope for a contract-space
|
|
42
41
|
* target mismatch. Shared between the declared-extension precheck (the
|
|
43
42
|
* descriptor's configured target disagrees with the project target) and
|
|
44
43
|
* the on-disk-contract check surfaced by `checkIntegrity`.
|
|
@@ -48,7 +47,7 @@ function targetMismatchError(
|
|
|
48
47
|
expected: string,
|
|
49
48
|
actual: string,
|
|
50
49
|
): CliStructuredError {
|
|
51
|
-
return
|
|
50
|
+
return contractSpaceViolationError(`Contract-space target mismatch for "${spaceId}"`, {
|
|
52
51
|
why: `Space "${spaceId}" targets "${actual}" but the project's adapter targets "${expected}".`,
|
|
53
52
|
fix: 'Update the extension descriptor to target the configured database, or change the project adapter.',
|
|
54
53
|
violations: [{ kind: 'targetMismatch', spaceId, expected, actual }],
|
|
@@ -89,9 +88,10 @@ function describeIntegrityViolation(violation: IntegrityViolation): string {
|
|
|
89
88
|
/**
|
|
90
89
|
* Map the integrity violations `checkIntegrity` reports into a single
|
|
91
90
|
* CLI structured-error envelope, preserving the error codes the prior
|
|
92
|
-
* throw-on-load loader emitted: `
|
|
93
|
-
* `
|
|
94
|
-
*
|
|
91
|
+
* throw-on-load loader emitted: `MIGRATION.CONTRACT_SPACE_LAYOUT_VIOLATION`
|
|
92
|
+
* (layout drift, bundled) and `MIGRATION.CONTRACT_SPACE_VIOLATION` (target /
|
|
93
|
+
* disjointness / contract-validation / structural integrity). Returns
|
|
94
|
+
* `null` when there is nothing to refuse on.
|
|
95
95
|
*
|
|
96
96
|
* Precedence reproduces the prior loader's first-failure ordering:
|
|
97
97
|
* layout drift first (every offence bundled into one envelope), then
|
|
@@ -113,8 +113,7 @@ export function mapIntegrityViolations(
|
|
|
113
113
|
layout.length === 1
|
|
114
114
|
? 'Contract-space layout violation detected'
|
|
115
115
|
: `Contract-space layout violations detected (${layout.length})`;
|
|
116
|
-
return new CliStructuredError('
|
|
117
|
-
domain: 'MIG',
|
|
116
|
+
return new CliStructuredError('MIGRATION.CONTRACT_SPACE_LAYOUT_VIOLATION', summary, {
|
|
118
117
|
why: `The on-disk \`migrations/\` directory and your \`extensionPacks\` declaration are not in agreement.\n${lines.join('\n')}`,
|
|
119
118
|
fix: 'Declare the extension in `extensionPacks` and re-emit its contract-space artefacts, or remove the orphan `migrations/<space>` directory.',
|
|
120
119
|
docsUrl: CONTRACT_SPACES_DOCS_URL,
|
|
@@ -133,7 +132,7 @@ export function mapIntegrityViolations(
|
|
|
133
132
|
|
|
134
133
|
const disjointness = violations.find((v) => v.kind === 'disjointness');
|
|
135
134
|
if (disjointness && disjointness.kind === 'disjointness') {
|
|
136
|
-
return
|
|
135
|
+
return contractSpaceViolationError(
|
|
137
136
|
`Contract-space disjointness violation: storage element "${disjointness.element}" claimed by multiple spaces`,
|
|
138
137
|
{
|
|
139
138
|
why: `Spaces ${disjointness.claimedBy.map((s) => `"${s}"`).join(', ')} all claim the storage element "${disjointness.element}". Each storage element must be owned by exactly one contract space.`,
|
|
@@ -145,7 +144,7 @@ export function mapIntegrityViolations(
|
|
|
145
144
|
|
|
146
145
|
const contractUnreadable = violations.find((v) => v.kind === 'contractUnreadable');
|
|
147
146
|
if (contractUnreadable && contractUnreadable.kind === 'contractUnreadable') {
|
|
148
|
-
return
|
|
147
|
+
return contractSpaceViolationError(
|
|
149
148
|
`Contract-space contract validation failed for "${contractUnreadable.spaceId}"`,
|
|
150
149
|
{
|
|
151
150
|
why: contractUnreadable.detail,
|
|
@@ -160,7 +159,7 @@ export function mapIntegrityViolations(
|
|
|
160
159
|
// is still computed; the gate just renders one envelope).
|
|
161
160
|
const structural = violations[0]!;
|
|
162
161
|
const spaceId = 'spaceId' in structural ? structural.spaceId : '*';
|
|
163
|
-
return
|
|
162
|
+
return contractSpaceViolationError(`Contract-space integrity failure for "${spaceId}"`, {
|
|
164
163
|
why: describeIntegrityViolation(structural),
|
|
165
164
|
fix: 'Re-emit the affected migration package(s) or restore the on-disk `migrations/` directory from version control.',
|
|
166
165
|
violations: [structural],
|
|
@@ -7,6 +7,25 @@ import type { GlobalFlags } from '../global-flags';
|
|
|
7
7
|
import { createColorFormatter, formatDim, isVerbose } from './helpers';
|
|
8
8
|
import { formatPlannerWarningsBlock } from './migrations';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* The display label for a schema-diff issue in the shared error envelope,
|
|
12
|
+
* derived from which sides are present: expected-only is a missing object,
|
|
13
|
+
* actual-only an extra one, both a mismatch. `undefined` when the entry is not
|
|
14
|
+
* a schema-diff issue (it carries neither side) so the caller can fall through
|
|
15
|
+
* to its generic label.
|
|
16
|
+
*/
|
|
17
|
+
function schemaDiffIssueLabel(issue: {
|
|
18
|
+
readonly expected?: unknown;
|
|
19
|
+
readonly actual?: unknown;
|
|
20
|
+
}): 'missing' | 'extra' | 'mismatch' | undefined {
|
|
21
|
+
const hasExpected = issue.expected !== undefined;
|
|
22
|
+
const hasActual = issue.actual !== undefined;
|
|
23
|
+
if (hasExpected && hasActual) return 'mismatch';
|
|
24
|
+
if (hasExpected) return 'missing';
|
|
25
|
+
if (hasActual) return 'extra';
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
10
29
|
/**
|
|
11
30
|
* Formats error output for human-readable display.
|
|
12
31
|
*/
|
|
@@ -51,13 +70,15 @@ export function formatErrorOutput(error: CliErrorEnvelope, flags: GlobalFlags):
|
|
|
51
70
|
// Show issues list if present (always show a short list; show full list when verbose).
|
|
52
71
|
// `issues` is a shared error-envelope field: PSL interpretation diagnostics stamp
|
|
53
72
|
// `kind` and `message` (their diagnostic code and prose); schema-diff issues
|
|
54
|
-
// (`SchemaDiffIssue`) carry no `message` and stamp `
|
|
73
|
+
// (`SchemaDiffIssue`) carry no `message` and stamp `path` plus the
|
|
74
|
+
// `expected`/`actual` presence a label is derived from.
|
|
55
75
|
if (error.meta?.['issues']) {
|
|
56
76
|
const issues = error.meta['issues'] as readonly {
|
|
57
77
|
kind?: string;
|
|
58
|
-
reason?: string;
|
|
59
78
|
message?: string;
|
|
60
79
|
path?: readonly string[];
|
|
80
|
+
expected?: unknown;
|
|
81
|
+
actual?: unknown;
|
|
61
82
|
}[];
|
|
62
83
|
if (issues.length > 0) {
|
|
63
84
|
const maxToShow = isVerbose(flags, 1) ? issues.length : Math.min(3, issues.length);
|
|
@@ -66,7 +87,7 @@ export function formatErrorOutput(error: CliErrorEnvelope, flags: GlobalFlags):
|
|
|
66
87
|
: ` Issues (showing ${maxToShow} of ${issues.length}):`;
|
|
67
88
|
lines.push(`${formatDimText(header)}`);
|
|
68
89
|
for (const issue of issues.slice(0, maxToShow)) {
|
|
69
|
-
const label = issue.kind ?? issue
|
|
90
|
+
const label = issue.kind ?? schemaDiffIssueLabel(issue) ?? 'issue';
|
|
70
91
|
const message = issue.message ?? issue.path?.join('/') ?? '';
|
|
71
92
|
lines.push(`${formatDimText(` - [${label}] ${message}`)}`);
|
|
72
93
|
}
|
|
@@ -8,13 +8,14 @@ import type {
|
|
|
8
8
|
VerifyDatabaseResult,
|
|
9
9
|
VerifyDatabaseSchemaResult,
|
|
10
10
|
} from '@prisma-next/framework-components/control';
|
|
11
|
+
import { issueOutcome } from '@prisma-next/framework-components/control';
|
|
11
12
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
12
13
|
import { bold, cyan, dim, green, magenta, red, yellow } from 'colorette';
|
|
13
14
|
import type { GlobalFlags } from '../global-flags';
|
|
14
15
|
import { createColorFormatter, formatDim, isVerbose } from './helpers';
|
|
15
16
|
|
|
16
|
-
/** Human-readable label for each
|
|
17
|
-
const
|
|
17
|
+
/** Human-readable label for each outcome, prefixed onto an issue's message for display. */
|
|
18
|
+
const OUTCOME_LABEL: Record<ExpectationFailureReason, string> = {
|
|
18
19
|
'not-found': 'missing',
|
|
19
20
|
'not-expected': 'extra',
|
|
20
21
|
'not-equal': 'mismatch',
|
|
@@ -22,12 +23,12 @@ const REASON_LABEL: Record<ExpectationFailureReason, string> = {
|
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* The issue's display text: its own path, prefixed with a human label for
|
|
25
|
-
* why it's flagged. Turning
|
|
26
|
-
* formatter's job, not the differ's — the differ's issue is
|
|
27
|
-
* `
|
|
26
|
+
* why it's flagged. Turning the presence-derived outcome (and the path) into
|
|
27
|
+
* prose is this formatter's job, not the differ's — the differ's issue is
|
|
28
|
+
* data (`path` + nodes), not prose.
|
|
28
29
|
*/
|
|
29
30
|
function formatIssueMessage(issue: SchemaDiffIssue): string {
|
|
30
|
-
return `${
|
|
31
|
+
return `${OUTCOME_LABEL[issueOutcome(issue)]}: ${issue.path.join('/')}`;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
// ============================================================================
|
|
@@ -14,7 +14,7 @@ function migrationFileRelative(dirPath: string, fileName: string): string {
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Map one {@link IntegrityViolation} onto a `migration check` failure row.
|
|
17
|
-
* Sole catalogue mapping from integrity violations to `
|
|
17
|
+
* Sole catalogue mapping from integrity violations to `MIGRATION.CHECK_*` codes.
|
|
18
18
|
*/
|
|
19
19
|
export function integrityViolationToCheckFailure(
|
|
20
20
|
violation: IntegrityViolation,
|
|
@@ -31,7 +31,7 @@ export function integrityViolationToCheckFailure(
|
|
|
31
31
|
case 'hashMismatch':
|
|
32
32
|
return {
|
|
33
33
|
space: violation.spaceId,
|
|
34
|
-
code: '
|
|
34
|
+
code: 'MIGRATION.CHECK_HASH_MISMATCH',
|
|
35
35
|
where: migrationFileRelative(
|
|
36
36
|
join(migrationsDir, violation.spaceId, violation.dirName),
|
|
37
37
|
'migration.json',
|
|
@@ -42,7 +42,7 @@ export function integrityViolationToCheckFailure(
|
|
|
42
42
|
case 'providedInvariantsMismatch':
|
|
43
43
|
return {
|
|
44
44
|
space: violation.spaceId,
|
|
45
|
-
code: '
|
|
45
|
+
code: 'MIGRATION.CHECK_PROVIDED_INVARIANTS_MISMATCH',
|
|
46
46
|
where: packageRelative(violation.spaceId, violation.dirName),
|
|
47
47
|
why: `Migration "${violation.dirName}" providedInvariants in migration.json disagrees with ops.json.`,
|
|
48
48
|
fix: 'Re-emit the migration package so migration.json and ops.json agree.',
|
|
@@ -50,7 +50,7 @@ export function integrityViolationToCheckFailure(
|
|
|
50
50
|
case 'packageUnloadable':
|
|
51
51
|
return {
|
|
52
52
|
space: violation.spaceId,
|
|
53
|
-
code: '
|
|
53
|
+
code: 'MIGRATION.CHECK_PACKAGE_UNLOADABLE',
|
|
54
54
|
where: packageRelative(violation.spaceId, violation.dirName),
|
|
55
55
|
why: `Migration "${violation.dirName}" could not be loaded: ${violation.detail}`,
|
|
56
56
|
fix: 'Re-emit the migration package or restore from version control.',
|
|
@@ -58,7 +58,7 @@ export function integrityViolationToCheckFailure(
|
|
|
58
58
|
case 'sameSourceAndTarget':
|
|
59
59
|
return {
|
|
60
60
|
space: violation.spaceId,
|
|
61
|
-
code: '
|
|
61
|
+
code: 'MIGRATION.CHECK_NOOP_SELF_EDGE',
|
|
62
62
|
where: packageRelative(violation.spaceId, violation.dirName),
|
|
63
63
|
why: `Migration "${violation.dirName}" in space "${violation.spaceId}" has source equal to target (${violation.hash}) with no data invariant — a true no-op self-edge.`,
|
|
64
64
|
fix: 'Add a data operation if this self-edge was meant to carry a data invariant, or delete the migration if it is a true no-op.',
|
|
@@ -66,7 +66,7 @@ export function integrityViolationToCheckFailure(
|
|
|
66
66
|
case 'orphanSpaceDir':
|
|
67
67
|
return {
|
|
68
68
|
space: violation.spaceId,
|
|
69
|
-
code: '
|
|
69
|
+
code: 'MIGRATION.CHECK_ORPHAN_SPACE_DIR',
|
|
70
70
|
where: spaceRelative(violation.spaceId),
|
|
71
71
|
why: `Contract-space directory "${violation.spaceId}" exists on disk but no extension declares it.`,
|
|
72
72
|
fix: 'Remove the orphan directory, or declare the extension in `extensionPacks`.',
|
|
@@ -74,7 +74,7 @@ export function integrityViolationToCheckFailure(
|
|
|
74
74
|
case 'declaredButUnmigrated':
|
|
75
75
|
return {
|
|
76
76
|
space: violation.spaceId,
|
|
77
|
-
code: '
|
|
77
|
+
code: 'MIGRATION.CHECK_DECLARED_BUT_UNMIGRATED',
|
|
78
78
|
where: spaceRelative(violation.spaceId),
|
|
79
79
|
why: `Extension "${violation.spaceId}" is declared in \`extensionPacks\` but has no on-disk migrations directory.`,
|
|
80
80
|
fix: 'Re-emit the extension contract-space artefacts with `prisma-next contract emit` and migration planning, or remove the extension from `extensionPacks` if it is unused.',
|
|
@@ -82,7 +82,7 @@ export function integrityViolationToCheckFailure(
|
|
|
82
82
|
case 'headRefMissing':
|
|
83
83
|
return {
|
|
84
84
|
space: violation.spaceId,
|
|
85
|
-
code: '
|
|
85
|
+
code: 'MIGRATION.CHECK_HEAD_REF_MISSING',
|
|
86
86
|
where: refRelative(violation.spaceId, 'head'),
|
|
87
87
|
why: `Head ref \`refs/head.json\` is missing for contract space "${violation.spaceId}".`,
|
|
88
88
|
fix: 'Re-emit the contract-space migrations and head ref artefacts, or restore `refs/head.json` from version control.',
|
|
@@ -90,7 +90,7 @@ export function integrityViolationToCheckFailure(
|
|
|
90
90
|
case 'headRefNotInGraph':
|
|
91
91
|
return {
|
|
92
92
|
space: violation.spaceId,
|
|
93
|
-
code: '
|
|
93
|
+
code: 'MIGRATION.CHECK_HEAD_REF_NOT_IN_GRAPH',
|
|
94
94
|
where: refRelative(violation.spaceId, 'head'),
|
|
95
95
|
why: `Head ref ${violation.hash} for contract space "${violation.spaceId}" is not present in its migration graph.`,
|
|
96
96
|
fix: 'Re-emit the contract space migrations, or restore the missing migration package.',
|
|
@@ -98,7 +98,7 @@ export function integrityViolationToCheckFailure(
|
|
|
98
98
|
case 'refUnreadable':
|
|
99
99
|
return {
|
|
100
100
|
space: violation.spaceId,
|
|
101
|
-
code: '
|
|
101
|
+
code: 'MIGRATION.CHECK_REF_UNREADABLE',
|
|
102
102
|
where: refRelative(violation.spaceId, violation.refName),
|
|
103
103
|
why: `Ref "${violation.refName}" for contract space "${violation.spaceId}" is unreadable: ${violation.detail}`,
|
|
104
104
|
fix: 'Repair or remove the corrupt ref file.',
|
|
@@ -106,7 +106,7 @@ export function integrityViolationToCheckFailure(
|
|
|
106
106
|
case 'targetMismatch':
|
|
107
107
|
return {
|
|
108
108
|
space: violation.spaceId,
|
|
109
|
-
code: '
|
|
109
|
+
code: 'MIGRATION.CHECK_TARGET_MISMATCH',
|
|
110
110
|
where: spaceRelative(violation.spaceId),
|
|
111
111
|
why: `Contract space "${violation.spaceId}" targets "${violation.actual}" but the project targets "${violation.expected}".`,
|
|
112
112
|
fix: 'Update the extension to target the configured database, or change the project target.',
|
|
@@ -114,7 +114,7 @@ export function integrityViolationToCheckFailure(
|
|
|
114
114
|
case 'disjointness':
|
|
115
115
|
return {
|
|
116
116
|
space: 'app',
|
|
117
|
-
code: '
|
|
117
|
+
code: 'MIGRATION.CHECK_SPACE_DISJOINTNESS_VIOLATION',
|
|
118
118
|
where: migrationPathRelative(migrationsDir),
|
|
119
119
|
why: `Storage element "${violation.element}" is claimed by multiple contract spaces: ${violation.claimedBy.join(', ')}.`,
|
|
120
120
|
fix: 'Update the contracts so each storage element is owned by exactly one contract space.',
|
|
@@ -122,7 +122,7 @@ export function integrityViolationToCheckFailure(
|
|
|
122
122
|
case 'contractUnreadable':
|
|
123
123
|
return {
|
|
124
124
|
space: violation.spaceId,
|
|
125
|
-
code: '
|
|
125
|
+
code: 'MIGRATION.CHECK_CONTRACT_UNREADABLE',
|
|
126
126
|
where: migrationFileRelative(join(migrationsDir, violation.spaceId), 'contract.json'),
|
|
127
127
|
why: `Contract for space "${violation.spaceId}" is unreadable: ${violation.detail}`,
|
|
128
128
|
fix: 'Re-emit the extension contract artefacts, or fix the descriptor producing the invalid contract.',
|
|
@@ -130,7 +130,7 @@ export function integrityViolationToCheckFailure(
|
|
|
130
130
|
case 'duplicateMigrationHash':
|
|
131
131
|
return {
|
|
132
132
|
space: violation.spaceId,
|
|
133
|
-
code: '
|
|
133
|
+
code: 'MIGRATION.CHECK_DUPLICATE_MIGRATION_HASH',
|
|
134
134
|
where: spaceRelative(violation.spaceId),
|
|
135
135
|
why: `Multiple migrations in space "${violation.spaceId}" share migrationHash "${violation.migrationHash}" (${violation.dirNames.join(', ')}).`,
|
|
136
136
|
fix: 'Re-emit one of the conflicting packages so each migrationHash is unique.',
|
|
@@ -37,7 +37,9 @@ export function handleResult<T>(
|
|
|
37
37
|
ui.error(formatErrorOutput(envelope, flags));
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
//
|
|
41
|
-
|
|
40
|
+
// Every structured failure reaching this point is an expected failure and
|
|
41
|
+
// exits 2 (PRECONDITION), except a user-declined prompt, which exits 3
|
|
42
|
+
// (USER_ABORTED). See CLI Style Guide § Exit Codes / ADR 239 § Exit codes.
|
|
43
|
+
const exitCode = result.failure.code === 'CLI.INIT_USER_ABORTED' ? 3 : 2;
|
|
42
44
|
return exitCode;
|
|
43
45
|
}
|