prisma-next 0.11.0-dev.3 → 0.11.0-dev.31

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.
Files changed (123) hide show
  1. package/dist/cli-errors-DFF1LlfU.mjs +215 -0
  2. package/dist/cli-errors-DFF1LlfU.mjs.map +1 -0
  3. package/dist/cli.mjs +8 -9
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/{client-oXO2WCPD.mjs → client-a5NJce0-.mjs} +5 -5
  6. package/dist/{client-oXO2WCPD.mjs.map → client-a5NJce0-.mjs.map} +1 -1
  7. package/dist/{command-helpers-DtavI0wJ.mjs → command-helpers-BnqwTptC.mjs} +380 -6
  8. package/dist/command-helpers-BnqwTptC.mjs.map +1 -0
  9. package/dist/commands/contract-emit.d.mts.map +1 -1
  10. package/dist/commands/contract-emit.mjs +1 -1
  11. package/dist/commands/contract-infer.d.mts.map +1 -1
  12. package/dist/commands/contract-infer.mjs +1 -1
  13. package/dist/commands/db-init.d.mts.map +1 -1
  14. package/dist/commands/db-init.mjs +33 -7
  15. package/dist/commands/db-init.mjs.map +1 -1
  16. package/dist/commands/db-schema.d.mts.map +1 -1
  17. package/dist/commands/db-schema.mjs +3 -4
  18. package/dist/commands/db-schema.mjs.map +1 -1
  19. package/dist/commands/db-sign.d.mts.map +1 -1
  20. package/dist/commands/db-sign.mjs +6 -7
  21. package/dist/commands/db-sign.mjs.map +1 -1
  22. package/dist/commands/db-update.d.mts.map +1 -1
  23. package/dist/commands/db-update.mjs +36 -8
  24. package/dist/commands/db-update.mjs.map +1 -1
  25. package/dist/commands/db-verify.d.mts.map +1 -1
  26. package/dist/commands/db-verify.mjs +1 -1
  27. package/dist/commands/migrate.d.mts +5 -1
  28. package/dist/commands/migrate.d.mts.map +1 -1
  29. package/dist/commands/migrate.mjs +44 -9
  30. package/dist/commands/migrate.mjs.map +1 -1
  31. package/dist/commands/migration-check.d.mts.map +1 -1
  32. package/dist/commands/migration-check.mjs +2 -3
  33. package/dist/commands/migration-check.mjs.map +1 -1
  34. package/dist/commands/migration-graph.d.mts.map +1 -1
  35. package/dist/commands/migration-graph.mjs +2 -3
  36. package/dist/commands/migration-graph.mjs.map +1 -1
  37. package/dist/commands/migration-list.d.mts +57 -13
  38. package/dist/commands/migration-list.d.mts.map +1 -1
  39. package/dist/commands/migration-list.mjs +2 -103
  40. package/dist/commands/migration-log.d.mts.map +1 -1
  41. package/dist/commands/migration-log.mjs +3 -4
  42. package/dist/commands/migration-log.mjs.map +1 -1
  43. package/dist/commands/migration-new.d.mts.map +1 -1
  44. package/dist/commands/migration-new.mjs +3 -4
  45. package/dist/commands/migration-new.mjs.map +1 -1
  46. package/dist/commands/migration-plan.d.mts +1 -0
  47. package/dist/commands/migration-plan.d.mts.map +1 -1
  48. package/dist/commands/migration-plan.mjs +1 -1
  49. package/dist/commands/migration-show.d.mts +1 -1
  50. package/dist/commands/migration-show.d.mts.map +1 -1
  51. package/dist/commands/migration-show.mjs +6 -7
  52. package/dist/commands/migration-show.mjs.map +1 -1
  53. package/dist/commands/migration-status.d.mts.map +1 -1
  54. package/dist/commands/migration-status.mjs +6 -7
  55. package/dist/commands/migration-status.mjs.map +1 -1
  56. package/dist/commands/ref.d.mts +1 -1
  57. package/dist/commands/ref.d.mts.map +1 -1
  58. package/dist/commands/ref.mjs +34 -9
  59. package/dist/commands/ref.mjs.map +1 -1
  60. package/dist/config-loader-B6sJjXTv.mjs.map +1 -1
  61. package/dist/config-loader.d.mts.map +1 -1
  62. package/dist/{contract-emit-bcrpT-wD.mjs → contract-emit-DYBHfZqL.mjs} +8 -7
  63. package/dist/contract-emit-DYBHfZqL.mjs.map +1 -0
  64. package/dist/{contract-emit-uwT-Mj8-.mjs → contract-emit-aFcOi3aw.mjs} +20 -14
  65. package/dist/contract-emit-aFcOi3aw.mjs.map +1 -0
  66. package/dist/{contract-enrichment-Dani0mMW.mjs → contract-enrichment-XmUPhmsS.mjs} +4 -25
  67. package/dist/contract-enrichment-XmUPhmsS.mjs.map +1 -0
  68. package/dist/{contract-infer-pKkiCt7C.mjs → contract-infer-BpJeg-Eu.mjs} +3 -4
  69. package/dist/{contract-infer-pKkiCt7C.mjs.map → contract-infer-BpJeg-Eu.mjs.map} +1 -1
  70. package/dist/{contract-space-aggregate-loader-BmNQwlws.mjs → contract-space-aggregate-loader-EVU3n9YE.mjs} +2 -2
  71. package/dist/{contract-space-aggregate-loader-BmNQwlws.mjs.map → contract-space-aggregate-loader-EVU3n9YE.mjs.map} +1 -1
  72. package/dist/{db-verify-AoIUriL4.mjs → db-verify-CxtdGiL3.mjs} +6 -7
  73. package/dist/{db-verify-AoIUriL4.mjs.map → db-verify-CxtdGiL3.mjs.map} +1 -1
  74. package/dist/exports/control-api.d.mts +1 -1
  75. package/dist/exports/control-api.d.mts.map +1 -1
  76. package/dist/exports/control-api.mjs +3 -3
  77. package/dist/exports/index.d.mts.map +1 -1
  78. package/dist/exports/index.mjs +1 -1
  79. package/dist/exports/index.mjs.map +1 -1
  80. package/dist/exports/init-output.d.mts.map +1 -1
  81. package/dist/exports/init-output.mjs +1 -1
  82. package/dist/{framework-components-65gOHkHB.mjs → framework-components-DTcjouhS.mjs} +2 -2
  83. package/dist/{framework-components-65gOHkHB.mjs.map → framework-components-DTcjouhS.mjs.map} +1 -1
  84. package/dist/global-flags-CdE7M0d9.d.mts.map +1 -1
  85. package/dist/graph-render-DJVv0_uf.mjs.map +1 -1
  86. package/dist/{init-YX6lCJpG.mjs → init-eGkSo7hi.mjs} +5 -5
  87. package/dist/{init-YX6lCJpG.mjs.map → init-eGkSo7hi.mjs.map} +1 -1
  88. package/dist/{inspect-live-schema-LeWvkZVz.mjs → inspect-live-schema-B1GCyjAJ.mjs} +5 -5
  89. package/dist/{inspect-live-schema-LeWvkZVz.mjs.map → inspect-live-schema-B1GCyjAJ.mjs.map} +1 -1
  90. package/dist/migration-cli.d.mts.map +1 -1
  91. package/dist/migration-cli.mjs.map +1 -1
  92. package/dist/{migration-command-scaffold-BtkunvFQ.mjs → migration-command-scaffold-CNdZl60X.mjs} +5 -5
  93. package/dist/{migration-command-scaffold-BtkunvFQ.mjs.map → migration-command-scaffold-CNdZl60X.mjs.map} +1 -1
  94. package/dist/migration-list-CnYiHrNV.mjs +288 -0
  95. package/dist/migration-list-CnYiHrNV.mjs.map +1 -0
  96. package/dist/{migration-plan-C2jeH1J5.mjs → migration-plan-BnmP_yNz.mjs} +346 -88
  97. package/dist/migration-plan-BnmP_yNz.mjs.map +1 -0
  98. package/dist/{migrations-CwZMa1Ck.mjs → migrations-C7YTBnLy.mjs} +11 -2
  99. package/dist/migrations-C7YTBnLy.mjs.map +1 -0
  100. package/dist/{output-BlsrGMEF.mjs → output-CUIdfYo5.mjs} +1 -1
  101. package/dist/{output-BlsrGMEF.mjs.map → output-CUIdfYo5.mjs.map} +1 -1
  102. package/dist/{progress-adapter-DFfvZcYL.mjs → progress-adapter-xASh41wr.mjs} +1 -1
  103. package/dist/{progress-adapter-DFfvZcYL.mjs.map → progress-adapter-xASh41wr.mjs.map} +1 -1
  104. package/dist/ref-advancement-CHJ_8HxQ.mjs +50 -0
  105. package/dist/ref-advancement-CHJ_8HxQ.mjs.map +1 -0
  106. package/dist/{types--CqjMdk0.d.mts → types-UWB2-rrw.d.mts} +12 -4
  107. package/dist/types-UWB2-rrw.d.mts.map +1 -0
  108. package/dist/{verify-Bom75OYI.mjs → verify-DX4RQwq4.mjs} +2 -2
  109. package/dist/{verify-Bom75OYI.mjs.map → verify-DX4RQwq4.mjs.map} +1 -1
  110. package/package.json +12 -12
  111. package/dist/cli-errors-Czmx92Zy.d.mts +0 -3
  112. package/dist/cli-errors-Djtz98Vm.mjs +0 -71
  113. package/dist/cli-errors-Djtz98Vm.mjs.map +0 -1
  114. package/dist/command-helpers-DtavI0wJ.mjs.map +0 -1
  115. package/dist/commands/migration-list.mjs.map +0 -1
  116. package/dist/contract-emit-bcrpT-wD.mjs.map +0 -1
  117. package/dist/contract-emit-uwT-Mj8-.mjs.map +0 -1
  118. package/dist/contract-enrichment-Dani0mMW.mjs.map +0 -1
  119. package/dist/migration-plan-C2jeH1J5.mjs.map +0 -1
  120. package/dist/migrations-CwZMa1Ck.mjs.map +0 -1
  121. package/dist/terminal-ui-BiB_8KNo.mjs +0 -379
  122. package/dist/terminal-ui-BiB_8KNo.mjs.map +0 -1
  123. package/dist/types--CqjMdk0.d.mts.map +0 -1
