@prisma-next/cli 0.5.0-dev.1 → 0.5.0-dev.11
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 +17 -18
- package/dist/agent-skill-mongo.md +63 -31
- package/dist/agent-skill-postgres.md +1 -1
- package/dist/cli-errors-By1iVE3z.mjs +34 -0
- package/dist/cli-errors-By1iVE3z.mjs.map +1 -0
- package/dist/{cli-errors-C0JhVj0c.d.mts → cli-errors-D2NPMaxW.d.mts} +1 -0
- package/dist/cli.mjs +126 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-TG7rbCWT.mjs → client-faKQqcix.mjs} +19 -4
- package/dist/client-faKQqcix.mjs.map +1 -0
- package/dist/commands/contract-emit.mjs +7 -2
- package/dist/commands/contract-infer.mjs +8 -2
- package/dist/commands/db-init.mjs +8 -7
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +8 -5
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +8 -7
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.mjs +8 -7
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +8 -7
- package/dist/commands/db-verify.mjs.map +1 -1
- package/dist/commands/migration-apply.d.mts +1 -1
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +15 -38
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +21 -26
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +6 -3
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +31 -36
- package/dist/commands/migration-plan.mjs.map +1 -1
- package/dist/commands/migration-ref.d.mts +6 -4
- package/dist/commands/migration-ref.d.mts.map +1 -1
- package/dist/commands/migration-ref.mjs +31 -40
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +4 -4
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +19 -26
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +5 -4
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +7 -2
- package/dist/{config-loader-_W4T21X1.mjs → config-loader-C25b63rJ.mjs} +1 -1
- package/dist/{config-loader-_W4T21X1.mjs.map → config-loader-C25b63rJ.mjs.map} +1 -1
- package/dist/config-loader.mjs +1 -1
- package/dist/contract-emit-B9wkchud.mjs +6 -0
- package/dist/{contract-emit-CNYyzJwF.mjs → contract-emit-Cf3fjDL6.mjs} +8 -8
- package/dist/{contract-emit-CNYyzJwF.mjs.map → contract-emit-Cf3fjDL6.mjs.map} +1 -1
- package/dist/{contract-emit-CQfj7xJn.mjs → contract-emit-PeB96eHy.mjs} +6 -6
- package/dist/{contract-emit-CQfj7xJn.mjs.map → contract-emit-PeB96eHy.mjs.map} +1 -1
- package/dist/{contract-enrichment-CGW6mm-E.mjs → contract-enrichment-CAOELa-H.mjs} +1 -1
- package/dist/{contract-enrichment-CGW6mm-E.mjs.map → contract-enrichment-CAOELa-H.mjs.map} +1 -1
- package/dist/{contract-infer-BP3DrGgz.mjs → contract-infer-BgnsSkGp.mjs} +4 -4
- package/dist/{contract-infer-BP3DrGgz.mjs.map → contract-infer-BgnsSkGp.mjs.map} +1 -1
- package/dist/exports/control-api.mjs +6 -4
- package/dist/exports/index.mjs +7 -2
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts +39 -0
- package/dist/exports/init-output.d.mts.map +1 -0
- package/dist/exports/init-output.mjs +3 -0
- package/dist/{extract-operation-statements-DZUJNmL3.mjs → extract-operation-statements-DsFfxXVZ.mjs} +2 -2
- package/dist/{extract-operation-statements-DZUJNmL3.mjs.map → extract-operation-statements-DsFfxXVZ.mjs.map} +1 -1
- package/dist/{extract-sql-ddl-DDMX-9mz.mjs → extract-sql-ddl-D9UbZDyz.mjs} +1 -1
- package/dist/{extract-sql-ddl-DDMX-9mz.mjs.map → extract-sql-ddl-D9UbZDyz.mjs.map} +1 -1
- package/dist/{framework-components-DfZKQBQ2.mjs → framework-components-C6el-5x_.mjs} +2 -2
- package/dist/{framework-components-DfZKQBQ2.mjs.map → framework-components-C6el-5x_.mjs.map} +1 -1
- package/dist/init-jf33mNQ6.mjs +2062 -0
- package/dist/init-jf33mNQ6.mjs.map +1 -0
- package/dist/{inspect-live-schema-DWzf4Q_m.mjs → inspect-live-schema-yCu0JT0I.mjs} +6 -6
- package/dist/{inspect-live-schema-DWzf4Q_m.mjs.map → inspect-live-schema-yCu0JT0I.mjs.map} +1 -1
- package/dist/migration-cli.mjs +14 -7
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-CLMD302g.mjs → migration-command-scaffold-B8HAEGhQ.mjs} +6 -6
- package/dist/{migration-command-scaffold-CLMD302g.mjs.map → migration-command-scaffold-B8HAEGhQ.mjs.map} +1 -1
- package/dist/{migration-status-B0HLF7So.mjs → migration-status-8QUxCJHE.mjs} +19 -33
- package/dist/migration-status-8QUxCJHE.mjs.map +1 -0
- package/dist/{migrations-B0dOQlk0.mjs → migrations-CKRMAKka.mjs} +3 -3
- package/dist/migrations-CKRMAKka.mjs.map +1 -0
- package/dist/output-BpcQrnnq.mjs +103 -0
- package/dist/output-BpcQrnnq.mjs.map +1 -0
- package/dist/{progress-adapter-B-YvmcDu.mjs → progress-adapter-DvQWB1nK.mjs} +1 -1
- package/dist/{progress-adapter-B-YvmcDu.mjs.map → progress-adapter-DvQWB1nK.mjs.map} +1 -1
- package/dist/quick-reference-mongo.md +34 -13
- package/dist/quick-reference-postgres.md +11 -9
- package/dist/{result-handler-CIyu0Pdt.mjs → result-handler-CuhZ3kNu.mjs} +10 -91
- package/dist/result-handler-CuhZ3kNu.mjs.map +1 -0
- package/dist/{terminal-ui-C5k88MmW.mjs → terminal-ui-C3ZLwQxK.mjs} +76 -2
- package/dist/terminal-ui-C3ZLwQxK.mjs.map +1 -0
- package/dist/{validate-contract-deps-esa-VQ0h.mjs → validate-contract-deps-B_Cs29TL.mjs} +1 -1
- package/dist/{validate-contract-deps-esa-VQ0h.mjs.map → validate-contract-deps-B_Cs29TL.mjs.map} +1 -1
- package/dist/{verify-BxiVp50b.mjs → verify-Bkycc-Tf.mjs} +2 -2
- package/dist/{verify-BxiVp50b.mjs.map → verify-Bkycc-Tf.mjs.map} +1 -1
- package/package.json +20 -15
- package/src/commands/init/detect-pnpm-catalog.ts +141 -0
- package/src/commands/init/errors.ts +254 -0
- package/src/commands/init/exit-codes.ts +62 -0
- package/src/commands/init/hygiene-gitattributes.ts +97 -0
- package/src/commands/init/hygiene-gitignore.ts +48 -0
- package/src/commands/init/hygiene-package-scripts.ts +91 -0
- package/src/commands/init/index.ts +112 -7
- package/src/commands/init/init.ts +766 -144
- package/src/commands/init/inputs.ts +421 -0
- package/src/commands/init/output.ts +147 -0
- package/src/commands/init/probe-db.ts +308 -0
- package/src/commands/init/reinit-cleanup.ts +83 -0
- package/src/commands/init/templates/agent-skill-mongo.md +63 -31
- package/src/commands/init/templates/agent-skill-postgres.md +1 -1
- package/src/commands/init/templates/agent-skill.ts +25 -3
- package/src/commands/init/templates/code-templates.ts +125 -32
- package/src/commands/init/templates/env.ts +80 -0
- package/src/commands/init/templates/quick-reference-mongo.md +34 -13
- package/src/commands/init/templates/quick-reference-postgres.md +11 -9
- package/src/commands/init/templates/quick-reference.ts +42 -3
- package/src/commands/init/templates/tsconfig.ts +167 -5
- package/src/commands/migration-apply.ts +15 -50
- package/src/commands/migration-new.ts +23 -28
- package/src/commands/migration-plan.ts +53 -42
- package/src/commands/migration-ref.ts +40 -54
- package/src/commands/migration-show.ts +27 -28
- package/src/commands/migration-status.ts +33 -50
- package/src/control-api/operations/migration-apply.ts +15 -0
- package/src/exports/init-output.ts +10 -0
- package/src/migration-cli.ts +16 -9
- package/src/utils/cli-errors.ts +45 -1
- package/src/utils/command-helpers.ts +13 -26
- package/src/utils/formatters/graph-migration-mapper.ts +2 -2
- package/src/utils/formatters/migrations.ts +2 -2
- package/dist/cli-errors-DHq6GQGu.mjs +0 -5
- package/dist/client-TG7rbCWT.mjs.map +0 -1
- package/dist/contract-emit-fhNwwhkQ.mjs +0 -4
- package/dist/init-CQfo_4Ro.mjs +0 -430
- package/dist/init-CQfo_4Ro.mjs.map +0 -1
- package/dist/migration-status-B0HLF7So.mjs.map +0 -1
- package/dist/migrations-B0dOQlk0.mjs.map +0 -1
- package/dist/result-handler-CIyu0Pdt.mjs.map +0 -1
- package/dist/terminal-ui-C5k88MmW.mjs.map +0 -1
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';
|
|
2
|
-
import {
|
|
2
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
3
3
|
import { readMigrationPackage, readMigrationsDir } from '@prisma-next/migration-tools/io';
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
findLatestMigration,
|
|
6
|
+
reconstructGraph,
|
|
7
|
+
} from '@prisma-next/migration-tools/migration-graph';
|
|
8
|
+
import type { MigrationPackage } from '@prisma-next/migration-tools/package';
|
|
6
9
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
7
10
|
import { Command } from 'commander';
|
|
8
11
|
import { relative, resolve } from 'pathe';
|
|
9
12
|
import { loadConfig } from '../config-loader';
|
|
10
13
|
import { extractOperationStatements } from '../control-api/operations/extract-operation-statements';
|
|
11
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
type CliStructuredError,
|
|
16
|
+
errorRuntime,
|
|
17
|
+
errorUnexpected,
|
|
18
|
+
mapMigrationToolsError,
|
|
19
|
+
} from '../utils/cli-errors';
|
|
12
20
|
import {
|
|
13
21
|
addGlobalOptions,
|
|
14
22
|
setCommandDescriptions,
|
|
@@ -31,7 +39,7 @@ export interface MigrationShowResult {
|
|
|
31
39
|
readonly dirPath: string;
|
|
32
40
|
readonly from: string;
|
|
33
41
|
readonly to: string;
|
|
34
|
-
readonly
|
|
42
|
+
readonly migrationHash: string;
|
|
35
43
|
readonly kind: string;
|
|
36
44
|
readonly createdAt: string;
|
|
37
45
|
readonly operations: readonly {
|
|
@@ -48,11 +56,11 @@ function looksLikePath(target: string): boolean {
|
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
export function resolveByHashPrefix(
|
|
51
|
-
packages: readonly
|
|
59
|
+
packages: readonly MigrationPackage[],
|
|
52
60
|
prefix: string,
|
|
53
|
-
): Result<
|
|
61
|
+
): Result<MigrationPackage, CliStructuredError> {
|
|
54
62
|
const normalizedPrefix = prefix.startsWith('sha256:') ? prefix : `sha256:${prefix}`;
|
|
55
|
-
const matches = packages.filter((p) => p.
|
|
63
|
+
const matches = packages.filter((p) => p.metadata.migrationHash.startsWith(normalizedPrefix));
|
|
56
64
|
|
|
57
65
|
if (matches.length === 1) {
|
|
58
66
|
return ok(matches[0]!);
|
|
@@ -61,13 +69,13 @@ export function resolveByHashPrefix(
|
|
|
61
69
|
if (matches.length === 0) {
|
|
62
70
|
return notOk(
|
|
63
71
|
errorRuntime('No migration found matching prefix', {
|
|
64
|
-
why: `No migration has a
|
|
72
|
+
why: `No migration has a migrationHash starting with "${normalizedPrefix}"`,
|
|
65
73
|
fix: 'Run `prisma-next migration show` (no argument) to see the latest migration, or check the migrations directory for available packages.',
|
|
66
74
|
}),
|
|
67
75
|
);
|
|
68
76
|
}
|
|
69
77
|
|
|
70
|
-
const candidates = matches.map((p) => ` ${p.dirName} ${p.
|
|
78
|
+
const candidates = matches.map((p) => ` ${p.dirName} ${p.metadata.migrationHash}`).join('\n');
|
|
71
79
|
return notOk(
|
|
72
80
|
errorRuntime('Ambiguous hash prefix', {
|
|
73
81
|
why: `Multiple migrations match prefix "${normalizedPrefix}":\n${candidates}`,
|
|
@@ -110,7 +118,7 @@ async function executeMigrationShowCommand(
|
|
|
110
118
|
ui.stderr(header);
|
|
111
119
|
}
|
|
112
120
|
|
|
113
|
-
let pkg:
|
|
121
|
+
let pkg: MigrationPackage;
|
|
114
122
|
|
|
115
123
|
try {
|
|
116
124
|
if (target && looksLikePath(target)) {
|
|
@@ -142,7 +150,7 @@ async function executeMigrationShowCommand(
|
|
|
142
150
|
);
|
|
143
151
|
}
|
|
144
152
|
const leafPkg = allPackages.find(
|
|
145
|
-
(p) => p.
|
|
153
|
+
(p) => p.metadata.migrationHash === latestMigration.migrationHash,
|
|
146
154
|
);
|
|
147
155
|
if (!leafPkg) {
|
|
148
156
|
return notOk(
|
|
@@ -157,13 +165,7 @@ async function executeMigrationShowCommand(
|
|
|
157
165
|
}
|
|
158
166
|
} catch (error) {
|
|
159
167
|
if (MigrationToolsError.is(error)) {
|
|
160
|
-
return notOk(
|
|
161
|
-
errorRuntime(error.message, {
|
|
162
|
-
why: error.why,
|
|
163
|
-
fix: error.fix,
|
|
164
|
-
meta: { code: error.code, ...(error.details ?? {}) },
|
|
165
|
-
}),
|
|
166
|
-
);
|
|
168
|
+
return notOk(mapMigrationToolsError(error));
|
|
167
169
|
}
|
|
168
170
|
return notOk(
|
|
169
171
|
errorUnexpected(error instanceof Error ? error.message : String(error), {
|
|
@@ -179,11 +181,11 @@ async function executeMigrationShowCommand(
|
|
|
179
181
|
ok: true,
|
|
180
182
|
dirName: pkg.dirName,
|
|
181
183
|
dirPath: relative(process.cwd(), pkg.dirPath),
|
|
182
|
-
from: pkg.
|
|
183
|
-
to: pkg.
|
|
184
|
-
|
|
185
|
-
kind: pkg.
|
|
186
|
-
createdAt: pkg.
|
|
184
|
+
from: pkg.metadata.from,
|
|
185
|
+
to: pkg.metadata.to,
|
|
186
|
+
migrationHash: pkg.metadata.migrationHash,
|
|
187
|
+
kind: pkg.metadata.kind,
|
|
188
|
+
createdAt: pkg.metadata.createdAt,
|
|
187
189
|
operations: ops.map((op) => ({
|
|
188
190
|
id: op.id,
|
|
189
191
|
label: op.label,
|
|
@@ -209,10 +211,7 @@ export function createMigrationShowCommand(): Command {
|
|
|
209
211
|
'prisma-next migration show sha256:a1b2c3',
|
|
210
212
|
]);
|
|
211
213
|
addGlobalOptions(command)
|
|
212
|
-
.argument(
|
|
213
|
-
'[target]',
|
|
214
|
-
'Migration directory path or migrationId hash prefix (defaults to latest)',
|
|
215
|
-
)
|
|
214
|
+
.argument('[target]', 'Migration directory path or migrationHash prefix (defaults to latest)')
|
|
216
215
|
.option('--config <path>', 'Path to prisma-next.config.ts')
|
|
217
216
|
.action(async (target: string | undefined, options: MigrationShowOptions) => {
|
|
218
217
|
const flags = parseGlobalFlags(options);
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';
|
|
2
2
|
import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
3
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
4
|
+
import type { MigrationEdge, MigrationGraph } from '@prisma-next/migration-tools/graph';
|
|
3
5
|
import {
|
|
4
6
|
findPath,
|
|
5
7
|
findPathWithDecision,
|
|
6
8
|
findReachableLeaves,
|
|
7
|
-
} from '@prisma-next/migration-tools/
|
|
9
|
+
} from '@prisma-next/migration-tools/migration-graph';
|
|
10
|
+
import type { MigrationPackage } from '@prisma-next/migration-tools/package';
|
|
8
11
|
import type { Refs } from '@prisma-next/migration-tools/refs';
|
|
9
12
|
import { readRefs, resolveRef } from '@prisma-next/migration-tools/refs';
|
|
10
|
-
import type {
|
|
11
|
-
MigrationBundle,
|
|
12
|
-
MigrationChainEntry,
|
|
13
|
-
MigrationGraph,
|
|
14
|
-
} from '@prisma-next/migration-tools/types';
|
|
15
|
-
import { MigrationToolsError } from '@prisma-next/migration-tools/types';
|
|
16
13
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
17
14
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
18
15
|
import { cyan, dim, magenta, yellow } from 'colorette';
|
|
@@ -20,10 +17,15 @@ import { Command } from 'commander';
|
|
|
20
17
|
|
|
21
18
|
import { loadConfig } from '../config-loader';
|
|
22
19
|
import { createControlClient } from '../control-api/client';
|
|
23
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
type CliStructuredError,
|
|
22
|
+
errorRuntime,
|
|
23
|
+
errorUnexpected,
|
|
24
|
+
mapMigrationToolsError,
|
|
25
|
+
} from '../utils/cli-errors';
|
|
24
26
|
import {
|
|
25
27
|
addGlobalOptions,
|
|
26
|
-
|
|
28
|
+
loadMigrationPackages,
|
|
27
29
|
maskConnectionUrl,
|
|
28
30
|
readContractEnvelope,
|
|
29
31
|
resolveMigrationPaths,
|
|
@@ -61,7 +63,7 @@ export interface MigrationStatusEntry {
|
|
|
61
63
|
readonly dirName: string;
|
|
62
64
|
readonly from: string;
|
|
63
65
|
readonly to: string;
|
|
64
|
-
readonly
|
|
66
|
+
readonly migrationHash: string;
|
|
65
67
|
readonly operationCount: number;
|
|
66
68
|
readonly operationSummary: string;
|
|
67
69
|
readonly hasDestructive: boolean;
|
|
@@ -86,7 +88,7 @@ export interface MigrationStatusResult {
|
|
|
86
88
|
readonly refName?: string;
|
|
87
89
|
readonly selectedPath: readonly {
|
|
88
90
|
readonly dirName: string;
|
|
89
|
-
readonly
|
|
91
|
+
readonly migrationHash: string;
|
|
90
92
|
readonly from: string;
|
|
91
93
|
readonly to: string;
|
|
92
94
|
}[];
|
|
@@ -94,7 +96,7 @@ export interface MigrationStatusResult {
|
|
|
94
96
|
readonly summary: string;
|
|
95
97
|
readonly diagnostics: readonly StatusDiagnostic[];
|
|
96
98
|
readonly graph?: MigrationGraph;
|
|
97
|
-
readonly bundles?: readonly
|
|
99
|
+
readonly bundles?: readonly MigrationPackage[];
|
|
98
100
|
readonly edgeStatuses?: readonly EdgeStatus[];
|
|
99
101
|
readonly activeRefHash?: string;
|
|
100
102
|
readonly activeRefName?: string;
|
|
@@ -154,7 +156,7 @@ export function deriveEdgeStatuses(
|
|
|
154
156
|
): EdgeStatus[] {
|
|
155
157
|
if (mode === 'offline') return [];
|
|
156
158
|
|
|
157
|
-
const edgeKey = (e:
|
|
159
|
+
const edgeKey = (e: MigrationEdge) => `${e.from}\0${e.to}`;
|
|
158
160
|
|
|
159
161
|
// No marker = empty DB — treat root as the marker (nothing applied, everything pending)
|
|
160
162
|
const effectiveMarker = markerHash ?? EMPTY_CONTRACT_HASH;
|
|
@@ -224,8 +226,8 @@ export function deriveEdgeStatuses(
|
|
|
224
226
|
* @param markerHash — the marker hash from the database, or undefined if no marker row / offline
|
|
225
227
|
*/
|
|
226
228
|
function buildMigrationEntries(
|
|
227
|
-
chain: readonly
|
|
228
|
-
packages: readonly
|
|
229
|
+
chain: readonly MigrationEdge[],
|
|
230
|
+
packages: readonly MigrationPackage[],
|
|
229
231
|
mode: 'online' | 'offline',
|
|
230
232
|
markerHash: string | undefined,
|
|
231
233
|
edgeStatuses?: readonly EdgeStatus[],
|
|
@@ -261,7 +263,7 @@ function buildMigrationEntries(
|
|
|
261
263
|
dirName: migration.dirName,
|
|
262
264
|
from: migration.from,
|
|
263
265
|
to: migration.to,
|
|
264
|
-
|
|
266
|
+
migrationHash: migration.migrationHash,
|
|
265
267
|
operationCount: ops.length,
|
|
266
268
|
operationSummary: summary,
|
|
267
269
|
hasDestructive,
|
|
@@ -294,7 +296,7 @@ function resolveDisplayChain(
|
|
|
294
296
|
graph: MigrationGraph,
|
|
295
297
|
targetHash: string,
|
|
296
298
|
markerHash: string | undefined,
|
|
297
|
-
): readonly
|
|
299
|
+
): readonly MigrationEdge[] | null {
|
|
298
300
|
if (markerHash === undefined) {
|
|
299
301
|
return findPath(graph, EMPTY_CONTRACT_HASH, targetHash);
|
|
300
302
|
}
|
|
@@ -345,7 +347,7 @@ async function executeMigrationStatusCommand(
|
|
|
345
347
|
ui: TerminalUI,
|
|
346
348
|
): Promise<Result<MigrationStatusResult, CliStructuredError>> {
|
|
347
349
|
const config = await loadConfig(options.config);
|
|
348
|
-
const { configPath, migrationsDir, migrationsRelative,
|
|
350
|
+
const { configPath, migrationsDir, migrationsRelative, refsDir } = resolveMigrationPaths(
|
|
349
351
|
options.config,
|
|
350
352
|
config,
|
|
351
353
|
);
|
|
@@ -357,46 +359,29 @@ async function executeMigrationStatusCommand(
|
|
|
357
359
|
let activeRefHash: string | undefined;
|
|
358
360
|
let allRefs: Refs = {};
|
|
359
361
|
try {
|
|
360
|
-
allRefs = await readRefs(
|
|
362
|
+
allRefs = await readRefs(refsDir);
|
|
361
363
|
} catch (error) {
|
|
362
364
|
if (MigrationToolsError.is(error)) {
|
|
363
|
-
return notOk(
|
|
364
|
-
errorRuntime(error.message, {
|
|
365
|
-
why: error.why,
|
|
366
|
-
fix: error.fix,
|
|
367
|
-
meta: { code: error.code },
|
|
368
|
-
}),
|
|
369
|
-
);
|
|
365
|
+
return notOk(mapMigrationToolsError(error));
|
|
370
366
|
}
|
|
371
367
|
throw error;
|
|
372
368
|
}
|
|
373
369
|
|
|
374
370
|
if (options.ref) {
|
|
375
371
|
activeRefName = options.ref;
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
activeRefHash = resolveRef(allRefs, activeRefName);
|
|
382
|
-
} catch (error) {
|
|
383
|
-
if (MigrationToolsError.is(error)) {
|
|
384
|
-
return notOk(
|
|
385
|
-
errorRuntime(error.message, {
|
|
386
|
-
why: error.why,
|
|
387
|
-
fix: error.fix,
|
|
388
|
-
meta: { code: error.code },
|
|
389
|
-
}),
|
|
390
|
-
);
|
|
391
|
-
}
|
|
392
|
-
throw error;
|
|
372
|
+
try {
|
|
373
|
+
activeRefHash = resolveRef(allRefs, activeRefName).hash;
|
|
374
|
+
} catch (error) {
|
|
375
|
+
if (MigrationToolsError.is(error)) {
|
|
376
|
+
return notOk(mapMigrationToolsError(error));
|
|
393
377
|
}
|
|
378
|
+
throw error;
|
|
394
379
|
}
|
|
395
380
|
}
|
|
396
381
|
|
|
397
|
-
const statusRefs: StatusRef[] = Object.entries(allRefs).map(([name,
|
|
382
|
+
const statusRefs: StatusRef[] = Object.entries(allRefs).map(([name, entry]) => ({
|
|
398
383
|
name,
|
|
399
|
-
hash,
|
|
384
|
+
hash: entry.hash,
|
|
400
385
|
active: name === activeRefName,
|
|
401
386
|
}));
|
|
402
387
|
|
|
@@ -434,15 +419,13 @@ async function executeMigrationStatusCommand(
|
|
|
434
419
|
});
|
|
435
420
|
}
|
|
436
421
|
|
|
437
|
-
let bundles: readonly
|
|
422
|
+
let bundles: readonly MigrationPackage[];
|
|
438
423
|
let graph: MigrationGraph;
|
|
439
424
|
try {
|
|
440
|
-
({ bundles, graph } = await
|
|
425
|
+
({ bundles, graph } = await loadMigrationPackages(migrationsDir));
|
|
441
426
|
} catch (error) {
|
|
442
427
|
if (MigrationToolsError.is(error)) {
|
|
443
|
-
return notOk(
|
|
444
|
-
errorRuntime(error.message, { why: error.why, fix: error.fix, meta: { code: error.code } }),
|
|
445
|
-
);
|
|
428
|
+
return notOk(mapMigrationToolsError(error));
|
|
446
429
|
}
|
|
447
430
|
return notOk(
|
|
448
431
|
errorUnexpected(error instanceof Error ? error.message : String(error), {
|
|
@@ -30,6 +30,21 @@ export interface ExecuteMigrationApplyOptions<TFamilyId extends string, TTargetI
|
|
|
30
30
|
readonly onProgress?: OnControlProgress;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Apply a sequence of migration packages against the configured driver.
|
|
35
|
+
*
|
|
36
|
+
* Validates the path's continuity (origin → ... → destination, no gaps),
|
|
37
|
+
* then drives the family/target's migration runner over each package's
|
|
38
|
+
* operations in order, surfacing per-migration progress through `onProgress`.
|
|
39
|
+
*
|
|
40
|
+
* The `pendingMigrations` parameter is trusted input. Callers are responsible
|
|
41
|
+
* for upstream verification of the originating migration packages — typically
|
|
42
|
+
* by loading them via `readMigrationPackage` from
|
|
43
|
+
* `@prisma-next/migration-tools/io`, which performs hash-integrity checks at
|
|
44
|
+
* the load boundary. This operation does not re-verify the packages and
|
|
45
|
+
* assumes the `(metadata, ops)` pairs on disk have not been tampered with
|
|
46
|
+
* since emit.
|
|
47
|
+
*/
|
|
33
48
|
export async function executeMigrationApply<TFamilyId extends string, TTargetId extends string>(
|
|
34
49
|
options: ExecuteMigrationApplyOptions<TFamilyId, TTargetId>,
|
|
35
50
|
): Promise<MigrationApplyResult> {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public re-export of the `init --json` success-document schema (FR1.5).
|
|
3
|
+
*
|
|
4
|
+
* Imported as `@prisma-next/cli/init-output`. The shared error envelope is
|
|
5
|
+
* exported separately from `@prisma-next/errors`; consumers should branch
|
|
6
|
+
* on the `ok` discriminator (success documents carry `ok: true`, error
|
|
7
|
+
* envelopes carry `ok: false`) per the
|
|
8
|
+
* [Style Guide § JSON Semantics](../../../../../../../docs/CLI%20Style%20Guide.md#json-semantics).
|
|
9
|
+
*/
|
|
10
|
+
export { type InitOutput, InitOutputSchema } from '../commands/init/output';
|
package/src/migration-cli.ts
CHANGED
|
@@ -41,13 +41,13 @@ import { fileURLToPath } from 'node:url';
|
|
|
41
41
|
import { CliStructuredError, errorMigrationCliInvalidConfigArg } from '@prisma-next/errors/control';
|
|
42
42
|
import { errorMigrationTargetMismatch } from '@prisma-next/errors/migration';
|
|
43
43
|
import { createControlStack } from '@prisma-next/framework-components/control';
|
|
44
|
+
import type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';
|
|
44
45
|
import {
|
|
45
46
|
buildMigrationArtifacts,
|
|
46
47
|
isDirectEntrypoint,
|
|
47
48
|
type Migration,
|
|
48
49
|
printMigrationHelp,
|
|
49
50
|
} from '@prisma-next/migration-tools/migration';
|
|
50
|
-
import type { MigrationManifest } from '@prisma-next/migration-tools/types';
|
|
51
51
|
import { dirname, join } from 'pathe';
|
|
52
52
|
import { loadConfig } from './config-loader';
|
|
53
53
|
|
|
@@ -202,16 +202,23 @@ export class MigrationCLI {
|
|
|
202
202
|
* `buildMigrationArtifacts` so the pure builder can preserve fields owned
|
|
203
203
|
* by `migration plan` (contract bookends, hints, labels, `createdAt`)
|
|
204
204
|
* across re-emits.
|
|
205
|
+
*
|
|
206
|
+
* Author-time path: this loader is non-verifying by design. Hash mismatch
|
|
207
|
+
* is the *expected* outcome of a re-author (the developer's source
|
|
208
|
+
* changes invalidate the prior hash by construction), and verification
|
|
209
|
+
* here would block legitimate regenerations. Apply-time consumers always
|
|
210
|
+
* route through the verifying `readMigrationPackage` in
|
|
211
|
+
* `@prisma-next/migration-tools/io` instead.
|
|
205
212
|
*/
|
|
206
|
-
function
|
|
213
|
+
function readExistingMetadata(metadataPath: string): Partial<MigrationMetadata> | null {
|
|
207
214
|
let raw: string;
|
|
208
215
|
try {
|
|
209
|
-
raw = readFileSync(
|
|
216
|
+
raw = readFileSync(metadataPath, 'utf-8');
|
|
210
217
|
} catch {
|
|
211
218
|
return null;
|
|
212
219
|
}
|
|
213
220
|
try {
|
|
214
|
-
return JSON.parse(raw) as Partial<
|
|
221
|
+
return JSON.parse(raw) as Partial<MigrationMetadata>;
|
|
215
222
|
} catch {
|
|
216
223
|
return null;
|
|
217
224
|
}
|
|
@@ -236,19 +243,19 @@ function serializeMigrationToDisk(
|
|
|
236
243
|
migrationDir: string,
|
|
237
244
|
dryRun: boolean,
|
|
238
245
|
): void {
|
|
239
|
-
const
|
|
240
|
-
const existing =
|
|
241
|
-
const { opsJson,
|
|
246
|
+
const metadataPath = join(migrationDir, 'migration.json');
|
|
247
|
+
const existing = readExistingMetadata(metadataPath);
|
|
248
|
+
const { opsJson, metadataJson } = buildMigrationArtifacts(instance, existing);
|
|
242
249
|
|
|
243
250
|
if (dryRun) {
|
|
244
|
-
process.stdout.write(`--- migration.json ---\n${
|
|
251
|
+
process.stdout.write(`--- migration.json ---\n${metadataJson}\n`);
|
|
245
252
|
process.stdout.write('--- ops.json ---\n');
|
|
246
253
|
process.stdout.write(`${opsJson}\n`);
|
|
247
254
|
return;
|
|
248
255
|
}
|
|
249
256
|
|
|
250
257
|
writeFileSync(join(migrationDir, 'ops.json'), opsJson);
|
|
251
|
-
writeFileSync(
|
|
258
|
+
writeFileSync(metadataPath, metadataJson);
|
|
252
259
|
|
|
253
260
|
process.stdout.write(`Wrote ops.json + migration.json to ${migrationDir}\n`);
|
|
254
261
|
}
|
package/src/utils/cli-errors.ts
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* CLI-specific errors (e.g., Commander.js argument validation) can be added here if needed.
|
|
4
4
|
*/
|
|
5
5
|
export type { CliErrorConflict, CliErrorEnvelope } from '@prisma-next/errors/control';
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
import {
|
|
7
8
|
CliStructuredError,
|
|
8
9
|
errorConfigFileNotFound,
|
|
9
10
|
errorConfigValidation,
|
|
@@ -20,6 +21,26 @@ export {
|
|
|
20
21
|
errorTargetMigrationNotSupported,
|
|
21
22
|
errorUnexpected,
|
|
22
23
|
} from '@prisma-next/errors/control';
|
|
24
|
+
import { errorRuntime } from '@prisma-next/errors/execution';
|
|
25
|
+
import type { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
CliStructuredError,
|
|
29
|
+
errorConfigFileNotFound,
|
|
30
|
+
errorConfigValidation,
|
|
31
|
+
errorContractConfigMissing,
|
|
32
|
+
errorContractMissingExtensionPacks,
|
|
33
|
+
errorContractValidationFailed,
|
|
34
|
+
errorDatabaseConnectionRequired,
|
|
35
|
+
errorDriverRequired,
|
|
36
|
+
errorFamilyReadMarkerSqlRequired,
|
|
37
|
+
errorFileNotFound,
|
|
38
|
+
errorMigrationCliInvalidConfigArg,
|
|
39
|
+
errorMigrationPlanningFailed,
|
|
40
|
+
errorQueryRunnerFactoryRequired,
|
|
41
|
+
errorTargetMigrationNotSupported,
|
|
42
|
+
errorUnexpected,
|
|
43
|
+
};
|
|
23
44
|
export {
|
|
24
45
|
ERROR_CODE_DESTRUCTIVE_CHANGES,
|
|
25
46
|
errorDestructiveChanges,
|
|
@@ -38,3 +59,26 @@ export {
|
|
|
38
59
|
errorUnfilledPlaceholder,
|
|
39
60
|
placeholder,
|
|
40
61
|
} from '@prisma-next/errors/migration';
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Maps a `MigrationToolsError` raised by the migration-tools loader/graph
|
|
65
|
+
* surface (`readMigrationPackage`, `readMigrationsDir`, `readRefs`,
|
|
66
|
+
* `resolveRef`, `reconstructGraph`, ...) into a CLI `errorRuntime` envelope.
|
|
67
|
+
*
|
|
68
|
+
* The full `error.details` payload is forwarded into `meta` so machine
|
|
69
|
+
* consumers (`--json`) see structural fields like `dir`, `storedHash`,
|
|
70
|
+
* `computedHash` (for `MIGRATION.HASH_MISMATCH`) alongside the stable
|
|
71
|
+
* `code`. The user-visible `summary`/`why`/`fix` text is unchanged.
|
|
72
|
+
*
|
|
73
|
+
* Callers are expected to gate on `MigrationToolsError.is(error)` first
|
|
74
|
+
* (mirroring the original inline pattern); non-`MigrationToolsError`
|
|
75
|
+
* values are caller-classified (rethrow, wrap with command-specific
|
|
76
|
+
* `errorUnexpected`, etc.).
|
|
77
|
+
*/
|
|
78
|
+
export function mapMigrationToolsError(error: MigrationToolsError): CliStructuredError {
|
|
79
|
+
return errorRuntime(error.message, {
|
|
80
|
+
why: error.why,
|
|
81
|
+
fix: error.fix,
|
|
82
|
+
meta: { code: error.code, ...(error.details ?? {}) },
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import type { ControlTargetDescriptor } from '@prisma-next/framework-components/control';
|
|
3
3
|
import { hasMigrations } from '@prisma-next/framework-components/control';
|
|
4
|
-
import type {
|
|
5
|
-
import { reconstructGraph } from '@prisma-next/migration-tools/dag';
|
|
4
|
+
import type { MigrationGraph } from '@prisma-next/migration-tools/graph';
|
|
6
5
|
import { readMigrationsDir } from '@prisma-next/migration-tools/io';
|
|
7
|
-
import type {
|
|
6
|
+
import type { PathDecision } from '@prisma-next/migration-tools/migration-graph';
|
|
7
|
+
import { reconstructGraph } from '@prisma-next/migration-tools/migration-graph';
|
|
8
|
+
import type { MigrationPackage } from '@prisma-next/migration-tools/package';
|
|
8
9
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
9
10
|
import type { Command } from 'commander';
|
|
10
11
|
import { relative, resolve } from 'pathe';
|
|
@@ -85,7 +86,7 @@ export function resolveMigrationPaths(
|
|
|
85
86
|
configPath: string;
|
|
86
87
|
migrationsDir: string;
|
|
87
88
|
migrationsRelative: string;
|
|
88
|
-
|
|
89
|
+
refsDir: string;
|
|
89
90
|
} {
|
|
90
91
|
const configPath = configOption
|
|
91
92
|
? relative(process.cwd(), resolve(configOption))
|
|
@@ -95,8 +96,8 @@ export function resolveMigrationPaths(
|
|
|
95
96
|
config.migrations?.dir ?? 'migrations',
|
|
96
97
|
);
|
|
97
98
|
const migrationsRelative = relative(process.cwd(), migrationsDir);
|
|
98
|
-
const
|
|
99
|
-
return { configPath, migrationsDir, migrationsRelative,
|
|
99
|
+
const refsDir = resolve(migrationsDir, 'refs');
|
|
100
|
+
return { configPath, migrationsDir, migrationsRelative, refsDir };
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
/**
|
|
@@ -111,7 +112,7 @@ export interface PathDecisionResult {
|
|
|
111
112
|
readonly refName?: string;
|
|
112
113
|
readonly selectedPath: readonly {
|
|
113
114
|
readonly dirName: string;
|
|
114
|
-
readonly
|
|
115
|
+
readonly migrationHash: string;
|
|
115
116
|
readonly from: string;
|
|
116
117
|
readonly to: string;
|
|
117
118
|
}[];
|
|
@@ -129,7 +130,7 @@ export function toPathDecisionResult(decision: PathDecision): PathDecisionResult
|
|
|
129
130
|
...ifDefined('refName', decision.refName),
|
|
130
131
|
selectedPath: decision.selectedPath.map((entry) => ({
|
|
131
132
|
dirName: entry.dirName,
|
|
132
|
-
|
|
133
|
+
migrationHash: entry.migrationHash,
|
|
133
134
|
from: entry.from,
|
|
134
135
|
to: entry.to,
|
|
135
136
|
})),
|
|
@@ -146,13 +147,13 @@ export function getTargetMigrations(target: ControlTargetDescriptor<string, stri
|
|
|
146
147
|
|
|
147
148
|
/**
|
|
148
149
|
* Reads the migrations directory and builds the migration graph from all
|
|
149
|
-
*
|
|
150
|
+
* packages. Throws on I/O or graph errors — callers handle error mapping.
|
|
150
151
|
*
|
|
151
|
-
* Every on-disk
|
|
152
|
+
* Every on-disk package is content-addressed (`migrationHash` is always a
|
|
152
153
|
* string); there is no draft state to filter out.
|
|
153
154
|
*/
|
|
154
|
-
export async function
|
|
155
|
-
bundles: readonly
|
|
155
|
+
export async function loadMigrationPackages(migrationsDir: string): Promise<{
|
|
156
|
+
bundles: readonly MigrationPackage[];
|
|
156
157
|
graph: MigrationGraph;
|
|
157
158
|
}> {
|
|
158
159
|
const bundles = await readMigrationsDir(migrationsDir);
|
|
@@ -160,20 +161,6 @@ export async function loadMigrationBundles(migrationsDir: string): Promise<{
|
|
|
160
161
|
return { bundles, graph };
|
|
161
162
|
}
|
|
162
163
|
|
|
163
|
-
export interface MigrationBundleSet {
|
|
164
|
-
readonly bundles: readonly MigrationBundle[];
|
|
165
|
-
readonly graph: MigrationGraph;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Alias of `loadMigrationBundles` retained for naming-clarity in commands
|
|
170
|
-
* that previously needed both attested and draft splits. With the
|
|
171
|
-
* collapse of the draft state, both helpers do the same thing.
|
|
172
|
-
*/
|
|
173
|
-
export async function loadAllBundles(migrationsDir: string): Promise<MigrationBundleSet> {
|
|
174
|
-
return loadMigrationBundles(migrationsDir);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
164
|
/**
|
|
178
165
|
* The subset of the emitted contract.json that the framework layer can
|
|
179
166
|
* safely type. The emitter adds these fields on top of the family-specific
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Maps MigrationGraph + status info to the generic graph renderer types.
|
|
3
3
|
*/
|
|
4
4
|
import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import type { MigrationGraph } from '@prisma-next/migration-tools/graph';
|
|
6
|
+
import { findPath } from '@prisma-next/migration-tools/migration-graph';
|
|
7
7
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
8
8
|
|
|
9
9
|
import type { StatusRef } from '../migration-types';
|
|
@@ -183,7 +183,7 @@ interface MigrationShowResult {
|
|
|
183
183
|
readonly dirPath: string;
|
|
184
184
|
readonly from: string;
|
|
185
185
|
readonly to: string;
|
|
186
|
-
readonly
|
|
186
|
+
readonly migrationHash: string;
|
|
187
187
|
readonly kind: string;
|
|
188
188
|
readonly createdAt: string;
|
|
189
189
|
readonly operations: readonly {
|
|
@@ -211,7 +211,7 @@ export function formatMigrationShowOutput(result: MigrationShowResult, flags: Gl
|
|
|
211
211
|
lines.push(`${formatDimText(` kind: ${result.kind}`)}`);
|
|
212
212
|
lines.push(`${formatDimText(` from: ${result.from}`)}`);
|
|
213
213
|
lines.push(`${formatDimText(` to: ${result.to}`)}`);
|
|
214
|
-
lines.push(`${formatDimText(`
|
|
214
|
+
lines.push(`${formatDimText(` migrationHash: ${result.migrationHash}`)}`);
|
|
215
215
|
lines.push(`${formatDimText(` created: ${result.createdAt}`)}`);
|
|
216
216
|
|
|
217
217
|
lines.push('');
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { CliStructuredError as CliStructuredError$1, errorConfigValidation as errorConfigValidation$1, errorContractConfigMissing as errorContractConfigMissing$1, errorContractValidationFailed, errorDatabaseConnectionRequired, errorDriverRequired, errorFileNotFound, errorMigrationPlanningFailed, errorTargetMigrationNotSupported, errorUnexpected as errorUnexpected$1 } from "@prisma-next/errors/control";
|
|
2
|
-
import { ERROR_CODE_DESTRUCTIVE_CHANGES, errorDestructiveChanges, errorHashMismatch, errorMarkerMissing, errorRunnerFailed, errorRuntime as errorRuntime$1, errorTargetMismatch } from "@prisma-next/errors/execution";
|
|
3
|
-
import "@prisma-next/errors/migration";
|
|
4
|
-
|
|
5
|
-
export { errorUnexpected$1 as _, errorContractValidationFailed as a, errorDriverRequired as c, errorMarkerMissing as d, errorMigrationPlanningFailed as f, errorTargetMismatch as g, errorTargetMigrationNotSupported as h, errorContractConfigMissing$1 as i, errorFileNotFound as l, errorRuntime$1 as m, ERROR_CODE_DESTRUCTIVE_CHANGES as n, errorDatabaseConnectionRequired as o, errorRunnerFailed as p, errorConfigValidation$1 as r, errorDestructiveChanges as s, CliStructuredError$1 as t, errorHashMismatch as u };
|