prisma-next 0.5.0-dev.36 → 0.5.0-dev.37

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 (41) hide show
  1. package/dist/cli.mjs +4 -4
  2. package/dist/{client-Buy8_40Y.mjs → client-1JqqkiC7.mjs} +3 -2
  3. package/dist/client-1JqqkiC7.mjs.map +1 -0
  4. package/dist/commands/contract-emit.mjs +1 -1
  5. package/dist/commands/contract-infer.mjs +1 -1
  6. package/dist/commands/db-init.mjs +3 -3
  7. package/dist/commands/db-schema.mjs +2 -2
  8. package/dist/commands/db-sign.mjs +2 -2
  9. package/dist/commands/db-update.mjs +3 -3
  10. package/dist/commands/db-verify.mjs +2 -2
  11. package/dist/commands/migration-apply.d.mts +3 -0
  12. package/dist/commands/migration-apply.d.mts.map +1 -1
  13. package/dist/commands/migration-apply.mjs +46 -23
  14. package/dist/commands/migration-apply.mjs.map +1 -1
  15. package/dist/commands/migration-new.mjs +3 -3
  16. package/dist/commands/migration-new.mjs.map +1 -1
  17. package/dist/commands/migration-plan.mjs +1 -1
  18. package/dist/commands/migration-ref.mjs +1 -1
  19. package/dist/commands/migration-show.mjs +2 -2
  20. package/dist/commands/migration-status.d.mts +18 -1
  21. package/dist/commands/migration-status.d.mts.map +1 -1
  22. package/dist/commands/migration-status.mjs +2 -2
  23. package/dist/{contract-emit-DWtGQYCD.mjs → contract-emit-rt_Nmdwq.mjs} +2 -2
  24. package/dist/{contract-emit-DWtGQYCD.mjs.map → contract-emit-rt_Nmdwq.mjs.map} +1 -1
  25. package/dist/{contract-infer-DmLiksNp.mjs → contract-infer-Cf5J2wVg.mjs} +3 -3
  26. package/dist/{contract-infer-DmLiksNp.mjs.map → contract-infer-Cf5J2wVg.mjs.map} +1 -1
  27. package/dist/exports/control-api.d.mts +8 -0
  28. package/dist/exports/control-api.d.mts.map +1 -1
  29. package/dist/exports/control-api.mjs +1 -1
  30. package/dist/exports/index.mjs +1 -1
  31. package/dist/{inspect-live-schema-6nsKS6m5.mjs → inspect-live-schema-LWtXfxm_.mjs} +3 -3
  32. package/dist/{inspect-live-schema-6nsKS6m5.mjs.map → inspect-live-schema-LWtXfxm_.mjs.map} +1 -1
  33. package/dist/{migration-command-scaffold-Ck1_lcsf.mjs → migration-command-scaffold-CU452v9h.mjs} +3 -3
  34. package/dist/{migration-command-scaffold-Ck1_lcsf.mjs.map → migration-command-scaffold-CU452v9h.mjs.map} +1 -1
  35. package/dist/{migration-status-DYJIRnK3.mjs → migration-status-DoPrFIOQ.mjs} +103 -34
  36. package/dist/migration-status-DoPrFIOQ.mjs.map +1 -0
  37. package/dist/{result-handler-BmVh8AeV.mjs → result-handler-Ch6hVnOo.mjs} +26 -3
  38. package/dist/{result-handler-BmVh8AeV.mjs.map → result-handler-Ch6hVnOo.mjs.map} +1 -1
  39. package/package.json +10 -10
  40. package/dist/client-Buy8_40Y.mjs.map +0 -1
  41. package/dist/migration-status-DYJIRnK3.mjs.map +0 -1
@@ -488,6 +488,26 @@ function resolveMigrationPaths(configOption, config) {
488
488
  refsDir: resolve(migrationsDir, "refs")
489
489
  };
490
490
  }
491
+ function collectDeclaredInvariants(graph) {
492
+ const declared = /* @__PURE__ */ new Set();
493
+ for (const edges of graph.forwardChain.values()) for (const edge of edges) for (const inv of edge.invariants) declared.add(inv);
494
+ return declared;
495
+ }
496
+ /**
497
+ * Maps a `MigrationEdge` to the structural-edge shape used in the
498
+ * `MIGRATION.NO_INVARIANT_PATH` error envelope. Shared between
499
+ * `migration apply` and `migration status` so both commands surface
500
+ * the same JSON wire shape when an invariant-aware route is unsatisfiable.
501
+ */
502
+ function toStructuralEdge(edge) {
503
+ return {
504
+ dirName: edge.dirName,
505
+ migrationHash: edge.migrationHash,
506
+ from: edge.from,
507
+ to: edge.to,
508
+ invariants: edge.invariants
509
+ };
510
+ }
491
511
  /**
492
512
  * Maps a PathDecision to the slim CLI output representation.
493
513
  */
@@ -497,12 +517,15 @@ function toPathDecisionResult(decision) {
497
517
  toHash: decision.toHash,
498
518
  alternativeCount: decision.alternativeCount,
499
519
  tieBreakReasons: decision.tieBreakReasons,
520
+ requiredInvariants: decision.requiredInvariants ?? [],
521
+ satisfiedInvariants: decision.satisfiedInvariants ?? [],
500
522
  ...ifDefined("refName", decision.refName),
501
523
  selectedPath: decision.selectedPath.map((entry) => ({
502
524
  dirName: entry.dirName,
503
525
  migrationHash: entry.migrationHash,
504
526
  from: entry.from,
505
- to: entry.to
527
+ to: entry.to,
528
+ invariants: entry.invariants
506
529
  }))
507
530
  };
508
531
  }
@@ -623,5 +646,5 @@ function handleResult(result, flags, ui, onSuccess) {
623
646
  }
624
647
 
625
648
  //#endregion