@@ -1,23 +1,23 @@
1
1
  import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
2
- import { _ as errorTargetMigrationNotSupported, a as errorContractValidationFailed, b as mapMigrationToolsError, l as errorFileNotFound, p as errorMigrationPlanningFailed, t as CliStructuredError, x as mapRefResolutionError, y as errorUnexpected } from "./cli-errors-Djtz98Vm.mjs";
3
- import { t as assertFrameworkComponentsCompatible } from "./framework-components-65gOHkHB.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-DtavI0wJ.mjs";
6
- import { n as toExtensionInputs, t as buildContractSpaceAggregate } from "./contract-space-aggregate-loader-BmNQwlws.mjs";
2
+ import { A as mapRefResolutionError, E as errorTargetMigrationNotSupported, O as errorUnexpected, a as errorContractValidationFailed, h as errorMigrationPlanningFailed, k as mapMigrationToolsError, l as errorFileNotFound, t as CliStructuredError, v as errorPlanForgotTheFlag, w as errorSnapshotMissing } from "./cli-errors-DFF1LlfU.mjs";
3
+ import { t as assertFrameworkComponentsCompatible } from "./framework-components-DTcjouhS.mjs";
4
+ import { D 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, x as handleResult, y as createTerminalUI } from "./command-helpers-BnqwTptC.mjs";
5
+ import { n as toExtensionInputs, t as buildContractSpaceAggregate } from "./contract-space-aggregate-loader-EVU3n9YE.mjs";
7
6
  import { Command } from "commander";
