@prisma-next/cli 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{cli-errors-CF60g2cG.mjs → cli-errors-Djtz98Vm.mjs} +3 -3
- package/dist/cli-errors-Djtz98Vm.mjs.map +1 -0
- package/dist/cli.mjs +151 -12
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-Brv4qlfB.mjs → client-oXO2WCPD.mjs} +6 -5
- package/dist/client-oXO2WCPD.mjs.map +1 -0
- package/dist/{command-helpers-D3vL5yi8.mjs → command-helpers-BSb0tRC8.mjs} +104 -10
- package/dist/command-helpers-BSb0tRC8.mjs.map +1 -0
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +19 -20
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +6 -10
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +7 -11
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +16 -17
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +1 -1
- package/dist/commands/migrate.mjs +7 -11
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.mjs +4 -7
- package/dist/commands/migration-check.mjs.map +1 -1
- package/dist/commands/migration-graph.d.mts +1 -1
- package/dist/commands/migration-graph.mjs +6 -10
- package/dist/commands/migration-graph.mjs.map +1 -1
- package/dist/commands/migration-list.mjs +5 -9
- package/dist/commands/migration-list.mjs.map +1 -1
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +7 -10
- package/dist/commands/migration-log.mjs.map +1 -1
- package/dist/commands/migration-new.mjs +6 -10
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +8 -12
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +1 -1
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +36 -14
- package/dist/commands/migration-status.mjs.map +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.mjs +9 -19
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/{contract-emit-iynA3BCA.mjs → contract-emit-bcrpT-wD.mjs} +3 -3
- package/dist/{contract-emit-iynA3BCA.mjs.map → contract-emit-bcrpT-wD.mjs.map} +1 -1
- package/dist/{contract-emit-C3STUIBg.mjs → contract-emit-r4y8Zhf1.mjs} +7 -12
- package/dist/contract-emit-r4y8Zhf1.mjs.map +1 -0
- package/dist/{contract-infer-Cnj8G1E2.mjs → contract-infer-BmySmqVT.mjs} +8 -13
- package/dist/contract-infer-BmySmqVT.mjs.map +1 -0
- package/dist/{contract-space-aggregate-loader-pAc8CDfY.mjs → contract-space-aggregate-loader-BmNQwlws.mjs} +2 -2
- package/dist/{contract-space-aggregate-loader-pAc8CDfY.mjs.map → contract-space-aggregate-loader-BmNQwlws.mjs.map} +1 -1
- package/dist/{db-verify-D7cyH_zz.mjs → db-verify-BClPs3ph.mjs} +9 -13
- package/dist/db-verify-BClPs3ph.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +2 -2
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{framework-components-xFLFpZUO.mjs → framework-components-65gOHkHB.mjs} +2 -2
- package/dist/{framework-components-xFLFpZUO.mjs.map → framework-components-65gOHkHB.mjs.map} +1 -1
- package/dist/{global-flags-DGmw6Kqg.d.mts → global-flags-CdE7M0d9.d.mts} +4 -1
- package/dist/global-flags-CdE7M0d9.d.mts.map +1 -0
- package/dist/{graph-render-eJDcLWny.mjs → graph-render-DJVv0_uf.mjs} +1 -1
- package/dist/{graph-render-eJDcLWny.mjs.map → graph-render-DJVv0_uf.mjs.map} +1 -1
- package/dist/{init-eh2z5Tl6.mjs → init-BCJZPWE1.mjs} +547 -399
- package/dist/init-BCJZPWE1.mjs.map +1 -0
- package/dist/{inspect-live-schema-CWLK_lgs.mjs → inspect-live-schema-DSRbFoOL.mjs} +4 -4
- package/dist/{inspect-live-schema-CWLK_lgs.mjs.map → inspect-live-schema-DSRbFoOL.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-CmXXC1UZ.mjs → migration-command-scaffold-Bzd9La5c.mjs} +4 -4
- package/dist/{migration-command-scaffold-CmXXC1UZ.mjs.map → migration-command-scaffold-Bzd9La5c.mjs.map} +1 -1
- package/dist/{migration-plan-CHyUlBV0.mjs → migration-plan-CFwqw3Gk.mjs} +8 -12
- package/dist/migration-plan-CFwqw3Gk.mjs.map +1 -0
- package/dist/{migration-types-D2FW63pr.d.mts → migration-types-BXWvz12q.d.mts} +1 -1
- package/dist/{migration-types-D2FW63pr.d.mts.map → migration-types-BXWvz12q.d.mts.map} +1 -1
- package/dist/{migrations-DyUf5lTt.mjs → migrations-CwZMa1Ck.mjs} +2 -2
- package/dist/{migrations-DyUf5lTt.mjs.map → migrations-CwZMa1Ck.mjs.map} +1 -1
- package/dist/{output-B60Gw5fu.mjs → output-BlsrGMEF.mjs} +1 -1
- package/dist/{output-B60Gw5fu.mjs.map → output-BlsrGMEF.mjs.map} +1 -1
- package/dist/quick-reference-mongo.md +1 -1
- package/dist/quick-reference-postgres.md +1 -1
- package/dist/readme-mongo.md +35 -0
- package/dist/readme-postgres.md +34 -0
- package/dist/{terminal-ui-XtOQsqe9.mjs → terminal-ui-BiB_8KNo.mjs} +131 -24
- package/dist/terminal-ui-BiB_8KNo.mjs.map +1 -0
- package/dist/{types-0aS865QN.d.mts → types--CqjMdk0.d.mts} +2 -2
- package/dist/{types-0aS865QN.d.mts.map → types--CqjMdk0.d.mts.map} +1 -1
- package/dist/{verify-D7ypCCe6.mjs → verify-Bom75OYI.mjs} +2 -2
- package/dist/{verify-D7ypCCe6.mjs.map → verify-Bom75OYI.mjs.map} +1 -1
- package/package.json +19 -17
- package/src/cli.ts +42 -0
- package/src/commands/contract-emit.ts +4 -4
- package/src/commands/contract-infer.ts +6 -6
- package/src/commands/db-init.ts +13 -5
- package/src/commands/db-schema.ts +4 -4
- package/src/commands/db-sign.ts +4 -4
- package/src/commands/db-update.ts +13 -5
- package/src/commands/db-verify.ts +5 -5
- package/src/commands/init/detect-package-manager.ts +15 -0
- package/src/commands/init/errors.ts +33 -2
- package/src/commands/init/index.ts +13 -5
- package/src/commands/init/init.ts +61 -32
- package/src/commands/init/inputs.ts +82 -5
- package/src/commands/init/output.ts +1 -1
- package/src/commands/init/{agent-skill-install.ts → skill-install.ts} +42 -31
- package/src/commands/init/templates/code-templates.ts +22 -22
- package/src/commands/init/templates/env.ts +8 -1
- package/src/commands/init/templates/quick-reference-mongo.md +1 -1
- package/src/commands/init/templates/quick-reference-postgres.md +1 -1
- package/src/commands/init/templates/readme-mongo.md +35 -0
- package/src/commands/init/templates/readme-postgres.md +34 -0
- package/src/commands/init/templates/readme.ts +62 -0
- package/src/commands/migrate.ts +4 -7
- package/src/commands/migration-check.ts +4 -4
- package/src/commands/migration-graph.ts +4 -4
- package/src/commands/migration-list.ts +4 -4
- package/src/commands/migration-log.ts +6 -5
- package/src/commands/migration-new.ts +4 -4
- package/src/commands/migration-plan.ts +4 -4
- package/src/commands/migration-show.ts +4 -4
- package/src/commands/migration-status.ts +49 -6
- package/src/commands/ref.ts +8 -8
- package/src/control-api/operations/apply-aggregate.ts +1 -0
- package/src/utils/cli-errors.ts +4 -0
- package/src/utils/command-helpers.ts +6 -2
- package/src/utils/global-flags.ts +105 -16
- package/src/utils/is-ci.ts +18 -0
- package/src/utils/telemetry.ts +141 -0
- package/src/utils/terminal-ui.ts +44 -23
- package/dist/cli-errors-CF60g2cG.mjs.map +0 -1
- package/dist/client-Brv4qlfB.mjs.map +0 -1
- package/dist/command-helpers-D3vL5yi8.mjs.map +0 -1
- package/dist/contract-emit-C3STUIBg.mjs.map +0 -1
- package/dist/contract-infer-Cnj8G1E2.mjs.map +0 -1
- package/dist/db-verify-D7cyH_zz.mjs.map +0 -1
- package/dist/errors-Cw6kyTyV.mjs +0 -56
- package/dist/errors-Cw6kyTyV.mjs.map +0 -1
- package/dist/global-flags-DGmw6Kqg.d.mts.map +0 -1
- package/dist/helpers-eqdN8tH6.mjs +0 -25
- package/dist/helpers-eqdN8tH6.mjs.map +0 -1
- package/dist/init-eh2z5Tl6.mjs.map +0 -1
- package/dist/migration-plan-CHyUlBV0.mjs.map +0 -1
- package/dist/result-handler-Bm_6dDYg.mjs +0 -25
- package/dist/result-handler-Bm_6dDYg.mjs.map +0 -1
- package/dist/terminal-ui-XtOQsqe9.mjs.map +0 -1
- /package/dist/{cli-errors-DdcjVLJV.d.mts → cli-errors-Czmx92Zy.d.mts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-check.mjs","names":[],"sources":["../../src/commands/migration-check.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { verifyMigrationHash } from '@prisma-next/migration-tools/hash';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport { parseMigrationRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { Command } from 'commander';\nimport { join, relative } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport { TerminalUI } from '../utils/terminal-ui';\nimport { INTEGRITY_FAILED, OK, PRECONDITION } from './migration-check/exit-codes';\n\ninterface MigrationCheckOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nexport interface CheckFailure {\n readonly pnCode: string;\n readonly where: string;\n readonly why: string;\n readonly fix: string;\n}\n\nexport interface MigrationCheckResult {\n readonly ok: boolean;\n readonly failures: readonly CheckFailure[];\n readonly summary: string;\n}\n\n/**\n * Canonical user-facing locator for a check failure: the cwd-relative path\n * to the migration package directory. Surfacing the same shape across every\n * PN code means `--json` consumers can branch uniformly on `where`.\n */\nfunction migrationPathRelative(dirPath: string): string {\n return relative(process.cwd(), dirPath);\n}\n\nfunction migrationFileRelative(dirPath: string, fileName: string): string {\n return join(migrationPathRelative(dirPath), fileName);\n}\n\nfunction checkFileExists(dirPath: string, dirName: string, fileName: string): CheckFailure | null {\n if (!existsSync(join(dirPath, fileName))) {\n return {\n pnCode: 'PN-MIG-CHECK-002',\n where: migrationFileRelative(dirPath, fileName),\n why: `${fileName} is missing from ${dirName}`,\n fix: 'Re-emit the migration package or restore from version control.',\n };\n }\n return null;\n}\n\n/**\n * Within-migration snapshot-consistency check (PN-MIG-CHECK-005).\n *\n * Compares the migration's stored `metadata.to` against the `storageHash`\n * recorded in its on-disk `end-contract.json` snapshot. The two values are\n * independent on-disk records of the same fact (the migration's destination\n * contract); drift between them indicates the package is internally\n * corrupt. Cross-migration consistency (one migration's end-contract.json\n * agreeing with the next migration's start-contract.json) is a separate\n * check that requires shadow execution and is deferred to\n * `migration preflight`.\n *\n * Shared between the graph-wide and per-migration code paths so both report\n * the same failure for the same on-disk state.\n */\nfunction checkSnapshotConsistency(pkg: OnDiskMigrationPackage): CheckFailure | null {\n const endContractPath = join(pkg.dirPath, 'end-contract.json');\n if (!existsSync(endContractPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(endContractPath, 'utf-8')) as Record<string, unknown>;\n const storage = raw['storage'] as Record<string, unknown> | undefined;\n const snapshotHash = storage?.['storageHash'];\n if (typeof snapshotHash === 'string' && snapshotHash !== pkg.metadata.to) {\n return {\n pnCode: 'PN-MIG-CHECK-005',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" declares to=${pkg.metadata.to} but end-contract.json has storageHash=${snapshotHash}`,\n fix: 'Re-emit the migration package so migration.json and end-contract.json agree.',\n };\n }\n } catch {\n return {\n pnCode: 'PN-MIG-CHECK-006',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" has an unparseable end-contract.json.`,\n fix: 'Re-emit the migration package to repair the snapshot file.',\n };\n }\n return null;\n}\n\nasync function executeMigrationCheckCommand(\n target: string | undefined,\n options: MigrationCheckOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<{ result: MigrationCheckResult; exitCode: number }> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ];\n if (target) {\n details.push({ label: 'target', value: target });\n }\n const header = formatStyledHeader({\n command: 'migration check',\n description: 'Verify artifact and graph integrity',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n const failures: CheckFailure[] = [];\n\n let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n const loaded = await loadMigrationPackages(appMigrationsDir);\n bundles = loaded.bundles;\n graph = loaded.graph;\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n const pnCode =\n error.code === 'MIGRATION.HASH_MISMATCH' ? 'PN-MIG-CHECK-001' : 'PN-MIG-CHECK-002';\n // Normalise to a cwd-relative path. `error.details.dir` is absolute\n // (the migration-tools layer doesn't know the caller's cwd); the\n // `filePath` fallback is also absolute. Surfacing the relative form\n // matches the rest of the command's `where` shape and keeps `--json`\n // consumers from having to special-case the bootstrap-failure path.\n const rawWhere =\n (error.details?.['dir'] as string) ?? (error.details?.['filePath'] as string) ?? null;\n const where = rawWhere ? relative(process.cwd(), rawWhere) : 'unknown';\n failures.push({\n pnCode,\n where,\n why: error.why,\n fix: error.fix,\n });\n return {\n result: { ok: false, failures, summary: `${failures.length} integrity failure(s)` },\n exitCode: INTEGRITY_FAILED,\n };\n }\n throw error;\n }\n\n if (existsSync(appMigrationsDir)) {\n const loadedDirNames = new Set(bundles.map((p) => p.dirName));\n try {\n const entries = readdirSync(appMigrationsDir);\n for (const entry of entries) {\n if (entry.startsWith('.') || entry.startsWith('_') || entry === 'refs') continue;\n const entryPath = join(appMigrationsDir, entry);\n try {\n if (!statSync(entryPath).isDirectory()) continue;\n } catch {\n continue;\n }\n if (!loadedDirNames.has(entry)) {\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(entryPath, entry, f);\n if (fail) failures.push(fail);\n }\n }\n }\n } catch {\n // migrations dir unreadable — skip\n }\n }\n\n if (target) {\n const refs = await readRefs(refsDir);\n const migResult = parseMigrationRef(target, { graph, refs });\n if (!migResult.ok) {\n const msg =\n migResult.failure.kind === 'not-found'\n ? `Migration \"${target}\" does not exist`\n : migResult.failure.kind === 'wrong-grammar'\n ? migResult.failure.message\n : `Invalid migration reference: \"${target}\"`;\n return {\n result: { ok: false, failures: [], summary: msg },\n exitCode: PRECONDITION,\n };\n }\n\n const matchedPkg = bundles.find(\n (p) => p.metadata.migrationHash === migResult.value.migrationHash,\n );\n if (!matchedPkg) {\n return {\n result: {\n ok: false,\n failures: [],\n summary: `Migration package for \"${target}\" not found on disk`,\n },\n exitCode: PRECONDITION,\n };\n }\n\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(matchedPkg.dirPath, matchedPkg.dirName, f);\n if (fail) failures.push(fail);\n }\n\n const verification = verifyMigrationHash(matchedPkg);\n if (!verification.ok) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(matchedPkg.dirPath, 'migration.json'),\n why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,\n fix: 'Re-emit the migration package or restore from version control.',\n });\n }\n\n // PN-MIG-CHECK-005 must fire per-migration as well as graph-wide; both\n // call sites delegate to the shared helper so the same on-disk drift\n // produces the same failure regardless of how the user invoked check.\n const snapshotFailure = checkSnapshotConsistency(matchedPkg);\n if (snapshotFailure) failures.push(snapshotFailure);\n } else {\n for (const pkg of bundles) {\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(pkg.dirPath, pkg.dirName, f);\n if (fail) failures.push(fail);\n }\n\n const verification = verifyMigrationHash(pkg);\n if (!verification.ok) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(pkg.dirPath, 'migration.json'),\n why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,\n fix: 'Re-emit the migration package or restore from version control.',\n });\n }\n }\n\n for (const pkg of bundles) {\n const snapshotFailure = checkSnapshotConsistency(pkg);\n if (snapshotFailure) failures.push(snapshotFailure);\n }\n\n const allToHashes = new Set(bundles.map((p) => p.metadata.to));\n for (const pkg of bundles) {\n const isReachable =\n pkg.metadata.from === null ||\n allToHashes.has(pkg.metadata.from) ||\n pkg.metadata.from === 'sha256:empty';\n if (!isReachable) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-003',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" starts from ${pkg.metadata.from} which no other migration produces`,\n fix: 'This migration is unreachable in the graph. Delete it or re-emit a connecting migration.',\n });\n }\n }\n\n try {\n const refs = await readRefs(refsDir);\n for (const [name, entry] of Object.entries(refs)) {\n if (!graph.nodes.has(entry.hash)) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-004',\n where: relative(process.cwd(), join(refsDir, `${name}.json`)),\n why: `Ref \"${name}\" points at ${entry.hash} which does not exist in the migration graph`,\n fix: `Update the ref with \\`prisma-next ref set ${name} <valid-hash>\\` or delete it.`,\n });\n }\n }\n } catch {\n // Refs unreadable — skip ref checks\n }\n }\n\n if (failures.length === 0) {\n return {\n result: { ok: true, failures: [], summary: 'All checks passed' },\n exitCode: OK,\n };\n }\n\n return {\n result: { ok: false, failures, summary: `${failures.length} integrity failure(s)` },\n exitCode: INTEGRITY_FAILED,\n };\n}\n\nexport function createMigrationCheckCommand(): Command {\n const command = new Command('check');\n setCommandDescriptions(\n command,\n 'Verify artifact and graph integrity',\n 'Validates that on-disk migration packages are internally consistent\\n' +\n '(hashes match, manifests are complete) and that the graph is well-formed\\n' +\n '(edges connect, refs point at valid nodes). Offline — does not consult\\n' +\n 'the database.',\n );\n setCommandExamples(command, [\n 'prisma-next migration check',\n 'prisma-next migration check 20260101-add-users',\n 'prisma-next migration check --json',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n ]);\n command.exitOverride();\n addGlobalOptions(command)\n .argument('[migration]', 'Migration reference (directory name or hash) to check')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (target: string | undefined, options: MigrationCheckOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n\n let result: MigrationCheckResult;\n let exitCode: number;\n try {\n ({ result, exitCode } = await executeMigrationCheckCommand(target, options, flags, ui));\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n result = { ok: false, failures: [], summary: msg };\n exitCode = PRECONDITION;\n }\n\n if (flags.json) {\n ui.output(JSON.stringify(result, null, 2));\n } else if (!flags.quiet) {\n if (result.ok) {\n ui.log(`✔ ${result.summary}`);\n } else {\n for (const f of result.failures) {\n ui.log(`✗ [${f.pnCode}] ${f.where}: ${f.why}`);\n ui.log(` fix: ${f.fix}`);\n }\n ui.log(`\\n${result.summary}`);\n }\n }\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-check.mjs","names":[],"sources":["../../src/commands/migration-check.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { verifyMigrationHash } from '@prisma-next/migration-tools/hash';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport { parseMigrationRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { Command } from 'commander';\nimport { join, relative } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\nimport { INTEGRITY_FAILED, OK, PRECONDITION } from './migration-check/exit-codes';\n\ninterface MigrationCheckOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nexport interface CheckFailure {\n readonly pnCode: string;\n readonly where: string;\n readonly why: string;\n readonly fix: string;\n}\n\nexport interface MigrationCheckResult {\n readonly ok: boolean;\n readonly failures: readonly CheckFailure[];\n readonly summary: string;\n}\n\n/**\n * Canonical user-facing locator for a check failure: the cwd-relative path\n * to the migration package directory. Surfacing the same shape across every\n * PN code means `--json` consumers can branch uniformly on `where`.\n */\nfunction migrationPathRelative(dirPath: string): string {\n return relative(process.cwd(), dirPath);\n}\n\nfunction migrationFileRelative(dirPath: string, fileName: string): string {\n return join(migrationPathRelative(dirPath), fileName);\n}\n\nfunction checkFileExists(dirPath: string, dirName: string, fileName: string): CheckFailure | null {\n if (!existsSync(join(dirPath, fileName))) {\n return {\n pnCode: 'PN-MIG-CHECK-002',\n where: migrationFileRelative(dirPath, fileName),\n why: `${fileName} is missing from ${dirName}`,\n fix: 'Re-emit the migration package or restore from version control.',\n };\n }\n return null;\n}\n\n/**\n * Within-migration snapshot-consistency check (PN-MIG-CHECK-005).\n *\n * Compares the migration's stored `metadata.to` against the `storageHash`\n * recorded in its on-disk `end-contract.json` snapshot. The two values are\n * independent on-disk records of the same fact (the migration's destination\n * contract); drift between them indicates the package is internally\n * corrupt. Cross-migration consistency (one migration's end-contract.json\n * agreeing with the next migration's start-contract.json) is a separate\n * check that requires shadow execution and is deferred to\n * `migration preflight`.\n *\n * Shared between the graph-wide and per-migration code paths so both report\n * the same failure for the same on-disk state.\n */\nfunction checkSnapshotConsistency(pkg: OnDiskMigrationPackage): CheckFailure | null {\n const endContractPath = join(pkg.dirPath, 'end-contract.json');\n if (!existsSync(endContractPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(endContractPath, 'utf-8')) as Record<string, unknown>;\n const storage = raw['storage'] as Record<string, unknown> | undefined;\n const snapshotHash = storage?.['storageHash'];\n if (typeof snapshotHash === 'string' && snapshotHash !== pkg.metadata.to) {\n return {\n pnCode: 'PN-MIG-CHECK-005',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" declares to=${pkg.metadata.to} but end-contract.json has storageHash=${snapshotHash}`,\n fix: 'Re-emit the migration package so migration.json and end-contract.json agree.',\n };\n }\n } catch {\n return {\n pnCode: 'PN-MIG-CHECK-006',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" has an unparseable end-contract.json.`,\n fix: 'Re-emit the migration package to repair the snapshot file.',\n };\n }\n return null;\n}\n\nasync function executeMigrationCheckCommand(\n target: string | undefined,\n options: MigrationCheckOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<{ result: MigrationCheckResult; exitCode: number }> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ];\n if (target) {\n details.push({ label: 'target', value: target });\n }\n const header = formatStyledHeader({\n command: 'migration check',\n description: 'Verify artifact and graph integrity',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n const failures: CheckFailure[] = [];\n\n let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n const loaded = await loadMigrationPackages(appMigrationsDir);\n bundles = loaded.bundles;\n graph = loaded.graph;\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n const pnCode =\n error.code === 'MIGRATION.HASH_MISMATCH' ? 'PN-MIG-CHECK-001' : 'PN-MIG-CHECK-002';\n // Normalise to a cwd-relative path. `error.details.dir` is absolute\n // (the migration-tools layer doesn't know the caller's cwd); the\n // `filePath` fallback is also absolute. Surfacing the relative form\n // matches the rest of the command's `where` shape and keeps `--json`\n // consumers from having to special-case the bootstrap-failure path.\n const rawWhere =\n (error.details?.['dir'] as string) ?? (error.details?.['filePath'] as string) ?? null;\n const where = rawWhere ? relative(process.cwd(), rawWhere) : 'unknown';\n failures.push({\n pnCode,\n where,\n why: error.why,\n fix: error.fix,\n });\n return {\n result: { ok: false, failures, summary: `${failures.length} integrity failure(s)` },\n exitCode: INTEGRITY_FAILED,\n };\n }\n throw error;\n }\n\n if (existsSync(appMigrationsDir)) {\n const loadedDirNames = new Set(bundles.map((p) => p.dirName));\n try {\n const entries = readdirSync(appMigrationsDir);\n for (const entry of entries) {\n if (entry.startsWith('.') || entry.startsWith('_') || entry === 'refs') continue;\n const entryPath = join(appMigrationsDir, entry);\n try {\n if (!statSync(entryPath).isDirectory()) continue;\n } catch {\n continue;\n }\n if (!loadedDirNames.has(entry)) {\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(entryPath, entry, f);\n if (fail) failures.push(fail);\n }\n }\n }\n } catch {\n // migrations dir unreadable — skip\n }\n }\n\n if (target) {\n const refs = await readRefs(refsDir);\n const migResult = parseMigrationRef(target, { graph, refs });\n if (!migResult.ok) {\n const msg =\n migResult.failure.kind === 'not-found'\n ? `Migration \"${target}\" does not exist`\n : migResult.failure.kind === 'wrong-grammar'\n ? migResult.failure.message\n : `Invalid migration reference: \"${target}\"`;\n return {\n result: { ok: false, failures: [], summary: msg },\n exitCode: PRECONDITION,\n };\n }\n\n const matchedPkg = bundles.find(\n (p) => p.metadata.migrationHash === migResult.value.migrationHash,\n );\n if (!matchedPkg) {\n return {\n result: {\n ok: false,\n failures: [],\n summary: `Migration package for \"${target}\" not found on disk`,\n },\n exitCode: PRECONDITION,\n };\n }\n\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(matchedPkg.dirPath, matchedPkg.dirName, f);\n if (fail) failures.push(fail);\n }\n\n const verification = verifyMigrationHash(matchedPkg);\n if (!verification.ok) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(matchedPkg.dirPath, 'migration.json'),\n why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,\n fix: 'Re-emit the migration package or restore from version control.',\n });\n }\n\n // PN-MIG-CHECK-005 must fire per-migration as well as graph-wide; both\n // call sites delegate to the shared helper so the same on-disk drift\n // produces the same failure regardless of how the user invoked check.\n const snapshotFailure = checkSnapshotConsistency(matchedPkg);\n if (snapshotFailure) failures.push(snapshotFailure);\n } else {\n for (const pkg of bundles) {\n for (const f of ['migration.json', 'ops.json']) {\n const fail = checkFileExists(pkg.dirPath, pkg.dirName, f);\n if (fail) failures.push(fail);\n }\n\n const verification = verifyMigrationHash(pkg);\n if (!verification.ok) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-001',\n where: migrationFileRelative(pkg.dirPath, 'migration.json'),\n why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,\n fix: 'Re-emit the migration package or restore from version control.',\n });\n }\n }\n\n for (const pkg of bundles) {\n const snapshotFailure = checkSnapshotConsistency(pkg);\n if (snapshotFailure) failures.push(snapshotFailure);\n }\n\n const allToHashes = new Set(bundles.map((p) => p.metadata.to));\n for (const pkg of bundles) {\n const isReachable =\n pkg.metadata.from === null ||\n allToHashes.has(pkg.metadata.from) ||\n pkg.metadata.from === 'sha256:empty';\n if (!isReachable) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-003',\n where: migrationPathRelative(pkg.dirPath),\n why: `Migration \"${pkg.dirName}\" starts from ${pkg.metadata.from} which no other migration produces`,\n fix: 'This migration is unreachable in the graph. Delete it or re-emit a connecting migration.',\n });\n }\n }\n\n try {\n const refs = await readRefs(refsDir);\n for (const [name, entry] of Object.entries(refs)) {\n if (!graph.nodes.has(entry.hash)) {\n failures.push({\n pnCode: 'PN-MIG-CHECK-004',\n where: relative(process.cwd(), join(refsDir, `${name}.json`)),\n why: `Ref \"${name}\" points at ${entry.hash} which does not exist in the migration graph`,\n fix: `Update the ref with \\`prisma-next ref set ${name} <valid-hash>\\` or delete it.`,\n });\n }\n }\n } catch {\n // Refs unreadable — skip ref checks\n }\n }\n\n if (failures.length === 0) {\n return {\n result: { ok: true, failures: [], summary: 'All checks passed' },\n exitCode: OK,\n };\n }\n\n return {\n result: { ok: false, failures, summary: `${failures.length} integrity failure(s)` },\n exitCode: INTEGRITY_FAILED,\n };\n}\n\nexport function createMigrationCheckCommand(): Command {\n const command = new Command('check');\n setCommandDescriptions(\n command,\n 'Verify artifact and graph integrity',\n 'Validates that on-disk migration packages are internally consistent\\n' +\n '(hashes match, manifests are complete) and that the graph is well-formed\\n' +\n '(edges connect, refs point at valid nodes). Offline — does not consult\\n' +\n 'the database.',\n );\n setCommandExamples(command, [\n 'prisma-next migration check',\n 'prisma-next migration check 20260101-add-users',\n 'prisma-next migration check --json',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n ]);\n command.exitOverride();\n addGlobalOptions(command)\n .argument('[migration]', 'Migration reference (directory name or hash) to check')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (target: string | undefined, options: MigrationCheckOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n let result: MigrationCheckResult;\n let exitCode: number;\n try {\n ({ result, exitCode } = await executeMigrationCheckCommand(target, options, flags, ui));\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n result = { ok: false, failures: [], summary: msg };\n exitCode = PRECONDITION;\n }\n\n if (flags.json) {\n ui.output(JSON.stringify(result, null, 2));\n } else if (!flags.quiet) {\n if (result.ok) {\n ui.log(`✔ ${result.summary}`);\n } else {\n for (const f of result.failures) {\n ui.log(`✗ [${f.pnCode}] ${f.where}: ${f.why}`);\n ui.log(` fix: ${f.fix}`);\n }\n ui.log(`\\n${result.summary}`);\n }\n }\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as handleResult } from "../
|
|
5
|
-
import {
|
|
6
|
-
import { i as migrationGraphToRenderInput, n as graphRenderer } from "../graph-render-eJDcLWny.mjs";
|
|
2
|
+
import { b as mapMigrationToolsError, y as errorUnexpected } from "../cli-errors-Djtz98Vm.mjs";
|
|
3
|
+
import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
|
|
4
|
+
import { S as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, s as readContractEnvelope, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-BSb0tRC8.mjs";
|
|
5
|
+
import { i as migrationGraphToRenderInput, n as graphRenderer } from "../graph-render-DJVv0_uf.mjs";
|
|
7
6
|
import { Command } from "commander";
|
|
8
7
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
9
8
|
import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
|
|
@@ -83,11 +82,8 @@ function createMigrationGraphCommand() {
|
|
|
83
82
|
}
|
|
84
83
|
]);
|
|
85
84
|
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").option("--dot", "Output in Graphviz DOT format").action(async (options) => {
|
|
86
|
-
const flags =
|
|
87
|
-
const ui =
|
|
88
|
-
color: flags.color,
|
|
89
|
-
interactive: flags.interactive
|
|
90
|
-
});
|
|
85
|
+
const flags = parseGlobalFlagsOrExit(options);
|
|
86
|
+
const ui = createTerminalUI(flags);
|
|
91
87
|
const exitCode = handleResult(await executeMigrationGraphCommand(options, flags, ui), flags, ui, (graphResult) => {
|
|
92
88
|
if (options.dot) {
|
|
93
89
|
const lines = ["digraph migrations {"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-graph.mjs","names":[],"sources":["../../src/commands/migration-graph.ts"],"sourcesContent":["import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n readContractEnvelope,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { migrationGraphToRenderInput } from '../utils/formatters/graph-migration-mapper';\nimport { graphRenderer } from '../utils/formatters/graph-render';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags,
|
|
1
|
+
{"version":3,"file":"migration-graph.mjs","names":[],"sources":["../../src/commands/migration-graph.ts"],"sourcesContent":["import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n readContractEnvelope,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { migrationGraphToRenderInput } from '../utils/formatters/graph-migration-mapper';\nimport { graphRenderer } from '../utils/formatters/graph-render';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { StatusRef } from '../utils/migration-types';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationGraphOptions extends CommonCommandOptions {\n readonly config?: string;\n readonly dot?: boolean;\n}\n\nexport interface MigrationGraphResult {\n readonly ok: true;\n readonly graph: MigrationGraph;\n readonly contractHash: string | null;\n readonly refs: readonly StatusRef[];\n readonly summary: string;\n}\n\nasync function executeMigrationGraphCommand(\n options: MigrationGraphOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationGraphResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration graph',\n description: 'Show the migration graph topology',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n let graph: MigrationGraph;\n try {\n ({ graph } = await loadMigrationPackages(appMigrationsDir));\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n let contractHash: string | null = null;\n try {\n const envelope = await readContractEnvelope(config);\n contractHash = envelope.storageHash;\n } catch {\n // Contract unreadable — render graph without contract marker\n }\n\n let refs: readonly StatusRef[] = [];\n try {\n const allRefs = await readRefs(refsDir);\n refs = Object.entries(allRefs).map(([name, entry]) => ({\n name,\n hash: entry.hash,\n active: false,\n }));\n } catch {\n // Refs unreadable — render graph without ref markers\n }\n\n return ok({\n ok: true,\n graph,\n contractHash,\n refs,\n summary: `${graph.nodes.size} node(s), ${graph.migrationByHash.size} edge(s)`,\n });\n}\n\nexport function createMigrationGraphCommand(): Command {\n const command = new Command('graph');\n setCommandDescriptions(\n command,\n 'Show the migration graph topology',\n 'Renders the migration graph as an ASCII tree. Offline — does not\\n' +\n 'consult the database. Use --json for machine-readable output or\\n' +\n '--dot for Graphviz DOT format.',\n );\n setCommandExamples(command, [\n 'prisma-next migration graph',\n 'prisma-next migration graph --json',\n 'prisma-next migration graph --dot',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dot', 'Output in Graphviz DOT format')\n .action(async (options: MigrationGraphOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationGraphCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (graphResult) => {\n // Explicit format flags win over the auto-JSON default. `flags.json`\n // is auto-enabled when stdout is non-TTY (per CLI Style Guide §\n // JSON Semantics); without this ordering, `migration graph --dot |\n // dot -Tsvg` pipes JSON into the GraphViz binary, which then\n // errors. `--dot` is the more specific instruction; honour it.\n if (options.dot) {\n const lines = ['digraph migrations {'];\n for (const edge of graphResult.graph.migrationByHash.values()) {\n const from = edge.from.slice(0, 12);\n const to = edge.to.slice(0, 12);\n lines.push(` \"${from}\" -> \"${to}\" [label=\"${edge.dirName}\"];`);\n }\n lines.push('}');\n ui.output(lines.join('\\n'));\n } else if (flags.json) {\n const nodes = [...graphResult.graph.nodes];\n const edges = [...graphResult.graph.migrationByHash.values()].map((e) => ({\n dirName: e.dirName,\n from: e.from,\n to: e.to,\n migrationHash: e.migrationHash,\n }));\n ui.output(\n JSON.stringify({ ok: true, nodes, edges, summary: graphResult.summary }, null, 2),\n );\n } else if (!flags.quiet) {\n const renderInput = migrationGraphToRenderInput({\n graph: graphResult.graph,\n mode: 'offline',\n markerHash: undefined,\n contractHash: graphResult.contractHash ?? EMPTY_CONTRACT_HASH,\n refs: graphResult.refs,\n activeRefHash: undefined,\n activeRefName: undefined,\n edgeStatuses: [],\n });\n const graphOutput = graphRenderer.render(renderInput.graph, {\n ...renderInput.options,\n colorize: flags.color !== false,\n });\n ui.log(graphOutput);\n ui.log(`\\n${graphResult.summary}`);\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as handleResult } from "../
|
|
5
|
-
import { t as TerminalUI } from "../terminal-ui-XtOQsqe9.mjs";
|
|
2
|
+
import { b as mapMigrationToolsError, y as errorUnexpected } from "../cli-errors-Djtz98Vm.mjs";
|
|
3
|
+
import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
|
|
4
|
+
import { S as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-BSb0tRC8.mjs";
|
|
6
5
|
import { Command } from "commander";
|
|
7
6
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
8
7
|
import { findPath } from "@prisma-next/migration-tools/migration-graph";
|
|
@@ -84,11 +83,8 @@ function createMigrationListCommand() {
|
|
|
84
83
|
}
|
|
85
84
|
]);
|
|
86
85
|
addGlobalOptions(command).option("--config <path>", "Path to prisma-next.config.ts").action(async (options) => {
|
|
87
|
-
const flags =
|
|
88
|
-
const ui =
|
|
89
|
-
color: flags.color,
|
|
90
|
-
interactive: flags.interactive
|
|
91
|
-
});
|
|
86
|
+
const flags = parseGlobalFlagsOrExit(options);
|
|
87
|
+
const ui = createTerminalUI(flags);
|
|
92
88
|
const exitCode = handleResult(await executeMigrationListCommand(options, flags, ui), flags, ui, (listResult) => {
|
|
93
89
|
if (flags.json) ui.output(JSON.stringify(listResult, null, 2));
|
|
94
90
|
else if (!flags.quiet) if (listResult.migrations.length === 0) ui.log("No migrations found");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-list.mjs","names":[],"sources":["../../src/commands/migration-list.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findPath } from '@prisma-next/migration-tools/migration-graph';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags,
|
|
1
|
+
{"version":3,"file":"migration-list.mjs","names":[],"sources":["../../src/commands/migration-list.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findPath } from '@prisma-next/migration-tools/migration-graph';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport {\n type CliStructuredError,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationListOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nexport interface MigrationListEntry {\n readonly dirName: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly operationCount: number;\n readonly createdAt: string;\n}\n\nexport interface MigrationListResult {\n readonly ok: true;\n readonly migrations: readonly MigrationListEntry[];\n readonly summary: string;\n}\n\nasync function executeMigrationListCommand(\n options: MigrationListOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationListResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration list',\n description: 'List on-disk migrations in topological order',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n ({ bundles, graph } = await loadMigrationPackages(appMigrationsDir));\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n if (bundles.length === 0) {\n return ok({ ok: true, migrations: [], summary: 'No migrations found' });\n }\n\n const leaves = [...graph.nodes].filter(\n (n) => !graph.forwardChain.has(n) || graph.forwardChain.get(n)!.length === 0,\n );\n const targetHash =\n leaves.length === 1 ? leaves[0]! : ([...graph.nodes].values().next().value as string);\n const chain = findPath(graph, EMPTY_CONTRACT_HASH, targetHash) ?? [];\n\n const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));\n const entries: MigrationListEntry[] = chain.map((edge) => {\n const pkg = pkgByDirName.get(edge.dirName);\n const ops = (pkg?.ops ?? []) as readonly MigrationPlanOperation[];\n return {\n dirName: edge.dirName,\n from: edge.from,\n to: edge.to,\n migrationHash: edge.migrationHash,\n operationCount: ops.length,\n createdAt: edge.createdAt,\n };\n });\n\n return ok({\n ok: true,\n migrations: entries,\n summary: `${entries.length} migration(s) on disk`,\n });\n}\n\nexport function createMigrationListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(\n command,\n 'List on-disk migrations in topological order',\n 'Enumerates all migration packages under migrations/<space>/ in\\n' +\n 'topological order. Offline — does not consult the database.',\n );\n setCommandExamples(command, ['prisma-next migration list']);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationListOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationListCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (listResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(listResult, null, 2));\n } else if (!flags.quiet) {\n if (listResult.migrations.length === 0) {\n ui.log('No migrations found');\n } else {\n for (const entry of listResult.migrations) {\n ui.log(\n `${entry.dirName} ${entry.migrationHash.slice(0, 16)}… ${entry.operationCount} op(s)`,\n );\n }\n ui.log(`\\n${listResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-log.d.mts","names":[],"sources":["../../src/commands/migration-log.ts"],"mappings":";;;UAqCiB,iBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,kBAAA;EAAA,SACN,EAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA,WAAkB,iBAAA;EAAA,SAClB,OAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"migration-log.d.mts","names":[],"sources":["../../src/commands/migration-log.ts"],"mappings":";;;UAqCiB,iBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,SAAA;AAAA;AAAA,UAGM,kBAAA;EAAA,SACN,EAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA,WAAkB,iBAAA;EAAA,SAClB,OAAA;AAAA;AAAA,iBA2HK,yBAAA,CAAA,GAA6B,OAAA"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as handleResult } from "../
|
|
5
|
-
import { t as
|
|
6
|
-
import { t as createControlClient } from "../client-Brv4qlfB.mjs";
|
|
2
|
+
import { b as mapMigrationToolsError, c as errorDriverRequired, o as errorDatabaseConnectionRequired, t as CliStructuredError, y as errorUnexpected } from "../cli-errors-Djtz98Vm.mjs";
|
|
3
|
+
import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
|
|
4
|
+
import { S as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, m as targetSupportsMigrations, o as maskConnectionUrl, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-BSb0tRC8.mjs";
|
|
5
|
+
import { t as createControlClient } from "../client-oXO2WCPD.mjs";
|
|
7
6
|
import { Command } from "commander";
|
|
8
7
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
9
8
|
import { findPath } from "@prisma-next/migration-tools/migration-graph";
|
|
@@ -91,6 +90,7 @@ async function executeMigrationLogCommand(options, flags, ui) {
|
|
|
91
90
|
summary: `${entries.length} migration(s) applied`
|
|
92
91
|
});
|
|
93
92
|
} catch (error) {
|
|
93
|
+
if (CliStructuredError.is(error)) return notOk(error);
|
|
94
94
|
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
95
95
|
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migration log: ${error instanceof Error ? error.message : String(error)}` }));
|
|
96
96
|
} finally {
|
|
@@ -120,11 +120,8 @@ function createMigrationLogCommand() {
|
|
|
120
120
|
}
|
|
121
121
|
]);
|
|
122
122
|
addGlobalOptions(command).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").action(async (options) => {
|
|
123
|
-
const flags =
|
|
124
|
-
const ui =
|
|
125
|
-
color: flags.color,
|
|
126
|
-
interactive: flags.interactive
|
|
127
|
-
});
|
|
123
|
+
const flags = parseGlobalFlagsOrExit(options);
|
|
124
|
+
const ui = createTerminalUI(flags);
|
|
128
125
|
const exitCode = handleResult(await executeMigrationLogCommand(options, flags, ui), flags, ui, (logResult) => {
|
|
129
126
|
if (flags.json) ui.output(JSON.stringify(logResult, null, 2));
|
|
130
127
|
else if (!flags.quiet) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-log.mjs","names":[],"sources":["../../src/commands/migration-log.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findPath } from '@prisma-next/migration-tools/migration-graph';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { cyan, dim } from 'colorette';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n type CliStructuredError,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n maskConnectionUrl,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n targetSupportsMigrations,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationLogOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n}\n\nexport interface MigrationLogEntry {\n readonly dirName: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly operationCount: number;\n readonly createdAt: string;\n}\n\nexport interface MigrationLogResult {\n readonly ok: true;\n readonly markerHash: string | null;\n readonly applied: readonly MigrationLogEntry[];\n readonly summary: string;\n}\n\nasync function executeMigrationLogCommand(\n options: MigrationLogOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationLogResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for migration log (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migration log',\n }),\n );\n }\n if (!config.driver) {\n return notOk(errorDriverRequired({ why: 'Config.driver is required for migration log' }));\n }\n if (!targetSupportsMigrations(config.target)) {\n return notOk(errorUnexpected('Target does not support migrations'));\n }\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration log',\n description: 'Show executed migration history',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ...(typeof dbConnection === 'string'\n ? [{ label: 'database', value: maskConnectionUrl(dbConnection) }]\n : []),\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n ({ bundles, graph } = await loadMigrationPackages(appMigrationsDir));\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n try {\n await client.connect(dbConnection);\n const marker = await client.readMarker();\n const markerHash = marker?.storageHash ?? null;\n\n if (!markerHash) {\n return ok({\n ok: true,\n markerHash: null,\n applied: [],\n summary: 'No migrations applied (database has no marker)',\n });\n }\n\n const appliedPath = findPath(graph, EMPTY_CONTRACT_HASH, markerHash);\n if (appliedPath === null) {\n return notOk(\n errorUnexpected('Database marker is not reachable from migration history', {\n why: `Marker hash ${markerHash} is not reachable from the root of the on-disk migration graph.`,\n fix: 'The database may have been migrated outside this project. Use `migration status` to inspect the current state.',\n }),\n );\n }\n const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));\n const entries: MigrationLogEntry[] = appliedPath.map((edge) => {\n const pkg = pkgByDirName.get(edge.dirName);\n const ops = (pkg?.ops ?? []) as readonly MigrationPlanOperation[];\n return {\n dirName: edge.dirName,\n from: edge.from,\n to: edge.to,\n migrationHash: edge.migrationHash,\n operationCount: ops.length,\n createdAt: edge.createdAt,\n };\n });\n\n return ok({\n ok: true,\n markerHash,\n applied: entries,\n summary: `${entries.length} migration(s) applied`,\n });\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migration log: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrationLogCommand(): Command {\n const command = new Command('log');\n setCommandDescriptions(\n command,\n 'Show executed migration history',\n 'Reads the database marker and displays the applied migration chain\\n' +\n 'from the initial state to the current marker position.',\n );\n setCommandExamples(command, [\n 'prisma-next migration log --db $DATABASE_URL',\n 'prisma-next migration log --json --db $DATABASE_URL',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationLogOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const result = await executeMigrationLogCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (logResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(logResult, null, 2));\n } else if (!flags.quiet) {\n const c = (fn: (s: string) => string, s: string) => (flags.color !== false ? fn(s) : s);\n if (logResult.applied.length === 0) {\n ui.log(logResult.summary);\n } else {\n for (const entry of logResult.applied) {\n ui.log(\n `${c(cyan, '✓')} ${entry.dirName} ${c(dim, entry.migrationHash.slice(0, 16) + '…')} ${entry.operationCount} op(s)`,\n );\n }\n ui.log(`\\n${logResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-log.mjs","names":[],"sources":["../../src/commands/migration-log.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findPath } from '@prisma-next/migration-tools/migration-graph';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { cyan, dim } from 'colorette';\nimport { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n CliStructuredError,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n loadMigrationPackages,\n maskConnectionUrl,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n targetSupportsMigrations,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationLogOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n}\n\nexport interface MigrationLogEntry {\n readonly dirName: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly operationCount: number;\n readonly createdAt: string;\n}\n\nexport interface MigrationLogResult {\n readonly ok: true;\n readonly markerHash: string | null;\n readonly applied: readonly MigrationLogEntry[];\n readonly summary: string;\n}\n\nasync function executeMigrationLogCommand(\n options: MigrationLogOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationLogResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for migration log (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migration log',\n }),\n );\n }\n if (!config.driver) {\n return notOk(errorDriverRequired({ why: 'Config.driver is required for migration log' }));\n }\n if (!targetSupportsMigrations(config.target)) {\n return notOk(errorUnexpected('Target does not support migrations'));\n }\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration log',\n description: 'Show executed migration history',\n details: [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ...(typeof dbConnection === 'string'\n ? [{ label: 'database', value: maskConnectionUrl(dbConnection) }]\n : []),\n ],\n flags,\n });\n ui.stderr(header);\n }\n\n let bundles: Awaited<ReturnType<typeof loadMigrationPackages>>['bundles'];\n let graph: Awaited<ReturnType<typeof loadMigrationPackages>>['graph'];\n try {\n ({ bundles, graph } = await loadMigrationPackages(appMigrationsDir));\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n try {\n await client.connect(dbConnection);\n const marker = await client.readMarker();\n const markerHash = marker?.storageHash ?? null;\n\n if (!markerHash) {\n return ok({\n ok: true,\n markerHash: null,\n applied: [],\n summary: 'No migrations applied (database has no marker)',\n });\n }\n\n const appliedPath = findPath(graph, EMPTY_CONTRACT_HASH, markerHash);\n if (appliedPath === null) {\n return notOk(\n errorUnexpected('Database marker is not reachable from migration history', {\n why: `Marker hash ${markerHash} is not reachable from the root of the on-disk migration graph.`,\n fix: 'The database may have been migrated outside this project. Use `migration status` to inspect the current state.',\n }),\n );\n }\n const pkgByDirName = new Map(bundles.map((p) => [p.dirName, p]));\n const entries: MigrationLogEntry[] = appliedPath.map((edge) => {\n const pkg = pkgByDirName.get(edge.dirName);\n const ops = (pkg?.ops ?? []) as readonly MigrationPlanOperation[];\n return {\n dirName: edge.dirName,\n from: edge.from,\n to: edge.to,\n migrationHash: edge.migrationHash,\n operationCount: ops.length,\n createdAt: edge.createdAt,\n };\n });\n\n return ok({\n ok: true,\n markerHash,\n applied: entries,\n summary: `${entries.length} migration(s) applied`,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) return notOk(error);\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migration log: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrationLogCommand(): Command {\n const command = new Command('log');\n setCommandDescriptions(\n command,\n 'Show executed migration history',\n 'Reads the database marker and displays the applied migration chain\\n' +\n 'from the initial state to the current marker position.',\n );\n setCommandExamples(command, [\n 'prisma-next migration log --db $DATABASE_URL',\n 'prisma-next migration log --json --db $DATABASE_URL',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration status', oneLiner: 'Show migration path and pending status' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationLogOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const result = await executeMigrationLogCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (logResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(logResult, null, 2));\n } else if (!flags.quiet) {\n const c = (fn: (s: string) => string, s: string) => (flags.color !== false ? fn(s) : s);\n if (logResult.applied.length === 0) {\n ui.log(logResult.summary);\n } else {\n for (const entry of logResult.applied) {\n ui.log(\n `${c(cyan, '✓')} ${entry.dirName} ${c(dim, entry.migrationHash.slice(0, 16) + '…')} ${entry.operationCount} op(s)`,\n );\n }\n ui.log(`\\n${logResult.summary}`);\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n"],"mappings":";;;;;;;;;;;;AAqDA,eAAe,2BACb,SACA,OACA,IACyD;CACzD,MAAM,SAAS,MAAM,WAAW,QAAQ,OAAO;CAC/C,MAAM,EAAE,YAAY,kBAAkB,0BAA0B,sBAC9D,QAAQ,QACR,OACD;CAED,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;CAC9C,IAAI,CAAC,cACH,OAAO,MACL,gCAAgC;EAC9B,KAAK,2EAA2E,WAAW;EAC3F,aAAa;EACd,CAAC,CACH;CAEH,IAAI,CAAC,OAAO,QACV,OAAO,MAAM,oBAAoB,EAAE,KAAK,+CAA+C,CAAC,CAAC;CAE3F,IAAI,CAAC,yBAAyB,OAAO,OAAO,EAC1C,OAAO,MAAM,gBAAgB,qCAAqC,CAAC;CAGrE,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAM,SAAS,mBAAmB;GAChC,SAAS;GACT,aAAa;GACb,SAAS;IACP;KAAE,OAAO;KAAU,OAAO;KAAY;IACtC;KAAE,OAAO;KAAc,OAAO;KAAuB;IACrD,GAAI,OAAO,iBAAiB,WACxB,CAAC;KAAE,OAAO;KAAY,OAAO,kBAAkB,aAAa;KAAE,CAAC,GAC/D,EAAE;IACP;GACD;GACD,CAAC;EACF,GAAG,OAAO,OAAO;;CAGnB,IAAI;CACJ,IAAI;CACJ,IAAI;EACF,CAAC,CAAE,SAAS,SAAU,MAAM,sBAAsB,iBAAiB;UAC5D,OAAO;EACd,IAAI,oBAAoB,GAAG,MAAM,EAAE,OAAO,MAAM,uBAAuB,MAAM,CAAC;EAC9E,OAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,8BAA8B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC1F,CAAC,CACH;;CAGH,MAAM,SAAS,oBAAoB;EACjC,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,gBAAgB,OAAO,kBAAkB,EAAE;EAC5C,CAAC;CAEF,IAAI;EACF,MAAM,OAAO,QAAQ,aAAa;EAElC,MAAM,cAAa,MADE,OAAO,YAAY,GACb,eAAe;EAE1C,IAAI,CAAC,YACH,OAAO,GAAG;GACR,IAAI;GACJ,YAAY;GACZ,SAAS,EAAE;GACX,SAAS;GACV,CAAC;EAGJ,MAAM,cAAc,SAAS,OAAO,qBAAqB,WAAW;EACpE,IAAI,gBAAgB,MAClB,OAAO,MACL,gBAAgB,2DAA2D;GACzE,KAAK,eAAe,WAAW;GAC/B,KAAK;GACN,CAAC,CACH;EAEH,MAAM,eAAe,IAAI,IAAI,QAAQ,KAAK,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;EAChE,MAAM,UAA+B,YAAY,KAAK,SAAS;GAE7D,MAAM,MADM,aAAa,IAAI,KAAK,QAClB,EAAE,OAAO,EAAE;GAC3B,OAAO;IACL,SAAS,KAAK;IACd,MAAM,KAAK;IACX,IAAI,KAAK;IACT,eAAe,KAAK;IACpB,gBAAgB,IAAI;IACpB,WAAW,KAAK;IACjB;IACD;EAEF,OAAO,GAAG;GACR,IAAI;GACJ;GACA,SAAS;GACT,SAAS,GAAG,QAAQ,OAAO;GAC5B,CAAC;UACK,OAAO;EACd,IAAI,mBAAmB,GAAG,MAAM,EAAE,OAAO,MAAM,MAAM;EACrD,IAAI,oBAAoB,GAAG,MAAM,EAAE,OAAO,MAAM,uBAAuB,MAAM,CAAC;EAC9E,OAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC7F,CAAC,CACH;WACO;EACR,MAAM,OAAO,OAAO;;;AAIxB,SAAgB,4BAAqC;CACnD,MAAM,UAAU,IAAI,QAAQ,MAAM;CAClC,uBACE,SACA,mCACA,6HAED;CACD,mBAAmB,SAAS,CAC1B,gDACA,sDACD,CAAC;CACF,kBAAkB,SAAS;EACzB;GAAE,MAAM;GAAoB,UAAU;GAA0C;EAChF;GAAE,MAAM;GAAkB,UAAU;GAA2B;EAC/D;GAAE,MAAM;GAAmB,UAAU;GAAqC;EAC1E;GAAE,MAAM;GAAkB,UAAU;GAAsC;EAC3E,CAAC;CACF,iBAAiB,QAAQ,CACtB,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,OAAO,YAAiC;EAC9C,MAAM,QAAQ,uBAAuB,QAAQ;EAC7C,MAAM,KAAK,iBAAiB,MAAM;EAElC,MAAM,WAAW,aAAa,MADT,2BAA2B,SAAS,OAAO,GAAG,EAC7B,OAAO,KAAK,cAAc;GAC9D,IAAI,MAAM,MACR,GAAG,OAAO,KAAK,UAAU,WAAW,MAAM,EAAE,CAAC;QACxC,IAAI,CAAC,MAAM,OAAO;IACvB,MAAM,KAAK,IAA2B,MAAe,MAAM,UAAU,QAAQ,GAAG,EAAE,GAAG;IACrF,IAAI,UAAU,QAAQ,WAAW,GAC/B,GAAG,IAAI,UAAU,QAAQ;SACpB;KACL,KAAK,MAAM,SAAS,UAAU,SAC5B,GAAG,IACD,GAAG,EAAE,MAAM,IAAI,CAAC,GAAG,MAAM,QAAQ,IAAI,EAAE,KAAK,MAAM,cAAc,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,MAAM,eAAe,QAC9G;KAEH,GAAG,IAAI,KAAK,UAAU,UAAU;;;IAGpC;EACF,QAAQ,KAAK,SAAS;GACtB;CACJ,OAAO"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import { _ as
|
|
3
|
-
import { t as assertFrameworkComponentsCompatible } from "../framework-components-
|
|
4
|
-
import {
|
|
5
|
-
import { t as handleResult } from "../
|
|
6
|
-
import { t as TerminalUI } from "../terminal-ui-XtOQsqe9.mjs";
|
|
2
|
+
import { _ as errorTargetMigrationNotSupported, b as mapMigrationToolsError, g as errorRuntime, l as errorFileNotFound, t as CliStructuredError, y as errorUnexpected } from "../cli-errors-Djtz98Vm.mjs";
|
|
3
|
+
import { t as assertFrameworkComponentsCompatible } from "../framework-components-65gOHkHB.mjs";
|
|
4
|
+
import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
|
|
5
|
+
import { S as formatStyledHeader, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, i as getTargetMigrations, l as resolveMigrationPaths, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-BSb0tRC8.mjs";
|
|
7
6
|
import { Command } from "commander";
|
|
8
7
|
import { getEmittedArtifactPaths } from "@prisma-next/emitter";
|
|
9
8
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
@@ -162,11 +161,8 @@ function createMigrationNewCommand() {
|
|
|
162
161
|
setCommandDescriptions(command, "Scaffold a new migration for manual authoring", "Creates a migration package with a migration.ts file for manual authoring.\nWrite the migration body in migration.ts, then run the file with Node\n(`node migration.ts`) to self-emit ops.json and attest the package.");
|
|
163
162
|
setCommandExamples(command, ["prisma-next migration new --name split-name", "prisma-next migration new --name custom-fk --from sha256:abc..."]);
|
|
164
163
|
addGlobalOptions(command).option("--name <slug>", "Migration name (used in directory name)").option("--from <hash>", "Starting contract hash (default: latest migration target)").option("--config <path>", "Path to prisma-next.config.ts").action(async (options) => {
|
|
165
|
-
const flags =
|
|
166
|
-
const ui =
|
|
167
|
-
color: flags.color,
|
|
168
|
-
interactive: flags.interactive
|
|
169
|
-
});
|
|
164
|
+
const flags = parseGlobalFlagsOrExit(options);
|
|
165
|
+
const ui = createTerminalUI(flags);
|
|
170
166
|
if (!flags.json && !flags.quiet) {
|
|
171
167
|
const header = formatStyledHeader({
|
|
172
168
|
command: "migration new",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-new.mjs","names":[],"sources":["../../src/commands/migration-new.ts"],"sourcesContent":["/**\n * `migration new` — scaffolds a migration package with a `migration.ts` file\n * for manual authoring.\n *\n * The planner's `emptyMigration(context)` returns a\n * `MigrationPlanWithAuthoringSurface`, whose `renderTypeScript()` produces\n * the target-appropriate empty stub. The CLI writes the returned source\n * verbatim.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport { APP_SPACE_ID, createControlStack } from '@prisma-next/framework-components/control';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { computeMigrationHash } from '@prisma-next/migration-tools/hash';\nimport {\n copyFilesWithRename,\n formatMigrationDirName,\n readMigrationsDir,\n writeMigrationPackage,\n} from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport {\n findLatestMigration,\n reconstructGraph,\n} from '@prisma-next/migration-tools/migration-graph';\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 CliStructuredError,\n errorFileNotFound,\n errorRuntime,\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 { formatStyledHeader } from '../utils/formatters/styled';\nimport { assertFrameworkComponentsCompatible } from '../utils/framework-components';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationNewOptions extends CommonCommandOptions {\n readonly name?: string;\n readonly from?: string;\n readonly config?: string;\n}\n\ninterface MigrationNewResult {\n readonly ok: true;\n readonly dir: string;\n readonly from: string | null;\n readonly to: string;\n readonly summary: string;\n}\n\nasync function executeMigrationNewCommand(\n options: MigrationNewOptions,\n): Promise<Result<MigrationNewResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);\n\n // Construct the family instance up-front so the on-disk contract read\n // below crosses the serializer seam (`familyInstance.deserializeContract`)\n // at the read site, not somewhere downstream. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n const contractPathAbsolute = resolveContractPath(config);\n\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 errorRuntime(`Contract file not found at ${contractPathAbsolute}`, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: 'Run `prisma-next contract emit` first to generate the contract',\n }),\n );\n }\n throw error;\n }\n\n let toContract: Contract;\n try {\n toContract = familyInstance.deserializeContract(JSON.parse(contractJsonContent) as unknown);\n } catch (error) {\n return notOk(\n errorRuntime('Contract JSON is invalid', {\n why: `Failed to deserialize ${contractPathAbsolute}: ${error instanceof Error ? error.message : String(error)}`,\n fix: 'Run `prisma-next contract emit` to regenerate the contract',\n }),\n );\n }\n\n const toStorageHash = toContract.storage?.storageHash;\n if (typeof toStorageHash !== 'string') {\n return notOk(\n errorRuntime('Contract is missing storageHash', {\n why: `Contract at ${contractPathAbsolute} has no storageHash`,\n fix: 'Run `prisma-next contract emit` to regenerate the contract',\n }),\n );\n }\n\n let fromHash: string | null = null;\n let fromContractSourceDir: string | null = null;\n\n try {\n const packages = await readMigrationsDir(appMigrationsDir);\n\n if (packages.length > 0) {\n const graph = reconstructGraph(packages);\n\n if (options.from) {\n const match = packages.find((p) => p.metadata.to.startsWith(options.from!));\n if (!match) {\n return notOk(\n errorRuntime('Starting contract not found', {\n why: `No migration with to hash matching \"${options.from}\" exists in ${appMigrationsRelative}`,\n fix: 'Check that the --from hash matches a known migration target hash.',\n }),\n );\n }\n fromHash = match.metadata.to;\n fromContractSourceDir = match.dirPath;\n } else {\n const latestMigration = findLatestMigration(graph);\n if (latestMigration) {\n fromHash = latestMigration.to;\n const leafPkg = packages.find(\n (p) => p.metadata.migrationHash === latestMigration.migrationHash,\n );\n if (leafPkg) {\n fromContractSourceDir = leafPkg.dirPath;\n }\n }\n }\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n\n if (fromHash === toStorageHash && !options.from) {\n return notOk(\n errorRuntime('No changes detected', {\n why: 'The from and to contract hashes are identical — there is nothing to migrate.',\n fix: 'Change the contract and run `prisma-next contract emit` before creating a new migration. To author a data-only migration on the current contract hash, pass `--from <hash>` explicitly.',\n }),\n );\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 // `migration new` scaffolds an empty `migration.ts` for the user to\n // fill, so we attest over `ops: []`. Re-running self-emit after the\n // user adds operations will produce a different `migrationHash` (over\n // the real ops). This is intentional — there is no on-disk draft.\n const baseMetadata: Omit<MigrationMetadata, 'migrationHash'> = {\n from: fromHash,\n to: toStorageHash,\n hints: {\n used: [],\n applied: [],\n plannerVersion: '1.0.0',\n },\n labels: [],\n providedInvariants: [],\n createdAt: timestamp.toISOString(),\n };\n const metadata: MigrationMetadata = {\n ...baseMetadata,\n migrationHash: computeMigrationHash(baseMetadata, []),\n };\n\n const migrations = getTargetMigrations(config.target);\n if (!migrations) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.targetId}\" does not support migrations`,\n }),\n );\n }\n\n try {\n assertFrameworkComponentsCompatible(config.family.familyId, config.target.targetId, [\n config.target,\n config.adapter,\n ...(config.extensionPacks ?? []),\n ]);\n\n await writeMigrationPackage(packageDir, metadata, []);\n const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);\n await copyFilesWithRename(packageDir, [\n { sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },\n { sourcePath: destinationArtifacts.dtsPath, destName: 'end-contract.d.ts' },\n ]);\n if (fromContractSourceDir !== null) {\n const sourceArtifacts = getEmittedArtifactPaths(\n join(fromContractSourceDir, 'end-contract.json'),\n );\n try {\n await copyFilesWithRename(packageDir, [\n { sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },\n { sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },\n ]);\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(sourceArtifacts.jsonPath, {\n why: `Predecessor migration is missing its destination contract snapshot at ${sourceArtifacts.jsonPath}`,\n fix: 'Re-emit the predecessor migration (`prisma-next migration plan` from its source) so its sibling `end-contract.json` is restored, then re-run this command.',\n }),\n );\n }\n throw error;\n }\n }\n\n const planner = migrations.createPlanner(familyInstance);\n const emptyPlan = planner.emptyMigration(\n {\n packageDir,\n contractJsonPath: join(packageDir, 'end-contract.json'),\n fromHash,\n toHash: toStorageHash,\n },\n APP_SPACE_ID,\n );\n await writeMigrationTs(packageDir, emptyPlan.renderTypeScript());\n\n return ok({\n ok: true as const,\n dir: relative(process.cwd(), packageDir),\n from: fromHash,\n to: toStorageHash,\n summary: `Scaffolded migration at ${relative(process.cwd(), packageDir)}`,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to scaffold migration: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n}\n\nexport function createMigrationNewCommand(): Command {\n const command = new Command('new');\n setCommandDescriptions(\n command,\n 'Scaffold a new migration for manual authoring',\n 'Creates a migration package with a migration.ts file for manual authoring.\\n' +\n 'Write the migration body in migration.ts, then run the file with Node\\n' +\n '(`node migration.ts`) to self-emit ops.json and attest the package.',\n );\n setCommandExamples(command, [\n 'prisma-next migration new --name split-name',\n 'prisma-next migration new --name custom-fk --from sha256:abc...',\n ]);\n addGlobalOptions(command)\n .option('--name <slug>', 'Migration name (used in directory name)')\n .option('--from <hash>', 'Starting contract hash (default: latest migration target)')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationNewOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration new',\n description: 'Scaffold a new migration',\n details: [],\n flags,\n });\n ui.stderr(header);\n }\n\n const result = await executeMigrationNewCommand(options);\n\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value, null, 2));\n } else if (!flags.quiet) {\n ui.output(`\\nScaffolded migration at ${value.dir}`);\n ui.output(` from: ${value.from}`);\n ui.output(` to: ${value.to}`);\n ui.output(\n `\\nEdit migration.ts, then run it directly (\\`node \"${value.dir}/migration.ts\"\\`) to self-emit and attest.`,\n );\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-new.mjs","names":[],"sources":["../../src/commands/migration-new.ts"],"sourcesContent":["/**\n * `migration new` — scaffolds a migration package with a `migration.ts` file\n * for manual authoring.\n *\n * The planner's `emptyMigration(context)` returns a\n * `MigrationPlanWithAuthoringSurface`, whose `renderTypeScript()` produces\n * the target-appropriate empty stub. The CLI writes the returned source\n * verbatim.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport { APP_SPACE_ID, createControlStack } from '@prisma-next/framework-components/control';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { computeMigrationHash } from '@prisma-next/migration-tools/hash';\nimport {\n copyFilesWithRename,\n formatMigrationDirName,\n readMigrationsDir,\n writeMigrationPackage,\n} from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport {\n findLatestMigration,\n reconstructGraph,\n} from '@prisma-next/migration-tools/migration-graph';\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 CliStructuredError,\n errorFileNotFound,\n errorRuntime,\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 { formatStyledHeader } from '../utils/formatters/styled';\nimport { assertFrameworkComponentsCompatible } from '../utils/framework-components';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationNewOptions extends CommonCommandOptions {\n readonly name?: string;\n readonly from?: string;\n readonly config?: string;\n}\n\ninterface MigrationNewResult {\n readonly ok: true;\n readonly dir: string;\n readonly from: string | null;\n readonly to: string;\n readonly summary: string;\n}\n\nasync function executeMigrationNewCommand(\n options: MigrationNewOptions,\n): Promise<Result<MigrationNewResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);\n\n // Construct the family instance up-front so the on-disk contract read\n // below crosses the serializer seam (`familyInstance.deserializeContract`)\n // at the read site, not somewhere downstream. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n const contractPathAbsolute = resolveContractPath(config);\n\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 errorRuntime(`Contract file not found at ${contractPathAbsolute}`, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: 'Run `prisma-next contract emit` first to generate the contract',\n }),\n );\n }\n throw error;\n }\n\n let toContract: Contract;\n try {\n toContract = familyInstance.deserializeContract(JSON.parse(contractJsonContent) as unknown);\n } catch (error) {\n return notOk(\n errorRuntime('Contract JSON is invalid', {\n why: `Failed to deserialize ${contractPathAbsolute}: ${error instanceof Error ? error.message : String(error)}`,\n fix: 'Run `prisma-next contract emit` to regenerate the contract',\n }),\n );\n }\n\n const toStorageHash = toContract.storage?.storageHash;\n if (typeof toStorageHash !== 'string') {\n return notOk(\n errorRuntime('Contract is missing storageHash', {\n why: `Contract at ${contractPathAbsolute} has no storageHash`,\n fix: 'Run `prisma-next contract emit` to regenerate the contract',\n }),\n );\n }\n\n let fromHash: string | null = null;\n let fromContractSourceDir: string | null = null;\n\n try {\n const packages = await readMigrationsDir(appMigrationsDir);\n\n if (packages.length > 0) {\n const graph = reconstructGraph(packages);\n\n if (options.from) {\n const match = packages.find((p) => p.metadata.to.startsWith(options.from!));\n if (!match) {\n return notOk(\n errorRuntime('Starting contract not found', {\n why: `No migration with to hash matching \"${options.from}\" exists in ${appMigrationsRelative}`,\n fix: 'Check that the --from hash matches a known migration target hash.',\n }),\n );\n }\n fromHash = match.metadata.to;\n fromContractSourceDir = match.dirPath;\n } else {\n const latestMigration = findLatestMigration(graph);\n if (latestMigration) {\n fromHash = latestMigration.to;\n const leafPkg = packages.find(\n (p) => p.metadata.migrationHash === latestMigration.migrationHash,\n );\n if (leafPkg) {\n fromContractSourceDir = leafPkg.dirPath;\n }\n }\n }\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n\n if (fromHash === toStorageHash && !options.from) {\n return notOk(\n errorRuntime('No changes detected', {\n why: 'The from and to contract hashes are identical — there is nothing to migrate.',\n fix: 'Change the contract and run `prisma-next contract emit` before creating a new migration. To author a data-only migration on the current contract hash, pass `--from <hash>` explicitly.',\n }),\n );\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 // `migration new` scaffolds an empty `migration.ts` for the user to\n // fill, so we attest over `ops: []`. Re-running self-emit after the\n // user adds operations will produce a different `migrationHash` (over\n // the real ops). This is intentional — there is no on-disk draft.\n const baseMetadata: Omit<MigrationMetadata, 'migrationHash'> = {\n from: fromHash,\n to: toStorageHash,\n hints: {\n used: [],\n applied: [],\n plannerVersion: '1.0.0',\n },\n labels: [],\n providedInvariants: [],\n createdAt: timestamp.toISOString(),\n };\n const metadata: MigrationMetadata = {\n ...baseMetadata,\n migrationHash: computeMigrationHash(baseMetadata, []),\n };\n\n const migrations = getTargetMigrations(config.target);\n if (!migrations) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.targetId}\" does not support migrations`,\n }),\n );\n }\n\n try {\n assertFrameworkComponentsCompatible(config.family.familyId, config.target.targetId, [\n config.target,\n config.adapter,\n ...(config.extensionPacks ?? []),\n ]);\n\n await writeMigrationPackage(packageDir, metadata, []);\n const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);\n await copyFilesWithRename(packageDir, [\n { sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },\n { sourcePath: destinationArtifacts.dtsPath, destName: 'end-contract.d.ts' },\n ]);\n if (fromContractSourceDir !== null) {\n const sourceArtifacts = getEmittedArtifactPaths(\n join(fromContractSourceDir, 'end-contract.json'),\n );\n try {\n await copyFilesWithRename(packageDir, [\n { sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },\n { sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },\n ]);\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(sourceArtifacts.jsonPath, {\n why: `Predecessor migration is missing its destination contract snapshot at ${sourceArtifacts.jsonPath}`,\n fix: 'Re-emit the predecessor migration (`prisma-next migration plan` from its source) so its sibling `end-contract.json` is restored, then re-run this command.',\n }),\n );\n }\n throw error;\n }\n }\n\n const planner = migrations.createPlanner(familyInstance);\n const emptyPlan = planner.emptyMigration(\n {\n packageDir,\n contractJsonPath: join(packageDir, 'end-contract.json'),\n fromHash,\n toHash: toStorageHash,\n },\n APP_SPACE_ID,\n );\n await writeMigrationTs(packageDir, emptyPlan.renderTypeScript());\n\n return ok({\n ok: true as const,\n dir: relative(process.cwd(), packageDir),\n from: fromHash,\n to: toStorageHash,\n summary: `Scaffolded migration at ${relative(process.cwd(), packageDir)}`,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to scaffold migration: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n}\n\nexport function createMigrationNewCommand(): Command {\n const command = new Command('new');\n setCommandDescriptions(\n command,\n 'Scaffold a new migration for manual authoring',\n 'Creates a migration package with a migration.ts file for manual authoring.\\n' +\n 'Write the migration body in migration.ts, then run the file with Node\\n' +\n '(`node migration.ts`) to self-emit ops.json and attest the package.',\n );\n setCommandExamples(command, [\n 'prisma-next migration new --name split-name',\n 'prisma-next migration new --name custom-fk --from sha256:abc...',\n ]);\n addGlobalOptions(command)\n .option('--name <slug>', 'Migration name (used in directory name)')\n .option('--from <hash>', 'Starting contract hash (default: latest migration target)')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationNewOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration new',\n description: 'Scaffold a new migration',\n details: [],\n flags,\n });\n ui.stderr(header);\n }\n\n const result = await executeMigrationNewCommand(options);\n\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value, null, 2));\n } else if (!flags.quiet) {\n ui.output(`\\nScaffolded migration at ${value.dir}`);\n ui.output(` from: ${value.from}`);\n ui.output(` to: ${value.to}`);\n ui.output(\n `\\nEdit migration.ts, then run it directly (\\`node \"${value.dir}/migration.ts\"\\`) to self-emit and attest.`,\n );\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as GlobalFlags } from "../global-flags-
|
|
1
|
+
import { t as GlobalFlags } from "../global-flags-CdE7M0d9.mjs";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { Result } from "@prisma-next/utils/result";
|
|
4
4
|
import { OperationPreview } from "@prisma-next/framework-components/control";
|
|
@@ -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-CFwqw3Gk.mjs";
|
|
2
2
|
export { createMigrationPlanCommand, formatMigrationPlanOutput, resolveBundleByPrefix };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as CliStructuredError } from "../cli-errors-
|
|
1
|
+
import { t as CliStructuredError } from "../cli-errors-Czmx92Zy.mjs";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { Result } from "@prisma-next/utils/result";
|
|
4
4
|
import { OperationPreview } from "@prisma-next/framework-components/control";
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as handleResult } from "../
|
|
5
|
-
import { t as
|
|
6
|
-
import { t as
|
|
7
|
-
import {
|
|
8
|
-
import { a as formatMigrationShowOutput } from "../migrations-DyUf5lTt.mjs";
|
|
2
|
+
import { a as errorContractValidationFailed, b as mapMigrationToolsError, g as errorRuntime, l as errorFileNotFound, x as mapRefResolutionError, y as errorUnexpected } from "../cli-errors-Djtz98Vm.mjs";
|
|
3
|
+
import { t as createTerminalUI } from "../terminal-ui-BiB_8KNo.mjs";
|
|
4
|
+
import { S as formatStyledHeader, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "../command-helpers-BSb0tRC8.mjs";
|
|
5
|
+
import { t as createControlClient } from "../client-oXO2WCPD.mjs";
|
|
6
|
+
import { t as buildContractSpaceAggregate } from "../contract-space-aggregate-loader-BmNQwlws.mjs";
|
|
7
|
+
import { a as formatMigrationShowOutput } from "../migrations-CwZMa1Ck.mjs";
|
|
9
8
|
import { Command } from "commander";
|
|
10
9
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
11
10
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
@@ -260,11 +259,8 @@ function createMigrationShowCommand() {
|
|
|
260
259
|
}
|
|
261
260
|
]);
|
|
262
261
|
addGlobalOptions(command).argument("[target]", "Migration reference: directory name, hash/prefix, or path (defaults to latest)").option("--config <path>", "Path to prisma-next.config.ts").action(async (target, options) => {
|
|
263
|
-
const flags =
|
|
264
|
-
const ui =
|
|
265
|
-
color: flags.color,
|
|
266
|
-
interactive: flags.interactive
|
|
267
|
-
});
|
|
262
|
+
const flags = parseGlobalFlagsOrExit(options);
|
|
263
|
+
const ui = createTerminalUI(flags);
|
|
268
264
|
const exitCode = handleResult(await executeMigrationShowCommand(target, options, flags, ui), flags, ui, (showResult) => {
|
|
269
265
|
if (flags.json) ui.output(JSON.stringify(showResult, null, 2));
|
|
270
266
|
else if (!flags.quiet) ui.log(formatMigrationShowOutput(showResult, flags));
|