prisma-next 0.11.0-dev.9 → 0.12.0-dev.1
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.mjs +9 -10
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-UnIveZxZ.mjs → client-KgJorIvG.mjs} +72 -60
- package/dist/client-KgJorIvG.mjs.map +1 -0
- package/dist/{command-helpers-CRfjbZRz.mjs → command-helpers-Bbw1GbwL.mjs} +642 -45
- package/dist/command-helpers-Bbw1GbwL.mjs.map +1 -0
- 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.map +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 +5 -7
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.d.mts.map +1 -1
- package/dist/commands/db-schema.mjs +3 -4
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +12 -10
- 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 +12 -11
- package/dist/commands/db-update.mjs.map +1 -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 +2 -2
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +68 -69
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +4 -3
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +1 -280
- package/dist/commands/migration-graph.d.mts +13 -2
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +2 -137
- package/dist/commands/migration-list.d.mts +64 -4
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +143 -56
- package/dist/commands/migration-list.mjs.map +1 -1
- package/dist/commands/migration-log.d.mts +10 -1
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +10 -15
- package/dist/commands/migration-log.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +32 -38
- 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 +4 -55
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +61 -153
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +12 -49
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +84 -80
- package/dist/commands/migration-status.mjs.map +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +10 -8
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/config-loader-B6sJjXTv.mjs.map +1 -1
- package/dist/config-loader.d.mts.map +1 -1
- package/dist/contract-at-errors-BxP-TOMl.mjs +42 -0
- package/dist/contract-at-errors-BxP-TOMl.mjs.map +1 -0
- package/dist/{contract-emit-C6rlsljO.mjs → contract-emit-D-4jrNve.mjs} +21 -7
- package/dist/{contract-emit-C6rlsljO.mjs.map → contract-emit-D-4jrNve.mjs.map} +1 -1
- package/dist/{contract-emit-mqXmapxB.mjs → contract-emit-DxcGl4Uq.mjs} +4 -6
- package/dist/{contract-emit-mqXmapxB.mjs.map → contract-emit-DxcGl4Uq.mjs.map} +1 -1
- package/dist/{contract-enrichment-Dani0mMW.mjs → contract-enrichment-a0V5Y_mL.mjs} +4 -25
- package/dist/contract-enrichment-a0V5Y_mL.mjs.map +1 -0
- package/dist/{contract-infer-C4jxc1aZ.mjs → contract-infer-D8uEbJuu.mjs} +3 -4
- package/dist/{contract-infer-C4jxc1aZ.mjs.map → contract-infer-D8uEbJuu.mjs.map} +1 -1
- package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs +247 -0
- package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs.map +1 -0
- package/dist/{db-verify-1d8tDoFN.mjs → db-verify-v_vUKXTU.mjs} +5 -7
- package/dist/{db-verify-1d8tDoFN.mjs.map → db-verify-v_vUKXTU.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +3 -3
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +1 -1
- 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/extension-pack-inputs-IDvjRCi3.mjs +62 -0
- package/dist/extension-pack-inputs-IDvjRCi3.mjs.map +1 -0
- package/dist/{framework-components-Bexd0f4E.mjs → framework-components-fYXjz_in.mjs} +2 -2
- package/dist/{framework-components-Bexd0f4E.mjs.map → framework-components-fYXjz_in.mjs.map} +1 -1
- package/dist/global-flags-DEHjV8_s.d.mts +34 -0
- package/dist/global-flags-DEHjV8_s.d.mts.map +1 -0
- package/dist/{graph-render-BE8vmJ_7.mjs → graph-render-rFAqZujX.mjs} +2 -2
- package/dist/{graph-render-BE8vmJ_7.mjs.map → graph-render-rFAqZujX.mjs.map} +1 -1
- package/dist/{init-ByoeQphC.mjs → init-Cv9UzWL5.mjs} +17 -19
- package/dist/init-Cv9UzWL5.mjs.map +1 -0
- package/dist/{inspect-live-schema-B1Q49RF0.mjs → inspect-live-schema-C6ohV_oQ.mjs} +4 -5
- package/dist/{inspect-live-schema-B1Q49RF0.mjs.map → inspect-live-schema-C6ohV_oQ.mjs.map} +1 -1
- package/dist/migration-check-BiBJoYYW.mjs +341 -0
- package/dist/migration-check-BiBJoYYW.mjs.map +1 -0
- package/dist/migration-cli.d.mts.map +1 -1
- package/dist/migration-cli.mjs +4 -4
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-oY4P1Qto.mjs → migration-command-scaffold-CjvwO6at.mjs} +4 -5
- package/dist/{migration-command-scaffold-oY4P1Qto.mjs.map → migration-command-scaffold-CjvwO6at.mjs.map} +1 -1
- package/dist/migration-graph-D7DVUElV.mjs +1232 -0
- package/dist/migration-graph-D7DVUElV.mjs.map +1 -0
- package/dist/migration-list-styler-BRwF4-gy.mjs +399 -0
- package/dist/migration-list-styler-BRwF4-gy.mjs.map +1 -0
- package/dist/{migration-plan-jdAHg_gK.mjs → migration-plan-9DJ7q7_z.mjs} +169 -189
- package/dist/migration-plan-9DJ7q7_z.mjs.map +1 -0
- package/dist/{migration-types-BXWvz12q.d.mts → migration-types-D2FW63pr.d.mts} +1 -1
- package/dist/{migration-types-BXWvz12q.d.mts.map → migration-types-D2FW63pr.d.mts.map} +1 -1
- package/dist/{migrations-B7n518mT.mjs → migrations-Cv2jxNNK.mjs} +3 -13
- package/dist/migrations-Cv2jxNNK.mjs.map +1 -0
- package/dist/{output-CUIdfYo5.mjs → output-B60Gw5fu.mjs} +1 -1
- package/dist/{output-CUIdfYo5.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs → progress-adapter-C644QK8l.mjs} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs.map → progress-adapter-C644QK8l.mjs.map} +1 -1
- package/dist/{ref-advancement-DRh5Nquq.mjs → ref-advancement-DUZqsue6.mjs} +1 -1
- package/dist/{ref-advancement-DRh5Nquq.mjs.map → ref-advancement-DUZqsue6.mjs.map} +1 -1
- package/dist/terminal-ui-5Y6mrg93.d.mts +133 -0
- package/dist/terminal-ui-5Y6mrg93.d.mts.map +1 -0
- package/dist/{types-UWB2-rrw.d.mts → types-Dt_SfqFm.d.mts} +18 -26
- package/dist/types-Dt_SfqFm.d.mts.map +1 -0
- package/dist/{verify-C5UvbrF1.mjs → verify-DCA9Sldu.mjs} +2 -2
- package/dist/{verify-C5UvbrF1.mjs.map → verify-DCA9Sldu.mjs.map} +1 -1
- package/package.json +27 -16
- package/dist/cli-errors-Bw2GlweY.mjs +0 -175
- package/dist/cli-errors-Bw2GlweY.mjs.map +0 -1
- package/dist/client-UnIveZxZ.mjs.map +0 -1
- package/dist/command-helpers-CRfjbZRz.mjs.map +0 -1
- package/dist/commands/migration-check.mjs.map +0 -1
- package/dist/commands/migration-graph.mjs.map +0 -1
- package/dist/contract-enrichment-Dani0mMW.mjs.map +0 -1
- package/dist/contract-space-aggregate-loader-CGakRlKM.mjs +0 -160
- package/dist/contract-space-aggregate-loader-CGakRlKM.mjs.map +0 -1
- package/dist/global-flags-CdE7M0d9.d.mts +0 -15
- package/dist/global-flags-CdE7M0d9.d.mts.map +0 -1
- package/dist/init-ByoeQphC.mjs.map +0 -1
- package/dist/migration-plan-jdAHg_gK.mjs.map +0 -1
- package/dist/migrations-B7n518mT.mjs.map +0 -1
- package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
- package/dist/terminal-ui-BiB_8KNo.mjs +0 -379
- package/dist/terminal-ui-BiB_8KNo.mjs.map +0 -1
- package/dist/types-UWB2-rrw.d.mts.map +0 -1
|
@@ -1,69 +1,157 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { B as errorInvalidSpaceId, Q as errorSpaceNotFound, T as formatStyledHeader, _ as createTerminalUI, d as setCommandSeeAlso, g as parseGlobalFlagsOrExit, l as setCommandDescriptions, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, y as handleResult } from "../command-helpers-Bbw1GbwL.mjs";
|
|
3
|
+
import { r as buildReadAggregate } from "../contract-space-aggregate-loader-DvZwdkrr.mjs";
|
|
4
|
+
import { i as renderMigrationListWithStyle, n as createAnsiMigrationListStyler, r as buildMigrationListTopologyBySpace } from "../migration-list-styler-BRwF4-gy.mjs";
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
+
import { ifDefined } from "@prisma-next/utils/defined";
|
|
6
7
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
8
|
+
import { APP_SPACE_ID, RESERVED_SPACE_SUBDIR_NAMES, isValidSpaceId, listContractSpaceDirectories } from "@prisma-next/migration-tools/spaces";
|
|
9
|
+
import { HEAD_REF_NAME, refsByContractHash } from "@prisma-next/migration-tools/refs";
|
|
10
10
|
//#region src/commands/migration-list.ts
|
|
11
|
+
function compareSpaceIds(a, b) {
|
|
12
|
+
if (a === APP_SPACE_ID) return b === APP_SPACE_ID ? 0 : -1;
|
|
13
|
+
if (b === APP_SPACE_ID) return 1;
|
|
14
|
+
if (a < b) return -1;
|
|
15
|
+
if (a > b) return 1;
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
function compareDirNamesDescending(a, b) {
|
|
19
|
+
if (a.dirName < b.dirName) return 1;
|
|
20
|
+
if (a.dirName > b.dirName) return -1;
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Ref names decorating a space's destination contract hashes. The
|
|
25
|
+
* tolerant `member.refs` deliberately omits the structural `head.json`;
|
|
26
|
+
* for extension spaces the old enumerator surfaced it as a `head`
|
|
27
|
+
* decoration on the tip migration, so fold `member.headRef` back in to
|
|
28
|
+
* keep that output. The app space synthesises its head, so it carries
|
|
29
|
+
* no on-disk `head` ref to restore.
|
|
30
|
+
*/
|
|
31
|
+
function listRefsByContractHash(member) {
|
|
32
|
+
const byHash = new Map(refsByContractHash(member.refs));
|
|
33
|
+
if (member.spaceId !== APP_SPACE_ID && member.headRef !== null) {
|
|
34
|
+
const hash = member.headRef.hash;
|
|
35
|
+
const bucket = byHash.get(hash) ?? [];
|
|
36
|
+
if (!bucket.includes(HEAD_REF_NAME)) byHash.set(hash, [...bucket, HEAD_REF_NAME].sort());
|
|
37
|
+
}
|
|
38
|
+
return byHash;
|
|
39
|
+
}
|
|
40
|
+
async function orderedOnDiskSpaceIds(projectMigrationsDir) {
|
|
41
|
+
return (await listContractSpaceDirectories(projectMigrationsDir)).filter((name) => !RESERVED_SPACE_SUBDIR_NAMES.has(name)).filter(isValidSpaceId).sort(compareSpaceIds);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Project the loaded {@link ContractSpaceAggregate} into the render-ready
|
|
45
|
+
* {@link MigrationSpaceListEntry} rows `migration list` displays.
|
|
46
|
+
*
|
|
47
|
+
* Space membership matches the on-disk contract-space directories (not the
|
|
48
|
+
* aggregate's always-present synthesized app member when `migrations/app/`
|
|
49
|
+
* is absent); package and ref data come from `aggregate.space(id)`.
|
|
50
|
+
*/
|
|
51
|
+
async function migrationSpaceListEntriesFromAggregate(aggregate, projectMigrationsDir) {
|
|
52
|
+
const spaceIds = await orderedOnDiskSpaceIds(projectMigrationsDir);
|
|
53
|
+
const spaces = [];
|
|
54
|
+
for (const spaceId of spaceIds) {
|
|
55
|
+
const member = aggregate.space(spaceId);
|
|
56
|
+
if (member === void 0) continue;
|
|
57
|
+
const refsByHash = listRefsByContractHash(member);
|
|
58
|
+
const migrations = member.packages.map((pkg) => ({
|
|
59
|
+
dirName: pkg.dirName,
|
|
60
|
+
from: pkg.metadata.from,
|
|
61
|
+
to: pkg.metadata.to,
|
|
62
|
+
migrationHash: pkg.metadata.migrationHash,
|
|
63
|
+
operationCount: pkg.ops.length,
|
|
64
|
+
createdAt: pkg.metadata.createdAt,
|
|
65
|
+
refs: refsByHash.get(pkg.metadata.to) ?? [],
|
|
66
|
+
providedInvariants: pkg.metadata.providedInvariants
|
|
67
|
+
})).sort(compareDirNamesDescending);
|
|
68
|
+
spaces.push({
|
|
69
|
+
spaceId,
|
|
70
|
+
migrations
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return spaces;
|
|
74
|
+
}
|
|
75
|
+
function renderMigrationListHumanOutput(result, options) {
|
|
76
|
+
const styler = createAnsiMigrationListStyler({ useColor: options.useColor });
|
|
77
|
+
const topologyBySpaceId = buildMigrationListTopologyBySpace(result);
|
|
78
|
+
return renderMigrationListWithStyle(result, styler, options.glyphMode, topologyBySpaceId);
|
|
79
|
+
}
|
|
80
|
+
function computeSummary(spaces) {
|
|
81
|
+
const totalMigrations = spaces.reduce((count, space) => count + space.migrations.length, 0);
|
|
82
|
+
if (spaces.length <= 1) return `${totalMigrations} migration(s) on disk`;
|
|
83
|
+
return `${totalMigrations} migration(s) across ${spaces.length} contract space(s)`;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Policy core of `migration list`: validates `--space`, narrows the
|
|
87
|
+
* pre-enumerated spaces, and assembles a {@link MigrationListResult}.
|
|
88
|
+
*
|
|
89
|
+
* - `migrations/` missing or contains no valid space directories →
|
|
90
|
+
* caller passes `spaces: []`; this synthesizes `[{ spaceId: APP_SPACE_ID, migrations: [] }]`.
|
|
91
|
+
* - `--space <id>` on an existing-but-empty space → `{ spaceId, migrations: [] }` in the input.
|
|
92
|
+
* - `--space <id>` on a non-existent (or reserved) space → `SPACE_NOT_FOUND`.
|
|
93
|
+
*/
|
|
94
|
+
function runMigrationList(inputs) {
|
|
95
|
+
const { spaces, spaceFilter } = inputs;
|
|
96
|
+
if (spaceFilter !== void 0 && !isValidSpaceId(spaceFilter)) return notOk(errorInvalidSpaceId(spaceFilter));
|
|
97
|
+
if (spaceFilter !== void 0 && !spaces.some((s) => s.spaceId === spaceFilter)) return notOk(errorSpaceNotFound(spaceFilter, spaces.map((s) => s.spaceId).sort()));
|
|
98
|
+
const scopedSpaces = spaceFilter !== void 0 ? spaces.filter((s) => s.spaceId === spaceFilter) : spaces;
|
|
99
|
+
const resultSpaces = scopedSpaces.length === 0 ? [{
|
|
100
|
+
spaceId: APP_SPACE_ID,
|
|
101
|
+
migrations: []
|
|
102
|
+
}] : scopedSpaces;
|
|
103
|
+
return ok({
|
|
104
|
+
ok: true,
|
|
105
|
+
spaces: resultSpaces,
|
|
106
|
+
summary: computeSummary(resultSpaces)
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* CLI shell: loads config, resolves paths, prints the styled header on
|
|
111
|
+
* stderr (interactive mode only), and delegates to {@link runMigrationList}.
|
|
112
|
+
* Kept intentionally thin so the unit-testable surface lives in the core.
|
|
113
|
+
*/
|
|
11
114
|
async function executeMigrationListCommand(options, flags, ui) {
|
|
12
115
|
const config = await loadConfig(options.config);
|
|
13
|
-
const { configPath,
|
|
116
|
+
const { configPath, migrationsDir, migrationsRelative } = resolveMigrationPaths(options.config, config);
|
|
14
117
|
if (!flags.json && !flags.quiet) {
|
|
15
118
|
const header = formatStyledHeader({
|
|
16
119
|
command: "migration list",
|
|
17
|
-
description: "List on-disk migrations
|
|
18
|
-
details: [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
120
|
+
description: "List on-disk migrations, latest first, per contract space",
|
|
121
|
+
details: [
|
|
122
|
+
{
|
|
123
|
+
label: "config",
|
|
124
|
+
value: configPath
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
label: "migrations",
|
|
128
|
+
value: migrationsRelative
|
|
129
|
+
},
|
|
130
|
+
...options.space !== void 0 ? [{
|
|
131
|
+
label: "space",
|
|
132
|
+
value: options.space
|
|
133
|
+
}] : []
|
|
134
|
+
],
|
|
25
135
|
flags
|
|
26
136
|
});
|
|
27
137
|
ui.stderr(header);
|
|
28
138
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
35
|
-
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}` }));
|
|
36
|
-
}
|
|
37
|
-
if (bundles.length === 0) return ok({
|
|
38
|
-
ok: true,
|
|
39
|
-
migrations: [],
|
|
40
|
-
summary: "No migrations found"
|
|
41
|
-
});
|
|
42
|
-
const leaves = [...graph.nodes].filter((n) => !graph.forwardChain.has(n) || graph.forwardChain.get(n).length === 0);
|
|
43
|
-
const targetHash = leaves.length === 1 ? leaves[0] : [...graph.nodes].values().next().value;
|
|
44
|
-
const chain = findPath(graph, EMPTY_CONTRACT_HASH, targetHash) ?? [];
|
|
45
|
-
const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));
|
|
46
|
-
const entries = chain.map((edge) => {
|
|
47
|
-
const ops = pkgByDirName.get(edge.dirName)?.ops ?? [];
|
|
48
|
-
return {
|
|
49
|
-
dirName: edge.dirName,
|
|
50
|
-
from: edge.from,
|
|
51
|
-
to: edge.to,
|
|
52
|
-
migrationHash: edge.migrationHash,
|
|
53
|
-
operationCount: ops.length,
|
|
54
|
-
createdAt: edge.createdAt
|
|
55
|
-
};
|
|
56
|
-
});
|
|
57
|
-
return ok({
|
|
58
|
-
ok: true,
|
|
59
|
-
migrations: entries,
|
|
60
|
-
summary: `${entries.length} migration(s) on disk`
|
|
139
|
+
const loaded = await buildReadAggregate(config, { migrationsDir });
|
|
140
|
+
if (!loaded.ok) return notOk(loaded.failure);
|
|
141
|
+
return runMigrationList({
|
|
142
|
+
spaces: await migrationSpaceListEntriesFromAggregate(loaded.value.aggregate, migrationsDir),
|
|
143
|
+
...ifDefined("spaceFilter", options.space)
|
|
61
144
|
});
|
|
62
145
|
}
|
|
63
146
|
function createMigrationListCommand() {
|
|
64
147
|
const command = new Command("list");
|
|
65
|
-
setCommandDescriptions(command, "List on-disk migrations
|
|
66
|
-
setCommandExamples(command, [
|
|
148
|
+
setCommandDescriptions(command, "List on-disk migrations, latest first, per contract space", "Enumerates every on-disk migration under migrations/<space>/ for every\ncontract space found on disk, latest first. Offline — does not consult\nthe database. Each row leads with a kind glyph (* forward, ↩ rollback,\n⟲ self), then dirName, then source → destination contract hashes\n(7-char git-style). Self-edges show a single hash. Invariants render as\n{...}; refs on the destination as (production, db). Pass --space <id>\nto narrow to one contract space. --ascii forces ASCII kind glyphs\n(orthogonal to --no-color).");
|
|
149
|
+
setCommandExamples(command, [
|
|
150
|
+
"prisma-next migration list",
|
|
151
|
+
"prisma-next migration list --space app",
|
|
152
|
+
"prisma-next migration list --ascii",
|
|
153
|
+
"prisma-next migration list --json"
|
|
154
|
+
]);
|
|
67
155
|
setCommandSeeAlso(command, [
|
|
68
156
|
{
|
|
69
157
|
verb: "migration status",
|
|
@@ -82,22 +170,21 @@ function createMigrationListCommand() {
|
|
|
82
170
|
oneLiner: "Display migration package contents"
|
|
83
171
|
}
|
|
84
172
|
]);
|
|
85
|
-
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").action(async (options) => {
|
|
173
|
+
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").option("--space <id>", "Narrow output to a single contract space").option("--ascii", "Use ASCII kind glyphs (pipe-friendly)").action(async (options) => {
|
|
86
174
|
const flags = parseGlobalFlagsOrExit(options);
|
|
87
175
|
const ui = createTerminalUI(flags);
|
|
88
176
|
const exitCode = handleResult(await executeMigrationListCommand(options, flags, ui), flags, ui, (listResult) => {
|
|
89
177
|
if (flags.json) ui.output(JSON.stringify(listResult, null, 2));
|
|
90
|
-
else if (!flags.quiet)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
178
|
+
else if (!flags.quiet) ui.output(renderMigrationListHumanOutput(listResult, {
|
|
179
|
+
glyphMode: ui.resolveGlyphMode(options.ascii === true),
|
|
180
|
+
useColor: ui.useColor
|
|
181
|
+
}));
|
|
95
182
|
});
|
|
96
183
|
process.exit(exitCode);
|
|
97
184
|
});
|
|
98
185
|
return command;
|
|
99
186
|
}
|
|
100
187
|
//#endregion
|
|
101
|
-
export { createMigrationListCommand };
|
|
188
|
+
export { createMigrationListCommand, executeMigrationListCommand, migrationSpaceListEntriesFromAggregate, renderMigrationListHumanOutput, runMigrationList };
|
|
102
189
|
|
|
103
190
|
//# sourceMappingURL=migration-list.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-list.mjs","names":[],"sources":["../../src/commands/migration-list.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findPath } from '@prisma-next/migration-tools/migration-graph';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationListOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nexport interface MigrationListEntry {\n readonly dirName: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly operationCount: number;\n readonly createdAt: string;\n}\n\nexport interface MigrationListResult {\n readonly ok: true;\n readonly migrations: readonly MigrationListEntry[];\n readonly summary: string;\n}\n\nasync function executeMigrationListCommand(\n options: MigrationListOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationListResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration list',\n description: 'List on-disk migrations in topological order',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n ({ bundles, graph } = await loadMigrationPackages(appMigrationsDir));\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n if (bundles.length === 0) {\n return ok({ ok: true, migrations: [], summary: 'No migrations found' });\n }\n\n const leaves = [...graph.nodes].filter(\n (n) => !graph.forwardChain.has(n) || graph.forwardChain.get(n)!.length === 0,\n );\n const targetHash =\n leaves.length === 1 ? leaves[0]! : ([...graph.nodes].values().next().value as string);\n const chain = findPath(graph, EMPTY_CONTRACT_HASH, targetHash) ?? [];\n\n const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));\n const entries: MigrationListEntry[] = chain.map((edge) => {\n const pkg = pkgByDirName.get(edge.dirName);\n const ops = (pkg?.ops ?? []) as readonly MigrationPlanOperation[];\n return {\n dirName: edge.dirName,\n from: edge.from,\n to: edge.to,\n migrationHash: edge.migrationHash,\n operationCount: ops.length,\n createdAt: edge.createdAt,\n };\n });\n\n return ok({\n ok: true,\n migrations: entries,\n summary: `${entries.length} migration(s) on disk`,\n });\n}\n\nexport function createMigrationListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(\n command,\n 'List on-disk migrations in topological order',\n 'Enumerates all migration packages under migrations/<space>/ in\\n' +\n 'topological order. Offline — does not consult the database.',\n );\n setCommandExamples(command, ['prisma-next migration list']);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationListOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationListCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (listResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(listResult, null, 2));\n } else if (!flags.quiet) {\n if (listResult.migrations.length === 0) {\n ui.log('No migrations found');\n } else {\n for (const entry of listResult.migrations) {\n ui.log(\n `${entry.dirName} ${entry.migrationHash.slice(0, 16)}… ${entry.operationCount} op(s)`,\n );\n }\n ui.log(`\\n${listResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-list.mjs","names":[],"sources":["../../src/commands/migration-list.ts"],"sourcesContent":["import type {\n ContractSpaceAggregate,\n ContractSpaceMember,\n} from '@prisma-next/migration-tools/aggregate';\nimport { HEAD_REF_NAME, refsByContractHash } from '@prisma-next/migration-tools/refs';\nimport {\n APP_SPACE_ID,\n isValidSpaceId,\n listContractSpaceDirectories,\n RESERVED_SPACE_SUBDIR_NAMES,\n} from '@prisma-next/migration-tools/spaces';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorInvalidSpaceId,\n errorSpaceNotFound,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport {\n buildMigrationListTopologyBySpace,\n renderMigrationListWithStyle,\n} from '../utils/formatters/migration-list-render';\nimport { createAnsiMigrationListStyler } from '../utils/formatters/migration-list-styler';\nimport type {\n MigrationListEntry,\n MigrationListResult,\n MigrationSpaceListEntry,\n} from '../utils/formatters/migration-list-types';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { GlyphMode } from '../utils/glyph-mode';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\nfunction compareSpaceIds(a: string, b: string): number {\n if (a === APP_SPACE_ID) return b === APP_SPACE_ID ? 0 : -1;\n if (b === APP_SPACE_ID) return 1;\n if (a < b) return -1;\n if (a > b) return 1;\n return 0;\n}\n\nfunction compareDirNamesDescending(a: MigrationListEntry, b: MigrationListEntry): number {\n if (a.dirName < b.dirName) return 1;\n if (a.dirName > b.dirName) return -1;\n return 0;\n}\n\n/**\n * Ref names decorating a space's destination contract hashes. The\n * tolerant `member.refs` deliberately omits the structural `head.json`;\n * for extension spaces the old enumerator surfaced it as a `head`\n * decoration on the tip migration, so fold `member.headRef` back in to\n * keep that output. The app space synthesises its head, so it carries\n * no on-disk `head` ref to restore.\n */\nfunction listRefsByContractHash(\n member: ContractSpaceMember,\n): ReadonlyMap<string, readonly string[]> {\n const byHash = new Map(refsByContractHash(member.refs));\n if (member.spaceId !== APP_SPACE_ID && member.headRef !== null) {\n const hash = member.headRef.hash;\n const bucket = byHash.get(hash) ?? [];\n if (!bucket.includes(HEAD_REF_NAME)) {\n byHash.set(hash, [...bucket, HEAD_REF_NAME].sort());\n }\n }\n return byHash;\n}\n\nasync function orderedOnDiskSpaceIds(projectMigrationsDir: string): Promise<readonly string[]> {\n const candidateDirs = await listContractSpaceDirectories(projectMigrationsDir);\n return candidateDirs\n .filter((name) => !RESERVED_SPACE_SUBDIR_NAMES.has(name))\n .filter(isValidSpaceId)\n .sort(compareSpaceIds);\n}\n\n/**\n * Project the loaded {@link ContractSpaceAggregate} into the render-ready\n * {@link MigrationSpaceListEntry} rows `migration list` displays.\n *\n * Space membership matches the on-disk contract-space directories (not the\n * aggregate's always-present synthesized app member when `migrations/app/`\n * is absent); package and ref data come from `aggregate.space(id)`.\n */\nexport async function migrationSpaceListEntriesFromAggregate(\n aggregate: ContractSpaceAggregate,\n projectMigrationsDir: string,\n): Promise<readonly MigrationSpaceListEntry[]> {\n const spaceIds = await orderedOnDiskSpaceIds(projectMigrationsDir);\n const spaces: MigrationSpaceListEntry[] = [];\n\n for (const spaceId of spaceIds) {\n const member = aggregate.space(spaceId);\n if (member === undefined) {\n continue;\n }\n const refsByHash = listRefsByContractHash(member);\n const migrations: MigrationListEntry[] = member.packages\n .map((pkg) => ({\n dirName: pkg.dirName,\n from: pkg.metadata.from,\n to: pkg.metadata.to,\n migrationHash: pkg.metadata.migrationHash,\n operationCount: pkg.ops.length,\n createdAt: pkg.metadata.createdAt,\n refs: refsByHash.get(pkg.metadata.to) ?? [],\n providedInvariants: pkg.metadata.providedInvariants,\n }))\n .sort(compareDirNamesDescending);\n\n spaces.push({ spaceId, migrations });\n }\n\n return spaces;\n}\n\ninterface MigrationListOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly space?: string;\n readonly ascii?: boolean;\n}\n\nexport interface MigrationListHumanRenderOptions {\n readonly glyphMode: GlyphMode;\n readonly useColor: boolean;\n}\n\nexport function renderMigrationListHumanOutput(\n result: MigrationListResult,\n options: MigrationListHumanRenderOptions,\n): string {\n const styler = createAnsiMigrationListStyler({ useColor: options.useColor });\n const topologyBySpaceId = buildMigrationListTopologyBySpace(result);\n return renderMigrationListWithStyle(result, styler, options.glyphMode, topologyBySpaceId);\n}\n\n/**\n * Inputs for {@link runMigrationList} — the policy core of `migration list`\n * that tests exercise directly.\n *\n * The core does not call `loadConfig`, parse CLI flags, render a styled\n * header, or write to any stream. Enumeration is supplied by the caller\n * (the CLI shell builds it from {@link migrationSpaceListEntriesFromAggregate}).\n */\nexport interface RunMigrationListInputs {\n readonly spaces: readonly MigrationSpaceListEntry[];\n readonly spaceFilter?: string;\n}\n\nfunction computeSummary(spaces: readonly MigrationSpaceListEntry[]): string {\n const totalMigrations = spaces.reduce((count, space) => count + space.migrations.length, 0);\n if (spaces.length <= 1) {\n return `${totalMigrations} migration(s) on disk`;\n }\n return `${totalMigrations} migration(s) across ${spaces.length} contract space(s)`;\n}\n\n/**\n * Policy core of `migration list`: validates `--space`, narrows the\n * pre-enumerated spaces, and assembles a {@link MigrationListResult}.\n *\n * - `migrations/` missing or contains no valid space directories →\n * caller passes `spaces: []`; this synthesizes `[{ spaceId: APP_SPACE_ID, migrations: [] }]`.\n * - `--space <id>` on an existing-but-empty space → `{ spaceId, migrations: [] }` in the input.\n * - `--space <id>` on a non-existent (or reserved) space → `SPACE_NOT_FOUND`.\n */\nexport function runMigrationList(\n inputs: RunMigrationListInputs,\n): Result<MigrationListResult, CliStructuredError> {\n const { spaces, spaceFilter } = inputs;\n\n if (spaceFilter !== undefined && !isValidSpaceId(spaceFilter)) {\n return notOk(errorInvalidSpaceId(spaceFilter));\n }\n\n if (spaceFilter !== undefined && !spaces.some((s) => s.spaceId === spaceFilter)) {\n return notOk(errorSpaceNotFound(spaceFilter, spaces.map((s) => s.spaceId).sort()));\n }\n\n const scopedSpaces =\n spaceFilter !== undefined ? spaces.filter((s) => s.spaceId === spaceFilter) : spaces;\n\n const resultSpaces: readonly MigrationSpaceListEntry[] =\n scopedSpaces.length === 0 ? [{ spaceId: APP_SPACE_ID, migrations: [] }] : scopedSpaces;\n\n return ok({\n ok: true,\n spaces: resultSpaces,\n summary: computeSummary(resultSpaces),\n });\n}\n\n/**\n * CLI shell: loads config, resolves paths, prints the styled header on\n * stderr (interactive mode only), and delegates to {@link runMigrationList}.\n * Kept intentionally thin so the unit-testable surface lives in the core.\n */\nexport async function executeMigrationListCommand(\n options: MigrationListOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationListResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, migrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration list',\n description: 'List on-disk migrations, latest first, per contract space',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: migrationsRelative },\n ...(options.space !== undefined ? [{ label: 'space', value: options.space }] : []),\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n\n const spaces = await migrationSpaceListEntriesFromAggregate(\n loaded.value.aggregate,\n migrationsDir,\n );\n\n return runMigrationList({\n spaces,\n ...ifDefined('spaceFilter', options.space),\n });\n}\n\nexport function createMigrationListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(\n command,\n 'List on-disk migrations, latest first, per contract space',\n 'Enumerates every on-disk migration under migrations/<space>/ for every\\n' +\n 'contract space found on disk, latest first. Offline — does not consult\\n' +\n 'the database. Each row leads with a kind glyph (* forward, ↩ rollback,\\n' +\n '⟲ self), then dirName, then source → destination contract hashes\\n' +\n '(7-char git-style). Self-edges show a single hash. Invariants render as\\n' +\n '{...}; refs on the destination as (production, db). Pass --space <id>\\n' +\n 'to narrow to one contract space. --ascii forces ASCII kind glyphs\\n' +\n '(orthogonal to --no-color).',\n );\n setCommandExamples(command, [\n 'prisma-next migration list',\n 'prisma-next migration list --space app',\n 'prisma-next migration list --ascii',\n 'prisma-next migration list --json',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--space <id>', 'Narrow output to a single contract space')\n .option('--ascii', 'Use ASCII kind glyphs (pipe-friendly)')\n .action(async (options: MigrationListOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationListCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (listResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(listResult, null, 2));\n } else if (!flags.quiet) {\n ui.output(\n renderMigrationListHumanOutput(listResult, {\n glyphMode: ui.resolveGlyphMode(options.ascii === true),\n useColor: ui.useColor,\n }),\n );\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
import { N as CliStructuredError } from "../types-Dt_SfqFm.mjs";
|
|
2
|
+
import { n as GlobalFlags, t as CommonCommandOptions } from "../global-flags-DEHjV8_s.mjs";
|
|
3
|
+
import { t as TerminalUI } from "../terminal-ui-5Y6mrg93.mjs";
|
|
1
4
|
import { Command } from "commander";
|
|
5
|
+
import { Result } from "@prisma-next/utils/result";
|
|
2
6
|
|
|
3
7
|
//#region src/commands/migration-log.d.ts
|
|
8
|
+
interface MigrationLogOptions extends CommonCommandOptions {
|
|
9
|
+
readonly db?: string;
|
|
10
|
+
readonly config?: string;
|
|
11
|
+
}
|
|
4
12
|
interface MigrationLogEntry {
|
|
5
13
|
readonly dirName: string;
|
|
6
14
|
readonly from: string;
|
|
@@ -15,7 +23,8 @@ interface MigrationLogResult {
|
|
|
15
23
|
readonly applied: readonly MigrationLogEntry[];
|
|
16
24
|
readonly summary: string;
|
|
17
25
|
}
|
|
26
|
+
declare function executeMigrationLogCommand(options: MigrationLogOptions, flags: GlobalFlags, ui: TerminalUI): Promise<Result<MigrationLogResult, CliStructuredError>>;
|
|
18
27
|
declare function createMigrationLogCommand(): Command;
|
|
19
28
|
//#endregion
|
|
20
|
-
export { MigrationLogEntry, MigrationLogResult, createMigrationLogCommand };
|
|
29
|
+
export { MigrationLogEntry, MigrationLogResult, createMigrationLogCommand, executeMigrationLogCommand };
|
|
21
30
|
//# sourceMappingURL=migration-log.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-log.d.mts","names":[],"sources":["../../src/commands/migration-log.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration-log.d.mts","names":[],"sources":["../../src/commands/migration-log.ts"],"mappings":";;;;;;;UAgCU,mBAAA,SAA4B,oBAAoB;EAAA,SAC/C,EAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAGM,iBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,kBAAA;EAAA,SACN,EAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA,WAAkB,iBAAiB;EAAA,SACnC,OAAA;AAAA;AAAA,iBAGW,0BAAA,CACpB,OAAA,EAAS,mBAAA,EACT,KAAA,EAAO,WAAA,EACP,EAAA,EAAI,UAAA,GACH,OAAA,CAAQ,MAAA,CAAO,kBAAA,EAAoB,kBAAA;AAAA,iBA8GtB,yBAAA,CAAA,GAA6B,OAAO"}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { t as
|
|
4
|
-
import {
|
|
5
|
-
import { t as createControlClient } from "../client-UnIveZxZ.mjs";
|
|
2
|
+
import { A as CliStructuredError, F as errorDatabaseConnectionRequired, L as errorDriverRequired, T as formatStyledHeader, _ as createTerminalUI, d as setCommandSeeAlso, f as targetSupportsMigrations, g as parseGlobalFlagsOrExit, i as maskConnectionUrl, l as setCommandDescriptions, nt as mapMigrationToolsError, s as resolveMigrationPaths, t as addGlobalOptions, tt as errorUnexpected, u as setCommandExamples, y as handleResult } from "../command-helpers-Bbw1GbwL.mjs";
|
|
3
|
+
import { t as createControlClient } from "../client-KgJorIvG.mjs";
|
|
4
|
+
import { r as buildReadAggregate } from "../contract-space-aggregate-loader-DvZwdkrr.mjs";
|
|
6
5
|
import { Command } from "commander";
|
|
7
6
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
8
|
-
import { findPath } from "@prisma-next/migration-tools/migration-graph";
|
|
9
7
|
import { cyan, dim } from "colorette";
|
|
10
8
|
import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
|
|
11
9
|
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
10
|
+
import { findPath } from "@prisma-next/migration-tools/migration-graph";
|
|
12
11
|
//#region src/commands/migration-log.ts
|
|
13
12
|
async function executeMigrationLogCommand(options, flags, ui) {
|
|
14
13
|
const config = await loadConfig(options.config);
|
|
15
|
-
const { configPath,
|
|
14
|
+
const { configPath, appMigrationsRelative, migrationsDir } = resolveMigrationPaths(options.config, config);
|
|
16
15
|
const dbConnection = options.db ?? config.db?.connection;
|
|
17
16
|
if (!dbConnection) return notOk(errorDatabaseConnectionRequired({
|
|
18
17
|
why: `Database connection is required for migration log (set db.connection in ${configPath}, or pass --db <url>)`,
|
|
@@ -42,14 +41,10 @@ async function executeMigrationLogCommand(options, flags, ui) {
|
|
|
42
41
|
});
|
|
43
42
|
ui.stderr(header);
|
|
44
43
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
} catch (error) {
|
|
50
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
51
|
-
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}` }));
|
|
52
|
-
}
|
|
44
|
+
const loaded = await buildReadAggregate(config, { migrationsDir });
|
|
45
|
+
if (!loaded.ok) return loaded;
|
|
46
|
+
const graph = loaded.value.aggregate.app.graph();
|
|
47
|
+
const bundles = loaded.value.aggregate.app.packages;
|
|
53
48
|
const client = createControlClient({
|
|
54
49
|
family: config.family,
|
|
55
50
|
target: config.target,
|
|
@@ -138,6 +133,6 @@ function createMigrationLogCommand() {
|
|
|
138
133
|
return command;
|
|
139
134
|
}
|
|
140
135
|
//#endregion
|
|
141
|
-
export { createMigrationLogCommand };
|
|
136
|
+
export { createMigrationLogCommand, executeMigrationLogCommand };
|
|
142
137
|
|
|
143
138
|
//# sourceMappingURL=migration-log.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-log.mjs","names":[],"sources":["../../src/commands/migration-log.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findPath } from '@prisma-next/migration-tools/migration-graph';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { cyan, dim } from 'colorette';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n CliStructuredError,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n maskConnectionUrl,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n targetSupportsMigrations,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationLogOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n}\n\nexport interface MigrationLogEntry {\n readonly dirName: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly operationCount: number;\n readonly createdAt: string;\n}\n\nexport interface MigrationLogResult {\n readonly ok: true;\n readonly markerHash: string | null;\n readonly applied: readonly MigrationLogEntry[];\n readonly summary: string;\n}\n\nasync function executeMigrationLogCommand(\n options: MigrationLogOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationLogResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for migration log (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migration log',\n }),\n );\n }\n if (!config.driver) {\n return notOk(errorDriverRequired({ why: 'Config.driver is required for migration log' }));\n }\n if (!targetSupportsMigrations(config.target)) {\n return notOk(errorUnexpected('Target does not support migrations'));\n }\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration log',\n description: 'Show executed migration history',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ...(typeof dbConnection === 'string'\n ? [{ label: 'database', value: maskConnectionUrl(dbConnection) }]\n : []),\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n ({ bundles, graph } = await loadMigrationPackages(appMigrationsDir));\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n try {\n await client.connect(dbConnection);\n const marker = await client.readMarker();\n const markerHash = marker?.storageHash ?? null;\n\n if (!markerHash) {\n return ok({\n ok: true,\n markerHash: null,\n applied: [],\n summary: 'No migrations applied (database has no marker)',\n });\n }\n\n const appliedPath = findPath(graph, EMPTY_CONTRACT_HASH, markerHash);\n if (appliedPath === null) {\n return notOk(\n errorUnexpected('Database marker is not reachable from migration history', {\n why: `Marker hash ${markerHash} is not reachable from the root of the on-disk migration graph.`,\n fix: 'The database may have been migrated outside this project. Use `migration status` to inspect the current state.',\n }),\n );\n }\n const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));\n const entries: MigrationLogEntry[] = appliedPath.map((edge) => {\n const pkg = pkgByDirName.get(edge.dirName);\n const ops = (pkg?.ops ?? []) as readonly MigrationPlanOperation[];\n return {\n dirName: edge.dirName,\n from: edge.from,\n to: edge.to,\n migrationHash: edge.migrationHash,\n operationCount: ops.length,\n createdAt: edge.createdAt,\n };\n });\n\n return ok({\n ok: true,\n markerHash,\n applied: entries,\n summary: `${entries.length} migration(s) applied`,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) return notOk(error);\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migration log: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrationLogCommand(): Command {\n const command = new Command('log');\n setCommandDescriptions(\n command,\n 'Show executed migration history',\n 'Reads the database marker and displays the applied migration chain\\n' +\n 'from the initial state to the current marker position.',\n );\n setCommandExamples(command, [\n 'prisma-next migration log --db $DATABASE_URL',\n 'prisma-next migration log --json --db $DATABASE_URL',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationLogOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationLogCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (logResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(logResult, null, 2));\n } else if (!flags.quiet) {\n const c = (fn: (s: string) => string, s: string) => (flags.color !== false ? fn(s) : s);\n if (logResult.applied.length === 0) {\n ui.log(logResult.summary);\n } else {\n for (const entry of logResult.applied) {\n ui.log(\n `${c(cyan, '✓')} ${entry.dirName} ${c(dim, entry.migrationHash.slice(0, 16) + '…')} ${entry.operationCount} op(s)`,\n );\n }\n ui.log(`\\n${logResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-log.mjs","names":[],"sources":["../../src/commands/migration-log.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findPath } from '@prisma-next/migration-tools/migration-graph';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { cyan, dim } from 'colorette';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n CliStructuredError,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n maskConnectionUrl,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n targetSupportsMigrations,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationLogOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n}\n\nexport interface MigrationLogEntry {\n readonly dirName: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly operationCount: number;\n readonly createdAt: string;\n}\n\nexport interface MigrationLogResult {\n readonly ok: true;\n readonly markerHash: string | null;\n readonly applied: readonly MigrationLogEntry[];\n readonly summary: string;\n}\n\nexport async function executeMigrationLogCommand(\n options: MigrationLogOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationLogResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsRelative, migrationsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for migration log (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migration log',\n }),\n );\n }\n if (!config.driver) {\n return notOk(errorDriverRequired({ why: 'Config.driver is required for migration log' }));\n }\n if (!targetSupportsMigrations(config.target)) {\n return notOk(errorUnexpected('Target does not support migrations'));\n }\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration log',\n description: 'Show executed migration history',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ...(typeof dbConnection === 'string'\n ? [{ label: 'database', value: maskConnectionUrl(dbConnection) }]\n : []),\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return loaded;\n }\n const graph = loaded.value.aggregate.app.graph();\n const bundles = loaded.value.aggregate.app.packages;\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n try {\n await client.connect(dbConnection);\n const marker = await client.readMarker();\n const markerHash = marker?.storageHash ?? null;\n\n if (!markerHash) {\n return ok({\n ok: true,\n markerHash: null,\n applied: [],\n summary: 'No migrations applied (database has no marker)',\n });\n }\n\n const appliedPath = findPath(graph, EMPTY_CONTRACT_HASH, markerHash);\n if (appliedPath === null) {\n return notOk(\n errorUnexpected('Database marker is not reachable from migration history', {\n why: `Marker hash ${markerHash} is not reachable from the root of the on-disk migration graph.`,\n fix: 'The database may have been migrated outside this project. Use `migration status` to inspect the current state.',\n }),\n );\n }\n const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));\n const entries: MigrationLogEntry[] = appliedPath.map((edge) => {\n const pkg = pkgByDirName.get(edge.dirName);\n const ops = (pkg?.ops ?? []) as readonly MigrationPlanOperation[];\n return {\n dirName: edge.dirName,\n from: edge.from,\n to: edge.to,\n migrationHash: edge.migrationHash,\n operationCount: ops.length,\n createdAt: edge.createdAt,\n };\n });\n\n return ok({\n ok: true,\n markerHash,\n applied: entries,\n summary: `${entries.length} migration(s) applied`,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) return notOk(error);\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migration log: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrationLogCommand(): Command {\n const command = new Command('log');\n setCommandDescriptions(\n command,\n 'Show executed migration history',\n 'Reads the database marker and displays the applied migration chain\\n' +\n 'from the initial state to the current marker position.',\n );\n setCommandExamples(command, [\n 'prisma-next migration log --db $DATABASE_URL',\n 'prisma-next migration log --json --db $DATABASE_URL',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationLogOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationLogCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (logResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(logResult, null, 2));\n } else if (!flags.quiet) {\n const c = (fn: (s: string) => string, s: string) => (flags.color !== false ? fn(s) : s);\n if (logResult.applied.length === 0) {\n ui.log(logResult.summary);\n } else {\n for (const entry of logResult.applied) {\n ui.log(\n `${c(cyan, '✓')} ${entry.dirName} ${c(dim, entry.migrationHash.slice(0, 16) + '…')} ${entry.operationCount} op(s)`,\n );\n }\n ui.log(`\\n${logResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-new.d.mts","names":[],"sources":["../../src/commands/migration-new.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"migration-new.d.mts","names":[],"sources":["../../src/commands/migration-new.ts"],"mappings":";;;iBA2QgB,yBAAA,CAAA,GAA6B,OAAO"}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { t as assertFrameworkComponentsCompatible } from "../framework-components-
|
|
4
|
-
import {
|
|
5
|
-
import { S as formatStyledHeader, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, i as getTargetMigrations, l as resolveMigrationPaths, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-CRfjbZRz.mjs";
|
|
2
|
+
import { $ as errorTargetMigrationNotSupported, A as CliStructuredError, R as errorFileNotFound, T as formatStyledHeader, X as errorRuntime, _ as createTerminalUI, g as parseGlobalFlagsOrExit, l as setCommandDescriptions, o as resolveContractPath, r as getTargetMigrations, s as resolveMigrationPaths, t as addGlobalOptions, tt as errorUnexpected, u as setCommandExamples, y as handleResult } from "../command-helpers-Bbw1GbwL.mjs";
|
|
3
|
+
import { t as assertFrameworkComponentsCompatible } from "../framework-components-fYXjz_in.mjs";
|
|
4
|
+
import { s as refusePackageCorruptionOnAggregate } from "../contract-space-aggregate-loader-DvZwdkrr.mjs";
|
|
6
5
|
import { Command } from "commander";
|
|
7
6
|
import { getEmittedArtifactPaths } from "@prisma-next/emitter";
|
|
8
7
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
9
8
|
import { join, relative } from "pathe";
|
|
10
9
|
import { readFile } from "node:fs/promises";
|
|
11
10
|
import { APP_SPACE_ID, createControlStack } from "@prisma-next/framework-components/control";
|
|
12
|
-
import {
|
|
13
|
-
import { findLatestMigration
|
|
14
|
-
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
11
|
+
import { loadContractSpaceAggregate } from "@prisma-next/migration-tools/aggregate";
|
|
12
|
+
import { findLatestMigration } from "@prisma-next/migration-tools/migration-graph";
|
|
15
13
|
import { computeMigrationHash } from "@prisma-next/migration-tools/hash";
|
|
14
|
+
import { copyFilesWithRename, formatMigrationDirName, writeMigrationPackage } from "@prisma-next/migration-tools/io";
|
|
16
15
|
import { writeMigrationTs } from "@prisma-next/migration-tools/migration-ts";
|
|
17
16
|
//#region src/commands/migration-new.ts
|
|
18
17
|
/**
|
|
@@ -26,7 +25,7 @@ import { writeMigrationTs } from "@prisma-next/migration-tools/migration-ts";
|
|
|
26
25
|
*/
|
|
27
26
|
async function executeMigrationNewCommand(options) {
|
|
28
27
|
const config = await loadConfig(options.config);
|
|
29
|
-
const { appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);
|
|
28
|
+
const { migrationsDir, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);
|
|
30
29
|
const stack = createControlStack(config);
|
|
31
30
|
const familyInstance = config.family.create(stack);
|
|
32
31
|
const contractPathAbsolute = resolveContractPath(config);
|
|
@@ -42,7 +41,8 @@ async function executeMigrationNewCommand(options) {
|
|
|
42
41
|
}
|
|
43
42
|
let toContract;
|
|
44
43
|
try {
|
|
45
|
-
|
|
44
|
+
const parsedContract = JSON.parse(contractJsonContent);
|
|
45
|
+
toContract = familyInstance.deserializeContract(parsedContract);
|
|
46
46
|
} catch (error) {
|
|
47
47
|
return notOk(errorRuntime("Contract JSON is invalid", {
|
|
48
48
|
why: `Failed to deserialize ${contractPathAbsolute}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -54,32 +54,32 @@ async function executeMigrationNewCommand(options) {
|
|
|
54
54
|
why: `Contract at ${contractPathAbsolute} has no storageHash`,
|
|
55
55
|
fix: "Run `prisma-next contract emit` to regenerate the contract"
|
|
56
56
|
}));
|
|
57
|
+
const aggregate = await loadContractSpaceAggregate({
|
|
58
|
+
migrationsDir,
|
|
59
|
+
deserializeContract: (json) => familyInstance.deserializeContract(json),
|
|
60
|
+
appContract: toContract
|
|
61
|
+
});
|
|
62
|
+
const packageCorruptionFailure = refusePackageCorruptionOnAggregate(aggregate);
|
|
63
|
+
if (packageCorruptionFailure) return notOk(packageCorruptionFailure);
|
|
64
|
+
const packages = aggregate.app.packages;
|
|
65
|
+
const graph = aggregate.app.graph();
|
|
57
66
|
let fromHash = null;
|
|
58
67
|
let fromContractSourceDir = null;
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (latestMigration) {
|
|
74
|
-
fromHash = latestMigration.to;
|
|
75
|
-
const leafPkg = packages.find((p) => p.metadata.migrationHash === latestMigration.migrationHash);
|
|
76
|
-
if (leafPkg) fromContractSourceDir = leafPkg.dirPath;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
68
|
+
if (packages.length > 0) if (options.from) {
|
|
69
|
+
const match = packages.find((p) => p.metadata.to.startsWith(options.from));
|
|
70
|
+
if (!match) return notOk(errorRuntime("Starting contract not found", {
|
|
71
|
+
why: `No migration with to hash matching "${options.from}" exists in ${appMigrationsRelative}`,
|
|
72
|
+
fix: "Check that the --from hash matches a known migration target hash."
|
|
73
|
+
}));
|
|
74
|
+
fromHash = match.metadata.to;
|
|
75
|
+
fromContractSourceDir = match.dirPath;
|
|
76
|
+
} else {
|
|
77
|
+
const latestMigration = findLatestMigration(graph);
|
|
78
|
+
if (latestMigration) {
|
|
79
|
+
fromHash = latestMigration.to;
|
|
80
|
+
const leafPkg = packages.find((p) => p.metadata.migrationHash === latestMigration.migrationHash);
|
|
81
|
+
if (leafPkg) fromContractSourceDir = leafPkg.dirPath;
|
|
79
82
|
}
|
|
80
|
-
} catch (error) {
|
|
81
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
82
|
-
throw error;
|
|
83
83
|
}
|
|
84
84
|
if (fromHash === toStorageHash && !options.from) return notOk(errorRuntime("No changes detected", {
|
|
85
85
|
why: "The from and to contract hashes are identical — there is nothing to migrate.",
|
|
@@ -90,12 +90,6 @@ async function executeMigrationNewCommand(options) {
|
|
|
90
90
|
const baseMetadata = {
|
|
91
91
|
from: fromHash,
|
|
92
92
|
to: toStorageHash,
|
|
93
|
-
hints: {
|
|
94
|
-
used: [],
|
|
95
|
-
applied: [],
|
|
96
|
-
plannerVersion: "1.0.0"
|
|
97
|
-
},
|
|
98
|
-
labels: [],
|
|
99
93
|
providedInvariants: [],
|
|
100
94
|
createdAt: timestamp.toISOString()
|
|
101
95
|
};
|