8
7
  import { getEmittedArtifactPaths } from "@prisma-next/emitter";
9
8
  import { notOk, ok } from "@prisma-next/utils/result";
10
9
  import { join, relative } from "pathe";
11
- import { readFile } from "node:fs/promises";
10
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
12
11
  import { createControlStack, hasOperationPreview } from "@prisma-next/framework-components/control";
13
12
  import { copyFilesWithRename, formatMigrationDirName, materialiseExtensionMigrationPackageIfMissing, writeMigrationPackage } from "@prisma-next/migration-tools/io";
14
- import { findLatestMigration } from "@prisma-next/migration-tools/migration-graph";
13
+ import { assertHashIsGraphNode, findLatestMigration, isGraphNode } from "@prisma-next/migration-tools/migration-graph";
15
14
  import { emitContractSpaceArtefacts, planAllSpaces, readContractSpaceHeadRef, spaceMigrationDirectory } from "@prisma-next/migration-tools/spaces";
16
15
  import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
16
+ import { readRefSnapshot, readRefs } from "@prisma-next/migration-tools/refs";
17
17
  import { parseContractRef } from "@prisma-next/migration-tools/ref-resolution";
18
- import { readRefs } from "@prisma-next/migration-tools/refs";
19
18
  import { computeMigrationHash } from "@prisma-next/migration-tools/hash";
20
19
  import { writeMigrationTs } from "@prisma-next/migration-tools/migration-ts";
20
+ import { canonicalizeJson } from "@prisma-next/framework-components/utils";
21
21
  import { deriveProvidedInvariants } from "@prisma-next/migration-tools/invariants";
22
22
  //#region src/utils/contract-space-seed-phase.ts
