@prisma-next/cli 0.5.0-dev.25 → 0.5.0-dev.27

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 (68) hide show
  1. package/README.md +2 -0
  2. package/dist/cli-errors-By1iVE3z.mjs.map +1 -1
  3. package/dist/cli.mjs +7 -13
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/{client-enZIahga.mjs → client-CJT9lqBd.mjs} +12 -10
  6. package/dist/client-CJT9lqBd.mjs.map +1 -0
  7. package/dist/commands/contract-emit.mjs +0 -5
  8. package/dist/commands/contract-infer.mjs +1 -7
  9. package/dist/commands/db-init.mjs +3 -4
  10. package/dist/commands/db-init.mjs.map +1 -1
  11. package/dist/commands/db-schema.mjs +1 -4
  12. package/dist/commands/db-schema.mjs.map +1 -1
  13. package/dist/commands/db-sign.mjs +1 -2
  14. package/dist/commands/db-sign.mjs.map +1 -1
  15. package/dist/commands/db-update.mjs +3 -4
  16. package/dist/commands/db-update.mjs.map +1 -1
  17. package/dist/commands/db-verify.mjs +1 -2
  18. package/dist/commands/db-verify.mjs.map +1 -1
  19. package/dist/commands/migration-apply.d.mts +1 -1
  20. package/dist/commands/migration-apply.mjs +2 -3
  21. package/dist/commands/migration-apply.mjs.map +1 -1
  22. package/dist/commands/migration-new.d.mts.map +1 -1
  23. package/dist/commands/migration-new.mjs +1 -3
  24. package/dist/commands/migration-new.mjs.map +1 -1
  25. package/dist/commands/migration-plan.d.mts +1 -1
  26. package/dist/commands/migration-plan.d.mts.map +1 -1
  27. package/dist/commands/migration-plan.mjs +1 -3
  28. package/dist/commands/migration-plan.mjs.map +1 -1
  29. package/dist/commands/migration-show.d.mts +1 -2
  30. package/dist/commands/migration-show.d.mts.map +1 -1
  31. package/dist/commands/migration-show.mjs +1 -2
  32. package/dist/commands/migration-show.mjs.map +1 -1
  33. package/dist/commands/migration-status.mjs +1 -6
  34. package/dist/{contract-emit-DS5NzZh2.mjs → contract-emit-LjzCoicC.mjs} +0 -2
  35. package/dist/{contract-infer-BjzkcwQt.mjs → contract-infer-CPQRrGmy.mjs} +2 -2
  36. package/dist/{contract-infer-BjzkcwQt.mjs.map → contract-infer-CPQRrGmy.mjs.map} +1 -1
  37. package/dist/exports/control-api.d.mts +2 -2
  38. package/dist/exports/control-api.mjs +1 -3
  39. package/dist/exports/index.mjs +0 -5
  40. package/dist/exports/index.mjs.map +1 -1
  41. package/dist/{init-C-H-if1m.mjs → init-BKgjxw6r.mjs} +2 -2
  42. package/dist/{init-C-H-if1m.mjs.map → init-BKgjxw6r.mjs.map} +1 -1
  43. package/dist/{inspect-live-schema-QklSDLt_.mjs → inspect-live-schema-CLchu1d-.mjs} +2 -2
  44. package/dist/{inspect-live-schema-QklSDLt_.mjs.map → inspect-live-schema-CLchu1d-.mjs.map} +1 -1
  45. package/dist/migration-cli.d.mts +41 -11
  46. package/dist/migration-cli.d.mts.map +1 -1
  47. package/dist/migration-cli.mjs +281 -72
  48. package/dist/migration-cli.mjs.map +1 -1
  49. package/dist/{migration-command-scaffold-BfloSWPZ.mjs → migration-command-scaffold-BP50SzoG.mjs} +2 -2
  50. package/dist/{migration-command-scaffold-BfloSWPZ.mjs.map → migration-command-scaffold-BP50SzoG.mjs.map} +1 -1
  51. package/dist/{migration-status-C5VYA5r9.mjs → migration-status-CMjpUefa.mjs} +2 -2
  52. package/dist/{migration-status-C5VYA5r9.mjs.map → migration-status-CMjpUefa.mjs.map} +1 -1
  53. package/dist/{migrations-CSaDHNpB.mjs → migrations-CYYmURZx.mjs} +2 -3
  54. package/dist/{migrations-CSaDHNpB.mjs.map → migrations-CYYmURZx.mjs.map} +1 -1
  55. package/package.json +16 -15
  56. package/src/cli.ts +32 -6
  57. package/src/commands/migration-apply.ts +1 -1
  58. package/src/commands/migration-new.ts +2 -4
  59. package/src/commands/migration-plan.ts +2 -4
  60. package/src/commands/migration-show.ts +1 -3
  61. package/src/control-api/operations/db-init.ts +3 -2
  62. package/src/control-api/operations/db-update.ts +3 -2
  63. package/src/control-api/operations/migration-apply.ts +14 -9
  64. package/src/control-api/types.ts +2 -2
  65. package/src/migration-cli.ts +414 -106
  66. package/src/utils/cli-errors.ts +4 -1
  67. package/src/utils/formatters/migrations.ts +2 -4
  68. package/dist/client-enZIahga.mjs.map +0 -1
