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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/dist/cli-errors-DFF1LlfU.mjs +215 -0
  2. package/dist/cli-errors-DFF1LlfU.mjs.map +1 -0
  3. package/dist/cli.mjs +8 -9
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/{client-oXO2WCPD.mjs → client-a5NJce0-.mjs} +5 -5
  6. package/dist/{client-oXO2WCPD.mjs.map → client-a5NJce0-.mjs.map} +1 -1
  7. package/dist/{command-helpers-DtavI0wJ.mjs → command-helpers-BnqwTptC.mjs} +380 -6
  8. package/dist/command-helpers-BnqwTptC.mjs.map +1 -0
  9. package/dist/commands/contract-emit.d.mts.map +1 -1
  10. package/dist/commands/contract-emit.mjs +1 -1
  11. package/dist/commands/contract-infer.d.mts.map +1 -1
  12. package/dist/commands/contract-infer.mjs +1 -1
  13. package/dist/commands/db-init.d.mts.map +1 -1
  14. package/dist/commands/db-init.mjs +33 -7
  15. package/dist/commands/db-init.mjs.map +1 -1
  16. package/dist/commands/db-schema.d.mts.map +1 -1
  17. package/dist/commands/db-schema.mjs +3 -4
  18. package/dist/commands/db-schema.mjs.map +1 -1
  19. package/dist/commands/db-sign.d.mts.map +1 -1
  20. package/dist/commands/db-sign.mjs +6 -7
  21. package/dist/commands/db-sign.mjs.map +1 -1
  22. package/dist/commands/db-update.d.mts.map +1 -1
  23. package/dist/commands/db-update.mjs +36 -8
  24. package/dist/commands/db-update.mjs.map +1 -1
  25. package/dist/commands/db-verify.d.mts.map +1 -1
  26. package/dist/commands/db-verify.mjs +1 -1
  27. package/dist/commands/migrate.d.mts +5 -1
  28. package/dist/commands/migrate.d.mts.map +1 -1
  29. package/dist/commands/migrate.mjs +44 -9
  30. package/dist/commands/migrate.mjs.map +1 -1
  31. package/dist/commands/migration-check.d.mts.map +1 -1
  32. package/dist/commands/migration-check.mjs +2 -3
  33. package/dist/commands/migration-check.mjs.map +1 -1
  34. package/dist/commands/migration-graph.d.mts.map +1 -1
  35. package/dist/commands/migration-graph.mjs +2 -3
  36. package/dist/commands/migration-graph.mjs.map +1 -1
  37. package/dist/commands/migration-list.d.mts +57 -13
  38. package/dist/commands/migration-list.d.mts.map +1 -1
  39. package/dist/commands/migration-list.mjs +2 -103
  40. package/dist/commands/migration-log.d.mts.map +1 -1
  41. package/dist/commands/migration-log.mjs +3 -4
  42. package/dist/commands/migration-log.mjs.map +1 -1
  43. package/dist/commands/migration-new.d.mts.map +1 -1
  44. package/dist/commands/migration-new.mjs +3 -4
  45. package/dist/commands/migration-new.mjs.map +1 -1
  46. package/dist/commands/migration-plan.d.mts +1 -0
  47. package/dist/commands/migration-plan.d.mts.map +1 -1
  48. package/dist/commands/migration-plan.mjs +1 -1
  49. package/dist/commands/migration-show.d.mts +1 -1
  50. package/dist/commands/migration-show.d.mts.map +1 -1
  51. package/dist/commands/migration-show.mjs +6 -7
  52. package/dist/commands/migration-show.mjs.map +1 -1
  53. package/dist/commands/migration-status.d.mts.map +1 -1
  54. package/dist/commands/migration-status.mjs +6 -7
  55. package/dist/commands/migration-status.mjs.map +1 -1
  56. package/dist/commands/ref.d.mts +1 -1
  57. package/dist/commands/ref.d.mts.map +1 -1
  58. package/dist/commands/ref.mjs +34 -9
  59. package/dist/commands/ref.mjs.map +1 -1
  60. package/dist/config-loader-B6sJjXTv.mjs.map +1 -1
  61. package/dist/config-loader.d.mts.map +1 -1
  62. package/dist/{contract-emit-bcrpT-wD.mjs → contract-emit-DYBHfZqL.mjs} +8 -7
  63. package/dist/contract-emit-DYBHfZqL.mjs.map +1 -0
  64. package/dist/{contract-emit-uwT-Mj8-.mjs → contract-emit-aFcOi3aw.mjs} +20 -14
  65. package/dist/contract-emit-aFcOi3aw.mjs.map +1 -0
  66. package/dist/{contract-enrichment-Dani0mMW.mjs → contract-enrichment-XmUPhmsS.mjs} +4 -25
  67. package/dist/contract-enrichment-XmUPhmsS.mjs.map +1 -0
  68. package/dist/{contract-infer-pKkiCt7C.mjs → contract-infer-BpJeg-Eu.mjs} +3 -4
  69. package/dist/{contract-infer-pKkiCt7C.mjs.map → contract-infer-BpJeg-Eu.mjs.map} +1 -1
  70. package/dist/{contract-space-aggregate-loader-BmNQwlws.mjs → contract-space-aggregate-loader-EVU3n9YE.mjs} +2 -2
  71. package/dist/{contract-space-aggregate-loader-BmNQwlws.mjs.map → contract-space-aggregate-loader-EVU3n9YE.mjs.map} +1 -1
  72. package/dist/{db-verify-AoIUriL4.mjs → db-verify-CxtdGiL3.mjs} +6 -7
  73. package/dist/{db-verify-AoIUriL4.mjs.map → db-verify-CxtdGiL3.mjs.map} +1 -1
  74. package/dist/exports/control-api.d.mts +1 -1
  75. package/dist/exports/control-api.d.mts.map +1 -1
  76. package/dist/exports/control-api.mjs +3 -3
  77. package/dist/exports/index.d.mts.map +1 -1
  78. package/dist/exports/index.mjs +1 -1
  79. package/dist/exports/index.mjs.map +1 -1
  80. package/dist/exports/init-output.d.mts.map +1 -1
  81. package/dist/exports/init-output.mjs +1 -1
  82. package/dist/{framework-components-65gOHkHB.mjs → framework-components-DTcjouhS.mjs} +2 -2
  83. package/dist/{framework-components-65gOHkHB.mjs.map → framework-components-DTcjouhS.mjs.map} +1 -1
  84. package/dist/global-flags-CdE7M0d9.d.mts.map +1 -1
  85. package/dist/graph-render-DJVv0_uf.mjs.map +1 -1
  86. package/dist/{init-YX6lCJpG.mjs → init-eGkSo7hi.mjs} +5 -5
  87. package/dist/{init-YX6lCJpG.mjs.map → init-eGkSo7hi.mjs.map} +1 -1
  88. package/dist/{inspect-live-schema-LeWvkZVz.mjs → inspect-live-schema-B1GCyjAJ.mjs} +5 -5
  89. package/dist/{inspect-live-schema-LeWvkZVz.mjs.map → inspect-live-schema-B1GCyjAJ.mjs.map} +1 -1
  90. package/dist/migration-cli.d.mts.map +1 -1
  91. package/dist/migration-cli.mjs.map +1 -1
  92. package/dist/{migration-command-scaffold-BtkunvFQ.mjs → migration-command-scaffold-CNdZl60X.mjs} +5 -5
  93. package/dist/{migration-command-scaffold-BtkunvFQ.mjs.map → migration-command-scaffold-CNdZl60X.mjs.map} +1 -1
  94. package/dist/migration-list-CnYiHrNV.mjs +288 -0
  95. package/dist/migration-list-CnYiHrNV.mjs.map +1 -0
  96. package/dist/{migration-plan-C2jeH1J5.mjs → migration-plan-BnmP_yNz.mjs} +346 -88
  97. package/dist/migration-plan-BnmP_yNz.mjs.map +1 -0
  98. package/dist/{migrations-CwZMa1Ck.mjs → migrations-C7YTBnLy.mjs} +11 -2
  99. package/dist/migrations-C7YTBnLy.mjs.map +1 -0
  100. package/dist/{output-BlsrGMEF.mjs → output-CUIdfYo5.mjs} +1 -1
  101. package/dist/{output-BlsrGMEF.mjs.map → output-CUIdfYo5.mjs.map} +1 -1
  102. package/dist/{progress-adapter-DFfvZcYL.mjs → progress-adapter-xASh41wr.mjs} +1 -1
  103. package/dist/{progress-adapter-DFfvZcYL.mjs.map → progress-adapter-xASh41wr.mjs.map} +1 -1
  104. package/dist/ref-advancement-CHJ_8HxQ.mjs +50 -0
  105. package/dist/ref-advancement-CHJ_8HxQ.mjs.map +1 -0
  106. package/dist/{types--CqjMdk0.d.mts → types-UWB2-rrw.d.mts} +12 -4
  107. package/dist/types-UWB2-rrw.d.mts.map +1 -0
  108. package/dist/{verify-Bom75OYI.mjs → verify-DX4RQwq4.mjs} +2 -2
  109. package/dist/{verify-Bom75OYI.mjs.map → verify-DX4RQwq4.mjs.map} +1 -1
  110. package/package.json +12 -12
  111. package/dist/cli-errors-Czmx92Zy.d.mts +0 -3
  112. package/dist/cli-errors-Djtz98Vm.mjs +0 -71
  113. package/dist/cli-errors-Djtz98Vm.mjs.map +0 -1
  114. package/dist/command-helpers-DtavI0wJ.mjs.map +0 -1
  115. package/dist/commands/migration-list.mjs.map +0 -1
  116. package/dist/contract-emit-bcrpT-wD.mjs.map +0 -1
  117. package/dist/contract-emit-uwT-Mj8-.mjs.map +0 -1
  118. package/dist/contract-enrichment-Dani0mMW.mjs.map +0 -1
  119. package/dist/migration-plan-C2jeH1J5.mjs.map +0 -1
  120. package/dist/migrations-CwZMa1Ck.mjs.map +0 -1
  121. package/dist/terminal-ui-BiB_8KNo.mjs +0 -379
  122. package/dist/terminal-ui-BiB_8KNo.mjs.map +0 -1
  123. package/dist/types--CqjMdk0.d.mts.map +0 -1
