@prisma-next/cli 0.12.0 → 0.13.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/cli.mjs +180 -163
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-KgJorIvG.mjs → client-CJzuo5wX.mjs} +222 -107
- package/dist/client-CJzuo5wX.mjs.map +1 -0
- package/dist/{command-helpers-Bbw1GbwL.mjs → command-helpers-DGMvGBeX.mjs} +318 -25
- package/dist/command-helpers-DGMvGBeX.mjs.map +1 -0
- package/dist/commands/contract-emit.d.mts.map +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.d.mts.map +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +4 -5
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.d.mts.map +1 -1
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +6 -6
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +10 -7
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.d.mts.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +37 -3
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +298 -12
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +55 -13
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +3 -2
- package/dist/commands/migration-graph.d.mts +17 -8
- package/dist/commands/migration-graph.d.mts.map +1 -1
- package/dist/commands/migration-graph.mjs +185 -2
- package/dist/commands/migration-graph.mjs.map +1 -0
- package/dist/commands/migration-list.d.mts +26 -27
- package/dist/commands/migration-list.d.mts.map +1 -1
- package/dist/commands/migration-list.mjs +2 -190
- package/dist/commands/migration-log.d.mts +9 -19
- package/dist/commands/migration-log.d.mts.map +1 -1
- package/dist/commands/migration-log.mjs +1 -137
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +6 -5
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +1 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +17 -21
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +24 -36
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +42 -144
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +3 -759
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +4 -4
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/commands/telemetry/index.d.mts +7 -0
- package/dist/commands/telemetry/index.d.mts.map +1 -0
- package/dist/commands/telemetry/index.mjs +2 -0
- package/dist/{config-loader-B6sJjXTv.mjs → config-loader-p9JMrekQ.mjs} +1 -1
- package/dist/{config-loader-B6sJjXTv.mjs.map → config-loader-p9JMrekQ.mjs.map} +1 -1
- package/dist/config-loader.mjs +1 -1
- package/dist/{contract-at-errors-BxP-TOMl.mjs → contract-at-errors-CFXsstzm.mjs} +2 -2
- package/dist/{contract-at-errors-BxP-TOMl.mjs.map → contract-at-errors-CFXsstzm.mjs.map} +1 -1
- package/dist/{contract-emit-DxcGl4Uq.mjs → contract-emit-B_qriF8B.mjs} +5 -5
- package/dist/{contract-emit-DxcGl4Uq.mjs.map → contract-emit-B_qriF8B.mjs.map} +1 -1
- package/dist/{contract-emit-D-4jrNve.mjs → contract-emit-C8HmtboH.mjs} +12 -7
- package/dist/contract-emit-C8HmtboH.mjs.map +1 -0
- package/dist/{contract-enrichment-a0V5Y_mL.mjs → contract-enrichment-gn9sWbPw.mjs} +1 -1
- package/dist/{contract-enrichment-a0V5Y_mL.mjs.map → contract-enrichment-gn9sWbPw.mjs.map} +1 -1
- package/dist/{contract-infer-D8uEbJuu.mjs → contract-infer-BYT_ra_U.mjs} +5 -5
- package/dist/contract-infer-BYT_ra_U.mjs.map +1 -0
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs → contract-space-aggregate-loader-ClI1KN6d.mjs} +5 -5
- package/dist/{contract-space-aggregate-loader-DvZwdkrr.mjs.map → contract-space-aggregate-loader-ClI1KN6d.mjs.map} +1 -1
- package/dist/{db-verify-v_vUKXTU.mjs → db-verify-C24FKhb7.mjs} +6 -6
- package/dist/{db-verify-v_vUKXTU.mjs.map → db-verify-C24FKhb7.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +5 -3
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/index.mjs.map +1 -1
- package/dist/exports/init-output.d.mts +1 -3
- package/dist/exports/init-output.d.mts.map +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{extension-pack-inputs-IDvjRCi3.mjs → extension-pack-inputs-1ySHqxKG.mjs} +1 -1
- package/dist/{extension-pack-inputs-IDvjRCi3.mjs.map → extension-pack-inputs-1ySHqxKG.mjs.map} +1 -1
- package/dist/{framework-components-fYXjz_in.mjs → framework-components-YVQHhPH7.mjs} +2 -2
- package/dist/{framework-components-fYXjz_in.mjs.map → framework-components-YVQHhPH7.mjs.map} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts → global-flags-BpoOYtNZ.d.mts} +1 -1
- package/dist/{global-flags-DEHjV8_s.d.mts.map → global-flags-BpoOYtNZ.d.mts.map} +1 -1
- package/dist/{init-Cv9UzWL5.mjs → init-0HwB-Vh8.mjs} +5 -58
- package/dist/init-0HwB-Vh8.mjs.map +1 -0
- package/dist/{inspect-live-schema-C6ohV_oQ.mjs → inspect-live-schema-DF6IwcDl.mjs} +7 -5
- package/dist/inspect-live-schema-DF6IwcDl.mjs.map +1 -0
- package/dist/migration-check-soB5uZEQ.mjs +573 -0
- package/dist/migration-check-soB5uZEQ.mjs.map +1 -0
- package/dist/migration-cli.mjs +1 -1
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-CjvwO6at.mjs → migration-command-scaffold-DA-Lhx6o.mjs} +5 -5
- package/dist/{migration-command-scaffold-CjvwO6at.mjs.map → migration-command-scaffold-DA-Lhx6o.mjs.map} +1 -1
- package/dist/migration-graph-command-render-CEez7YUK.mjs +1960 -0
- package/dist/migration-graph-command-render-CEez7YUK.mjs.map +1 -0
- package/dist/migration-list-DlJJ_38Z.mjs +230 -0
- package/dist/migration-list-DlJJ_38Z.mjs.map +1 -0
- package/dist/migration-log-CG0qQAFm.mjs +222 -0
- package/dist/migration-log-CG0qQAFm.mjs.map +1 -0
- package/dist/migration-path-target-Ce6OZImp.mjs +38 -0
- package/dist/migration-path-target-Ce6OZImp.mjs.map +1 -0
- package/dist/{migration-plan-9DJ7q7_z.mjs → migration-plan-z5Ing-TD.mjs} +9 -8
- package/dist/migration-plan-z5Ing-TD.mjs.map +1 -0
- package/dist/migration-status-CgWSoI_g.mjs +446 -0
- package/dist/migration-status-CgWSoI_g.mjs.map +1 -0
- package/dist/{output-B60Gw5fu.mjs → output-mEQ74_nd.mjs} +1 -1
- package/dist/{output-B60Gw5fu.mjs.map → output-mEQ74_nd.mjs.map} +1 -1
- package/dist/{progress-adapter-C644QK8l.mjs → progress-adapter-CjAeTxY_.mjs} +1 -1
- package/dist/{progress-adapter-C644QK8l.mjs.map → progress-adapter-CjAeTxY_.mjs.map} +1 -1
- package/dist/{ref-advancement-DUZqsue6.mjs → ref-advancement-BkXlikCA.mjs} +1 -1
- package/dist/{ref-advancement-DUZqsue6.mjs.map → ref-advancement-BkXlikCA.mjs.map} +1 -1
- package/dist/schemas-CeGMYFYX.d.mts +191 -0
- package/dist/schemas-CeGMYFYX.d.mts.map +1 -0
- package/dist/schemas-KhXMzNA_.mjs +112 -0
- package/dist/schemas-KhXMzNA_.mjs.map +1 -0
- package/dist/telemetry-BIM4beEO.mjs +122 -0
- package/dist/telemetry-BIM4beEO.mjs.map +1 -0
- package/dist/{terminal-ui-5Y6mrg93.d.mts → terminal-ui-DGRNFWna.d.mts} +1 -1
- package/dist/terminal-ui-DGRNFWna.d.mts.map +1 -0
- package/dist/{types-Dt_SfqFm.d.mts → types-C_tYiJYx.d.mts} +53 -31
- package/dist/types-C_tYiJYx.d.mts.map +1 -0
- package/dist/{verify-DCA9Sldu.mjs → verify-DcOYZ1tH.mjs} +2 -2
- package/dist/{verify-DCA9Sldu.mjs.map → verify-DcOYZ1tH.mjs.map} +1 -1
- package/package.json +26 -22
- package/src/cli.ts +5 -0
- package/src/commands/contract-infer.ts +2 -2
- package/src/commands/db-update.ts +7 -1
- package/src/commands/init/index.ts +6 -35
- package/src/commands/init/init.ts +1 -14
- package/src/commands/init/inputs.ts +0 -75
- package/src/commands/inspect-live-schema.ts +10 -0
- package/src/commands/json/schemas.ts +195 -0
- package/src/commands/migrate.ts +527 -8
- package/src/commands/migration-check.ts +469 -134
- package/src/commands/migration-graph.ts +164 -91
- package/src/commands/migration-list.ts +72 -39
- package/src/commands/migration-log.ts +52 -102
- package/src/commands/migration-new.ts +2 -1
- package/src/commands/migration-plan.ts +2 -1
- package/src/commands/migration-show.ts +31 -66
- package/src/commands/migration-status-overlay.ts +61 -0
- package/src/commands/migration-status.ts +458 -1066
- package/src/commands/telemetry/index.ts +107 -0
- package/src/commands/telemetry/status.ts +67 -0
- package/src/control-api/client.ts +70 -9
- package/src/control-api/operations/contract-emit.ts +22 -2
- package/src/control-api/operations/db-init.ts +6 -3
- package/src/control-api/operations/{db-apply.ts → db-run.ts} +55 -14
- package/src/control-api/operations/db-update.ts +7 -4
- package/src/control-api/operations/db-verify.ts +15 -5
- package/src/control-api/operations/{migration-apply.ts → migrate.ts} +181 -80
- package/src/control-api/operations/{apply.ts → run-migration.ts} +33 -27
- package/src/control-api/types.ts +56 -29
- package/src/utils/cli-errors.ts +70 -2
- package/src/utils/formatters/errors.ts +11 -0
- package/src/utils/formatters/migration-graph-command-render.ts +239 -0
- package/src/utils/formatters/migration-graph-grid-layout.ts +1134 -0
- package/src/utils/formatters/migration-graph-labels.ts +408 -0
- package/src/utils/formatters/migration-graph-model.ts +103 -0
- package/src/utils/formatters/migration-graph-occlusion-render.ts +258 -0
- package/src/utils/formatters/migration-graph-rows.ts +128 -15
- package/src/utils/formatters/migration-graph-space-render.ts +188 -0
- package/src/utils/formatters/migration-list-data-column.ts +4 -91
- package/src/utils/formatters/migration-list-graph-topology.ts +72 -94
- package/src/utils/formatters/migration-list-render.ts +135 -71
- package/src/utils/formatters/migration-list-styler.ts +46 -5
- package/src/utils/formatters/migration-list-types.ts +5 -21
- package/src/utils/formatters/migration-log-table.ts +205 -0
- package/src/utils/formatters/migrations.ts +33 -11
- package/src/utils/global-flags.ts +35 -0
- package/src/utils/integrity-violation-to-check-failure.ts +28 -19
- package/src/utils/legend.ts +38 -0
- package/src/utils/migration-path-target.ts +60 -0
- package/src/utils/telemetry.ts +68 -32
- package/dist/client-KgJorIvG.mjs.map +0 -1
- package/dist/command-helpers-Bbw1GbwL.mjs.map +0 -1
- package/dist/commands/migration-list.mjs.map +0 -1
- package/dist/commands/migration-log.mjs.map +0 -1
- package/dist/commands/migration-status.mjs.map +0 -1
- package/dist/contract-emit-D-4jrNve.mjs.map +0 -1
- package/dist/contract-infer-D8uEbJuu.mjs.map +0 -1
- package/dist/graph-render-rFAqZujX.mjs +0 -1081
- package/dist/graph-render-rFAqZujX.mjs.map +0 -1
- package/dist/init-Cv9UzWL5.mjs.map +0 -1
- package/dist/inspect-live-schema-C6ohV_oQ.mjs.map +0 -1
- package/dist/migration-check-BiBJoYYW.mjs +0 -341
- package/dist/migration-check-BiBJoYYW.mjs.map +0 -1
- package/dist/migration-graph-D7DVUElV.mjs +0 -1232
- package/dist/migration-graph-D7DVUElV.mjs.map +0 -1
- package/dist/migration-list-styler-BRwF4-gy.mjs +0 -399
- package/dist/migration-list-styler-BRwF4-gy.mjs.map +0 -1
- package/dist/migration-plan-9DJ7q7_z.mjs.map +0 -1
- package/dist/migration-types-D2FW63pr.d.mts +0 -15
- package/dist/migration-types-D2FW63pr.d.mts.map +0 -1
- package/dist/migrations-Cv2jxNNK.mjs +0 -228
- package/dist/migrations-Cv2jxNNK.mjs.map +0 -1
- package/dist/terminal-ui-5Y6mrg93.d.mts.map +0 -1
- package/dist/types-Dt_SfqFm.d.mts.map +0 -1
- package/src/utils/formatters/graph-migration-mapper.ts +0 -235
- package/src/utils/formatters/graph-render.ts +0 -1323
- package/src/utils/formatters/graph-types.ts +0 -120
- package/src/utils/formatters/migration-graph-layout.ts +0 -1119
- package/src/utils/formatters/migration-graph-tree-render.ts +0 -459
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-sign.mjs","names":[],"sources":["../../src/commands/db-sign.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type {\n SignDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join, 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 errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n maskConnectionUrl,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport {\n formatSchemaVerifyJson,\n formatSchemaVerifyOutput,\n formatSignJson,\n formatSignOutput,\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 DbSignOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly contract?: string;\n}\n\n/**\n * Failure type for db sign command.\n * Either an infrastructure error (CliStructuredError) or a logical failure (schema verification failed).\n */\ntype DbSignFailure = CliStructuredError | VerifyDatabaseSchemaResult;\n\n/**\n * Executes the db sign command and returns a structured Result.\n * Success: SignDatabaseResult (sign happened)\n * Failure: CliStructuredError (infra error) or VerifyDatabaseSchemaResult (schema mismatch)\n */\nasync function executeDbSignCommand(\n contractArg: string | undefined,\n options: DbSignOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<SignDatabaseResult, DbSignFailure>> {\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\n const effectiveContractArg = contractArg ?? options.contract;\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: effectiveContractArg ?? contractPath },\n ];\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n }\n const header = formatStyledHeader({\n command: 'db sign',\n description: 'Sign the database with your contract so you can safely run queries',\n url: 'https://pris.ly/db-sign',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n let contractJson: Record<string, unknown>;\n\n if (effectiveContractArg) {\n try {\n const { migrationsDir } = resolveMigrationPaths(options.config, config);\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n const graph = loaded.value.aggregate.app.graph();\n const bundles = loaded.value.aggregate.app.packages;\n const refs = loaded.value.aggregate.app.refs;\n const refResult = parseContractRef(effectiveContractArg, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n const targetHash = refResult.value.hash;\n const matchingBundle = bundles.find((p) => p.metadata.to === targetHash);\n if (matchingBundle) {\n const endContractPath = join(matchingBundle.dirPath, 'end-contract.json');\n const raw = await readFile(endContractPath, 'utf-8');\n contractJson = JSON.parse(raw) as Record<string, unknown>;\n } else {\n const defaultRaw = await readFile(contractPathAbsolute, 'utf-8');\n const defaultContract = JSON.parse(defaultRaw) as Record<string, unknown>;\n const storageHash = (defaultContract['storage'] as Record<string, unknown> | undefined)?.[\n 'storageHash'\n ];\n if (storageHash === targetHash) {\n contractJson = defaultContract;\n } else {\n return notOk(\n errorRuntime(`No contract file found for hash \"${targetHash}\"`, {\n why: `Resolved contract reference \"${effectiveContractArg}\" to hash \"${targetHash}\" but no migration produces that hash and the emitted contract does not match.`,\n fix: 'Ensure the target contract exists on disk — either as a migration endpoint or as the emitted contract.json.',\n }),\n );\n }\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to resolve contract reference: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n } else {\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 try {\n contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;\n } catch (error) {\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\n // Resolve database connection (--db flag or config.db.connection)\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for db sign (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'db sign',\n }),\n );\n }\n\n // Check for driver\n if (!config.driver) {\n return notOk(errorDriverRequired({ why: 'Config.driver is required for db sign' }));\n }\n\n // Create control client\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n // Step 1: Schema verification - connect here\n const schemaVerifyResult = await client.schemaVerify({\n contract: contractJson,\n strict: false,\n connection: dbConnection,\n onProgress,\n });\n\n // If schema verification failed, return as failure\n if (!schemaVerifyResult.ok) {\n return notOk(schemaVerifyResult);\n }\n\n // Step 2: Sign (already connected from schemaVerify)\n const signResult = await client.sign({\n contract: contractJson,\n contractPath,\n configPath,\n onProgress,\n });\n\n return ok(signResult);\n } catch (error) {\n // Driver already throws CliStructuredError for connection failures\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n\n if (error instanceof ContractValidationError) {\n return notOk(\n errorContractValidationFailed(`Contract validation failed: ${error.message}`, {\n where: { path: contractPathAbsolute },\n }),\n );\n }\n\n // Wrap unexpected errors\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Unexpected error during db sign: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createDbSignCommand(): Command {\n const command = new Command('sign');\n setCommandDescriptions(\n command,\n 'Sign the database with your contract so you can safely run queries',\n 'Verifies that your database schema satisfies the emitted contract, and if so, writes or\\n' +\n 'updates the database signature. This command is idempotent and safe to run\\n' +\n 'in CI/deployment pipelines. The signature records that this database instance is aligned\\n' +\n 'with a specific contract version.',\n );\n setCommandExamples(command, [\n 'prisma-next db sign --db $DATABASE_URL',\n 'prisma-next db sign production --db $DATABASE_URL',\n 'prisma-next db sign --contract production --db $DATABASE_URL',\n ]);\n addGlobalOptions(command)\n .argument('[contract]', 'Contract reference (hash, prefix, ref name, or migration dir name)')\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option(\n '--contract <contract>',\n 'Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .action(async (positionalContract: string | undefined, options: DbSignOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n\n if (positionalContract && options.contract) {\n process.stderr.write(\n 'Cannot specify both a positional contract argument and --contract flag.\\n',\n );\n process.exit(2);\n return;\n }\n\n const ui = createTerminalUI(flags);\n\n const result = await executeDbSignCommand(positionalContract, options, flags, ui);\n\n if (result.ok) {\n // Success - format sign output\n if (flags.json) {\n ui.output(formatSignJson(result.value));\n } else {\n const output = formatSignOutput(result.value, flags);\n if (output) {\n ui.log(output);\n }\n }\n process.exit(0);\n }\n\n // Failure - determine type and handle appropriately\n const failure = result.failure;\n\n if (failure instanceof CliStructuredError) {\n // Infrastructure error - use standard handler\n const exitCode = handleResult(result as Result<never, CliStructuredError>, flags, ui);\n process.exit(exitCode);\n }\n\n // Schema verification failed - format and print schema verification output\n if (flags.json) {\n ui.output(formatSchemaVerifyJson(failure));\n } else {\n const output = formatSchemaVerifyOutput(failure, flags);\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-sign.mjs","names":[],"sources":["../../src/commands/db-sign.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type {\n SignDatabaseResult,\n VerifyDatabaseSchemaResult,\n} from '@prisma-next/framework-components/control';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join, 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 errorRuntime,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n maskConnectionUrl,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport {\n formatSchemaVerifyJson,\n formatSchemaVerifyOutput,\n formatSignJson,\n formatSignOutput,\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 DbSignOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly contract?: string;\n}\n\n/**\n * Failure type for db sign command.\n * Either an infrastructure error (CliStructuredError) or a logical failure (schema verification failed).\n */\ntype DbSignFailure = CliStructuredError | VerifyDatabaseSchemaResult;\n\n/**\n * Executes the db sign command and returns a structured Result.\n * Success: SignDatabaseResult (sign happened)\n * Failure: CliStructuredError (infra error) or VerifyDatabaseSchemaResult (schema mismatch)\n */\nasync function executeDbSignCommand(\n contractArg: string | undefined,\n options: DbSignOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<SignDatabaseResult, DbSignFailure>> {\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\n const effectiveContractArg = contractArg ?? options.contract;\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: effectiveContractArg ?? contractPath },\n ];\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n }\n const header = formatStyledHeader({\n command: 'db sign',\n description: 'Sign the database with your contract so you can safely run queries',\n url: 'https://pris.ly/db-sign',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n let contractJson: Record<string, unknown>;\n\n if (effectiveContractArg) {\n try {\n const { migrationsDir } = resolveMigrationPaths(options.config, config);\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n const graph = loaded.value.aggregate.app.graph();\n const bundles = loaded.value.aggregate.app.packages;\n const refs = loaded.value.aggregate.app.refs;\n const refResult = parseContractRef(effectiveContractArg, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n const targetHash = refResult.value.hash;\n const matchingBundle = bundles.find((p) => p.metadata.to === targetHash);\n if (matchingBundle) {\n const endContractPath = join(matchingBundle.dirPath, 'end-contract.json');\n const raw = await readFile(endContractPath, 'utf-8');\n contractJson = JSON.parse(raw) as Record<string, unknown>;\n } else {\n const defaultRaw = await readFile(contractPathAbsolute, 'utf-8');\n const defaultContract = JSON.parse(defaultRaw) as Record<string, unknown>;\n const storageHash = (defaultContract['storage'] as Record<string, unknown> | undefined)?.[\n 'storageHash'\n ];\n if (storageHash === targetHash) {\n contractJson = defaultContract;\n } else {\n return notOk(\n errorRuntime(`No contract file found for hash \"${targetHash}\"`, {\n why: `Resolved contract reference \"${effectiveContractArg}\" to hash \"${targetHash}\" but no migration produces that hash and the emitted contract does not match.`,\n fix: 'Ensure the target contract exists on disk — either as a migration endpoint or as the emitted contract.json.',\n }),\n );\n }\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));\n if (error instanceof CliStructuredError) return notOk(error);\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to resolve contract reference: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n } else {\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 try {\n contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;\n } catch (error) {\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\n // Resolve database connection (--db flag or config.db.connection)\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for db sign (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'db sign',\n }),\n );\n }\n\n // Check for driver\n if (!config.driver) {\n return notOk(errorDriverRequired({ why: 'Config.driver is required for db sign' }));\n }\n\n // Create control client\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n // Step 1: Schema verification - connect here\n const schemaVerifyResult = await client.schemaVerify({\n contract: contractJson,\n strict: false,\n connection: dbConnection,\n onProgress,\n });\n\n // If schema verification failed, return as failure\n if (!schemaVerifyResult.ok) {\n return notOk(schemaVerifyResult);\n }\n\n // Step 2: Sign (already connected from schemaVerify)\n const signResult = await client.sign({\n contract: contractJson,\n contractPath,\n configPath,\n onProgress,\n });\n\n return ok(signResult);\n } catch (error) {\n // Driver already throws CliStructuredError for connection failures\n if (error instanceof CliStructuredError) {\n return notOk(error);\n }\n\n if (error instanceof ContractValidationError) {\n return notOk(\n errorContractValidationFailed(`Contract validation failed: ${error.message}`, {\n where: { path: contractPathAbsolute },\n }),\n );\n }\n\n // Wrap unexpected errors\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Unexpected error during db sign: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createDbSignCommand(): Command {\n const command = new Command('sign');\n setCommandDescriptions(\n command,\n 'Sign the database with your contract so you can safely run queries',\n 'Verifies that your database schema satisfies the emitted contract, and if so, writes or\\n' +\n 'updates the database signature. This command is idempotent and safe to run\\n' +\n 'in CI/deployment pipelines. The signature records that this database instance is aligned\\n' +\n 'with a specific contract version.',\n );\n setCommandExamples(command, [\n 'prisma-next db sign --db $DATABASE_URL',\n 'prisma-next db sign production --db $DATABASE_URL',\n 'prisma-next db sign --contract production --db $DATABASE_URL',\n ]);\n addGlobalOptions(command)\n .argument('[contract]', 'Contract reference (hash, prefix, ref name, or migration dir name)')\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option(\n '--contract <contract>',\n 'Contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .action(async (positionalContract: string | undefined, options: DbSignOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n\n if (positionalContract && options.contract) {\n process.stderr.write(\n 'Cannot specify both a positional contract argument and --contract flag.\\n',\n );\n process.exit(2);\n return;\n }\n\n const ui = createTerminalUI(flags);\n\n const result = await executeDbSignCommand(positionalContract, options, flags, ui);\n\n if (result.ok) {\n // Success - format sign output\n if (flags.json) {\n ui.output(formatSignJson(result.value));\n } else {\n const output = formatSignOutput(result.value, flags);\n if (output) {\n ui.log(output);\n }\n }\n process.exit(0);\n }\n\n // Failure - determine type and handle appropriately\n const failure = result.failure;\n\n if (failure instanceof CliStructuredError) {\n // Infrastructure error - use standard handler\n const exitCode = handleResult(result as Result<never, CliStructuredError>, flags, ui);\n process.exit(exitCode);\n }\n\n // Schema verification failed - format and print schema verification output\n if (flags.json) {\n ui.output(formatSchemaVerifyJson(failure));\n } else {\n const output = formatSchemaVerifyOutput(failure, flags);\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-update.d.mts","names":[],"sources":["../../src/commands/db-update.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"db-update.d.mts","names":[],"sources":["../../src/commands/db-update.ts"],"mappings":";;;iBAuRgB,qBAAA,IAAyB,OAAO"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { n as
|
|
6
|
-
import { i as readContractIR, n as computeRefAdvancementName, t as buildRefAdvancementFields } from "../ref-advancement-DUZqsue6.mjs";
|
|
1
|
+
import { B as errorContractValidationFailed, C as formatMigrationApplyOutput, F as CliStructuredError, H as errorDestructiveChanges, I as ERROR_CODE_DESTRUCTIVE_CHANGES, T as formatMigrationPlanOutput, X as errorMigrationPlanningFailed, _ as createTerminalUI, c as sanitizeErrorMessage, ct as errorUnexpected, g as parseGlobalFlagsOrExit, l as setCommandDescriptions, lt as mapMigrationToolsError, nt as errorRunnerFailed, s as resolveMigrationPaths, u as setCommandExamples, ut as mapRefResolutionError, w as formatMigrationJson, y as handleResult } from "../command-helpers-DGMvGBeX.mjs";
|
|
2
|
+
import { o as ContractValidationError } from "../client-CJzuo5wX.mjs";
|
|
3
|
+
import { n as buildReadAggregate } from "../contract-space-aggregate-loader-ClI1KN6d.mjs";
|
|
4
|
+
import { n as prepareMigrationContext, t as addMigrationCommandOptions } from "../migration-command-scaffold-DA-Lhx6o.mjs";
|
|
5
|
+
import { i as readContractIR, n as computeRefAdvancementName, t as buildRefAdvancementFields } from "../ref-advancement-BkXlikCA.mjs";
|
|
7
6
|
import { Command } from "commander";
|
|
8
7
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
9
8
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
@@ -22,7 +21,10 @@ function mapDbUpdateFailure(failure) {
|
|
|
22
21
|
return errorRunnerFailed(failure.summary, {
|
|
23
22
|
why: failure.why ?? "Migration runner failed",
|
|
24
23
|
fix,
|
|
25
|
-
|
|
24
|
+
meta: {
|
|
25
|
+
...failure.meta,
|
|
26
|
+
...failure.warnings && failure.warnings.length > 0 ? { plannerWarnings: failure.warnings } : {}
|
|
27
|
+
}
|
|
26
28
|
});
|
|
27
29
|
}
|
|
28
30
|
if (failure.code === "DESTRUCTIVE_CHANGES") return errorDestructiveChanges(failure.summary, {
|
|
@@ -130,6 +132,7 @@ async function executeDbUpdateCommand(options, flags, ui, startTime) {
|
|
|
130
132
|
...ifDefined("profileHash", result.value.marker.profileHash)
|
|
131
133
|
} : void 0),
|
|
132
134
|
...ifDefined("perSpace", result.value.perSpace),
|
|
135
|
+
...ifDefined("warnings", result.value.warnings),
|
|
133
136
|
advancedRef: refAdvancementFields.advancedRef,
|
|
134
137
|
plannedAdvanceRef: refAdvancementFields.plannedAdvanceRef,
|
|
135
138
|
summary: result.value.summary,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-update.mjs","names":[],"sources":["../../src/commands/db-update.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join } from 'pathe';\nimport { ContractValidationError } from '../control-api/errors';\nimport type { DbUpdateFailure } from '../control-api/types';\nimport {\n CliStructuredError,\n ERROR_CODE_DESTRUCTIVE_CHANGES,\n errorContractValidationFailed,\n errorDestructiveChanges,\n errorMigrationPlanningFailed,\n errorRunnerFailed,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport type { MigrationCommandOptions } from '../utils/command-helpers';\nimport {\n resolveMigrationPaths,\n sanitizeErrorMessage,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport {\n formatMigrationApplyOutput,\n formatMigrationJson,\n formatMigrationPlanOutput,\n type MigrationCommandResult,\n} from '../utils/formatters/migrations';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport {\n addMigrationCommandOptions,\n prepareMigrationContext,\n} from '../utils/migration-command-scaffold';\nimport {\n buildRefAdvancementFields,\n computeRefAdvancementName,\n type RefAdvancementFields,\n readContractIR,\n} from '../utils/ref-advancement';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface DbUpdateOptions extends MigrationCommandOptions {\n readonly to?: string;\n readonly advanceRef?: string;\n}\n\n/**\n * Maps a DbUpdateFailure to a CliStructuredError for consistent error handling.\n */\nfunction mapDbUpdateFailure(failure: DbUpdateFailure): CliStructuredError {\n if (failure.code === 'PLANNING_FAILED') {\n return errorMigrationPlanningFailed({ conflicts: failure.conflicts ?? [] });\n }\n\n if (failure.code === 'RUNNER_FAILED') {\n const runnerCode =\n typeof failure.meta?.['runnerErrorCode'] === 'string'\n ? failure.meta['runnerErrorCode']\n : undefined;\n const fix =\n runnerCode === 'LEGACY_MARKER_SHAPE'\n ? 'Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `prisma-next db init` to recreate it with the current per-space schema.'\n : 'Inspect the reported conflict, reconcile schema drift if needed, then re-run `prisma-next db update`';\n return errorRunnerFailed(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix,\n ...ifDefined('meta', failure.meta),\n });\n }\n\n if (failure.code === 'DESTRUCTIVE_CHANGES') {\n return errorDestructiveChanges(failure.summary, {\n ...ifDefined('why', failure.why),\n fix: 'Re-run with `-y` to apply destructive changes, or use `--dry-run` to preview first',\n ...ifDefined('meta', failure.meta),\n });\n }\n\n const exhaustive: never = failure.code;\n throw new Error(`Unhandled DbUpdateFailure code: ${exhaustive}`);\n}\n\n/**\n * Executes the db update command and returns a structured Result.\n */\nasync function executeDbUpdateCommand(\n options: DbUpdateOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrationCommandResult, CliStructuredError>> {\n // Prepare shared migration context (config, contract, connection, client)\n const ctxResult = await prepareMigrationContext(options, flags, ui, {\n commandName: 'db update',\n description: 'Update your database schema to match your contract',\n url: 'https://pris.ly/db-update',\n });\n if (!ctxResult.ok) {\n return ctxResult;\n }\n const { client, config, dbConnection, onProgress, contractPathAbsolute } = ctxResult.value;\n let { contractJson } = ctxResult.value;\n let contractJsonPathForSnapshot = contractPathAbsolute;\n const { migrationsDir, refsDir } = resolveMigrationPaths(options.config, config);\n\n if (options.to) {\n try {\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n const graph = loaded.value.aggregate.app.graph();\n const bundles = loaded.value.aggregate.app.packages;\n const refs = loaded.value.aggregate.app.refs;\n const refResult = parseContractRef(options.to, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n const targetHash = refResult.value.hash;\n const matchingBundle = bundles.find((p) => p.metadata.to === targetHash);\n if (!matchingBundle) {\n return notOk(\n errorUnexpected(\n `No migration bundle found for --to \"${options.to}\" (resolved hash: ${targetHash})`,\n {\n why: `The ref resolved successfully but no on-disk migration package has an end-contract hash matching ${targetHash}.`,\n fix: 'Provide a ref or hash that corresponds to an existing migration package, or run `migration list` to see available migrations.',\n },\n ),\n );\n }\n const endContractPath = join(matchingBundle.dirPath, 'end-contract.json');\n const raw = await readFile(endContractPath, 'utf-8');\n contractJson = JSON.parse(raw) as Record<string, unknown>;\n contractJsonPathForSnapshot = endContractPath;\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n throw error;\n }\n }\n\n try {\n await client.connect(dbConnection);\n\n const result = await client.dbUpdate({\n contract: contractJson,\n mode: options.dryRun ? 'plan' : 'apply',\n migrationsDir,\n ...(flags.yes ? { acceptDataLoss: true } : {}),\n onProgress,\n });\n\n // Handle failures by mapping to CLI structured error\n if (!result.ok) {\n return notOk(mapDbUpdateFailure(result.failure));\n }\n\n const advancementHash =\n result.value.mode === 'apply'\n ? (result.value.marker?.storageHash ?? result.value.destination.storageHash)\n : result.value.destination.storageHash;\n\n let refAdvancementFields: RefAdvancementFields = {\n advancedRef: null,\n plannedAdvanceRef: null,\n };\n if (\n computeRefAdvancementName({\n ...ifDefined('advanceRef', options.advanceRef),\n ...ifDefined('db', options.db),\n }) !== null\n ) {\n try {\n const contractIR = await readContractIR(contractJson, contractJsonPathForSnapshot);\n refAdvancementFields = await buildRefAdvancementFields({\n ...ifDefined('advanceRef', options.advanceRef),\n ...ifDefined('db', options.db),\n refsDir,\n contractIR,\n mode: result.value.mode,\n hash: advancementHash,\n });\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n }\n\n // Convert success result to CLI output format\n const dbUpdateResult: MigrationCommandResult = {\n ok: true,\n mode: result.value.mode,\n plan: {\n targetId: ctxResult.value.config.target.targetId,\n destination: {\n storageHash: result.value.destination.storageHash,\n ...ifDefined('profileHash', result.value.destination.profileHash),\n },\n operations: result.value.plan.operations.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n ...ifDefined('preview', result.value.plan.preview),\n },\n ...ifDefined(\n 'execution',\n result.value.execution\n ? {\n operationsPlanned: result.value.execution.operationsPlanned,\n operationsExecuted: result.value.execution.operationsExecuted,\n }\n : undefined,\n ),\n ...ifDefined(\n 'marker',\n result.value.marker\n ? {\n storageHash: result.value.marker.storageHash,\n ...ifDefined('profileHash', result.value.marker.profileHash),\n }\n : undefined,\n ),\n ...ifDefined('perSpace', result.value.perSpace),\n advancedRef: refAdvancementFields.advancedRef,\n plannedAdvanceRef: refAdvancementFields.plannedAdvanceRef,\n summary: result.value.summary,\n timings: { total: Date.now() - startTime },\n };\n\n return ok(dbUpdateResult);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n if (error instanceof ContractValidationError) {\n return notOk(\n errorContractValidationFailed(`Contract validation failed: ${error.message}`, {\n where: { path: contractPathAbsolute },\n }),\n );\n }\n\n const rawMessage = error instanceof Error ? error.message : String(error);\n const safeMessage = sanitizeErrorMessage(\n rawMessage,\n typeof dbConnection === 'string' ? dbConnection : undefined,\n );\n return notOk(\n errorUnexpected(safeMessage, {\n why: `Unexpected error during db update: ${safeMessage}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createDbUpdateCommand(): Command {\n const command = new Command('update');\n setCommandDescriptions(\n command,\n 'Update your database schema to match your contract',\n 'Compares your database schema to the emitted contract and applies the necessary\\n' +\n 'changes. Works on any database, whether or not it has been initialized with `db init`.\\n' +\n 'Destructive operations prompt for confirmation in interactive mode. Use -y to\\n' +\n 'auto-accept or --dry-run to preview first.',\n );\n setCommandExamples(command, [\n 'prisma-next db update --db $DATABASE_URL',\n 'prisma-next db update --db $DATABASE_URL --dry-run',\n ]);\n addMigrationCommandOptions(command);\n command.option(\n '--to <contract>',\n 'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n );\n command.option('--advance-ref <name>', 'Ref to advance to the post-command contract hash');\n command.action(async (options: DbUpdateOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const startTime = Date.now();\n\n const ui = createTerminalUI(flags);\n\n let result = await executeDbUpdateCommand(options, flags, ui, startTime);\n\n // Interactive confirmation for destructive operations:\n // When the control API rejects destructive changes, prompt the user instead of failing.\n // In non-interactive mode (CI, piped, --no-interactive, --json), the error is returned as-is.\n if (\n !result.ok &&\n result.failure.code === ERROR_CODE_DESTRUCTIVE_CHANGES &&\n flags.interactive &&\n !flags.json &&\n !flags.yes\n ) {\n const meta = result.failure.meta as\n | { destructiveOperations?: readonly { id: string; label: string }[] }\n | undefined;\n const destructiveOps = meta?.destructiveOperations ?? [];\n\n if (destructiveOps.length > 0) {\n ui.warn(\n `${destructiveOps.length} destructive operation(s) that may cause data loss:\\n${destructiveOps.map((op) => ` ${ui.yellow('▸')} ${op.label}`).join('\\n')}`,\n );\n }\n\n const confirmed = await ui.confirm('Apply destructive changes? This cannot be undone.');\n\n if (confirmed) {\n result = await executeDbUpdateCommand(options, { ...flags, yes: true }, ui, Date.now());\n }\n }\n\n const exitCode = handleResult(result, flags, ui, (dbUpdateResult) => {\n if (flags.json) {\n ui.output(formatMigrationJson(dbUpdateResult));\n } else {\n const output =\n dbUpdateResult.mode === 'plan'\n ? formatMigrationPlanOutput(dbUpdateResult, flags)\n : formatMigrationApplyOutput(dbUpdateResult, flags);\n if (output) {\n ui.log(output);\n }\n }\n });\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAwDA,SAAS,mBAAmB,SAA8C;CACxE,IAAI,QAAQ,SAAS,mBACnB,OAAO,6BAA6B,EAAE,WAAW,QAAQ,aAAa,CAAC,EAAE,CAAC;CAG5E,IAAI,QAAQ,SAAS,iBAAiB;EAKpC,MAAM,OAHJ,OAAO,QAAQ,OAAO,uBAAuB,WACzC,QAAQ,KAAK,qBACb,KAAA,OAEW,wBACX,iMACA;EACN,OAAO,kBAAkB,QAAQ,SAAS;GACxC,KAAK,QAAQ,OAAO;GACpB;GACA,GAAG,UAAU,QAAQ,QAAQ,IAAI;EACnC,CAAC;CACH;CAEA,IAAI,QAAQ,SAAS,uBACnB,OAAO,wBAAwB,QAAQ,SAAS;EAC9C,GAAG,UAAU,OAAO,QAAQ,GAAG;EAC/B,KAAK;EACL,GAAG,UAAU,QAAQ,QAAQ,IAAI;CACnC,CAAC;CAGH,MAAM,aAAoB,QAAQ;CAClC,MAAM,IAAI,MAAM,mCAAmC,YAAY;AACjE;;;;AAKA,eAAe,uBACb,SACA,OACA,IACA,WAC6D;CAE7D,MAAM,YAAY,MAAM,wBAAwB,SAAS,OAAO,IAAI;EAClE,aAAa;EACb,aAAa;EACb,KAAK;CACP,CAAC;CACD,IAAI,CAAC,UAAU,IACb,OAAO;CAET,MAAM,EAAE,QAAQ,QAAQ,cAAc,YAAY,yBAAyB,UAAU;CACrF,IAAI,EAAE,iBAAiB,UAAU;CACjC,IAAI,8BAA8B;CAClC,MAAM,EAAE,eAAe,YAAY,sBAAsB,QAAQ,QAAQ,MAAM;CAE/E,IAAI,QAAQ,IACV,IAAI;EACF,MAAM,SAAS,MAAM,mBAAmB,QAAQ,EAAE,cAAc,CAAC;EACjE,IAAI,CAAC,OAAO,IACV,OAAO,MAAM,OAAO,OAAO;EAE7B,MAAM,QAAQ,OAAO,MAAM,UAAU,IAAI,MAAM;EAC/C,MAAM,UAAU,OAAO,MAAM,UAAU,IAAI;EAC3C,MAAM,OAAO,OAAO,MAAM,UAAU,IAAI;EACxC,MAAM,YAAY,iBAAiB,QAAQ,IAAI;GAAE;GAAO;EAAK,CAAC;EAC9D,IAAI,CAAC,UAAU,IACb,OAAO,MAAM,sBAAsB,UAAU,OAAO,CAAC;EAEvD,MAAM,aAAa,UAAU,MAAM;EACnC,MAAM,iBAAiB,QAAQ,MAAM,MAAM,EAAE,SAAS,OAAO,UAAU;EACvE,IAAI,CAAC,gBACH,OAAO,MACL,gBACE,uCAAuC,QAAQ,GAAG,oBAAoB,WAAW,IACjF;GACE,KAAK,oGAAoG,WAAW;GACpH,KAAK;EACP,CACF,CACF;EAEF,MAAM,kBAAkB,KAAK,eAAe,SAAS,mBAAmB;EACxE,MAAM,MAAM,MAAM,SAAS,iBAAiB,OAAO;EACnD,eAAe,KAAK,MAAM,GAAG;EAC7B,8BAA8B;CAChC,SAAS,OAAO;EACd,IAAI,oBAAoB,GAAG,KAAK,GAC9B,OAAO,MAAM,uBAAuB,KAAK,CAAC;EAE5C,IAAI,mBAAmB,GAAG,KAAK,GAC7B,OAAO,MAAM,KAAK;EAEpB,MAAM;CACR;CAGF,IAAI;EACF,MAAM,OAAO,QAAQ,YAAY;EAEjC,MAAM,SAAS,MAAM,OAAO,SAAS;GACnC,UAAU;GACV,MAAM,QAAQ,SAAS,SAAS;GAChC;GACA,GAAI,MAAM,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;GAC5C;EACF,CAAC;EAGD,IAAI,CAAC,OAAO,IACV,OAAO,MAAM,mBAAmB,OAAO,OAAO,CAAC;EAGjD,MAAM,kBACJ,OAAO,MAAM,SAAS,UACjB,OAAO,MAAM,QAAQ,eAAe,OAAO,MAAM,YAAY,cAC9D,OAAO,MAAM,YAAY;EAE/B,IAAI,uBAA6C;GAC/C,aAAa;GACb,mBAAmB;EACrB;EACA,IACE,0BAA0B;GACxB,GAAG,UAAU,cAAc,QAAQ,UAAU;GAC7C,GAAG,UAAU,MAAM,QAAQ,EAAE;EAC/B,CAAC,MAAM,MAEP,IAAI;GACF,MAAM,aAAa,MAAM,eAAe,cAAc,2BAA2B;GACjF,uBAAuB,MAAM,0BAA0B;IACrD,GAAG,UAAU,cAAc,QAAQ,UAAU;IAC7C,GAAG,UAAU,MAAM,QAAQ,EAAE;IAC7B;IACA;IACA,MAAM,OAAO,MAAM;IACnB,MAAM;GACR,CAAC;EACH,SAAS,OAAO;GACd,IAAI,oBAAoB,GAAG,KAAK,GAC9B,OAAO,MAAM,uBAAuB,KAAK,CAAC;GAE5C,MAAM;EACR;EA6CF,OAAO,GAAG;GAxCR,IAAI;GACJ,MAAM,OAAO,MAAM;GACnB,MAAM;IACJ,UAAU,UAAU,MAAM,OAAO,OAAO;IACxC,aAAa;KACX,aAAa,OAAO,MAAM,YAAY;KACtC,GAAG,UAAU,eAAe,OAAO,MAAM,YAAY,WAAW;IAClE;IACA,YAAY,OAAO,MAAM,KAAK,WAAW,KAAK,QAAQ;KACpD,IAAI,GAAG;KACP,OAAO,GAAG;KACV,gBAAgB,GAAG;IACrB,EAAE;IACF,GAAG,UAAU,WAAW,OAAO,MAAM,KAAK,OAAO;GACnD;GACA,GAAG,UACD,aACA,OAAO,MAAM,YACT;IACE,mBAAmB,OAAO,MAAM,UAAU;IAC1C,oBAAoB,OAAO,MAAM,UAAU;GAC7C,IACA,KAAA,CACN;GACA,GAAG,UACD,UACA,OAAO,MAAM,SACT;IACE,aAAa,OAAO,MAAM,OAAO;IACjC,GAAG,UAAU,eAAe,OAAO,MAAM,OAAO,WAAW;GAC7D,IACA,KAAA,CACN;GACA,GAAG,UAAU,YAAY,OAAO,MAAM,QAAQ;GAC9C,aAAa,qBAAqB;GAClC,mBAAmB,qBAAqB;GACxC,SAAS,OAAO,MAAM;GACtB,SAAS,EAAE,OAAO,KAAK,IAAI,IAAI,UAAU;EAGpB,CAAC;CAC1B,SAAS,OAAO;EACd,IAAI,mBAAmB,GAAG,KAAK,GAC7B,OAAO,MAAM,KAAK;EAGpB,IAAI,iBAAiB,yBACnB,OAAO,MACL,8BAA8B,+BAA+B,MAAM,WAAW,EAC5E,OAAO,EAAE,MAAM,qBAAqB,EACtC,CAAC,CACH;EAIF,MAAM,cAAc,qBADD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAGtE,OAAO,iBAAiB,WAAW,eAAe,KAAA,CACpD;EACA,OAAO,MACL,gBAAgB,aAAa,EAC3B,KAAK,sCAAsC,cAC7C,CAAC,CACH;CACF,UAAU;EACR,MAAM,OAAO,MAAM;CACrB;AACF;AAEA,SAAgB,wBAAiC;CAC/C,MAAM,UAAU,IAAI,QAAQ,QAAQ;CACpC,uBACE,SACA,sDACA,oSAIF;CACA,mBAAmB,SAAS,CAC1B,4CACA,oDACF,CAAC;CACD,2BAA2B,OAAO;CAClC,QAAQ,OACN,mBACA,2FACF;CACA,QAAQ,OAAO,wBAAwB,kDAAkD;CACzF,QAAQ,OAAO,OAAO,YAA6B;EACjD,MAAM,QAAQ,uBAAuB,OAAO;EAC5C,MAAM,YAAY,KAAK,IAAI;EAE3B,MAAM,KAAK,iBAAiB,KAAK;EAEjC,IAAI,SAAS,MAAM,uBAAuB,SAAS,OAAO,IAAI,SAAS;EAKvE,IACE,CAAC,OAAO,MACR,OAAO,QAAQ,SAAS,kCACxB,MAAM,eACN,CAAC,MAAM,QACP,CAAC,MAAM,KACP;GAIA,MAAM,iBAHO,OAAO,QAAQ,MAGC,yBAAyB,CAAC;GAEvD,IAAI,eAAe,SAAS,GAC1B,GAAG,KACD,GAAG,eAAe,OAAO,uDAAuD,eAAe,KAAK,OAAO,KAAK,GAAG,OAAO,GAAG,EAAE,GAAG,GAAG,OAAO,EAAE,KAAK,IAAI,GACzJ;GAKF,IAAI,MAFoB,GAAG,QAAQ,mDAAmD,GAGpF,SAAS,MAAM,uBAAuB,SAAS;IAAE,GAAG;IAAO,KAAK;GAAK,GAAG,IAAI,KAAK,IAAI,CAAC;EAE1F;EAEA,MAAM,WAAW,aAAa,QAAQ,OAAO,KAAK,mBAAmB;GACnE,IAAI,MAAM,MACR,GAAG,OAAO,oBAAoB,cAAc,CAAC;QACxC;IACL,MAAM,SACJ,eAAe,SAAS,SACpB,0BAA0B,gBAAgB,KAAK,IAC/C,2BAA2B,gBAAgB,KAAK;IACtD,IAAI,QACF,GAAG,IAAI,MAAM;GAEjB;EACF,CAAC;EACD,QAAQ,KAAK,QAAQ;CACvB,CAAC;CAED,OAAO;AACT"}
|
|
1
|
+
{"version":3,"file":"db-update.mjs","names":[],"sources":["../../src/commands/db-update.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join } from 'pathe';\nimport { ContractValidationError } from '../control-api/errors';\nimport type { DbUpdateFailure } from '../control-api/types';\nimport {\n CliStructuredError,\n ERROR_CODE_DESTRUCTIVE_CHANGES,\n errorContractValidationFailed,\n errorDestructiveChanges,\n errorMigrationPlanningFailed,\n errorRunnerFailed,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport type { MigrationCommandOptions } from '../utils/command-helpers';\nimport {\n resolveMigrationPaths,\n sanitizeErrorMessage,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { buildReadAggregate } from '../utils/contract-space-aggregate-loader';\nimport {\n formatMigrationApplyOutput,\n formatMigrationJson,\n formatMigrationPlanOutput,\n type MigrationCommandResult,\n} from '../utils/formatters/migrations';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport {\n addMigrationCommandOptions,\n prepareMigrationContext,\n} from '../utils/migration-command-scaffold';\nimport {\n buildRefAdvancementFields,\n computeRefAdvancementName,\n type RefAdvancementFields,\n readContractIR,\n} from '../utils/ref-advancement';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface DbUpdateOptions extends MigrationCommandOptions {\n readonly to?: string;\n readonly advanceRef?: string;\n}\n\n/**\n * Maps a DbUpdateFailure to a CliStructuredError for consistent error handling.\n */\nfunction mapDbUpdateFailure(failure: DbUpdateFailure): CliStructuredError {\n if (failure.code === 'PLANNING_FAILED') {\n return errorMigrationPlanningFailed({ conflicts: failure.conflicts ?? [] });\n }\n\n if (failure.code === 'RUNNER_FAILED') {\n const runnerCode =\n typeof failure.meta?.['runnerErrorCode'] === 'string'\n ? failure.meta['runnerErrorCode']\n : undefined;\n const fix =\n runnerCode === 'LEGACY_MARKER_SHAPE'\n ? 'Legacy marker-table shape detected. Drop `prisma_contract.marker` (Postgres) or `_prisma_marker` (SQLite) and re-run `prisma-next db init` to recreate it with the current per-space schema.'\n : 'Inspect the reported conflict, reconcile schema drift if needed, then re-run `prisma-next db update`';\n return errorRunnerFailed(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix,\n meta: {\n ...failure.meta,\n ...(failure.warnings && failure.warnings.length > 0\n ? { plannerWarnings: failure.warnings }\n : {}),\n },\n });\n }\n\n if (failure.code === 'DESTRUCTIVE_CHANGES') {\n return errorDestructiveChanges(failure.summary, {\n ...ifDefined('why', failure.why),\n fix: 'Re-run with `-y` to apply destructive changes, or use `--dry-run` to preview first',\n ...ifDefined('meta', failure.meta),\n });\n }\n\n const exhaustive: never = failure.code;\n throw new Error(`Unhandled DbUpdateFailure code: ${exhaustive}`);\n}\n\n/**\n * Executes the db update command and returns a structured Result.\n */\nasync function executeDbUpdateCommand(\n options: DbUpdateOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrationCommandResult, CliStructuredError>> {\n // Prepare shared migration context (config, contract, connection, client)\n const ctxResult = await prepareMigrationContext(options, flags, ui, {\n commandName: 'db update',\n description: 'Update your database schema to match your contract',\n url: 'https://pris.ly/db-update',\n });\n if (!ctxResult.ok) {\n return ctxResult;\n }\n const { client, config, dbConnection, onProgress, contractPathAbsolute } = ctxResult.value;\n let { contractJson } = ctxResult.value;\n let contractJsonPathForSnapshot = contractPathAbsolute;\n const { migrationsDir, refsDir } = resolveMigrationPaths(options.config, config);\n\n if (options.to) {\n try {\n const loaded = await buildReadAggregate(config, { migrationsDir });\n if (!loaded.ok) {\n return notOk(loaded.failure);\n }\n const graph = loaded.value.aggregate.app.graph();\n const bundles = loaded.value.aggregate.app.packages;\n const refs = loaded.value.aggregate.app.refs;\n const refResult = parseContractRef(options.to, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n const targetHash = refResult.value.hash;\n const matchingBundle = bundles.find((p) => p.metadata.to === targetHash);\n if (!matchingBundle) {\n return notOk(\n errorUnexpected(\n `No migration bundle found for --to \"${options.to}\" (resolved hash: ${targetHash})`,\n {\n why: `The ref resolved successfully but no on-disk migration package has an end-contract hash matching ${targetHash}.`,\n fix: 'Provide a ref or hash that corresponds to an existing migration package, or run `migration list` to see available migrations.',\n },\n ),\n );\n }\n const endContractPath = join(matchingBundle.dirPath, 'end-contract.json');\n const raw = await readFile(endContractPath, 'utf-8');\n contractJson = JSON.parse(raw) as Record<string, unknown>;\n contractJsonPathForSnapshot = endContractPath;\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n throw error;\n }\n }\n\n try {\n await client.connect(dbConnection);\n\n const result = await client.dbUpdate({\n contract: contractJson,\n mode: options.dryRun ? 'plan' : 'apply',\n migrationsDir,\n ...(flags.yes ? { acceptDataLoss: true } : {}),\n onProgress,\n });\n\n // Handle failures by mapping to CLI structured error\n if (!result.ok) {\n return notOk(mapDbUpdateFailure(result.failure));\n }\n\n const advancementHash =\n result.value.mode === 'apply'\n ? (result.value.marker?.storageHash ?? result.value.destination.storageHash)\n : result.value.destination.storageHash;\n\n let refAdvancementFields: RefAdvancementFields = {\n advancedRef: null,\n plannedAdvanceRef: null,\n };\n if (\n computeRefAdvancementName({\n ...ifDefined('advanceRef', options.advanceRef),\n ...ifDefined('db', options.db),\n }) !== null\n ) {\n try {\n const contractIR = await readContractIR(contractJson, contractJsonPathForSnapshot);\n refAdvancementFields = await buildRefAdvancementFields({\n ...ifDefined('advanceRef', options.advanceRef),\n ...ifDefined('db', options.db),\n refsDir,\n contractIR,\n mode: result.value.mode,\n hash: advancementHash,\n });\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n }\n\n // Convert success result to CLI output format\n const dbUpdateResult: MigrationCommandResult = {\n ok: true,\n mode: result.value.mode,\n plan: {\n targetId: ctxResult.value.config.target.targetId,\n destination: {\n storageHash: result.value.destination.storageHash,\n ...ifDefined('profileHash', result.value.destination.profileHash),\n },\n operations: result.value.plan.operations.map((op) => ({\n id: op.id,\n label: op.label,\n operationClass: op.operationClass,\n })),\n ...ifDefined('preview', result.value.plan.preview),\n },\n ...ifDefined(\n 'execution',\n result.value.execution\n ? {\n operationsPlanned: result.value.execution.operationsPlanned,\n operationsExecuted: result.value.execution.operationsExecuted,\n }\n : undefined,\n ),\n ...ifDefined(\n 'marker',\n result.value.marker\n ? {\n storageHash: result.value.marker.storageHash,\n ...ifDefined('profileHash', result.value.marker.profileHash),\n }\n : undefined,\n ),\n ...ifDefined('perSpace', result.value.perSpace),\n ...ifDefined('warnings', result.value.warnings),\n advancedRef: refAdvancementFields.advancedRef,\n plannedAdvanceRef: refAdvancementFields.plannedAdvanceRef,\n summary: result.value.summary,\n timings: { total: Date.now() - startTime },\n };\n\n return ok(dbUpdateResult);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n if (error instanceof ContractValidationError) {\n return notOk(\n errorContractValidationFailed(`Contract validation failed: ${error.message}`, {\n where: { path: contractPathAbsolute },\n }),\n );\n }\n\n const rawMessage = error instanceof Error ? error.message : String(error);\n const safeMessage = sanitizeErrorMessage(\n rawMessage,\n typeof dbConnection === 'string' ? dbConnection : undefined,\n );\n return notOk(\n errorUnexpected(safeMessage, {\n why: `Unexpected error during db update: ${safeMessage}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createDbUpdateCommand(): Command {\n const command = new Command('update');\n setCommandDescriptions(\n command,\n 'Update your database schema to match your contract',\n 'Compares your database schema to the emitted contract and applies the necessary\\n' +\n 'changes. Works on any database, whether or not it has been initialized with `db init`.\\n' +\n 'Destructive operations prompt for confirmation in interactive mode. Use -y to\\n' +\n 'auto-accept or --dry-run to preview first.',\n );\n setCommandExamples(command, [\n 'prisma-next db update --db $DATABASE_URL',\n 'prisma-next db update --db $DATABASE_URL --dry-run',\n ]);\n addMigrationCommandOptions(command);\n command.option(\n '--to <contract>',\n 'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n );\n command.option('--advance-ref <name>', 'Ref to advance to the post-command contract hash');\n command.action(async (options: DbUpdateOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const startTime = Date.now();\n\n const ui = createTerminalUI(flags);\n\n let result = await executeDbUpdateCommand(options, flags, ui, startTime);\n\n // Interactive confirmation for destructive operations:\n // When the control API rejects destructive changes, prompt the user instead of failing.\n // In non-interactive mode (CI, piped, --no-interactive, --json), the error is returned as-is.\n if (\n !result.ok &&\n result.failure.code === ERROR_CODE_DESTRUCTIVE_CHANGES &&\n flags.interactive &&\n !flags.json &&\n !flags.yes\n ) {\n const meta = result.failure.meta as\n | { destructiveOperations?: readonly { id: string; label: string }[] }\n | undefined;\n const destructiveOps = meta?.destructiveOperations ?? [];\n\n if (destructiveOps.length > 0) {\n ui.warn(\n `${destructiveOps.length} destructive operation(s) that may cause data loss:\\n${destructiveOps.map((op) => ` ${ui.yellow('▸')} ${op.label}`).join('\\n')}`,\n );\n }\n\n const confirmed = await ui.confirm('Apply destructive changes? This cannot be undone.');\n\n if (confirmed) {\n result = await executeDbUpdateCommand(options, { ...flags, yes: true }, ui, Date.now());\n }\n }\n\n const exitCode = handleResult(result, flags, ui, (dbUpdateResult) => {\n if (flags.json) {\n ui.output(formatMigrationJson(dbUpdateResult));\n } else {\n const output =\n dbUpdateResult.mode === 'plan'\n ? formatMigrationPlanOutput(dbUpdateResult, flags)\n : formatMigrationApplyOutput(dbUpdateResult, flags);\n if (output) {\n ui.log(output);\n }\n }\n });\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-verify.d.mts","names":[],"sources":["../../src/commands/db-verify.ts"],"mappings":";;;iBAmfgB,qBAAA,
|
|
1
|
+
{"version":3,"file":"db-verify.d.mts","names":[],"sources":["../../src/commands/db-verify.ts"],"mappings":";;;iBAmfgB,qBAAA,IAAyB,OAAO"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as createDbVerifyCommand } from "../db-verify-
|
|
1
|
+
import { t as createDbVerifyCommand } from "../db-verify-C24FKhb7.mjs";
|
|
2
2
|
export { createDbVerifyCommand };
|
|
@@ -1,7 +1,41 @@
|
|
|
1
|
-
import { E as PerSpaceExecutionEntry, w as
|
|
1
|
+
import { E as PerSpaceExecutionEntry, w as MigratePathDecision } from "../types-C_tYiJYx.mjs";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
|
|
4
4
|
//#region src/commands/migrate.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* One migration that will run in a `migrate --show` preview, in execution order.
|
|
7
|
+
*/
|
|
8
|
+
interface MigrateShowMigration {
|
|
9
|
+
readonly spaceId: string;
|
|
10
|
+
readonly dirName: string;
|
|
11
|
+
readonly migrationHash: string;
|
|
12
|
+
readonly from: string;
|
|
13
|
+
readonly to: string;
|
|
14
|
+
}
|
|
15
|
+
/** Result returned by `migrate --show`. Read-only; no writes performed. */
|
|
16
|
+
interface MigrateShowResult {
|
|
17
|
+
readonly ok: true;
|
|
18
|
+
readonly migrations: readonly MigrateShowMigration[];
|
|
19
|
+
readonly summary: string;
|
|
20
|
+
/**
|
|
21
|
+
* Pre-rendered Tier-3 graph tree for human output. Off-path migrations render
|
|
22
|
+
* dim; on-path migrations render in ordinary colours. Only present in human
|
|
23
|
+
* (non-JSON) mode.
|
|
24
|
+
*/
|
|
25
|
+
readonly graphOutput?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Name column width for the "Will run, in order:" list — globally aligned with
|
|
28
|
+
* every graph-tree section. Only present in human (non-JSON) mode.
|
|
29
|
+
*/
|
|
30
|
+
readonly runListDirNameWidth?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Left-pad offset (number of blank spaces) matching the graph's data-column
|
|
33
|
+
* offset (`globalMaxEdgeTreePrefixWidth`). Used to align list rows with graph
|
|
34
|
+
* rows so every `→` in the output (graph + list) lands at the same column.
|
|
35
|
+
* Only present in human (non-JSON) mode when multiple spaces are rendered.
|
|
36
|
+
*/
|
|
37
|
+
readonly runListLeftPad?: number;
|
|
38
|
+
}
|
|
5
39
|
interface MigrateResult {
|
|
6
40
|
readonly ok: boolean;
|
|
7
41
|
readonly migrationsApplied: number;
|
|
@@ -17,7 +51,7 @@ interface MigrateResult {
|
|
|
17
51
|
}[];
|
|
18
52
|
readonly summary: string;
|
|
19
53
|
readonly perSpace: readonly PerSpaceExecutionEntry[];
|
|
20
|
-
readonly pathDecision?:
|
|
54
|
+
readonly pathDecision?: MigratePathDecision;
|
|
21
55
|
readonly timings: {
|
|
22
56
|
readonly total: number;
|
|
23
57
|
};
|
|
@@ -28,5 +62,5 @@ interface MigrateResult {
|
|
|
28
62
|
}
|
|
29
63
|
declare function createMigrateCommand(): Command;
|
|
30
64
|
//#endregion
|
|
31
|
-
export { MigrateResult, createMigrateCommand };
|
|
65
|
+
export { MigrateResult, MigrateShowMigration, MigrateShowResult, createMigrateCommand };
|
|
32
66
|
//# sourceMappingURL=migrate.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.mts","names":[],"sources":["../../src/commands/migrate.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"migrate.d.mts","names":[],"sources":["../../src/commands/migrate.ts"],"mappings":";;;;;;AA0FA;UAAiB,oBAAA;EAAA,SACN,OAAA;EAAA,SACA,OAAA;EAAA,SACA,aAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;AAAA;;UAIM,iBAAA;EAAA,SACN,EAAA;EAAA,SACA,UAAA,WAAqB,oBAAoB;EAAA,SACzC,OAAA;;;;;;WAMA,WAAA;EAAA;;;;EAAA,SAKA,mBAAA;EAUM;;;;;;EAAA,SAHN,cAAA;AAAA;AAAA,UAGM,aAAA;EAAA,SACN,EAAA;EAAA,SACA,iBAAA;EAAA,SACA,eAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA;IAAA,SACE,OAAA;IAAA,SACA,OAAA;IAAA,SACA,aAAA;IAAA,SACA,IAAA;IAAA,SACA,EAAA;IAAA,SACA,kBAAA;EAAA;EAAA,SAEF,OAAA;EAAA,SACA,QAAA,WAAmB,sBAAA;EAAA,SACnB,YAAA,GAAe,mBAAmB;EAAA,SAClC,OAAA;IAAA,SACE,KAAA;EAAA;EAAA,SAEF,WAAA;IAAA,SAAyB,IAAA;IAAA,SAAuB,IAAA;EAAA;AAAA;AAAA,iBAytB3C,oBAAA,IAAwB,OAAO"}
|
|
@@ -1,20 +1,296 @@
|
|
|
1
|
-
import { t as loadConfig } from "../config-loader-
|
|
2
|
-
import {
|
|
3
|
-
import { t as
|
|
4
|
-
import { t as
|
|
5
|
-
import { a as loadContractSpaceAggregateForCli,
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { t as
|
|
1
|
+
import { t as loadConfig } from "../config-loader-p9JMrekQ.mjs";
|
|
2
|
+
import { A as formatStyledHeader, B as errorContractValidationFailed, F as CliStructuredError, J as errorMarkerMismatch, S as formatMigrationApplyCommandOutput, U as errorDriverRequired, V as errorDatabaseConnectionRequired, W as errorFileNotFound, Z as errorPathUnreachable, _ as createTerminalUI, ct as errorUnexpected, dt as requireLiveDatabase, f as targetSupportsMigrations, g as parseGlobalFlagsOrExit, i as maskConnectionUrl, l as setCommandDescriptions, lt as mapMigrationToolsError, n as collectDeclaredInvariants, o as resolveContractPath, ot as errorTargetMigrationNotSupported, rt as errorRuntime, s as resolveMigrationPaths, t as addGlobalOptions, u as setCommandExamples, ut as mapRefResolutionError, y as handleResult } from "../command-helpers-DGMvGBeX.mjs";
|
|
3
|
+
import { t as toDeclaredExtensionsFromRaw } from "../extension-pack-inputs-1ySHqxKG.mjs";
|
|
4
|
+
import { n as planMemberPath, t as createControlClient } from "../client-CJzuo5wX.mjs";
|
|
5
|
+
import { a as refuseContractSpaceIntegrity, i as loadContractSpaceAggregateForCli, n as buildReadAggregate } from "../contract-space-aggregate-loader-ClI1KN6d.mjs";
|
|
6
|
+
import { i as readContractIR, r as executeRefAdvancement } from "../ref-advancement-BkXlikCA.mjs";
|
|
7
|
+
import { t as mapContractAtError } from "../contract-at-errors-CFXsstzm.mjs";
|
|
8
|
+
import { d as highlightFromEdgeAnnotations, f as indentMigrationGraphTreeBlock, h as buildGrid, i as formatOnPathMigrationRow, m as buildMigrationGraphRows, n as computeMaxDirNameWidth, r as renderMigrationGraphCommand, t as computeLabelColumn } from "../migration-graph-command-render-CEez7YUK.mjs";
|
|
9
|
+
import { r as listRefsByContractHash } from "../migration-list-DlJJ_38Z.mjs";
|
|
9
10
|
import { Command } from "commander";
|
|
10
11
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
11
12
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
12
13
|
import { readFile } from "node:fs/promises";
|
|
13
14
|
import { createControlStack } from "@prisma-next/framework-components/control";
|
|
15
|
+
import { requireHeadRef } from "@prisma-next/migration-tools/aggregate";
|
|
16
|
+
import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
|
|
14
17
|
import { MigrationToolsError, errorUnknownInvariant } from "@prisma-next/migration-tools/errors";
|
|
15
18
|
import { findLatestMigration, isGraphNode } from "@prisma-next/migration-tools/migration-graph";
|
|
19
|
+
import { readRefs } from "@prisma-next/migration-tools/refs";
|
|
16
20
|
import { parseContractRef } from "@prisma-next/migration-tools/ref-resolution";
|
|
17
21
|
//#region src/commands/migrate.ts
|
|
22
|
+
/**
|
|
23
|
+
* Read-only preview of the migration path `migrate` will take.
|
|
24
|
+
*
|
|
25
|
+
* Computes the path through the SAME seam as `executeMigrate`:
|
|
26
|
+
* - `readAllMarkers()` for the from-state (when no `--from` is given), preserving
|
|
27
|
+
* the full marker including `invariants` (not just `storageHash`).
|
|
28
|
+
* - `planMemberPath()` (shared with `executeMigrate`) for per-member path selection,
|
|
29
|
+
* which feeds `graphWalkStrategy()` with the same target hash, target invariants,
|
|
30
|
+
* and current marker as the real apply path uses.
|
|
31
|
+
*
|
|
32
|
+
* Returns BEFORE any write boundary (`runMigration` / marker / DDL). No
|
|
33
|
+
* DB state is mutated.
|
|
34
|
+
*/
|
|
35
|
+
async function executeMigrateShowCommand(options, flags, ui) {
|
|
36
|
+
const config = await loadConfig(options.config);
|
|
37
|
+
const { configPath, migrationsDir, migrationsRelative, refsDir } = resolveMigrationPaths(options.config, config);
|
|
38
|
+
const dbConnection = options.db ?? config.db?.connection;
|
|
39
|
+
const hasDriver = !!config.driver;
|
|
40
|
+
const hasExplicitFrom = options.from !== void 0;
|
|
41
|
+
if (!hasExplicitFrom) {
|
|
42
|
+
const missingDb = requireLiveDatabase({
|
|
43
|
+
dbConnection,
|
|
44
|
+
hasDriver,
|
|
45
|
+
why: "migrate --show needs a database connection to read the live marker (or pass --from <contract> for an offline preview)",
|
|
46
|
+
retryCommand: "prisma-next migrate --show --from <contract>"
|
|
47
|
+
});
|
|
48
|
+
if (missingDb) return notOk(missingDb);
|
|
49
|
+
}
|
|
50
|
+
let allRefs = {};
|
|
51
|
+
try {
|
|
52
|
+
allRefs = await readRefs(refsDir);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
const loaded = await buildReadAggregate(config, { migrationsDir });
|
|
58
|
+
if (!loaded.ok) return notOk(loaded.failure);
|
|
59
|
+
const { aggregate, contractHash } = loaded.value;
|
|
60
|
+
const appGraph = aggregate.app.graph();
|
|
61
|
+
let targetHash = contractHash;
|
|
62
|
+
let refInvariants;
|
|
63
|
+
if (options.to) {
|
|
64
|
+
const toResult = parseContractRef(options.to, {
|
|
65
|
+
graph: appGraph,
|
|
66
|
+
refs: allRefs,
|
|
67
|
+
contractHash
|
|
68
|
+
});
|
|
69
|
+
if (!toResult.ok) return notOk(mapRefResolutionError(toResult.failure));
|
|
70
|
+
if (toResult.value.provenance.kind === "reserved-db") return notOk(errorDatabaseConnectionRequired({
|
|
71
|
+
why: "@db is not valid as a --to target; it names the live database state, not a target contract.",
|
|
72
|
+
commandName: "migrate --show"
|
|
73
|
+
}));
|
|
74
|
+
targetHash = toResult.value.hash;
|
|
75
|
+
if (toResult.value.provenance.kind === "ref") {
|
|
76
|
+
const refEntry = allRefs[toResult.value.provenance.refName];
|
|
77
|
+
if (refEntry) refInvariants = refEntry.invariants;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (!flags.json && !flags.quiet) {
|
|
81
|
+
const details = [{
|
|
82
|
+
label: "config",
|
|
83
|
+
value: configPath
|
|
84
|
+
}, {
|
|
85
|
+
label: "migrations",
|
|
86
|
+
value: migrationsRelative
|
|
87
|
+
}];
|
|
88
|
+
if (dbConnection && !hasExplicitFrom) details.push({
|
|
89
|
+
label: "database",
|
|
90
|
+
value: maskConnectionUrl(String(dbConnection))
|
|
91
|
+
});
|
|
92
|
+
if (options.from) details.push({
|
|
93
|
+
label: "from",
|
|
94
|
+
value: options.from
|
|
95
|
+
});
|
|
96
|
+
if (options.to) details.push({
|
|
97
|
+
label: "to",
|
|
98
|
+
value: options.to
|
|
99
|
+
});
|
|
100
|
+
const header = formatStyledHeader({
|
|
101
|
+
command: "migrate --show",
|
|
102
|
+
description: "Preview the migration path migrate will take (read-only)",
|
|
103
|
+
details,
|
|
104
|
+
flags
|
|
105
|
+
});
|
|
106
|
+
ui.stderr(header);
|
|
107
|
+
}
|
|
108
|
+
const markerBySpace = /* @__PURE__ */ new Map();
|
|
109
|
+
const allMembers = [aggregate.app, ...aggregate.extensions];
|
|
110
|
+
if (hasExplicitFrom) if (options.from === "@db") {
|
|
111
|
+
const missingDb = requireLiveDatabase({
|
|
112
|
+
dbConnection,
|
|
113
|
+
hasDriver,
|
|
114
|
+
why: "@db resolves to the live database marker and requires a --db connection",
|
|
115
|
+
retryCommand: "prisma-next migrate --show --from @db --db $DATABASE_URL"
|
|
116
|
+
});
|
|
117
|
+
if (missingDb) return notOk(missingDb);
|
|
118
|
+
} else {
|
|
119
|
+
const fromResult = parseContractRef(options.from, {
|
|
120
|
+
graph: appGraph,
|
|
121
|
+
refs: allRefs,
|
|
122
|
+
contractHash
|
|
123
|
+
});
|
|
124
|
+
if (!fromResult.ok) return notOk(mapRefResolutionError(fromResult.failure));
|
|
125
|
+
if (fromResult.value.provenance.kind === "reserved-db") {
|
|
126
|
+
const missingDb = requireLiveDatabase({
|
|
127
|
+
dbConnection,
|
|
128
|
+
hasDriver,
|
|
129
|
+
why: "@db resolves to the live database marker and requires a --db connection"
|
|
130
|
+
});
|
|
131
|
+
if (missingDb) return notOk(missingDb);
|
|
132
|
+
} else {
|
|
133
|
+
const fromHash = fromResult.value.hash;
|
|
134
|
+
const offlineMarker = fromHash === EMPTY_CONTRACT_HASH ? null : {
|
|
135
|
+
storageHash: fromHash,
|
|
136
|
+
invariants: []
|
|
137
|
+
};
|
|
138
|
+
markerBySpace.set(aggregate.app.spaceId, offlineMarker);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const needsLiveMarker = !hasExplicitFrom || options.from === "@db";
|
|
142
|
+
if (needsLiveMarker) {
|
|
143
|
+
if (!dbConnection || !hasDriver) return notOk(errorDatabaseConnectionRequired({
|
|
144
|
+
why: "A database connection is required to read the live marker for migrate --show",
|
|
145
|
+
commandName: "migrate --show"
|
|
146
|
+
}));
|
|
147
|
+
const client = createControlClient({
|
|
148
|
+
family: config.family,
|
|
149
|
+
target: config.target,
|
|
150
|
+
adapter: config.adapter,
|
|
151
|
+
driver: config.driver,
|
|
152
|
+
extensionPacks: config.extensionPacks ?? []
|
|
153
|
+
});
|
|
154
|
+
try {
|
|
155
|
+
await client.connect(dbConnection);
|
|
156
|
+
const allMarkers = await client.readAllMarkers();
|
|
157
|
+
for (const member of allMembers) {
|
|
158
|
+
const marker = allMarkers.get(member.spaceId);
|
|
159
|
+
markerBySpace.set(member.spaceId, marker ?? null);
|
|
160
|
+
}
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (CliStructuredError.is(error)) return notOk(error);
|
|
163
|
+
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
164
|
+
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read live DB marker: ${error instanceof Error ? error.message : String(error)}` }));
|
|
165
|
+
} finally {
|
|
166
|
+
await client.close();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const canonicalOrderMembers = [...aggregate.extensions, aggregate.app];
|
|
170
|
+
const orderedMigrations = [];
|
|
171
|
+
for (const member of canonicalOrderMembers) {
|
|
172
|
+
const isAppMember = member.spaceId === aggregate.app.spaceId;
|
|
173
|
+
const headRef = requireHeadRef(member);
|
|
174
|
+
const outcome = planMemberPath({
|
|
175
|
+
member,
|
|
176
|
+
aggregate,
|
|
177
|
+
targetHash: isAppMember ? targetHash : headRef.hash,
|
|
178
|
+
refInvariants: isAppMember ? refInvariants : void 0,
|
|
179
|
+
liveMarker: markerBySpace.get(member.spaceId) ?? null
|
|
180
|
+
});
|
|
181
|
+
if (outcome.kind === "at-head") continue;
|
|
182
|
+
if (outcome.kind === "never-planned") return notOk(errorPathUnreachable({
|
|
183
|
+
code: "MIGRATION_PATH_NOT_FOUND",
|
|
184
|
+
summary: `No on-disk migrations for contract space "${outcome.spaceId}"`,
|
|
185
|
+
why: `migrate is replay-only: space "${outcome.spaceId}" has no on-disk migrations but its head ref targets "${outcome.targetHash}".`,
|
|
186
|
+
meta: {
|
|
187
|
+
spaceId: outcome.spaceId,
|
|
188
|
+
target: outcome.targetHash,
|
|
189
|
+
kind: "neverPlanned"
|
|
190
|
+
}
|
|
191
|
+
}));
|
|
192
|
+
if (outcome.kind === "unreachable") {
|
|
193
|
+
const fromHash = outcome.liveMarker?.storageHash ?? EMPTY_CONTRACT_HASH;
|
|
194
|
+
return notOk(errorPathUnreachable({
|
|
195
|
+
code: "MIGRATION_PATH_NOT_FOUND",
|
|
196
|
+
summary: `No migration path from ${fromHash.slice(0, 14)} to ${outcome.targetHash.slice(0, 14)} in space "${outcome.spaceId}".`,
|
|
197
|
+
why: `The migration graph has no path from the from-state to the target in space "${outcome.spaceId}".`,
|
|
198
|
+
meta: {
|
|
199
|
+
spaceId: outcome.spaceId,
|
|
200
|
+
from: fromHash,
|
|
201
|
+
to: outcome.targetHash
|
|
202
|
+
}
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
if (outcome.kind === "unsatisfiable") return notOk(errorRuntime(`Missing required invariants for space "${outcome.spaceId}"`, { why: `The path requires invariants not available on disk: ${outcome.missing.join(", ")}` }));
|
|
206
|
+
for (const edge of outcome.plan.migrationEdges) orderedMigrations.push({
|
|
207
|
+
spaceId: member.spaceId,
|
|
208
|
+
dirName: edge.dirName,
|
|
209
|
+
migrationHash: edge.migrationHash,
|
|
210
|
+
from: edge.from,
|
|
211
|
+
to: edge.to
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const count = orderedMigrations.length;
|
|
215
|
+
const summary = count === 0 ? "Already up to date — nothing to run" : `${count} migration${count === 1 ? "" : "s"} will run`;
|
|
216
|
+
let graphOutput;
|
|
217
|
+
let runListDirNameWidth;
|
|
218
|
+
let runListLeftPad;
|
|
219
|
+
if (!flags.json) {
|
|
220
|
+
const onPathHashes = new Set(orderedMigrations.map((m) => m.migrationHash));
|
|
221
|
+
const colorize = flags.color !== false;
|
|
222
|
+
const memberLayouts = allMembers.map((member) => {
|
|
223
|
+
const isApp = member.spaceId === aggregate.app.spaceId;
|
|
224
|
+
const memberGraph = member.graph();
|
|
225
|
+
const rowModel = buildMigrationGraphRows(memberGraph, isApp ? { contractHash } : {});
|
|
226
|
+
const edgeAnnotations = /* @__PURE__ */ new Map();
|
|
227
|
+
for (const edge of memberGraph.migrationByHash.values()) edgeAnnotations.set(edge.migrationHash, { pathHighlight: onPathHashes.has(edge.migrationHash) ? "on-path" : "off-path" });
|
|
228
|
+
return {
|
|
229
|
+
member,
|
|
230
|
+
isApp,
|
|
231
|
+
memberGraph,
|
|
232
|
+
rowModel,
|
|
233
|
+
grid: buildGrid(rowModel, {}, highlightFromEdgeAnnotations(edgeAnnotations)),
|
|
234
|
+
edgeAnnotations
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
const globalLabelColumn = memberLayouts.length > 1 ? Math.max(...memberLayouts.map(({ grid }) => computeLabelColumn(grid, "unicode"))) : void 0;
|
|
238
|
+
const globalMaxDirNameWidthFromLayouts = memberLayouts.length > 1 ? Math.max(...memberLayouts.map(({ rowModel }) => computeMaxDirNameWidth(rowModel))) : void 0;
|
|
239
|
+
const runListMaxFromMigrations = orderedMigrations.length > 0 ? Math.max(...orderedMigrations.map((m) => m.dirName.length)) : 0;
|
|
240
|
+
const globalMaxDirNameWidth = globalMaxDirNameWidthFromLayouts !== void 0 ? Math.max(globalMaxDirNameWidthFromLayouts, runListMaxFromMigrations) : void 0;
|
|
241
|
+
runListDirNameWidth = globalMaxDirNameWidth ?? runListMaxFromMigrations;
|
|
242
|
+
runListLeftPad = globalLabelColumn;
|
|
243
|
+
const showSpaceHeadings = allMembers.length > 1;
|
|
244
|
+
const sections = [];
|
|
245
|
+
for (const { member, isApp, rowModel, grid, edgeAnnotations } of memberLayouts) {
|
|
246
|
+
const liveMarkerHash = (markerBySpace.get(member.spaceId) ?? null)?.storageHash ?? EMPTY_CONTRACT_HASH;
|
|
247
|
+
const tree = renderMigrationGraphCommand({
|
|
248
|
+
grid,
|
|
249
|
+
rowModel,
|
|
250
|
+
contractHash,
|
|
251
|
+
isAppSpace: isApp,
|
|
252
|
+
...needsLiveMarker ? { dbHash: liveMarkerHash } : {},
|
|
253
|
+
refsByHash: listRefsByContractHash(member),
|
|
254
|
+
edgeAnnotationsByHash: edgeAnnotations,
|
|
255
|
+
colorize,
|
|
256
|
+
glyphMode: "unicode",
|
|
257
|
+
...globalLabelColumn !== void 0 ? { globalLabelColumn } : {},
|
|
258
|
+
...globalMaxDirNameWidth !== void 0 ? { globalMaxDirNameWidth } : {}
|
|
259
|
+
});
|
|
260
|
+
if (tree.length === 0) continue;
|
|
261
|
+
if (showSpaceHeadings) sections.push(`${member.spaceId}:\n${indentMigrationGraphTreeBlock(tree, " ")}`);
|
|
262
|
+
else sections.push(tree);
|
|
263
|
+
}
|
|
264
|
+
graphOutput = sections.join("\n\n");
|
|
265
|
+
}
|
|
266
|
+
return ok({
|
|
267
|
+
ok: true,
|
|
268
|
+
migrations: orderedMigrations,
|
|
269
|
+
summary,
|
|
270
|
+
...graphOutput !== void 0 ? { graphOutput } : {},
|
|
271
|
+
...runListDirNameWidth !== void 0 ? { runListDirNameWidth } : {},
|
|
272
|
+
...runListLeftPad !== void 0 ? { runListLeftPad } : {}
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
function formatMigrateShowOutput(result, flags) {
|
|
276
|
+
if (flags.quiet) return "";
|
|
277
|
+
const colorize = flags.color !== false;
|
|
278
|
+
const lines = [];
|
|
279
|
+
if (result.graphOutput !== void 0 && result.graphOutput.length > 0) {
|
|
280
|
+
lines.push(result.graphOutput);
|
|
281
|
+
lines.push("");
|
|
282
|
+
}
|
|
283
|
+
const n = result.migrations.length;
|
|
284
|
+
if (n > 0) {
|
|
285
|
+
lines.push(`The following ${n} migration${n === 1 ? "" : "s"} will run:`);
|
|
286
|
+
const isMultiSpace = result.runListLeftPad !== void 0;
|
|
287
|
+
const gutter = result.runListLeftPad ?? 0;
|
|
288
|
+
const rawDirNameWidth = result.runListDirNameWidth ?? Math.max(...result.migrations.map((m) => m.dirName.length));
|
|
289
|
+
const listDirNameWidth = gutter + Math.max(rawDirNameWidth + 2, 25 - gutter) - (isMultiSpace ? 2 : 4);
|
|
290
|
+
for (const m of result.migrations) lines.push(` ${formatOnPathMigrationRow(m.dirName, m.from, m.to, listDirNameWidth, colorize, "unicode")}`);
|
|
291
|
+
} else lines.push(result.summary);
|
|
292
|
+
return lines.join("\n");
|
|
293
|
+
}
|
|
18
294
|
function mapApplyFailure(failure) {
|
|
19
295
|
if (failure.code === "MIGRATION_PATH_NOT_FOUND") return errorPathUnreachable(failure);
|
|
20
296
|
return errorRuntime(failure.summary, {
|
|
@@ -148,7 +424,7 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
|
|
|
148
424
|
return mapContractAtError(error, { artifactRole: "to" });
|
|
149
425
|
}
|
|
150
426
|
}
|
|
151
|
-
const applyResult = await client.
|
|
427
|
+
const applyResult = await client.migrate({
|
|
152
428
|
contract: applyContract,
|
|
153
429
|
migrationsDir,
|
|
154
430
|
...ifDefined("refHash", refEntry?.hash),
|
|
@@ -190,16 +466,26 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
|
|
|
190
466
|
}
|
|
191
467
|
function createMigrateCommand() {
|
|
192
468
|
const command = new Command("migrate");
|
|
193
|
-
setCommandDescriptions(command, "Apply planned migrations to advance the database", "Walks every contract space (app + extensions) and applies pending\non-disk migrations in canonical order (extensions alphabetically,\nthen app). Graph-walks the on-disk migration graph for every space.\nUse --to to target a specific contract (hash, ref name, migration dir).");
|
|
469
|
+
setCommandDescriptions(command, "Apply planned migrations to advance the database", "Walks every contract space (app + extensions) and applies pending\non-disk migrations in canonical order (extensions alphabetically,\nthen app). Graph-walks the on-disk migration graph for every space.\nUse --to to target a specific contract (hash, ref name, migration dir).\nUse --show for a read-only preview of the path that would run.");
|
|
194
470
|
setCommandExamples(command, [
|
|
195
471
|
"prisma-next migrate --db $DATABASE_URL",
|
|
196
472
|
"prisma-next migrate --to production --db $DATABASE_URL",
|
|
197
|
-
"prisma-next migrate --to sha256:abc123 --db $DATABASE_URL"
|
|
473
|
+
"prisma-next migrate --to sha256:abc123 --db $DATABASE_URL",
|
|
474
|
+
"prisma-next migrate --show --db $DATABASE_URL",
|
|
475
|
+
"prisma-next migrate --show --from @contract --to production"
|
|
198
476
|
]);
|
|
199
|
-
addGlobalOptions(command).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--to <contract>", "Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)").option("--advance-ref <name>", "Advance the named ref to the post-apply marker after success").action(async (options) => {
|
|
477
|
+
addGlobalOptions(command).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--to <contract>", "Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)").option("--advance-ref <name>", "Advance the named ref to the post-apply marker after success").option("--show", "Preview the migration path without applying (read-only)").option("--from <contract>", "From-state for --show preview (@contract, @db, hash, ref name, or migration dir)").action(async (options) => {
|
|
200
478
|
const flags = parseGlobalFlagsOrExit(options);
|
|
201
479
|
const startTime = Date.now();
|
|
202
480
|
const ui = createTerminalUI(flags);
|
|
481
|
+
if (options.show) {
|
|
482
|
+
const exitCode = handleResult(await executeMigrateShowCommand(options, flags, ui), flags, ui, (showResult) => {
|
|
483
|
+
if (flags.json) ui.output(JSON.stringify(showResult, null, 2));
|
|
484
|
+
else ui.output(formatMigrateShowOutput(showResult, flags));
|
|
485
|
+
});
|
|
486
|
+
process.exit(exitCode);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
203
489
|
const exitCode = handleResult(await executeMigrateCommand(options, flags, ui, startTime), flags, ui, (migrateResult) => {
|
|
204
490
|
if (flags.json) ui.output(JSON.stringify(migrateResult, null, 2));
|
|
205
491
|
else if (!flags.quiet) ui.log(formatMigrationApplyCommandOutput(migrateResult, flags));
|