626
- export { formatStyledHeader as _, maskConnectionUrl as a, resolveMigrationPaths as c, setCommandExamples as d, targetSupportsMigrations as f, formatRootHelp as g, formatCommandHelp as h, loadMigrationPackages as i, sanitizeErrorMessage as l, parseGlobalFlags as m, addGlobalOptions as n, readContractEnvelope as o, toPathDecisionResult as p, getTargetMigrations as r, resolveContractPath as s, handleResult as t, setCommandDescriptions as u, formatSuccessMessage as v };
627
- //# sourceMappingURL=result-handler-BmVh8AeV.mjs.map
649
+ export { formatCommandHelp as _, loadMigrationPackages as a, formatSuccessMessage as b, resolveContractPath as c, setCommandDescriptions as d, setCommandExamples as f, parseGlobalFlags as g, toStructuralEdge as h, getTargetMigrations as i, resolveMigrationPaths as l, toPathDecisionResult as m, addGlobalOptions as n, maskConnectionUrl as o, targetSupportsMigrations as p, collectDeclaredInvariants as r, readContractEnvelope as s, handleResult as t, sanitizeErrorMessage as u, formatRootHelp as v, formatStyledHeader as y };
650
+ //# sourceMappingURL=result-handler-Ch6hVnOo.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"result-handler-BmVh8AeV.mjs","names":["LEFT_COLUMN_WIDTH","createPrismaNextBadge","formatHeaderLine","formatReadMoreLine","lines: string[]","lines: string[]","parts: string[]","current: Command | undefined","flags: {\n json?: boolean;\n quiet?: boolean;\n verbose?: number;\n color?: boolean;\n interactive?: boolean;\n yes?: boolean;\n }"],"sources":["../src/utils/formatters/styled.ts","../src/utils/formatters/help.ts","../src/utils/global-flags.ts","../src/utils/command-helpers.ts","../src/utils/result-handler.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, 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 'migration apply': 'https://pris.ly/migration-apply',\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 // 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","export interface GlobalFlags {\n readonly json?: boolean;\n readonly quiet?: boolean;\n readonly verbose?: number; // 0, 1, or 2\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 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\n/**\n * Parses global flags from CLI options.\n * Handles verbosity flags (-v, --trace), JSON output, quiet mode, color,\n * interactivity (--interactive/--no-interactive), and auto-accept (-y/--yes).\n */\nexport function parseGlobalFlags(options: CommonCommandOptions): GlobalFlags {\n const flags: {\n json?: boolean;\n quiet?: boolean;\n verbose?: number;\n color?: boolean;\n interactive?: boolean;\n yes?: boolean;\n } = {};\n\n // JSON output: explicit --json flag or auto-detect piped stdout (Unix convention)\n if (options.json || !process.stdout.isTTY) {\n flags.json = true;\n }\n\n // Quiet mode\n if (options.quiet || options.q) {\n flags.quiet = true;\n }\n\n // Verbosity: -v = 1, --trace = 2\n // Env toggles: PRISMA_NEXT_TRACE=1 ≅ --trace, PRISMA_NEXT_DEBUG=1 ≅ -v\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 // Color: respect NO_COLOR env var, --color/--no-color flags\n // When JSON output is enabled, disable color to ensure clean JSON output\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 // Default: enable color if TTY\n flags.color = process.stdout.isTTY && !process.env['CI'];\n }\n\n // Interactivity: --interactive/--no-interactive\n // Default: interactive when stdout is a TTY\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 // Auto-accept prompts: -y/--yes\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 { 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 { MigrationPackage } from '@prisma-next/migration-tools/package';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Command } from 'commander';\nimport { relative, resolve } from 'pathe';\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[]>();\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 * 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 * Centralises the fallback logic shared by every command that reads the contract.\n */\nexport function resolveContractPath(config: { contract?: { output?: string } }): string {\n return config.contract?.output\n ? resolve(config.contract.output)\n : resolve('src/prisma/contract.json');\n}\n\n/**\n * Resolves the migrations directory and config path from CLI options.\n * Shared by migration-apply, migration-plan, and migration-status.\n */\nexport function resolveMigrationPaths(\n configOption: string | undefined,\n config: { migrations?: { dir?: string } },\n): {\n configPath: string;\n migrationsDir: string;\n migrationsRelative: 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 refsDir = resolve(migrationsDir, 'refs');\n return { configPath, migrationsDir, migrationsRelative, refsDir };\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 selectedPath: readonly {\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\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 ...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 })),\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 MigrationPackage[];\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 * --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('--json', 'Output as 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","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"],"mappings":"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"}
1
+ {"version":3,"file":"result-handler-Ch6hVnOo.mjs","names":["LEFT_COLUMN_WIDTH","createPrismaNextBadge","formatHeaderLine","formatReadMoreLine","lines: string[]","lines: string[]","parts: string[]","current: Command | undefined","flags: {\n json?: boolean;\n quiet?: boolean;\n verbose?: number;\n color?: boolean;\n interactive?: boolean;\n yes?: boolean;\n }"],"sources":["../src/utils/formatters/styled.ts","../src/utils/formatters/help.ts","../src/utils/global-flags.ts","../src/utils/command-helpers.ts","../src/utils/result-handler.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, 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 'migration apply': 'https://pris.ly/migration-apply',\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 // 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","export interface GlobalFlags {\n readonly json?: boolean;\n readonly quiet?: boolean;\n readonly verbose?: number; // 0, 1, or 2\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 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\n/**\n * Parses global flags from CLI options.\n * Handles verbosity flags (-v, --trace), JSON output, quiet mode, color,\n * interactivity (--interactive/--no-interactive), and auto-accept (-y/--yes).\n */\nexport function parseGlobalFlags(options: CommonCommandOptions): GlobalFlags {\n const flags: {\n json?: boolean;\n quiet?: boolean;\n verbose?: number;\n color?: boolean;\n interactive?: boolean;\n yes?: boolean;\n } = {};\n\n // JSON output: explicit --json flag or auto-detect piped stdout (Unix convention)\n if (options.json || !process.stdout.isTTY) {\n flags.json = true;\n }\n\n // Quiet mode\n if (options.quiet || options.q) {\n flags.quiet = true;\n }\n\n // Verbosity: -v = 1, --trace = 2\n // Env toggles: PRISMA_NEXT_TRACE=1 ≅ --trace, PRISMA_NEXT_DEBUG=1 ≅ -v\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 // Color: respect NO_COLOR env var, --color/--no-color flags\n // When JSON output is enabled, disable color to ensure clean JSON output\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 // Default: enable color if TTY\n flags.color = process.stdout.isTTY && !process.env['CI'];\n }\n\n // Interactivity: --interactive/--no-interactive\n // Default: interactive when stdout is a TTY\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 // Auto-accept prompts: -y/--yes\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 { MigrationPackage } from '@prisma-next/migration-tools/package';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { Command } from 'commander';\nimport { relative, resolve } from 'pathe';\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[]>();\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 * 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 * Centralises the fallback logic shared by every command that reads the contract.\n */\nexport function resolveContractPath(config: { contract?: { output?: string } }): string {\n return config.contract?.output\n ? resolve(config.contract.output)\n : resolve('src/prisma/contract.json');\n}\n\n/**\n * Resolves the migrations directory and config path from CLI options.\n * Shared by migration-apply, migration-plan, and migration-status.\n */\nexport function resolveMigrationPaths(\n configOption: string | undefined,\n config: { migrations?: { dir?: string } },\n): {\n configPath: string;\n migrationsDir: string;\n migrationsRelative: 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 refsDir = resolve(migrationsDir, 'refs');\n return { configPath, migrationsDir, migrationsRelative, refsDir };\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 * `migration apply` 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 MigrationPackage[];\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 * --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('--json', 'Output as 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","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"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prisma-next",
3
- "version": "0.5.0-dev.36",
3
+ "version": "0.5.0-dev.37",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Prisma Next CLI: emit, verify, sign, and migrate databases from a type-safe contract.",
@@ -26,17 +26,17 @@
26
26
  "string-width": "^8.2.0",
27
27
  "strip-ansi": "^7.1.2",
28
28
  "wrap-ansi": "^10.0.0",
29
- "@prisma-next/config": "0.5.0-dev.36",
30
- "@prisma-next/contract": "0.5.0-dev.36",
31
- "@prisma-next/errors": "0.5.0-dev.36",
32
- "@prisma-next/framework-components": "0.5.0-dev.36",
33
- "@prisma-next/migration-tools": "0.5.0-dev.36",
34
- "@prisma-next/utils": "0.5.0-dev.36",
35
- "@prisma-next/psl-printer": "0.5.0-dev.36",
36
- "@prisma-next/emitter": "0.5.0-dev.36"
29
+ "@prisma-next/config": "0.5.0-dev.37",
30
+ "@prisma-next/contract": "0.5.0-dev.37",
31
+ "@prisma-next/errors": "0.5.0-dev.37",
32
+ "@prisma-next/framework-components": "0.5.0-dev.37",
33
+ "@prisma-next/migration-tools": "0.5.0-dev.37",
34
+ "@prisma-next/emitter": "0.5.0-dev.37",
35
+ "@prisma-next/utils": "0.5.0-dev.37",
36
+ "@prisma-next/psl-printer": "0.5.0-dev.37"
37
37
  },
38
38
  "devDependencies": {
39
- "@prisma-next/cli": "0.5.0-dev.36"
39
+ "@prisma-next/cli": "0.5.0-dev.37"
40
40
  },
41
41
  "publishConfig": {
42
42
  "access": "public"
@@ -1 +0,0 @@
1
- {"version":3,"file":"client-Buy8_40Y.mjs","names":["plannerResult: MigrationPlannerResult","migrationPlan: MigrationPlan","runnerResult: MigrationRunnerResult","plannerResult: MigrationPlannerResult","runnerResult: MigrationRunnerResult","applied: MigrationApplyAppliedEntry[]","runnerResult: MigrationRunnerResult","contract: Contract","contractRaw: unknown","emitContractArtifacts"],"sources":["../src/control-api/errors.ts","../src/control-api/operations/migration-helpers.ts","../src/control-api/operations/db-init.ts","../src/control-api/operations/db-update.ts","../src/control-api/operations/migration-apply.ts","../src/control-api/client.ts"],"sourcesContent":["export class ContractValidationError extends Error {\n override readonly cause?: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'ContractValidationError';\n this.cause = cause;\n }\n}\n","import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport type { ControlActionName, OnControlProgress } from '../types';\n\n/**\n * Strips operation objects to their public shape (id, label, operationClass).\n * Used at the API boundary to avoid leaking internal fields (precheck, execute, postcheck, etc.).\n */\nexport function stripOperations(\n operations: readonly MigrationPlanOperation[],\n): ReadonlyArray<{ readonly id: string; readonly label: string; readonly operationClass: string }> {\n return operations.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n }));\n}\n\n/**\n * Creates per-operation progress callbacks for the runner.\n * Returns undefined when no onProgress callback is provided.\n */\nexport function createOperationCallbacks(\n onProgress: OnControlProgress | undefined,\n action: ControlActionName,\n parentSpanId: string,\n) {\n if (!onProgress) {\n return undefined;\n }\n return {\n onOperationStart: (op: MigrationPlanOperation) => {\n onProgress({\n action,\n kind: 'spanStart',\n spanId: `operation:${op.id}`,\n parentSpanId,\n label: op.label,\n });\n },\n onOperationComplete: (op: MigrationPlanOperation) => {\n onProgress({\n action,\n kind: 'spanEnd',\n spanId: `operation:${op.id}`,\n outcome: 'ok',\n });\n },\n };\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n MigrationPlan,\n MigrationPlannerResult,\n MigrationRunnerResult,\n TargetMigrationsCapability,\n} from '@prisma-next/framework-components/control';\nimport { hasOperationPreview } from '@prisma-next/framework-components/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport type { DbInitResult, DbInitSuccess, OnControlProgress } from '../types';\nimport { createOperationCallbacks, stripOperations } from './migration-helpers';\n\n/**\n * Options for executing dbInit operation.\n */\nexport interface ExecuteDbInitOptions<TFamilyId extends string, TTargetId extends string> {\n readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;\n readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;\n readonly contract: Contract;\n readonly mode: 'plan' | 'apply';\n readonly migrations: TargetMigrationsCapability<\n TFamilyId,\n TTargetId,\n ControlFamilyInstance<TFamilyId, unknown>\n >;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n /** Optional progress callback for observing operation progress */\n readonly onProgress?: OnControlProgress;\n}\n\n/**\n * Executes the dbInit operation.\n *\n * This is the core logic extracted from the CLI command, without any file I/O,\n * process.exit(), or console output. It uses the Result pattern to return\n * success or failure details.\n *\n * @param options - The options for executing dbInit\n * @returns Result with DbInitSuccess on success, DbInitFailure on failure\n */\nexport async function executeDbInit<TFamilyId extends string, TTargetId extends string>(\n options: ExecuteDbInitOptions<TFamilyId, TTargetId>,\n): Promise<DbInitResult> {\n const { driver, familyInstance, contract, mode, migrations, frameworkComponents, onProgress } =\n options;\n\n // Create planner and runner from target migrations capability\n const planner = migrations.createPlanner(familyInstance);\n const runner = migrations.createRunner(familyInstance);\n\n // Introspect live schema\n const introspectSpanId = 'introspect';\n onProgress?.({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: introspectSpanId,\n label: 'Introspecting database schema',\n });\n const schemaIR = await familyInstance.introspect({ driver });\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: introspectSpanId,\n outcome: 'ok',\n });\n\n // Policy for init mode (additive only)\n const policy = { allowedOperationClasses: ['additive'] as const };\n\n // Plan migration\n const planSpanId = 'plan';\n onProgress?.({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: planSpanId,\n label: 'Planning migration',\n });\n const plannerResult: MigrationPlannerResult = await planner.plan({\n contract,\n schema: schemaIR,\n policy,\n // `db init` reconciles against the live introspected schema; there is no\n // prior contract to derive a \"from\" identity from. The required\n // `fromContract: null` makes that structural fact visible at the call\n // site (vs. silently letting the planner default to a baseline plan).\n fromContract: null,\n frameworkComponents,\n });\n\n if (plannerResult.kind === 'failure') {\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: planSpanId,\n outcome: 'error',\n });\n return notOk({\n code: 'PLANNING_FAILED' as const,\n summary: 'Migration planning failed due to conflicts',\n conflicts: plannerResult.conflicts,\n why: undefined,\n meta: undefined,\n });\n }\n\n const migrationPlan: MigrationPlan = plannerResult.plan;\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: planSpanId,\n outcome: 'ok',\n });\n\n // Check for existing marker - handle idempotency and mismatch errors\n const checkMarkerSpanId = 'checkMarker';\n onProgress?.({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: checkMarkerSpanId,\n label: 'Checking database signature',\n });\n const existingMarker = await familyInstance.readMarker({ driver });\n if (existingMarker) {\n const markerMatchesDestination =\n existingMarker.storageHash === migrationPlan.destination.storageHash &&\n (!migrationPlan.destination.profileHash ||\n existingMarker.profileHash === migrationPlan.destination.profileHash);\n\n if (markerMatchesDestination) {\n // Already at destination - return success with no operations\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: checkMarkerSpanId,\n outcome: 'skipped',\n });\n const result: DbInitSuccess = {\n mode,\n plan: { operations: [] },\n destination: {\n storageHash: migrationPlan.destination.storageHash,\n ...ifDefined('profileHash', migrationPlan.destination.profileHash),\n },\n ...ifDefined(\n 'execution',\n mode === 'apply' ? { operationsPlanned: 0, operationsExecuted: 0 } : undefined,\n ),\n ...ifDefined(\n 'marker',\n mode === 'apply'\n ? {\n storageHash: existingMarker.storageHash,\n profileHash: existingMarker.profileHash,\n }\n : undefined,\n ),\n summary: 'Database already at target contract state',\n };\n return ok(result);\n }\n\n // Marker exists but doesn't match destination - fail\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: checkMarkerSpanId,\n outcome: 'error',\n });\n return notOk({\n code: 'MARKER_ORIGIN_MISMATCH' as const,\n summary: 'Existing contract marker does not match plan destination',\n marker: {\n storageHash: existingMarker.storageHash,\n profileHash: existingMarker.profileHash,\n },\n destination: {\n storageHash: migrationPlan.destination.storageHash,\n profileHash: migrationPlan.destination.profileHash,\n },\n why: undefined,\n conflicts: undefined,\n meta: undefined,\n });\n }\n\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: checkMarkerSpanId,\n outcome: 'ok',\n });\n\n // Plan mode - don't execute\n if (mode === 'plan') {\n const preview = hasOperationPreview(familyInstance)\n ? familyInstance.toOperationPreview(migrationPlan.operations)\n : undefined;\n const result: DbInitSuccess = {\n mode: 'plan',\n plan: {\n operations: stripOperations(migrationPlan.operations),\n ...ifDefined('preview', preview),\n },\n destination: {\n storageHash: migrationPlan.destination.storageHash,\n ...ifDefined('profileHash', migrationPlan.destination.profileHash),\n },\n summary: `Planned ${migrationPlan.operations.length} operation(s)`,\n };\n return ok(result);\n }\n\n // Apply mode - execute runner\n const applySpanId = 'apply';\n onProgress?.({\n action: 'dbInit',\n kind: 'spanStart',\n spanId: applySpanId,\n label: 'Applying migration plan',\n });\n\n const callbacks = createOperationCallbacks(onProgress, 'dbInit', applySpanId);\n\n const runnerResult: MigrationRunnerResult = await runner.execute({\n plan: migrationPlan,\n driver,\n destinationContract: contract,\n policy,\n ...ifDefined('callbacks', callbacks),\n // db init plans and applies back-to-back from a fresh introspection, so per-operation\n // pre/postchecks and the idempotency probe are usually redundant overhead. We still\n // enforce marker/origin compatibility and a full schema verification after apply.\n executionChecks: {\n prechecks: false,\n postchecks: false,\n idempotencyChecks: false,\n },\n frameworkComponents,\n });\n\n if (!runnerResult.ok) {\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: applySpanId,\n outcome: 'error',\n });\n return notOk({\n code: 'RUNNER_FAILED' as const,\n summary: runnerResult.failure.summary,\n why: runnerResult.failure.why,\n meta: runnerResult.failure.meta,\n conflicts: undefined,\n });\n }\n\n const execution = runnerResult.value;\n\n onProgress?.({\n action: 'dbInit',\n kind: 'spanEnd',\n spanId: applySpanId,\n outcome: 'ok',\n });\n\n const result: DbInitSuccess = {\n mode: 'apply',\n plan: {\n operations: stripOperations(migrationPlan.operations),\n },\n destination: {\n storageHash: migrationPlan.destination.storageHash,\n ...ifDefined('profileHash', migrationPlan.destination.profileHash),\n },\n execution: {\n operationsPlanned: execution.operationsPlanned,\n operationsExecuted: execution.operationsExecuted,\n },\n marker: migrationPlan.destination.profileHash\n ? {\n storageHash: migrationPlan.destination.storageHash,\n profileHash: migrationPlan.destination.profileHash,\n }\n : { storageHash: migrationPlan.destination.storageHash },\n summary: `Applied ${execution.operationsExecuted} operation(s), database signed`,\n };\n return ok(result);\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n MigrationPlannerResult,\n MigrationRunnerResult,\n TargetMigrationsCapability,\n} from '@prisma-next/framework-components/control';\nimport { hasOperationPreview } from '@prisma-next/framework-components/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport type { DbUpdateResult, DbUpdateSuccess, OnControlProgress } from '../types';\nimport { createOperationCallbacks, stripOperations } from './migration-helpers';\n\n// F12: db update allows additive, widening, and destructive operations.\nconst DB_UPDATE_POLICY = {\n allowedOperationClasses: ['additive', 'widening', 'destructive'] as const,\n} as const;\n\n/**\n * Options for the executeDbUpdate operation.\n * Config-agnostic: receives pre-resolved driver, family, contract, and migrations capability.\n */\nexport interface ExecuteDbUpdateOptions<TFamilyId extends string, TTargetId extends string> {\n readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;\n readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;\n readonly contract: Contract;\n readonly mode: 'plan' | 'apply';\n readonly migrations: TargetMigrationsCapability<\n TFamilyId,\n TTargetId,\n ControlFamilyInstance<TFamilyId, unknown>\n >;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n readonly acceptDataLoss?: boolean;\n /** Optional progress callback for observing operation progress. */\n readonly onProgress?: OnControlProgress;\n}\n\n/**\n * Executes the db update operation: introspect → plan → (optionally) apply → marker.\n *\n * db update is a pure reconciliation command: it introspects the live schema, plans the diff\n * to the destination contract, and applies operations. The marker is bookkeeping only — written\n * after apply so that `verify` and `db init` can reference it, but never read or validated\n * by db update itself. The runner creates the marker table if it does not exist.\n */\nexport async function executeDbUpdate<TFamilyId extends string, TTargetId extends string>(\n options: ExecuteDbUpdateOptions<TFamilyId, TTargetId>,\n): Promise<DbUpdateResult> {\n const { driver, familyInstance, contract, mode, migrations, frameworkComponents, onProgress } =\n options;\n\n const planner = migrations.createPlanner(familyInstance);\n const runner = migrations.createRunner(familyInstance);\n\n const introspectSpanId = 'introspect';\n onProgress?.({\n action: 'dbUpdate',\n kind: 'spanStart',\n spanId: introspectSpanId,\n label: 'Introspecting database schema',\n });\n const schemaIR = await familyInstance.introspect({ driver });\n onProgress?.({\n action: 'dbUpdate',\n kind: 'spanEnd',\n spanId: introspectSpanId,\n outcome: 'ok',\n });\n\n const policy = DB_UPDATE_POLICY;\n\n const planSpanId = 'plan';\n onProgress?.({\n action: 'dbUpdate',\n kind: 'spanStart',\n spanId: planSpanId,\n label: 'Planning migration',\n });\n const plannerResult: MigrationPlannerResult = await planner.plan({\n contract,\n schema: schemaIR,\n policy,\n // `db update` reconciles against the live introspected schema; there is\n // no prior contract to derive a \"from\" identity from. The required\n // `fromContract: null` makes that structural fact visible at the call\n // site (vs. silently letting the planner default to a baseline plan).\n fromContract: null,\n frameworkComponents,\n });\n if (plannerResult.kind === 'failure') {\n onProgress?.({\n action: 'dbUpdate',\n kind: 'spanEnd',\n spanId: planSpanId,\n outcome: 'error',\n });\n return notOk({\n code: 'PLANNING_FAILED',\n summary: 'Migration planning failed due to conflicts',\n conflicts: plannerResult.conflicts,\n why: undefined,\n meta: undefined,\n });\n }\n onProgress?.({\n action: 'dbUpdate',\n kind: 'spanEnd',\n spanId: planSpanId,\n outcome: 'ok',\n });\n\n const migrationPlan = plannerResult.plan;\n\n if (mode === 'plan') {\n const preview = hasOperationPreview(familyInstance)\n ? familyInstance.toOperationPreview(migrationPlan.operations)\n : undefined;\n const result: DbUpdateSuccess = {\n mode: 'plan',\n plan: {\n operations: stripOperations(migrationPlan.operations),\n ...ifDefined('preview', preview),\n },\n destination: {\n storageHash: migrationPlan.destination.storageHash,\n ...ifDefined('profileHash', migrationPlan.destination.profileHash),\n },\n summary: `Planned ${migrationPlan.operations.length} operation(s)`,\n };\n return ok(result);\n }\n\n // When applying, require explicit acceptance for destructive operations\n if (!options.acceptDataLoss) {\n const destructiveOps = migrationPlan.operations\n .filter((op) => op.operationClass === 'destructive')\n .map((op) => ({ id: op.id, label: op.label }));\n if (destructiveOps.length > 0) {\n return notOk({\n code: 'DESTRUCTIVE_CHANGES',\n summary: `Planned ${destructiveOps.length} destructive operation(s) that require confirmation`,\n why: 'Destructive operations require confirmation — re-run with -y to accept',\n conflicts: undefined,\n meta: { destructiveOperations: destructiveOps },\n });\n }\n }\n\n const applySpanId = 'apply';\n onProgress?.({\n action: 'dbUpdate',\n kind: 'spanStart',\n spanId: applySpanId,\n label: 'Applying migration plan',\n });\n\n const callbacks = createOperationCallbacks(onProgress, 'dbUpdate', applySpanId);\n\n const runnerResult: MigrationRunnerResult = await runner.execute({\n plan: migrationPlan,\n driver,\n destinationContract: contract,\n policy,\n ...(callbacks ? { callbacks } : {}),\n // db update plans and applies from a single introspection pass, so per-operation pre/postchecks\n // and idempotency probes are intentionally disabled to avoid redundant roundtrips.\n executionChecks: {\n prechecks: false,\n postchecks: false,\n idempotencyChecks: false,\n },\n frameworkComponents,\n });\n\n if (!runnerResult.ok) {\n onProgress?.({\n action: 'dbUpdate',\n kind: 'spanEnd',\n spanId: applySpanId,\n outcome: 'error',\n });\n return notOk({\n code: 'RUNNER_FAILED',\n summary: runnerResult.failure.summary,\n why: runnerResult.failure.why,\n meta: runnerResult.failure.meta,\n conflicts: undefined,\n });\n }\n\n const execution = runnerResult.value;\n onProgress?.({\n action: 'dbUpdate',\n kind: 'spanEnd',\n spanId: applySpanId,\n outcome: 'ok',\n });\n\n const result: DbUpdateSuccess = {\n mode: 'apply',\n plan: {\n operations: stripOperations(migrationPlan.operations),\n },\n destination: {\n storageHash: migrationPlan.destination.storageHash,\n ...ifDefined('profileHash', migrationPlan.destination.profileHash),\n },\n execution: {\n operationsPlanned: execution.operationsPlanned,\n operationsExecuted: execution.operationsExecuted,\n },\n marker: migrationPlan.destination.profileHash\n ? {\n storageHash: migrationPlan.destination.storageHash,\n profileHash: migrationPlan.destination.profileHash,\n }\n : { storageHash: migrationPlan.destination.storageHash },\n summary:\n execution.operationsExecuted === 0\n ? 'Database already matches contract, signature updated'\n : `Applied ${execution.operationsExecuted} operation(s), signature updated`,\n };\n return ok(result);\n}\n","import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n MigrationRunnerResult,\n TargetMigrationsCapability,\n} from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport type {\n MigrationApplyAppliedEntry,\n MigrationApplyResult,\n MigrationApplyStep,\n OnControlProgress,\n} from '../types';\n\nexport interface ExecuteMigrationApplyOptions<TFamilyId extends string, TTargetId extends string> {\n readonly driver: ControlDriverInstance<TFamilyId, TTargetId>;\n readonly familyInstance: ControlFamilyInstance<TFamilyId, unknown>;\n readonly originHash: string;\n readonly destinationHash: string;\n readonly pendingMigrations: readonly MigrationApplyStep[];\n readonly migrations: TargetMigrationsCapability<\n TFamilyId,\n TTargetId,\n ControlFamilyInstance<TFamilyId, unknown>\n >;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n readonly targetId: string;\n readonly onProgress?: OnControlProgress;\n}\n\n/**\n * Apply a sequence of migration packages against the configured driver.\n *\n * Validates the path's continuity (origin → ... → destination, no gaps),\n * then drives the family/target's migration runner over each package's\n * operations in order, surfacing per-migration progress through `onProgress`.\n *\n * The `pendingMigrations` parameter is trusted input. Callers are responsible\n * for upstream verification of the originating migration packages — typically\n * by loading them via `readMigrationPackage` from\n * `@prisma-next/migration-tools/io`, which performs hash-integrity checks at\n * the load boundary. This operation does not re-verify the packages and\n * assumes the `(metadata, ops)` pairs on disk have not been tampered with\n * since emit.\n */\nexport async function executeMigrationApply<TFamilyId extends string, TTargetId extends string>(\n options: ExecuteMigrationApplyOptions<TFamilyId, TTargetId>,\n): Promise<MigrationApplyResult> {\n const {\n driver,\n familyInstance,\n originHash,\n destinationHash,\n pendingMigrations,\n migrations,\n frameworkComponents,\n targetId,\n onProgress,\n } = options;\n\n if (pendingMigrations.length === 0) {\n if (originHash !== destinationHash) {\n return notOk({\n code: 'MIGRATION_PATH_NOT_FOUND' as const,\n summary: 'No migrations provided for requested origin and destination',\n why: `Requested ${originHash} -> ${destinationHash} but pendingMigrations is empty`,\n meta: { originHash, destinationHash },\n });\n }\n return ok({\n migrationsApplied: 0,\n markerHash: originHash,\n applied: [],\n summary: 'Already up to date',\n });\n }\n\n const firstMigration = pendingMigrations[0]!;\n const lastMigration = pendingMigrations[pendingMigrations.length - 1]!;\n // Manifest `from` is `string | null` (null = baseline). The live-marker\n // layer encodes \"no prior state\" as EMPTY_CONTRACT_HASH; bridge here so the\n // string comparisons below work uniformly.\n const firstFromMarker = firstMigration.from ?? EMPTY_CONTRACT_HASH;\n if (firstFromMarker !== originHash || lastMigration.to !== destinationHash) {\n return notOk({\n code: 'MIGRATION_PATH_NOT_FOUND' as const,\n summary: 'Migration apply path does not match requested origin and destination',\n why: `Path resolved as ${firstFromMarker} -> ${lastMigration.to}, but requested ${originHash} -> ${destinationHash}`,\n meta: {\n originHash,\n destinationHash,\n pathOrigin: firstFromMarker,\n pathDestination: lastMigration.to,\n },\n });\n }\n\n for (let i = 1; i < pendingMigrations.length; i++) {\n const previous = pendingMigrations[i - 1]!;\n const current = pendingMigrations[i]!;\n const currentFromMarker = current.from ?? EMPTY_CONTRACT_HASH;\n if (previous.to !== currentFromMarker) {\n return notOk({\n code: 'MIGRATION_PATH_NOT_FOUND' as const,\n summary: 'Migration apply path contains a discontinuity between adjacent migrations',\n why: `Migration \"${previous.dirName}\" ends at ${previous.to}, but next migration \"${current.dirName}\" starts at ${currentFromMarker}`,\n meta: {\n originHash,\n destinationHash,\n previousDirName: previous.dirName,\n previousTo: previous.to,\n currentDirName: current.dirName,\n currentFrom: currentFromMarker,\n discontinuityIndex: i,\n },\n });\n }\n }\n\n const runner = migrations.createRunner(familyInstance);\n const applied: MigrationApplyAppliedEntry[] = [];\n\n for (const migration of pendingMigrations) {\n const migrationSpanId = `migration:${migration.dirName}`;\n onProgress?.({\n action: 'migrationApply',\n kind: 'spanStart',\n spanId: migrationSpanId,\n label: `Applying ${migration.dirName}`,\n });\n\n const { operations } = migration;\n\n // Allow all operation classes. The policy gate belongs at plan time, not\n // apply time — the planner already decided what to emit. Restricting here\n // would be a tautology (the allowed set would just mirror what's in ops).\n const policy = {\n allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'] as const,\n };\n\n // Manifest `from === null` means \"no prior state\" — the runner expects\n // `origin: null` for a fresh database (no marker present).\n const plan = {\n targetId,\n origin: migration.from === null ? null : { storageHash: migration.from },\n destination: { storageHash: migration.to },\n operations,\n };\n\n const destinationContract = familyInstance.validateContract(migration.toContract);\n\n const runnerResult: MigrationRunnerResult = await runner.execute({\n plan,\n driver,\n destinationContract,\n policy,\n executionChecks: {\n prechecks: true,\n postchecks: true,\n idempotencyChecks: true,\n },\n frameworkComponents,\n });\n\n if (!runnerResult.ok) {\n onProgress?.({\n action: 'migrationApply',\n kind: 'spanEnd',\n spanId: migrationSpanId,\n outcome: 'error',\n });\n return notOk({\n code: 'RUNNER_FAILED' as const,\n summary: runnerResult.failure.summary,\n why: runnerResult.failure.why,\n meta: {\n migration: migration.dirName,\n from: migration.from,\n to: migration.to,\n ...(runnerResult.failure.meta ?? {}),\n },\n });\n }\n\n onProgress?.({\n action: 'migrationApply',\n kind: 'spanEnd',\n spanId: migrationSpanId,\n outcome: 'ok',\n });\n\n applied.push({\n dirName: migration.dirName,\n from: migration.from,\n to: migration.to,\n operationsExecuted: runnerResult.value.operationsExecuted,\n });\n }\n\n const finalHash = pendingMigrations[pendingMigrations.length - 1]!.to;\n const totalOps = applied.reduce((sum, a) => sum + a.operationsExecuted, 0);\n\n return ok({\n migrationsApplied: applied.length,\n markerHash: finalHash,\n applied,\n summary: `Applied ${applied.length} migration(s) (${totalOps} operation(s)), marker at ${finalHash}`,\n });\n}\n","import type { Contract, ContractMarkerRecord } from '@prisma-next/contract/types';\nimport { emit as emitContractArtifacts } from '@prisma-next/emitter';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n ControlDriverInstance,\n ControlFamilyInstance,\n ControlStack,\n CoreSchemaView,\n MigrationPlanOperation,\n OperationPreview,\n SignDatabaseResult,\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport {\n createControlStack,\n hasMigrations,\n hasOperationPreview,\n hasPslContractInfer,\n hasSchemaView,\n} from '@prisma-next/framework-components/control';\nimport type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { assertFrameworkComponentsCompatible } from '../utils/framework-components';\nimport { enrichContract } from './contract-enrichment';\nimport { ContractValidationError } from './errors';\nimport { executeDbInit } from './operations/db-init';\nimport { executeDbUpdate } from './operations/db-update';\nimport { executeMigrationApply } from './operations/migration-apply';\nimport type {\n ControlActionName,\n ControlClient,\n ControlClientOptions,\n DbInitOptions,\n DbInitResult,\n DbUpdateOptions,\n DbUpdateResult,\n EmitOptions,\n EmitResult,\n IntrospectOptions,\n MigrationApplyOptions,\n MigrationApplyResult,\n OnControlProgress,\n SchemaVerifyOptions,\n SignOptions,\n VerifyOptions,\n} from './types';\n\n/**\n * Creates a programmatic control client for Prisma Next operations.\n *\n * The client accepts framework component descriptors at creation time,\n * manages driver lifecycle via connect()/close(), and exposes domain\n * operations that delegate to the existing family instance methods.\n *\n * @see {@link ControlClient} for the client interface\n * @see README.md \"Programmatic Control API\" section for usage examples\n */\nexport function createControlClient(options: ControlClientOptions): ControlClient {\n return new ControlClientImpl(options);\n}\n\n/**\n * Implementation of ControlClient.\n * Manages initialization and connection state, delegates operations to family instance.\n */\nclass ControlClientImpl implements ControlClient {\n private readonly options: ControlClientOptions;\n private stack: ControlStack | null = null;\n private driver: ControlDriverInstance<string, string> | null = null;\n private familyInstance: ControlFamilyInstance<string, unknown> | null = null;\n private frameworkComponents: ReadonlyArray<\n TargetBoundComponentDescriptor<string, string>\n > | null = null;\n private initialized = false;\n private readonly defaultConnection: unknown;\n\n constructor(options: ControlClientOptions) {\n this.options = options;\n this.defaultConnection = options.connection;\n }\n\n init(): void {\n if (this.initialized) {\n return; // Idempotent\n }\n\n this.stack = createControlStack({\n family: this.options.family,\n target: this.options.target,\n adapter: this.options.adapter,\n driver: this.options.driver,\n extensionPacks: this.options.extensionPacks,\n });\n\n this.familyInstance = this.options.family.create(this.stack);\n\n // Validate and type-narrow framework components\n const rawComponents = [\n this.options.target,\n this.options.adapter,\n ...(this.options.extensionPacks ?? []),\n ];\n this.frameworkComponents = assertFrameworkComponentsCompatible(\n this.options.family.familyId,\n this.options.target.targetId,\n rawComponents,\n );\n\n this.initialized = true;\n }\n\n async connect(connection?: unknown): Promise<void> {\n // Auto-init if needed\n this.init();\n\n if (this.driver) {\n throw new Error('Already connected. Call close() before reconnecting.');\n }\n\n // Resolve connection: argument > default from options\n const resolvedConnection = connection ?? this.defaultConnection;\n if (resolvedConnection === undefined) {\n throw new Error(\n 'No connection provided. Pass a connection to connect() or provide a default connection when creating the client.',\n );\n }\n\n // Check for driver descriptor\n if (!this.stack?.driver) {\n throw new Error(\n 'Driver is not configured. Pass a driver descriptor when creating the control client to enable database operations.',\n );\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: required for runtime connection type flexibility\n this.driver = await this.stack.driver.create(resolvedConnection as any);\n }\n\n async close(): Promise<void> {\n if (this.driver) {\n await this.driver.close();\n this.driver = null;\n }\n }\n\n private async ensureConnected(): Promise<{\n driver: ControlDriverInstance<string, string>;\n familyInstance: ControlFamilyInstance<string, unknown>;\n frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<string, string>>;\n }> {\n // Auto-init if needed\n this.init();\n\n // Auto-connect if not connected and default connection is available\n if (!this.driver && this.defaultConnection !== undefined) {\n await this.connect(this.defaultConnection);\n }\n\n if (!this.driver || !this.familyInstance || !this.frameworkComponents) {\n throw new Error('Not connected. Call connect(connection) first.');\n }\n return {\n driver: this.driver,\n familyInstance: this.familyInstance,\n frameworkComponents: this.frameworkComponents,\n };\n }\n\n private async connectWithProgress(\n connection: unknown | undefined,\n action: ControlActionName,\n onProgress?: OnControlProgress,\n ): Promise<void> {\n if (connection === undefined) return;\n onProgress?.({\n action,\n kind: 'spanStart',\n spanId: 'connect',\n label: 'Connecting to database...',\n });\n try {\n await this.connect(connection);\n onProgress?.({ action, kind: 'spanEnd', spanId: 'connect', outcome: 'ok' });\n } catch (error) {\n onProgress?.({ action, kind: 'spanEnd', spanId: 'connect', outcome: 'error' });\n throw error;\n }\n }\n\n async verify(options: VerifyOptions): Promise<VerifyDatabaseResult> {\n const { onProgress } = options;\n await this.connectWithProgress(options.connection, 'verify', onProgress);\n const { driver, familyInstance } = await this.ensureConnected();\n\n // Validate contract using family instance\n let contract: Contract;\n try {\n contract = familyInstance.validateContract(options.contract);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new ContractValidationError(message, error);\n }\n\n // Emit verify span\n onProgress?.({\n action: 'verify',\n kind: 'spanStart',\n spanId: 'verify',\n label: 'Verifying database marker...',\n });\n\n try {\n // Delegate to family instance verify method\n // Note: We pass empty strings for contractPath/configPath since the programmatic\n // API doesn't deal with file paths. The family instance accepts these as optional\n // metadata for error reporting.\n const result = await familyInstance.verify({\n driver,\n contract,\n expectedTargetId: this.options.target.targetId,\n contractPath: '',\n });\n\n onProgress?.({\n action: 'verify',\n kind: 'spanEnd',\n spanId: 'verify',\n outcome: result.ok ? 'ok' : 'error',\n });\n\n return result;\n } catch (error) {\n onProgress?.({\n action: 'verify',\n kind: 'spanEnd',\n spanId: 'verify',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n async schemaVerify(options: SchemaVerifyOptions): Promise<VerifyDatabaseSchemaResult> {\n const { onProgress } = options;\n await this.connectWithProgress(options.connection, 'schemaVerify', onProgress);\n const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();\n\n // Validate contract using family instance\n let contract: Contract;\n try {\n contract = familyInstance.validateContract(options.contract);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new ContractValidationError(message, error);\n }\n\n // Emit schemaVerify span\n onProgress?.({\n action: 'schemaVerify',\n kind: 'spanStart',\n spanId: 'schemaVerify',\n label: 'Verifying database schema...',\n });\n\n try {\n // Delegate to family instance schemaVerify method\n const result = await familyInstance.schemaVerify({\n driver,\n contract,\n strict: options.strict ?? false,\n contractPath: '',\n frameworkComponents,\n });\n\n onProgress?.({\n action: 'schemaVerify',\n kind: 'spanEnd',\n spanId: 'schemaVerify',\n outcome: result.ok ? 'ok' : 'error',\n });\n\n return result;\n } catch (error) {\n onProgress?.({\n action: 'schemaVerify',\n kind: 'spanEnd',\n spanId: 'schemaVerify',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n async sign(options: SignOptions): Promise<SignDatabaseResult> {\n const { onProgress } = options;\n await this.connectWithProgress(options.connection, 'sign', onProgress);\n const { driver, familyInstance } = await this.ensureConnected();\n\n // Validate contract using family instance\n let contract: Contract;\n try {\n contract = familyInstance.validateContract(options.contract);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new ContractValidationError(message, error);\n }\n\n // Emit sign span\n onProgress?.({\n action: 'sign',\n kind: 'spanStart',\n spanId: 'sign',\n label: 'Signing database...',\n });\n\n try {\n // Delegate to family instance sign method\n const result = await familyInstance.sign({\n driver,\n contract,\n contractPath: options.contractPath ?? '',\n ...ifDefined('configPath', options.configPath),\n });\n\n onProgress?.({\n action: 'sign',\n kind: 'spanEnd',\n spanId: 'sign',\n outcome: 'ok',\n });\n\n return result;\n } catch (error) {\n onProgress?.({\n action: 'sign',\n kind: 'spanEnd',\n spanId: 'sign',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n async dbInit(options: DbInitOptions): Promise<DbInitResult> {\n const { onProgress } = options;\n await this.connectWithProgress(options.connection, 'dbInit', onProgress);\n const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();\n\n if (!hasMigrations(this.options.target)) {\n throw new Error(`Target \"${this.options.target.targetId}\" does not support migrations`);\n }\n\n let contract: Contract;\n try {\n contract = familyInstance.validateContract(options.contract);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new ContractValidationError(message, error);\n }\n\n return executeDbInit({\n driver,\n familyInstance,\n contract,\n mode: options.mode,\n migrations: this.options.target.migrations,\n frameworkComponents,\n ...ifDefined('onProgress', onProgress),\n });\n }\n\n async dbUpdate(options: DbUpdateOptions): Promise<DbUpdateResult> {\n const { onProgress } = options;\n await this.connectWithProgress(options.connection, 'dbUpdate', onProgress);\n const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();\n\n if (!hasMigrations(this.options.target)) {\n throw new Error(`Target \"${this.options.target.targetId}\" does not support migrations`);\n }\n\n let contract: Contract;\n try {\n contract = familyInstance.validateContract(options.contract);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new ContractValidationError(message, error);\n }\n\n return executeDbUpdate({\n driver,\n familyInstance,\n contract,\n mode: options.mode,\n migrations: this.options.target.migrations,\n frameworkComponents,\n ...ifDefined('acceptDataLoss', options.acceptDataLoss),\n ...ifDefined('onProgress', onProgress),\n });\n }\n\n async readMarker(): Promise<ContractMarkerRecord | null> {\n const { driver, familyInstance } = await this.ensureConnected();\n return familyInstance.readMarker({ driver });\n }\n\n async migrationApply(options: MigrationApplyOptions): Promise<MigrationApplyResult> {\n const { onProgress } = options;\n await this.connectWithProgress(options.connection, 'migrationApply', onProgress);\n const { driver, familyInstance, frameworkComponents } = await this.ensureConnected();\n\n if (!hasMigrations(this.options.target)) {\n throw new Error(`Target \"${this.options.target.targetId}\" does not support migrations`);\n }\n\n return executeMigrationApply({\n driver,\n familyInstance,\n originHash: options.originHash,\n destinationHash: options.destinationHash,\n pendingMigrations: options.pendingMigrations,\n migrations: this.options.target.migrations,\n frameworkComponents,\n targetId: this.options.target.targetId,\n ...(onProgress ? { onProgress } : {}),\n });\n }\n\n async introspect(options?: IntrospectOptions): Promise<unknown> {\n const onProgress = options?.onProgress;\n await this.connectWithProgress(options?.connection, 'introspect', onProgress);\n const { driver, familyInstance } = await this.ensureConnected();\n\n // TODO: Pass schema option to familyInstance.introspect when schema filtering is implemented\n const _schema = options?.schema;\n void _schema;\n\n // Emit introspect span\n onProgress?.({\n action: 'introspect',\n kind: 'spanStart',\n spanId: 'introspect',\n label: 'Introspecting database schema...',\n });\n\n try {\n const result = await familyInstance.introspect({ driver });\n\n onProgress?.({\n action: 'introspect',\n kind: 'spanEnd',\n spanId: 'introspect',\n outcome: 'ok',\n });\n\n return result;\n } catch (error) {\n onProgress?.({\n action: 'introspect',\n kind: 'spanEnd',\n spanId: 'introspect',\n outcome: 'error',\n });\n throw error;\n }\n }\n\n toSchemaView(schemaIR: unknown): CoreSchemaView | undefined {\n this.init();\n if (this.familyInstance && hasSchemaView(this.familyInstance)) {\n return this.familyInstance.toSchemaView(schemaIR);\n }\n return undefined;\n }\n\n inferPslContract(schemaIR: unknown): PslDocumentAst | undefined {\n this.init();\n if (this.familyInstance && hasPslContractInfer(this.familyInstance)) {\n return this.familyInstance.inferPslContract(schemaIR);\n }\n return undefined;\n }\n\n toOperationPreview(operations: readonly MigrationPlanOperation[]): OperationPreview | undefined {\n this.init();\n if (this.familyInstance && hasOperationPreview(this.familyInstance)) {\n return this.familyInstance.toOperationPreview(operations);\n }\n return undefined;\n }\n\n async emit(options: EmitOptions): Promise<EmitResult> {\n const { onProgress, contractConfig } = options;\n\n // Ensure initialized (creates stack and family instance)\n // emit() does NOT require a database connection\n this.init();\n\n if (!this.familyInstance) {\n throw new Error('Family instance was not initialized. This is a bug.');\n }\n\n let contractRaw: unknown;\n onProgress?.({\n action: 'emit',\n kind: 'spanStart',\n spanId: 'resolveSource',\n label: 'Resolving contract source...',\n });\n\n try {\n const stack = this.stack!;\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 const providerResult = await contractConfig.source.load(sourceContext);\n if (!providerResult.ok) {\n onProgress?.({\n action: 'emit',\n kind: 'spanEnd',\n spanId: 'resolveSource',\n outcome: 'error',\n });\n\n return notOk({\n code: 'CONTRACT_SOURCE_INVALID',\n summary: providerResult.failure.summary,\n why: providerResult.failure.summary,\n meta: providerResult.failure.meta,\n diagnostics: providerResult.failure,\n });\n }\n contractRaw = providerResult.value;\n\n onProgress?.({\n action: 'emit',\n kind: 'spanEnd',\n spanId: 'resolveSource',\n outcome: 'ok',\n });\n } catch (error) {\n onProgress?.({\n action: 'emit',\n kind: 'spanEnd',\n spanId: 'resolveSource',\n outcome: 'error',\n });\n\n const message = error instanceof Error ? error.message : String(error);\n return notOk({\n code: 'CONTRACT_SOURCE_INVALID',\n summary: 'Failed to resolve contract source',\n why: message,\n diagnostics: {\n summary: 'Contract source provider threw an exception',\n diagnostics: [\n {\n code: 'PROVIDER_THROW',\n message,\n },\n ],\n },\n meta: undefined,\n });\n }\n\n // Emit contract\n onProgress?.({\n action: 'emit',\n kind: 'spanStart',\n spanId: 'emit',\n label: 'Emitting contract...',\n });\n\n try {\n const enrichedIR = enrichContract(contractRaw as Contract, this.frameworkComponents ?? []);\n\n try {\n this.familyInstance.validateContract(enrichedIR);\n } catch (error) {\n onProgress?.({\n action: 'emit',\n kind: 'spanEnd',\n spanId: 'emit',\n outcome: 'error',\n });\n const message = error instanceof Error ? error.message : String(error);\n return notOk({\n code: 'CONTRACT_VALIDATION_FAILED',\n summary: 'Contract validation failed',\n why: message,\n meta: undefined,\n });\n }\n\n const result = await emitContractArtifacts(\n enrichedIR,\n this.stack!,\n this.options.family.emission,\n );\n\n onProgress?.({\n action: 'emit',\n kind: 'spanEnd',\n spanId: 'emit',\n outcome: 'ok',\n });\n\n return ok({\n storageHash: result.storageHash,\n ...ifDefined('executionHash', result.executionHash),\n profileHash: result.profileHash,\n contractJson: result.contractJson,\n contractDts: result.contractDts,\n });\n } catch (error) {\n onProgress?.({\n action: 'emit',\n kind: 'spanEnd',\n spanId: 'emit',\n outcome: 'error',\n });\n\n return notOk({\n code: 'EMIT_FAILED',\n summary: 'Failed to emit contract',\n why: error instanceof Error ? error.message : String(error),\n meta: undefined,\n });\n }\n }\n}\n"],"mappings":"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"}