prisma-next 0.5.0-dev.73 → 0.5.0-dev.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +8 -8
- package/dist/{client-0ZX24FXF.mjs → client-qVH-rEgd.mjs} +433 -236
- package/dist/client-qVH-rEgd.mjs.map +1 -0
- package/dist/{result-handler-DWb1rFS-.mjs → command-helpers-BeZHkxV8.mjs} +22 -24
- package/dist/command-helpers-BeZHkxV8.mjs.map +1 -0
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +7 -5
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +5 -4
- package/dist/commands/db-schema.mjs.map +1 -1
- package/dist/commands/db-sign.mjs +6 -5
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +7 -5
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migration-apply.d.mts +29 -17
- package/dist/commands/migration-apply.d.mts.map +1 -1
- package/dist/commands/migration-apply.mjs +35 -129
- package/dist/commands/migration-apply.mjs.map +1 -1
- package/dist/commands/migration-new.mjs +4 -3
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +19 -1
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +2 -2
- package/dist/commands/migration-ref.d.mts +1 -1
- package/dist/commands/migration-ref.mjs +3 -2
- package/dist/commands/migration-ref.mjs.map +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +5 -4
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +104 -1
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +2 -2
- package/dist/{contract-emit-DkMqO7f2.mjs → contract-emit-9DBda5Ou.mjs} +7 -5
- package/dist/{contract-emit-DkMqO7f2.mjs.map → contract-emit-9DBda5Ou.mjs.map} +1 -1
- package/dist/{contract-emit-B3ChISB_.mjs → contract-emit-B77TsJqf.mjs} +4 -15
- package/dist/{contract-emit-B3ChISB_.mjs.map → contract-emit-B77TsJqf.mjs.map} +1 -1
- package/dist/{contract-enrichment-CF6ogEJ_.mjs → contract-enrichment-Dani0mMW.mjs} +1 -1
- package/dist/{contract-enrichment-CF6ogEJ_.mjs.map → contract-enrichment-Dani0mMW.mjs.map} +1 -1
- package/dist/{contract-infer-BDKAE0B0.mjs → contract-infer-BK9YFGEG.mjs} +5 -4
- package/dist/{contract-infer-BDKAE0B0.mjs.map → contract-infer-BK9YFGEG.mjs.map} +1 -1
- package/dist/{db-verify-B4TdDKOI.mjs → db-verify-C0y1PCO2.mjs} +7 -6
- package/dist/{db-verify-B4TdDKOI.mjs.map → db-verify-C0y1PCO2.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +3 -746
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +3 -3
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/extension-pack-inputs-C7xgE-vv.mjs +74 -0
- package/dist/extension-pack-inputs-C7xgE-vv.mjs.map +1 -0
- package/dist/{framework-components-gwAHl7ml.mjs → framework-components-ChqVUxR-.mjs} +1 -1
- package/dist/{framework-components-gwAHl7ml.mjs.map → framework-components-ChqVUxR-.mjs.map} +1 -1
- package/dist/global-flags-Icqpxk23.d.mts +12 -0
- package/dist/global-flags-Icqpxk23.d.mts.map +1 -0
- package/dist/helpers-eqdN8tH6.mjs +25 -0
- package/dist/helpers-eqdN8tH6.mjs.map +1 -0
- package/dist/{init-Deo7U8_U.mjs → init-CoDVPvQ4.mjs} +4 -4
- package/dist/{init-Deo7U8_U.mjs.map → init-CoDVPvQ4.mjs.map} +1 -1
- package/dist/{inspect-live-schema-BAgQMYpD.mjs → inspect-live-schema-CWYxGKlb.mjs} +4 -4
- package/dist/{inspect-live-schema-BAgQMYpD.mjs.map → inspect-live-schema-CWYxGKlb.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-B8J702Uh.mjs → migration-command-scaffold-B5dORFEv.mjs} +4 -4
- package/dist/{migration-command-scaffold-B8J702Uh.mjs.map → migration-command-scaffold-B5dORFEv.mjs.map} +1 -1
- package/dist/{migration-plan-BcKNnTM7.mjs → migration-plan-C6lVaHsO.mjs} +47 -23
- package/dist/migration-plan-C6lVaHsO.mjs.map +1 -0
- package/dist/{migration-status-CjwB2of-.mjs → migration-status-CZ-D5k7k.mjs} +161 -7
- package/dist/migration-status-CZ-D5k7k.mjs.map +1 -0
- package/dist/{migrations-CIK94AJf.mjs → migrations-D_UJnpuW.mjs} +67 -24
- package/dist/migrations-D_UJnpuW.mjs.map +1 -0
- package/dist/{output-DnjfCC_u.mjs → output-B16Kefzx.mjs} +1 -1
- package/dist/{output-DnjfCC_u.mjs.map → output-B16Kefzx.mjs.map} +1 -1
- package/dist/{progress-adapter-xASh41wr.mjs → progress-adapter-DFfvZcYL.mjs} +1 -1
- package/dist/{progress-adapter-xASh41wr.mjs.map → progress-adapter-DFfvZcYL.mjs.map} +1 -1
- package/dist/result-handler-rmPVKIP2.mjs +25 -0
- package/dist/result-handler-rmPVKIP2.mjs.map +1 -0
- package/dist/rolldown-runtime-twds-ZHy.mjs +14 -0
- package/dist/{terminal-ui-zaRDhJnP.mjs → terminal-ui-C_hFNbAn.mjs} +3 -23
- package/dist/terminal-ui-C_hFNbAn.mjs.map +1 -0
- package/dist/types-D7x-IFLO.d.mts +858 -0
- package/dist/types-D7x-IFLO.d.mts.map +1 -0
- package/dist/{verify-BEIa9638.mjs → verify-CiwNWM9N.mjs} +2 -2
- package/dist/{verify-BEIa9638.mjs.map → verify-CiwNWM9N.mjs.map} +1 -1
- package/package.json +10 -10
- package/dist/client-0ZX24FXF.mjs.map +0 -1
- package/dist/migration-plan-BcKNnTM7.mjs.map +0 -1
- package/dist/migration-status-CjwB2of-.mjs.map +0 -1
- package/dist/migrations-CIK94AJf.mjs.map +0 -1
- package/dist/result-handler-DWb1rFS-.mjs.map +0 -1
- package/dist/terminal-ui-zaRDhJnP.mjs.map +0 -1
- /package/dist/{cli-errors-QH8kf-C2.d.mts → cli-errors-B9OBbled.d.mts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-init.mjs","names":[],"sources":["../../src/commands/db-init.ts"],"sourcesContent":["import { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { ContractValidationError } from '../control-api/errors';\nimport type { DbInitFailure } from '../control-api/types';\nimport {\n CliStructuredError,\n errorContractValidationFailed,\n errorMigrationPlanningFailed,\n errorRunnerFailed,\n errorRuntime,\n errorUnexpected,\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 {\n formatMigrationApplyOutput,\n formatMigrationJson,\n formatMigrationPlanOutput,\n type MigrationCommandResult,\n} from '../utils/formatters/migrations';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport {\n addMigrationCommandOptions,\n prepareMigrationContext,\n} from '../utils/migration-command-scaffold';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ntype DbInitOptions = MigrationCommandOptions;\n\n/**\n * Maps a DbInitFailure to a CliStructuredError for consistent error handling.\n */\nfunction mapDbInitFailure(failure: DbInitFailure): CliStructuredError {\n if (failure.code === 'PLANNING_FAILED') {\n return errorMigrationPlanningFailed({ conflicts: failure.conflicts ?? [] });\n }\n\n if (failure.code === 'MARKER_ORIGIN_MISMATCH') {\n const mismatchParts: string[] = [];\n if (\n failure.marker?.storageHash !== failure.destination?.storageHash &&\n failure.marker?.storageHash &&\n failure.destination?.storageHash\n ) {\n mismatchParts.push(\n `storageHash (marker: ${failure.marker.storageHash}, destination: ${failure.destination.storageHash})`,\n );\n }\n if (\n failure.marker?.profileHash !== failure.destination?.profileHash &&\n failure.marker?.profileHash &&\n failure.destination?.profileHash\n ) {\n mismatchParts.push(\n `profileHash (marker: ${failure.marker.profileHash}, destination: ${failure.destination.profileHash})`,\n );\n }\n\n return errorRuntime(\n `Existing database signature does not match plan destination.${mismatchParts.length > 0 ? ` Mismatch in ${mismatchParts.join(' and ')}.` : ''}`,\n {\n why: 'Database has an existing signature (marker) that does not match the target contract',\n fix: 'If bootstrapping, drop/reset the database then re-run `prisma-next db init`; otherwise reconcile schema/marker using your migration workflow',\n meta: {\n code: 'MARKER_ORIGIN_MISMATCH',\n ...ifDefined('markerStorageHash', failure.marker?.storageHash),\n ...ifDefined('destinationStorageHash', failure.destination?.storageHash),\n ...ifDefined('markerProfileHash', failure.marker?.profileHash),\n ...ifDefined('destinationProfileHash', failure.destination?.profileHash),\n },\n },\n );\n }\n\n if (failure.code === 'RUNNER_FAILED') {\n return errorRunnerFailed(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Fix the schema mismatch (db init is additive-only), or drop/reset the database and re-run `prisma-next db init`',\n ...(failure.meta\n ? { meta: { code: 'RUNNER_FAILED', ...failure.meta } }\n : { meta: { code: 'RUNNER_FAILED' } }),\n });\n }\n\n // Exhaustive check - TypeScript will error if a new code is added but not handled\n const exhaustive: never = failure.code;\n throw new Error(`Unhandled DbInitFailure code: ${exhaustive}`);\n}\n\n/**\n * Executes the db init command and returns a structured Result.\n */\nasync function executeDbInitCommand(\n options: DbInitOptions,\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 init',\n description: 'Bootstrap a database to match the current contract',\n url: 'https://pris.ly/db-init',\n });\n if (!ctxResult.ok) {\n return ctxResult;\n }\n const { client, config, contractJson, dbConnection, onProgress, contractPathAbsolute } =\n ctxResult.value;\n\n // The aggregate loader (loader → planner → runner pipeline) catches\n // layout / drift / disjointness violations on its own; the legacy\n // per-space precheck + marker-check helpers are no longer needed at\n // this surface. Marker-vs-on-disk drift surfaces through the planner's\n // graph-walk strategy.\n const { migrationsDir } = resolveMigrationPaths(options.config, config);\n\n try {\n await client.connect(dbConnection);\n\n const result = await client.dbInit({\n contract: contractJson,\n mode: options.dryRun ? 'plan' : 'apply',\n migrationsDir,\n onProgress,\n });\n\n // Handle failures by mapping to CLI structured error\n if (!result.ok) {\n return notOk(mapDbInitFailure(result.failure));\n }\n\n // Convert success result to CLI output format\n const dbInitResult: 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 ...(result.value.execution\n ? {\n execution: {\n operationsPlanned: result.value.execution.operationsPlanned,\n operationsExecuted: result.value.execution.operationsExecuted,\n },\n }\n : {}),\n ...(result.value.marker\n ? {\n marker: {\n storageHash: result.value.marker.storageHash,\n ...ifDefined('profileHash', result.value.marker.profileHash),\n },\n }\n : {}),\n summary: result.value.summary,\n timings: { total: Date.now() - startTime },\n };\n\n return ok(dbInitResult);\n } catch (error) {\n // Driver already throws CliStructuredError for connection failures\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 init: ${safeMessage}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createDbInitCommand(): Command {\n const command = new Command('init');\n setCommandDescriptions(\n command,\n 'Bootstrap a database to match the current contract and sign it',\n 'Initializes a database to match your emitted contract using additive-only operations.\\n' +\n 'Creates any missing tables, columns, indexes, and constraints defined in your contract.\\n' +\n 'Leaves existing compatible structures in place, surfaces conflicts when destructive changes\\n' +\n 'would be required, and signs the database to track contract state. Use --dry-run to\\n' +\n 'preview changes without applying.',\n );\n setCommandExamples(command, [\n 'prisma-next db init --db $DATABASE_URL',\n 'prisma-next db init --db $DATABASE_URL --dry-run',\n ]);\n addMigrationCommandOptions(command);\n command.action(async (options: DbInitOptions) => {\n const flags = parseGlobalFlags(options);\n const startTime = Date.now();\n\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n\n const result = await executeDbInitCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (dbInitResult) => {\n if (flags.json) {\n ui.output(formatMigrationJson(dbInitResult));\n } else {\n const output =\n dbInitResult.mode === 'plan'\n ? formatMigrationPlanOutput(dbInitResult, flags)\n : formatMigrationApplyOutput(dbInitResult, flags);\n if (output) {\n ui.log(output);\n }\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"db-init.mjs","names":[],"sources":["../../src/commands/db-init.ts"],"sourcesContent":["import { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { ContractValidationError } from '../control-api/errors';\nimport type { DbInitFailure } from '../control-api/types';\nimport {\n CliStructuredError,\n errorContractValidationFailed,\n errorMigrationPlanningFailed,\n errorRunnerFailed,\n errorRuntime,\n errorUnexpected,\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 {\n formatMigrationApplyOutput,\n formatMigrationJson,\n formatMigrationPlanOutput,\n type MigrationCommandResult,\n} from '../utils/formatters/migrations';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport {\n addMigrationCommandOptions,\n prepareMigrationContext,\n} from '../utils/migration-command-scaffold';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ntype DbInitOptions = MigrationCommandOptions;\n\n/**\n * Maps a DbInitFailure to a CliStructuredError for consistent error handling.\n */\nfunction mapDbInitFailure(failure: DbInitFailure): CliStructuredError {\n if (failure.code === 'PLANNING_FAILED') {\n return errorMigrationPlanningFailed({ conflicts: failure.conflicts ?? [] });\n }\n\n if (failure.code === 'MARKER_ORIGIN_MISMATCH') {\n const mismatchParts: string[] = [];\n if (\n failure.marker?.storageHash !== failure.destination?.storageHash &&\n failure.marker?.storageHash &&\n failure.destination?.storageHash\n ) {\n mismatchParts.push(\n `storageHash (marker: ${failure.marker.storageHash}, destination: ${failure.destination.storageHash})`,\n );\n }\n if (\n failure.marker?.profileHash !== failure.destination?.profileHash &&\n failure.marker?.profileHash &&\n failure.destination?.profileHash\n ) {\n mismatchParts.push(\n `profileHash (marker: ${failure.marker.profileHash}, destination: ${failure.destination.profileHash})`,\n );\n }\n\n return errorRuntime(\n `Existing database signature does not match plan destination.${mismatchParts.length > 0 ? ` Mismatch in ${mismatchParts.join(' and ')}.` : ''}`,\n {\n why: 'Database has an existing signature (marker) that does not match the target contract',\n fix: 'If bootstrapping, drop/reset the database then re-run `prisma-next db init`; otherwise reconcile schema/marker using your migration workflow',\n meta: {\n code: 'MARKER_ORIGIN_MISMATCH',\n ...ifDefined('markerStorageHash', failure.marker?.storageHash),\n ...ifDefined('destinationStorageHash', failure.destination?.storageHash),\n ...ifDefined('markerProfileHash', failure.marker?.profileHash),\n ...ifDefined('destinationProfileHash', failure.destination?.profileHash),\n },\n },\n );\n }\n\n if (failure.code === 'RUNNER_FAILED') {\n return errorRunnerFailed(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Fix the schema mismatch (db init is additive-only), or drop/reset the database and re-run `prisma-next db init`',\n ...(failure.meta\n ? { meta: { code: 'RUNNER_FAILED', ...failure.meta } }\n : { meta: { code: 'RUNNER_FAILED' } }),\n });\n }\n\n // Exhaustive check - TypeScript will error if a new code is added but not handled\n const exhaustive: never = failure.code;\n throw new Error(`Unhandled DbInitFailure code: ${exhaustive}`);\n}\n\n/**\n * Executes the db init command and returns a structured Result.\n */\nasync function executeDbInitCommand(\n options: DbInitOptions,\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 init',\n description: 'Bootstrap a database to match the current contract',\n url: 'https://pris.ly/db-init',\n });\n if (!ctxResult.ok) {\n return ctxResult;\n }\n const { client, config, contractJson, dbConnection, onProgress, contractPathAbsolute } =\n ctxResult.value;\n\n // The aggregate loader (loader → planner → runner pipeline) catches\n // layout / drift / disjointness violations on its own; the legacy\n // per-space precheck + marker-check helpers are no longer needed at\n // this surface. Marker-vs-on-disk drift surfaces through the planner's\n // graph-walk strategy.\n const { migrationsDir } = resolveMigrationPaths(options.config, config);\n\n try {\n await client.connect(dbConnection);\n\n const result = await client.dbInit({\n contract: contractJson,\n mode: options.dryRun ? 'plan' : 'apply',\n migrationsDir,\n onProgress,\n });\n\n // Handle failures by mapping to CLI structured error\n if (!result.ok) {\n return notOk(mapDbInitFailure(result.failure));\n }\n\n // Convert success result to CLI output format\n const dbInitResult: 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 ...(result.value.execution\n ? {\n execution: {\n operationsPlanned: result.value.execution.operationsPlanned,\n operationsExecuted: result.value.execution.operationsExecuted,\n },\n }\n : {}),\n ...(result.value.marker\n ? {\n marker: {\n storageHash: result.value.marker.storageHash,\n ...ifDefined('profileHash', result.value.marker.profileHash),\n },\n }\n : {}),\n ...ifDefined('perSpace', result.value.perSpace),\n summary: result.value.summary,\n timings: { total: Date.now() - startTime },\n };\n\n return ok(dbInitResult);\n } catch (error) {\n // Driver already throws CliStructuredError for connection failures\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 init: ${safeMessage}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createDbInitCommand(): Command {\n const command = new Command('init');\n setCommandDescriptions(\n command,\n 'Bootstrap a database to match the current contract and sign it',\n 'Initializes a database to match your emitted contract using additive-only operations.\\n' +\n 'Creates any missing tables, columns, indexes, and constraints defined in your contract.\\n' +\n 'Leaves existing compatible structures in place, surfaces conflicts when destructive changes\\n' +\n 'would be required, and signs the database to track contract state. Use --dry-run to\\n' +\n 'preview changes without applying.',\n );\n setCommandExamples(command, [\n 'prisma-next db init --db $DATABASE_URL',\n 'prisma-next db init --db $DATABASE_URL --dry-run',\n ]);\n addMigrationCommandOptions(command);\n command.action(async (options: DbInitOptions) => {\n const flags = parseGlobalFlags(options);\n const startTime = Date.now();\n\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n\n const result = await executeDbInitCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (dbInitResult) => {\n if (flags.json) {\n ui.output(formatMigrationJson(dbInitResult));\n } else {\n const output =\n dbInitResult.mode === 'plan'\n ? formatMigrationPlanOutput(dbInitResult, flags)\n : formatMigrationApplyOutput(dbInitResult, flags);\n if (output) {\n ui.log(output);\n }\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import {
|
|
3
|
-
import { t as
|
|
4
|
-
import {
|
|
1
|
+
import { d as setCommandDescriptions, f as setCommandExamples, g as parseGlobalFlags, t as addGlobalOptions } from "../command-helpers-BeZHkxV8.mjs";
|
|
2
|
+
import { t as TerminalUI } from "../terminal-ui-C_hFNbAn.mjs";
|
|
3
|
+
import { t as handleResult } from "../result-handler-rmPVKIP2.mjs";
|
|
4
|
+
import { t as inspectLiveSchema } from "../inspect-live-schema-CWYxGKlb.mjs";
|
|
5
|
+
import { n as formatIntrospectOutput, t as formatIntrospectJson } from "../verify-CiwNWM9N.mjs";
|
|
5
6
|
import { Command } from "commander";
|
|
6
7
|
//#region src/commands/db-schema.ts
|
|
7
8
|
function toIntrospectSchemaResult(result) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-schema.mjs","names":[],"sources":["../../src/commands/db-schema.ts"],"sourcesContent":["import type { IntrospectSchemaResult } from '@prisma-next/framework-components/control';\nimport { Command } from 'commander';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { formatIntrospectJson, formatIntrospectOutput } from '../utils/formatters/verify';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\nimport {\n type InspectLiveSchemaOptions,\n type InspectLiveSchemaResult,\n inspectLiveSchema,\n} from './inspect-live-schema';\n\nfunction toIntrospectSchemaResult(\n result: InspectLiveSchemaResult,\n): IntrospectSchemaResult<unknown> {\n return {\n ok: true,\n summary: 'Schema read successfully',\n target: result.target,\n schema: result.schema,\n meta: result.meta,\n timings: result.timings,\n };\n}\n\nexport function createDbSchemaCommand(): Command {\n const command = new Command('schema');\n setCommandDescriptions(\n command,\n 'Inspect the live database schema',\n 'Reads the live database schema and prints it as a tree by default or as JSON with\\n' +\n '--json. This command is always read-only and never writes files. To save machine-\\n' +\n 'readable output, use shell redirection, for example `prisma-next db schema --json > schema.json`.',\n );\n setCommandExamples(command, [\n 'prisma-next db schema --db $DATABASE_URL',\n 'prisma-next db schema --db $DATABASE_URL --json',\n 'prisma-next db schema --db $DATABASE_URL --json > schema.json',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: InspectLiveSchemaOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const startTime = Date.now();\n\n const result = await inspectLiveSchema(options, flags, ui, startTime, {\n commandName: 'db schema',\n description: 'Inspect the live database schema',\n url: 'https://pris.ly/db-schema',\n });\n\n const exitCode = handleResult(result, flags, ui, (value) => {\n const introspectResult = toIntrospectSchemaResult(value);\n\n if (flags.json) {\n ui.output(formatIntrospectJson(introspectResult));\n return;\n }\n\n const output = formatIntrospectOutput(introspectResult, value.schemaView, flags);\n if (output) {\n ui.log(output);\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"db-schema.mjs","names":[],"sources":["../../src/commands/db-schema.ts"],"sourcesContent":["import type { IntrospectSchemaResult } from '@prisma-next/framework-components/control';\nimport { Command } from 'commander';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { formatIntrospectJson, formatIntrospectOutput } from '../utils/formatters/verify';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\nimport {\n type InspectLiveSchemaOptions,\n type InspectLiveSchemaResult,\n inspectLiveSchema,\n} from './inspect-live-schema';\n\nfunction toIntrospectSchemaResult(\n result: InspectLiveSchemaResult,\n): IntrospectSchemaResult<unknown> {\n return {\n ok: true,\n summary: 'Schema read successfully',\n target: result.target,\n schema: result.schema,\n meta: result.meta,\n timings: result.timings,\n };\n}\n\nexport function createDbSchemaCommand(): Command {\n const command = new Command('schema');\n setCommandDescriptions(\n command,\n 'Inspect the live database schema',\n 'Reads the live database schema and prints it as a tree by default or as JSON with\\n' +\n '--json. This command is always read-only and never writes files. To save machine-\\n' +\n 'readable output, use shell redirection, for example `prisma-next db schema --json > schema.json`.',\n );\n setCommandExamples(command, [\n 'prisma-next db schema --db $DATABASE_URL',\n 'prisma-next db schema --db $DATABASE_URL --json',\n 'prisma-next db schema --db $DATABASE_URL --json > schema.json',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: InspectLiveSchemaOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const startTime = Date.now();\n\n const result = await inspectLiveSchema(options, flags, ui, startTime, {\n commandName: 'db schema',\n description: 'Inspect the live database schema',\n url: 'https://pris.ly/db-schema',\n });\n\n const exitCode = handleResult(result, flags, ui, (value) => {\n const introspectResult = toIntrospectSchemaResult(value);\n\n if (flags.json) {\n ui.output(formatIntrospectJson(introspectResult));\n return;\n }\n\n const output = formatIntrospectOutput(introspectResult, value.schemaView, flags);\n if (output) {\n ui.log(output);\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":";;;;;;;AAiBA,SAAS,yBACP,QACiC;CACjC,OAAO;EACL,IAAI;EACJ,SAAS;EACT,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,MAAM,OAAO;EACb,SAAS,OAAO;EACjB;;AAGH,SAAgB,wBAAiC;CAC/C,MAAM,UAAU,IAAI,QAAQ,SAAS;CACrC,uBACE,SACA,oCACA,0QAGD;CACD,mBAAmB,SAAS;EAC1B;EACA;EACA;EACD,CAAC;CACF,iBAAiB,QAAQ,CACtB,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,OAAO,YAAsC;EACnD,MAAM,QAAQ,iBAAiB,QAAQ;EACvC,MAAM,KAAK,IAAI,WAAW;GAAE,OAAO,MAAM;GAAO,aAAa,MAAM;GAAa,CAAC;EASjF,MAAM,WAAW,aAAa,MANT,kBAAkB,SAAS,OAAO,IAFrC,KAAK,KAE6C,EAAE;GACpE,aAAa;GACb,aAAa;GACb,KAAK;GACN,CAAC,EAEoC,OAAO,KAAK,UAAU;GAC1D,MAAM,mBAAmB,yBAAyB,MAAM;GAExD,IAAI,MAAM,MAAM;IACd,GAAG,OAAO,qBAAqB,iBAAiB,CAAC;IACjD;;GAGF,MAAM,SAAS,uBAAuB,kBAAkB,MAAM,YAAY,MAAM;GAChF,IAAI,QACF,GAAG,IAAI,OAAO;IAEhB;EAEF,QAAQ,KAAK,SAAS;GACtB;CAEJ,OAAO"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { _ as errorUnexpected, a as errorContractValidationFailed, c as errorDriverRequired, l as errorFileNotFound, o as errorDatabaseConnectionRequired, t as CliStructuredError } from "../cli-errors-D3_sMh2K.mjs";
|
|
3
|
-
import { t as
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, g as parseGlobalFlags, o as maskConnectionUrl, t as addGlobalOptions, y as formatStyledHeader } from "../command-helpers-BeZHkxV8.mjs";
|
|
4
|
+
import { t as createProgressAdapter } from "../progress-adapter-DFfvZcYL.mjs";
|
|
5
|
+
import { t as TerminalUI } from "../terminal-ui-C_hFNbAn.mjs";
|
|
6
|
+
import { t as handleResult } from "../result-handler-rmPVKIP2.mjs";
|
|
7
|
+
import { o as ContractValidationError, t as createControlClient } from "../client-qVH-rEgd.mjs";
|
|
8
|
+
import { a as formatSignJson, i as formatSchemaVerifyOutput, o as formatSignOutput, r as formatSchemaVerifyJson } from "../verify-CiwNWM9N.mjs";
|
|
8
9
|
import { Command } from "commander";
|
|
9
10
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
10
11
|
import { relative, resolve } from "pathe";
|
|
@@ -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 { 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 errorUnexpected,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n maskConnectionUrl,\n resolveContractPath,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\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, parseGlobalFlags } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ninterface DbSignOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: 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 options: DbSignOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<SignDatabaseResult, DbSignFailure>> {\n // Load config\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 // Output header\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n ];\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 // Load contract file\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 let contractJson: Record<string, unknown>;\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 // 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, ['prisma-next db sign --db $DATABASE_URL']);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: DbSignOptions) => {\n const flags = parseGlobalFlags(options);\n\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n\n const result = await executeDbSignCommand(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 { 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 errorUnexpected,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n maskConnectionUrl,\n resolveContractPath,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\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, parseGlobalFlags } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ninterface DbSignOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: 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 options: DbSignOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n): Promise<Result<SignDatabaseResult, DbSignFailure>> {\n // Load config\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 // Output header\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n ];\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 // Load contract file\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 let contractJson: Record<string, unknown>;\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 // 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, ['prisma-next db sign --db $DATABASE_URL']);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: DbSignOptions) => {\n const flags = parseGlobalFlags(options);\n\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n\n const result = await executeDbSignCommand(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":";;;iBA4KgB,qBAAA,CAAA,GAAyB,OAAA"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { _ as errorUnexpected, a as errorContractValidationFailed, f as errorMigrationPlanningFailed, n as ERROR_CODE_DESTRUCTIVE_CHANGES, p as errorRunnerFailed, s as errorDestructiveChanges, t as CliStructuredError } from "../cli-errors-D3_sMh2K.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { n as
|
|
2
|
+
import { d as setCommandDescriptions, f as setCommandExamples, g as parseGlobalFlags, l as resolveMigrationPaths, u as sanitizeErrorMessage } from "../command-helpers-BeZHkxV8.mjs";
|
|
3
|
+
import { t as TerminalUI } from "../terminal-ui-C_hFNbAn.mjs";
|
|
4
|
+
import { t as handleResult } from "../result-handler-rmPVKIP2.mjs";
|
|
5
|
+
import { o as ContractValidationError } from "../client-qVH-rEgd.mjs";
|
|
6
|
+
import { i as formatMigrationPlanOutput, n as formatMigrationApplyOutput, r as formatMigrationJson } from "../migrations-D_UJnpuW.mjs";
|
|
7
|
+
import { n as prepareMigrationContext, t as addMigrationCommandOptions } from "../migration-command-scaffold-B5dORFEv.mjs";
|
|
7
8
|
import { Command } from "commander";
|
|
8
9
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
9
10
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
@@ -72,6 +73,7 @@ async function executeDbUpdateCommand(options, flags, ui, startTime) {
|
|
|
72
73
|
storageHash: result.value.marker.storageHash,
|
|
73
74
|
...ifDefined("profileHash", result.value.marker.profileHash)
|
|
74
75
|
} : void 0),
|
|
76
|
+
...ifDefined("perSpace", result.value.perSpace),
|
|
75
77
|
summary: result.value.summary,
|
|
76
78
|
timings: { total: Date.now() - startTime }
|
|
77
79
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db-update.mjs","names":[],"sources":["../../src/commands/db-update.ts"],"sourcesContent":["import { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\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} 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 {\n formatMigrationApplyOutput,\n formatMigrationJson,\n formatMigrationPlanOutput,\n type MigrationCommandResult,\n} from '../utils/formatters/migrations';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport {\n addMigrationCommandOptions,\n prepareMigrationContext,\n} from '../utils/migration-command-scaffold';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ntype DbUpdateOptions = MigrationCommandOptions;\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 return errorRunnerFailed(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Inspect the reported conflict, reconcile schema drift if needed, then re-run `prisma-next db update`',\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, contractJson, dbConnection, onProgress, contractPathAbsolute } =\n ctxResult.value;\n const { migrationsDir } = resolveMigrationPaths(options.config, config);\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 // 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 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.action(async (options: DbUpdateOptions) => {\n const flags = parseGlobalFlags(options);\n const startTime = Date.now();\n\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\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
|
+
{"version":3,"file":"db-update.mjs","names":[],"sources":["../../src/commands/db-update.ts"],"sourcesContent":["import { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\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} 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 {\n formatMigrationApplyOutput,\n formatMigrationJson,\n formatMigrationPlanOutput,\n type MigrationCommandResult,\n} from '../utils/formatters/migrations';\nimport { type GlobalFlags, parseGlobalFlags } from '../utils/global-flags';\nimport {\n addMigrationCommandOptions,\n prepareMigrationContext,\n} from '../utils/migration-command-scaffold';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\n\ntype DbUpdateOptions = MigrationCommandOptions;\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 return errorRunnerFailed(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Inspect the reported conflict, reconcile schema drift if needed, then re-run `prisma-next db update`',\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, contractJson, dbConnection, onProgress, contractPathAbsolute } =\n ctxResult.value;\n const { migrationsDir } = resolveMigrationPaths(options.config, config);\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 // 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 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.action(async (options: DbUpdateOptions) => {\n const flags = parseGlobalFlags(options);\n const startTime = Date.now();\n\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\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,2 +1,2 @@
|
|
|
1
|
-
import { t as createDbVerifyCommand } from "../db-verify-
|
|
1
|
+
import { t as createDbVerifyCommand } from "../db-verify-C0y1PCO2.mjs";
|
|
2
2
|
export { createDbVerifyCommand };
|
|
@@ -1,34 +1,46 @@
|
|
|
1
|
+
import { T as MigrationApplyPathDecision, t as AggregatePerSpaceExecutionEntry } from "../types-D7x-IFLO.mjs";
|
|
1
2
|
import { Command } from "commander";
|
|
2
3
|
|
|
3
4
|
//#region src/commands/migration-apply.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Per-space breakdown of an apply run. The CLI command surfaces these
|
|
7
|
+
* for both the JSON shape (`appliedSpaces[]`) and the human-readable
|
|
8
|
+
* formatter (per-space block — same shape `db init` / `db update`
|
|
9
|
+
* use, M6 sub-spec § Output shape contract).
|
|
10
|
+
*/
|
|
4
11
|
interface MigrationApplyResult {
|
|
5
12
|
readonly ok: boolean;
|
|
13
|
+
/** Number of contract spaces that had non-zero pending operations applied. */
|
|
6
14
|
readonly migrationsApplied: number;
|
|
15
|
+
/** Total contract spaces visible in the aggregate (pending + already-up-to-date). */
|
|
7
16
|
readonly migrationsTotal: number;
|
|
17
|
+
/**
|
|
18
|
+
* Marker hash for the **app member** post-apply. Surfaced for
|
|
19
|
+
* back-compat with single-space callers; per-space markers live on
|
|
20
|
+
* `perSpace[].marker.storageHash`.
|
|
21
|
+
*/
|
|
8
22
|
readonly markerHash: string;
|
|
9
23
|
readonly applied: readonly {
|
|
24
|
+
readonly spaceId: string;
|
|
10
25
|
readonly dirName: string;
|
|
11
|
-
readonly
|
|
26
|
+
readonly migrationHash: string;
|
|
27
|
+
readonly from: string;
|
|
12
28
|
readonly to: string;
|
|
13
29
|
readonly operationsExecuted: number;
|
|
14
30
|
}[];
|
|
15
31
|
readonly summary: string;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
readonly to: string;
|
|
29
|
-
readonly invariants: readonly string[];
|
|
30
|
-
}[];
|
|
31
|
-
};
|
|
32
|
+
/**
|
|
33
|
+
* Per-space breakdown in canonical schedule order (extensions
|
|
34
|
+
* alphabetically, then app). Always present for the aggregate-walking
|
|
35
|
+
* apply path.
|
|
36
|
+
*/
|
|
37
|
+
readonly perSpace: readonly AggregatePerSpaceExecutionEntry[];
|
|
38
|
+
/**
|
|
39
|
+
* Path-decision data for the app member. Surfaced for back-compat
|
|
40
|
+
* with single-space callers (cli-journeys invariant tests).
|
|
41
|
+
* Absent for no-op applies where the app had nothing to do.
|
|
42
|
+
*/
|
|
43
|
+
readonly pathDecision?: MigrationApplyPathDecision;
|
|
32
44
|
readonly timings: {
|
|
33
45
|
readonly total: number;
|
|
34
46
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-apply.d.mts","names":[],"sources":["../../src/commands/migration-apply.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration-apply.d.mts","names":[],"sources":["../../src/commands/migration-apply.ts"],"mappings":";;;;;;AA0DA;;;;UAAiB,oBAAA;EAAA,SACN,EAAA;EAIA;EAAA,SAFA,iBAAA;EASA;EAAA,SAPA,eAAA;EASE;;;;;EAAA,SAHF,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;EA8NgC;;;;;EAAA,SAxNhC,QAAA,WAAmB,+BAAA;;;;;;WAMnB,YAAA,GAAe,0BAAA;EAAA,SACf,OAAA;IAAA,SACE,KAAA;EAAA;AAAA;AAAA,iBAgNG,2BAAA,CAAA,GAA+B,OAAA"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import { _ as errorUnexpected, c as errorDriverRequired, h as errorTargetMigrationNotSupported, m as errorRuntime, o as errorDatabaseConnectionRequired, t as CliStructuredError, v as mapMigrationToolsError } from "../cli-errors-D3_sMh2K.mjs";
|
|
3
|
-
import { t as
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import { t as
|
|
2
|
+
import { _ as errorUnexpected, a as errorContractValidationFailed, c as errorDriverRequired, h as errorTargetMigrationNotSupported, l as errorFileNotFound, m as errorRuntime, o as errorDatabaseConnectionRequired, t as CliStructuredError, v as mapMigrationToolsError } from "../cli-errors-D3_sMh2K.mjs";
|
|
3
|
+
import { a as loadMigrationPackages, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, g as parseGlobalFlags, l as resolveMigrationPaths, n as collectDeclaredInvariants, o as maskConnectionUrl, p as targetSupportsMigrations, t as addGlobalOptions, y as formatStyledHeader } from "../command-helpers-BeZHkxV8.mjs";
|
|
4
|
+
import { t as TerminalUI } from "../terminal-ui-C_hFNbAn.mjs";
|
|
5
|
+
import { t as handleResult } from "../result-handler-rmPVKIP2.mjs";
|
|
6
|
+
import { t as createControlClient } from "../client-qVH-rEgd.mjs";
|
|
7
|
+
import { t as formatMigrationApplyCommandOutput } from "../migrations-D_UJnpuW.mjs";
|
|
7
8
|
import { Command } from "commander";
|
|
8
9
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
9
10
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { MigrationToolsError, errorNoInvariantPath, errorUnknownInvariant } from "@prisma-next/migration-tools/errors";
|
|
11
|
+
import { readFile } from "node:fs/promises";
|
|
12
|
+
import { MigrationToolsError, errorUnknownInvariant } from "@prisma-next/migration-tools/errors";
|
|
13
13
|
import { readRefs, resolveRef } from "@prisma-next/migration-tools/refs";
|
|
14
14
|
//#region src/commands/migration-apply.ts
|
|
15
15
|
function mapApplyFailure(failure) {
|
|
@@ -19,19 +19,9 @@ function mapApplyFailure(failure) {
|
|
|
19
19
|
meta: failure.meta ?? {}
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
|
-
function packageToStep(pkg) {
|
|
23
|
-
return {
|
|
24
|
-
dirName: pkg.dirName,
|
|
25
|
-
from: pkg.metadata.from,
|
|
26
|
-
to: pkg.metadata.to,
|
|
27
|
-
toContract: pkg.metadata.toContract,
|
|
28
|
-
operations: pkg.ops,
|
|
29
|
-
providedInvariants: pkg.metadata.providedInvariants
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
22
|
async function executeMigrationApplyCommand(options, flags, ui, startTime) {
|
|
33
23
|
const config = await loadConfig(options.config);
|
|
34
|
-
const { configPath, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(options.config, config);
|
|
24
|
+
const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(options.config, config);
|
|
35
25
|
const dbConnection = options.db ?? config.db?.connection;
|
|
36
26
|
if (!dbConnection) return notOk(errorDatabaseConnectionRequired({
|
|
37
27
|
why: `Database connection is required for migration apply (set db.connection in ${configPath}, or pass --db <url>)`,
|
|
@@ -40,7 +30,6 @@ async function executeMigrationApplyCommand(options, flags, ui, startTime) {
|
|
|
40
30
|
if (!config.driver) return notOk(errorDriverRequired({ why: "Config.driver is required for migration apply" }));
|
|
41
31
|
if (!targetSupportsMigrations(config.target)) return notOk(errorTargetMigrationNotSupported({ why: `Target "${config.target.id}" does not support migrations` }));
|
|
42
32
|
let refEntry;
|
|
43
|
-
let envelopeHash;
|
|
44
33
|
const refName = options.ref;
|
|
45
34
|
if (refName) try {
|
|
46
35
|
refEntry = resolveRef(await readRefs(refsDir), refName);
|
|
@@ -48,15 +37,18 @@ async function executeMigrationApplyCommand(options, flags, ui, startTime) {
|
|
|
48
37
|
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
49
38
|
throw error;
|
|
50
39
|
}
|
|
51
|
-
|
|
52
|
-
|
|
40
|
+
const contractPathAbsolute = resolveContractPath(config);
|
|
41
|
+
let contractRaw;
|
|
42
|
+
try {
|
|
43
|
+
const contractContent = await readFile(contractPathAbsolute, "utf-8");
|
|
44
|
+
contractRaw = JSON.parse(contractContent);
|
|
53
45
|
} catch (error) {
|
|
54
|
-
|
|
55
|
-
why: `
|
|
46
|
+
if (error instanceof Error && error.code === "ENOENT") return notOk(errorFileNotFound(contractPathAbsolute, {
|
|
47
|
+
why: `Contract file not found at ${contractPathAbsolute}`,
|
|
56
48
|
fix: "Run `prisma-next contract emit` to generate a valid contract.json, then retry apply."
|
|
57
49
|
}));
|
|
50
|
+
return notOk(errorContractValidationFailed(`Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`, { where: { path: contractPathAbsolute } }));
|
|
58
51
|
}
|
|
59
|
-
const destinationHash = refEntry?.hash ?? envelopeHash;
|
|
60
52
|
if (!flags.json && !flags.quiet) {
|
|
61
53
|
const details = [{
|
|
62
54
|
label: "config",
|
|
@@ -82,9 +74,9 @@ async function executeMigrationApplyCommand(options, flags, ui, startTime) {
|
|
|
82
74
|
});
|
|
83
75
|
ui.stderr(header);
|
|
84
76
|
}
|
|
85
|
-
let
|
|
77
|
+
let appPackages;
|
|
86
78
|
try {
|
|
87
|
-
|
|
79
|
+
appPackages = await loadMigrationPackages(appMigrationsDir);
|
|
88
80
|
} catch (error) {
|
|
89
81
|
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
90
82
|
throw error;
|
|
@@ -98,11 +90,11 @@ async function executeMigrationApplyCommand(options, flags, ui, startTime) {
|
|
|
98
90
|
});
|
|
99
91
|
try {
|
|
100
92
|
await client.connect(dbConnection);
|
|
101
|
-
const marker = await client.readMarker();
|
|
102
93
|
if (refEntry && refEntry.invariants.length > 0) {
|
|
103
|
-
const
|
|
94
|
+
const appMarker = (await client.readAllMarkers()).get("app") ?? null;
|
|
95
|
+
const declared = collectDeclaredInvariants(appPackages.graph);
|
|
104
96
|
const known = new Set(declared);
|
|
105
|
-
for (const id of
|
|
97
|
+
for (const id of appMarker?.invariants ?? []) known.add(id);
|
|
106
98
|
const unknown = refEntry.invariants.filter((id) => !known.has(id));
|
|
107
99
|
if (unknown.length > 0) return notOk(mapMigrationToolsError(errorUnknownInvariant({
|
|
108
100
|
...ifDefined("refName", refName),
|
|
@@ -110,117 +102,31 @@ async function executeMigrationApplyCommand(options, flags, ui, startTime) {
|
|
|
110
102
|
declared: [...declared].sort()
|
|
111
103
|
})));
|
|
112
104
|
}
|
|
113
|
-
if (
|
|
114
|
-
if (marker?.storageHash) return notOk(errorRuntime("Database has state but no migrations exist", {
|
|
115
|
-
why: `The database marker hash "${marker.storageHash}" exists but no migrations were found in ${appMigrationsRelative}`,
|
|
116
|
-
fix: "Ensure the migrations directory is correct. If the database was managed with `db init` or `db update`, run `prisma-next db sign` to update the marker.",
|
|
117
|
-
meta: {
|
|
118
|
-
markerHash: marker.storageHash,
|
|
119
|
-
migrationsDir: appMigrationsRelative
|
|
120
|
-
}
|
|
121
|
-
}));
|
|
122
|
-
if (destinationHash !== EMPTY_CONTRACT_HASH) return notOk(errorRuntime("Current contract has no planned migrations", {
|
|
123
|
-
why: `No migrations were found in ${appMigrationsRelative}, but current contract hash is "${destinationHash}"`,
|
|
124
|
-
fix: "Run `prisma-next migration plan` to create a migration for the current contract.",
|
|
125
|
-
meta: {
|
|
126
|
-
destinationHash,
|
|
127
|
-
migrationsDir: appMigrationsRelative
|
|
128
|
-
}
|
|
129
|
-
}));
|
|
130
|
-
return ok({
|
|
131
|
-
ok: true,
|
|
132
|
-
migrationsApplied: 0,
|
|
133
|
-
migrationsTotal: 0,
|
|
134
|
-
markerHash: EMPTY_CONTRACT_HASH,
|
|
135
|
-
applied: [],
|
|
136
|
-
summary: "No migrations found",
|
|
137
|
-
timings: { total: Date.now() - startTime }
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
if (marker?.storageHash === EMPTY_CONTRACT_HASH) return notOk(errorRuntime("Database marker contains the empty sentinel hash", {
|
|
141
|
-
why: `The marker row exists but contains the empty sentinel value "${EMPTY_CONTRACT_HASH}". This should never happen — the marker should contain the hash of the last applied contract.`,
|
|
142
|
-
fix: "The marker is corrupted. Run `prisma-next db sign` to overwrite it with the correct contract hash, or drop and recreate the database.",
|
|
143
|
-
meta: { markerHash: EMPTY_CONTRACT_HASH }
|
|
144
|
-
}));
|
|
145
|
-
const markerHash = marker?.storageHash;
|
|
146
|
-
if (markerHash !== void 0 && !migrations.graph.nodes.has(markerHash)) return notOk(errorRuntime("Database marker does not match any known migration", {
|
|
147
|
-
why: `The database marker hash "${markerHash}" is not found in the migration history at ${appMigrationsRelative}`,
|
|
148
|
-
fix: "Ensure the migrations directory matches this database. If the database was managed with `db init` or `db update`, run `prisma-next db sign` to update the marker.",
|
|
149
|
-
meta: {
|
|
150
|
-
markerHash,
|
|
151
|
-
knownNodes: [...migrations.graph.nodes]
|
|
152
|
-
}
|
|
153
|
-
}));
|
|
154
|
-
if (!migrations.graph.nodes.has(destinationHash)) return notOk(errorRuntime("Current contract has no planned migration path", {
|
|
155
|
-
why: `Current contract hash "${destinationHash}" is not present in the migration history at ${appMigrationsRelative}`,
|
|
156
|
-
fix: "Run `prisma-next migration plan` to create a migration for the current contract, then re-run apply.",
|
|
157
|
-
meta: {
|
|
158
|
-
destinationHash,
|
|
159
|
-
knownNodes: [...migrations.graph.nodes]
|
|
160
|
-
}
|
|
161
|
-
}));
|
|
162
|
-
const originHash = markerHash ?? EMPTY_CONTRACT_HASH;
|
|
163
|
-
const appliedInvariants = new Set(marker?.invariants ?? []);
|
|
164
|
-
const effectiveRequired = new Set((refEntry?.invariants ?? []).filter((id) => !appliedInvariants.has(id)));
|
|
165
|
-
const outcome = findPathWithDecision(migrations.graph, originHash, destinationHash, {
|
|
166
|
-
...ifDefined("refName", refName),
|
|
167
|
-
required: effectiveRequired
|
|
168
|
-
});
|
|
169
|
-
if (outcome.kind === "unsatisfiable") return notOk(mapMigrationToolsError(errorNoInvariantPath({
|
|
170
|
-
...ifDefined("refName", refName),
|
|
171
|
-
required: [...effectiveRequired].sort(),
|
|
172
|
-
missing: outcome.missing,
|
|
173
|
-
structuralPath: outcome.structuralPath.map(toStructuralEdge)
|
|
174
|
-
})));
|
|
175
|
-
if (outcome.kind === "unreachable") return notOk(errorRuntime("No migration path from current state to target", {
|
|
176
|
-
why: `Cannot find a path from "${originHash}" to target "${destinationHash}"`,
|
|
177
|
-
fix: "Check the migration history for gaps or inconsistencies.",
|
|
178
|
-
meta: {
|
|
179
|
-
markerHash: originHash,
|
|
180
|
-
destinationHash
|
|
181
|
-
}
|
|
182
|
-
}));
|
|
183
|
-
const pathDecision = toPathDecisionResult(outcome.decision);
|
|
184
|
-
if (outcome.decision.selectedPath.length === 0) return ok({
|
|
185
|
-
ok: true,
|
|
186
|
-
migrationsApplied: 0,
|
|
187
|
-
migrationsTotal: 0,
|
|
188
|
-
markerHash: originHash,
|
|
189
|
-
applied: [],
|
|
190
|
-
summary: "Already up to date",
|
|
191
|
-
pathDecision,
|
|
192
|
-
timings: { total: Date.now() - startTime }
|
|
193
|
-
});
|
|
194
|
-
const bundleByDir = new Map(migrations.bundles.map((b) => [b.dirName, b]));
|
|
195
|
-
const pendingMigrations = [];
|
|
196
|
-
for (const migration of outcome.decision.selectedPath) {
|
|
197
|
-
const pkg = bundleByDir.get(migration.dirName);
|
|
198
|
-
if (!pkg) return notOk(errorRuntime(`Migration package not found: ${migration.dirName}`, {
|
|
199
|
-
why: `The migration directory for path segment ${migration.from} → ${migration.to} was not found`,
|
|
200
|
-
fix: "Ensure all migration directories are present and intact."
|
|
201
|
-
}));
|
|
202
|
-
pendingMigrations.push(packageToStep(pkg));
|
|
203
|
-
}
|
|
204
|
-
if (!flags.quiet && !flags.json) for (const migration of pendingMigrations) ui.step(`Pending ${migration.dirName}`);
|
|
105
|
+
if (!flags.quiet && !flags.json) ui.step("Loading contract spaces…");
|
|
205
106
|
const applyResult = await client.migrationApply({
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
107
|
+
contract: contractRaw,
|
|
108
|
+
migrationsDir,
|
|
109
|
+
appMigrationPackages: appPackages.bundles,
|
|
110
|
+
...ifDefined("refHash", refEntry?.hash),
|
|
111
|
+
...refEntry?.invariants ? { refInvariants: refEntry.invariants } : {},
|
|
112
|
+
...refEntry !== void 0 ? ifDefined("refName", refName) : {}
|
|
209
113
|
});
|
|
210
114
|
if (!applyResult.ok) return notOk(mapApplyFailure(applyResult.failure));
|
|
211
115
|
const { value } = applyResult;
|
|
212
116
|
return ok({
|
|
213
117
|
ok: true,
|
|
214
118
|
migrationsApplied: value.migrationsApplied,
|
|
215
|
-
migrationsTotal:
|
|
119
|
+
migrationsTotal: value.perSpace.length,
|
|
216
120
|
markerHash: value.markerHash,
|
|
217
121
|
applied: value.applied,
|
|
218
122
|
summary: value.summary,
|
|
219
|
-
|
|
123
|
+
perSpace: value.perSpace,
|
|
124
|
+
...ifDefined("pathDecision", value.pathDecision),
|
|
220
125
|
timings: { total: Date.now() - startTime }
|
|
221
126
|
});
|
|
222
127
|
} catch (error) {
|
|
223
128
|
if (CliStructuredError.is(error)) return notOk(error);
|
|
129
|
+
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
224
130
|
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Unexpected error during migration apply: ${error instanceof Error ? error.message : String(error)}` }));
|
|
225
131
|
} finally {
|
|
226
132
|
await client.close();
|
|
@@ -228,9 +134,9 @@ async function executeMigrationApplyCommand(options, flags, ui, startTime) {
|
|
|
228
134
|
}
|
|
229
135
|
function createMigrationApplyCommand() {
|
|
230
136
|
const command = new Command("apply");
|
|
231
|
-
setCommandDescriptions(command, "Apply planned migrations to the database", "
|
|
137
|
+
setCommandDescriptions(command, "Apply planned migrations to 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 —\nno introspection, no synth. Each space's marker advances inside its\ntransaction; per-space failure rolls back every space's writes.");
|
|
232
138
|
setCommandExamples(command, ["prisma-next migration apply --db $DATABASE_URL"]);
|
|
233
|
-
addGlobalOptions(command).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--ref <name>", "
|
|
139
|
+
addGlobalOptions(command).option("--db <url>", "Database connection string").option("--config <path>", "Path to prisma-next.config.ts").option("--ref <name>", "App-space target ref name from migrations/app/refs/").action(async (options) => {
|
|
234
140
|
const flags = parseGlobalFlags(options);
|
|
235
141
|
const startTime = Date.now();
|
|
236
142
|
const ui = new TerminalUI({
|