@@ -87,8 +87,7 @@ function formatMigrationShowOutput(result, flags) {
87
87
  const formatYellow = createColorFormatter(useColor, yellow);
88
88
  const formatDimText = (text) => formatDim(useColor, text);
89
89
  lines.push(`${formatGreen("✔")} ${result.dirName}`);
90
- lines.push(`${formatDimText(` kind: ${result.kind}`)}`);
91
- lines.push(`${formatDimText(` from: ${result.from}`)}`);
90
+ lines.push(`${formatDimText(` from: ${result.from ?? "(baseline)"}`)}`);
92
91
  lines.push(`${formatDimText(` to: ${result.to}`)}`);
93
92
  lines.push(`${formatDimText(` migrationHash: ${result.migrationHash}`)}`);
94
93
  lines.push(`${formatDimText(` created: ${result.createdAt}`)}`);
@@ -150,4 +149,4 @@ function formatMigrationJson(result) {
150
149
 
151
150
  //#endregion
152
151
  export { formatMigrationShowOutput as a, formatMigrationPlanOutput as i, formatMigrationApplyOutput as n, formatMigrationJson as r, formatMigrationApplyCommandOutput as t };
153
- //# sourceMappingURL=migrations-CSaDHNpB.mjs.map
152
+ //# sourceMappingURL=migrations-CYYmURZx.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"migrations-CSaDHNpB.mjs","names":["lines: string[]"],"sources":["../src/utils/formatters/migrations.ts"],"sourcesContent":["import { green, yellow } from 'colorette';\n\nimport type { GlobalFlags } from '../global-flags';\nimport { createColorFormatter, formatDim, isVerbose } from './helpers';\n\n// ============================================================================\n// Migration Command Output Formatters (shared by db init and db update)\n// ============================================================================\n\n/**\n * Shared CLI output type for migration commands (db init, db update).\n */\nexport interface MigrationCommandResult {\n readonly ok: true;\n readonly mode: 'plan' | 'apply';\n readonly plan: {\n readonly targetId: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n readonly sql?: readonly string[];\n };\n readonly execution?: {\n readonly operationsPlanned: number;\n readonly operationsExecuted: number;\n };\n readonly marker?: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly summary: string;\n readonly timings: {\n readonly total: number;\n };\n}\n\n/**\n * Formats human-readable output for migration commands (db init, db update) in plan mode.\n */\nexport function formatMigrationPlanOutput(\n result: MigrationCommandResult,\n flags: GlobalFlags,\n): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Plan summary\n const operationCount = result.plan?.operations.length ?? 0;\n lines.push(`${formatGreen('✔')} Planned ${operationCount} operation(s)`);\n\n // Show operations tree\n if (result.plan?.operations && result.plan.operations.length > 0) {\n const formatYellow = createColorFormatter(useColor, yellow);\n lines.push(`${formatDimText('│')}`);\n for (let i = 0; i < result.plan.operations.length; i++) {\n const op = result.plan.operations[i];\n if (!op) continue;\n const isLast = i === result.plan.operations.length - 1;\n const treeChar = isLast ? '└' : '├';\n const opClassLabel =\n op.operationClass === 'destructive'\n ? formatYellow(`[${op.operationClass}]`)\n : formatDimText(`[${op.operationClass}]`);\n lines.push(`${formatDimText(treeChar)}─ ${op.label} ${opClassLabel}`);\n }\n\n const hasDestructive = result.plan.operations.some((op) => op.operationClass === 'destructive');\n if (hasDestructive) {\n lines.push('');\n lines.push(\n `${formatYellow('⚠')} This migration contains destructive operations that may cause data loss.`,\n );\n }\n }\n\n // Destination hash\n if (result.plan?.destination) {\n lines.push('');\n lines.push(`${formatDimText(`Destination hash: ${result.plan.destination.storageHash}`)}`);\n }\n\n // SQL DDL preview (SQL family only)\n const planSql = result.plan?.sql;\n if (planSql) {\n lines.push('');\n lines.push(`${formatDimText('DDL preview')}`);\n if (planSql.length === 0) {\n lines.push(`${formatDimText('No DDL operations.')}`);\n } else {\n lines.push('');\n for (const statement of planSql) {\n const trimmed = statement.trim();\n if (!trimmed) continue;\n const line = trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n lines.push(`${line}`);\n }\n }\n }\n\n // Timings in verbose mode\n if (isVerbose(flags, 1)) {\n lines.push(`${formatDimText(`Total time: ${result.timings.total}ms`)}`);\n }\n\n // Note about dry run\n lines.push('');\n lines.push(`${formatDimText('This is a dry run. No changes were applied.')}`);\n lines.push(`${formatDimText('Run without --dry-run to apply changes.')}`);\n\n return lines.join('\\n');\n}\n\nexport interface MigrationApplyCommandOutputResult {\n readonly migrationsApplied: number;\n readonly markerHash: string;\n readonly applied: readonly {\n readonly dirName: string;\n readonly operationsExecuted: number;\n }[];\n readonly summary: string;\n readonly timings?: {\n readonly total: number;\n };\n}\n\nexport function formatMigrationApplyCommandOutput(\n result: MigrationApplyCommandOutputResult,\n flags: GlobalFlags,\n): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n if (result.migrationsApplied === 0) {\n lines.push(`${formatGreen('✔')} ${result.summary}`);\n lines.push(formatDimText(` marker: ${result.markerHash}`));\n return lines.join('\\n');\n }\n\n lines.push(`${formatGreen('✔')} ${result.summary}`);\n lines.push('');\n\n for (let i = 0; i < result.applied.length; i++) {\n const migration = result.applied[i]!;\n const isLast = i === result.applied.length - 1;\n const treeChar = isLast ? '└' : '├';\n lines.push(\n `${formatDimText(treeChar)}─ ${migration.dirName} ${formatDimText(`[${migration.operationsExecuted} op(s)]`)}`,\n );\n }\n\n lines.push('');\n lines.push(formatDimText(`marker: ${result.markerHash}`));\n\n if (isVerbose(flags, 1) && result.timings) {\n lines.push('');\n lines.push(formatDimText(`Total time: ${result.timings.total}ms`));\n }\n\n return lines.join('\\n');\n}\n\ninterface MigrationShowResult {\n readonly dirName: string;\n readonly dirPath: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly kind: string;\n readonly createdAt: string;\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n readonly sql: readonly string[];\n readonly summary: string;\n}\n\nexport function formatMigrationShowOutput(result: MigrationShowResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatYellow = createColorFormatter(useColor, yellow);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n lines.push(`${formatGreen('✔')} ${result.dirName}`);\n lines.push(`${formatDimText(` kind: ${result.kind}`)}`);\n lines.push(`${formatDimText(` from: ${result.from}`)}`);\n lines.push(`${formatDimText(` to: ${result.to}`)}`);\n lines.push(`${formatDimText(` migrationHash: ${result.migrationHash}`)}`);\n lines.push(`${formatDimText(` created: ${result.createdAt}`)}`);\n\n lines.push('');\n lines.push(`${result.operations.length} operation(s)`);\n\n if (result.operations.length > 0) {\n lines.push(`${formatDimText('│')}`);\n for (let i = 0; i < result.operations.length; i++) {\n const op = result.operations[i]!;\n const isLast = i === result.operations.length - 1;\n const treeChar = isLast ? '└' : '├';\n const opClassLabel =\n op.operationClass === 'destructive'\n ? formatYellow(`[${op.operationClass}]`)\n : formatDimText(`[${op.operationClass}]`);\n lines.push(`${formatDimText(treeChar)}─ ${op.label} ${opClassLabel}`);\n }\n\n const hasDestructive = result.operations.some((op) => op.operationClass === 'destructive');\n if (hasDestructive) {\n lines.push('');\n lines.push(\n `${formatYellow('⚠')} This migration contains destructive operations that may cause data loss.`,\n );\n }\n }\n\n if (result.sql.length > 0) {\n lines.push('');\n lines.push(`${formatDimText('DDL preview')}`);\n lines.push('');\n for (const statement of result.sql) {\n const trimmed = statement.trim();\n if (!trimmed) continue;\n const line = trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n lines.push(`${line}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats human-readable output for migration commands (db init, db update) in apply mode.\n */\nexport function formatMigrationApplyOutput(\n result: MigrationCommandResult,\n flags: GlobalFlags,\n): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n if (result.ok) {\n // Success summary\n const executed = result.execution?.operationsExecuted ?? 0;\n if (executed === 0) {\n lines.push(`${formatGreen('✔')} Database already matches contract`);\n } else {\n lines.push(`${formatGreen('✔')} Applied ${executed} operation(s)`);\n }\n\n // Marker info\n if (result.marker) {\n lines.push(`${formatDimText(` Signature: ${result.marker.storageHash}`)}`);\n if (result.marker.profileHash) {\n lines.push(`${formatDimText(` Profile hash: ${result.marker.profileHash}`)}`);\n }\n }\n\n // Timings in verbose mode\n if (isVerbose(flags, 1)) {\n lines.push(`${formatDimText(` Total time: ${result.timings.total}ms`)}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for migration commands (db init, db update).\n */\nexport function formatMigrationJson(result: MigrationCommandResult): string {\n return JSON.stringify(result, null, 2);\n}\n"],"mappings":";;;;;;;AA6CA,SAAgB,0BACd,QACA,OACQ;AACR,KAAI,MAAM,MACR,QAAO;CAGT,MAAMA,QAAkB,EAAE;CAE1B,MAAM,WAAW,MAAM,UAAU;CACjC,MAAM,cAAc,qBAAqB,UAAU,MAAM;CACzD,MAAM,iBAAiB,SAAiB,UAAU,UAAU,KAAK;CAGjE,MAAM,iBAAiB,OAAO,MAAM,WAAW,UAAU;AACzD,OAAM,KAAK,GAAG,YAAY,IAAI,CAAC,WAAW,eAAe,eAAe;AAGxE,KAAI,OAAO,MAAM,cAAc,OAAO,KAAK,WAAW,SAAS,GAAG;EAChE,MAAM,eAAe,qBAAqB,UAAU,OAAO;AAC3D,QAAM,KAAK,GAAG,cAAc,IAAI,GAAG;AACnC,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK,WAAW,QAAQ,KAAK;GACtD,MAAM,KAAK,OAAO,KAAK,WAAW;AAClC,OAAI,CAAC,GAAI;GAET,MAAM,WADS,MAAM,OAAO,KAAK,WAAW,SAAS,IAC3B,MAAM;GAChC,MAAM,eACJ,GAAG,mBAAmB,gBAClB,aAAa,IAAI,GAAG,eAAe,GAAG,GACtC,cAAc,IAAI,GAAG,eAAe,GAAG;AAC7C,SAAM,KAAK,GAAG,cAAc,SAAS,CAAC,IAAI,GAAG,MAAM,GAAG,eAAe;;AAIvE,MADuB,OAAO,KAAK,WAAW,MAAM,OAAO,GAAG,mBAAmB,cAAc,EAC3E;AAClB,SAAM,KAAK,GAAG;AACd,SAAM,KACJ,GAAG,aAAa,IAAI,CAAC,2EACtB;;;AAKL,KAAI,OAAO,MAAM,aAAa;AAC5B,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,GAAG,cAAc,qBAAqB,OAAO,KAAK,YAAY,cAAc,GAAG;;CAI5F,MAAM,UAAU,OAAO,MAAM;AAC7B,KAAI,SAAS;AACX,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,GAAG,cAAc,cAAc,GAAG;AAC7C,MAAI,QAAQ,WAAW,EACrB,OAAM,KAAK,GAAG,cAAc,qBAAqB,GAAG;OAC/C;AACL,SAAM,KAAK,GAAG;AACd,QAAK,MAAM,aAAa,SAAS;IAC/B,MAAM,UAAU,UAAU,MAAM;AAChC,QAAI,CAAC,QAAS;IACd,MAAM,OAAO,QAAQ,SAAS,IAAI,GAAG,UAAU,GAAG,QAAQ;AAC1D,UAAM,KAAK,GAAG,OAAO;;;;AAM3B,KAAI,UAAU,OAAO,EAAE,CACrB,OAAM,KAAK,GAAG,cAAc,eAAe,OAAO,QAAQ,MAAM,IAAI,GAAG;AAIzE,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,GAAG,cAAc,8CAA8C,GAAG;AAC7E,OAAM,KAAK,GAAG,cAAc,0CAA0C,GAAG;AAEzE,QAAO,MAAM,KAAK,KAAK;;AAgBzB,SAAgB,kCACd,QACA,OACQ;AACR,KAAI,MAAM,MACR,QAAO;CAGT,MAAMA,QAAkB,EAAE;CAC1B,MAAM,WAAW,MAAM,UAAU;CACjC,MAAM,cAAc,qBAAqB,UAAU,MAAM;CACzD,MAAM,iBAAiB,SAAiB,UAAU,UAAU,KAAK;AAEjE,KAAI,OAAO,sBAAsB,GAAG;AAClC,QAAM,KAAK,GAAG,YAAY,IAAI,CAAC,GAAG,OAAO,UAAU;AACnD,QAAM,KAAK,cAAc,aAAa,OAAO,aAAa,CAAC;AAC3D,SAAO,MAAM,KAAK,KAAK;;AAGzB,OAAM,KAAK,GAAG,YAAY,IAAI,CAAC,GAAG,OAAO,UAAU;AACnD,OAAM,KAAK,GAAG;AAEd,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,KAAK;EAC9C,MAAM,YAAY,OAAO,QAAQ;EAEjC,MAAM,WADS,MAAM,OAAO,QAAQ,SAAS,IACnB,MAAM;AAChC,QAAM,KACJ,GAAG,cAAc,SAAS,CAAC,IAAI,UAAU,QAAQ,GAAG,cAAc,IAAI,UAAU,mBAAmB,SAAS,GAC7G;;AAGH,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,cAAc,WAAW,OAAO,aAAa,CAAC;AAEzD,KAAI,UAAU,OAAO,EAAE,IAAI,OAAO,SAAS;AACzC,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,cAAc,eAAe,OAAO,QAAQ,MAAM,IAAI,CAAC;;AAGpE,QAAO,MAAM,KAAK,KAAK;;AAoBzB,SAAgB,0BAA0B,QAA6B,OAA4B;AACjG,KAAI,MAAM,MACR,QAAO;CAGT,MAAMA,QAAkB,EAAE;CAE1B,MAAM,WAAW,MAAM,UAAU;CACjC,MAAM,cAAc,qBAAqB,UAAU,MAAM;CACzD,MAAM,eAAe,qBAAqB,UAAU,OAAO;CAC3D,MAAM,iBAAiB,SAAiB,UAAU,UAAU,KAAK;AAEjE,OAAM,KAAK,GAAG,YAAY,IAAI,CAAC,GAAG,OAAO,UAAU;AACnD,OAAM,KAAK,GAAG,cAAc,WAAW,OAAO,OAAO,GAAG;AACxD,OAAM,KAAK,GAAG,cAAc,WAAW,OAAO,OAAO,GAAG;AACxD,OAAM,KAAK,GAAG,cAAc,WAAW,OAAO,KAAK,GAAG;AACtD,OAAM,KAAK,GAAG,cAAc,oBAAoB,OAAO,gBAAgB,GAAG;AAC1E,OAAM,KAAK,GAAG,cAAc,cAAc,OAAO,YAAY,GAAG;AAEhE,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,GAAG,OAAO,WAAW,OAAO,eAAe;AAEtD,KAAI,OAAO,WAAW,SAAS,GAAG;AAChC,QAAM,KAAK,GAAG,cAAc,IAAI,GAAG;AACnC,OAAK,IAAI,IAAI,GAAG,IAAI,OAAO,WAAW,QAAQ,KAAK;GACjD,MAAM,KAAK,OAAO,WAAW;GAE7B,MAAM,WADS,MAAM,OAAO,WAAW,SAAS,IACtB,MAAM;GAChC,MAAM,eACJ,GAAG,mBAAmB,gBAClB,aAAa,IAAI,GAAG,eAAe,GAAG,GACtC,cAAc,IAAI,GAAG,eAAe,GAAG;AAC7C,SAAM,KAAK,GAAG,cAAc,SAAS,CAAC,IAAI,GAAG,MAAM,GAAG,eAAe;;AAIvE,MADuB,OAAO,WAAW,MAAM,OAAO,GAAG,mBAAmB,cAAc,EACtE;AAClB,SAAM,KAAK,GAAG;AACd,SAAM,KACJ,GAAG,aAAa,IAAI,CAAC,2EACtB;;;AAIL,KAAI,OAAO,IAAI,SAAS,GAAG;AACzB,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,GAAG,cAAc,cAAc,GAAG;AAC7C,QAAM,KAAK,GAAG;AACd,OAAK,MAAM,aAAa,OAAO,KAAK;GAClC,MAAM,UAAU,UAAU,MAAM;AAChC,OAAI,CAAC,QAAS;GACd,MAAM,OAAO,QAAQ,SAAS,IAAI,GAAG,UAAU,GAAG,QAAQ;AAC1D,SAAM,KAAK,GAAG,OAAO;;;AAIzB,QAAO,MAAM,KAAK,KAAK;;;;;AAMzB,SAAgB,2BACd,QACA,OACQ;AACR,KAAI,MAAM,MACR,QAAO;CAGT,MAAMA,QAAkB,EAAE;CAE1B,MAAM,WAAW,MAAM,UAAU;CACjC,MAAM,cAAc,qBAAqB,UAAU,MAAM;CACzD,MAAM,iBAAiB,SAAiB,UAAU,UAAU,KAAK;AAEjE,KAAI,OAAO,IAAI;EAEb,MAAM,WAAW,OAAO,WAAW,sBAAsB;AACzD,MAAI,aAAa,EACf,OAAM,KAAK,GAAG,YAAY,IAAI,CAAC,oCAAoC;MAEnE,OAAM,KAAK,GAAG,YAAY,IAAI,CAAC,WAAW,SAAS,eAAe;AAIpE,MAAI,OAAO,QAAQ;AACjB,SAAM,KAAK,GAAG,cAAc,gBAAgB,OAAO,OAAO,cAAc,GAAG;AAC3E,OAAI,OAAO,OAAO,YAChB,OAAM,KAAK,GAAG,cAAc,mBAAmB,OAAO,OAAO,cAAc,GAAG;;AAKlF,MAAI,UAAU,OAAO,EAAE,CACrB,OAAM,KAAK,GAAG,cAAc,iBAAiB,OAAO,QAAQ,MAAM,IAAI,GAAG;;AAI7E,QAAO,MAAM,KAAK,KAAK;;;;;AAMzB,SAAgB,oBAAoB,QAAwC;AAC1E,QAAO,KAAK,UAAU,QAAQ,MAAM,EAAE"}
1
+ {"version":3,"file":"migrations-CYYmURZx.mjs","names":["lines: string[]"],"sources":["../src/utils/formatters/migrations.ts"],"sourcesContent":["import { green, yellow } from 'colorette';\n\nimport type { GlobalFlags } from '../global-flags';\nimport { createColorFormatter, formatDim, isVerbose } from './helpers';\n\n// ============================================================================\n// Migration Command Output Formatters (shared by db init and db update)\n// ============================================================================\n\n/**\n * Shared CLI output type for migration commands (db init, db update).\n */\nexport interface MigrationCommandResult {\n readonly ok: true;\n readonly mode: 'plan' | 'apply';\n readonly plan: {\n readonly targetId: string;\n readonly destination: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n readonly sql?: readonly string[];\n };\n readonly execution?: {\n readonly operationsPlanned: number;\n readonly operationsExecuted: number;\n };\n readonly marker?: {\n readonly storageHash: string;\n readonly profileHash?: string;\n };\n readonly summary: string;\n readonly timings: {\n readonly total: number;\n };\n}\n\n/**\n * Formats human-readable output for migration commands (db init, db update) in plan mode.\n */\nexport function formatMigrationPlanOutput(\n result: MigrationCommandResult,\n flags: GlobalFlags,\n): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Plan summary\n const operationCount = result.plan?.operations.length ?? 0;\n lines.push(`${formatGreen('✔')} Planned ${operationCount} operation(s)`);\n\n // Show operations tree\n if (result.plan?.operations && result.plan.operations.length > 0) {\n const formatYellow = createColorFormatter(useColor, yellow);\n lines.push(`${formatDimText('│')}`);\n for (let i = 0; i < result.plan.operations.length; i++) {\n const op = result.plan.operations[i];\n if (!op) continue;\n const isLast = i === result.plan.operations.length - 1;\n const treeChar = isLast ? '└' : '├';\n const opClassLabel =\n op.operationClass === 'destructive'\n ? formatYellow(`[${op.operationClass}]`)\n : formatDimText(`[${op.operationClass}]`);\n lines.push(`${formatDimText(treeChar)}─ ${op.label} ${opClassLabel}`);\n }\n\n const hasDestructive = result.plan.operations.some((op) => op.operationClass === 'destructive');\n if (hasDestructive) {\n lines.push('');\n lines.push(\n `${formatYellow('⚠')} This migration contains destructive operations that may cause data loss.`,\n );\n }\n }\n\n // Destination hash\n if (result.plan?.destination) {\n lines.push('');\n lines.push(`${formatDimText(`Destination hash: ${result.plan.destination.storageHash}`)}`);\n }\n\n // SQL DDL preview (SQL family only)\n const planSql = result.plan?.sql;\n if (planSql) {\n lines.push('');\n lines.push(`${formatDimText('DDL preview')}`);\n if (planSql.length === 0) {\n lines.push(`${formatDimText('No DDL operations.')}`);\n } else {\n lines.push('');\n for (const statement of planSql) {\n const trimmed = statement.trim();\n if (!trimmed) continue;\n const line = trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n lines.push(`${line}`);\n }\n }\n }\n\n // Timings in verbose mode\n if (isVerbose(flags, 1)) {\n lines.push(`${formatDimText(`Total time: ${result.timings.total}ms`)}`);\n }\n\n // Note about dry run\n lines.push('');\n lines.push(`${formatDimText('This is a dry run. No changes were applied.')}`);\n lines.push(`${formatDimText('Run without --dry-run to apply changes.')}`);\n\n return lines.join('\\n');\n}\n\nexport interface MigrationApplyCommandOutputResult {\n readonly migrationsApplied: number;\n readonly markerHash: string;\n readonly applied: readonly {\n readonly dirName: string;\n readonly operationsExecuted: number;\n }[];\n readonly summary: string;\n readonly timings?: {\n readonly total: number;\n };\n}\n\nexport function formatMigrationApplyCommandOutput(\n result: MigrationApplyCommandOutputResult,\n flags: GlobalFlags,\n): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n if (result.migrationsApplied === 0) {\n lines.push(`${formatGreen('✔')} ${result.summary}`);\n lines.push(formatDimText(` marker: ${result.markerHash}`));\n return lines.join('\\n');\n }\n\n lines.push(`${formatGreen('✔')} ${result.summary}`);\n lines.push('');\n\n for (let i = 0; i < result.applied.length; i++) {\n const migration = result.applied[i]!;\n const isLast = i === result.applied.length - 1;\n const treeChar = isLast ? '└' : '├';\n lines.push(\n `${formatDimText(treeChar)}─ ${migration.dirName} ${formatDimText(`[${migration.operationsExecuted} op(s)]`)}`,\n );\n }\n\n lines.push('');\n lines.push(formatDimText(`marker: ${result.markerHash}`));\n\n if (isVerbose(flags, 1) && result.timings) {\n lines.push('');\n lines.push(formatDimText(`Total time: ${result.timings.total}ms`));\n }\n\n return lines.join('\\n');\n}\n\ninterface MigrationShowResult {\n readonly dirName: string;\n readonly dirPath: string;\n readonly from: string | null;\n readonly to: string;\n readonly migrationHash: string;\n readonly createdAt: string;\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n readonly sql: readonly string[];\n readonly summary: string;\n}\n\nexport function formatMigrationShowOutput(result: MigrationShowResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatYellow = createColorFormatter(useColor, yellow);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n lines.push(`${formatGreen('✔')} ${result.dirName}`);\n lines.push(`${formatDimText(` from: ${result.from ?? '(baseline)'}`)}`);\n lines.push(`${formatDimText(` to: ${result.to}`)}`);\n lines.push(`${formatDimText(` migrationHash: ${result.migrationHash}`)}`);\n lines.push(`${formatDimText(` created: ${result.createdAt}`)}`);\n\n lines.push('');\n lines.push(`${result.operations.length} operation(s)`);\n\n if (result.operations.length > 0) {\n lines.push(`${formatDimText('│')}`);\n for (let i = 0; i < result.operations.length; i++) {\n const op = result.operations[i]!;\n const isLast = i === result.operations.length - 1;\n const treeChar = isLast ? '└' : '├';\n const opClassLabel =\n op.operationClass === 'destructive'\n ? formatYellow(`[${op.operationClass}]`)\n : formatDimText(`[${op.operationClass}]`);\n lines.push(`${formatDimText(treeChar)}─ ${op.label} ${opClassLabel}`);\n }\n\n const hasDestructive = result.operations.some((op) => op.operationClass === 'destructive');\n if (hasDestructive) {\n lines.push('');\n lines.push(\n `${formatYellow('⚠')} This migration contains destructive operations that may cause data loss.`,\n );\n }\n }\n\n if (result.sql.length > 0) {\n lines.push('');\n lines.push(`${formatDimText('DDL preview')}`);\n lines.push('');\n for (const statement of result.sql) {\n const trimmed = statement.trim();\n if (!trimmed) continue;\n const line = trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n lines.push(`${line}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats human-readable output for migration commands (db init, db update) in apply mode.\n */\nexport function formatMigrationApplyOutput(\n result: MigrationCommandResult,\n flags: GlobalFlags,\n): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n if (result.ok) {\n // Success summary\n const executed = result.execution?.operationsExecuted ?? 0;\n if (executed === 0) {\n lines.push(`${formatGreen('✔')} Database already matches contract`);\n } else {\n lines.push(`${formatGreen('✔')} Applied ${executed} operation(s)`);\n }\n\n // Marker info\n if (result.marker) {\n lines.push(`${formatDimText(` Signature: ${result.marker.storageHash}`)}`);\n if (result.marker.profileHash) {\n lines.push(`${formatDimText(` Profile hash: ${result.marker.profileHash}`)}`);\n }\n }\n\n // Timings in verbose mode\n if (isVerbose(flags, 1)) {\n lines.push(`${formatDimText(` Total time: ${result.timings.total}ms`)}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for migration commands (db init, db update).\n */\nexport function formatMigrationJson(result: MigrationCommandResult): string {\n return JSON.stringify(result, null, 2);\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma-next/cli",
3
- "version": "0.5.0-dev.25",
3
+ "version": "0.5.0-dev.27",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "files": [
@@ -15,6 +15,7 @@
15
15
  "@dagrejs/dagre": "^3.0.0",
16
16
  "arktype": "^2.0.0",
17
17
  "c12": "^3.3.2",
18
+ "clipanion": "4.0.0-rc.4",
18
19
  "closest-match": "^1.3.3",
19
20
  "colorette": "^2.0.20",
20
21
  "commander": "^12.0.0",
@@ -25,27 +26,27 @@
25
26
  "string-width": "^8.2.0",
26
27
  "strip-ansi": "^7.1.2",
27
28
  "wrap-ansi": "^10.0.0",
28
- "@prisma-next/contract": "0.5.0-dev.25",
29
- "@prisma-next/emitter": "0.5.0-dev.25",
30
- "@prisma-next/framework-components": "0.5.0-dev.25",
31
- "@prisma-next/config": "0.5.0-dev.25",
32
- "@prisma-next/errors": "0.5.0-dev.25",
33
- "@prisma-next/migration-tools": "0.5.0-dev.25",
34
- "@prisma-next/psl-printer": "0.5.0-dev.25",
35
- "@prisma-next/utils": "0.5.0-dev.25"
29
+ "@prisma-next/config": "0.5.0-dev.27",
30
+ "@prisma-next/contract": "0.5.0-dev.27",
31
+ "@prisma-next/emitter": "0.5.0-dev.27",
32
+ "@prisma-next/framework-components": "0.5.0-dev.27",
33
+ "@prisma-next/migration-tools": "0.5.0-dev.27",
34
+ "@prisma-next/errors": "0.5.0-dev.27",
35
+ "@prisma-next/utils": "0.5.0-dev.27",
36
+ "@prisma-next/psl-printer": "0.5.0-dev.27"
36
37
  },
37
38
  "devDependencies": {
38
39
  "@types/node": "24.10.4",
39
40
  "tsdown": "0.18.4",
40
41
  "typescript": "5.9.3",
41
42
  "vitest": "4.0.17",
42
- "@prisma-next/sql-contract": "0.5.0-dev.25",
43
- "@prisma-next/sql-contract-ts": "0.5.0-dev.25",
44
- "@prisma-next/sql-contract-emitter": "0.5.0-dev.25",
45
- "@prisma-next/sql-runtime": "0.5.0-dev.25",
46
- "@prisma-next/sql-operations": "0.5.0-dev.25",
47
- "@prisma-next/tsconfig": "0.0.0",
43
+ "@prisma-next/sql-contract": "0.5.0-dev.27",
44
+ "@prisma-next/sql-contract-emitter": "0.5.0-dev.27",
45
+ "@prisma-next/sql-operations": "0.5.0-dev.27",
46
+ "@prisma-next/sql-contract-ts": "0.5.0-dev.27",
47
+ "@prisma-next/sql-runtime": "0.5.0-dev.27",
48
48
  "@prisma-next/test-utils": "0.0.1",
49
+ "@prisma-next/tsconfig": "0.0.0",
49
50
  "@prisma-next/tsdown": "0.0.0"
50
51
  },
51
52
  "exports": {
package/src/cli.ts CHANGED
@@ -50,8 +50,18 @@ program.configureOutput({
50
50
  writeErr: () => {
51
51
  // Suppress all default error output - we handle errors in exitOverride
52
52
  },
53
- writeOut: () => {
54
- // Suppress all default output - our custom formatters handle everything
53
+ writeOut: (str) => {
54
+ // Commander routes explicitly-requested `--help` (success-path help)
55
+ // through writeOut; per the Style Guide § Output Conventions rule 8,
56
+ // user-requested help is data and goes to stdout. Error-path help
57
+ // (e.g. usage shown after an unknown command) goes through writeErr,
58
+ // which stays suppressed because we render that ourselves with the
59
+ // matching error envelope.
60
+ //
61
+ // Explicit `--version` is short-circuited before `program.parse()`
62
+ // (see the argv pre-scan at the bottom of this file), so it does not
63
+ // reach this writer.
64
+ process.stdout.write(str);
55
65
  },
56
66
  });
57
67
 
@@ -261,14 +271,25 @@ const helpCommand = new Command('help')
261
271
  .action(() => {
262
272
  const flags = parseGlobalFlags({});
263
273
  const helpText = formatRootHelp({ program, flags });
264
- // Help is decoration stderr
265
- process.stderr.write(`${helpText}\n`);
274
+ // The `help` command was invoked explicitly: help is the data the
275
+ // caller asked for. Per Style Guide § Output Conventions rule 8,
276
+ // explicit help goes to stdout with exit code 0.
277
+ process.stdout.write(`${helpText}\n`);
266
278
  process.exit(0);
267
279
  });
268
280
 
269
281
  program.addCommand(helpCommand);
270
282
 
271
- // Set help as the default action when no command is provided
283
+ // Set help as the default action when no command is provided. The user
284
+ // did not invoke `--help`; we are voluntarily showing usage to help them
285
+ // recover from an underspecified invocation, so the help text is
286
+ // decoration around an implicit "what did you want me to do?" and goes
287
+ // to stderr (Style Guide § Output Conventions rule 8).
288
+ //
289
+ // FOLLOW-UP: the exit code here is 0 today, but a no-arg invocation is
290
+ // arguably a usage error (PRECONDITION → exit 2) for consistency with
291
+ // the unknown-command path. Out of scope for the explicit-help routing
292
+ // work; revisit when tightening exit-code semantics across the CLI.
272
293
  program.action(() => {
273
294
  const flags = parseGlobalFlags({});
274
295
  const helpText = formatRootHelp({ program, flags });
@@ -304,7 +325,12 @@ if (args.length > 0) {
304
325
  process.stderr.write(`${helpText}\n`);
305
326
  process.exit(2);
306
327
  } else if (command.commands.length > 0 && args.length === 1) {
307
- // Parent command called with no subcommand - show help and exit with 0
328
+ // Parent command called with no subcommand. Same shape as the
329
+ // no-args case above: the user did not request help, we are
330
+ // voluntarily rendering it as decoration around an underspecified
331
+ // invocation, so it goes to stderr per Style Guide § Output
332
+ // Conventions rule 8. Exit code 0 today; the FOLLOW-UP note on
333
+ // `program.action` applies here too (arguably should be 2).
308
334
  const flags = parseGlobalFlags({});
309
335
  const helpText = formatCommandHelp({ command, flags });
310
336
  process.stderr.write(`${helpText}\n`);
@@ -50,7 +50,7 @@ export interface MigrationApplyResult {
50
50
  readonly markerHash: string;
51
51
  readonly applied: readonly {
52
52
  readonly dirName: string;
53
- readonly from: string;
53
+ readonly from: string | null;
54
54
  readonly to: string;
55
55
  readonly operationsExecuted: number;
56
56
  }[];
@@ -12,7 +12,6 @@ import { readFileSync } from 'node:fs';
12
12
  import type { Contract } from '@prisma-next/contract/types';
13
13
  import { getEmittedArtifactPaths } from '@prisma-next/emitter';
14
14
  import { createControlStack } from '@prisma-next/framework-components/control';
15
- import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
16
15
  import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
17
16
  import { computeMigrationHash } from '@prisma-next/migration-tools/hash';
18
17
  import {
@@ -62,7 +61,7 @@ interface MigrationNewOptions extends CommonCommandOptions {
62
61
  interface MigrationNewResult {
63
62
  readonly ok: true;
64
63
  readonly dir: string;
65
- readonly from: string;
64
+ readonly from: string | null;
66
65
  readonly to: string;
67
66
  readonly summary: string;
68
67
  }
@@ -117,7 +116,7 @@ async function executeMigrationNewCommand(
117
116
  }
118
117
 
119
118
  let fromContract: Contract | null = null;
120
- let fromHash: string = EMPTY_CONTRACT_HASH;
119
+ let fromHash: string | null = null;
121
120
  let fromContractSourceDir: string | null = null;
122
121
 
123
122
  try {
@@ -181,7 +180,6 @@ async function executeMigrationNewCommand(
181
180
  const baseMetadata: Omit<MigrationMetadata, 'migrationHash'> = {
182
181
  from: fromHash,
183
182
  to: toStorageHash,
184
- kind: 'regular',
185
183
  fromContract,
186
184
  toContract: toContractJson,
187
185
  hints: {
@@ -5,7 +5,6 @@ import {
5
5
  createControlStack,
6
6
  type MigrationPlanOperation,
7
7
  } from '@prisma-next/framework-components/control';
8
- import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';
9
8
  import { MigrationToolsError } from '@prisma-next/migration-tools/errors';
10
9
  import { computeMigrationHash } from '@prisma-next/migration-tools/hash';
11
10
  import { deriveProvidedInvariants } from '@prisma-next/migration-tools/invariants';
@@ -58,7 +57,7 @@ interface MigrationPlanOptions extends CommonCommandOptions {
58
57
  export interface MigrationPlanResult {
59
58
  readonly ok: boolean;
60
59
  readonly noOp: boolean;
61
- readonly from: string;
60
+ readonly from: string | null;
62
61
  readonly to: string;
63
62
  readonly dir?: string;
64
63
  readonly operations: readonly {
@@ -160,7 +159,7 @@ async function executeMigrationPlanCommand(
160
159
 
161
160
  // Read existing migrations and determine "from" contract
162
161
  let fromContract: Contract | null = null;
163
- let fromHash: string = EMPTY_CONTRACT_HASH;
162
+ let fromHash: string | null = null;
164
163
  let fromContractSourceDir: string | null = null;
165
164
 
166
165
  try {
@@ -252,7 +251,6 @@ async function executeMigrationPlanCommand(
252
251
  const baseMetadata: Omit<MigrationMetadata, 'migrationHash' | 'providedInvariants'> = {
253
252
  from: fromHash,
254
253
  to: toStorageHash,
255
- kind: 'regular',
256
254
  fromContract,
257
255
  toContract: toContractJson,
258
256
  hints: {
@@ -37,10 +37,9 @@ export interface MigrationShowResult {
37
37
  readonly ok: true;
38
38
  readonly dirName: string;
39
39
  readonly dirPath: string;
40
- readonly from: string;
40
+ readonly from: string | null;
41
41
  readonly to: string;
42
42
  readonly migrationHash: string;
43
- readonly kind: string;
44
43
  readonly createdAt: string;
45
44
  readonly operations: readonly {
46
45
  readonly id: string;
@@ -184,7 +183,6 @@ async function executeMigrationShowCommand(
184
183
  from: pkg.metadata.from,
185
184
  to: pkg.metadata.to,
186
185
  migrationHash: pkg.metadata.migrationHash,
187
- kind: pkg.metadata.kind,
188
186
  createdAt: pkg.metadata.createdAt,
189
187
  operations: ops.map((op) => ({
190
188
  id: op.id,
@@ -84,8 +84,9 @@ export async function executeDbInit<TFamilyId extends string, TTargetId extends
84
84
  schema: schemaIR,
85
85
  policy,
86
86
  // `db init` does not produce a `migration.ts`, so the from-hash on the
87
- // resulting plan is never surfaced to authoring — pass empty string.
88
- fromHash: '',
87
+ // resulting plan is never surfaced to authoring — pass null (the
88
+ // baseline encoding for `MigrationPlanner.plan({ fromHash })`).
89
+ fromHash: null,
89
90
  frameworkComponents,
90
91
  });
91
92
 
@@ -84,8 +84,9 @@ export async function executeDbUpdate<TFamilyId extends string, TTargetId extend
84
84
  schema: schemaIR,
85
85
  policy,
86
86
  // `db update` does not produce a `migration.ts`, so the from-hash on the
87
- // resulting plan is never surfaced to authoring — pass empty string.
88
- fromHash: '',
87
+ // resulting plan is never surfaced to authoring — pass null (the
88
+ // baseline encoding for `MigrationPlanner.plan({ fromHash })`).
89
+ fromHash: null,
89
90
  frameworkComponents,
90
91
  });
91
92
  if (plannerResult.kind === 'failure') {
@@ -79,15 +79,19 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
79
79
 
80
80
  const firstMigration = pendingMigrations[0]!;
81
81
  const lastMigration = pendingMigrations[pendingMigrations.length - 1]!;
82
- if (firstMigration.from !== originHash || lastMigration.to !== destinationHash) {
82
+ // Manifest `from` is `string | null` (null = baseline). The live-marker
83
+ // layer encodes "no prior state" as EMPTY_CONTRACT_HASH; bridge here so the
84
+ // string comparisons below work uniformly.
85
+ const firstFromMarker = firstMigration.from ?? EMPTY_CONTRACT_HASH;
86
+ if (firstFromMarker !== originHash || lastMigration.to !== destinationHash) {
83
87
  return notOk({
84
88
  code: 'MIGRATION_PATH_NOT_FOUND' as const,
85
89
  summary: 'Migration apply path does not match requested origin and destination',
86
- why: `Path resolved as ${firstMigration.from} -> ${lastMigration.to}, but requested ${originHash} -> ${destinationHash}`,
90
+ why: `Path resolved as ${firstFromMarker} -> ${lastMigration.to}, but requested ${originHash} -> ${destinationHash}`,
87
91
  meta: {
88
92
  originHash,
89
93
  destinationHash,
90
- pathOrigin: firstMigration.from,
94
+ pathOrigin: firstFromMarker,
91
95
  pathDestination: lastMigration.to,
92
96
  },
93
97
  });
@@ -96,18 +100,19 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
96
100
  for (let i = 1; i < pendingMigrations.length; i++) {
97
101
  const previous = pendingMigrations[i - 1]!;
98
102
  const current = pendingMigrations[i]!;
99
- if (previous.to !== current.from) {
103
+ const currentFromMarker = current.from ?? EMPTY_CONTRACT_HASH;
104
+ if (previous.to !== currentFromMarker) {
100
105
  return notOk({
101
106
  code: 'MIGRATION_PATH_NOT_FOUND' as const,
102
107
  summary: 'Migration apply path contains a discontinuity between adjacent migrations',
103
- why: `Migration "${previous.dirName}" ends at ${previous.to}, but next migration "${current.dirName}" starts at ${current.from}`,
108
+ why: `Migration "${previous.dirName}" ends at ${previous.to}, but next migration "${current.dirName}" starts at ${currentFromMarker}`,
104
109
  meta: {
105
110
  originHash,
106
111
  destinationHash,
107
112
  previousDirName: previous.dirName,
108
113
  previousTo: previous.to,
109
114
  currentDirName: current.dirName,
110
- currentFrom: current.from,
115
+ currentFrom: currentFromMarker,
111
116
  discontinuityIndex: i,
112
117
  },
113
118
  });
@@ -135,11 +140,11 @@ export async function executeMigrationApply<TFamilyId extends string, TTargetId
135
140
  allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'] as const,
136
141
  };
137
142
 
138
- // EMPTY_CONTRACT_HASH means "no prior state" — the runner expects origin: null
139
- // for a fresh database (no marker present).
143
+ // Manifest `from === null` means "no prior state" — the runner expects
144
+ // `origin: null` for a fresh database (no marker present).
140
145
  const plan = {
141
146
  targetId,
142
- origin: migration.from === EMPTY_CONTRACT_HASH ? null : { storageHash: migration.from },
147
+ origin: migration.from === null ? null : { storageHash: migration.from },
143
148
  destination: { storageHash: migration.to },
144
149
  operations,
145
150
  };
@@ -432,7 +432,7 @@ export type EmitResult = Result<EmitSuccess, EmitFailure>;
432
432
  */
433
433
  export interface MigrationApplyStep {
434
434
  readonly dirName: string;
435
- readonly from: string;
435
+ readonly from: string | null;
436
436
  readonly to: string;
437
437
  readonly toContract: Contract;
438
438
  readonly operations: readonly MigrationPlanOperation[];
@@ -471,7 +471,7 @@ export interface MigrationApplyOptions {
471
471
  */
472
472
  export interface MigrationApplyAppliedEntry {
473
473
  readonly dirName: string;
474
- readonly from: string;
474
+ readonly from: string | null;
475
475
  readonly to: string;
476
476
  readonly operationsExecuted: number;
477
477
  }