@prisma-next/cli 0.13.0 → 0.14.0-dev.2
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/dist/cli.mjs +6 -6
- package/dist/cli.mjs.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/migration-cli.mjs +3 -3
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-plan-z5Ing-TD.mjs → migration-plan-W_E8FQOk.mjs} +2 -2
- package/dist/migration-plan-W_E8FQOk.mjs.map +1 -0
- package/package.json +18 -18
- package/src/commands/init/templates/code-templates.ts +4 -4
- package/src/commands/migration-plan.ts +1 -1
- package/src/migration-cli.ts +4 -4
- package/dist/migration-plan-z5Ing-TD.mjs.map +0 -1
package/dist/cli.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import { t as createMigrationCheckCommand } from "./migration-check-soB5uZEQ.mjs
|
|
|
13
13
|
import { createMigrationGraphCommand } from "./commands/migration-graph.mjs";
|
|
14
14
|
import { t as createMigrationLogCommand } from "./migration-log-CG0qQAFm.mjs";
|
|
15
15
|
import { createMigrationNewCommand } from "./commands/migration-new.mjs";
|
|
16
|
-
import { t as createMigrationPlanCommand } from "./migration-plan-
|
|
16
|
+
import { t as createMigrationPlanCommand } from "./migration-plan-W_E8FQOk.mjs";
|
|
17
17
|
import { createMigrationShowCommand } from "./commands/migration-show.mjs";
|
|
18
18
|
import { r as createMigrationStatusCommand } from "./migration-status-CgWSoI_g.mjs";
|
|
19
19
|
import { createRefCommand } from "./commands/ref.mjs";
|
|
@@ -24,7 +24,7 @@ import { ensureInstallationId, readUserConfig, resolveGating, runTelemetry, user
|
|
|
24
24
|
import { distance } from "closest-match";
|
|
25
25
|
import { fileURLToPath } from "node:url";
|
|
26
26
|
//#region package.json
|
|
27
|
-
var version = "0.
|
|
27
|
+
var version = "0.14.0-dev.2";
|
|
28
28
|
//#endregion
|
|
29
29
|
//#region src/commands/init/templates/code-templates.ts
|
|
30
30
|
function targetPackageName(target) {
|
|
@@ -85,7 +85,7 @@ export const contract = defineContract(
|
|
|
85
85
|
models: {
|
|
86
86
|
User: model('User', {
|
|
87
87
|
fields: {
|
|
88
|
-
id: field.id.
|
|
88
|
+
id: field.id.uuidv7String(),
|
|
89
89
|
email: field.text().unique(),
|
|
90
90
|
username: field.text().optional(),
|
|
91
91
|
name: field.text().optional(),
|
|
@@ -173,7 +173,7 @@ export const contract = defineContract(
|
|
|
173
173
|
models: {
|
|
174
174
|
User: model('User', {
|
|
175
175
|
fields: {
|
|
176
|
-
id: field.id.
|
|
176
|
+
id: field.id.uuidv7String(),
|
|
177
177
|
email: field.text().unique(),
|
|
178
178
|
username: field.text().optional(),
|
|
179
179
|
name: field.text().optional(),
|
|
@@ -187,10 +187,10 @@ export const contract = defineContract(
|
|
|
187
187
|
|
|
188
188
|
Post: model('Post', {
|
|
189
189
|
fields: {
|
|
190
|
-
id: field.id.
|
|
190
|
+
id: field.id.uuidv7String(),
|
|
191
191
|
title: field.text(),
|
|
192
192
|
content: field.text().optional(),
|
|
193
|
-
authorId: field.
|
|
193
|
+
authorId: field.uuidString(),
|
|
194
194
|
createdAt: field.temporal.createdAt(),
|
|
195
195
|
updatedAt: field.temporal.updatedAt(),
|
|
196
196
|
},
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":["CLI_VERSION","packageJson.version"],"sources":["../package.json","../src/commands/init/templates/code-templates.ts","../src/commands/init/index.ts","../src/utils/suggest-command.ts","../src/utils/telemetry.ts","../src/cli.ts"],"sourcesContent":["","import { DEFAULT_CONTRACT_SOURCE_DIR } from '@prisma-next/config/config-types';\n\nexport type TargetId = 'postgres' | 'mongo';\nexport type AuthoringId = 'psl' | 'typescript';\n\nexport function targetPackageName(target: TargetId): string {\n return target === 'postgres' ? '@prisma-next/postgres' : '@prisma-next/mongo';\n}\n\nexport function targetLabel(target: TargetId): string {\n return target === 'postgres' ? 'PostgreSQL' : 'MongoDB';\n}\n\nexport function defaultSchemaPath(authoring: AuthoringId): string {\n if (authoring === 'typescript') {\n return `${DEFAULT_CONTRACT_SOURCE_DIR}/contract.ts`;\n }\n return `${DEFAULT_CONTRACT_SOURCE_DIR}/contract.prisma`;\n}\n\nexport function starterSchema(target: TargetId, authoring: AuthoringId): string {\n if (authoring === 'typescript') {\n return target === 'mongo' ? starterSchemaTsMongo() : starterSchemaTsPostgres();\n }\n return target === 'mongo' ? starterSchemaPslMongo() : starterSchemaPslPostgres();\n}\n\n/**\n * Renders a short authoring-appropriate schema sample (FR5.1) for embedding\n * in `prisma-next.md`. Returns a complete fenced markdown code block.\n *\n * The sample intentionally shows just one model: it's illustrative, not\n * a substitute for the full scaffolded contract file. The TS samples use\n * the same outer shape as `starterSchemaTs*` (FR5.3) so a user reading\n * the doc and the file side-by-side sees the same structure.\n */\nexport function schemaSample(target: TargetId, authoring: AuthoringId): string {\n if (authoring === 'typescript') {\n return target === 'mongo' ? schemaSampleTsMongo() : schemaSampleTsPostgres();\n }\n return target === 'mongo' ? schemaSamplePslMongo() : schemaSamplePslPostgres();\n}\n\nfunction schemaSamplePslPostgres(): string {\n return `\\`\\`\\`prisma\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n username String?\n name String?\n}\n\\`\\`\\``;\n}\n\nfunction schemaSamplePslMongo(): string {\n return `\\`\\`\\`prisma\nmodel User {\n id ObjectId @id @map(\"_id\")\n email String @unique\n username String?\n name String?\n @@map(\"users\")\n}\n\\`\\`\\``;\n}\n\nfunction schemaSampleTsPostgres(): string {\n return `\\`\\`\\`typescript\nimport { defineContract } from '@prisma-next/postgres/contract-builder';\n\nexport const contract = defineContract(\n {},\n ({ field, model }) => ({\n models: {\n User: model('User', {\n fields: {\n id: field.id.uuidv7(),\n email: field.text().unique(),\n username: field.text().optional(),\n name: field.text().optional(),\n },\n }),\n },\n }),\n);\n\\`\\`\\``;\n}\n\nfunction schemaSampleTsMongo(): string {\n return `\\`\\`\\`typescript\nimport { defineContract } from '@prisma-next/mongo/contract-builder';\n\nexport const contract = defineContract(\n {},\n ({ field, model }) => ({\n models: {\n User: model('User', {\n collection: 'users',\n fields: {\n _id: field.objectId(),\n email: field.string(),\n username: field.string().optional(),\n name: field.string().optional(),\n },\n }),\n },\n }),\n);\n\\`\\`\\``;\n}\n\nfunction starterSchemaPslPostgres(): string {\n return `// use prisma-next\n\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n username String?\n name String?\n posts Post[]\n createdAt DateTime @default(now())\n updatedAt temporal.updatedAt()\n}\n\nmodel Post {\n id Int @id @default(autoincrement())\n title String\n content String?\n author User @relation(fields: [authorId], references: [id])\n authorId Int\n createdAt DateTime @default(now())\n updatedAt temporal.updatedAt()\n}\n`;\n}\n\nfunction starterSchemaPslMongo(): string {\n return `// use prisma-next\n\nmodel User {\n id ObjectId @id @map(\"_id\")\n email String @unique\n username String?\n name String?\n posts Post[]\n @@map(\"users\")\n}\n\nmodel Post {\n id ObjectId @id @map(\"_id\")\n title String\n content String?\n author User @relation(fields: [authorId], references: [id])\n authorId ObjectId\n @@map(\"posts\")\n}\n`;\n}\n\nfunction starterSchemaTsPostgres(): string {\n return `import { defineContract } from '@prisma-next/postgres/contract-builder';\n\nexport const contract = defineContract(\n {},\n ({ field, model, rel }) => ({\n models: {\n User: model('User', {\n fields: {\n id: field.id.uuidv7(),\n email: field.text().unique(),\n username: field.text().optional(),\n name: field.text().optional(),\n createdAt: field.temporal.createdAt(),\n updatedAt: field.temporal.updatedAt(),\n },\n relations: {\n posts: rel.hasMany('Post', { by: 'authorId' }),\n },\n }),\n\n Post: model('Post', {\n fields: {\n id: field.id.uuidv7(),\n title: field.text(),\n content: field.text().optional(),\n authorId: field.uuid(),\n createdAt: field.temporal.createdAt(),\n updatedAt: field.temporal.updatedAt(),\n },\n relations: {\n author: rel.belongsTo('User', { from: 'authorId', to: 'id' }),\n },\n }),\n },\n }),\n);\n`;\n}\n\nfunction starterSchemaTsMongo(): string {\n return `import { defineContract } from '@prisma-next/mongo/contract-builder';\n\nexport const contract = defineContract(\n {},\n ({ field, model, rel }) => ({\n models: {\n User: model('User', {\n collection: 'users',\n fields: {\n _id: field.objectId(),\n email: field.string(),\n username: field.string().optional(),\n name: field.string().optional(),\n },\n relations: {\n posts: rel.hasMany('Post', { from: '_id', to: 'authorId' }),\n },\n }),\n\n Post: model('Post', {\n collection: 'posts',\n fields: {\n _id: field.objectId(),\n title: field.string(),\n content: field.string().optional(),\n authorId: field.objectId(),\n },\n relations: {\n author: rel.belongsTo('User', { from: 'authorId', to: '_id' }),\n },\n }),\n },\n }),\n);\n`;\n}\n\nexport function configFile(target: TargetId, contractPath: string): string {\n const pkg = targetPackageName(target);\n return `import 'dotenv/config';\nimport { defineConfig } from '${pkg}/config';\n\nexport default defineConfig({\n contract: ${JSON.stringify(contractPath)},\n db: {\n connection: process.env['DATABASE_URL']!,\n },\n});\n`;\n}\n\nexport function dbFile(target: TargetId): string {\n if (target === 'postgres') {\n return `import postgres from '@prisma-next/postgres/runtime';\nimport type { Contract } from './contract.d';\nimport contractJson from './contract.json' with { type: 'json' };\n\nexport const db = postgres<Contract>({\n contractJson,\n url: process.env['DATABASE_URL']!,\n});\n`;\n }\n\n return `import mongo from '@prisma-next/mongo/runtime';\nimport type { Contract } from './contract.d';\nimport contractJson from './contract.json' with { type: 'json' };\n\nexport const db = mongo<Contract>({\n contractJson,\n url: process.env['DATABASE_URL']!,\n});\n`;\n}\n","import { Command } from 'commander';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../../utils/command-helpers';\nimport {\n type CommonCommandOptions,\n deriveCanPrompt,\n parseGlobalFlagsOrExit,\n} from '../../utils/global-flags';\nimport {\n INIT_EXIT_EMIT_FAILED,\n INIT_EXIT_INSTALL_FAILED,\n INIT_EXIT_INTERNAL_ERROR,\n INIT_EXIT_OK,\n INIT_EXIT_PRECONDITION,\n INIT_EXIT_SKILL_INSTALL_FAILED,\n INIT_EXIT_USER_ABORTED,\n} from './exit-codes';\nimport { defaultSchemaPath } from './templates/code-templates';\n\n/**\n * Commander.js parsed options for `init`. The init-specific options live\n * alongside the inherited `CommonCommandOptions` global flags.\n *\n * `target` and `authoring` are typed as plain `string` here because\n * Commander.js does not enforce enums at parse time — the validation /\n * normalisation happens in `inputs.ts::resolveInitInputs`, which can\n * raise a structured `errorInitInvalidFlagValue` with the full set of\n * allowed values.\n */\ninterface InitCommandOptions extends CommonCommandOptions {\n readonly target?: string;\n readonly authoring?: string;\n readonly schemaPath?: string;\n readonly force?: boolean;\n readonly writeEnv?: boolean;\n readonly probeDb?: boolean;\n readonly strictProbe?: boolean;\n readonly install?: boolean;\n readonly skill?: boolean;\n}\n\nexport function createInitCommand(): Command {\n const command = new Command('init');\n setCommandDescriptions(\n command,\n 'Initialize a new Prisma Next project',\n 'Scaffolds config, schema, and runtime files, installs dependencies,\\n' +\n 'and emits the contract. Gets you from zero to typed queries in one step.\\n' +\n '\\n' +\n 'Run interactively for a guided experience, or supply --target / --authoring\\n' +\n 'and --yes for a fully scriptable run (CI, AI coding agents, automation).\\n' +\n '\\n' +\n 'Exit codes (see CLI Style Guide § Exit Codes):\\n' +\n ` ${INIT_EXIT_OK} OK Init succeeded.\\n` +\n ` ${INIT_EXIT_INTERNAL_ERROR} INTERNAL_ERROR Unexpected bug in prisma-next (please report).\\n` +\n ` ${INIT_EXIT_PRECONDITION} PRECONDITION Bad flags / missing prerequisite (e.g. no package.json).\\n` +\n ` ${INIT_EXIT_USER_ABORTED} USER_ABORTED User cancelled an interactive prompt.\\n` +\n ` ${INIT_EXIT_INSTALL_FAILED} INSTALL_FAILED Dependency installation failed (init-specific).\\n` +\n ` ${INIT_EXIT_EMIT_FAILED} EMIT_FAILED \\`contract emit\\` failed after install (init-specific).\\n` +\n ` ${INIT_EXIT_SKILL_INSTALL_FAILED} SKILL_INSTALL_FAILED Agent-skill install failed (re-run with --no-skill to skip).`,\n );\n setCommandExamples(command, [\n 'prisma-next init',\n 'prisma-next init --yes --target postgres --authoring psl',\n 'prisma-next init --yes --target mongodb --authoring typescript --json',\n 'prisma-next init --yes --force --target postgres --authoring psl # overwrite an existing scaffold',\n 'prisma-next init --no-install # skip pnpm/npm install + emit',\n 'prisma-next init --no-skill # skip the skills install (air-gapped / restricted env)',\n ]);\n\n return addGlobalOptions(command)\n .option('--target <db>', 'Database target: postgres or mongodb')\n .option('--authoring <style>', 'Schema authoring style: psl or typescript')\n .option(\n '--schema-path <path>',\n `Where to write the starter schema (default: ${defaultSchemaPath('psl')})`,\n )\n .option('--force', 'Overwrite an existing scaffold without prompting')\n .option(\n '--write-env',\n 'Write a .env file from .env.example (gitignored; default: only .env.example)',\n )\n .option(\n '--probe-db',\n 'Connect to DATABASE_URL once and check the server version against the target minimum (opt-in; off by default)',\n )\n .option(\n '--strict-probe',\n 'Treat a failed --probe-db as fatal (no-op without --probe-db; init is offline-by-default)',\n )\n .option('--no-install', 'Skip dependency installation and contract emission')\n .option(\n '--no-skill',\n 'Skip Prisma Next skills install (air-gapped CI, restricted registries, etc.)',\n )\n .action(async (options: InitCommandOptions) => {\n const { runInit } = await import('./init');\n const flags = parseGlobalFlagsOrExit(options);\n const canPrompt = deriveCanPrompt({\n flagsInteractive: flags.interactive,\n optionInteractive: options.interactive,\n stdinIsTTY: Boolean(process.stdin.isTTY),\n });\n const exitCode = await runInit(process.cwd(), {\n options,\n flags,\n canPrompt,\n });\n process.exit(exitCode);\n });\n}\n","import { distance } from 'closest-match';\n\n/**\n * Suggests similar command names for a mistyped input.\n *\n * Uses Levenshtein distance to find close matches. Only suggests commands\n * within a reasonable distance threshold (40% of the input length, minimum 2).\n * Returns up to 3 suggestions in case of ties.\n *\n * @returns Array of suggested command names (empty if nothing is close enough).\n */\nexport function suggestCommands(input: string, candidates: readonly string[]): string[] {\n if (candidates.length === 0) return [];\n\n // Threshold: at most 40% of the input length (min 2) to avoid absurd suggestions\n const maxDistance = Math.max(2, Math.ceil(input.length * 0.4));\n\n const scored = candidates\n .map((name) => ({ name, dist: distance(input, name) }))\n .filter((entry) => entry.dist <= maxDistance)\n .sort((a, b) => a.dist - b.dist);\n\n if (scored.length === 0) return [];\n\n // Take the best distance, then include ties (up to 3)\n const bestDist = scored[0]!.dist;\n return scored\n .filter((entry) => entry.dist === bestDist)\n .slice(0, 3)\n .map((entry) => entry.name);\n}\n","import { fileURLToPath } from 'node:url';\nimport {\n type CommanderOptionShape,\n type CommanderResultShape,\n ensureInstallationId,\n readUserConfig,\n resolveGating,\n runTelemetry,\n type TelemetryRunOutcome,\n type UserConfig,\n userConfigPath,\n} from '@prisma-next/cli-telemetry';\nimport type { Command } from 'commander';\nimport { version as CLI_VERSION } from '../../package.json' with { type: 'json' };\nimport { isCI } from './is-ci';\n\ntype TelemetryGate =\n | { readonly enabled: true; readonly userConfig: UserConfig }\n | { readonly enabled: false; readonly outcome: TelemetryRunOutcome };\n\n/**\n * Resolve the commander command path from a leaf `Command`, walking up\n * the parent chain. Result is rooted at the program name and ends at\n * the leaf — `['prisma-next', 'migration', 'new']` for\n * `prisma-next migration new …`.\n */\nfunction commandPathFor(actionCommand: Command): string[] {\n const path: string[] = [];\n let cursor: Command | null = actionCommand;\n while (cursor !== null) {\n path.unshift(cursor.name());\n cursor = cursor.parent;\n }\n return path;\n}\n\nfunction commanderOptionSnapshots(actionCommand: Command): CommanderOptionShape[] {\n return actionCommand.options.map((option) => {\n const attributeName = option.attributeName();\n return {\n attributeName,\n longName: option.long ?? null,\n source: actionCommand.getOptionValueSource(attributeName) ?? null,\n };\n });\n}\n\n/**\n * Project commander's leaf `Command` into the wire-shape snapshot the\n * telemetry sanitiser consumes. Pure projection — no env, no I/O.\n */\nexport function commanderSnapshotForTelemetry(actionCommand: Command): CommanderResultShape {\n return {\n commandPath: commandPathFor(actionCommand),\n positionalArgs: actionCommand.args,\n options: commanderOptionSnapshots(actionCommand),\n };\n}\n\nfunction resolveTelemetryGate(): TelemetryGate {\n if (isCI()) {\n return { enabled: false, outcome: { spawned: false, reason: 'ci' } };\n }\n const userConfig = readUserConfig();\n const gating = resolveGating({ env: process.env, config: userConfig });\n if (!gating.enabled) {\n return { enabled: false, outcome: { spawned: false, reason: 'gated-off' } };\n }\n return { enabled: true, userConfig };\n}\n\n/**\n * Path to the compiled sender script inside `@prisma-next/cli-telemetry`'s\n * `dist/`. Resolved off this module's `import.meta.url` via the package\n * specifier `@prisma-next/cli-telemetry/sender`, so the consumer pays\n * no attention to internal package layout.\n */\nfunction senderPath(): string {\n return fileURLToPath(new URL(import.meta.resolve('@prisma-next/cli-telemetry/sender')));\n}\n\nfunction fireTelemetry(actionCommand: Command, userConfig: UserConfig): TelemetryRunOutcome {\n return runTelemetry({\n command: commanderSnapshotForTelemetry(actionCommand),\n version: CLI_VERSION,\n projectRoot: process.cwd(),\n senderPath: senderPath(),\n isCI: isCI(),\n env: process.env,\n userConfig,\n });\n}\n\n/**\n * preAction-stage entry point. Synchronous by construction: resolve\n * env/CI/user-consent gates (cheap, all in-memory and a single tiny\n * user-config read), then — only when enabled — `fork()` the detached\n * sender script. The forked child loads `prisma-next.config.*` via\n * c12 on its own (see `loadProjectConfig` in cli-telemetry); the\n * parent does no project-config I/O on the command's hot path.\n *\n * Privacy invariant: gate resolution always happens before any project\n * config touches disk. The child loading user TS code is acceptable\n * only because it's gated behind the same resolved-enabled signal.\n */\n/**\n * Builds the one-time first-run disclosure. The resolved absolute path to\n * the user-level config file is substituted in so the user can see exactly\n * which file to edit (it must not be confused with `prisma-next.config.ts`).\n * `prisma-next telemetry disable` is named as the primary, friendliest\n * opt-out, alongside the env vars and the config edit.\n */\nfunction firstRunNotice(configPath: string): string {\n return [\n 'Prisma Next collects anonymous CLI usage data, enabled by default.',\n \"What's collected and why: https://prisma-next.dev/docs/cli/telemetry.\",\n 'Opt out: run \"prisma-next telemetry disable\", set DO_NOT_TRACK=1 or',\n `PRISMA_NEXT_DISABLE_TELEMETRY=1, or set \"enableTelemetry\": false in ${configPath}.`,\n ].join(' ');\n}\n\n/**\n * Best-effort first-run disclosure + installationId mint. Runs only on the\n * gating-enabled path. Prints the notice to stderr (never stdout) and mints\n * a persistent id without touching `enableTelemetry`, so the opt-out default\n * stays intact and no unasked-for consent is recorded.\n *\n * Every step is wrapped so an un-writable config dir (or any other failure)\n * never throws and never blocks the command. Returns the minted (or\n * pre-existing) id so the caller can forward it to `runTelemetry` without a\n * redundant disk read. On mint failure it returns `undefined`: the notice may\n * reprint next run, and `runTelemetry` no-ops on the missing id.\n */\nfunction discloseAndMintOnFirstRun(): string | undefined {\n try {\n process.stderr.write(`${firstRunNotice(userConfigPath())}\\n`);\n } catch {}\n try {\n return ensureInstallationId();\n } catch {}\n return undefined;\n}\n\n/**\n * True when the run is the `telemetry` command (or one of its\n * subcommands). The usage-telemetry preAction fire is exempted for it:\n * it would be absurd for `telemetry disable` to send a usage event before\n * disabling, or for `telemetry status` to mint an id + send while merely\n * reporting state. This is the only command-specific exemption.\n *\n * The check is rooted at the program: the path must be\n * `['prisma-next', 'telemetry', …]`, so it matches the top-level\n * `telemetry` command and its subcommands without matching a hypothetical\n * nested `… telemetry` elsewhere.\n */\nfunction isTelemetryCommand(actionCommand: Command): boolean {\n return commandPathFor(actionCommand)[1] === 'telemetry';\n}\n\nexport function fireTelemetryFromPreAction(actionCommand: Command): TelemetryRunOutcome {\n if (isTelemetryCommand(actionCommand)) {\n return { spawned: false, reason: 'gated-off' };\n }\n const gate = resolveTelemetryGate();\n if (!gate.enabled) {\n return gate.outcome;\n }\n const storedId = gate.userConfig.installationId;\n if (typeof storedId !== 'string' || storedId.length === 0) {\n const installationId = discloseAndMintOnFirstRun();\n return fireTelemetry(\n actionCommand,\n installationId === undefined ? gate.userConfig : { ...gate.userConfig, installationId },\n );\n }\n return fireTelemetry(actionCommand, gate.userConfig);\n}\n","import { Command } from 'commander';\nimport packageJson from '../package.json' with { type: 'json' };\nimport { createContractEmitCommand } from './commands/contract-emit';\nimport { createContractInferCommand } from './commands/contract-infer';\nimport { createInitCommand } from './commands/init';\nimport { installShutdownHandlers } from './utils/shutdown';\n\n// Install SIGINT/SIGTERM handlers before anything else\ninstallShutdownHandlers();\n\nimport { createDbInitCommand } from './commands/db-init';\nimport { createDbSchemaCommand } from './commands/db-schema';\nimport { createDbSignCommand } from './commands/db-sign';\nimport { createDbUpdateCommand } from './commands/db-update';\nimport { createDbVerifyCommand } from './commands/db-verify';\nimport { createMigrateCommand } from './commands/migrate';\nimport { createMigrationCheckCommand } from './commands/migration-check';\nimport { createMigrationGraphCommand } from './commands/migration-graph';\nimport { createMigrationListCommand } from './commands/migration-list';\nimport { createMigrationLogCommand } from './commands/migration-log';\nimport { createMigrationNewCommand } from './commands/migration-new';\nimport { createMigrationPlanCommand } from './commands/migration-plan';\nimport { createMigrationShowCommand } from './commands/migration-show';\nimport { createMigrationStatusCommand } from './commands/migration-status';\nimport { createRefCommand } from './commands/ref';\nimport { createTelemetryCommand } from './commands/telemetry';\nimport { setCommandDescriptions } from './utils/command-helpers';\nimport { formatCommandHelp, formatRootHelp } from './utils/formatters/help';\nimport { parseGlobalFlags } from './utils/global-flags';\nimport { suggestCommands } from './utils/suggest-command';\nimport { fireTelemetryFromPreAction } from './utils/telemetry';\n\n/**\n * Lookup table mapping removed subcommands to their replacement verbs.\n * Keyed by `<parent>:<subcommand>` (e.g. `migration:apply`).\n * The handler consults this before falling back to the fuzzy suggest engine.\n */\nconst removedVerbRedirects: Record<string, string> = {\n 'migration:apply': 'Use `prisma-next migrate --to <contract>` instead.',\n 'migration:ref': 'Use `prisma-next ref set|list|delete` instead.',\n};\n\n/**\n * Removed flags on specific subcommands. Keyed by `<parent>:<sub>:<flag>`.\n * Checked during the pre-parse argv scan before commander sees the flags.\n */\nconst removedFlagRedirects: Record<string, string> = {\n 'migration:status:graph': 'Use `prisma-next migration graph` to view the migration graph.',\n 'migration:status:all':\n 'Use `prisma-next migration log --db <url>` to view the full execution history.',\n 'migration:status:limit':\n 'Use `prisma-next migration log --db <url>` to view the full execution history.',\n 'migration:status:ref': 'Use `--to <contract>` instead of `--ref`.',\n};\n\n/**\n * Formats the \"Did you mean ...?\" hint for an unknown command.\n */\nfunction formatSuggestion(input: string, candidates: readonly string[]): string {\n const suggestions = suggestCommands(\n input,\n candidates.map((c) => c),\n );\n if (suggestions.length === 0) return '';\n if (suggestions.length === 1) return `\\nDid you mean ${suggestions[0]}?\\n`;\n return `\\nDid you mean one of these?\\n${suggestions.map((s) => ` ${s}`).join('\\n')}\\n`;\n}\n\nconst program = new Command();\n\nprogram.name('prisma-next').description('Prisma Next CLI').version(packageJson.version);\n\n// Telemetry hook — fires at command start, before the action body\n// runs. Synchronous by construction: `fireTelemetryFromPreAction`\n// resolves gates (cheap), then `fork()`s the detached sender. The\n// fork is enqueued before the action body runs at all, so the child\n// survives even when the action throws synchronously. The try/catch\n// is defence-in-depth — `runTelemetry` already swallows every failure\n// mode internally and returns an outcome instead of throwing.\nprogram.hook('preAction', (_thisCommand, actionCommand) => {\n try {\n fireTelemetryFromPreAction(actionCommand);\n } catch {\n // defence-in-depth — runTelemetry already swallows internally.\n }\n});\n\n// Override version option description to match capitalization style\nconst versionOption = program.options.find((opt) => opt.flags.includes('--version'));\nif (versionOption) {\n versionOption.description = 'Output the version number';\n}\n\nprogram.configureOutput({\n writeErr: () => {\n // Suppress all default error output - we handle errors in exitOverride\n },\n writeOut: (str) => {\n // Commander routes explicitly-requested `--help` (success-path help)\n // through writeOut; per the Style Guide § Output Conventions rule 8,\n // user-requested help is data and goes to stdout. Error-path help\n // (e.g. usage shown after an unknown command) goes through writeErr,\n // which stays suppressed because we render that ourselves with the\n // matching error envelope.\n //\n // Explicit `--version` is short-circuited before `program.parse()`\n // (see the argv pre-scan at the bottom of this file), so it does not\n // reach this writer.\n process.stdout.write(str);\n },\n});\n\n// Customize root help output to use our styled format\nconst rootHelpFormatter = (cmd: Command) => {\n const flags = parseGlobalFlags({});\n return formatRootHelp({ program: cmd, flags });\n};\n\nprogram.configureHelp({\n formatHelp: rootHelpFormatter,\n subcommandDescription: () => '',\n});\n\n// Override exit to handle unhandled errors (fail fast cases)\n// Commands handle structured errors themselves via process.exit()\nprogram.exitOverride((err) => {\n if (err) {\n const errorCode = (err as { code?: string }).code;\n const errorMessage = String(err.message ?? '');\n const errorName = err.name ?? '';\n\n // Unknown command/argument → exit 2 (CLI usage error)\n const isUnknownCommandError =\n errorCode === 'commander.unknownCommand' ||\n errorCode === 'commander.unknownArgument' ||\n (errorName === 'CommanderError' &&\n (errorMessage.includes('unknown command') || errorMessage.includes('unknown argument')));\n if (isUnknownCommandError) {\n const flags = parseGlobalFlags({});\n const match = errorMessage.match(/unknown command ['\"]([^'\"]+)['\"]/);\n const commandName = match ? match[1] : process.argv[3] || process.argv[2] || 'unknown';\n\n const firstArg = process.argv[2];\n const parentCommand = firstArg\n ? program.commands.find((cmd) => cmd.name() === firstArg)\n : undefined;\n\n if (parentCommand && commandName !== firstArg) {\n const subNames = parentCommand.commands.map((c) => c.name());\n process.stderr.write(\n `Unknown command: ${commandName}${formatSuggestion(commandName!, subNames)}\\n`,\n );\n const helpText = formatCommandHelp({ command: parentCommand, flags });\n process.stderr.write(`${helpText}\\n`);\n } else {\n const topNames = program.commands.map((c) => c.name());\n process.stderr.write(\n `Unknown command: ${commandName}${formatSuggestion(commandName!, topNames)}\\n`,\n );\n const helpText = formatRootHelp({ program, flags });\n process.stderr.write(`${helpText}\\n`);\n }\n process.exit(2);\n return;\n }\n\n // Help requests → exit 0\n const isHelpError =\n errorCode === 'commander.help' ||\n errorCode === 'commander.helpDisplayed' ||\n errorCode === 'outputHelp' ||\n errorMessage === '(outputHelp)' ||\n errorMessage.includes('outputHelp') ||\n (errorName === 'CommanderError' && errorMessage.includes('outputHelp'));\n if (isHelpError) {\n process.exit(0);\n return;\n }\n\n // Missing required arguments → exit 2 (CLI usage error)\n const isMissingArgumentError =\n errorCode === 'commander.missingArgument' ||\n errorCode === 'commander.missingMandatoryOptionValue' ||\n (errorName === 'CommanderError' &&\n (errorMessage.includes('missing') || errorMessage.includes('required')));\n if (isMissingArgumentError) {\n process.exit(2);\n return;\n }\n\n // Unhandled error → exit 1\n process.stderr.write(`Unhandled error: ${err.message}\\n`);\n if (err.stack) {\n process.stderr.write(`${err.stack}\\n`);\n }\n process.exit(1);\n }\n process.exit(0);\n});\n\n// Register contract subcommand\nconst contractCommand = new Command('contract');\nsetCommandDescriptions(\n contractCommand,\n 'Contract management commands',\n 'Define and emit your application data contract. The contract describes your schema as a\\n' +\n 'declarative data structure that can be signed and verified against your database.',\n);\ncontractCommand.configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n subcommandDescription: () => '',\n});\n\n// Add emit subcommand to contract\nconst contractEmitCommand = createContractEmitCommand();\ncontractCommand.addCommand(contractEmitCommand);\n\n// Add infer subcommand to contract\nconst contractInferCommand = createContractInferCommand();\ncontractCommand.addCommand(contractInferCommand);\n\n// Register db subcommand\nconst dbCommand = new Command('db');\nsetCommandDescriptions(\n dbCommand,\n 'Database management commands',\n 'Verify and sign your database with your contract. Ensure your database schema matches\\n' +\n 'your contract, and sign it to record the contract hash for future verification.',\n);\ndbCommand.configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n subcommandDescription: () => '',\n});\n\n// Add verify subcommand to db\nconst dbVerifyCommand = createDbVerifyCommand();\ndbCommand.addCommand(dbVerifyCommand);\n\n// Add init subcommand to db\nconst dbInitCommand = createDbInitCommand();\ndbCommand.addCommand(dbInitCommand);\n\n// Add update subcommand to db\nconst dbUpdateCommand = createDbUpdateCommand();\ndbCommand.addCommand(dbUpdateCommand);\n\n// Add schema subcommand to db\nconst dbSchemaCommand = createDbSchemaCommand();\ndbCommand.addCommand(dbSchemaCommand);\n\n// Add sign subcommand to db\nconst dbSignCommand = createDbSignCommand();\ndbCommand.addCommand(dbSignCommand);\n\n// Register migration subcommand\nconst migrationCommand = new Command('migration');\nsetCommandDescriptions(\n migrationCommand,\n 'On-disk migration management commands',\n 'Plan, apply, and scaffold on-disk migration packages. Migrations are\\n' +\n 'contract-to-contract edges stored as versioned directories under migrations/.',\n);\nmigrationCommand.configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n subcommandDescription: () => '',\n});\n\nconst migrationPlanCommand = createMigrationPlanCommand();\nmigrationCommand.addCommand(migrationPlanCommand);\n\nconst migrationNewCommand = createMigrationNewCommand();\nmigrationCommand.addCommand(migrationNewCommand);\n\nconst migrationShowCommand = createMigrationShowCommand();\nmigrationCommand.addCommand(migrationShowCommand);\n\nconst migrationStatusCommand = createMigrationStatusCommand();\nmigrationCommand.addCommand(migrationStatusCommand);\n\nconst migrationLogCommand = createMigrationLogCommand();\nmigrationCommand.addCommand(migrationLogCommand);\n\nconst migrationListCommand = createMigrationListCommand();\nmigrationCommand.addCommand(migrationListCommand);\n\nconst migrationGraphCommand = createMigrationGraphCommand();\nmigrationCommand.addCommand(migrationGraphCommand);\n\nconst migrationCheckCommand = createMigrationCheckCommand();\nmigrationCommand.addCommand(migrationCheckCommand);\n\n// Top-level migrate command\nconst migrateCommand = createMigrateCommand();\n\n// Top-level ref command (replaces `migration ref`)\nconst refCommand = createRefCommand();\n\n// Top-level telemetry command\nconst telemetryCommand = createTelemetryCommand();\n\n// Top-level init command\nconst initCommand = createInitCommand();\n\n// Register top-level commands in the order the spec's intended-surface\n// diagram lists them: verbs (init, migrate) first, then subject\n// namespaces (contract, db, migration, ref). The order shows up in\n// `prisma-next --help` and is the first thing a new user sees, so it\n// matches the order spec.md uses to introduce the surface.\nprogram.addCommand(initCommand);\nprogram.addCommand(migrateCommand);\nprogram.addCommand(contractCommand);\nprogram.addCommand(dbCommand);\nprogram.addCommand(migrationCommand);\nprogram.addCommand(refCommand);\nprogram.addCommand(telemetryCommand);\n\n// Test-only hidden command used by `cli-telemetry`'s `cli-e2e.test.ts`\n// to verify that telemetry still lands when a CLI command crashes\n// mid-execution. The preAction hook is synchronous and `fork()`s the\n// detached sender before this action body runs; the small sleep\n// gives the IPC `child.send()` a tick to flush before the throw\n// triggers commander's `exitOverride` and `process.exit(1)`. Hidden\n// from help; underscore prefix marks it as internal. Doesn't depend\n// on any project state, so it runs in any tempdir.\n//\n// Gated behind `PRISMA_NEXT_ENABLE_TEST_COMMANDS=1` so the command is\n// not even registered (and therefore not invocable) in shipped\n// binaries. `hidden: true` only filters the help output; without this\n// env gate the command would still be callable from production. The\n// e2e suite sets the env var when it spawns the CLI.\nconst TELEMETRY_CRASH_TEST_SLEEP_MS = 200;\nif (process.env['PRISMA_NEXT_ENABLE_TEST_COMMANDS'] === '1') {\n const telemetryCrashTestCommand = new Command('__telemetry-crash-test')\n .description('Internal: deliberately throw for the telemetry e2e suite.')\n .action(async () => {\n await new Promise((settle) => setTimeout(settle, TELEMETRY_CRASH_TEST_SLEEP_MS));\n throw new Error('__telemetry-crash-test: intentional crash for e2e coverage');\n });\n telemetryCrashTestCommand.configureHelp({ visibleCommands: () => [] });\n program.addCommand(telemetryCrashTestCommand, { hidden: true });\n}\n\n// Create help command\nconst helpCommand = new Command('help')\n .description('Show usage instructions')\n .configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n })\n .action(() => {\n const flags = parseGlobalFlags({});\n const helpText = formatRootHelp({ program, flags });\n // The `help` command was invoked explicitly: help is the data the\n // caller asked for. Per Style Guide § Output Conventions rule 8,\n // explicit help goes to stdout with exit code 0.\n process.stdout.write(`${helpText}\\n`);\n process.exit(0);\n });\n\nprogram.addCommand(helpCommand);\n\n// Set help as the default action when no command is provided. The user\n// did not invoke `--help`; we are voluntarily showing usage to help them\n// recover from an underspecified invocation, so the help text is\n// decoration around an implicit \"what did you want me to do?\" and goes\n// to stderr (Style Guide § Output Conventions rule 8).\n//\n// FOLLOW-UP: the exit code here is 0 today, but a no-arg invocation is\n// arguably a usage error (PRECONDITION → exit 2) for consistency with\n// the unknown-command path. Out of scope for the explicit-help routing\n// work; revisit when tightening exit-code semantics across the CLI.\nprogram.action(() => {\n const flags = parseGlobalFlags({});\n const helpText = formatRootHelp({ program, flags });\n process.stderr.write(`${helpText}\\n`);\n process.exit(0);\n});\n\n// Check if a command was invoked with no arguments (just the command name)\n// or if an unrecognized command was provided\nconst args = process.argv.slice(2);\nif (args.length > 0) {\n const commandName = args[0];\n // Handle version option explicitly since we suppress default output\n if (commandName === '--version' || commandName === '-V') {\n // Version is data → stdout\n process.stdout.write(`${program.version()}\\n`);\n process.exit(0);\n }\n // Skip command check for global options like --help, -h\n const isGlobalOption = commandName === '--help' || commandName === '-h';\n if (!isGlobalOption) {\n // Check if this is a recognized command\n const command = program.commands.find((cmd) => cmd.name() === commandName);\n\n if (!command) {\n // Unrecognized command → exit 2 (CLI usage error)\n const flags = parseGlobalFlags({});\n const topNames = program.commands.map((c) => c.name());\n process.stderr.write(\n `Unknown command: ${commandName}${formatSuggestion(commandName!, topNames)}\\n`,\n );\n const helpText = formatRootHelp({ program, flags });\n process.stderr.write(`${helpText}\\n`);\n process.exit(2);\n } else if (command.commands.length > 0 && args.length >= 2) {\n const subcommandName = args[1];\n const redirectKey = `${commandName}:${subcommandName}`;\n const redirect = removedVerbRedirects[redirectKey];\n if (redirect) {\n process.stderr.write(`Unknown command: ${subcommandName}\\n${redirect}\\n`);\n process.exit(2);\n }\n for (let i = 2; i < args.length; i++) {\n const arg = args[i]!;\n if (!arg.startsWith('--')) continue;\n const flagName = arg.slice(2);\n const flagKey = `${commandName}:${subcommandName}:${flagName}`;\n const flagRedirect = removedFlagRedirects[flagKey];\n if (flagRedirect) {\n process.stderr.write(`Unknown option: ${arg}\\n${flagRedirect}\\n`);\n process.exit(2);\n }\n }\n }\n\n if (command.commands.length > 0 && args.length === 1) {\n // Parent command called with no subcommand. Same shape as the\n // no-args case above: the user did not request help, we are\n // voluntarily rendering it as decoration around an underspecified\n // invocation, so it goes to stderr per Style Guide § Output\n // Conventions rule 8. Exit code 0 today; the FOLLOW-UP note on\n // `program.action` applies here too (arguably should be 2).\n const flags = parseGlobalFlags({});\n const helpText = formatCommandHelp({ command, flags });\n process.stderr.write(`${helpText}\\n`);\n process.exit(0);\n }\n }\n}\n\nprogram.parse();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKA,SAAgB,kBAAkB,QAA0B;CAC1D,OAAO,WAAW,aAAa,0BAA0B;AAC3D;AAEA,SAAgB,YAAY,QAA0B;CACpD,OAAO,WAAW,aAAa,eAAe;AAChD;AAEA,SAAgB,kBAAkB,WAAgC;CAChE,IAAI,cAAc,cAChB,OAAO,GAAG,4BAA4B;CAExC,OAAO,GAAG,4BAA4B;AACxC;AAEA,SAAgB,cAAc,QAAkB,WAAgC;CAC9E,IAAI,cAAc,cAChB,OAAO,WAAW,UAAU,qBAAqB,IAAI,wBAAwB;CAE/E,OAAO,WAAW,UAAU,sBAAsB,IAAI,yBAAyB;AACjF;;;;;;;;;;AAWA,SAAgB,aAAa,QAAkB,WAAgC;CAC7E,IAAI,cAAc,cAChB,OAAO,WAAW,UAAU,oBAAoB,IAAI,uBAAuB;CAE7E,OAAO,WAAW,UAAU,qBAAqB,IAAI,wBAAwB;AAC/E;AAEA,SAAS,0BAAkC;CACzC,OAAO;;;;;;;;AAQT;AAEA,SAAS,uBAA+B;CACtC,OAAO;;;;;;;;;AAST;AAEA,SAAS,yBAAiC;CACxC,OAAO;;;;;;;;;;;;;;;;;;;AAmBT;AAEA,SAAS,sBAA8B;CACrC,OAAO;;;;;;;;;;;;;;;;;;;;AAoBT;AAEA,SAAS,2BAAmC;CAC1C,OAAO;;;;;;;;;;;;;;;;;;;;;;AAsBT;AAEA,SAAS,wBAAgC;CACvC,OAAO;;;;;;;;;;;;;;;;;;;;AAoBT;AAEA,SAAS,0BAAkC;CACzC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCT;AAEA,SAAS,uBAA+B;CACtC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCT;AAEA,SAAgB,WAAW,QAAkB,cAA8B;CAEzE,OAAO;gCADK,kBAAkB,MAEE,EAAE;;;cAGtB,KAAK,UAAU,YAAY,EAAE;;;;;;AAM3C;AAEA,SAAgB,OAAO,QAA0B;CAC/C,IAAI,WAAW,YACb,OAAO;;;;;;;;;CAWT,OAAO;;;;;;;;;AAST;;;ACrOA,SAAgB,oBAA6B;CAC3C,MAAM,UAAU,IAAI,QAAQ,MAAM;CAClC,uBACE,SACA,wCACA;;;;;;;6gBAcF;CACA,mBAAmB,SAAS;EAC1B;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,OAAO,iBAAiB,OAAO,CAAC,CAC7B,OAAO,iBAAiB,sCAAsC,CAAC,CAC/D,OAAO,uBAAuB,2CAA2C,CAAC,CAC1E,OACC,wBACA,+CAA+C,kBAAkB,KAAK,EAAE,EAC1E,CAAC,CACA,OAAO,WAAW,kDAAkD,CAAC,CACrE,OACC,eACA,8EACF,CAAC,CACA,OACC,cACA,+GACF,CAAC,CACA,OACC,kBACA,2FACF,CAAC,CACA,OAAO,gBAAgB,oDAAoD,CAAC,CAC5E,OACC,cACA,8EACF,CAAC,CACA,OAAO,OAAO,YAAgC;EAC7C,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,MAAM,QAAQ,uBAAuB,OAAO;EAC5C,MAAM,YAAY,gBAAgB;GAChC,kBAAkB,MAAM;GACxB,mBAAmB,QAAQ;GAC3B,YAAY,QAAQ,QAAQ,MAAM,KAAK;EACzC,CAAC;EACD,MAAM,WAAW,MAAM,QAAQ,QAAQ,IAAI,GAAG;GAC5C;GACA;GACA;EACF,CAAC;EACD,QAAQ,KAAK,QAAQ;CACvB,CAAC;AACL;;;;;;;;;;;;ACtGA,SAAgB,gBAAgB,OAAe,YAAyC;CACtF,IAAI,WAAW,WAAW,GAAG,OAAO,CAAC;CAGrC,MAAM,cAAc,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,SAAS,EAAG,CAAC;CAE7D,MAAM,SAAS,WACZ,KAAK,UAAU;EAAE;EAAM,MAAM,SAAS,OAAO,IAAI;CAAE,EAAE,CAAC,CACtD,QAAQ,UAAU,MAAM,QAAQ,WAAW,CAAC,CAC5C,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;CAEjC,IAAI,OAAO,WAAW,GAAG,OAAO,CAAC;CAGjC,MAAM,WAAW,OAAO,EAAE,CAAE;CAC5B,OAAO,OACJ,QAAQ,UAAU,MAAM,SAAS,QAAQ,CAAC,CAC1C,MAAM,GAAG,CAAC,CAAC,CACX,KAAK,UAAU,MAAM,IAAI;AAC9B;;;;;;;;;ACJA,SAAS,eAAe,eAAkC;CACxD,MAAM,OAAiB,CAAC;CACxB,IAAI,SAAyB;CAC7B,OAAO,WAAW,MAAM;EACtB,KAAK,QAAQ,OAAO,KAAK,CAAC;EAC1B,SAAS,OAAO;CAClB;CACA,OAAO;AACT;AAEA,SAAS,yBAAyB,eAAgD;CAChF,OAAO,cAAc,QAAQ,KAAK,WAAW;EAC3C,MAAM,gBAAgB,OAAO,cAAc;EAC3C,OAAO;GACL;GACA,UAAU,OAAO,QAAQ;GACzB,QAAQ,cAAc,qBAAqB,aAAa,KAAK;EAC/D;CACF,CAAC;AACH;;;;;AAMA,SAAgB,8BAA8B,eAA8C;CAC1F,OAAO;EACL,aAAa,eAAe,aAAa;EACzC,gBAAgB,cAAc;EAC9B,SAAS,yBAAyB,aAAa;CACjD;AACF;AAEA,SAAS,uBAAsC;CAC7C,IAAI,KAAK,GACP,OAAO;EAAE,SAAS;EAAO,SAAS;GAAE,SAAS;GAAO,QAAQ;EAAK;CAAE;CAErE,MAAM,aAAa,eAAe;CAElC,IAAI,CADW,cAAc;EAAE,KAAK,QAAQ;EAAK,QAAQ;CAAW,CAC1D,CAAC,CAAC,SACV,OAAO;EAAE,SAAS;EAAO,SAAS;GAAE,SAAS;GAAO,QAAQ;EAAY;CAAE;CAE5E,OAAO;EAAE,SAAS;EAAM;CAAW;AACrC;;;;;;;AAQA,SAAS,aAAqB;CAC5B,OAAO,cAAc,IAAI,IAAI,OAAO,KAAK,QAAQ,mCAAmC,CAAC,CAAC;AACxF;AAEA,SAAS,cAAc,eAAwB,YAA6C;CAC1F,OAAO,aAAa;EAClB,SAAS,8BAA8B,aAAa;EAC3CA;EACT,aAAa,QAAQ,IAAI;EACzB,YAAY,WAAW;EACvB,MAAM,KAAK;EACX,KAAK,QAAQ;EACb;CACF,CAAC;AACH;;;;;;;;;;;;;;;;;;;;AAqBA,SAAS,eAAe,YAA4B;CAClD,OAAO;EACL;EACA;EACA;EACA,uEAAuE,WAAW;CACpF,CAAC,CAAC,KAAK,GAAG;AACZ;;;;;;;;;;;;;AAcA,SAAS,4BAAgD;CACvD,IAAI;EACF,QAAQ,OAAO,MAAM,GAAG,eAAe,eAAe,CAAC,EAAE,GAAG;CAC9D,QAAQ,CAAC;CACT,IAAI;EACF,OAAO,qBAAqB;CAC9B,QAAQ,CAAC;AAEX;;;;;;;;;;;;;AAcA,SAAS,mBAAmB,eAAiC;CAC3D,OAAO,eAAe,aAAa,CAAC,CAAC,OAAO;AAC9C;AAEA,SAAgB,2BAA2B,eAA6C;CACtF,IAAI,mBAAmB,aAAa,GAClC,OAAO;EAAE,SAAS;EAAO,QAAQ;CAAY;CAE/C,MAAM,OAAO,qBAAqB;CAClC,IAAI,CAAC,KAAK,SACR,OAAO,KAAK;CAEd,MAAM,WAAW,KAAK,WAAW;CACjC,IAAI,OAAO,aAAa,YAAY,SAAS,WAAW,GAAG;EACzD,MAAM,iBAAiB,0BAA0B;EACjD,OAAO,cACL,eACA,mBAAmB,KAAA,IAAY,KAAK,aAAa;GAAE,GAAG,KAAK;GAAY;EAAe,CACxF;CACF;CACA,OAAO,cAAc,eAAe,KAAK,UAAU;AACrD;;;ACxKA,wBAAwB;;;;;;AA6BxB,MAAM,uBAA+C;CACnD,mBAAmB;CACnB,iBAAiB;AACnB;;;;;AAMA,MAAM,uBAA+C;CACnD,0BAA0B;CAC1B,wBACE;CACF,0BACE;CACF,wBAAwB;AAC1B;;;;AAKA,SAAS,iBAAiB,OAAe,YAAuC;CAC9E,MAAM,cAAc,gBAClB,OACA,WAAW,KAAK,MAAM,CAAC,CACzB;CACA,IAAI,YAAY,WAAW,GAAG,OAAO;CACrC,IAAI,YAAY,WAAW,GAAG,OAAO,kBAAkB,YAAY,GAAG;CACtE,OAAO,iCAAiC,YAAY,KAAK,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE;AACtF;AAEA,MAAM,UAAU,IAAI,QAAQ;AAE5B,QAAQ,KAAK,aAAa,CAAC,CAAC,YAAY,iBAAiB,CAAC,CAAC,QAAQC,OAAmB;AAStF,QAAQ,KAAK,cAAc,cAAc,kBAAkB;CACzD,IAAI;EACF,2BAA2B,aAAa;CAC1C,QAAQ,CAER;AACF,CAAC;AAGD,MAAM,gBAAgB,QAAQ,QAAQ,MAAM,QAAQ,IAAI,MAAM,SAAS,WAAW,CAAC;AACnF,IAAI,eACF,cAAc,cAAc;AAG9B,QAAQ,gBAAgB;CACtB,gBAAgB,CAEhB;CACA,WAAW,QAAQ;EAWjB,QAAQ,OAAO,MAAM,GAAG;CAC1B;AACF,CAAC;AAGD,MAAM,qBAAqB,QAAiB;CAE1C,OAAO,eAAe;EAAE,SAAS;EAAK,OADxB,iBAAiB,CAAC,CACU;CAAE,CAAC;AAC/C;AAEA,QAAQ,cAAc;CACpB,YAAY;CACZ,6BAA6B;AAC/B,CAAC;AAID,QAAQ,cAAc,QAAQ;CAC5B,IAAI,KAAK;EACP,MAAM,YAAa,IAA0B;EAC7C,MAAM,eAAe,OAAO,IAAI,WAAW,EAAE;EAC7C,MAAM,YAAY,IAAI,QAAQ;EAQ9B,IAJE,cAAc,8BACd,cAAc,+BACb,cAAc,qBACZ,aAAa,SAAS,iBAAiB,KAAK,aAAa,SAAS,kBAAkB,IAC9D;GACzB,MAAM,QAAQ,iBAAiB,CAAC,CAAC;GACjC,MAAM,QAAQ,aAAa,MAAM,kCAAkC;GACnE,MAAM,cAAc,QAAQ,MAAM,KAAK,QAAQ,KAAK,MAAM,QAAQ,KAAK,MAAM;GAE7E,MAAM,WAAW,QAAQ,KAAK;GAC9B,MAAM,gBAAgB,WAClB,QAAQ,SAAS,MAAM,QAAQ,IAAI,KAAK,MAAM,QAAQ,IACtD,KAAA;GAEJ,IAAI,iBAAiB,gBAAgB,UAAU;IAC7C,MAAM,WAAW,cAAc,SAAS,KAAK,MAAM,EAAE,KAAK,CAAC;IAC3D,QAAQ,OAAO,MACb,oBAAoB,cAAc,iBAAiB,aAAc,QAAQ,EAAE,GAC7E;IACA,MAAM,WAAW,kBAAkB;KAAE,SAAS;KAAe;IAAM,CAAC;IACpE,QAAQ,OAAO,MAAM,GAAG,SAAS,GAAG;GACtC,OAAO;IACL,MAAM,WAAW,QAAQ,SAAS,KAAK,MAAM,EAAE,KAAK,CAAC;IACrD,QAAQ,OAAO,MACb,oBAAoB,cAAc,iBAAiB,aAAc,QAAQ,EAAE,GAC7E;IACA,MAAM,WAAW,eAAe;KAAE;KAAS;IAAM,CAAC;IAClD,QAAQ,OAAO,MAAM,GAAG,SAAS,GAAG;GACtC;GACA,QAAQ,KAAK,CAAC;GACd;EACF;EAUA,IANE,cAAc,oBACd,cAAc,6BACd,cAAc,gBACd,iBAAiB,kBACjB,aAAa,SAAS,YAAY,KACjC,cAAc,oBAAoB,aAAa,SAAS,YAAY,GACtD;GACf,QAAQ,KAAK,CAAC;GACd;EACF;EAQA,IAJE,cAAc,+BACd,cAAc,2CACb,cAAc,qBACZ,aAAa,SAAS,SAAS,KAAK,aAAa,SAAS,UAAU,IAC7C;GAC1B,QAAQ,KAAK,CAAC;GACd;EACF;EAGA,QAAQ,OAAO,MAAM,oBAAoB,IAAI,QAAQ,GAAG;EACxD,IAAI,IAAI,OACN,QAAQ,OAAO,MAAM,GAAG,IAAI,MAAM,GAAG;EAEvC,QAAQ,KAAK,CAAC;CAChB;CACA,QAAQ,KAAK,CAAC;AAChB,CAAC;AAGD,MAAM,kBAAkB,IAAI,QAAQ,UAAU;AAC9C,uBACE,iBACA,gCACA,4KAEF;AACA,gBAAgB,cAAc;CAC5B,aAAa,QAAQ;EAEnB,OAAO,kBAAkB;GAAE,SAAS;GAAK,OAD3B,iBAAiB,CAAC,CACa;EAAE,CAAC;CAClD;CACA,6BAA6B;AAC/B,CAAC;AAGD,MAAM,sBAAsB,0BAA0B;AACtD,gBAAgB,WAAW,mBAAmB;AAG9C,MAAM,uBAAuB,2BAA2B;AACxD,gBAAgB,WAAW,oBAAoB;AAG/C,MAAM,YAAY,IAAI,QAAQ,IAAI;AAClC,uBACE,WACA,gCACA,wKAEF;AACA,UAAU,cAAc;CACtB,aAAa,QAAQ;EAEnB,OAAO,kBAAkB;GAAE,SAAS;GAAK,OAD3B,iBAAiB,CAAC,CACa;EAAE,CAAC;CAClD;CACA,6BAA6B;AAC/B,CAAC;AAGD,MAAM,kBAAkB,sBAAsB;AAC9C,UAAU,WAAW,eAAe;AAGpC,MAAM,gBAAgB,oBAAoB;AAC1C,UAAU,WAAW,aAAa;AAGlC,MAAM,kBAAkB,sBAAsB;AAC9C,UAAU,WAAW,eAAe;AAGpC,MAAM,kBAAkB,sBAAsB;AAC9C,UAAU,WAAW,eAAe;AAGpC,MAAM,gBAAgB,oBAAoB;AAC1C,UAAU,WAAW,aAAa;AAGlC,MAAM,mBAAmB,IAAI,QAAQ,WAAW;AAChD,uBACE,kBACA,yCACA,qJAEF;AACA,iBAAiB,cAAc;CAC7B,aAAa,QAAQ;EAEnB,OAAO,kBAAkB;GAAE,SAAS;GAAK,OAD3B,iBAAiB,CAAC,CACa;EAAE,CAAC;CAClD;CACA,6BAA6B;AAC/B,CAAC;AAED,MAAM,uBAAuB,2BAA2B;AACxD,iBAAiB,WAAW,oBAAoB;AAEhD,MAAM,sBAAsB,0BAA0B;AACtD,iBAAiB,WAAW,mBAAmB;AAE/C,MAAM,uBAAuB,2BAA2B;AACxD,iBAAiB,WAAW,oBAAoB;AAEhD,MAAM,yBAAyB,6BAA6B;AAC5D,iBAAiB,WAAW,sBAAsB;AAElD,MAAM,sBAAsB,0BAA0B;AACtD,iBAAiB,WAAW,mBAAmB;AAE/C,MAAM,uBAAuB,2BAA2B;AACxD,iBAAiB,WAAW,oBAAoB;AAEhD,MAAM,wBAAwB,4BAA4B;AAC1D,iBAAiB,WAAW,qBAAqB;AAEjD,MAAM,wBAAwB,4BAA4B;AAC1D,iBAAiB,WAAW,qBAAqB;AAGjD,MAAM,iBAAiB,qBAAqB;AAG5C,MAAM,aAAa,iBAAiB;AAGpC,MAAM,mBAAmB,uBAAuB;AAGhD,MAAM,cAAc,kBAAkB;AAOtC,QAAQ,WAAW,WAAW;AAC9B,QAAQ,WAAW,cAAc;AACjC,QAAQ,WAAW,eAAe;AAClC,QAAQ,WAAW,SAAS;AAC5B,QAAQ,WAAW,gBAAgB;AACnC,QAAQ,WAAW,UAAU;AAC7B,QAAQ,WAAW,gBAAgB;AAgBnC,MAAM,gCAAgC;AACtC,IAAI,QAAQ,IAAI,wCAAwC,KAAK;CAC3D,MAAM,4BAA4B,IAAI,QAAQ,wBAAwB,CAAC,CACpE,YAAY,2DAA2D,CAAC,CACxE,OAAO,YAAY;EAClB,MAAM,IAAI,SAAS,WAAW,WAAW,QAAQ,6BAA6B,CAAC;EAC/E,MAAM,IAAI,MAAM,4DAA4D;CAC9E,CAAC;CACH,0BAA0B,cAAc,EAAE,uBAAuB,CAAC,EAAE,CAAC;CACrE,QAAQ,WAAW,2BAA2B,EAAE,QAAQ,KAAK,CAAC;AAChE;AAGA,MAAM,cAAc,IAAI,QAAQ,MAAM,CAAC,CACpC,YAAY,yBAAyB,CAAC,CACtC,cAAc,EACb,aAAa,QAAQ;CAEnB,OAAO,kBAAkB;EAAE,SAAS;EAAK,OAD3B,iBAAiB,CAAC,CACa;CAAE,CAAC;AAClD,EACF,CAAC,CAAC,CACD,aAAa;CAEZ,MAAM,WAAW,eAAe;EAAE;EAAS,OAD7B,iBAAiB,CAAC,CACe;CAAE,CAAC;CAIlD,QAAQ,OAAO,MAAM,GAAG,SAAS,GAAG;CACpC,QAAQ,KAAK,CAAC;AAChB,CAAC;AAEH,QAAQ,WAAW,WAAW;AAY9B,QAAQ,aAAa;CAEnB,MAAM,WAAW,eAAe;EAAE;EAAS,OAD7B,iBAAiB,CAAC,CACe;CAAE,CAAC;CAClD,QAAQ,OAAO,MAAM,GAAG,SAAS,GAAG;CACpC,QAAQ,KAAK,CAAC;AAChB,CAAC;AAID,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAI,KAAK,SAAS,GAAG;CACnB,MAAM,cAAc,KAAK;CAEzB,IAAI,gBAAgB,eAAe,gBAAgB,MAAM;EAEvD,QAAQ,OAAO,MAAM,GAAG,QAAQ,QAAQ,EAAE,GAAG;EAC7C,QAAQ,KAAK,CAAC;CAChB;CAGA,IAAI,EADmB,gBAAgB,YAAY,gBAAgB,OAC9C;EAEnB,MAAM,UAAU,QAAQ,SAAS,MAAM,QAAQ,IAAI,KAAK,MAAM,WAAW;EAEzE,IAAI,CAAC,SAAS;GAEZ,MAAM,QAAQ,iBAAiB,CAAC,CAAC;GACjC,MAAM,WAAW,QAAQ,SAAS,KAAK,MAAM,EAAE,KAAK,CAAC;GACrD,QAAQ,OAAO,MACb,oBAAoB,cAAc,iBAAiB,aAAc,QAAQ,EAAE,GAC7E;GACA,MAAM,WAAW,eAAe;IAAE;IAAS;GAAM,CAAC;GAClD,QAAQ,OAAO,MAAM,GAAG,SAAS,GAAG;GACpC,QAAQ,KAAK,CAAC;EAChB,OAAO,IAAI,QAAQ,SAAS,SAAS,KAAK,KAAK,UAAU,GAAG;GAC1D,MAAM,iBAAiB,KAAK;GAE5B,MAAM,WAAW,qBAAqB,GADf,YAAY,GAAG;GAEtC,IAAI,UAAU;IACZ,QAAQ,OAAO,MAAM,oBAAoB,eAAe,IAAI,SAAS,GAAG;IACxE,QAAQ,KAAK,CAAC;GAChB;GACA,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;IACpC,MAAM,MAAM,KAAK;IACjB,IAAI,CAAC,IAAI,WAAW,IAAI,GAAG;IAG3B,MAAM,eAAe,qBAAqB,GADvB,YAAY,GAAG,eAAe,GADhC,IAAI,MAAM,CACgC;IAE3D,IAAI,cAAc;KAChB,QAAQ,OAAO,MAAM,mBAAmB,IAAI,IAAI,aAAa,GAAG;KAChE,QAAQ,KAAK,CAAC;IAChB;GACF;EACF;EAEA,IAAI,QAAQ,SAAS,SAAS,KAAK,KAAK,WAAW,GAAG;GAQpD,MAAM,WAAW,kBAAkB;IAAE;IAAS,OADhC,iBAAiB,CAAC,CACkB;GAAE,CAAC;GACrD,QAAQ,OAAO,MAAM,GAAG,SAAS,GAAG;GACpC,QAAQ,KAAK,CAAC;EAChB;CACF;AACF;AAEA,QAAQ,MAAM"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":["CLI_VERSION","packageJson.version"],"sources":["../package.json","../src/commands/init/templates/code-templates.ts","../src/commands/init/index.ts","../src/utils/suggest-command.ts","../src/utils/telemetry.ts","../src/cli.ts"],"sourcesContent":["","import { DEFAULT_CONTRACT_SOURCE_DIR } from '@prisma-next/config/config-types';\n\nexport type TargetId = 'postgres' | 'mongo';\nexport type AuthoringId = 'psl' | 'typescript';\n\nexport function targetPackageName(target: TargetId): string {\n return target === 'postgres' ? '@prisma-next/postgres' : '@prisma-next/mongo';\n}\n\nexport function targetLabel(target: TargetId): string {\n return target === 'postgres' ? 'PostgreSQL' : 'MongoDB';\n}\n\nexport function defaultSchemaPath(authoring: AuthoringId): string {\n if (authoring === 'typescript') {\n return `${DEFAULT_CONTRACT_SOURCE_DIR}/contract.ts`;\n }\n return `${DEFAULT_CONTRACT_SOURCE_DIR}/contract.prisma`;\n}\n\nexport function starterSchema(target: TargetId, authoring: AuthoringId): string {\n if (authoring === 'typescript') {\n return target === 'mongo' ? starterSchemaTsMongo() : starterSchemaTsPostgres();\n }\n return target === 'mongo' ? starterSchemaPslMongo() : starterSchemaPslPostgres();\n}\n\n/**\n * Renders a short authoring-appropriate schema sample (FR5.1) for embedding\n * in `prisma-next.md`. Returns a complete fenced markdown code block.\n *\n * The sample intentionally shows just one model: it's illustrative, not\n * a substitute for the full scaffolded contract file. The TS samples use\n * the same outer shape as `starterSchemaTs*` (FR5.3) so a user reading\n * the doc and the file side-by-side sees the same structure.\n */\nexport function schemaSample(target: TargetId, authoring: AuthoringId): string {\n if (authoring === 'typescript') {\n return target === 'mongo' ? schemaSampleTsMongo() : schemaSampleTsPostgres();\n }\n return target === 'mongo' ? schemaSamplePslMongo() : schemaSamplePslPostgres();\n}\n\nfunction schemaSamplePslPostgres(): string {\n return `\\`\\`\\`prisma\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n username String?\n name String?\n}\n\\`\\`\\``;\n}\n\nfunction schemaSamplePslMongo(): string {\n return `\\`\\`\\`prisma\nmodel User {\n id ObjectId @id @map(\"_id\")\n email String @unique\n username String?\n name String?\n @@map(\"users\")\n}\n\\`\\`\\``;\n}\n\nfunction schemaSampleTsPostgres(): string {\n return `\\`\\`\\`typescript\nimport { defineContract } from '@prisma-next/postgres/contract-builder';\n\nexport const contract = defineContract(\n {},\n ({ field, model }) => ({\n models: {\n User: model('User', {\n fields: {\n id: field.id.uuidv7String(),\n email: field.text().unique(),\n username: field.text().optional(),\n name: field.text().optional(),\n },\n }),\n },\n }),\n);\n\\`\\`\\``;\n}\n\nfunction schemaSampleTsMongo(): string {\n return `\\`\\`\\`typescript\nimport { defineContract } from '@prisma-next/mongo/contract-builder';\n\nexport const contract = defineContract(\n {},\n ({ field, model }) => ({\n models: {\n User: model('User', {\n collection: 'users',\n fields: {\n _id: field.objectId(),\n email: field.string(),\n username: field.string().optional(),\n name: field.string().optional(),\n },\n }),\n },\n }),\n);\n\\`\\`\\``;\n}\n\nfunction starterSchemaPslPostgres(): string {\n return `// use prisma-next\n\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n username String?\n name String?\n posts Post[]\n createdAt DateTime @default(now())\n updatedAt temporal.updatedAt()\n}\n\nmodel Post {\n id Int @id @default(autoincrement())\n title String\n content String?\n author User @relation(fields: [authorId], references: [id])\n authorId Int\n createdAt DateTime @default(now())\n updatedAt temporal.updatedAt()\n}\n`;\n}\n\nfunction starterSchemaPslMongo(): string {\n return `// use prisma-next\n\nmodel User {\n id ObjectId @id @map(\"_id\")\n email String @unique\n username String?\n name String?\n posts Post[]\n @@map(\"users\")\n}\n\nmodel Post {\n id ObjectId @id @map(\"_id\")\n title String\n content String?\n author User @relation(fields: [authorId], references: [id])\n authorId ObjectId\n @@map(\"posts\")\n}\n`;\n}\n\nfunction starterSchemaTsPostgres(): string {\n return `import { defineContract } from '@prisma-next/postgres/contract-builder';\n\nexport const contract = defineContract(\n {},\n ({ field, model, rel }) => ({\n models: {\n User: model('User', {\n fields: {\n id: field.id.uuidv7String(),\n email: field.text().unique(),\n username: field.text().optional(),\n name: field.text().optional(),\n createdAt: field.temporal.createdAt(),\n updatedAt: field.temporal.updatedAt(),\n },\n relations: {\n posts: rel.hasMany('Post', { by: 'authorId' }),\n },\n }),\n\n Post: model('Post', {\n fields: {\n id: field.id.uuidv7String(),\n title: field.text(),\n content: field.text().optional(),\n authorId: field.uuidString(),\n createdAt: field.temporal.createdAt(),\n updatedAt: field.temporal.updatedAt(),\n },\n relations: {\n author: rel.belongsTo('User', { from: 'authorId', to: 'id' }),\n },\n }),\n },\n }),\n);\n`;\n}\n\nfunction starterSchemaTsMongo(): string {\n return `import { defineContract } from '@prisma-next/mongo/contract-builder';\n\nexport const contract = defineContract(\n {},\n ({ field, model, rel }) => ({\n models: {\n User: model('User', {\n collection: 'users',\n fields: {\n _id: field.objectId(),\n email: field.string(),\n username: field.string().optional(),\n name: field.string().optional(),\n },\n relations: {\n posts: rel.hasMany('Post', { from: '_id', to: 'authorId' }),\n },\n }),\n\n Post: model('Post', {\n collection: 'posts',\n fields: {\n _id: field.objectId(),\n title: field.string(),\n content: field.string().optional(),\n authorId: field.objectId(),\n },\n relations: {\n author: rel.belongsTo('User', { from: 'authorId', to: '_id' }),\n },\n }),\n },\n }),\n);\n`;\n}\n\nexport function configFile(target: TargetId, contractPath: string): string {\n const pkg = targetPackageName(target);\n return `import 'dotenv/config';\nimport { defineConfig } from '${pkg}/config';\n\nexport default defineConfig({\n contract: ${JSON.stringify(contractPath)},\n db: {\n connection: process.env['DATABASE_URL']!,\n },\n});\n`;\n}\n\nexport function dbFile(target: TargetId): string {\n if (target === 'postgres') {\n return `import postgres from '@prisma-next/postgres/runtime';\nimport type { Contract } from './contract.d';\nimport contractJson from './contract.json' with { type: 'json' };\n\nexport const db = postgres<Contract>({\n contractJson,\n url: process.env['DATABASE_URL']!,\n});\n`;\n }\n\n return `import mongo from '@prisma-next/mongo/runtime';\nimport type { Contract } from './contract.d';\nimport contractJson from './contract.json' with { type: 'json' };\n\nexport const db = mongo<Contract>({\n contractJson,\n url: process.env['DATABASE_URL']!,\n});\n`;\n}\n","import { Command } from 'commander';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../../utils/command-helpers';\nimport {\n type CommonCommandOptions,\n deriveCanPrompt,\n parseGlobalFlagsOrExit,\n} from '../../utils/global-flags';\nimport {\n INIT_EXIT_EMIT_FAILED,\n INIT_EXIT_INSTALL_FAILED,\n INIT_EXIT_INTERNAL_ERROR,\n INIT_EXIT_OK,\n INIT_EXIT_PRECONDITION,\n INIT_EXIT_SKILL_INSTALL_FAILED,\n INIT_EXIT_USER_ABORTED,\n} from './exit-codes';\nimport { defaultSchemaPath } from './templates/code-templates';\n\n/**\n * Commander.js parsed options for `init`. The init-specific options live\n * alongside the inherited `CommonCommandOptions` global flags.\n *\n * `target` and `authoring` are typed as plain `string` here because\n * Commander.js does not enforce enums at parse time — the validation /\n * normalisation happens in `inputs.ts::resolveInitInputs`, which can\n * raise a structured `errorInitInvalidFlagValue` with the full set of\n * allowed values.\n */\ninterface InitCommandOptions extends CommonCommandOptions {\n readonly target?: string;\n readonly authoring?: string;\n readonly schemaPath?: string;\n readonly force?: boolean;\n readonly writeEnv?: boolean;\n readonly probeDb?: boolean;\n readonly strictProbe?: boolean;\n readonly install?: boolean;\n readonly skill?: boolean;\n}\n\nexport function createInitCommand(): Command {\n const command = new Command('init');\n setCommandDescriptions(\n command,\n 'Initialize a new Prisma Next project',\n 'Scaffolds config, schema, and runtime files, installs dependencies,\\n' +\n 'and emits the contract. Gets you from zero to typed queries in one step.\\n' +\n '\\n' +\n 'Run interactively for a guided experience, or supply --target / --authoring\\n' +\n 'and --yes for a fully scriptable run (CI, AI coding agents, automation).\\n' +\n '\\n' +\n 'Exit codes (see CLI Style Guide § Exit Codes):\\n' +\n ` ${INIT_EXIT_OK} OK Init succeeded.\\n` +\n ` ${INIT_EXIT_INTERNAL_ERROR} INTERNAL_ERROR Unexpected bug in prisma-next (please report).\\n` +\n ` ${INIT_EXIT_PRECONDITION} PRECONDITION Bad flags / missing prerequisite (e.g. no package.json).\\n` +\n ` ${INIT_EXIT_USER_ABORTED} USER_ABORTED User cancelled an interactive prompt.\\n` +\n ` ${INIT_EXIT_INSTALL_FAILED} INSTALL_FAILED Dependency installation failed (init-specific).\\n` +\n ` ${INIT_EXIT_EMIT_FAILED} EMIT_FAILED \\`contract emit\\` failed after install (init-specific).\\n` +\n ` ${INIT_EXIT_SKILL_INSTALL_FAILED} SKILL_INSTALL_FAILED Agent-skill install failed (re-run with --no-skill to skip).`,\n );\n setCommandExamples(command, [\n 'prisma-next init',\n 'prisma-next init --yes --target postgres --authoring psl',\n 'prisma-next init --yes --target mongodb --authoring typescript --json',\n 'prisma-next init --yes --force --target postgres --authoring psl # overwrite an existing scaffold',\n 'prisma-next init --no-install # skip pnpm/npm install + emit',\n 'prisma-next init --no-skill # skip the skills install (air-gapped / restricted env)',\n ]);\n\n return addGlobalOptions(command)\n .option('--target <db>', 'Database target: postgres or mongodb')\n .option('--authoring <style>', 'Schema authoring style: psl or typescript')\n .option(\n '--schema-path <path>',\n `Where to write the starter schema (default: ${defaultSchemaPath('psl')})`,\n )\n .option('--force', 'Overwrite an existing scaffold without prompting')\n .option(\n '--write-env',\n 'Write a .env file from .env.example (gitignored; default: only .env.example)',\n )\n .option(\n '--probe-db',\n 'Connect to DATABASE_URL once and check the server version against the target minimum (opt-in; off by default)',\n )\n .option(\n '--strict-probe',\n 'Treat a failed --probe-db as fatal (no-op without --probe-db; init is offline-by-default)',\n )\n .option('--no-install', 'Skip dependency installation and contract emission')\n .option(\n '--no-skill',\n 'Skip Prisma Next skills install (air-gapped CI, restricted registries, etc.)',\n )\n .action(async (options: InitCommandOptions) => {\n const { runInit } = await import('./init');\n const flags = parseGlobalFlagsOrExit(options);\n const canPrompt = deriveCanPrompt({\n flagsInteractive: flags.interactive,\n optionInteractive: options.interactive,\n stdinIsTTY: Boolean(process.stdin.isTTY),\n });\n const exitCode = await runInit(process.cwd(), {\n options,\n flags,\n canPrompt,\n });\n process.exit(exitCode);\n });\n}\n","import { distance } from 'closest-match';\n\n/**\n * Suggests similar command names for a mistyped input.\n *\n * Uses Levenshtein distance to find close matches. Only suggests commands\n * within a reasonable distance threshold (40% of the input length, minimum 2).\n * Returns up to 3 suggestions in case of ties.\n *\n * @returns Array of suggested command names (empty if nothing is close enough).\n */\nexport function suggestCommands(input: string, candidates: readonly string[]): string[] {\n if (candidates.length === 0) return [];\n\n // Threshold: at most 40% of the input length (min 2) to avoid absurd suggestions\n const maxDistance = Math.max(2, Math.ceil(input.length * 0.4));\n\n const scored = candidates\n .map((name) => ({ name, dist: distance(input, name) }))\n .filter((entry) => entry.dist <= maxDistance)\n .sort((a, b) => a.dist - b.dist);\n\n if (scored.length === 0) return [];\n\n // Take the best distance, then include ties (up to 3)\n const bestDist = scored[0]!.dist;\n return scored\n .filter((entry) => entry.dist === bestDist)\n .slice(0, 3)\n .map((entry) => entry.name);\n}\n","import { fileURLToPath } from 'node:url';\nimport {\n type CommanderOptionShape,\n type CommanderResultShape,\n ensureInstallationId,\n readUserConfig,\n resolveGating,\n runTelemetry,\n type TelemetryRunOutcome,\n type UserConfig,\n userConfigPath,\n} from '@prisma-next/cli-telemetry';\nimport type { Command } from 'commander';\nimport { version as CLI_VERSION } from '../../package.json' with { type: 'json' };\nimport { isCI } from './is-ci';\n\ntype TelemetryGate =\n | { readonly enabled: true; readonly userConfig: UserConfig }\n | { readonly enabled: false; readonly outcome: TelemetryRunOutcome };\n\n/**\n * Resolve the commander command path from a leaf `Command`, walking up\n * the parent chain. Result is rooted at the program name and ends at\n * the leaf — `['prisma-next', 'migration', 'new']` for\n * `prisma-next migration new …`.\n */\nfunction commandPathFor(actionCommand: Command): string[] {\n const path: string[] = [];\n let cursor: Command | null = actionCommand;\n while (cursor !== null) {\n path.unshift(cursor.name());\n cursor = cursor.parent;\n }\n return path;\n}\n\nfunction commanderOptionSnapshots(actionCommand: Command): CommanderOptionShape[] {\n return actionCommand.options.map((option) => {\n const attributeName = option.attributeName();\n return {\n attributeName,\n longName: option.long ?? null,\n source: actionCommand.getOptionValueSource(attributeName) ?? null,\n };\n });\n}\n\n/**\n * Project commander's leaf `Command` into the wire-shape snapshot the\n * telemetry sanitiser consumes. Pure projection — no env, no I/O.\n */\nexport function commanderSnapshotForTelemetry(actionCommand: Command): CommanderResultShape {\n return {\n commandPath: commandPathFor(actionCommand),\n positionalArgs: actionCommand.args,\n options: commanderOptionSnapshots(actionCommand),\n };\n}\n\nfunction resolveTelemetryGate(): TelemetryGate {\n if (isCI()) {\n return { enabled: false, outcome: { spawned: false, reason: 'ci' } };\n }\n const userConfig = readUserConfig();\n const gating = resolveGating({ env: process.env, config: userConfig });\n if (!gating.enabled) {\n return { enabled: false, outcome: { spawned: false, reason: 'gated-off' } };\n }\n return { enabled: true, userConfig };\n}\n\n/**\n * Path to the compiled sender script inside `@prisma-next/cli-telemetry`'s\n * `dist/`. Resolved off this module's `import.meta.url` via the package\n * specifier `@prisma-next/cli-telemetry/sender`, so the consumer pays\n * no attention to internal package layout.\n */\nfunction senderPath(): string {\n return fileURLToPath(new URL(import.meta.resolve('@prisma-next/cli-telemetry/sender')));\n}\n\nfunction fireTelemetry(actionCommand: Command, userConfig: UserConfig): TelemetryRunOutcome {\n return runTelemetry({\n command: commanderSnapshotForTelemetry(actionCommand),\n version: CLI_VERSION,\n projectRoot: process.cwd(),\n senderPath: senderPath(),\n isCI: isCI(),\n env: process.env,\n userConfig,\n });\n}\n\n/**\n * preAction-stage entry point. Synchronous by construction: resolve\n * env/CI/user-consent gates (cheap, all in-memory and a single tiny\n * user-config read), then — only when enabled — `fork()` the detached\n * sender script. The forked child loads `prisma-next.config.*` via\n * c12 on its own (see `loadProjectConfig` in cli-telemetry); the\n * parent does no project-config I/O on the command's hot path.\n *\n * Privacy invariant: gate resolution always happens before any project\n * config touches disk. The child loading user TS code is acceptable\n * only because it's gated behind the same resolved-enabled signal.\n */\n/**\n * Builds the one-time first-run disclosure. The resolved absolute path to\n * the user-level config file is substituted in so the user can see exactly\n * which file to edit (it must not be confused with `prisma-next.config.ts`).\n * `prisma-next telemetry disable` is named as the primary, friendliest\n * opt-out, alongside the env vars and the config edit.\n */\nfunction firstRunNotice(configPath: string): string {\n return [\n 'Prisma Next collects anonymous CLI usage data, enabled by default.',\n \"What's collected and why: https://prisma-next.dev/docs/cli/telemetry.\",\n 'Opt out: run \"prisma-next telemetry disable\", set DO_NOT_TRACK=1 or',\n `PRISMA_NEXT_DISABLE_TELEMETRY=1, or set \"enableTelemetry\": false in ${configPath}.`,\n ].join(' ');\n}\n\n/**\n * Best-effort first-run disclosure + installationId mint. Runs only on the\n * gating-enabled path. Prints the notice to stderr (never stdout) and mints\n * a persistent id without touching `enableTelemetry`, so the opt-out default\n * stays intact and no unasked-for consent is recorded.\n *\n * Every step is wrapped so an un-writable config dir (or any other failure)\n * never throws and never blocks the command. Returns the minted (or\n * pre-existing) id so the caller can forward it to `runTelemetry` without a\n * redundant disk read. On mint failure it returns `undefined`: the notice may\n * reprint next run, and `runTelemetry` no-ops on the missing id.\n */\nfunction discloseAndMintOnFirstRun(): string | undefined {\n try {\n process.stderr.write(`${firstRunNotice(userConfigPath())}\\n`);\n } catch {}\n try {\n return ensureInstallationId();\n } catch {}\n return undefined;\n}\n\n/**\n * True when the run is the `telemetry` command (or one of its\n * subcommands). The usage-telemetry preAction fire is exempted for it:\n * it would be absurd for `telemetry disable` to send a usage event before\n * disabling, or for `telemetry status` to mint an id + send while merely\n * reporting state. This is the only command-specific exemption.\n *\n * The check is rooted at the program: the path must be\n * `['prisma-next', 'telemetry', …]`, so it matches the top-level\n * `telemetry` command and its subcommands without matching a hypothetical\n * nested `… telemetry` elsewhere.\n */\nfunction isTelemetryCommand(actionCommand: Command): boolean {\n return commandPathFor(actionCommand)[1] === 'telemetry';\n}\n\nexport function fireTelemetryFromPreAction(actionCommand: Command): TelemetryRunOutcome {\n if (isTelemetryCommand(actionCommand)) {\n return { spawned: false, reason: 'gated-off' };\n }\n const gate = resolveTelemetryGate();\n if (!gate.enabled) {\n return gate.outcome;\n }\n const storedId = gate.userConfig.installationId;\n if (typeof storedId !== 'string' || storedId.length === 0) {\n const installationId = discloseAndMintOnFirstRun();\n return fireTelemetry(\n actionCommand,\n installationId === undefined ? gate.userConfig : { ...gate.userConfig, installationId },\n );\n }\n return fireTelemetry(actionCommand, gate.userConfig);\n}\n","import { Command } from 'commander';\nimport packageJson from '../package.json' with { type: 'json' };\nimport { createContractEmitCommand } from './commands/contract-emit';\nimport { createContractInferCommand } from './commands/contract-infer';\nimport { createInitCommand } from './commands/init';\nimport { installShutdownHandlers } from './utils/shutdown';\n\n// Install SIGINT/SIGTERM handlers before anything else\ninstallShutdownHandlers();\n\nimport { createDbInitCommand } from './commands/db-init';\nimport { createDbSchemaCommand } from './commands/db-schema';\nimport { createDbSignCommand } from './commands/db-sign';\nimport { createDbUpdateCommand } from './commands/db-update';\nimport { createDbVerifyCommand } from './commands/db-verify';\nimport { createMigrateCommand } from './commands/migrate';\nimport { createMigrationCheckCommand } from './commands/migration-check';\nimport { createMigrationGraphCommand } from './commands/migration-graph';\nimport { createMigrationListCommand } from './commands/migration-list';\nimport { createMigrationLogCommand } from './commands/migration-log';\nimport { createMigrationNewCommand } from './commands/migration-new';\nimport { createMigrationPlanCommand } from './commands/migration-plan';\nimport { createMigrationShowCommand } from './commands/migration-show';\nimport { createMigrationStatusCommand } from './commands/migration-status';\nimport { createRefCommand } from './commands/ref';\nimport { createTelemetryCommand } from './commands/telemetry';\nimport { setCommandDescriptions } from './utils/command-helpers';\nimport { formatCommandHelp, formatRootHelp } from './utils/formatters/help';\nimport { parseGlobalFlags } from './utils/global-flags';\nimport { suggestCommands } from './utils/suggest-command';\nimport { fireTelemetryFromPreAction } from './utils/telemetry';\n\n/**\n * Lookup table mapping removed subcommands to their replacement verbs.\n * Keyed by `<parent>:<subcommand>` (e.g. `migration:apply`).\n * The handler consults this before falling back to the fuzzy suggest engine.\n */\nconst removedVerbRedirects: Record<string, string> = {\n 'migration:apply': 'Use `prisma-next migrate --to <contract>` instead.',\n 'migration:ref': 'Use `prisma-next ref set|list|delete` instead.',\n};\n\n/**\n * Removed flags on specific subcommands. Keyed by `<parent>:<sub>:<flag>`.\n * Checked during the pre-parse argv scan before commander sees the flags.\n */\nconst removedFlagRedirects: Record<string, string> = {\n 'migration:status:graph': 'Use `prisma-next migration graph` to view the migration graph.',\n 'migration:status:all':\n 'Use `prisma-next migration log --db <url>` to view the full execution history.',\n 'migration:status:limit':\n 'Use `prisma-next migration log --db <url>` to view the full execution history.',\n 'migration:status:ref': 'Use `--to <contract>` instead of `--ref`.',\n};\n\n/**\n * Formats the \"Did you mean ...?\" hint for an unknown command.\n */\nfunction formatSuggestion(input: string, candidates: readonly string[]): string {\n const suggestions = suggestCommands(\n input,\n candidates.map((c) => c),\n );\n if (suggestions.length === 0) return '';\n if (suggestions.length === 1) return `\\nDid you mean ${suggestions[0]}?\\n`;\n return `\\nDid you mean one of these?\\n${suggestions.map((s) => ` ${s}`).join('\\n')}\\n`;\n}\n\nconst program = new Command();\n\nprogram.name('prisma-next').description('Prisma Next CLI').version(packageJson.version);\n\n// Telemetry hook — fires at command start, before the action body\n// runs. Synchronous by construction: `fireTelemetryFromPreAction`\n// resolves gates (cheap), then `fork()`s the detached sender. The\n// fork is enqueued before the action body runs at all, so the child\n// survives even when the action throws synchronously. The try/catch\n// is defence-in-depth — `runTelemetry` already swallows every failure\n// mode internally and returns an outcome instead of throwing.\nprogram.hook('preAction', (_thisCommand, actionCommand) => {\n try {\n fireTelemetryFromPreAction(actionCommand);\n } catch {\n // defence-in-depth — runTelemetry already swallows internally.\n }\n});\n\n// Override version option description to match capitalization style\nconst versionOption = program.options.find((opt) => opt.flags.includes('--version'));\nif (versionOption) {\n versionOption.description = 'Output the version number';\n}\n\nprogram.configureOutput({\n writeErr: () => {\n // Suppress all default error output - we handle errors in exitOverride\n },\n writeOut: (str) => {\n // Commander routes explicitly-requested `--help` (success-path help)\n // through writeOut; per the Style Guide § Output Conventions rule 8,\n // user-requested help is data and goes to stdout. Error-path help\n // (e.g. usage shown after an unknown command) goes through writeErr,\n // which stays suppressed because we render that ourselves with the\n // matching error envelope.\n //\n // Explicit `--version` is short-circuited before `program.parse()`\n // (see the argv pre-scan at the bottom of this file), so it does not\n // reach this writer.\n process.stdout.write(str);\n },\n});\n\n// Customize root help output to use our styled format\nconst rootHelpFormatter = (cmd: Command) => {\n const flags = parseGlobalFlags({});\n return formatRootHelp({ program: cmd, flags });\n};\n\nprogram.configureHelp({\n formatHelp: rootHelpFormatter,\n subcommandDescription: () => '',\n});\n\n// Override exit to handle unhandled errors (fail fast cases)\n// Commands handle structured errors themselves via process.exit()\nprogram.exitOverride((err) => {\n if (err) {\n const errorCode = (err as { code?: string }).code;\n const errorMessage = String(err.message ?? '');\n const errorName = err.name ?? '';\n\n // Unknown command/argument → exit 2 (CLI usage error)\n const isUnknownCommandError =\n errorCode === 'commander.unknownCommand' ||\n errorCode === 'commander.unknownArgument' ||\n (errorName === 'CommanderError' &&\n (errorMessage.includes('unknown command') || errorMessage.includes('unknown argument')));\n if (isUnknownCommandError) {\n const flags = parseGlobalFlags({});\n const match = errorMessage.match(/unknown command ['\"]([^'\"]+)['\"]/);\n const commandName = match ? match[1] : process.argv[3] || process.argv[2] || 'unknown';\n\n const firstArg = process.argv[2];\n const parentCommand = firstArg\n ? program.commands.find((cmd) => cmd.name() === firstArg)\n : undefined;\n\n if (parentCommand && commandName !== firstArg) {\n const subNames = parentCommand.commands.map((c) => c.name());\n process.stderr.write(\n `Unknown command: ${commandName}${formatSuggestion(commandName!, subNames)}\\n`,\n );\n const helpText = formatCommandHelp({ command: parentCommand, flags });\n process.stderr.write(`${helpText}\\n`);\n } else {\n const topNames = program.commands.map((c) => c.name());\n process.stderr.write(\n `Unknown command: ${commandName}${formatSuggestion(commandName!, topNames)}\\n`,\n );\n const helpText = formatRootHelp({ program, flags });\n process.stderr.write(`${helpText}\\n`);\n }\n process.exit(2);\n return;\n }\n\n // Help requests → exit 0\n const isHelpError =\n errorCode === 'commander.help' ||\n errorCode === 'commander.helpDisplayed' ||\n errorCode === 'outputHelp' ||\n errorMessage === '(outputHelp)' ||\n errorMessage.includes('outputHelp') ||\n (errorName === 'CommanderError' && errorMessage.includes('outputHelp'));\n if (isHelpError) {\n process.exit(0);\n return;\n }\n\n // Missing required arguments → exit 2 (CLI usage error)\n const isMissingArgumentError =\n errorCode === 'commander.missingArgument' ||\n errorCode === 'commander.missingMandatoryOptionValue' ||\n (errorName === 'CommanderError' &&\n (errorMessage.includes('missing') || errorMessage.includes('required')));\n if (isMissingArgumentError) {\n process.exit(2);\n return;\n }\n\n // Unhandled error → exit 1\n process.stderr.write(`Unhandled error: ${err.message}\\n`);\n if (err.stack) {\n process.stderr.write(`${err.stack}\\n`);\n }\n process.exit(1);\n }\n process.exit(0);\n});\n\n// Register contract subcommand\nconst contractCommand = new Command('contract');\nsetCommandDescriptions(\n contractCommand,\n 'Contract management commands',\n 'Define and emit your application data contract. The contract describes your schema as a\\n' +\n 'declarative data structure that can be signed and verified against your database.',\n);\ncontractCommand.configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n subcommandDescription: () => '',\n});\n\n// Add emit subcommand to contract\nconst contractEmitCommand = createContractEmitCommand();\ncontractCommand.addCommand(contractEmitCommand);\n\n// Add infer subcommand to contract\nconst contractInferCommand = createContractInferCommand();\ncontractCommand.addCommand(contractInferCommand);\n\n// Register db subcommand\nconst dbCommand = new Command('db');\nsetCommandDescriptions(\n dbCommand,\n 'Database management commands',\n 'Verify and sign your database with your contract. Ensure your database schema matches\\n' +\n 'your contract, and sign it to record the contract hash for future verification.',\n);\ndbCommand.configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n subcommandDescription: () => '',\n});\n\n// Add verify subcommand to db\nconst dbVerifyCommand = createDbVerifyCommand();\ndbCommand.addCommand(dbVerifyCommand);\n\n// Add init subcommand to db\nconst dbInitCommand = createDbInitCommand();\ndbCommand.addCommand(dbInitCommand);\n\n// Add update subcommand to db\nconst dbUpdateCommand = createDbUpdateCommand();\ndbCommand.addCommand(dbUpdateCommand);\n\n// Add schema subcommand to db\nconst dbSchemaCommand = createDbSchemaCommand();\ndbCommand.addCommand(dbSchemaCommand);\n\n// Add sign subcommand to db\nconst dbSignCommand = createDbSignCommand();\ndbCommand.addCommand(dbSignCommand);\n\n// Register migration subcommand\nconst migrationCommand = new Command('migration');\nsetCommandDescriptions(\n migrationCommand,\n 'On-disk migration management commands',\n 'Plan, apply, and scaffold on-disk migration packages. Migrations are\\n' +\n 'contract-to-contract edges stored as versioned directories under migrations/.',\n);\nmigrationCommand.configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n subcommandDescription: () => '',\n});\n\nconst migrationPlanCommand = createMigrationPlanCommand();\nmigrationCommand.addCommand(migrationPlanCommand);\n\nconst migrationNewCommand = createMigrationNewCommand();\nmigrationCommand.addCommand(migrationNewCommand);\n\nconst migrationShowCommand = createMigrationShowCommand();\nmigrationCommand.addCommand(migrationShowCommand);\n\nconst migrationStatusCommand = createMigrationStatusCommand();\nmigrationCommand.addCommand(migrationStatusCommand);\n\nconst migrationLogCommand = createMigrationLogCommand();\nmigrationCommand.addCommand(migrationLogCommand);\n\nconst migrationListCommand = createMigrationListCommand();\nmigrationCommand.addCommand(migrationListCommand);\n\nconst migrationGraphCommand = createMigrationGraphCommand();\nmigrationCommand.addCommand(migrationGraphCommand);\n\nconst migrationCheckCommand = createMigrationCheckCommand();\nmigrationCommand.addCommand(migrationCheckCommand);\n\n// Top-level migrate command\nconst migrateCommand = createMigrateCommand();\n\n// Top-level ref command (replaces `migration ref`)\nconst refCommand = createRefCommand();\n\n// Top-level telemetry command\nconst telemetryCommand = createTelemetryCommand();\n\n// Top-level init command\nconst initCommand = createInitCommand();\n\n// Register top-level commands in the order the spec's intended-surface\n// diagram lists them: verbs (init, migrate) first, then subject\n// namespaces (contract, db, migration, ref). The order shows up in\n// `prisma-next --help` and is the first thing a new user sees, so it\n// matches the order spec.md uses to introduce the surface.\nprogram.addCommand(initCommand);\nprogram.addCommand(migrateCommand);\nprogram.addCommand(contractCommand);\nprogram.addCommand(dbCommand);\nprogram.addCommand(migrationCommand);\nprogram.addCommand(refCommand);\nprogram.addCommand(telemetryCommand);\n\n// Test-only hidden command used by `cli-telemetry`'s `cli-e2e.test.ts`\n// to verify that telemetry still lands when a CLI command crashes\n// mid-execution. The preAction hook is synchronous and `fork()`s the\n// detached sender before this action body runs; the small sleep\n// gives the IPC `child.send()` a tick to flush before the throw\n// triggers commander's `exitOverride` and `process.exit(1)`. Hidden\n// from help; underscore prefix marks it as internal. Doesn't depend\n// on any project state, so it runs in any tempdir.\n//\n// Gated behind `PRISMA_NEXT_ENABLE_TEST_COMMANDS=1` so the command is\n// not even registered (and therefore not invocable) in shipped\n// binaries. `hidden: true` only filters the help output; without this\n// env gate the command would still be callable from production. The\n// e2e suite sets the env var when it spawns the CLI.\nconst TELEMETRY_CRASH_TEST_SLEEP_MS = 200;\nif (process.env['PRISMA_NEXT_ENABLE_TEST_COMMANDS'] === '1') {\n const telemetryCrashTestCommand = new Command('__telemetry-crash-test')\n .description('Internal: deliberately throw for the telemetry e2e suite.')\n .action(async () => {\n await new Promise((settle) => setTimeout(settle, TELEMETRY_CRASH_TEST_SLEEP_MS));\n throw new Error('__telemetry-crash-test: intentional crash for e2e coverage');\n });\n telemetryCrashTestCommand.configureHelp({ visibleCommands: () => [] });\n program.addCommand(telemetryCrashTestCommand, { hidden: true });\n}\n\n// Create help command\nconst helpCommand = new Command('help')\n .description('Show usage instructions')\n .configureHelp({\n formatHelp: (cmd) => {\n const flags = parseGlobalFlags({});\n return formatCommandHelp({ command: cmd, flags });\n },\n })\n .action(() => {\n const flags = parseGlobalFlags({});\n const helpText = formatRootHelp({ program, flags });\n // The `help` command was invoked explicitly: help is the data the\n // caller asked for. Per Style Guide § Output Conventions rule 8,\n // explicit help goes to stdout with exit code 0.\n process.stdout.write(`${helpText}\\n`);\n process.exit(0);\n });\n\nprogram.addCommand(helpCommand);\n\n// Set help as the default action when no command is provided. The user\n// did not invoke `--help`; we are voluntarily showing usage to help them\n// recover from an underspecified invocation, so the help text is\n// decoration around an implicit \"what did you want me to do?\" and goes\n// to stderr (Style Guide § Output Conventions rule 8).\n//\n// FOLLOW-UP: the exit code here is 0 today, but a no-arg invocation is\n// arguably a usage error (PRECONDITION → exit 2) for consistency with\n// the unknown-command path. Out of scope for the explicit-help routing\n// work; revisit when tightening exit-code semantics across the CLI.\nprogram.action(() => {\n const flags = parseGlobalFlags({});\n const helpText = formatRootHelp({ program, flags });\n process.stderr.write(`${helpText}\\n`);\n process.exit(0);\n});\n\n// Check if a command was invoked with no arguments (just the command name)\n// or if an unrecognized command was provided\nconst args = process.argv.slice(2);\nif (args.length > 0) {\n const commandName = args[0];\n // Handle version option explicitly since we suppress default output\n if (commandName === '--version' || commandName === '-V') {\n // Version is data → stdout\n process.stdout.write(`${program.version()}\\n`);\n process.exit(0);\n }\n // Skip command check for global options like --help, -h\n const isGlobalOption = commandName === '--help' || commandName === '-h';\n if (!isGlobalOption) {\n // Check if this is a recognized command\n const command = program.commands.find((cmd) => cmd.name() === commandName);\n\n if (!command) {\n // Unrecognized command → exit 2 (CLI usage error)\n const flags = parseGlobalFlags({});\n const topNames = program.commands.map((c) => c.name());\n process.stderr.write(\n `Unknown command: ${commandName}${formatSuggestion(commandName!, topNames)}\\n`,\n );\n const helpText = formatRootHelp({ program, flags });\n process.stderr.write(`${helpText}\\n`);\n process.exit(2);\n } else if (command.commands.length > 0 && args.length >= 2) {\n const subcommandName = args[1];\n const redirectKey = `${commandName}:${subcommandName}`;\n const redirect = removedVerbRedirects[redirectKey];\n if (redirect) {\n process.stderr.write(`Unknown command: ${subcommandName}\\n${redirect}\\n`);\n process.exit(2);\n }\n for (let i = 2; i < args.length; i++) {\n const arg = args[i]!;\n if (!arg.startsWith('--')) continue;\n const flagName = arg.slice(2);\n const flagKey = `${commandName}:${subcommandName}:${flagName}`;\n const flagRedirect = removedFlagRedirects[flagKey];\n if (flagRedirect) {\n process.stderr.write(`Unknown option: ${arg}\\n${flagRedirect}\\n`);\n process.exit(2);\n }\n }\n }\n\n if (command.commands.length > 0 && args.length === 1) {\n // Parent command called with no subcommand. Same shape as the\n // no-args case above: the user did not request help, we are\n // voluntarily rendering it as decoration around an underspecified\n // invocation, so it goes to stderr per Style Guide § Output\n // Conventions rule 8. Exit code 0 today; the FOLLOW-UP note on\n // `program.action` applies here too (arguably should be 2).\n const flags = parseGlobalFlags({});\n const helpText = formatCommandHelp({ command, flags });\n process.stderr.write(`${helpText}\\n`);\n process.exit(0);\n }\n }\n}\n\nprogram.parse();\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as formatMigrationPlanOutput, r as resolveBundleByPrefix, t as createMigrationPlanCommand } from "../migration-plan-
|
|
1
|
+
import { n as formatMigrationPlanOutput, r as resolveBundleByPrefix, t as createMigrationPlanCommand } from "../migration-plan-W_E8FQOk.mjs";
|
|
2
2
|
export { createMigrationPlanCommand, formatMigrationPlanOutput, resolveBundleByPrefix };
|
package/dist/migration-cli.mjs
CHANGED
|
@@ -369,9 +369,9 @@ function readExistingMetadata(metadataPath) {
|
|
|
369
369
|
* legitimate site for combining config loading, stack assembly, and
|
|
370
370
|
* filesystem persistence.
|
|
371
371
|
*/
|
|
372
|
-
function serializeMigrationToDisk(instance, migrationDir, dryRun, stdout) {
|
|
372
|
+
async function serializeMigrationToDisk(instance, migrationDir, dryRun, stdout) {
|
|
373
373
|
const metadataPath = join(migrationDir, "migration.json");
|
|
374
|
-
const { opsJson, metadataJson } = buildMigrationArtifacts(instance, readExistingMetadata(metadataPath));
|
|
374
|
+
const { opsJson, metadataJson } = await buildMigrationArtifacts(instance, readExistingMetadata(metadataPath));
|
|
375
375
|
if (dryRun) {
|
|
376
376
|
stdout.write(`--- migration.json ---\n${metadataJson}\n`);
|
|
377
377
|
stdout.write("--- ops.json ---\n");
|
|
@@ -398,7 +398,7 @@ async function runMigration(importMetaUrl, MigrationClass, parsed, ctx) {
|
|
|
398
398
|
migrationTargetId: probe.targetId,
|
|
399
399
|
configTargetId: config.target.targetId
|
|
400
400
|
});
|
|
401
|
-
serializeMigrationToDisk(new MigrationClass(createControlStack(config)), migrationDir, parsed.dryRun, ctx.stdout);
|
|
401
|
+
await serializeMigrationToDisk(new MigrationClass(createControlStack(config)), migrationDir, parsed.dryRun, ctx.stdout);
|
|
402
402
|
ctx.stderr;
|
|
403
403
|
}
|
|
404
404
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-cli.mjs","names":[],"sources":["../src/migration-cli.ts"],"sourcesContent":["/**\n * The migration-file CLI interface: the actor invoked when the author runs\n * `node migration.ts` directly.\n *\n * Naming: this is *not* a \"migration runner\" in the apply-time sense. The\n * apply-time runner is the thing `prisma-next migrate` uses to\n * execute migration JSON ops against a database. `MigrationCLI` is the\n * tiny CLI surface owned by an authored `migration.ts` file: parse the\n * file's argv, load the project's `prisma-next.config.ts`, assemble a\n * `ControlStack`, instantiate the migration class, and serialize.\n *\n * The user authors a migration class, then calls\n * `MigrationCLI.run(import.meta.url, MigrationClass)` at module scope\n * after the class definition. When the file is invoked as a node\n * entrypoint (`node migration.ts`), the CLI:\n *\n * 1. Detects whether the file is the direct entrypoint (no-op when imported).\n * 2. Parses CLI args (`--help`, `--dry-run`, `--config <path>`) via\n * [clipanion](https://github.com/arcanis/clipanion).\n * 3. Loads the project's `prisma-next.config.ts` via the same `loadConfig`\n * the CLI commands use, walking up from the migration file's directory.\n * 4. Probe-instantiates the migration class without a stack so it can read\n * `targetId` and verify it matches `config.target.targetId`\n * (`PN-MIG-2006` on mismatch) before any stack-driven adapter\n * construction runs.\n * 5. Assembles a `ControlStack` from the loaded config descriptors and\n * constructs the migration with that stack.\n * 6. Reads any previously-scaffolded `migration.json`, then calls\n * `buildMigrationArtifacts` from `@prisma-next/migration-tools` to\n * produce in-memory `ops.json` + `migration.json` content. Persists\n * the result to disk (or prints in dry-run mode).\n *\n * File I/O lives here, in `@prisma-next/cli`: this is the only place\n * that legitimately combines config loading, stack assembly, and\n * on-disk persistence. `@prisma-next/migration-tools` owns the pure\n * conversion from a `Migration` instance to artifact strings; `Migration`\n * stays a pure abstract class.\n *\n * Parser library: clipanion (chosen over Commander/citty/`node:util.parseArgs`\n * for its in-process testability and runtime-agnostic execution surface; see\n * `docs/architecture docs/research/commander-friction-points.md` for the\n * evaluation rubric and the durable rationale that drove the choice).\n */\n\nimport { readFileSync, realpathSync, writeFileSync } from 'node:fs';\nimport type { Writable } from 'node:stream';\nimport { fileURLToPath } from 'node:url';\nimport {\n CliStructuredError,\n errorMigrationCliInvalidConfigArg,\n errorMigrationCliUnknownFlag,\n} from '@prisma-next/errors/control';\nimport { errorMigrationTargetMismatch } from '@prisma-next/errors/migration';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { errorInvalidJson, MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport { buildMigrationArtifacts, type Migration } from '@prisma-next/migration-tools/migration';\nimport { Cli, Command, Option, UsageError } from 'clipanion';\nimport { dirname, join } from 'pathe';\nimport { loadConfig } from './config-loader';\n\n/**\n * Constructor shape accepted by `MigrationCLI.run`. `Migration` subclasses\n * accept an optional `ControlStack` in their constructor (each subclass\n * narrows the stack to its own family/target generics); the CLI always\n * passes one assembled from the loaded config. We use a rest-args `any[]`\n * constructor signature so that subclass constructors with narrower\n * parameter types remain assignable - constructor type compatibility in\n * TS is contravariant in the parameter, and a wider `unknown` parameter\n * on the alias side would reject any narrower subclass signature.\n *\n * The CLI only ever passes one argument (`new MigrationClass(stack)`);\n * the rest-arity is purely a type-compatibility concession for subclass\n * constructors that declare narrower parameter types, not an extension\n * point for additional construction arguments.\n */\n// biome-ignore lint/suspicious/noExplicitAny: see JSDoc - rest args with any are the idiomatic TS pattern for accepting arbitrary subclass constructor signatures\nexport type MigrationConstructor = new (...args: any[]) => Migration;\n\n/**\n * Stream surface accepted by `MigrationCLI.run`'s `options.stdout` /\n * `options.stderr`. Aliases node's `Writable` because clipanion's\n * `BaseContext.stdout`/`stderr` are typed as `Writable`, and the CLI\n * forwards the injected streams into clipanion's context.\n *\n * `process.stdout` and `process.stderr` are `Writable`-shaped, so the\n * default-fallback path remains a no-op for existing two-argument\n * callers like `MigrationCLI.run(import.meta.url, MyMigration)`.\n *\n * Tests inject a `Writable` subclass that captures chunks for\n * assertions.\n */\nexport type MigrationCliWritable = Writable;\n\n/**\n * Flags exposed by the migration-file CLI.\n *\n * Must stay in sync with the `Option` declarations on\n * `MigrationFileCommand` below. This list is rendered in the\n * `errorMigrationCliUnknownFlag` envelope's `fix` text and `meta`,\n * so order matters for user-visible output (declaration order is the\n * order users see when they run `--help`).\n */\nconst KNOWN_FLAGS: readonly string[] = ['--help', '--dry-run', '--config'];\n\n/**\n * The clipanion command that owns the migration-file CLI's option\n * declarations. The class is internal — `MigrationCLI.run` is the\n * stable public surface. Adding a flag here automatically updates\n * `--help` rendering and the `KNOWN_FLAGS` list (the latter must be\n * updated in tandem).\n */\nclass MigrationFileCommand extends Command {\n static override paths = [Command.Default];\n\n static override usage = Command.Usage({\n description: 'Self-emit ops.json and migration.json from a class-flow migration',\n details: `\n Loads the project's prisma-next.config.ts, assembles a ControlStack\n from the configured target/adapter/extensions, and serializes the\n migration's operations + metadata next to this file.\n `,\n examples: [\n ['Self-emit ops.json + migration.json next to migration.ts', '$0'],\n ['Preview without writing files', '$0 --dry-run'],\n ['Use a non-default config path', '$0 --config ./custom.config.ts'],\n ],\n });\n\n dryRun = Option.Boolean('--dry-run', false, {\n description: 'Print operations to stdout without writing files',\n });\n\n config = Option.String('--config', {\n description: 'Path to prisma-next.config.ts',\n });\n\n /**\n * Unused: orchestration runs inside `MigrationCLI.run` so error\n * routing stays under our control (clipanion's `cli.run` writes\n * error output to `context.stdout`, but our contract requires\n * structured errors on stderr). `cli.process` is used to parse\n * argv into a populated `MigrationFileCommand` instance whose\n * fields drive the orchestration directly.\n */\n override async execute(): Promise<number> {\n return 0;\n }\n}\n\n/**\n * The CLI surface invoked by an authored `migration.ts` file. Exposed as\n * a class with a static `run` method (rather than a free function) to\n * give the concept a stable identity in the ubiquitous language: this is\n * the \"migration-file CLI\", distinct from the apply-time runner that\n * executes migration JSON ops.\n *\n * Currently a single static method. Future surface (e.g. a programmatic\n * `MigrationCLI.serializeOnly(...)` for tests, or extra subcommands) can\n * land here without changing the import shape used by every authored\n * migration.\n */\n// biome-ignore lint/complexity/noStaticOnlyClass: see JSDoc - intentional class facade for the migration-file CLI surface; future methods will share state derived from argv/config.\nexport class MigrationCLI {\n /**\n * Orchestrates a class-flow `migration.ts` script run.\n *\n * The third argument is the in-process testability surface: callers\n * (and tests) may inject `argv`, `stdout`, and `stderr` instead of\n * relying on `process.argv` / `process.stdout` / `process.stderr`.\n * Each option defaults to its `process` global when omitted, so\n * existing two-argument call sites\n * (`MigrationCLI.run(import.meta.url, MyMigration)`) continue to\n * compile and behave identically.\n *\n * Returns the exit code so the caller can branch on it. Also writes\n * the same code to `process.exitCode` so script-style callers that\n * don't await the return value still surface a non-zero exit when\n * something fails.\n *\n * Exit codes:\n * - 0 — success, or `--help`, or imported-not-entrypoint no-op.\n * - 1 — runtime/orchestration error (config not found, target\n * mismatch, etc.).\n * - 2 — usage error (unknown flag, malformed `--config`). Aligns\n * with `docs/CLI Style Guide.md` § Exit Codes.\n */\n static async run(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n options: {\n readonly argv?: readonly string[];\n readonly stdout?: MigrationCliWritable;\n readonly stderr?: MigrationCliWritable;\n } = {},\n ): Promise<number> {\n if (!importMetaUrl) {\n return 0;\n }\n\n const argv = options.argv ?? process.argv;\n const stdout = options.stdout ?? process.stdout;\n const stderr = options.stderr ?? process.stderr;\n\n if (!isDirectEntrypoint(importMetaUrl, argv)) {\n return 0;\n }\n\n const exitCode = await orchestrate(importMetaUrl, MigrationClass, {\n argv,\n stdout,\n stderr,\n });\n // Preserve any pre-existing non-zero `process.exitCode` set by code\n // running alongside `MigrationCLI.run` (an unhandled rejection\n // upstream, an explicit `process.exitCode = N` from another\n // module). Overwriting it with our success would mask the upstream\n // failure for script-style callers that don't await the return\n // value. Failures we return here are still surfaced — non-zero\n // codes always win over the prior status — but successes never\n // clear it.\n if (exitCode !== 0 || !process.exitCode) {\n process.exitCode = exitCode;\n }\n return exitCode;\n }\n}\n\n/**\n * Argv-aware variant of the entrypoint guard. The shared\n * `@prisma-next/migration-tools` helper of the same name reads\n * `process.argv[1]` directly, which doesn't compose with the new\n * in-process testability surface (tests inject `argv` without mutating\n * the process global). Inlined here so the migration-file CLI's check\n * follows the injected `argv[1]` consistently.\n */\nfunction isDirectEntrypoint(importMetaUrl: string, argv: readonly string[]): boolean {\n const argv1 = argv[1];\n if (!argv1) {\n return false;\n }\n try {\n return realpathSync(fileURLToPath(importMetaUrl)) === realpathSync(argv1);\n } catch {\n return false;\n }\n}\n\n/**\n * Argv-and-stream-driven orchestration body. Pulled out of the static\n * method so the entrypoint guard / process-default plumbing stays\n * separate from the parse + load + serialize steps.\n */\nasync function orchestrate(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n ctx: {\n readonly argv: readonly string[];\n readonly stdout: MigrationCliWritable;\n readonly stderr: MigrationCliWritable;\n },\n): Promise<number> {\n const cli = Cli.from([MigrationFileCommand], {\n binaryName: 'migration.ts',\n binaryLabel: 'Migration file CLI',\n });\n\n const input = ctx.argv.slice(2);\n\n // Pre-scan for malformed `--config` (no value, or value-shaped-as-flag)\n // before delegating to clipanion. The legacy parser surfaced both as\n // `errorMigrationCliInvalidConfigArg` (`PN-CLI-4012`); pre-scanning\n // here keeps that contract independent of how clipanion classifies\n // the error internally (it variably throws `UnknownSyntaxError` or\n // accepts the flag-shaped token as the value depending on what other\n // options are registered).\n const configError = detectInvalidConfig(input);\n if (configError) {\n writeStructuredError(ctx.stderr, configError);\n return 2;\n }\n\n let parsed: MigrationFileCommand;\n try {\n const command = cli.process({\n input: [...input],\n context: { stdout: ctx.stdout, stderr: ctx.stderr },\n });\n if (!(command instanceof MigrationFileCommand)) {\n // The only registered command class is `MigrationFileCommand`;\n // any other concrete type indicates clipanion emitted its\n // built-in `HelpCommand`. Render usage directly so we don't\n // depend on calling `cli.run` (which routes errors to stdout —\n // wrong stream for our contract).\n ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));\n return 0;\n }\n parsed = command;\n } catch (err) {\n return renderParseError(err, input, ctx.stderr);\n }\n\n if (parsed.help) {\n ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));\n return 0;\n }\n\n try {\n await runMigration(importMetaUrl, MigrationClass, parsed, ctx);\n return 0;\n } catch (err) {\n if (CliStructuredError.is(err)) {\n writeStructuredError(ctx.stderr, err);\n } else if (MigrationToolsError.is(err)) {\n // Migration-tools errors (e.g. `errorInvalidJson` thrown by\n // `readExistingMetadata` when migration.json is malformed) carry\n // their own `code`/`why`/`fix` shape. Render them with the same\n // visual structure as `CliStructuredError` so consumers grepping\n // for `MIGRATION.<CODE>` see consistent output across surfaces.\n const fix = err.fix ? `\\n${err.fix}` : '';\n ctx.stderr.write(`${err.code}: ${err.message}\\n${err.why}${fix}\\n`);\n } else {\n ctx.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`);\n }\n return 1;\n }\n}\n\n/**\n * Returns an `errorMigrationCliInvalidConfigArg` envelope when `input`\n * contains a malformed `--config`:\n *\n * - `--config` as the last token (no value follows).\n * - `--config <flag>` where `<flag>` starts with `-` (silently\n * consuming the next flag would either drop the flag or serialize\n * against the wrong project).\n * - `--config <empty>` where the value is the empty string. Shells\n * expand `--config \"\"` (or `--config \"$UNSET_VAR\"`) into a real\n * empty argv token; treating that as a usage error here surfaces\n * `PN-CLI-4012` instead of a less actionable loader error on an\n * empty path.\n * - `--config=` (the equals form with an empty value). Same shape as\n * the empty-string case above; the user expressed intent to override\n * the config path but the override is empty.\n *\n * `--config=<value>` and `--config <value>` with a non-empty value are\n * both valid (and the equals form's value is allowed to start with\n * `-` — the `=` makes the binding explicit).\n */\nfunction detectInvalidConfig(input: readonly string[]): CliStructuredError | null {\n for (let i = 0; i < input.length; i++) {\n const token = input[i];\n if (token === '--config') {\n const next = input[i + 1];\n if (next === undefined || next === '') {\n return errorMigrationCliInvalidConfigArg();\n }\n if (next.startsWith('-')) {\n return errorMigrationCliInvalidConfigArg({ nextToken: next });\n }\n continue;\n }\n if (token === '--config=') {\n return errorMigrationCliInvalidConfigArg();\n }\n }\n return null;\n}\n\n/**\n * Translate clipanion's parse-time errors into the project's structured\n * error envelopes.\n *\n * - `UnknownSyntaxError` covers both unknown flags (`--frobnicate`) and\n * the bare-trailing `--config` case (where arity-1 needs a value but\n * none was supplied). Distinguished by inspecting the input array.\n * - `UsageError` covers schema/validator failures from typanion. None\n * of the migration-file CLI's options have validators today, but we\n * still translate it as a usage error (exit 2) for forward-compat.\n * - Anything else re-throws — caller's outer catch will surface it as\n * exit 1 (runtime error).\n */\nfunction renderParseError(\n err: unknown,\n input: readonly string[],\n stderr: MigrationCliWritable,\n): number {\n if (isUnknownSyntaxError(err)) {\n const flag = findOffendingFlag(input);\n writeStructuredError(stderr, errorMigrationCliUnknownFlag({ flag, knownFlags: KNOWN_FLAGS }));\n return 2;\n }\n if (err instanceof UsageError) {\n // typanion validator failures and similar usage errors. None of\n // the migration-file CLI's options have validators today, so this\n // branch is forward-compat scaffolding — kept so that a future\n // option declaration with a validator routes through the same PN\n // envelope path rather than escaping as exit 1.\n writeStructuredError(stderr, errorMigrationCliInvalidConfigArg({ nextToken: err.message }));\n return 2;\n }\n throw err;\n}\n\n/**\n * Duck-type check for clipanion's `UnknownSyntaxError`: the class is\n * thrown by the parser but is not re-exported from the package's main\n * entry (only `UsageError` is — see clipanion's `advanced/index.d.ts`).\n * Identified by `name === 'UnknownSyntaxError'` and the\n * `clipanion.type === 'none'` discriminator that clipanion's\n * `ErrorWithMeta` interface guarantees.\n */\nfunction isUnknownSyntaxError(err: unknown): err is Error {\n if (!(err instanceof Error) || err.name !== 'UnknownSyntaxError') {\n return false;\n }\n // clipanion's `ErrorWithMeta` interface guarantees a `clipanion` field with\n // a `type` discriminator on every error it throws. Read it via a structural\n // shape rather than importing the class (it's not re-exported from the\n // package main).\n const meta = (err as { clipanion?: { type?: string } }).clipanion;\n return typeof meta === 'object' && meta !== null && meta.type === 'none';\n}\n\n/**\n * Best-effort: pull the first input token that doesn't match a known\n * flag. Falls back to the first token when we can't pinpoint it. The\n * returned name is rendered into the user-visible PN-CLI-4013 envelope\n * (`Unknown flag \\`<name>\\``) and round-tripped via `meta.flag` so\n * agent consumers can render their own \"did you mean\" suggestions.\n */\nfunction findOffendingFlag(input: readonly string[]): string {\n for (const token of input) {\n if (!token.startsWith('-')) {\n continue;\n }\n const head = token.split('=', 1)[0] ?? token;\n if (!KNOWN_FLAGS.includes(head) && head !== '-h') {\n return head;\n }\n }\n return input[0] ?? '';\n}\n\n/**\n * Write a `CliStructuredError` envelope to the given stream. Format\n * matches the legacy hand-rolled writer (`message: why`) so the rest of\n * the project's error rendering stays consistent across surfaces. The\n * full PN code (`PN-<domain>-<code>`) is included so consumers can\n * grep for stable identifiers.\n */\nfunction writeStructuredError(stream: MigrationCliWritable, err: CliStructuredError): void {\n const envelope = err.toEnvelope();\n const why = envelope.why ?? envelope.summary;\n const fix = envelope.fix ? `\\n${envelope.fix}` : '';\n stream.write(`${envelope.code}: ${envelope.summary}\\n${why}${fix}\\n`);\n}\n\n/**\n * Read a previously-scaffolded `migration.json` from disk, returning\n * `null` when the file is missing and throwing `MIGRATION.INVALID_JSON`\n * when the file is present but cannot be parsed as JSON. The CLI feeds\n * this into `buildMigrationArtifacts` so the pure builder can preserve\n * fields owned by `migration plan` (contract bookends, `createdAt`) across\n * re-emits.\n *\n * Author-time path: this loader still does not verify the manifest hash\n * or schema — that is the apply-time loader's job. Hash mismatch is the\n * *expected* outcome of a re-author (the developer's source changes\n * invalidate the prior hash by construction), and verification here\n * would block legitimate regenerations. Syntactic JSON-parse failure,\n * however, is now surfaced rather than swallowed: a malformed\n * `migration.json` indicates either a hand-edit gone wrong or partial\n * write, and silently rebuilding from `describe()` would discard the\n * user's on-disk content (preserved bookends, `createdAt`) without any\n * indication something was wrong on disk.\n * Apply-time consumers always route through the verifying\n * `readMigrationPackage` in `@prisma-next/migration-tools/io` instead.\n */\nfunction readExistingMetadata(metadataPath: string): Partial<MigrationMetadata> | null {\n let raw: string;\n try {\n raw = readFileSync(metadataPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n return JSON.parse(raw) as Partial<MigrationMetadata>;\n } catch (e) {\n throw errorInvalidJson(metadataPath, e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Persist a migration instance's artifacts to `migrationDir`. In\n * `dryRun` mode the artifacts are printed to stdout (with the same\n * `--- migration.json --- / --- ops.json ---` framing the legacy\n * `serializeMigration` helper used) and no files are written. Otherwise\n * `ops.json` and `migration.json` are written next to `migration.ts` and\n * a confirmation line is printed.\n *\n * File I/O lives in the CLI rather than `@prisma-next/migration-tools`\n * so the migration-tools package stays focused on the pure\n * `Migration` → in-memory artifact conversion. The CLI is the only\n * legitimate site for combining config loading, stack assembly, and\n * filesystem persistence.\n */\nfunction serializeMigrationToDisk(\n instance: Migration,\n migrationDir: string,\n dryRun: boolean,\n stdout: MigrationCliWritable,\n): void {\n const metadataPath = join(migrationDir, 'migration.json');\n const existing = readExistingMetadata(metadataPath);\n const { opsJson, metadataJson } = buildMigrationArtifacts(instance, existing);\n\n if (dryRun) {\n stdout.write(`--- migration.json ---\\n${metadataJson}\\n`);\n stdout.write('--- ops.json ---\\n');\n stdout.write(`${opsJson}\\n`);\n return;\n }\n\n writeFileSync(join(migrationDir, 'ops.json'), opsJson);\n writeFileSync(metadataPath, metadataJson);\n\n stdout.write(`Wrote ops.json + migration.json to ${migrationDir}\\n`);\n}\n\n/**\n * Inner orchestration: load config, probe-construct the migration,\n * verify target, assemble the stack, construct with the stack, persist.\n *\n * Throws `CliStructuredError` for known failure modes (config not\n * found, target mismatch); the outer `orchestrate` translates those to\n * exit 1.\n */\nasync function runMigration(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n parsed: MigrationFileCommand,\n ctx: {\n readonly stdout: MigrationCliWritable;\n readonly stderr: MigrationCliWritable;\n },\n): Promise<void> {\n const migrationFile = fileURLToPath(importMetaUrl);\n const migrationDir = dirname(migrationFile);\n\n const config = await loadConfig(parsed.config);\n\n // Probe-instantiate without a stack so we can read `targetId` before\n // any target-specific constructor side effects (e.g.\n // `PostgresMigration`'s `stack.adapter.create(stack)`) run. Concrete\n // subclasses are required to accept the no-arg form; the abstract\n // `Migration` constructor declares `stack?` and target subclasses\n // (Postgres, Mongo) propagate that optionality. This makes the\n // target-mismatch guard fail fast with `PN-MIG-2006` before any\n // stack-driven adapter construction begins, even if the wrong-target\n // adapter's `create` would otherwise succeed and silently misshapen\n // the stored adapter cast.\n const probe = new MigrationClass();\n\n if (probe.targetId !== config.target.targetId) {\n throw errorMigrationTargetMismatch({\n migrationTargetId: probe.targetId,\n configTargetId: config.target.targetId,\n });\n }\n\n const stack = createControlStack(config);\n const instance = new MigrationClass(stack);\n\n serializeMigrationToDisk(instance, migrationDir, parsed.dryRun, ctx.stdout);\n void ctx.stderr;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-cli.mjs","names":[],"sources":["../src/migration-cli.ts"],"sourcesContent":["/**\n * The migration-file CLI interface: the actor invoked when the author runs\n * `node migration.ts` directly.\n *\n * Naming: this is *not* a \"migration runner\" in the apply-time sense. The\n * apply-time runner is the thing `prisma-next migrate` uses to\n * execute migration JSON ops against a database. `MigrationCLI` is the\n * tiny CLI surface owned by an authored `migration.ts` file: parse the\n * file's argv, load the project's `prisma-next.config.ts`, assemble a\n * `ControlStack`, instantiate the migration class, and serialize.\n *\n * The user authors a migration class, then calls\n * `MigrationCLI.run(import.meta.url, MigrationClass)` at module scope\n * after the class definition. When the file is invoked as a node\n * entrypoint (`node migration.ts`), the CLI:\n *\n * 1. Detects whether the file is the direct entrypoint (no-op when imported).\n * 2. Parses CLI args (`--help`, `--dry-run`, `--config <path>`) via\n * [clipanion](https://github.com/arcanis/clipanion).\n * 3. Loads the project's `prisma-next.config.ts` via the same `loadConfig`\n * the CLI commands use, walking up from the migration file's directory.\n * 4. Probe-instantiates the migration class without a stack so it can read\n * `targetId` and verify it matches `config.target.targetId`\n * (`PN-MIG-2006` on mismatch) before any stack-driven adapter\n * construction runs.\n * 5. Assembles a `ControlStack` from the loaded config descriptors and\n * constructs the migration with that stack.\n * 6. Reads any previously-scaffolded `migration.json`, then calls\n * `buildMigrationArtifacts` from `@prisma-next/migration-tools` to\n * produce in-memory `ops.json` + `migration.json` content. Persists\n * the result to disk (or prints in dry-run mode).\n *\n * File I/O lives here, in `@prisma-next/cli`: this is the only place\n * that legitimately combines config loading, stack assembly, and\n * on-disk persistence. `@prisma-next/migration-tools` owns the pure\n * conversion from a `Migration` instance to artifact strings; `Migration`\n * stays a pure abstract class.\n *\n * Parser library: clipanion (chosen over Commander/citty/`node:util.parseArgs`\n * for its in-process testability and runtime-agnostic execution surface; see\n * `docs/architecture docs/research/commander-friction-points.md` for the\n * evaluation rubric and the durable rationale that drove the choice).\n */\n\nimport { readFileSync, realpathSync, writeFileSync } from 'node:fs';\nimport type { Writable } from 'node:stream';\nimport { fileURLToPath } from 'node:url';\nimport {\n CliStructuredError,\n errorMigrationCliInvalidConfigArg,\n errorMigrationCliUnknownFlag,\n} from '@prisma-next/errors/control';\nimport { errorMigrationTargetMismatch } from '@prisma-next/errors/migration';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { errorInvalidJson, MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport { buildMigrationArtifacts, type Migration } from '@prisma-next/migration-tools/migration';\nimport { Cli, Command, Option, UsageError } from 'clipanion';\nimport { dirname, join } from 'pathe';\nimport { loadConfig } from './config-loader';\n\n/**\n * Constructor shape accepted by `MigrationCLI.run`. `Migration` subclasses\n * accept an optional `ControlStack` in their constructor (each subclass\n * narrows the stack to its own family/target generics); the CLI always\n * passes one assembled from the loaded config. We use a rest-args `any[]`\n * constructor signature so that subclass constructors with narrower\n * parameter types remain assignable - constructor type compatibility in\n * TS is contravariant in the parameter, and a wider `unknown` parameter\n * on the alias side would reject any narrower subclass signature.\n *\n * The CLI only ever passes one argument (`new MigrationClass(stack)`);\n * the rest-arity is purely a type-compatibility concession for subclass\n * constructors that declare narrower parameter types, not an extension\n * point for additional construction arguments.\n */\n// biome-ignore lint/suspicious/noExplicitAny: see JSDoc - rest args with any are the idiomatic TS pattern for accepting arbitrary subclass constructor signatures\nexport type MigrationConstructor = new (...args: any[]) => Migration;\n\n/**\n * Stream surface accepted by `MigrationCLI.run`'s `options.stdout` /\n * `options.stderr`. Aliases node's `Writable` because clipanion's\n * `BaseContext.stdout`/`stderr` are typed as `Writable`, and the CLI\n * forwards the injected streams into clipanion's context.\n *\n * `process.stdout` and `process.stderr` are `Writable`-shaped, so the\n * default-fallback path remains a no-op for existing two-argument\n * callers like `MigrationCLI.run(import.meta.url, MyMigration)`.\n *\n * Tests inject a `Writable` subclass that captures chunks for\n * assertions.\n */\nexport type MigrationCliWritable = Writable;\n\n/**\n * Flags exposed by the migration-file CLI.\n *\n * Must stay in sync with the `Option` declarations on\n * `MigrationFileCommand` below. This list is rendered in the\n * `errorMigrationCliUnknownFlag` envelope's `fix` text and `meta`,\n * so order matters for user-visible output (declaration order is the\n * order users see when they run `--help`).\n */\nconst KNOWN_FLAGS: readonly string[] = ['--help', '--dry-run', '--config'];\n\n/**\n * The clipanion command that owns the migration-file CLI's option\n * declarations. The class is internal — `MigrationCLI.run` is the\n * stable public surface. Adding a flag here automatically updates\n * `--help` rendering and the `KNOWN_FLAGS` list (the latter must be\n * updated in tandem).\n */\nclass MigrationFileCommand extends Command {\n static override paths = [Command.Default];\n\n static override usage = Command.Usage({\n description: 'Self-emit ops.json and migration.json from a class-flow migration',\n details: `\n Loads the project's prisma-next.config.ts, assembles a ControlStack\n from the configured target/adapter/extensions, and serializes the\n migration's operations + metadata next to this file.\n `,\n examples: [\n ['Self-emit ops.json + migration.json next to migration.ts', '$0'],\n ['Preview without writing files', '$0 --dry-run'],\n ['Use a non-default config path', '$0 --config ./custom.config.ts'],\n ],\n });\n\n dryRun = Option.Boolean('--dry-run', false, {\n description: 'Print operations to stdout without writing files',\n });\n\n config = Option.String('--config', {\n description: 'Path to prisma-next.config.ts',\n });\n\n /**\n * Unused: orchestration runs inside `MigrationCLI.run` so error\n * routing stays under our control (clipanion's `cli.run` writes\n * error output to `context.stdout`, but our contract requires\n * structured errors on stderr). `cli.process` is used to parse\n * argv into a populated `MigrationFileCommand` instance whose\n * fields drive the orchestration directly.\n */\n override async execute(): Promise<number> {\n return 0;\n }\n}\n\n/**\n * The CLI surface invoked by an authored `migration.ts` file. Exposed as\n * a class with a static `run` method (rather than a free function) to\n * give the concept a stable identity in the ubiquitous language: this is\n * the \"migration-file CLI\", distinct from the apply-time runner that\n * executes migration JSON ops.\n *\n * Currently a single static method. Future surface (e.g. a programmatic\n * `MigrationCLI.serializeOnly(...)` for tests, or extra subcommands) can\n * land here without changing the import shape used by every authored\n * migration.\n */\n// biome-ignore lint/complexity/noStaticOnlyClass: see JSDoc - intentional class facade for the migration-file CLI surface; future methods will share state derived from argv/config.\nexport class MigrationCLI {\n /**\n * Orchestrates a class-flow `migration.ts` script run.\n *\n * The third argument is the in-process testability surface: callers\n * (and tests) may inject `argv`, `stdout`, and `stderr` instead of\n * relying on `process.argv` / `process.stdout` / `process.stderr`.\n * Each option defaults to its `process` global when omitted, so\n * existing two-argument call sites\n * (`MigrationCLI.run(import.meta.url, MyMigration)`) continue to\n * compile and behave identically.\n *\n * Returns the exit code so the caller can branch on it. Also writes\n * the same code to `process.exitCode` so script-style callers that\n * don't await the return value still surface a non-zero exit when\n * something fails.\n *\n * Exit codes:\n * - 0 — success, or `--help`, or imported-not-entrypoint no-op.\n * - 1 — runtime/orchestration error (config not found, target\n * mismatch, etc.).\n * - 2 — usage error (unknown flag, malformed `--config`). Aligns\n * with `docs/CLI Style Guide.md` § Exit Codes.\n */\n static async run(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n options: {\n readonly argv?: readonly string[];\n readonly stdout?: MigrationCliWritable;\n readonly stderr?: MigrationCliWritable;\n } = {},\n ): Promise<number> {\n if (!importMetaUrl) {\n return 0;\n }\n\n const argv = options.argv ?? process.argv;\n const stdout = options.stdout ?? process.stdout;\n const stderr = options.stderr ?? process.stderr;\n\n if (!isDirectEntrypoint(importMetaUrl, argv)) {\n return 0;\n }\n\n const exitCode = await orchestrate(importMetaUrl, MigrationClass, {\n argv,\n stdout,\n stderr,\n });\n // Preserve any pre-existing non-zero `process.exitCode` set by code\n // running alongside `MigrationCLI.run` (an unhandled rejection\n // upstream, an explicit `process.exitCode = N` from another\n // module). Overwriting it with our success would mask the upstream\n // failure for script-style callers that don't await the return\n // value. Failures we return here are still surfaced — non-zero\n // codes always win over the prior status — but successes never\n // clear it.\n if (exitCode !== 0 || !process.exitCode) {\n process.exitCode = exitCode;\n }\n return exitCode;\n }\n}\n\n/**\n * Argv-aware variant of the entrypoint guard. The shared\n * `@prisma-next/migration-tools` helper of the same name reads\n * `process.argv[1]` directly, which doesn't compose with the new\n * in-process testability surface (tests inject `argv` without mutating\n * the process global). Inlined here so the migration-file CLI's check\n * follows the injected `argv[1]` consistently.\n */\nfunction isDirectEntrypoint(importMetaUrl: string, argv: readonly string[]): boolean {\n const argv1 = argv[1];\n if (!argv1) {\n return false;\n }\n try {\n return realpathSync(fileURLToPath(importMetaUrl)) === realpathSync(argv1);\n } catch {\n return false;\n }\n}\n\n/**\n * Argv-and-stream-driven orchestration body. Pulled out of the static\n * method so the entrypoint guard / process-default plumbing stays\n * separate from the parse + load + serialize steps.\n */\nasync function orchestrate(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n ctx: {\n readonly argv: readonly string[];\n readonly stdout: MigrationCliWritable;\n readonly stderr: MigrationCliWritable;\n },\n): Promise<number> {\n const cli = Cli.from([MigrationFileCommand], {\n binaryName: 'migration.ts',\n binaryLabel: 'Migration file CLI',\n });\n\n const input = ctx.argv.slice(2);\n\n // Pre-scan for malformed `--config` (no value, or value-shaped-as-flag)\n // before delegating to clipanion. The legacy parser surfaced both as\n // `errorMigrationCliInvalidConfigArg` (`PN-CLI-4012`); pre-scanning\n // here keeps that contract independent of how clipanion classifies\n // the error internally (it variably throws `UnknownSyntaxError` or\n // accepts the flag-shaped token as the value depending on what other\n // options are registered).\n const configError = detectInvalidConfig(input);\n if (configError) {\n writeStructuredError(ctx.stderr, configError);\n return 2;\n }\n\n let parsed: MigrationFileCommand;\n try {\n const command = cli.process({\n input: [...input],\n context: { stdout: ctx.stdout, stderr: ctx.stderr },\n });\n if (!(command instanceof MigrationFileCommand)) {\n // The only registered command class is `MigrationFileCommand`;\n // any other concrete type indicates clipanion emitted its\n // built-in `HelpCommand`. Render usage directly so we don't\n // depend on calling `cli.run` (which routes errors to stdout —\n // wrong stream for our contract).\n ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));\n return 0;\n }\n parsed = command;\n } catch (err) {\n return renderParseError(err, input, ctx.stderr);\n }\n\n if (parsed.help) {\n ctx.stdout.write(cli.usage(MigrationFileCommand, { detailed: true }));\n return 0;\n }\n\n try {\n await runMigration(importMetaUrl, MigrationClass, parsed, ctx);\n return 0;\n } catch (err) {\n if (CliStructuredError.is(err)) {\n writeStructuredError(ctx.stderr, err);\n } else if (MigrationToolsError.is(err)) {\n // Migration-tools errors (e.g. `errorInvalidJson` thrown by\n // `readExistingMetadata` when migration.json is malformed) carry\n // their own `code`/`why`/`fix` shape. Render them with the same\n // visual structure as `CliStructuredError` so consumers grepping\n // for `MIGRATION.<CODE>` see consistent output across surfaces.\n const fix = err.fix ? `\\n${err.fix}` : '';\n ctx.stderr.write(`${err.code}: ${err.message}\\n${err.why}${fix}\\n`);\n } else {\n ctx.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`);\n }\n return 1;\n }\n}\n\n/**\n * Returns an `errorMigrationCliInvalidConfigArg` envelope when `input`\n * contains a malformed `--config`:\n *\n * - `--config` as the last token (no value follows).\n * - `--config <flag>` where `<flag>` starts with `-` (silently\n * consuming the next flag would either drop the flag or serialize\n * against the wrong project).\n * - `--config <empty>` where the value is the empty string. Shells\n * expand `--config \"\"` (or `--config \"$UNSET_VAR\"`) into a real\n * empty argv token; treating that as a usage error here surfaces\n * `PN-CLI-4012` instead of a less actionable loader error on an\n * empty path.\n * - `--config=` (the equals form with an empty value). Same shape as\n * the empty-string case above; the user expressed intent to override\n * the config path but the override is empty.\n *\n * `--config=<value>` and `--config <value>` with a non-empty value are\n * both valid (and the equals form's value is allowed to start with\n * `-` — the `=` makes the binding explicit).\n */\nfunction detectInvalidConfig(input: readonly string[]): CliStructuredError | null {\n for (let i = 0; i < input.length; i++) {\n const token = input[i];\n if (token === '--config') {\n const next = input[i + 1];\n if (next === undefined || next === '') {\n return errorMigrationCliInvalidConfigArg();\n }\n if (next.startsWith('-')) {\n return errorMigrationCliInvalidConfigArg({ nextToken: next });\n }\n continue;\n }\n if (token === '--config=') {\n return errorMigrationCliInvalidConfigArg();\n }\n }\n return null;\n}\n\n/**\n * Translate clipanion's parse-time errors into the project's structured\n * error envelopes.\n *\n * - `UnknownSyntaxError` covers both unknown flags (`--frobnicate`) and\n * the bare-trailing `--config` case (where arity-1 needs a value but\n * none was supplied). Distinguished by inspecting the input array.\n * - `UsageError` covers schema/validator failures from typanion. None\n * of the migration-file CLI's options have validators today, but we\n * still translate it as a usage error (exit 2) for forward-compat.\n * - Anything else re-throws — caller's outer catch will surface it as\n * exit 1 (runtime error).\n */\nfunction renderParseError(\n err: unknown,\n input: readonly string[],\n stderr: MigrationCliWritable,\n): number {\n if (isUnknownSyntaxError(err)) {\n const flag = findOffendingFlag(input);\n writeStructuredError(stderr, errorMigrationCliUnknownFlag({ flag, knownFlags: KNOWN_FLAGS }));\n return 2;\n }\n if (err instanceof UsageError) {\n // typanion validator failures and similar usage errors. None of\n // the migration-file CLI's options have validators today, so this\n // branch is forward-compat scaffolding — kept so that a future\n // option declaration with a validator routes through the same PN\n // envelope path rather than escaping as exit 1.\n writeStructuredError(stderr, errorMigrationCliInvalidConfigArg({ nextToken: err.message }));\n return 2;\n }\n throw err;\n}\n\n/**\n * Duck-type check for clipanion's `UnknownSyntaxError`: the class is\n * thrown by the parser but is not re-exported from the package's main\n * entry (only `UsageError` is — see clipanion's `advanced/index.d.ts`).\n * Identified by `name === 'UnknownSyntaxError'` and the\n * `clipanion.type === 'none'` discriminator that clipanion's\n * `ErrorWithMeta` interface guarantees.\n */\nfunction isUnknownSyntaxError(err: unknown): err is Error {\n if (!(err instanceof Error) || err.name !== 'UnknownSyntaxError') {\n return false;\n }\n // clipanion's `ErrorWithMeta` interface guarantees a `clipanion` field with\n // a `type` discriminator on every error it throws. Read it via a structural\n // shape rather than importing the class (it's not re-exported from the\n // package main).\n const meta = (err as { clipanion?: { type?: string } }).clipanion;\n return typeof meta === 'object' && meta !== null && meta.type === 'none';\n}\n\n/**\n * Best-effort: pull the first input token that doesn't match a known\n * flag. Falls back to the first token when we can't pinpoint it. The\n * returned name is rendered into the user-visible PN-CLI-4013 envelope\n * (`Unknown flag \\`<name>\\``) and round-tripped via `meta.flag` so\n * agent consumers can render their own \"did you mean\" suggestions.\n */\nfunction findOffendingFlag(input: readonly string[]): string {\n for (const token of input) {\n if (!token.startsWith('-')) {\n continue;\n }\n const head = token.split('=', 1)[0] ?? token;\n if (!KNOWN_FLAGS.includes(head) && head !== '-h') {\n return head;\n }\n }\n return input[0] ?? '';\n}\n\n/**\n * Write a `CliStructuredError` envelope to the given stream. Format\n * matches the legacy hand-rolled writer (`message: why`) so the rest of\n * the project's error rendering stays consistent across surfaces. The\n * full PN code (`PN-<domain>-<code>`) is included so consumers can\n * grep for stable identifiers.\n */\nfunction writeStructuredError(stream: MigrationCliWritable, err: CliStructuredError): void {\n const envelope = err.toEnvelope();\n const why = envelope.why ?? envelope.summary;\n const fix = envelope.fix ? `\\n${envelope.fix}` : '';\n stream.write(`${envelope.code}: ${envelope.summary}\\n${why}${fix}\\n`);\n}\n\n/**\n * Read a previously-scaffolded `migration.json` from disk, returning\n * `null` when the file is missing and throwing `MIGRATION.INVALID_JSON`\n * when the file is present but cannot be parsed as JSON. The CLI feeds\n * this into `buildMigrationArtifacts` so the pure builder can preserve\n * fields owned by `migration plan` (contract bookends, `createdAt`) across\n * re-emits.\n *\n * Author-time path: this loader still does not verify the manifest hash\n * or schema — that is the apply-time loader's job. Hash mismatch is the\n * *expected* outcome of a re-author (the developer's source changes\n * invalidate the prior hash by construction), and verification here\n * would block legitimate regenerations. Syntactic JSON-parse failure,\n * however, is now surfaced rather than swallowed: a malformed\n * `migration.json` indicates either a hand-edit gone wrong or partial\n * write, and silently rebuilding from `describe()` would discard the\n * user's on-disk content (preserved bookends, `createdAt`) without any\n * indication something was wrong on disk.\n * Apply-time consumers always route through the verifying\n * `readMigrationPackage` in `@prisma-next/migration-tools/io` instead.\n */\nfunction readExistingMetadata(metadataPath: string): Partial<MigrationMetadata> | null {\n let raw: string;\n try {\n raw = readFileSync(metadataPath, 'utf-8');\n } catch {\n return null;\n }\n try {\n return JSON.parse(raw) as Partial<MigrationMetadata>;\n } catch (e) {\n throw errorInvalidJson(metadataPath, e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Persist a migration instance's artifacts to `migrationDir`. In\n * `dryRun` mode the artifacts are printed to stdout (with the same\n * `--- migration.json --- / --- ops.json ---` framing the legacy\n * `serializeMigration` helper used) and no files are written. Otherwise\n * `ops.json` and `migration.json` are written next to `migration.ts` and\n * a confirmation line is printed.\n *\n * File I/O lives in the CLI rather than `@prisma-next/migration-tools`\n * so the migration-tools package stays focused on the pure\n * `Migration` → in-memory artifact conversion. The CLI is the only\n * legitimate site for combining config loading, stack assembly, and\n * filesystem persistence.\n */\nasync function serializeMigrationToDisk(\n instance: Migration,\n migrationDir: string,\n dryRun: boolean,\n stdout: MigrationCliWritable,\n): Promise<void> {\n const metadataPath = join(migrationDir, 'migration.json');\n const existing = readExistingMetadata(metadataPath);\n const { opsJson, metadataJson } = await buildMigrationArtifacts(instance, existing);\n\n if (dryRun) {\n stdout.write(`--- migration.json ---\\n${metadataJson}\\n`);\n stdout.write('--- ops.json ---\\n');\n stdout.write(`${opsJson}\\n`);\n return;\n }\n\n writeFileSync(join(migrationDir, 'ops.json'), opsJson);\n writeFileSync(metadataPath, metadataJson);\n\n stdout.write(`Wrote ops.json + migration.json to ${migrationDir}\\n`);\n}\n\n/**\n * Inner orchestration: load config, probe-construct the migration,\n * verify target, assemble the stack, construct with the stack, persist.\n *\n * Throws `CliStructuredError` for known failure modes (config not\n * found, target mismatch); the outer `orchestrate` translates those to\n * exit 1.\n */\nasync function runMigration(\n importMetaUrl: string,\n MigrationClass: MigrationConstructor,\n parsed: MigrationFileCommand,\n ctx: {\n readonly stdout: MigrationCliWritable;\n readonly stderr: MigrationCliWritable;\n },\n): Promise<void> {\n const migrationFile = fileURLToPath(importMetaUrl);\n const migrationDir = dirname(migrationFile);\n\n const config = await loadConfig(parsed.config);\n\n // Probe-instantiate without a stack so we can read `targetId` before\n // any target-specific constructor side effects (e.g.\n // `PostgresMigration`'s `stack.adapter.create(stack)`) run. Concrete\n // subclasses are required to accept the no-arg form; the abstract\n // `Migration` constructor declares `stack?` and target subclasses\n // (Postgres, Mongo) propagate that optionality. This makes the\n // target-mismatch guard fail fast with `PN-MIG-2006` before any\n // stack-driven adapter construction begins, even if the wrong-target\n // adapter's `create` would otherwise succeed and silently misshapen\n // the stored adapter cast.\n const probe = new MigrationClass();\n\n if (probe.targetId !== config.target.targetId) {\n throw errorMigrationTargetMismatch({\n migrationTargetId: probe.targetId,\n configTargetId: config.target.targetId,\n });\n }\n\n const stack = createControlStack(config);\n const instance = new MigrationClass(stack);\n\n await serializeMigrationToDisk(instance, migrationDir, parsed.dryRun, ctx.stdout);\n void ctx.stderr;\n}\n"],"mappings":"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"}
|
|
@@ -278,7 +278,7 @@ async function runPlannerLeg(planner, migrations, frameworkComponents, contract,
|
|
|
278
278
|
let plannedOps = [];
|
|
279
279
|
let hasPlaceholders = false;
|
|
280
280
|
try {
|
|
281
|
-
plannedOps = plannerResult.plan.operations;
|
|
281
|
+
plannedOps = await Promise.all(plannerResult.plan.operations);
|
|
282
282
|
if (plannedOps.length === 0) return notOk(errorMigrationPlanningFailed({ conflicts: [{
|
|
283
283
|
kind: "unsupportedChange",
|
|
284
284
|
summary: "Contract changed but planner produced no operations. This indicates unsupported or ignored changes."
|
|
@@ -766,4 +766,4 @@ function resolveBundleByPrefix(bundles, needle) {
|
|
|
766
766
|
//#endregion
|
|
767
767
|
export { formatMigrationPlanOutput as n, resolveBundleByPrefix as r, createMigrationPlanCommand as t };
|
|
768
768
|
|
|
769
|
-
//# sourceMappingURL=migration-plan-
|
|
769
|
+
//# sourceMappingURL=migration-plan-W_E8FQOk.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-plan-W_E8FQOk.mjs","names":[],"sources":["../src/utils/contract-space-seed-phase.ts","../src/utils/plan-resolution.ts","../src/commands/migration-plan.ts"],"sourcesContent":["import { materialiseExtensionMigrationPackageIfMissing } from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport type { MigrationOps } from '@prisma-next/migration-tools/package';\nimport {\n emitContractSpaceArtefacts,\n planAllSpaces,\n readContractSpaceHeadRef,\n type SpacePlanOutput,\n spaceMigrationDirectory,\n} from '@prisma-next/migration-tools/spaces';\n\n/**\n * In-memory authored migration package shipped by an extension descriptor.\n * Mirrors `MigrationPackage` from `@prisma-next/migration-tools/io` (the\n * on-disk shape minus `dirPath`); redeclared structurally here so the\n * CLI helper does not couple to any family's `ExtensionMigrationPackage`\n * type — any family that ships pre-built migration packages can pass\n * them through unchanged.\n */\nexport interface DescriptorMigrationPackage {\n readonly dirName: string;\n readonly metadata: MigrationMetadata;\n readonly ops: MigrationOps;\n}\n\n/**\n * Minimal descriptor view consumed by the seed phase. Mirrors the shape\n * the SQL family ships on each declared extension entry; only the fields\n * the seed phase needs are surfaced.\n */\nexport interface SeedPhaseExtensionInput {\n readonly id: string;\n readonly contractSpace?: {\n readonly contractJson: unknown;\n readonly headRef: { readonly hash: string; readonly invariants: readonly string[] };\n readonly migrations: readonly DescriptorMigrationPackage[];\n };\n}\n\nexport interface ContractSpaceSeedPhaseInputs {\n readonly migrationsDir: string;\n readonly extensionPacks: ReadonlyArray<SeedPhaseExtensionInput>;\n}\n\n/**\n * One per-space record describing what the seed phase did for an\n * extension contract space. Surfaced verbatim by the caller (typically\n * `migration plan`) so users see a single line per touched extension.\n *\n * - `action: 'updated'` — either the on-disk head pointer changed, or\n * one or more new descriptor-shipped migration packages were\n * materialised into `migrations/<spaceId>/<dirName>/`.\n * - `action: 'unchanged'` — the on-disk head already matched the\n * descriptor and no new migration packages needed to be written.\n *\n * Either way, the artefacts (`contract.json`, `contract.d.ts`,\n * `refs/head.json`) are re-emitted: the framework owns those files and\n * makes the re-emit observably idempotent at the byte level.\n */\nexport interface ContractSpaceSeedPhaseRecord {\n readonly spaceId: string;\n readonly action: 'updated' | 'unchanged';\n readonly priorHash: string | null;\n readonly newHash: string;\n readonly newMigrationDirs: readonly string[];\n}\n\nexport interface ContractSpaceSeedPhaseResult {\n readonly seeded: readonly ContractSpaceSeedPhaseRecord[];\n}\n\n/**\n * Phase-1 of the two-phase `migration plan` pipeline (sub-spec § 4).\n *\n * For every extension that exposes a `contractSpace`:\n *\n * 1. Read the on-disk head ref (returns `null` on first emit).\n * 2. Re-emit `contract.json` / `contract.d.ts` / `refs/head.json`\n * unconditionally via {@link emitContractSpaceArtefacts}. The\n * framework owns these files; re-emit is the contract.\n * 3. Materialise any descriptor-shipped migration packages not yet on\n * disk via {@link materialiseExtensionMigrationPackageIfMissing}.\n * Existing packages are left untouched (by-existence skip).\n *\n * The return value lets the caller render a per-space status line and\n * lets the phase-2 aggregate loader run on a now-consistent disk state\n * (every loaded extension is guaranteed to have its head ref pinned\n * to the descriptor's hash and to ship every package the descriptor\n * declares).\n *\n * Output ordering is deterministic and alphabetical by spaceId (via\n * {@link planAllSpaces}, which also detects duplicate spaceIds). This\n * matches the canonical sort order used by every other aggregate\n * surface (`migrate`, `migration status`, the runner).\n */\nexport async function runContractSpaceSeedPhase(\n inputs: ContractSpaceSeedPhaseInputs,\n): Promise<ContractSpaceSeedPhaseResult> {\n const planInputs = inputs.extensionPacks\n .filter(\n (\n pack,\n ): pack is SeedPhaseExtensionInput & {\n contractSpace: NonNullable<SeedPhaseExtensionInput['contractSpace']>;\n } => pack.contractSpace !== undefined,\n )\n .map((pack) => ({\n spaceId: pack.id,\n priorContract: null,\n newContract: pack.contractSpace.contractJson,\n __pack: pack.contractSpace,\n }));\n\n // `planAllSpaces` brings deterministic alphabetical ordering and\n // duplicate-spaceId detection. The \"planner\" callback is a no-op\n // pass-through that simply returns the descriptor's pre-built\n // migration packages.\n const planned: readonly SpacePlanOutput<DescriptorMigrationPackage>[] = planAllSpaces(\n planInputs,\n (input) =>\n (\n input as typeof input & {\n readonly __pack: NonNullable<SeedPhaseExtensionInput['contractSpace']>;\n }\n ).__pack.migrations,\n );\n\n // Reassemble a spaceId → descriptor lookup so the loop below can read\n // the contractJson / headRef without leaking the typed-cast back into\n // `planAllSpaces`'s output shape.\n const descriptorBySpace = new Map<\n string,\n NonNullable<SeedPhaseExtensionInput['contractSpace']>\n >();\n for (const pack of inputs.extensionPacks) {\n if (pack.contractSpace !== undefined) descriptorBySpace.set(pack.id, pack.contractSpace);\n }\n\n const seeded: ContractSpaceSeedPhaseRecord[] = [];\n for (const space of planned) {\n const descriptor = descriptorBySpace.get(space.spaceId);\n if (descriptor === undefined) continue;\n\n const onDiskHeadRef = await readContractSpaceHeadRef(inputs.migrationsDir, space.spaceId);\n const priorHash = onDiskHeadRef?.hash ?? null;\n\n await emitContractSpaceArtefacts(inputs.migrationsDir, space.spaceId, {\n contract: descriptor.contractJson,\n contractDts: buildPlaceholderContractDts(space.spaceId),\n headRef: { hash: descriptor.headRef.hash, invariants: descriptor.headRef.invariants },\n });\n\n const spaceDir = spaceMigrationDirectory(inputs.migrationsDir, space.spaceId);\n const newMigrationDirs: string[] = [];\n for (const pkg of space.migrationPackages) {\n const { written } = await materialiseExtensionMigrationPackageIfMissing(spaceDir, pkg);\n if (written) newMigrationDirs.push(pkg.dirName);\n }\n\n const action: ContractSpaceSeedPhaseRecord['action'] =\n priorHash !== descriptor.headRef.hash || newMigrationDirs.length > 0\n ? 'updated'\n : 'unchanged';\n\n seeded.push({\n spaceId: space.spaceId,\n action,\n priorHash,\n newHash: descriptor.headRef.hash,\n newMigrationDirs,\n });\n }\n\n return { seeded };\n}\n\n/**\n * Placeholder `.d.ts` content for an extension space's on-disk mirror.\n *\n * Rendering a fully-typed `.d.ts` for an extension contract requires\n * the SQL-family renderer with the codec / typemap registry threaded\n * through; until that integration ships, the on-disk `.d.ts` is a\n * stub `export {};` module that documents how consumers should\n * validate the sibling `contract.json`. The stub typechecks on its\n * own and does not need any TypeScript suppressions.\n */\nfunction buildPlaceholderContractDts(spaceId: string): string {\n return [\n '/**',\n ` * Placeholder \\`.d.ts\\` for extension space \"${spaceId}\".`,\n ' *',\n ' * The framework re-emits this file on every `migration plan` run',\n ' * alongside `contract.json` and `refs/head.json`. A typed `.d.ts`',\n ' * rendering pass for extension contracts is tracked separately;',\n ' * until that ships, consumers should import `contract.json`',\n ' * and pass it through the target descriptor’s `contractSerializer`.',\n ' */',\n 'export {};',\n '',\n ].join('\\n');\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type { ContractSpaceMember } from '@prisma-next/migration-tools/aggregate';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport {\n assertHashIsGraphNode,\n findLatestMigration,\n isGraphNode,\n} from '@prisma-next/migration-tools/migration-graph';\nimport type { ContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { Refs } from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport {\n CliStructuredError,\n errorPlanForgotTheFlag,\n errorSnapshotMissing,\n mapRefResolutionError,\n} from './cli-errors';\nimport { mapContractAtError } from './contract-at-errors';\n\nconst FULL_HASH_PATTERN = /^sha256:([0-9a-f]{64}|empty)$/;\n\nexport function looksLikeFullHash(input: string): boolean {\n return FULL_HASH_PATTERN.test(input);\n}\n\nexport type FromResolution =\n | { kind: 'greenfield'; fromHash: null; fromContract: null }\n | { kind: 'graph-node'; fromHash: string; fromContract: Contract; sourceDir: string }\n | {\n kind: 'snapshot';\n fromHash: string;\n fromContract: Contract;\n contractDts: string;\n contractJson: unknown;\n }\n | {\n kind: 'auto-baseline';\n fromHash: string;\n fromContract: Contract;\n contractDts: string;\n contractJson: unknown;\n };\n\nexport interface ResolveFromForPlanInput {\n readonly optionsFrom?: string | undefined;\n readonly member: ContractSpaceMember;\n}\n\nfunction graphIsEmpty(member: ContractSpaceMember): boolean {\n return member.packages.length === 0;\n}\n\nfunction getReachableRefs(\n refs: Refs,\n graph: MigrationGraph,\n): ReadonlyArray<{ name: string; hash: string }> {\n return Object.entries(refs)\n .flatMap(([name, entry]) =>\n entry && isGraphNode(entry.hash, graph) ? [{ name, hash: entry.hash }] : [],\n )\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport function assertFromIsGraphNode(\n fromHash: string,\n graph: MigrationGraph,\n refs: Refs,\n graphTipHash: string | null,\n): void {\n try {\n assertHashIsGraphNode(fromHash, graph);\n } catch (error) {\n if (MigrationToolsError.is(error) && error.code === 'MIGRATION.HASH_NOT_IN_GRAPH') {\n throw errorPlanForgotTheFlag(fromHash, getReachableRefs(refs, graph), graphTipHash);\n }\n throw error;\n }\n}\n\ntype RefContractResolution =\n | {\n kind: 'snapshot';\n hash: string;\n contract: Contract;\n contractJson: unknown;\n contractDts: string;\n }\n | {\n kind: 'graph-node';\n hash: string;\n contract: Contract;\n contractJson: unknown;\n contractDts: string;\n sourceDir: string;\n };\n\nasync function resolveContractRef(\n parsed: ContractRef,\n member: ContractSpaceMember,\n options?: { readonly explicitLabel?: string; readonly artifactRole?: 'from' | 'to' },\n): Promise<Result<RefContractResolution, CliStructuredError>> {\n const { hash, provenance } = parsed;\n const refName = provenance.kind === 'ref' ? provenance.refName : undefined;\n\n try {\n const at = await member.contractAt(hash, refName !== undefined ? { refName } : undefined);\n\n if (at.provenance === 'snapshot') {\n return ok({\n kind: 'snapshot',\n hash: at.hash,\n contract: at.contract,\n contractJson: at.contractJson,\n contractDts: at.contractDts,\n });\n }\n\n return ok({\n kind: 'graph-node',\n hash: at.hash,\n contract: at.contract,\n contractJson: at.contractJson,\n contractDts: at.contractDts,\n sourceDir: at.sourceDir,\n });\n } catch (error) {\n return mapContractAtError(\n error,\n options?.artifactRole !== undefined ? { artifactRole: options.artifactRole } : undefined,\n );\n }\n}\n\nasync function resolveFromPolicy(\n parsed: ContractRef,\n input: ResolveFromForPlanInput,\n refs: Refs,\n explicitFromLabel?: string,\n): Promise<Result<FromResolution, CliStructuredError>> {\n const resolution = await resolveContractRef(parsed, input.member, {\n ...(explicitFromLabel !== undefined ? { explicitLabel: explicitFromLabel } : {}),\n artifactRole: 'from',\n });\n if (!resolution.ok) {\n return resolution;\n }\n\n if (resolution.value.kind === 'graph-node') {\n return ok({\n kind: 'graph-node',\n fromHash: resolution.value.hash,\n fromContract: resolution.value.contract,\n sourceDir: resolution.value.sourceDir,\n });\n }\n\n const { hash, contract, contractJson, contractDts } = resolution.value;\n if (graphIsEmpty(input.member)) {\n return ok({\n kind: 'auto-baseline',\n fromHash: hash,\n fromContract: contract,\n contractDts,\n contractJson,\n });\n }\n\n const graph = input.member.graph();\n const graphTip = findLatestMigration(graph)?.to ?? null;\n try {\n assertFromIsGraphNode(hash, graph, refs, graphTip);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n throw error;\n }\n return ok({\n kind: 'snapshot',\n fromHash: hash,\n fromContract: contract,\n contractDts,\n contractJson,\n });\n}\n\nexport async function resolveFromForPlan(\n input: ResolveFromForPlanInput,\n): Promise<Result<FromResolution, CliStructuredError>> {\n const { optionsFrom, member } = input;\n const graph = member.graph();\n const refs = member.refs;\n\n if (optionsFrom === undefined) {\n const dbRef = refs['db'];\n if (!dbRef) {\n return ok({ kind: 'greenfield', fromHash: null, fromContract: null });\n }\n return resolveFromPolicy(\n { hash: dbRef.hash, provenance: { kind: 'ref', refName: 'db' } },\n input,\n refs,\n );\n }\n\n const refResult = parseContractRef(optionsFrom, { graph, refs });\n if (!refResult.ok) {\n if (looksLikeFullHash(optionsFrom)) {\n const empty = graphIsEmpty(member);\n const graphTip = findLatestMigration(graph)?.to ?? null;\n if (empty) {\n return notOk(errorSnapshotMissing(optionsFrom, { viaRef: false }));\n }\n return notOk(errorPlanForgotTheFlag(optionsFrom, getReachableRefs(refs, graph), graphTip));\n }\n return notOk(mapRefResolutionError(refResult.failure));\n }\n\n return resolveFromPolicy(refResult.value, input, refs, optionsFrom);\n}\n\nexport interface ResolveToForPlanInput {\n readonly member: ContractSpaceMember;\n}\n\nexport interface ResolvedContractRef {\n readonly hash: string;\n readonly contract: Contract;\n readonly contractJson: unknown;\n readonly contractDts: string;\n}\n\nexport async function resolveToForPlan(\n optionsTo: string,\n input: ResolveToForPlanInput,\n): Promise<Result<ResolvedContractRef, CliStructuredError>> {\n const { member } = input;\n const graph = member.graph();\n const refs = member.refs;\n\n const refResult = parseContractRef(optionsTo, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n\n const resolution = await resolveContractRef(refResult.value, member, {\n explicitLabel: optionsTo,\n artifactRole: 'to',\n });\n if (!resolution.ok) {\n return resolution;\n }\n\n const { hash, contract, contractJson, contractDts } = resolution.value;\n return ok({ hash, contract, contractJson, contractDts });\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport {\n createControlStack,\n hasOperationPreview,\n type MigrationPlanOperation,\n type OperationPreview,\n} from '@prisma-next/framework-components/control';\nimport { canonicalizeJson } from '@prisma-next/framework-components/utils';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { computeMigrationHash } from '@prisma-next/migration-tools/hash';\nimport { deriveProvidedInvariants } from '@prisma-next/migration-tools/invariants';\nimport {\n copyFilesWithRename,\n formatMigrationDirName,\n writeMigrationPackage,\n} from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport { writeMigrationTs } from '@prisma-next/migration-tools/migration-ts';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join, relative } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliErrorConflict,\n CliStructuredError,\n errorContractValidationFailed,\n errorFileNotFound,\n errorMigrationPlanningFailed,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n getTargetMigrations,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport {\n buildContractSpaceAggregate,\n loadContractSpaceAggregateForCli,\n} from '../utils/contract-space-aggregate-loader';\nimport { runContractSpaceSeedPhase } from '../utils/contract-space-seed-phase';\nimport { toExtensionInputs } from '../utils/extension-pack-inputs';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport { assertFrameworkComponentsCompatible } from '../utils/framework-components';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { resolveFromForPlan, resolveToForPlan } from '../utils/plan-resolution';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationPlanOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly name?: string;\n readonly from?: string;\n readonly to?: string;\n}\n\nasync function writeSnapshotContractArtifacts(\n packageDir: string,\n contractJson: unknown,\n contractDts: string,\n artifactBasename: 'start-contract' | 'end-contract',\n): Promise<void> {\n await mkdir(packageDir, { recursive: true });\n const jsonContent = `${canonicalizeJson(contractJson)}\\n`;\n const dtsContent = contractDts.endsWith('\\n') ? contractDts : `${contractDts}\\n`;\n await writeFile(join(packageDir, `${artifactBasename}.json`), jsonContent);\n await writeFile(join(packageDir, `${artifactBasename}.d.ts`), dtsContent);\n}\n\nasync function writeSnapshotStartContract(\n packageDir: string,\n contractJson: unknown,\n contractDts: string,\n): Promise<void> {\n await writeSnapshotContractArtifacts(packageDir, contractJson, contractDts, 'start-contract');\n}\n\ntype PlannerSuccess = {\n readonly plannedOps: readonly MigrationPlanOperation[];\n readonly migrationTsContent: string;\n readonly hasPlaceholders: boolean;\n};\n\ntype TargetMigrationsApi = NonNullable<ReturnType<typeof getTargetMigrations>>;\n\nasync function runPlannerLeg(\n planner: ReturnType<TargetMigrationsApi['createPlanner']>,\n migrations: TargetMigrationsApi,\n frameworkComponents: ReturnType<typeof assertFrameworkComponentsCompatible>,\n contract: Contract,\n fromContract: Contract | null,\n spaceId: string,\n): Promise<Result<PlannerSuccess, CliStructuredError>> {\n const fromSchema = migrations.contractToSchema(fromContract, frameworkComponents);\n const plannerResult = planner.plan({\n contract,\n schema: fromSchema,\n policy: { allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'] },\n fromContract,\n frameworkComponents,\n spaceId,\n });\n if (plannerResult.kind === 'failure') {\n return notOk(\n errorMigrationPlanningFailed({\n conflicts: plannerResult.conflicts as readonly CliErrorConflict[],\n }),\n );\n }\n\n let plannedOps: readonly MigrationPlanOperation[] = [];\n let hasPlaceholders = false;\n try {\n plannedOps = await Promise.all(plannerResult.plan.operations);\n if (plannedOps.length === 0) {\n return notOk(\n errorMigrationPlanningFailed({\n conflicts: [\n {\n kind: 'unsupportedChange',\n summary:\n 'Contract changed but planner produced no operations. ' +\n 'This indicates unsupported or ignored changes.',\n },\n ],\n }),\n );\n }\n } catch (e) {\n if (CliStructuredError.is(e) && e.domain === 'MIG' && e.code === '2001') {\n hasPlaceholders = true;\n } else {\n throw e;\n }\n }\n\n return ok({\n plannedOps,\n migrationTsContent: plannerResult.plan.renderTypeScript(),\n hasPlaceholders,\n });\n}\n\nasync function writePlannedMigrationPackage(\n packageDir: string,\n fromHash: string | null,\n toHash: string,\n createdAt: Date,\n leg: PlannerSuccess,\n): Promise<void> {\n const opsForWrite = leg.hasPlaceholders ? [] : leg.plannedOps;\n const metadataWithInvariants: Omit<MigrationMetadata, 'migrationHash'> = {\n from: fromHash,\n to: toHash,\n providedInvariants: deriveProvidedInvariants(opsForWrite),\n createdAt: createdAt.toISOString(),\n };\n const metadata: MigrationMetadata = {\n ...metadataWithInvariants,\n migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite),\n };\n await writeMigrationPackage(packageDir, metadata, opsForWrite);\n await writeMigrationTs(packageDir, leg.migrationTsContent);\n}\n\nexport interface MigrationPlanResult {\n readonly ok: boolean;\n readonly noOp: boolean;\n readonly from: string | null;\n readonly to: string;\n readonly dir?: string;\n readonly baselineDir?: string;\n /**\n * Extension-space migration packages materialised onto disk during this\n * `plan` run. Each entry names a `migrations/<spaceId>/<dirName>/`\n * tree the framework wrote alongside the app-space migration directory.\n * Empty when the project has no extension packs declaring a contract\n * space, or when every extension-space package is already on disk.\n *\n * Surfacing these in the result (rather than only via `ui.step` log\n * lines) makes the cross-space side effect explicit to JSON consumers\n * and the success-summary renderer — the same cross-space side effect\n * that `migrate` will replay.\n */\n readonly emittedExtensionDirs: readonly { readonly spaceId: string; readonly dirName: string }[];\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n /**\n * Family-agnostic textual preview of the migration plan operations.\n * Replaces the previous `sql?: readonly string[]` field; consumers should\n * read `result.preview?.statements`.\n */\n readonly preview?: OperationPreview;\n readonly summary: string;\n /**\n * When true, `migration.ts` was written but contains unfilled\n * `placeholder(...)` calls. The user must edit the file and then run\n * `node migration.ts` to self-emit `ops.json` / `migration.json`.\n */\n readonly pendingPlaceholders?: boolean;\n readonly timings: {\n readonly total: number;\n };\n}\n\nasync function executeMigrationPlanCommand(\n options: MigrationPlanOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrationPlanResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative } =\n resolveMigrationPaths(options.config, config);\n\n const contractPathAbsolute = resolveContractPath(config);\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n { label: 'migrations', value: appMigrationsRelative },\n ];\n if (options.from) {\n details.push({ label: 'from', value: options.from });\n }\n if (options.to) {\n details.push({ label: 'to', value: options.to });\n }\n if (options.name) {\n details.push({ label: 'name', value: options.name });\n }\n const header = formatStyledHeader({\n command: 'migration plan',\n description: 'Plan a migration from contract changes',\n url: 'https://pris.ly/migration-plan',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n // Load contract file (the \"to\" contract)\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: `Run \\`prisma-next contract emit\\` to generate ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Construct the family instance up-front so on-disk contract reads cross the\n // serializer seam at the read site, not after the planner has already\n // started dispatching on raw shapes. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n const controlAdapter = config.adapter.create(stack);\n\n let toContract: Contract;\n try {\n toContract = familyInstance.deserializeContract(JSON.parse(contractJsonContent) as unknown);\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract at ${contractPathAbsolute} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n\n const rawStorageHash = toContract.storage?.storageHash;\n if (typeof rawStorageHash !== 'string') {\n return notOk(\n errorContractValidationFailed('Contract is missing storageHash', {\n where: { path: contractPathAbsolute },\n }),\n );\n }\n let toStorageHash: string = rawStorageHash;\n\n // When `--to <ref>` resolves a non-default destination, these carry its raw\n // artifacts so the planned package's `end-contract.*` is written from the\n // resolved target rather than copied from the emitted `contract.json`.\n let toArtifacts: { contractJson: unknown; contractDts: string } | null = null;\n\n let fromContract: Contract | null = null;\n let fromHash: string | null = null;\n let fromContractSourceDir: string | null = null;\n let snapshotStartContract: { contractJson: unknown; contractDts: string } | null = null;\n let isAutoBaseline = false;\n\n const tolerantAggregateResult = await loadContractSpaceAggregateForCli({\n targetId: config.target.targetId,\n migrationsDir,\n appContract: toContract,\n extensionPacks: config.extensionPacks ?? [],\n deserializeContract: (json: unknown) => familyInstance.deserializeContract(json),\n });\n if (!tolerantAggregateResult.ok) {\n return notOk(tolerantAggregateResult.failure);\n }\n const resolutionMember = tolerantAggregateResult.value.app;\n\n const resolutionResult = await resolveFromForPlan({\n optionsFrom: options.from,\n member: resolutionMember,\n });\n\n if (!resolutionResult.ok) {\n return notOk(resolutionResult.failure);\n }\n\n switch (resolutionResult.value.kind) {\n case 'greenfield':\n break;\n case 'graph-node':\n fromHash = resolutionResult.value.fromHash;\n fromContract = resolutionResult.value.fromContract;\n fromContractSourceDir = resolutionResult.value.sourceDir;\n break;\n case 'snapshot':\n fromHash = resolutionResult.value.fromHash;\n fromContract = resolutionResult.value.fromContract;\n snapshotStartContract = {\n contractJson: resolutionResult.value.contractJson,\n contractDts: resolutionResult.value.contractDts,\n };\n break;\n case 'auto-baseline':\n fromHash = resolutionResult.value.fromHash;\n fromContract = resolutionResult.value.fromContract;\n snapshotStartContract = {\n contractJson: resolutionResult.value.contractJson,\n contractDts: resolutionResult.value.contractDts,\n };\n isAutoBaseline = true;\n break;\n }\n\n // `--to <ref>` swaps the planner destination to an arbitrary resolved\n // contract (e.g. an ancestor / rollback target). The from-side resolution\n // above is untouched; only the destination + its emitted `end-contract.*`\n // change.\n if (options.to !== undefined) {\n const toResolution = await resolveToForPlan(options.to, {\n member: resolutionMember,\n });\n if (!toResolution.ok) {\n return notOk(toResolution.failure);\n }\n toContract = toResolution.value.contract;\n toStorageHash = toResolution.value.hash;\n toArtifacts = {\n contractJson: toResolution.value.contractJson,\n contractDts: toResolution.value.contractDts,\n };\n }\n\n // Phase 1 — seed: unconditionally re-emit per-space pinned artefacts\n // (contract.json / contract.d.ts / refs/head.json) and materialise any\n // descriptor-shipped migration packages not yet on disk. Runs before\n // the no-op check so that an extension bump alone (with no structural\n // app-space change) still re-pins extension artefacts on disk.\n const canonicalExtensionInputs = toExtensionInputs(config.extensionPacks ?? []);\n const seedResult = await runContractSpaceSeedPhase({\n migrationsDir,\n extensionPacks: canonicalExtensionInputs,\n });\n if (!flags.json && !flags.quiet) {\n for (const record of seedResult.seeded) {\n if (record.action === 'updated') {\n const pkgSuffix =\n record.newMigrationDirs.length > 0\n ? `; ${record.newMigrationDirs.length} new migration package(s) materialised`\n : '';\n ui.step(`Updated ${record.spaceId} to ${record.newHash}${pkgSuffix}`);\n }\n }\n }\n const emittedExtensionDirs = seedResult.seeded.flatMap((r) =>\n r.newMigrationDirs.map((dirName) => ({ spaceId: r.spaceId, dirName })),\n );\n\n // Check for no-op (same hash means no changes). Auto-baseline is exempt:\n // an empty graph with db ref at the current contract still needs a\n // null → fromHash baseline bundle so migrate can anchor the marker.\n if (fromHash === toStorageHash && !isAutoBaseline) {\n const result: MigrationPlanResult = {\n ok: true,\n noOp: true,\n from: fromHash,\n to: toStorageHash,\n operations: [],\n emittedExtensionDirs,\n summary: 'No changes detected between contracts',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n // Check target supports migrations\n const migrations = getTargetMigrations(config.target);\n if (!migrations) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n // Phase 2 — load: build the aggregate against the now-consistent disk\n // state that phase 1 just seeded. The seed phase guarantees every\n // declared extension has its head ref pinned, so the loader's\n // declaredButUnmigrated precheck always passes here. The app contract\n // was already routed through `familyInstance.deserializeContract` at the\n // read site above (see TML-2536), so it's the hydrated `Contract`\n // here — no second validation pass needed.\n const aggregateResult = await buildContractSpaceAggregate({\n targetId: config.target.targetId,\n migrationsDir,\n appContract: toContract,\n extensionPacks: config.extensionPacks ?? [],\n deserializeContract: (json: unknown) => familyInstance.deserializeContract(json),\n });\n if (!aggregateResult.ok) {\n return notOk(aggregateResult.failure);\n }\n const aggregate = aggregateResult.value;\n\n const frameworkComponents = assertFrameworkComponentsCompatible(\n config.family.familyId,\n config.target.targetId,\n [config.target, config.adapter, ...(config.extensionPacks ?? [])],\n );\n\n // Write the planned package's destination `end-contract.*`. With `--to`, the\n // resolved target's raw artifacts are written; otherwise the emitted\n // `contract.json` / `contract.d.ts` are copied verbatim (today's behaviour).\n async function writeDestinationEndContract(packageDir: string): Promise<void> {\n if (toArtifacts !== null) {\n await writeSnapshotContractArtifacts(\n packageDir,\n toArtifacts.contractJson,\n toArtifacts.contractDts,\n 'end-contract',\n );\n return;\n }\n const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);\n await copyFilesWithRename(packageDir, [\n { sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },\n { sourcePath: destinationArtifacts.dtsPath, destName: 'end-contract.d.ts' },\n ]);\n }\n\n try {\n const planner = migrations.createPlanner(controlAdapter);\n\n if (\n isAutoBaseline &&\n fromHash !== null &&\n fromContract !== null &&\n snapshotStartContract !== null\n ) {\n const baselineTimestamp = new Date();\n const deltaTimestamp = new Date(baselineTimestamp.getTime() + 60_000);\n const baselineDirName = formatMigrationDirName(baselineTimestamp, 'baseline');\n const deltaDirName = formatMigrationDirName(deltaTimestamp, options.name ?? 'migration');\n const baselinePackageDir = join(appMigrationsDir, baselineDirName);\n const deltaPackageDir = join(appMigrationsDir, deltaDirName);\n\n const baselineLeg = await runPlannerLeg(\n planner,\n migrations,\n frameworkComponents,\n fromContract,\n null,\n aggregate.app.spaceId,\n );\n if (!baselineLeg.ok) {\n return notOk(baselineLeg.failure);\n }\n\n await writePlannedMigrationPackage(\n baselinePackageDir,\n null,\n fromHash,\n baselineTimestamp,\n baselineLeg.value,\n );\n await writeSnapshotContractArtifacts(\n baselinePackageDir,\n snapshotStartContract.contractJson,\n snapshotStartContract.contractDts,\n 'end-contract',\n );\n\n if (fromHash === toStorageHash) {\n const baselineOps = baselineLeg.value.hasPlaceholders ? [] : baselineLeg.value.plannedOps;\n if (baselineLeg.value.hasPlaceholders) {\n const baselineDir = relative(process.cwd(), baselinePackageDir);\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: baselineDir,\n baselineDir,\n operations: [],\n emittedExtensionDirs,\n pendingPlaceholders: true,\n summary:\n 'Planned baseline with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const preview = hasOperationPreview(familyInstance)\n ? familyInstance.toOperationPreview(baselineOps)\n : undefined;\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n baselineDir: relative(process.cwd(), baselinePackageDir),\n operations: baselineOps.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n emittedExtensionDirs,\n ...(preview !== undefined ? { preview } : {}),\n summary: buildAutoBaselinePlanSummary(0, emittedExtensionDirs.length),\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const deltaLeg = await runPlannerLeg(\n planner,\n migrations,\n frameworkComponents,\n aggregate.app.contract(),\n fromContract,\n aggregate.app.spaceId,\n );\n if (!deltaLeg.ok) {\n return notOk(deltaLeg.failure);\n }\n\n await writePlannedMigrationPackage(\n deltaPackageDir,\n fromHash,\n toStorageHash,\n deltaTimestamp,\n deltaLeg.value,\n );\n await writeDestinationEndContract(deltaPackageDir);\n await writeSnapshotStartContract(\n deltaPackageDir,\n snapshotStartContract.contractJson,\n snapshotStartContract.contractDts,\n );\n\n const deltaOps = deltaLeg.value.hasPlaceholders ? [] : deltaLeg.value.plannedOps;\n if (deltaLeg.value.hasPlaceholders) {\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), deltaPackageDir),\n baselineDir: relative(process.cwd(), baselinePackageDir),\n operations: [],\n emittedExtensionDirs,\n pendingPlaceholders: true,\n summary:\n 'Planned baseline + migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const preview = hasOperationPreview(familyInstance)\n ? familyInstance.toOperationPreview(deltaOps)\n : undefined;\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), deltaPackageDir),\n baselineDir: relative(process.cwd(), baselinePackageDir),\n operations: deltaOps.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n emittedExtensionDirs,\n ...(preview !== undefined ? { preview } : {}),\n summary: buildAutoBaselinePlanSummary(deltaOps.length, emittedExtensionDirs.length),\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const timestamp = new Date();\n const slug = options.name ?? 'migration';\n const dirName = formatMigrationDirName(timestamp, slug);\n const packageDir = join(appMigrationsDir, dirName);\n\n const deltaLeg = await runPlannerLeg(\n planner,\n migrations,\n frameworkComponents,\n aggregate.app.contract(),\n fromContract,\n aggregate.app.spaceId,\n );\n if (!deltaLeg.ok) {\n return notOk(deltaLeg.failure);\n }\n\n await writePlannedMigrationPackage(\n packageDir,\n fromHash,\n toStorageHash,\n timestamp,\n deltaLeg.value,\n );\n await writeDestinationEndContract(packageDir);\n if (fromContractSourceDir !== null) {\n const sourceArtifacts = getEmittedArtifactPaths(\n join(fromContractSourceDir, 'end-contract.json'),\n );\n await copyFilesWithRename(packageDir, [\n { sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },\n { sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },\n ]);\n } else if (snapshotStartContract !== null) {\n await writeSnapshotStartContract(\n packageDir,\n snapshotStartContract.contractJson,\n snapshotStartContract.contractDts,\n );\n }\n\n if (deltaLeg.value.hasPlaceholders) {\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), packageDir),\n operations: [],\n emittedExtensionDirs,\n pendingPlaceholders: true,\n summary:\n 'Planned migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const plannedOps = deltaLeg.value.plannedOps;\n const preview = hasOperationPreview(familyInstance)\n ? familyInstance.toOperationPreview(plannedOps)\n : undefined;\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), packageDir),\n operations: plannedOps.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n emittedExtensionDirs,\n ...(preview !== undefined ? { preview } : {}),\n summary: buildPlanSummary(plannedOps.length, emittedExtensionDirs.length),\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n const message = error instanceof Error ? error.message : String(error);\n return notOk(\n errorUnexpected(message, {\n why: `Unexpected error during migration plan: ${message}`,\n }),\n );\n }\n}\n\nexport function createMigrationPlanCommand(): Command {\n const command = new Command('plan');\n setCommandDescriptions(\n command,\n 'Plan a migration from contract changes',\n 'Compares the emitted contract against the latest on-disk migration state and\\n' +\n 'produces a new migration package with the required operations. No database\\n' +\n 'connection is needed — this is a fully offline operation.',\n );\n setCommandExamples(command, [\n 'prisma-next migration plan',\n 'prisma-next migration plan --name add-users-table',\n 'prisma-next migration plan --to <migration-dir>^ --name rollback',\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--name <slug>', 'Name slug for the migration directory', 'migration')\n .option(\n '--from <contract>',\n 'Starting contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option(\n '--to <contract>',\n 'Destination contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path); defaults to the emitted contract',\n )\n .action(async (options: MigrationPlanOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const startTime = Date.now();\n\n const ui = createTerminalUI(flags);\n const result = await executeMigrationPlanCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (planResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(planResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationPlanOutput(planResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n\n/**\n * Compose the success-line summary so the cross-space side effect\n * (extension-space migration packages materialised on disk during\n * this `plan` run) is visible in the top line — not just in the\n * step log above it.\n *\n * Example outputs:\n * - `Planned 3 operation(s)` (app-space-only project)\n * - `Planned 3 operation(s); materialised 1 extension-space migration` (one extension)\n * - `Planned 3 operation(s); materialised 2 extension-space migrations` (two extensions)\n *\n * Locks AC3 at the summary-line level: a reader of the success line\n * can tell that something happened beyond the app space.\n */\nfunction buildPlanSummary(plannedOpsCount: number, emittedExtensionDirsCount: number): string {\n const base = `Planned ${plannedOpsCount} operation(s)`;\n if (emittedExtensionDirsCount === 0) return base;\n const noun =\n emittedExtensionDirsCount === 1 ? 'extension-space migration' : 'extension-space migrations';\n return `${base}; materialised ${emittedExtensionDirsCount} ${noun}`;\n}\n\nfunction buildAutoBaselinePlanSummary(\n deltaOpsCount: number,\n emittedExtensionDirsCount: number,\n): string {\n const base = `Planned baseline + ${deltaOpsCount} operation(s)`;\n if (emittedExtensionDirsCount === 0) return base;\n const noun =\n emittedExtensionDirsCount === 1 ? 'extension-space migration' : 'extension-space migrations';\n return `${base}; materialised ${emittedExtensionDirsCount} ${noun}`;\n}\n\nexport function formatMigrationPlanOutput(result: MigrationPlanResult, flags: GlobalFlags): string {\n const lines: string[] = [];\n const useColor = flags.color !== false;\n\n const green_ = useColor ? (s: string) => `\\x1b[32m${s}\\x1b[0m` : (s: string) => s;\n const yellow_ = useColor ? (s: string) => `\\x1b[33m${s}\\x1b[0m` : (s: string) => s;\n const dim_ = useColor ? (s: string) => `\\x1b[2m${s}\\x1b[0m` : (s: string) => s;\n\n // Renders the extension-space materialisation block + canonical apply-step\n // hint shared by the no-op, placeholder, and full-plan branches. The app\n // space short-circuits do not skip it: an extension-only bump emits new\n // `migrations/<spaceId>/<dirName>/` directories on disk that the user\n // still has to apply, so the success line must surface them.\n function appendEmittedExtensions(): void {\n if (result.emittedExtensionDirs.length === 0) return;\n lines.push('');\n lines.push(dim_('Emitted extension migrations:'));\n for (const entry of result.emittedExtensionDirs) {\n lines.push(dim_(` ${entry.spaceId} → migrations/${entry.spaceId}/${entry.dirName}`));\n }\n lines.push('');\n lines.push(\n `Next: review the extension migrations above, then run ${green_('prisma-next migrate')}.`,\n );\n }\n\n if (result.noOp) {\n lines.push(`${green_('✔')} No changes detected`);\n lines.push(dim_(` from: ${result.from}`));\n lines.push(dim_(` to: ${result.to}`));\n appendEmittedExtensions();\n return lines.join('\\n');\n }\n\n if (result.pendingPlaceholders) {\n lines.push(`${yellow_('⚠')} ${result.summary}`);\n lines.push('');\n lines.push(dim_(`from: ${result.from}`));\n lines.push(dim_(`to: ${result.to}`));\n if (result.dir) {\n lines.push(dim_(`dir: ${result.dir}`));\n }\n lines.push('');\n lines.push(\n 'Open migration.ts and replace each `placeholder(...)` call with your actual query.',\n );\n lines.push(`Then run: ${green_(`node ${result.dir ?? '<dir>'}/migration.ts`)}`);\n appendEmittedExtensions();\n return lines.join('\\n');\n }\n\n lines.push(`${green_('✔')} ${result.summary}`);\n lines.push('');\n\n if (result.operations.length > 0) {\n lines.push(dim_('│'));\n for (let i = 0; i < result.operations.length; i++) {\n const op = result.operations[i]!;\n const isLast = i === result.operations.length - 1;\n const treeChar = isLast ? '└' : '├';\n // operationClass tag is intentionally NOT inlined per spec:\n // a destructive footer warning still surfaces below this list.\n const destructiveMarker =\n op.operationClass === 'destructive' ? ` ${yellow_('(destructive)')}` : '';\n lines.push(`${dim_(treeChar)}─ ${op.label}${destructiveMarker}`);\n }\n\n const hasDestructive = result.operations.some((op) => op.operationClass === 'destructive');\n if (hasDestructive) {\n lines.push('');\n lines.push(\n `${yellow_('⚠')} This migration contains destructive operations that may cause data loss.`,\n );\n }\n lines.push('');\n }\n\n lines.push(dim_(`from: ${result.from}`));\n lines.push(dim_(`to: ${result.to}`));\n if (result.baselineDir) {\n lines.push(dim_(`Baseline → ${result.baselineDir}`));\n }\n if (result.dir) {\n lines.push(dim_(`App space → ${result.dir}`));\n }\n // Per-space block: surface the extension-space directories materialised\n // alongside the app-space migration. Without this block the cross-space\n // side effect is invisible in the success summary (e2e finding F1).\n for (const entry of result.emittedExtensionDirs) {\n lines.push(\n dim_(`Extension space ${entry.spaceId} → migrations/${entry.spaceId}/${entry.dirName}`),\n );\n }\n\n lines.push('');\n // The \"Next:\" hint always points at the canonical apply path\n // (`prisma-next migrate`) regardless of how many spaces were\n // materialised — `db update` is a dev-time convenience, not the\n // canonical replay step.\n const reviewTarget =\n result.baselineDir !== undefined && result.dir !== undefined\n ? `${result.baselineDir} and ${result.dir}`\n : (result.baselineDir ?? result.dir ?? '<dir>');\n lines.push(\n `Next: review ${green_(reviewTarget)} if needed, then run ${green_('prisma-next migrate')}.`,\n );\n\n if (result.preview && result.preview.statements.length > 0) {\n // The non-empty length is already guaranteed by the surrounding check, so\n // a plain `every` here is equivalent to the helper in formatters/migrations.ts.\n const allSql = result.preview.statements.every((s) => s.language === 'sql');\n lines.push('');\n lines.push(dim_(allSql ? 'DDL preview' : 'Operation preview'));\n lines.push('');\n for (const statement of result.preview.statements) {\n const trimmed = statement.text.trim();\n if (!trimmed) continue;\n const line = statement.language === 'sql' && !trimmed.endsWith(';') ? `${trimmed};` : trimmed;\n lines.push(line);\n }\n }\n\n if (flags.verbose && result.timings) {\n lines.push('');\n lines.push(dim_(`Total time: ${result.timings.total}ms`));\n }\n\n return lines.join('\\n');\n}\n\nexport type PrefixResolutionFailure =\n | { reason: 'ambiguous'; count: number }\n | { reason: 'not-found' };\n\n/**\n * Resolve a migration package by **target contract hash** (`metadata.to`)\n * using exact match or prefix match.\n *\n * Note: matches `metadata.to` (the contract hash this migration produces),\n * not `metadata.migrationHash` (the package's content-addressed identity).\n * Tries exact match first, then prefix match (auto-prepending `sha256:` when\n * the needle omits the scheme). Returns the matched package on success, or a\n * discriminated failure indicating whether the prefix was ambiguous or simply\n * not found.\n *\n * @internal Exported for testing only.\n */\nexport function resolveBundleByPrefix<T extends { metadata: { to: string } }>(\n bundles: readonly T[],\n needle: string,\n): Result<T, PrefixResolutionFailure> {\n const exact = bundles.find((p) => p.metadata.to === needle);\n if (exact) return ok(exact);\n\n const prefixWithScheme = needle.startsWith('sha256:') ? needle : `sha256:${needle}`;\n const candidates = bundles.filter((p) => p.metadata.to.startsWith(prefixWithScheme));\n\n if (candidates.length === 1) return ok(candidates[0]!);\n if (candidates.length > 1) return notOk({ reason: 'ambiguous', count: candidates.length });\n return notOk({ reason: 'not-found' });\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0-dev.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@clack/prompts": "^1.4.0",
|
|
12
|
-
"@prisma-next/config": "0.
|
|
13
|
-
"@prisma-next/contract": "0.
|
|
14
|
-
"@prisma-next/emitter": "0.
|
|
15
|
-
"@prisma-next/errors": "0.
|
|
16
|
-
"@prisma-next/framework-components": "0.
|
|
17
|
-
"@prisma-next/migration-tools": "0.
|
|
18
|
-
"@prisma-next/psl-printer": "0.
|
|
19
|
-
"@prisma-next/cli-telemetry": "0.
|
|
20
|
-
"@prisma-next/utils": "0.
|
|
12
|
+
"@prisma-next/config": "0.14.0-dev.2",
|
|
13
|
+
"@prisma-next/contract": "0.14.0-dev.2",
|
|
14
|
+
"@prisma-next/emitter": "0.14.0-dev.2",
|
|
15
|
+
"@prisma-next/errors": "0.14.0-dev.2",
|
|
16
|
+
"@prisma-next/framework-components": "0.14.0-dev.2",
|
|
17
|
+
"@prisma-next/migration-tools": "0.14.0-dev.2",
|
|
18
|
+
"@prisma-next/psl-printer": "0.14.0-dev.2",
|
|
19
|
+
"@prisma-next/cli-telemetry": "0.14.0-dev.2",
|
|
20
|
+
"@prisma-next/utils": "0.14.0-dev.2",
|
|
21
21
|
"arktype": "^2.2.0",
|
|
22
22
|
"c12": "^3.3.4",
|
|
23
23
|
"ci-info": "^4.3.1",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"wrap-ansi": "^10.0.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@prisma-next/sql-contract": "0.
|
|
38
|
-
"@prisma-next/sql-contract-emitter": "0.
|
|
39
|
-
"@prisma-next/sql-contract-ts": "0.
|
|
40
|
-
"@prisma-next/sql-operations": "0.
|
|
41
|
-
"@prisma-next/sql-runtime": "0.
|
|
42
|
-
"@prisma-next/test-utils": "0.
|
|
43
|
-
"@prisma-next/tsconfig": "0.
|
|
44
|
-
"@prisma-next/tsdown": "0.
|
|
37
|
+
"@prisma-next/sql-contract": "0.14.0-dev.2",
|
|
38
|
+
"@prisma-next/sql-contract-emitter": "0.14.0-dev.2",
|
|
39
|
+
"@prisma-next/sql-contract-ts": "0.14.0-dev.2",
|
|
40
|
+
"@prisma-next/sql-operations": "0.14.0-dev.2",
|
|
41
|
+
"@prisma-next/sql-runtime": "0.14.0-dev.2",
|
|
42
|
+
"@prisma-next/test-utils": "0.14.0-dev.2",
|
|
43
|
+
"@prisma-next/tsconfig": "0.14.0-dev.2",
|
|
44
|
+
"@prisma-next/tsdown": "0.14.0-dev.2",
|
|
45
45
|
"@types/node": "25.9.1",
|
|
46
46
|
"tsdown": "0.22.1",
|
|
47
47
|
"typescript": "5.9.3",
|
|
@@ -74,7 +74,7 @@ export const contract = defineContract(
|
|
|
74
74
|
models: {
|
|
75
75
|
User: model('User', {
|
|
76
76
|
fields: {
|
|
77
|
-
id: field.id.
|
|
77
|
+
id: field.id.uuidv7String(),
|
|
78
78
|
email: field.text().unique(),
|
|
79
79
|
username: field.text().optional(),
|
|
80
80
|
name: field.text().optional(),
|
|
@@ -166,7 +166,7 @@ export const contract = defineContract(
|
|
|
166
166
|
models: {
|
|
167
167
|
User: model('User', {
|
|
168
168
|
fields: {
|
|
169
|
-
id: field.id.
|
|
169
|
+
id: field.id.uuidv7String(),
|
|
170
170
|
email: field.text().unique(),
|
|
171
171
|
username: field.text().optional(),
|
|
172
172
|
name: field.text().optional(),
|
|
@@ -180,10 +180,10 @@ export const contract = defineContract(
|
|
|
180
180
|
|
|
181
181
|
Post: model('Post', {
|
|
182
182
|
fields: {
|
|
183
|
-
id: field.id.
|
|
183
|
+
id: field.id.uuidv7String(),
|
|
184
184
|
title: field.text(),
|
|
185
185
|
content: field.text().optional(),
|
|
186
|
-
authorId: field.
|
|
186
|
+
authorId: field.uuidString(),
|
|
187
187
|
createdAt: field.temporal.createdAt(),
|
|
188
188
|
updatedAt: field.temporal.updatedAt(),
|
|
189
189
|
},
|
|
@@ -118,7 +118,7 @@ async function runPlannerLeg(
|
|
|
118
118
|
let plannedOps: readonly MigrationPlanOperation[] = [];
|
|
119
119
|
let hasPlaceholders = false;
|
|
120
120
|
try {
|
|
121
|
-
plannedOps = plannerResult.plan.operations;
|
|
121
|
+
plannedOps = await Promise.all(plannerResult.plan.operations);
|
|
122
122
|
if (plannedOps.length === 0) {
|
|
123
123
|
return notOk(
|
|
124
124
|
errorMigrationPlanningFailed({
|
package/src/migration-cli.ts
CHANGED
|
@@ -505,15 +505,15 @@ function readExistingMetadata(metadataPath: string): Partial<MigrationMetadata>
|
|
|
505
505
|
* legitimate site for combining config loading, stack assembly, and
|
|
506
506
|
* filesystem persistence.
|
|
507
507
|
*/
|
|
508
|
-
function serializeMigrationToDisk(
|
|
508
|
+
async function serializeMigrationToDisk(
|
|
509
509
|
instance: Migration,
|
|
510
510
|
migrationDir: string,
|
|
511
511
|
dryRun: boolean,
|
|
512
512
|
stdout: MigrationCliWritable,
|
|
513
|
-
): void {
|
|
513
|
+
): Promise<void> {
|
|
514
514
|
const metadataPath = join(migrationDir, 'migration.json');
|
|
515
515
|
const existing = readExistingMetadata(metadataPath);
|
|
516
|
-
const { opsJson, metadataJson } = buildMigrationArtifacts(instance, existing);
|
|
516
|
+
const { opsJson, metadataJson } = await buildMigrationArtifacts(instance, existing);
|
|
517
517
|
|
|
518
518
|
if (dryRun) {
|
|
519
519
|
stdout.write(`--- migration.json ---\n${metadataJson}\n`);
|
|
@@ -572,6 +572,6 @@ async function runMigration(
|
|
|
572
572
|
const stack = createControlStack(config);
|
|
573
573
|
const instance = new MigrationClass(stack);
|
|
574
574
|
|
|
575
|
-
serializeMigrationToDisk(instance, migrationDir, parsed.dryRun, ctx.stdout);
|
|
575
|
+
await serializeMigrationToDisk(instance, migrationDir, parsed.dryRun, ctx.stdout);
|
|
576
576
|
void ctx.stderr;
|
|
577
577
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"migration-plan-z5Ing-TD.mjs","names":[],"sources":["../src/utils/contract-space-seed-phase.ts","../src/utils/plan-resolution.ts","../src/commands/migration-plan.ts"],"sourcesContent":["import { materialiseExtensionMigrationPackageIfMissing } from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport type { MigrationOps } from '@prisma-next/migration-tools/package';\nimport {\n emitContractSpaceArtefacts,\n planAllSpaces,\n readContractSpaceHeadRef,\n type SpacePlanOutput,\n spaceMigrationDirectory,\n} from '@prisma-next/migration-tools/spaces';\n\n/**\n * In-memory authored migration package shipped by an extension descriptor.\n * Mirrors `MigrationPackage` from `@prisma-next/migration-tools/io` (the\n * on-disk shape minus `dirPath`); redeclared structurally here so the\n * CLI helper does not couple to any family's `ExtensionMigrationPackage`\n * type — any family that ships pre-built migration packages can pass\n * them through unchanged.\n */\nexport interface DescriptorMigrationPackage {\n readonly dirName: string;\n readonly metadata: MigrationMetadata;\n readonly ops: MigrationOps;\n}\n\n/**\n * Minimal descriptor view consumed by the seed phase. Mirrors the shape\n * the SQL family ships on each declared extension entry; only the fields\n * the seed phase needs are surfaced.\n */\nexport interface SeedPhaseExtensionInput {\n readonly id: string;\n readonly contractSpace?: {\n readonly contractJson: unknown;\n readonly headRef: { readonly hash: string; readonly invariants: readonly string[] };\n readonly migrations: readonly DescriptorMigrationPackage[];\n };\n}\n\nexport interface ContractSpaceSeedPhaseInputs {\n readonly migrationsDir: string;\n readonly extensionPacks: ReadonlyArray<SeedPhaseExtensionInput>;\n}\n\n/**\n * One per-space record describing what the seed phase did for an\n * extension contract space. Surfaced verbatim by the caller (typically\n * `migration plan`) so users see a single line per touched extension.\n *\n * - `action: 'updated'` — either the on-disk head pointer changed, or\n * one or more new descriptor-shipped migration packages were\n * materialised into `migrations/<spaceId>/<dirName>/`.\n * - `action: 'unchanged'` — the on-disk head already matched the\n * descriptor and no new migration packages needed to be written.\n *\n * Either way, the artefacts (`contract.json`, `contract.d.ts`,\n * `refs/head.json`) are re-emitted: the framework owns those files and\n * makes the re-emit observably idempotent at the byte level.\n */\nexport interface ContractSpaceSeedPhaseRecord {\n readonly spaceId: string;\n readonly action: 'updated' | 'unchanged';\n readonly priorHash: string | null;\n readonly newHash: string;\n readonly newMigrationDirs: readonly string[];\n}\n\nexport interface ContractSpaceSeedPhaseResult {\n readonly seeded: readonly ContractSpaceSeedPhaseRecord[];\n}\n\n/**\n * Phase-1 of the two-phase `migration plan` pipeline (sub-spec § 4).\n *\n * For every extension that exposes a `contractSpace`:\n *\n * 1. Read the on-disk head ref (returns `null` on first emit).\n * 2. Re-emit `contract.json` / `contract.d.ts` / `refs/head.json`\n * unconditionally via {@link emitContractSpaceArtefacts}. The\n * framework owns these files; re-emit is the contract.\n * 3. Materialise any descriptor-shipped migration packages not yet on\n * disk via {@link materialiseExtensionMigrationPackageIfMissing}.\n * Existing packages are left untouched (by-existence skip).\n *\n * The return value lets the caller render a per-space status line and\n * lets the phase-2 aggregate loader run on a now-consistent disk state\n * (every loaded extension is guaranteed to have its head ref pinned\n * to the descriptor's hash and to ship every package the descriptor\n * declares).\n *\n * Output ordering is deterministic and alphabetical by spaceId (via\n * {@link planAllSpaces}, which also detects duplicate spaceIds). This\n * matches the canonical sort order used by every other aggregate\n * surface (`migrate`, `migration status`, the runner).\n */\nexport async function runContractSpaceSeedPhase(\n inputs: ContractSpaceSeedPhaseInputs,\n): Promise<ContractSpaceSeedPhaseResult> {\n const planInputs = inputs.extensionPacks\n .filter(\n (\n pack,\n ): pack is SeedPhaseExtensionInput & {\n contractSpace: NonNullable<SeedPhaseExtensionInput['contractSpace']>;\n } => pack.contractSpace !== undefined,\n )\n .map((pack) => ({\n spaceId: pack.id,\n priorContract: null,\n newContract: pack.contractSpace.contractJson,\n __pack: pack.contractSpace,\n }));\n\n // `planAllSpaces` brings deterministic alphabetical ordering and\n // duplicate-spaceId detection. The \"planner\" callback is a no-op\n // pass-through that simply returns the descriptor's pre-built\n // migration packages.\n const planned: readonly SpacePlanOutput<DescriptorMigrationPackage>[] = planAllSpaces(\n planInputs,\n (input) =>\n (\n input as typeof input & {\n readonly __pack: NonNullable<SeedPhaseExtensionInput['contractSpace']>;\n }\n ).__pack.migrations,\n );\n\n // Reassemble a spaceId → descriptor lookup so the loop below can read\n // the contractJson / headRef without leaking the typed-cast back into\n // `planAllSpaces`'s output shape.\n const descriptorBySpace = new Map<\n string,\n NonNullable<SeedPhaseExtensionInput['contractSpace']>\n >();\n for (const pack of inputs.extensionPacks) {\n if (pack.contractSpace !== undefined) descriptorBySpace.set(pack.id, pack.contractSpace);\n }\n\n const seeded: ContractSpaceSeedPhaseRecord[] = [];\n for (const space of planned) {\n const descriptor = descriptorBySpace.get(space.spaceId);\n if (descriptor === undefined) continue;\n\n const onDiskHeadRef = await readContractSpaceHeadRef(inputs.migrationsDir, space.spaceId);\n const priorHash = onDiskHeadRef?.hash ?? null;\n\n await emitContractSpaceArtefacts(inputs.migrationsDir, space.spaceId, {\n contract: descriptor.contractJson,\n contractDts: buildPlaceholderContractDts(space.spaceId),\n headRef: { hash: descriptor.headRef.hash, invariants: descriptor.headRef.invariants },\n });\n\n const spaceDir = spaceMigrationDirectory(inputs.migrationsDir, space.spaceId);\n const newMigrationDirs: string[] = [];\n for (const pkg of space.migrationPackages) {\n const { written } = await materialiseExtensionMigrationPackageIfMissing(spaceDir, pkg);\n if (written) newMigrationDirs.push(pkg.dirName);\n }\n\n const action: ContractSpaceSeedPhaseRecord['action'] =\n priorHash !== descriptor.headRef.hash || newMigrationDirs.length > 0\n ? 'updated'\n : 'unchanged';\n\n seeded.push({\n spaceId: space.spaceId,\n action,\n priorHash,\n newHash: descriptor.headRef.hash,\n newMigrationDirs,\n });\n }\n\n return { seeded };\n}\n\n/**\n * Placeholder `.d.ts` content for an extension space's on-disk mirror.\n *\n * Rendering a fully-typed `.d.ts` for an extension contract requires\n * the SQL-family renderer with the codec / typemap registry threaded\n * through; until that integration ships, the on-disk `.d.ts` is a\n * stub `export {};` module that documents how consumers should\n * validate the sibling `contract.json`. The stub typechecks on its\n * own and does not need any TypeScript suppressions.\n */\nfunction buildPlaceholderContractDts(spaceId: string): string {\n return [\n '/**',\n ` * Placeholder \\`.d.ts\\` for extension space \"${spaceId}\".`,\n ' *',\n ' * The framework re-emits this file on every `migration plan` run',\n ' * alongside `contract.json` and `refs/head.json`. A typed `.d.ts`',\n ' * rendering pass for extension contracts is tracked separately;',\n ' * until that ships, consumers should import `contract.json`',\n ' * and pass it through the target descriptor’s `contractSerializer`.',\n ' */',\n 'export {};',\n '',\n ].join('\\n');\n}\n","import type { Contract } from '@prisma-next/contract/types';\nimport type { ContractSpaceMember } from '@prisma-next/migration-tools/aggregate';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport {\n assertHashIsGraphNode,\n findLatestMigration,\n isGraphNode,\n} from '@prisma-next/migration-tools/migration-graph';\nimport type { ContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { Refs } from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport {\n CliStructuredError,\n errorPlanForgotTheFlag,\n errorSnapshotMissing,\n mapRefResolutionError,\n} from './cli-errors';\nimport { mapContractAtError } from './contract-at-errors';\n\nconst FULL_HASH_PATTERN = /^sha256:([0-9a-f]{64}|empty)$/;\n\nexport function looksLikeFullHash(input: string): boolean {\n return FULL_HASH_PATTERN.test(input);\n}\n\nexport type FromResolution =\n | { kind: 'greenfield'; fromHash: null; fromContract: null }\n | { kind: 'graph-node'; fromHash: string; fromContract: Contract; sourceDir: string }\n | {\n kind: 'snapshot';\n fromHash: string;\n fromContract: Contract;\n contractDts: string;\n contractJson: unknown;\n }\n | {\n kind: 'auto-baseline';\n fromHash: string;\n fromContract: Contract;\n contractDts: string;\n contractJson: unknown;\n };\n\nexport interface ResolveFromForPlanInput {\n readonly optionsFrom?: string | undefined;\n readonly member: ContractSpaceMember;\n}\n\nfunction graphIsEmpty(member: ContractSpaceMember): boolean {\n return member.packages.length === 0;\n}\n\nfunction getReachableRefs(\n refs: Refs,\n graph: MigrationGraph,\n): ReadonlyArray<{ name: string; hash: string }> {\n return Object.entries(refs)\n .flatMap(([name, entry]) =>\n entry && isGraphNode(entry.hash, graph) ? [{ name, hash: entry.hash }] : [],\n )\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\nexport function assertFromIsGraphNode(\n fromHash: string,\n graph: MigrationGraph,\n refs: Refs,\n graphTipHash: string | null,\n): void {\n try {\n assertHashIsGraphNode(fromHash, graph);\n } catch (error) {\n if (MigrationToolsError.is(error) && error.code === 'MIGRATION.HASH_NOT_IN_GRAPH') {\n throw errorPlanForgotTheFlag(fromHash, getReachableRefs(refs, graph), graphTipHash);\n }\n throw error;\n }\n}\n\ntype RefContractResolution =\n | {\n kind: 'snapshot';\n hash: string;\n contract: Contract;\n contractJson: unknown;\n contractDts: string;\n }\n | {\n kind: 'graph-node';\n hash: string;\n contract: Contract;\n contractJson: unknown;\n contractDts: string;\n sourceDir: string;\n };\n\nasync function resolveContractRef(\n parsed: ContractRef,\n member: ContractSpaceMember,\n options?: { readonly explicitLabel?: string; readonly artifactRole?: 'from' | 'to' },\n): Promise<Result<RefContractResolution, CliStructuredError>> {\n const { hash, provenance } = parsed;\n const refName = provenance.kind === 'ref' ? provenance.refName : undefined;\n\n try {\n const at = await member.contractAt(hash, refName !== undefined ? { refName } : undefined);\n\n if (at.provenance === 'snapshot') {\n return ok({\n kind: 'snapshot',\n hash: at.hash,\n contract: at.contract,\n contractJson: at.contractJson,\n contractDts: at.contractDts,\n });\n }\n\n return ok({\n kind: 'graph-node',\n hash: at.hash,\n contract: at.contract,\n contractJson: at.contractJson,\n contractDts: at.contractDts,\n sourceDir: at.sourceDir,\n });\n } catch (error) {\n return mapContractAtError(\n error,\n options?.artifactRole !== undefined ? { artifactRole: options.artifactRole } : undefined,\n );\n }\n}\n\nasync function resolveFromPolicy(\n parsed: ContractRef,\n input: ResolveFromForPlanInput,\n refs: Refs,\n explicitFromLabel?: string,\n): Promise<Result<FromResolution, CliStructuredError>> {\n const resolution = await resolveContractRef(parsed, input.member, {\n ...(explicitFromLabel !== undefined ? { explicitLabel: explicitFromLabel } : {}),\n artifactRole: 'from',\n });\n if (!resolution.ok) {\n return resolution;\n }\n\n if (resolution.value.kind === 'graph-node') {\n return ok({\n kind: 'graph-node',\n fromHash: resolution.value.hash,\n fromContract: resolution.value.contract,\n sourceDir: resolution.value.sourceDir,\n });\n }\n\n const { hash, contract, contractJson, contractDts } = resolution.value;\n if (graphIsEmpty(input.member)) {\n return ok({\n kind: 'auto-baseline',\n fromHash: hash,\n fromContract: contract,\n contractDts,\n contractJson,\n });\n }\n\n const graph = input.member.graph();\n const graphTip = findLatestMigration(graph)?.to ?? null;\n try {\n assertFromIsGraphNode(hash, graph, refs, graphTip);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n throw error;\n }\n return ok({\n kind: 'snapshot',\n fromHash: hash,\n fromContract: contract,\n contractDts,\n contractJson,\n });\n}\n\nexport async function resolveFromForPlan(\n input: ResolveFromForPlanInput,\n): Promise<Result<FromResolution, CliStructuredError>> {\n const { optionsFrom, member } = input;\n const graph = member.graph();\n const refs = member.refs;\n\n if (optionsFrom === undefined) {\n const dbRef = refs['db'];\n if (!dbRef) {\n return ok({ kind: 'greenfield', fromHash: null, fromContract: null });\n }\n return resolveFromPolicy(\n { hash: dbRef.hash, provenance: { kind: 'ref', refName: 'db' } },\n input,\n refs,\n );\n }\n\n const refResult = parseContractRef(optionsFrom, { graph, refs });\n if (!refResult.ok) {\n if (looksLikeFullHash(optionsFrom)) {\n const empty = graphIsEmpty(member);\n const graphTip = findLatestMigration(graph)?.to ?? null;\n if (empty) {\n return notOk(errorSnapshotMissing(optionsFrom, { viaRef: false }));\n }\n return notOk(errorPlanForgotTheFlag(optionsFrom, getReachableRefs(refs, graph), graphTip));\n }\n return notOk(mapRefResolutionError(refResult.failure));\n }\n\n return resolveFromPolicy(refResult.value, input, refs, optionsFrom);\n}\n\nexport interface ResolveToForPlanInput {\n readonly member: ContractSpaceMember;\n}\n\nexport interface ResolvedContractRef {\n readonly hash: string;\n readonly contract: Contract;\n readonly contractJson: unknown;\n readonly contractDts: string;\n}\n\nexport async function resolveToForPlan(\n optionsTo: string,\n input: ResolveToForPlanInput,\n): Promise<Result<ResolvedContractRef, CliStructuredError>> {\n const { member } = input;\n const graph = member.graph();\n const refs = member.refs;\n\n const refResult = parseContractRef(optionsTo, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n\n const resolution = await resolveContractRef(refResult.value, member, {\n explicitLabel: optionsTo,\n artifactRole: 'to',\n });\n if (!resolution.ok) {\n return resolution;\n }\n\n const { hash, contract, contractJson, contractDts } = resolution.value;\n return ok({ hash, contract, contractJson, contractDts });\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport {\n createControlStack,\n hasOperationPreview,\n type MigrationPlanOperation,\n type OperationPreview,\n} from '@prisma-next/framework-components/control';\nimport { canonicalizeJson } from '@prisma-next/framework-components/utils';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { computeMigrationHash } from '@prisma-next/migration-tools/hash';\nimport { deriveProvidedInvariants } from '@prisma-next/migration-tools/invariants';\nimport {\n copyFilesWithRename,\n formatMigrationDirName,\n writeMigrationPackage,\n} from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport { writeMigrationTs } from '@prisma-next/migration-tools/migration-ts';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join, relative } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliErrorConflict,\n CliStructuredError,\n errorContractValidationFailed,\n errorFileNotFound,\n errorMigrationPlanningFailed,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n getTargetMigrations,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport {\n buildContractSpaceAggregate,\n loadContractSpaceAggregateForCli,\n} from '../utils/contract-space-aggregate-loader';\nimport { runContractSpaceSeedPhase } from '../utils/contract-space-seed-phase';\nimport { toExtensionInputs } from '../utils/extension-pack-inputs';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport { assertFrameworkComponentsCompatible } from '../utils/framework-components';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { resolveFromForPlan, resolveToForPlan } from '../utils/plan-resolution';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationPlanOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly name?: string;\n readonly from?: string;\n readonly to?: string;\n}\n\nasync function writeSnapshotContractArtifacts(\n packageDir: string,\n contractJson: unknown,\n contractDts: string,\n artifactBasename: 'start-contract' | 'end-contract',\n): Promise<void> {\n await mkdir(packageDir, { recursive: true });\n const jsonContent = `${canonicalizeJson(contractJson)}\\n`;\n const dtsContent = contractDts.endsWith('\\n') ? contractDts : `${contractDts}\\n`;\n await writeFile(join(packageDir, `${artifactBasename}.json`), jsonContent);\n await writeFile(join(packageDir, `${artifactBasename}.d.ts`), dtsContent);\n}\n\nasync function writeSnapshotStartContract(\n packageDir: string,\n contractJson: unknown,\n contractDts: string,\n): Promise<void> {\n await writeSnapshotContractArtifacts(packageDir, contractJson, contractDts, 'start-contract');\n}\n\ntype PlannerSuccess = {\n readonly plannedOps: readonly MigrationPlanOperation[];\n readonly migrationTsContent: string;\n readonly hasPlaceholders: boolean;\n};\n\ntype TargetMigrationsApi = NonNullable<ReturnType<typeof getTargetMigrations>>;\n\nasync function runPlannerLeg(\n planner: ReturnType<TargetMigrationsApi['createPlanner']>,\n migrations: TargetMigrationsApi,\n frameworkComponents: ReturnType<typeof assertFrameworkComponentsCompatible>,\n contract: Contract,\n fromContract: Contract | null,\n spaceId: string,\n): Promise<Result<PlannerSuccess, CliStructuredError>> {\n const fromSchema = migrations.contractToSchema(fromContract, frameworkComponents);\n const plannerResult = planner.plan({\n contract,\n schema: fromSchema,\n policy: { allowedOperationClasses: ['additive', 'widening', 'destructive', 'data'] },\n fromContract,\n frameworkComponents,\n spaceId,\n });\n if (plannerResult.kind === 'failure') {\n return notOk(\n errorMigrationPlanningFailed({\n conflicts: plannerResult.conflicts as readonly CliErrorConflict[],\n }),\n );\n }\n\n let plannedOps: readonly MigrationPlanOperation[] = [];\n let hasPlaceholders = false;\n try {\n plannedOps = plannerResult.plan.operations;\n if (plannedOps.length === 0) {\n return notOk(\n errorMigrationPlanningFailed({\n conflicts: [\n {\n kind: 'unsupportedChange',\n summary:\n 'Contract changed but planner produced no operations. ' +\n 'This indicates unsupported or ignored changes.',\n },\n ],\n }),\n );\n }\n } catch (e) {\n if (CliStructuredError.is(e) && e.domain === 'MIG' && e.code === '2001') {\n hasPlaceholders = true;\n } else {\n throw e;\n }\n }\n\n return ok({\n plannedOps,\n migrationTsContent: plannerResult.plan.renderTypeScript(),\n hasPlaceholders,\n });\n}\n\nasync function writePlannedMigrationPackage(\n packageDir: string,\n fromHash: string | null,\n toHash: string,\n createdAt: Date,\n leg: PlannerSuccess,\n): Promise<void> {\n const opsForWrite = leg.hasPlaceholders ? [] : leg.plannedOps;\n const metadataWithInvariants: Omit<MigrationMetadata, 'migrationHash'> = {\n from: fromHash,\n to: toHash,\n providedInvariants: deriveProvidedInvariants(opsForWrite),\n createdAt: createdAt.toISOString(),\n };\n const metadata: MigrationMetadata = {\n ...metadataWithInvariants,\n migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite),\n };\n await writeMigrationPackage(packageDir, metadata, opsForWrite);\n await writeMigrationTs(packageDir, leg.migrationTsContent);\n}\n\nexport interface MigrationPlanResult {\n readonly ok: boolean;\n readonly noOp: boolean;\n readonly from: string | null;\n readonly to: string;\n readonly dir?: string;\n readonly baselineDir?: string;\n /**\n * Extension-space migration packages materialised onto disk during this\n * `plan` run. Each entry names a `migrations/<spaceId>/<dirName>/`\n * tree the framework wrote alongside the app-space migration directory.\n * Empty when the project has no extension packs declaring a contract\n * space, or when every extension-space package is already on disk.\n *\n * Surfacing these in the result (rather than only via `ui.step` log\n * lines) makes the cross-space side effect explicit to JSON consumers\n * and the success-summary renderer — the same cross-space side effect\n * that `migrate` will replay.\n */\n readonly emittedExtensionDirs: readonly { readonly spaceId: string; readonly dirName: string }[];\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n /**\n * Family-agnostic textual preview of the migration plan operations.\n * Replaces the previous `sql?: readonly string[]` field; consumers should\n * read `result.preview?.statements`.\n */\n readonly preview?: OperationPreview;\n readonly summary: string;\n /**\n * When true, `migration.ts` was written but contains unfilled\n * `placeholder(...)` calls. The user must edit the file and then run\n * `node migration.ts` to self-emit `ops.json` / `migration.json`.\n */\n readonly pendingPlaceholders?: boolean;\n readonly timings: {\n readonly total: number;\n };\n}\n\nasync function executeMigrationPlanCommand(\n options: MigrationPlanOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrationPlanResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative } =\n resolveMigrationPaths(options.config, config);\n\n const contractPathAbsolute = resolveContractPath(config);\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n { label: 'migrations', value: appMigrationsRelative },\n ];\n if (options.from) {\n details.push({ label: 'from', value: options.from });\n }\n if (options.to) {\n details.push({ label: 'to', value: options.to });\n }\n if (options.name) {\n details.push({ label: 'name', value: options.name });\n }\n const header = formatStyledHeader({\n command: 'migration plan',\n description: 'Plan a migration from contract changes',\n url: 'https://pris.ly/migration-plan',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n // Load contract file (the \"to\" contract)\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: `Run \\`prisma-next contract emit\\` to generate ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Construct the family instance up-front so on-disk contract reads cross the\n // serializer seam at the read site, not after the planner has already\n // started dispatching on raw shapes. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n const controlAdapter = config.adapter.create(stack);\n\n let toContract: Contract;\n try {\n toContract = familyInstance.deserializeContract(JSON.parse(contractJsonContent) as unknown);\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract at ${contractPathAbsolute} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n\n const rawStorageHash = toContract.storage?.storageHash;\n if (typeof rawStorageHash !== 'string') {\n return notOk(\n errorContractValidationFailed('Contract is missing storageHash', {\n where: { path: contractPathAbsolute },\n }),\n );\n }\n let toStorageHash: string = rawStorageHash;\n\n // When `--to <ref>` resolves a non-default destination, these carry its raw\n // artifacts so the planned package's `end-contract.*` is written from the\n // resolved target rather than copied from the emitted `contract.json`.\n let toArtifacts: { contractJson: unknown; contractDts: string } | null = null;\n\n let fromContract: Contract | null = null;\n let fromHash: string | null = null;\n let fromContractSourceDir: string | null = null;\n let snapshotStartContract: { contractJson: unknown; contractDts: string } | null = null;\n let isAutoBaseline = false;\n\n const tolerantAggregateResult = await loadContractSpaceAggregateForCli({\n targetId: config.target.targetId,\n migrationsDir,\n appContract: toContract,\n extensionPacks: config.extensionPacks ?? [],\n deserializeContract: (json: unknown) => familyInstance.deserializeContract(json),\n });\n if (!tolerantAggregateResult.ok) {\n return notOk(tolerantAggregateResult.failure);\n }\n const resolutionMember = tolerantAggregateResult.value.app;\n\n const resolutionResult = await resolveFromForPlan({\n optionsFrom: options.from,\n member: resolutionMember,\n });\n\n if (!resolutionResult.ok) {\n return notOk(resolutionResult.failure);\n }\n\n switch (resolutionResult.value.kind) {\n case 'greenfield':\n break;\n case 'graph-node':\n fromHash = resolutionResult.value.fromHash;\n fromContract = resolutionResult.value.fromContract;\n fromContractSourceDir = resolutionResult.value.sourceDir;\n break;\n case 'snapshot':\n fromHash = resolutionResult.value.fromHash;\n fromContract = resolutionResult.value.fromContract;\n snapshotStartContract = {\n contractJson: resolutionResult.value.contractJson,\n contractDts: resolutionResult.value.contractDts,\n };\n break;\n case 'auto-baseline':\n fromHash = resolutionResult.value.fromHash;\n fromContract = resolutionResult.value.fromContract;\n snapshotStartContract = {\n contractJson: resolutionResult.value.contractJson,\n contractDts: resolutionResult.value.contractDts,\n };\n isAutoBaseline = true;\n break;\n }\n\n // `--to <ref>` swaps the planner destination to an arbitrary resolved\n // contract (e.g. an ancestor / rollback target). The from-side resolution\n // above is untouched; only the destination + its emitted `end-contract.*`\n // change.\n if (options.to !== undefined) {\n const toResolution = await resolveToForPlan(options.to, {\n member: resolutionMember,\n });\n if (!toResolution.ok) {\n return notOk(toResolution.failure);\n }\n toContract = toResolution.value.contract;\n toStorageHash = toResolution.value.hash;\n toArtifacts = {\n contractJson: toResolution.value.contractJson,\n contractDts: toResolution.value.contractDts,\n };\n }\n\n // Phase 1 — seed: unconditionally re-emit per-space pinned artefacts\n // (contract.json / contract.d.ts / refs/head.json) and materialise any\n // descriptor-shipped migration packages not yet on disk. Runs before\n // the no-op check so that an extension bump alone (with no structural\n // app-space change) still re-pins extension artefacts on disk.\n const canonicalExtensionInputs = toExtensionInputs(config.extensionPacks ?? []);\n const seedResult = await runContractSpaceSeedPhase({\n migrationsDir,\n extensionPacks: canonicalExtensionInputs,\n });\n if (!flags.json && !flags.quiet) {\n for (const record of seedResult.seeded) {\n if (record.action === 'updated') {\n const pkgSuffix =\n record.newMigrationDirs.length > 0\n ? `; ${record.newMigrationDirs.length} new migration package(s) materialised`\n : '';\n ui.step(`Updated ${record.spaceId} to ${record.newHash}${pkgSuffix}`);\n }\n }\n }\n const emittedExtensionDirs = seedResult.seeded.flatMap((r) =>\n r.newMigrationDirs.map((dirName) => ({ spaceId: r.spaceId, dirName })),\n );\n\n // Check for no-op (same hash means no changes). Auto-baseline is exempt:\n // an empty graph with db ref at the current contract still needs a\n // null → fromHash baseline bundle so migrate can anchor the marker.\n if (fromHash === toStorageHash && !isAutoBaseline) {\n const result: MigrationPlanResult = {\n ok: true,\n noOp: true,\n from: fromHash,\n to: toStorageHash,\n operations: [],\n emittedExtensionDirs,\n summary: 'No changes detected between contracts',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n // Check target supports migrations\n const migrations = getTargetMigrations(config.target);\n if (!migrations) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n // Phase 2 — load: build the aggregate against the now-consistent disk\n // state that phase 1 just seeded. The seed phase guarantees every\n // declared extension has its head ref pinned, so the loader's\n // declaredButUnmigrated precheck always passes here. The app contract\n // was already routed through `familyInstance.deserializeContract` at the\n // read site above (see TML-2536), so it's the hydrated `Contract`\n // here — no second validation pass needed.\n const aggregateResult = await buildContractSpaceAggregate({\n targetId: config.target.targetId,\n migrationsDir,\n appContract: toContract,\n extensionPacks: config.extensionPacks ?? [],\n deserializeContract: (json: unknown) => familyInstance.deserializeContract(json),\n });\n if (!aggregateResult.ok) {\n return notOk(aggregateResult.failure);\n }\n const aggregate = aggregateResult.value;\n\n const frameworkComponents = assertFrameworkComponentsCompatible(\n config.family.familyId,\n config.target.targetId,\n [config.target, config.adapter, ...(config.extensionPacks ?? [])],\n );\n\n // Write the planned package's destination `end-contract.*`. With `--to`, the\n // resolved target's raw artifacts are written; otherwise the emitted\n // `contract.json` / `contract.d.ts` are copied verbatim (today's behaviour).\n async function writeDestinationEndContract(packageDir: string): Promise<void> {\n if (toArtifacts !== null) {\n await writeSnapshotContractArtifacts(\n packageDir,\n toArtifacts.contractJson,\n toArtifacts.contractDts,\n 'end-contract',\n );\n return;\n }\n const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);\n await copyFilesWithRename(packageDir, [\n { sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },\n { sourcePath: destinationArtifacts.dtsPath, destName: 'end-contract.d.ts' },\n ]);\n }\n\n try {\n const planner = migrations.createPlanner(controlAdapter);\n\n if (\n isAutoBaseline &&\n fromHash !== null &&\n fromContract !== null &&\n snapshotStartContract !== null\n ) {\n const baselineTimestamp = new Date();\n const deltaTimestamp = new Date(baselineTimestamp.getTime() + 60_000);\n const baselineDirName = formatMigrationDirName(baselineTimestamp, 'baseline');\n const deltaDirName = formatMigrationDirName(deltaTimestamp, options.name ?? 'migration');\n const baselinePackageDir = join(appMigrationsDir, baselineDirName);\n const deltaPackageDir = join(appMigrationsDir, deltaDirName);\n\n const baselineLeg = await runPlannerLeg(\n planner,\n migrations,\n frameworkComponents,\n fromContract,\n null,\n aggregate.app.spaceId,\n );\n if (!baselineLeg.ok) {\n return notOk(baselineLeg.failure);\n }\n\n await writePlannedMigrationPackage(\n baselinePackageDir,\n null,\n fromHash,\n baselineTimestamp,\n baselineLeg.value,\n );\n await writeSnapshotContractArtifacts(\n baselinePackageDir,\n snapshotStartContract.contractJson,\n snapshotStartContract.contractDts,\n 'end-contract',\n );\n\n if (fromHash === toStorageHash) {\n const baselineOps = baselineLeg.value.hasPlaceholders ? [] : baselineLeg.value.plannedOps;\n if (baselineLeg.value.hasPlaceholders) {\n const baselineDir = relative(process.cwd(), baselinePackageDir);\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: baselineDir,\n baselineDir,\n operations: [],\n emittedExtensionDirs,\n pendingPlaceholders: true,\n summary:\n 'Planned baseline with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const preview = hasOperationPreview(familyInstance)\n ? familyInstance.toOperationPreview(baselineOps)\n : undefined;\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n baselineDir: relative(process.cwd(), baselinePackageDir),\n operations: baselineOps.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n emittedExtensionDirs,\n ...(preview !== undefined ? { preview } : {}),\n summary: buildAutoBaselinePlanSummary(0, emittedExtensionDirs.length),\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const deltaLeg = await runPlannerLeg(\n planner,\n migrations,\n frameworkComponents,\n aggregate.app.contract(),\n fromContract,\n aggregate.app.spaceId,\n );\n if (!deltaLeg.ok) {\n return notOk(deltaLeg.failure);\n }\n\n await writePlannedMigrationPackage(\n deltaPackageDir,\n fromHash,\n toStorageHash,\n deltaTimestamp,\n deltaLeg.value,\n );\n await writeDestinationEndContract(deltaPackageDir);\n await writeSnapshotStartContract(\n deltaPackageDir,\n snapshotStartContract.contractJson,\n snapshotStartContract.contractDts,\n );\n\n const deltaOps = deltaLeg.value.hasPlaceholders ? [] : deltaLeg.value.plannedOps;\n if (deltaLeg.value.hasPlaceholders) {\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), deltaPackageDir),\n baselineDir: relative(process.cwd(), baselinePackageDir),\n operations: [],\n emittedExtensionDirs,\n pendingPlaceholders: true,\n summary:\n 'Planned baseline + migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const preview = hasOperationPreview(familyInstance)\n ? familyInstance.toOperationPreview(deltaOps)\n : undefined;\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), deltaPackageDir),\n baselineDir: relative(process.cwd(), baselinePackageDir),\n operations: deltaOps.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n emittedExtensionDirs,\n ...(preview !== undefined ? { preview } : {}),\n summary: buildAutoBaselinePlanSummary(deltaOps.length, emittedExtensionDirs.length),\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const timestamp = new Date();\n const slug = options.name ?? 'migration';\n const dirName = formatMigrationDirName(timestamp, slug);\n const packageDir = join(appMigrationsDir, dirName);\n\n const deltaLeg = await runPlannerLeg(\n planner,\n migrations,\n frameworkComponents,\n aggregate.app.contract(),\n fromContract,\n aggregate.app.spaceId,\n );\n if (!deltaLeg.ok) {\n return notOk(deltaLeg.failure);\n }\n\n await writePlannedMigrationPackage(\n packageDir,\n fromHash,\n toStorageHash,\n timestamp,\n deltaLeg.value,\n );\n await writeDestinationEndContract(packageDir);\n if (fromContractSourceDir !== null) {\n const sourceArtifacts = getEmittedArtifactPaths(\n join(fromContractSourceDir, 'end-contract.json'),\n );\n await copyFilesWithRename(packageDir, [\n { sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },\n { sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },\n ]);\n } else if (snapshotStartContract !== null) {\n await writeSnapshotStartContract(\n packageDir,\n snapshotStartContract.contractJson,\n snapshotStartContract.contractDts,\n );\n }\n\n if (deltaLeg.value.hasPlaceholders) {\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), packageDir),\n operations: [],\n emittedExtensionDirs,\n pendingPlaceholders: true,\n summary:\n 'Planned migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit',\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n }\n\n const plannedOps = deltaLeg.value.plannedOps;\n const preview = hasOperationPreview(familyInstance)\n ? familyInstance.toOperationPreview(plannedOps)\n : undefined;\n const result: MigrationPlanResult = {\n ok: true,\n noOp: false,\n from: fromHash,\n to: toStorageHash,\n dir: relative(process.cwd(), packageDir),\n operations: plannedOps.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n emittedExtensionDirs,\n ...(preview !== undefined ? { preview } : {}),\n summary: buildPlanSummary(plannedOps.length, emittedExtensionDirs.length),\n timings: { total: Date.now() - startTime },\n };\n return ok(result);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n const message = error instanceof Error ? error.message : String(error);\n return notOk(\n errorUnexpected(message, {\n why: `Unexpected error during migration plan: ${message}`,\n }),\n );\n }\n}\n\nexport function createMigrationPlanCommand(): Command {\n const command = new Command('plan');\n setCommandDescriptions(\n command,\n 'Plan a migration from contract changes',\n 'Compares the emitted contract against the latest on-disk migration state and\\n' +\n 'produces a new migration package with the required operations. No database\\n' +\n 'connection is needed — this is a fully offline operation.',\n );\n setCommandExamples(command, [\n 'prisma-next migration plan',\n 'prisma-next migration plan --name add-users-table',\n 'prisma-next migration plan --to <migration-dir>^ --name rollback',\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--name <slug>', 'Name slug for the migration directory', 'migration')\n .option(\n '--from <contract>',\n 'Starting contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option(\n '--to <contract>',\n 'Destination contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path); defaults to the emitted contract',\n )\n .action(async (options: MigrationPlanOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const startTime = Date.now();\n\n const ui = createTerminalUI(flags);\n const result = await executeMigrationPlanCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (planResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(planResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationPlanOutput(planResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n\n/**\n * Compose the success-line summary so the cross-space side effect\n * (extension-space migration packages materialised on disk during\n * this `plan` run) is visible in the top line — not just in the\n * step log above it.\n *\n * Example outputs:\n * - `Planned 3 operation(s)` (app-space-only project)\n * - `Planned 3 operation(s); materialised 1 extension-space migration` (one extension)\n * - `Planned 3 operation(s); materialised 2 extension-space migrations` (two extensions)\n *\n * Locks AC3 at the summary-line level: a reader of the success line\n * can tell that something happened beyond the app space.\n */\nfunction buildPlanSummary(plannedOpsCount: number, emittedExtensionDirsCount: number): string {\n const base = `Planned ${plannedOpsCount} operation(s)`;\n if (emittedExtensionDirsCount === 0) return base;\n const noun =\n emittedExtensionDirsCount === 1 ? 'extension-space migration' : 'extension-space migrations';\n return `${base}; materialised ${emittedExtensionDirsCount} ${noun}`;\n}\n\nfunction buildAutoBaselinePlanSummary(\n deltaOpsCount: number,\n emittedExtensionDirsCount: number,\n): string {\n const base = `Planned baseline + ${deltaOpsCount} operation(s)`;\n if (emittedExtensionDirsCount === 0) return base;\n const noun =\n emittedExtensionDirsCount === 1 ? 'extension-space migration' : 'extension-space migrations';\n return `${base}; materialised ${emittedExtensionDirsCount} ${noun}`;\n}\n\nexport function formatMigrationPlanOutput(result: MigrationPlanResult, flags: GlobalFlags): string {\n const lines: string[] = [];\n const useColor = flags.color !== false;\n\n const green_ = useColor ? (s: string) => `\\x1b[32m${s}\\x1b[0m` : (s: string) => s;\n const yellow_ = useColor ? (s: string) => `\\x1b[33m${s}\\x1b[0m` : (s: string) => s;\n const dim_ = useColor ? (s: string) => `\\x1b[2m${s}\\x1b[0m` : (s: string) => s;\n\n // Renders the extension-space materialisation block + canonical apply-step\n // hint shared by the no-op, placeholder, and full-plan branches. The app\n // space short-circuits do not skip it: an extension-only bump emits new\n // `migrations/<spaceId>/<dirName>/` directories on disk that the user\n // still has to apply, so the success line must surface them.\n function appendEmittedExtensions(): void {\n if (result.emittedExtensionDirs.length === 0) return;\n lines.push('');\n lines.push(dim_('Emitted extension migrations:'));\n for (const entry of result.emittedExtensionDirs) {\n lines.push(dim_(` ${entry.spaceId} → migrations/${entry.spaceId}/${entry.dirName}`));\n }\n lines.push('');\n lines.push(\n `Next: review the extension migrations above, then run ${green_('prisma-next migrate')}.`,\n );\n }\n\n if (result.noOp) {\n lines.push(`${green_('✔')} No changes detected`);\n lines.push(dim_(` from: ${result.from}`));\n lines.push(dim_(` to: ${result.to}`));\n appendEmittedExtensions();\n return lines.join('\\n');\n }\n\n if (result.pendingPlaceholders) {\n lines.push(`${yellow_('⚠')} ${result.summary}`);\n lines.push('');\n lines.push(dim_(`from: ${result.from}`));\n lines.push(dim_(`to: ${result.to}`));\n if (result.dir) {\n lines.push(dim_(`dir: ${result.dir}`));\n }\n lines.push('');\n lines.push(\n 'Open migration.ts and replace each `placeholder(...)` call with your actual query.',\n );\n lines.push(`Then run: ${green_(`node ${result.dir ?? '<dir>'}/migration.ts`)}`);\n appendEmittedExtensions();\n return lines.join('\\n');\n }\n\n lines.push(`${green_('✔')} ${result.summary}`);\n lines.push('');\n\n if (result.operations.length > 0) {\n lines.push(dim_('│'));\n for (let i = 0; i < result.operations.length; i++) {\n const op = result.operations[i]!;\n const isLast = i === result.operations.length - 1;\n const treeChar = isLast ? '└' : '├';\n // operationClass tag is intentionally NOT inlined per spec:\n // a destructive footer warning still surfaces below this list.\n const destructiveMarker =\n op.operationClass === 'destructive' ? ` ${yellow_('(destructive)')}` : '';\n lines.push(`${dim_(treeChar)}─ ${op.label}${destructiveMarker}`);\n }\n\n const hasDestructive = result.operations.some((op) => op.operationClass === 'destructive');\n if (hasDestructive) {\n lines.push('');\n lines.push(\n `${yellow_('⚠')} This migration contains destructive operations that may cause data loss.`,\n );\n }\n lines.push('');\n }\n\n lines.push(dim_(`from: ${result.from}`));\n lines.push(dim_(`to: ${result.to}`));\n if (result.baselineDir) {\n lines.push(dim_(`Baseline → ${result.baselineDir}`));\n }\n if (result.dir) {\n lines.push(dim_(`App space → ${result.dir}`));\n }\n // Per-space block: surface the extension-space directories materialised\n // alongside the app-space migration. Without this block the cross-space\n // side effect is invisible in the success summary (e2e finding F1).\n for (const entry of result.emittedExtensionDirs) {\n lines.push(\n dim_(`Extension space ${entry.spaceId} → migrations/${entry.spaceId}/${entry.dirName}`),\n );\n }\n\n lines.push('');\n // The \"Next:\" hint always points at the canonical apply path\n // (`prisma-next migrate`) regardless of how many spaces were\n // materialised — `db update` is a dev-time convenience, not the\n // canonical replay step.\n const reviewTarget =\n result.baselineDir !== undefined && result.dir !== undefined\n ? `${result.baselineDir} and ${result.dir}`\n : (result.baselineDir ?? result.dir ?? '<dir>');\n lines.push(\n `Next: review ${green_(reviewTarget)} if needed, then run ${green_('prisma-next migrate')}.`,\n );\n\n if (result.preview && result.preview.statements.length > 0) {\n // The non-empty length is already guaranteed by the surrounding check, so\n // a plain `every` here is equivalent to the helper in formatters/migrations.ts.\n const allSql = result.preview.statements.every((s) => s.language === 'sql');\n lines.push('');\n lines.push(dim_(allSql ? 'DDL preview' : 'Operation preview'));\n lines.push('');\n for (const statement of result.preview.statements) {\n const trimmed = statement.text.trim();\n if (!trimmed) continue;\n const line = statement.language === 'sql' && !trimmed.endsWith(';') ? `${trimmed};` : trimmed;\n lines.push(line);\n }\n }\n\n if (flags.verbose && result.timings) {\n lines.push('');\n lines.push(dim_(`Total time: ${result.timings.total}ms`));\n }\n\n return lines.join('\\n');\n}\n\nexport type PrefixResolutionFailure =\n | { reason: 'ambiguous'; count: number }\n | { reason: 'not-found' };\n\n/**\n * Resolve a migration package by **target contract hash** (`metadata.to`)\n * using exact match or prefix match.\n *\n * Note: matches `metadata.to` (the contract hash this migration produces),\n * not `metadata.migrationHash` (the package's content-addressed identity).\n * Tries exact match first, then prefix match (auto-prepending `sha256:` when\n * the needle omits the scheme). Returns the matched package on success, or a\n * discriminated failure indicating whether the prefix was ambiguous or simply\n * not found.\n *\n * @internal Exported for testing only.\n */\nexport function resolveBundleByPrefix<T extends { metadata: { to: string } }>(\n bundles: readonly T[],\n needle: string,\n): Result<T, PrefixResolutionFailure> {\n const exact = bundles.find((p) => p.metadata.to === needle);\n if (exact) return ok(exact);\n\n const prefixWithScheme = needle.startsWith('sha256:') ? needle : `sha256:${needle}`;\n const candidates = bundles.filter((p) => p.metadata.to.startsWith(prefixWithScheme));\n\n if (candidates.length === 1) return ok(candidates[0]!);\n if (candidates.length > 1) return notOk({ reason: 'ambiguous', count: candidates.length });\n return notOk({ reason: 'not-found' });\n}\n"],"mappings":"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"}
|