@prisma-next/cli 0.8.0-dev.1 → 0.8.0-dev.10
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 +7 -8
- package/dist/{cli-errors-D3_sMh2K.mjs → cli-errors-CF60g2cG.mjs} +40 -2
- package/dist/cli-errors-CF60g2cG.mjs.map +1 -0
- package/dist/cli.mjs +67 -19
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-4d26awB-.mjs → client-XkUw4xD0.mjs} +10 -9
- package/dist/client-XkUw4xD0.mjs.map +1 -0
- package/dist/{command-helpers-BeZHkxV8.mjs → command-helpers-D3vL5yi8.mjs} +29 -6
- package/dist/command-helpers-D3vL5yi8.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.mjs +7 -7
- package/dist/commands/db-schema.mjs +5 -5
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +67 -25
- 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 +37 -9
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +28 -0
- package/dist/commands/migrate.d.mts.map +1 -0
- package/dist/commands/{migration-apply.mjs → migrate.mjs} +54 -36
- package/dist/commands/migrate.mjs.map +1 -0
- package/dist/commands/migration-check.d.mts +18 -0
- package/dist/commands/migration-check.d.mts.map +1 -0
- package/dist/commands/migration-check.mjs +284 -0
- package/dist/commands/migration-check.mjs.map +1 -0
- package/dist/commands/migration-graph.d.mts +16 -0
- package/dist/commands/migration-graph.d.mts.map +1 -0
- package/dist/commands/migration-graph.mjs +141 -0
- package/dist/commands/migration-graph.mjs.map +1 -0
- package/dist/commands/migration-list.d.mts +20 -0
- package/dist/commands/migration-list.d.mts.map +1 -0
- package/dist/commands/migration-list.mjs +107 -0
- package/dist/commands/migration-list.mjs.map +1 -0
- package/dist/commands/migration-log.d.mts +21 -0
- package/dist/commands/migration-log.d.mts.map +1 -0
- package/dist/commands/migration-log.mjs +146 -0
- package/dist/commands/migration-log.mjs.map +1 -0
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +21 -20
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +2 -2
- 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 +1 -1
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +85 -47
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +3 -15
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +732 -1
- package/dist/commands/migration-status.mjs.map +1 -0
- package/dist/commands/ref.d.mts +34 -0
- package/dist/commands/ref.d.mts.map +1 -0
- package/dist/commands/{migration-ref.mjs → ref.mjs} +28 -57
- package/dist/commands/ref.mjs.map +1 -0
- package/dist/{contract-emit-DLc5GYbr.mjs → contract-emit-CgoFk9AU.mjs} +3 -3
- package/dist/{contract-emit-DLc5GYbr.mjs.map → contract-emit-CgoFk9AU.mjs.map} +1 -1
- package/dist/{contract-emit-BhKR-D9Y.mjs → contract-emit-GpxW5RLe.mjs} +6 -6
- package/dist/{contract-emit-BhKR-D9Y.mjs.map → contract-emit-GpxW5RLe.mjs.map} +1 -1
- package/dist/{contract-infer-Bnla2kuK.mjs → contract-infer-D8edZOCi.mjs} +5 -5
- package/dist/{contract-infer-Bnla2kuK.mjs.map → contract-infer-D8edZOCi.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-BrwKK6Q6.mjs → contract-space-aggregate-loader-D68YpuPR.mjs} +3 -3
- package/dist/{contract-space-aggregate-loader-BrwKK6Q6.mjs.map → contract-space-aggregate-loader-D68YpuPR.mjs.map} +1 -1
- package/dist/{db-verify-DitNxDiE.mjs → db-verify-DtRB9iHJ.mjs} +7 -7
- package/dist/{db-verify-DitNxDiE.mjs.map → db-verify-DtRB9iHJ.mjs.map} +1 -1
- package/dist/errors-Cw6kyTyV.mjs +56 -0
- package/dist/errors-Cw6kyTyV.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{framework-components-ChqVUxR-.mjs → framework-components-xFLFpZUO.mjs} +2 -2
- package/dist/{framework-components-ChqVUxR-.mjs.map → framework-components-xFLFpZUO.mjs.map} +1 -1
- package/dist/{global-flags-Icqpxk23.d.mts → global-flags-DGmw6Kqg.d.mts} +1 -1
- package/dist/{global-flags-Icqpxk23.d.mts.map → global-flags-DGmw6Kqg.d.mts.map} +1 -1
- package/dist/{migration-status-Do4Ei0i_.mjs → graph-render-eJDcLWny.mjs} +3 -692
- package/dist/graph-render-eJDcLWny.mjs.map +1 -0
- package/dist/{init-DW94FRsD.mjs → init-Dm0QZPUA.mjs} +133 -61
- package/dist/init-Dm0QZPUA.mjs.map +1 -0
- package/dist/{inspect-live-schema-CyzAzPzF.mjs → inspect-live-schema-CPPqCips.mjs} +4 -4
- package/dist/{inspect-live-schema-CyzAzPzF.mjs.map → inspect-live-schema-CPPqCips.mjs.map} +1 -1
- package/dist/migration-cli.mjs +1 -1
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-Jp1rosw8.mjs → migration-command-scaffold-B_ezTTwX.mjs} +4 -4
- package/dist/{migration-command-scaffold-Jp1rosw8.mjs.map → migration-command-scaffold-B_ezTTwX.mjs.map} +1 -1
- package/dist/{migration-plan-q1pPoOCf.mjs → migration-plan-DWB-NTxH.mjs} +54 -28
- package/dist/migration-plan-DWB-NTxH.mjs.map +1 -0
- package/dist/migration-types-D2FW63pr.d.mts +15 -0
- package/dist/migration-types-D2FW63pr.d.mts.map +1 -0
- package/dist/{migrations-CTsyBXCA.mjs → migrations-DyUf5lTt.mjs} +2 -2
- package/dist/migrations-DyUf5lTt.mjs.map +1 -0
- package/dist/{output-BVj6a971.mjs → output-B60Gw5fu.mjs} +12 -11
- package/dist/{output-BVj6a971.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
- package/dist/{result-handler-rmPVKIP2.mjs → result-handler-Bm_6dDYg.mjs} +2 -2
- package/dist/{result-handler-rmPVKIP2.mjs.map → result-handler-Bm_6dDYg.mjs.map} +1 -1
- package/dist/{terminal-ui-C_hFNbAn.mjs → terminal-ui-XtOQsqe9.mjs} +2 -54
- package/dist/terminal-ui-XtOQsqe9.mjs.map +1 -0
- package/dist/{types-LItU7E4l.d.mts → types-BS_wpjAY.d.mts} +2 -2
- package/dist/{types-LItU7E4l.d.mts.map → types-BS_wpjAY.d.mts.map} +1 -1
- package/dist/{verify-CiwNWM9N.mjs → verify-D7ypCCe6.mjs} +1 -1
- package/dist/{verify-CiwNWM9N.mjs.map → verify-D7ypCCe6.mjs.map} +1 -1
- package/package.json +39 -23
- package/src/cli.ts +78 -15
- package/src/commands/db-sign.ts +102 -32
- package/src/commands/db-update.ts +56 -4
- package/src/commands/init/agent-skill-install.ts +145 -43
- package/src/commands/init/errors.ts +2 -2
- package/src/commands/init/exit-codes.ts +2 -2
- package/src/commands/init/index.ts +1 -1
- package/src/commands/init/init.ts +15 -6
- package/src/commands/init/inputs.ts +1 -1
- package/src/commands/init/output.ts +22 -17
- package/src/commands/{migration-apply.ts → migrate.ts} +54 -70
- package/src/commands/migration-check/exit-codes.ts +3 -0
- package/src/commands/migration-check.ts +369 -0
- package/src/commands/migration-graph.ts +184 -0
- package/src/commands/migration-list.ts +155 -0
- package/src/commands/migration-log.ts +218 -0
- package/src/commands/migration-new.ts +17 -9
- package/src/commands/migration-plan.ts +65 -26
- package/src/commands/migration-show.ts +132 -60
- package/src/commands/migration-status.ts +77 -64
- package/src/commands/{migration-ref.ts → ref.ts} +32 -86
- package/src/control-api/operations/apply-aggregate.ts +4 -4
- package/src/control-api/operations/db-apply-aggregate.ts +3 -2
- package/src/control-api/operations/migration-apply.ts +4 -3
- package/src/control-api/types.ts +1 -2
- package/src/migration-cli.ts +1 -1
- package/src/utils/cli-errors.ts +37 -0
- package/src/utils/command-helpers.ts +28 -3
- package/src/utils/contract-space-aggregate-loader.ts +2 -2
- package/src/utils/contract-space-seed-phase.ts +1 -1
- package/src/utils/formatters/help.ts +12 -2
- package/src/utils/formatters/migrations.ts +2 -2
- package/dist/cli-errors-D3_sMh2K.mjs.map +0 -1
- package/dist/client-4d26awB-.mjs.map +0 -1
- package/dist/command-helpers-BeZHkxV8.mjs.map +0 -1
- package/dist/commands/migration-apply.d.mts +0 -51
- package/dist/commands/migration-apply.d.mts.map +0 -1
- package/dist/commands/migration-apply.mjs.map +0 -1
- package/dist/commands/migration-ref.d.mts +0 -45
- package/dist/commands/migration-ref.d.mts.map +0 -1
- package/dist/commands/migration-ref.mjs.map +0 -1
- package/dist/init-DW94FRsD.mjs.map +0 -1
- package/dist/migration-plan-q1pPoOCf.mjs.map +0 -1
- package/dist/migration-status-Do4Ei0i_.mjs.map +0 -1
- package/dist/migrations-CTsyBXCA.mjs.map +0 -1
- package/dist/terminal-ui-C_hFNbAn.mjs.map +0 -1
- /package/dist/{cli-errors-B9OBbled.d.mts → cli-errors-DdcjVLJV.d.mts} +0 -0
|
@@ -19,8 +19,9 @@ import {
|
|
|
19
19
|
findReachableLeaves,
|
|
20
20
|
} from '@prisma-next/migration-tools/migration-graph';
|
|
21
21
|
import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
|
|
22
|
+
import { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';
|
|
22
23
|
import type { RefEntry, Refs } from '@prisma-next/migration-tools/refs';
|
|
23
|
-
import { readRefs
|
|
24
|
+
import { readRefs } from '@prisma-next/migration-tools/refs';
|
|
24
25
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
25
26
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
26
27
|
import { cyan, dim, magenta, yellow } from 'colorette';
|
|
@@ -33,6 +34,7 @@ import {
|
|
|
33
34
|
errorRuntime,
|
|
34
35
|
errorUnexpected,
|
|
35
36
|
mapMigrationToolsError,
|
|
37
|
+
mapRefResolutionError,
|
|
36
38
|
} from '../utils/cli-errors';
|
|
37
39
|
import {
|
|
38
40
|
addGlobalOptions,
|
|
@@ -43,6 +45,7 @@ import {
|
|
|
43
45
|
resolveMigrationPaths,
|
|
44
46
|
setCommandDescriptions,
|
|
45
47
|
setCommandExamples,
|
|
48
|
+
setCommandSeeAlso,
|
|
46
49
|
toPathDecisionResult,
|
|
47
50
|
toStructuralEdge,
|
|
48
51
|
} from '../utils/command-helpers';
|
|
@@ -70,10 +73,8 @@ import { TerminalUI } from '../utils/terminal-ui';
|
|
|
70
73
|
interface MigrationStatusOptions extends CommonCommandOptions {
|
|
71
74
|
readonly db?: string;
|
|
72
75
|
readonly config?: string;
|
|
73
|
-
readonly
|
|
74
|
-
readonly
|
|
75
|
-
readonly limit?: string;
|
|
76
|
-
readonly all?: boolean;
|
|
76
|
+
readonly to?: string;
|
|
77
|
+
readonly from?: string;
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
export interface MigrationStatusEntry {
|
|
@@ -94,7 +95,7 @@ export interface MigrationStatusEntry {
|
|
|
94
95
|
*
|
|
95
96
|
* - `headHash`: the on-disk head ref's hash (where the space is going).
|
|
96
97
|
* - `markerHash`: the live marker hash for the space, or null if no
|
|
97
|
-
* marker has been written yet (greenfield, or pre-`
|
|
98
|
+
* marker has been written yet (greenfield, or pre-`migrate`).
|
|
98
99
|
* - `pendingCount`: number of migration edges between marker and head.
|
|
99
100
|
* Computed via {@link graphWalkStrategy}; 0 means the space is
|
|
100
101
|
* already at head.
|
|
@@ -420,23 +421,6 @@ function resolveDisplayChain(
|
|
|
420
421
|
return toTarget;
|
|
421
422
|
}
|
|
422
423
|
|
|
423
|
-
const DEFAULT_LIMIT = 10;
|
|
424
|
-
|
|
425
|
-
function determineLimit(opts: MigrationStatusOptions) {
|
|
426
|
-
if (opts.all) {
|
|
427
|
-
// No limit
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
if (!opts.limit) {
|
|
431
|
-
return DEFAULT_LIMIT;
|
|
432
|
-
}
|
|
433
|
-
const parsed = Number.parseInt(opts.limit, 10);
|
|
434
|
-
if (Number.isNaN(parsed)) {
|
|
435
|
-
return DEFAULT_LIMIT;
|
|
436
|
-
}
|
|
437
|
-
return parsed;
|
|
438
|
-
}
|
|
439
|
-
|
|
440
424
|
/**
|
|
441
425
|
* Build the aggregate enumeration of contract spaces for the status
|
|
442
426
|
* output. Loads the aggregate from disk (lossy on failure — extension
|
|
@@ -581,11 +565,32 @@ async function executeMigrationStatusCommand(
|
|
|
581
565
|
throw error;
|
|
582
566
|
}
|
|
583
567
|
|
|
584
|
-
|
|
585
|
-
|
|
568
|
+
let fromOverrideHash: string | undefined;
|
|
569
|
+
|
|
570
|
+
if (options.to || options.from) {
|
|
586
571
|
try {
|
|
587
|
-
|
|
588
|
-
|
|
572
|
+
const { graph: earlyGraph } = await loadMigrationPackages(appMigrationsDir);
|
|
573
|
+
|
|
574
|
+
if (options.to) {
|
|
575
|
+
const refResult = parseContractRef(options.to, { graph: earlyGraph, refs: allRefs });
|
|
576
|
+
if (!refResult.ok) {
|
|
577
|
+
return notOk(mapRefResolutionError(refResult.failure));
|
|
578
|
+
}
|
|
579
|
+
activeRefHash = refResult.value.hash;
|
|
580
|
+
if (refResult.value.provenance.kind === 'ref') {
|
|
581
|
+
const resolvedRefName = refResult.value.provenance.refName;
|
|
582
|
+
activeRefName = resolvedRefName;
|
|
583
|
+
activeRefEntry = allRefs[resolvedRefName];
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (options.from) {
|
|
588
|
+
const fromResult = parseContractRef(options.from, { graph: earlyGraph, refs: allRefs });
|
|
589
|
+
if (!fromResult.ok) {
|
|
590
|
+
return notOk(mapRefResolutionError(fromResult.failure));
|
|
591
|
+
}
|
|
592
|
+
fromOverrideHash = fromResult.value.hash;
|
|
593
|
+
}
|
|
589
594
|
} catch (error) {
|
|
590
595
|
if (MigrationToolsError.is(error)) {
|
|
591
596
|
return notOk(mapMigrationToolsError(error));
|
|
@@ -613,6 +618,9 @@ async function executeMigrationStatusCommand(
|
|
|
613
618
|
if (activeRefName) {
|
|
614
619
|
details.push({ label: 'ref', value: activeRefName });
|
|
615
620
|
}
|
|
621
|
+
if (options.from) {
|
|
622
|
+
details.push({ label: 'from', value: options.from });
|
|
623
|
+
}
|
|
616
624
|
if (activeRefEntry && activeRefEntry.invariants.length > 0) {
|
|
617
625
|
details.push({
|
|
618
626
|
label: 'required',
|
|
@@ -696,8 +704,8 @@ async function executeMigrationStatusCommand(
|
|
|
696
704
|
severity: 'warn',
|
|
697
705
|
message: 'There are multiple valid migration paths — you must select a target',
|
|
698
706
|
hints: [
|
|
699
|
-
"Use '--
|
|
700
|
-
"Or 'prisma-next
|
|
707
|
+
"Use '--to <contract>' to select a target",
|
|
708
|
+
"Or 'prisma-next ref set <name> <hash>' to create one",
|
|
701
709
|
],
|
|
702
710
|
});
|
|
703
711
|
}
|
|
@@ -751,6 +759,12 @@ async function executeMigrationStatusCommand(
|
|
|
751
759
|
}
|
|
752
760
|
}
|
|
753
761
|
|
|
762
|
+
if (fromOverrideHash !== undefined) {
|
|
763
|
+
markerHash = fromOverrideHash;
|
|
764
|
+
mode = 'offline';
|
|
765
|
+
allMarkers = null;
|
|
766
|
+
}
|
|
767
|
+
|
|
754
768
|
// Build the aggregate enumeration of contract spaces. Lossy on
|
|
755
769
|
// failure (extensions are simply omitted) so the existing
|
|
756
770
|
// single-space app pipeline below still runs even if extensions
|
|
@@ -863,7 +877,7 @@ async function executeMigrationStatusCommand(
|
|
|
863
877
|
code: 'MIGRATION.NO_MARKER',
|
|
864
878
|
severity: 'warn',
|
|
865
879
|
message: 'Database has not been initialized — no migration marker found',
|
|
866
|
-
hints: ["Run 'prisma-next
|
|
880
|
+
hints: ["Run 'prisma-next migrate' to apply pending migrations"],
|
|
867
881
|
});
|
|
868
882
|
}
|
|
869
883
|
|
|
@@ -923,7 +937,7 @@ async function executeMigrationStatusCommand(
|
|
|
923
937
|
let missingInvariants: readonly string[] | undefined;
|
|
924
938
|
let effectiveRequired = new Set<string>();
|
|
925
939
|
if (mode === 'online') {
|
|
926
|
-
// Mirrors `
|
|
940
|
+
// Mirrors `migrate.ts`: compute `effectiveRequired = required −
|
|
927
941
|
// marker.invariants` directly, then derive the display fields from it.
|
|
928
942
|
// `appliedInvariants` is the intersection (`required ∩ marker`), which
|
|
929
943
|
// is what JSON consumers see for the active ref; the unfiltered set
|
|
@@ -945,17 +959,17 @@ async function executeMigrationStatusCommand(
|
|
|
945
959
|
if (mode === 'online') {
|
|
946
960
|
if (markerHash !== undefined && !graph.nodes.has(markerHash) && markerHash === contractHash) {
|
|
947
961
|
summary = `${bundles.length} migration(s) on disk`;
|
|
948
|
-
} else if (activeRefHash && markerHash !== undefined) {
|
|
949
|
-
const distance = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName
|
|
962
|
+
} else if (activeRefHash && activeRefName && markerHash !== undefined) {
|
|
963
|
+
const distance = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName);
|
|
950
964
|
summary = hasInvariantWork ? `${distance} — missing invariant(s): ${missingList}` : distance;
|
|
951
965
|
} else if (pendingCount === 0 && !hasInvariantWork) {
|
|
952
966
|
summary = `Database is up to date (${appliedCount} migration${appliedCount !== 1 ? 's' : ''} applied)`;
|
|
953
967
|
} else if (pendingCount === 0 && hasInvariantWork) {
|
|
954
|
-
summary = `Missing invariant(s): ${missingList} — run 'prisma-next
|
|
968
|
+
summary = `Missing invariant(s): ${missingList} — run 'prisma-next migrate --to ${activeRefName ?? '<ref>'}' to apply`;
|
|
955
969
|
} else if (markerHash === undefined) {
|
|
956
970
|
summary = `${pendingCount} pending migration(s) — database has no marker`;
|
|
957
971
|
} else {
|
|
958
|
-
summary = `${pendingCount} pending migration(s) — run 'prisma-next
|
|
972
|
+
summary = `${pendingCount} pending migration(s) — run 'prisma-next migrate' to apply`;
|
|
959
973
|
}
|
|
960
974
|
} else {
|
|
961
975
|
summary = `${entries.length} migration(s) on disk`;
|
|
@@ -997,8 +1011,7 @@ async function executeMigrationStatusCommand(
|
|
|
997
1011
|
diagnostics.push({
|
|
998
1012
|
code: 'MIGRATION.MARKER_NOT_IN_HISTORY',
|
|
999
1013
|
severity: 'warn',
|
|
1000
|
-
message:
|
|
1001
|
-
'Database matches the current contract but was updated directly (not via migration apply)',
|
|
1014
|
+
message: 'Database matches the current contract but was updated directly (not via migrate)',
|
|
1002
1015
|
hints: ["Run 'prisma-next migration plan' to plan a migration to your current contract"],
|
|
1003
1016
|
});
|
|
1004
1017
|
} else if (pendingCount > 0) {
|
|
@@ -1006,7 +1019,7 @@ async function executeMigrationStatusCommand(
|
|
|
1006
1019
|
code: 'MIGRATION.DATABASE_BEHIND',
|
|
1007
1020
|
severity: 'info',
|
|
1008
1021
|
message: `${pendingCount} migration(s) pending`,
|
|
1009
|
-
hints: ["Run 'prisma-next
|
|
1022
|
+
hints: ["Run 'prisma-next migrate' to apply pending migrations"],
|
|
1010
1023
|
});
|
|
1011
1024
|
} else if (hasInvariantWork) {
|
|
1012
1025
|
diagnostics.push({
|
|
@@ -1014,7 +1027,7 @@ async function executeMigrationStatusCommand(
|
|
|
1014
1027
|
severity: 'info',
|
|
1015
1028
|
message: `Missing required invariant(s): ${missingList}`,
|
|
1016
1029
|
hints: [
|
|
1017
|
-
`Run 'prisma-next
|
|
1030
|
+
`Run 'prisma-next migrate --to ${activeRefName ?? '<ref>'}' to apply a path that covers the required invariants`,
|
|
1018
1031
|
],
|
|
1019
1032
|
});
|
|
1020
1033
|
} else if (!routingUnreachable) {
|
|
@@ -1056,37 +1069,41 @@ export function createMigrationStatusCommand(): Command {
|
|
|
1056
1069
|
const command = new Command('status');
|
|
1057
1070
|
setCommandDescriptions(
|
|
1058
1071
|
command,
|
|
1059
|
-
'Show migration
|
|
1060
|
-
'
|
|
1061
|
-
'
|
|
1062
|
-
'
|
|
1072
|
+
'Show migration path and pending status',
|
|
1073
|
+
'Shows which migrations are pending between the database marker and\n' +
|
|
1074
|
+
'the target contract. Requires a database connection for live status.\n' +
|
|
1075
|
+
'Use `migration graph` for topology, `migration log` for history,\n' +
|
|
1076
|
+
'and `migration list` for on-disk enumeration.',
|
|
1063
1077
|
);
|
|
1064
1078
|
setCommandExamples(command, [
|
|
1065
|
-
'prisma-next migration status',
|
|
1066
1079
|
'prisma-next migration status --db $DATABASE_URL',
|
|
1080
|
+
'prisma-next migration status --to production --db $DATABASE_URL',
|
|
1081
|
+
]);
|
|
1082
|
+
setCommandSeeAlso(command, [
|
|
1083
|
+
{ verb: 'migration log', oneLiner: 'Show executed migration history' },
|
|
1084
|
+
{ verb: 'migration list', oneLiner: 'List on-disk migrations' },
|
|
1085
|
+
{ verb: 'migration graph', oneLiner: 'Show the migration graph topology' },
|
|
1086
|
+
{ verb: 'migration show', oneLiner: 'Display migration package contents' },
|
|
1067
1087
|
]);
|
|
1068
1088
|
addGlobalOptions(command)
|
|
1069
1089
|
.option('--db <url>', 'Database connection string')
|
|
1070
1090
|
.option('--config <path>', 'Path to prisma-next.config.ts')
|
|
1071
|
-
.option(
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1091
|
+
.option(
|
|
1092
|
+
'--to <contract>',
|
|
1093
|
+
'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',
|
|
1094
|
+
)
|
|
1095
|
+
.option(
|
|
1096
|
+
'--from <contract>',
|
|
1097
|
+
'Origin contract reference; same grammar as --to. Supplying --from switches to offline path computation.',
|
|
1098
|
+
)
|
|
1075
1099
|
.action(async (options: MigrationStatusOptions) => {
|
|
1076
1100
|
const flags = parseGlobalFlags(options);
|
|
1077
|
-
|
|
1078
1101
|
const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
|
|
1079
1102
|
|
|
1080
1103
|
const result = await executeMigrationStatusCommand(options, flags, ui);
|
|
1081
1104
|
|
|
1082
1105
|
const exitCode = handleResult(result, flags, ui, (statusResult) => {
|
|
1083
1106
|
if (flags.json) {
|
|
1084
|
-
// Strip non-JSON-shape fields before emitting. These belong to
|
|
1085
|
-
// the in-memory result so the human renderer can avoid
|
|
1086
|
-
// recomputing them, but they would either bloat the wire format
|
|
1087
|
-
// (graph, bundles, edgeStatuses) or expose internals
|
|
1088
|
-
// (activeRefHash, activeRefName, diverged) that consumers should
|
|
1089
|
-
// read off `pathDecision` / `refs` instead.
|
|
1090
1107
|
const {
|
|
1091
1108
|
graph: _graph,
|
|
1092
1109
|
bundles: _bundles,
|
|
@@ -1101,7 +1118,6 @@ export function createMigrationStatusCommand(): Command {
|
|
|
1101
1118
|
const colorize = flags.color !== false;
|
|
1102
1119
|
|
|
1103
1120
|
if (statusResult.graph) {
|
|
1104
|
-
const limit = determineLimit(options);
|
|
1105
1121
|
const renderInput = migrationGraphToRenderInput({
|
|
1106
1122
|
graph: statusResult.graph,
|
|
1107
1123
|
mode: statusResult.mode,
|
|
@@ -1113,16 +1129,13 @@ export function createMigrationStatusCommand(): Command {
|
|
|
1113
1129
|
edgeStatuses: statusResult.edgeStatuses,
|
|
1114
1130
|
});
|
|
1115
1131
|
|
|
1116
|
-
const graphToRender =
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
const dagreOptions =
|
|
1121
|
-
!options.graph && isLinearGraph(graphToRender) ? { ranksep: 1 } : undefined;
|
|
1132
|
+
const graphToRender = statusResult.diverged
|
|
1133
|
+
? renderInput.graph
|
|
1134
|
+
: extractRelevantSubgraph(renderInput.graph, renderInput.relevantPaths);
|
|
1135
|
+
const dagreOptions = isLinearGraph(graphToRender) ? { ranksep: 1 } : undefined;
|
|
1122
1136
|
const renderOptions = {
|
|
1123
1137
|
...renderInput.options,
|
|
1124
1138
|
colorize,
|
|
1125
|
-
...ifDefined('limit', limit),
|
|
1126
1139
|
...ifDefined('dagreOptions', dagreOptions),
|
|
1127
1140
|
};
|
|
1128
1141
|
const graphOutput = graphRenderer.render(graphToRender, renderOptions);
|
|
@@ -1209,7 +1222,7 @@ export function formatStatusSummary(result: MigrationStatusResult, colorize: boo
|
|
|
1209
1222
|
if (total > 0) {
|
|
1210
1223
|
lines.push('');
|
|
1211
1224
|
lines.push(
|
|
1212
|
-
`${c(yellow, '⧗')} ${total} pending migration(s) across ${result.spaces.length} space(s) — run 'prisma-next
|
|
1225
|
+
`${c(yellow, '⧗')} ${total} pending migration(s) across ${result.spaces.length} space(s) — run 'prisma-next migrate' to apply`,
|
|
1213
1226
|
);
|
|
1214
1227
|
}
|
|
1215
1228
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
2
|
+
import { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';
|
|
2
3
|
import type { RefEntry } from '@prisma-next/migration-tools/refs';
|
|
3
4
|
import {
|
|
4
5
|
deleteRef,
|
|
5
|
-
readRef,
|
|
6
6
|
readRefs,
|
|
7
7
|
validateRefName,
|
|
8
8
|
validateRefValue,
|
|
@@ -16,9 +16,11 @@ import {
|
|
|
16
16
|
errorRuntime,
|
|
17
17
|
errorUnexpected,
|
|
18
18
|
mapMigrationToolsError,
|
|
19
|
+
mapRefResolutionError,
|
|
19
20
|
} from '../utils/cli-errors';
|
|
20
21
|
import {
|
|
21
22
|
addGlobalOptions,
|
|
23
|
+
loadMigrationPackages,
|
|
22
24
|
resolveMigrationPaths,
|
|
23
25
|
setCommandDescriptions,
|
|
24
26
|
} from '../utils/command-helpers';
|
|
@@ -34,13 +36,6 @@ interface RefSetResult {
|
|
|
34
36
|
readonly invariants: readonly string[];
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
interface RefGetResult {
|
|
38
|
-
readonly ok: true;
|
|
39
|
-
readonly ref: string;
|
|
40
|
-
readonly hash: string;
|
|
41
|
-
readonly invariants: readonly string[];
|
|
42
|
-
}
|
|
43
|
-
|
|
44
39
|
interface RefDeleteResult {
|
|
45
40
|
readonly ok: true;
|
|
46
41
|
readonly ref: string;
|
|
@@ -66,53 +61,42 @@ function cliErrorInvalidRefName(name: string): CliStructuredError {
|
|
|
66
61
|
});
|
|
67
62
|
}
|
|
68
63
|
|
|
69
|
-
function
|
|
70
|
-
return errorRuntime(`Invalid contract hash "${hash}"`, {
|
|
71
|
-
why: `"${hash}" is not a valid contract hash`,
|
|
72
|
-
fix: 'Contract hashes must match the format "sha256:<64 hex chars>". Copy the hash from `prisma-next contract emit` or `migration status --json`.',
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function executeRefSetCommand(
|
|
64
|
+
export async function executeRefSetCommand(
|
|
77
65
|
name: string,
|
|
78
|
-
|
|
66
|
+
contractInput: string,
|
|
79
67
|
options: { config?: string },
|
|
80
68
|
): Promise<Result<RefSetResult, CliStructuredError>> {
|
|
81
69
|
if (!validateRefName(name)) {
|
|
82
70
|
return notOk(cliErrorInvalidRefName(name));
|
|
83
71
|
}
|
|
84
|
-
if (!validateRefValue(hash)) {
|
|
85
|
-
return notOk(cliErrorInvalidRefValue(hash));
|
|
86
|
-
}
|
|
87
72
|
|
|
88
73
|
try {
|
|
89
74
|
const config = await loadConfig(options.config);
|
|
90
|
-
const { refsDir } = resolveMigrationPaths(options.config, config);
|
|
91
|
-
|
|
75
|
+
const { appMigrationsDir, refsDir } = resolveMigrationPaths(options.config, config);
|
|
76
|
+
|
|
77
|
+
let resolvedHash: string;
|
|
78
|
+
if (validateRefValue(contractInput)) {
|
|
79
|
+
resolvedHash = contractInput;
|
|
80
|
+
} else {
|
|
81
|
+
const { graph } = await loadMigrationPackages(appMigrationsDir);
|
|
82
|
+
const refs = await readRefs(refsDir);
|
|
83
|
+
const refResult = parseContractRef(contractInput, { graph, refs });
|
|
84
|
+
if (!refResult.ok) {
|
|
85
|
+
return notOk(mapRefResolutionError(refResult.failure));
|
|
86
|
+
}
|
|
87
|
+
resolvedHash = refResult.value.hash;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const entry: RefEntry = { hash: resolvedHash, invariants: [] };
|
|
92
91
|
await writeRef(refsDir, name, entry);
|
|
93
|
-
return ok({ ok: true as const, ref: name, hash, invariants: [] });
|
|
94
|
-
} catch (error) {
|
|
95
|
-
if (error instanceof CliStructuredError) return notOk(error);
|
|
96
|
-
return notOk(mapError(error));
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async function executeRefGetCommand(
|
|
101
|
-
name: string,
|
|
102
|
-
options: { config?: string },
|
|
103
|
-
): Promise<Result<RefGetResult, CliStructuredError>> {
|
|
104
|
-
try {
|
|
105
|
-
const config = await loadConfig(options.config);
|
|
106
|
-
const { refsDir } = resolveMigrationPaths(options.config, config);
|
|
107
|
-
const entry = await readRef(refsDir, name);
|
|
108
|
-
return ok({ ok: true as const, ref: name, hash: entry.hash, invariants: entry.invariants });
|
|
92
|
+
return ok({ ok: true as const, ref: name, hash: resolvedHash, invariants: [] });
|
|
109
93
|
} catch (error) {
|
|
110
94
|
if (error instanceof CliStructuredError) return notOk(error);
|
|
111
95
|
return notOk(mapError(error));
|
|
112
96
|
}
|
|
113
97
|
}
|
|
114
98
|
|
|
115
|
-
async function executeRefDeleteCommand(
|
|
99
|
+
export async function executeRefDeleteCommand(
|
|
116
100
|
name: string,
|
|
117
101
|
options: { config?: string },
|
|
118
102
|
): Promise<Result<RefDeleteResult, CliStructuredError>> {
|
|
@@ -127,7 +111,7 @@ async function executeRefDeleteCommand(
|
|
|
127
111
|
}
|
|
128
112
|
}
|
|
129
113
|
|
|
130
|
-
async function executeRefListCommand(options: {
|
|
114
|
+
export async function executeRefListCommand(options: {
|
|
131
115
|
config?: string;
|
|
132
116
|
}): Promise<Result<RefListResult, CliStructuredError>> {
|
|
133
117
|
try {
|
|
@@ -145,12 +129,15 @@ function createRefSetCommand(): Command {
|
|
|
145
129
|
const command = new Command('set');
|
|
146
130
|
setCommandDescriptions(
|
|
147
131
|
command,
|
|
148
|
-
'Set a ref to a contract
|
|
149
|
-
'Sets a named ref to point to a contract hash in migrations/refs/.',
|
|
132
|
+
'Set a ref to a contract reference',
|
|
133
|
+
'Sets a named ref to point to a resolved contract reference (hash, alias, or path) in migrations/refs/.',
|
|
150
134
|
);
|
|
151
135
|
addGlobalOptions(command)
|
|
152
136
|
.argument('<name>', 'Ref name (e.g., staging, production)')
|
|
153
|
-
.argument(
|
|
137
|
+
.argument(
|
|
138
|
+
'<contract>',
|
|
139
|
+
'Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',
|
|
140
|
+
)
|
|
154
141
|
.option('--config <path>', 'Path to prisma-next.config.ts')
|
|
155
142
|
.action(
|
|
156
143
|
async (
|
|
@@ -174,37 +161,6 @@ function createRefSetCommand(): Command {
|
|
|
174
161
|
return command;
|
|
175
162
|
}
|
|
176
163
|
|
|
177
|
-
function createRefGetCommand(): Command {
|
|
178
|
-
const command = new Command('get');
|
|
179
|
-
setCommandDescriptions(
|
|
180
|
-
command,
|
|
181
|
-
'Get the hash for a ref',
|
|
182
|
-
'Reads a named ref from migrations/refs/ and prints its contract hash.',
|
|
183
|
-
);
|
|
184
|
-
addGlobalOptions(command)
|
|
185
|
-
.argument('<name>', 'Ref name to look up')
|
|
186
|
-
.option('--config <path>', 'Path to prisma-next.config.ts')
|
|
187
|
-
.action(
|
|
188
|
-
async (
|
|
189
|
-
name: string,
|
|
190
|
-
options: { config?: string; json?: string | boolean; quiet?: boolean },
|
|
191
|
-
) => {
|
|
192
|
-
const flags = parseGlobalFlags(options);
|
|
193
|
-
const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });
|
|
194
|
-
const result = await executeRefGetCommand(name, options);
|
|
195
|
-
const exitCode = handleResult(result, flags, ui, (value) => {
|
|
196
|
-
if (flags.json) {
|
|
197
|
-
ui.output(JSON.stringify(value));
|
|
198
|
-
} else {
|
|
199
|
-
ui.output(value.hash);
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
process.exit(exitCode);
|
|
203
|
-
},
|
|
204
|
-
);
|
|
205
|
-
return command;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
164
|
function createRefDeleteCommand(): Command {
|
|
209
165
|
const command = new Command('delete');
|
|
210
166
|
setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs/.');
|
|
@@ -262,20 +218,11 @@ function createRefListCommand(): Command {
|
|
|
262
218
|
return command;
|
|
263
219
|
}
|
|
264
220
|
|
|
265
|
-
export {
|
|
266
|
-
cliErrorInvalidRefName,
|
|
267
|
-
cliErrorInvalidRefValue,
|
|
268
|
-
executeRefDeleteCommand,
|
|
269
|
-
executeRefGetCommand,
|
|
270
|
-
executeRefListCommand,
|
|
271
|
-
executeRefSetCommand,
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
export function createMigrationRefCommand(): Command {
|
|
221
|
+
export function createRefCommand(): Command {
|
|
275
222
|
const command = new Command('ref');
|
|
276
223
|
setCommandDescriptions(
|
|
277
224
|
command,
|
|
278
|
-
'Manage
|
|
225
|
+
'Manage contract refs',
|
|
279
226
|
'Manage named refs in migrations/refs/. Refs map logical environment\n' +
|
|
280
227
|
'names (e.g., staging, production) to contract hashes.',
|
|
281
228
|
);
|
|
@@ -284,7 +231,6 @@ export function createMigrationRefCommand(): Command {
|
|
|
284
231
|
subcommandDescription: () => '',
|
|
285
232
|
});
|
|
286
233
|
command.addCommand(createRefSetCommand());
|
|
287
|
-
command.addCommand(createRefGetCommand());
|
|
288
234
|
command.addCommand(createRefDeleteCommand());
|
|
289
235
|
command.addCommand(createRefListCommand());
|
|
290
236
|
return command;
|
|
@@ -49,7 +49,7 @@ export interface ApplyAggregateInputs<TFamilyId extends string, TTargetId extend
|
|
|
49
49
|
* Per-space plans, keyed by `spaceId`. Produced by either the full
|
|
50
50
|
* {@link planAggregate} pipeline (`db init` / `db update` — synth
|
|
51
51
|
* for the app, graph-walk for extensions) or by direct
|
|
52
|
-
* {@link graphWalkStrategy} calls (`
|
|
52
|
+
* {@link graphWalkStrategy} calls (`migrate` — graph-walk
|
|
53
53
|
* for every member). Either way, the runner consumes the same shape.
|
|
54
54
|
*/
|
|
55
55
|
readonly perSpacePlans: ReadonlyMap<string, AggregatePerSpacePlan>;
|
|
@@ -100,7 +100,7 @@ export type ApplyAggregateResult = Result<ApplyAggregateValue, AggregateApplyRun
|
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* Runner-driving tail shared by every aggregate apply caller — `db init`,
|
|
103
|
-
* `db update`, and `
|
|
103
|
+
* `db update`, and `migrate`. Consumes already-resolved per-space
|
|
104
104
|
* plans (the planner-vs-replay distinction is owned by the caller) and
|
|
105
105
|
* dispatches them to the multi-space runner in canonical order.
|
|
106
106
|
*
|
|
@@ -264,7 +264,7 @@ export function collectOrdered(
|
|
|
264
264
|
/**
|
|
265
265
|
* Action-appropriate label for the `spanStart` event the apply
|
|
266
266
|
* primitive emits. `applyAggregate` is shared by `db init`, `db update`,
|
|
267
|
-
* and `
|
|
267
|
+
* and `migrate`; the span label tracks the user-visible action
|
|
268
268
|
* so structured-progress output reads naturally for each surface.
|
|
269
269
|
*/
|
|
270
270
|
export function progressLabelForAction(action: AggregateApplyAction): string {
|
|
@@ -285,6 +285,6 @@ function labelForAction(action: AggregateApplyAction): string {
|
|
|
285
285
|
case 'dbUpdate':
|
|
286
286
|
return 'db update';
|
|
287
287
|
case 'migrationApply':
|
|
288
|
-
return '
|
|
288
|
+
return 'migrate';
|
|
289
289
|
}
|
|
290
290
|
}
|
|
@@ -207,9 +207,10 @@ export async function executeAggregateApply<TFamilyId extends string, TTargetId
|
|
|
207
207
|
|
|
208
208
|
// 5. Apply mode: hand off to the shared `applyAggregate` primitive.
|
|
209
209
|
// The runner-driving tail is identical for `db init` / `db update` /
|
|
210
|
-
// `
|
|
210
|
+
// `migrate` — only how each caller produces `perSpacePlans`
|
|
211
211
|
// differs (synth + graph-walk via planAggregate here; graph-walk
|
|
212
|
-
// only for
|
|
212
|
+
// only for migrate). Each caller produces perSpacePlans differently;
|
|
213
|
+
// this helper handles the shared apply tail.
|
|
213
214
|
const applied = await applyAggregate({
|
|
214
215
|
aggregate,
|
|
215
216
|
perSpacePlans: planResult.value.perSpace,
|
|
@@ -34,7 +34,7 @@ import type {
|
|
|
34
34
|
import { applyAggregate, buildPerSpaceBreakdown } from './apply-aggregate';
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Inputs for the aggregate-walking `
|
|
37
|
+
* Inputs for the aggregate-walking `migrate` control-api
|
|
38
38
|
* operation.
|
|
39
39
|
*
|
|
40
40
|
* The CLI command resolves the descriptor surface (config, refs,
|
|
@@ -110,7 +110,8 @@ export interface ExecuteMigrationApplyOptions<TFamilyId extends string, TTargetI
|
|
|
110
110
|
* shared with `db init` / `db update`). Marker advancement is
|
|
111
111
|
* inside the per-space transaction.
|
|
112
112
|
*
|
|
113
|
-
*
|
|
113
|
+
* Encodes the replay-only contract: every contract space must have an
|
|
114
|
+
* authored migration graph on disk before this operation can advance it.
|
|
114
115
|
*/
|
|
115
116
|
export async function executeMigrationApply<TFamilyId extends string, TTargetId extends string>(
|
|
116
117
|
options: ExecuteMigrationApplyOptions<TFamilyId, TTargetId>,
|
|
@@ -461,7 +462,7 @@ function buildNeverPlannedFailure(spaceId: string, targetHash: string): Migratio
|
|
|
461
462
|
return {
|
|
462
463
|
code: 'MIGRATION_PATH_NOT_FOUND',
|
|
463
464
|
summary: `No on-disk migrations for contract space "${spaceId}"`,
|
|
464
|
-
why: `
|
|
465
|
+
why: `migrate is replay-only: every contract space must have an authored migration graph on disk. Space "${spaceId}" has no migrations under \`migrations/${spaceId}/\` but its head ref targets "${targetHash}". Run \`prisma-next migration plan\` first to materialise the path.`,
|
|
465
466
|
meta: { spaceId, target: targetHash, kind: 'neverPlanned' },
|
|
466
467
|
};
|
|
467
468
|
}
|
package/src/control-api/types.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type {
|
|
|
2
2
|
ContractSourceDiagnostics,
|
|
3
3
|
ContractSourceProvider,
|
|
4
4
|
} from '@prisma-next/config/config-types';
|
|
5
|
-
import type {
|
|
5
|
+
import type { ContractMarkerRecord } from '@prisma-next/contract/types';
|
|
6
6
|
import type {
|
|
7
7
|
ControlAdapterDescriptor,
|
|
8
8
|
ControlDriverDescriptor,
|
|
@@ -590,7 +590,6 @@ export interface MigrationApplyStep {
|
|
|
590
590
|
readonly dirName: string;
|
|
591
591
|
readonly from: string | null;
|
|
592
592
|
readonly to: string;
|
|
593
|
-
readonly toContract: Contract;
|
|
594
593
|
readonly operations: readonly MigrationPlanOperation[];
|
|
595
594
|
/**
|
|
596
595
|
* Sorted, deduplicated invariant ids from `migration.json.providedInvariants`.
|
package/src/migration-cli.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* `node migration.ts` directly.
|
|
4
4
|
*
|
|
5
5
|
* Naming: this is *not* a "migration runner" in the apply-time sense. The
|
|
6
|
-
* apply-time runner is the thing `prisma-next
|
|
6
|
+
* apply-time runner is the thing `prisma-next migrate` uses to
|
|
7
7
|
* execute migration JSON ops against a database. `MigrationCLI` is the
|
|
8
8
|
* tiny CLI surface owned by an authored `migration.ts` file: parse the
|
|
9
9
|
* file's argv, load the project's `prisma-next.config.ts`, assemble a
|
package/src/utils/cli-errors.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
} from '@prisma-next/errors/control';
|
|
26
26
|
import { errorRuntime } from '@prisma-next/errors/execution';
|
|
27
27
|
import type { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
28
|
+
import type { RefResolutionError } from '@prisma-next/migration-tools/ref-resolution';
|
|
28
29
|
|
|
29
30
|
export {
|
|
30
31
|
ERROR_CODE_DESTRUCTIVE_CHANGES,
|
|
@@ -85,3 +86,39 @@ export function mapMigrationToolsError(error: MigrationToolsError): CliStructure
|
|
|
85
86
|
meta: { code: error.code, ...(error.details ?? {}) },
|
|
86
87
|
});
|
|
87
88
|
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Maps a `RefResolutionError` from the contract/migration reference
|
|
92
|
+
* resolver into a CLI structured error envelope.
|
|
93
|
+
*/
|
|
94
|
+
export function mapRefResolutionError(error: RefResolutionError): CliStructuredError {
|
|
95
|
+
switch (error.kind) {
|
|
96
|
+
case 'not-found':
|
|
97
|
+
return errorRuntime(`Not a known ${error.grammar} reference: "${error.input}"`, {
|
|
98
|
+
why: `No ${error.grammar} matching "${error.input}" exists in the migration graph or refs index.`,
|
|
99
|
+
fix:
|
|
100
|
+
error.grammar === 'contract'
|
|
101
|
+
? 'Provide a valid contract hash, ref name, or migration directory name.'
|
|
102
|
+
: 'Provide a valid migration directory name or migration hash.',
|
|
103
|
+
meta: { input: error.input, grammar: error.grammar },
|
|
104
|
+
});
|
|
105
|
+
case 'ambiguous':
|
|
106
|
+
return errorRuntime(`Ambiguous ${error.grammar} reference: "${error.input}"`, {
|
|
107
|
+
why: `"${error.input}" matches multiple ${error.grammar}s: ${error.candidates.join(', ')}`,
|
|
108
|
+
fix: 'Provide a longer prefix or use the full hash to disambiguate.',
|
|
109
|
+
meta: { input: error.input, candidates: error.candidates, grammar: error.grammar },
|
|
110
|
+
});
|
|
111
|
+
case 'wrong-grammar':
|
|
112
|
+
return errorRuntime(error.message, {
|
|
113
|
+
why: error.message,
|
|
114
|
+
fix: error.fix,
|
|
115
|
+
meta: { input: error.input, expectedGrammar: error.expectedGrammar },
|
|
116
|
+
});
|
|
117
|
+
case 'invalid-format':
|
|
118
|
+
return errorRuntime(`Invalid reference format: "${error.input}"`, {
|
|
119
|
+
why: error.reason,
|
|
120
|
+
fix: 'Provide a valid contract hash, ref name, or migration directory name.',
|
|
121
|
+
meta: { input: error.input },
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|