@prisma-next/cli 0.11.0-dev.4 → 0.11.0-dev.41

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 (143) 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 -10
  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 +4 -4
  92. package/dist/migration-cli.mjs.map +1 -1
  93. package/dist/{migration-command-scaffold-BtkunvFQ.mjs → migration-command-scaffold-CNdZl60X.mjs} +5 -5
  94. package/dist/{migration-command-scaffold-BtkunvFQ.mjs.map → migration-command-scaffold-CNdZl60X.mjs.map} +1 -1
  95. package/dist/migration-list-CnYiHrNV.mjs +288 -0
  96. package/dist/migration-list-CnYiHrNV.mjs.map +1 -0
  97. package/dist/{migration-plan-C2jeH1J5.mjs → migration-plan-ulpJu26J.mjs} +340 -88
  98. package/dist/migration-plan-ulpJu26J.mjs.map +1 -0
  99. package/dist/{migrations-CwZMa1Ck.mjs → migrations-C7YTBnLy.mjs} +11 -2
  100. package/dist/migrations-C7YTBnLy.mjs.map +1 -0
  101. package/dist/{output-BlsrGMEF.mjs → output-CUIdfYo5.mjs} +1 -1
  102. package/dist/{output-BlsrGMEF.mjs.map → output-CUIdfYo5.mjs.map} +1 -1
  103. package/dist/{progress-adapter-DFfvZcYL.mjs → progress-adapter-xASh41wr.mjs} +1 -1
  104. package/dist/{progress-adapter-DFfvZcYL.mjs.map → progress-adapter-xASh41wr.mjs.map} +1 -1
  105. package/dist/ref-advancement-CHJ_8HxQ.mjs +50 -0
  106. package/dist/ref-advancement-CHJ_8HxQ.mjs.map +1 -0
  107. package/dist/{types--CqjMdk0.d.mts → types-UWB2-rrw.d.mts} +12 -4
  108. package/dist/types-UWB2-rrw.d.mts.map +1 -0
  109. package/dist/{verify-Bom75OYI.mjs → verify-DX4RQwq4.mjs} +2 -2
  110. package/dist/{verify-Bom75OYI.mjs.map → verify-DX4RQwq4.mjs.map} +1 -1
  111. package/package.json +20 -20
  112. package/src/commands/contract-emit.ts +19 -7
  113. package/src/commands/db-init.ts +48 -2
  114. package/src/commands/db-update.ts +45 -0
  115. package/src/commands/migrate.ts +73 -3
  116. package/src/commands/migration-list.ts +145 -74
  117. package/src/commands/migration-new.ts +0 -6
  118. package/src/commands/migration-plan.ts +359 -128
  119. package/src/commands/ref.ts +46 -6
  120. package/src/control-api/contract-enrichment.ts +6 -42
  121. package/src/control-api/operations/contract-emit.ts +7 -4
  122. package/src/control-api/types.ts +7 -0
  123. package/src/migration-cli.ts +4 -4
  124. package/src/utils/cli-errors.ts +224 -0
  125. package/src/utils/command-helpers.ts +1 -1
  126. package/src/utils/formatters/migration-list-render.ts +171 -0
  127. package/src/utils/formatters/migration-list-styler.ts +56 -0
  128. package/src/utils/formatters/migrations.ts +25 -0
  129. package/src/utils/plan-resolution.ts +257 -0
  130. package/src/utils/ref-advancement.ts +68 -0
  131. package/dist/cli-errors-Czmx92Zy.d.mts +0 -3
  132. package/dist/cli-errors-Djtz98Vm.mjs +0 -71
  133. package/dist/cli-errors-Djtz98Vm.mjs.map +0 -1
  134. package/dist/command-helpers-DtavI0wJ.mjs.map +0 -1
  135. package/dist/commands/migration-list.mjs.map +0 -1
  136. package/dist/contract-emit-bcrpT-wD.mjs.map +0 -1
  137. package/dist/contract-emit-uwT-Mj8-.mjs.map +0 -1
  138. package/dist/contract-enrichment-Dani0mMW.mjs.map +0 -1
  139. package/dist/migration-plan-C2jeH1J5.mjs.map +0 -1
  140. package/dist/migrations-CwZMa1Ck.mjs.map +0 -1
  141. package/dist/terminal-ui-BiB_8KNo.mjs +0 -379
  142. package/dist/terminal-ui-BiB_8KNo.mjs.map +0 -1
  143. package/dist/types--CqjMdk0.d.mts.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"command-helpers-DtavI0wJ.mjs","names":["LEFT_COLUMN_WIDTH","createPrismaNextBadge","formatHeaderLine","formatReadMoreLine","APP_SPACE_ID"],"sources":["../src/utils/formatters/styled.ts","../src/utils/formatters/help.ts","../src/utils/result-handler.ts","../src/utils/global-flags.ts","../src/utils/command-helpers.ts"],"sourcesContent":["import { blue, bold, cyan, green } from 'colorette';\nimport type { Command } from 'commander';\nimport stringWidth from 'string-width';\nimport stripAnsi from 'strip-ansi';\n\nimport type { GlobalFlags } from '../global-flags';\nimport { createColorFormatter, formatDim } from './helpers';\n\n// ============================================================================\n// Styled Output Formatters\n// ============================================================================\n\n/**\n * Fixed width for left column in help output.\n */\nconst LEFT_COLUMN_WIDTH = 20;\n\n/**\n * Creates an arrow segment badge with green background and white text.\n * Body: green background with white \"prisma-next\" text\n * Tip: dark grey arrow pointing right (Powerline separator)\n */\nfunction createPrismaNextBadge(useColor: boolean): string {\n if (!useColor) {\n return 'prisma-next';\n }\n return bold('prisma-next');\n}\n\n/**\n * Creates a padding function.\n */\nfunction createPadFunction(): (s: string, w: number) => string {\n return (s: string, w: number) => s + ' '.repeat(Math.max(0, w - s.length));\n}\n\n/**\n * Formats a header line: brand + operation + intent\n */\nfunction formatHeaderLine(options: {\n readonly brand: string;\n readonly operation: string;\n readonly intent: string;\n}): string {\n if (options.operation) {\n return `${options.brand} ${options.operation} → ${options.intent}`;\n }\n return `${options.brand} ${options.intent}`;\n}\n\n/**\n * Formats a \"Read more\" URL line.\n * The \"Read more\" label is in default color (not cyan), and the URL is blue.\n */\nfunction formatReadMoreLine(options: {\n readonly url: string;\n readonly maxLabelWidth: number;\n readonly useColor: boolean;\n readonly formatDimText: (text: string) => string;\n}): string {\n const pad = createPadFunction();\n const labelPadded = pad('Read more', options.maxLabelWidth);\n // Label is default color (not cyan)\n const valueColored = options.useColor ? blue(options.url) : options.url;\n return `${options.formatDimText('│')} ${labelPadded} ${valueColored}`;\n}\n\n/**\n * Pads text to a fixed width, accounting for ANSI escape codes.\n * Uses string-width to measure the actual display width.\n */\nexport function padToFixedWidth(text: string, width: number): string {\n const actualWidth = stringWidth(text);\n const padding = Math.max(0, width - actualWidth);\n return text + ' '.repeat(padding);\n}\n\n/**\n * Renders a command tree structure.\n * Handles both single-level (subcommands of a command) and multi-level (top-level commands with subcommands) trees.\n */\nexport function renderCommandTree(options: {\n readonly commands: readonly Command[];\n readonly useColor: boolean;\n readonly formatDimText: (text: string) => string;\n readonly hasItemsAfter: boolean;\n readonly continuationPrefix?: string;\n}): string[] {\n const { commands, useColor, formatDimText, hasItemsAfter, continuationPrefix } = options;\n const lines: string[] = [];\n\n if (commands.length === 0) {\n return lines;\n }\n\n // Format each command\n for (let i = 0; i < commands.length; i++) {\n const cmd = commands[i];\n if (!cmd) continue;\n\n const subcommands = cmd.commands.filter((subcmd) => !subcmd.name().startsWith('_'));\n const isLastCommand = i === commands.length - 1;\n\n if (subcommands.length > 0) {\n // Command with subcommands - show command name, then tree-structured subcommands\n const treeChar = isLastCommand && !hasItemsAfter ? formatDimText('└') : formatDimText('├');\n // For top-level command, pad name to fixed width (accounting for \"| |-- \" = 5 chars)\n const treePrefix = `${treeChar}─ `;\n const treePrefixWidth = stringWidth(stripAnsi(treePrefix));\n const remainingWidth = LEFT_COLUMN_WIDTH - treePrefixWidth;\n const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);\n const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;\n lines.push(`${formatDimText('│')} ${treePrefix}${commandNameColored}`);\n\n for (let j = 0; j < subcommands.length; j++) {\n const subcmd = subcommands[j];\n if (!subcmd) continue;\n\n const isLastSubcommand = j === subcommands.length - 1;\n const shortDescription = subcmd.description() || '';\n\n // Use tree characters: -- for last subcommand, |-- for others\n const treeChar = isLastSubcommand ? '└' : '├';\n const continuation =\n continuationPrefix ??\n (isLastCommand && isLastSubcommand && !hasItemsAfter ? ' ' : formatDimText('│'));\n // For subcommands, account for \"| | -- \" = 7 chars (or \"| -- \" = 6 chars if continuation is space)\n const continuationStr = continuation === ' ' ? ' ' : continuation;\n const subTreePrefix = `${continuationStr} ${formatDimText(treeChar)}─ `;\n const subTreePrefixWidth = stringWidth(stripAnsi(subTreePrefix));\n const subRemainingWidth = LEFT_COLUMN_WIDTH - subTreePrefixWidth;\n const subcommandNamePadded = padToFixedWidth(subcmd.name(), subRemainingWidth);\n const subcommandNameColored = useColor ? cyan(subcommandNamePadded) : subcommandNamePadded;\n lines.push(\n `${formatDimText('│')} ${subTreePrefix}${subcommandNameColored} ${shortDescription}`,\n );\n }\n } else {\n // Standalone command - show command name and description on same line\n const treeChar = isLastCommand && !hasItemsAfter ? formatDimText('└') : formatDimText('├');\n const treePrefix = `${treeChar}─ `;\n const treePrefixWidth = stringWidth(stripAnsi(treePrefix));\n const remainingWidth = LEFT_COLUMN_WIDTH - treePrefixWidth;\n const commandNamePadded = padToFixedWidth(cmd.name(), remainingWidth);\n const commandNameColored = useColor ? cyan(commandNamePadded) : commandNamePadded;\n const shortDescription = cmd.description() || '';\n lines.push(`${formatDimText('│')} ${treePrefix}${commandNameColored} ${shortDescription}`);\n }\n }\n\n return lines;\n}\n\n/**\n * Formats the header in the new experimental visual style.\n * This header appears at the start of command output, showing the operation,\n * intent, documentation link, and parameters.\n */\nexport function formatStyledHeader(options: {\n readonly command: string;\n readonly description: string;\n readonly url?: string;\n readonly details: ReadonlyArray<{ readonly label: string; readonly value: string }>;\n readonly flags: GlobalFlags;\n}): string {\n const lines: string[] = [];\n const useColor = options.flags.color !== false;\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Header: arrow + operation badge + intent\n const brand = createPrismaNextBadge(useColor);\n // Use full command path (e.g., \"contract emit\" not just \"emit\")\n const operation = useColor ? bold(options.command) : options.command;\n const intent = formatDimText(options.description);\n lines.push(formatHeaderLine({ brand, operation, intent }));\n lines.push(formatDimText('│')); // Vertical line separator between command and params\n\n // Format details using fixed left column width (same style as help text options)\n for (const detail of options.details) {\n // Add colon to label, then pad to fixed width using padToFixedWidth for ANSI-aware padding\n const labelWithColon = `${detail.label}:`;\n const labelPadded = padToFixedWidth(labelWithColon, LEFT_COLUMN_WIDTH);\n const labelColored = useColor ? cyan(labelPadded) : labelPadded;\n lines.push(`${formatDimText('│')} ${labelColored} ${detail.value}`);\n }\n\n // Add \"Read more\" URL if present (same style as help text)\n if (options.url) {\n lines.push(formatDimText('│')); // Separator line before \"Read more\"\n lines.push(\n formatReadMoreLine({\n url: options.url,\n maxLabelWidth: LEFT_COLUMN_WIDTH,\n useColor,\n formatDimText,\n }),\n );\n }\n\n lines.push(formatDimText('└'));\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/**\n * Formats a success message in the styled output format.\n */\nexport function formatSuccessMessage(flags: GlobalFlags): string {\n const useColor = flags.color !== false;\n const formatGreen = createColorFormatter(useColor, green);\n return `${formatGreen('✔')} Success`;\n}\n","import { blue, bold, cyan, dim, green, magenta } from 'colorette';\nimport type { Command } from 'commander';\nimport wrapAnsi from 'wrap-ansi';\n\nimport { getCommandExamples, getCommandSeeAlso, getLongDescription } from '../command-helpers';\nimport type { GlobalFlags } from '../global-flags';\nimport { formatDim } from './helpers';\nimport { padToFixedWidth, renderCommandTree } from './styled';\n\n// ============================================================================\n// Help Output Formatters\n// ============================================================================\n\n/**\n * Fixed width for left column in help output.\n * Must match the value in styled.ts.\n */\nconst LEFT_COLUMN_WIDTH = 20;\n\n/**\n * Minimum width for right column wrapping in help output.\n */\nconst RIGHT_COLUMN_MIN_WIDTH = 40;\n\n/**\n * Maximum width for right column wrapping in help output (when terminal is wide enough).\n */\nconst RIGHT_COLUMN_MAX_WIDTH = 90;\n\n/**\n * Gets the terminal width, or returns a default if not available.\n */\nfunction getTerminalWidth(): number {\n // Help text goes to stderr, so prefer stderr columns. Fall back to stdout, then CLI_WIDTH env.\n const terminalWidth = process.stderr.columns || process.stdout.columns;\n const envWidth = Number.parseInt(process.env['CLI_WIDTH'] || '', 10);\n return terminalWidth || (Number.isFinite(envWidth) ? envWidth : 80);\n}\n\n/**\n * Calculates the available width for the right column based on terminal width.\n */\nfunction calculateRightColumnWidth(): number {\n const terminalWidth = getTerminalWidth();\n const availableWidth = terminalWidth - 2 - LEFT_COLUMN_WIDTH - 2;\n return Math.max(RIGHT_COLUMN_MIN_WIDTH, Math.min(availableWidth, RIGHT_COLUMN_MAX_WIDTH));\n}\n\n/**\n * Creates the CLI brand badge.\n */\nfunction createPrismaNextBadge(useColor: boolean): string {\n return useColor ? bold('prisma-next') : 'prisma-next';\n}\n\n/**\n * Formats a header line: brand + operation + intent\n */\nfunction formatHeaderLine(options: {\n readonly brand: string;\n readonly operation: string;\n readonly intent: string;\n}): string {\n if (options.operation) {\n return `${options.brand} ${options.operation} → ${options.intent}`;\n }\n return `${options.brand} ${options.intent}`;\n}\n\n/**\n * Wraps text to fit within a specified width using wrap-ansi.\n */\nfunction wrapTextAnsi(text: string, width: number): string[] {\n const wrapped = wrapAnsi(text, width, { hard: false, trim: true });\n return wrapped.split('\\n');\n}\n\n/**\n * Formats a default value as \"default: <value>\" with dimming.\n */\nfunction formatDefaultValue(value: unknown, useColor: boolean): string {\n const valueStr = String(value);\n const defaultText = `default: ${valueStr}`;\n return useColor ? dim(defaultText) : defaultText;\n}\n\n/**\n * Formats a \"Read more\" URL line.\n */\nfunction formatReadMoreLine(options: {\n readonly url: string;\n readonly maxLabelWidth: number;\n readonly useColor: boolean;\n readonly formatDimText: (text: string) => string;\n}): string {\n const labelPadded = `Read more${' '.repeat(Math.max(0, options.maxLabelWidth - 'Read more'.length))}`;\n const valueColored = options.useColor ? blue(options.url) : options.url;\n return `${options.formatDimText('│')} ${labelPadded} ${valueColored}`;\n}\n\n/**\n * Formats multiline description with \"Prisma Next\" in green.\n */\nfunction formatMultilineDescription(options: {\n readonly descriptionLines: readonly string[];\n readonly useColor: boolean;\n readonly formatDimText: (text: string) => string;\n}): string[] {\n const lines: string[] = [];\n const formatGreen = (text: string) => (options.useColor ? green(text) : text);\n\n const rightColumnWidth = calculateRightColumnWidth();\n const totalWidth = 2 + LEFT_COLUMN_WIDTH + 2 + rightColumnWidth;\n const wrapWidth = totalWidth - 2;\n\n for (const descLine of options.descriptionLines) {\n const formattedLine = descLine.replace(/Prisma Next/g, (match) => formatGreen(match));\n const wrappedLines = wrapTextAnsi(formattedLine, wrapWidth);\n for (const wrappedLine of wrappedLines) {\n lines.push(`${options.formatDimText('│')} ${wrappedLine}`);\n }\n }\n return lines;\n}\n\n/**\n * Maps command paths to their documentation URLs.\n */\nfunction getCommandDocsUrl(commandPath: string): string | undefined {\n const docsMap: Record<string, string> = {\n 'contract emit': 'https://pris.ly/contract-emit',\n 'contract infer': 'https://pris.ly/contract-infer',\n 'db schema': 'https://pris.ly/db-schema',\n 'db verify': 'https://pris.ly/db-verify',\n 'db update': 'https://pris.ly/db-update',\n 'migration plan': 'https://pris.ly/migration-plan',\n migrate: 'https://pris.ly/migrate',\n 'migration show': 'https://pris.ly/migration-show',\n 'migration status': 'https://pris.ly/migration-status',\n };\n return docsMap[commandPath];\n}\n\n/**\n * Builds the full command path from a command and its parents.\n */\nfunction buildCommandPath(command: Command): string {\n const parts: string[] = [];\n let current: Command | undefined = command;\n while (current && current.name() !== 'prisma-next') {\n parts.unshift(current.name());\n current = current.parent ?? undefined;\n }\n return parts.join(' ');\n}\n\n/**\n * Formats help output for a command using the styled format.\n */\nexport function formatCommandHelp(options: {\n readonly command: Command;\n readonly flags: GlobalFlags;\n}): string {\n const { command, flags } = options;\n const lines: string[] = [];\n const useColor = flags.color !== false;\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Build full command path (e.g., \"db verify\")\n const commandPath = buildCommandPath(command);\n const shortDescription = command.description() || '';\n const longDescription = getLongDescription(command);\n\n // Include positional arguments in the header line\n const argsSuffix = command.registeredArguments\n .map((arg) => (arg.required ? `<${arg.name()}>` : `[${arg.name()}]`))\n .join(' ');\n const brand = createPrismaNextBadge(useColor);\n const commandWithArgs = argsSuffix ? `${commandPath} ${argsSuffix}` : commandPath;\n const operation = useColor ? bold(commandWithArgs) : commandWithArgs;\n const intent = formatDimText(shortDescription);\n lines.push(formatHeaderLine({ brand, operation, intent }));\n lines.push(formatDimText('│'));\n\n // Extract options and format them\n const optionsList = command.options.map((opt) => {\n const description = opt.description || '';\n // Commander.js stores default value in defaultValue property\n const defaultValue = (opt as { defaultValue?: unknown }).defaultValue;\n return { flags: opt.flags, description, defaultValue };\n });\n\n // Extract subcommands if any\n const subcommands = command.commands.filter((cmd) => !cmd.name().startsWith('_'));\n\n // Format subcommands as a tree if present\n if (subcommands.length > 0) {\n const hasItemsAfter = optionsList.length > 0;\n const treeLines = renderCommandTree({\n commands: subcommands,\n useColor,\n formatDimText,\n hasItemsAfter,\n });\n lines.push(...treeLines);\n }\n\n // Add separator between subcommands and options if both exist\n if (subcommands.length > 0 && optionsList.length > 0) {\n lines.push(formatDimText('│'));\n }\n\n // Format options with fixed width, wrapping, and default values\n if (optionsList.length > 0) {\n for (const opt of optionsList) {\n // Format flag with fixed 30-char width\n const flagsPadded = padToFixedWidth(opt.flags, LEFT_COLUMN_WIDTH);\n let flagsColored = flagsPadded;\n if (useColor) {\n // Color placeholders in magenta, then wrap in cyan\n flagsColored = flagsPadded.replace(/(<[^>]+>)/g, (match: string) => magenta(match));\n flagsColored = cyan(flagsColored);\n }\n\n // Wrap description based on terminal width\n const rightColumnWidth = calculateRightColumnWidth();\n const wrappedDescription = wrapTextAnsi(opt.description, rightColumnWidth);\n\n // First line: flag + first line of description\n lines.push(`${formatDimText('│')} ${flagsColored} ${wrappedDescription[0] || ''}`);\n\n // Continuation lines: empty label (30 spaces) + wrapped lines\n for (let i = 1; i < wrappedDescription.length; i++) {\n const emptyLabel = ' '.repeat(LEFT_COLUMN_WIDTH);\n lines.push(`${formatDimText('│')} ${emptyLabel} ${wrappedDescription[i] || ''}`);\n }\n\n // Default value line (if present)\n if (opt.defaultValue !== undefined) {\n const emptyLabel = ' '.repeat(LEFT_COLUMN_WIDTH);\n const defaultText = formatDefaultValue(opt.defaultValue, useColor);\n lines.push(`${formatDimText('│')} ${emptyLabel} ${defaultText}`);\n }\n }\n }\n\n // Add docs URL if available (with separator line before it)\n const docsUrl = getCommandDocsUrl(commandPath);\n if (docsUrl) {\n lines.push(formatDimText('│')); // Separator line between params and docs\n lines.push(\n formatReadMoreLine({\n url: docsUrl,\n maxLabelWidth: LEFT_COLUMN_WIDTH,\n useColor,\n formatDimText,\n }),\n );\n }\n\n // Examples (copy-pastable)\n const examples = getCommandExamples(command);\n if (examples && examples.length > 0) {\n lines.push(formatDimText('│'));\n lines.push(`${formatDimText('│')} ${formatDimText('Examples:')}`);\n for (const example of examples) {\n lines.push(`${formatDimText('│')} ${useColor ? dim('$') : '$'} ${example}`);\n }\n }\n\n // See also (cross-references to related commands)\n const seeAlso = getCommandSeeAlso(command);\n if (seeAlso && seeAlso.length > 0) {\n lines.push(formatDimText('│'));\n lines.push(`${formatDimText('│')} ${formatDimText('See also:')}`);\n for (const ref of seeAlso) {\n lines.push(`${formatDimText('│')} ${ref.verb} ${formatDimText(ref.oneLiner)}`);\n }\n }\n\n // Multi-line description (if present) - shown after all other content\n if (longDescription) {\n lines.push(formatDimText('│'));\n const descriptionLines = longDescription.split('\\n').filter((line) => line.trim().length > 0);\n lines.push(...formatMultilineDescription({ descriptionLines, useColor, formatDimText }));\n }\n\n lines.push(formatDimText('└'));\n\n return `${lines.join('\\n')}\\n`;\n}\n\n/**\n * Formats help output for the root program using the styled format.\n */\nexport function formatRootHelp(options: {\n readonly program: Command;\n readonly flags: GlobalFlags;\n}): string {\n const { program, flags } = options;\n const lines: string[] = [];\n const useColor = flags.color !== false;\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n // Header: \"prisma-next -> Manage your data layer\"\n const brand = createPrismaNextBadge(useColor);\n const shortDescription = 'Manage your data layer';\n const intent = formatDimText(shortDescription);\n lines.push(formatHeaderLine({ brand, operation: '', intent }));\n lines.push(formatDimText('│')); // Vertical line separator after header\n\n // Extract top-level commands (exclude hidden commands starting with '_' and the 'help' command)\n const topLevelCommands = program.commands.filter(\n (cmd) => !cmd.name().startsWith('_') && cmd.name() !== 'help',\n );\n\n // Extract global options (needed to determine if last command)\n const globalOptions = program.options.map((opt) => {\n const description = opt.description || '';\n // Commander.js stores default value in defaultValue property\n const defaultValue = (opt as { defaultValue?: unknown }).defaultValue;\n return { flags: opt.flags, description, defaultValue };\n });\n\n // Build command tree\n if (topLevelCommands.length > 0) {\n const hasItemsAfter = globalOptions.length > 0;\n const treeLines = renderCommandTree({\n commands: topLevelCommands,\n useColor,\n formatDimText,\n hasItemsAfter,\n });\n lines.push(...treeLines);\n }\n\n // Add separator between commands and options if both exist\n if (topLevelCommands.length > 0 && globalOptions.length > 0) {\n lines.push(formatDimText('│'));\n }\n\n // Format global options with fixed width, wrapping, and default values\n if (globalOptions.length > 0) {\n for (const opt of globalOptions) {\n // Format flag with fixed 30-char width\n const flagsPadded = padToFixedWidth(opt.flags, LEFT_COLUMN_WIDTH);\n let flagsColored = flagsPadded;\n if (useColor) {\n // Color placeholders in magenta, then wrap in cyan\n flagsColored = flagsPadded.replace(/(<[^>]+>)/g, (match: string) => magenta(match));\n flagsColored = cyan(flagsColored);\n }\n\n // Wrap description based on terminal width\n const rightColumnWidth = calculateRightColumnWidth();\n const wrappedDescription = wrapTextAnsi(opt.description, rightColumnWidth);\n\n // First line: flag + first line of description\n lines.push(`${formatDimText('│')} ${flagsColored} ${wrappedDescription[0] || ''}`);\n\n // Continuation lines: empty label (30 spaces) + wrapped lines\n for (let i = 1; i < wrappedDescription.length; i++) {\n const emptyLabel = ' '.repeat(LEFT_COLUMN_WIDTH);\n lines.push(`${formatDimText('│')} ${emptyLabel} ${wrappedDescription[i] || ''}`);\n }\n\n // Default value line (if present)\n if (opt.defaultValue !== undefined) {\n const emptyLabel = ' '.repeat(LEFT_COLUMN_WIDTH);\n const defaultText = formatDefaultValue(opt.defaultValue, useColor);\n lines.push(`${formatDimText('│')} ${emptyLabel} ${defaultText}`);\n }\n }\n }\n\n // Multi-line description (white, not dimmed, with \"Prisma Next\" in green) - shown at bottom\n const formatGreen = (text: string) => (useColor ? green(text) : text);\n const descriptionLines = [\n `Use ${formatGreen('Prisma Next')} to define your data layer as a contract. Sign your database and application with the same contract to guarantee compatibility. Plan and apply migrations to safely evolve your schema.`,\n ];\n if (descriptionLines.length > 0) {\n lines.push(formatDimText('│')); // Separator line before description\n lines.push(...formatMultilineDescription({ descriptionLines, useColor, formatDimText }));\n }\n\n lines.push(formatDimText('└'));\n\n return `${lines.join('\\n')}\\n`;\n}\n","import type { Result } from '@prisma-next/utils/result';\nimport type { CliStructuredError } from './cli-errors';\nimport { formatErrorJson, formatErrorOutput } from './formatters/errors';\nimport type { GlobalFlags } from './global-flags';\nimport type { TerminalUI } from './terminal-ui';\n\n/**\n * Processes a CLI command result, handling both success and error cases.\n * Formats output appropriately and returns the exit code.\n * Never throws - returns exit code for commands to use with process.exit().\n *\n * Error output:\n * - JSON mode: JSON error to stdout (piped) via ui.output(), human sees nothing on stderr.\n * - Interactive: human-readable error to stderr.\n */\nexport function handleResult<T>(\n result: Result<T, CliStructuredError>,\n flags: GlobalFlags,\n ui: TerminalUI,\n onSuccess?: (value: T) => void,\n): number {\n if (result.ok) {\n if (onSuccess) {\n onSuccess(result.value);\n }\n return 0;\n }\n\n // Convert to CLI envelope\n const envelope = result.failure.toEnvelope();\n\n if (flags.json) {\n // JSON error → stdout only\n ui.output(formatErrorJson(envelope));\n } else {\n // Human-readable error → stderr\n ui.error(formatErrorOutput(envelope, flags));\n }\n\n // Infer exit code from error domain: CLI errors = 2, RUN errors = 1\n const exitCode = result.failure.domain === 'CLI' ? 2 : 1;\n return exitCode;\n}\n","import { notOk } from '@prisma-next/utils/result';\nimport { CliStructuredError, errorInvalidOutputFormat, errorOutputFormatMutex } from './cli-errors';\nimport { isCI } from './is-ci';\nimport { handleResult } from './result-handler';\nimport { createTerminalUI } from './terminal-ui';\n\nexport type OutputFormat = 'pretty' | 'json';\n\nexport interface GlobalFlags {\n readonly format: OutputFormat;\n readonly explicitFormat: boolean;\n readonly json?: boolean;\n readonly quiet?: boolean;\n readonly verbose?: number;\n readonly color?: boolean;\n readonly interactive?: boolean;\n readonly yes?: boolean;\n}\n\n/**\n * Common options parsed by Commander.js for every command.\n * Extend this for command-specific options instead of duplicating these fields.\n */\nexport interface CommonCommandOptions {\n readonly format?: string;\n readonly json?: string | boolean;\n readonly quiet?: boolean;\n readonly q?: boolean;\n readonly verbose?: boolean;\n readonly v?: boolean;\n readonly trace?: boolean;\n readonly color?: boolean;\n readonly 'no-color'?: boolean;\n readonly interactive?: boolean;\n readonly 'no-interactive'?: boolean;\n readonly yes?: boolean;\n readonly y?: boolean;\n}\n\nfunction isJsonFlagSet(json: string | boolean | undefined): boolean {\n return json === true;\n}\n\ninterface ResolvedOutputFormat {\n readonly format: OutputFormat;\n readonly explicitFormat: boolean;\n}\n\nfunction resolveOutputFormat(options: CommonCommandOptions): ResolvedOutputFormat {\n const formatOption = options.format;\n const jsonFlag = isJsonFlagSet(options.json);\n\n if (formatOption !== undefined) {\n if (formatOption !== 'pretty' && formatOption !== 'json') {\n throw errorInvalidOutputFormat(formatOption);\n }\n if (jsonFlag && formatOption === 'pretty') {\n throw errorOutputFormatMutex();\n }\n return { format: formatOption, explicitFormat: true };\n }\n\n if (jsonFlag) {\n return { format: 'json', explicitFormat: false };\n }\n\n if (!process.stdout.isTTY) {\n return { format: 'json', explicitFormat: false };\n }\n\n return { format: 'pretty', explicitFormat: false };\n}\n\nfunction inferJsonModeForParseError(options: CommonCommandOptions): boolean {\n if (options.format === 'json') {\n return true;\n }\n if (isJsonFlagSet(options.json) && options.format !== 'pretty') {\n return true;\n }\n if (options.format !== undefined) {\n return false;\n }\n return !process.stdout.isTTY;\n}\n\nfunction emitGlobalFlagParseError(error: CliStructuredError, options: CommonCommandOptions): never {\n const jsonMode = inferJsonModeForParseError(options);\n const flags: GlobalFlags = {\n format: jsonMode ? 'json' : 'pretty',\n explicitFormat: false,\n ...(jsonMode ? { json: true } : {}),\n color: false,\n verbose: 0,\n interactive: false,\n };\n const ui = createTerminalUI(flags);\n const exitCode = handleResult(notOk(error), flags, ui);\n process.exit(exitCode);\n}\n\n/**\n * Parses global flags from CLI options.\n * Handles verbosity flags (-v, --trace), output format (--format, --json),\n * quiet mode, color, interactivity (--interactive/--no-interactive), and\n * auto-accept (-y/--yes).\n *\n * On invalid or conflicting format flags, prints a structured CLI error\n * envelope and exits with code 2.\n */\nexport function parseGlobalFlagsOrExit(options: CommonCommandOptions): GlobalFlags {\n try {\n return parseGlobalFlags(options);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n emitGlobalFlagParseError(error, options);\n }\n throw error;\n }\n}\n\n/**\n * Parses global flags from CLI options.\n * Handles verbosity flags (-v, --trace), output format (--format, --json),\n * quiet mode, color, interactivity (--interactive/--no-interactive), and\n * auto-accept (-y/--yes).\n *\n * Throws {@link CliStructuredError} for invalid or conflicting format flags.\n */\nexport function parseGlobalFlags(options: CommonCommandOptions): GlobalFlags {\n const { format, explicitFormat } = resolveOutputFormat(options);\n const flags: {\n format: OutputFormat;\n explicitFormat: boolean;\n json?: boolean;\n quiet?: boolean;\n verbose?: number;\n color?: boolean;\n interactive?: boolean;\n yes?: boolean;\n } = { format, explicitFormat };\n\n if (format === 'json') {\n flags.json = true;\n }\n\n if (options.quiet || options.q) {\n flags.quiet = true;\n }\n\n if (options.trace || process.env['PRISMA_NEXT_TRACE'] === '1') {\n flags.verbose = 2;\n } else if (options.verbose || options.v || process.env['PRISMA_NEXT_DEBUG'] === '1') {\n flags.verbose = 1;\n } else {\n flags.verbose = 0;\n }\n\n if (process.env['NO_COLOR'] || flags.json) {\n flags.color = false;\n } else if (options['no-color']) {\n flags.color = false;\n } else if (options.color !== undefined) {\n flags.color = options.color;\n } else {\n flags.color = process.stdout.isTTY && !isCI();\n }\n\n if (options['no-interactive']) {\n flags.interactive = false;\n } else if (options.interactive !== undefined) {\n flags.interactive = options.interactive;\n } else {\n flags.interactive = !!process.stdout.isTTY;\n }\n\n if (options.yes || options.y) {\n flags.yes = true;\n }\n\n return flags as GlobalFlags;\n}\n","import { readFile } from 'node:fs/promises';\nimport type { ControlTargetDescriptor } from '@prisma-next/framework-components/control';\nimport { hasMigrations } from '@prisma-next/framework-components/control';\nimport type { NoInvariantPathStructuralEdge } from '@prisma-next/migration-tools/errors';\nimport type { MigrationEdge, MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport { readMigrationsDir } from '@prisma-next/migration-tools/io';\nimport type { PathDecision } from '@prisma-next/migration-tools/migration-graph';\nimport { reconstructGraph } from '@prisma-next/migration-tools/migration-graph';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport { APP_SPACE_ID, spaceMigrationDirectory } from '@prisma-next/migration-tools/spaces';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Command } from 'commander';\nimport { relative, resolve } from 'pathe';\nimport { errorRuntime } from './cli-errors';\nimport { formatCommandHelp } from './formatters/help';\nimport type { CommonCommandOptions } from './global-flags';\nimport { parseGlobalFlags } from './global-flags';\n\nconst longDescriptions = new WeakMap<Command, string>();\nconst commandExamples = new WeakMap<Command, readonly string[]>();\nconst commandSeeAlso = new WeakMap<\n Command,\n readonly { readonly verb: string; readonly oneLiner: string }[]\n>();\n\n/**\n * Sets both short and long descriptions for a command.\n * The short description is used in command trees and headers.\n * The long description is shown at the bottom of help output.\n */\nexport function setCommandDescriptions(\n command: Command,\n shortDescription: string,\n longDescription?: string,\n): Command {\n command.description(shortDescription);\n if (longDescription) {\n longDescriptions.set(command, longDescription);\n }\n return command;\n}\n\n/**\n * Sets copy-pastable examples for a command, shown in help text.\n */\nexport function setCommandExamples(command: Command, examples: readonly string[]): Command {\n commandExamples.set(command, examples);\n return command;\n}\n\n/**\n * Gets the long description from a command if it was set via setCommandDescriptions.\n */\nexport function getLongDescription(command: Command): string | undefined {\n return longDescriptions.get(command);\n}\n\n/**\n * Gets examples from a command if set via setCommandExamples.\n */\nexport function getCommandExamples(command: Command): readonly string[] | undefined {\n return commandExamples.get(command);\n}\n\n/**\n * Sets cross-references to related commands, rendered in a \"See also\"\n * section below the Examples block in help output.\n */\nexport function setCommandSeeAlso(\n command: Command,\n refs: readonly { readonly verb: string; readonly oneLiner: string }[],\n): Command {\n commandSeeAlso.set(command, refs);\n return command;\n}\n\n/**\n * Gets the see-also cross-references from a command.\n */\nexport function getCommandSeeAlso(\n command: Command,\n): readonly { readonly verb: string; readonly oneLiner: string }[] | undefined {\n return commandSeeAlso.get(command);\n}\n\n/**\n * Shared CLI options interface for migration commands (db init, db update).\n * These are the Commander.js parsed options common to both commands.\n */\nexport interface MigrationCommandOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly dryRun?: boolean;\n}\n\n/**\n * Resolves the absolute path to contract.json from the config.\n */\nexport function resolveContractPath(config: { contract?: { output?: string } }): string {\n if (config.contract?.output === undefined) {\n throw errorRuntime('config.contract.output is required to resolve the contract path', {\n why: 'CLI commands read the emitted contract from config.contract.output; the config has no value to read.',\n fix: 'Ensure your prisma-next.config.ts goes through `defineConfig()`, which normalises a default output when the provider supplies an input path, or set `contract.output` explicitly.',\n });\n }\n return resolve(config.contract.output);\n}\n\n/**\n * Resolves the migrations directory and config path from CLI options.\n * Shared by migrate, migration-plan, and migration-status.\n *\n * - `migrationsDir` is the project's top-level `migrations/` directory\n * (the root that the aggregate loader walks for every contract space).\n * - `appMigrationsDir` is the app subspace directory under it\n * (`<migrationsDir>/<APP_SPACE_ID>/`). Every per-app reader / writer\n * (`migration new`, `migration plan`, `migrate`,\n * `migration status`, `migration show`, `migration ref`) operates on\n * this directory. Extensions own their own `migrations/<spaceId>/`.\n * - `refsDir` is the app's refs directory (`<appMigrationsDir>/refs/`).\n * The framework does not maintain refs at the migrations root.\n */\nexport function resolveMigrationPaths(\n configOption: string | undefined,\n config: { migrations?: { dir?: string } },\n): {\n configPath: string;\n migrationsDir: string;\n migrationsRelative: string;\n appMigrationsDir: string;\n appMigrationsRelative: string;\n refsDir: string;\n} {\n const configPath = configOption\n ? relative(process.cwd(), resolve(configOption))\n : 'prisma-next.config.ts';\n const migrationsDir = resolve(\n configOption ? resolve(configOption, '..') : process.cwd(),\n config.migrations?.dir ?? 'migrations',\n );\n const migrationsRelative = relative(process.cwd(), migrationsDir);\n const appMigrationsDir = spaceMigrationDirectory(migrationsDir, APP_SPACE_ID);\n const appMigrationsRelative = relative(process.cwd(), appMigrationsDir);\n const refsDir = resolve(appMigrationsDir, 'refs');\n return {\n configPath,\n migrationsDir,\n migrationsRelative,\n appMigrationsDir,\n appMigrationsRelative,\n refsDir,\n };\n}\n\n/**\n * Slim representation of a PathDecision for CLI JSON output.\n * Strips internal fields (createdAt, labels) from path entries.\n */\nexport interface PathDecisionResult {\n readonly fromHash: string;\n readonly toHash: string;\n readonly alternativeCount: number;\n readonly tieBreakReasons: readonly string[];\n readonly refName?: string;\n readonly requiredInvariants: readonly string[];\n readonly satisfiedInvariants: readonly string[];\n readonly selectedPath: readonly {\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly invariants: readonly string[];\n }[];\n}\n\nexport function collectDeclaredInvariants(graph: MigrationGraph): ReadonlySet<string> {\n const declared = new Set<string>();\n for (const edges of graph.forwardChain.values()) {\n for (const edge of edges) {\n for (const inv of edge.invariants) {\n declared.add(inv);\n }\n }\n }\n return declared;\n}\n\n/**\n * Maps a `MigrationEdge` to the structural-edge shape used in the\n * `MIGRATION.NO_INVARIANT_PATH` error envelope. Shared between\n * `migrate` and `migration status` so both commands surface\n * the same JSON wire shape when an invariant-aware route is unsatisfiable.\n */\nexport function toStructuralEdge(edge: MigrationEdge): NoInvariantPathStructuralEdge {\n return {\n dirName: edge.dirName,\n migrationHash: edge.migrationHash,\n from: edge.from,\n to: edge.to,\n invariants: edge.invariants,\n };\n}\n\n/**\n * Maps a PathDecision to the slim CLI output representation.\n */\nexport function toPathDecisionResult(decision: PathDecision): PathDecisionResult {\n return {\n fromHash: decision.fromHash,\n toHash: decision.toHash,\n alternativeCount: decision.alternativeCount,\n tieBreakReasons: decision.tieBreakReasons,\n requiredInvariants: decision.requiredInvariants ?? [],\n satisfiedInvariants: decision.satisfiedInvariants ?? [],\n ...ifDefined('refName', decision.refName),\n selectedPath: decision.selectedPath.map((entry) => ({\n dirName: entry.dirName,\n migrationHash: entry.migrationHash,\n from: entry.from,\n to: entry.to,\n invariants: entry.invariants,\n })),\n };\n}\n\nexport function targetSupportsMigrations(target: ControlTargetDescriptor<string, string>): boolean {\n return hasMigrations(target);\n}\n\nexport function getTargetMigrations(target: ControlTargetDescriptor<string, string>) {\n return hasMigrations(target) ? target.migrations : undefined;\n}\n\n/**\n * Reads the migrations directory and builds the migration graph from all\n * packages. Throws on I/O or graph errors — callers handle error mapping.\n *\n * Every on-disk package is content-addressed (`migrationHash` is always a\n * string); there is no draft state to filter out.\n */\nexport async function loadMigrationPackages(migrationsDir: string): Promise<{\n bundles: readonly OnDiskMigrationPackage[];\n graph: MigrationGraph;\n}> {\n const bundles = await readMigrationsDir(migrationsDir);\n const graph = reconstructGraph(bundles);\n return { bundles, graph };\n}\n\n/**\n * The subset of the emitted contract.json that the framework layer can\n * safely type. The emitter adds these fields on top of the family-specific\n * storage/models/relations. Other fields exist in the JSON but are opaque\n * at this layer — the index signature preserves them for downstream\n * consumers that operate at the family level (e.g., the control client).\n */\nexport interface ContractEnvelope {\n readonly storageHash: string;\n readonly schemaVersion: string;\n readonly target: string;\n readonly targetFamily: string;\n readonly profileHash?: string;\n readonly [key: string]: unknown;\n}\n\n/**\n * Reads and parses contract.json, validating the framework-level envelope\n * fields (storageHash, schemaVersion, target, targetFamily).\n *\n * Family-specific validation (storage structure, codec mappings, etc.)\n * happens downstream in the control client via the family instance.\n */\nexport async function readContractEnvelope(config: {\n contract?: { output?: string };\n}): Promise<ContractEnvelope> {\n const contractPath = resolveContractPath(config);\n const content = await readFile(contractPath, 'utf-8');\n const json = JSON.parse(content) as Record<string, unknown>;\n\n const { schemaVersion, target, targetFamily, profileHash } = json;\n const storage = json['storage'] as Record<string, unknown> | undefined;\n const storageHash = storage?.['storageHash'];\n\n if (typeof storageHash !== 'string') {\n throw new Error(\n `Contract at ${relative(process.cwd(), contractPath)} is missing a valid storage.storageHash. Run \\`prisma-next contract emit\\` to regenerate.`,\n );\n }\n if (typeof schemaVersion !== 'string') {\n throw new Error(\n `Contract at ${relative(process.cwd(), contractPath)} is missing schemaVersion.`,\n );\n }\n if (typeof target !== 'string') {\n throw new Error(`Contract at ${relative(process.cwd(), contractPath)} is missing target.`);\n }\n if (typeof targetFamily !== 'string') {\n throw new Error(\n `Contract at ${relative(process.cwd(), contractPath)} is missing targetFamily.`,\n );\n }\n\n return {\n ...json,\n storageHash,\n schemaVersion,\n target,\n targetFamily,\n ...(typeof profileHash === 'string' ? { profileHash } : {}),\n };\n}\n\n/**\n * Masks credentials in a database connection URL.\n * Handles standard URLs (username + password + query params) and libpq-style key=value strings.\n */\nexport function maskConnectionUrl(url: string): string {\n try {\n const parsed = new URL(url);\n if (parsed.username) {\n parsed.username = '****';\n }\n if (parsed.password) {\n parsed.password = '****';\n }\n // Also mask password in query parameters (e.g., ?password=secret, ?sslpassword=secret)\n for (const key of [...parsed.searchParams.keys()]) {\n if (/password/i.test(key)) {\n parsed.searchParams.set(key, '****');\n }\n }\n return parsed.toString();\n } catch {\n // Fallback for libpq-style key=value connection strings (e.g., \"host=localhost password=secret user=admin\")\n return url\n .replace(/password\\s*=\\s*\\S+/gi, 'password=****')\n .replace(/user\\s*=\\s*\\S+/gi, 'user=****');\n }\n}\n\n/**\n * Strips raw connection URL fragments from an error message to prevent credential leakage.\n * Call this before surfacing driver errors to the user.\n */\nexport function sanitizeErrorMessage(message: string, connectionUrl?: string): string {\n if (!connectionUrl) {\n return message;\n }\n try {\n const parsed = new URL(connectionUrl);\n // Replace the full URL (with and without trailing slash)\n let sanitized = message;\n sanitized = sanitized.replaceAll(connectionUrl, maskConnectionUrl(connectionUrl));\n // Also replace the password and username individually if they appear\n if (parsed.password) {\n sanitized = sanitized.replaceAll(parsed.password, '****');\n }\n if (parsed.username) {\n sanitized = sanitized.replaceAll(parsed.username, '****');\n }\n return sanitized;\n } catch {\n // For libpq-style strings, mask password and user values in the message\n return message\n .replace(/password\\s*=\\s*\\S+/gi, 'password=****')\n .replace(/user\\s*=\\s*\\S+/gi, 'user=****');\n }\n}\n\n/**\n * Registers the global CLI options shared by every command:\n * --format, --json, -q/--quiet, -v/--verbose, --trace, --color, --no-color,\n * --interactive, --no-interactive, -y/--yes.\n *\n * Also sets up the styled help formatter.\n */\nexport function addGlobalOptions(command: Command): Command {\n return command\n .configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n })\n .option(\n '--format <pretty|json>',\n 'Output format (default: pretty, or json when stdout is not a TTY)',\n )\n .option('--json', 'Output as JSON (alias for --format json)')\n .option('-q, --quiet', 'Quiet mode: errors only')\n .option('-v, --verbose', 'Verbose output: debug info, timings')\n .option('--trace', 'Trace output: deep internals, stack traces')\n .option('--color', 'Force color output')\n .option('--no-color', 'Disable color output')\n .option('--interactive', 'Force interactive mode')\n .option('--no-interactive', 'Disable interactive prompts')\n .option('-y, --yes', 'Auto-accept prompts');\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"migration-list.mjs","names":[],"sources":["../../src/commands/migration-list.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findPath } from '@prisma-next/migration-tools/migration-graph';\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 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 { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationListOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nexport interface MigrationListEntry {\n readonly dirName: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly operationCount: number;\n readonly createdAt: string;\n}\n\nexport interface MigrationListResult {\n readonly ok: true;\n readonly migrations: readonly MigrationListEntry[];\n readonly summary: string;\n}\n\nasync function executeMigrationListCommand(\n options: MigrationListOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationListResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration list',\n description: 'List on-disk migrations in topological order',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n ({ bundles, 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 if (bundles.length === 0) {\n return ok({ ok: true, migrations: [], summary: 'No migrations found' });\n }\n\n const leaves = [...graph.nodes].filter(\n (n) => !graph.forwardChain.has(n) || graph.forwardChain.get(n)!.length === 0,\n );\n const targetHash =\n leaves.length === 1 ? leaves[0]! : ([...graph.nodes].values().next().value as string);\n const chain = findPath(graph, EMPTY_CONTRACT_HASH, targetHash) ?? [];\n\n const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));\n const entries: MigrationListEntry[] = chain.map((edge) => {\n const pkg = pkgByDirName.get(edge.dirName);\n const ops = (pkg?.ops ?? []) as readonly MigrationPlanOperation[];\n return {\n dirName: edge.dirName,\n from: edge.from,\n to: edge.to,\n migrationHash: edge.migrationHash,\n operationCount: ops.length,\n createdAt: edge.createdAt,\n };\n });\n\n return ok({\n ok: true,\n migrations: entries,\n summary: `${entries.length} migration(s) on disk`,\n });\n}\n\nexport function createMigrationListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(\n command,\n 'List on-disk migrations in topological order',\n 'Enumerates all migration packages under migrations/<space>/ in\\n' +\n 'topological order. Offline — does not consult the database.',\n );\n setCommandExamples(command, ['prisma-next migration list']);\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 graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationListOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationListCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (listResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(listResult, null, 2));\n } else if (!flags.quiet) {\n if (listResult.migrations.length === 0) {\n ui.log('No migrations found');\n } else {\n for (const entry of listResult.migrations) {\n ui.log(\n `${entry.dirName} ${entry.migrationHash.slice(0, 16)}… ${entry.operationCount} op(s)`,\n );\n }\n ui.log(`\\n${listResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract-emit-bcrpT-wD.mjs","names":["isRecord"],"sources":["../src/utils/emit-queue.ts","../src/utils/publish-contract-artifact-pair.ts","../src/utils/validate-contract-deps.ts","../src/control-api/operations/contract-emit.ts"],"sourcesContent":["/**\n * Per-output FIFO queue for `executeContractEmit`.\n *\n * Ensures that at most one emit (load → resolve source → emit bytes → publish)\n * runs per output JSON path at a time. Concurrent calls for the same path\n * line up behind the in-flight one and run in submission order; the user-visible\n * outcome is \"last submission wins on disk\" without any supersession bookkeeping.\n *\n * Long-lived hosts (Vite dev server, watch CLIs) must call `disposeEmitQueue`\n * when they stop publishing to a path, otherwise the module-global `Map`\n * accumulates one entry per unique output path for the lifetime of the process.\n */\nconst emitQueues = new Map<string, Promise<unknown>>();\n\nexport function queueEmitByOutput<T>(outputJsonPath: string, action: () => Promise<T>): Promise<T> {\n const previous = emitQueues.get(outputJsonPath) ?? Promise.resolve();\n // Continue regardless of the previous task's outcome — a failed emit must not\n // block subsequent ones. The current task's outcome propagates via `next`.\n const next = previous.then(action, action);\n emitQueues.set(outputJsonPath, next);\n return next;\n}\n\nexport function disposeEmitQueue(outputJsonPath: string): void {\n emitQueues.delete(outputJsonPath);\n}\n","import { readFile, rename, rm, writeFile } from 'node:fs/promises';\nimport { basename, dirname, join } from 'pathe';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction createTempArtifactPath(path: string, publicationToken: string, phase: string): string {\n return join(dirname(path), `.${basename(path)}.${process.pid}.${publicationToken}.${phase}.tmp`);\n}\n\ntype PreviousArtifact = { readonly content: string } | 'remove';\n\nasync function readExistingArtifact(path: string): Promise<PreviousArtifact> {\n try {\n return { content: await readFile(path, 'utf-8') };\n } catch (error) {\n if (isRecord(error) && error['code'] === 'ENOENT') {\n return 'remove';\n }\n throw error;\n }\n}\n\nasync function restoreArtifact(\n path: string,\n previous: PreviousArtifact,\n publicationToken: string,\n): Promise<void> {\n if (previous === 'remove') {\n await rm(path, { force: true });\n return;\n }\n\n const restorePath = createTempArtifactPath(path, publicationToken, 'rollback');\n await writeFile(restorePath, previous.content, 'utf-8');\n try {\n await rename(restorePath, path);\n } finally {\n await rm(restorePath, { force: true });\n }\n}\n\ninterface PublishEntry {\n readonly tempPath: string;\n readonly outputPath: string;\n readonly previous: PreviousArtifact;\n}\n\nfunction withRollbackFailureCause(error: unknown, rollbackFailures: readonly unknown[]): Error {\n const rollbackCause = new AggregateError(\n rollbackFailures,\n 'Failed to restore published artifacts',\n );\n\n if (error instanceof Error) {\n Object.defineProperty(error, 'cause', {\n value: rollbackCause,\n configurable: true,\n writable: true,\n });\n return error;\n }\n\n return new Error(String(error), { cause: rollbackCause });\n}\n\nasync function publishPairWithRollback(\n entries: readonly PublishEntry[],\n publicationToken: string,\n): Promise<void> {\n const replaced: PublishEntry[] = [];\n try {\n for (const entry of entries) {\n await rename(entry.tempPath, entry.outputPath);\n replaced.push(entry);\n }\n } catch (error) {\n const rollbackResults = await Promise.allSettled(\n replaced.map((entry) => restoreArtifact(entry.outputPath, entry.previous, publicationToken)),\n );\n const rollbackFailures = rollbackResults.flatMap((result) =>\n result.status === 'rejected' ? [result.reason] : [],\n );\n\n if (rollbackFailures.length > 0) {\n throw withRollbackFailureCause(error, rollbackFailures);\n }\n\n throw error;\n }\n}\n\nexport async function publishContractArtifactPair({\n outputJsonPath,\n outputDtsPath,\n contractJson,\n contractDts,\n publicationToken,\n beforePublish,\n}: {\n readonly outputJsonPath: string;\n readonly outputDtsPath: string;\n readonly contractJson: string;\n readonly contractDts: string;\n readonly publicationToken: string;\n readonly beforePublish?: () => Promise<boolean> | boolean;\n}): Promise<boolean> {\n const tempJsonPath = createTempArtifactPath(outputJsonPath, publicationToken, 'next');\n const tempDtsPath = createTempArtifactPath(outputDtsPath, publicationToken, 'next');\n\n try {\n await writeFile(tempJsonPath, contractJson, 'utf-8');\n await writeFile(tempDtsPath, contractDts, 'utf-8');\n\n if ((await beforePublish?.()) === false) {\n return false;\n }\n\n const previousJson = await readExistingArtifact(outputJsonPath);\n const previousDts = await readExistingArtifact(outputDtsPath);\n\n await publishPairWithRollback(\n [\n { tempPath: tempDtsPath, outputPath: outputDtsPath, previous: previousDts },\n { tempPath: tempJsonPath, outputPath: outputJsonPath, previous: previousJson },\n ],\n publicationToken,\n );\n return true;\n } finally {\n await Promise.allSettled([rm(tempJsonPath, { force: true }), rm(tempDtsPath, { force: true })]);\n }\n}\n","import { createRequire } from 'node:module';\n\nconst IMPORT_PATTERN = /import\\s+type\\s+.*?\\s+from\\s+['\"](@[^/]+\\/[^/'\"]+)/g;\n\nexport function extractPackageSpecifiers(dtsContent: string): string[] {\n const packages = new Set<string>();\n for (const match of dtsContent.matchAll(IMPORT_PATTERN)) {\n const pkg = match[1];\n if (pkg) packages.add(pkg);\n }\n return [...packages];\n}\n\nexport interface ContractDepsValidation {\n readonly missing: readonly string[];\n readonly warning?: string;\n}\n\nexport function validateContractDeps(\n dtsContent: string,\n projectRoot: string,\n): ContractDepsValidation {\n const packages = extractPackageSpecifiers(dtsContent);\n const resolve = createRequire(`${projectRoot}/package.json`);\n\n const missing: string[] = [];\n for (const pkg of packages) {\n try {\n resolve.resolve(`${pkg}/package.json`);\n } catch {\n missing.push(pkg);\n }\n }\n\n if (missing.length === 0) {\n return { missing };\n }\n\n const list = missing.map((p) => ` - ${p}`).join('\\n');\n const warning = [\n 'contract.d.ts imports types from packages that are not installed:',\n list,\n '',\n 'Install them with your package manager:',\n ...missing.map((p) => ` ${p}`),\n ].join('\\n');\n\n return { missing, warning };\n}\n","import { mkdir } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { emit, getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { abortable } from '@prisma-next/utils/abortable';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { JsonObject } from '@prisma-next/utils/json';\nimport { dirname } from 'pathe';\nimport { loadConfig } from '../../config-loader';\nimport { errorContractConfigMissing, errorRuntime } from '../../utils/cli-errors';\nimport { queueEmitByOutput } from '../../utils/emit-queue';\nimport { assertFrameworkComponentsCompatible } from '../../utils/framework-components';\nimport { publishContractArtifactPair } from '../../utils/publish-contract-artifact-pair';\nimport { validateContractDeps } from '../../utils/validate-contract-deps';\nimport { enrichContract } from '../contract-enrichment';\nimport type {\n ContractEmitOptions,\n ContractEmitResult,\n ControlActionName,\n OnControlProgress,\n} from '../types';\n\nconst EMIT_ACTION: ControlActionName = 'emit';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction startSpan(onProgress: OnControlProgress | undefined, spanId: string, label: string): void {\n onProgress?.({ action: EMIT_ACTION, kind: 'spanStart', spanId, label });\n}\n\nfunction endSpan(\n onProgress: OnControlProgress | undefined,\n spanId: string,\n outcome: 'ok' | 'error',\n): void {\n onProgress?.({ action: EMIT_ACTION, kind: 'spanEnd', spanId, outcome });\n}\n\nfunction failedToResolveContractSource(why: string, fix: string, meta?: Record<string, unknown>) {\n return errorRuntime('Failed to resolve contract source', {\n why,\n fix,\n ...ifDefined('meta', meta),\n });\n}\n\ntype ValidatedProviderResult =\n | { readonly ok: true; readonly value: unknown }\n | { readonly ok: false; readonly error: ReturnType<typeof errorRuntime> };\n\nfunction diagnosticLocationSuffix(diagnostic: Record<string, unknown>): string {\n const sourceId = typeof diagnostic['sourceId'] === 'string' ? diagnostic['sourceId'] : undefined;\n const span = isRecord(diagnostic['span']) ? diagnostic['span'] : undefined;\n const start = span && isRecord(span['start']) ? span['start'] : undefined;\n const line = start && typeof start['line'] === 'number' ? start['line'] : undefined;\n const column = start && typeof start['column'] === 'number' ? start['column'] : undefined;\n if (sourceId && line !== undefined && column !== undefined) {\n return ` (${sourceId}:${line}:${column})`;\n }\n if (sourceId) {\n return ` (${sourceId})`;\n }\n return '';\n}\n\nfunction mapDiagnosticsToIssues(\n diagnostics: readonly unknown[],\n): ReadonlyArray<{ readonly kind: string; readonly message: string }> {\n const issues: { readonly kind: string; readonly message: string }[] = [];\n for (const raw of diagnostics) {\n if (!isRecord(raw)) continue;\n const code = typeof raw['code'] === 'string' ? raw['code'] : 'diagnostic';\n const message = typeof raw['message'] === 'string' ? raw['message'] : '';\n issues.push({ kind: code, message: `${message}${diagnosticLocationSuffix(raw)}` });\n }\n return issues;\n}\n\nfunction validateProviderResult(providerResult: unknown): ValidatedProviderResult {\n if (!isRecord(providerResult) || typeof providerResult['ok'] !== 'boolean') {\n return {\n ok: false,\n error: failedToResolveContractSource(\n 'Contract source provider returned malformed result shape.',\n 'Ensure contract.source.load resolves to ok(Contract) or notOk({ summary, diagnostics }).',\n ),\n };\n }\n\n if (providerResult['ok']) {\n if (!('value' in providerResult)) {\n return {\n ok: false,\n error: failedToResolveContractSource(\n 'Contract source provider returned malformed success result: missing value.',\n 'Ensure contract.source.load success payload is ok(Contract).',\n ),\n };\n }\n return { ok: true, value: providerResult['value'] };\n }\n\n const failure = providerResult['failure'];\n if (\n !isRecord(failure) ||\n typeof failure['summary'] !== 'string' ||\n !Array.isArray(failure['diagnostics'])\n ) {\n return {\n ok: false,\n error: failedToResolveContractSource(\n 'Contract source provider returned malformed failure result: expected summary and diagnostics.',\n 'Ensure contract.source.load failure payload is notOk({ summary, diagnostics, meta? }).',\n ),\n };\n }\n return {\n ok: false,\n error: failedToResolveContractSource(\n String(failure['summary']),\n 'Fix contract source diagnostics and return ok(Contract).',\n {\n diagnostics: failure['diagnostics'],\n issues: mapDiagnosticsToIssues(failure['diagnostics']),\n ...ifDefined('providerMeta', failure['meta']),\n },\n ),\n };\n}\n\n/**\n * Canonical contract emit operation.\n *\n * This is the SINGLE publication path used by both the CLI command\n * (`prisma-next contract emit`) and the Vite plugin\n * (`@prisma-next/vite-plugin-contract-emit`). New callers must go through this\n * function rather than re-implementing load → emit → publish.\n *\n * The whole flow (load config → resolve source → emit bytes → atomic publish)\n * is serialized per output JSON path via `queueEmitByOutput`. Concurrent calls\n * for the same output line up FIFO; the user-visible outcome is \"last\n * submission wins on disk\" without any supersession bookkeeping. Within a\n * single emit, `publishContractArtifactPair` stages temp files, renames\n * `contract.d.ts` before `contract.json`, and attempts to restore the previous\n * pair if either rename fails — so type-only consumers never observe a\n * mismatched pair.\n *\n * @throws {CliStructuredError} on config/source/validation problems\n * @throws {DOMException} `AbortError` if cancelled via `signal`\n */\nexport async function executeContractEmit(\n options: ContractEmitOptions,\n): Promise<ContractEmitResult> {\n const { configPath, signal = new AbortController().signal, onProgress } = options;\n const unlessAborted = abortable(signal);\n\n const config = await unlessAborted(loadConfig(configPath));\n\n if (!config.contract) {\n throw errorContractConfigMissing({\n why: 'Config.contract is required for emit. Define it in your config: contract: { source: ..., output: ... }',\n });\n }\n\n const contractConfig = config.contract;\n\n if (!contractConfig.output) {\n throw errorContractConfigMissing({\n why: 'Contract config must have output path. This should not happen if defineConfig() was used.',\n });\n }\n\n if (typeof contractConfig.source?.load !== 'function') {\n throw errorContractConfigMissing({\n why: 'Contract config must include a valid source provider object',\n });\n }\n\n let outputPaths: ReturnType<typeof getEmittedArtifactPaths>;\n try {\n outputPaths = getEmittedArtifactPaths(contractConfig.output);\n } catch (error) {\n throw errorContractConfigMissing({\n why: error instanceof Error ? error.message : String(error),\n });\n }\n const { jsonPath: outputJsonPath, dtsPath: outputDtsPath } = outputPaths;\n\n return queueEmitByOutput(outputJsonPath, async () => {\n const stack = createControlStack(config);\n\n const sourceContext = {\n composedExtensionPacks: stack.extensionPacks.map((p) => p.id),\n scalarTypeDescriptors: stack.scalarTypeDescriptors,\n authoringContributions: stack.authoringContributions,\n codecLookup: stack.codecLookup,\n controlMutationDefaults: stack.controlMutationDefaults,\n resolvedInputs: contractConfig.source.inputs ?? [],\n };\n\n startSpan(onProgress, 'resolveSource', 'Resolving contract source...');\n let providerResult: Awaited<ReturnType<typeof contractConfig.source.load>>;\n try {\n providerResult = await unlessAborted(contractConfig.source.load(sourceContext));\n } catch (error) {\n endSpan(onProgress, 'resolveSource', 'error');\n if (signal.aborted || (isRecord(error) && error['name'] === 'AbortError')) {\n throw error;\n }\n throw failedToResolveContractSource(\n error instanceof Error ? error.message : String(error),\n 'Ensure contract.source.load resolves to ok(Contract) or returns structured diagnostics.',\n );\n }\n\n const validatedContract = validateProviderResult(providerResult);\n if (!validatedContract.ok) {\n endSpan(onProgress, 'resolveSource', 'error');\n throw validatedContract.error;\n }\n endSpan(onProgress, 'resolveSource', 'ok');\n\n startSpan(onProgress, 'emit', 'Emitting contract...');\n let emitResult: Awaited<ReturnType<typeof emit>>;\n try {\n const familyInstance = config.family.create(stack);\n const rawComponents = [config.target, config.adapter, ...(config.extensionPacks ?? [])];\n const frameworkComponents = assertFrameworkComponentsCompatible(\n config.family.familyId,\n config.target.targetId,\n rawComponents,\n );\n // Blind cast: `validateProviderResult` upstream has already\n // pinned `validatedContract.value` to the provider's loose\n // `Contract` envelope, but the local `Contract` type at this\n // call site is the precise structural interface. Re-narrowing\n // the envelope into the precise type is exactly what the\n // `familyInstance.deserializeContract(enrichedIR)` call on the\n // next line does — the cast just defers the structural check\n // by one statement so `enrichContract` can decorate first.\n const enrichedIR = enrichContract(\n validatedContract.value as unknown as Contract,\n frameworkComponents,\n );\n familyInstance.deserializeContract(enrichedIR);\n // Each target's descriptor ships a `contractSerializer` SPI; the\n // framework canonicalizer threads its `serializeContract` so the\n // on-disk JSON envelope is constructed by target-owned code\n // rather than by walking the in-memory contract with\n // `Object.entries` (which would leak runtime-only class API\n // fields into the persisted shape).\n const serializeContract = (c: Contract): JsonObject =>\n config.target.contractSerializer.serializeContract(c);\n emitResult = await unlessAborted(\n emit(enrichedIR, stack, config.family.emission, {\n outputJsonPath,\n serializeContract,\n }),\n );\n } catch (error) {\n endSpan(onProgress, 'emit', 'error');\n throw error;\n }\n endSpan(onProgress, 'emit', 'ok');\n\n await unlessAborted(mkdir(dirname(outputJsonPath), { recursive: true }));\n await publishContractArtifactPair({\n outputJsonPath,\n outputDtsPath,\n contractJson: emitResult.contractJson,\n contractDts: emitResult.contractDts,\n publicationToken: String(process.hrtime.bigint()),\n });\n\n const validationWarning = validateContractDeps(\n emitResult.contractDts,\n dirname(outputDtsPath),\n ).warning;\n\n return {\n storageHash: emitResult.storageHash,\n ...ifDefined('executionHash', emitResult.executionHash),\n profileHash: emitResult.profileHash,\n files: {\n json: outputJsonPath,\n dts: outputDtsPath,\n },\n ...ifDefined('validationWarning', validationWarning),\n };\n });\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract-emit-uwT-Mj8-.mjs","names":["CliStructuredError","errorUnexpected"],"sources":["../src/utils/formatters/emit.ts","../src/commands/contract-emit.ts"],"sourcesContent":["import { ifDefined } from '@prisma-next/utils/defined';\nimport { relative } from 'pathe';\n\nimport type { GlobalFlags } from '../global-flags';\nimport { isVerbose } from './helpers';\n\n// EmitContractResult type for CLI output formatting (includes file paths)\nexport interface EmitContractResult {\n readonly storageHash: string;\n readonly executionHash?: string;\n readonly profileHash: string;\n readonly outDir: string;\n readonly files: {\n readonly json: string;\n readonly dts: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\n/**\n * Formats human-readable output for contract emit.\n */\nexport function formatEmitOutput(result: EmitContractResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const lines: string[] = [];\n\n // Convert absolute paths to relative paths from cwd\n const jsonPath = relative(process.cwd(), result.files.json);\n const dtsPath = relative(process.cwd(), result.files.dts);\n\n lines.push(`✔ Emitted contract.json → ${jsonPath}`);\n lines.push(`✔ Emitted contract.d.ts → ${dtsPath}`);\n lines.push(` storageHash: ${result.storageHash}`);\n if (result.executionHash) {\n lines.push(` executionHash: ${result.executionHash}`);\n }\n if (result.profileHash) {\n lines.push(` profileHash: ${result.profileHash}`);\n }\n if (isVerbose(flags, 1)) {\n lines.push(` Total time: ${result.timings.total}ms`);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Formats JSON output for contract emit.\n */\nexport function formatEmitJson(result: EmitContractResult): string {\n const output = {\n ok: true,\n storageHash: result.storageHash,\n ...ifDefined('executionHash', result.executionHash),\n ...(result.profileHash ? { profileHash: result.profileHash } : {}),\n outDir: result.outDir,\n files: result.files,\n timings: result.timings,\n };\n\n return JSON.stringify(output, null, 2);\n}\n","import { getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport { errorContractConfigMissing } from '@prisma-next/errors/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { dirname, relative, resolve } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { executeContractEmit } from '../control-api/operations/contract-emit';\nimport type { ContractEmitResult } from '../control-api/types';\nimport { CliStructuredError, errorUnexpected } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport {\n type EmitContractResult,\n formatEmitJson,\n formatEmitOutput,\n} from '../utils/formatters/emit';\nimport { formatStyledHeader, formatSuccessMessage } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface ContractEmitOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\ninterface HeaderPaths {\n readonly displayConfigPath: string;\n readonly outputJsonPath: string;\n readonly outputDtsPath: string;\n}\n\n/**\n * Pre-load the config just to compute display paths for the styled header. The\n * actual emit work goes through `executeContractEmit`, which loads the config\n * itself; the redundant load here is bounded and lets the header render before\n * the emit spans start.\n */\nasync function resolveHeaderPaths(\n configOption: string | undefined,\n): Promise<Result<HeaderPaths, CliStructuredError>> {\n const displayConfigPath = configOption\n ? relative(process.cwd(), resolve(configOption))\n : 'prisma-next.config.ts';\n\n let config: Awaited<ReturnType<typeof loadConfig>>;\n try {\n config = await loadConfig(configOption);\n } catch (error) {\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: 'Failed to load config',\n }),\n );\n }\n\n if (!config.contract?.output) {\n return notOk(\n errorContractConfigMissing({\n why: 'Config.contract.output is required for emit. Define it in your config: contract: { source: ..., output: ... }',\n }),\n );\n }\n\n try {\n const { jsonPath: outputJsonPath, dtsPath: outputDtsPath } = getEmittedArtifactPaths(\n config.contract.output,\n );\n return ok({ displayConfigPath, outputJsonPath, outputDtsPath });\n } catch (error) {\n return notOk(\n errorContractConfigMissing({\n why: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n}\n\nasync function executeContractEmitCommand(\n options: ContractEmitOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<EmitContractResult, CliStructuredError>> {\n const headerPathsResult = await resolveHeaderPaths(options.config);\n if (!headerPathsResult.ok) {\n return headerPathsResult;\n }\n const { displayConfigPath, outputJsonPath, outputDtsPath } = headerPathsResult.value;\n\n if (!flags.json && !flags.quiet) {\n ui.stderr(\n formatStyledHeader({\n command: 'contract emit',\n description: 'Emit your contract artifacts',\n url: 'https://pris.ly/contract-emit',\n details: [\n { label: 'config', value: displayConfigPath },\n { label: 'contract', value: relative(process.cwd(), outputJsonPath) },\n { label: 'types', value: relative(process.cwd(), outputDtsPath) },\n ],\n flags,\n }),\n );\n }\n\n const onProgress = createProgressAdapter({ ui, flags });\n const configPath = options.config ? resolve(options.config) : 'prisma-next.config.ts';\n\n let result: ContractEmitResult;\n try {\n result = await executeContractEmit({ configPath, onProgress });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected('Unexpected error during contract emit', {\n why: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n\n if (result.validationWarning) {\n ui.warn(result.validationWarning);\n }\n\n return ok({\n storageHash: result.storageHash,\n ...ifDefined('executionHash', result.executionHash),\n profileHash: result.profileHash,\n outDir: dirname(result.files.json),\n files: result.files,\n timings: { total: Date.now() - startTime },\n });\n}\n\nexport function createContractEmitCommand(): Command {\n const command = new Command('emit');\n setCommandDescriptions(\n command,\n 'Emit your contract artifacts',\n 'Reads your contract source (TypeScript or Prisma schema) and emits contract.json and\\n' +\n 'contract.d.ts. The contract.json contains the canonical contract structure, and\\n' +\n 'contract.d.ts provides TypeScript types for type-safe query building.',\n );\n setCommandExamples(command, [\n 'prisma-next contract emit',\n 'prisma-next contract emit --config ./custom-config.ts',\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: ContractEmitOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const startTime = Date.now();\n\n const result = await executeContractEmitCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (emitResult) => {\n if (flags.json) {\n ui.output(formatEmitJson(emitResult));\n } else {\n const output = formatEmitOutput(emitResult, flags);\n if (output) {\n ui.log(output);\n }\n if (!flags.quiet) {\n ui.success(formatSuccessMessage(flags));\n }\n }\n });\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"contract-enrichment-Dani0mMW.mjs","names":[],"sources":["../src/control-api/contract-enrichment.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\n\ntype CapabilityMatrix = Record<string, Record<string, boolean>>;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction sortDeep(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortDeep);\n }\n if (!isPlainObject(value)) {\n return value;\n }\n const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));\n const next: Record<string, unknown> = {};\n for (const [key, child] of entries) {\n next[key] = sortDeep(child);\n }\n return next;\n}\n\nfunction sortDeepTyped<T>(value: T): T {\n return sortDeep(value) as T;\n}\n\nfunction extractCapabilityMatrix(value: unknown): CapabilityMatrix {\n if (!isPlainObject(value)) return {};\n\n const out: CapabilityMatrix = {};\n for (const [namespace, maybeCaps] of Object.entries(value)) {\n if (!isPlainObject(maybeCaps)) continue;\n const caps: Record<string, boolean> = {};\n for (const [key, flag] of Object.entries(maybeCaps)) {\n if (typeof flag === 'boolean') {\n caps[key] = flag;\n }\n }\n if (Object.keys(caps).length > 0) {\n out[namespace] = caps;\n }\n }\n\n return out;\n}\n\nfunction mergeCapabilities(left: CapabilityMatrix, right: CapabilityMatrix): CapabilityMatrix {\n const next: CapabilityMatrix = { ...left };\n for (const [namespace, capabilities] of Object.entries(right)) {\n next[namespace] = {\n ...(left[namespace] ?? {}),\n ...capabilities,\n };\n }\n return next;\n}\n\nfunction extractExtensionPackMeta(\n component: TargetBoundComponentDescriptor<string, string>,\n): Record<string, unknown> {\n const { kind, id, version, capabilities, types } = component;\n const base: Record<string, unknown> = {\n kind,\n id,\n familyId: component.familyId,\n targetId: component.targetId,\n version,\n };\n if (capabilities) {\n base['capabilities'] = capabilities;\n }\n if (types) {\n if (types.codecTypes) {\n const {\n controlPlaneHooks: _,\n codecDescriptors: _cd,\n ...cleanedCodecTypes\n } = types.codecTypes;\n base['types'] = { ...types, codecTypes: cleanedCodecTypes };\n } else {\n base['types'] = types;\n }\n }\n return base;\n}\n\n/**\n * Enriches a raw contract with framework-derived metadata: capabilities from all component descriptors and extension pack metadata from extension descriptors. Produces deterministically sorted output.\n */\nexport function enrichContract(\n ir: Contract,\n components: ReadonlyArray<TargetBoundComponentDescriptor<string, string>>,\n): Contract {\n let mergedCapabilities = ir.capabilities;\n const extensionPacksMeta: Record<string, unknown> = {};\n\n for (const component of components) {\n if (component.capabilities) {\n mergedCapabilities = mergeCapabilities(\n mergedCapabilities,\n extractCapabilityMatrix(component.capabilities),\n );\n }\n if (component.kind === 'extension') {\n extensionPacksMeta[component.id] = extractExtensionPackMeta(component);\n }\n }\n\n const extensionPacks =\n Object.keys(extensionPacksMeta).length > 0\n ? { ...ir.extensionPacks, ...extensionPacksMeta }\n : ir.extensionPacks;\n\n return {\n ...ir,\n capabilities: sortDeepTyped(mergedCapabilities),\n extensionPacks: sortDeepTyped(extensionPacks),\n };\n}\n"],"mappings":";AAKA,SAAS,cAAc,OAAkD;CACvE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG7E,SAAS,SAAS,OAAyB;CACzC,IAAI,MAAM,QAAQ,MAAM,EACtB,OAAO,MAAM,IAAI,SAAS;CAE5B,IAAI,CAAC,cAAc,MAAM,EACvB,OAAO;CAET,MAAM,UAAU,OAAO,QAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC;CAC5E,MAAM,OAAgC,EAAE;CACxC,KAAK,MAAM,CAAC,KAAK,UAAU,SACzB,KAAK,OAAO,SAAS,MAAM;CAE7B,OAAO;;AAGT,SAAS,cAAiB,OAAa;CACrC,OAAO,SAAS,MAAM;;AAGxB,SAAS,wBAAwB,OAAkC;CACjE,IAAI,CAAC,cAAc,MAAM,EAAE,OAAO,EAAE;CAEpC,MAAM,MAAwB,EAAE;CAChC,KAAK,MAAM,CAAC,WAAW,cAAc,OAAO,QAAQ,MAAM,EAAE;EAC1D,IAAI,CAAC,cAAc,UAAU,EAAE;EAC/B,MAAM,OAAgC,EAAE;EACxC,KAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,UAAU,EACjD,IAAI,OAAO,SAAS,WAClB,KAAK,OAAO;EAGhB,IAAI,OAAO,KAAK,KAAK,CAAC,SAAS,GAC7B,IAAI,aAAa;;CAIrB,OAAO;;AAGT,SAAS,kBAAkB,MAAwB,OAA2C;CAC5F,MAAM,OAAyB,EAAE,GAAG,MAAM;CAC1C,KAAK,MAAM,CAAC,WAAW,iBAAiB,OAAO,QAAQ,MAAM,EAC3D,KAAK,aAAa;EAChB,GAAI,KAAK,cAAc,EAAE;EACzB,GAAG;EACJ;CAEH,OAAO;;AAGT,SAAS,yBACP,WACyB;CACzB,MAAM,EAAE,MAAM,IAAI,SAAS,cAAc,UAAU;CACnD,MAAM,OAAgC;EACpC;EACA;EACA,UAAU,UAAU;EACpB,UAAU,UAAU;EACpB;EACD;CACD,IAAI,cACF,KAAK,kBAAkB;CAEzB,IAAI,OACF,IAAI,MAAM,YAAY;EACpB,MAAM,EACJ,mBAAmB,GACnB,kBAAkB,KAClB,GAAG,sBACD,MAAM;EACV,KAAK,WAAW;GAAE,GAAG;GAAO,YAAY;GAAmB;QAE3D,KAAK,WAAW;CAGpB,OAAO;;;;;AAMT,SAAgB,eACd,IACA,YACU;CACV,IAAI,qBAAqB,GAAG;CAC5B,MAAM,qBAA8C,EAAE;CAEtD,KAAK,MAAM,aAAa,YAAY;EAClC,IAAI,UAAU,cACZ,qBAAqB,kBACnB,oBACA,wBAAwB,UAAU,aAAa,CAChD;EAEH,IAAI,UAAU,SAAS,aACrB,mBAAmB,UAAU,MAAM,yBAAyB,UAAU;;CAI1E,MAAM,iBACJ,OAAO,KAAK,mBAAmB,CAAC,SAAS,IACrC;EAAE,GAAG,GAAG;EAAgB,GAAG;EAAoB,GAC/C,GAAG;CAET,OAAO;EACL,GAAG;EACH,cAAc,cAAc,mBAAmB;EAC/C,gBAAgB,cAAc,eAAe;EAC9C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"migration-plan-C2jeH1J5.mjs","names":[],"sources":["../src/utils/contract-space-seed-phase.ts","../src/commands/migration-plan.ts"],"sourcesContent":["import { materialiseExtensionMigrationPackageIfMissing } from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport type { MigrationOps } from '@prisma-next/migration-tools/package';\nimport {\n emitContractSpaceArtefacts,\n planAllSpaces,\n readContractSpaceHeadRef,\n type SpacePlanOutput,\n spaceMigrationDirectory,\n} from '@prisma-next/migration-tools/spaces';\n\n/**\n * In-memory authored migration package shipped by an extension descriptor.\n * Mirrors `MigrationPackage` from `@prisma-next/migration-tools/io` (the\n * on-disk shape minus `dirPath`); redeclared structurally here so the\n * CLI helper does not couple to any family's `ExtensionMigrationPackage`\n * type — any family that ships pre-built migration packages can pass\n * them through unchanged.\n */\nexport interface DescriptorMigrationPackage {\n readonly dirName: string;\n readonly metadata: MigrationMetadata;\n readonly ops: MigrationOps;\n}\n\n/**\n * Minimal descriptor view consumed by the seed phase. Mirrors the shape\n * the SQL family ships on each declared extension entry; only the fields\n * the seed phase needs are surfaced.\n */\nexport interface SeedPhaseExtensionInput {\n readonly id: string;\n readonly contractSpace?: {\n readonly contractJson: unknown;\n readonly headRef: { readonly hash: string; readonly invariants: readonly string[] };\n readonly migrations: readonly DescriptorMigrationPackage[];\n };\n}\n\nexport interface ContractSpaceSeedPhaseInputs {\n readonly migrationsDir: string;\n readonly extensionPacks: ReadonlyArray<SeedPhaseExtensionInput>;\n}\n\n/**\n * One per-space record describing what the seed phase did for an\n * extension contract space. Surfaced verbatim by the caller (typically\n * `migration plan`) so users see a single line per touched extension.\n *\n * - `action: 'updated'` — either the on-disk head pointer changed, or\n * one or more new descriptor-shipped migration packages were\n * materialised into `migrations/<spaceId>/<dirName>/`.\n * - `action: 'unchanged'` — the on-disk head already matched the\n * descriptor and no new migration packages needed to be written.\n *\n * Either way, the artefacts (`contract.json`, `contract.d.ts`,\n * `refs/head.json`) are re-emitted: the framework owns those files and\n * makes the re-emit observably idempotent at the byte level.\n */\nexport interface ContractSpaceSeedPhaseRecord {\n readonly spaceId: string;\n readonly action: 'updated' | 'unchanged';\n readonly priorHash: string | null;\n readonly newHash: string;\n readonly newMigrationDirs: readonly string[];\n}\n\nexport interface ContractSpaceSeedPhaseResult {\n readonly seeded: readonly ContractSpaceSeedPhaseRecord[];\n}\n\n/**\n * Phase-1 of the two-phase `migration plan` pipeline (sub-spec § 4).\n *\n * For every extension that exposes a `contractSpace`:\n *\n * 1. Read the on-disk head ref (returns `null` on first emit).\n * 2. Re-emit `contract.json` / `contract.d.ts` / `refs/head.json`\n * unconditionally via {@link emitContractSpaceArtefacts}. The\n * framework owns these files; re-emit is the contract.\n * 3. Materialise any descriptor-shipped migration packages not yet on\n * disk via {@link materialiseExtensionMigrationPackageIfMissing}.\n * Existing packages are left untouched (by-existence skip).\n *\n * The return value lets the caller render a per-space status line and\n * lets the phase-2 aggregate loader run on a now-consistent disk state\n * (every loaded extension is guaranteed to have its head ref pinned\n * to the descriptor's hash and to ship every package the descriptor\n * declares).\n *\n * Output ordering is deterministic and alphabetical by spaceId (via\n * {@link planAllSpaces}, which also detects duplicate spaceIds). This\n * matches the canonical sort order used by every other aggregate\n * surface (`migrate`, `migration status`, the runner).\n */\nexport async function runContractSpaceSeedPhase(\n inputs: ContractSpaceSeedPhaseInputs,\n): Promise<ContractSpaceSeedPhaseResult> {\n const planInputs = inputs.extensionPacks\n .filter(\n (\n pack,\n ): pack is SeedPhaseExtensionInput & {\n contractSpace: NonNullable<SeedPhaseExtensionInput['contractSpace']>;\n } => pack.contractSpace !== undefined,\n )\n .map((pack) => ({\n spaceId: pack.id,\n priorContract: null,\n newContract: pack.contractSpace.contractJson,\n __pack: pack.contractSpace,\n }));\n\n // `planAllSpaces` brings deterministic alphabetical ordering and\n // duplicate-spaceId detection. The \"planner\" callback is a no-op\n // pass-through that simply returns the descriptor's pre-built\n // migration packages.\n const planned: readonly SpacePlanOutput<DescriptorMigrationPackage>[] = planAllSpaces(\n planInputs,\n (input) =>\n (\n input as typeof input & {\n readonly __pack: NonNullable<SeedPhaseExtensionInput['contractSpace']>;\n }\n ).__pack.migrations,\n );\n\n // Reassemble a spaceId → descriptor lookup so the loop below can read\n // the contractJson / headRef without leaking the typed-cast back into\n // `planAllSpaces`'s output shape.\n const descriptorBySpace = new Map<\n string,\n NonNullable<SeedPhaseExtensionInput['contractSpace']>\n >();\n for (const pack of inputs.extensionPacks) {\n if (pack.contractSpace !== undefined) descriptorBySpace.set(pack.id, pack.contractSpace);\n }\n\n const seeded: ContractSpaceSeedPhaseRecord[] = [];\n for (const space of planned) {\n const descriptor = descriptorBySpace.get(space.spaceId);\n if (descriptor === undefined) continue;\n\n const onDiskHeadRef = await readContractSpaceHeadRef(inputs.migrationsDir, space.spaceId);\n const priorHash = onDiskHeadRef?.hash ?? null;\n\n await emitContractSpaceArtefacts(inputs.migrationsDir, space.spaceId, {\n contract: descriptor.contractJson,\n contractDts: buildPlaceholderContractDts(space.spaceId),\n headRef: { hash: descriptor.headRef.hash, invariants: descriptor.headRef.invariants },\n });\n\n const spaceDir = spaceMigrationDirectory(inputs.migrationsDir, space.spaceId);\n const newMigrationDirs: string[] = [];\n for (const pkg of space.migrationPackages) {\n const { written } = await materialiseExtensionMigrationPackageIfMissing(spaceDir, pkg);\n if (written) newMigrationDirs.push(pkg.dirName);\n }\n\n const action: ContractSpaceSeedPhaseRecord['action'] =\n priorHash !== descriptor.headRef.hash || newMigrationDirs.length > 0\n ? 'updated'\n : 'unchanged';\n\n seeded.push({\n spaceId: space.spaceId,\n action,\n priorHash,\n newHash: descriptor.headRef.hash,\n newMigrationDirs,\n });\n }\n\n return { seeded };\n}\n\n/**\n * Placeholder `.d.ts` content for an extension space's on-disk mirror.\n *\n * Rendering a fully-typed `.d.ts` for an extension contract requires\n * the SQL-family renderer with the codec / typemap registry threaded\n * through; until that integration ships, the on-disk `.d.ts` is a\n * stub `export {};` module that documents how consumers should\n * validate the sibling `contract.json`. The stub typechecks on its\n * own and does not need any TypeScript suppressions.\n */\nfunction buildPlaceholderContractDts(spaceId: string): string {\n return [\n '/**',\n ` * Placeholder \\`.d.ts\\` for extension space \"${spaceId}\".`,\n ' *',\n ' * The framework re-emits this file on every `migration plan` run',\n ' * alongside `contract.json` and `refs/head.json`. A typed `.d.ts`',\n ' * rendering pass for extension contracts is tracked separately;',\n ' * until that ships, consumers should import `contract.json`',\n ' * and pass it through the target descriptor’s `contractSerializer`.',\n ' */',\n 'export {};',\n '',\n ].join('\\n');\n}\n","import { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport {\n type ControlFamilyInstance,\n createControlStack,\n hasOperationPreview,\n type MigrationPlanOperation,\n type OperationPreview,\n} from '@prisma-next/framework-components/control';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { computeMigrationHash } from '@prisma-next/migration-tools/hash';\nimport { deriveProvidedInvariants } from '@prisma-next/migration-tools/invariants';\nimport {\n copyFilesWithRename,\n formatMigrationDirName,\n writeMigrationPackage,\n} from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport { findLatestMigration } from '@prisma-next/migration-tools/migration-graph';\nimport { writeMigrationTs } from '@prisma-next/migration-tools/migration-ts';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join, relative } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliErrorConflict,\n CliStructuredError,\n errorContractValidationFailed,\n errorFileNotFound,\n errorMigrationPlanningFailed,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n getTargetMigrations,\n loadMigrationPackages,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { buildContractSpaceAggregate } from '../utils/contract-space-aggregate-loader';\nimport { runContractSpaceSeedPhase } from '../utils/contract-space-seed-phase';\nimport { toExtensionInputs } from '../utils/extension-pack-inputs';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport { assertFrameworkComponentsCompatible } from '../utils/framework-components';\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 MigrationPlanOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly name?: string;\n readonly from?: string;\n}\n\n/**\n * Load a predecessor migration's destination contract from its sibling\n * `end-contract.json` on disk and route it through the family's\n * `ContractSerializer` (via `deserializeContract`) so the in-memory shape\n * is the hydrated `Contract` every other caller sees. Bypassing this\n * seam was the root cause of TML-2536: a raw `JSON.parse(...) as Contract`\n * here let polymorphic `storage.types` entries reach the planner without\n * the `kind` discriminator the planner dispatches on.\n *\n * Throws `CliStructuredError` with:\n * - `errorFileNotFound` when the sibling file is missing — the user\n * has likely deleted or never authored the snapshot, and the\n * message names the file and points them at re-emitting from the\n * source.\n * - `errorContractValidationFailed` when the JSON parses but the\n * family deserializer rejects it (legacy untagged shape, structural\n * mismatch, etc.) — the message names the predecessor's path so\n * the operator can locate the bad snapshot.\n */\nasync function readPredecessorEndContract(\n migrationDir: string,\n familyInstance: ControlFamilyInstance<string, unknown>,\n): Promise<Contract> {\n const path = join(migrationDir, 'end-contract.json');\n let raw: string;\n try {\n raw = await readFile(path, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n throw errorFileNotFound(path, {\n why: `Predecessor migration is missing its destination contract snapshot at ${path}`,\n fix: 'Re-emit the predecessor migration (`prisma-next migration plan` from its source) so its sibling `end-contract.json` is restored, then re-run this command.',\n });\n }\n throw error;\n }\n try {\n return familyInstance.deserializeContract(JSON.parse(raw) as unknown);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n throw error;\n }\n throw errorContractValidationFailed(\n `Predecessor contract at ${path} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path } },\n );\n }\n}\n\nexport interface MigrationPlanResult {\n readonly ok: boolean;\n readonly noOp: boolean;\n readonly from: string | null;\n readonly to: string;\n readonly dir?: string;\n /**\n * Extension-space migration packages materialised onto disk during this\n * `plan` run. Each entry names a `migrations/<spaceId>/<dirName>/`\n * tree the framework wrote alongside the app-space migration directory.\n * Empty when the project has no extension packs declaring a contract\n * space, or when every extension-space package is already on disk.\n *\n * Surfacing these in the result (rather than only via `ui.step` log\n * lines) makes the cross-space side effect explicit to JSON consumers\n * and the success-summary renderer — the same multi-space side effect\n * that `migrate` will replay.\n */\n readonly emittedExtensionDirs: readonly { readonly spaceId: string; readonly dirName: string }[];\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n /**\n * Family-agnostic textual preview of the migration plan operations.\n * Replaces the previous `sql?: readonly string[]` field; consumers should\n * read `result.preview?.statements`.\n */\n readonly preview?: OperationPreview;\n readonly summary: string;\n /**\n * When true, `migration.ts` was written but contains unfilled\n * `placeholder(...)` calls. The user must edit the file and then run\n * `node migration.ts` to self-emit `ops.json` / `migration.json`.\n */\n readonly pendingPlaceholders?: boolean;\n readonly timings: {\n readonly total: number;\n };\n}\n\nasync function executeMigrationPlanCommand(\n options: MigrationPlanOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrationPlanResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative } =\n resolveMigrationPaths(options.config, config);\n\n const contractPathAbsolute = resolveContractPath(config);\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n { label: 'migrations', value: appMigrationsRelative },\n ];\n if (options.from) {\n details.push({ label: 'from', value: options.from });\n }\n if (options.name) {\n details.push({ label: 'name', value: options.name });\n }\n const header = formatStyledHeader({\n command: 'migration plan',\n description: 'Plan a migration from contract changes',\n url: 'https://pris.ly/migration-plan',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n // Load contract file (the \"to\" contract)\n let contractJsonContent: string;\n try {\n contractJsonContent = 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 ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Construct the family instance up-front so on-disk reads (the app\n // contract here + every `readPredecessorEndContract` below) cross the\n // serializer seam at the read site, not after the planner has already\n // started dispatching on raw shapes. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n let toContract: Contract;\n try {\n toContract = familyInstance.deserializeContract(JSON.parse(contractJsonContent) 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 const rawStorageHash = toContract.storage?.storageHash;\n if (typeof rawStorageHash !== 'string') {\n return notOk(\n errorContractValidationFailed('Contract is missing storageHash', {\n where: { path: contractPathAbsolute },\n }),\n );\n }\n const toStorageHash = rawStorageHash;\n\n // Read existing migrations and determine \"from\" contract\n let fromContract: Contract | null = null;\n let fromHash: string | null = null;\n let fromContractSourceDir: string | null = null;\n\n try {\n const { bundles, graph } = await loadMigrationPackages(appMigrationsDir);\n\n if (options.from) {\n const refs = await readRefs(resolveMigrationPaths(options.config, config).refsDir);\n const refResult = parseContractRef(options.from, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n fromHash = refResult.value.hash;\n const matchingBundle = bundles.find((p) => p.metadata.to === fromHash);\n if (!matchingBundle) {\n return notOk(\n errorUnexpected(\n `No migration bundle found for --from \"${options.from}\" (resolved hash: ${fromHash})`,\n {\n why: `The ref resolved successfully but no on-disk migration package has an end-contract hash matching ${fromHash}.`,\n fix: 'Provide a ref or hash that corresponds to an existing migration package, or run `migration list` to see available migrations.',\n },\n ),\n );\n }\n fromContractSourceDir = matchingBundle.dirPath;\n fromContract = await readPredecessorEndContract(fromContractSourceDir, familyInstance);\n } else {\n const latestMigration = findLatestMigration(graph);\n if (latestMigration) {\n fromHash = latestMigration.to;\n const leafPkg = bundles.find(\n (p) => p.metadata.migrationHash === latestMigration.migrationHash,\n );\n if (leafPkg) {\n fromContractSourceDir = leafPkg.dirPath;\n fromContract = await readPredecessorEndContract(fromContractSourceDir, familyInstance);\n }\n }\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n // `readPredecessorEndContract` raises a `CliStructuredError` directly\n // for the missing-snapshot case so the operator gets a precise\n // why/fix; pass it through unchanged rather than re-wrapping.\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n // Wrap unexpected (non-MigrationToolsError) failures from the migration\n // load phase in a structured CLI envelope. Letting them throw would\n // bypass `handleResult()` and crash the command — see CLI structured-\n // errors guideline (CliStructuredError + Result pattern).\n const message = error instanceof Error ? error.message : String(error);\n return notOk(\n errorUnexpected(message, {\n why: `Unexpected error while loading migrations: ${message}`,\n }),\n );\n }\n\n // Phase 1 — seed: unconditionally re-emit per-space pinned artefacts\n // (contract.json / contract.d.ts / refs/head.json) and materialise any\n // descriptor-shipped migration packages not yet on disk. Runs before\n // the no-op check so that an extension bump alone (with no structural\n // app-space change) still re-pins extension artefacts on disk.\n const canonicalExtensionInputs = toExtensionInputs(config.extensionPacks ?? []);\n const seedResult = await runContractSpaceSeedPhase({\n migrationsDir,\n extensionPacks: canonicalExtensionInputs,\n });\n if (!flags.json && !flags.quiet) {\n for (const record of seedResult.seeded) {\n if (record.action === 'updated') {\n const pkgSuffix =\n record.newMigrationDirs.length > 0\n ? `; ${record.newMigrationDirs.length} new migration package(s) materialised`\n : '';\n ui.step(`Updated ${record.spaceId} to ${record.newHash}${pkgSuffix}`);\n }\n }\n }\n const emittedExtensionDirs = seedResult.seeded.flatMap((r) =>\n r.newMigrationDirs.map((dirName) => ({ spaceId: r.spaceId, dirName })),\n );\n\n // Check for no-op (same hash means no changes)\n if (fromHash === toStorageHash) {\n const result: MigrationPlanResult = {\n ok: true,\n noOp: true,\n from: fromHash,\n to: toStorageHash,\n operations: [],\n emittedExtensionDirs,\n summary: 'No changes detected between contracts',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n // Check target supports migrations\n const migrations = getTargetMigrations(config.target);\n if (!migrations) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n // Phase 2 — load: build the aggregate against the now-consistent disk\n // state that phase 1 just seeded. The seed phase guarantees every\n // declared extension has its head ref pinned, so the loader's\n // declaredButUnmigrated precheck always passes here. The app contract\n // was already routed through `familyInstance.deserializeContract` at the\n // read site above (see TML-2536), so it's the hydrated `Contract`\n // here — no second validation pass needed.\n const aggregateResult = await buildContractSpaceAggregate({\n targetId: config.target.targetId,\n migrationsDir,\n appContract: toContract,\n extensionPacks: config.extensionPacks ?? [],\n deserializeContract: (json: unknown) => familyInstance.deserializeContract(json),\n });\n if (!aggregateResult.ok) {\n return notOk(aggregateResult.failure);\n }\n const aggregate = aggregateResult.value;\n\n const frameworkComponents = assertFrameworkComponentsCompatible(\n config.family.familyId,\n config.target.targetId,\n [config.target, config.adapter, ...(config.extensionPacks ?? [])],\n );\n\n // Build manifest and write migration package\n const timestamp = new Date();\n const slug = options.name ?? 'migration';\n const dirName = formatMigrationDirName(timestamp, slug);\n const packageDir = join(appMigrationsDir, dirName);\n\n const baseMetadata: Omit<MigrationMetadata, 'migrationHash' | 'providedInvariants'> = {\n from: fromHash,\n to: toStorageHash,\n hints: {\n used: [],\n applied: [],\n plannerVersion: '2.0.0',\n },\n labels: [],\n createdAt: timestamp.toISOString(),\n };\n\n try {\n const planner = migrations.createPlanner(familyInstance);\n const fromSchema = migrations.contractToSchema(fromContract, frameworkComponents);\n const plannerResult = planner.plan({\n contract: aggregate.app.contract,\n schema: fromSchema,\n policy: { allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'] },\n fromContract,\n frameworkComponents,\n spaceId: aggregate.app.spaceId,\n });\n if (plannerResult.kind === 'failure') {\n return notOk(\n errorMigrationPlanningFailed({\n conflicts: plannerResult.conflicts as readonly CliErrorConflict[],\n }),\n );\n }\n\n // Accessing .operations triggers toOp() on each call. If any call\n // is a DataTransformCall with an unfilled placeholder stub, toOp()\n // throws PN-MIG-2001. We catch that here so the migration can still\n // be scaffolded with `ops: []`; the user fills the placeholder, then\n // re-runs `node migration.ts` to attest with the real ops.\n let plannedOps: readonly MigrationPlanOperation[] = [];\n let hasPlaceholders = false;\n try {\n plannedOps = plannerResult.plan.operations;\n if (plannedOps.length === 0) {\n return notOk(\n errorMigrationPlanningFailed({\n conflicts: [\n {\n kind: 'unsupportedChange',\n summary:\n 'Contract changed but planner produced no operations. ' +\n 'This indicates unsupported or ignored changes.',\n },\n ],\n }),\n );\n }\n } catch (e) {\n if (CliStructuredError.is(e) && e.domain === 'MIG' && e.code === '2001') {\n hasPlaceholders = true;\n } else {\n throw e;\n }\n }\n\n const migrationTsContent = plannerResult.plan.renderTypeScript();\n\n // Always-attest: compute migrationHash over (metadata, ops). When\n // placeholders blocked lowering, ops is `[]` and the hash is computed\n // over the empty list — re-emitting after the user fills the placeholder\n // produces a different hash (over the real ops). This is intentional;\n // there is no on-disk \"draft\" state.\n const opsForWrite = hasPlaceholders ? [] : plannedOps;\n const metadataWithInvariants: Omit<MigrationMetadata, 'migrationHash'> = {\n ...baseMetadata,\n providedInvariants: deriveProvidedInvariants(opsForWrite),\n };\n const metadata: MigrationMetadata = {\n ...metadataWithInvariants,\n migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite),\n };\n\n await writeMigrationPackage(packageDir, metadata, opsForWrite);\n const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);\n await copyFilesWithRename(packageDir, [\n { sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },\n { sourcePath: destinationArtifacts.dtsPath, destName: 'end-contract.d.ts' },\n ]);\n if (fromContractSourceDir !== null) {\n const sourceArtifacts = getEmittedArtifactPaths(\n join(fromContractSourceDir, 'end-contract.json'),\n );\n await copyFilesWithRename(packageDir, [\n { sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },\n { sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },\n ]);\n }\n await writeMigrationTs(packageDir, migrationTsContent);\n\n if (hasPlaceholders) {\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), packageDir),\n operations: [],\n emittedExtensionDirs,\n pendingPlaceholders: true,\n summary:\n 'Planned migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const preview = hasOperationPreview(familyInstance)\n ? familyInstance.toOperationPreview(plannedOps)\n : undefined;\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), packageDir),\n operations: plannedOps.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n emittedExtensionDirs,\n ...(preview !== undefined ? { preview } : {}),\n summary: buildPlanSummary(plannedOps.length, emittedExtensionDirs.length),\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\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 const message = error instanceof Error ? error.message : String(error);\n return notOk(\n errorUnexpected(message, {\n why: `Unexpected error during migration plan: ${message}`,\n }),\n );\n }\n}\n\nexport function createMigrationPlanCommand(): Command {\n const command = new Command('plan');\n setCommandDescriptions(\n command,\n 'Plan a migration from contract changes',\n 'Compares the emitted contract against the latest on-disk migration state and\\n' +\n 'produces a new migration package with the required operations. No database\\n' +\n 'connection is needed — this is a fully offline operation.',\n );\n setCommandExamples(command, [\n 'prisma-next migration plan',\n 'prisma-next migration plan --name add-users-table',\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--name <slug>', 'Name slug for the migration directory', 'migration')\n .option(\n '--from <contract>',\n 'Starting contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .action(async (options: MigrationPlanOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const startTime = Date.now();\n\n const ui = createTerminalUI(flags);\n const result = await executeMigrationPlanCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (planResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(planResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationPlanOutput(planResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n\n/**\n * Compose the success-line summary so the cross-space side effect\n * (extension-space migration packages materialised on disk during\n * this `plan` run) is visible in the top line — not just in the\n * step log above it.\n *\n * Example outputs:\n * - `Planned 3 operation(s)` (app-space-only project)\n * - `Planned 3 operation(s); materialised 1 extension-space migration` (one extension)\n * - `Planned 3 operation(s); materialised 2 extension-space migrations` (two extensions)\n *\n * Locks AC3 at the summary-line level: a reader of the success line\n * can tell that something happened beyond the app space.\n */\nfunction buildPlanSummary(plannedOpsCount: number, emittedExtensionDirsCount: number): string {\n const base = `Planned ${plannedOpsCount} operation(s)`;\n if (emittedExtensionDirsCount === 0) return base;\n const noun =\n emittedExtensionDirsCount === 1 ? 'extension-space migration' : 'extension-space migrations';\n return `${base}; materialised ${emittedExtensionDirsCount} ${noun}`;\n}\n\nexport function formatMigrationPlanOutput(result: MigrationPlanResult, flags: GlobalFlags): string {\n const lines: string[] = [];\n const useColor = flags.color !== false;\n\n const green_ = useColor ? (s: string) => `\\x1b[32m${s}\\x1b[0m` : (s: string) => s;\n const yellow_ = useColor ? (s: string) => `\\x1b[33m${s}\\x1b[0m` : (s: string) => s;\n const dim_ = useColor ? (s: string) => `\\x1b[2m${s}\\x1b[0m` : (s: string) => s;\n\n // Renders the extension-space materialisation block + canonical apply-step\n // hint shared by the no-op, placeholder, and full-plan branches. The app\n // space short-circuits do not skip it: an extension-only bump emits new\n // `migrations/<spaceId>/<dirName>/` directories on disk that the user\n // still has to apply, so the success line must surface them.\n function appendEmittedExtensions(): void {\n if (result.emittedExtensionDirs.length === 0) return;\n lines.push('');\n lines.push(dim_('Emitted extension migrations:'));\n for (const entry of result.emittedExtensionDirs) {\n lines.push(dim_(` ${entry.spaceId} → migrations/${entry.spaceId}/${entry.dirName}`));\n }\n lines.push('');\n lines.push(\n `Next: review the extension migrations above, then run ${green_('prisma-next migrate')}.`,\n );\n }\n\n if (result.noOp) {\n lines.push(`${green_('✔')} No changes detected`);\n lines.push(dim_(` from: ${result.from}`));\n lines.push(dim_(` to: ${result.to}`));\n appendEmittedExtensions();\n return lines.join('\\n');\n }\n\n if (result.pendingPlaceholders) {\n lines.push(`${yellow_('⚠')} ${result.summary}`);\n lines.push('');\n lines.push(dim_(`from: ${result.from}`));\n lines.push(dim_(`to: ${result.to}`));\n if (result.dir) {\n lines.push(dim_(`dir: ${result.dir}`));\n }\n lines.push('');\n lines.push(\n 'Open migration.ts and replace each `placeholder(...)` call with your actual query.',\n );\n lines.push(`Then run: ${green_(`node ${result.dir ?? '<dir>'}/migration.ts`)}`);\n appendEmittedExtensions();\n return lines.join('\\n');\n }\n\n lines.push(`${green_('✔')} ${result.summary}`);\n lines.push('');\n\n if (result.operations.length > 0) {\n lines.push(dim_('│'));\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 // operationClass tag is intentionally NOT inlined per spec:\n // a destructive footer warning still surfaces below this list.\n const destructiveMarker =\n op.operationClass === 'destructive' ? ` ${yellow_('(destructive)')}` : '';\n lines.push(`${dim_(treeChar)}─ ${op.label}${destructiveMarker}`);\n }\n\n const hasDestructive = result.operations.some((op) => op.operationClass === 'destructive');\n if (hasDestructive) {\n lines.push('');\n lines.push(\n `${yellow_('⚠')} This migration contains destructive operations that may cause data loss.`,\n );\n }\n lines.push('');\n }\n\n lines.push(dim_(`from: ${result.from}`));\n lines.push(dim_(`to: ${result.to}`));\n if (result.dir) {\n lines.push(dim_(`App space → ${result.dir}`));\n }\n // Per-space block: surface the extension-space directories materialised\n // alongside the app-space migration. Without this block the cross-space\n // side effect is invisible in the success summary (e2e finding F1).\n for (const entry of result.emittedExtensionDirs) {\n lines.push(\n dim_(`Extension space ${entry.spaceId} → migrations/${entry.spaceId}/${entry.dirName}`),\n );\n }\n\n lines.push('');\n // The \"Next:\" hint always points at the canonical apply path\n // (`prisma-next migrate`) regardless of how many spaces were\n // materialised — `db update` is a dev-time convenience, not the\n // canonical replay step.\n lines.push(\n `Next: review ${green_(result.dir ?? '<dir>')} if needed, then run ${green_('prisma-next migrate')}.`,\n );\n\n if (result.preview && result.preview.statements.length > 0) {\n // The non-empty length is already guaranteed by the surrounding check, so\n // a plain `every` here is equivalent to the helper in formatters/migrations.ts.\n const allSql = result.preview.statements.every((s) => s.language === 'sql');\n lines.push('');\n lines.push(dim_(allSql ? 'DDL preview' : 'Operation preview'));\n lines.push('');\n for (const statement of result.preview.statements) {\n const trimmed = statement.text.trim();\n if (!trimmed) continue;\n const line = statement.language === 'sql' && !trimmed.endsWith(';') ? `${trimmed};` : trimmed;\n lines.push(line);\n }\n }\n\n if (flags.verbose && result.timings) {\n lines.push('');\n lines.push(dim_(`Total time: ${result.timings.total}ms`));\n }\n\n return lines.join('\\n');\n}\n\nexport type PrefixResolutionFailure =\n | { reason: 'ambiguous'; count: number }\n | { reason: 'not-found' };\n\n/**\n * Resolve a migration package by **target contract hash** (`metadata.to`)\n * using exact match or prefix match.\n *\n * Note: matches `metadata.to` (the contract hash this migration produces),\n * not `metadata.migrationHash` (the package's content-addressed identity).\n * Tries exact match first, then prefix match (auto-prepending `sha256:` when\n * the needle omits the scheme). Returns the matched package on success, or a\n * discriminated failure indicating whether the prefix was ambiguous or simply\n * not found.\n *\n * @internal Exported for testing only.\n */\nexport function resolveBundleByPrefix<T extends { metadata: { to: string } }>(\n bundles: readonly T[],\n needle: string,\n): Result<T, PrefixResolutionFailure> {\n const exact = bundles.find((p) => p.metadata.to === needle);\n if (exact) return ok(exact);\n\n const prefixWithScheme = needle.startsWith('sha256:') ? needle : `sha256:${needle}`;\n const candidates = bundles.filter((p) => p.metadata.to.startsWith(prefixWithScheme));\n\n if (candidates.length === 1) return ok(candidates[0]!);\n if (candidates.length > 1) return notOk({ reason: 'ambiguous', count: candidates.length });\n return notOk({ reason: 'not-found' });\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"migrations-CwZMa1Ck.mjs","names":[],"sources":["../src/utils/formatters/migrations.ts"],"sourcesContent":["import type { OperationPreview } from '@prisma-next/framework-components/control';\nimport { cyan, green, yellow } from 'colorette';\n\nimport type { AggregatePerSpaceExecutionEntry } from '../../control-api/types';\nimport type { GlobalFlags } from '../global-flags';\nimport { createColorFormatter, formatDim, isVerbose } from './helpers';\n\n/**\n * Render a single statement of an `OperationPreview` for the human-readable\n * preview block. SQL statements get a trailing `;` if missing so the rendered\n * preview is byte-identical to the legacy `string[]`-based renderer for SQL\n * targets. Other languages (`'mongodb-shell'`) render verbatim.\n */\nfunction renderPreviewStatement(text: string, language: string): string | undefined {\n const trimmed = text.trim();\n if (!trimmed) return undefined;\n if (language === 'sql') {\n return trimmed.endsWith(';') ? trimmed : `${trimmed};`;\n }\n return trimmed;\n}\n\n/**\n * Choose the header label for a preview block. SQL-only previews keep the\n * legacy `DDL preview` label so the rendered output is byte-identical to the\n * pre-aggregate SQL CLI; previews from any other family — or a mix that\n * includes any non-SQL language — use the family-agnostic `Operation preview`\n * label.\n *\n * An empty `statements` array deliberately renders as `Operation preview`\n * rather than `DDL preview`: `Array.prototype.every` is vacuously true for\n * empty arrays, but we have no evidence the preview is SQL-only when no\n * statements are present, so the family-agnostic label is the safer default.\n */\nexport function previewBlockHeader(preview: OperationPreview): string {\n const allSql =\n preview.statements.length > 0 && preview.statements.every((s) => s.language === 'sql');\n return allSql ? 'DDL preview' : 'Operation preview';\n}\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 /**\n * Family-agnostic textual preview of the planned operations. Replaces the\n * previous `sql?: readonly string[]`. Consumers should read\n * `plan.preview?.statements`.\n */\n readonly preview?: OperationPreview;\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 /**\n * Per-space execution breakdown in canonical schedule order\n * (extensions alphabetically, then app). Surfaces per-space markers\n * and the ops grouped by space, so the CLI summary can name which\n * space each op and marker belongs to instead of flattening them\n * into a single ambiguous list. See {@link AggregatePerSpaceExecutionEntry}.\n */\n readonly perSpace?: ReadonlyArray<AggregatePerSpaceExecutionEntry>;\n readonly summary: string;\n readonly timings: {\n readonly total: number;\n };\n}\n\n/**\n * Render the shared per-space execution block consumed by the `db init`\n * / `db update` / `migrate` summaries. Always shows: space\n * label (`Extension space: <id>` or `App space`) → per-op lines under\n * each space → per-space marker hash (when known).\n *\n * `mode` controls the marker label phrasing — `'apply'` shows\n * `marker → <hash>` (post-apply), `'plan'` omits the marker line\n * entirely (no marker has been written yet).\n */\nexport function formatPerSpaceBlock(\n perSpace: ReadonlyArray<AggregatePerSpaceExecutionEntry>,\n mode: 'plan' | 'apply',\n useColor: boolean,\n): readonly string[] {\n const formatYellow = createColorFormatter(useColor, yellow);\n const formatCyan = createColorFormatter(useColor, cyan);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n const lines: string[] = [];\n for (let s = 0; s < perSpace.length; s++) {\n const space = perSpace[s]!;\n if (s > 0) lines.push('');\n const header =\n space.kind === 'app'\n ? formatCyan('App space')\n : formatCyan(`Extension space: ${space.spaceId}`);\n lines.push(header);\n if (space.operations.length === 0) {\n lines.push(` ${formatDimText('(no operations)')}`);\n } else {\n for (let i = 0; i < space.operations.length; i++) {\n const op = space.operations[i]!;\n const isLast = i === space.operations.length - 1;\n const treeChar = isLast ? '└' : '├';\n const destructiveMarker =\n op.operationClass === 'destructive' ? ` ${formatYellow('(destructive)')}` : '';\n lines.push(` ${formatDimText(treeChar)}─ ${op.label}${destructiveMarker}`);\n }\n }\n if (mode === 'apply' && space.marker) {\n lines.push(` ${formatDimText(`marker: ${space.marker.storageHash}`)}`);\n }\n }\n return lines;\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 const spaceCount = result.perSpace?.length ?? 0;\n if (spaceCount > 0) {\n lines.push(\n `${formatGreen('✔')} Planned ${operationCount} operation(s) across ${spaceCount} contract space${spaceCount === 1 ? '' : 's'}`,\n );\n } else {\n lines.push(`${formatGreen('✔')} Planned ${operationCount} operation(s)`);\n }\n\n const formatYellow = createColorFormatter(useColor, yellow);\n\n // Per-space breakdown takes precedence over the flat ops tree when\n // the aggregate flow surfaced one.\n if (result.perSpace && result.perSpace.length > 0) {\n lines.push('');\n lines.push(...formatPerSpaceBlock(result.perSpace, 'plan', useColor));\n const hasDestructive = result.perSpace.some((s) =>\n s.operations.some((op) => op.operationClass === 'destructive'),\n );\n if (hasDestructive) {\n lines.push('');\n lines.push(\n `${formatYellow('⚠')} This migration contains destructive operations that may cause data loss.`,\n );\n }\n } else if (result.plan?.operations && result.plan.operations.length > 0) {\n // Single-space fallback (no aggregate breakdown). Same flat tree\n // we've always rendered.\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 destructiveMarker =\n op.operationClass === 'destructive' ? ` ${formatYellow('(destructive)')}` : '';\n lines.push(`${formatDimText(treeChar)}─ ${op.label}${destructiveMarker}`);\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 // Statement preview (any family that implements OperationPreviewCapable)\n const preview = result.plan?.preview;\n if (preview) {\n lines.push('');\n lines.push(`${formatDimText(previewBlockHeader(preview))}`);\n if (preview.statements.length === 0) {\n lines.push(`${formatDimText('No operations.')}`);\n } else {\n lines.push('');\n for (const statement of preview.statements) {\n const rendered = renderPreviewStatement(statement.text, statement.language);\n if (rendered) {\n lines.push(rendered);\n }\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 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 /**\n * Per-space breakdown in canonical schedule order (extensions\n * alphabetically, then app). Always present for the aggregate-walking\n * `migrate` command.\n */\n readonly perSpace: readonly AggregatePerSpaceExecutionEntry[];\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 lines.push(`${formatGreen('✔')} ${result.summary}`);\n\n if (result.perSpace.length > 0) {\n lines.push('');\n for (const line of formatPerSpaceBlock(result.perSpace, 'apply', useColor)) {\n lines.push(line);\n }\n }\n\n lines.push('');\n lines.push(formatDimText('Next: prisma-next migration status'));\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 MigrationShowSpacePresent {\n readonly kind: 'present';\n readonly spaceId: string;\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 preview: OperationPreview;\n readonly summary: string;\n}\n\ninterface MigrationShowSpaceMissing {\n readonly kind: 'missing';\n readonly spaceId: string;\n readonly summary: string;\n}\n\ntype MigrationShowSpaceResult = MigrationShowSpacePresent | MigrationShowSpaceMissing;\n\ninterface MigrationShowResult {\n readonly spaces: readonly MigrationShowSpaceResult[];\n}\n\nfunction formatSpaceShowBlock(\n space: MigrationShowSpacePresent,\n useColor: boolean,\n): readonly string[] {\n const formatGreen = createColorFormatter(useColor, green);\n const formatYellow = createColorFormatter(useColor, yellow);\n const formatDimText = (text: string) => formatDim(useColor, text);\n\n const lines: string[] = [];\n lines.push(`${formatGreen('✔')} ${space.dirName}`);\n lines.push(`${formatDimText(` from: ${space.from ?? '(baseline)'}`)}`);\n lines.push(`${formatDimText(` to: ${space.to}`)}`);\n lines.push(`${formatDimText(` migrationHash: ${space.migrationHash}`)}`);\n lines.push(`${formatDimText(` created: ${space.createdAt}`)}`);\n\n lines.push('');\n lines.push(`${space.operations.length} operation(s)`);\n\n if (space.operations.length > 0) {\n lines.push(`${formatDimText('│')}`);\n for (let i = 0; i < space.operations.length; i++) {\n const op = space.operations[i]!;\n const isLast = i === space.operations.length - 1;\n const treeChar = isLast ? '└' : '├';\n const destructiveMarker =\n op.operationClass === 'destructive' ? ` ${formatYellow('(destructive)')}` : '';\n lines.push(`${formatDimText(treeChar)}─ ${op.label}${destructiveMarker}`);\n }\n\n const hasDestructive = space.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 (space.preview.statements.length > 0) {\n lines.push('');\n lines.push(`${formatDimText(previewBlockHeader(space.preview))}`);\n lines.push('');\n for (const statement of space.preview.statements) {\n const rendered = renderPreviewStatement(statement.text, statement.language);\n if (rendered) {\n lines.push(rendered);\n }\n }\n }\n\n return lines;\n}\n\nexport function formatMigrationShowOutput(result: MigrationShowResult, flags: GlobalFlags): string {\n if (flags.quiet) {\n return '';\n }\n\n const useColor = flags.color !== false;\n const formatDimText = (text: string) => formatDim(useColor, text);\n const multipleSpaces = result.spaces.length > 1;\n const lines: string[] = [];\n\n for (let i = 0; i < result.spaces.length; i++) {\n const space = result.spaces[i]!;\n if (multipleSpaces) {\n lines.push(formatDimText(`── ${space.spaceId} ──`));\n }\n if (space.kind === 'missing') {\n lines.push(formatDimText(` ${space.summary}`));\n } else {\n for (const line of formatSpaceShowBlock(space, useColor)) {\n lines.push(line);\n }\n }\n if (i < result.spaces.length - 1) {\n lines.push('');\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 const spaceCount = result.perSpace?.length ?? 0;\n\n if (executed === 0) {\n const acrossClause =\n spaceCount > 0 ? ` across ${spaceCount} contract space${spaceCount === 1 ? '' : 's'}` : '';\n lines.push(`${formatGreen('✔')} Database already matches contract${acrossClause}`);\n } else if (spaceCount > 0) {\n lines.push(\n `${formatGreen('✔')} Applied ${executed} operation(s) across ${spaceCount} contract space${spaceCount === 1 ? '' : 's'}`,\n );\n } else {\n lines.push(`${formatGreen('✔')} Applied ${executed} operation(s)`);\n }\n\n // Per-space breakdown — replaces the single ambiguous `Signature:`\n // line with a per-space marker + ops listing.\n if (result.perSpace && result.perSpace.length > 0) {\n lines.push('');\n lines.push(...formatPerSpaceBlock(result.perSpace, 'apply', useColor));\n lines.push('');\n lines.push(\n formatDimText(\n `Run 'prisma-next migration status' to confirm ${\n spaceCount === 1 ? 'the space is' : 'all spaces are'\n } up to date.`,\n ),\n );\n } else if (result.marker) {\n // Single-space fallback (no aggregate breakdown surfaced — e.g.\n // older callers / non-aggregate code paths). The label is\n // `App-space marker` (not `Signature`) so that when only one\n // marker is observable we still name what it covers explicitly.\n lines.push(`${formatDimText(` App-space marker: ${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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"}