@prisma-next/cli 0.5.0-dev.7 → 0.5.0-dev.71
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 +56 -21
- package/dist/cli-errors-D3_sMh2K.mjs +33 -0
- package/dist/cli-errors-D3_sMh2K.mjs.map +1 -0
- package/dist/cli-errors-QH8kf-C2.d.mts +3 -0
- package/dist/cli.mjs +16 -78
- package/dist/cli.mjs.map +1 -1
- package/dist/client-0ZX24FXF.mjs +1398 -0
- package/dist/client-0ZX24FXF.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +2 -4
- package/dist/commands/contract-infer.d.mts.map +1 -1
- package/dist/commands/contract-infer.mjs +2 -4
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +14 -13
- 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 +5 -7
- 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 +8 -9
- 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 +13 -13
- 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 -321
- package/dist/commands/migration-apply.d.mts +5 -2
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +64 -66
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.d.mts +0 -1
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +33 -40
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +14 -5
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -347
- package/dist/commands/migration-ref.d.mts +1 -1
- package/dist/commands/migration-ref.d.mts.map +1 -1
- package/dist/commands/migration-ref.mjs +7 -12
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +13 -7
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +34 -36
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +23 -5
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -4
- package/dist/{config-loader-C25b63rJ.mjs → config-loader-B6sJjXTv.mjs} +3 -5
- package/dist/config-loader-B6sJjXTv.mjs.map +1 -0
- package/dist/config-loader.d.mts +0 -1
- package/dist/config-loader.d.mts.map +1 -1
- package/dist/config-loader.mjs +2 -3
- package/dist/contract-emit-B3ChISB_.mjs +338 -0
- package/dist/contract-emit-B3ChISB_.mjs.map +1 -0
- package/dist/contract-emit-DkMqO7f2.mjs +148 -0
- package/dist/contract-emit-DkMqO7f2.mjs.map +1 -0
- package/dist/{contract-enrichment-CAOELa-H.mjs → contract-enrichment-CF6ogEJ_.mjs} +4 -6
- package/dist/contract-enrichment-CF6ogEJ_.mjs.map +1 -0
- package/dist/{contract-infer-D9cC3rJm.mjs → contract-infer-BDKAE0B0.mjs} +12 -22
- package/dist/contract-infer-BDKAE0B0.mjs.map +1 -0
- package/dist/db-verify-B4TdDKOI.mjs +403 -0
- package/dist/db-verify-B4TdDKOI.mjs.map +1 -0
- package/dist/exports/config-types.mjs +1 -2
- package/dist/exports/control-api.d.mts +287 -29
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +4 -6
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +28 -30
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts +2 -4
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +2 -3
- package/dist/{framework-components-Cr--XBKy.mjs → framework-components-gwAHl7ml.mjs} +3 -4
- package/dist/{framework-components-Cr--XBKy.mjs.map → framework-components-gwAHl7ml.mjs.map} +1 -1
- package/dist/{init-C5220SY9.mjs → init-Deo7U8_U.mjs} +26 -35
- package/dist/init-Deo7U8_U.mjs.map +1 -0
- package/dist/{inspect-live-schema-yrHAvG71.mjs → inspect-live-schema-BAgQMYpD.mjs} +10 -11
- package/dist/inspect-live-schema-BAgQMYpD.mjs.map +1 -0
- package/dist/migration-cli.d.mts +41 -12
- package/dist/migration-cli.d.mts.map +1 -1
- package/dist/migration-cli.mjs +309 -86
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-B3B09et6.mjs → migration-command-scaffold-B8J702Uh.mjs} +8 -9
- package/dist/migration-command-scaffold-B8J702Uh.mjs.map +1 -0
- package/dist/migration-plan-BcKNnTM7.mjs +530 -0
- package/dist/migration-plan-BcKNnTM7.mjs.map +1 -0
- package/dist/{migration-status-DUMiH8_G.mjs → migration-status-CjwB2of-.mjs} +117 -64
- package/dist/migration-status-CjwB2of-.mjs.map +1 -0
- package/dist/{migrations-Bo5WtTla.mjs → migrations-CIK94AJf.mjs} +43 -23
- package/dist/migrations-CIK94AJf.mjs.map +1 -0
- package/dist/{output-BpcQrnnq.mjs → output-DnjfCC_u.mjs} +9 -3
- package/dist/output-DnjfCC_u.mjs.map +1 -0
- package/dist/{progress-adapter-DvQWB1nK.mjs → progress-adapter-xASh41wr.mjs} +2 -2
- package/dist/{progress-adapter-DvQWB1nK.mjs.map → progress-adapter-xASh41wr.mjs.map} +1 -1
- package/dist/{result-handler-Ba3zWQsI.mjs → result-handler-DWb1rFS-.mjs} +52 -27
- package/dist/result-handler-DWb1rFS-.mjs.map +1 -0
- package/dist/{terminal-ui-C3ZLwQxK.mjs → terminal-ui-zaRDhJnP.mjs} +2 -6
- package/dist/{terminal-ui-C3ZLwQxK.mjs.map → terminal-ui-zaRDhJnP.mjs.map} +1 -1
- package/dist/{verify-Bkycc-Tf.mjs → verify-BEIa9638.mjs} +3 -4
- package/dist/verify-BEIa9638.mjs.map +1 -0
- package/package.json +28 -26
- package/src/cli.ts +32 -6
- package/src/commands/contract-emit.ts +67 -163
- package/src/commands/contract-infer.ts +7 -20
- package/src/commands/db-init.ts +14 -3
- package/src/commands/db-update.ts +8 -4
- package/src/commands/db-verify.ts +47 -15
- package/src/commands/init/index.ts +1 -1
- package/src/commands/init/init.ts +2 -2
- package/src/commands/init/templates/code-templates.ts +12 -4
- package/src/commands/inspect-live-schema.ts +10 -5
- package/src/commands/migration-apply.ts +92 -71
- package/src/commands/migration-new.ts +42 -45
- package/src/commands/migration-plan.ts +147 -64
- package/src/commands/migration-ref.ts +8 -7
- package/src/commands/migration-show.ts +60 -41
- package/src/commands/migration-status.ts +196 -60
- package/src/config-path-validation.ts +0 -1
- package/src/control-api/client.ts +69 -1
- package/src/control-api/contract-enrichment.ts +6 -4
- package/src/control-api/operations/contract-emit.ts +198 -115
- package/src/control-api/operations/db-apply-aggregate.ts +446 -0
- package/src/control-api/operations/db-init.ts +51 -253
- package/src/control-api/operations/db-update.ts +66 -183
- package/src/control-api/operations/db-verify.ts +342 -0
- package/src/control-api/operations/migration-apply.ts +37 -9
- package/src/control-api/types.ts +125 -7
- package/src/exports/control-api.ts +15 -3
- package/src/load-ts-contract.ts +28 -26
- package/src/migration-cli.ts +445 -122
- package/src/utils/cli-errors.ts +49 -2
- package/src/utils/combine-schema-results.ts +84 -0
- package/src/utils/command-helpers.ts +69 -25
- package/src/utils/contract-space-aggregate-loader.ts +236 -0
- package/src/utils/contract-space-extension-migrations-pass.ts +120 -0
- package/src/utils/contract-space-migrate-pass.ts +156 -0
- package/src/utils/emit-queue.ts +26 -0
- package/src/utils/formatters/graph-migration-mapper.ts +7 -3
- package/src/utils/formatters/migrations.ts +62 -26
- package/src/utils/publish-contract-artifact-pair.ts +134 -0
- package/dist/cli-errors-BFYgBH3L.d.mts +0 -4
- package/dist/cli-errors-Cd79vmTH.mjs +0 -5
- package/dist/client-CrsnY58k.mjs +0 -997
- package/dist/client-CrsnY58k.mjs.map +0 -1
- package/dist/commands/db-verify.mjs.map +0 -1
- package/dist/commands/migration-plan.mjs.map +0 -1
- package/dist/config-loader-C25b63rJ.mjs.map +0 -1
- package/dist/contract-emit--feXyNd7.mjs +0 -4
- package/dist/contract-emit-NJ01hiiv.mjs +0 -195
- package/dist/contract-emit-NJ01hiiv.mjs.map +0 -1
- package/dist/contract-emit-V5SSitUT.mjs +0 -122
- package/dist/contract-emit-V5SSitUT.mjs.map +0 -1
- package/dist/contract-enrichment-CAOELa-H.mjs.map +0 -1
- package/dist/contract-infer-D9cC3rJm.mjs.map +0 -1
- package/dist/extract-operation-statements-DsFfxXVZ.mjs +0 -13
- package/dist/extract-operation-statements-DsFfxXVZ.mjs.map +0 -1
- package/dist/extract-sql-ddl-D9UbZDyz.mjs +0 -26
- package/dist/extract-sql-ddl-D9UbZDyz.mjs.map +0 -1
- package/dist/init-C5220SY9.mjs.map +0 -1
- package/dist/inspect-live-schema-yrHAvG71.mjs.map +0 -1
- package/dist/migration-command-scaffold-B3B09et6.mjs.map +0 -1
- package/dist/migration-status-DUMiH8_G.mjs.map +0 -1
- package/dist/migrations-Bo5WtTla.mjs.map +0 -1
- package/dist/output-BpcQrnnq.mjs.map +0 -1
- package/dist/result-handler-Ba3zWQsI.mjs.map +0 -1
- package/dist/validate-contract-deps-B_Cs29TL.mjs +0 -37
- package/dist/validate-contract-deps-B_Cs29TL.mjs.map +0 -1
- package/dist/verify-Bkycc-Tf.mjs.map +0 -1
- package/src/control-api/operations/extract-operation-statements.ts +0 -14
- package/src/control-api/operations/extract-sql-ddl.ts +0 -47
|
@@ -2,24 +2,27 @@ import { readFile } from 'node:fs/promises';
|
|
|
2
2
|
import type { Contract } from '@prisma-next/contract/types';
|
|
3
3
|
import { getEmittedArtifactPaths } from '@prisma-next/emitter';
|
|
4
4
|
import {
|
|
5
|
+
APP_SPACE_ID,
|
|
5
6
|
createControlStack,
|
|
7
|
+
hasOperationPreview,
|
|
6
8
|
type MigrationPlanOperation,
|
|
9
|
+
type OperationPreview,
|
|
7
10
|
} from '@prisma-next/framework-components/control';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
12
|
+
import { computeMigrationHash } from '@prisma-next/migration-tools/hash';
|
|
13
|
+
import { deriveProvidedInvariants } from '@prisma-next/migration-tools/invariants';
|
|
11
14
|
import {
|
|
12
15
|
copyFilesWithRename,
|
|
13
16
|
formatMigrationDirName,
|
|
14
17
|
writeMigrationPackage,
|
|
15
18
|
} from '@prisma-next/migration-tools/io';
|
|
19
|
+
import type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';
|
|
20
|
+
import { findLatestMigration } from '@prisma-next/migration-tools/migration-graph';
|
|
16
21
|
import { writeMigrationTs } from '@prisma-next/migration-tools/migration-ts';
|
|
17
|
-
import { type MigrationManifest, MigrationToolsError } from '@prisma-next/migration-tools/types';
|
|
18
22
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
19
23
|
import { Command } from 'commander';
|
|
20
24
|
import { join, relative } from 'pathe';
|
|
21
25
|
import { loadConfig } from '../config-loader';
|
|
22
|
-
import { extractSqlDdl } from '../control-api/operations/extract-sql-ddl';
|
|
23
26
|
import {
|
|
24
27
|
type CliErrorConflict,
|
|
25
28
|
CliStructuredError,
|
|
@@ -29,16 +32,26 @@ import {
|
|
|
29
32
|
errorRuntime,
|
|
30
33
|
errorTargetMigrationNotSupported,
|
|
31
34
|
errorUnexpected,
|
|
35
|
+
mapMigrationToolsError,
|
|
32
36
|
} from '../utils/cli-errors';
|
|
33
37
|
import {
|
|
34
38
|
addGlobalOptions,
|
|
35
39
|
getTargetMigrations,
|
|
36
|
-
|
|
40
|
+
loadMigrationPackages,
|
|
37
41
|
resolveContractPath,
|
|
38
42
|
resolveMigrationPaths,
|
|
39
43
|
setCommandDescriptions,
|
|
40
44
|
setCommandExamples,
|
|
41
45
|
} from '../utils/command-helpers';
|
|
46
|
+
import {
|
|
47
|
+
type ExtensionMigrationsExtensionInput,
|
|
48
|
+
runContractSpaceExtensionMigrationsPass,
|
|
49
|
+
} from '../utils/contract-space-extension-migrations-pass';
|
|
50
|
+
import {
|
|
51
|
+
formatContractSpaceDriftWarning,
|
|
52
|
+
type MigrateExtensionInput,
|
|
53
|
+
runContractSpaceMigratePass,
|
|
54
|
+
} from '../utils/contract-space-migrate-pass';
|
|
42
55
|
import { formatStyledHeader } from '../utils/formatters/styled';
|
|
43
56
|
import { assertFrameworkComponentsCompatible } from '../utils/framework-components';
|
|
44
57
|
import type { CommonCommandOptions } from '../utils/global-flags';
|
|
@@ -55,7 +68,7 @@ interface MigrationPlanOptions extends CommonCommandOptions {
|
|
|
55
68
|
export interface MigrationPlanResult {
|
|
56
69
|
readonly ok: boolean;
|
|
57
70
|
readonly noOp: boolean;
|
|
58
|
-
readonly from: string;
|
|
71
|
+
readonly from: string | null;
|
|
59
72
|
readonly to: string;
|
|
60
73
|
readonly dir?: string;
|
|
61
74
|
readonly operations: readonly {
|
|
@@ -63,7 +76,12 @@ export interface MigrationPlanResult {
|
|
|
63
76
|
readonly label: string;
|
|
64
77
|
readonly operationClass: string;
|
|
65
78
|
}[];
|
|
66
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Family-agnostic textual preview of the migration plan operations.
|
|
81
|
+
* Replaces the previous `sql?: readonly string[]` field; consumers should
|
|
82
|
+
* read `result.preview?.statements`.
|
|
83
|
+
*/
|
|
84
|
+
readonly preview?: OperationPreview;
|
|
67
85
|
readonly summary: string;
|
|
68
86
|
/**
|
|
69
87
|
* When true, `migration.ts` was written but contains unfilled
|
|
@@ -76,22 +94,6 @@ export interface MigrationPlanResult {
|
|
|
76
94
|
};
|
|
77
95
|
}
|
|
78
96
|
|
|
79
|
-
function mapMigrationToolsError(error: unknown): CliStructuredError {
|
|
80
|
-
if (CliStructuredError.is(error)) {
|
|
81
|
-
return error;
|
|
82
|
-
}
|
|
83
|
-
if (MigrationToolsError.is(error)) {
|
|
84
|
-
return errorRuntime(error.message, {
|
|
85
|
-
why: error.why,
|
|
86
|
-
fix: error.fix,
|
|
87
|
-
meta: { code: error.code, ...(error.details ?? {}) },
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
return errorUnexpected(error instanceof Error ? error.message : String(error), {
|
|
91
|
-
why: `Unexpected error during migration plan: ${error instanceof Error ? error.message : String(error)}`,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
97
|
async function executeMigrationPlanCommand(
|
|
96
98
|
options: MigrationPlanOptions,
|
|
97
99
|
flags: GlobalFlags,
|
|
@@ -99,10 +101,8 @@ async function executeMigrationPlanCommand(
|
|
|
99
101
|
startTime: number,
|
|
100
102
|
): Promise<Result<MigrationPlanResult, CliStructuredError>> {
|
|
101
103
|
const config = await loadConfig(options.config);
|
|
102
|
-
const { configPath, migrationsDir,
|
|
103
|
-
options.config,
|
|
104
|
-
config,
|
|
105
|
-
);
|
|
104
|
+
const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative } =
|
|
105
|
+
resolveMigrationPaths(options.config, config);
|
|
106
106
|
|
|
107
107
|
const contractPathAbsolute = resolveContractPath(config);
|
|
108
108
|
const contractPath = relative(process.cwd(), contractPathAbsolute);
|
|
@@ -111,7 +111,7 @@ async function executeMigrationPlanCommand(
|
|
|
111
111
|
const details: Array<{ label: string; value: string }> = [
|
|
112
112
|
{ label: 'config', value: configPath },
|
|
113
113
|
{ label: 'contract', value: contractPath },
|
|
114
|
-
{ label: 'migrations', value:
|
|
114
|
+
{ label: 'migrations', value: appMigrationsRelative },
|
|
115
115
|
];
|
|
116
116
|
if (options.from) {
|
|
117
117
|
details.push({ label: 'from', value: options.from });
|
|
@@ -173,11 +173,11 @@ async function executeMigrationPlanCommand(
|
|
|
173
173
|
|
|
174
174
|
// Read existing migrations and determine "from" contract
|
|
175
175
|
let fromContract: Contract | null = null;
|
|
176
|
-
let fromHash: string =
|
|
176
|
+
let fromHash: string | null = null;
|
|
177
177
|
let fromContractSourceDir: string | null = null;
|
|
178
178
|
|
|
179
179
|
try {
|
|
180
|
-
const { bundles, graph } = await
|
|
180
|
+
const { bundles, graph } = await loadMigrationPackages(appMigrationsDir);
|
|
181
181
|
|
|
182
182
|
if (options.from) {
|
|
183
183
|
const resolved = resolveBundleByPrefix(bundles, options.from);
|
|
@@ -186,25 +186,27 @@ async function executeMigrationPlanCommand(
|
|
|
186
186
|
return notOk(
|
|
187
187
|
f.reason === 'ambiguous'
|
|
188
188
|
? errorRuntime('Multiple matching migrations found', {
|
|
189
|
-
why: `Prefix "${options.from}" matches ${f.count} migrations in ${
|
|
189
|
+
why: `Prefix "${options.from}" matches ${f.count} migrations in ${appMigrationsRelative}`,
|
|
190
190
|
fix: 'Provide a longer prefix to disambiguate, or omit --from to use the latest migration target.',
|
|
191
191
|
})
|
|
192
192
|
: errorRuntime('Starting contract not found', {
|
|
193
|
-
why: `No migration with to hash matching "${options.from}" exists in ${
|
|
193
|
+
why: `No migration with to hash matching "${options.from}" exists in ${appMigrationsRelative}`,
|
|
194
194
|
fix: 'Check that the --from hash matches a known migration target hash, or omit --from to use the latest migration target.',
|
|
195
195
|
}),
|
|
196
196
|
);
|
|
197
197
|
}
|
|
198
|
-
fromHash = resolved.value.
|
|
199
|
-
fromContract = resolved.value.
|
|
198
|
+
fromHash = resolved.value.metadata.to;
|
|
199
|
+
fromContract = resolved.value.metadata.toContract;
|
|
200
200
|
fromContractSourceDir = resolved.value.dirPath;
|
|
201
201
|
} else {
|
|
202
202
|
const latestMigration = findLatestMigration(graph);
|
|
203
203
|
if (latestMigration) {
|
|
204
204
|
fromHash = latestMigration.to;
|
|
205
|
-
const leafPkg = bundles.find(
|
|
205
|
+
const leafPkg = bundles.find(
|
|
206
|
+
(p) => p.metadata.migrationHash === latestMigration.migrationHash,
|
|
207
|
+
);
|
|
206
208
|
if (leafPkg) {
|
|
207
|
-
fromContract = leafPkg.
|
|
209
|
+
fromContract = leafPkg.metadata.toContract;
|
|
208
210
|
fromContractSourceDir = leafPkg.dirPath;
|
|
209
211
|
}
|
|
210
212
|
}
|
|
@@ -213,7 +215,66 @@ async function executeMigrationPlanCommand(
|
|
|
213
215
|
if (MigrationToolsError.is(error)) {
|
|
214
216
|
return notOk(mapMigrationToolsError(error));
|
|
215
217
|
}
|
|
216
|
-
|
|
218
|
+
// Wrap unexpected (non-MigrationToolsError) failures from the migration
|
|
219
|
+
// load phase in a structured CLI envelope. Letting them throw would
|
|
220
|
+
// bypass `handleResult()` and crash the command — see CLI structured-
|
|
221
|
+
// errors guideline (CliStructuredError + Result pattern).
|
|
222
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
223
|
+
return notOk(
|
|
224
|
+
errorUnexpected(message, {
|
|
225
|
+
why: `Unexpected error while loading migrations: ${message}`,
|
|
226
|
+
}),
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Per-space migrate pass: drift detection + on-disk artefact emission for
|
|
231
|
+
// every loaded extension that exposes a `contractSpace`. Runs *before*
|
|
232
|
+
// the app-space no-op check so that an extension bump alone (with no
|
|
233
|
+
// structural app-space change) still re-pins extension artefacts on
|
|
234
|
+
// disk. Drift warnings are non-fatal — the on-disk artefacts are refreshed
|
|
235
|
+
// and the user is notified that the bump is being captured.
|
|
236
|
+
const extensionInputs: readonly MigrateExtensionInput[] = (config.extensionPacks ?? []).map(
|
|
237
|
+
(pack) => {
|
|
238
|
+
const cs = (pack as { readonly contractSpace?: MigrateExtensionInput['contractSpace'] })
|
|
239
|
+
.contractSpace;
|
|
240
|
+
return cs !== undefined ? { id: pack.id, contractSpace: cs } : { id: pack.id };
|
|
241
|
+
},
|
|
242
|
+
);
|
|
243
|
+
const migratePass = await runContractSpaceMigratePass({
|
|
244
|
+
migrationsDir,
|
|
245
|
+
extensionPacks: extensionInputs,
|
|
246
|
+
});
|
|
247
|
+
if (!flags.json && !flags.quiet) {
|
|
248
|
+
for (const drift of migratePass.drifts) {
|
|
249
|
+
if (drift.kind === 'drift') {
|
|
250
|
+
ui.stderr(formatContractSpaceDriftWarning(drift));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Materialise descriptor-shipped migration packages onto disk under
|
|
256
|
+
// `migrations/<spaceId>/<dirName>/` for any package not yet present.
|
|
257
|
+
// Idempotent (existing dirs are left untouched).
|
|
258
|
+
// Uses `planAllSpaces` for deterministic ordering + duplicate-spaceId
|
|
259
|
+
// detection.
|
|
260
|
+
const extensionMigrationsInputs: readonly ExtensionMigrationsExtensionInput[] = (
|
|
261
|
+
config.extensionPacks ?? []
|
|
262
|
+
).map((pack) => {
|
|
263
|
+
const cs = (
|
|
264
|
+
pack as {
|
|
265
|
+
readonly contractSpace?: ExtensionMigrationsExtensionInput['contractSpace'];
|
|
266
|
+
}
|
|
267
|
+
).contractSpace;
|
|
268
|
+
return cs !== undefined ? { id: pack.id, contractSpace: cs } : { id: pack.id };
|
|
269
|
+
});
|
|
270
|
+
const extensionMigrationsResult = await runContractSpaceExtensionMigrationsPass({
|
|
271
|
+
migrationsDir,
|
|
272
|
+
extensionPacks: extensionMigrationsInputs,
|
|
273
|
+
});
|
|
274
|
+
if (!flags.json && !flags.quiet) {
|
|
275
|
+
for (const entry of extensionMigrationsResult.emitted) {
|
|
276
|
+
ui.step(`Emitted ${entry.spaceId}/${entry.dirName}`);
|
|
277
|
+
}
|
|
217
278
|
}
|
|
218
279
|
|
|
219
280
|
// Check for no-op (same hash means no changes)
|
|
@@ -249,12 +310,11 @@ async function executeMigrationPlanCommand(
|
|
|
249
310
|
const timestamp = new Date();
|
|
250
311
|
const slug = options.name ?? 'migration';
|
|
251
312
|
const dirName = formatMigrationDirName(timestamp, slug);
|
|
252
|
-
const packageDir = join(
|
|
313
|
+
const packageDir = join(appMigrationsDir, dirName);
|
|
253
314
|
|
|
254
|
-
const
|
|
315
|
+
const baseMetadata: Omit<MigrationMetadata, 'migrationHash' | 'providedInvariants'> = {
|
|
255
316
|
from: fromHash,
|
|
256
317
|
to: toStorageHash,
|
|
257
|
-
kind: 'regular',
|
|
258
318
|
fromContract,
|
|
259
319
|
toContract: toContractJson,
|
|
260
320
|
hints: {
|
|
@@ -275,9 +335,9 @@ async function executeMigrationPlanCommand(
|
|
|
275
335
|
contract: toContractJson,
|
|
276
336
|
schema: fromSchema,
|
|
277
337
|
policy: { allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'] },
|
|
278
|
-
fromHash,
|
|
279
338
|
fromContract,
|
|
280
339
|
frameworkComponents,
|
|
340
|
+
spaceId: APP_SPACE_ID,
|
|
281
341
|
});
|
|
282
342
|
if (plannerResult.kind === 'failure') {
|
|
283
343
|
return notOk(
|
|
@@ -320,18 +380,22 @@ async function executeMigrationPlanCommand(
|
|
|
320
380
|
|
|
321
381
|
const migrationTsContent = plannerResult.plan.renderTypeScript();
|
|
322
382
|
|
|
323
|
-
// Always-attest: compute
|
|
324
|
-
// placeholders blocked lowering, ops is `[]` and the
|
|
325
|
-
// the empty list — re-emitting after the user fills the placeholder
|
|
326
|
-
// produces a different
|
|
383
|
+
// Always-attest: compute migrationHash over (metadata, ops). When
|
|
384
|
+
// placeholders blocked lowering, ops is `[]` and the hash is computed
|
|
385
|
+
// over the empty list — re-emitting after the user fills the placeholder
|
|
386
|
+
// produces a different hash (over the real ops). This is intentional;
|
|
327
387
|
// there is no on-disk "draft" state.
|
|
328
388
|
const opsForWrite = hasPlaceholders ? [] : plannedOps;
|
|
329
|
-
const
|
|
330
|
-
...
|
|
331
|
-
|
|
389
|
+
const metadataWithInvariants: Omit<MigrationMetadata, 'migrationHash'> = {
|
|
390
|
+
...baseMetadata,
|
|
391
|
+
providedInvariants: deriveProvidedInvariants(opsForWrite),
|
|
392
|
+
};
|
|
393
|
+
const metadata: MigrationMetadata = {
|
|
394
|
+
...metadataWithInvariants,
|
|
395
|
+
migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite),
|
|
332
396
|
};
|
|
333
397
|
|
|
334
|
-
await writeMigrationPackage(packageDir,
|
|
398
|
+
await writeMigrationPackage(packageDir, metadata, opsForWrite);
|
|
335
399
|
const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
|
|
336
400
|
await copyFilesWithRename(packageDir, [
|
|
337
401
|
{ sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },
|
|
@@ -364,7 +428,9 @@ async function executeMigrationPlanCommand(
|
|
|
364
428
|
return ok(result);
|
|
365
429
|
}
|
|
366
430
|
|
|
367
|
-
const
|
|
431
|
+
const preview = hasOperationPreview(familyInstance)
|
|
432
|
+
? familyInstance.toOperationPreview(plannedOps)
|
|
433
|
+
: undefined;
|
|
368
434
|
const result: MigrationPlanResult = {
|
|
369
435
|
ok: true,
|
|
370
436
|
noOp: false,
|
|
@@ -376,13 +442,24 @@ async function executeMigrationPlanCommand(
|
|
|
376
442
|
label: op.label,
|
|
377
443
|
operationClass: op.operationClass,
|
|
378
444
|
})),
|
|
379
|
-
|
|
445
|
+
...(preview !== undefined ? { preview } : {}),
|
|
380
446
|
summary: `Planned ${plannedOps.length} operation(s)`,
|
|
381
447
|
timings: { total: Date.now() - startTime },
|
|
382
448
|
};
|
|
383
449
|
return ok(result);
|
|
384
450
|
} catch (error) {
|
|
385
|
-
|
|
451
|
+
if (CliStructuredError.is(error)) {
|
|
452
|
+
return notOk(error);
|
|
453
|
+
}
|
|
454
|
+
if (MigrationToolsError.is(error)) {
|
|
455
|
+
return notOk(mapMigrationToolsError(error));
|
|
456
|
+
}
|
|
457
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
458
|
+
return notOk(
|
|
459
|
+
errorUnexpected(message, {
|
|
460
|
+
why: `Unexpected error during migration plan: ${message}`,
|
|
461
|
+
}),
|
|
462
|
+
);
|
|
386
463
|
}
|
|
387
464
|
}
|
|
388
465
|
|
|
@@ -489,17 +566,20 @@ function formatMigrationPlanOutput(result: MigrationPlanResult, flags: GlobalFla
|
|
|
489
566
|
|
|
490
567
|
lines.push('');
|
|
491
568
|
lines.push(
|
|
492
|
-
`Next: ${green_(
|
|
569
|
+
`Next: review ${green_(result.dir ?? '<dir>')} if needed, then run ${green_('prisma-next migration apply')}.`,
|
|
493
570
|
);
|
|
494
571
|
|
|
495
|
-
if (result.
|
|
572
|
+
if (result.preview && result.preview.statements.length > 0) {
|
|
573
|
+
// The non-empty length is already guaranteed by the surrounding check, so
|
|
574
|
+
// a plain `every` here is equivalent to the helper in formatters/migrations.ts.
|
|
575
|
+
const allSql = result.preview.statements.every((s) => s.language === 'sql');
|
|
496
576
|
lines.push('');
|
|
497
|
-
lines.push(dim_('DDL preview'));
|
|
577
|
+
lines.push(dim_(allSql ? 'DDL preview' : 'Operation preview'));
|
|
498
578
|
lines.push('');
|
|
499
|
-
for (const statement of result.
|
|
500
|
-
const trimmed = statement.trim();
|
|
579
|
+
for (const statement of result.preview.statements) {
|
|
580
|
+
const trimmed = statement.text.trim();
|
|
501
581
|
if (!trimmed) continue;
|
|
502
|
-
const line = trimmed.endsWith(';') ? trimmed :
|
|
582
|
+
const line = statement.language === 'sql' && !trimmed.endsWith(';') ? `${trimmed};` : trimmed;
|
|
503
583
|
lines.push(line);
|
|
504
584
|
}
|
|
505
585
|
}
|
|
@@ -517,24 +597,27 @@ export type PrefixResolutionFailure =
|
|
|
517
597
|
| { reason: 'not-found' };
|
|
518
598
|
|
|
519
599
|
/**
|
|
520
|
-
* Resolve a migration
|
|
600
|
+
* Resolve a migration package by **target contract hash** (`metadata.to`)
|
|
601
|
+
* using exact match or prefix match.
|
|
521
602
|
*
|
|
603
|
+
* Note: matches `metadata.to` (the contract hash this migration produces),
|
|
604
|
+
* not `metadata.migrationHash` (the package's content-addressed identity).
|
|
522
605
|
* Tries exact match first, then prefix match (auto-prepending `sha256:` when
|
|
523
|
-
* the needle omits the scheme). Returns the matched
|
|
606
|
+
* the needle omits the scheme). Returns the matched package on success, or a
|
|
524
607
|
* discriminated failure indicating whether the prefix was ambiguous or simply
|
|
525
608
|
* not found.
|
|
526
609
|
*
|
|
527
610
|
* @internal Exported for testing only.
|
|
528
611
|
*/
|
|
529
|
-
export function resolveBundleByPrefix<T extends {
|
|
612
|
+
export function resolveBundleByPrefix<T extends { metadata: { to: string } }>(
|
|
530
613
|
bundles: readonly T[],
|
|
531
614
|
needle: string,
|
|
532
615
|
): Result<T, PrefixResolutionFailure> {
|
|
533
|
-
const exact = bundles.find((p) => p.
|
|
616
|
+
const exact = bundles.find((p) => p.metadata.to === needle);
|
|
534
617
|
if (exact) return ok(exact);
|
|
535
618
|
|
|
536
619
|
const prefixWithScheme = needle.startsWith('sha256:') ? needle : `sha256:${needle}`;
|
|
537
|
-
const candidates = bundles.filter((p) => p.
|
|
620
|
+
const candidates = bundles.filter((p) => p.metadata.to.startsWith(prefixWithScheme));
|
|
538
621
|
|
|
539
622
|
if (candidates.length === 1) return ok(candidates[0]!);
|
|
540
623
|
if (candidates.length > 1) return notOk({ reason: 'ambiguous', count: candidates.length });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
1
2
|
import type { RefEntry } from '@prisma-next/migration-tools/refs';
|
|
2
3
|
import {
|
|
3
4
|
deleteRef,
|
|
@@ -7,11 +8,15 @@ import {
|
|
|
7
8
|
validateRefValue,
|
|
8
9
|
writeRef,
|
|
9
10
|
} from '@prisma-next/migration-tools/refs';
|
|
10
|
-
import { MigrationToolsError } from '@prisma-next/migration-tools/types';
|
|
11
11
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
12
12
|
import { Command } from 'commander';
|
|
13
13
|
import { loadConfig } from '../config-loader';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
CliStructuredError,
|
|
16
|
+
errorRuntime,
|
|
17
|
+
errorUnexpected,
|
|
18
|
+
mapMigrationToolsError,
|
|
19
|
+
} from '../utils/cli-errors';
|
|
15
20
|
import {
|
|
16
21
|
addGlobalOptions,
|
|
17
22
|
resolveMigrationPaths,
|
|
@@ -49,11 +54,7 @@ interface RefListResult {
|
|
|
49
54
|
|
|
50
55
|
function mapError(error: unknown): CliStructuredError {
|
|
51
56
|
if (MigrationToolsError.is(error)) {
|
|
52
|
-
return
|
|
53
|
-
why: error.why,
|
|
54
|
-
fix: error.fix,
|
|
55
|
-
meta: { code: error.code },
|
|
56
|
-
});
|
|
57
|
+
return mapMigrationToolsError(error);
|
|
57
58
|
}
|
|
58
59
|
return errorUnexpected(error instanceof Error ? error.message : String(error));
|
|
59
60
|
}
|
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
MigrationPlanOperation,
|
|
3
|
+
OperationPreview,
|
|
4
|
+
} from '@prisma-next/framework-components/control';
|
|
5
|
+
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
3
6
|
import { readMigrationPackage, readMigrationsDir } from '@prisma-next/migration-tools/io';
|
|
4
|
-
import
|
|
5
|
-
|
|
7
|
+
import {
|
|
8
|
+
findLatestMigration,
|
|
9
|
+
reconstructGraph,
|
|
10
|
+
} from '@prisma-next/migration-tools/migration-graph';
|
|
11
|
+
import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
|
|
12
|
+
import { APP_SPACE_ID, spaceMigrationDirectory } from '@prisma-next/migration-tools/spaces';
|
|
6
13
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
7
14
|
import { Command } from 'commander';
|
|
8
15
|
import { relative, resolve } from 'pathe';
|
|
9
16
|
import { loadConfig } from '../config-loader';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
17
|
+
import { createControlClient } from '../control-api/client';
|
|
18
|
+
import {
|
|
19
|
+
type CliStructuredError,
|
|
20
|
+
errorRuntime,
|
|
21
|
+
errorUnexpected,
|
|
22
|
+
mapMigrationToolsError,
|
|
23
|
+
} from '../utils/cli-errors';
|
|
12
24
|
import {
|
|
13
25
|
addGlobalOptions,
|
|
14
26
|
setCommandDescriptions,
|
|
@@ -29,17 +41,22 @@ export interface MigrationShowResult {
|
|
|
29
41
|
readonly ok: true;
|
|
30
42
|
readonly dirName: string;
|
|
31
43
|
readonly dirPath: string;
|
|
32
|
-
readonly from: string;
|
|
44
|
+
readonly from: string | null;
|
|
33
45
|
readonly to: string;
|
|
34
|
-
readonly
|
|
35
|
-
readonly kind: string;
|
|
46
|
+
readonly migrationHash: string;
|
|
36
47
|
readonly createdAt: string;
|
|
37
48
|
readonly operations: readonly {
|
|
38
49
|
readonly id: string;
|
|
39
50
|
readonly label: string;
|
|
40
51
|
readonly operationClass: string;
|
|
41
52
|
}[];
|
|
42
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Family-agnostic textual preview of the migration's operations. Replaces
|
|
55
|
+
* the previous string-array DDL field. Always defined; statements is empty
|
|
56
|
+
* for a no-op migration or a family that does not implement the
|
|
57
|
+
* `OperationPreviewCapable` capability.
|
|
58
|
+
*/
|
|
59
|
+
readonly preview: OperationPreview;
|
|
43
60
|
readonly summary: string;
|
|
44
61
|
}
|
|
45
62
|
|
|
@@ -48,11 +65,11 @@ function looksLikePath(target: string): boolean {
|
|
|
48
65
|
}
|
|
49
66
|
|
|
50
67
|
export function resolveByHashPrefix(
|
|
51
|
-
packages: readonly
|
|
68
|
+
packages: readonly OnDiskMigrationPackage[],
|
|
52
69
|
prefix: string,
|
|
53
|
-
): Result<
|
|
70
|
+
): Result<OnDiskMigrationPackage, CliStructuredError> {
|
|
54
71
|
const normalizedPrefix = prefix.startsWith('sha256:') ? prefix : `sha256:${prefix}`;
|
|
55
|
-
const matches = packages.filter((p) => p.
|
|
72
|
+
const matches = packages.filter((p) => p.metadata.migrationHash.startsWith(normalizedPrefix));
|
|
56
73
|
|
|
57
74
|
if (matches.length === 1) {
|
|
58
75
|
return ok(matches[0]!);
|
|
@@ -61,13 +78,13 @@ export function resolveByHashPrefix(
|
|
|
61
78
|
if (matches.length === 0) {
|
|
62
79
|
return notOk(
|
|
63
80
|
errorRuntime('No migration found matching prefix', {
|
|
64
|
-
why: `No migration has a
|
|
81
|
+
why: `No migration has a migrationHash starting with "${normalizedPrefix}"`,
|
|
65
82
|
fix: 'Run `prisma-next migration show` (no argument) to see the latest migration, or check the migrations directory for available packages.',
|
|
66
83
|
}),
|
|
67
84
|
);
|
|
68
85
|
}
|
|
69
86
|
|
|
70
|
-
const candidates = matches.map((p) => ` ${p.dirName} ${p.
|
|
87
|
+
const candidates = matches.map((p) => ` ${p.dirName} ${p.metadata.migrationHash}`).join('\n');
|
|
71
88
|
return notOk(
|
|
72
89
|
errorRuntime('Ambiguous hash prefix', {
|
|
73
90
|
why: `Multiple migrations match prefix "${normalizedPrefix}":\n${candidates}`,
|
|
@@ -87,16 +104,17 @@ async function executeMigrationShowCommand(
|
|
|
87
104
|
? relative(process.cwd(), resolve(options.config))
|
|
88
105
|
: 'prisma-next.config.ts';
|
|
89
106
|
|
|
90
|
-
const
|
|
107
|
+
const migrationsDirRoot = resolve(
|
|
91
108
|
options.config ? resolve(options.config, '..') : process.cwd(),
|
|
92
109
|
config.migrations?.dir ?? 'migrations',
|
|
93
110
|
);
|
|
94
|
-
const
|
|
111
|
+
const appMigrationsDir = spaceMigrationDirectory(migrationsDirRoot, APP_SPACE_ID);
|
|
112
|
+
const appMigrationsRelative = relative(process.cwd(), appMigrationsDir);
|
|
95
113
|
|
|
96
114
|
if (!flags.json && !flags.quiet) {
|
|
97
115
|
const details: Array<{ label: string; value: string }> = [
|
|
98
116
|
{ label: 'config', value: configPath },
|
|
99
|
-
{ label: 'migrations', value:
|
|
117
|
+
{ label: 'migrations', value: appMigrationsRelative },
|
|
100
118
|
];
|
|
101
119
|
if (target) {
|
|
102
120
|
details.push({ label: 'target', value: target });
|
|
@@ -110,17 +128,17 @@ async function executeMigrationShowCommand(
|
|
|
110
128
|
ui.stderr(header);
|
|
111
129
|
}
|
|
112
130
|
|
|
113
|
-
let pkg:
|
|
131
|
+
let pkg: OnDiskMigrationPackage;
|
|
114
132
|
|
|
115
133
|
try {
|
|
116
134
|
if (target && looksLikePath(target)) {
|
|
117
135
|
pkg = await readMigrationPackage(resolve(target));
|
|
118
136
|
} else {
|
|
119
|
-
const allPackages = await readMigrationsDir(
|
|
137
|
+
const allPackages = await readMigrationsDir(appMigrationsDir);
|
|
120
138
|
if (allPackages.length === 0) {
|
|
121
139
|
return notOk(
|
|
122
140
|
errorRuntime('No migrations found', {
|
|
123
|
-
why: `No migration packages found in ${
|
|
141
|
+
why: `No migration packages found in ${appMigrationsRelative}`,
|
|
124
142
|
fix: 'Run `prisma-next migration plan` to create a migration first.',
|
|
125
143
|
}),
|
|
126
144
|
);
|
|
@@ -142,7 +160,7 @@ async function executeMigrationShowCommand(
|
|
|
142
160
|
);
|
|
143
161
|
}
|
|
144
162
|
const leafPkg = allPackages.find(
|
|
145
|
-
(p) => p.
|
|
163
|
+
(p) => p.metadata.migrationHash === latestMigration.migrationHash,
|
|
146
164
|
);
|
|
147
165
|
if (!leafPkg) {
|
|
148
166
|
return notOk(
|
|
@@ -157,13 +175,7 @@ async function executeMigrationShowCommand(
|
|
|
157
175
|
}
|
|
158
176
|
} catch (error) {
|
|
159
177
|
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
|
-
);
|
|
178
|
+
return notOk(mapMigrationToolsError(error));
|
|
167
179
|
}
|
|
168
180
|
return notOk(
|
|
169
181
|
errorUnexpected(error instanceof Error ? error.message : String(error), {
|
|
@@ -173,23 +185,33 @@ async function executeMigrationShowCommand(
|
|
|
173
185
|
}
|
|
174
186
|
|
|
175
187
|
const ops = pkg.ops as readonly MigrationPlanOperation[];
|
|
176
|
-
|
|
188
|
+
|
|
189
|
+
// `migration show` is an offline command; the control client is constructed
|
|
190
|
+
// purely to dispatch the family-specific `toOperationPreview` capability and
|
|
191
|
+
// is not connected to a database.
|
|
192
|
+
const client = createControlClient({
|
|
193
|
+
family: config.family,
|
|
194
|
+
target: config.target,
|
|
195
|
+
adapter: config.adapter,
|
|
196
|
+
...(config.driver ? { driver: config.driver } : {}),
|
|
197
|
+
extensionPacks: config.extensionPacks ?? [],
|
|
198
|
+
});
|
|
199
|
+
const preview: OperationPreview = client.toOperationPreview(ops) ?? { statements: [] };
|
|
177
200
|
|
|
178
201
|
const result: MigrationShowResult = {
|
|
179
202
|
ok: true,
|
|
180
203
|
dirName: pkg.dirName,
|
|
181
204
|
dirPath: relative(process.cwd(), pkg.dirPath),
|
|
182
|
-
from: pkg.
|
|
183
|
-
to: pkg.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
createdAt: pkg.manifest.createdAt,
|
|
205
|
+
from: pkg.metadata.from,
|
|
206
|
+
to: pkg.metadata.to,
|
|
207
|
+
migrationHash: pkg.metadata.migrationHash,
|
|
208
|
+
createdAt: pkg.metadata.createdAt,
|
|
187
209
|
operations: ops.map((op) => ({
|
|
188
210
|
id: op.id,
|
|
189
211
|
label: op.label,
|
|
190
212
|
operationClass: op.operationClass,
|
|
191
213
|
})),
|
|
192
|
-
|
|
214
|
+
preview,
|
|
193
215
|
summary: `${ops.length} operation(s)`,
|
|
194
216
|
};
|
|
195
217
|
return ok(result);
|
|
@@ -200,7 +222,7 @@ export function createMigrationShowCommand(): Command {
|
|
|
200
222
|
setCommandDescriptions(
|
|
201
223
|
command,
|
|
202
224
|
'Display migration package contents',
|
|
203
|
-
'Shows the operations,
|
|
225
|
+
'Shows the operations, statement preview, and metadata for a migration package.\n' +
|
|
204
226
|
'Accepts a directory path, a hash prefix (git-style), or defaults to the\n' +
|
|
205
227
|
'latest migration.',
|
|
206
228
|
);
|
|
@@ -209,10 +231,7 @@ export function createMigrationShowCommand(): Command {
|
|
|
209
231
|
'prisma-next migration show sha256:a1b2c3',
|
|
210
232
|
]);
|
|
211
233
|
addGlobalOptions(command)
|
|
212
|
-
.argument(
|
|
213
|
-
'[target]',
|
|
214
|
-
'Migration directory path or migrationId hash prefix (defaults to latest)',
|
|
215
|
-
)
|
|
234
|
+
.argument('[target]', 'Migration directory path or migrationHash prefix (defaults to latest)')
|
|
216
235
|
.option('--config <path>', 'Path to prisma-next.config.ts')
|
|
217
236
|
.action(async (target: string | undefined, options: MigrationShowOptions) => {
|
|
218
237
|
const flags = parseGlobalFlags(options);
|