prisma-next 0.5.0-dev.74 → 0.5.0-dev.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +8 -8
- package/dist/{client-0ZX24FXF.mjs → client-qVH-rEgd.mjs} +433 -236
- package/dist/client-qVH-rEgd.mjs.map +1 -0
- package/dist/{result-handler-DWb1rFS-.mjs → command-helpers-BeZHkxV8.mjs} +22 -24
- package/dist/command-helpers-BeZHkxV8.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 +7 -5
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +5 -4
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +6 -5
- 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 +7 -5
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migration-apply.d.mts +29 -17
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +35 -129
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.mjs +4 -3
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +19 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +2 -2
- package/dist/commands/migration-ref.d.mts +1 -1
- package/dist/commands/migration-ref.mjs +3 -2
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +5 -4
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +104 -1
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -2
- package/dist/{contract-emit-DkMqO7f2.mjs → contract-emit-9DBda5Ou.mjs} +7 -5
- package/dist/{contract-emit-DkMqO7f2.mjs.map → contract-emit-9DBda5Ou.mjs.map} +1 -1
- package/dist/{contract-emit-B3ChISB_.mjs → contract-emit-B77TsJqf.mjs} +4 -15
- package/dist/{contract-emit-B3ChISB_.mjs.map → contract-emit-B77TsJqf.mjs.map} +1 -1
- package/dist/{contract-enrichment-CF6ogEJ_.mjs → contract-enrichment-Dani0mMW.mjs} +1 -1
- package/dist/{contract-enrichment-CF6ogEJ_.mjs.map → contract-enrichment-Dani0mMW.mjs.map} +1 -1
- package/dist/{contract-infer-BDKAE0B0.mjs → contract-infer-BK9YFGEG.mjs} +5 -4
- package/dist/{contract-infer-BDKAE0B0.mjs.map → contract-infer-BK9YFGEG.mjs.map} +1 -1
- package/dist/{db-verify-B4TdDKOI.mjs → db-verify-C0y1PCO2.mjs} +7 -6
- package/dist/{db-verify-B4TdDKOI.mjs.map → db-verify-C0y1PCO2.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +3 -746
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/extension-pack-inputs-C7xgE-vv.mjs +74 -0
- package/dist/extension-pack-inputs-C7xgE-vv.mjs.map +1 -0
- package/dist/{framework-components-gwAHl7ml.mjs → framework-components-ChqVUxR-.mjs} +1 -1
- package/dist/{framework-components-gwAHl7ml.mjs.map → framework-components-ChqVUxR-.mjs.map} +1 -1
- package/dist/global-flags-Icqpxk23.d.mts +12 -0
- package/dist/global-flags-Icqpxk23.d.mts.map +1 -0
- package/dist/helpers-eqdN8tH6.mjs +25 -0
- package/dist/helpers-eqdN8tH6.mjs.map +1 -0
- package/dist/{init-Deo7U8_U.mjs → init-CoDVPvQ4.mjs} +4 -4
- package/dist/{init-Deo7U8_U.mjs.map → init-CoDVPvQ4.mjs.map} +1 -1
- package/dist/{inspect-live-schema-BAgQMYpD.mjs → inspect-live-schema-CWYxGKlb.mjs} +4 -4
- package/dist/{inspect-live-schema-BAgQMYpD.mjs.map → inspect-live-schema-CWYxGKlb.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-B8J702Uh.mjs → migration-command-scaffold-B5dORFEv.mjs} +4 -4
- package/dist/{migration-command-scaffold-B8J702Uh.mjs.map → migration-command-scaffold-B5dORFEv.mjs.map} +1 -1
- package/dist/{migration-plan-BcKNnTM7.mjs → migration-plan-C6lVaHsO.mjs} +47 -23
- package/dist/migration-plan-C6lVaHsO.mjs.map +1 -0
- package/dist/{migration-status-CjwB2of-.mjs → migration-status-CZ-D5k7k.mjs} +161 -7
- package/dist/migration-status-CZ-D5k7k.mjs.map +1 -0
- package/dist/{migrations-CIK94AJf.mjs → migrations-D_UJnpuW.mjs} +67 -24
- package/dist/migrations-D_UJnpuW.mjs.map +1 -0
- package/dist/{output-DnjfCC_u.mjs → output-B16Kefzx.mjs} +1 -1
- package/dist/{output-DnjfCC_u.mjs.map → output-B16Kefzx.mjs.map} +1 -1
- package/dist/{progress-adapter-xASh41wr.mjs → progress-adapter-DFfvZcYL.mjs} +1 -1
- package/dist/{progress-adapter-xASh41wr.mjs.map → progress-adapter-DFfvZcYL.mjs.map} +1 -1
- package/dist/result-handler-rmPVKIP2.mjs +25 -0
- package/dist/result-handler-rmPVKIP2.mjs.map +1 -0
- package/dist/rolldown-runtime-twds-ZHy.mjs +14 -0
- package/dist/{terminal-ui-zaRDhJnP.mjs → terminal-ui-C_hFNbAn.mjs} +3 -23
- package/dist/terminal-ui-C_hFNbAn.mjs.map +1 -0
- package/dist/types-D7x-IFLO.d.mts +858 -0
- package/dist/types-D7x-IFLO.d.mts.map +1 -0
- package/dist/{verify-BEIa9638.mjs → verify-CiwNWM9N.mjs} +2 -2
- package/dist/{verify-BEIa9638.mjs.map → verify-CiwNWM9N.mjs.map} +1 -1
- package/package.json +10 -10
- package/dist/client-0ZX24FXF.mjs.map +0 -1
- package/dist/migration-plan-BcKNnTM7.mjs.map +0 -1
- package/dist/migration-status-CjwB2of-.mjs.map +0 -1
- package/dist/migrations-CIK94AJf.mjs.map +0 -1
- package/dist/result-handler-DWb1rFS-.mjs.map +0 -1
- package/dist/terminal-ui-zaRDhJnP.mjs.map +0 -1
- /package/dist/{cli-errors-QH8kf-C2.d.mts → cli-errors-B9OBbled.d.mts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-apply.mjs","names":[],"sources":["../../src/commands/migration-apply.ts"],"sourcesContent":["import { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport {\n errorNoInvariantPath,\n errorUnknownInvariant,\n MigrationToolsError,\n} from '@prisma-next/migration-tools/errors';\nimport { findPathWithDecision } from '@prisma-next/migration-tools/migration-graph';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport { readRefs, resolveRef } from '@prisma-next/migration-tools/refs';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\n\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { MigrationApplyFailure, MigrationApplyStep } from '../control-api/types';\nimport {\n CliStructuredError,\n type CliStructuredError as CliStructuredErrorType,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorRuntime,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n collectDeclaredInvariants,\n loadMigrationPackages,\n maskConnectionUrl,\n readContractEnvelope,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n targetSupportsMigrations,\n toPathDecisionResult,\n toStructuralEdge,\n} from '../utils/command-helpers';\nimport { formatMigrationApplyCommandOutput } from '../utils/formatters/migrations';\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 MigrationApplyCommandOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly ref?: string;\n}\n\nexport interface MigrationApplyResult {\n readonly ok: boolean;\n readonly migrationsApplied: number;\n readonly migrationsTotal: number;\n readonly markerHash: string;\n readonly applied: readonly {\n readonly dirName: string;\n readonly from: string | null;\n readonly to: string;\n readonly operationsExecuted: number;\n }[];\n readonly summary: string;\n readonly pathDecision?: {\n readonly fromHash: string;\n readonly toHash: string;\n readonly alternativeCount: number;\n readonly tieBreakReasons: readonly string[];\n readonly refName?: string;\n readonly requiredInvariants: readonly string[];\n readonly satisfiedInvariants: readonly string[];\n readonly selectedPath: readonly {\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly invariants: readonly string[];\n }[];\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nfunction mapApplyFailure(failure: MigrationApplyFailure): CliStructuredErrorType {\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Fix the issue and re-run `prisma-next migration apply` — previously applied migrations are preserved.',\n meta: failure.meta ?? {},\n });\n}\n\nfunction packageToStep(pkg: OnDiskMigrationPackage): MigrationApplyStep {\n return {\n dirName: pkg.dirName,\n from: pkg.metadata.from,\n to: pkg.metadata.to,\n toContract: pkg.metadata.toContract,\n operations: pkg.ops,\n providedInvariants: pkg.metadata.providedInvariants,\n };\n}\n\nasync function executeMigrationApplyCommand(\n options: MigrationApplyCommandOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrationApplyResult, CliStructuredErrorType>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsDir, appMigrationsRelative, refsDir } = 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 apply (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migration apply',\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: 'Config.driver is required for migration apply',\n }),\n );\n }\n\n if (!targetSupportsMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n let refEntry: RefEntry | undefined;\n let envelopeHash: string | undefined;\n const refName = options.ref;\n\n if (refName) {\n try {\n const refs = await readRefs(refsDir);\n refEntry = resolveRef(refs, refName);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n } else {\n try {\n const envelope = await readContractEnvelope(config);\n envelopeHash = envelope.storageHash;\n } catch (error) {\n return notOk(\n errorRuntime('Current contract is unavailable', {\n why: `Failed to read contract: ${error instanceof Error ? error.message : String(error)}`,\n fix: 'Run `prisma-next contract emit` to generate a valid contract.json, then retry apply.',\n }),\n );\n }\n }\n const destinationHash = refEntry?.hash ?? envelopeHash!;\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 (typeof dbConnection === 'string') {\n details.push({\n label: 'database',\n value: maskConnectionUrl(dbConnection),\n });\n }\n if (refName) {\n details.push({ label: 'ref', value: refName });\n }\n const header = formatStyledHeader({\n command: 'migration apply',\n description: 'Apply planned migrations to the database',\n url: 'https://pris.ly/migration-apply',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n // Read migrations and build migration chain model (offline — no DB needed)\n let migrations: Awaited<ReturnType<typeof loadMigrationPackages>>;\n try {\n migrations = await loadMigrationPackages(appMigrationsDir);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\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\n // Pre-check unknown invariants against `(declared by graph) ∪\n // (already on the marker)`. The union catches the edge case where the\n // ref carries an invariant whose declaring migration was retired (e.g.\n // history rewritten) but whose id is recorded on the marker —\n // surfacing that as MIGRATION.UNKNOWN_INVARIANT would be misleading\n // because the database has already satisfied the requirement, so the\n // marker-subtraction below empties `effectiveRequired` and apply\n // short-circuits to \"Already up to date\".\n if (refEntry && refEntry.invariants.length > 0) {\n const declared = collectDeclaredInvariants(migrations.graph);\n const known = new Set<string>(declared);\n for (const id of marker?.invariants ?? []) known.add(id);\n const unknown = refEntry.invariants.filter((id) => !known.has(id));\n if (unknown.length > 0) {\n return notOk(\n mapMigrationToolsError(\n errorUnknownInvariant({\n ...ifDefined('refName', refName),\n unknown,\n declared: [...declared].sort(),\n }),\n ),\n );\n }\n }\n\n // --- No migrations on disk ---\n if (migrations.bundles.length === 0) {\n if (marker?.storageHash) {\n return notOk(\n errorRuntime('Database has state but no migrations exist', {\n why: `The database marker hash \"${marker.storageHash}\" exists but no migrations were found in ${appMigrationsRelative}`,\n fix: 'Ensure the migrations directory is correct. If the database was managed with `db init` or `db update`, run `prisma-next db sign` to update the marker.',\n meta: { markerHash: marker.storageHash, migrationsDir: appMigrationsRelative },\n }),\n );\n }\n // Non-empty contract + no migrations = user needs to plan first.\n if (destinationHash !== EMPTY_CONTRACT_HASH) {\n return notOk(\n errorRuntime('Current contract has no planned migrations', {\n why: `No migrations were found in ${appMigrationsRelative}, but current contract hash is \"${destinationHash}\"`,\n fix: 'Run `prisma-next migration plan` to create a migration for the current contract.',\n meta: { destinationHash, migrationsDir: appMigrationsRelative },\n }),\n );\n }\n // Empty contract + no migrations = nothing to do.\n return ok({\n ok: true,\n migrationsApplied: 0,\n migrationsTotal: 0,\n markerHash: EMPTY_CONTRACT_HASH,\n applied: [],\n summary: 'No migrations found',\n timings: { total: Date.now() - startTime },\n });\n }\n\n // --- Validate marker state ---\n\n // The empty sentinel should never appear in a real marker row — if it does,\n // the marker was corrupted and replaying all migrations would be dangerous.\n if (marker?.storageHash === EMPTY_CONTRACT_HASH) {\n return notOk(\n errorRuntime('Database marker contains the empty sentinel hash', {\n why: `The marker row exists but contains the empty sentinel value \"${EMPTY_CONTRACT_HASH}\". This should never happen — the marker should contain the hash of the last applied contract.`,\n fix: 'The marker is corrupted. Run `prisma-next db sign` to overwrite it with the correct contract hash, or drop and recreate the database.',\n meta: { markerHash: EMPTY_CONTRACT_HASH },\n }),\n );\n }\n\n const markerHash = marker?.storageHash;\n\n if (markerHash !== undefined && !migrations.graph.nodes.has(markerHash)) {\n return notOk(\n errorRuntime('Database marker does not match any known migration', {\n why: `The database marker hash \"${markerHash}\" is not found in the migration history at ${appMigrationsRelative}`,\n fix: 'Ensure the migrations directory matches this database. If the database was managed with `db init` or `db update`, run `prisma-next db sign` to update the marker.',\n meta: { markerHash, knownNodes: [...migrations.graph.nodes] },\n }),\n );\n }\n\n if (!migrations.graph.nodes.has(destinationHash)) {\n return notOk(\n errorRuntime('Current contract has no planned migration path', {\n why: `Current contract hash \"${destinationHash}\" is not present in the migration history at ${appMigrationsRelative}`,\n fix: 'Run `prisma-next migration plan` to create a migration for the current contract, then re-run apply.',\n meta: { destinationHash, knownNodes: [...migrations.graph.nodes] },\n }),\n );\n }\n\n // \"No marker\" means the database is fresh — start from the empty contract hash.\n const originHash = markerHash ?? EMPTY_CONTRACT_HASH;\n\n const appliedInvariants = new Set(marker?.invariants ?? []);\n const effectiveRequired = new Set(\n (refEntry?.invariants ?? []).filter((id) => !appliedInvariants.has(id)),\n );\n\n const outcome = findPathWithDecision(migrations.graph, originHash, destinationHash, {\n ...ifDefined('refName', refName),\n required: effectiveRequired,\n });\n if (outcome.kind === 'unsatisfiable') {\n return notOk(\n mapMigrationToolsError(\n errorNoInvariantPath({\n ...ifDefined('refName', refName),\n required: [...effectiveRequired].sort(),\n missing: outcome.missing,\n structuralPath: outcome.structuralPath.map(toStructuralEdge),\n }),\n ),\n );\n }\n if (outcome.kind === 'unreachable') {\n return notOk(\n errorRuntime('No migration path from current state to target', {\n why: `Cannot find a path from \"${originHash}\" to target \"${destinationHash}\"`,\n fix: 'Check the migration history for gaps or inconsistencies.',\n meta: { markerHash: originHash, destinationHash },\n }),\n );\n }\n\n const pathDecision = toPathDecisionResult(outcome.decision);\n\n if (outcome.decision.selectedPath.length === 0) {\n return ok({\n ok: true,\n migrationsApplied: 0,\n migrationsTotal: 0,\n markerHash: originHash,\n applied: [],\n summary: 'Already up to date',\n pathDecision,\n timings: { total: Date.now() - startTime },\n });\n }\n\n const bundleByDir = new Map(migrations.bundles.map((b) => [b.dirName, b]));\n const pendingMigrations: MigrationApplyStep[] = [];\n for (const migration of outcome.decision.selectedPath) {\n const pkg = bundleByDir.get(migration.dirName);\n if (!pkg) {\n return notOk(\n errorRuntime(`Migration package not found: ${migration.dirName}`, {\n why: `The migration directory for path segment ${migration.from} → ${migration.to} was not found`,\n fix: 'Ensure all migration directories are present and intact.',\n }),\n );\n }\n pendingMigrations.push(packageToStep(pkg));\n }\n\n if (!flags.quiet && !flags.json) {\n for (const migration of pendingMigrations) {\n ui.step(`Pending ${migration.dirName}`);\n }\n }\n\n const applyResult = await client.migrationApply({\n originHash,\n destinationHash,\n pendingMigrations,\n });\n\n if (!applyResult.ok) {\n return notOk(mapApplyFailure(applyResult.failure));\n }\n\n const { value } = applyResult;\n\n return ok({\n ok: true,\n migrationsApplied: value.migrationsApplied,\n migrationsTotal: outcome.decision.selectedPath.length,\n markerHash: value.markerHash,\n applied: value.applied,\n summary: value.summary,\n pathDecision,\n timings: { total: Date.now() - startTime },\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: `Unexpected error during migration apply: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrationApplyCommand(): Command {\n const command = new Command('apply');\n setCommandDescriptions(\n command,\n 'Apply planned migrations to the database',\n 'Applies previously planned migrations (created by `migration plan`) to a live database.\\n' +\n 'Compares the database marker against the migration history to determine which\\n' +\n 'migrations are pending, then executes them sequentially. Each migration runs\\n' +\n 'in its own transaction. Does not plan new migrations — run `migration plan` first.',\n );\n setCommandExamples(command, ['prisma-next migration apply --db $DATABASE_URL']);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--ref <name>', 'Target ref name from migrations/refs/')\n .action(async (options: MigrationApplyCommandOptions) => {\n const flags = parseGlobalFlags(options);\n const startTime = Date.now();\n\n const ui = new TerminalUI({\n color: flags.color,\n interactive: flags.interactive,\n });\n\n const result = await executeMigrationApplyCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (applyResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(applyResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationApplyCommandOutput(applyResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-apply.mjs","names":[],"sources":["../../src/commands/migration-apply.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { errorUnknownInvariant, MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport { readRefs, resolveRef } from '@prisma-next/migration-tools/refs';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\n\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type {\n AggregatePerSpaceExecutionEntry,\n MigrationApplyFailure,\n MigrationApplyPathDecision,\n} from '../control-api/types';\nimport {\n CliStructuredError,\n type CliStructuredError as CliStructuredErrorType,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorRuntime,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n collectDeclaredInvariants,\n loadMigrationPackages,\n maskConnectionUrl,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n targetSupportsMigrations,\n} from '../utils/command-helpers';\nimport { formatMigrationApplyCommandOutput } from '../utils/formatters/migrations';\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 MigrationApplyCommandOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly ref?: string;\n}\n\n/**\n * Per-space breakdown of an apply run. The CLI command surfaces these\n * for both the JSON shape (`appliedSpaces[]`) and the human-readable\n * formatter (per-space block — same shape `db init` / `db update`\n * use, M6 sub-spec § Output shape contract).\n */\nexport interface MigrationApplyResult {\n readonly ok: boolean;\n /** Number of contract spaces that had non-zero pending operations applied. */\n readonly migrationsApplied: number;\n /** Total contract spaces visible in the aggregate (pending + already-up-to-date). */\n readonly migrationsTotal: number;\n /**\n * Marker hash for the **app member** post-apply. Surfaced for\n * back-compat with single-space callers; per-space markers live on\n * `perSpace[].marker.storageHash`.\n */\n readonly markerHash: string;\n readonly applied: readonly {\n readonly spaceId: string;\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly operationsExecuted: number;\n }[];\n readonly summary: string;\n /**\n * Per-space breakdown in canonical schedule order (extensions\n * alphabetically, then app). Always present for the aggregate-walking\n * apply path.\n */\n readonly perSpace: readonly AggregatePerSpaceExecutionEntry[];\n /**\n * Path-decision data for the app member. Surfaced for back-compat\n * with single-space callers (cli-journeys invariant tests).\n * Absent for no-op applies where the app had nothing to do.\n */\n readonly pathDecision?: MigrationApplyPathDecision;\n readonly timings: {\n readonly total: number;\n };\n}\n\nfunction mapApplyFailure(failure: MigrationApplyFailure): CliStructuredErrorType {\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Fix the issue and re-run `prisma-next migration apply` — previously applied migrations are preserved.',\n meta: failure.meta ?? {},\n });\n}\n\nasync function executeMigrationApplyCommand(\n options: MigrationApplyCommandOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrationApplyResult, CliStructuredErrorType>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative, refsDir } =\n resolveMigrationPaths(options.config, config);\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 apply (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migration apply',\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: 'Config.driver is required for migration apply',\n }),\n );\n }\n\n if (!targetSupportsMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n let refEntry: RefEntry | undefined;\n const refName = options.ref;\n\n if (refName) {\n try {\n const refs = await readRefs(refsDir);\n refEntry = resolveRef(refs, refName);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n }\n\n // Resolve and parse the contract envelope. The aggregate-walking\n // operation needs the validated app contract to load the aggregate.\n const contractPathAbsolute = resolveContractPath(config);\n let contractRaw: Contract;\n try {\n const contractContent = await readFile(contractPathAbsolute, 'utf-8');\n contractRaw = JSON.parse(contractContent) as Contract;\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: 'Run `prisma-next contract emit` to generate a valid contract.json, then retry apply.',\n }),\n );\n }\n return notOk(\n errorContractValidationFailed(\n `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\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 (typeof dbConnection === 'string') {\n details.push({\n label: 'database',\n value: maskConnectionUrl(dbConnection),\n });\n }\n if (refName) {\n details.push({ label: 'ref', value: refName });\n }\n const header = formatStyledHeader({\n command: 'migration apply',\n description: 'Apply planned migrations to the database',\n url: 'https://pris.ly/migration-apply',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n // Load app-space migration packages — the aggregate operation\n // needs them to hydrate the app member's graph for graph-walk.\n let appPackages: Awaited<ReturnType<typeof loadMigrationPackages>>;\n try {\n appPackages = await loadMigrationPackages(appMigrationsDir);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\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\n // Pre-check unknown invariants against `(declared by app graph) ∪\n // (already on the app marker)`. The marker side of the union\n // catches the case where the ref carries an invariant whose\n // declaring migration was retired (history rewritten) but whose\n // id is recorded on the marker — surfacing UNKNOWN_INVARIANT\n // there would be misleading because the database has already\n // satisfied the requirement.\n if (refEntry && refEntry.invariants.length > 0) {\n const allMarkers = await client.readAllMarkers();\n const appMarker = allMarkers.get('app') ?? null;\n const declared = collectDeclaredInvariants(appPackages.graph);\n const known = new Set<string>(declared);\n for (const id of appMarker?.invariants ?? []) known.add(id);\n const unknown = refEntry.invariants.filter((id) => !known.has(id));\n if (unknown.length > 0) {\n return notOk(\n mapMigrationToolsError(\n errorUnknownInvariant({\n ...ifDefined('refName', refName),\n unknown,\n declared: [...declared].sort(),\n }),\n ),\n );\n }\n }\n\n if (!flags.quiet && !flags.json) {\n ui.step('Loading contract spaces…');\n }\n\n const applyResult = await client.migrationApply({\n contract: contractRaw,\n migrationsDir,\n appMigrationPackages: appPackages.bundles,\n ...ifDefined('refHash', refEntry?.hash),\n ...(refEntry?.invariants ? { refInvariants: refEntry.invariants } : {}),\n ...(refEntry !== undefined ? ifDefined('refName', refName) : {}),\n });\n\n if (!applyResult.ok) {\n return notOk(mapApplyFailure(applyResult.failure));\n }\n\n const { value } = applyResult;\n\n return ok({\n ok: true,\n migrationsApplied: value.migrationsApplied,\n migrationsTotal: value.perSpace.length,\n markerHash: value.markerHash,\n applied: value.applied,\n summary: value.summary,\n perSpace: value.perSpace,\n ...ifDefined('pathDecision', value.pathDecision),\n timings: { total: Date.now() - startTime },\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Unexpected error during migration apply: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrationApplyCommand(): Command {\n const command = new Command('apply');\n setCommandDescriptions(\n command,\n 'Apply planned migrations to the database',\n 'Walks every contract space (app + extensions) and applies pending\\n' +\n 'on-disk migrations in canonical order (extensions alphabetically,\\n' +\n 'then app). Graph-walks the on-disk migration graph for every space —\\n' +\n \"no introspection, no synth. Each space's marker advances inside its\\n\" +\n \"transaction; per-space failure rolls back every space's writes.\",\n );\n setCommandExamples(command, ['prisma-next migration apply --db $DATABASE_URL']);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--ref <name>', 'App-space target ref name from migrations/app/refs/')\n .action(async (options: MigrationApplyCommandOptions) => {\n const flags = parseGlobalFlags(options);\n const startTime = Date.now();\n\n const ui = new TerminalUI({\n color: flags.color,\n interactive: flags.interactive,\n });\n\n const result = await executeMigrationApplyCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (applyResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(applyResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationApplyCommandOutput(applyResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { _ as errorUnexpected, h as errorTargetMigrationNotSupported, m as errorRuntime, t as CliStructuredError, v as mapMigrationToolsError } from "../cli-errors-D3_sMh2K.mjs";
|
|
3
|
-
import { t as assertFrameworkComponentsCompatible } from "../framework-components-
|
|
4
|
-
import { t as
|
|
5
|
-
import {
|
|
3
|
+
import { t as assertFrameworkComponentsCompatible } from "../framework-components-ChqVUxR-.mjs";
|
|
4
|
+
import { c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, g as parseGlobalFlags, i as getTargetMigrations, l as resolveMigrationPaths, t as addGlobalOptions, y as formatStyledHeader } from "../command-helpers-BeZHkxV8.mjs";
|
|
5
|
+
import { t as TerminalUI } from "../terminal-ui-C_hFNbAn.mjs";
|
|
6
|
+
import { t as handleResult } from "../result-handler-rmPVKIP2.mjs";
|
|
6
7
|
import { Command } from "commander";
|
|
7
8
|
import { getEmittedArtifactPaths } from "@prisma-next/emitter";
|
|
8
9
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
@@ -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 { readFileSync } from 'node:fs';\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 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 const contractPathAbsolute = resolveContractPath(config);\n\n let contractJsonContent: string;\n try {\n contractJsonContent = readFileSync(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 toContractJson: Contract;\n try {\n toContractJson = JSON.parse(contractJsonContent) as Contract;\n } catch (error) {\n return notOk(\n errorRuntime('Contract JSON is invalid', {\n why: `Failed to parse ${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 = (\n (toContractJson as unknown as Record<string, unknown>)['storage'] as\n | Record<string, unknown>\n | undefined\n )?.['storageHash'] as string | undefined;\n if (!toStorageHash) {\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 fromContract: Contract | null = null;\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 fromContract = match.metadata.toContract;\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 fromContract = leafPkg.metadata.toContract;\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 fromContract,\n toContract: toContractJson,\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 await copyFilesWithRename(packageDir, [\n { sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },\n { sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },\n ]);\n }\n\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\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 { readFileSync } from 'node:fs';\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 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 const contractPathAbsolute = resolveContractPath(config);\n\n let contractJsonContent: string;\n try {\n contractJsonContent = readFileSync(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 toContractJson: Contract;\n try {\n toContractJson = JSON.parse(contractJsonContent) as Contract;\n } catch (error) {\n return notOk(\n errorRuntime('Contract JSON is invalid', {\n why: `Failed to parse ${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 = (\n (toContractJson as unknown as Record<string, unknown>)['storage'] as\n | Record<string, unknown>\n | undefined\n )?.['storageHash'] as string | undefined;\n if (!toStorageHash) {\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 fromContract: Contract | null = null;\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 fromContract = match.metadata.toContract;\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 fromContract = leafPkg.metadata.toContract;\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 fromContract,\n toContract: toContractJson,\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 await copyFilesWithRename(packageDir, [\n { sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },\n { sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },\n ]);\n }\n\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\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,3 +1,4 @@
|
|
|
1
|
+
import { t as GlobalFlags } from "../global-flags-Icqpxk23.mjs";
|
|
1
2
|
import { Command } from "commander";
|
|
2
3
|
import { Result } from "@prisma-next/utils/result";
|
|
3
4
|
import { OperationPreview } from "@prisma-next/framework-components/control";
|
|
@@ -9,6 +10,22 @@ interface MigrationPlanResult {
|
|
|
9
10
|
readonly from: string | null;
|
|
10
11
|
readonly to: string;
|
|
11
12
|
readonly dir?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Extension-space migration packages materialised onto disk during this
|
|
15
|
+
* `plan` run. Each entry names a `migrations/<spaceId>/<dirName>/`
|
|
16
|
+
* tree the framework wrote alongside the app-space migration directory.
|
|
17
|
+
* Empty when the project has no extension packs declaring a contract
|
|
18
|
+
* space, or when every extension-space package is already on disk.
|
|
19
|
+
*
|
|
20
|
+
* Surfacing these in the result (rather than only via `ui.step` log
|
|
21
|
+
* lines) makes the cross-space side effect explicit to JSON consumers
|
|
22
|
+
* and the success-summary renderer — the same multi-space side effect
|
|
23
|
+
* that `migration apply` will replay.
|
|
24
|
+
*/
|
|
25
|
+
readonly emittedExtensionDirs: readonly {
|
|
26
|
+
readonly spaceId: string;
|
|
27
|
+
readonly dirName: string;
|
|
28
|
+
}[];
|
|
12
29
|
readonly operations: readonly {
|
|
13
30
|
readonly id: string;
|
|
14
31
|
readonly label: string;
|
|
@@ -32,6 +49,7 @@ interface MigrationPlanResult {
|
|
|
32
49
|
};
|
|
33
50
|
}
|
|
34
51
|
declare function createMigrationPlanCommand(): Command;
|
|
52
|
+
declare function formatMigrationPlanOutput(result: MigrationPlanResult, flags: GlobalFlags): string;
|
|
35
53
|
type PrefixResolutionFailure = {
|
|
36
54
|
reason: 'ambiguous';
|
|
37
55
|
count: number;
|
|
@@ -57,5 +75,5 @@ declare function resolveBundleByPrefix<T extends {
|
|
|
57
75
|
};
|
|
58
76
|
}>(bundles: readonly T[], needle: string): Result<T, PrefixResolutionFailure>;
|
|
59
77
|
//#endregion
|
|
60
|
-
export { MigrationPlanResult, PrefixResolutionFailure, createMigrationPlanCommand, resolveBundleByPrefix };
|
|
78
|
+
export { MigrationPlanResult, PrefixResolutionFailure, createMigrationPlanCommand, formatMigrationPlanOutput, resolveBundleByPrefix };
|
|
61
79
|
//# sourceMappingURL=migration-plan.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-plan.d.mts","names":[],"sources":["../../src/commands/migration-plan.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration-plan.d.mts","names":[],"sources":["../../src/commands/migration-plan.ts"],"mappings":";;;;;;UAoEiB,mBAAA;EAAA,SACN,EAAA;EAAA,SACA,IAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,GAAA;EAJA;;;;;;;;;;;;EAAA,SAiBA,oBAAA;IAAA,SAA0C,OAAA;IAAA,SAA0B,OAAA;EAAA;EAAA,SACpE,UAAA;IAAA,SACE,EAAA;IAAA,SACA,KAAA;IAAA,SACA,cAAA;EAAA;EA0X6B;;;;AA4D1C;EA5D0C,SAnX/B,OAAA,GAAU,gBAAA;EAAA,SACV,OAAA;EA8a8E;;;;;EAAA,SAxa9E,mBAAA;EAAA,SACA,OAAA;IAAA,SACE,KAAA;EAAA;AAAA;AAAA,iBA0WG,0BAAA,CAAA,GAA8B,OAAA;AAAA,iBA4D9B,yBAAA,CAA0B,MAAA,EAAQ,mBAAA,EAAqB,KAAA,EAAO,WAAA;AAAA,KA2HlE,uBAAA;EACN,MAAA;EAAqB,KAAA;AAAA;EACrB,MAAA;AAAA;;;;;;;;;;;;;;iBAeU,qBAAA;EAAkC,QAAA;IAAY,EAAA;EAAA;AAAA,EAAA,CAC5D,OAAA,WAAkB,CAAA,IAClB,MAAA,WACC,MAAA,CAAO,CAAA,EAAG,uBAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as resolveBundleByPrefix, t as createMigrationPlanCommand } from "../migration-plan-
|
|
2
|
-
export { createMigrationPlanCommand, resolveBundleByPrefix };
|
|
1
|
+
import { n as formatMigrationPlanOutput, r as resolveBundleByPrefix, t as createMigrationPlanCommand } from "../migration-plan-C6lVaHsO.mjs";
|
|
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-B9OBbled.mjs";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { Result } from "@prisma-next/utils/result";
|
|
4
4
|
import { RefEntry } from "@prisma-next/migration-tools/refs";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { _ as errorUnexpected, m as errorRuntime, t as CliStructuredError, v as mapMigrationToolsError } from "../cli-errors-D3_sMh2K.mjs";
|
|
3
|
-
import { t as
|
|
4
|
-
import {
|
|
3
|
+
import { _ as formatCommandHelp, d as setCommandDescriptions, g as parseGlobalFlags, l as resolveMigrationPaths, t as addGlobalOptions } from "../command-helpers-BeZHkxV8.mjs";
|
|
4
|
+
import { t as TerminalUI } from "../terminal-ui-C_hFNbAn.mjs";
|
|
5
|
+
import { t as handleResult } from "../result-handler-rmPVKIP2.mjs";
|
|
5
6
|
import { Command } from "commander";
|
|
6
7
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
8
|
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-ref.mjs","names":[],"sources":["../../src/commands/migration-ref.ts"],"sourcesContent":["import { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport {\n deleteRef,\n readRef,\n readRefs,\n validateRefName,\n validateRefValue,\n writeRef,\n} 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 CliStructuredError,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n} from '../utils/command-helpers';\nimport { formatCommandHelp } from '../utils/formatters/help';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ninterface RefSetResult {\n readonly ok: true;\n readonly ref: string;\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\ninterface RefGetResult {\n readonly ok: true;\n readonly ref: string;\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\ninterface RefDeleteResult {\n readonly ok: true;\n readonly ref: string;\n readonly deleted: true;\n}\n\ninterface RefListResult {\n readonly ok: true;\n readonly refs: Record<string, RefEntry>;\n}\n\nfunction mapError(error: unknown): CliStructuredError {\n if (MigrationToolsError.is(error)) {\n return mapMigrationToolsError(error);\n }\n return errorUnexpected(error instanceof Error ? error.message : String(error));\n}\n\nfunction cliErrorInvalidRefName(name: string): CliStructuredError {\n return errorRuntime(`Invalid ref name \"${name}\"`, {\n why: `Ref name \"${name}\" does not match the required format`,\n fix: 'Ref names must be lowercase alphanumeric with hyphens or forward slashes, no `.` or `..` segments',\n });\n}\n\nfunction cliErrorInvalidRefValue(hash: string): CliStructuredError {\n return errorRuntime(`Invalid contract hash \"${hash}\"`, {\n why: `\"${hash}\" is not a valid contract hash`,\n fix: 'Contract hashes must match the format \"sha256:<64 hex chars>\". Copy the hash from `prisma-next contract emit` or `migration status --json`.',\n });\n}\n\nasync function executeRefSetCommand(\n name: string,\n hash: string,\n options: { config?: string },\n): Promise<Result<RefSetResult, CliStructuredError>> {\n if (!validateRefName(name)) {\n return notOk(cliErrorInvalidRefName(name));\n }\n if (!validateRefValue(hash)) {\n return notOk(cliErrorInvalidRefValue(hash));\n }\n\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const entry: RefEntry = { hash, invariants: [] };\n await writeRef(refsDir, name, entry);\n return ok({ ok: true as const, ref: name, hash, invariants: [] });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nasync function executeRefGetCommand(\n name: string,\n options: { config?: string },\n): Promise<Result<RefGetResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const entry = await readRef(refsDir, name);\n return ok({ ok: true as const, ref: name, hash: entry.hash, invariants: entry.invariants });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nasync function executeRefDeleteCommand(\n name: string,\n options: { config?: string },\n): Promise<Result<RefDeleteResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n await deleteRef(refsDir, name);\n return ok({ ok: true as const, ref: name, deleted: true as const });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nasync function executeRefListCommand(options: {\n config?: string;\n}): Promise<Result<RefListResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const refs = await readRefs(refsDir);\n return ok({ ok: true as const, refs });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nfunction createRefSetCommand(): Command {\n const command = new Command('set');\n setCommandDescriptions(\n command,\n 'Set a ref to a contract hash',\n 'Sets a named ref to point to a contract hash in migrations/refs/.',\n );\n addGlobalOptions(command)\n .argument('<name>', 'Ref name (e.g., staging, production)')\n .argument('<hash>', 'Contract hash to point to')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n hash: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const result = await executeRefSetCommand(name, hash, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Set ref \"${value.ref}\" → ${value.hash}`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefGetCommand(): Command {\n const command = new Command('get');\n setCommandDescriptions(\n command,\n 'Get the hash for a ref',\n 'Reads a named ref from migrations/refs/ and prints its contract hash.',\n );\n addGlobalOptions(command)\n .argument('<name>', 'Ref name to look up')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const result = await executeRefGetCommand(name, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else {\n ui.output(value.hash);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefDeleteCommand(): Command {\n const command = new Command('delete');\n setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs/.');\n addGlobalOptions(command)\n .argument('<name>', 'Ref name to delete')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const result = await executeRefDeleteCommand(name, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Deleted ref \"${value.ref}\"`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(command, 'List all refs', 'Lists all named refs from migrations/refs/.');\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: { config?: string; json?: string | boolean; quiet?: boolean }) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const result = await executeRefListCommand(options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n const entries = Object.entries(value.refs);\n if (entries.length === 0) {\n ui.output('No refs defined');\n } else {\n for (const [refName, entry] of entries) {\n const invariantsSuffix =\n entry.invariants.length > 0 ? ` [invariants: ${entry.invariants.join(', ')}]` : '';\n ui.output(`${refName} → ${entry.hash}${invariantsSuffix}`);\n }\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n\nexport {\n executeRefSetCommand,\n executeRefGetCommand,\n executeRefDeleteCommand,\n executeRefListCommand,\n cliErrorInvalidRefName,\n cliErrorInvalidRefValue,\n};\n\nexport function createMigrationRefCommand(): Command {\n const command = new Command('ref');\n setCommandDescriptions(\n command,\n 'Manage migration refs',\n 'Manage named refs in migrations/refs/. Refs map logical environment\\n' +\n 'names (e.g., staging, production) to contract hashes.',\n );\n addGlobalOptions(command).configureHelp({\n formatHelp: (cmd) => formatCommandHelp({ command: cmd, flags: parseGlobalFlags({}) }),\n subcommandDescription: () => '',\n });\n command.addCommand(createRefSetCommand());\n command.addCommand(createRefGetCommand());\n command.addCommand(createRefDeleteCommand());\n command.addCommand(createRefListCommand());\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-ref.mjs","names":[],"sources":["../../src/commands/migration-ref.ts"],"sourcesContent":["import { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport {\n deleteRef,\n readRef,\n readRefs,\n validateRefName,\n validateRefValue,\n writeRef,\n} 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 CliStructuredError,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n resolveMigrationPaths,\n setCommandDescriptions,\n} from '../utils/command-helpers';\nimport { formatCommandHelp } from '../utils/formatters/help';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ninterface RefSetResult {\n readonly ok: true;\n readonly ref: string;\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\ninterface RefGetResult {\n readonly ok: true;\n readonly ref: string;\n readonly hash: string;\n readonly invariants: readonly string[];\n}\n\ninterface RefDeleteResult {\n readonly ok: true;\n readonly ref: string;\n readonly deleted: true;\n}\n\ninterface RefListResult {\n readonly ok: true;\n readonly refs: Record<string, RefEntry>;\n}\n\nfunction mapError(error: unknown): CliStructuredError {\n if (MigrationToolsError.is(error)) {\n return mapMigrationToolsError(error);\n }\n return errorUnexpected(error instanceof Error ? error.message : String(error));\n}\n\nfunction cliErrorInvalidRefName(name: string): CliStructuredError {\n return errorRuntime(`Invalid ref name \"${name}\"`, {\n why: `Ref name \"${name}\" does not match the required format`,\n fix: 'Ref names must be lowercase alphanumeric with hyphens or forward slashes, no `.` or `..` segments',\n });\n}\n\nfunction cliErrorInvalidRefValue(hash: string): CliStructuredError {\n return errorRuntime(`Invalid contract hash \"${hash}\"`, {\n why: `\"${hash}\" is not a valid contract hash`,\n fix: 'Contract hashes must match the format \"sha256:<64 hex chars>\". Copy the hash from `prisma-next contract emit` or `migration status --json`.',\n });\n}\n\nasync function executeRefSetCommand(\n name: string,\n hash: string,\n options: { config?: string },\n): Promise<Result<RefSetResult, CliStructuredError>> {\n if (!validateRefName(name)) {\n return notOk(cliErrorInvalidRefName(name));\n }\n if (!validateRefValue(hash)) {\n return notOk(cliErrorInvalidRefValue(hash));\n }\n\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const entry: RefEntry = { hash, invariants: [] };\n await writeRef(refsDir, name, entry);\n return ok({ ok: true as const, ref: name, hash, invariants: [] });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nasync function executeRefGetCommand(\n name: string,\n options: { config?: string },\n): Promise<Result<RefGetResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const entry = await readRef(refsDir, name);\n return ok({ ok: true as const, ref: name, hash: entry.hash, invariants: entry.invariants });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nasync function executeRefDeleteCommand(\n name: string,\n options: { config?: string },\n): Promise<Result<RefDeleteResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n await deleteRef(refsDir, name);\n return ok({ ok: true as const, ref: name, deleted: true as const });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nasync function executeRefListCommand(options: {\n config?: string;\n}): Promise<Result<RefListResult, CliStructuredError>> {\n try {\n const config = await loadConfig(options.config);\n const { refsDir } = resolveMigrationPaths(options.config, config);\n const refs = await readRefs(refsDir);\n return ok({ ok: true as const, refs });\n } catch (error) {\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(mapError(error));\n }\n}\n\nfunction createRefSetCommand(): Command {\n const command = new Command('set');\n setCommandDescriptions(\n command,\n 'Set a ref to a contract hash',\n 'Sets a named ref to point to a contract hash in migrations/refs/.',\n );\n addGlobalOptions(command)\n .argument('<name>', 'Ref name (e.g., staging, production)')\n .argument('<hash>', 'Contract hash to point to')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n hash: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const result = await executeRefSetCommand(name, hash, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Set ref \"${value.ref}\" → ${value.hash}`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefGetCommand(): Command {\n const command = new Command('get');\n setCommandDescriptions(\n command,\n 'Get the hash for a ref',\n 'Reads a named ref from migrations/refs/ and prints its contract hash.',\n );\n addGlobalOptions(command)\n .argument('<name>', 'Ref name to look up')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const result = await executeRefGetCommand(name, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else {\n ui.output(value.hash);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefDeleteCommand(): Command {\n const command = new Command('delete');\n setCommandDescriptions(command, 'Delete a ref', 'Removes a named ref from migrations/refs/.');\n addGlobalOptions(command)\n .argument('<name>', 'Ref name to delete')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(\n async (\n name: string,\n options: { config?: string; json?: string | boolean; quiet?: boolean },\n ) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const result = await executeRefDeleteCommand(name, options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n ui.output(`Deleted ref \"${value.ref}\"`);\n }\n });\n process.exit(exitCode);\n },\n );\n return command;\n}\n\nfunction createRefListCommand(): Command {\n const command = new Command('list');\n setCommandDescriptions(command, 'List all refs', 'Lists all named refs from migrations/refs/.');\n addGlobalOptions(command)\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: { config?: string; json?: string | boolean; quiet?: boolean }) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const result = await executeRefListCommand(options);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value));\n } else if (!flags.quiet) {\n const entries = Object.entries(value.refs);\n if (entries.length === 0) {\n ui.output('No refs defined');\n } else {\n for (const [refName, entry] of entries) {\n const invariantsSuffix =\n entry.invariants.length > 0 ? ` [invariants: ${entry.invariants.join(', ')}]` : '';\n ui.output(`${refName} → ${entry.hash}${invariantsSuffix}`);\n }\n }\n }\n });\n process.exit(exitCode);\n });\n return command;\n}\n\nexport {\n executeRefSetCommand,\n executeRefGetCommand,\n executeRefDeleteCommand,\n executeRefListCommand,\n cliErrorInvalidRefName,\n cliErrorInvalidRefValue,\n};\n\nexport function createMigrationRefCommand(): Command {\n const command = new Command('ref');\n setCommandDescriptions(\n command,\n 'Manage migration refs',\n 'Manage named refs in migrations/refs/. Refs map logical environment\\n' +\n 'names (e.g., staging, production) to contract hashes.',\n );\n addGlobalOptions(command).configureHelp({\n formatHelp: (cmd) => formatCommandHelp({ command: cmd, flags: parseGlobalFlags({}) }),\n subcommandDescription: () => '',\n });\n command.addCommand(createRefSetCommand());\n command.addCommand(createRefGetCommand());\n command.addCommand(createRefDeleteCommand());\n command.addCommand(createRefListCommand());\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as CliStructuredError } from "../cli-errors-
|
|
1
|
+
import { t as CliStructuredError } from "../cli-errors-B9OBbled.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,9 +1,10 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { _ as errorUnexpected, m as errorRuntime, v as mapMigrationToolsError } from "../cli-errors-D3_sMh2K.mjs";
|
|
3
|
-
import { t as
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
3
|
+
import { d as setCommandDescriptions, f as setCommandExamples, g as parseGlobalFlags, t as addGlobalOptions, y as formatStyledHeader } from "../command-helpers-BeZHkxV8.mjs";
|
|
4
|
+
import { t as TerminalUI } from "../terminal-ui-C_hFNbAn.mjs";
|
|
5
|
+
import { t as handleResult } from "../result-handler-rmPVKIP2.mjs";
|
|
6
|
+
import { t as createControlClient } from "../client-qVH-rEgd.mjs";
|
|
7
|
+
import { a as formatMigrationShowOutput } from "../migrations-D_UJnpuW.mjs";
|
|
7
8
|
import { Command } from "commander";
|
|
8
9
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
9
10
|
import { relative, resolve } from "pathe";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-show.mjs","names":[],"sources":["../../src/commands/migration-show.ts"],"sourcesContent":["import type {\n MigrationPlanOperation,\n OperationPreview,\n} from '@prisma-next/framework-components/control';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { readMigrationPackage, readMigrationsDir } from '@prisma-next/migration-tools/io';\nimport {\n findLatestMigration,\n reconstructGraph,\n} from '@prisma-next/migration-tools/migration-graph';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport { APP_SPACE_ID, spaceMigrationDirectory } from '@prisma-next/migration-tools/spaces';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { relative, resolve } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n type CliStructuredError,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { formatMigrationShowOutput } from '../utils/formatters/migrations';\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 MigrationShowOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nexport interface MigrationShowResult {\n readonly ok: true;\n readonly dirName: string;\n readonly dirPath: string;\n readonly from: string | null;\n readonly to: string;\n readonly migrationHash: string;\n readonly createdAt: string;\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n /**\n * Family-agnostic textual preview of the migration's operations. Replaces\n * the previous string-array DDL field. Always defined; statements is empty\n * for a no-op migration or a family that does not implement the\n * `OperationPreviewCapable` capability.\n */\n readonly preview: OperationPreview;\n readonly summary: string;\n}\n\nfunction looksLikePath(target: string): boolean {\n return target.includes('/') || target.includes('\\\\');\n}\n\nexport function resolveByHashPrefix(\n packages: readonly OnDiskMigrationPackage[],\n prefix: string,\n): Result<OnDiskMigrationPackage, CliStructuredError> {\n const normalizedPrefix = prefix.startsWith('sha256:') ? prefix : `sha256:${prefix}`;\n const matches = packages.filter((p) => p.metadata.migrationHash.startsWith(normalizedPrefix));\n\n if (matches.length === 1) {\n return ok(matches[0]!);\n }\n\n if (matches.length === 0) {\n return notOk(\n errorRuntime('No migration found matching prefix', {\n why: `No migration has a migrationHash starting with \"${normalizedPrefix}\"`,\n fix: 'Run `prisma-next migration show` (no argument) to see the latest migration, or check the migrations directory for available packages.',\n }),\n );\n }\n\n const candidates = matches.map((p) => ` ${p.dirName} ${p.metadata.migrationHash}`).join('\\n');\n return notOk(\n errorRuntime('Ambiguous hash prefix', {\n why: `Multiple migrations match prefix \"${normalizedPrefix}\":\\n${candidates}`,\n fix: 'Provide a longer prefix to uniquely identify the migration.',\n }),\n );\n}\n\nasync function executeMigrationShowCommand(\n target: string | undefined,\n options: MigrationShowOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationShowResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n\n const migrationsDirRoot = resolve(\n options.config ? resolve(options.config, '..') : process.cwd(),\n config.migrations?.dir ?? 'migrations',\n );\n const appMigrationsDir = spaceMigrationDirectory(migrationsDirRoot, APP_SPACE_ID);\n const appMigrationsRelative = relative(process.cwd(), appMigrationsDir);\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 show',\n description: 'Display migration package contents',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n let pkg: OnDiskMigrationPackage;\n\n try {\n if (target && looksLikePath(target)) {\n pkg = await readMigrationPackage(resolve(target));\n } else {\n const allPackages = await readMigrationsDir(appMigrationsDir);\n if (allPackages.length === 0) {\n return notOk(\n errorRuntime('No migrations found', {\n why: `No migration packages found in ${appMigrationsRelative}`,\n fix: 'Run `prisma-next migration plan` to create a migration first.',\n }),\n );\n }\n\n if (target) {\n const resolved = resolveByHashPrefix(allPackages, target);\n if (!resolved.ok) return resolved;\n pkg = resolved.value;\n } else {\n const graph = reconstructGraph(allPackages);\n const latestMigration = findLatestMigration(graph);\n if (!latestMigration) {\n return notOk(\n errorRuntime('Could not resolve latest migration', {\n why: 'No latest migration found in the migration history',\n fix: 'The migrations directory may be corrupted. Inspect the migration.json files.',\n }),\n );\n }\n const leafPkg = allPackages.find(\n (p) => p.metadata.migrationHash === latestMigration.migrationHash,\n );\n if (!leafPkg) {\n return notOk(\n errorRuntime('Could not resolve latest migration', {\n why: `Latest migration ${latestMigration.dirName} does not match any package`,\n fix: 'The migrations directory may be corrupted. Inspect the migration.json files.',\n }),\n );\n }\n pkg = leafPkg;\n }\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migration: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n const ops = pkg.ops as readonly MigrationPlanOperation[];\n\n // `migration show` is an offline command; the control client is constructed\n // purely to dispatch the family-specific `toOperationPreview` capability and\n // is not connected to a database.\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n ...(config.driver ? { driver: config.driver } : {}),\n extensionPacks: config.extensionPacks ?? [],\n });\n const preview: OperationPreview = client.toOperationPreview(ops) ?? { statements: [] };\n\n const result: MigrationShowResult = {\n ok: true,\n dirName: pkg.dirName,\n dirPath: relative(process.cwd(), pkg.dirPath),\n from: pkg.metadata.from,\n to: pkg.metadata.to,\n migrationHash: pkg.metadata.migrationHash,\n createdAt: pkg.metadata.createdAt,\n operations: ops.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n preview,\n summary: `${ops.length} operation(s)`,\n };\n return ok(result);\n}\n\nexport function createMigrationShowCommand(): Command {\n const command = new Command('show');\n setCommandDescriptions(\n command,\n 'Display migration package contents',\n 'Shows the operations, statement preview, and metadata for a migration package.\\n' +\n 'Accepts a directory path, a hash prefix (git-style), or defaults to the\\n' +\n 'latest migration.',\n );\n setCommandExamples(command, [\n 'prisma-next migration show',\n 'prisma-next migration show sha256:a1b2c3',\n ]);\n addGlobalOptions(command)\n .argument('[target]', 'Migration directory path or migrationHash prefix (defaults to latest)')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (target: string | undefined, options: MigrationShowOptions) => {\n const flags = parseGlobalFlags(options);\n\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n\n const result = await executeMigrationShowCommand(target, options, flags, ui);\n\n const exitCode = handleResult(result, flags, ui, (showResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(showResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationShowOutput(showResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-show.mjs","names":[],"sources":["../../src/commands/migration-show.ts"],"sourcesContent":["import type {\n MigrationPlanOperation,\n OperationPreview,\n} from '@prisma-next/framework-components/control';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { readMigrationPackage, readMigrationsDir } from '@prisma-next/migration-tools/io';\nimport {\n findLatestMigration,\n reconstructGraph,\n} from '@prisma-next/migration-tools/migration-graph';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport { APP_SPACE_ID, spaceMigrationDirectory } from '@prisma-next/migration-tools/spaces';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { relative, resolve } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n type CliStructuredError,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { formatMigrationShowOutput } from '../utils/formatters/migrations';\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 MigrationShowOptions extends CommonCommandOptions {\n readonly config?: string;\n}\n\nexport interface MigrationShowResult {\n readonly ok: true;\n readonly dirName: string;\n readonly dirPath: string;\n readonly from: string | null;\n readonly to: string;\n readonly migrationHash: string;\n readonly createdAt: string;\n readonly operations: readonly {\n readonly id: string;\n readonly label: string;\n readonly operationClass: string;\n }[];\n /**\n * Family-agnostic textual preview of the migration's operations. Replaces\n * the previous string-array DDL field. Always defined; statements is empty\n * for a no-op migration or a family that does not implement the\n * `OperationPreviewCapable` capability.\n */\n readonly preview: OperationPreview;\n readonly summary: string;\n}\n\nfunction looksLikePath(target: string): boolean {\n return target.includes('/') || target.includes('\\\\');\n}\n\nexport function resolveByHashPrefix(\n packages: readonly OnDiskMigrationPackage[],\n prefix: string,\n): Result<OnDiskMigrationPackage, CliStructuredError> {\n const normalizedPrefix = prefix.startsWith('sha256:') ? prefix : `sha256:${prefix}`;\n const matches = packages.filter((p) => p.metadata.migrationHash.startsWith(normalizedPrefix));\n\n if (matches.length === 1) {\n return ok(matches[0]!);\n }\n\n if (matches.length === 0) {\n return notOk(\n errorRuntime('No migration found matching prefix', {\n why: `No migration has a migrationHash starting with \"${normalizedPrefix}\"`,\n fix: 'Run `prisma-next migration show` (no argument) to see the latest migration, or check the migrations directory for available packages.',\n }),\n );\n }\n\n const candidates = matches.map((p) => ` ${p.dirName} ${p.metadata.migrationHash}`).join('\\n');\n return notOk(\n errorRuntime('Ambiguous hash prefix', {\n why: `Multiple migrations match prefix \"${normalizedPrefix}\":\\n${candidates}`,\n fix: 'Provide a longer prefix to uniquely identify the migration.',\n }),\n );\n}\n\nasync function executeMigrationShowCommand(\n target: string | undefined,\n options: MigrationShowOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationShowResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n\n const migrationsDirRoot = resolve(\n options.config ? resolve(options.config, '..') : process.cwd(),\n config.migrations?.dir ?? 'migrations',\n );\n const appMigrationsDir = spaceMigrationDirectory(migrationsDirRoot, APP_SPACE_ID);\n const appMigrationsRelative = relative(process.cwd(), appMigrationsDir);\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 show',\n description: 'Display migration package contents',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n let pkg: OnDiskMigrationPackage;\n\n try {\n if (target && looksLikePath(target)) {\n pkg = await readMigrationPackage(resolve(target));\n } else {\n const allPackages = await readMigrationsDir(appMigrationsDir);\n if (allPackages.length === 0) {\n return notOk(\n errorRuntime('No migrations found', {\n why: `No migration packages found in ${appMigrationsRelative}`,\n fix: 'Run `prisma-next migration plan` to create a migration first.',\n }),\n );\n }\n\n if (target) {\n const resolved = resolveByHashPrefix(allPackages, target);\n if (!resolved.ok) return resolved;\n pkg = resolved.value;\n } else {\n const graph = reconstructGraph(allPackages);\n const latestMigration = findLatestMigration(graph);\n if (!latestMigration) {\n return notOk(\n errorRuntime('Could not resolve latest migration', {\n why: 'No latest migration found in the migration history',\n fix: 'The migrations directory may be corrupted. Inspect the migration.json files.',\n }),\n );\n }\n const leafPkg = allPackages.find(\n (p) => p.metadata.migrationHash === latestMigration.migrationHash,\n );\n if (!leafPkg) {\n return notOk(\n errorRuntime('Could not resolve latest migration', {\n why: `Latest migration ${latestMigration.dirName} does not match any package`,\n fix: 'The migrations directory may be corrupted. Inspect the migration.json files.',\n }),\n );\n }\n pkg = leafPkg;\n }\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read migration: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n const ops = pkg.ops as readonly MigrationPlanOperation[];\n\n // `migration show` is an offline command; the control client is constructed\n // purely to dispatch the family-specific `toOperationPreview` capability and\n // is not connected to a database.\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n ...(config.driver ? { driver: config.driver } : {}),\n extensionPacks: config.extensionPacks ?? [],\n });\n const preview: OperationPreview = client.toOperationPreview(ops) ?? { statements: [] };\n\n const result: MigrationShowResult = {\n ok: true,\n dirName: pkg.dirName,\n dirPath: relative(process.cwd(), pkg.dirPath),\n from: pkg.metadata.from,\n to: pkg.metadata.to,\n migrationHash: pkg.metadata.migrationHash,\n createdAt: pkg.metadata.createdAt,\n operations: ops.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n preview,\n summary: `${ops.length} operation(s)`,\n };\n return ok(result);\n}\n\nexport function createMigrationShowCommand(): Command {\n const command = new Command('show');\n setCommandDescriptions(\n command,\n 'Display migration package contents',\n 'Shows the operations, statement preview, and metadata for a migration package.\\n' +\n 'Accepts a directory path, a hash prefix (git-style), or defaults to the\\n' +\n 'latest migration.',\n );\n setCommandExamples(command, [\n 'prisma-next migration show',\n 'prisma-next migration show sha256:a1b2c3',\n ]);\n addGlobalOptions(command)\n .argument('[target]', 'Migration directory path or migrationHash prefix (defaults to latest)')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (target: string | undefined, options: MigrationShowOptions) => {\n const flags = parseGlobalFlags(options);\n\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n\n const result = await executeMigrationShowCommand(target, options, flags, ui);\n\n const exitCode = handleResult(result, flags, ui, (showResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(showResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationShowOutput(showResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,40 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
import { Result } from "@prisma-next/utils/result";
|
|
3
|
+
import { ControlExtensionDescriptor } from "@prisma-next/framework-components/control";
|
|
4
|
+
import { ContractMarkerRecordLike } from "@prisma-next/migration-tools/aggregate";
|
|
5
|
+
import { Contract } from "@prisma-next/contract/types";
|
|
2
6
|
import { OnDiskMigrationPackage } from "@prisma-next/migration-tools/package";
|
|
3
7
|
import { MigrationGraph } from "@prisma-next/migration-tools/graph";
|
|
4
8
|
|
|
9
|
+
//#region src/utils/contract-space-aggregate-loader.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* Inputs needed to compose the aggregate loader at the CLI surface.
|
|
12
|
+
*
|
|
13
|
+
* Keeps the loader framework-neutral (no `Config` import) by accepting
|
|
14
|
+
* already-resolved structural inputs: validated app contract, target
|
|
15
|
+
* id, migrations root directory, and the set of extension descriptors.
|
|
16
|
+
*/
|
|
17
|
+
interface BuildAggregateInputs<TFamilyId extends string, TTargetId extends string> {
|
|
18
|
+
readonly targetId: TTargetId;
|
|
19
|
+
readonly migrationsDir: string;
|
|
20
|
+
readonly appContract: Contract;
|
|
21
|
+
readonly extensionPacks: ReadonlyArray<ControlExtensionDescriptor<TFamilyId, TTargetId>>;
|
|
22
|
+
readonly validateContract: (contractJson: unknown) => Contract;
|
|
23
|
+
/**
|
|
24
|
+
* App-space migration packages to hydrate the app member's
|
|
25
|
+
* migration graph with. Defaults to `[]` (matches the `db init` /
|
|
26
|
+
* `db update` daily-driver behaviour, where the app's authored
|
|
27
|
+
* `migrations/` graph is not walked — the planner uses the synth
|
|
28
|
+
* strategy for the app member instead).
|
|
29
|
+
*
|
|
30
|
+
* `migration apply` callers thread the user's authored app-space
|
|
31
|
+
* packages (loaded via `loadMigrationPackages(appMigrationsDir)`)
|
|
32
|
+
* through here so the graph-walk strategy can plot a path through
|
|
33
|
+
* them — the prod-time replay path explicitly forbids synth.
|
|
34
|
+
*/
|
|
35
|
+
readonly appMigrationPackages?: ReadonlyArray<OnDiskMigrationPackage>;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
5
38
|
//#region src/utils/migration-types.d.ts
|
|
6
39
|
interface StatusRef {
|
|
7
40
|
readonly name: string;
|
|
@@ -34,6 +67,41 @@ interface MigrationStatusEntry {
|
|
|
34
67
|
readonly hasDestructive: boolean;
|
|
35
68
|
readonly status: EdgeStatusKind | 'unknown';
|
|
36
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Per-space status row in the aggregate-shaped status output.
|
|
72
|
+
*
|
|
73
|
+
* Surfaces, for each contract space:
|
|
74
|
+
*
|
|
75
|
+
* - `headHash`: the on-disk head ref's hash (where the space is going).
|
|
76
|
+
* - `markerHash`: the live marker hash for the space, or null if no
|
|
77
|
+
* marker has been written yet (greenfield, or pre-`migration apply`).
|
|
78
|
+
* - `pendingCount`: number of migration edges between marker and head.
|
|
79
|
+
* Computed via {@link graphWalkStrategy}; 0 means the space is
|
|
80
|
+
* already at head.
|
|
81
|
+
* - `status`: convenience tag the formatter uses to pick a glyph.
|
|
82
|
+
* `'never-planned'` is reserved for spaces with non-empty head but
|
|
83
|
+
* no on-disk migrations — which shouldn't happen if the loader's
|
|
84
|
+
* integrity check passes.
|
|
85
|
+
*
|
|
86
|
+
* Online-only fields (`markerHash`, `status`) are absent when the
|
|
87
|
+
* command runs without a database connection.
|
|
88
|
+
*/
|
|
89
|
+
interface MigrationStatusSpaceEntry {
|
|
90
|
+
readonly spaceId: string;
|
|
91
|
+
readonly kind: 'app' | 'extension';
|
|
92
|
+
readonly headHash: string;
|
|
93
|
+
readonly markerHash?: string | null;
|
|
94
|
+
readonly pendingCount?: number;
|
|
95
|
+
readonly status?: 'up-to-date' | 'pending' | 'no-marker' | 'never-planned' | 'unreachable';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Sum per-space `pendingCount` into a cross-space total, but only when
|
|
99
|
+
* every loaded space reports a defined `pendingCount`. Returns
|
|
100
|
+
* `undefined` if any space is on the marker-unknown / offline path
|
|
101
|
+
* (where `pendingCount` is intentionally absent), so JSON consumers can
|
|
102
|
+
* distinguish "no pending" from "unknown".
|
|
103
|
+
*/
|
|
104
|
+
declare function computeTotalPendingAcrossSpaces(spaces: readonly MigrationStatusSpaceEntry[]): number | undefined;
|
|
37
105
|
interface MigrationStatusResult {
|
|
38
106
|
readonly ok: true;
|
|
39
107
|
readonly mode: 'online' | 'offline';
|
|
@@ -73,6 +141,22 @@ interface MigrationStatusResult {
|
|
|
73
141
|
};
|
|
74
142
|
readonly summary: string;
|
|
75
143
|
readonly diagnostics: readonly StatusDiagnostic[];
|
|
144
|
+
/**
|
|
145
|
+
* Aggregate enumeration of every on-disk contract space (app +
|
|
146
|
+
* extensions), in canonical schedule order (extensions
|
|
147
|
+
* alphabetically, then app). Present whenever the aggregate loader
|
|
148
|
+
* succeeded; absent in early-error returns (e.g. unreadable
|
|
149
|
+
* migrations directory) where the existing diagnostics already
|
|
150
|
+
* surface the failure.
|
|
151
|
+
*
|
|
152
|
+
* The legacy top-level fields (`migrations`, `markerHash`,
|
|
153
|
+
* `targetHash`, `pathDecision`, …) describe the **app member**
|
|
154
|
+
* specifically — back-compat with single-space callers. Per-space
|
|
155
|
+
* detail for extension members lives only on this list.
|
|
156
|
+
*/
|
|
157
|
+
readonly spaces?: readonly MigrationStatusSpaceEntry[];
|
|
158
|
+
/** Cross-space pending-migration total (sum of `spaces[].pendingCount`). Present when `spaces` is. */
|
|
159
|
+
readonly totalPendingAcrossSpaces?: number;
|
|
76
160
|
readonly graph?: MigrationGraph;
|
|
77
161
|
readonly bundles?: readonly OnDiskMigrationPackage[];
|
|
78
162
|
readonly edgeStatuses?: readonly EdgeStatus[];
|
|
@@ -96,8 +180,27 @@ interface MigrationStatusResult {
|
|
|
96
180
|
* @internal Exported for testing only.
|
|
97
181
|
*/
|
|
98
182
|
declare function deriveEdgeStatuses(graph: MigrationGraph, targetHash: string, contractHash: string, markerHash: string | undefined, mode: 'online' | 'offline'): EdgeStatus[];
|
|
183
|
+
/**
|
|
184
|
+
* Build the aggregate enumeration of contract spaces for the status
|
|
185
|
+
* output. Loads the aggregate from disk (lossy on failure — extension
|
|
186
|
+
* spaces are simply omitted, the existing single-space app behaviour
|
|
187
|
+
* keeps working), reads per-space marker rows when online, and uses
|
|
188
|
+
* {@link graphWalkStrategy} to compute each space's pending count.
|
|
189
|
+
*
|
|
190
|
+
* Sub-spec § `migration status` semantics — the aggregate-walking
|
|
191
|
+
* version reports per-space marker + pending state alongside the
|
|
192
|
+
* cross-space totals.
|
|
193
|
+
*/
|
|
194
|
+
declare function loadAggregateStatusSpaces(args: {
|
|
195
|
+
readonly targetId: string;
|
|
196
|
+
readonly migrationsDir: string;
|
|
197
|
+
readonly appContractRaw: unknown;
|
|
198
|
+
readonly extensionPacks: BuildAggregateInputs<string, string>['extensionPacks'];
|
|
199
|
+
readonly validateContract: BuildAggregateInputs<string, string>['validateContract'];
|
|
200
|
+
readonly markersBySpace: ReadonlyMap<string, ContractMarkerRecordLike> | null;
|
|
201
|
+
}): Promise<readonly MigrationStatusSpaceEntry[]>;
|
|
99
202
|
declare function createMigrationStatusCommand(): Command;
|
|
100
203
|
declare function formatStatusSummary(result: MigrationStatusResult, colorize: boolean): string;
|
|
101
204
|
//#endregion
|
|
102
|
-
export { MigrationStatusEntry, MigrationStatusResult, type StatusDiagnostic, type StatusRef, createMigrationStatusCommand, deriveEdgeStatuses, formatStatusSummary };
|
|
205
|
+
export { MigrationStatusEntry, MigrationStatusResult, MigrationStatusSpaceEntry, type StatusDiagnostic, type StatusRef, computeTotalPendingAcrossSpaces, createMigrationStatusCommand, deriveEdgeStatuses, formatStatusSummary, loadAggregateStatusSpaces };
|
|
103
206
|
//# sourceMappingURL=migration-status.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-status.d.mts","names":[],"sources":["../../src/utils/migration-types.ts","../../src/utils/formatters/graph-migration-mapper.ts","../../src/commands/migration-status.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration-status.d.mts","names":[],"sources":["../../src/utils/contract-space-aggregate-loader.ts","../../src/utils/migration-types.ts","../../src/utils/formatters/graph-migration-mapper.ts","../../src/commands/migration-status.ts"],"mappings":";;;;;;;;;;;;;;;;UAuIiB,oBAAA;EAAA,SACN,QAAA,EAAU,SAAA;EAAA,SACV,aAAA;EAAA,SACA,WAAA,EAAa,QAAA;EAAA,SACb,cAAA,EAAgB,aAAA,CAAc,0BAAA,CAA2B,SAAA,EAAW,SAAA;EAAA,SACpE,gBAAA,GAAmB,YAAA,cAA0B,QAAA;EAJnC;;;;;;;;;;;;EAAA,SAiBV,oBAAA,GAAuB,aAAA,CAAc,sBAAA;AAAA;;;UCzJ/B,SAAA;EAAA,SACN,IAAA;EAAA,SACA,IAAA;EAAA,SACA,MAAA;AAAA;AAAA,UAGM,gBAAA;EAAA,SACN,IAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA;AAAA;;;KCOC,cAAA;;UAmBK,UAAA;EAAA,SACN,OAAA;EAAA,SACA,MAAA,EAAQ,cAAA;AAAA;;;UCwCF,oBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,gBAAA;EAAA,SACA,cAAA;EAAA,SACA,MAAA,EAAQ,cAAA;AAAA;;;;;;;;;;;;;;;;;;;;UAsBF,yBAAA;EAAA,SACN,OAAA;EAAA,SACA,IAAA;EAAA,SACA,QAAA;EAAA,SACA,UAAA;EAAA,SACA,YAAA;EAAA,SACA,MAAA;AAAA;;;;AFlHX;;;;iBE4HgB,+BAAA,CACd,MAAA,WAAiB,yBAAA;AAAA,UAaF,qBAAA;EAAA,SACN,EAAA;EAAA,SACA,IAAA;EAAA,SACA,UAAA,WAAqB,oBAAA;EAAA,SACrB,UAAA;EAAA,SACA,UAAA;EAAA,SACA,YAAA;EAAA,SACA,IAAA,YAAgB,SAAA;EFzIhB;EAAA,SE2IA,kBAAA;EFzIA;;;;;;ACOX;;EDPW,SEkJA,iBAAA;ED3Ie;EAAA,SC6If,iBAAA;EAAA,SACA,YAAA;IAAA,SACE,QAAA;IAAA,SACA,MAAA;IAAA,SACA,gBAAA;IAAA,SACA,eAAA;IAAA,SACA,OAAA;IAAA,SACA,kBAAA;IAAA,SACA,mBAAA;IAAA,SACA,YAAA;MAAA,SACE,OAAA;MAAA,SACA,aAAA;MAAA,SACA,IAAA;MAAA,SACA,EAAA;MAAA,SACA,UAAA;IAAA;EAAA;EAAA,SAGJ,OAAA;EAAA,SACA,WAAA,WAAsB,gBAAA;EA/FtB;;;;;;;;;AA2BX;;;;EA3BW,SA6GA,MAAA,YAAkB,yBAAA;EAhFlB;EAAA,SAkFA,wBAAA;EAAA,SACA,KAAA,GAAQ,cAAA;EAAA,SACR,OAAA,YAAmB,sBAAA;EAAA,SACnB,YAAA,YAAwB,UAAA;EAAA,SACxB,aAAA;EAAA,SACA,aAAA;EAAA,SACA,QAAA;AAAA;;;;AA5DX;;;;;;;;;;;;iBA2GgB,kBAAA,CACd,KAAA,EAAO,cAAA,EACP,UAAA,UACA,YAAA,UACA,UAAA,sBACA,IAAA,yBACC,UAAA;;;;;;;;;;;;iBAuMmB,yBAAA,CAA0B,IAAA;EAAA,SACrC,QAAA;EAAA,SACA,aAAA;EAAA,SACA,cAAA;EAAA,SACA,cAAA,EAAgB,oBAAA;EAAA,SAChB,gBAAA,EAAkB,oBAAA;EAAA,SAClB,cAAA,EAAgB,WAAA,SAAoB,wBAAA;AAAA,IAC3C,OAAA,UAAiB,yBAAA;AAAA,iBA6kBL,4BAAA,CAAA,GAAgC,OAAA;AAAA,iBAoGhC,mBAAA,CAAoB,MAAA,EAAQ,qBAAA,EAAuB,QAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
export { createMigrationStatusCommand, deriveEdgeStatuses, formatStatusSummary };
|
|
1
|
+
import { a as loadAggregateStatusSpaces, i as formatStatusSummary, n as createMigrationStatusCommand, r as deriveEdgeStatuses, t as computeTotalPendingAcrossSpaces } from "../migration-status-CZ-D5k7k.mjs";
|
|
2
|
+
export { computeTotalPendingAcrossSpaces, createMigrationStatusCommand, deriveEdgeStatuses, formatStatusSummary, loadAggregateStatusSpaces };
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { n as executeContractEmit } from "./contract-emit-B3ChISB_.mjs";
|
|
2
1
|
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
3
2
|
import { _ as errorUnexpected$1, t as CliStructuredError$1 } from "./cli-errors-D3_sMh2K.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { t as
|
|
3
|
+
import { n as executeContractEmit } from "./contract-emit-B77TsJqf.mjs";
|
|
4
|
+
import { r as isVerbose } from "./helpers-eqdN8tH6.mjs";
|
|
5
|
+
import { b as formatSuccessMessage, d as setCommandDescriptions, f as setCommandExamples, g as parseGlobalFlags, t as addGlobalOptions, y as formatStyledHeader } from "./command-helpers-BeZHkxV8.mjs";
|
|
6
|
+
import { t as createProgressAdapter } from "./progress-adapter-DFfvZcYL.mjs";
|
|
7
|
+
import { t as TerminalUI } from "./terminal-ui-C_hFNbAn.mjs";
|
|
8
|
+
import { t as handleResult } from "./result-handler-rmPVKIP2.mjs";
|
|
7
9
|
import { Command } from "commander";
|
|
8
10
|
import { getEmittedArtifactPaths } from "@prisma-next/emitter";
|
|
9
11
|
import { errorContractConfigMissing } from "@prisma-next/errors/control";
|
|
@@ -145,4 +147,4 @@ function createContractEmitCommand() {
|
|
|
145
147
|
//#endregion
|
|
146
148
|
export { createContractEmitCommand as t };
|
|
147
149
|
|
|
148
|
-
//# sourceMappingURL=contract-emit-
|
|
150
|
+
//# sourceMappingURL=contract-emit-9DBda5Ou.mjs.map
|