@@ -1,19 +1,22 @@
1
1
  import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
2
- import { _ as errorTargetMigrationNotSupported, a as errorContractValidationFailed, b as mapMigrationToolsError, c as errorDriverRequired, g as errorRuntime, l as errorFileNotFound, o as errorDatabaseConnectionRequired, t as CliStructuredError, x as mapRefResolutionError, y as errorUnexpected } from "../cli-errors-Djtz98Vm.mjs";
3
- import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
4
- import { S as formatStyledHeader, a as loadMigrationPackages, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, m as targetSupportsMigrations, n as collectDeclaredInvariants, o as maskConnectionUrl, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-DtavI0wJ.mjs";
5
- import { t as createControlClient } from "../client-oXO2WCPD.mjs";
6
- import { t as formatMigrationApplyCommandOutput } from "../migrations-CwZMa1Ck.mjs";
2
+ import { A as mapRefResolutionError, C as errorRuntime, E as errorTargetMigrationNotSupported, O as errorUnexpected, _ as errorPathUnreachable, a as errorContractValidationFailed, c as errorDriverRequired, k as mapMigrationToolsError, l as errorFileNotFound, o as errorDatabaseConnectionRequired, p as errorMarkerMismatch, t as CliStructuredError } from "../cli-errors-DFF1LlfU.mjs";
3
+ import { D as formatStyledHeader, a as loadMigrationPackages, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, m as targetSupportsMigrations, n as collectDeclaredInvariants, o as maskConnectionUrl, t as addGlobalOptions, v as parseGlobalFlagsOrExit, x as handleResult, y as createTerminalUI } from "../command-helpers-BnqwTptC.mjs";
4
+ import { t as createControlClient } from "../client-a5NJce0-.mjs";
5
+ import { t as formatMigrationApplyCommandOutput } from "../migrations-C7YTBnLy.mjs";
6
+ import { i as readContractIR, r as executeRefAdvancement } from "../ref-advancement-CHJ_8HxQ.mjs";
7
7
  import { Command } from "commander";
8
8
  import { ifDefined } from "@prisma-next/utils/defined";
9
9
  import { notOk, ok } from "@prisma-next/utils/result";
10
+ import { join } from "pathe";
10
11
  import { readFile } from "node:fs/promises";
11
12
  import { createControlStack } from "@prisma-next/framework-components/control";
13
+ import { findLatestMigration, isGraphNode } from "@prisma-next/migration-tools/migration-graph";
12
14
  import { MigrationToolsError, errorUnknownInvariant } from "@prisma-next/migration-tools/errors";
13
- import { parseContractRef } from "@prisma-next/migration-tools/ref-resolution";
14
15
  import { readRefs } from "@prisma-next/migration-tools/refs";
16
+ import { parseContractRef } from "@prisma-next/migration-tools/ref-resolution";
15
17
  //#region src/commands/migrate.ts
16
18
  function mapApplyFailure(failure) {
19
+ if (failure.code === "MIGRATION_PATH_NOT_FOUND") return errorPathUnreachable(failure);
17
20
  return errorRuntime(failure.summary, {
18
21
  why: failure.why ?? "Migration runner failed",
19
22
  fix: "Fix the issue and re-run `prisma-next migrate --to <contract>` — previously applied migrations are preserved.",
@@ -111,8 +114,10 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
111
114
  });
112
115
  try {
113
116
  await client.connect(dbConnection);
117
+ const appMarker = (await client.readAllMarkers()).get("app") ?? null;
118
+ const { graph } = appPackages;
119
+ if (appMarker !== null && !isGraphNode(appMarker.storageHash, graph)) return notOk(errorMarkerMismatch(appMarker.storageHash, [...graph.nodes].sort(), findLatestMigration(graph)?.to ?? null));
114
120
  if (refEntry && refEntry.invariants.length > 0) {
115
- const appMarker = (await client.readAllMarkers()).get("app") ?? null;
116
121
  const declared = collectDeclaredInvariants(appPackages.graph);
117
122
  const known = new Set(declared);
118
123
  for (const id of appMarker?.invariants ?? []) known.add(id);
@@ -134,6 +139,35 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
134
139
  });
135
140
  if (!applyResult.ok) return notOk(mapApplyFailure(applyResult.failure));
136
141
  const { value } = applyResult;
142
+ let advancedRef = null;
143
+ if (options.advanceRef !== void 0) {
144
+ let contractJsonPathForSnapshot = contractPathAbsolute;
145
+ let contractJsonForSnapshot = JSON.parse(contractContent);
146
+ if (toArg && refEntry) {
147
+ const matchingBundle = appPackages.bundles.find((p) => p.metadata.to === refEntry.hash);
148
+ if (matchingBundle) {
149
+ const endContractPath = join(matchingBundle.dirPath, "end-contract.json");
150
+ contractJsonPathForSnapshot = endContractPath;
151
+ try {
152
+ const raw = await readFile(endContractPath, "utf-8");
153
+ contractJsonForSnapshot = JSON.parse(raw);
154
+ } catch (error) {
155
+ if (error instanceof Error && error.code === "ENOENT") return notOk(errorFileNotFound(endContractPath, {
156
+ why: `Bundle end-contract not found at ${endContractPath}`,
157
+ fix: "Re-emit the migration bundle or pick a different --to target."
158
+ }));
159
+ throw error;
160
+ }
161
+ }
162
+ }
163
+ try {
164
+ const contractIR = await readContractIR(contractJsonForSnapshot, contractJsonPathForSnapshot);
165
+ advancedRef = await executeRefAdvancement(refsDir, options.advanceRef, value.markerHash, contractIR);
166
+ } catch (error) {
167
+ if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
168
+ throw error;
169
+ }
170
+ }
137
171
  return ok({
138
172
  ok: true,
139
173
  migrationsApplied: value.migrationsApplied,
@@ -143,7 +177,8 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
143
177
  summary: value.summary,
144
178
  perSpace: value.perSpace,
145
179
  ...ifDefined("pathDecision", value.pathDecision),
146
- timings: { total: Date.now() - startTime }
180
+ timings: { total: Date.now() - startTime },
181
+ advancedRef
147
182
  });
148
183
  } catch (error) {
149
184
  if (CliStructuredError.is(error)) return notOk(error);
@@ -161,7 +196,7 @@ function createMigrateCommand() {
161
196
  "prisma-next migrate --to production --db $DATABASE_URL",
162
197
  "prisma-next migrate --to sha256:abc123 --db $DATABASE_URL"
163
198
  ]);
164
- addGlobalOptions(command).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--to <contract>", "Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)").action(async (options) => {
199
+ addGlobalOptions(command).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--to <contract>", "Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)").option("--advance-ref <name>", "Advance the named ref to the post-apply marker after success").action(async (options) => {
165
200
  const flags = parseGlobalFlagsOrExit(options);
