prisma-next 0.10.0 → 0.11.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli-errors-Bw2GlweY.mjs +175 -0
- package/dist/cli-errors-Bw2GlweY.mjs.map +1 -0
- package/dist/cli.mjs +400 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-Brv4qlfB.mjs → client-UnIveZxZ.mjs} +6 -5
- package/dist/client-UnIveZxZ.mjs.map +1 -0
- package/dist/{command-helpers-D3vL5yi8.mjs → command-helpers-CRfjbZRz.mjs} +109 -12
- package/dist/command-helpers-CRfjbZRz.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.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +47 -21
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +6 -10
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +8 -12
- 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 +47 -19
- package/dist/commands/db-update.mjs.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 +47 -15
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.mjs +5 -8
- package/dist/commands/migration-check.mjs.map +1 -1
- package/dist/commands/migration-graph.d.mts +1 -1
- package/dist/commands/migration-graph.mjs +6 -10
- package/dist/commands/migration-graph.mjs.map +1 -1
- package/dist/commands/migration-list.mjs +5 -9
- package/dist/commands/migration-list.mjs.map +1 -1
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +7 -10
- package/dist/commands/migration-log.mjs.map +1 -1
- package/dist/commands/migration-new.mjs +6 -10
- 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 +1 -1
- package/dist/commands/migration-show.mjs +9 -13
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +1 -1
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +37 -15
- 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 +41 -25
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/{contract-emit-iynA3BCA.mjs → contract-emit-C6rlsljO.mjs} +7 -6
- package/dist/contract-emit-C6rlsljO.mjs.map +1 -0
- package/dist/{contract-emit-C3STUIBg.mjs → contract-emit-mqXmapxB.mjs} +22 -20
- package/dist/contract-emit-mqXmapxB.mjs.map +1 -0
- package/dist/{contract-infer-Cnj8G1E2.mjs → contract-infer-C4jxc1aZ.mjs} +9 -14
- package/dist/contract-infer-C4jxc1aZ.mjs.map +1 -0
- package/dist/{contract-space-aggregate-loader-pAc8CDfY.mjs → contract-space-aggregate-loader-CGakRlKM.mjs} +2 -2
- package/dist/{contract-space-aggregate-loader-pAc8CDfY.mjs.map → contract-space-aggregate-loader-CGakRlKM.mjs.map} +1 -1
- package/dist/{db-verify-D7cyH_zz.mjs → db-verify-1d8tDoFN.mjs} +9 -13
- package/dist/db-verify-1d8tDoFN.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +2 -2
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{framework-components-xFLFpZUO.mjs → framework-components-Bexd0f4E.mjs} +2 -2
- package/dist/{framework-components-xFLFpZUO.mjs.map → framework-components-Bexd0f4E.mjs.map} +1 -1
- package/dist/{global-flags-DGmw6Kqg.d.mts → global-flags-CdE7M0d9.d.mts} +4 -1
- package/dist/global-flags-CdE7M0d9.d.mts.map +1 -0
- package/dist/{graph-render-eJDcLWny.mjs → graph-render-BE8vmJ_7.mjs} +1 -1
- package/dist/{graph-render-eJDcLWny.mjs.map → graph-render-BE8vmJ_7.mjs.map} +1 -1
- package/dist/{init-eh2z5Tl6.mjs → init-ByoeQphC.mjs} +528 -627
- package/dist/init-ByoeQphC.mjs.map +1 -0
- package/dist/{inspect-live-schema-CWLK_lgs.mjs → inspect-live-schema-B1Q49RF0.mjs} +4 -4
- package/dist/{inspect-live-schema-CWLK_lgs.mjs.map → inspect-live-schema-B1Q49RF0.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-CmXXC1UZ.mjs → migration-command-scaffold-oY4P1Qto.mjs} +4 -4
- package/dist/{migration-command-scaffold-CmXXC1UZ.mjs.map → migration-command-scaffold-oY4P1Qto.mjs.map} +1 -1
- package/dist/{migration-plan-CHyUlBV0.mjs → migration-plan-jdAHg_gK.mjs} +349 -94
- package/dist/migration-plan-jdAHg_gK.mjs.map +1 -0
- package/dist/{migration-types-D2FW63pr.d.mts → migration-types-BXWvz12q.d.mts} +1 -1
- package/dist/{migration-types-D2FW63pr.d.mts.map → migration-types-BXWvz12q.d.mts.map} +1 -1
- package/dist/{migrations-DyUf5lTt.mjs → migrations-B7n518mT.mjs} +11 -2
- package/dist/migrations-B7n518mT.mjs.map +1 -0
- package/dist/{output-B60Gw5fu.mjs → output-CUIdfYo5.mjs} +1 -1
- package/dist/{output-B60Gw5fu.mjs.map → output-CUIdfYo5.mjs.map} +1 -1
- package/dist/quick-reference-mongo.md +1 -1
- package/dist/quick-reference-postgres.md +1 -1
- package/dist/readme-mongo.md +35 -0
- package/dist/readme-postgres.md +34 -0
- package/dist/ref-advancement-DRh5Nquq.mjs +50 -0
- package/dist/ref-advancement-DRh5Nquq.mjs.map +1 -0
- package/dist/{terminal-ui-XtOQsqe9.mjs → terminal-ui-BiB_8KNo.mjs} +131 -24
- package/dist/terminal-ui-BiB_8KNo.mjs.map +1 -0
- package/dist/{types-0aS865QN.d.mts → types-UWB2-rrw.d.mts} +12 -4
- package/dist/types-UWB2-rrw.d.mts.map +1 -0
- package/dist/{verify-D7ypCCe6.mjs → verify-C5UvbrF1.mjs} +2 -2
- package/dist/{verify-D7ypCCe6.mjs.map → verify-C5UvbrF1.mjs.map} +1 -1
- package/package.json +13 -11
- package/dist/cli-errors-CF60g2cG.mjs +0 -71
- package/dist/cli-errors-CF60g2cG.mjs.map +0 -1
- package/dist/cli-errors-DdcjVLJV.d.mts +0 -3
- package/dist/client-Brv4qlfB.mjs.map +0 -1
- package/dist/command-helpers-D3vL5yi8.mjs.map +0 -1
- package/dist/contract-emit-C3STUIBg.mjs.map +0 -1
- package/dist/contract-emit-iynA3BCA.mjs.map +0 -1
- package/dist/contract-infer-Cnj8G1E2.mjs.map +0 -1
- package/dist/db-verify-D7cyH_zz.mjs.map +0 -1
- package/dist/errors-Cw6kyTyV.mjs +0 -56
- package/dist/errors-Cw6kyTyV.mjs.map +0 -1
- package/dist/global-flags-DGmw6Kqg.d.mts.map +0 -1
- package/dist/helpers-eqdN8tH6.mjs +0 -25
- package/dist/helpers-eqdN8tH6.mjs.map +0 -1
- package/dist/init-eh2z5Tl6.mjs.map +0 -1
- package/dist/migration-plan-CHyUlBV0.mjs.map +0 -1
- package/dist/migrations-DyUf5lTt.mjs.map +0 -1
- package/dist/result-handler-Bm_6dDYg.mjs +0 -25
- package/dist/result-handler-Bm_6dDYg.mjs.map +0 -1
- package/dist/terminal-ui-XtOQsqe9.mjs.map +0 -1
- package/dist/types-0aS865QN.d.mts.map +0 -1
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { t as assertFrameworkComponentsCompatible } from "./framework-components-
|
|
4
|
-
import {
|
|
5
|
-
import { t as handleResult } from "./
|
|
6
|
-
import { t as
|
|
7
|
-
import { n as toExtensionInputs, t as buildContractSpaceAggregate } from "./contract-space-aggregate-loader-pAc8CDfY.mjs";
|
|
2
|
+
import { C as errorSnapshotMissing, D as mapMigrationToolsError, E as errorUnexpected, O as mapRefResolutionError, _ as errorPlanForgotTheFlag, a as errorContractValidationFailed, l as errorFileNotFound, m as errorMigrationPlanningFailed, t as CliStructuredError, w as errorTargetMigrationNotSupported } from "./cli-errors-Bw2GlweY.mjs";
|
|
3
|
+
import { t as assertFrameworkComponentsCompatible } from "./framework-components-Bexd0f4E.mjs";
|
|
4
|
+
import { t as createTerminalUI } from "./terminal-ui-BiB_8KNo.mjs";
|
|
5
|
+
import { S as formatStyledHeader, a as loadMigrationPackages, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, i as getTargetMigrations, l as resolveMigrationPaths, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "./command-helpers-CRfjbZRz.mjs";
|
|
6
|
+
import { n as toExtensionInputs, t as buildContractSpaceAggregate } from "./contract-space-aggregate-loader-CGakRlKM.mjs";
|
|
8
7
|
import { Command } from "commander";
|
|
9
8
|
import { getEmittedArtifactPaths } from "@prisma-next/emitter";
|
|
10
9
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
11
10
|
import { join, relative } from "pathe";
|
|
12
|
-
import { readFile } from "node:fs/promises";
|
|
11
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
13
12
|
import { createControlStack, hasOperationPreview } from "@prisma-next/framework-components/control";
|
|
14
13
|
import { copyFilesWithRename, formatMigrationDirName, materialiseExtensionMigrationPackageIfMissing, writeMigrationPackage } from "@prisma-next/migration-tools/io";
|
|
15
|
-
import { findLatestMigration } from "@prisma-next/migration-tools/migration-graph";
|
|
14
|
+
import { assertHashIsGraphNode, findLatestMigration, isGraphNode } from "@prisma-next/migration-tools/migration-graph";
|
|
16
15
|
import { emitContractSpaceArtefacts, planAllSpaces, readContractSpaceHeadRef, spaceMigrationDirectory } from "@prisma-next/migration-tools/spaces";
|
|
17
16
|
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
17
|
+
import { readRefSnapshot, readRefs } from "@prisma-next/migration-tools/refs";
|
|
18
18
|
import { parseContractRef } from "@prisma-next/migration-tools/ref-resolution";
|
|
19
|
-
import { readRefs } from "@prisma-next/migration-tools/refs";
|
|
20
19
|
import { computeMigrationHash } from "@prisma-next/migration-tools/hash";
|
|
21
20
|
import { writeMigrationTs } from "@prisma-next/migration-tools/migration-ts";
|
|
21
|
+
import { canonicalizeJson } from "@prisma-next/framework-components/utils";
|
|
22
22
|
import { deriveProvidedInvariants } from "@prisma-next/migration-tools/invariants";
|
|
23
23
|
//#region src/utils/contract-space-seed-phase.ts
|
|
24
24
|
/**
|
|
@@ -110,6 +110,135 @@ function buildPlaceholderContractDts(spaceId) {
|
|
|
110
110
|
].join("\n");
|
|
111
111
|
}
|
|
112
112
|
//#endregion
|
|
113
|
+
//#region src/utils/plan-resolution.ts
|
|
114
|
+
const FULL_HASH_PATTERN = /^sha256:([0-9a-f]{64}|empty)$/;
|
|
115
|
+
function looksLikeFullHash(input) {
|
|
116
|
+
return FULL_HASH_PATTERN.test(input);
|
|
117
|
+
}
|
|
118
|
+
function graphIsEmpty(bundles) {
|
|
119
|
+
return bundles.length === 0;
|
|
120
|
+
}
|
|
121
|
+
function getReachableRefs(refs, graph) {
|
|
122
|
+
return Object.entries(refs).flatMap(([name, entry]) => entry && isGraphNode(entry.hash, graph) ? [{
|
|
123
|
+
name,
|
|
124
|
+
hash: entry.hash
|
|
125
|
+
}] : []).sort((a, b) => a.name.localeCompare(b.name));
|
|
126
|
+
}
|
|
127
|
+
function assertFromIsGraphNode(fromHash, graph, refs, graphTipHash) {
|
|
128
|
+
try {
|
|
129
|
+
assertHashIsGraphNode(fromHash, graph);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (MigrationToolsError.is(error) && error.code === "MIGRATION.HASH_NOT_IN_GRAPH") throw errorPlanForgotTheFlag(fromHash, getReachableRefs(refs, graph), graphTipHash);
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function deserializeSnapshotContract(familyInstance, contract) {
|
|
136
|
+
try {
|
|
137
|
+
return ok(familyInstance.deserializeContract(contract));
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (CliStructuredError.is(error)) return notOk(error);
|
|
140
|
+
return notOk(errorContractValidationFailed(`Ref snapshot contract failed to deserialize: ${error instanceof Error ? error.message : String(error)}`, { where: { path: "ref-snapshot" } }));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function resolveGraphNodeFromBundle(fromHash, bundles, readBundleEndContract, explicitFromLabel) {
|
|
144
|
+
const matchingBundle = bundles.find((pkg) => pkg.metadata.to === fromHash);
|
|
145
|
+
if (!matchingBundle) return notOk(errorUnexpected(explicitFromLabel ? `No migration bundle found for --from "${explicitFromLabel}" (resolved hash: ${fromHash})` : `No migration bundle found for graph node ${fromHash}`, {
|
|
146
|
+
why: `The hash ${fromHash} is a graph node but no on-disk migration package has an end-contract hash matching it.`,
|
|
147
|
+
fix: "Provide a ref or hash that corresponds to an existing migration package, or run `migration list` to see available migrations."
|
|
148
|
+
}));
|
|
149
|
+
try {
|
|
150
|
+
return ok({
|
|
151
|
+
kind: "graph-node",
|
|
152
|
+
fromHash,
|
|
153
|
+
fromContract: await readBundleEndContract(matchingBundle.dirPath),
|
|
154
|
+
sourceDir: matchingBundle.dirPath
|
|
155
|
+
});
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (CliStructuredError.is(error)) return notOk(error);
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function resolveFromRefName(refName, fromHash, input, refs) {
|
|
162
|
+
const { refsDir, bundles, graph, familyInstance, readBundleEndContract } = input;
|
|
163
|
+
const empty = graphIsEmpty(bundles);
|
|
164
|
+
const graphTip = findLatestMigration(graph)?.to ?? null;
|
|
165
|
+
let snapshot;
|
|
166
|
+
try {
|
|
167
|
+
snapshot = await readRefSnapshot(refsDir, refName);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
if (snapshot) {
|
|
173
|
+
const contractResult = await deserializeSnapshotContract(familyInstance, snapshot.contract);
|
|
174
|
+
if (!contractResult.ok) return contractResult;
|
|
175
|
+
const fromContract = contractResult.value;
|
|
176
|
+
const { contractDts, contract: contractJson } = snapshot;
|
|
177
|
+
if (empty) return ok({
|
|
178
|
+
kind: "auto-baseline",
|
|
179
|
+
fromHash,
|
|
180
|
+
fromContract,
|
|
181
|
+
contractDts,
|
|
182
|
+
contractJson
|
|
183
|
+
});
|
|
184
|
+
try {
|
|
185
|
+
assertFromIsGraphNode(fromHash, graph, refs, graphTip);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
if (CliStructuredError.is(error)) return notOk(error);
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
return ok({
|
|
191
|
+
kind: "snapshot",
|
|
192
|
+
fromHash,
|
|
193
|
+
fromContract,
|
|
194
|
+
contractDts,
|
|
195
|
+
contractJson
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (isGraphNode(fromHash, graph)) return resolveGraphNodeFromBundle(fromHash, bundles, readBundleEndContract);
|
|
199
|
+
return notOk(errorSnapshotMissing(refName));
|
|
200
|
+
}
|
|
201
|
+
async function resolveFromHashProvenance(fromHash, input, _refs, explicitFromLabel) {
|
|
202
|
+
const { bundles, graph } = input;
|
|
203
|
+
if (isGraphNode(fromHash, graph)) return resolveGraphNodeFromBundle(fromHash, bundles, input.readBundleEndContract, explicitFromLabel);
|
|
204
|
+
throw new Error(`resolveFromHashProvenance: non-graph-node hash ${fromHash} should be refused via looksLikeFullHash before this helper is called`);
|
|
205
|
+
}
|
|
206
|
+
async function resolveFromForPlan(input) {
|
|
207
|
+
const { optionsFrom, refsDir, graph } = input;
|
|
208
|
+
let refs;
|
|
209
|
+
try {
|
|
210
|
+
refs = await readRefs(refsDir);
|
|
211
|
+
} catch (error) {
|
|
212
|
+
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
if (optionsFrom === void 0) {
|
|
216
|
+
const dbRef = refs["db"];
|
|
217
|
+
if (!dbRef) return ok({
|
|
218
|
+
kind: "greenfield",
|
|
219
|
+
fromHash: null,
|
|
220
|
+
fromContract: null
|
|
221
|
+
});
|
|
222
|
+
return resolveFromRefName("db", dbRef.hash, input, refs);
|
|
223
|
+
}
|
|
224
|
+
const refResult = parseContractRef(optionsFrom, {
|
|
225
|
+
graph,
|
|
226
|
+
refs
|
|
227
|
+
});
|
|
228
|
+
if (!refResult.ok) {
|
|
229
|
+
if (looksLikeFullHash(optionsFrom)) {
|
|
230
|
+
const empty = graphIsEmpty(input.bundles);
|
|
231
|
+
const graphTip = findLatestMigration(graph)?.to ?? null;
|
|
232
|
+
if (empty) return notOk(errorSnapshotMissing(optionsFrom, { viaRef: false }));
|
|
233
|
+
return notOk(errorPlanForgotTheFlag(optionsFrom, getReachableRefs(refs, graph), graphTip));
|
|
234
|
+
}
|
|
235
|
+
return notOk(mapRefResolutionError(refResult.failure));
|
|
236
|
+
}
|
|
237
|
+
const { hash: fromHash, provenance } = refResult.value;
|
|
238
|
+
if (provenance.kind === "ref") return resolveFromRefName(provenance.refName, fromHash, input, refs);
|
|
239
|
+
return resolveFromHashProvenance(fromHash, input, refs, optionsFrom);
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
113
242
|
//#region src/commands/migration-plan.ts
|
|
114
243
|
/**
|
|
115
244
|
* Load a predecessor migration's destination contract from its sibling
|
|
@@ -149,6 +278,70 @@ async function readPredecessorEndContract(migrationDir, familyInstance) {
|
|
|
149
278
|
throw errorContractValidationFailed(`Predecessor contract at ${path} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`, { where: { path } });
|
|
150
279
|
}
|
|
151
280
|
}
|
|
281
|
+
async function writeSnapshotContractArtifacts(packageDir, contractJson, contractDts, artifactBasename) {
|
|
282
|
+
await mkdir(packageDir, { recursive: true });
|
|
283
|
+
const jsonContent = `${canonicalizeJson(contractJson)}\n`;
|
|
284
|
+
const dtsContent = contractDts.endsWith("\n") ? contractDts : `${contractDts}\n`;
|
|
285
|
+
await writeFile(join(packageDir, `${artifactBasename}.json`), jsonContent);
|
|
286
|
+
await writeFile(join(packageDir, `${artifactBasename}.d.ts`), dtsContent);
|
|
287
|
+
}
|
|
288
|
+
async function writeSnapshotStartContract(packageDir, contractJson, contractDts) {
|
|
289
|
+
await writeSnapshotContractArtifacts(packageDir, contractJson, contractDts, "start-contract");
|
|
290
|
+
}
|
|
291
|
+
async function runPlannerLeg(planner, migrations, frameworkComponents, contract, fromContract, spaceId) {
|
|
292
|
+
const fromSchema = migrations.contractToSchema(fromContract, frameworkComponents);
|
|
293
|
+
const plannerResult = planner.plan({
|
|
294
|
+
contract,
|
|
295
|
+
schema: fromSchema,
|
|
296
|
+
policy: { allowedOperationClasses: [
|
|
297
|
+
"additive",
|
|
298
|
+
"widening",
|
|
299
|
+
"destructive",
|
|
300
|
+
"data"
|
|
301
|
+
] },
|
|
302
|
+
fromContract,
|
|
303
|
+
frameworkComponents,
|
|
304
|
+
spaceId
|
|
305
|
+
});
|
|
306
|
+
if (plannerResult.kind === "failure") return notOk(errorMigrationPlanningFailed({ conflicts: plannerResult.conflicts }));
|
|
307
|
+
let plannedOps = [];
|
|
308
|
+
let hasPlaceholders = false;
|
|
309
|
+
try {
|
|
310
|
+
plannedOps = plannerResult.plan.operations;
|
|
311
|
+
if (plannedOps.length === 0) return notOk(errorMigrationPlanningFailed({ conflicts: [{
|
|
312
|
+
kind: "unsupportedChange",
|
|
313
|
+
summary: "Contract changed but planner produced no operations. This indicates unsupported or ignored changes."
|
|
314
|
+
}] }));
|
|
315
|
+
} catch (e) {
|
|
316
|
+
if (CliStructuredError.is(e) && e.domain === "MIG" && e.code === "2001") hasPlaceholders = true;
|
|
317
|
+
else throw e;
|
|
318
|
+
}
|
|
319
|
+
return ok({
|
|
320
|
+
plannedOps,
|
|
321
|
+
migrationTsContent: plannerResult.plan.renderTypeScript(),
|
|
322
|
+
hasPlaceholders
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
async function writePlannedMigrationPackage(packageDir, fromHash, toHash, createdAt, leg) {
|
|
326
|
+
const opsForWrite = leg.hasPlaceholders ? [] : leg.plannedOps;
|
|
327
|
+
const metadataWithInvariants = {
|
|
328
|
+
from: fromHash,
|
|
329
|
+
to: toHash,
|
|
330
|
+
hints: {
|
|
331
|
+
used: [],
|
|
332
|
+
applied: [],
|
|
333
|
+
plannerVersion: "2.0.0"
|
|
334
|
+
},
|
|
335
|
+
labels: [],
|
|
336
|
+
providedInvariants: deriveProvidedInvariants(opsForWrite),
|
|
337
|
+
createdAt: createdAt.toISOString()
|
|
338
|
+
};
|
|
339
|
+
await writeMigrationPackage(packageDir, {
|
|
340
|
+
...metadataWithInvariants,
|
|
341
|
+
migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite)
|
|
342
|
+
}, opsForWrite);
|
|
343
|
+
await writeMigrationTs(packageDir, leg.migrationTsContent);
|
|
344
|
+
}
|
|
152
345
|
async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
153
346
|
const config = await loadConfig(options.config);
|
|
154
347
|
const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);
|
|
@@ -207,36 +400,47 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
207
400
|
const rawStorageHash = toContract.storage?.storageHash;
|
|
208
401
|
if (typeof rawStorageHash !== "string") return notOk(errorContractValidationFailed("Contract is missing storageHash", { where: { path: contractPathAbsolute } }));
|
|
209
402
|
const toStorageHash = rawStorageHash;
|
|
403
|
+
const { refsDir } = resolveMigrationPaths(options.config, config);
|
|
210
404
|
let fromContract = null;
|
|
211
405
|
let fromHash = null;
|
|
212
406
|
let fromContractSourceDir = null;
|
|
407
|
+
let snapshotStartContract = null;
|
|
408
|
+
let isAutoBaseline = false;
|
|
213
409
|
try {
|
|
214
410
|
const { bundles, graph } = await loadMigrationPackages(appMigrationsDir);
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
411
|
+
const resolutionResult = await resolveFromForPlan({
|
|
412
|
+
optionsFrom: options.from,
|
|
413
|
+
refsDir,
|
|
414
|
+
bundles,
|
|
415
|
+
graph,
|
|
416
|
+
familyInstance,
|
|
417
|
+
readBundleEndContract: (migrationDir) => readPredecessorEndContract(migrationDir, familyInstance)
|
|
418
|
+
});
|
|
419
|
+
if (!resolutionResult.ok) return notOk(resolutionResult.failure);
|
|
420
|
+
switch (resolutionResult.value.kind) {
|
|
421
|
+
case "greenfield": break;
|
|
422
|
+
case "graph-node":
|
|
423
|
+
fromHash = resolutionResult.value.fromHash;
|
|
424
|
+
fromContract = resolutionResult.value.fromContract;
|
|
425
|
+
fromContractSourceDir = resolutionResult.value.sourceDir;
|
|
426
|
+
break;
|
|
427
|
+
case "snapshot":
|
|
428
|
+
fromHash = resolutionResult.value.fromHash;
|
|
429
|
+
fromContract = resolutionResult.value.fromContract;
|
|
430
|
+
snapshotStartContract = {
|
|
431
|
+
contractJson: resolutionResult.value.contractJson,
|
|
432
|
+
contractDts: resolutionResult.value.contractDts
|
|
433
|
+
};
|
|
434
|
+
break;
|
|
435
|
+
case "auto-baseline":
|
|
436
|
+
fromHash = resolutionResult.value.fromHash;
|
|
437
|
+
fromContract = resolutionResult.value.fromContract;
|
|
438
|
+
snapshotStartContract = {
|
|
439
|
+
contractJson: resolutionResult.value.contractJson,
|
|
440
|
+
contractDts: resolutionResult.value.contractDts
|
|
441
|
+
};
|
|
442
|
+
isAutoBaseline = true;
|
|
443
|
+
break;
|
|
240
444
|
}
|
|
241
445
|
} catch (error) {
|
|
242
446
|
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
@@ -258,7 +462,7 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
258
462
|
spaceId: r.spaceId,
|
|
259
463
|
dirName
|
|
260
464
|
})));
|
|
261
|
-
if (fromHash === toStorageHash) return ok({
|
|
465
|
+
if (fromHash === toStorageHash && !isAutoBaseline) return ok({
|
|
262
466
|
ok: true,
|
|
263
467
|
noOp: true,
|
|
264
468
|
from: fromHash,
|
|
@@ -284,58 +488,105 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
284
488
|
config.adapter,
|
|
285
489
|
...config.extensionPacks ?? []
|
|
286
490
|
]);
|
|
287
|
-
const timestamp = /* @__PURE__ */ new Date();
|
|
288
|
-
const packageDir = join(appMigrationsDir, formatMigrationDirName(timestamp, options.name ?? "migration"));
|
|
289
|
-
const baseMetadata = {
|
|
290
|
-
from: fromHash,
|
|
291
|
-
to: toStorageHash,
|
|
292
|
-
hints: {
|
|
293
|
-
used: [],
|
|
294
|
-
applied: [],
|
|
295
|
-
plannerVersion: "2.0.0"
|
|
296
|
-
},
|
|
297
|
-
labels: [],
|
|
298
|
-
createdAt: timestamp.toISOString()
|
|
299
|
-
};
|
|
300
491
|
try {
|
|
301
492
|
const planner = migrations.createPlanner(familyInstance);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
493
|
+
if (isAutoBaseline && fromHash !== null && fromContract !== null && snapshotStartContract !== null) {
|
|
494
|
+
const baselineTimestamp = /* @__PURE__ */ new Date();
|
|
495
|
+
const deltaTimestamp = new Date(baselineTimestamp.getTime() + 6e4);
|
|
496
|
+
const baselineDirName = formatMigrationDirName(baselineTimestamp, "baseline");
|
|
497
|
+
const deltaDirName = formatMigrationDirName(deltaTimestamp, options.name ?? "migration");
|
|
498
|
+
const baselinePackageDir = join(appMigrationsDir, baselineDirName);
|
|
499
|
+
const deltaPackageDir = join(appMigrationsDir, deltaDirName);
|
|
500
|
+
const baselineLeg = await runPlannerLeg(planner, migrations, frameworkComponents, fromContract, null, aggregate.app.spaceId);
|
|
501
|
+
if (!baselineLeg.ok) return notOk(baselineLeg.failure);
|
|
502
|
+
await writePlannedMigrationPackage(baselinePackageDir, null, fromHash, baselineTimestamp, baselineLeg.value);
|
|
503
|
+
await writeSnapshotContractArtifacts(baselinePackageDir, snapshotStartContract.contractJson, snapshotStartContract.contractDts, "end-contract");
|
|
504
|
+
if (fromHash === toStorageHash) {
|
|
505
|
+
const baselineOps = baselineLeg.value.hasPlaceholders ? [] : baselineLeg.value.plannedOps;
|
|
506
|
+
if (baselineLeg.value.hasPlaceholders) {
|
|
507
|
+
const baselineDir = relative(process.cwd(), baselinePackageDir);
|
|
508
|
+
return ok({
|
|
509
|
+
ok: true,
|
|
510
|
+
noOp: false,
|
|
511
|
+
from: fromHash,
|
|
512
|
+
to: toStorageHash,
|
|
513
|
+
dir: baselineDir,
|
|
514
|
+
baselineDir,
|
|
515
|
+
operations: [],
|
|
516
|
+
emittedExtensionDirs,
|
|
517
|
+
pendingPlaceholders: true,
|
|
518
|
+
summary: "Planned baseline with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit",
|
|
519
|
+
timings: { total: Date.now() - startTime }
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(baselineOps) : void 0;
|
|
523
|
+
return ok({
|
|
524
|
+
ok: true,
|
|
525
|
+
noOp: false,
|
|
526
|
+
from: fromHash,
|
|
527
|
+
to: toStorageHash,
|
|
528
|
+
baselineDir: relative(process.cwd(), baselinePackageDir),
|
|
529
|
+
operations: baselineOps.map((op) => ({
|
|
530
|
+
id: op.id,
|
|
531
|
+
label: op.label,
|
|
532
|
+
operationClass: op.operationClass
|
|
533
|
+
})),
|
|
534
|
+
emittedExtensionDirs,
|
|
535
|
+
...preview !== void 0 ? { preview } : {},
|
|
536
|
+
summary: buildAutoBaselinePlanSummary(0, emittedExtensionDirs.length),
|
|
537
|
+
timings: { total: Date.now() - startTime }
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
const deltaLeg = await runPlannerLeg(planner, migrations, frameworkComponents, aggregate.app.contract, fromContract, aggregate.app.spaceId);
|
|
541
|
+
if (!deltaLeg.ok) return notOk(deltaLeg.failure);
|
|
542
|
+
await writePlannedMigrationPackage(deltaPackageDir, fromHash, toStorageHash, deltaTimestamp, deltaLeg.value);
|
|
543
|
+
const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
|
|
544
|
+
await copyFilesWithRename(deltaPackageDir, [{
|
|
545
|
+
sourcePath: destinationArtifacts.jsonPath,
|
|
546
|
+
destName: "end-contract.json"
|
|
547
|
+
}, {
|
|
548
|
+
sourcePath: destinationArtifacts.dtsPath,
|
|
549
|
+
destName: "end-contract.d.ts"
|
|
550
|
+
}]);
|
|
551
|
+
await writeSnapshotStartContract(deltaPackageDir, snapshotStartContract.contractJson, snapshotStartContract.contractDts);
|
|
552
|
+
const deltaOps = deltaLeg.value.hasPlaceholders ? [] : deltaLeg.value.plannedOps;
|
|
553
|
+
if (deltaLeg.value.hasPlaceholders) return ok({
|
|
554
|
+
ok: true,
|
|
555
|
+
noOp: false,
|
|
556
|
+
from: fromHash,
|
|
557
|
+
to: toStorageHash,
|
|
558
|
+
dir: relative(process.cwd(), deltaPackageDir),
|
|
559
|
+
baselineDir: relative(process.cwd(), baselinePackageDir),
|
|
560
|
+
operations: [],
|
|
561
|
+
emittedExtensionDirs,
|
|
562
|
+
pendingPlaceholders: true,
|
|
563
|
+
summary: "Planned baseline + migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit",
|
|
564
|
+
timings: { total: Date.now() - startTime }
|
|
565
|
+
});
|
|
566
|
+
const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(deltaOps) : void 0;
|
|
567
|
+
return ok({
|
|
568
|
+
ok: true,
|
|
569
|
+
noOp: false,
|
|
570
|
+
from: fromHash,
|
|
571
|
+
to: toStorageHash,
|
|
572
|
+
dir: relative(process.cwd(), deltaPackageDir),
|
|
573
|
+
baselineDir: relative(process.cwd(), baselinePackageDir),
|
|
574
|
+
operations: deltaOps.map((op) => ({
|
|
575
|
+
id: op.id,
|
|
576
|
+
label: op.label,
|
|
577
|
+
operationClass: op.operationClass
|
|
578
|
+
})),
|
|
579
|
+
emittedExtensionDirs,
|
|
580
|
+
...preview !== void 0 ? { preview } : {},
|
|
581
|
+
summary: buildAutoBaselinePlanSummary(deltaOps.length, emittedExtensionDirs.length),
|
|
582
|
+
timings: { total: Date.now() - startTime }
|
|
583
|
+
});
|
|
328
584
|
}
|
|
329
|
-
const
|
|
330
|
-
const
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
};
|
|
335
|
-
await writeMigrationPackage(packageDir, {
|
|
336
|
-
...metadataWithInvariants,
|
|
337
|
-
migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite)
|
|
338
|
-
}, opsForWrite);
|
|
585
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
586
|
+
const packageDir = join(appMigrationsDir, formatMigrationDirName(timestamp, options.name ?? "migration"));
|
|
587
|
+
const deltaLeg = await runPlannerLeg(planner, migrations, frameworkComponents, aggregate.app.contract, fromContract, aggregate.app.spaceId);
|
|
588
|
+
if (!deltaLeg.ok) return notOk(deltaLeg.failure);
|
|
589
|
+
await writePlannedMigrationPackage(packageDir, fromHash, toStorageHash, timestamp, deltaLeg.value);
|
|
339
590
|
const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
|
|
340
591
|
await copyFilesWithRename(packageDir, [{
|
|
341
592
|
sourcePath: destinationArtifacts.jsonPath,
|
|
@@ -353,9 +604,8 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
353
604
|
sourcePath: sourceArtifacts.dtsPath,
|
|
354
605
|
destName: "start-contract.d.ts"
|
|
355
606
|
}]);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (hasPlaceholders) return ok({
|
|
607
|
+
} else if (snapshotStartContract !== null) await writeSnapshotStartContract(packageDir, snapshotStartContract.contractJson, snapshotStartContract.contractDts);
|
|
608
|
+
if (deltaLeg.value.hasPlaceholders) return ok({
|
|
359
609
|
ok: true,
|
|
360
610
|
noOp: false,
|
|
361
611
|
from: fromHash,
|
|
@@ -367,6 +617,7 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
367
617
|
summary: "Planned migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit",
|
|
368
618
|
timings: { total: Date.now() - startTime }
|
|
369
619
|
});
|
|
620
|
+
const plannedOps = deltaLeg.value.plannedOps;
|
|
370
621
|
const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(plannedOps) : void 0;
|
|
371
622
|
return ok({
|
|
372
623
|
ok: true,
|
|
@@ -396,12 +647,9 @@ function createMigrationPlanCommand() {
|
|
|
396
647
|
setCommandDescriptions(command, "Plan a migration from contract changes", "Compares the emitted contract against the latest on-disk migration state and\nproduces a new migration package with the required operations. No database\nconnection is needed — this is a fully offline operation.");
|
|
397
648
|
setCommandExamples(command, ["prisma-next migration plan", "prisma-next migration plan --name add-users-table"]);
|
|
398
649
|
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").option("--name <slug>", "Name slug for the migration directory", "migration").option("--from <contract>", "Starting contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)").action(async (options) => {
|
|
399
|
-
const flags =
|
|
650
|
+
const flags = parseGlobalFlagsOrExit(options);
|
|
400
651
|
const startTime = Date.now();
|
|
401
|
-
const ui =
|
|
402
|
-
color: flags.color,
|
|
403
|
-
interactive: flags.interactive
|
|
404
|
-
});
|
|
652
|
+
const ui = createTerminalUI(flags);
|
|
405
653
|
const exitCode = handleResult(await executeMigrationPlanCommand(options, flags, ui, startTime), flags, ui, (planResult) => {
|
|
406
654
|
if (flags.json) ui.output(JSON.stringify(planResult, null, 2));
|
|
407
655
|
else if (!flags.quiet) ui.log(formatMigrationPlanOutput(planResult, flags));
|
|
@@ -429,6 +677,11 @@ function buildPlanSummary(plannedOpsCount, emittedExtensionDirsCount) {
|
|
|
429
677
|
if (emittedExtensionDirsCount === 0) return base;
|
|
430
678
|
return `${base}; materialised ${emittedExtensionDirsCount} ${emittedExtensionDirsCount === 1 ? "extension-space migration" : "extension-space migrations"}`;
|
|
431
679
|
}
|
|
680
|
+
function buildAutoBaselinePlanSummary(deltaOpsCount, emittedExtensionDirsCount) {
|
|
681
|
+
const base = `Planned baseline + ${deltaOpsCount} operation(s)`;
|
|
682
|
+
if (emittedExtensionDirsCount === 0) return base;
|
|
683
|
+
return `${base}; materialised ${emittedExtensionDirsCount} ${emittedExtensionDirsCount === 1 ? "extension-space migration" : "extension-space migrations"}`;
|
|
684
|
+
}
|
|
432
685
|
function formatMigrationPlanOutput(result, flags) {
|
|
433
686
|
const lines = [];
|
|
434
687
|
const useColor = flags.color !== false;
|
|
@@ -480,10 +733,12 @@ function formatMigrationPlanOutput(result, flags) {
|
|
|
480
733
|
}
|
|
481
734
|
lines.push(dim_(`from: ${result.from}`));
|
|
482
735
|
lines.push(dim_(`to: ${result.to}`));
|
|
736
|
+
if (result.baselineDir) lines.push(dim_(`Baseline → ${result.baselineDir}`));
|
|
483
737
|
if (result.dir) lines.push(dim_(`App space → ${result.dir}`));
|
|
484
738
|
for (const entry of result.emittedExtensionDirs) lines.push(dim_(`Extension space ${entry.spaceId} → migrations/${entry.spaceId}/${entry.dirName}`));
|
|
485
739
|
lines.push("");
|
|
486
|
-
|
|
740
|
+
const reviewTarget = result.baselineDir !== void 0 && result.dir !== void 0 ? `${result.baselineDir} and ${result.dir}` : result.baselineDir ?? result.dir ?? "<dir>";
|
|
741
|
+
lines.push(`Next: review ${green_(reviewTarget)} if needed, then run ${green_("prisma-next migrate")}.`);
|
|
487
742
|
if (result.preview && result.preview.statements.length > 0) {
|
|
488
743
|
const allSql = result.preview.statements.every((s) => s.language === "sql");
|
|
489
744
|
lines.push("");
|
|
@@ -530,4 +785,4 @@ function resolveBundleByPrefix(bundles, needle) {
|
|
|
530
785
|
//#endregion
|
|
531
786
|
export { formatMigrationPlanOutput as n, resolveBundleByPrefix as r, createMigrationPlanCommand as t };
|
|
532
787
|
|
|
533
|
-
//# sourceMappingURL=migration-plan-
|
|
788
|
+
//# sourceMappingURL=migration-plan-jdAHg_gK.mjs.map
|