@prisma-next/cli 0.11.0-dev.5 → 0.11.0-dev.51
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-errors-DFF1LlfU.mjs +215 -0
- package/dist/cli-errors-DFF1LlfU.mjs.map +1 -0
- package/dist/cli.mjs +9 -10
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-oXO2WCPD.mjs → client-5uvDppD8.mjs} +23 -21
- package/dist/client-5uvDppD8.mjs.map +1 -0
- package/dist/{command-helpers-DtavI0wJ.mjs → command-helpers-4UNsRRc4.mjs} +427 -9
- package/dist/command-helpers-4UNsRRc4.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 +33 -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 +6 -7
- 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 +36 -8
- 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 +5 -1
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +79 -39
- 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 +1 -1
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +3 -4
- package/dist/commands/migration-graph.mjs.map +1 -1
- package/dist/commands/migration-list.d.mts +63 -12
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +2 -103
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +3 -4
- 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 +33 -38
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +2 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +4 -55
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +62 -153
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +5 -40
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +93 -67
- 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 +34 -9
- 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-emit-o-8VmdQX.mjs → contract-emit-C-CFGZsI.mjs} +9 -6
- package/dist/{contract-emit-o-8VmdQX.mjs.map → contract-emit-C-CFGZsI.mjs.map} +1 -1
- package/dist/{contract-emit-CmsklifJ.mjs → contract-emit-CuUzzM46.mjs} +5 -6
- package/dist/{contract-emit-CmsklifJ.mjs.map → contract-emit-CuUzzM46.mjs.map} +1 -1
- package/dist/{contract-enrichment-Dani0mMW.mjs → contract-enrichment-XmUPhmsS.mjs} +4 -25
- package/dist/contract-enrichment-XmUPhmsS.mjs.map +1 -0
- package/dist/{contract-infer-pKkiCt7C.mjs → contract-infer-C98ZaRhp.mjs} +3 -4
- package/dist/{contract-infer-pKkiCt7C.mjs.map → contract-infer-C98ZaRhp.mjs.map} +1 -1
- package/dist/contract-space-aggregate-loader-CVHGuA35.mjs +170 -0
- package/dist/contract-space-aggregate-loader-CVHGuA35.mjs.map +1 -0
- package/dist/{db-verify-AoIUriL4.mjs → db-verify-BWl1Yxi-.mjs} +6 -7
- package/dist/{db-verify-AoIUriL4.mjs.map → db-verify-BWl1Yxi-.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +1 -1
- 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-BiY86HbQ.mjs +62 -0
- package/dist/extension-pack-inputs-BiY86HbQ.mjs.map +1 -0
- package/dist/{framework-components-65gOHkHB.mjs → framework-components-DTcjouhS.mjs} +2 -2
- package/dist/{framework-components-65gOHkHB.mjs.map → framework-components-DTcjouhS.mjs.map} +1 -1
- package/dist/{global-flags-CdE7M0d9.d.mts → global-flags-DWsQ6SSI.d.mts} +1 -1
- package/dist/global-flags-DWsQ6SSI.d.mts.map +1 -0
- package/dist/glyph-mode-CBB4emzO.d.mts +5 -0
- package/dist/glyph-mode-CBB4emzO.d.mts.map +1 -0
- package/dist/{graph-render-DJVv0_uf.mjs → graph-render-D2FnLpuK.mjs} +1 -1
- package/dist/{graph-render-DJVv0_uf.mjs.map → graph-render-D2FnLpuK.mjs.map} +1 -1
- package/dist/{init-Db5Itt5r.mjs → init-C7PvN163.mjs} +5 -5
- package/dist/{init-Db5Itt5r.mjs.map → init-C7PvN163.mjs.map} +1 -1
- package/dist/{inspect-live-schema-LeWvkZVz.mjs → inspect-live-schema-BRCWQ-Sr.mjs} +5 -5
- package/dist/{inspect-live-schema-LeWvkZVz.mjs.map → inspect-live-schema-BRCWQ-Sr.mjs.map} +1 -1
- package/dist/migration-check-DoskM1nB.mjs +341 -0
- package/dist/migration-check-DoskM1nB.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-BtkunvFQ.mjs → migration-command-scaffold-CXLkoIJx.mjs} +5 -5
- package/dist/{migration-command-scaffold-BtkunvFQ.mjs.map → migration-command-scaffold-CXLkoIJx.mjs.map} +1 -1
- package/dist/migration-list-B2-iQ5Jd.mjs +646 -0
- package/dist/migration-list-B2-iQ5Jd.mjs.map +1 -0
- package/dist/{migration-plan-C2jeH1J5.mjs → migration-plan-BqmIKQpZ.mjs} +341 -88
- package/dist/migration-plan-BqmIKQpZ.mjs.map +1 -0
- package/dist/{migration-types-BXWvz12q.d.mts → migration-types-q64xAI_J.d.mts} +1 -1
- package/dist/{migration-types-BXWvz12q.d.mts.map → migration-types-q64xAI_J.d.mts.map} +1 -1
- package/dist/{migrations-CwZMa1Ck.mjs → migrations-BcVTutso.mjs} +12 -13
- package/dist/migrations-BcVTutso.mjs.map +1 -0
- package/dist/{output-BlsrGMEF.mjs → output-B60Gw5fu.mjs} +1 -1
- package/dist/{output-BlsrGMEF.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs → progress-adapter-xASh41wr.mjs} +1 -1
- package/dist/{progress-adapter-DFfvZcYL.mjs.map → progress-adapter-xASh41wr.mjs.map} +1 -1
- package/dist/ref-advancement-DRh5Nquq.mjs +50 -0
- package/dist/ref-advancement-DRh5Nquq.mjs.map +1 -0
- package/dist/{types-C9FfXb1l.d.mts → types-CEtm6v6a.d.mts} +5 -11
- package/dist/types-CEtm6v6a.d.mts.map +1 -0
- package/dist/{verify-Bom75OYI.mjs → verify-DOHbbrub.mjs} +2 -2
- package/dist/{verify-Bom75OYI.mjs.map → verify-DOHbbrub.mjs.map} +1 -1
- package/package.json +20 -20
- package/src/commands/db-init.ts +48 -2
- package/src/commands/db-update.ts +45 -0
- package/src/commands/migrate.ts +120 -40
- package/src/commands/migration-check.ts +43 -83
- package/src/commands/migration-list.ts +173 -74
- package/src/commands/migration-new.ts +44 -48
- package/src/commands/migration-plan.ts +359 -128
- package/src/commands/migration-show.ts +65 -284
- package/src/commands/migration-status.ts +131 -99
- package/src/commands/ref.ts +46 -6
- package/src/control-api/client.ts +0 -1
- package/src/control-api/contract-enrichment.ts +6 -42
- package/src/control-api/operations/contract-emit.ts +7 -2
- package/src/control-api/operations/db-verify.ts +9 -5
- package/src/control-api/operations/migration-apply.ts +11 -19
- package/src/control-api/types.ts +0 -7
- package/src/migration-cli.ts +4 -4
- package/src/utils/cli-errors.ts +224 -0
- package/src/utils/command-helpers.ts +9 -4
- package/src/utils/contract-space-aggregate-loader.ts +221 -117
- package/src/utils/formatters/migration-list-data-column.ts +115 -0
- package/src/utils/formatters/migration-list-graph-layout.ts +268 -0
- package/src/utils/formatters/migration-list-graph-render.ts +314 -0
- package/src/utils/formatters/migration-list-render.ts +194 -0
- package/src/utils/formatters/migration-list-styler.ts +61 -0
- package/src/utils/formatters/migrations.ts +29 -38
- package/src/utils/glyph-mode.ts +22 -0
- package/src/utils/integrity-violation-to-check-failure.ts +130 -0
- package/src/utils/plan-resolution.ts +257 -0
- package/src/utils/ref-advancement.ts +68 -0
- package/src/utils/terminal-ui.ts +42 -1
- package/dist/cli-errors-Czmx92Zy.d.mts +0 -3
- package/dist/cli-errors-Djtz98Vm.mjs +0 -71
- package/dist/cli-errors-Djtz98Vm.mjs.map +0 -1
- package/dist/client-oXO2WCPD.mjs.map +0 -1
- package/dist/command-helpers-DtavI0wJ.mjs.map +0 -1
- package/dist/commands/migration-check.mjs.map +0 -1
- package/dist/commands/migration-list.mjs.map +0 -1
- package/dist/contract-enrichment-Dani0mMW.mjs.map +0 -1
- package/dist/contract-space-aggregate-loader-BmNQwlws.mjs +0 -160
- package/dist/contract-space-aggregate-loader-BmNQwlws.mjs.map +0 -1
- package/dist/global-flags-CdE7M0d9.d.mts.map +0 -1
- package/dist/migration-plan-C2jeH1J5.mjs.map +0 -1
- package/dist/migrations-CwZMa1Ck.mjs.map +0 -1
- package/dist/terminal-ui-BiB_8KNo.mjs +0 -379
- package/dist/terminal-ui-BiB_8KNo.mjs.map +0 -1
- package/dist/types-C9FfXb1l.d.mts.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
1
|
+
import { mkdir, readFile, writeFile } 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 {
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type MigrationPlanOperation,
|
|
9
9
|
type OperationPreview,
|
|
10
10
|
} from '@prisma-next/framework-components/control';
|
|
11
|
+
import { canonicalizeJson } from '@prisma-next/framework-components/utils';
|
|
11
12
|
import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
|
|
12
13
|
import { computeMigrationHash } from '@prisma-next/migration-tools/hash';
|
|
13
14
|
import { deriveProvidedInvariants } from '@prisma-next/migration-tools/invariants';
|
|
@@ -17,10 +18,7 @@ import {
|
|
|
17
18
|
writeMigrationPackage,
|
|
18
19
|
} from '@prisma-next/migration-tools/io';
|
|
19
20
|
import type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';
|
|
20
|
-
import { findLatestMigration } from '@prisma-next/migration-tools/migration-graph';
|
|
21
21
|
import { writeMigrationTs } from '@prisma-next/migration-tools/migration-ts';
|
|
22
|
-
import { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';
|
|
23
|
-
import { readRefs } from '@prisma-next/migration-tools/refs';
|
|
24
22
|
import { notOk, ok, type Result } from '@prisma-next/utils/result';
|
|
25
23
|
import { Command } from 'commander';
|
|
26
24
|
import { join, relative } from 'pathe';
|
|
@@ -34,7 +32,6 @@ import {
|
|
|
34
32
|
errorTargetMigrationNotSupported,
|
|
35
33
|
errorUnexpected,
|
|
36
34
|
mapMigrationToolsError,
|
|
37
|
-
mapRefResolutionError,
|
|
38
35
|
} from '../utils/cli-errors';
|
|
39
36
|
import {
|
|
40
37
|
addGlobalOptions,
|
|
@@ -52,6 +49,7 @@ import { formatStyledHeader } from '../utils/formatters/styled';
|
|
|
52
49
|
import { assertFrameworkComponentsCompatible } from '../utils/framework-components';
|
|
53
50
|
import type { CommonCommandOptions } from '../utils/global-flags';
|
|
54
51
|
import { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';
|
|
52
|
+
import { resolveFromForPlan } from '../utils/plan-resolution';
|
|
55
53
|
import { handleResult } from '../utils/result-handler';
|
|
56
54
|
import { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';
|
|
57
55
|
|
|
@@ -110,12 +108,122 @@ async function readPredecessorEndContract(
|
|
|
110
108
|
}
|
|
111
109
|
}
|
|
112
110
|
|
|
111
|
+
async function writeSnapshotContractArtifacts(
|
|
112
|
+
packageDir: string,
|
|
113
|
+
contractJson: unknown,
|
|
114
|
+
contractDts: string,
|
|
115
|
+
artifactBasename: 'start-contract' | 'end-contract',
|
|
116
|
+
): Promise<void> {
|
|
117
|
+
await mkdir(packageDir, { recursive: true });
|
|
118
|
+
const jsonContent = `${canonicalizeJson(contractJson)}\n`;
|
|
119
|
+
const dtsContent = contractDts.endsWith('\n') ? contractDts : `${contractDts}\n`;
|
|
120
|
+
await writeFile(join(packageDir, `${artifactBasename}.json`), jsonContent);
|
|
121
|
+
await writeFile(join(packageDir, `${artifactBasename}.d.ts`), dtsContent);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function writeSnapshotStartContract(
|
|
125
|
+
packageDir: string,
|
|
126
|
+
contractJson: unknown,
|
|
127
|
+
contractDts: string,
|
|
128
|
+
): Promise<void> {
|
|
129
|
+
await writeSnapshotContractArtifacts(packageDir, contractJson, contractDts, 'start-contract');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
type PlannerSuccess = {
|
|
133
|
+
readonly plannedOps: readonly MigrationPlanOperation[];
|
|
134
|
+
readonly migrationTsContent: string;
|
|
135
|
+
readonly hasPlaceholders: boolean;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
type TargetMigrationsApi = NonNullable<ReturnType<typeof getTargetMigrations>>;
|
|
139
|
+
|
|
140
|
+
async function runPlannerLeg(
|
|
141
|
+
planner: ReturnType<TargetMigrationsApi['createPlanner']>,
|
|
142
|
+
migrations: TargetMigrationsApi,
|
|
143
|
+
frameworkComponents: ReturnType<typeof assertFrameworkComponentsCompatible>,
|
|
144
|
+
contract: Contract,
|
|
145
|
+
fromContract: Contract | null,
|
|
146
|
+
spaceId: string,
|
|
147
|
+
): Promise<Result<PlannerSuccess, CliStructuredError>> {
|
|
148
|
+
const fromSchema = migrations.contractToSchema(fromContract, frameworkComponents);
|
|
149
|
+
const plannerResult = planner.plan({
|
|
150
|
+
contract,
|
|
151
|
+
schema: fromSchema,
|
|
152
|
+
policy: { allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'] },
|
|
153
|
+
fromContract,
|
|
154
|
+
frameworkComponents,
|
|
155
|
+
spaceId,
|
|
156
|
+
});
|
|
157
|
+
if (plannerResult.kind === 'failure') {
|
|
158
|
+
return notOk(
|
|
159
|
+
errorMigrationPlanningFailed({
|
|
160
|
+
conflicts: plannerResult.conflicts as readonly CliErrorConflict[],
|
|
161
|
+
}),
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let plannedOps: readonly MigrationPlanOperation[] = [];
|
|
166
|
+
let hasPlaceholders = false;
|
|
167
|
+
try {
|
|
168
|
+
plannedOps = plannerResult.plan.operations;
|
|
169
|
+
if (plannedOps.length === 0) {
|
|
170
|
+
return notOk(
|
|
171
|
+
errorMigrationPlanningFailed({
|
|
172
|
+
conflicts: [
|
|
173
|
+
{
|
|
174
|
+
kind: 'unsupportedChange',
|
|
175
|
+
summary:
|
|
176
|
+
'Contract changed but planner produced no operations. ' +
|
|
177
|
+
'This indicates unsupported or ignored changes.',
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
}),
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
} catch (e) {
|
|
184
|
+
if (CliStructuredError.is(e) && e.domain === 'MIG' && e.code === '2001') {
|
|
185
|
+
hasPlaceholders = true;
|
|
186
|
+
} else {
|
|
187
|
+
throw e;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return ok({
|
|
192
|
+
plannedOps,
|
|
193
|
+
migrationTsContent: plannerResult.plan.renderTypeScript(),
|
|
194
|
+
hasPlaceholders,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function writePlannedMigrationPackage(
|
|
199
|
+
packageDir: string,
|
|
200
|
+
fromHash: string | null,
|
|
201
|
+
toHash: string,
|
|
202
|
+
createdAt: Date,
|
|
203
|
+
leg: PlannerSuccess,
|
|
204
|
+
): Promise<void> {
|
|
205
|
+
const opsForWrite = leg.hasPlaceholders ? [] : leg.plannedOps;
|
|
206
|
+
const metadataWithInvariants: Omit<MigrationMetadata, 'migrationHash'> = {
|
|
207
|
+
from: fromHash,
|
|
208
|
+
to: toHash,
|
|
209
|
+
providedInvariants: deriveProvidedInvariants(opsForWrite),
|
|
210
|
+
createdAt: createdAt.toISOString(),
|
|
211
|
+
};
|
|
212
|
+
const metadata: MigrationMetadata = {
|
|
213
|
+
...metadataWithInvariants,
|
|
214
|
+
migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite),
|
|
215
|
+
};
|
|
216
|
+
await writeMigrationPackage(packageDir, metadata, opsForWrite);
|
|
217
|
+
await writeMigrationTs(packageDir, leg.migrationTsContent);
|
|
218
|
+
}
|
|
219
|
+
|
|
113
220
|
export interface MigrationPlanResult {
|
|
114
221
|
readonly ok: boolean;
|
|
115
222
|
readonly noOp: boolean;
|
|
116
223
|
readonly from: string | null;
|
|
117
224
|
readonly to: string;
|
|
118
225
|
readonly dir?: string;
|
|
226
|
+
readonly baselineDir?: string;
|
|
119
227
|
/**
|
|
120
228
|
* Extension-space migration packages materialised onto disk during this
|
|
121
229
|
* `plan` run. Each entry names a `migrations/<spaceId>/<dirName>/`
|
|
@@ -236,62 +344,64 @@ async function executeMigrationPlanCommand(
|
|
|
236
344
|
}
|
|
237
345
|
const toStorageHash = rawStorageHash;
|
|
238
346
|
|
|
239
|
-
|
|
347
|
+
const { refsDir } = resolveMigrationPaths(options.config, config);
|
|
348
|
+
|
|
240
349
|
let fromContract: Contract | null = null;
|
|
241
350
|
let fromHash: string | null = null;
|
|
242
351
|
let fromContractSourceDir: string | null = null;
|
|
352
|
+
let snapshotStartContract: { contractJson: unknown; contractDts: string } | null = null;
|
|
353
|
+
let isAutoBaseline = false;
|
|
243
354
|
|
|
244
355
|
try {
|
|
245
356
|
const { bundles, graph } = await loadMigrationPackages(appMigrationsDir);
|
|
246
357
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
358
|
+
const resolutionResult = await resolveFromForPlan({
|
|
359
|
+
optionsFrom: options.from,
|
|
360
|
+
refsDir,
|
|
361
|
+
bundles,
|
|
362
|
+
graph,
|
|
363
|
+
familyInstance,
|
|
364
|
+
readBundleEndContract: (migrationDir) =>
|
|
365
|
+
readPredecessorEndContract(migrationDir, familyInstance),
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
if (!resolutionResult.ok) {
|
|
369
|
+
return notOk(resolutionResult.failure);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
switch (resolutionResult.value.kind) {
|
|
373
|
+
case 'greenfield':
|
|
374
|
+
break;
|
|
375
|
+
case 'graph-node':
|
|
376
|
+
fromHash = resolutionResult.value.fromHash;
|
|
377
|
+
fromContract = resolutionResult.value.fromContract;
|
|
378
|
+
fromContractSourceDir = resolutionResult.value.sourceDir;
|
|
379
|
+
break;
|
|
380
|
+
case 'snapshot':
|
|
381
|
+
fromHash = resolutionResult.value.fromHash;
|
|
382
|
+
fromContract = resolutionResult.value.fromContract;
|
|
383
|
+
snapshotStartContract = {
|
|
384
|
+
contractJson: resolutionResult.value.contractJson,
|
|
385
|
+
contractDts: resolutionResult.value.contractDts,
|
|
386
|
+
};
|
|
387
|
+
break;
|
|
388
|
+
case 'auto-baseline':
|
|
389
|
+
fromHash = resolutionResult.value.fromHash;
|
|
390
|
+
fromContract = resolutionResult.value.fromContract;
|
|
391
|
+
snapshotStartContract = {
|
|
392
|
+
contractJson: resolutionResult.value.contractJson,
|
|
393
|
+
contractDts: resolutionResult.value.contractDts,
|
|
394
|
+
};
|
|
395
|
+
isAutoBaseline = true;
|
|
396
|
+
break;
|
|
280
397
|
}
|
|
281
398
|
} catch (error) {
|
|
282
399
|
if (MigrationToolsError.is(error)) {
|
|
283
400
|
return notOk(mapMigrationToolsError(error));
|
|
284
401
|
}
|
|
285
|
-
// `readPredecessorEndContract` raises a `CliStructuredError` directly
|
|
286
|
-
// for the missing-snapshot case so the operator gets a precise
|
|
287
|
-
// why/fix; pass it through unchanged rather than re-wrapping.
|
|
288
402
|
if (CliStructuredError.is(error)) {
|
|
289
403
|
return notOk(error);
|
|
290
404
|
}
|
|
291
|
-
// Wrap unexpected (non-MigrationToolsError) failures from the migration
|
|
292
|
-
// load phase in a structured CLI envelope. Letting them throw would
|
|
293
|
-
// bypass `handleResult()` and crash the command — see CLI structured-
|
|
294
|
-
// errors guideline (CliStructuredError + Result pattern).
|
|
295
405
|
const message = error instanceof Error ? error.message : String(error);
|
|
296
406
|
return notOk(
|
|
297
407
|
errorUnexpected(message, {
|
|
@@ -325,8 +435,10 @@ async function executeMigrationPlanCommand(
|
|
|
325
435
|
r.newMigrationDirs.map((dirName) => ({ spaceId: r.spaceId, dirName })),
|
|
326
436
|
);
|
|
327
437
|
|
|
328
|
-
// Check for no-op (same hash means no changes)
|
|
329
|
-
|
|
438
|
+
// Check for no-op (same hash means no changes). Auto-baseline is exempt:
|
|
439
|
+
// an empty graph with db ref at the current contract still needs a
|
|
440
|
+
// null → fromHash baseline bundle so migrate can anchor the marker.
|
|
441
|
+
if (fromHash === toStorageHash && !isAutoBaseline) {
|
|
330
442
|
const result: MigrationPlanResult = {
|
|
331
443
|
ok: true,
|
|
332
444
|
noOp: true,
|
|
@@ -375,92 +487,187 @@ async function executeMigrationPlanCommand(
|
|
|
375
487
|
[config.target, config.adapter, ...(config.extensionPacks ?? [])],
|
|
376
488
|
);
|
|
377
489
|
|
|
378
|
-
// Build manifest and write migration package
|
|
379
|
-
const timestamp = new Date();
|
|
380
|
-
const slug = options.name ?? 'migration';
|
|
381
|
-
const dirName = formatMigrationDirName(timestamp, slug);
|
|
382
|
-
const packageDir = join(appMigrationsDir, dirName);
|
|
383
|
-
|
|
384
|
-
const baseMetadata: Omit<MigrationMetadata, 'migrationHash' | 'providedInvariants'> = {
|
|
385
|
-
from: fromHash,
|
|
386
|
-
to: toStorageHash,
|
|
387
|
-
hints: {
|
|
388
|
-
used: [],
|
|
389
|
-
applied: [],
|
|
390
|
-
plannerVersion: '2.0.0',
|
|
391
|
-
},
|
|
392
|
-
labels: [],
|
|
393
|
-
createdAt: timestamp.toISOString(),
|
|
394
|
-
};
|
|
395
|
-
|
|
396
490
|
try {
|
|
397
491
|
const planner = migrations.createPlanner(familyInstance);
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
492
|
+
|
|
493
|
+
if (
|
|
494
|
+
isAutoBaseline &&
|
|
495
|
+
fromHash !== null &&
|
|
496
|
+
fromContract !== null &&
|
|
497
|
+
snapshotStartContract !== null
|
|
498
|
+
) {
|
|
499
|
+
const baselineTimestamp = new Date();
|
|
500
|
+
const deltaTimestamp = new Date(baselineTimestamp.getTime() + 60_000);
|
|
501
|
+
const baselineDirName = formatMigrationDirName(baselineTimestamp, 'baseline');
|
|
502
|
+
const deltaDirName = formatMigrationDirName(deltaTimestamp, options.name ?? 'migration');
|
|
503
|
+
const baselinePackageDir = join(appMigrationsDir, baselineDirName);
|
|
504
|
+
const deltaPackageDir = join(appMigrationsDir, deltaDirName);
|
|
505
|
+
|
|
506
|
+
const baselineLeg = await runPlannerLeg(
|
|
507
|
+
planner,
|
|
508
|
+
migrations,
|
|
509
|
+
frameworkComponents,
|
|
510
|
+
fromContract,
|
|
511
|
+
null,
|
|
512
|
+
aggregate.app.spaceId,
|
|
412
513
|
);
|
|
413
|
-
|
|
514
|
+
if (!baselineLeg.ok) {
|
|
515
|
+
return notOk(baselineLeg.failure);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
await writePlannedMigrationPackage(
|
|
519
|
+
baselinePackageDir,
|
|
520
|
+
null,
|
|
521
|
+
fromHash,
|
|
522
|
+
baselineTimestamp,
|
|
523
|
+
baselineLeg.value,
|
|
524
|
+
);
|
|
525
|
+
await writeSnapshotContractArtifacts(
|
|
526
|
+
baselinePackageDir,
|
|
527
|
+
snapshotStartContract.contractJson,
|
|
528
|
+
snapshotStartContract.contractDts,
|
|
529
|
+
'end-contract',
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
if (fromHash === toStorageHash) {
|
|
533
|
+
const baselineOps = baselineLeg.value.hasPlaceholders ? [] : baselineLeg.value.plannedOps;
|
|
534
|
+
if (baselineLeg.value.hasPlaceholders) {
|
|
535
|
+
const baselineDir = relative(process.cwd(), baselinePackageDir);
|
|
536
|
+
const result: MigrationPlanResult = {
|
|
537
|
+
ok: true,
|
|
538
|
+
noOp: false,
|
|
539
|
+
from: fromHash,
|
|
540
|
+
to: toStorageHash,
|
|
541
|
+
dir: baselineDir,
|
|
542
|
+
baselineDir,
|
|
543
|
+
operations: [],
|
|
544
|
+
emittedExtensionDirs,
|
|
545
|
+
pendingPlaceholders: true,
|
|
546
|
+
summary:
|
|
547
|
+
'Planned baseline with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit',
|
|
548
|
+
timings: { total: Date.now() - startTime },
|
|
549
|
+
};
|
|
550
|
+
return ok(result);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const preview = hasOperationPreview(familyInstance)
|
|
554
|
+
? familyInstance.toOperationPreview(baselineOps)
|
|
555
|
+
: undefined;
|
|
556
|
+
const result: MigrationPlanResult = {
|
|
557
|
+
ok: true,
|
|
558
|
+
noOp: false,
|
|
559
|
+
from: fromHash,
|
|
560
|
+
to: toStorageHash,
|
|
561
|
+
baselineDir: relative(process.cwd(), baselinePackageDir),
|
|
562
|
+
operations: baselineOps.map((op) => ({
|
|
563
|
+
id: op.id,
|
|
564
|
+
label: op.label,
|
|
565
|
+
operationClass: op.operationClass,
|
|
566
|
+
})),
|
|
567
|
+
emittedExtensionDirs,
|
|
568
|
+
...(preview !== undefined ? { preview } : {}),
|
|
569
|
+
summary: buildAutoBaselinePlanSummary(0, emittedExtensionDirs.length),
|
|
570
|
+
timings: { total: Date.now() - startTime },
|
|
571
|
+
};
|
|
572
|
+
return ok(result);
|
|
573
|
+
}
|
|
414
574
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return notOk(
|
|
426
|
-
errorMigrationPlanningFailed({
|
|
427
|
-
conflicts: [
|
|
428
|
-
{
|
|
429
|
-
kind: 'unsupportedChange',
|
|
430
|
-
summary:
|
|
431
|
-
'Contract changed but planner produced no operations. ' +
|
|
432
|
-
'This indicates unsupported or ignored changes.',
|
|
433
|
-
},
|
|
434
|
-
],
|
|
435
|
-
}),
|
|
436
|
-
);
|
|
575
|
+
const deltaLeg = await runPlannerLeg(
|
|
576
|
+
planner,
|
|
577
|
+
migrations,
|
|
578
|
+
frameworkComponents,
|
|
579
|
+
aggregate.app.contract(),
|
|
580
|
+
fromContract,
|
|
581
|
+
aggregate.app.spaceId,
|
|
582
|
+
);
|
|
583
|
+
if (!deltaLeg.ok) {
|
|
584
|
+
return notOk(deltaLeg.failure);
|
|
437
585
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
586
|
+
|
|
587
|
+
await writePlannedMigrationPackage(
|
|
588
|
+
deltaPackageDir,
|
|
589
|
+
fromHash,
|
|
590
|
+
toStorageHash,
|
|
591
|
+
deltaTimestamp,
|
|
592
|
+
deltaLeg.value,
|
|
593
|
+
);
|
|
594
|
+
const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
|
|
595
|
+
await copyFilesWithRename(deltaPackageDir, [
|
|
596
|
+
{ sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },
|
|
597
|
+
{ sourcePath: destinationArtifacts.dtsPath, destName: 'end-contract.d.ts' },
|
|
598
|
+
]);
|
|
599
|
+
await writeSnapshotStartContract(
|
|
600
|
+
deltaPackageDir,
|
|
601
|
+
snapshotStartContract.contractJson,
|
|
602
|
+
snapshotStartContract.contractDts,
|
|
603
|
+
);
|
|
604
|
+
|
|
605
|
+
const deltaOps = deltaLeg.value.hasPlaceholders ? [] : deltaLeg.value.plannedOps;
|
|
606
|
+
if (deltaLeg.value.hasPlaceholders) {
|
|
607
|
+
const result: MigrationPlanResult = {
|
|
608
|
+
ok: true,
|
|
609
|
+
noOp: false,
|
|
610
|
+
from: fromHash,
|
|
611
|
+
to: toStorageHash,
|
|
612
|
+
dir: relative(process.cwd(), deltaPackageDir),
|
|
613
|
+
baselineDir: relative(process.cwd(), baselinePackageDir),
|
|
614
|
+
operations: [],
|
|
615
|
+
emittedExtensionDirs,
|
|
616
|
+
pendingPlaceholders: true,
|
|
617
|
+
summary:
|
|
618
|
+
'Planned baseline + migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit',
|
|
619
|
+
timings: { total: Date.now() - startTime },
|
|
620
|
+
};
|
|
621
|
+
return ok(result);
|
|
443
622
|
}
|
|
623
|
+
|
|
624
|
+
const preview = hasOperationPreview(familyInstance)
|
|
625
|
+
? familyInstance.toOperationPreview(deltaOps)
|
|
626
|
+
: undefined;
|
|
627
|
+
const result: MigrationPlanResult = {
|
|
628
|
+
ok: true,
|
|
629
|
+
noOp: false,
|
|
630
|
+
from: fromHash,
|
|
631
|
+
to: toStorageHash,
|
|
632
|
+
dir: relative(process.cwd(), deltaPackageDir),
|
|
633
|
+
baselineDir: relative(process.cwd(), baselinePackageDir),
|
|
634
|
+
operations: deltaOps.map((op) => ({
|
|
635
|
+
id: op.id,
|
|
636
|
+
label: op.label,
|
|
637
|
+
operationClass: op.operationClass,
|
|
638
|
+
})),
|
|
639
|
+
emittedExtensionDirs,
|
|
640
|
+
...(preview !== undefined ? { preview } : {}),
|
|
641
|
+
summary: buildAutoBaselinePlanSummary(deltaOps.length, emittedExtensionDirs.length),
|
|
642
|
+
timings: { total: Date.now() - startTime },
|
|
643
|
+
};
|
|
644
|
+
return ok(result);
|
|
444
645
|
}
|
|
445
646
|
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
// over the empty list — re-emitting after the user fills the placeholder
|
|
451
|
-
// produces a different hash (over the real ops). This is intentional;
|
|
452
|
-
// there is no on-disk "draft" state.
|
|
453
|
-
const opsForWrite = hasPlaceholders ? [] : plannedOps;
|
|
454
|
-
const metadataWithInvariants: Omit<MigrationMetadata, 'migrationHash'> = {
|
|
455
|
-
...baseMetadata,
|
|
456
|
-
providedInvariants: deriveProvidedInvariants(opsForWrite),
|
|
457
|
-
};
|
|
458
|
-
const metadata: MigrationMetadata = {
|
|
459
|
-
...metadataWithInvariants,
|
|
460
|
-
migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite),
|
|
461
|
-
};
|
|
647
|
+
const timestamp = new Date();
|
|
648
|
+
const slug = options.name ?? 'migration';
|
|
649
|
+
const dirName = formatMigrationDirName(timestamp, slug);
|
|
650
|
+
const packageDir = join(appMigrationsDir, dirName);
|
|
462
651
|
|
|
463
|
-
await
|
|
652
|
+
const deltaLeg = await runPlannerLeg(
|
|
653
|
+
planner,
|
|
654
|
+
migrations,
|
|
655
|
+
frameworkComponents,
|
|
656
|
+
aggregate.app.contract(),
|
|
657
|
+
fromContract,
|
|
658
|
+
aggregate.app.spaceId,
|
|
659
|
+
);
|
|
660
|
+
if (!deltaLeg.ok) {
|
|
661
|
+
return notOk(deltaLeg.failure);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
await writePlannedMigrationPackage(
|
|
665
|
+
packageDir,
|
|
666
|
+
fromHash,
|
|
667
|
+
toStorageHash,
|
|
668
|
+
timestamp,
|
|
669
|
+
deltaLeg.value,
|
|
670
|
+
);
|
|
464
671
|
const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
|
|
465
672
|
await copyFilesWithRename(packageDir, [
|
|
466
673
|
{ sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },
|
|
@@ -474,10 +681,15 @@ async function executeMigrationPlanCommand(
|
|
|
474
681
|
{ sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },
|
|
475
682
|
{ sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },
|
|
476
683
|
]);
|
|
684
|
+
} else if (snapshotStartContract !== null) {
|
|
685
|
+
await writeSnapshotStartContract(
|
|
686
|
+
packageDir,
|
|
687
|
+
snapshotStartContract.contractJson,
|
|
688
|
+
snapshotStartContract.contractDts,
|
|
689
|
+
);
|
|
477
690
|
}
|
|
478
|
-
await writeMigrationTs(packageDir, migrationTsContent);
|
|
479
691
|
|
|
480
|
-
if (hasPlaceholders) {
|
|
692
|
+
if (deltaLeg.value.hasPlaceholders) {
|
|
481
693
|
const result: MigrationPlanResult = {
|
|
482
694
|
ok: true,
|
|
483
695
|
noOp: false,
|
|
@@ -494,6 +706,7 @@ async function executeMigrationPlanCommand(
|
|
|
494
706
|
return ok(result);
|
|
495
707
|
}
|
|
496
708
|
|
|
709
|
+
const plannedOps = deltaLeg.value.plannedOps;
|
|
497
710
|
const preview = hasOperationPreview(familyInstance)
|
|
498
711
|
? familyInstance.toOperationPreview(plannedOps)
|
|
499
712
|
: undefined;
|
|
@@ -593,6 +806,17 @@ function buildPlanSummary(plannedOpsCount: number, emittedExtensionDirsCount: nu
|
|
|
593
806
|
return `${base}; materialised ${emittedExtensionDirsCount} ${noun}`;
|
|
594
807
|
}
|
|
595
808
|
|
|
809
|
+
function buildAutoBaselinePlanSummary(
|
|
810
|
+
deltaOpsCount: number,
|
|
811
|
+
emittedExtensionDirsCount: number,
|
|
812
|
+
): string {
|
|
813
|
+
const base = `Planned baseline + ${deltaOpsCount} operation(s)`;
|
|
814
|
+
if (emittedExtensionDirsCount === 0) return base;
|
|
815
|
+
const noun =
|
|
816
|
+
emittedExtensionDirsCount === 1 ? 'extension-space migration' : 'extension-space migrations';
|
|
817
|
+
return `${base}; materialised ${emittedExtensionDirsCount} ${noun}`;
|
|
818
|
+
}
|
|
819
|
+
|
|
596
820
|
export function formatMigrationPlanOutput(result: MigrationPlanResult, flags: GlobalFlags): string {
|
|
597
821
|
const lines: string[] = [];
|
|
598
822
|
const useColor = flags.color !== false;
|
|
@@ -672,6 +896,9 @@ export function formatMigrationPlanOutput(result: MigrationPlanResult, flags: Gl
|
|
|
672
896
|
|
|
673
897
|
lines.push(dim_(`from: ${result.from}`));
|
|
674
898
|
lines.push(dim_(`to: ${result.to}`));
|
|
899
|
+
if (result.baselineDir) {
|
|
900
|
+
lines.push(dim_(`Baseline → ${result.baselineDir}`));
|
|
901
|
+
}
|
|
675
902
|
if (result.dir) {
|
|
676
903
|
lines.push(dim_(`App space → ${result.dir}`));
|
|
677
904
|
}
|
|
@@ -689,8 +916,12 @@ export function formatMigrationPlanOutput(result: MigrationPlanResult, flags: Gl
|
|
|
689
916
|
// (`prisma-next migrate`) regardless of how many spaces were
|
|
690
917
|
// materialised — `db update` is a dev-time convenience, not the
|
|
691
918
|
// canonical replay step.
|
|
919
|
+
const reviewTarget =
|
|
920
|
+
result.baselineDir !== undefined && result.dir !== undefined
|
|
921
|
+
? `${result.baselineDir} and ${result.dir}`
|
|
922
|
+
: (result.baselineDir ?? result.dir ?? '<dir>');
|
|
692
923
|
lines.push(
|
|
693
|
-
`Next: review ${green_(
|
|
924
|
+
`Next: review ${green_(reviewTarget)} if needed, then run ${green_('prisma-next migrate')}.`,
|
|
694
925
|
);
|
|
695
926
|
|
|
696
927
|
if (result.preview && result.preview.statements.length > 0) {
|