23
23
  /**
@@ -109,6 +109,135 @@ function buildPlaceholderContractDts(spaceId) {
109
109
  ].join("\n");
110
110
  }
111
111
  //#endregion
112
+ //#region src/utils/plan-resolution.ts
113
+ const FULL_HASH_PATTERN = /^sha256:([0-9a-f]{64}|empty)$/;
114
+ function looksLikeFullHash(input) {
115
+ return FULL_HASH_PATTERN.test(input);
116
+ }
117
+ function graphIsEmpty(bundles) {
118
+ return bundles.length === 0;
119
+ }
120
+ function getReachableRefs(refs, graph) {
121
+ return Object.entries(refs).flatMap(([name, entry]) => entry && isGraphNode(entry.hash, graph) ? [{
122
+ name,
123
+ hash: entry.hash
124
+ }] : []).sort((a, b) => a.name.localeCompare(b.name));
125
+ }
126
+ function assertFromIsGraphNode(fromHash, graph, refs, graphTipHash) {
127
+ try {
128
+ assertHashIsGraphNode(fromHash, graph);
129
+ } catch (error) {
130
+ if (MigrationToolsError.is(error) && error.code === "MIGRATION.HASH_NOT_IN_GRAPH") throw errorPlanForgotTheFlag(fromHash, getReachableRefs(refs, graph), graphTipHash);
131
+ throw error;
132
+ }
133
+ }
134
+ async function deserializeSnapshotContract(familyInstance, contract) {
135
+ try {
136
+ return ok(familyInstance.deserializeContract(contract));
137
+ } catch (error) {
138
+ if (CliStructuredError.is(error)) return notOk(error);
139
+ return notOk(errorContractValidationFailed(`Ref snapshot contract failed to deserialize: ${error instanceof Error ? error.message : String(error)}`, { where: { path: "ref-snapshot" } }));
140
+ }
141
+ }
142
+ async function resolveGraphNodeFromBundle(fromHash, bundles, readBundleEndContract, explicitFromLabel) {
143
+ const matchingBundle = bundles.find((pkg) => pkg.metadata.to === fromHash);
144
+ if (!matchingBundle) return notOk(errorUnexpected(explicitFromLabel ? `No migration bundle found for --from "${explicitFromLabel}" (resolved hash: ${fromHash})` : `No migration bundle found for graph node ${fromHash}`, {
145
+ why: `The hash ${fromHash} is a graph node but no on-disk migration package has an end-contract hash matching it.`,
146
+ fix: "Provide a ref or hash that corresponds to an existing migration package, or run `migration list` to see available migrations."
147
+ }));
148
+ try {
149
+ return ok({
150
+ kind: "graph-node",
151
+ fromHash,
152
+ fromContract: await readBundleEndContract(matchingBundle.dirPath),
153
+ sourceDir: matchingBundle.dirPath
154
+ });
155
+ } catch (error) {
156
+ if (CliStructuredError.is(error)) return notOk(error);
157
+ throw error;
158
+ }
159
+ }
160
+ async function resolveFromRefName(refName, fromHash, input, refs) {
161
+ const { refsDir, bundles, graph, familyInstance, readBundleEndContract } = input;
162
+ const empty = graphIsEmpty(bundles);
163
+ const graphTip = findLatestMigration(graph)?.to ?? null;
164
+ let snapshot;
165
+ try {
166
+ snapshot = await readRefSnapshot(refsDir, refName);
167
+ } catch (error) {
168
+ if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
169
+ throw error;
170
+ }
171
+ if (snapshot) {
172
+ const contractResult = await deserializeSnapshotContract(familyInstance, snapshot.contract);
173
+ if (!contractResult.ok) return contractResult;
174
+ const fromContract = contractResult.value;
175
+ const { contractDts, contract: contractJson } = snapshot;
176
+ if (empty) return ok({
177
+ kind: "auto-baseline",
178
+ fromHash,
179
+ fromContract,
180
+ contractDts,
181
+ contractJson
182
+ });
183
+ try {
184
+ assertFromIsGraphNode(fromHash, graph, refs, graphTip);
185
+ } catch (error) {
186
+ if (CliStructuredError.is(error)) return notOk(error);
187
+ throw error;
188
+ }
189
+ return ok({
190
+ kind: "snapshot",
191
+ fromHash,
192
+ fromContract,
193
+ contractDts,
194
+ contractJson
195
+ });
196
+ }
197
+ if (isGraphNode(fromHash, graph)) return resolveGraphNodeFromBundle(fromHash, bundles, readBundleEndContract);
198
+ return notOk(errorSnapshotMissing(refName));
199
+ }
200
+ async function resolveFromHashProvenance(fromHash, input, _refs, explicitFromLabel) {
201
+ const { bundles, graph } = input;
202
+ if (isGraphNode(fromHash, graph)) return resolveGraphNodeFromBundle(fromHash, bundles, input.readBundleEndContract, explicitFromLabel);
203
+ throw new Error(`resolveFromHashProvenance: non-graph-node hash ${fromHash} should be refused via looksLikeFullHash before this helper is called`);
204
+ }
205
+ async function resolveFromForPlan(input) {
206
+ const { optionsFrom, refsDir, graph } = input;
207
+ let refs;
208
+ try {
209
+ refs = await readRefs(refsDir);
210
+ } catch (error) {
211
+ if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
212
+ throw error;
213
+ }
214
+ if (optionsFrom === void 0) {
215
+ const dbRef = refs["db"];
216
+ if (!dbRef) return ok({
217
+ kind: "greenfield",
218
+ fromHash: null,
219
+ fromContract: null
220
+ });
221
+ return resolveFromRefName("db", dbRef.hash, input, refs);
222
+ }
223
+ const refResult = parseContractRef(optionsFrom, {
224
+ graph,
225
+ refs
226
+ });
227
+ if (!refResult.ok) {
228
+ if (looksLikeFullHash(optionsFrom)) {
229
+ const empty = graphIsEmpty(input.bundles);
230
+ const graphTip = findLatestMigration(graph)?.to ?? null;
231
+ if (empty) return notOk(errorSnapshotMissing(optionsFrom, { viaRef: false }));
232
+ return notOk(errorPlanForgotTheFlag(optionsFrom, getReachableRefs(refs, graph), graphTip));
233
+ }
234
+ return notOk(mapRefResolutionError(refResult.failure));
235
+ }
236
+ const { hash: fromHash, provenance } = refResult.value;
237
+ if (provenance.kind === "ref") return resolveFromRefName(provenance.refName, fromHash, input, refs);
238
+ return resolveFromHashProvenance(fromHash, input, refs, optionsFrom);
239
+ }
240
+ //#endregion
112
241
  //#region src/commands/migration-plan.ts
113
242
  /**
114
243
  * Load a predecessor migration's destination contract from its sibling
@@ -148,6 +277,70 @@ async function readPredecessorEndContract(migrationDir, familyInstance) {
148
277
  throw errorContractValidationFailed(`Predecessor contract at ${path} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`, { where: { path } });
149
278
  }
150
279
  }
280
+ async function writeSnapshotContractArtifacts(packageDir, contractJson, contractDts, artifactBasename) {
281
+ await mkdir(packageDir, { recursive: true });
282
+ const jsonContent = `${canonicalizeJson(contractJson)}\n`;
283
+ const dtsContent = contractDts.endsWith("\n") ? contractDts : `${contractDts}\n`;
284
+ await writeFile(join(packageDir, `${artifactBasename}.json`), jsonContent);
285
+ await writeFile(join(packageDir, `${artifactBasename}.d.ts`), dtsContent);
286
+ }
287
+ async function writeSnapshotStartContract(packageDir, contractJson, contractDts) {
288
+ await writeSnapshotContractArtifacts(packageDir, contractJson, contractDts, "start-contract");
289
+ }
290
+ async function runPlannerLeg(planner, migrations, frameworkComponents, contract, fromContract, spaceId) {
291
+ const fromSchema = migrations.contractToSchema(fromContract, frameworkComponents);
292
+ const plannerResult = planner.plan({
293
+ contract,
294
+ schema: fromSchema,
295
+ policy: { allowedOperationClasses: [
296
+ "additive",
297
+ "widening",
298
+ "destructive",
299
+ "data"
300
+ ] },
301
+ fromContract,
302
+ frameworkComponents,
303
+ spaceId
304
+ });
305
+ if (plannerResult.kind === "failure") return notOk(errorMigrationPlanningFailed({ conflicts: plannerResult.conflicts }));
306
+ let plannedOps = [];
307
+ let hasPlaceholders = false;
308
+ try {
309
+ plannedOps = plannerResult.plan.operations;
310
+ if (plannedOps.length === 0) return notOk(errorMigrationPlanningFailed({ conflicts: [{
311
+ kind: "unsupportedChange",
312
+ summary: "Contract changed but planner produced no operations. This indicates unsupported or ignored changes."
313
+ }] }));
314
+ } catch (e) {
315
+ if (CliStructuredError.is(e) && e.domain === "MIG" && e.code === "2001") hasPlaceholders = true;
316
+ else throw e;
317
+ }
318
+ return ok({
319
+ plannedOps,
320
+ migrationTsContent: plannerResult.plan.renderTypeScript(),
321
+ hasPlaceholders
322
+ });
323
+ }
324
+ async function writePlannedMigrationPackage(packageDir, fromHash, toHash, createdAt, leg) {
325
+ const opsForWrite = leg.hasPlaceholders ? [] : leg.plannedOps;
326
+ const metadataWithInvariants = {
327
+ from: fromHash,
328
+ to: toHash,
329
+ hints: {
330
+ used: [],
331
+ applied: [],
332
+ plannerVersion: "2.0.0"
333
+ },
334
+ labels: [],
335
+ providedInvariants: deriveProvidedInvariants(opsForWrite),
336
+ createdAt: createdAt.toISOString()
337
+ };
338
+ await writeMigrationPackage(packageDir, {
339
+ ...metadataWithInvariants,
340
+ migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite)
341
+ }, opsForWrite);
342
+ await writeMigrationTs(packageDir, leg.migrationTsContent);
343
+ }
151
344
  async function executeMigrationPlanCommand(options, flags, ui, startTime) {
152
345
  const config = await loadConfig(options.config);
153
346
  const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);
@@ -206,36 +399,47 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
206
399
  const rawStorageHash = toContract.storage?.storageHash;
207
400
  if (typeof rawStorageHash !== "string") return notOk(errorContractValidationFailed("Contract is missing storageHash", { where: { path: contractPathAbsolute } }));
208
401
  const toStorageHash = rawStorageHash;
402
+ const { refsDir } = resolveMigrationPaths(options.config, config);
209
403
  let fromContract = null;
210
404
  let fromHash = null;
211
405
  let fromContractSourceDir = null;
406
+ let snapshotStartContract = null;
407
+ let isAutoBaseline = false;
212
408
  try {
213
409
  const { bundles, graph } = await loadMigrationPackages(appMigrationsDir);
214
- if (options.from) {
215
- const refs = await readRefs(resolveMigrationPaths(options.config, config).refsDir);
216
- const refResult = parseContractRef(options.from, {
217
- graph,
218
- refs
219
- });
220
- if (!refResult.ok) return notOk(mapRefResolutionError(refResult.failure));
221
- fromHash = refResult.value.hash;
222
- const matchingBundle = bundles.find((p) => p.metadata.to === fromHash);
223
- if (!matchingBundle) return notOk(errorUnexpected(`No migration bundle found for --from "${options.from}" (resolved hash: ${fromHash})`, {
224
- why: `The ref resolved successfully but no on-disk migration package has an end-contract hash matching ${fromHash}.`,
225
- fix: "Provide a ref or hash that corresponds to an existing migration package, or run `migration list` to see available migrations."
226
- }));
227
- fromContractSourceDir = matchingBundle.dirPath;
228
- fromContract = await readPredecessorEndContract(fromContractSourceDir, familyInstance);
229
- } else {
230
- const latestMigration = findLatestMigration(graph);
231
- if (latestMigration) {
232
- fromHash = latestMigration.to;
233
- const leafPkg = bundles.find((p) => p.metadata.migrationHash === latestMigration.migrationHash);
234
- if (leafPkg) {
235
- fromContractSourceDir = leafPkg.dirPath;
236
- fromContract = await readPredecessorEndContract(fromContractSourceDir, familyInstance);
237
- }
238
- }
410
+ const resolutionResult = await resolveFromForPlan({
411
+ optionsFrom: options.from,
412
+ refsDir,
413
+ bundles,
414
+ graph,
415
+ familyInstance,
416
+ readBundleEndContract: (migrationDir) => readPredecessorEndContract(migrationDir, familyInstance)
417
+ });
418
+ if (!resolutionResult.ok) return notOk(resolutionResult.failure);
419
+ switch (resolutionResult.value.kind) {
420
+ case "greenfield": break;
421
+ case "graph-node":
422
+ fromHash = resolutionResult.value.fromHash;
423
+ fromContract = resolutionResult.value.fromContract;
424
+ fromContractSourceDir = resolutionResult.value.sourceDir;
425
+ break;
426
+ case "snapshot":
427
+ fromHash = resolutionResult.value.fromHash;
428
+ fromContract = resolutionResult.value.fromContract;
429
+ snapshotStartContract = {
430
+ contractJson: resolutionResult.value.contractJson,
431
+ contractDts: resolutionResult.value.contractDts
432
+ };
433
+ break;
434
+ case "auto-baseline":
435
+ fromHash = resolutionResult.value.fromHash;
436
+ fromContract = resolutionResult.value.fromContract;
437
+ snapshotStartContract = {
438
+ contractJson: resolutionResult.value.contractJson,
439
+ contractDts: resolutionResult.value.contractDts
440
+ };
441
+ isAutoBaseline = true;
442
+ break;
239
443
  }
240
444
  } catch (error) {
241
445
  if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
@@ -257,7 +461,7 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
257
461
  spaceId: r.spaceId,
258
462
  dirName
259
463
  })));
260
- if (fromHash === toStorageHash) return ok({
464
+ if (fromHash === toStorageHash && !isAutoBaseline) return ok({
261
465
  ok: true,
262
466
  noOp: true,
263
467
  from: fromHash,
@@ -283,58 +487,105 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
283
487
  config.adapter,
284
488
  ...config.extensionPacks ?? []
285
489
  ]);
286
- const timestamp = /* @__PURE__ */ new Date();
287
- const packageDir = join(appMigrationsDir, formatMigrationDirName(timestamp, options.name ?? "migration"));
288
- const baseMetadata = {
289
- from: fromHash,
290
- to: toStorageHash,
291
- hints: {
292
- used: [],
293
- applied: [],
294
- plannerVersion: "2.0.0"
295
- },
296
- labels: [],
297
- createdAt: timestamp.toISOString()
298
- };
299
490
  try {
300
491
  const planner = migrations.createPlanner(familyInstance);
301
- const fromSchema = migrations.contractToSchema(fromContract, frameworkComponents);
302
- const plannerResult = planner.plan({
303
- contract: aggregate.app.contract,
304
- schema: fromSchema,
305
- policy: { allowedOperationClasses: [
306
- "additive",
307
- "widening",
308
- "destructive",
309
- "data"
310
- ] },
311
- fromContract,
312
- frameworkComponents,
313
- spaceId: aggregate.app.spaceId
314
- });
315
- if (plannerResult.kind === "failure") return notOk(errorMigrationPlanningFailed({ conflicts: plannerResult.conflicts }));
316
- let plannedOps = [];
317
- let hasPlaceholders = false;
318
- try {
319
- plannedOps = plannerResult.plan.operations;
320
- if (plannedOps.length === 0) return notOk(errorMigrationPlanningFailed({ conflicts: [{
321
- kind: "unsupportedChange",
322
- summary: "Contract changed but planner produced no operations. This indicates unsupported or ignored changes."
323
- }] }));
324
- } catch (e) {
325
- if (CliStructuredError.is(e) && e.domain === "MIG" && e.code === "2001") hasPlaceholders = true;
326
- else throw e;
492
+ if (isAutoBaseline && fromHash !== null && fromContract !== null && snapshotStartContract !== null) {
493
+ const baselineTimestamp = /* @__PURE__ */ new Date();
494
+ const deltaTimestamp = new Date(baselineTimestamp.getTime() + 6e4);
495
+ const baselineDirName = formatMigrationDirName(baselineTimestamp, "baseline");
496
+ const deltaDirName = formatMigrationDirName(deltaTimestamp, options.name ?? "migration");
497
+ const baselinePackageDir = join(appMigrationsDir, baselineDirName);
498
+ const deltaPackageDir = join(appMigrationsDir, deltaDirName);
499
+ const baselineLeg = await runPlannerLeg(planner, migrations, frameworkComponents, fromContract, null, aggregate.app.spaceId);
500
+ if (!baselineLeg.ok) return notOk(baselineLeg.failure);
501
+ await writePlannedMigrationPackage(baselinePackageDir, null, fromHash, baselineTimestamp, baselineLeg.value);
502
+ await writeSnapshotContractArtifacts(baselinePackageDir, snapshotStartContract.contractJson, snapshotStartContract.contractDts, "end-contract");
503
+ if (fromHash === toStorageHash) {
504
+ const baselineOps = baselineLeg.value.hasPlaceholders ? [] : baselineLeg.value.plannedOps;
505
+ if (baselineLeg.value.hasPlaceholders) {
506
+ const baselineDir = relative(process.cwd(), baselinePackageDir);
507
+ return ok({
508
+ ok: true,
509
+ noOp: false,
510
+ from: fromHash,
511
+ to: toStorageHash,
512
+ dir: baselineDir,
513
+ baselineDir,
514
+ operations: [],
515
+ emittedExtensionDirs,
516
+ pendingPlaceholders: true,
517
+ summary: "Planned baseline with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit",
518
+ timings: { total: Date.now() - startTime }
519
+ });
520
+ }
521
+ const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(baselineOps) : void 0;
522
+ return ok({
523
+ ok: true,
524
+ noOp: false,
525
+ from: fromHash,
526
+ to: toStorageHash,
527
+ baselineDir: relative(process.cwd(), baselinePackageDir),
528
+ operations: baselineOps.map((op) => ({
529
+ id: op.id,
530
+ label: op.label,
531
+ operationClass: op.operationClass
532
+ })),
533
+ emittedExtensionDirs,
534
+ ...preview !== void 0 ? { preview } : {},
535
+ summary: buildAutoBaselinePlanSummary(0, emittedExtensionDirs.length),
536
+ timings: { total: Date.now() - startTime }
537
+ });
538
+ }
539
+ const deltaLeg = await runPlannerLeg(planner, migrations, frameworkComponents, aggregate.app.contract, fromContract, aggregate.app.spaceId);
540
+ if (!deltaLeg.ok) return notOk(deltaLeg.failure);
541
+ await writePlannedMigrationPackage(deltaPackageDir, fromHash, toStorageHash, deltaTimestamp, deltaLeg.value);
542
+ const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
543
+ await copyFilesWithRename(deltaPackageDir, [{
544
+ sourcePath: destinationArtifacts.jsonPath,
545
+ destName: "end-contract.json"
546
+ }, {
547
+ sourcePath: destinationArtifacts.dtsPath,
548
+ destName: "end-contract.d.ts"
549
+ }]);
550
+ await writeSnapshotStartContract(deltaPackageDir, snapshotStartContract.contractJson, snapshotStartContract.contractDts);
551
+ const deltaOps = deltaLeg.value.hasPlaceholders ? [] : deltaLeg.value.plannedOps;
552
+ if (deltaLeg.value.hasPlaceholders) return ok({
553
+ ok: true,
554
+ noOp: false,
555
+ from: fromHash,
556
+ to: toStorageHash,
557
+ dir: relative(process.cwd(), deltaPackageDir),
558
+ baselineDir: relative(process.cwd(), baselinePackageDir),
559
+ operations: [],
560
+ emittedExtensionDirs,
561
+ pendingPlaceholders: true,
562
+ summary: "Planned baseline + migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit",
563
+ timings: { total: Date.now() - startTime }
564
+ });
565
+ const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(deltaOps) : void 0;
566
+ return ok({
567
+ ok: true,
568
+ noOp: false,
569
+ from: fromHash,
570
+ to: toStorageHash,
571
+ dir: relative(process.cwd(), deltaPackageDir),
572
+ baselineDir: relative(process.cwd(), baselinePackageDir),
573
+ operations: deltaOps.map((op) => ({
574
+ id: op.id,
575
+ label: op.label,
576
+ operationClass: op.operationClass
577
+ })),
578
+ emittedExtensionDirs,
579
+ ...preview !== void 0 ? { preview } : {},
580
+ summary: buildAutoBaselinePlanSummary(deltaOps.length, emittedExtensionDirs.length),
581
+ timings: { total: Date.now() - startTime }
582
+ });
327
583
  }
328
- const migrationTsContent = plannerResult.plan.renderTypeScript();
329
- const opsForWrite = hasPlaceholders ? [] : plannedOps;
330
- const metadataWithInvariants = {
331
- ...baseMetadata,
332
- providedInvariants: deriveProvidedInvariants(opsForWrite)
333
- };
334
- await writeMigrationPackage(packageDir, {
335
- ...metadataWithInvariants,
336
- migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite)
337
- }, opsForWrite);
584
+ const timestamp = /* @__PURE__ */ new Date();
585
+ const packageDir = join(appMigrationsDir, formatMigrationDirName(timestamp, options.name ?? "migration"));
586
+ const deltaLeg = await runPlannerLeg(planner, migrations, frameworkComponents, aggregate.app.contract, fromContract, aggregate.app.spaceId);
587
+ if (!deltaLeg.ok) return notOk(deltaLeg.failure);
588
+ await writePlannedMigrationPackage(packageDir, fromHash, toStorageHash, timestamp, deltaLeg.value);
338
589
  const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
339
590
  await copyFilesWithRename(packageDir, [{
340
591
  sourcePath: destinationArtifacts.jsonPath,
@@ -352,9 +603,8 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
352
603
  sourcePath: sourceArtifacts.dtsPath,
353
604
  destName: "start-contract.d.ts"
354
605
  }]);
355
- }
356
- await writeMigrationTs(packageDir, migrationTsContent);
357
- if (hasPlaceholders) return ok({
606
+ } else if (snapshotStartContract !== null) await writeSnapshotStartContract(packageDir, snapshotStartContract.contractJson, snapshotStartContract.contractDts);
607
+ if (deltaLeg.value.hasPlaceholders) return ok({
358
608
  ok: true,
359
609
  noOp: false,
360
610
  from: fromHash,
@@ -366,6 +616,7 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
366
616
  summary: "Planned migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit",
367
617
  timings: { total: Date.now() - startTime }
368
618
  });
619
+ const plannedOps = deltaLeg.value.plannedOps;
369
620
  const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(plannedOps) : void 0;
370
621
  return ok({
371
622
  ok: true,
@@ -425,6 +676,11 @@ function buildPlanSummary(plannedOpsCount, emittedExtensionDirsCount) {
425
676
  if (emittedExtensionDirsCount === 0) return base;
426
677
  return `${base}; materialised ${emittedExtensionDirsCount} ${emittedExtensionDirsCount === 1 ? "extension-space migration" : "extension-space migrations"}`;
427
678
  }
679
+ function buildAutoBaselinePlanSummary(deltaOpsCount, emittedExtensionDirsCount) {
680
+ const base = `Planned baseline + ${deltaOpsCount} operation(s)`;
681
+ if (emittedExtensionDirsCount === 0) return base;
682
+ return `${base}; materialised ${emittedExtensionDirsCount} ${emittedExtensionDirsCount === 1 ? "extension-space migration" : "extension-space migrations"}`;
683
+ }
428
684
  function formatMigrationPlanOutput(result, flags) {
429
685
  const lines = [];
430
686
  const useColor = flags.color !== false;
@@ -476,10 +732,12 @@ function formatMigrationPlanOutput(result, flags) {
476
732
  }
477
733
  lines.push(dim_(`from: ${result.from}`));
478
734
  lines.push(dim_(`to: ${result.to}`));
735
+ if (result.baselineDir) lines.push(dim_(`Baseline → ${result.baselineDir}`));
479
736
  if (result.dir) lines.push(dim_(`App space → ${result.dir}`));
480
737
  for (const entry of result.emittedExtensionDirs) lines.push(dim_(`Extension space ${entry.spaceId} → migrations/${entry.spaceId}/${entry.dirName}`));
481
738
  lines.push("");
482
- lines.push(`Next: review ${green_(result.dir ?? "<dir>")} if needed, then run ${green_("prisma-next migrate")}.`);
739
+ const reviewTarget = result.baselineDir !== void 0 && result.dir !== void 0 ? `${result.baselineDir} and ${result.dir}` : result.baselineDir ?? result.dir ?? "<dir>";
740
+ lines.push(`Next: review ${green_(reviewTarget)} if needed, then run ${green_("prisma-next migrate")}.`);
483
741
  if (result.preview && result.preview.statements.length > 0) {
484
742
  const allSql = result.preview.statements.every((s) => s.language === "sql");
485
743
  lines.push("");
@@ -526,4 +784,4 @@ function resolveBundleByPrefix(bundles, needle) {
526
784
  //#endregion
527
785
  export { formatMigrationPlanOutput as n, resolveBundleByPrefix as r, createMigrationPlanCommand as t };
528
786
 
529
- //# sourceMappingURL=migration-plan-C2jeH1J5.mjs.map
787
+ //# sourceMappingURL=migration-plan-BnmP_yNz.mjs.map