prisma-next 0.12.0-dev.1 → 0.12.0-dev.10
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 +4 -4
- package/dist/{client-KgJorIvG.mjs → client-CDr4o07S.mjs} +18 -5
- package/dist/client-CDr4o07S.mjs.map +1 -0
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.mjs +2 -2
- package/dist/commands/db-schema.mjs +1 -1
- package/dist/commands/db-sign.mjs +1 -1
- package/dist/commands/db-update.mjs +2 -2
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +1 -1
- package/dist/commands/migrate.mjs +1 -1
- package/dist/commands/migration-graph.d.mts +20 -2
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +2 -2
- package/dist/commands/migration-list.d.mts +1 -1
- package/dist/commands/migration-log.d.mts +1 -1
- package/dist/commands/migration-log.mjs +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +1 -1
- package/dist/commands/migration-status.mjs +2 -2
- package/dist/commands/migration-status.mjs.map +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-C8J1WMvO.mjs} +2 -2
- package/dist/{contract-infer-D8uEbJuu.mjs.map → contract-infer-C8J1WMvO.mjs.map} +1 -1
- package/dist/{db-verify-v_vUKXTU.mjs → db-verify-BeRHwN8M.mjs} +2 -2
- package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-BeRHwN8M.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +1 -1
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +1 -1
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-BlKR2Zln.mjs} +2 -2
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs.map → inspect-live-schema-BlKR2Zln.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-BAGUiGOK.mjs} +2 -2
- package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-BAGUiGOK.mjs.map} +1 -1
- package/dist/{migration-graph-D7DVUElV.mjs → migration-graph-C9WC-7eO.mjs} +324 -78
- package/dist/migration-graph-C9WC-7eO.mjs.map +1 -0
- package/dist/{types-Dt_SfqFm.d.mts → types-CeC5ec2Y.d.mts} +8 -2
- package/dist/{types-Dt_SfqFm.d.mts.map → types-CeC5ec2Y.d.mts.map} +1 -1
- package/package.json +11 -11
- package/dist/client-KgJorIvG.mjs.map +0 -1
- package/dist/migration-graph-D7DVUElV.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-status.mjs","names":[],"sources":["../../src/commands/migration-status.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport {\n createControlStack,\n type MigrationPlanOperation,\n} from '@prisma-next/framework-components/control';\nimport {\n type ContractMarkerRecordLike,\n type ContractSpaceAggregate,\n graphWalkStrategy,\n loadContractSpaceAggregate,\n requireHeadRef,\n} from '@prisma-next/migration-tools/aggregate';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport {\n errorNoInvariantPath,\n errorUnknownInvariant,\n MigrationToolsError,\n} from '@prisma-next/migration-tools/errors';\nimport type { MigrationEdge, MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport {\n findPath,\n findPathWithDecision,\n findReachableLeaves,\n} from '@prisma-next/migration-tools/migration-graph';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry, Refs } from '@prisma-next/migration-tools/refs';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { cyan, dim, magenta, yellow } from 'colorette';\nimport { Command } from 'commander';\n\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n CliStructuredError,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n collectDeclaredInvariants,\n maskConnectionUrl,\n readContractEnvelope,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n toPathDecisionResult,\n toStructuralEdge,\n} from '../utils/command-helpers';\nimport {\n appContractStandInFromIdentity,\n loadContractRawSafely,\n refuseContractSpaceIntegrity,\n refusePackageCorruptionOnAggregate,\n} from '../utils/contract-space-aggregate-loader';\nimport { toDeclaredExtensionsFromRaw } from '../utils/extension-pack-inputs';\nimport {\n type EdgeStatus,\n type EdgeStatusKind,\n migrationGraphToRenderInput,\n} from '../utils/formatters/graph-migration-mapper';\nimport {\n extractRelevantSubgraph,\n graphRenderer,\n isLinearGraph,\n} from '../utils/formatters/graph-render';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { StatusDiagnostic, StatusRef } from '../utils/migration-types';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationStatusOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly to?: string;\n readonly from?: string;\n}\n\nexport interface MigrationStatusEntry {\n readonly dirName: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly operationCount: number;\n readonly operationSummary: string;\n readonly hasDestructive: boolean;\n readonly status: EdgeStatusKind | 'unknown';\n}\n\n/**\n * Per-space status row in the aggregate-shaped status output.\n *\n * Surfaces, for each contract space:\n *\n * - `headHash`: the on-disk head ref's hash (where the space is going).\n * - `markerHash`: the live marker hash for the space, or null if no\n * marker has been written yet (greenfield, or pre-`migrate`).\n * - `pendingCount`: number of migration edges between marker and head.\n * Computed via {@link graphWalkStrategy}; 0 means the space is\n * already at head.\n * - `status`: convenience tag the formatter uses to pick a glyph.\n * `'never-planned'` is reserved for spaces with non-empty head but\n * no on-disk migrations — which shouldn't happen if the loader's\n * integrity check passes.\n *\n * Online-only fields (`markerHash`, `status`) are absent when the\n * command runs without a database connection.\n */\nexport interface MigrationStatusSpaceEntry {\n readonly spaceId: string;\n readonly kind: 'app' | 'extension';\n readonly headHash: string;\n readonly markerHash?: string | null;\n readonly pendingCount?: number;\n readonly status?: 'up-to-date' | 'pending' | 'no-marker' | 'never-planned' | 'unreachable';\n}\n\n/**\n * Sum per-space `pendingCount` into a cross-space total, but only when\n * every loaded space reports a defined `pendingCount`. Returns\n * `undefined` if any space is on the marker-unknown / offline path\n * (where `pendingCount` is intentionally absent), so JSON consumers can\n * distinguish \"no pending\" from \"unknown\".\n */\nexport function computeTotalPendingAcrossSpaces(\n spaces: readonly MigrationStatusSpaceEntry[],\n): number | undefined {\n if (spaces.length === 0) return undefined;\n let total = 0;\n for (const s of spaces) {\n if (s.pendingCount === undefined) return undefined;\n total += s.pendingCount;\n }\n return total;\n}\n\nexport type { StatusDiagnostic, StatusRef } from '../utils/migration-types';\n\nexport interface MigrationStatusResult {\n readonly ok: true;\n readonly mode: 'online' | 'offline';\n readonly migrations: readonly MigrationStatusEntry[];\n readonly markerHash?: string;\n readonly targetHash: string;\n readonly contractHash: string;\n readonly refs?: readonly StatusRef[];\n /** Required invariants from the active ref, sorted ascending. Always present (`[]` when no `--ref` or the ref declares none) — knowable offline. */\n readonly requiredInvariants: readonly string[];\n /**\n * Invariants the marker has applied at least once, intersected with\n * `requiredInvariants` for display relevance. JSON consumers see only the\n * subset overlapping the active ref's required set — the full unfiltered\n * marker invariant list lives on `marker.invariants` (control plane) and\n * is not surfaced here. Present only in `mode === 'online'`; absent when\n * offline (the marker is unknown, not empty).\n */\n readonly appliedInvariants?: readonly string[];\n /** required − applied. Present only in `mode === 'online'`; absent when offline. */\n readonly missingInvariants?: readonly 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 summary: string;\n readonly diagnostics: readonly StatusDiagnostic[];\n /**\n * Aggregate enumeration of every on-disk contract space (app +\n * extensions), in canonical schedule order (extensions\n * alphabetically, then app). Present whenever the aggregate loader\n * succeeded; absent in early-error returns (e.g. unreadable\n * migrations directory) where the existing diagnostics already\n * surface the failure.\n *\n * The top-level fields (`migrations`, `markerHash`, `targetHash`,\n * `pathDecision`, …) describe the **app member** specifically.\n * Per-space detail for extension members lives only on this list.\n */\n readonly spaces?: readonly MigrationStatusSpaceEntry[];\n /** Cross-space pending-migration total (sum of `spaces[].pendingCount`). Present when `spaces` is. */\n readonly totalPendingAcrossSpaces?: number;\n readonly graph?: MigrationGraph;\n readonly bundles?: readonly OnDiskMigrationPackage[];\n readonly edgeStatuses?: readonly EdgeStatus[];\n readonly activeRefHash?: string;\n readonly activeRefName?: string;\n readonly diverged?: boolean;\n}\n\nfunction summarizeOps(ops: readonly MigrationPlanOperation[]): {\n summary: string;\n hasDestructive: boolean;\n} {\n if (ops.length === 0) return { summary: '0 ops', hasDestructive: false };\n\n const classes = new Map<string, number>();\n for (const op of ops) {\n classes.set(op.operationClass, (classes.get(op.operationClass) ?? 0) + 1);\n }\n\n const hasDestructive = classes.has('destructive');\n const count = ops.length;\n const noun = count === 1 ? 'op' : 'ops';\n\n if (classes.size === 1) {\n const cls = [...classes.keys()][0]!;\n return { summary: `${count} ${noun} (all ${cls})`, hasDestructive };\n }\n\n const destructiveCount = classes.get('destructive');\n if (destructiveCount) {\n return { summary: `${count} ${noun} (${destructiveCount} destructive)`, hasDestructive };\n }\n\n const parts = [...classes.entries()].map(([cls, n]) => `${n} ${cls}`);\n return { summary: `${count} ${noun} (${parts.join(', ')})`, hasDestructive };\n}\n\n/**\n * Derive per-edge status across the full graph using path analysis.\n *\n * - **applied**: edge is on the path from root to the DB marker\n * - **pending**: edge is on the path from the DB marker to the target\n * (and the marker is reachable from root, i.e. it's on the same branch)\n * - **unreachable**: edge is on the path from root to the target but the DB\n * marker is on a different branch — `apply` can't reach these edges\n * without the DB first moving to this branch\n *\n * Returns statuses only for edges that have a known status (skips offline\n * and edges not on any relevant path).\n *\n * @internal Exported for testing only.\n */\nexport function deriveEdgeStatuses(\n graph: MigrationGraph,\n targetHash: string,\n contractHash: string,\n markerHash: string | undefined,\n mode: 'online' | 'offline',\n): EdgeStatus[] {\n if (mode === 'offline') return [];\n\n const edgeKey = (e: MigrationEdge) => `${e.from}\\0${e.to}`;\n\n // No marker = empty DB — treat root as the marker (nothing applied, everything pending)\n const effectiveMarker = markerHash ?? EMPTY_CONTRACT_HASH;\n\n const appliedPath =\n markerHash !== undefined ? findPath(graph, EMPTY_CONTRACT_HASH, markerHash) : null;\n\n const pendingPath = findPath(graph, effectiveMarker, targetHash);\n const targetPath = findPath(graph, EMPTY_CONTRACT_HASH, targetHash);\n\n const statuses: EdgeStatus[] = [];\n const assignedKeys = new Set<string>();\n\n // Applied edges (root → marker)\n if (appliedPath) {\n for (const e of appliedPath) {\n assignedKeys.add(edgeKey(e));\n statuses.push({ dirName: e.dirName, status: 'applied' });\n }\n }\n\n // Pending edges (marker → target)\n if (pendingPath) {\n for (const e of pendingPath) {\n assignedKeys.add(edgeKey(e));\n statuses.push({ dirName: e.dirName, status: 'pending' });\n }\n }\n\n // Pending edges beyond the target: target → contract (when target is a ref\n // and the contract is reachable from it)\n if (\n contractHash !== EMPTY_CONTRACT_HASH &&\n contractHash !== targetHash &&\n graph.nodes.has(contractHash)\n ) {\n const beyondTarget = findPath(graph, targetHash, contractHash);\n if (beyondTarget) {\n for (const e of beyondTarget) {\n if (!assignedKeys.has(edgeKey(e))) {\n assignedKeys.add(edgeKey(e));\n statuses.push({ dirName: e.dirName, status: 'pending' });\n }\n }\n }\n }\n\n // Unreachable edges: on the path from root to the target but neither applied\n // nor pending. This covers two cases:\n // 1. Marker can't reach target at all (different branch entirely)\n // 2. Marker reaches target via a different route, leaving some root→target\n // edges orphaned (e.g. a fork where one branch was applied and apply\n // will continue through the other)\n if (targetPath) {\n for (const e of targetPath) {\n if (!assignedKeys.has(edgeKey(e))) {\n statuses.push({ dirName: e.dirName, status: 'unreachable' });\n }\n }\n }\n\n return statuses;\n}\n\n/**\n * @param mode — 'online' if we connected to the database, 'offline' otherwise\n * @param markerHash — the marker hash from the database, or undefined if no marker row / offline\n */\nfunction buildMigrationEntries(\n chain: readonly MigrationEdge[],\n packages: readonly OnDiskMigrationPackage[],\n mode: 'online' | 'offline',\n markerHash: string | undefined,\n edgeStatuses?: readonly EdgeStatus[],\n): MigrationStatusEntry[] {\n const pkgByDirName = new Map(packages.map((p) => [p.dirName, p]));\n const statusByDirName = edgeStatuses\n ? new Map(edgeStatuses.map((e) => [e.dirName, e.status]))\n : undefined;\n\n const markerInChain = markerHash === undefined || chain.some((e) => e.to === markerHash);\n\n const entries: MigrationStatusEntry[] = [];\n let reachedMarker = mode === 'online' && markerHash === undefined;\n\n for (const migration of chain) {\n const pkg = pkgByDirName.get(migration.dirName);\n const ops = (pkg?.ops ?? []) as readonly MigrationPlanOperation[];\n const { summary, hasDestructive } = summarizeOps(ops);\n\n let status: EdgeStatusKind | 'unknown';\n const edgeStatus = statusByDirName?.get(migration.dirName);\n if (edgeStatus) {\n status = edgeStatus;\n } else if (mode === 'offline' || !markerInChain) {\n status = 'unknown';\n } else if (reachedMarker) {\n status = 'pending';\n } else {\n status = 'applied';\n }\n\n entries.push({\n dirName: migration.dirName,\n from: migration.from,\n to: migration.to,\n migrationHash: migration.migrationHash,\n operationCount: ops.length,\n operationSummary: summary,\n hasDestructive,\n status,\n });\n\n if (!reachedMarker && migration.to === markerHash) {\n reachedMarker = true;\n }\n }\n\n return entries;\n}\n\n/**\n * Resolve the migration chain to display in status output.\n *\n * When offline or the marker is at EMPTY, the chain is simply the shortest\n * path from EMPTY to the target — all structural paths are equivalent per\n * the spec, so the deterministic shortest path is the canonical display.\n *\n * When online with a non-empty marker, the chain routes *through* the marker:\n * EMPTY→marker (applied history) + marker→target (pending edges). This ensures\n * the displayed chain includes the marker node so applied/pending status is\n * correct. Without this, BFS from EMPTY to target could pick a shortest path\n * that bypasses the marker entirely (e.g. in a diamond graph), causing the\n * marker to appear \"diverged\" when it isn't.\n */\nfunction resolveDisplayChain(\n graph: MigrationGraph,\n targetHash: string,\n markerHash: string | undefined,\n): readonly MigrationEdge[] | null {\n if (markerHash === undefined) {\n return findPath(graph, EMPTY_CONTRACT_HASH, targetHash);\n }\n\n const toMarker = findPath(graph, EMPTY_CONTRACT_HASH, markerHash);\n // Marker unreachable from EMPTY — show the target chain anyway.\n // The caller detects this via markerInChain and emits a divergence diagnostic.\n if (!toMarker) return findPath(graph, EMPTY_CONTRACT_HASH, targetHash);\n\n if (markerHash === targetHash) return toMarker;\n\n const fromMarker = findPath(graph, markerHash, targetHash);\n if (fromMarker) return [...toMarker, ...fromMarker];\n\n // Marker is ahead of target (or on a disconnected branch).\n // Try the inverse: target→marker. If it succeeds, the marker is ahead —\n // show the full chain from EMPTY through the target and on to the marker.\n const toTarget = findPath(graph, EMPTY_CONTRACT_HASH, targetHash);\n if (!toTarget) return null;\n\n const targetToMarker = findPath(graph, targetHash, markerHash);\n if (targetToMarker) return [...toTarget, ...targetToMarker];\n\n // Genuinely disconnected — show EMPTY→target; caller handles divergence diagnostic.\n return toTarget;\n}\n\n/**\n * Build the aggregate enumeration of contract spaces for the status\n * output. Loads the aggregate from disk (lossy on failure — extension\n * spaces are simply omitted, the app member's output keeps working),\n * reads per-space marker rows when online, and uses\n * {@link graphWalkStrategy} to compute each space's pending count.\n *\n * The aggregate-walking status reports per-space marker + pending\n * state alongside the cross-space totals.\n */\nexport async function loadAggregateStatusSpaces(args: {\n readonly aggregate: ContractSpaceAggregate;\n readonly extensionPacks: ReadonlyArray<unknown>;\n readonly markersBySpace: ReadonlyMap<string, ContractMarkerRecordLike> | null;\n}): Promise<readonly MigrationStatusSpaceEntry[]> {\n const declaredExtensions = toDeclaredExtensionsFromRaw(args.extensionPacks);\n if (\n refuseContractSpaceIntegrity(args.aggregate, {\n declaredExtensions,\n checkContracts: true,\n })\n ) {\n // Full integrity refusal (drift, layout violation, etc.) — surfacing\n // it as a status diagnostic would duplicate `migration plan`'s job.\n // The app pipeline still runs; extensions are simply not enumerated.\n return [];\n }\n const aggregate = args.aggregate;\n\n const orderedMembers = [...aggregate.extensions, aggregate.app];\n const rows: MigrationStatusSpaceEntry[] = [];\n for (const member of orderedMembers) {\n const liveMarker = args.markersBySpace?.get(member.spaceId) ?? null;\n const isApp = member.spaceId === aggregate.app.spaceId;\n // The aggregate passed the integrity gate above, so every member has\n // a resolved head ref (a missing one would have refused the load).\n const headRef = requireHeadRef(member);\n\n if (member.graph().nodes.size === 0) {\n rows.push({\n spaceId: member.spaceId,\n kind: isApp ? 'app' : 'extension',\n headHash: headRef.hash,\n ...(args.markersBySpace !== null\n ? {\n markerHash: liveMarker?.storageHash ?? null,\n status: headRef.hash === EMPTY_CONTRACT_HASH ? 'up-to-date' : 'never-planned',\n pendingCount: 0,\n }\n : {}),\n });\n continue;\n }\n\n if (args.markersBySpace === null) {\n rows.push({\n spaceId: member.spaceId,\n kind: isApp ? 'app' : 'extension',\n headHash: headRef.hash,\n });\n continue;\n }\n\n const walked = graphWalkStrategy({\n aggregateTargetId: aggregate.targetId,\n member,\n currentMarker: liveMarker,\n });\n let pendingCount = 0;\n let status: MigrationStatusSpaceEntry['status'];\n if (walked.kind === 'ok') {\n // Count pending *migrations* (graph edges), not operations: a\n // single authored migration that lowers to N ops or zero ops\n // both count as exactly one pending unit of work for the user.\n pendingCount = walked.result.migrationEdges?.length ?? 0;\n if (liveMarker === null) {\n status = pendingCount === 0 ? 'no-marker' : 'pending';\n } else {\n status = pendingCount === 0 ? 'up-to-date' : 'pending';\n }\n } else {\n status = 'unreachable';\n }\n\n rows.push({\n spaceId: member.spaceId,\n kind: isApp ? 'app' : 'extension',\n headHash: headRef.hash,\n markerHash: liveMarker?.storageHash ?? null,\n pendingCount,\n ...(status ? { status } : {}),\n });\n }\n return rows;\n}\n\n/**\n * Read the raw contract.json bytes from disk for the aggregate\n * loader. Returns `null` if the file is missing or unparseable —\n * the existing `readContractEnvelope` path will report the same\n * problem via a status diagnostic, no need to double-surface.\n */\n\nasync function validateOnlineMarkerRead(\n config: Awaited<ReturnType<typeof loadConfig>>,\n dbConnection: unknown,\n): Promise<Result<void, CliStructuredError>> {\n const driver = config.driver;\n if (!driver) {\n return ok(undefined);\n }\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n try {\n await client.connect(dbConnection);\n await client.readMarker();\n return ok(undefined);\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 read database marker: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nasync function executeMigrationStatusCommand(\n options: MigrationStatusOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationStatusResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsRelative, migrationsDir, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n const dbConnection = options.db ?? config.db?.connection;\n const hasDriver = !!config.driver;\n\n let activeRefName: string | undefined;\n let activeRefHash: string | undefined;\n let activeRefEntry: RefEntry | undefined;\n let allRefs: Refs = {};\n try {\n allRefs = await readRefs(refsDir);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n\n const diagnostics: StatusDiagnostic[] = [];\n let contractHash: string = EMPTY_CONTRACT_HASH;\n try {\n const envelope = await readContractEnvelope(config);\n contractHash = envelope.storageHash;\n } catch (error) {\n diagnostics.push({\n code: 'CONTRACT.UNREADABLE',\n severity: 'warn',\n message: `Could not read contract: ${error instanceof Error ? error.message : 'unknown error'}`,\n hints: [\"Run 'prisma-next contract emit' to generate a valid contract\"],\n });\n }\n\n const contractRawForAggregate = await loadContractRawSafely(config);\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n const deserializeContract = (json: unknown): Contract => familyInstance.deserializeContract(json);\n const appContractStandIn = appContractStandInFromIdentity({\n contractHash,\n targetId: config.target.id,\n targetFamily: config.target.familyId,\n });\n let appContractForLoad: Contract = appContractStandIn;\n if (contractRawForAggregate !== null) {\n try {\n appContractForLoad = deserializeContract(contractRawForAggregate);\n } catch (error) {\n diagnostics.push({\n code: 'CONTRACT.UNREADABLE',\n severity: 'warn',\n message: `Could not deserialize contract: ${error instanceof Error ? error.message : 'unknown error'}`,\n hints: [\"Run 'prisma-next contract emit' to generate a valid contract\"],\n });\n }\n }\n\n let aggregate: ContractSpaceAggregate;\n try {\n aggregate = await loadContractSpaceAggregate({\n migrationsDir,\n deserializeContract,\n appContract: appContractForLoad,\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 migrations directory: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n if (contractRawForAggregate !== null) {\n const corruptionFailure = refusePackageCorruptionOnAggregate(aggregate);\n if (corruptionFailure) {\n return notOk(corruptionFailure);\n }\n }\n\n const appGraph = aggregate.app.graph();\n\n let fromOverrideHash: string | undefined;\n\n if (options.to || options.from) {\n if (options.to) {\n const refResult = parseContractRef(options.to, { graph: appGraph, refs: allRefs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n activeRefHash = refResult.value.hash;\n if (refResult.value.provenance.kind === 'ref') {\n const resolvedRefName = refResult.value.provenance.refName;\n activeRefName = resolvedRefName;\n activeRefEntry = allRefs[resolvedRefName];\n }\n }\n\n if (options.from) {\n const fromResult = parseContractRef(options.from, { graph: appGraph, refs: allRefs });\n if (!fromResult.ok) {\n return notOk(mapRefResolutionError(fromResult.failure));\n }\n fromOverrideHash = fromResult.value.hash;\n }\n }\n\n const requiredInvariants: readonly string[] = [...(activeRefEntry?.invariants ?? [])].sort();\n\n const statusRefs: StatusRef[] = Object.entries(allRefs).map(([name, entry]) => ({\n name,\n hash: entry.hash,\n active: name === activeRefName,\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 (dbConnection && hasDriver) {\n details.push({ label: 'database', value: maskConnectionUrl(String(dbConnection)) });\n }\n if (activeRefName) {\n details.push({ label: 'ref', value: activeRefName });\n }\n if (options.from) {\n details.push({ label: 'from', value: options.from });\n }\n if (activeRefEntry && activeRefEntry.invariants.length > 0) {\n details.push({\n label: 'required',\n value: formatInvariantList(activeRefEntry.invariants),\n });\n }\n const header = formatStyledHeader({\n command: 'migration status',\n description: 'Show migration history and applied status',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n const bundles = aggregate.app.packages;\n const graph = appGraph;\n\n if (bundles.length === 0) {\n if (dbConnection && hasDriver) {\n const markerProbe = await validateOnlineMarkerRead(config, dbConnection);\n if (!markerProbe.ok) {\n return markerProbe;\n }\n }\n if (contractHash !== EMPTY_CONTRACT_HASH) {\n diagnostics.push({\n code: 'CONTRACT.AHEAD',\n severity: 'warn',\n message: 'No migration exists for the current contract',\n hints: [\n \"Run 'prisma-next migration plan' to generate a migration for the current contract\",\n ],\n });\n }\n return ok({\n ok: true,\n mode: dbConnection && hasDriver ? 'online' : 'offline',\n migrations: [],\n targetHash: EMPTY_CONTRACT_HASH,\n contractHash,\n summary: 'No migrations found',\n diagnostics,\n requiredInvariants,\n });\n }\n\n let targetHash: string | undefined;\n\n if (activeRefHash) {\n targetHash = activeRefHash;\n } else if (graph.nodes.has(contractHash)) {\n targetHash = contractHash;\n } else {\n const leaves = findReachableLeaves(graph, EMPTY_CONTRACT_HASH);\n if (leaves.length === 1) {\n targetHash = leaves[0];\n } else {\n diagnostics.push({\n code: 'MIGRATION.DIVERGED',\n severity: 'warn',\n message: 'There are multiple valid migration paths — you must select a target',\n hints: [\n \"Use '--to <contract>' to select a target\",\n \"Or 'prisma-next ref set <name> <hash>' to create one\",\n ],\n });\n }\n }\n\n let markerHash: string | undefined;\n let markerInvariants: readonly string[] = [];\n let mode: 'online' | 'offline' = 'offline';\n let allMarkers: ReadonlyMap<string, ContractMarkerRecordLike> | null = null;\n\n if (dbConnection && hasDriver) {\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 try {\n await client.connect(dbConnection);\n const marker = await client.readMarker();\n markerHash = marker?.storageHash;\n markerInvariants = marker?.invariants ?? [];\n mode = 'online';\n // Read every space's marker so the aggregate enumeration can\n // surface per-space marker state. `readAllMarkers` mirrors what\n // `db init` / `db update` already use to drive the planner;\n // here it powers the aggregate status output.\n //\n // Probe for the method first so we only swallow the\n // unsupported-method case: older family instances may not\n // implement `readAllMarkers` (per-space enumeration then falls\n // back to \"marker unknown\"). Real query / runtime errors from\n // an instance that *does* expose the method must propagate up\n // — otherwise transient DB failures would silently degrade\n // status to \"markers unknown\".\n if (typeof client.readAllMarkers === 'function') {\n allMarkers = await client.readAllMarkers();\n } else {\n // Leaving `allMarkers` as `null` signals \"unknown\" to the\n // aggregate loader (an empty `Map` would instead mean \"every\n // space has no marker\", which is a different condition).\n allMarkers = null;\n }\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (!flags.json && !flags.quiet) {\n ui.warn('Could not connect to database — showing offline status');\n }\n } finally {\n await client.close();\n }\n }\n\n if (fromOverrideHash !== undefined) {\n markerHash = fromOverrideHash;\n mode = 'offline';\n allMarkers = null;\n }\n\n let aggregateSpaces: readonly MigrationStatusSpaceEntry[] = [];\n if (contractRawForAggregate !== null) {\n try {\n aggregateSpaces = await loadAggregateStatusSpaces({\n aggregate,\n extensionPacks: config.extensionPacks ?? [],\n markersBySpace: allMarkers,\n });\n } catch {\n aggregateSpaces = [];\n }\n }\n const totalPendingAcrossSpaces = computeTotalPendingAcrossSpaces(aggregateSpaces);\n\n // Pre-check unknown invariants. Online: union the graph's declared\n // invariants with the marker's recorded set so a retired-but-applied\n // invariant doesn't surface as MIGRATION.UNKNOWN_INVARIANT — apply would\n // route fine because marker subtraction empties `effectiveRequired`.\n // Offline: keep the check graph-strict (the marker is unknown, and a\n // missing declarer is the dominant signal we can offer).\n if (activeRefEntry && activeRefEntry.invariants.length > 0) {\n const declared = collectDeclaredInvariants(graph);\n const known = new Set<string>(declared);\n if (mode === 'online') {\n for (const id of markerInvariants) known.add(id);\n }\n const unknown = activeRefEntry.invariants.filter((id) => !known.has(id));\n if (unknown.length > 0) {\n return notOk(\n mapMigrationToolsError(\n errorUnknownInvariant({\n ...ifDefined('refName', activeRefName),\n unknown,\n declared: [...declared].sort(),\n }),\n ),\n );\n }\n }\n\n // Marker exists but is not in the migration graph and doesn't match the\n // contract hash. The DB is at an unknown state relative to the graph.\n // Bail out early with a clear diagnostic instead of rendering a confusing\n // graph with no statuses.\n //\n // When marker === contract (both off-graph), the DB matches the current\n // contract — proceed normally; the detached contract node will carry both\n // the db and contract markers.\n if (\n mode === 'online' &&\n markerHash !== undefined &&\n !graph.nodes.has(markerHash) &&\n markerHash !== contractHash\n ) {\n const hints: string[] = [];\n if (graph.nodes.has(contractHash)) {\n hints.push(\n \"Run 'prisma-next db sign' to overwrite the marker if the database already matches the contract\",\n \"Run 'prisma-next db update' to push the current contract to the database\",\n \"Run 'prisma-next contract infer' to make your contract match the database\",\n \"Run 'prisma-next db verify' to inspect the database state\",\n );\n } else {\n hints.push(\n \"Run 'prisma-next db update' to push the current contract to the database\",\n \"Run 'prisma-next contract infer' to make your contract match the database\",\n \"Run 'prisma-next db verify' to inspect the database state\",\n );\n }\n diagnostics.push({\n code: 'MIGRATION.MARKER_NOT_IN_HISTORY',\n severity: 'warn',\n message:\n 'Database was updated outside the migration system (marker does not match any migration)',\n hints,\n });\n return ok({\n ok: true,\n mode,\n migrations: [],\n targetHash: EMPTY_CONTRACT_HASH,\n contractHash,\n summary: `${bundles.length} migration(s) on disk`,\n diagnostics,\n markerHash,\n requiredInvariants,\n ...(statusRefs.length > 0 ? { refs: statusRefs } : {}),\n });\n }\n\n if (mode === 'online' && markerHash === undefined) {\n diagnostics.push({\n code: 'MIGRATION.NO_MARKER',\n severity: 'warn',\n message: 'Database has not been initialized — no migration marker found',\n hints: [\"Run 'prisma-next migrate' to apply pending migrations\"],\n });\n }\n\n // Contract diagnostic — fires when no migration produces the current contract hash.\n // Suppressed when: (a) graph is diverged (MIGRATION.DIVERGED already guides the user),\n // (b) marker === contract and both off-graph (marker-not-in-graph diagnostic covers it).\n if (\n targetHash &&\n contractHash !== EMPTY_CONTRACT_HASH &&\n !graph.nodes.has(contractHash) &&\n markerHash !== contractHash\n ) {\n diagnostics.push({\n code: 'CONTRACT.AHEAD',\n severity: 'warn',\n message: 'Contract has changed since the last migration was planned',\n hints: [\"Run 'prisma-next migration plan' to generate a migration for the current contract\"],\n });\n }\n\n if (!targetHash) {\n return ok({\n ok: true,\n mode,\n migrations: [],\n targetHash: EMPTY_CONTRACT_HASH,\n contractHash,\n summary: `${bundles.length} migration(s) on disk`,\n diagnostics,\n ...ifDefined('markerHash', markerHash),\n requiredInvariants,\n ...(statusRefs.length > 0 ? { refs: statusRefs } : {}),\n graph,\n bundles,\n diverged: true,\n });\n }\n\n const chain = resolveDisplayChain(graph, targetHash, markerHash);\n\n if (!chain) {\n return notOk(\n errorRuntime('Cannot reconstruct migration history', {\n why: `No path from ${EMPTY_CONTRACT_HASH} to target ${targetHash}`,\n fix: 'The migration history may have gaps. Check the migrations directory for missing or corrupted packages.',\n }),\n );\n }\n\n const edgeStatuses = deriveEdgeStatuses(graph, targetHash, contractHash, markerHash, mode);\n const entries = buildMigrationEntries(chain, bundles, mode, markerHash, edgeStatuses);\n\n const pendingCount = edgeStatuses.filter((e) => e.status === 'pending').length;\n const appliedCount = edgeStatuses.filter((e) => e.status === 'applied').length;\n\n let appliedInvariants: readonly string[] | undefined;\n let missingInvariants: readonly string[] | undefined;\n let effectiveRequired = new Set<string>();\n if (mode === 'online') {\n // Mirrors `migrate.ts`: compute `effectiveRequired = required −\n // marker.invariants` directly, then derive the display fields from it.\n // `appliedInvariants` is the intersection (`required ∩ marker`), which\n // is what JSON consumers see for the active ref; the unfiltered set\n // lives on `marker.invariants`.\n const markerSet = new Set(markerInvariants);\n effectiveRequired = new Set(requiredInvariants.filter((id) => !markerSet.has(id)));\n appliedInvariants = requiredInvariants.filter((id) => markerSet.has(id));\n missingInvariants = [...effectiveRequired].sort();\n }\n\n // The marker can match the structural target while still missing required\n // invariants — for example, a self-edge that provides X, applied via a ref\n // declaring X. `pendingCount` (structural) says zero in that case but\n // `effectiveRequired` is non-empty, so up-to-date messaging would mislead.\n const hasInvariantWork = effectiveRequired.size > 0;\n const missingList = [...effectiveRequired].sort().join(', ');\n\n let summary: string;\n if (mode === 'online') {\n if (markerHash !== undefined && !graph.nodes.has(markerHash) && markerHash === contractHash) {\n summary = `${bundles.length} migration(s) on disk`;\n } else if (activeRefHash && activeRefName && markerHash !== undefined) {\n const distance = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName);\n summary = hasInvariantWork ? `${distance} — missing invariant(s): ${missingList}` : distance;\n } else if (pendingCount === 0 && !hasInvariantWork) {\n summary = `Database is up to date (${appliedCount} migration${appliedCount !== 1 ? 's' : ''} applied)`;\n } else if (pendingCount === 0 && hasInvariantWork) {\n summary = `Missing invariant(s): ${missingList} — run 'prisma-next migrate --to ${activeRefName ?? '<ref>'}' to apply`;\n } else if (markerHash === undefined) {\n summary = `${pendingCount} pending migration(s) — database has no marker`;\n } else {\n summary = `${pendingCount} pending migration(s) — run 'prisma-next migrate' to apply`;\n }\n } else {\n summary = `${entries.length} migration(s) on disk`;\n }\n\n let pathDecision: MigrationStatusResult['pathDecision'];\n let routingUnreachable = false;\n if (mode === 'online') {\n const originHash = markerHash ?? EMPTY_CONTRACT_HASH;\n const outcome = findPathWithDecision(graph, originHash, targetHash, {\n ...ifDefined('refName', activeRefName),\n required: effectiveRequired,\n });\n if (outcome.kind === 'ok') {\n pathDecision = toPathDecisionResult(outcome.decision);\n } else if (outcome.kind === 'unsatisfiable') {\n return notOk(\n mapMigrationToolsError(\n errorNoInvariantPath({\n ...ifDefined('refName', activeRefName),\n required: [...effectiveRequired].sort(),\n missing: outcome.missing,\n structuralPath: outcome.structuralPath.map(toStructuralEdge),\n }),\n ),\n );\n } else {\n // outcome.kind === 'unreachable' — origin (marker) has no structural\n // path to the active target. `pendingCount` and `hasInvariantWork`\n // both report zero in this case, but emitting MIGRATION.UP_TO_DATE\n // would be wrong: the database simply cannot reach the requested\n // ref/contract from its current state. Suppress UP_TO_DATE below.\n routingUnreachable = true;\n }\n }\n\n if (mode === 'online') {\n if (markerHash !== undefined && !graph.nodes.has(markerHash) && markerHash === contractHash) {\n diagnostics.push({\n code: 'MIGRATION.MARKER_NOT_IN_HISTORY',\n severity: 'warn',\n message: 'Database matches the current contract but was updated directly (not via migrate)',\n hints: [\"Run 'prisma-next migration plan' to plan a migration to your current contract\"],\n });\n } else if (pendingCount > 0) {\n diagnostics.push({\n code: 'MIGRATION.DATABASE_BEHIND',\n severity: 'info',\n message: `${pendingCount} migration(s) pending`,\n hints: [\"Run 'prisma-next migrate' to apply pending migrations\"],\n });\n } else if (hasInvariantWork) {\n diagnostics.push({\n code: 'MIGRATION.INVARIANTS_PENDING',\n severity: 'info',\n message: `Missing required invariant(s): ${missingList}`,\n hints: [\n `Run 'prisma-next migrate --to ${activeRefName ?? '<ref>'}' to apply a path that covers the required invariants`,\n ],\n });\n } else if (!routingUnreachable) {\n diagnostics.push({\n code: 'MIGRATION.UP_TO_DATE',\n severity: 'info',\n message: 'Database is up to date',\n hints: [],\n });\n }\n }\n\n const result: MigrationStatusResult = {\n ok: true,\n mode,\n migrations: entries,\n targetHash,\n contractHash,\n summary,\n diagnostics,\n ...ifDefined('markerHash', markerHash),\n requiredInvariants,\n ...ifDefined('appliedInvariants', appliedInvariants),\n ...ifDefined('missingInvariants', missingInvariants),\n ...(statusRefs.length > 0 ? { refs: statusRefs } : {}),\n ...ifDefined('pathDecision', pathDecision),\n graph,\n bundles,\n edgeStatuses,\n ...ifDefined('activeRefHash', activeRefHash),\n ...ifDefined('activeRefName', activeRefName),\n spaces: aggregateSpaces,\n ...ifDefined('totalPendingAcrossSpaces', totalPendingAcrossSpaces),\n };\n return ok(result);\n}\n\nexport function createMigrationStatusCommand(): Command {\n const command = new Command('status');\n setCommandDescriptions(\n command,\n 'Show migration path and pending status',\n 'Shows which migrations are pending between the database marker and\\n' +\n 'the target contract. Requires a database connection for live status.\\n' +\n 'Use `migration graph` for topology, `migration log` for history,\\n' +\n 'and `migration list` for on-disk enumeration.',\n );\n setCommandExamples(command, [\n 'prisma-next migration status --db $DATABASE_URL',\n 'prisma-next migration status --to production --db $DATABASE_URL',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option(\n '--to <contract>',\n 'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option(\n '--from <contract>',\n 'Origin contract reference; same grammar as --to. Supplying --from switches to offline path computation.',\n )\n .action(async (options: MigrationStatusOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n const result = await executeMigrationStatusCommand(options, flags, ui);\n\n const exitCode = handleResult(result, flags, ui, (statusResult) => {\n if (flags.json) {\n const {\n graph: _graph,\n bundles: _bundles,\n edgeStatuses: _edgeStatuses,\n activeRefHash: _activeRefHash,\n activeRefName: _activeRefName,\n diverged: _diverged,\n ...jsonResult\n } = statusResult;\n ui.output(JSON.stringify(jsonResult, null, 2));\n } else if (!flags.quiet) {\n const colorize = flags.color !== false;\n\n if (statusResult.graph) {\n const renderInput = migrationGraphToRenderInput({\n graph: statusResult.graph,\n mode: statusResult.mode,\n markerHash: statusResult.markerHash,\n contractHash: statusResult.contractHash,\n refs: statusResult.refs,\n activeRefHash: statusResult.activeRefHash,\n activeRefName: statusResult.activeRefName,\n edgeStatuses: statusResult.edgeStatuses,\n });\n\n const graphToRender = statusResult.diverged\n ? renderInput.graph\n : extractRelevantSubgraph(renderInput.graph, renderInput.relevantPaths);\n const dagreOptions = isLinearGraph(graphToRender) ? { ranksep: 1 } : undefined;\n const renderOptions = {\n ...renderInput.options,\n colorize,\n ...ifDefined('dagreOptions', dagreOptions),\n };\n const graphOutput = graphRenderer.render(graphToRender, renderOptions);\n ui.log(graphOutput);\n if (statusResult.mode === 'online') {\n ui.log(formatLegend(colorize));\n }\n }\n ui.log('');\n ui.log(formatStatusSummary(statusResult, colorize));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n\nfunction formatLegend(colorize: boolean): string {\n const c = (fn: (s: string) => string, s: string) => (colorize ? fn(s) : s);\n const parts = [\n `${c(cyan, '✓')} applied`,\n `${c(yellow, '⧗')} pending`,\n `${c(magenta, '✗')} unreachable`,\n ];\n return c(dim, parts.join(' '));\n}\n\nexport function formatStatusSummary(result: MigrationStatusResult, colorize: boolean): string {\n const c = (fn: (s: string) => string, s: string) => (colorize ? fn(s) : s);\n const lines: string[] = [];\n\n const hasUnknown = result.migrations.some((e) => e.status === 'unknown');\n const pendingCount = result.migrations.filter((e) => e.status === 'pending').length;\n\n const hasWarnings = result.diagnostics?.some((d) => d.severity === 'warn') ?? false;\n // INVARIANTS_PENDING is filed at severity 'info' (per ADR 208) so the\n // warn-severity check above doesn't see it. It still represents pending\n // work, so it must promote the summary off the success icon.\n const hasInvariantPending =\n result.diagnostics?.some((d) => d.code === 'MIGRATION.INVARIANTS_PENDING') ?? false;\n\n if (result.mode === 'online') {\n if (hasUnknown || hasWarnings) {\n lines.push(`${c(yellow, '⚠')} ${result.summary}`);\n } else if (pendingCount === 0 && !hasInvariantPending) {\n lines.push(`${c(cyan, '✔')} ${result.summary}`);\n } else {\n lines.push(`${c(yellow, '⧗')} ${result.summary}`);\n }\n } else {\n lines.push(result.summary);\n }\n\n if (result.requiredInvariants.length > 0) {\n if (result.appliedInvariants !== undefined && result.missingInvariants !== undefined) {\n lines.push(`${c(dim, 'applied ')}${formatInvariantList(result.appliedInvariants)}`);\n lines.push(`${c(dim, 'missing ')}${formatInvariantList(result.missingInvariants)}`);\n } else {\n lines.push(`${c(dim, 'applied ')}(unknown — connect a database to evaluate)`);\n }\n }\n\n const warnings = result.diagnostics?.filter((d) => d.severity === 'warn') ?? [];\n for (const diag of warnings) {\n lines.push(`${c(yellow, '⚠')} ${diag.message}`);\n for (const hint of diag.hints) {\n lines.push(` ${c(dim, hint)}`);\n }\n }\n\n // Per-space section. Suppressed when there's no extension space —\n // the top-level output already covers the app member.\n // When extensions exist, render every space (including the app)\n // for consistency, plus a cross-space pending total + apply hint.\n if (result.spaces?.some((s) => s.kind === 'extension')) {\n const total = result.totalPendingAcrossSpaces ?? 0;\n lines.push('');\n lines.push(c(dim, 'spaces'));\n for (const space of result.spaces) {\n lines.push(formatSpaceLine(space, c));\n }\n if (total > 0) {\n lines.push('');\n lines.push(\n `${c(yellow, '⧗')} ${total} pending migration(s) across ${result.spaces.length} space(s) — run 'prisma-next migrate' to apply`,\n );\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction formatSpaceLine(\n space: MigrationStatusSpaceEntry,\n c: (fn: (s: string) => string, s: string) => string,\n): string {\n const glyph = (() => {\n if (space.status === 'up-to-date' || space.status === 'no-marker') return c(cyan, '✓');\n if (space.status === 'pending') return c(yellow, '⧗');\n if (space.status === 'unreachable' || space.status === 'never-planned') return c(magenta, '✗');\n return ' ';\n })();\n const tag = space.kind === 'app' ? '[app]' : '[ext]';\n const head = space.headHash.slice(0, 8);\n const marker =\n space.markerHash === undefined\n ? '(unknown)'\n : space.markerHash === null\n ? '(no marker)'\n : space.markerHash.slice(0, 8);\n const pending =\n space.pendingCount === undefined\n ? ''\n : space.pendingCount === 0\n ? c(dim, ' (up to date)')\n : c(yellow, ` (${space.pendingCount} pending)`);\n return ` ${glyph} ${c(dim, tag)} ${space.spaceId} → head ${c(dim, head)}, marker ${c(dim, marker)}${pending}`;\n}\n\nfunction formatInvariantList(ids: readonly string[]): string {\n return ids.length === 0 ? '(none)' : ids.join(', ');\n}\n\nfunction summarizeRefDistance(\n graph: MigrationGraph,\n markerHash: string,\n refHash: string,\n refName: string,\n): string {\n if (markerHash === refHash) return `At ref \"${refName}\" target`;\n\n const pathToRef = findPath(graph, markerHash, refHash);\n if (pathToRef) return `${pathToRef.length} migration(s) behind ref \"${refName}\"`;\n\n const pathFromRef = findPath(graph, refHash, markerHash);\n if (pathFromRef) return `${pathFromRef.length} migration(s) ahead of ref \"${refName}\"`;\n\n return `No path between database marker and ref \"${refName}\" target`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-status.mjs","names":[],"sources":["../../src/commands/migration-status.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport {\n createControlStack,\n type MigrationPlanOperation,\n} from '@prisma-next/framework-components/control';\nimport {\n type ContractMarkerRecordLike,\n type ContractSpaceAggregate,\n graphWalkStrategy,\n loadContractSpaceAggregate,\n requireHeadRef,\n} from '@prisma-next/migration-tools/aggregate';\nimport { EMPTY_CONTRACT_HASH } from '@prisma-next/migration-tools/constants';\nimport {\n errorNoInvariantPath,\n errorUnknownInvariant,\n MigrationToolsError,\n} from '@prisma-next/migration-tools/errors';\nimport type { MigrationEdge, MigrationGraph } from '@prisma-next/migration-tools/graph';\nimport {\n findPath,\n findPathWithDecision,\n findReachableLeaves,\n} from '@prisma-next/migration-tools/migration-graph';\nimport type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry, Refs } from '@prisma-next/migration-tools/refs';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { cyan, dim, magenta, yellow } from 'colorette';\nimport { Command } from 'commander';\n\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n CliStructuredError,\n errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n collectDeclaredInvariants,\n maskConnectionUrl,\n readContractEnvelope,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n setCommandSeeAlso,\n toPathDecisionResult,\n toStructuralEdge,\n} from '../utils/command-helpers';\nimport {\n appContractStandInFromIdentity,\n loadContractRawSafely,\n refuseContractSpaceIntegrity,\n refusePackageCorruptionOnAggregate,\n} from '../utils/contract-space-aggregate-loader';\nimport { toDeclaredExtensionsFromRaw } from '../utils/extension-pack-inputs';\nimport {\n type EdgeStatus,\n type EdgeStatusKind,\n migrationGraphToRenderInput,\n} from '../utils/formatters/graph-migration-mapper';\nimport {\n extractRelevantSubgraph,\n graphRenderer,\n isLinearGraph,\n} from '../utils/formatters/graph-render';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport type { StatusDiagnostic, StatusRef } from '../utils/migration-types';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationStatusOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly to?: string;\n readonly from?: string;\n}\n\nexport interface MigrationStatusEntry {\n readonly dirName: string;\n readonly from: string;\n readonly to: string;\n readonly migrationHash: string;\n readonly operationCount: number;\n readonly operationSummary: string;\n readonly hasDestructive: boolean;\n readonly status: EdgeStatusKind | 'unknown';\n}\n\n/**\n * Per-space status row in the aggregate-shaped status output.\n *\n * Surfaces, for each contract space:\n *\n * - `headHash`: the on-disk head ref's hash (where the space is going).\n * - `markerHash`: the live marker hash for the space, or null if no\n * marker has been written yet (greenfield, or pre-`migrate`).\n * - `pendingCount`: number of migration edges between marker and head.\n * Computed via {@link graphWalkStrategy}; 0 means the space is\n * already at head.\n * - `status`: convenience tag the formatter uses to pick a glyph.\n * `'never-planned'` is reserved for spaces with non-empty head but\n * no on-disk migrations — which shouldn't happen if the loader's\n * integrity check passes.\n *\n * Online-only fields (`markerHash`, `status`) are absent when the\n * command runs without a database connection.\n */\nexport interface MigrationStatusSpaceEntry {\n readonly spaceId: string;\n readonly kind: 'app' | 'extension';\n readonly headHash: string;\n readonly markerHash?: string | null;\n readonly pendingCount?: number;\n readonly status?: 'up-to-date' | 'pending' | 'no-marker' | 'never-planned' | 'unreachable';\n}\n\n/**\n * Sum per-space `pendingCount` into a cross-space total, but only when\n * every loaded space reports a defined `pendingCount`. Returns\n * `undefined` if any space is on the marker-unknown / offline path\n * (where `pendingCount` is intentionally absent), so JSON consumers can\n * distinguish \"no pending\" from \"unknown\".\n */\nexport function computeTotalPendingAcrossSpaces(\n spaces: readonly MigrationStatusSpaceEntry[],\n): number | undefined {\n if (spaces.length === 0) return undefined;\n let total = 0;\n for (const s of spaces) {\n if (s.pendingCount === undefined) return undefined;\n total += s.pendingCount;\n }\n return total;\n}\n\nexport type { StatusDiagnostic, StatusRef } from '../utils/migration-types';\n\nexport interface MigrationStatusResult {\n readonly ok: true;\n readonly mode: 'online' | 'offline';\n readonly migrations: readonly MigrationStatusEntry[];\n readonly markerHash?: string;\n readonly targetHash: string;\n readonly contractHash: string;\n readonly refs?: readonly StatusRef[];\n /** Required invariants from the active ref, sorted ascending. Always present (`[]` when no `--ref` or the ref declares none) — knowable offline. */\n readonly requiredInvariants: readonly string[];\n /**\n * Invariants the marker has applied at least once, intersected with\n * `requiredInvariants` for display relevance. JSON consumers see only the\n * subset overlapping the active ref's required set — the full unfiltered\n * marker invariant list lives on `marker.invariants` (control plane) and\n * is not surfaced here. Present only in `mode === 'online'`; absent when\n * offline (the marker is unknown, not empty).\n */\n readonly appliedInvariants?: readonly string[];\n /** required − applied. Present only in `mode === 'online'`; absent when offline. */\n readonly missingInvariants?: readonly 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 summary: string;\n readonly diagnostics: readonly StatusDiagnostic[];\n /**\n * Aggregate enumeration of every on-disk contract space (app +\n * extensions), in canonical schedule order (extensions\n * alphabetically, then app). Present whenever the aggregate loader\n * succeeded; absent in early-error returns (e.g. unreadable\n * migrations directory) where the existing diagnostics already\n * surface the failure.\n *\n * The top-level fields (`migrations`, `markerHash`, `targetHash`,\n * `pathDecision`, …) describe the **app member** specifically.\n * Per-space detail for extension members lives only on this list.\n */\n readonly spaces?: readonly MigrationStatusSpaceEntry[];\n /** Cross-space pending-migration total (sum of `spaces[].pendingCount`). Present when `spaces` is. */\n readonly totalPendingAcrossSpaces?: number;\n readonly graph?: MigrationGraph;\n readonly bundles?: readonly OnDiskMigrationPackage[];\n readonly edgeStatuses?: readonly EdgeStatus[];\n readonly activeRefHash?: string;\n readonly activeRefName?: string;\n readonly diverged?: boolean;\n}\n\nfunction summarizeOps(ops: readonly MigrationPlanOperation[]): {\n summary: string;\n hasDestructive: boolean;\n} {\n if (ops.length === 0) return { summary: '0 ops', hasDestructive: false };\n\n const classes = new Map<string, number>();\n for (const op of ops) {\n classes.set(op.operationClass, (classes.get(op.operationClass) ?? 0) + 1);\n }\n\n const hasDestructive = classes.has('destructive');\n const count = ops.length;\n const noun = count === 1 ? 'op' : 'ops';\n\n if (classes.size === 1) {\n const cls = [...classes.keys()][0]!;\n return { summary: `${count} ${noun} (all ${cls})`, hasDestructive };\n }\n\n const destructiveCount = classes.get('destructive');\n if (destructiveCount) {\n return { summary: `${count} ${noun} (${destructiveCount} destructive)`, hasDestructive };\n }\n\n const parts = [...classes.entries()].map(([cls, n]) => `${n} ${cls}`);\n return { summary: `${count} ${noun} (${parts.join(', ')})`, hasDestructive };\n}\n\n/**\n * Derive per-edge status across the full graph using path analysis.\n *\n * - **applied**: edge is on the path from root to the DB marker\n * - **pending**: edge is on the path from the DB marker to the target\n * (and the marker is reachable from root, i.e. it's on the same branch)\n * - **unreachable**: edge is on the path from root to the target but the DB\n * marker is on a different branch — `apply` can't reach these edges\n * without the DB first moving to this branch\n *\n * Returns statuses only for edges that have a known status (skips offline\n * and edges not on any relevant path).\n *\n * @internal Exported for testing only.\n */\nexport function deriveEdgeStatuses(\n graph: MigrationGraph,\n targetHash: string,\n contractHash: string,\n markerHash: string | undefined,\n mode: 'online' | 'offline',\n): EdgeStatus[] {\n if (mode === 'offline') return [];\n\n const edgeKey = (e: MigrationEdge) => `${e.from}\\0${e.to}`;\n\n // No marker = empty DB — treat root as the marker (nothing applied, everything pending)\n const effectiveMarker = markerHash ?? EMPTY_CONTRACT_HASH;\n\n const appliedPath =\n markerHash !== undefined ? findPath(graph, EMPTY_CONTRACT_HASH, markerHash) : null;\n\n const pendingPath = findPath(graph, effectiveMarker, targetHash);\n const targetPath = findPath(graph, EMPTY_CONTRACT_HASH, targetHash);\n\n const statuses: EdgeStatus[] = [];\n const assignedKeys = new Set<string>();\n\n // Applied edges (root → marker)\n if (appliedPath) {\n for (const e of appliedPath) {\n assignedKeys.add(edgeKey(e));\n statuses.push({ dirName: e.dirName, status: 'applied' });\n }\n }\n\n // Pending edges (marker → target)\n if (pendingPath) {\n for (const e of pendingPath) {\n assignedKeys.add(edgeKey(e));\n statuses.push({ dirName: e.dirName, status: 'pending' });\n }\n }\n\n // Pending edges beyond the target: target → contract (when target is a ref\n // and the contract is reachable from it)\n if (\n contractHash !== EMPTY_CONTRACT_HASH &&\n contractHash !== targetHash &&\n graph.nodes.has(contractHash)\n ) {\n const beyondTarget = findPath(graph, targetHash, contractHash);\n if (beyondTarget) {\n for (const e of beyondTarget) {\n if (!assignedKeys.has(edgeKey(e))) {\n assignedKeys.add(edgeKey(e));\n statuses.push({ dirName: e.dirName, status: 'pending' });\n }\n }\n }\n }\n\n // Unreachable edges: on the path from root to the target but neither applied\n // nor pending. This covers two cases:\n // 1. Marker can't reach target at all (different branch entirely)\n // 2. Marker reaches target via a different route, leaving some root→target\n // edges orphaned (e.g. a fork where one branch was applied and apply\n // will continue through the other)\n if (targetPath) {\n for (const e of targetPath) {\n if (!assignedKeys.has(edgeKey(e))) {\n statuses.push({ dirName: e.dirName, status: 'unreachable' });\n }\n }\n }\n\n return statuses;\n}\n\n/**\n * @param mode — 'online' if we connected to the database, 'offline' otherwise\n * @param markerHash — the marker hash from the database, or undefined if no marker row / offline\n */\nfunction buildMigrationEntries(\n chain: readonly MigrationEdge[],\n packages: readonly OnDiskMigrationPackage[],\n mode: 'online' | 'offline',\n markerHash: string | undefined,\n edgeStatuses?: readonly EdgeStatus[],\n): MigrationStatusEntry[] {\n const pkgByDirName = new Map(packages.map((p) => [p.dirName, p]));\n const statusByDirName = edgeStatuses\n ? new Map(edgeStatuses.map((e) => [e.dirName, e.status]))\n : undefined;\n\n const markerInChain = markerHash === undefined || chain.some((e) => e.to === markerHash);\n\n const entries: MigrationStatusEntry[] = [];\n let reachedMarker = mode === 'online' && markerHash === undefined;\n\n for (const migration of chain) {\n const pkg = pkgByDirName.get(migration.dirName);\n const ops = (pkg?.ops ?? []) as readonly MigrationPlanOperation[];\n const { summary, hasDestructive } = summarizeOps(ops);\n\n let status: EdgeStatusKind | 'unknown';\n const edgeStatus = statusByDirName?.get(migration.dirName);\n if (edgeStatus) {\n status = edgeStatus;\n } else if (mode === 'offline' || !markerInChain) {\n status = 'unknown';\n } else if (reachedMarker) {\n status = 'pending';\n } else {\n status = 'applied';\n }\n\n entries.push({\n dirName: migration.dirName,\n from: migration.from,\n to: migration.to,\n migrationHash: migration.migrationHash,\n operationCount: ops.length,\n operationSummary: summary,\n hasDestructive,\n status,\n });\n\n if (!reachedMarker && migration.to === markerHash) {\n reachedMarker = true;\n }\n }\n\n return entries;\n}\n\n/**\n * Resolve the migration chain to display in status output.\n *\n * When offline or the marker is at EMPTY, the chain is simply the shortest\n * path from EMPTY to the target — all structural paths are equivalent per\n * the spec, so the deterministic shortest path is the canonical display.\n *\n * When online with a non-empty marker, the chain routes *through* the marker:\n * EMPTY→marker (applied history) + marker→target (pending edges). This ensures\n * the displayed chain includes the marker node so applied/pending status is\n * correct. Without this, BFS from EMPTY to target could pick a shortest path\n * that bypasses the marker entirely (e.g. in a diamond graph), causing the\n * marker to appear \"diverged\" when it isn't.\n */\nfunction resolveDisplayChain(\n graph: MigrationGraph,\n targetHash: string,\n markerHash: string | undefined,\n): readonly MigrationEdge[] | null {\n if (markerHash === undefined) {\n return findPath(graph, EMPTY_CONTRACT_HASH, targetHash);\n }\n\n const toMarker = findPath(graph, EMPTY_CONTRACT_HASH, markerHash);\n // Marker unreachable from EMPTY — show the target chain anyway.\n // The caller detects this via markerInChain and emits a divergence diagnostic.\n if (!toMarker) return findPath(graph, EMPTY_CONTRACT_HASH, targetHash);\n\n if (markerHash === targetHash) return toMarker;\n\n const fromMarker = findPath(graph, markerHash, targetHash);\n if (fromMarker) return [...toMarker, ...fromMarker];\n\n // Marker is ahead of target (or on a disconnected branch).\n // Try the inverse: target→marker. If it succeeds, the marker is ahead —\n // show the full chain from EMPTY through the target and on to the marker.\n const toTarget = findPath(graph, EMPTY_CONTRACT_HASH, targetHash);\n if (!toTarget) return null;\n\n const targetToMarker = findPath(graph, targetHash, markerHash);\n if (targetToMarker) return [...toTarget, ...targetToMarker];\n\n // Genuinely disconnected — show EMPTY→target; caller handles divergence diagnostic.\n return toTarget;\n}\n\n/**\n * Build the aggregate enumeration of contract spaces for the status\n * output. Loads the aggregate from disk (lossy on failure — extension\n * spaces are simply omitted, the app member's output keeps working),\n * reads per-space marker rows when online, and uses\n * {@link graphWalkStrategy} to compute each space's pending count.\n *\n * The aggregate-walking status reports per-space marker + pending\n * state alongside the cross-space totals.\n */\nexport async function loadAggregateStatusSpaces(args: {\n readonly aggregate: ContractSpaceAggregate;\n readonly extensionPacks: ReadonlyArray<unknown>;\n readonly markersBySpace: ReadonlyMap<string, ContractMarkerRecordLike> | null;\n}): Promise<readonly MigrationStatusSpaceEntry[]> {\n const declaredExtensions = toDeclaredExtensionsFromRaw(args.extensionPacks);\n if (\n refuseContractSpaceIntegrity(args.aggregate, {\n declaredExtensions,\n checkContracts: true,\n })\n ) {\n // Full integrity refusal (drift, layout violation, etc.) — surfacing\n // it as a status diagnostic would duplicate `migration plan`'s job.\n // The app pipeline still runs; extensions are simply not enumerated.\n return [];\n }\n const aggregate = args.aggregate;\n\n const orderedMembers = [...aggregate.extensions, aggregate.app];\n const rows: MigrationStatusSpaceEntry[] = [];\n for (const member of orderedMembers) {\n const liveMarker = args.markersBySpace?.get(member.spaceId) ?? null;\n const isApp = member.spaceId === aggregate.app.spaceId;\n // The aggregate passed the integrity gate above, so every member has\n // a resolved head ref (a missing one would have refused the load).\n const headRef = requireHeadRef(member);\n\n if (member.graph().nodes.size === 0) {\n rows.push({\n spaceId: member.spaceId,\n kind: isApp ? 'app' : 'extension',\n headHash: headRef.hash,\n ...(args.markersBySpace !== null\n ? {\n markerHash: liveMarker?.storageHash ?? null,\n status: headRef.hash === EMPTY_CONTRACT_HASH ? 'up-to-date' : 'never-planned',\n pendingCount: 0,\n }\n : {}),\n });\n continue;\n }\n\n if (args.markersBySpace === null) {\n rows.push({\n spaceId: member.spaceId,\n kind: isApp ? 'app' : 'extension',\n headHash: headRef.hash,\n });\n continue;\n }\n\n const walked = graphWalkStrategy({\n aggregateTargetId: aggregate.targetId,\n member,\n currentMarker: liveMarker,\n });\n let pendingCount = 0;\n let status: MigrationStatusSpaceEntry['status'];\n if (walked.kind === 'ok') {\n // Count pending *migrations* (graph edges), not operations: a\n // single authored migration that lowers to N ops or zero ops\n // both count as exactly one pending unit of work for the user.\n pendingCount = walked.result.migrationEdges.length;\n if (liveMarker === null) {\n status = pendingCount === 0 ? 'no-marker' : 'pending';\n } else {\n status = pendingCount === 0 ? 'up-to-date' : 'pending';\n }\n } else {\n status = 'unreachable';\n }\n\n rows.push({\n spaceId: member.spaceId,\n kind: isApp ? 'app' : 'extension',\n headHash: headRef.hash,\n markerHash: liveMarker?.storageHash ?? null,\n pendingCount,\n ...(status ? { status } : {}),\n });\n }\n return rows;\n}\n\n/**\n * Read the raw contract.json bytes from disk for the aggregate\n * loader. Returns `null` if the file is missing or unparseable —\n * the existing `readContractEnvelope` path will report the same\n * problem via a status diagnostic, no need to double-surface.\n */\n\nasync function validateOnlineMarkerRead(\n config: Awaited<ReturnType<typeof loadConfig>>,\n dbConnection: unknown,\n): Promise<Result<void, CliStructuredError>> {\n const driver = config.driver;\n if (!driver) {\n return ok(undefined);\n }\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n try {\n await client.connect(dbConnection);\n await client.readMarker();\n return ok(undefined);\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 read database marker: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nasync function executeMigrationStatusCommand(\n options: MigrationStatusOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<MigrationStatusResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { configPath, appMigrationsRelative, migrationsDir, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n const dbConnection = options.db ?? config.db?.connection;\n const hasDriver = !!config.driver;\n\n let activeRefName: string | undefined;\n let activeRefHash: string | undefined;\n let activeRefEntry: RefEntry | undefined;\n let allRefs: Refs = {};\n try {\n allRefs = await readRefs(refsDir);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n\n const diagnostics: StatusDiagnostic[] = [];\n let contractHash: string = EMPTY_CONTRACT_HASH;\n try {\n const envelope = await readContractEnvelope(config);\n contractHash = envelope.storageHash;\n } catch (error) {\n diagnostics.push({\n code: 'CONTRACT.UNREADABLE',\n severity: 'warn',\n message: `Could not read contract: ${error instanceof Error ? error.message : 'unknown error'}`,\n hints: [\"Run 'prisma-next contract emit' to generate a valid contract\"],\n });\n }\n\n const contractRawForAggregate = await loadContractRawSafely(config);\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n const deserializeContract = (json: unknown): Contract => familyInstance.deserializeContract(json);\n const appContractStandIn = appContractStandInFromIdentity({\n contractHash,\n targetId: config.target.id,\n targetFamily: config.target.familyId,\n });\n let appContractForLoad: Contract = appContractStandIn;\n if (contractRawForAggregate !== null) {\n try {\n appContractForLoad = deserializeContract(contractRawForAggregate);\n } catch (error) {\n diagnostics.push({\n code: 'CONTRACT.UNREADABLE',\n severity: 'warn',\n message: `Could not deserialize contract: ${error instanceof Error ? error.message : 'unknown error'}`,\n hints: [\"Run 'prisma-next contract emit' to generate a valid contract\"],\n });\n }\n }\n\n let aggregate: ContractSpaceAggregate;\n try {\n aggregate = await loadContractSpaceAggregate({\n migrationsDir,\n deserializeContract,\n appContract: appContractForLoad,\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 migrations directory: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n if (contractRawForAggregate !== null) {\n const corruptionFailure = refusePackageCorruptionOnAggregate(aggregate);\n if (corruptionFailure) {\n return notOk(corruptionFailure);\n }\n }\n\n const appGraph = aggregate.app.graph();\n\n let fromOverrideHash: string | undefined;\n\n if (options.to || options.from) {\n if (options.to) {\n const refResult = parseContractRef(options.to, { graph: appGraph, refs: allRefs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n activeRefHash = refResult.value.hash;\n if (refResult.value.provenance.kind === 'ref') {\n const resolvedRefName = refResult.value.provenance.refName;\n activeRefName = resolvedRefName;\n activeRefEntry = allRefs[resolvedRefName];\n }\n }\n\n if (options.from) {\n const fromResult = parseContractRef(options.from, { graph: appGraph, refs: allRefs });\n if (!fromResult.ok) {\n return notOk(mapRefResolutionError(fromResult.failure));\n }\n fromOverrideHash = fromResult.value.hash;\n }\n }\n\n const requiredInvariants: readonly string[] = [...(activeRefEntry?.invariants ?? [])].sort();\n\n const statusRefs: StatusRef[] = Object.entries(allRefs).map(([name, entry]) => ({\n name,\n hash: entry.hash,\n active: name === activeRefName,\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 (dbConnection && hasDriver) {\n details.push({ label: 'database', value: maskConnectionUrl(String(dbConnection)) });\n }\n if (activeRefName) {\n details.push({ label: 'ref', value: activeRefName });\n }\n if (options.from) {\n details.push({ label: 'from', value: options.from });\n }\n if (activeRefEntry && activeRefEntry.invariants.length > 0) {\n details.push({\n label: 'required',\n value: formatInvariantList(activeRefEntry.invariants),\n });\n }\n const header = formatStyledHeader({\n command: 'migration status',\n description: 'Show migration history and applied status',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n const bundles = aggregate.app.packages;\n const graph = appGraph;\n\n if (bundles.length === 0) {\n if (dbConnection && hasDriver) {\n const markerProbe = await validateOnlineMarkerRead(config, dbConnection);\n if (!markerProbe.ok) {\n return markerProbe;\n }\n }\n if (contractHash !== EMPTY_CONTRACT_HASH) {\n diagnostics.push({\n code: 'CONTRACT.AHEAD',\n severity: 'warn',\n message: 'No migration exists for the current contract',\n hints: [\n \"Run 'prisma-next migration plan' to generate a migration for the current contract\",\n ],\n });\n }\n return ok({\n ok: true,\n mode: dbConnection && hasDriver ? 'online' : 'offline',\n migrations: [],\n targetHash: EMPTY_CONTRACT_HASH,\n contractHash,\n summary: 'No migrations found',\n diagnostics,\n requiredInvariants,\n });\n }\n\n let targetHash: string | undefined;\n\n if (activeRefHash) {\n targetHash = activeRefHash;\n } else if (graph.nodes.has(contractHash)) {\n targetHash = contractHash;\n } else {\n const leaves = findReachableLeaves(graph, EMPTY_CONTRACT_HASH);\n if (leaves.length === 1) {\n targetHash = leaves[0];\n } else {\n diagnostics.push({\n code: 'MIGRATION.DIVERGED',\n severity: 'warn',\n message: 'There are multiple valid migration paths — you must select a target',\n hints: [\n \"Use '--to <contract>' to select a target\",\n \"Or 'prisma-next ref set <name> <hash>' to create one\",\n ],\n });\n }\n }\n\n let markerHash: string | undefined;\n let markerInvariants: readonly string[] = [];\n let mode: 'online' | 'offline' = 'offline';\n let allMarkers: ReadonlyMap<string, ContractMarkerRecordLike> | null = null;\n\n if (dbConnection && hasDriver) {\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 try {\n await client.connect(dbConnection);\n const marker = await client.readMarker();\n markerHash = marker?.storageHash;\n markerInvariants = marker?.invariants ?? [];\n mode = 'online';\n // Read every space's marker so the aggregate enumeration can\n // surface per-space marker state. `readAllMarkers` mirrors what\n // `db init` / `db update` already use to drive the planner;\n // here it powers the aggregate status output.\n //\n // Probe for the method first so we only swallow the\n // unsupported-method case: older family instances may not\n // implement `readAllMarkers` (per-space enumeration then falls\n // back to \"marker unknown\"). Real query / runtime errors from\n // an instance that *does* expose the method must propagate up\n // — otherwise transient DB failures would silently degrade\n // status to \"markers unknown\".\n if (typeof client.readAllMarkers === 'function') {\n allMarkers = await client.readAllMarkers();\n } else {\n // Leaving `allMarkers` as `null` signals \"unknown\" to the\n // aggregate loader (an empty `Map` would instead mean \"every\n // space has no marker\", which is a different condition).\n allMarkers = null;\n }\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (!flags.json && !flags.quiet) {\n ui.warn('Could not connect to database — showing offline status');\n }\n } finally {\n await client.close();\n }\n }\n\n if (fromOverrideHash !== undefined) {\n markerHash = fromOverrideHash;\n mode = 'offline';\n allMarkers = null;\n }\n\n let aggregateSpaces: readonly MigrationStatusSpaceEntry[] = [];\n if (contractRawForAggregate !== null) {\n try {\n aggregateSpaces = await loadAggregateStatusSpaces({\n aggregate,\n extensionPacks: config.extensionPacks ?? [],\n markersBySpace: allMarkers,\n });\n } catch {\n aggregateSpaces = [];\n }\n }\n const totalPendingAcrossSpaces = computeTotalPendingAcrossSpaces(aggregateSpaces);\n\n // Pre-check unknown invariants. Online: union the graph's declared\n // invariants with the marker's recorded set so a retired-but-applied\n // invariant doesn't surface as MIGRATION.UNKNOWN_INVARIANT — apply would\n // route fine because marker subtraction empties `effectiveRequired`.\n // Offline: keep the check graph-strict (the marker is unknown, and a\n // missing declarer is the dominant signal we can offer).\n if (activeRefEntry && activeRefEntry.invariants.length > 0) {\n const declared = collectDeclaredInvariants(graph);\n const known = new Set<string>(declared);\n if (mode === 'online') {\n for (const id of markerInvariants) known.add(id);\n }\n const unknown = activeRefEntry.invariants.filter((id) => !known.has(id));\n if (unknown.length > 0) {\n return notOk(\n mapMigrationToolsError(\n errorUnknownInvariant({\n ...ifDefined('refName', activeRefName),\n unknown,\n declared: [...declared].sort(),\n }),\n ),\n );\n }\n }\n\n // Marker exists but is not in the migration graph and doesn't match the\n // contract hash. The DB is at an unknown state relative to the graph.\n // Bail out early with a clear diagnostic instead of rendering a confusing\n // graph with no statuses.\n //\n // When marker === contract (both off-graph), the DB matches the current\n // contract — proceed normally; the detached contract node will carry both\n // the db and contract markers.\n if (\n mode === 'online' &&\n markerHash !== undefined &&\n !graph.nodes.has(markerHash) &&\n markerHash !== contractHash\n ) {\n const hints: string[] = [];\n if (graph.nodes.has(contractHash)) {\n hints.push(\n \"Run 'prisma-next db sign' to overwrite the marker if the database already matches the contract\",\n \"Run 'prisma-next db update' to push the current contract to the database\",\n \"Run 'prisma-next contract infer' to make your contract match the database\",\n \"Run 'prisma-next db verify' to inspect the database state\",\n );\n } else {\n hints.push(\n \"Run 'prisma-next db update' to push the current contract to the database\",\n \"Run 'prisma-next contract infer' to make your contract match the database\",\n \"Run 'prisma-next db verify' to inspect the database state\",\n );\n }\n diagnostics.push({\n code: 'MIGRATION.MARKER_NOT_IN_HISTORY',\n severity: 'warn',\n message:\n 'Database was updated outside the migration system (marker does not match any migration)',\n hints,\n });\n return ok({\n ok: true,\n mode,\n migrations: [],\n targetHash: EMPTY_CONTRACT_HASH,\n contractHash,\n summary: `${bundles.length} migration(s) on disk`,\n diagnostics,\n markerHash,\n requiredInvariants,\n ...(statusRefs.length > 0 ? { refs: statusRefs } : {}),\n });\n }\n\n if (mode === 'online' && markerHash === undefined) {\n diagnostics.push({\n code: 'MIGRATION.NO_MARKER',\n severity: 'warn',\n message: 'Database has not been initialized — no migration marker found',\n hints: [\"Run 'prisma-next migrate' to apply pending migrations\"],\n });\n }\n\n // Contract diagnostic — fires when no migration produces the current contract hash.\n // Suppressed when: (a) graph is diverged (MIGRATION.DIVERGED already guides the user),\n // (b) marker === contract and both off-graph (marker-not-in-graph diagnostic covers it).\n if (\n targetHash &&\n contractHash !== EMPTY_CONTRACT_HASH &&\n !graph.nodes.has(contractHash) &&\n markerHash !== contractHash\n ) {\n diagnostics.push({\n code: 'CONTRACT.AHEAD',\n severity: 'warn',\n message: 'Contract has changed since the last migration was planned',\n hints: [\"Run 'prisma-next migration plan' to generate a migration for the current contract\"],\n });\n }\n\n if (!targetHash) {\n return ok({\n ok: true,\n mode,\n migrations: [],\n targetHash: EMPTY_CONTRACT_HASH,\n contractHash,\n summary: `${bundles.length} migration(s) on disk`,\n diagnostics,\n ...ifDefined('markerHash', markerHash),\n requiredInvariants,\n ...(statusRefs.length > 0 ? { refs: statusRefs } : {}),\n graph,\n bundles,\n diverged: true,\n });\n }\n\n const chain = resolveDisplayChain(graph, targetHash, markerHash);\n\n if (!chain) {\n return notOk(\n errorRuntime('Cannot reconstruct migration history', {\n why: `No path from ${EMPTY_CONTRACT_HASH} to target ${targetHash}`,\n fix: 'The migration history may have gaps. Check the migrations directory for missing or corrupted packages.',\n }),\n );\n }\n\n const edgeStatuses = deriveEdgeStatuses(graph, targetHash, contractHash, markerHash, mode);\n const entries = buildMigrationEntries(chain, bundles, mode, markerHash, edgeStatuses);\n\n const pendingCount = edgeStatuses.filter((e) => e.status === 'pending').length;\n const appliedCount = edgeStatuses.filter((e) => e.status === 'applied').length;\n\n let appliedInvariants: readonly string[] | undefined;\n let missingInvariants: readonly string[] | undefined;\n let effectiveRequired = new Set<string>();\n if (mode === 'online') {\n // Mirrors `migrate.ts`: compute `effectiveRequired = required −\n // marker.invariants` directly, then derive the display fields from it.\n // `appliedInvariants` is the intersection (`required ∩ marker`), which\n // is what JSON consumers see for the active ref; the unfiltered set\n // lives on `marker.invariants`.\n const markerSet = new Set(markerInvariants);\n effectiveRequired = new Set(requiredInvariants.filter((id) => !markerSet.has(id)));\n appliedInvariants = requiredInvariants.filter((id) => markerSet.has(id));\n missingInvariants = [...effectiveRequired].sort();\n }\n\n // The marker can match the structural target while still missing required\n // invariants — for example, a self-edge that provides X, applied via a ref\n // declaring X. `pendingCount` (structural) says zero in that case but\n // `effectiveRequired` is non-empty, so up-to-date messaging would mislead.\n const hasInvariantWork = effectiveRequired.size > 0;\n const missingList = [...effectiveRequired].sort().join(', ');\n\n let summary: string;\n if (mode === 'online') {\n if (markerHash !== undefined && !graph.nodes.has(markerHash) && markerHash === contractHash) {\n summary = `${bundles.length} migration(s) on disk`;\n } else if (activeRefHash && activeRefName && markerHash !== undefined) {\n const distance = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName);\n summary = hasInvariantWork ? `${distance} — missing invariant(s): ${missingList}` : distance;\n } else if (pendingCount === 0 && !hasInvariantWork) {\n summary = `Database is up to date (${appliedCount} migration${appliedCount !== 1 ? 's' : ''} applied)`;\n } else if (pendingCount === 0 && hasInvariantWork) {\n summary = `Missing invariant(s): ${missingList} — run 'prisma-next migrate --to ${activeRefName ?? '<ref>'}' to apply`;\n } else if (markerHash === undefined) {\n summary = `${pendingCount} pending migration(s) — database has no marker`;\n } else {\n summary = `${pendingCount} pending migration(s) — run 'prisma-next migrate' to apply`;\n }\n } else {\n summary = `${entries.length} migration(s) on disk`;\n }\n\n let pathDecision: MigrationStatusResult['pathDecision'];\n let routingUnreachable = false;\n if (mode === 'online') {\n const originHash = markerHash ?? EMPTY_CONTRACT_HASH;\n const outcome = findPathWithDecision(graph, originHash, targetHash, {\n ...ifDefined('refName', activeRefName),\n required: effectiveRequired,\n });\n if (outcome.kind === 'ok') {\n pathDecision = toPathDecisionResult(outcome.decision);\n } else if (outcome.kind === 'unsatisfiable') {\n return notOk(\n mapMigrationToolsError(\n errorNoInvariantPath({\n ...ifDefined('refName', activeRefName),\n required: [...effectiveRequired].sort(),\n missing: outcome.missing,\n structuralPath: outcome.structuralPath.map(toStructuralEdge),\n }),\n ),\n );\n } else {\n // outcome.kind === 'unreachable' — origin (marker) has no structural\n // path to the active target. `pendingCount` and `hasInvariantWork`\n // both report zero in this case, but emitting MIGRATION.UP_TO_DATE\n // would be wrong: the database simply cannot reach the requested\n // ref/contract from its current state. Suppress UP_TO_DATE below.\n routingUnreachable = true;\n }\n }\n\n if (mode === 'online') {\n if (markerHash !== undefined && !graph.nodes.has(markerHash) && markerHash === contractHash) {\n diagnostics.push({\n code: 'MIGRATION.MARKER_NOT_IN_HISTORY',\n severity: 'warn',\n message: 'Database matches the current contract but was updated directly (not via migrate)',\n hints: [\"Run 'prisma-next migration plan' to plan a migration to your current contract\"],\n });\n } else if (pendingCount > 0) {\n diagnostics.push({\n code: 'MIGRATION.DATABASE_BEHIND',\n severity: 'info',\n message: `${pendingCount} migration(s) pending`,\n hints: [\"Run 'prisma-next migrate' to apply pending migrations\"],\n });\n } else if (hasInvariantWork) {\n diagnostics.push({\n code: 'MIGRATION.INVARIANTS_PENDING',\n severity: 'info',\n message: `Missing required invariant(s): ${missingList}`,\n hints: [\n `Run 'prisma-next migrate --to ${activeRefName ?? '<ref>'}' to apply a path that covers the required invariants`,\n ],\n });\n } else if (!routingUnreachable) {\n diagnostics.push({\n code: 'MIGRATION.UP_TO_DATE',\n severity: 'info',\n message: 'Database is up to date',\n hints: [],\n });\n }\n }\n\n const result: MigrationStatusResult = {\n ok: true,\n mode,\n migrations: entries,\n targetHash,\n contractHash,\n summary,\n diagnostics,\n ...ifDefined('markerHash', markerHash),\n requiredInvariants,\n ...ifDefined('appliedInvariants', appliedInvariants),\n ...ifDefined('missingInvariants', missingInvariants),\n ...(statusRefs.length > 0 ? { refs: statusRefs } : {}),\n ...ifDefined('pathDecision', pathDecision),\n graph,\n bundles,\n edgeStatuses,\n ...ifDefined('activeRefHash', activeRefHash),\n ...ifDefined('activeRefName', activeRefName),\n spaces: aggregateSpaces,\n ...ifDefined('totalPendingAcrossSpaces', totalPendingAcrossSpaces),\n };\n return ok(result);\n}\n\nexport function createMigrationStatusCommand(): Command {\n const command = new Command('status');\n setCommandDescriptions(\n command,\n 'Show migration path and pending status',\n 'Shows which migrations are pending between the database marker and\\n' +\n 'the target contract. Requires a database connection for live status.\\n' +\n 'Use `migration graph` for topology, `migration log` for history,\\n' +\n 'and `migration list` for on-disk enumeration.',\n );\n setCommandExamples(command, [\n 'prisma-next migration status --db $DATABASE_URL',\n 'prisma-next migration status --to production --db $DATABASE_URL',\n ]);\n setCommandSeeAlso(command, [\n { verb: 'migration log', oneLiner: 'Show executed migration history' },\n { verb: 'migration list', oneLiner: 'List on-disk migrations' },\n { verb: 'migration graph', oneLiner: 'Show the migration graph topology' },\n { verb: 'migration show', oneLiner: 'Display migration package contents' },\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option(\n '--to <contract>',\n 'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option(\n '--from <contract>',\n 'Origin contract reference; same grammar as --to. Supplying --from switches to offline path computation.',\n )\n .action(async (options: MigrationStatusOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n const result = await executeMigrationStatusCommand(options, flags, ui);\n\n const exitCode = handleResult(result, flags, ui, (statusResult) => {\n if (flags.json) {\n const {\n graph: _graph,\n bundles: _bundles,\n edgeStatuses: _edgeStatuses,\n activeRefHash: _activeRefHash,\n activeRefName: _activeRefName,\n diverged: _diverged,\n ...jsonResult\n } = statusResult;\n ui.output(JSON.stringify(jsonResult, null, 2));\n } else if (!flags.quiet) {\n const colorize = flags.color !== false;\n\n if (statusResult.graph) {\n const renderInput = migrationGraphToRenderInput({\n graph: statusResult.graph,\n mode: statusResult.mode,\n markerHash: statusResult.markerHash,\n contractHash: statusResult.contractHash,\n refs: statusResult.refs,\n activeRefHash: statusResult.activeRefHash,\n activeRefName: statusResult.activeRefName,\n edgeStatuses: statusResult.edgeStatuses,\n });\n\n const graphToRender = statusResult.diverged\n ? renderInput.graph\n : extractRelevantSubgraph(renderInput.graph, renderInput.relevantPaths);\n const dagreOptions = isLinearGraph(graphToRender) ? { ranksep: 1 } : undefined;\n const renderOptions = {\n ...renderInput.options,\n colorize,\n ...ifDefined('dagreOptions', dagreOptions),\n };\n const graphOutput = graphRenderer.render(graphToRender, renderOptions);\n ui.log(graphOutput);\n if (statusResult.mode === 'online') {\n ui.log(formatLegend(colorize));\n }\n }\n ui.log('');\n ui.log(formatStatusSummary(statusResult, colorize));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n\nfunction formatLegend(colorize: boolean): string {\n const c = (fn: (s: string) => string, s: string) => (colorize ? fn(s) : s);\n const parts = [\n `${c(cyan, '✓')} applied`,\n `${c(yellow, '⧗')} pending`,\n `${c(magenta, '✗')} unreachable`,\n ];\n return c(dim, parts.join(' '));\n}\n\nexport function formatStatusSummary(result: MigrationStatusResult, colorize: boolean): string {\n const c = (fn: (s: string) => string, s: string) => (colorize ? fn(s) : s);\n const lines: string[] = [];\n\n const hasUnknown = result.migrations.some((e) => e.status === 'unknown');\n const pendingCount = result.migrations.filter((e) => e.status === 'pending').length;\n\n const hasWarnings = result.diagnostics?.some((d) => d.severity === 'warn') ?? false;\n // INVARIANTS_PENDING is filed at severity 'info' (per ADR 208) so the\n // warn-severity check above doesn't see it. It still represents pending\n // work, so it must promote the summary off the success icon.\n const hasInvariantPending =\n result.diagnostics?.some((d) => d.code === 'MIGRATION.INVARIANTS_PENDING') ?? false;\n\n if (result.mode === 'online') {\n if (hasUnknown || hasWarnings) {\n lines.push(`${c(yellow, '⚠')} ${result.summary}`);\n } else if (pendingCount === 0 && !hasInvariantPending) {\n lines.push(`${c(cyan, '✔')} ${result.summary}`);\n } else {\n lines.push(`${c(yellow, '⧗')} ${result.summary}`);\n }\n } else {\n lines.push(result.summary);\n }\n\n if (result.requiredInvariants.length > 0) {\n if (result.appliedInvariants !== undefined && result.missingInvariants !== undefined) {\n lines.push(`${c(dim, 'applied ')}${formatInvariantList(result.appliedInvariants)}`);\n lines.push(`${c(dim, 'missing ')}${formatInvariantList(result.missingInvariants)}`);\n } else {\n lines.push(`${c(dim, 'applied ')}(unknown — connect a database to evaluate)`);\n }\n }\n\n const warnings = result.diagnostics?.filter((d) => d.severity === 'warn') ?? [];\n for (const diag of warnings) {\n lines.push(`${c(yellow, '⚠')} ${diag.message}`);\n for (const hint of diag.hints) {\n lines.push(` ${c(dim, hint)}`);\n }\n }\n\n // Per-space section. Suppressed when there's no extension space —\n // the top-level output already covers the app member.\n // When extensions exist, render every space (including the app)\n // for consistency, plus a cross-space pending total + apply hint.\n if (result.spaces?.some((s) => s.kind === 'extension')) {\n const total = result.totalPendingAcrossSpaces ?? 0;\n lines.push('');\n lines.push(c(dim, 'spaces'));\n for (const space of result.spaces) {\n lines.push(formatSpaceLine(space, c));\n }\n if (total > 0) {\n lines.push('');\n lines.push(\n `${c(yellow, '⧗')} ${total} pending migration(s) across ${result.spaces.length} space(s) — run 'prisma-next migrate' to apply`,\n );\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction formatSpaceLine(\n space: MigrationStatusSpaceEntry,\n c: (fn: (s: string) => string, s: string) => string,\n): string {\n const glyph = (() => {\n if (space.status === 'up-to-date' || space.status === 'no-marker') return c(cyan, '✓');\n if (space.status === 'pending') return c(yellow, '⧗');\n if (space.status === 'unreachable' || space.status === 'never-planned') return c(magenta, '✗');\n return ' ';\n })();\n const tag = space.kind === 'app' ? '[app]' : '[ext]';\n const head = space.headHash.slice(0, 8);\n const marker =\n space.markerHash === undefined\n ? '(unknown)'\n : space.markerHash === null\n ? '(no marker)'\n : space.markerHash.slice(0, 8);\n const pending =\n space.pendingCount === undefined\n ? ''\n : space.pendingCount === 0\n ? c(dim, ' (up to date)')\n : c(yellow, ` (${space.pendingCount} pending)`);\n return ` ${glyph} ${c(dim, tag)} ${space.spaceId} → head ${c(dim, head)}, marker ${c(dim, marker)}${pending}`;\n}\n\nfunction formatInvariantList(ids: readonly string[]): string {\n return ids.length === 0 ? '(none)' : ids.join(', ');\n}\n\nfunction summarizeRefDistance(\n graph: MigrationGraph,\n markerHash: string,\n refHash: string,\n refName: string,\n): string {\n if (markerHash === refHash) return `At ref \"${refName}\" target`;\n\n const pathToRef = findPath(graph, markerHash, refHash);\n if (pathToRef) return `${pathToRef.length} migration(s) behind ref \"${refName}\"`;\n\n const pathFromRef = findPath(graph, refHash, markerHash);\n if (pathFromRef) return `${pathFromRef.length} migration(s) ahead of ref \"${refName}\"`;\n\n return `No path between database marker and ref \"${refName}\" target`;\n}\n"],"mappings":"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"}
|
package/dist/commands/ref.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { N as CliStructuredError } from "../types-
|
|
1
|
+
import { N as CliStructuredError } from "../types-CeC5ec2Y.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,5 +1,5 @@
|
|
|
1
1
|
import { _ as createTerminalUI, g as parseGlobalFlagsOrExit, l as setCommandDescriptions, t as addGlobalOptions, u as setCommandExamples, y as handleResult } from "./command-helpers-Bbw1GbwL.mjs";
|
|
2
|
-
import { t as inspectLiveSchema } from "./inspect-live-schema-
|
|
2
|
+
import { t as inspectLiveSchema } from "./inspect-live-schema-BlKR2Zln.mjs";
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
5
5
|
import { dirname, relative, resolve } from "pathe";
|
|
@@ -72,4 +72,4 @@ function createContractInferCommand() {
|
|
|
72
72
|
//#endregion
|
|
73
73
|
export { createContractInferCommand as t };
|
|
74
74
|
|
|
75
|
-
//# sourceMappingURL=contract-infer-
|
|
75
|
+
//# sourceMappingURL=contract-infer-C8J1WMvO.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-infer-
|
|
1
|
+
{"version":3,"file":"contract-infer-C8J1WMvO.mjs","names":[],"sources":["../src/commands/contract-infer-paths.ts","../src/commands/contract-infer.ts"],"sourcesContent":["import { dirname, resolve } from 'pathe';\n\ninterface ContractInferPathOptions {\n readonly output?: string;\n readonly config?: string;\n}\n\n/**\n * Resolves the output path for the inferred PSL contract.\n *\n * Priority:\n * 1. --output <path> flag (resolved relative to cwd)\n * 2. contract.prisma next to config.contract.output\n * 3. Canonical default: contract.prisma in the config directory\n */\nexport function resolveContractInferOutputPath(\n options: ContractInferPathOptions,\n contractOutput: string | undefined,\n): string {\n const configDir = options.config\n ? dirname(resolve(process.cwd(), options.config))\n : process.cwd();\n\n if (options.output) {\n return resolve(process.cwd(), options.output);\n }\n if (contractOutput) {\n const contractPath = resolve(configDir, contractOutput);\n return resolve(dirname(contractPath), 'contract.prisma');\n }\n return resolve(configDir, 'contract.prisma');\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { errorRuntime } from '@prisma-next/errors/execution';\nimport { printPsl } from '@prisma-next/psl-printer';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { dirname, relative } from 'pathe';\nimport type { CliStructuredError } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\nimport { resolveContractInferOutputPath } from './contract-infer-paths';\nimport {\n type InspectLiveSchemaOptions,\n type InspectLiveSchemaResult,\n inspectLiveSchema,\n} from './inspect-live-schema';\n\ninterface ContractInferOptions extends InspectLiveSchemaOptions {\n readonly output?: string;\n}\n\ninterface ContractInferSuccessResult {\n readonly ok: true;\n readonly summary: string;\n readonly target: InspectLiveSchemaResult['target'];\n readonly psl: {\n readonly path: string;\n };\n readonly meta: InspectLiveSchemaResult['meta'];\n readonly timings: {\n readonly total: number;\n };\n}\n\nasync function executeContractInferCommand(\n options: ContractInferOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<ContractInferSuccessResult, CliStructuredError>> {\n const inspectResult = await inspectLiveSchema(options, flags, ui, startTime, {\n commandName: 'contract infer',\n description: 'Infer a PSL contract from the live database schema',\n url: 'https://pris.ly/contract-infer',\n });\n\n if (!inspectResult.ok) {\n return inspectResult;\n }\n\n const { config, target, meta, pslContractAst } = inspectResult.value;\n\n if (!pslContractAst) {\n return notOk(\n errorRuntime('contract infer is not supported for this family', {\n why: 'The configured family does not implement the PslContractInferCapable capability, so an inferred PSL contract cannot be produced from the live database schema.',\n fix: 'Use a family that supports contract inference (e.g. SQL/Postgres).',\n }),\n );\n }\n\n const outputPath = resolveContractInferOutputPath(options, config.contract?.output);\n const pslContent = printPsl(pslContractAst);\n\n if (existsSync(outputPath) && !flags.json && !flags.quiet) {\n ui.stderr(`\\u26A0 Overwriting existing file: ${relative(process.cwd(), outputPath)}`);\n }\n\n mkdirSync(dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, pslContent, 'utf-8');\n\n const pslPath = relative(process.cwd(), outputPath);\n if (!flags.json && !flags.quiet) {\n ui.stderr(`\\u2714 Contract written to ${pslPath}`);\n }\n\n return ok({\n ok: true,\n summary: 'Contract inferred successfully',\n target,\n psl: {\n path: pslPath,\n },\n meta,\n timings: {\n total: Date.now() - startTime,\n },\n });\n}\n\nexport function createContractInferCommand(): Command {\n const command = new Command('infer');\n setCommandDescriptions(\n command,\n 'Infer a PSL contract from the live database schema',\n 'Reads the live database schema and writes an inferred PSL contract to disk.\\n' +\n 'This command stops at `contract.prisma`; follow it with `contract emit` and\\n' +\n '`db sign` as separate steps.',\n );\n setCommandExamples(command, [\n 'prisma-next contract infer --db $DATABASE_URL',\n 'prisma-next contract infer --db $DATABASE_URL --output ./src/prisma/contract.prisma',\n 'prisma-next contract infer --db $DATABASE_URL --json',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--output <path>', 'Write the inferred PSL contract to the specified path')\n .action(async (options: ContractInferOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n const startTime = Date.now();\n\n const result = await executeContractInferCommand(options, flags, ui, startTime);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value, null, 2));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAeA,SAAgB,+BACd,SACA,gBACQ;CACR,MAAM,YAAY,QAAQ,SACtB,QAAQ,QAAQ,QAAQ,IAAI,GAAG,QAAQ,MAAM,CAAC,IAC9C,QAAQ,IAAI;CAEhB,IAAI,QAAQ,QACV,OAAO,QAAQ,QAAQ,IAAI,GAAG,QAAQ,MAAM;CAE9C,IAAI,gBAEF,OAAO,QAAQ,QADM,QAAQ,WAAW,cACN,CAAC,GAAG,iBAAiB;CAEzD,OAAO,QAAQ,WAAW,iBAAiB;AAC7C;;;ACQA,eAAe,4BACb,SACA,OACA,IACA,WACiE;CACjE,MAAM,gBAAgB,MAAM,kBAAkB,SAAS,OAAO,IAAI,WAAW;EAC3E,aAAa;EACb,aAAa;EACb,KAAK;CACP,CAAC;CAED,IAAI,CAAC,cAAc,IACjB,OAAO;CAGT,MAAM,EAAE,QAAQ,QAAQ,MAAM,mBAAmB,cAAc;CAE/D,IAAI,CAAC,gBACH,OAAO,MACL,aAAa,mDAAmD;EAC9D,KAAK;EACL,KAAK;CACP,CAAC,CACH;CAGF,MAAM,aAAa,+BAA+B,SAAS,OAAO,UAAU,MAAM;CAClF,MAAM,aAAa,SAAS,cAAc;CAE1C,IAAI,WAAW,UAAU,KAAK,CAAC,MAAM,QAAQ,CAAC,MAAM,OAClD,GAAG,OAAO,qCAAqC,SAAS,QAAQ,IAAI,GAAG,UAAU,GAAG;CAGtF,UAAU,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;CAClD,cAAc,YAAY,YAAY,OAAO;CAE7C,MAAM,UAAU,SAAS,QAAQ,IAAI,GAAG,UAAU;CAClD,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OACxB,GAAG,OAAO,8BAA8B,SAAS;CAGnD,OAAO,GAAG;EACR,IAAI;EACJ,SAAS;EACT;EACA,KAAK,EACH,MAAM,QACR;EACA;EACA,SAAS,EACP,OAAO,KAAK,IAAI,IAAI,UACtB;CACF,CAAC;AACH;AAEA,SAAgB,6BAAsC;CACpD,MAAM,UAAU,IAAI,QAAQ,OAAO;CACnC,uBACE,SACA,sDACA,wLAGF;CACA,mBAAmB,SAAS;EAC1B;EACA;EACA;CACF,CAAC;CACD,iBAAiB,OAAO,EACrB,OAAO,cAAc,4BAA4B,EACjD,OAAO,mBAAmB,+BAA+B,EACzD,OAAO,mBAAmB,uDAAuD,EACjF,OAAO,OAAO,YAAkC;EAC/C,MAAM,QAAQ,uBAAuB,OAAO;EAC5C,MAAM,KAAK,iBAAiB,KAAK;EAIjC,MAAM,WAAW,aAAa,MADT,4BAA4B,SAAS,OAAO,IAF/C,KAAK,IAEsD,CAAC,GACxC,OAAO,KAAK,UAAU;GAC1D,IAAI,MAAM,MACR,GAAG,OAAO,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;EAE5C,CAAC;EAED,QAAQ,KAAK,QAAQ;CACvB,CAAC;CAEH,OAAO;AACT"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { A as CliStructuredError, F as errorDatabaseConnectionRequired, H as errorMarkerMissing, L as errorDriverRequired, P as errorContractValidationFailed, R as errorFileNotFound, T as formatStyledHeader, X as errorRuntime, _ as createTerminalUI, et as errorTargetMismatch, g as parseGlobalFlagsOrExit, i as maskConnectionUrl, l as setCommandDescriptions, o as resolveContractPath, s as resolveMigrationPaths, t as addGlobalOptions, tt as errorUnexpected, u as setCommandExamples, y as handleResult, z as errorHashMismatch } from "./command-helpers-Bbw1GbwL.mjs";
|
|
3
3
|
import { t as createProgressAdapter } from "./progress-adapter-C644QK8l.mjs";
|
|
4
|
-
import { a as ContractValidationError, t as createControlClient } from "./client-
|
|
4
|
+
import { a as ContractValidationError, t as createControlClient } from "./client-CDr4o07S.mjs";
|
|
5
5
|
import { c as formatVerifyOutput, i as formatSchemaVerifyOutput, r as formatSchemaVerifyJson, s as formatVerifyJson } from "./verify-DCA9Sldu.mjs";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
@@ -398,4 +398,4 @@ function createDbVerifyCommand() {
|
|
|
398
398
|
//#endregion
|
|
399
399
|
export { createDbVerifyCommand as t };
|
|
400
400
|
|
|
401
|
-
//# sourceMappingURL=db-verify-
|
|
401
|
+
//# sourceMappingURL=db-verify-BeRHwN8M.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-verify-v_vUKXTU.mjs","names":[],"sources":["../src/utils/combine-schema-results.ts","../src/commands/db-verify.ts"],"sourcesContent":["import type { VerifyDatabaseSchemaResult } from '@prisma-next/framework-components/control';\n\n/**\n * Collapse the aggregate verifier's per-space schema results into a\n * single {@link VerifyDatabaseSchemaResult} for the existing CLI\n * display surface. Concatenates issues across members; sums counts;\n * uses the app member's result as the structural envelope (storage\n * hash, target).\n *\n * **Summary policy.** Preserve the per-family phrasing whenever the\n * combined `ok` flag agrees with the app member's `ok` flag — this is\n * the common case (single-family deployments, single-app deployments)\n * and the family's \"satisfies / does not satisfy contract\" phrasing\n * stays user-visible. When the app passes but an extension fails (or\n * vice versa) the app's summary contradicts the envelope, so fall back\n * to the first failing member's summary. This keeps family phrasing\n * intact and the envelope internally consistent (`ok: false` ↔ failure\n * summary).\n */\nexport function combineSchemaResults(\n perSpace: ReadonlyMap<string, VerifyDatabaseSchemaResult>,\n appSpaceId: string,\n strict: boolean,\n): VerifyDatabaseSchemaResult {\n const appResult = perSpace.get(appSpaceId) ?? perSpace.values().next().value;\n if (appResult === undefined) {\n throw new Error('Aggregate verifier returned no schema results — this is a wiring bug.');\n }\n\n let okAll = true;\n let firstFailure: VerifyDatabaseSchemaResult | undefined;\n let issues: VerifyDatabaseSchemaResult['schema']['issues'] = [];\n const counts = { pass: 0, warn: 0, fail: 0, totalNodes: 0 };\n const childRoots: Array<VerifyDatabaseSchemaResult['schema']['root']> = [];\n for (const [, result] of perSpace) {\n if (!result.ok) {\n okAll = false;\n if (firstFailure === undefined) firstFailure = result;\n }\n issues = [...issues, ...result.schema.issues];\n counts.pass += result.schema.counts.pass;\n counts.warn += result.schema.counts.warn;\n counts.fail += result.schema.counts.fail;\n counts.totalNodes += result.schema.counts.totalNodes;\n childRoots.push(result.schema.root);\n }\n\n // When `okAll !== appResult.ok`, exactly one shape is reachable: app passes\n // (`appResult.ok === true`) and at least one other member failed\n // (`okAll === false`). In that shape the failure was assigned to\n // `firstFailure` during iteration, so non-null assertion is safe. The mirror\n // shape (app fails while every member passes) is impossible because\n // `appResult` either *is* a member of `perSpace` or is the first iterator\n // value; either way its `ok` flag participates in `okAll`.\n const summary =\n okAll === appResult.ok\n ? appResult.summary\n : (firstFailure as VerifyDatabaseSchemaResult).summary;\n\n return {\n ok: okAll,\n ...(okAll ? {} : { code: appResult.code ?? 'PN-RUN-3010' }),\n summary,\n contract: appResult.contract,\n target: appResult.target,\n schema: {\n issues,\n root: {\n status: okAll ? 'pass' : 'fail',\n kind: 'aggregate',\n name: 'aggregate',\n contractPath: '',\n code: 'AGGREGATE',\n message: okAll ? 'Aggregate schema matches' : 'Aggregate schema mismatch',\n expected: undefined,\n actual: undefined,\n children: childRoots,\n },\n counts,\n },\n meta: { strict },\n timings: { total: 0 },\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type {\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport {\n createControlStack,\n VERIFY_CODE_HASH_MISMATCH,\n VERIFY_CODE_MARKER_MISSING,\n VERIFY_CODE_TARGET_MISMATCH,\n} from '@prisma-next/framework-components/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\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 { ContractValidationError } from '../control-api/errors';\nimport {\n CliStructuredError,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorHashMismatch,\n errorMarkerMissing,\n errorRuntime,\n errorTargetMismatch,\n errorUnexpected,\n} from '../utils/cli-errors';\nimport { combineSchemaResults } from '../utils/combine-schema-results';\nimport {\n addGlobalOptions,\n maskConnectionUrl,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport {\n type DbVerifyCommandSuccessResult,\n formatSchemaVerifyJson,\n formatSchemaVerifyOutput,\n formatVerifyJson,\n formatVerifyOutput,\n} from '../utils/formatters/verify';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface DbVerifyOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly markerOnly?: boolean;\n readonly schemaOnly?: boolean;\n readonly strict?: boolean;\n}\n\ntype DbVerifyMode = 'full' | 'marker-only' | 'schema-only';\n\n/**\n * Maps a VerifyDatabaseResult failure to a CliStructuredError.\n */\nfunction mapVerifyFailure(verifyResult: VerifyDatabaseResult): CliStructuredError {\n if (!verifyResult.ok && verifyResult.code) {\n if (verifyResult.code === VERIFY_CODE_MARKER_MISSING) {\n return errorMarkerMissing();\n }\n if (verifyResult.code === VERIFY_CODE_HASH_MISMATCH) {\n const storageMatch = verifyResult.marker?.storageHash === verifyResult.contract.storageHash;\n const profileMatch =\n !verifyResult.contract.profileHash ||\n verifyResult.marker?.profileHash === verifyResult.contract.profileHash;\n\n if (!storageMatch) {\n return errorHashMismatch({\n why: 'Contract storageHash does not match database marker',\n expected: verifyResult.contract.storageHash,\n ...ifDefined('actual', verifyResult.marker?.storageHash),\n });\n }\n\n return errorHashMismatch({\n why: profileMatch\n ? 'Contract hash does not match database marker'\n : 'Contract profileHash does not match database marker',\n ...ifDefined('expected', verifyResult.contract.profileHash),\n ...ifDefined('actual', verifyResult.marker?.profileHash),\n });\n }\n if (verifyResult.code === VERIFY_CODE_TARGET_MISMATCH) {\n return errorTargetMismatch(\n verifyResult.target.expected,\n verifyResult.target.actual ?? 'unknown',\n );\n }\n // Unknown code - fall through to runtime error\n }\n return errorRuntime(verifyResult.summary);\n}\n\ntype DbVerifyFailure = CliStructuredError | VerifyDatabaseSchemaResult;\n\nfunction errorInvalidVerifyMode(options: {\n readonly why: string;\n readonly fix: string;\n}): CliStructuredError {\n return new CliStructuredError('4012', 'Invalid verify mode', {\n domain: 'CLI',\n why: options.why,\n fix: options.fix,\n docsUrl: 'https://pris.ly/db-verify',\n });\n}\n\nfunction resolveDbVerifyMode(options: DbVerifyOptions): Result<DbVerifyMode, CliStructuredError> {\n if (options.markerOnly && options.schemaOnly) {\n return notOk(\n errorInvalidVerifyMode({\n why: '`--marker-only` and `--schema-only` cannot be used together',\n fix: 'Choose one mode: omit both to check the marker and schema, use `--marker-only` to check only the marker, or use `--schema-only` to check only the live schema.',\n }),\n );\n }\n\n if (options.markerOnly && options.strict) {\n return notOk(\n errorInvalidVerifyMode({\n why: '`--strict` requires schema verification, but `--marker-only` skips it',\n fix: 'Remove `--strict`, or use `db verify` / `db verify --schema-only` when you want to check the live schema in strict mode.',\n }),\n );\n }\n\n if (options.schemaOnly) {\n return ok('schema-only');\n }\n\n if (options.markerOnly) {\n return ok('marker-only');\n }\n\n return ok('full');\n}\n\nfunction formatDbVerifyModeLabel(mode: DbVerifyMode, strict: boolean): string {\n if (mode === 'marker-only') {\n return 'marker only';\n }\n\n if (mode === 'schema-only') {\n return `schema only (${strict ? 'strict' : 'tolerant'})`;\n }\n\n return `full (marker + schema, ${strict ? 'strict' : 'tolerant'})`;\n}\n\nfunction formatDbVerifyInvocation(mode: DbVerifyMode, strict: boolean): string {\n const args = ['db verify'];\n\n if (mode === 'marker-only') {\n args.push('--marker-only');\n }\n\n if (mode === 'schema-only') {\n args.push('--schema-only');\n }\n\n if (strict) {\n args.push('--strict');\n }\n\n return args.join(' ');\n}\n\nfunction createDbVerifyConnectionRequiredError(options: {\n readonly configPath: string;\n readonly mode: DbVerifyMode;\n readonly strict: boolean;\n}): CliStructuredError {\n const invocation = formatDbVerifyInvocation(options.mode, options.strict);\n return errorDatabaseConnectionRequired({\n why: `Database connection is required for ${invocation} (set db.connection in ${options.configPath}, or pass --db <url>)`,\n retryCommand: `prisma-next ${invocation} --db <url>`,\n });\n}\n\nfunction renderVerifyHeader(\n paths: { configPath: string; contractPath: string },\n options: DbVerifyOptions,\n mode: DbVerifyMode,\n flags: GlobalFlags,\n ui: TerminalUI,\n): void {\n if (flags.json || flags.quiet) return;\n\n const description =\n mode === 'schema-only'\n ? 'Check whether the live database schema matches your contract'\n : mode === 'marker-only'\n ? 'Check whether the database marker matches your contract'\n : 'Check whether the database marker and live schema match your contract';\n\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: paths.configPath },\n { label: 'contract', value: paths.contractPath },\n { label: 'mode', value: formatDbVerifyModeLabel(mode, options.strict ?? false) },\n ];\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n }\n\n ui.stderr(\n formatStyledHeader({\n command: 'db verify',\n description,\n url: 'https://pris.ly/db-verify',\n details,\n flags,\n }),\n );\n}\n\nasync function resolveVerifyPaths(options: DbVerifyOptions) {\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 const contractPathAbsolute = resolveContractPath(config);\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n return { config, configPath, contractPathAbsolute, contractPath };\n}\n\ntype VerifyPaths = Awaited<ReturnType<typeof resolveVerifyPaths>>;\n\ninterface VerifySetup extends VerifyPaths {\n readonly contractJson: Contract;\n readonly dbConnection: string;\n}\n\nasync function resolveVerifySetup(\n paths: VerifyPaths,\n options: DbVerifyOptions,\n mode: DbVerifyMode,\n): Promise<Result<VerifySetup, CliStructuredError>> {\n const { config, configPath, contractPathAbsolute, contractPath } = paths;\n\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: `Run \\`prisma-next contract emit\\` to generate ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Cross the family `deserializeContract` seam at the read site, just\n // like every other CLI on-disk read (TML-2536). The downstream\n // `dbVerify` op accepts the hydrated `Contract` directly and no\n // longer re-deserializes.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n let contractJson: Contract;\n try {\n contractJson = familyInstance.deserializeContract(JSON.parse(contractJsonContent) as unknown);\n } catch (error) {\n if (error instanceof ContractValidationError) {\n return notOk(\n errorContractValidationFailed(`Contract validation failed: ${error.message}`, {\n where: { path: contractPathAbsolute },\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 const dbConnection = options.db ?? config.db?.connection;\n if (typeof dbConnection !== 'string' || dbConnection.length === 0) {\n return notOk(\n createDbVerifyConnectionRequiredError({\n configPath,\n mode,\n strict: options.strict ?? false,\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: `Config.driver is required for ${formatDbVerifyInvocation(mode, options.strict ?? false)}`,\n }),\n );\n }\n\n return ok({ ...paths, contractJson, dbConnection });\n}\n\nfunction createVerifyClient(setup: VerifySetup) {\n return createControlClient({\n family: setup.config.family,\n target: setup.config.target,\n adapter: setup.config.adapter,\n driver: setup.config.driver!,\n extensionPacks: setup.config.extensionPacks ?? [],\n });\n}\n\nfunction wrapVerifyError(\n error: unknown,\n contractPathAbsolute: string,\n modeLabel: string,\n): Result<never, CliStructuredError> {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (error instanceof ContractValidationError) {\n return notOk(\n errorContractValidationFailed(`Contract validation failed: ${error.message}`, {\n where: { path: contractPathAbsolute },\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Unexpected error during ${modeLabel}: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n}\n\n/**\n * Executes the db verify command and returns a structured Result.\n */\nasync function executeDbVerifyCommand(\n options: DbVerifyOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n mode: Extract<DbVerifyMode, 'full' | 'marker-only'>,\n): Promise<Result<DbVerifyCommandSuccessResult, DbVerifyFailure>> {\n const startTime = Date.now();\n const paths = await resolveVerifyPaths(options);\n renderVerifyHeader(paths, options, mode, flags, ui);\n\n const setupResult = await resolveVerifySetup(paths, options, mode);\n if (!setupResult.ok) return setupResult;\n const { contractJson, dbConnection, contractPathAbsolute } = setupResult.value;\n const { migrationsDir } = resolveMigrationPaths(options.config, setupResult.value.config);\n\n const client = createVerifyClient(setupResult.value);\n const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n // Single-contract marker verification preserved for the existing\n // marker / target / hash failure surface (`PN-RUN-3001/3002/3003`).\n // The aggregate verifier (run below for the per-space marker /\n // schema checks) does not duplicate this: it concerns itself with\n // marker-vs-on-disk and orphan-marker drift, not the\n // hash-mismatch-against-the-app-contract lane that today's\n // `client.verify` covers.\n const verifyResult = await client.verify({\n contract: contractJson,\n connection: dbConnection,\n onProgress,\n });\n\n if (!verifyResult.ok) {\n return notOk(mapVerifyFailure(verifyResult));\n }\n\n // Aggregate verifier (loader → verifier pipeline). Runs the layout\n // precheck, marker-aware per-space verifier, and (full mode only)\n // per-space pre-projected schema verification (closes F23).\n const aggregateResult = await client.dbVerify({\n contract: contractJson,\n migrationsDir,\n strict: options.strict ?? false,\n skipSchema: mode === 'marker-only',\n skipMarker: false,\n onProgress,\n });\n if (!aggregateResult.ok) return notOk(aggregateResult.failure);\n\n if (mode === 'marker-only') {\n return ok({\n ok: true,\n mode: 'marker-only',\n summary: 'Database marker matches contract',\n contract: verifyResult.contract,\n marker: verifyResult.marker,\n target: verifyResult.target,\n ...ifDefined('missingCodecs', verifyResult.missingCodecs),\n ...ifDefined('codecCoverageSkipped', verifyResult.codecCoverageSkipped),\n warning: 'Schema verification skipped because --marker-only was provided',\n meta: {\n ...(verifyResult.meta ?? {}),\n schemaVerification: 'skipped',\n },\n timings: { total: Date.now() - startTime },\n });\n }\n\n const combined = combineSchemaResults(\n aggregateResult.value.schemaResults,\n aggregateResult.value.appSpaceId,\n options.strict ?? false,\n );\n if (!combined.ok) {\n return notOk(combined);\n }\n\n return ok({\n ok: true,\n mode: 'full',\n summary: 'Database marker and schema match contract',\n contract: verifyResult.contract,\n marker: verifyResult.marker,\n target: verifyResult.target,\n ...ifDefined('missingCodecs', verifyResult.missingCodecs),\n ...ifDefined('codecCoverageSkipped', verifyResult.codecCoverageSkipped),\n schema: {\n summary: combined.summary,\n counts: combined.schema.counts,\n strict: combined.meta?.strict ?? false,\n },\n meta: {\n ...(verifyResult.meta ?? {}),\n schemaVerification: 'performed',\n },\n timings: { total: Date.now() - startTime },\n });\n } catch (error) {\n return wrapVerifyError(error, contractPathAbsolute, 'db verify');\n } finally {\n await client.close();\n }\n}\n\nasync function executeDbSchemaOnlyVerifyCommand(\n options: DbVerifyOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<VerifyDatabaseSchemaResult, CliStructuredError>> {\n const paths = await resolveVerifyPaths(options);\n renderVerifyHeader(paths, options, 'schema-only', flags, ui);\n\n const setupResult = await resolveVerifySetup(paths, options, 'schema-only');\n if (!setupResult.ok) return setupResult;\n const { contractJson, dbConnection, contractPathAbsolute } = setupResult.value;\n const { migrationsDir } = resolveMigrationPaths(options.config, setupResult.value.config);\n\n const client = createVerifyClient(setupResult.value);\n const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n await client.connect(dbConnection);\n const aggregateResult = await client.dbVerify({\n contract: contractJson,\n migrationsDir,\n strict: options.strict ?? false,\n skipSchema: false,\n skipMarker: true,\n onProgress,\n });\n if (!aggregateResult.ok) return notOk(aggregateResult.failure);\n\n return ok(\n combineSchemaResults(\n aggregateResult.value.schemaResults,\n aggregateResult.value.appSpaceId,\n options.strict ?? false,\n ),\n );\n } catch (error) {\n return wrapVerifyError(error, contractPathAbsolute, 'db verify --schema-only');\n } finally {\n await client.close();\n }\n}\n\nexport function createDbVerifyCommand(): Command {\n const command = new Command('verify');\n setCommandDescriptions(\n command,\n 'Check whether the database marker and live schema match your contract',\n 'Verifies the database marker first, then checks the database schema matches your contract.\\n' +\n 'Use `--marker-only` for marker-only verification, `--schema-only` to skip marker checks and\\n' +\n 'inspect only the live schema, and `--strict` to fail if the database includes elements\\n' +\n 'not present in the contract.',\n );\n setCommandExamples(command, [\n 'prisma-next db verify --db $DATABASE_URL',\n 'prisma-next db verify --db $DATABASE_URL --strict',\n 'prisma-next db verify --db $DATABASE_URL --schema-only',\n 'prisma-next db verify --db $DATABASE_URL --schema-only --strict',\n 'prisma-next db verify --db $DATABASE_URL --marker-only',\n 'prisma-next db verify --db $DATABASE_URL --json',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--marker-only', 'Skip schema verification and only check the database marker')\n .option(\n '--schema-only',\n 'Skip marker verification and only check whether the live schema satisfies the contract',\n )\n .option(\n '--strict',\n 'Strict mode: schema elements not present in the contract are considered an error',\n false,\n )\n .action(async (options: DbVerifyOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n const modeResult = resolveDbVerifyMode(options);\n if (!modeResult.ok) {\n const exitCode = handleResult(modeResult as Result<never, CliStructuredError>, flags, ui);\n process.exit(exitCode);\n }\n\n const mode = modeResult.value;\n\n if (mode === 'schema-only') {\n const result = await executeDbSchemaOnlyVerifyCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (schemaVerifyResult) => {\n if (flags.json) {\n ui.output(formatSchemaVerifyJson(schemaVerifyResult));\n } else {\n const output = formatSchemaVerifyOutput(schemaVerifyResult, flags);\n if (output) {\n ui.log(output);\n }\n }\n });\n\n if (result.ok && !result.value.ok) {\n process.exit(1);\n }\n\n process.exit(exitCode);\n }\n\n const result = await executeDbVerifyCommand(options, flags, ui, mode);\n\n if (result.ok) {\n if (flags.json) {\n ui.output(formatVerifyJson(result.value));\n } else {\n const output = formatVerifyOutput(result.value, flags);\n if (output) {\n ui.log(output);\n }\n }\n process.exit(0);\n }\n\n if (CliStructuredError.is(result.failure)) {\n const exitCode = handleResult(result as Result<never, CliStructuredError>, flags, ui);\n process.exit(exitCode);\n }\n\n if (flags.json) {\n ui.output(formatSchemaVerifyJson(result.failure));\n } else {\n // Always show schema-drift failures, even in quiet mode — exiting 1 without\n // diagnostics is unhelpful.\n const output = formatSchemaVerifyOutput(result.failure, { ...flags, quiet: false });\n if (output) {\n ui.log(output);\n }\n }\n process.exit(1);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"db-verify-BeRHwN8M.mjs","names":[],"sources":["../src/utils/combine-schema-results.ts","../src/commands/db-verify.ts"],"sourcesContent":["import type { VerifyDatabaseSchemaResult } from '@prisma-next/framework-components/control';\n\n/**\n * Collapse the aggregate verifier's per-space schema results into a\n * single {@link VerifyDatabaseSchemaResult} for the existing CLI\n * display surface. Concatenates issues across members; sums counts;\n * uses the app member's result as the structural envelope (storage\n * hash, target).\n *\n * **Summary policy.** Preserve the per-family phrasing whenever the\n * combined `ok` flag agrees with the app member's `ok` flag — this is\n * the common case (single-family deployments, single-app deployments)\n * and the family's \"satisfies / does not satisfy contract\" phrasing\n * stays user-visible. When the app passes but an extension fails (or\n * vice versa) the app's summary contradicts the envelope, so fall back\n * to the first failing member's summary. This keeps family phrasing\n * intact and the envelope internally consistent (`ok: false` ↔ failure\n * summary).\n */\nexport function combineSchemaResults(\n perSpace: ReadonlyMap<string, VerifyDatabaseSchemaResult>,\n appSpaceId: string,\n strict: boolean,\n): VerifyDatabaseSchemaResult {\n const appResult = perSpace.get(appSpaceId) ?? perSpace.values().next().value;\n if (appResult === undefined) {\n throw new Error('Aggregate verifier returned no schema results — this is a wiring bug.');\n }\n\n let okAll = true;\n let firstFailure: VerifyDatabaseSchemaResult | undefined;\n let issues: VerifyDatabaseSchemaResult['schema']['issues'] = [];\n const counts = { pass: 0, warn: 0, fail: 0, totalNodes: 0 };\n const childRoots: Array<VerifyDatabaseSchemaResult['schema']['root']> = [];\n for (const [, result] of perSpace) {\n if (!result.ok) {\n okAll = false;\n if (firstFailure === undefined) firstFailure = result;\n }\n issues = [...issues, ...result.schema.issues];\n counts.pass += result.schema.counts.pass;\n counts.warn += result.schema.counts.warn;\n counts.fail += result.schema.counts.fail;\n counts.totalNodes += result.schema.counts.totalNodes;\n childRoots.push(result.schema.root);\n }\n\n // When `okAll !== appResult.ok`, exactly one shape is reachable: app passes\n // (`appResult.ok === true`) and at least one other member failed\n // (`okAll === false`). In that shape the failure was assigned to\n // `firstFailure` during iteration, so non-null assertion is safe. The mirror\n // shape (app fails while every member passes) is impossible because\n // `appResult` either *is* a member of `perSpace` or is the first iterator\n // value; either way its `ok` flag participates in `okAll`.\n const summary =\n okAll === appResult.ok\n ? appResult.summary\n : (firstFailure as VerifyDatabaseSchemaResult).summary;\n\n return {\n ok: okAll,\n ...(okAll ? {} : { code: appResult.code ?? 'PN-RUN-3010' }),\n summary,\n contract: appResult.contract,\n target: appResult.target,\n schema: {\n issues,\n root: {\n status: okAll ? 'pass' : 'fail',\n kind: 'aggregate',\n name: 'aggregate',\n contractPath: '',\n code: 'AGGREGATE',\n message: okAll ? 'Aggregate schema matches' : 'Aggregate schema mismatch',\n expected: undefined,\n actual: undefined,\n children: childRoots,\n },\n counts,\n },\n meta: { strict },\n timings: { total: 0 },\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type {\n VerifyDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport {\n createControlStack,\n VERIFY_CODE_HASH_MISMATCH,\n VERIFY_CODE_MARKER_MISSING,\n VERIFY_CODE_TARGET_MISMATCH,\n} from '@prisma-next/framework-components/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\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 { ContractValidationError } from '../control-api/errors';\nimport {\n CliStructuredError,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorHashMismatch,\n errorMarkerMissing,\n errorRuntime,\n errorTargetMismatch,\n errorUnexpected,\n} from '../utils/cli-errors';\nimport { combineSchemaResults } from '../utils/combine-schema-results';\nimport {\n addGlobalOptions,\n maskConnectionUrl,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport {\n type DbVerifyCommandSuccessResult,\n formatSchemaVerifyJson,\n formatSchemaVerifyOutput,\n formatVerifyJson,\n formatVerifyOutput,\n} from '../utils/formatters/verify';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface DbVerifyOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly markerOnly?: boolean;\n readonly schemaOnly?: boolean;\n readonly strict?: boolean;\n}\n\ntype DbVerifyMode = 'full' | 'marker-only' | 'schema-only';\n\n/**\n * Maps a VerifyDatabaseResult failure to a CliStructuredError.\n */\nfunction mapVerifyFailure(verifyResult: VerifyDatabaseResult): CliStructuredError {\n if (!verifyResult.ok && verifyResult.code) {\n if (verifyResult.code === VERIFY_CODE_MARKER_MISSING) {\n return errorMarkerMissing();\n }\n if (verifyResult.code === VERIFY_CODE_HASH_MISMATCH) {\n const storageMatch = verifyResult.marker?.storageHash === verifyResult.contract.storageHash;\n const profileMatch =\n !verifyResult.contract.profileHash ||\n verifyResult.marker?.profileHash === verifyResult.contract.profileHash;\n\n if (!storageMatch) {\n return errorHashMismatch({\n why: 'Contract storageHash does not match database marker',\n expected: verifyResult.contract.storageHash,\n ...ifDefined('actual', verifyResult.marker?.storageHash),\n });\n }\n\n return errorHashMismatch({\n why: profileMatch\n ? 'Contract hash does not match database marker'\n : 'Contract profileHash does not match database marker',\n ...ifDefined('expected', verifyResult.contract.profileHash),\n ...ifDefined('actual', verifyResult.marker?.profileHash),\n });\n }\n if (verifyResult.code === VERIFY_CODE_TARGET_MISMATCH) {\n return errorTargetMismatch(\n verifyResult.target.expected,\n verifyResult.target.actual ?? 'unknown',\n );\n }\n // Unknown code - fall through to runtime error\n }\n return errorRuntime(verifyResult.summary);\n}\n\ntype DbVerifyFailure = CliStructuredError | VerifyDatabaseSchemaResult;\n\nfunction errorInvalidVerifyMode(options: {\n readonly why: string;\n readonly fix: string;\n}): CliStructuredError {\n return new CliStructuredError('4012', 'Invalid verify mode', {\n domain: 'CLI',\n why: options.why,\n fix: options.fix,\n docsUrl: 'https://pris.ly/db-verify',\n });\n}\n\nfunction resolveDbVerifyMode(options: DbVerifyOptions): Result<DbVerifyMode, CliStructuredError> {\n if (options.markerOnly && options.schemaOnly) {\n return notOk(\n errorInvalidVerifyMode({\n why: '`--marker-only` and `--schema-only` cannot be used together',\n fix: 'Choose one mode: omit both to check the marker and schema, use `--marker-only` to check only the marker, or use `--schema-only` to check only the live schema.',\n }),\n );\n }\n\n if (options.markerOnly && options.strict) {\n return notOk(\n errorInvalidVerifyMode({\n why: '`--strict` requires schema verification, but `--marker-only` skips it',\n fix: 'Remove `--strict`, or use `db verify` / `db verify --schema-only` when you want to check the live schema in strict mode.',\n }),\n );\n }\n\n if (options.schemaOnly) {\n return ok('schema-only');\n }\n\n if (options.markerOnly) {\n return ok('marker-only');\n }\n\n return ok('full');\n}\n\nfunction formatDbVerifyModeLabel(mode: DbVerifyMode, strict: boolean): string {\n if (mode === 'marker-only') {\n return 'marker only';\n }\n\n if (mode === 'schema-only') {\n return `schema only (${strict ? 'strict' : 'tolerant'})`;\n }\n\n return `full (marker + schema, ${strict ? 'strict' : 'tolerant'})`;\n}\n\nfunction formatDbVerifyInvocation(mode: DbVerifyMode, strict: boolean): string {\n const args = ['db verify'];\n\n if (mode === 'marker-only') {\n args.push('--marker-only');\n }\n\n if (mode === 'schema-only') {\n args.push('--schema-only');\n }\n\n if (strict) {\n args.push('--strict');\n }\n\n return args.join(' ');\n}\n\nfunction createDbVerifyConnectionRequiredError(options: {\n readonly configPath: string;\n readonly mode: DbVerifyMode;\n readonly strict: boolean;\n}): CliStructuredError {\n const invocation = formatDbVerifyInvocation(options.mode, options.strict);\n return errorDatabaseConnectionRequired({\n why: `Database connection is required for ${invocation} (set db.connection in ${options.configPath}, or pass --db <url>)`,\n retryCommand: `prisma-next ${invocation} --db <url>`,\n });\n}\n\nfunction renderVerifyHeader(\n paths: { configPath: string; contractPath: string },\n options: DbVerifyOptions,\n mode: DbVerifyMode,\n flags: GlobalFlags,\n ui: TerminalUI,\n): void {\n if (flags.json || flags.quiet) return;\n\n const description =\n mode === 'schema-only'\n ? 'Check whether the live database schema matches your contract'\n : mode === 'marker-only'\n ? 'Check whether the database marker matches your contract'\n : 'Check whether the database marker and live schema match your contract';\n\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: paths.configPath },\n { label: 'contract', value: paths.contractPath },\n { label: 'mode', value: formatDbVerifyModeLabel(mode, options.strict ?? false) },\n ];\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n }\n\n ui.stderr(\n formatStyledHeader({\n command: 'db verify',\n description,\n url: 'https://pris.ly/db-verify',\n details,\n flags,\n }),\n );\n}\n\nasync function resolveVerifyPaths(options: DbVerifyOptions) {\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 const contractPathAbsolute = resolveContractPath(config);\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n return { config, configPath, contractPathAbsolute, contractPath };\n}\n\ntype VerifyPaths = Awaited<ReturnType<typeof resolveVerifyPaths>>;\n\ninterface VerifySetup extends VerifyPaths {\n readonly contractJson: Contract;\n readonly dbConnection: string;\n}\n\nasync function resolveVerifySetup(\n paths: VerifyPaths,\n options: DbVerifyOptions,\n mode: DbVerifyMode,\n): Promise<Result<VerifySetup, CliStructuredError>> {\n const { config, configPath, contractPathAbsolute, contractPath } = paths;\n\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: `Run \\`prisma-next contract emit\\` to generate ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Cross the family `deserializeContract` seam at the read site, just\n // like every other CLI on-disk read (TML-2536). The downstream\n // `dbVerify` op accepts the hydrated `Contract` directly and no\n // longer re-deserializes.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n let contractJson: Contract;\n try {\n contractJson = familyInstance.deserializeContract(JSON.parse(contractJsonContent) as unknown);\n } catch (error) {\n if (error instanceof ContractValidationError) {\n return notOk(\n errorContractValidationFailed(`Contract validation failed: ${error.message}`, {\n where: { path: contractPathAbsolute },\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 const dbConnection = options.db ?? config.db?.connection;\n if (typeof dbConnection !== 'string' || dbConnection.length === 0) {\n return notOk(\n createDbVerifyConnectionRequiredError({\n configPath,\n mode,\n strict: options.strict ?? false,\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: `Config.driver is required for ${formatDbVerifyInvocation(mode, options.strict ?? false)}`,\n }),\n );\n }\n\n return ok({ ...paths, contractJson, dbConnection });\n}\n\nfunction createVerifyClient(setup: VerifySetup) {\n return createControlClient({\n family: setup.config.family,\n target: setup.config.target,\n adapter: setup.config.adapter,\n driver: setup.config.driver!,\n extensionPacks: setup.config.extensionPacks ?? [],\n });\n}\n\nfunction wrapVerifyError(\n error: unknown,\n contractPathAbsolute: string,\n modeLabel: string,\n): Result<never, CliStructuredError> {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (error instanceof ContractValidationError) {\n return notOk(\n errorContractValidationFailed(`Contract validation failed: ${error.message}`, {\n where: { path: contractPathAbsolute },\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Unexpected error during ${modeLabel}: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n}\n\n/**\n * Executes the db verify command and returns a structured Result.\n */\nasync function executeDbVerifyCommand(\n options: DbVerifyOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n mode: Extract<DbVerifyMode, 'full' | 'marker-only'>,\n): Promise<Result<DbVerifyCommandSuccessResult, DbVerifyFailure>> {\n const startTime = Date.now();\n const paths = await resolveVerifyPaths(options);\n renderVerifyHeader(paths, options, mode, flags, ui);\n\n const setupResult = await resolveVerifySetup(paths, options, mode);\n if (!setupResult.ok) return setupResult;\n const { contractJson, dbConnection, contractPathAbsolute } = setupResult.value;\n const { migrationsDir } = resolveMigrationPaths(options.config, setupResult.value.config);\n\n const client = createVerifyClient(setupResult.value);\n const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n // Single-contract marker verification preserved for the existing\n // marker / target / hash failure surface (`PN-RUN-3001/3002/3003`).\n // The aggregate verifier (run below for the per-space marker /\n // schema checks) does not duplicate this: it concerns itself with\n // marker-vs-on-disk and orphan-marker drift, not the\n // hash-mismatch-against-the-app-contract lane that today's\n // `client.verify` covers.\n const verifyResult = await client.verify({\n contract: contractJson,\n connection: dbConnection,\n onProgress,\n });\n\n if (!verifyResult.ok) {\n return notOk(mapVerifyFailure(verifyResult));\n }\n\n // Aggregate verifier (loader → verifier pipeline). Runs the layout\n // precheck, marker-aware per-space verifier, and (full mode only)\n // per-space pre-projected schema verification (closes F23).\n const aggregateResult = await client.dbVerify({\n contract: contractJson,\n migrationsDir,\n strict: options.strict ?? false,\n skipSchema: mode === 'marker-only',\n skipMarker: false,\n onProgress,\n });\n if (!aggregateResult.ok) return notOk(aggregateResult.failure);\n\n if (mode === 'marker-only') {\n return ok({\n ok: true,\n mode: 'marker-only',\n summary: 'Database marker matches contract',\n contract: verifyResult.contract,\n marker: verifyResult.marker,\n target: verifyResult.target,\n ...ifDefined('missingCodecs', verifyResult.missingCodecs),\n ...ifDefined('codecCoverageSkipped', verifyResult.codecCoverageSkipped),\n warning: 'Schema verification skipped because --marker-only was provided',\n meta: {\n ...(verifyResult.meta ?? {}),\n schemaVerification: 'skipped',\n },\n timings: { total: Date.now() - startTime },\n });\n }\n\n const combined = combineSchemaResults(\n aggregateResult.value.schemaResults,\n aggregateResult.value.appSpaceId,\n options.strict ?? false,\n );\n if (!combined.ok) {\n return notOk(combined);\n }\n\n return ok({\n ok: true,\n mode: 'full',\n summary: 'Database marker and schema match contract',\n contract: verifyResult.contract,\n marker: verifyResult.marker,\n target: verifyResult.target,\n ...ifDefined('missingCodecs', verifyResult.missingCodecs),\n ...ifDefined('codecCoverageSkipped', verifyResult.codecCoverageSkipped),\n schema: {\n summary: combined.summary,\n counts: combined.schema.counts,\n strict: combined.meta?.strict ?? false,\n },\n meta: {\n ...(verifyResult.meta ?? {}),\n schemaVerification: 'performed',\n },\n timings: { total: Date.now() - startTime },\n });\n } catch (error) {\n return wrapVerifyError(error, contractPathAbsolute, 'db verify');\n } finally {\n await client.close();\n }\n}\n\nasync function executeDbSchemaOnlyVerifyCommand(\n options: DbVerifyOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<VerifyDatabaseSchemaResult, CliStructuredError>> {\n const paths = await resolveVerifyPaths(options);\n renderVerifyHeader(paths, options, 'schema-only', flags, ui);\n\n const setupResult = await resolveVerifySetup(paths, options, 'schema-only');\n if (!setupResult.ok) return setupResult;\n const { contractJson, dbConnection, contractPathAbsolute } = setupResult.value;\n const { migrationsDir } = resolveMigrationPaths(options.config, setupResult.value.config);\n\n const client = createVerifyClient(setupResult.value);\n const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n await client.connect(dbConnection);\n const aggregateResult = await client.dbVerify({\n contract: contractJson,\n migrationsDir,\n strict: options.strict ?? false,\n skipSchema: false,\n skipMarker: true,\n onProgress,\n });\n if (!aggregateResult.ok) return notOk(aggregateResult.failure);\n\n return ok(\n combineSchemaResults(\n aggregateResult.value.schemaResults,\n aggregateResult.value.appSpaceId,\n options.strict ?? false,\n ),\n );\n } catch (error) {\n return wrapVerifyError(error, contractPathAbsolute, 'db verify --schema-only');\n } finally {\n await client.close();\n }\n}\n\nexport function createDbVerifyCommand(): Command {\n const command = new Command('verify');\n setCommandDescriptions(\n command,\n 'Check whether the database marker and live schema match your contract',\n 'Verifies the database marker first, then checks the database schema matches your contract.\\n' +\n 'Use `--marker-only` for marker-only verification, `--schema-only` to skip marker checks and\\n' +\n 'inspect only the live schema, and `--strict` to fail if the database includes elements\\n' +\n 'not present in the contract.',\n );\n setCommandExamples(command, [\n 'prisma-next db verify --db $DATABASE_URL',\n 'prisma-next db verify --db $DATABASE_URL --strict',\n 'prisma-next db verify --db $DATABASE_URL --schema-only',\n 'prisma-next db verify --db $DATABASE_URL --schema-only --strict',\n 'prisma-next db verify --db $DATABASE_URL --marker-only',\n 'prisma-next db verify --db $DATABASE_URL --json',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--marker-only', 'Skip schema verification and only check the database marker')\n .option(\n '--schema-only',\n 'Skip marker verification and only check whether the live schema satisfies the contract',\n )\n .option(\n '--strict',\n 'Strict mode: schema elements not present in the contract are considered an error',\n false,\n )\n .action(async (options: DbVerifyOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n const modeResult = resolveDbVerifyMode(options);\n if (!modeResult.ok) {\n const exitCode = handleResult(modeResult as Result<never, CliStructuredError>, flags, ui);\n process.exit(exitCode);\n }\n\n const mode = modeResult.value;\n\n if (mode === 'schema-only') {\n const result = await executeDbSchemaOnlyVerifyCommand(options, flags, ui);\n const exitCode = handleResult(result, flags, ui, (schemaVerifyResult) => {\n if (flags.json) {\n ui.output(formatSchemaVerifyJson(schemaVerifyResult));\n } else {\n const output = formatSchemaVerifyOutput(schemaVerifyResult, flags);\n if (output) {\n ui.log(output);\n }\n }\n });\n\n if (result.ok && !result.value.ok) {\n process.exit(1);\n }\n\n process.exit(exitCode);\n }\n\n const result = await executeDbVerifyCommand(options, flags, ui, mode);\n\n if (result.ok) {\n if (flags.json) {\n ui.output(formatVerifyJson(result.value));\n } else {\n const output = formatVerifyOutput(result.value, flags);\n if (output) {\n ui.log(output);\n }\n }\n process.exit(0);\n }\n\n if (CliStructuredError.is(result.failure)) {\n const exitCode = handleResult(result as Result<never, CliStructuredError>, flags, ui);\n process.exit(exitCode);\n }\n\n if (flags.json) {\n ui.output(formatSchemaVerifyJson(result.failure));\n } else {\n // Always show schema-drift failures, even in quiet mode — exiting 1 without\n // diagnostics is unhelpful.\n const output = formatSchemaVerifyOutput(result.failure, { ...flags, quiet: false });\n if (output) {\n ui.log(output);\n }\n }\n process.exit(1);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as ExecuteDbVerifyOptions, C as IntrospectOptions, D as SchemaVerifyOptions, M as executeDbVerify, O as SignOptions, S as EmitSuccess, T as OnControlProgress, _ as EmitContractConfig, a as ControlClientOptions, b as EmitOptions, c as DbInitFailureCode, d as DbInitSuccess, f as DbUpdateFailure, g as DbUpdateSuccess, h as DbUpdateResult, i as ControlClient, j as ExecuteDbVerifyResult, k as VerifyOptions, l as DbInitOptions, m as DbUpdateOptions, n as ContractEmitResult, o as ControlProgressEvent, p as DbUpdateFailureCode, r as ControlActionName, s as DbInitFailure, t as ContractEmitOptions, u as DbInitResult, v as EmitFailure, x as EmitResult, y as EmitFailureCode } from "../types-
|
|
1
|
+
import { A as ExecuteDbVerifyOptions, C as IntrospectOptions, D as SchemaVerifyOptions, M as executeDbVerify, O as SignOptions, S as EmitSuccess, T as OnControlProgress, _ as EmitContractConfig, a as ControlClientOptions, b as EmitOptions, c as DbInitFailureCode, d as DbInitSuccess, f as DbUpdateFailure, g as DbUpdateSuccess, h as DbUpdateResult, i as ControlClient, j as ExecuteDbVerifyResult, k as VerifyOptions, l as DbInitOptions, m as DbUpdateOptions, n as ContractEmitResult, o as ControlProgressEvent, p as DbUpdateFailureCode, r as ControlActionName, s as DbInitFailure, t as ContractEmitOptions, u as DbInitResult, v as EmitFailure, x as EmitResult, y as EmitFailureCode } from "../types-CeC5ec2Y.mjs";
|
|
2
2
|
import { ControlDriverInstance, ControlExtensionDescriptor, ControlFamilyInstance, ControlStack, SignDatabaseResult, TargetMigrationsCapability, VerifyDatabaseResult, VerifyDatabaseSchemaResult } from "@prisma-next/framework-components/control";
|
|
3
3
|
import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
|
|
4
4
|
import { Contract } from "@prisma-next/contract/types";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-api.d.mts","names":[],"sources":["../../src/control-api/client.ts","../../src/control-api/contract-enrichment.ts","../../src/control-api/operations/contract-emit.ts","../../src/control-api/operations/db-init.ts","../../src/control-api/operations/db-update.ts","../../src/utils/emit-queue.ts"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"control-api.d.mts","names":[],"sources":["../../src/control-api/client.ts","../../src/control-api/contract-enrichment.ts","../../src/control-api/operations/contract-emit.ts","../../src/control-api/operations/db-init.ts","../../src/control-api/operations/db-update.ts","../../src/utils/emit-queue.ts"],"mappings":";;;;;;;;;;;AAmEA;;;;;iBAAgB,mBAAA,CAAoB,OAAA,EAAS,oBAAA,GAAuB,aAAa;;;;;;iBCNjE,cAAA,CACd,EAAA,EAAI,QAAA,EACJ,UAAA,EAAY,aAAA,CAAc,8BAAA,oBACzB,QAAA;;;;;;;;ADGH;;;;;;;;AAAiF;;;;ACNjF;;;iBC2FsB,mBAAA,CACpB,OAAA,EAAS,mBAAA,GACR,OAAA,CAAQ,kBAAA;;;;;AFvFX;;;;;;;;AAAiF;;;;ACNjF;;;UEhCiB,oBAAA;EAAA,SACN,MAAA,EAAQ,qBAAA,CAAsB,SAAA,EAAW,SAAA;EAAA,SACzC,cAAA,EAAgB,qBAAA,CAAsB,SAAA;EAAA,SACtC,QAAA,EAAU,QAAA;EAAA,SACV,IAAA;EAAA,SACA,UAAA,EAAY,0BAAA,CACnB,SAAA,EACA,SAAA,EACA,qBAAA,CAAsB,SAAA;EAAA,SAEf,mBAAA,EAAqB,aAAA,CAAc,8BAAA,CAA+B,SAAA,EAAW,SAAA;EFuBtF;;;;EAAA,SElBS,aAAA;EFoBA;AAAA;;;EAAA,SEfA,QAAA,EAAU,SAAA;EDuGC;;;;;EAAA,SCjGX,cAAA,GAAiB,aAAA,CAAc,0BAAA,CAA2B,SAAA,EAAW,SAAA;EDmGtE;EAAA,SCjGC,UAAA,GAAa,iBAAA;AAAA;;;;;ADiGK;;;iBCvFP,aAAA,oDAAA,CACpB,OAAA,EAAS,oBAAA,CAAqB,SAAA,EAAW,SAAA,IACxC,OAAA,CAAQ,YAAA;;;;;AHFX;;;;;;;UIzCiB,sBAAA;EAAA,SACN,MAAA,EAAQ,qBAAA,CAAsB,SAAA,EAAW,SAAA;EAAA,SACzC,cAAA,EAAgB,qBAAA,CAAsB,SAAA;EAAA,SACtC,QAAA,EAAU,QAAA;EAAA,SACV,IAAA;EAAA,SACA,UAAA,EAAY,0BAAA,CACnB,SAAA,EACA,SAAA,EACA,qBAAA,CAAsB,SAAA;EAAA,SAEf,mBAAA,EAAqB,aAAA,CAAc,8BAAA,CAA+B,SAAA,EAAW,SAAA;EAAA,SAC7E,cAAA;EAAA,SACA,aAAA;EAAA,SACA,QAAA,EAAU,SAAA;EAAA,SACV,cAAA,GAAiB,aAAA,CAAc,0BAAA,CAA2B,SAAA,EAAW,SAAA;EAAA,SACrE,UAAA,GAAa,iBAAA;AAAA;;;;;;;;;AHuBb;iBGXW,eAAA,oDAAA,CACpB,OAAA,EAAS,sBAAA,CAAuB,SAAA,EAAW,SAAA,IAC1C,OAAA,CAAQ,cAAA;;;iBChCK,gBAAA,CAAiB,cAAsB"}
|