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