prisma-next 0.11.0 → 0.12.0

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 (147) hide show
  1. package/dist/cli.mjs +259 -12
  2. package/dist/cli.mjs.map +1 -1
  3. package/dist/{client-oXO2WCPD.mjs → client-KgJorIvG.mjs} +72 -60
  4. package/dist/client-KgJorIvG.mjs.map +1 -0
  5. package/dist/{command-helpers-BSb0tRC8.mjs → command-helpers-Bbw1GbwL.mjs} +646 -46
  6. package/dist/command-helpers-Bbw1GbwL.mjs.map +1 -0
  7. package/dist/commands/contract-emit.d.mts.map +1 -1
  8. package/dist/commands/contract-emit.mjs +1 -1
  9. package/dist/commands/contract-infer.d.mts.map +1 -1
  10. package/dist/commands/contract-infer.mjs +1 -1
  11. package/dist/commands/db-init.d.mts.map +1 -1
  12. package/dist/commands/db-init.mjs +32 -7
  13. package/dist/commands/db-init.mjs.map +1 -1
  14. package/dist/commands/db-schema.d.mts.map +1 -1
  15. package/dist/commands/db-schema.mjs +3 -4
  16. package/dist/commands/db-schema.mjs.map +1 -1
  17. package/dist/commands/db-sign.d.mts.map +1 -1
  18. package/dist/commands/db-sign.mjs +12 -10
  19. package/dist/commands/db-sign.mjs.map +1 -1
  20. package/dist/commands/db-update.d.mts.map +1 -1
  21. package/dist/commands/db-update.mjs +41 -11
  22. package/dist/commands/db-update.mjs.map +1 -1
  23. package/dist/commands/db-verify.d.mts.map +1 -1
  24. package/dist/commands/db-verify.mjs +1 -1
  25. package/dist/commands/migrate.d.mts +6 -2
  26. package/dist/commands/migrate.d.mts.map +1 -1
  27. package/dist/commands/migrate.mjs +75 -40
  28. package/dist/commands/migrate.mjs.map +1 -1
  29. package/dist/commands/migration-check.d.mts +4 -3
  30. package/dist/commands/migration-check.d.mts.map +1 -1
  31. package/dist/commands/migration-check.mjs +1 -280
  32. package/dist/commands/migration-graph.d.mts +13 -2
  33. package/dist/commands/migration-graph.d.mts.map +1 -1
  34. package/dist/commands/migration-graph.mjs +2 -137
  35. package/dist/commands/migration-list.d.mts +64 -4
  36. package/dist/commands/migration-list.d.mts.map +1 -1
  37. package/dist/commands/migration-list.mjs +143 -56
  38. package/dist/commands/migration-list.mjs.map +1 -1
  39. package/dist/commands/migration-log.d.mts +10 -1
  40. package/dist/commands/migration-log.d.mts.map +1 -1
  41. package/dist/commands/migration-log.mjs +10 -15
  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 +32 -38
  45. package/dist/commands/migration-new.mjs.map +1 -1
  46. package/dist/commands/migration-plan.d.mts +3 -2
  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 +4 -55
  50. package/dist/commands/migration-show.d.mts.map +1 -1
  51. package/dist/commands/migration-show.mjs +61 -153
  52. package/dist/commands/migration-show.mjs.map +1 -1
  53. package/dist/commands/migration-status.d.mts +12 -49
  54. package/dist/commands/migration-status.d.mts.map +1 -1
  55. package/dist/commands/migration-status.mjs +85 -81
  56. package/dist/commands/migration-status.mjs.map +1 -1
  57. package/dist/commands/ref.d.mts +1 -1
  58. package/dist/commands/ref.d.mts.map +1 -1
  59. package/dist/commands/ref.mjs +38 -10
  60. package/dist/commands/ref.mjs.map +1 -1
  61. package/dist/config-loader-B6sJjXTv.mjs.map +1 -1
  62. package/dist/config-loader.d.mts.map +1 -1
  63. package/dist/contract-at-errors-BxP-TOMl.mjs +42 -0
  64. package/dist/contract-at-errors-BxP-TOMl.mjs.map +1 -0
  65. package/dist/{contract-emit-bcrpT-wD.mjs → contract-emit-D-4jrNve.mjs} +25 -10
  66. package/dist/contract-emit-D-4jrNve.mjs.map +1 -0
  67. package/dist/{contract-emit-r4y8Zhf1.mjs → contract-emit-DxcGl4Uq.mjs} +19 -14
  68. package/dist/contract-emit-DxcGl4Uq.mjs.map +1 -0
  69. package/dist/{contract-enrichment-Dani0mMW.mjs → contract-enrichment-a0V5Y_mL.mjs} +4 -25
  70. package/dist/contract-enrichment-a0V5Y_mL.mjs.map +1 -0
  71. package/dist/{contract-infer-BmySmqVT.mjs → contract-infer-D8uEbJuu.mjs} +4 -5
  72. package/dist/{contract-infer-BmySmqVT.mjs.map → contract-infer-D8uEbJuu.mjs.map} +1 -1
  73. package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs +247 -0
  74. package/dist/contract-space-aggregate-loader-DvZwdkrr.mjs.map +1 -0
  75. package/dist/{db-verify-BClPs3ph.mjs → db-verify-v_vUKXTU.mjs} +5 -7
  76. package/dist/{db-verify-BClPs3ph.mjs.map → db-verify-v_vUKXTU.mjs.map} +1 -1
  77. package/dist/exports/control-api.d.mts +3 -3
  78. package/dist/exports/control-api.d.mts.map +1 -1
  79. package/dist/exports/control-api.mjs +3 -3
  80. package/dist/exports/index.d.mts.map +1 -1
  81. package/dist/exports/index.mjs +1 -1
  82. package/dist/exports/index.mjs.map +1 -1
  83. package/dist/exports/init-output.d.mts.map +1 -1
  84. package/dist/exports/init-output.mjs +1 -1
  85. package/dist/extension-pack-inputs-IDvjRCi3.mjs +62 -0
  86. package/dist/extension-pack-inputs-IDvjRCi3.mjs.map +1 -0
  87. package/dist/{framework-components-65gOHkHB.mjs → framework-components-fYXjz_in.mjs} +2 -2
  88. package/dist/{framework-components-65gOHkHB.mjs.map → framework-components-fYXjz_in.mjs.map} +1 -1
  89. package/dist/global-flags-DEHjV8_s.d.mts +34 -0
  90. package/dist/global-flags-DEHjV8_s.d.mts.map +1 -0
  91. package/dist/{graph-render-DJVv0_uf.mjs → graph-render-rFAqZujX.mjs} +2 -2
  92. package/dist/{graph-render-DJVv0_uf.mjs.map → graph-render-rFAqZujX.mjs.map} +1 -1
  93. package/dist/{init-BCJZPWE1.mjs → init-Cv9UzWL5.mjs} +20 -269
  94. package/dist/init-Cv9UzWL5.mjs.map +1 -0
  95. package/dist/{inspect-live-schema-DSRbFoOL.mjs → inspect-live-schema-C6ohV_oQ.mjs} +4 -5
  96. package/dist/{inspect-live-schema-DSRbFoOL.mjs.map → inspect-live-schema-C6ohV_oQ.mjs.map} +1 -1
  97. package/dist/migration-check-BiBJoYYW.mjs +341 -0
  98. package/dist/migration-check-BiBJoYYW.mjs.map +1 -0
  99. package/dist/migration-cli.d.mts.map +1 -1
  100. package/dist/migration-cli.mjs +4 -4
  101. package/dist/migration-cli.mjs.map +1 -1
  102. package/dist/{migration-command-scaffold-Bzd9La5c.mjs → migration-command-scaffold-CjvwO6at.mjs} +4 -5
  103. package/dist/{migration-command-scaffold-Bzd9La5c.mjs.map → migration-command-scaffold-CjvwO6at.mjs.map} +1 -1
  104. package/dist/migration-graph-D7DVUElV.mjs +1232 -0
  105. package/dist/migration-graph-D7DVUElV.mjs.map +1 -0
  106. package/dist/migration-list-styler-BRwF4-gy.mjs +399 -0
  107. package/dist/migration-list-styler-BRwF4-gy.mjs.map +1 -0
  108. package/dist/{migration-plan-CFwqw3Gk.mjs → migration-plan-9DJ7q7_z.mjs} +372 -133
  109. package/dist/migration-plan-9DJ7q7_z.mjs.map +1 -0
  110. package/dist/{migration-types-BXWvz12q.d.mts → migration-types-D2FW63pr.d.mts} +1 -1
  111. package/dist/{migration-types-BXWvz12q.d.mts.map → migration-types-D2FW63pr.d.mts.map} +1 -1
  112. package/dist/{migrations-CwZMa1Ck.mjs → migrations-Cv2jxNNK.mjs} +12 -13
  113. package/dist/migrations-Cv2jxNNK.mjs.map +1 -0
  114. package/dist/{output-BlsrGMEF.mjs → output-B60Gw5fu.mjs} +1 -1
  115. package/dist/{output-BlsrGMEF.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
  116. package/dist/{progress-adapter-DFfvZcYL.mjs → progress-adapter-C644QK8l.mjs} +1 -1
  117. package/dist/{progress-adapter-DFfvZcYL.mjs.map → progress-adapter-C644QK8l.mjs.map} +1 -1
  118. package/dist/ref-advancement-DUZqsue6.mjs +50 -0
  119. package/dist/ref-advancement-DUZqsue6.mjs.map +1 -0
  120. package/dist/terminal-ui-5Y6mrg93.d.mts +133 -0
  121. package/dist/terminal-ui-5Y6mrg93.d.mts.map +1 -0
  122. package/dist/{types--CqjMdk0.d.mts → types-Dt_SfqFm.d.mts} +28 -28
  123. package/dist/types-Dt_SfqFm.d.mts.map +1 -0
  124. package/dist/{verify-Bom75OYI.mjs → verify-DCA9Sldu.mjs} +2 -2
  125. package/dist/{verify-Bom75OYI.mjs.map → verify-DCA9Sldu.mjs.map} +1 -1
  126. package/package.json +28 -17
  127. package/dist/cli-errors-Czmx92Zy.d.mts +0 -3
  128. package/dist/cli-errors-Djtz98Vm.mjs +0 -71
  129. package/dist/cli-errors-Djtz98Vm.mjs.map +0 -1
  130. package/dist/client-oXO2WCPD.mjs.map +0 -1
  131. package/dist/command-helpers-BSb0tRC8.mjs.map +0 -1
  132. package/dist/commands/migration-check.mjs.map +0 -1
  133. package/dist/commands/migration-graph.mjs.map +0 -1
  134. package/dist/contract-emit-bcrpT-wD.mjs.map +0 -1
  135. package/dist/contract-emit-r4y8Zhf1.mjs.map +0 -1
  136. package/dist/contract-enrichment-Dani0mMW.mjs.map +0 -1
  137. package/dist/contract-space-aggregate-loader-BmNQwlws.mjs +0 -160
  138. package/dist/contract-space-aggregate-loader-BmNQwlws.mjs.map +0 -1
  139. package/dist/global-flags-CdE7M0d9.d.mts +0 -15
  140. package/dist/global-flags-CdE7M0d9.d.mts.map +0 -1
  141. package/dist/init-BCJZPWE1.mjs.map +0 -1
  142. package/dist/migration-plan-CFwqw3Gk.mjs.map +0 -1
  143. package/dist/migrations-CwZMa1Ck.mjs.map +0 -1
  144. package/dist/rolldown-runtime-twds-ZHy.mjs +0 -14
  145. package/dist/terminal-ui-BiB_8KNo.mjs +0 -379
  146. package/dist/terminal-ui-BiB_8KNo.mjs.map +0 -1
  147. package/dist/types--CqjMdk0.d.mts.map +0 -1
@@ -0,0 +1,341 @@
1
+ import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
2
+ import { T as formatStyledHeader, _ as createTerminalUI, d as setCommandSeeAlso, g as parseGlobalFlagsOrExit, l as setCommandDescriptions, o as resolveContractPath, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples } from "./command-helpers-Bbw1GbwL.mjs";
3
+ import { t as toDeclaredExtensionsFromRaw } from "./extension-pack-inputs-IDvjRCi3.mjs";
4
+ import { Command } from "commander";
5
+ import { join, relative } from "pathe";
6
+ import { readFile } from "node:fs/promises";
7
+ import { createControlStack } from "@prisma-next/framework-components/control";
8
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
9
+ import { loadContractSpaceAggregate } from "@prisma-next/migration-tools/aggregate";
10
+ import { reconstructGraph } from "@prisma-next/migration-tools/migration-graph";
11
+ import { readRefs } from "@prisma-next/migration-tools/refs";
12
+ import { parseMigrationRef } from "@prisma-next/migration-tools/ref-resolution";
13
+ import { verifyMigrationHash } from "@prisma-next/migration-tools/hash";
14
+ import { readMigrationsDir } from "@prisma-next/migration-tools/io";
15
+ //#region src/utils/integrity-violation-to-check-failure.ts
16
+ function migrationPathRelative$1(dirPath) {
17
+ return relative(process.cwd(), dirPath);
18
+ }
19
+ function migrationFileRelative$1(dirPath, fileName) {
20
+ return join(migrationPathRelative$1(dirPath), fileName);
21
+ }
22
+ /**
23
+ * Map one {@link IntegrityViolation} onto a `migration check` failure row.
24
+ * Sole catalogue mapping from integrity violations to `PN-MIG-CHECK-*`.
25
+ */
26
+ function integrityViolationToCheckFailure(violation, migrationsDir) {
27
+ const spaceRelative = (spaceId) => migrationPathRelative$1(join(migrationsDir, spaceId));
28
+ const packageRelative = (spaceId, dirName) => migrationPathRelative$1(join(migrationsDir, spaceId, dirName));
29
+ const refRelative = (spaceId, refName) => migrationPathRelative$1(join(migrationsDir, spaceId, "refs", `${refName}.json`));
30
+ switch (violation.kind) {
31
+ case "hashMismatch": return {
32
+ pnCode: "PN-MIG-CHECK-001",
33
+ where: migrationFileRelative$1(join(migrationsDir, violation.spaceId, violation.dirName), "migration.json"),
34
+ why: `Stored hash ${violation.stored} does not match recomputed hash ${violation.computed}`,
35
+ fix: "Re-emit the migration package or restore from version control."
36
+ };
37
+ case "providedInvariantsMismatch": return {
38
+ pnCode: "PN-MIG-CHECK-002",
39
+ where: packageRelative(violation.spaceId, violation.dirName),
40
+ why: `Migration "${violation.dirName}" providedInvariants in migration.json disagrees with ops.json.`,
41
+ fix: "Re-emit the migration package so migration.json and ops.json agree."
42
+ };
43
+ case "packageUnloadable": return {
44
+ pnCode: "PN-MIG-CHECK-002",
45
+ where: packageRelative(violation.spaceId, violation.dirName),
46
+ why: `Migration "${violation.dirName}" could not be loaded: ${violation.detail}`,
47
+ fix: "Re-emit the migration package or restore from version control."
48
+ };
49
+ case "sameSourceAndTarget": return {
50
+ pnCode: "PN-MIG-CHECK-007",
51
+ where: packageRelative(violation.spaceId, violation.dirName),
52
+ why: `Migration "${violation.dirName}" in space "${violation.spaceId}" has source equal to target (${violation.hash}) with no data invariant — a true no-op self-edge.`,
53
+ fix: "Add a data operation if this self-edge was meant to carry a data invariant, or delete the migration if it is a true no-op."
54
+ };
55
+ case "orphanSpaceDir": return {
56
+ pnCode: "PN-MIG-CHECK-008",
57
+ where: spaceRelative(violation.spaceId),
58
+ why: `Contract-space directory "${violation.spaceId}" exists on disk but no extension declares it.`,
59
+ fix: "Remove the orphan directory, or declare the extension in `extensionPacks`."
60
+ };
61
+ case "declaredButUnmigrated": return {
62
+ pnCode: "PN-MIG-CHECK-009",
63
+ where: spaceRelative(violation.spaceId),
64
+ why: `Extension "${violation.spaceId}" is declared in \`extensionPacks\` but has no on-disk migrations directory.`,
65
+ fix: "Re-emit the extension contract-space artefacts with `prisma-next contract emit` and migration planning, or remove the extension from `extensionPacks` if it is unused."
66
+ };
67
+ case "headRefMissing": return {
68
+ pnCode: "PN-MIG-CHECK-010",
69
+ where: refRelative(violation.spaceId, "head"),
70
+ why: `Head ref \`refs/head.json\` is missing for contract space "${violation.spaceId}".`,
71
+ fix: "Re-emit the contract-space migrations and head ref artefacts, or restore `refs/head.json` from version control."
72
+ };
73
+ case "headRefNotInGraph": return {
74
+ pnCode: "PN-MIG-CHECK-011",
75
+ where: refRelative(violation.spaceId, "head"),
76
+ why: `Head ref ${violation.hash} for contract space "${violation.spaceId}" is not present in its migration graph.`,
77
+ fix: "Re-emit the contract space migrations, or restore the missing migration package."
78
+ };
79
+ case "refUnreadable": return {
80
+ pnCode: "PN-MIG-CHECK-012",
81
+ where: refRelative(violation.spaceId, violation.refName),
82
+ why: `Ref "${violation.refName}" for contract space "${violation.spaceId}" is unreadable: ${violation.detail}`,
83
+ fix: "Repair or remove the corrupt ref file."
84
+ };
85
+ case "targetMismatch": return {
86
+ pnCode: "PN-MIG-CHECK-013",
87
+ where: spaceRelative(violation.spaceId),
88
+ why: `Contract space "${violation.spaceId}" targets "${violation.actual}" but the project targets "${violation.expected}".`,
89
+ fix: "Update the extension to target the configured database, or change the project target."
90
+ };
91
+ case "disjointness": return {
92
+ pnCode: "PN-MIG-CHECK-014",
93
+ where: migrationPathRelative$1(migrationsDir),
94
+ why: `Storage element "${violation.element}" is claimed by multiple contract spaces: ${violation.claimedBy.join(", ")}.`,
95
+ fix: "Update the contracts so each storage element is owned by exactly one contract space."
96
+ };
97
+ case "contractUnreadable": return {
98
+ pnCode: "PN-MIG-CHECK-015",
99
+ where: migrationFileRelative$1(join(migrationsDir, violation.spaceId), "contract.json"),
100
+ why: `Contract for space "${violation.spaceId}" is unreadable: ${violation.detail}`,
101
+ fix: "Re-emit the extension contract artefacts, or fix the descriptor producing the invalid contract."
102
+ };
103
+ case "duplicateMigrationHash": return {
104
+ pnCode: "PN-MIG-CHECK-016",
105
+ where: spaceRelative(violation.spaceId),
106
+ why: `Multiple migrations in space "${violation.spaceId}" share migrationHash "${violation.migrationHash}" (${violation.dirNames.join(", ")}).`,
107
+ fix: "Re-emit one of the conflicting packages so each migrationHash is unique."
108
+ };
109
+ }
110
+ }
111
+ //#endregion
112
+ //#region src/commands/migration-check.ts
113
+ function migrationPathRelative(dirPath) {
114
+ return relative(process.cwd(), dirPath);
115
+ }
116
+ function migrationFileRelative(dirPath, fileName) {
117
+ return join(migrationPathRelative(dirPath), fileName);
118
+ }
119
+ function checkFileExists(dirPath, dirName, fileName) {
120
+ if (!existsSync(join(dirPath, fileName))) return {
121
+ pnCode: "PN-MIG-CHECK-002",
122
+ where: migrationFileRelative(dirPath, fileName),
123
+ why: `${fileName} is missing from ${dirName}`,
124
+ fix: "Re-emit the migration package or restore from version control."
125
+ };
126
+ return null;
127
+ }
128
+ function checkSnapshotConsistency(pkg) {
129
+ const endContractPath = join(pkg.dirPath, "end-contract.json");
130
+ if (!existsSync(endContractPath)) return null;
131
+ try {
132
+ const snapshotHash = JSON.parse(readFileSync(endContractPath, "utf-8"))["storage"]?.["storageHash"];
133
+ if (typeof snapshotHash === "string" && snapshotHash !== pkg.metadata.to) return {
134
+ pnCode: "PN-MIG-CHECK-005",
135
+ where: migrationPathRelative(pkg.dirPath),
136
+ why: `Migration "${pkg.dirName}" declares to=${pkg.metadata.to} but end-contract.json has storageHash=${snapshotHash}`,
137
+ fix: "Re-emit the migration package so migration.json and end-contract.json agree."
138
+ };
139
+ } catch {
140
+ return {
141
+ pnCode: "PN-MIG-CHECK-006",
142
+ where: migrationPathRelative(pkg.dirPath),
143
+ why: `Migration "${pkg.dirName}" has an unparseable end-contract.json.`,
144
+ fix: "Re-emit the migration package to repair the snapshot file."
145
+ };
146
+ }
147
+ return null;
148
+ }
149
+ async function loadAggregateIntegrityViolations(config, migrationsDir) {
150
+ try {
151
+ const contractJsonContent = await readFile(resolveContractPath(config), "utf-8");
152
+ const familyInstance = config.family.create(createControlStack(config));
153
+ const declaredExtensions = toDeclaredExtensionsFromRaw(config.extensionPacks ?? []);
154
+ const parsedAppContract = JSON.parse(contractJsonContent);
155
+ return (await loadContractSpaceAggregate({
156
+ migrationsDir,
157
+ deserializeContract: (json) => familyInstance.deserializeContract(json),
158
+ appContract: familyInstance.deserializeContract(parsedAppContract)
159
+ })).checkIntegrity({
160
+ declaredExtensions,
161
+ checkContracts: true
162
+ });
163
+ } catch {
164
+ return [];
165
+ }
166
+ }
167
+ async function executeMigrationCheckCommand(target, options, flags, ui) {
168
+ const config = await loadConfig(options.config);
169
+ const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(options.config, config);
170
+ if (!flags.json && !flags.quiet) {
171
+ const details = [{
172
+ label: "config",
173
+ value: configPath
174
+ }, {
175
+ label: "migrations",
176
+ value: appMigrationsRelative
177
+ }];
178
+ if (target) details.push({
179
+ label: "target",
180
+ value: target
181
+ });
182
+ const header = formatStyledHeader({
183
+ command: "migration check",
184
+ description: "Verify artifact and graph integrity",
185
+ details,
186
+ flags
187
+ });
188
+ ui.stderr(header);
189
+ }
190
+ const failures = [];
191
+ const bundles = (await readMigrationsDir(appMigrationsDir)).packages;
192
+ const graph = reconstructGraph(bundles);
193
+ if (existsSync(appMigrationsDir)) {
194
+ const loadedDirNames = new Set(bundles.map((p) => p.dirName));
195
+ try {
196
+ const entries = readdirSync(appMigrationsDir);
197
+ for (const entry of entries) {
198
+ if (entry.startsWith(".") || entry.startsWith("_") || entry === "refs") continue;
199
+ const entryPath = join(appMigrationsDir, entry);
200
+ try {
201
+ if (!statSync(entryPath).isDirectory()) continue;
202
+ } catch {
203
+ continue;
204
+ }
205
+ if (!loadedDirNames.has(entry)) for (const f of ["migration.json", "ops.json"]) {
206
+ const fail = checkFileExists(entryPath, entry, f);
207
+ if (fail) failures.push(fail);
208
+ }
209
+ }
210
+ } catch {}
211
+ }
212
+ if (target) {
213
+ const migResult = parseMigrationRef(target, {
214
+ graph,
215
+ refs: await readRefs(refsDir)
216
+ });
217
+ if (!migResult.ok) return {
218
+ result: {
219
+ ok: false,
220
+ failures: [],
221
+ summary: migResult.failure.kind === "not-found" ? `Migration "${target}" does not exist` : migResult.failure.kind === "wrong-grammar" ? migResult.failure.message : `Invalid migration reference: "${target}"`
222
+ },
223
+ exitCode: 2
224
+ };
225
+ const matchedPkg = bundles.find((p) => p.metadata.migrationHash === migResult.value.migrationHash);
226
+ if (!matchedPkg) return {
227
+ result: {
228
+ ok: false,
229
+ failures: [],
230
+ summary: `Migration package for "${target}" not found on disk`
231
+ },
232
+ exitCode: 2
233
+ };
234
+ for (const f of ["migration.json", "ops.json"]) {
235
+ const fail = checkFileExists(matchedPkg.dirPath, matchedPkg.dirName, f);
236
+ if (fail) failures.push(fail);
237
+ }
238
+ const verification = verifyMigrationHash(matchedPkg);
239
+ if (!verification.ok) failures.push({
240
+ pnCode: "PN-MIG-CHECK-001",
241
+ where: migrationFileRelative(matchedPkg.dirPath, "migration.json"),
242
+ why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,
243
+ fix: "Re-emit the migration package or restore from version control."
244
+ });
245
+ const snapshotFailure = checkSnapshotConsistency(matchedPkg);
246
+ if (snapshotFailure) failures.push(snapshotFailure);
247
+ } else {
248
+ for (const pkg of bundles) {
249
+ const snapshotFailure = checkSnapshotConsistency(pkg);
250
+ if (snapshotFailure) failures.push(snapshotFailure);
251
+ }
252
+ const allToHashes = new Set(bundles.map((p) => p.metadata.to));
253
+ for (const pkg of bundles) if (!(pkg.metadata.from === null || allToHashes.has(pkg.metadata.from) || pkg.metadata.from === "sha256:empty")) failures.push({
254
+ pnCode: "PN-MIG-CHECK-003",
255
+ where: migrationPathRelative(pkg.dirPath),
256
+ why: `Migration "${pkg.dirName}" starts from ${pkg.metadata.from} which no other migration produces`,
257
+ fix: "This migration is unreachable in the graph. Delete it or re-emit a connecting migration."
258
+ });
259
+ try {
260
+ const refs = await readRefs(refsDir);
261
+ for (const [name, entry] of Object.entries(refs)) if (!graph.nodes.has(entry.hash)) failures.push({
262
+ pnCode: "PN-MIG-CHECK-004",
263
+ where: relative(process.cwd(), join(refsDir, `${name}.json`)),
264
+ why: `Ref "${name}" points at ${entry.hash} which does not exist in the migration graph`,
265
+ fix: `Update the ref with \`prisma-next ref set ${name} <valid-hash>\` or delete it.`
266
+ });
267
+ } catch {}
268
+ for (const violation of await loadAggregateIntegrityViolations(config, migrationsDir)) failures.push(integrityViolationToCheckFailure(violation, migrationsDir));
269
+ }
270
+ if (failures.length === 0) return {
271
+ result: {
272
+ ok: true,
273
+ failures: [],
274
+ summary: "All checks passed"
275
+ },
276
+ exitCode: 0
277
+ };
278
+ return {
279
+ result: {
280
+ ok: false,
281
+ failures,
282
+ summary: `${failures.length} integrity failure(s)`
283
+ },
284
+ exitCode: 4
285
+ };
286
+ }
287
+ function createMigrationCheckCommand() {
288
+ const command = new Command("check");
289
+ setCommandDescriptions(command, "Verify artifact and graph integrity", "Validates that on-disk migration packages are internally consistent\n(hashes match, manifests are complete) and that the graph is well-formed\n(edges connect, refs point at valid nodes). Offline — does not consult\nthe database.");
290
+ setCommandExamples(command, [
291
+ "prisma-next migration check",
292
+ "prisma-next migration check 20260101-add-users",
293
+ "prisma-next migration check --json"
294
+ ]);
295
+ setCommandSeeAlso(command, [
296
+ {
297
+ verb: "migration status",
298
+ oneLiner: "Show migration path and pending status"
299
+ },
300
+ {
301
+ verb: "migration list",
302
+ oneLiner: "List on-disk migrations"
303
+ },
304
+ {
305
+ verb: "migration graph",
306
+ oneLiner: "Show the migration graph topology"
307
+ }
308
+ ]);
309
+ command.exitOverride();
310
+ addGlobalOptions(command).argument("[migration]", "Migration reference (directory name or hash) to check").option("--config <path>", "Path to prisma-next.config.ts").action(async (target, options) => {
311
+ const flags = parseGlobalFlagsOrExit(options);
312
+ const ui = createTerminalUI(flags);
313
+ let result;
314
+ let exitCode;
315
+ try {
316
+ ({result, exitCode} = await executeMigrationCheckCommand(target, options, flags, ui));
317
+ } catch (error) {
318
+ result = {
319
+ ok: false,
320
+ failures: [],
321
+ summary: error instanceof Error ? error.message : String(error)
322
+ };
323
+ exitCode = 2;
324
+ }
325
+ if (flags.json) ui.output(JSON.stringify(result, null, 2));
326
+ else if (!flags.quiet) if (result.ok) ui.log(`✔ ${result.summary}`);
327
+ else {
328
+ for (const f of result.failures) {
329
+ ui.log(`✗ [${f.pnCode}] ${f.where}: ${f.why}`);
330
+ ui.log(` fix: ${f.fix}`);
331
+ }
332
+ ui.log(`\n${result.summary}`);
333
+ }
334
+ process.exit(exitCode);
335
+ });
336
+ return command;
337
+ }
338
+ //#endregion
339
+ export { createMigrationCheckCommand as t };
340
+
341
+ //# sourceMappingURL=migration-check-BiBJoYYW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-check-BiBJoYYW.mjs","names":["migrationPathRelative","migrationFileRelative"],"sources":["../src/utils/integrity-violation-to-check-failure.ts","../src/commands/migration-check.ts"],"sourcesContent":["import type { IntegrityViolation } from '@prisma-next/migration-tools/aggregate';\nimport { join, relative } from 'pathe';\n\nexport interface CheckFailure {\n readonly pnCode: string;\n readonly where: string;\n readonly why: string;\n readonly fix: string;\n}\n\nfunction migrationPathRelative(dirPath: string): string {\n return relative(process.cwd(), dirPath);\n}\n\nfunction migrationFileRelative(dirPath: string, fileName: string): string {\n return join(migrationPathRelative(dirPath), fileName);\n}\n\n/**\n * Map one {@link IntegrityViolation} onto a `migration check` failure row.\n * Sole catalogue mapping from integrity violations to `PN-MIG-CHECK-*`.\n */\nexport function integrityViolationToCheckFailure(\n violation: IntegrityViolation,\n migrationsDir: string,\n): CheckFailure {\n const spaceRelative = (spaceId: string): string =>\n migrationPathRelative(join(migrationsDir, spaceId));\n const packageRelative = (spaceId: string, dirName: string): string =>\n migrationPathRelative(join(migrationsDir, spaceId, dirName));\n const refRelative = (spaceId: string, refName: string): string =>\n migrationPathRelative(join(migrationsDir, spaceId, 'refs', `${refName}.json`));\n\n switch (violation.kind) {\n case 'hashMismatch':\n return {\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(\n join(migrationsDir, violation.spaceId, violation.dirName),\n 'migration.json',\n ),\n why: `Stored hash ${violation.stored} does not match recomputed hash ${violation.computed}`,\n fix: 'Re-emit the migration package or restore from version control.',\n };\n case 'providedInvariantsMismatch':\n return {\n pnCode: 'PN-MIG-CHECK-002',\n where: packageRelative(violation.spaceId, violation.dirName),\n why: `Migration \"${violation.dirName}\" providedInvariants in migration.json disagrees with ops.json.`,\n fix: 'Re-emit the migration package so migration.json and ops.json agree.',\n };\n case 'packageUnloadable':\n return {\n pnCode: 'PN-MIG-CHECK-002',\n where: packageRelative(violation.spaceId, violation.dirName),\n why: `Migration \"${violation.dirName}\" could not be loaded: ${violation.detail}`,\n fix: 'Re-emit the migration package or restore from version control.',\n };\n case 'sameSourceAndTarget':\n return {\n pnCode: 'PN-MIG-CHECK-007',\n where: packageRelative(violation.spaceId, violation.dirName),\n why: `Migration \"${violation.dirName}\" in space \"${violation.spaceId}\" has source equal to target (${violation.hash}) with no data invariant — a true no-op self-edge.`,\n fix: 'Add a data operation if this self-edge was meant to carry a data invariant, or delete the migration if it is a true no-op.',\n };\n case 'orphanSpaceDir':\n return {\n pnCode: 'PN-MIG-CHECK-008',\n where: spaceRelative(violation.spaceId),\n why: `Contract-space directory \"${violation.spaceId}\" exists on disk but no extension declares it.`,\n fix: 'Remove the orphan directory, or declare the extension in `extensionPacks`.',\n };\n case 'declaredButUnmigrated':\n return {\n pnCode: 'PN-MIG-CHECK-009',\n where: spaceRelative(violation.spaceId),\n why: `Extension \"${violation.spaceId}\" is declared in \\`extensionPacks\\` but has no on-disk migrations directory.`,\n fix: 'Re-emit the extension contract-space artefacts with `prisma-next contract emit` and migration planning, or remove the extension from `extensionPacks` if it is unused.',\n };\n case 'headRefMissing':\n return {\n pnCode: 'PN-MIG-CHECK-010',\n where: refRelative(violation.spaceId, 'head'),\n why: `Head ref \\`refs/head.json\\` is missing for contract space \"${violation.spaceId}\".`,\n fix: 'Re-emit the contract-space migrations and head ref artefacts, or restore `refs/head.json` from version control.',\n };\n case 'headRefNotInGraph':\n return {\n pnCode: 'PN-MIG-CHECK-011',\n where: refRelative(violation.spaceId, 'head'),\n why: `Head ref ${violation.hash} for contract space \"${violation.spaceId}\" is not present in its migration graph.`,\n fix: 'Re-emit the contract space migrations, or restore the missing migration package.',\n };\n case 'refUnreadable':\n return {\n pnCode: 'PN-MIG-CHECK-012',\n where: refRelative(violation.spaceId, violation.refName),\n why: `Ref \"${violation.refName}\" for contract space \"${violation.spaceId}\" is unreadable: ${violation.detail}`,\n fix: 'Repair or remove the corrupt ref file.',\n };\n case 'targetMismatch':\n return {\n pnCode: 'PN-MIG-CHECK-013',\n where: spaceRelative(violation.spaceId),\n why: `Contract space \"${violation.spaceId}\" targets \"${violation.actual}\" but the project targets \"${violation.expected}\".`,\n fix: 'Update the extension to target the configured database, or change the project target.',\n };\n case 'disjointness':\n return {\n pnCode: 'PN-MIG-CHECK-014',\n where: migrationPathRelative(migrationsDir),\n why: `Storage element \"${violation.element}\" is claimed by multiple contract spaces: ${violation.claimedBy.join(', ')}.`,\n fix: 'Update the contracts so each storage element is owned by exactly one contract space.',\n };\n case 'contractUnreadable':\n return {\n pnCode: 'PN-MIG-CHECK-015',\n where: migrationFileRelative(join(migrationsDir, violation.spaceId), 'contract.json'),\n why: `Contract for space \"${violation.spaceId}\" is unreadable: ${violation.detail}`,\n fix: 'Re-emit the extension contract artefacts, or fix the descriptor producing the invalid contract.',\n };\n case 'duplicateMigrationHash':\n return {\n pnCode: 'PN-MIG-CHECK-016',\n where: spaceRelative(violation.spaceId),\n why: `Multiple migrations in space \"${violation.spaceId}\" share migrationHash \"${violation.migrationHash}\" (${violation.dirNames.join(', ')}).`,\n fix: 'Re-emit one of the conflicting packages so each migrationHash is unique.',\n };\n }\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport type { IntegrityViolation } from '@prisma-next/migration-tools/aggregate';\nimport { loadContractSpaceAggregate } from '@prisma-next/migration-tools/aggregate';\nimport { verifyMigrationHash } from '@prisma-next/migration-tools/hash';\nimport { readMigrationsDir } from '@prisma-next/migration-tools/io';\nimport { reconstructGraph } from '@prisma-next/migration-tools/migration-graph';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport { parseMigrationRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { Command } from 'commander';\nimport { join, relative } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport {\n addGlobalOptions,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { toDeclaredExtensionsFromRaw } from '../utils/extension-pack-inputs';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport {\n type CheckFailure,\n integrityViolationToCheckFailure,\n} from '../utils/integrity-violation-to-check-failure';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\nimport { INTEGRITY_FAILED, OK, PRECONDITION } from './migration-check/exit-codes';\n\ninterface MigrationCheckOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nexport type { CheckFailure } from '../utils/integrity-violation-to-check-failure';\n\nexport interface MigrationCheckResult {\n readonly ok: boolean;\n readonly failures: readonly CheckFailure[];\n readonly summary: string;\n}\n\nfunction migrationPathRelative(dirPath: string): string {\n return relative(process.cwd(), dirPath);\n}\n\nfunction migrationFileRelative(dirPath: string, fileName: string): string {\n return join(migrationPathRelative(dirPath), fileName);\n}\n\nfunction checkFileExists(dirPath: string, dirName: string, fileName: string): CheckFailure | null {\n if (!existsSync(join(dirPath, fileName))) {\n return {\n pnCode: 'PN-MIG-CHECK-002',\n where: migrationFileRelative(dirPath, fileName),\n why: `${fileName} is missing from ${dirName}`,\n fix: 'Re-emit the migration package or restore from version control.',\n };\n }\n return null;\n}\n\nfunction checkSnapshotConsistency(pkg: OnDiskMigrationPackage): CheckFailure | null {\n const endContractPath = join(pkg.dirPath, 'end-contract.json');\n if (!existsSync(endContractPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(endContractPath, 'utf-8')) as Record<string, unknown>;\n const storage = raw['storage'] as Record<string, unknown> | undefined;\n const snapshotHash = storage?.['storageHash'];\n if (typeof snapshotHash === 'string' && snapshotHash !== pkg.metadata.to) {\n return {\n pnCode: 'PN-MIG-CHECK-005',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" declares to=${pkg.metadata.to} but end-contract.json has storageHash=${snapshotHash}`,\n fix: 'Re-emit the migration package so migration.json and end-contract.json agree.',\n };\n }\n } catch {\n return {\n pnCode: 'PN-MIG-CHECK-006',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" has an unparseable end-contract.json.`,\n fix: 'Re-emit the migration package to repair the snapshot file.',\n };\n }\n return null;\n}\n\nasync function loadAggregateIntegrityViolations(\n config: Awaited<ReturnType<typeof loadConfig>>,\n migrationsDir: string,\n): Promise<readonly IntegrityViolation[]> {\n try {\n const contractJsonContent = await readFile(resolveContractPath(config), 'utf-8');\n const familyInstance = config.family.create(createControlStack(config));\n const declaredExtensions = toDeclaredExtensionsFromRaw(config.extensionPacks ?? []);\n\n const parsedAppContract: unknown = JSON.parse(contractJsonContent);\n const aggregate = await loadContractSpaceAggregate({\n migrationsDir,\n deserializeContract: (json: unknown) => familyInstance.deserializeContract(json),\n appContract: familyInstance.deserializeContract(parsedAppContract),\n });\n return aggregate.checkIntegrity({ declaredExtensions, checkContracts: true });\n } catch {\n return [];\n }\n}\n\nasync function executeMigrationCheckCommand(\n target: string | undefined,\n options: MigrationCheckOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<{ result: MigrationCheckResult; exitCode: number }> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative, refsDir } =\n resolveMigrationPaths(options.config, config);\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ];\n if (target) {\n details.push({ label: 'target', value: target });\n }\n const header = formatStyledHeader({\n command: 'migration check',\n description: 'Verify artifact and graph integrity',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n const failures: CheckFailure[] = [];\n\n const loaded = await readMigrationsDir(appMigrationsDir);\n const bundles: readonly OnDiskMigrationPackage[] = loaded.packages;\n const graph = reconstructGraph(bundles);\n\n if (existsSync(appMigrationsDir)) {\n const loadedDirNames = new Set(bundles.map((p) => p.dirName));\n try {\n const entries = readdirSync(appMigrationsDir);\n for (const entry of entries) {\n if (entry.startsWith('.') || entry.startsWith('_') || entry === 'refs') continue;\n const entryPath = join(appMigrationsDir, entry);\n try {\n if (!statSync(entryPath).isDirectory()) continue;\n } catch {\n continue;\n }\n if (!loadedDirNames.has(entry)) {\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(entryPath, entry, f);\n if (fail) failures.push(fail);\n }\n }\n }\n } catch {\n // migrations dir unreadable — skip\n }\n }\n\n if (target) {\n const refs = await readRefs(refsDir);\n const migResult = parseMigrationRef(target, { graph, refs });\n if (!migResult.ok) {\n const msg =\n migResult.failure.kind === 'not-found'\n ? `Migration \"${target}\" does not exist`\n : migResult.failure.kind === 'wrong-grammar'\n ? migResult.failure.message\n : `Invalid migration reference: \"${target}\"`;\n return {\n result: { ok: false, failures: [], summary: msg },\n exitCode: PRECONDITION,\n };\n }\n\n const matchedPkg = bundles.find(\n (p) => p.metadata.migrationHash === migResult.value.migrationHash,\n );\n if (!matchedPkg) {\n return {\n result: {\n ok: false,\n failures: [],\n summary: `Migration package for \"${target}\" not found on disk`,\n },\n exitCode: PRECONDITION,\n };\n }\n\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(matchedPkg.dirPath, matchedPkg.dirName, f);\n if (fail) failures.push(fail);\n }\n\n const verification = verifyMigrationHash(matchedPkg);\n if (!verification.ok) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(matchedPkg.dirPath, 'migration.json'),\n why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,\n fix: 'Re-emit the migration package or restore from version control.',\n });\n }\n\n const snapshotFailure = checkSnapshotConsistency(matchedPkg);\n if (snapshotFailure) failures.push(snapshotFailure);\n } else {\n for (const pkg of bundles) {\n const snapshotFailure = checkSnapshotConsistency(pkg);\n if (snapshotFailure) failures.push(snapshotFailure);\n }\n\n const allToHashes = new Set(bundles.map((p) => p.metadata.to));\n for (const pkg of bundles) {\n const isReachable =\n pkg.metadata.from === null ||\n allToHashes.has(pkg.metadata.from) ||\n pkg.metadata.from === 'sha256:empty';\n if (!isReachable) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-003',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" starts from ${pkg.metadata.from} which no other migration produces`,\n fix: 'This migration is unreachable in the graph. Delete it or re-emit a connecting migration.',\n });\n }\n }\n\n try {\n const refs = await readRefs(refsDir);\n for (const [name, entry] of Object.entries(refs)) {\n if (!graph.nodes.has(entry.hash)) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-004',\n where: relative(process.cwd(), join(refsDir, `${name}.json`)),\n why: `Ref \"${name}\" points at ${entry.hash} which does not exist in the migration graph`,\n fix: `Update the ref with \\`prisma-next ref set ${name} <valid-hash>\\` or delete it.`,\n });\n }\n }\n } catch {\n // Refs unreadable — skip ref checks\n }\n\n for (const violation of await loadAggregateIntegrityViolations(config, migrationsDir)) {\n failures.push(integrityViolationToCheckFailure(violation, migrationsDir));\n }\n }\n\n if (failures.length === 0) {\n return {\n result: { ok: true, failures: [], summary: 'All checks passed' },\n exitCode: OK,\n };\n }\n\n return {\n result: { ok: false, failures, summary: `${failures.length} integrity failure(s)` },\n exitCode: INTEGRITY_FAILED,\n };\n}\n\nexport function createMigrationCheckCommand(): Command {\n const command = new Command('check');\n setCommandDescriptions(\n command,\n 'Verify artifact and graph integrity',\n 'Validates that on-disk migration packages are internally consistent\\n' +\n '(hashes match, manifests are complete) and that the graph is well-formed\\n' +\n '(edges connect, refs point at valid nodes). Offline — does not consult\\n' +\n 'the database.',\n );\n setCommandExamples(command, [\n 'prisma-next migration check',\n 'prisma-next migration check 20260101-add-users',\n 'prisma-next migration check --json',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n ]);\n command.exitOverride();\n addGlobalOptions(command)\n .argument('[migration]', 'Migration reference (directory name or hash) to check')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (target: string | undefined, options: MigrationCheckOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n let result: MigrationCheckResult;\n let exitCode: number;\n try {\n ({ result, exitCode } = await executeMigrationCheckCommand(target, options, flags, ui));\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n result = { ok: false, failures: [], summary: msg };\n exitCode = PRECONDITION;\n }\n\n if (flags.json) {\n ui.output(JSON.stringify(result, null, 2));\n } else if (!flags.quiet) {\n if (result.ok) {\n ui.log(`✔ ${result.summary}`);\n } else {\n for (const f of result.failures) {\n ui.log(`✗ [${f.pnCode}] ${f.where}: ${f.why}`);\n ui.log(` fix: ${f.fix}`);\n }\n ui.log(`\\n${result.summary}`);\n }\n }\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"migration-cli.d.mts","names":[],"sources":["../src/migration-cli.ts"],"mappings":";;;;;;;;;;;;;;;;;;;KA6EY,oBAAA,WAA+B,IAAA,YAAgB,SAAA;;;;;;;;;;;;;;KAe/C,oBAAA,GAAuB,QAAA;;;;;;;;;;;;;cAuEtB,YAAA;;;;;;;;;;;;;;;;;;;;;;;;SAwBE,GAAA,CACX,aAAA,UACA,cAAA,EAAgB,oBAAA,EAChB,OAAA;IAAA,SACW,IAAA;IAAA,SACA,MAAA,GAAS,oBAAA;IAAA,SACT,MAAA,GAAS,oBAAA;EAAA,IAEnB,OAAA;AAAA"}
1
+ {"version":3,"file":"migration-cli.d.mts","names":[],"sources":["../src/migration-cli.ts"],"mappings":";;;;;;;;;;;;;;;;;;;KA6EY,oBAAA,WAA+B,IAAA,YAAgB,SAAS;;;;;;;;;;;;;;KAexD,oBAAA,GAAuB,QAAQ;;;;;;;;;;;;;cAuE9B,YAAA;;;;;;;;;;;;;;;;;;;;;;;;SAwBE,GAAA,CACX,aAAA,UACA,cAAA,EAAgB,oBAAA,EAChB,OAAA;IAAA,SACW,IAAA;IAAA,SACA,MAAA,GAAS,oBAAA;IAAA,SACT,MAAA,GAAS,oBAAA;EAAA,IAEnB,OAAA;AAAA"}
@@ -326,8 +326,8 @@ function writeStructuredError(stream, err) {
326
326
  * `null` when the file is missing and throwing `MIGRATION.INVALID_JSON`
327
327
  * when the file is present but cannot be parsed as JSON. The CLI feeds
328
328
  * this into `buildMigrationArtifacts` so the pure builder can preserve
329
- * fields owned by `migration plan` (contract bookends, hints, labels,
330
- * `createdAt`) across re-emits.
329
+ * fields owned by `migration plan` (contract bookends, `createdAt`) across
330
+ * re-emits.
331
331
  *
332
332
  * Author-time path: this loader still does not verify the manifest hash
333
333
  * or schema — that is the apply-time loader's job. Hash mismatch is the
@@ -337,8 +337,8 @@ function writeStructuredError(stream, err) {
337
337
  * however, is now surfaced rather than swallowed: a malformed
338
338
  * `migration.json` indicates either a hand-edit gone wrong or partial
339
339
  * write, and silently rebuilding from `describe()` would discard the
340
- * user's on-disk content (preserved bookends, hints, labels,
341
- * `createdAt`) without any indication something was wrong on disk.
340
+ * user's on-disk content (preserved bookends, `createdAt`) without any
341
+ * indication something was wrong on disk.
342
342
  * Apply-time consumers always route through the verifying
343
343
  * `readMigrationPackage` in `@prisma-next/migration-tools/io` instead.
344
344
  */
@@ -1 +1 @@
1
- {"version":3,"file":"migration-cli.mjs","names":[],"sources":["../src/migration-cli.ts"],"sourcesContent":["/**\n * The migration-file CLI interface: the actor invoked when the author runs\n * `node migration.ts` directly.\n *\n * Naming: this is *not* a \"migration runner\" in the apply-time sense. The\n * apply-time runner is the thing `prisma-next migrate` uses to\n * execute migration JSON ops against a database. `MigrationCLI` is the\n * tiny CLI surface owned by an authored `migration.ts` file: parse the\n * file's argv, load the project's `prisma-next.config.ts`, assemble a\n * `ControlStack`, instantiate the migration class, and serialize.\n *\n * The user authors a migration class, then calls\n * `MigrationCLI.run(import.meta.url, MigrationClass)` at module scope\n * after the class definition. When the file is invoked as a node\n * entrypoint (`node migration.ts`), the CLI:\n *\n * 1. Detects whether the file is the direct entrypoint (no-op when imported).\n * 2. Parses CLI args (`--help`, `--dry-run`, `--config <path>`) via\n * [clipanion](https://github.com/arcanis/clipanion).\n * 3. Loads the project's `prisma-next.config.ts` via the same `loadConfig`\n * the CLI commands use, walking up from the migration file's directory.\n * 4. Probe-instantiates the migration class without a stack so it can read\n * `targetId` and verify it matches `config.target.targetId`\n * (`PN-MIG-2006` on mismatch) before any stack-driven adapter\n * construction runs.\n * 5. Assembles a `ControlStack` from the loaded config descriptors and\n * constructs the migration with that stack.\n * 6. Reads any previously-scaffolded `migration.json`, then calls\n * `buildMigrationArtifacts` from `@prisma-next/migration-tools` to\n * produce in-memory `ops.json` + `migration.json` content. Persists\n * the result to disk (or prints in dry-run mode).\n *\n * File I/O lives here, in `@prisma-next/cli`: this is the only place\n * that legitimately combines config loading, stack assembly, and\n * on-disk persistence. `@prisma-next/migration-tools` owns the pure\n * conversion from a `Migration` instance to artifact strings; `Migration`\n * stays a pure abstract class.\n *\n * Parser library: clipanion (chosen over Commander/citty/`node:util.parseArgs`\n * for its in-process testability and runtime-agnostic execution surface; see\n * `docs/architecture docs/research/commander-friction-points.md` for the\n * evaluation rubric and the durable rationale that drove the choice).\n */\n\nimport { readFileSync, realpathSync, writeFileSync } from 'node:fs';\nimport type { Writable } from 'node:stream';\nimport { fileURLToPath } from 'node:url';\nimport {\n CliStructuredError,\n errorMigrationCliInvalidConfigArg,\n errorMigrationCliUnknownFlag,\n} from '@prisma-next/errors/control';\nimport { errorMigrationTargetMismatch } from '@prisma-next/errors/migration';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { errorInvalidJson, MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport { buildMigrationArtifacts, type Migration } from '@prisma-next/migration-tools/migration';\nimport { Cli, Command, Option, UsageError } from 'clipanion';\nimport { dirname, join } from 'pathe';\nimport { loadConfig } from './config-loader';\n\n/**\n * Constructor shape accepted by `MigrationCLI.run`. `Migration` subclasses\n * accept an optional `ControlStack` in their constructor (each subclass\n * narrows the stack to its own family/target generics); the CLI always\n * passes one assembled from the loaded config. We use a rest-args `any[]`\n * constructor signature so that subclass constructors with narrower\n * parameter types remain assignable - constructor type compatibility in\n * TS is contravariant in the parameter, and a wider `unknown` parameter\n * on the alias side would reject any narrower subclass signature.\n *\n * The CLI only ever passes one argument (`new MigrationClass(stack)`);\n * the rest-arity is purely a type-compatibility concession for subclass\n * constructors that declare narrower parameter types, not an extension\n * point for additional construction arguments.\n */\n// biome-ignore lint/suspicious/noExplicitAny: see JSDoc - rest args with any are the idiomatic TS pattern for accepting arbitrary subclass constructor signatures\nexport type MigrationConstructor = new (...args: any[]) => Migration;\n\n/**\n * Stream surface accepted by `MigrationCLI.run`'s `options.stdout` /\n * `options.stderr`. Aliases node's `Writable` because clipanion's\n * `BaseContext.stdout`/`stderr` are typed as `Writable`, and the CLI\n * forwards the injected streams into clipanion's context.\n *\n * `process.stdout` and `process.stderr` are `Writable`-shaped, so the\n * default-fallback path remains a no-op for existing two-argument\n * callers like `MigrationCLI.run(import.meta.url, MyMigration)`.\n *\n * Tests inject a `Writable` subclass that captures chunks for\n * assertions.\n */\nexport type MigrationCliWritable = Writable;\n\n/**\n * Flags exposed by the migration-file CLI.\n *\n * Must stay in sync with the `Option` declarations on\n * `MigrationFileCommand` below. This list is rendered in the\n * `errorMigrationCliUnknownFlag` envelope's `fix` text and `meta`,\n * so order matters for user-visible output (declaration order is the\n * order users see when they run `--help`).\n */\nconst KNOWN_FLAGS: readonly string[] = ['--help', '--dry-run', '--config'];\n\n/**\n * The clipanion command that owns the migration-file CLI's option\n * declarations. The class is internal — `MigrationCLI.run` is the\n * stable public surface. Adding a flag here automatically updates\n * `--help` rendering and the `KNOWN_FLAGS` list (the latter must be\n * updated in tandem).\n */\nclass MigrationFileCommand extends Command {\n static override paths = [Command.Default];\n\n static override usage = Command.Usage({\n description: 'Self-emit ops.json and migration.json from a class-flow migration',\n details: `\n Loads the project's prisma-next.config.ts, assembles a ControlStack\n from the configured target/adapter/extensions, and serializes the\n migration's operations + metadata next to this file.\n `,\n examples: [\n ['Self-emit ops.json + migration.json next to migration.ts', '$0'],\n ['Preview without writing files', '$0 --dry-run'],\n ['Use a non-default config path', '$0 --config ./custom.config.ts'],\n ],\n });\n\n dryRun = Option.Boolean('--dry-run', false, {\n description: 'Print operations to stdout without writing files',\n });\n\n config = Option.String('--config', {\n description: 'Path to prisma-next.config.ts',\n });\n\n /**\n * Unused: orchestration runs inside `MigrationCLI.run` so error\n * routing stays under our control (clipanion's `cli.run` writes\n * error output to `context.stdout`, but our contract requires\n * structured errors on stderr). `cli.process` is used to parse\n * argv into a populated `MigrationFileCommand` instance whose\n * fields drive the orchestration directly.\n */\n override async execute(): Promise<number> {\n return 0;\n }\n}\n\n/**\n * The CLI surface invoked by an authored `migration.ts` file. Exposed as\n * a class with a static `run` method (rather than a free function) to\n * give the concept a stable identity in the ubiquitous language: this is\n * the \"migration-file CLI\", distinct from the apply-time runner that\n * executes migration JSON ops.\n *\n * Currently a single static method. Future surface (e.g. a programmatic\n * `MigrationCLI.serializeOnly(...)` for tests, or extra subcommands) can\n * land here without changing the import shape used by every authored\n * migration.\n */\n// biome-ignore lint/complexity/noStaticOnlyClass: see JSDoc - intentional class facade for the migration-file CLI surface; future methods will share state derived from argv/config.\nexport class MigrationCLI {\n /**\n * Orchestrates a class-flow `migration.ts` script run.\n *\n * The third argument is the in-process testability surface: callers\n * (and tests) may inject `argv`, `stdout`, and `stderr` instead of\n * relying on `process.argv` / `process.stdout` / `process.stderr`.\n * Each option defaults to its `process` global when omitted, so\n * existing two-argument call sites\n * (`MigrationCLI.run(import.meta.url, MyMigration)`) continue to\n * compile and behave identically.\n *\n * Returns the exit code so the caller can branch on it. Also writes\n * the same code to `process.exitCode` so script-style callers that\n * don't await the return value still surface a non-zero exit when\n * something fails.\n *\n * Exit codes:\n * - 0 — success, or `--help`, or imported-not-entrypoint no-op.\n * - 1 — runtime/orchestration error (config not found, target\n * mismatch, etc.).\n * - 2 — usage error (unknown flag, malformed `--config`). Aligns\n * with `docs/CLI Style Guide.md` § Exit Codes.\n */\n static async run(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n options: {\n readonly argv?: readonly string[];\n readonly stdout?: MigrationCliWritable;\n readonly stderr?: MigrationCliWritable;\n } = {},\n ): Promise<number> {\n if (!importMetaUrl) {\n return 0;\n }\n\n const argv = options.argv ?? process.argv;\n const stdout = options.stdout ?? process.stdout;\n const stderr = options.stderr ?? process.stderr;\n\n if (!isDirectEntrypoint(importMetaUrl, argv)) {\n return 0;\n }\n\n const exitCode = await orchestrate(importMetaUrl, MigrationClass, {\n argv,\n stdout,\n stderr,\n });\n // Preserve any pre-existing non-zero `process.exitCode` set by code\n // running alongside `MigrationCLI.run` (an unhandled rejection\n // upstream, an explicit `process.exitCode = N` from another\n // module). Overwriting it with our success would mask the upstream\n // failure for script-style callers that don't await the return\n // value. Failures we return here are still surfaced — non-zero\n // codes always win over the prior status — but successes never\n // clear it.\n if (exitCode !== 0 || !process.exitCode) {\n process.exitCode = exitCode;\n }\n return exitCode;\n }\n}\n\n/**\n * Argv-aware variant of the entrypoint guard. The shared\n * `@prisma-next/migration-tools` helper of the same name reads\n * `process.argv[1]` directly, which doesn't compose with the new\n * in-process testability surface (tests inject `argv` without mutating\n * the process global). Inlined here so the migration-file CLI's check\n * follows the injected `argv[1]` consistently.\n */\nfunction isDirectEntrypoint(importMetaUrl: string, argv: readonly string[]): boolean {\n const argv1 = argv[1];\n if (!argv1) {\n return false;\n }\n try {\n return realpathSync(fileURLToPath(importMetaUrl)) === realpathSync(argv1);\n } catch {\n return false;\n }\n}\n\n/**\n * Argv-and-stream-driven orchestration body. Pulled out of the static\n * method so the entrypoint guard / process-default plumbing stays\n * separate from the parse + load + serialize steps.\n */\nasync function orchestrate(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n ctx: {\n readonly argv: readonly string[];\n readonly stdout: MigrationCliWritable;\n readonly stderr: MigrationCliWritable;\n },\n): Promise<number> {\n const cli = Cli.from([MigrationFileCommand], {\n binaryName: 'migration.ts',\n binaryLabel: 'Migration file CLI',\n });\n\n const input = ctx.argv.slice(2);\n\n // Pre-scan for malformed `--config` (no value, or value-shaped-as-flag)\n // before delegating to clipanion. The legacy parser surfaced both as\n // `errorMigrationCliInvalidConfigArg` (`PN-CLI-4012`); pre-scanning\n // here keeps that contract independent of how clipanion classifies\n // the error internally (it variably throws `UnknownSyntaxError` or\n // accepts the flag-shaped token as the value depending on what other\n // options are registered).\n const configError = detectInvalidConfig(input);\n if (configError) {\n writeStructuredError(ctx.stderr, configError);\n return 2;\n }\n\n let parsed: MigrationFileCommand;\n try {\n const command = cli.process({\n input: [...input],\n context: { stdout: ctx.stdout, stderr: ctx.stderr },\n });\n if (!(command instanceof MigrationFileCommand)) {\n // The only registered command class is `MigrationFileCommand`;\n // any other concrete type indicates clipanion emitted its\n // built-in `HelpCommand`. Render usage directly so we don't\n // depend on calling `cli.run` (which routes errors to stdout —\n // wrong stream for our contract).\n ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));\n return 0;\n }\n parsed = command;\n } catch (err) {\n return renderParseError(err, input, ctx.stderr);\n }\n\n if (parsed.help) {\n ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));\n return 0;\n }\n\n try {\n await runMigration(importMetaUrl, MigrationClass, parsed, ctx);\n return 0;\n } catch (err) {\n if (CliStructuredError.is(err)) {\n writeStructuredError(ctx.stderr, err);\n } else if (MigrationToolsError.is(err)) {\n // Migration-tools errors (e.g. `errorInvalidJson` thrown by\n // `readExistingMetadata` when migration.json is malformed) carry\n // their own `code`/`why`/`fix` shape. Render them with the same\n // visual structure as `CliStructuredError` so consumers grepping\n // for `MIGRATION.<CODE>` see consistent output across surfaces.\n const fix = err.fix ? `\\n${err.fix}` : '';\n ctx.stderr.write(`${err.code}: ${err.message}\\n${err.why}${fix}\\n`);\n } else {\n ctx.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`);\n }\n return 1;\n }\n}\n\n/**\n * Returns an `errorMigrationCliInvalidConfigArg` envelope when `input`\n * contains a malformed `--config`:\n *\n * - `--config` as the last token (no value follows).\n * - `--config <flag>` where `<flag>` starts with `-` (silently\n * consuming the next flag would either drop the flag or serialize\n * against the wrong project).\n * - `--config <empty>` where the value is the empty string. Shells\n * expand `--config \"\"` (or `--config \"$UNSET_VAR\"`) into a real\n * empty argv token; treating that as a usage error here surfaces\n * `PN-CLI-4012` instead of a less actionable loader error on an\n * empty path.\n * - `--config=` (the equals form with an empty value). Same shape as\n * the empty-string case above; the user expressed intent to override\n * the config path but the override is empty.\n *\n * `--config=<value>` and `--config <value>` with a non-empty value are\n * both valid (and the equals form's value is allowed to start with\n * `-` — the `=` makes the binding explicit).\n */\nfunction detectInvalidConfig(input: readonly string[]): CliStructuredError | null {\n for (let i = 0; i < input.length; i++) {\n const token = input[i];\n if (token === '--config') {\n const next = input[i + 1];\n if (next === undefined || next === '') {\n return errorMigrationCliInvalidConfigArg();\n }\n if (next.startsWith('-')) {\n return errorMigrationCliInvalidConfigArg({ nextToken: next });\n }\n continue;\n }\n if (token === '--config=') {\n return errorMigrationCliInvalidConfigArg();\n }\n }\n return null;\n}\n\n/**\n * Translate clipanion's parse-time errors into the project's structured\n * error envelopes.\n *\n * - `UnknownSyntaxError` covers both unknown flags (`--frobnicate`) and\n * the bare-trailing `--config` case (where arity-1 needs a value but\n * none was supplied). Distinguished by inspecting the input array.\n * - `UsageError` covers schema/validator failures from typanion. None\n * of the migration-file CLI's options have validators today, but we\n * still translate it as a usage error (exit 2) for forward-compat.\n * - Anything else re-throws — caller's outer catch will surface it as\n * exit 1 (runtime error).\n */\nfunction renderParseError(\n err: unknown,\n input: readonly string[],\n stderr: MigrationCliWritable,\n): number {\n if (isUnknownSyntaxError(err)) {\n const flag = findOffendingFlag(input);\n writeStructuredError(stderr, errorMigrationCliUnknownFlag({ flag, knownFlags: KNOWN_FLAGS }));\n return 2;\n }\n if (err instanceof UsageError) {\n // typanion validator failures and similar usage errors. None of\n // the migration-file CLI's options have validators today, so this\n // branch is forward-compat scaffolding — kept so that a future\n // option declaration with a validator routes through the same PN\n // envelope path rather than escaping as exit 1.\n writeStructuredError(stderr, errorMigrationCliInvalidConfigArg({ nextToken: err.message }));\n return 2;\n }\n throw err;\n}\n\n/**\n * Duck-type check for clipanion's `UnknownSyntaxError`: the class is\n * thrown by the parser but is not re-exported from the package's main\n * entry (only `UsageError` is — see clipanion's `advanced/index.d.ts`).\n * Identified by `name === 'UnknownSyntaxError'` and the\n * `clipanion.type === 'none'` discriminator that clipanion's\n * `ErrorWithMeta` interface guarantees.\n */\nfunction isUnknownSyntaxError(err: unknown): err is Error {\n if (!(err instanceof Error) || err.name !== 'UnknownSyntaxError') {\n return false;\n }\n // clipanion's `ErrorWithMeta` interface guarantees a `clipanion` field with\n // a `type` discriminator on every error it throws. Read it via a structural\n // shape rather than importing the class (it's not re-exported from the\n // package main).\n const meta = (err as { clipanion?: { type?: string } }).clipanion;\n return typeof meta === 'object' && meta !== null && meta.type === 'none';\n}\n\n/**\n * Best-effort: pull the first input token that doesn't match a known\n * flag. Falls back to the first token when we can't pinpoint it. The\n * returned name is rendered into the user-visible PN-CLI-4013 envelope\n * (`Unknown flag \\`<name>\\``) and round-tripped via `meta.flag` so\n * agent consumers can render their own \"did you mean\" suggestions.\n */\nfunction findOffendingFlag(input: readonly string[]): string {\n for (const token of input) {\n if (!token.startsWith('-')) {\n continue;\n }\n const head = token.split('=', 1)[0] ?? token;\n if (!KNOWN_FLAGS.includes(head) && head !== '-h') {\n return head;\n }\n }\n return input[0] ?? '';\n}\n\n/**\n * Write a `CliStructuredError` envelope to the given stream. Format\n * matches the legacy hand-rolled writer (`message: why`) so the rest of\n * the project's error rendering stays consistent across surfaces. The\n * full PN code (`PN-<domain>-<code>`) is included so consumers can\n * grep for stable identifiers.\n */\nfunction writeStructuredError(stream: MigrationCliWritable, err: CliStructuredError): void {\n const envelope = err.toEnvelope();\n const why = envelope.why ?? envelope.summary;\n const fix = envelope.fix ? `\\n${envelope.fix}` : '';\n stream.write(`${envelope.code}: ${envelope.summary}\\n${why}${fix}\\n`);\n}\n\n/**\n * Read a previously-scaffolded `migration.json` from disk, returning\n * `null` when the file is missing and throwing `MIGRATION.INVALID_JSON`\n * when the file is present but cannot be parsed as JSON. The CLI feeds\n * this into `buildMigrationArtifacts` so the pure builder can preserve\n * fields owned by `migration plan` (contract bookends, hints, labels,\n * `createdAt`) across re-emits.\n *\n * Author-time path: this loader still does not verify the manifest hash\n * or schema — that is the apply-time loader's job. Hash mismatch is the\n * *expected* outcome of a re-author (the developer's source changes\n * invalidate the prior hash by construction), and verification here\n * would block legitimate regenerations. Syntactic JSON-parse failure,\n * however, is now surfaced rather than swallowed: a malformed\n * `migration.json` indicates either a hand-edit gone wrong or partial\n * write, and silently rebuilding from `describe()` would discard the\n * user's on-disk content (preserved bookends, hints, labels,\n * `createdAt`) without any indication something was wrong on disk.\n * Apply-time consumers always route through the verifying\n * `readMigrationPackage` in `@prisma-next/migration-tools/io` instead.\n */\nfunction readExistingMetadata(metadataPath: string): Partial<MigrationMetadata> | null {\n let raw: string;\n try {\n raw = readFileSync(metadataPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n return JSON.parse(raw) as Partial<MigrationMetadata>;\n } catch (e) {\n throw errorInvalidJson(metadataPath, e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Persist a migration instance's artifacts to `migrationDir`. In\n * `dryRun` mode the artifacts are printed to stdout (with the same\n * `--- migration.json --- / --- ops.json ---` framing the legacy\n * `serializeMigration` helper used) and no files are written. Otherwise\n * `ops.json` and `migration.json` are written next to `migration.ts` and\n * a confirmation line is printed.\n *\n * File I/O lives in the CLI rather than `@prisma-next/migration-tools`\n * so the migration-tools package stays focused on the pure\n * `Migration` → in-memory artifact conversion. The CLI is the only\n * legitimate site for combining config loading, stack assembly, and\n * filesystem persistence.\n */\nfunction serializeMigrationToDisk(\n instance: Migration,\n migrationDir: string,\n dryRun: boolean,\n stdout: MigrationCliWritable,\n): void {\n const metadataPath = join(migrationDir, 'migration.json');\n const existing = readExistingMetadata(metadataPath);\n const { opsJson, metadataJson } = buildMigrationArtifacts(instance, existing);\n\n if (dryRun) {\n stdout.write(`--- migration.json ---\\n${metadataJson}\\n`);\n stdout.write('--- ops.json ---\\n');\n stdout.write(`${opsJson}\\n`);\n return;\n }\n\n writeFileSync(join(migrationDir, 'ops.json'), opsJson);\n writeFileSync(metadataPath, metadataJson);\n\n stdout.write(`Wrote ops.json + migration.json to ${migrationDir}\\n`);\n}\n\n/**\n * Inner orchestration: load config, probe-construct the migration,\n * verify target, assemble the stack, construct with the stack, persist.\n *\n * Throws `CliStructuredError` for known failure modes (config not\n * found, target mismatch); the outer `orchestrate` translates those to\n * exit 1.\n */\nasync function runMigration(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n parsed: MigrationFileCommand,\n ctx: {\n readonly stdout: MigrationCliWritable;\n readonly stderr: MigrationCliWritable;\n },\n): Promise<void> {\n const migrationFile = fileURLToPath(importMetaUrl);\n const migrationDir = dirname(migrationFile);\n\n const config = await loadConfig(parsed.config);\n\n // Probe-instantiate without a stack so we can read `targetId` before\n // any target-specific constructor side effects (e.g.\n // `PostgresMigration`'s `stack.adapter.create(stack)`) run. Concrete\n // subclasses are required to accept the no-arg form; the abstract\n // `Migration` constructor declares `stack?` and target subclasses\n // (Postgres, Mongo) propagate that optionality. This makes the\n // target-mismatch guard fail fast with `PN-MIG-2006` before any\n // stack-driven adapter construction begins, even if the wrong-target\n // adapter's `create` would otherwise succeed and silently misshapen\n // the stored adapter cast.\n const probe = new MigrationClass();\n\n if (probe.targetId !== config.target.targetId) {\n throw errorMigrationTargetMismatch({\n migrationTargetId: probe.targetId,\n configTargetId: config.target.targetId,\n });\n }\n\n const stack = createControlStack(config);\n const instance = new MigrationClass(stack);\n\n serializeMigrationToDisk(instance, migrationDir, parsed.dryRun, ctx.stdout);\n void ctx.stderr;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"migration-cli.mjs","names":[],"sources":["../src/migration-cli.ts"],"sourcesContent":["/**\n * The migration-file CLI interface: the actor invoked when the author runs\n * `node migration.ts` directly.\n *\n * Naming: this is *not* a \"migration runner\" in the apply-time sense. The\n * apply-time runner is the thing `prisma-next migrate` uses to\n * execute migration JSON ops against a database. `MigrationCLI` is the\n * tiny CLI surface owned by an authored `migration.ts` file: parse the\n * file's argv, load the project's `prisma-next.config.ts`, assemble a\n * `ControlStack`, instantiate the migration class, and serialize.\n *\n * The user authors a migration class, then calls\n * `MigrationCLI.run(import.meta.url, MigrationClass)` at module scope\n * after the class definition. When the file is invoked as a node\n * entrypoint (`node migration.ts`), the CLI:\n *\n * 1. Detects whether the file is the direct entrypoint (no-op when imported).\n * 2. Parses CLI args (`--help`, `--dry-run`, `--config <path>`) via\n * [clipanion](https://github.com/arcanis/clipanion).\n * 3. Loads the project's `prisma-next.config.ts` via the same `loadConfig`\n * the CLI commands use, walking up from the migration file's directory.\n * 4. Probe-instantiates the migration class without a stack so it can read\n * `targetId` and verify it matches `config.target.targetId`\n * (`PN-MIG-2006` on mismatch) before any stack-driven adapter\n * construction runs.\n * 5. Assembles a `ControlStack` from the loaded config descriptors and\n * constructs the migration with that stack.\n * 6. Reads any previously-scaffolded `migration.json`, then calls\n * `buildMigrationArtifacts` from `@prisma-next/migration-tools` to\n * produce in-memory `ops.json` + `migration.json` content. Persists\n * the result to disk (or prints in dry-run mode).\n *\n * File I/O lives here, in `@prisma-next/cli`: this is the only place\n * that legitimately combines config loading, stack assembly, and\n * on-disk persistence. `@prisma-next/migration-tools` owns the pure\n * conversion from a `Migration` instance to artifact strings; `Migration`\n * stays a pure abstract class.\n *\n * Parser library: clipanion (chosen over Commander/citty/`node:util.parseArgs`\n * for its in-process testability and runtime-agnostic execution surface; see\n * `docs/architecture docs/research/commander-friction-points.md` for the\n * evaluation rubric and the durable rationale that drove the choice).\n */\n\nimport { readFileSync, realpathSync, writeFileSync } from 'node:fs';\nimport type { Writable } from 'node:stream';\nimport { fileURLToPath } from 'node:url';\nimport {\n CliStructuredError,\n errorMigrationCliInvalidConfigArg,\n errorMigrationCliUnknownFlag,\n} from '@prisma-next/errors/control';\nimport { errorMigrationTargetMismatch } from '@prisma-next/errors/migration';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { errorInvalidJson, MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport { buildMigrationArtifacts, type Migration } from '@prisma-next/migration-tools/migration';\nimport { Cli, Command, Option, UsageError } from 'clipanion';\nimport { dirname, join } from 'pathe';\nimport { loadConfig } from './config-loader';\n\n/**\n * Constructor shape accepted by `MigrationCLI.run`. `Migration` subclasses\n * accept an optional `ControlStack` in their constructor (each subclass\n * narrows the stack to its own family/target generics); the CLI always\n * passes one assembled from the loaded config. We use a rest-args `any[]`\n * constructor signature so that subclass constructors with narrower\n * parameter types remain assignable - constructor type compatibility in\n * TS is contravariant in the parameter, and a wider `unknown` parameter\n * on the alias side would reject any narrower subclass signature.\n *\n * The CLI only ever passes one argument (`new MigrationClass(stack)`);\n * the rest-arity is purely a type-compatibility concession for subclass\n * constructors that declare narrower parameter types, not an extension\n * point for additional construction arguments.\n */\n// biome-ignore lint/suspicious/noExplicitAny: see JSDoc - rest args with any are the idiomatic TS pattern for accepting arbitrary subclass constructor signatures\nexport type MigrationConstructor = new (...args: any[]) => Migration;\n\n/**\n * Stream surface accepted by `MigrationCLI.run`'s `options.stdout` /\n * `options.stderr`. Aliases node's `Writable` because clipanion's\n * `BaseContext.stdout`/`stderr` are typed as `Writable`, and the CLI\n * forwards the injected streams into clipanion's context.\n *\n * `process.stdout` and `process.stderr` are `Writable`-shaped, so the\n * default-fallback path remains a no-op for existing two-argument\n * callers like `MigrationCLI.run(import.meta.url, MyMigration)`.\n *\n * Tests inject a `Writable` subclass that captures chunks for\n * assertions.\n */\nexport type MigrationCliWritable = Writable;\n\n/**\n * Flags exposed by the migration-file CLI.\n *\n * Must stay in sync with the `Option` declarations on\n * `MigrationFileCommand` below. This list is rendered in the\n * `errorMigrationCliUnknownFlag` envelope's `fix` text and `meta`,\n * so order matters for user-visible output (declaration order is the\n * order users see when they run `--help`).\n */\nconst KNOWN_FLAGS: readonly string[] = ['--help', '--dry-run', '--config'];\n\n/**\n * The clipanion command that owns the migration-file CLI's option\n * declarations. The class is internal — `MigrationCLI.run` is the\n * stable public surface. Adding a flag here automatically updates\n * `--help` rendering and the `KNOWN_FLAGS` list (the latter must be\n * updated in tandem).\n */\nclass MigrationFileCommand extends Command {\n static override paths = [Command.Default];\n\n static override usage = Command.Usage({\n description: 'Self-emit ops.json and migration.json from a class-flow migration',\n details: `\n Loads the project's prisma-next.config.ts, assembles a ControlStack\n from the configured target/adapter/extensions, and serializes the\n migration's operations + metadata next to this file.\n `,\n examples: [\n ['Self-emit ops.json + migration.json next to migration.ts', '$0'],\n ['Preview without writing files', '$0 --dry-run'],\n ['Use a non-default config path', '$0 --config ./custom.config.ts'],\n ],\n });\n\n dryRun = Option.Boolean('--dry-run', false, {\n description: 'Print operations to stdout without writing files',\n });\n\n config = Option.String('--config', {\n description: 'Path to prisma-next.config.ts',\n });\n\n /**\n * Unused: orchestration runs inside `MigrationCLI.run` so error\n * routing stays under our control (clipanion's `cli.run` writes\n * error output to `context.stdout`, but our contract requires\n * structured errors on stderr). `cli.process` is used to parse\n * argv into a populated `MigrationFileCommand` instance whose\n * fields drive the orchestration directly.\n */\n override async execute(): Promise<number> {\n return 0;\n }\n}\n\n/**\n * The CLI surface invoked by an authored `migration.ts` file. Exposed as\n * a class with a static `run` method (rather than a free function) to\n * give the concept a stable identity in the ubiquitous language: this is\n * the \"migration-file CLI\", distinct from the apply-time runner that\n * executes migration JSON ops.\n *\n * Currently a single static method. Future surface (e.g. a programmatic\n * `MigrationCLI.serializeOnly(...)` for tests, or extra subcommands) can\n * land here without changing the import shape used by every authored\n * migration.\n */\n// biome-ignore lint/complexity/noStaticOnlyClass: see JSDoc - intentional class facade for the migration-file CLI surface; future methods will share state derived from argv/config.\nexport class MigrationCLI {\n /**\n * Orchestrates a class-flow `migration.ts` script run.\n *\n * The third argument is the in-process testability surface: callers\n * (and tests) may inject `argv`, `stdout`, and `stderr` instead of\n * relying on `process.argv` / `process.stdout` / `process.stderr`.\n * Each option defaults to its `process` global when omitted, so\n * existing two-argument call sites\n * (`MigrationCLI.run(import.meta.url, MyMigration)`) continue to\n * compile and behave identically.\n *\n * Returns the exit code so the caller can branch on it. Also writes\n * the same code to `process.exitCode` so script-style callers that\n * don't await the return value still surface a non-zero exit when\n * something fails.\n *\n * Exit codes:\n * - 0 — success, or `--help`, or imported-not-entrypoint no-op.\n * - 1 — runtime/orchestration error (config not found, target\n * mismatch, etc.).\n * - 2 — usage error (unknown flag, malformed `--config`). Aligns\n * with `docs/CLI Style Guide.md` § Exit Codes.\n */\n static async run(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n options: {\n readonly argv?: readonly string[];\n readonly stdout?: MigrationCliWritable;\n readonly stderr?: MigrationCliWritable;\n } = {},\n ): Promise<number> {\n if (!importMetaUrl) {\n return 0;\n }\n\n const argv = options.argv ?? process.argv;\n const stdout = options.stdout ?? process.stdout;\n const stderr = options.stderr ?? process.stderr;\n\n if (!isDirectEntrypoint(importMetaUrl, argv)) {\n return 0;\n }\n\n const exitCode = await orchestrate(importMetaUrl, MigrationClass, {\n argv,\n stdout,\n stderr,\n });\n // Preserve any pre-existing non-zero `process.exitCode` set by code\n // running alongside `MigrationCLI.run` (an unhandled rejection\n // upstream, an explicit `process.exitCode = N` from another\n // module). Overwriting it with our success would mask the upstream\n // failure for script-style callers that don't await the return\n // value. Failures we return here are still surfaced — non-zero\n // codes always win over the prior status — but successes never\n // clear it.\n if (exitCode !== 0 || !process.exitCode) {\n process.exitCode = exitCode;\n }\n return exitCode;\n }\n}\n\n/**\n * Argv-aware variant of the entrypoint guard. The shared\n * `@prisma-next/migration-tools` helper of the same name reads\n * `process.argv[1]` directly, which doesn't compose with the new\n * in-process testability surface (tests inject `argv` without mutating\n * the process global). Inlined here so the migration-file CLI's check\n * follows the injected `argv[1]` consistently.\n */\nfunction isDirectEntrypoint(importMetaUrl: string, argv: readonly string[]): boolean {\n const argv1 = argv[1];\n if (!argv1) {\n return false;\n }\n try {\n return realpathSync(fileURLToPath(importMetaUrl)) === realpathSync(argv1);\n } catch {\n return false;\n }\n}\n\n/**\n * Argv-and-stream-driven orchestration body. Pulled out of the static\n * method so the entrypoint guard / process-default plumbing stays\n * separate from the parse + load + serialize steps.\n */\nasync function orchestrate(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n ctx: {\n readonly argv: readonly string[];\n readonly stdout: MigrationCliWritable;\n readonly stderr: MigrationCliWritable;\n },\n): Promise<number> {\n const cli = Cli.from([MigrationFileCommand], {\n binaryName: 'migration.ts',\n binaryLabel: 'Migration file CLI',\n });\n\n const input = ctx.argv.slice(2);\n\n // Pre-scan for malformed `--config` (no value, or value-shaped-as-flag)\n // before delegating to clipanion. The legacy parser surfaced both as\n // `errorMigrationCliInvalidConfigArg` (`PN-CLI-4012`); pre-scanning\n // here keeps that contract independent of how clipanion classifies\n // the error internally (it variably throws `UnknownSyntaxError` or\n // accepts the flag-shaped token as the value depending on what other\n // options are registered).\n const configError = detectInvalidConfig(input);\n if (configError) {\n writeStructuredError(ctx.stderr, configError);\n return 2;\n }\n\n let parsed: MigrationFileCommand;\n try {\n const command = cli.process({\n input: [...input],\n context: { stdout: ctx.stdout, stderr: ctx.stderr },\n });\n if (!(command instanceof MigrationFileCommand)) {\n // The only registered command class is `MigrationFileCommand`;\n // any other concrete type indicates clipanion emitted its\n // built-in `HelpCommand`. Render usage directly so we don't\n // depend on calling `cli.run` (which routes errors to stdout —\n // wrong stream for our contract).\n ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));\n return 0;\n }\n parsed = command;\n } catch (err) {\n return renderParseError(err, input, ctx.stderr);\n }\n\n if (parsed.help) {\n ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));\n return 0;\n }\n\n try {\n await runMigration(importMetaUrl, MigrationClass, parsed, ctx);\n return 0;\n } catch (err) {\n if (CliStructuredError.is(err)) {\n writeStructuredError(ctx.stderr, err);\n } else if (MigrationToolsError.is(err)) {\n // Migration-tools errors (e.g. `errorInvalidJson` thrown by\n // `readExistingMetadata` when migration.json is malformed) carry\n // their own `code`/`why`/`fix` shape. Render them with the same\n // visual structure as `CliStructuredError` so consumers grepping\n // for `MIGRATION.<CODE>` see consistent output across surfaces.\n const fix = err.fix ? `\\n${err.fix}` : '';\n ctx.stderr.write(`${err.code}: ${err.message}\\n${err.why}${fix}\\n`);\n } else {\n ctx.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`);\n }\n return 1;\n }\n}\n\n/**\n * Returns an `errorMigrationCliInvalidConfigArg` envelope when `input`\n * contains a malformed `--config`:\n *\n * - `--config` as the last token (no value follows).\n * - `--config <flag>` where `<flag>` starts with `-` (silently\n * consuming the next flag would either drop the flag or serialize\n * against the wrong project).\n * - `--config <empty>` where the value is the empty string. Shells\n * expand `--config \"\"` (or `--config \"$UNSET_VAR\"`) into a real\n * empty argv token; treating that as a usage error here surfaces\n * `PN-CLI-4012` instead of a less actionable loader error on an\n * empty path.\n * - `--config=` (the equals form with an empty value). Same shape as\n * the empty-string case above; the user expressed intent to override\n * the config path but the override is empty.\n *\n * `--config=<value>` and `--config <value>` with a non-empty value are\n * both valid (and the equals form's value is allowed to start with\n * `-` — the `=` makes the binding explicit).\n */\nfunction detectInvalidConfig(input: readonly string[]): CliStructuredError | null {\n for (let i = 0; i < input.length; i++) {\n const token = input[i];\n if (token === '--config') {\n const next = input[i + 1];\n if (next === undefined || next === '') {\n return errorMigrationCliInvalidConfigArg();\n }\n if (next.startsWith('-')) {\n return errorMigrationCliInvalidConfigArg({ nextToken: next });\n }\n continue;\n }\n if (token === '--config=') {\n return errorMigrationCliInvalidConfigArg();\n }\n }\n return null;\n}\n\n/**\n * Translate clipanion's parse-time errors into the project's structured\n * error envelopes.\n *\n * - `UnknownSyntaxError` covers both unknown flags (`--frobnicate`) and\n * the bare-trailing `--config` case (where arity-1 needs a value but\n * none was supplied). Distinguished by inspecting the input array.\n * - `UsageError` covers schema/validator failures from typanion. None\n * of the migration-file CLI's options have validators today, but we\n * still translate it as a usage error (exit 2) for forward-compat.\n * - Anything else re-throws — caller's outer catch will surface it as\n * exit 1 (runtime error).\n */\nfunction renderParseError(\n err: unknown,\n input: readonly string[],\n stderr: MigrationCliWritable,\n): number {\n if (isUnknownSyntaxError(err)) {\n const flag = findOffendingFlag(input);\n writeStructuredError(stderr, errorMigrationCliUnknownFlag({ flag, knownFlags: KNOWN_FLAGS }));\n return 2;\n }\n if (err instanceof UsageError) {\n // typanion validator failures and similar usage errors. None of\n // the migration-file CLI's options have validators today, so this\n // branch is forward-compat scaffolding — kept so that a future\n // option declaration with a validator routes through the same PN\n // envelope path rather than escaping as exit 1.\n writeStructuredError(stderr, errorMigrationCliInvalidConfigArg({ nextToken: err.message }));\n return 2;\n }\n throw err;\n}\n\n/**\n * Duck-type check for clipanion's `UnknownSyntaxError`: the class is\n * thrown by the parser but is not re-exported from the package's main\n * entry (only `UsageError` is — see clipanion's `advanced/index.d.ts`).\n * Identified by `name === 'UnknownSyntaxError'` and the\n * `clipanion.type === 'none'` discriminator that clipanion's\n * `ErrorWithMeta` interface guarantees.\n */\nfunction isUnknownSyntaxError(err: unknown): err is Error {\n if (!(err instanceof Error) || err.name !== 'UnknownSyntaxError') {\n return false;\n }\n // clipanion's `ErrorWithMeta` interface guarantees a `clipanion` field with\n // a `type` discriminator on every error it throws. Read it via a structural\n // shape rather than importing the class (it's not re-exported from the\n // package main).\n const meta = (err as { clipanion?: { type?: string } }).clipanion;\n return typeof meta === 'object' && meta !== null && meta.type === 'none';\n}\n\n/**\n * Best-effort: pull the first input token that doesn't match a known\n * flag. Falls back to the first token when we can't pinpoint it. The\n * returned name is rendered into the user-visible PN-CLI-4013 envelope\n * (`Unknown flag \\`<name>\\``) and round-tripped via `meta.flag` so\n * agent consumers can render their own \"did you mean\" suggestions.\n */\nfunction findOffendingFlag(input: readonly string[]): string {\n for (const token of input) {\n if (!token.startsWith('-')) {\n continue;\n }\n const head = token.split('=', 1)[0] ?? token;\n if (!KNOWN_FLAGS.includes(head) && head !== '-h') {\n return head;\n }\n }\n return input[0] ?? '';\n}\n\n/**\n * Write a `CliStructuredError` envelope to the given stream. Format\n * matches the legacy hand-rolled writer (`message: why`) so the rest of\n * the project's error rendering stays consistent across surfaces. The\n * full PN code (`PN-<domain>-<code>`) is included so consumers can\n * grep for stable identifiers.\n */\nfunction writeStructuredError(stream: MigrationCliWritable, err: CliStructuredError): void {\n const envelope = err.toEnvelope();\n const why = envelope.why ?? envelope.summary;\n const fix = envelope.fix ? `\\n${envelope.fix}` : '';\n stream.write(`${envelope.code}: ${envelope.summary}\\n${why}${fix}\\n`);\n}\n\n/**\n * Read a previously-scaffolded `migration.json` from disk, returning\n * `null` when the file is missing and throwing `MIGRATION.INVALID_JSON`\n * when the file is present but cannot be parsed as JSON. The CLI feeds\n * this into `buildMigrationArtifacts` so the pure builder can preserve\n * fields owned by `migration plan` (contract bookends, `createdAt`) across\n * re-emits.\n *\n * Author-time path: this loader still does not verify the manifest hash\n * or schema — that is the apply-time loader's job. Hash mismatch is the\n * *expected* outcome of a re-author (the developer's source changes\n * invalidate the prior hash by construction), and verification here\n * would block legitimate regenerations. Syntactic JSON-parse failure,\n * however, is now surfaced rather than swallowed: a malformed\n * `migration.json` indicates either a hand-edit gone wrong or partial\n * write, and silently rebuilding from `describe()` would discard the\n * user's on-disk content (preserved bookends, `createdAt`) without any\n * indication something was wrong on disk.\n * Apply-time consumers always route through the verifying\n * `readMigrationPackage` in `@prisma-next/migration-tools/io` instead.\n */\nfunction readExistingMetadata(metadataPath: string): Partial<MigrationMetadata> | null {\n let raw: string;\n try {\n raw = readFileSync(metadataPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n return JSON.parse(raw) as Partial<MigrationMetadata>;\n } catch (e) {\n throw errorInvalidJson(metadataPath, e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Persist a migration instance's artifacts to `migrationDir`. In\n * `dryRun` mode the artifacts are printed to stdout (with the same\n * `--- migration.json --- / --- ops.json ---` framing the legacy\n * `serializeMigration` helper used) and no files are written. Otherwise\n * `ops.json` and `migration.json` are written next to `migration.ts` and\n * a confirmation line is printed.\n *\n * File I/O lives in the CLI rather than `@prisma-next/migration-tools`\n * so the migration-tools package stays focused on the pure\n * `Migration` → in-memory artifact conversion. The CLI is the only\n * legitimate site for combining config loading, stack assembly, and\n * filesystem persistence.\n */\nfunction serializeMigrationToDisk(\n instance: Migration,\n migrationDir: string,\n dryRun: boolean,\n stdout: MigrationCliWritable,\n): void {\n const metadataPath = join(migrationDir, 'migration.json');\n const existing = readExistingMetadata(metadataPath);\n const { opsJson, metadataJson } = buildMigrationArtifacts(instance, existing);\n\n if (dryRun) {\n stdout.write(`--- migration.json ---\\n${metadataJson}\\n`);\n stdout.write('--- ops.json ---\\n');\n stdout.write(`${opsJson}\\n`);\n return;\n }\n\n writeFileSync(join(migrationDir, 'ops.json'), opsJson);\n writeFileSync(metadataPath, metadataJson);\n\n stdout.write(`Wrote ops.json + migration.json to ${migrationDir}\\n`);\n}\n\n/**\n * Inner orchestration: load config, probe-construct the migration,\n * verify target, assemble the stack, construct with the stack, persist.\n *\n * Throws `CliStructuredError` for known failure modes (config not\n * found, target mismatch); the outer `orchestrate` translates those to\n * exit 1.\n */\nasync function runMigration(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n parsed: MigrationFileCommand,\n ctx: {\n readonly stdout: MigrationCliWritable;\n readonly stderr: MigrationCliWritable;\n },\n): Promise<void> {\n const migrationFile = fileURLToPath(importMetaUrl);\n const migrationDir = dirname(migrationFile);\n\n const config = await loadConfig(parsed.config);\n\n // Probe-instantiate without a stack so we can read `targetId` before\n // any target-specific constructor side effects (e.g.\n // `PostgresMigration`'s `stack.adapter.create(stack)`) run. Concrete\n // subclasses are required to accept the no-arg form; the abstract\n // `Migration` constructor declares `stack?` and target subclasses\n // (Postgres, Mongo) propagate that optionality. This makes the\n // target-mismatch guard fail fast with `PN-MIG-2006` before any\n // stack-driven adapter construction begins, even if the wrong-target\n // adapter's `create` would otherwise succeed and silently misshapen\n // the stored adapter cast.\n const probe = new MigrationClass();\n\n if (probe.targetId !== config.target.targetId) {\n throw errorMigrationTargetMismatch({\n migrationTargetId: probe.targetId,\n configTargetId: config.target.targetId,\n });\n }\n\n const stack = createControlStack(config);\n const instance = new MigrationClass(stack);\n\n serializeMigrationToDisk(instance, migrationDir, parsed.dryRun, ctx.stdout);\n void ctx.stderr;\n}\n"],"mappings":"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"}
@@ -1,8 +1,7 @@
1
1
  import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
2
- import { _ as errorTargetMigrationNotSupported, a as errorContractValidationFailed, c as errorDriverRequired, l as errorFileNotFound, o as errorDatabaseConnectionRequired, y as errorUnexpected } from "./cli-errors-Djtz98Vm.mjs";
3
- import { S as formatStyledHeader, c as resolveContractPath, o as maskConnectionUrl, t as addGlobalOptions } from "./command-helpers-BSb0tRC8.mjs";
4
- import { t as createProgressAdapter } from "./progress-adapter-DFfvZcYL.mjs";
5
- import { t as createControlClient } from "./client-oXO2WCPD.mjs";
2
+ import { $ as errorTargetMigrationNotSupported, F as errorDatabaseConnectionRequired, L as errorDriverRequired, P as errorContractValidationFailed, R as errorFileNotFound, T as formatStyledHeader, i as maskConnectionUrl, o as resolveContractPath, t as addGlobalOptions, tt as errorUnexpected } from "./command-helpers-Bbw1GbwL.mjs";
3
+ import { t as createProgressAdapter } from "./progress-adapter-C644QK8l.mjs";
4
+ import { t as createControlClient } from "./client-KgJorIvG.mjs";
6
5
  import { notOk, ok } from "@prisma-next/utils/result";
7
6
  import { readFile } from "node:fs/promises";
8
7
  import { hasMigrations } from "@prisma-next/framework-components/control";
@@ -101,4 +100,4 @@ function addMigrationCommandOptions(command) {
101
100
  //#endregion
102
101
  export { prepareMigrationContext as n, addMigrationCommandOptions as t };
103
102
 
104
- //# sourceMappingURL=migration-command-scaffold-Bzd9La5c.mjs.map
103
+ //# sourceMappingURL=migration-command-scaffold-CjvwO6at.mjs.map