166
201
  const startTime = Date.now();
167
202
  const ui = createTerminalUI(flags);
@@ -1 +1 @@
1
- {"version":3,"file":"migrate.mjs","names":[],"sources":["../../src/commands/migrate.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { errorUnknownInvariant, MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\n\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type {\n AggregatePerSpaceExecutionEntry,\n MigrationApplyFailure,\n MigrationApplyPathDecision,\n} from '../control-api/types';\nimport {\n CliStructuredError,\n type CliStructuredError as CliStructuredErrorType,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorRuntime,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n collectDeclaredInvariants,\n loadMigrationPackages,\n maskConnectionUrl,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n targetSupportsMigrations,\n} from '../utils/command-helpers';\nimport { formatMigrationApplyCommandOutput } from '../utils/formatters/migrations';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrateCommandOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly to?: string;\n}\n\nexport interface MigrateResult {\n readonly ok: boolean;\n readonly migrationsApplied: number;\n readonly migrationsTotal: number;\n readonly markerHash: string;\n readonly applied: readonly {\n readonly spaceId: string;\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly operationsExecuted: number;\n }[];\n readonly summary: string;\n readonly perSpace: readonly AggregatePerSpaceExecutionEntry[];\n readonly pathDecision?: MigrationApplyPathDecision;\n readonly timings: {\n readonly total: number;\n };\n}\n\nfunction mapApplyFailure(failure: MigrationApplyFailure): CliStructuredErrorType {\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Fix the issue and re-run `prisma-next migrate --to <contract>` — previously applied migrations are preserved.',\n meta: failure.meta ?? {},\n });\n}\n\nasync function executeMigrateCommand(\n options: MigrateCommandOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrateResult, CliStructuredErrorType>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative, refsDir } =\n resolveMigrationPaths(options.config, config);\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for migrate (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migrate',\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: 'Config.driver is required for migrate',\n }),\n );\n }\n\n if (!targetSupportsMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n let refEntry: RefEntry | undefined;\n const toArg = options.to;\n\n if (toArg) {\n try {\n const refs = await readRefs(refsDir);\n const { graph } = await loadMigrationPackages(appMigrationsDir);\n const refResult = parseContractRef(toArg, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n if (refResult.value.provenance.kind === 'ref') {\n const resolved = refs[refResult.value.provenance.refName];\n if (resolved) refEntry = resolved;\n } else {\n refEntry = { hash: refResult.value.hash, invariants: [] };\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n }\n\n // Construct the family instance up-front so the on-disk contract read\n // crosses the serializer seam (`familyInstance.deserializeContract`) at\n // the read site. The downstream `client.migrationApply({ contract })`\n // re-validates internally (no harm — validation is idempotent), but\n // closing the gap at the read site is what makes the cast-pattern\n // lint enforceable and matches the other CLI commands. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n const contractPathAbsolute = resolveContractPath(config);\n let contractRaw: Contract;\n let contractContent: string;\n try {\n contractContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: 'Run `prisma-next contract emit` to generate a valid contract.json, then retry.',\n }),\n );\n }\n return notOk(\n errorContractValidationFailed(\n `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n try {\n contractRaw = familyInstance.deserializeContract(JSON.parse(contractContent) as unknown);\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract at ${contractPathAbsolute} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\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 (typeof dbConnection === 'string') {\n details.push({\n label: 'database',\n value: maskConnectionUrl(dbConnection),\n });\n }\n if (toArg) {\n details.push({ label: 'to', value: toArg });\n }\n const header = formatStyledHeader({\n command: 'migrate',\n description: 'Apply planned migrations to advance the database',\n url: 'https://pris.ly/migrate',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n let appPackages: Awaited<ReturnType<typeof loadMigrationPackages>>;\n try {\n appPackages = await loadMigrationPackages(appMigrationsDir);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n try {\n await client.connect(dbConnection);\n\n if (refEntry && refEntry.invariants.length > 0) {\n const allMarkers = await client.readAllMarkers();\n const appMarker = allMarkers.get('app') ?? null;\n const declared = collectDeclaredInvariants(appPackages.graph);\n const known = new Set<string>(declared);\n for (const id of appMarker?.invariants ?? []) known.add(id);\n const unknown = refEntry.invariants.filter((id) => !known.has(id));\n if (unknown.length > 0) {\n return notOk(\n mapMigrationToolsError(\n errorUnknownInvariant({\n ...ifDefined('refName', toArg),\n unknown,\n declared: [...declared].sort(),\n }),\n ),\n );\n }\n }\n\n if (!flags.quiet && !flags.json) {\n ui.step('Loading contract spaces…');\n }\n\n const applyResult = await client.migrationApply({\n contract: contractRaw,\n migrationsDir,\n appMigrationPackages: appPackages.bundles,\n ...ifDefined('refHash', refEntry?.hash),\n ...(refEntry?.invariants ? { refInvariants: refEntry.invariants } : {}),\n ...(refEntry !== undefined ? ifDefined('refName', toArg) : {}),\n });\n\n if (!applyResult.ok) {\n return notOk(mapApplyFailure(applyResult.failure));\n }\n\n const { value } = applyResult;\n\n return ok({\n ok: true,\n migrationsApplied: value.migrationsApplied,\n migrationsTotal: value.perSpace.length,\n markerHash: value.markerHash,\n applied: value.applied,\n summary: value.summary,\n perSpace: value.perSpace,\n ...ifDefined('pathDecision', value.pathDecision),\n timings: { total: Date.now() - startTime },\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Unexpected error during migrate: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrateCommand(): Command {\n const command = new Command('migrate');\n setCommandDescriptions(\n command,\n 'Apply planned migrations to advance the database',\n 'Walks every contract space (app + extensions) and applies pending\\n' +\n 'on-disk migrations in canonical order (extensions alphabetically,\\n' +\n 'then app). Graph-walks the on-disk migration graph for every space.\\n' +\n 'Use --to to target a specific contract (hash, ref name, migration dir).',\n );\n setCommandExamples(command, [\n 'prisma-next migrate --db $DATABASE_URL',\n 'prisma-next migrate --to production --db $DATABASE_URL',\n 'prisma-next migrate --to sha256:abc123 --db $DATABASE_URL',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option(\n '--to <contract>',\n 'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .action(async (options: MigrateCommandOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const startTime = Date.now();\n\n const ui = createTerminalUI(flags);\n\n const result = await executeMigrateCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (migrateResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(migrateResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationApplyCommandOutput(migrateResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"migrate.mjs","names":[],"sources":["../../src/commands/migrate.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { errorUnknownInvariant, MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findLatestMigration, isGraphNode } from '@prisma-next/migration-tools/migration-graph';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type {\n AggregatePerSpaceExecutionEntry,\n MigrationApplyFailure,\n MigrationApplyPathDecision,\n} from '../control-api/types';\nimport {\n CliStructuredError,\n type CliStructuredError as CliStructuredErrorType,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorMarkerMismatch,\n errorPathUnreachable,\n errorRuntime,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n collectDeclaredInvariants,\n loadMigrationPackages,\n maskConnectionUrl,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n targetSupportsMigrations,\n} from '../utils/command-helpers';\nimport { formatMigrationApplyCommandOutput } from '../utils/formatters/migrations';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { executeRefAdvancement, readContractIR } from '../utils/ref-advancement';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrateCommandOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly to?: string;\n readonly advanceRef?: string;\n}\n\nexport interface MigrateResult {\n readonly ok: boolean;\n readonly migrationsApplied: number;\n readonly migrationsTotal: number;\n readonly markerHash: string;\n readonly applied: readonly {\n readonly spaceId: string;\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly operationsExecuted: number;\n }[];\n readonly summary: string;\n readonly perSpace: readonly AggregatePerSpaceExecutionEntry[];\n readonly pathDecision?: MigrationApplyPathDecision;\n readonly timings: {\n readonly total: number;\n };\n readonly advancedRef?: { readonly name: string; readonly hash: string } | null;\n}\n\nfunction mapApplyFailure(failure: MigrationApplyFailure): CliStructuredErrorType {\n if (failure.code === 'MIGRATION_PATH_NOT_FOUND') {\n return errorPathUnreachable(failure);\n }\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Fix the issue and re-run `prisma-next migrate --to <contract>` — previously applied migrations are preserved.',\n meta: failure.meta ?? {},\n });\n}\n\nasync function executeMigrateCommand(\n options: MigrateCommandOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrateResult, CliStructuredErrorType>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative, refsDir } =\n resolveMigrationPaths(options.config, config);\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for migrate (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migrate',\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: 'Config.driver is required for migrate',\n }),\n );\n }\n\n if (!targetSupportsMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n let refEntry: RefEntry | undefined;\n const toArg = options.to;\n\n if (toArg) {\n try {\n const refs = await readRefs(refsDir);\n const { graph } = await loadMigrationPackages(appMigrationsDir);\n const refResult = parseContractRef(toArg, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n if (refResult.value.provenance.kind === 'ref') {\n const resolved = refs[refResult.value.provenance.refName];\n if (resolved) refEntry = resolved;\n } else {\n refEntry = { hash: refResult.value.hash, invariants: [] };\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n }\n\n // Construct the family instance up-front so the on-disk contract read\n // crosses the serializer seam (`familyInstance.deserializeContract`) at\n // the read site. The downstream `client.migrationApply({ contract })`\n // re-validates internally (no harm — validation is idempotent), but\n // closing the gap at the read site is what makes the cast-pattern\n // lint enforceable and matches the other CLI commands. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n const contractPathAbsolute = resolveContractPath(config);\n let contractRaw: Contract;\n let contractContent: string;\n try {\n contractContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: 'Run `prisma-next contract emit` to generate a valid contract.json, then retry.',\n }),\n );\n }\n return notOk(\n errorContractValidationFailed(\n `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n try {\n contractRaw = familyInstance.deserializeContract(JSON.parse(contractContent) as unknown);\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract at ${contractPathAbsolute} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\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 (typeof dbConnection === 'string') {\n details.push({\n label: 'database',\n value: maskConnectionUrl(dbConnection),\n });\n }\n if (toArg) {\n details.push({ label: 'to', value: toArg });\n }\n const header = formatStyledHeader({\n command: 'migrate',\n description: 'Apply planned migrations to advance the database',\n url: 'https://pris.ly/migrate',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n let appPackages: Awaited<ReturnType<typeof loadMigrationPackages>>;\n try {\n appPackages = await loadMigrationPackages(appMigrationsDir);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n try {\n await client.connect(dbConnection);\n\n const allMarkers = await client.readAllMarkers();\n const appMarker = allMarkers.get('app') ?? null;\n const { graph } = appPackages;\n\n if (appMarker !== null && !isGraphNode(appMarker.storageHash, graph)) {\n return notOk(\n errorMarkerMismatch(\n appMarker.storageHash,\n [...graph.nodes].sort(),\n findLatestMigration(graph)?.to ?? null,\n ),\n );\n }\n\n if (refEntry && refEntry.invariants.length > 0) {\n const declared = collectDeclaredInvariants(appPackages.graph);\n const known = new Set<string>(declared);\n for (const id of appMarker?.invariants ?? []) known.add(id);\n const unknown = refEntry.invariants.filter((id) => !known.has(id));\n if (unknown.length > 0) {\n return notOk(\n mapMigrationToolsError(\n errorUnknownInvariant({\n ...ifDefined('refName', toArg),\n unknown,\n declared: [...declared].sort(),\n }),\n ),\n );\n }\n }\n\n if (!flags.quiet && !flags.json) {\n ui.step('Loading contract spaces…');\n }\n\n const applyResult = await client.migrationApply({\n contract: contractRaw,\n migrationsDir,\n appMigrationPackages: appPackages.bundles,\n ...ifDefined('refHash', refEntry?.hash),\n ...(refEntry?.invariants ? { refInvariants: refEntry.invariants } : {}),\n ...(refEntry !== undefined ? ifDefined('refName', toArg) : {}),\n });\n\n if (!applyResult.ok) {\n return notOk(mapApplyFailure(applyResult.failure));\n }\n\n const { value } = applyResult;\n\n let advancedRef: { name: string; hash: string } | null = null;\n if (options.advanceRef !== undefined) {\n let contractJsonPathForSnapshot = contractPathAbsolute;\n let contractJsonForSnapshot: Record<string, unknown> = JSON.parse(contractContent) as Record<\n string,\n unknown\n >;\n if (toArg && refEntry) {\n const matchingBundle = appPackages.bundles.find((p) => p.metadata.to === refEntry.hash);\n if (matchingBundle) {\n const endContractPath = join(matchingBundle.dirPath, 'end-contract.json');\n contractJsonPathForSnapshot = endContractPath;\n try {\n const raw = await readFile(endContractPath, 'utf-8');\n contractJsonForSnapshot = JSON.parse(raw) as Record<string, unknown>;\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(endContractPath, {\n why: `Bundle end-contract not found at ${endContractPath}`,\n fix: 'Re-emit the migration bundle or pick a different --to target.',\n }),\n );\n }\n throw error;\n }\n }\n }\n try {\n const contractIR = await readContractIR(\n contractJsonForSnapshot,\n contractJsonPathForSnapshot,\n );\n advancedRef = await executeRefAdvancement(\n refsDir,\n options.advanceRef,\n value.markerHash,\n contractIR,\n );\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n }\n\n return ok({\n ok: true,\n migrationsApplied: value.migrationsApplied,\n migrationsTotal: value.perSpace.length,\n markerHash: value.markerHash,\n applied: value.applied,\n summary: value.summary,\n perSpace: value.perSpace,\n ...ifDefined('pathDecision', value.pathDecision),\n timings: { total: Date.now() - startTime },\n advancedRef,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Unexpected error during migrate: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrateCommand(): Command {\n const command = new Command('migrate');\n setCommandDescriptions(\n command,\n 'Apply planned migrations to advance the database',\n 'Walks every contract space (app + extensions) and applies pending\\n' +\n 'on-disk migrations in canonical order (extensions alphabetically,\\n' +\n 'then app). Graph-walks the on-disk migration graph for every space.\\n' +\n 'Use --to to target a specific contract (hash, ref name, migration dir).',\n );\n setCommandExamples(command, [\n 'prisma-next migrate --db $DATABASE_URL',\n 'prisma-next migrate --to production --db $DATABASE_URL',\n 'prisma-next migrate --to sha256:abc123 --db $DATABASE_URL',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option(\n '--to <contract>',\n 'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option('--advance-ref <name>', 'Advance the named ref to the post-apply marker after success')\n .action(async (options: MigrateCommandOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const startTime = Date.now();\n\n const ui = createTerminalUI(flags);\n\n const result = await executeMigrateCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (migrateResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(migrateResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationApplyCommandOutput(migrateResult, flags));\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-check.d.mts","names":[],"sources":["../../src/commands/migration-check.ts"],"mappings":";;;UA2BiB,YAAA;EAAA,SACN,MAAA;EAAA,SACA,KAAA;EAAA,SACA,GAAA;EAAA,SACA,GAAA;AAAA;AAAA,UAGM,oBAAA;EAAA,SACN,EAAA;EAAA,SACA,QAAA,WAAmB,YAAA;EAAA,SACnB,OAAA;AAAA;AAAA,iBAmRK,2BAAA,CAAA,GAA+B,OAAA"}
1
+ {"version":3,"file":"migration-check.d.mts","names":[],"sources":["../../src/commands/migration-check.ts"],"mappings":";;;UA2BiB,YAAA;EAAA,SACN,MAAA;EAAA,SACA,KAAA;EAAA,SACA,GAAA;EAAA,SACA,GAAA;AAAA;AAAA,UAGM,oBAAA;EAAA,SACN,EAAA;EAAA,SACA,QAAA,WAAmB,YAAY;EAAA,SAC/B,OAAA;AAAA;AAAA,iBAmRK,2BAAA,CAAA,GAA+B,OAAO"}
@@ -1,12 +1,11 @@
1
1
  import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
2
- import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
3
- import { S as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit } from "../command-helpers-DtavI0wJ.mjs";
2
+ import { D as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as createTerminalUI } from "../command-helpers-BnqwTptC.mjs";
4
3
  import { Command } from "commander";
5
4
  import { join, relative } from "pathe";
6
5
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
7
6
  import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
8
- import { parseMigrationRef } from "@prisma-next/migration-tools/ref-resolution";
9
7
  import { readRefs } from "@prisma-next/migration-tools/refs";
8
+ import { parseMigrationRef } from "@prisma-next/migration-tools/ref-resolution";
10
9
  import { verifyMigrationHash } from "@prisma-next/migration-tools/hash";
11
10
  //#region src/commands/migration-check.ts
12
11
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"migration-check.mjs","names":[],"sources":["../../src/commands/migration-check.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { verifyMigrationHash } from '@prisma-next/migration-tools/hash';\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 loadMigrationPackages,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\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 interface CheckFailure {\n readonly pnCode: string;\n readonly where: string;\n readonly why: string;\n readonly fix: string;\n}\n\nexport interface MigrationCheckResult {\n readonly ok: boolean;\n readonly failures: readonly CheckFailure[];\n readonly summary: string;\n}\n\n/**\n * Canonical user-facing locator for a check failure: the cwd-relative path\n * to the migration package directory. Surfacing the same shape across every\n * PN code means `--json` consumers can branch uniformly on `where`.\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\n/**\n * Within-migration snapshot-consistency check (PN-MIG-CHECK-005).\n *\n * Compares the migration's stored `metadata.to` against the `storageHash`\n * recorded in its on-disk `end-contract.json` snapshot. The two values are\n * independent on-disk records of the same fact (the migration's destination\n * contract); drift between them indicates the package is internally\n * corrupt. Cross-migration consistency (one migration's end-contract.json\n * agreeing with the next migration's start-contract.json) is a separate\n * check that requires shadow execution and is deferred to\n * `migration preflight`.\n *\n * Shared between the graph-wide and per-migration code paths so both report\n * the same failure for the same on-disk state.\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 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, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\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 let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n const loaded = await loadMigrationPackages(appMigrationsDir);\n bundles = loaded.bundles;\n graph = loaded.graph;\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n const pnCode =\n error.code === 'MIGRATION.HASH_MISMATCH' ? 'PN-MIG-CHECK-001' : 'PN-MIG-CHECK-002';\n // Normalise to a cwd-relative path. `error.details.dir` is absolute\n // (the migration-tools layer doesn't know the caller's cwd); the\n // `filePath` fallback is also absolute. Surfacing the relative form\n // matches the rest of the command's `where` shape and keeps `--json`\n // consumers from having to special-case the bootstrap-failure path.\n const rawWhere =\n (error.details?.['dir'] as string) ?? (error.details?.['filePath'] as string) ?? null;\n const where = rawWhere ? relative(process.cwd(), rawWhere) : 'unknown';\n failures.push({\n pnCode,\n where,\n why: error.why,\n fix: error.fix,\n });\n return {\n result: { ok: false, failures, summary: `${failures.length} integrity failure(s)` },\n exitCode: INTEGRITY_FAILED,\n };\n }\n throw error;\n }\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 // PN-MIG-CHECK-005 must fire per-migration as well as graph-wide; both\n // call sites delegate to the shared helper so the same on-disk drift\n // produces the same failure regardless of how the user invoked check.\n const snapshotFailure = checkSnapshotConsistency(matchedPkg);\n if (snapshotFailure) failures.push(snapshotFailure);\n } else {\n for (const pkg of bundles) {\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(pkg.dirPath, pkg.dirName, f);\n if (fail) failures.push(fail);\n }\n\n const verification = verifyMigrationHash(pkg);\n if (!verification.ok) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(pkg.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\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\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
+ {"version":3,"file":"migration-check.mjs","names":[],"sources":["../../src/commands/migration-check.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { verifyMigrationHash } from '@prisma-next/migration-tools/hash';\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 loadMigrationPackages,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\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 interface CheckFailure {\n readonly pnCode: string;\n readonly where: string;\n readonly why: string;\n readonly fix: string;\n}\n\nexport interface MigrationCheckResult {\n readonly ok: boolean;\n readonly failures: readonly CheckFailure[];\n readonly summary: string;\n}\n\n/**\n * Canonical user-facing locator for a check failure: the cwd-relative path\n * to the migration package directory. Surfacing the same shape across every\n * PN code means `--json` consumers can branch uniformly on `where`.\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\n/**\n * Within-migration snapshot-consistency check (PN-MIG-CHECK-005).\n *\n * Compares the migration's stored `metadata.to` against the `storageHash`\n * recorded in its on-disk `end-contract.json` snapshot. The two values are\n * independent on-disk records of the same fact (the migration's destination\n * contract); drift between them indicates the package is internally\n * corrupt. Cross-migration consistency (one migration's end-contract.json\n * agreeing with the next migration's start-contract.json) is a separate\n * check that requires shadow execution and is deferred to\n * `migration preflight`.\n *\n * Shared between the graph-wide and per-migration code paths so both report\n * the same failure for the same on-disk state.\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 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, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\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 let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n const loaded = await loadMigrationPackages(appMigrationsDir);\n bundles = loaded.bundles;\n graph = loaded.graph;\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n const pnCode =\n error.code === 'MIGRATION.HASH_MISMATCH' ? 'PN-MIG-CHECK-001' : 'PN-MIG-CHECK-002';\n // Normalise to a cwd-relative path. `error.details.dir` is absolute\n // (the migration-tools layer doesn't know the caller's cwd); the\n // `filePath` fallback is also absolute. Surfacing the relative form\n // matches the rest of the command's `where` shape and keeps `--json`\n // consumers from having to special-case the bootstrap-failure path.\n const rawWhere =\n (error.details?.['dir'] as string) ?? (error.details?.['filePath'] as string) ?? null;\n const where = rawWhere ? relative(process.cwd(), rawWhere) : 'unknown';\n failures.push({\n pnCode,\n where,\n why: error.why,\n fix: error.fix,\n });\n return {\n result: { ok: false, failures, summary: `${failures.length} integrity failure(s)` },\n exitCode: INTEGRITY_FAILED,\n };\n }\n throw error;\n }\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 // PN-MIG-CHECK-005 must fire per-migration as well as graph-wide; both\n // call sites delegate to the shared helper so the same on-disk drift\n // produces the same failure regardless of how the user invoked check.\n const snapshotFailure = checkSnapshotConsistency(matchedPkg);\n if (snapshotFailure) failures.push(snapshotFailure);\n } else {\n for (const pkg of bundles) {\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(pkg.dirPath, pkg.dirName, f);\n if (fail) failures.push(fail);\n }\n\n const verification = verifyMigrationHash(pkg);\n if (!verification.ok) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(pkg.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\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\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-graph.d.mts","names":[],"sources":["../../src/commands/migration-graph.ts"],"mappings":";;;;;UAmCiB,oBAAA;EAAA,SACN,EAAA;EAAA,SACA,KAAA,EAAO,cAAA;EAAA,SACP,YAAA;EAAA,SACA,IAAA,WAAe,SAAA;EAAA,SACf,OAAA;AAAA;AAAA,iBAoEK,2BAAA,CAAA,GAA+B,OAAA"}
1
+ {"version":3,"file":"migration-graph.d.mts","names":[],"sources":["../../src/commands/migration-graph.ts"],"mappings":";;;;;UAmCiB,oBAAA;EAAA,SACN,EAAA;EAAA,SACA,KAAA,EAAO,cAAA;EAAA,SACP,YAAA;EAAA,SACA,IAAA,WAAe,SAAS;EAAA,SACxB,OAAA;AAAA;AAAA,iBAoEK,2BAAA,CAAA,GAA+B,OAAO"}
@@ -1,7 +1,6 @@
1
1
  import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
2
- import { b as mapMigrationToolsError, y as errorUnexpected } from "../cli-errors-Djtz98Vm.mjs";
3
- import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
4
- import { S as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, s as readContractEnvelope, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-DtavI0wJ.mjs";
2
+ import { O as errorUnexpected, k as mapMigrationToolsError } from "../cli-errors-DFF1LlfU.mjs";
3
+ import { D as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, s as readContractEnvelope, t as addGlobalOptions, v as parseGlobalFlagsOrExit, x as handleResult, y as createTerminalUI } from "../command-helpers-BnqwTptC.mjs";
5
4
  import { i as migrationGraphToRenderInput, n as graphRenderer } from "../graph-render-DJVv0_uf.mjs";
6
5
  import { Command } from "commander";
7
6
  import { notOk, ok } from "@prisma-next/utils/result";
@@ -1 +1 @@
1
- {"version":3,"file":"migration-graph.mjs","names":[],"sources":["../../src/commands/migration-graph.ts"],"sourcesContent":["import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n readContractEnvelope,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { migrationGraphToRenderInput } from '../utils/formatters/graph-migration-mapper';\nimport { graphRenderer } from '../utils/formatters/graph-render';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { StatusRef } from '../utils/migration-types';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationGraphOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly dot?: boolean;\n}\n\nexport interface MigrationGraphResult {\n readonly ok: true;\n readonly graph: MigrationGraph;\n readonly contractHash: string | null;\n readonly refs: readonly StatusRef[];\n readonly summary: string;\n}\n\nasync function executeMigrationGraphCommand(\n options: MigrationGraphOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationGraphResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration graph',\n description: 'Show the migration graph topology',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n let graph: MigrationGraph;\n try {\n ({ graph } = await loadMigrationPackages(appMigrationsDir));\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n let contractHash: string | null = null;\n try {\n const envelope = await readContractEnvelope(config);\n contractHash = envelope.storageHash;\n } catch {\n // Contract unreadable — render graph without contract marker\n }\n\n let refs: readonly StatusRef[] = [];\n try {\n const allRefs = await readRefs(refsDir);\n refs = Object.entries(allRefs).map(([name, entry]) => ({\n name,\n hash: entry.hash,\n active: false,\n }));\n } catch {\n // Refs unreadable — render graph without ref markers\n }\n\n return ok({\n ok: true,\n graph,\n contractHash,\n refs,\n summary: `${graph.nodes.size} node(s), ${graph.migrationByHash.size} edge(s)`,\n });\n}\n\nexport function createMigrationGraphCommand(): Command {\n const command = new Command('graph');\n setCommandDescriptions(\n command,\n 'Show the migration graph topology',\n 'Renders the migration graph as an ASCII tree. Offline — does not\\n' +\n 'consult the database. Use --json for machine-readable output or\\n' +\n '--dot for Graphviz DOT format.',\n );\n setCommandExamples(command, [\n 'prisma-next migration graph',\n 'prisma-next migration graph --json',\n 'prisma-next migration graph --dot',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dot', 'Output in Graphviz DOT format')\n .action(async (options: MigrationGraphOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationGraphCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (graphResult) => {\n // Explicit format flags win over the auto-JSON default. `flags.json`\n // is auto-enabled when stdout is non-TTY (per CLI Style Guide §\n // JSON Semantics); without this ordering, `migration graph --dot |\n // dot -Tsvg` pipes JSON into the GraphViz binary, which then\n // errors. `--dot` is the more specific instruction; honour it.\n if (options.dot) {\n const lines = ['digraph migrations {'];\n for (const edge of graphResult.graph.migrationByHash.values()) {\n const from = edge.from.slice(0, 12);\n const to = edge.to.slice(0, 12);\n lines.push(` \"${from}\" -> \"${to}\" [label=\"${edge.dirName}\"];`);\n }\n lines.push('}');\n ui.output(lines.join('\\n'));\n } else if (flags.json) {\n const nodes = [...graphResult.graph.nodes];\n const edges = [...graphResult.graph.migrationByHash.values()].map((e) => ({\n dirName: e.dirName,\n from: e.from,\n to: e.to,\n migrationHash: e.migrationHash,\n }));\n ui.output(\n JSON.stringify({ ok: true, nodes, edges, summary: graphResult.summary }, null, 2),\n );\n } else if (!flags.quiet) {\n const renderInput = migrationGraphToRenderInput({\n graph: graphResult.graph,\n mode: 'offline',\n markerHash: undefined,\n contractHash: graphResult.contractHash ?? EMPTY_CONTRACT_HASH,\n refs: graphResult.refs,\n activeRefHash: undefined,\n activeRefName: undefined,\n edgeStatuses: [],\n });\n const graphOutput = graphRenderer.render(renderInput.graph, {\n ...renderInput.options,\n colorize: flags.color !== false,\n });\n ui.log(graphOutput);\n ui.log(`\\n${graphResult.summary}`);\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"migration-graph.mjs","names":[],"sources":["../../src/commands/migration-graph.ts"],"sourcesContent":["import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n readContractEnvelope,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { migrationGraphToRenderInput } from '../utils/formatters/graph-migration-mapper';\nimport { graphRenderer } from '../utils/formatters/graph-render';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { StatusRef } from '../utils/migration-types';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationGraphOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly dot?: boolean;\n}\n\nexport interface MigrationGraphResult {\n readonly ok: true;\n readonly graph: MigrationGraph;\n readonly contractHash: string | null;\n readonly refs: readonly StatusRef[];\n readonly summary: string;\n}\n\nasync function executeMigrationGraphCommand(\n options: MigrationGraphOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationGraphResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration graph',\n description: 'Show the migration graph topology',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n let graph: MigrationGraph;\n try {\n ({ graph } = await loadMigrationPackages(appMigrationsDir));\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n let contractHash: string | null = null;\n try {\n const envelope = await readContractEnvelope(config);\n contractHash = envelope.storageHash;\n } catch {\n // Contract unreadable — render graph without contract marker\n }\n\n let refs: readonly StatusRef[] = [];\n try {\n const allRefs = await readRefs(refsDir);\n refs = Object.entries(allRefs).map(([name, entry]) => ({\n name,\n hash: entry.hash,\n active: false,\n }));\n } catch {\n // Refs unreadable — render graph without ref markers\n }\n\n return ok({\n ok: true,\n graph,\n contractHash,\n refs,\n summary: `${graph.nodes.size} node(s), ${graph.migrationByHash.size} edge(s)`,\n });\n}\n\nexport function createMigrationGraphCommand(): Command {\n const command = new Command('graph');\n setCommandDescriptions(\n command,\n 'Show the migration graph topology',\n 'Renders the migration graph as an ASCII tree. Offline — does not\\n' +\n 'consult the database. Use --json for machine-readable output or\\n' +\n '--dot for Graphviz DOT format.',\n );\n setCommandExamples(command, [\n 'prisma-next migration graph',\n 'prisma-next migration graph --json',\n 'prisma-next migration graph --dot',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dot', 'Output in Graphviz DOT format')\n .action(async (options: MigrationGraphOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationGraphCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (graphResult) => {\n // Explicit format flags win over the auto-JSON default. `flags.json`\n // is auto-enabled when stdout is non-TTY (per CLI Style Guide §\n // JSON Semantics); without this ordering, `migration graph --dot |\n // dot -Tsvg` pipes JSON into the GraphViz binary, which then\n // errors. `--dot` is the more specific instruction; honour it.\n if (options.dot) {\n const lines = ['digraph migrations {'];\n for (const edge of graphResult.graph.migrationByHash.values()) {\n const from = edge.from.slice(0, 12);\n const to = edge.to.slice(0, 12);\n lines.push(` \"${from}\" -> \"${to}\" [label=\"${edge.dirName}\"];`);\n }\n lines.push('}');\n ui.output(lines.join('\\n'));\n } else if (flags.json) {\n const nodes = [...graphResult.graph.nodes];\n const edges = [...graphResult.graph.migrationByHash.values()].map((e) => ({\n dirName: e.dirName,\n from: e.from,\n to: e.to,\n migrationHash: e.migrationHash,\n }));\n ui.output(\n JSON.stringify({ ok: true, nodes, edges, summary: graphResult.summary }, null, 2),\n );\n } else if (!flags.quiet) {\n const renderInput = migrationGraphToRenderInput({\n graph: graphResult.graph,\n mode: 'offline',\n markerHash: undefined,\n contractHash: graphResult.contractHash ?? EMPTY_CONTRACT_HASH,\n refs: graphResult.refs,\n activeRefHash: undefined,\n activeRefName: undefined,\n edgeStatuses: [],\n });\n const graphOutput = graphRenderer.render(renderInput.graph, {\n ...renderInput.options,\n colorize: flags.color !== false,\n });\n ui.log(graphOutput);\n ui.log(`\\n${graphResult.summary}`);\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
@@ -1,20 +1,64 @@
1
+ import { N as CliStructuredError } from "../types-UWB2-rrw.mjs";
1
2
  import { Command } from "commander";
3
+ import { Result } from "@prisma-next/utils/result";
4
+ import { MigrationListResult } from "@prisma-next/migration-tools/migration-list-types";
2
5
 
3
6
  //#region src/commands/migration-list.d.ts
4
- interface MigrationListEntry {
5
- readonly dirName: string;
6
- readonly from: string;
7
- readonly to: string;
8
- readonly migrationHash: string;
9
- readonly operationCount: number;
10
- readonly createdAt: string;
11
- }
12
- interface MigrationListResult {
13
- readonly ok: true;
14
- readonly migrations: readonly MigrationListEntry[];
15
- readonly summary: string;
7
+ /**
8
+ * Inputs for {@link runMigrationList} — the pure-ish data-and-policy core
9
+ * of `migration list` that tests exercise directly.
10
+ *
11
+ * The core depends only on the filesystem rooted at `migrationsDir`. It
12
+ * does NOT call `loadConfig`, parse CLI flags, render a styled header,
13
+ * or write to any stream. Output rendering is the caller's concern (the
14
+ * CLI shell renders via {@link renderMigrationList}; JSON callers
15
+ * serialize the {@link MigrationListResult} directly).
16
+ */
17
+ interface RunMigrationListInputs {
18
+ /** Absolute path to the project's `migrations/` directory. */
19
+ readonly migrationsDir: string;
20
+ /**
21
+ * Optional contract-space id to narrow the result to a single space.
22
+ * Same validation rules as {@link isValidSpaceId}. When absent, every
23
+ * on-disk space contributes.
24
+ */
25
+ readonly spaceFilter?: string;
16
26
  }
27
+ /**
28
+ * The unit-testable core of `migration list`. Given an absolute
29
+ * `migrationsDir` and an optional `spaceFilter`, enumerates every
30
+ * on-disk migration (via {@link enumerateMigrationSpaces}), narrows to
31
+ * the requested space if any, and assembles a {@link MigrationListResult}
32
+ * ready for the renderer or JSON serializer.
33
+ *
34
+ * The enumerator is the single source of truth for "what is a contract
35
+ * space": existence, the `--space` candidate-suggestion list, and
36
+ * scoping are all derived from one {@link enumerateMigrationSpaces}
37
+ * traversal. This means the reserved-name exclusion the enumerator
38
+ * applies (e.g. the per-space `refs/` subdirectory) is honoured here for
39
+ * free — a `--space refs` request resolves to `SPACE_NOT_FOUND`, not a
40
+ * synthesized empty-state.
41
+ *
42
+ * Distinct empty-state paths:
43
+ *
44
+ * - `migrations/` missing or contains no valid space directories →
45
+ * synthesizes `[{ spaceId: APP_SPACE_ID, migrations: [] }]` so the
46
+ * renderer's empty-state path can name a directory (spec § Empty-state +
47
+ * the `migrations/` missing edge case).
48
+ * - `--space <id>` on an existing-but-empty space dir → the enumerator
49
+ * surfaces `{ spaceId, migrations: [] }`; `<id>` is in the set, so it
50
+ * scopes to that entry and renders the empty-state the same way.
51
+ * - `--space <id>` on a non-existent (or reserved) space → structured
52
+ * `MIGRATION.SPACE_NOT_FOUND` error (NOT empty-state).
53
+ *
54
+ * Errors caught here:
55
+ *
56
+ * - {@link MigrationToolsError} from the enumerator → mapped through
57
+ * {@link mapMigrationToolsError} so callers see the catalogue code.
58
+ * - Anything else (filesystem etc.) → wrapped via {@link errorUnexpected}.
59
+ */
60
+ declare function runMigrationList(inputs: RunMigrationListInputs): Promise<Result<MigrationListResult, CliStructuredError>>;
17
61
  declare function createMigrationListCommand(): Command;
18
62
  //#endregion
19
- export { MigrationListEntry, MigrationListResult, createMigrationListCommand };
63
+ export { RunMigrationListInputs, createMigrationListCommand, runMigrationList };
20
64
  //# sourceMappingURL=migration-list.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"migration-list.d.mts","names":[],"sources":["../../src/commands/migration-list.ts"],"mappings":";;;UA8BiB,kBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,mBAAA;EAAA,SACN,EAAA;EAAA,SACA,UAAA,WAAqB,kBAAA;EAAA,SACrB,OAAA;AAAA;AAAA,iBAwEK,0BAAA,CAAA,GAA8B,OAAA"}
1
+ {"version":3,"file":"migration-list.d.mts","names":[],"sources":["../../src/commands/migration-list.ts"],"mappings":";;;;;;;;AAgDA;;;;AAQsB;AAsDtB;;;UA9DiB,sBAAA;EAgEC;EAAA,SA9DP,aAAA;EA8DA;;;;;EAAA,SAxDA,WAAW;AAAA;;;;;AAwDmC;AAwEzD;;;;AAAqD;;;;;;;;;;;;;;;;;;;;;;;;iBA1E/B,gBAAA,CACpB,MAAA,EAAQ,sBAAA,GACP,OAAA,CAAQ,MAAA,CAAO,mBAAA,EAAqB,kBAAA;AAAA,iBAwEvB,0BAAA,CAAA,GAA8B,OAAO"}
@@ -1,103 +1,2 @@
1
- import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
2
- import { b as mapMigrationToolsError, y as errorUnexpected } from "../cli-errors-Djtz98Vm.mjs";
3
- import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
4
- import { S as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-DtavI0wJ.mjs";
5
- import { Command } from "commander";
6
- import { notOk, ok } from "@prisma-next/utils/result";
7
- import { findPath } from "@prisma-next/migration-tools/migration-graph";
8
- import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
9
- import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
10
- //#region src/commands/migration-list.ts
11
- async function executeMigrationListCommand(options, flags, ui) {
12
- const config = await loadConfig(options.config);
13
- const { configPath, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);
14
- if (!flags.json && !flags.quiet) {
15
- const header = formatStyledHeader({
16
- command: "migration list",
17
- description: "List on-disk migrations in topological order",
18
- details: [{
19
- label: "config",
20
- value: configPath
21
- }, {
22
- label: "migrations",
23
- value: appMigrationsRelative
24
- }],
25
- flags
26
- });
27
- ui.stderr(header);
28
- }
29
- let bundles;
30
- let graph;
31
- try {
32
- ({bundles, graph} = await loadMigrationPackages(appMigrationsDir));
33
- } catch (error) {
34
- if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
35
- return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}` }));
36
- }
37
- if (bundles.length === 0) return ok({
38
- ok: true,
39
- migrations: [],
40
- summary: "No migrations found"
41
- });
42
- const leaves = [...graph.nodes].filter((n) => !graph.forwardChain.has(n) || graph.forwardChain.get(n).length === 0);
43
- const targetHash = leaves.length === 1 ? leaves[0] : [...graph.nodes].values().next().value;
44
- const chain = findPath(graph, EMPTY_CONTRACT_HASH, targetHash) ?? [];
45
- const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));
46
- const entries = chain.map((edge) => {
47
- const ops = pkgByDirName.get(edge.dirName)?.ops ?? [];
48
- return {
49
- dirName: edge.dirName,
50
- from: edge.from,
51
- to: edge.to,
52
- migrationHash: edge.migrationHash,
53
- operationCount: ops.length,
54
- createdAt: edge.createdAt
55
- };
56
- });
57
- return ok({
58
- ok: true,
59
- migrations: entries,
60
- summary: `${entries.length} migration(s) on disk`
61
- });
62
- }
63
- function createMigrationListCommand() {
64
- const command = new Command("list");
65
- setCommandDescriptions(command, "List on-disk migrations in topological order", "Enumerates all migration packages under migrations/<space>/ in\ntopological order. Offline — does not consult the database.");
66
- setCommandExamples(command, ["prisma-next migration list"]);
67
- setCommandSeeAlso(command, [
68
- {
69
- verb: "migration status",
70
- oneLiner: "Show migration path and pending status"
71
- },
72
- {
73
- verb: "migration log",
74
- oneLiner: "Show executed migration history"
75
- },
76
- {
77
- verb: "migration graph",
78
- oneLiner: "Show the migration graph topology"
79
- },
80
- {
81
- verb: "migration show",
82
- oneLiner: "Display migration package contents"
83
- }
84
- ]);
85
- addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").action(async (options) => {
86
- const flags = parseGlobalFlagsOrExit(options);
87
- const ui = createTerminalUI(flags);
88
- const exitCode = handleResult(await executeMigrationListCommand(options, flags, ui), flags, ui, (listResult) => {
89
- if (flags.json) ui.output(JSON.stringify(listResult, null, 2));
90
- else if (!flags.quiet) if (listResult.migrations.length === 0) ui.log("No migrations found");
91
- else {
92
- for (const entry of listResult.migrations) ui.log(`${entry.dirName} ${entry.migrationHash.slice(0, 16)}… ${entry.operationCount} op(s)`);
93
- ui.log(`\n${listResult.summary}`);
94
- }
95
- });
96
- process.exit(exitCode);
97
- });
98
- return command;
99
- }
100
- //#endregion
101
- export { createMigrationListCommand };
102
-
103
- //# sourceMappingURL=migration-list.mjs.map
1
+ import { n as runMigrationList, t as createMigrationListCommand } from "../migration-list-CnYiHrNV.mjs";
2
+ export { createMigrationListCommand, runMigrationList };
@@ -1 +1 @@
1
- {"version":3,"file":"migration-log.d.mts","names":[],"sources":["../../src/commands/migration-log.ts"],"mappings":";;;UAqCiB,iBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,kBAAA;EAAA,SACN,EAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA,WAAkB,iBAAA;EAAA,SAClB,OAAA;AAAA;AAAA,iBA2HK,yBAAA,CAAA,GAA6B,OAAA"}
1
+ {"version":3,"file":"migration-log.d.mts","names":[],"sources":["../../src/commands/migration-log.ts"],"mappings":";;;UAqCiB,iBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,kBAAA;EAAA,SACN,EAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA,WAAkB,iBAAiB;EAAA,SACnC,OAAA;AAAA;AAAA,iBA2HK,yBAAA,CAAA,GAA6B,OAAO"}
@@ -1,8 +1,7 @@
1
1
  import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
2
- import { b as mapMigrationToolsError, c as errorDriverRequired, o as errorDatabaseConnectionRequired, t as CliStructuredError, y as errorUnexpected } from "../cli-errors-Djtz98Vm.mjs";
3
- import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
4
- import { S as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, m as targetSupportsMigrations, o as maskConnectionUrl, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-DtavI0wJ.mjs";
5
- import { t as createControlClient } from "../client-oXO2WCPD.mjs";
2
+ import { O as errorUnexpected, c as errorDriverRequired, k as mapMigrationToolsError, o as errorDatabaseConnectionRequired, t as CliStructuredError } from "../cli-errors-DFF1LlfU.mjs";
3
+ import { D as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, m as targetSupportsMigrations, o as maskConnectionUrl, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, x as handleResult, y as createTerminalUI } from "../command-helpers-BnqwTptC.mjs";
4
+ import { t as createControlClient } from "../client-a5NJce0-.mjs";
6
5
  import { Command } from "commander";
7
6
  import { notOk, ok } from "@prisma-next/utils/result";
8
7
  import { findPath } from "@prisma-next/migration-tools/migration-graph";