prisma-next 0.11.0-dev.46 → 0.11.0-dev.48
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 +9 -9
- package/dist/{client-a5NJce0-.mjs → client-5uvDppD8.mjs} +20 -18
- package/dist/client-5uvDppD8.mjs.map +1 -0
- package/dist/{command-helpers-yLuA78TP.mjs → command-helpers-CI8P5Xyd.mjs} +4 -4
- package/dist/{command-helpers-yLuA78TP.mjs.map → command-helpers-CI8P5Xyd.mjs.map} +1 -1
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.mjs +5 -5
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-sign.mjs +3 -3
- package/dist/commands/db-update.mjs +5 -5
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +1 -1
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +42 -37
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.d.mts +4 -3
- package/dist/commands/migration-check.d.mts.map +1 -1
- package/dist/commands/migration-check.mjs +1 -279
- package/dist/commands/migration-graph.d.mts +1 -1
- package/dist/commands/migration-graph.mjs +2 -2
- package/dist/commands/migration-list.d.mts +2 -2
- package/dist/commands/migration-list.mjs +1 -1
- package/dist/commands/migration-log.mjs +2 -2
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +32 -30
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +4 -55
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +62 -152
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +5 -40
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +91 -64
- package/dist/commands/migration-status.mjs.map +1 -1
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.mjs +2 -2
- package/dist/{contract-emit-FtDVFs2Q.mjs → contract-emit-DmBG2Nnc.mjs} +2 -2
- package/dist/{contract-emit-FtDVFs2Q.mjs.map → contract-emit-DmBG2Nnc.mjs.map} +1 -1
- package/dist/{contract-infer-CVMuoJKk.mjs → contract-infer-BSWFKgI1.mjs} +3 -3
- package/dist/{contract-infer-CVMuoJKk.mjs.map → contract-infer-BSWFKgI1.mjs.map} +1 -1
- package/dist/contract-space-aggregate-loader-CVHGuA35.mjs +170 -0
- package/dist/contract-space-aggregate-loader-CVHGuA35.mjs.map +1 -0
- package/dist/{db-verify-B00o3LuC.mjs → db-verify-BzpwFyLg.mjs} +4 -4
- package/dist/{db-verify-B00o3LuC.mjs.map → db-verify-BzpwFyLg.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +1 -1
- package/dist/exports/control-api.mjs +1 -1
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/extension-pack-inputs-BiY86HbQ.mjs +62 -0
- package/dist/extension-pack-inputs-BiY86HbQ.mjs.map +1 -0
- package/dist/{global-flags-Dvibm2yu.d.mts → global-flags-DWsQ6SSI.d.mts} +1 -1
- package/dist/{global-flags-Dvibm2yu.d.mts.map → global-flags-DWsQ6SSI.d.mts.map} +1 -1
- package/dist/{graph-render-DJVv0_uf.mjs → graph-render-D2FnLpuK.mjs} +1 -1
- package/dist/{graph-render-DJVv0_uf.mjs.map → graph-render-D2FnLpuK.mjs.map} +1 -1
- package/dist/{init-BKgB6EKw.mjs → init-DEssiJ8j.mjs} +3 -3
- package/dist/{init-BKgB6EKw.mjs.map → init-DEssiJ8j.mjs.map} +1 -1
- package/dist/{inspect-live-schema-BXUd6RfS.mjs → inspect-live-schema-DlBM84nh.mjs} +3 -3
- package/dist/{inspect-live-schema-BXUd6RfS.mjs.map → inspect-live-schema-DlBM84nh.mjs.map} +1 -1
- package/dist/migration-check-CzLbAqIQ.mjs +341 -0
- package/dist/migration-check-CzLbAqIQ.mjs.map +1 -0
- package/dist/{migration-command-scaffold-3l3EdmSD.mjs → migration-command-scaffold-Bp8UHnvJ.mjs} +3 -3
- package/dist/{migration-command-scaffold-3l3EdmSD.mjs.map → migration-command-scaffold-Bp8UHnvJ.mjs.map} +1 -1
- package/dist/{migration-list-DopkAG7L.mjs → migration-list-C2xnaYsT.mjs} +2 -2
- package/dist/{migration-list-DopkAG7L.mjs.map → migration-list-C2xnaYsT.mjs.map} +1 -1
- package/dist/{migration-list-graph-render-C-daUZLU.d.mts → migration-list-graph-render-DKw1AT-e.d.mts} +1 -1
- package/dist/migration-list-graph-render-DKw1AT-e.d.mts.map +1 -0
- package/dist/{migration-plan-BHoeET4O.mjs → migration-plan-BLvOmNCu.mjs} +6 -5
- package/dist/{migration-plan-BHoeET4O.mjs.map → migration-plan-BLvOmNCu.mjs.map} +1 -1
- package/dist/{migration-types-BXWvz12q.d.mts → migration-types-q64xAI_J.d.mts} +1 -1
- package/dist/{migration-types-BXWvz12q.d.mts.map → migration-types-q64xAI_J.d.mts.map} +1 -1
- package/dist/{migrations-D-UCOGtk.mjs → migrations-vzQt9LI2.mjs} +3 -13
- package/dist/migrations-vzQt9LI2.mjs.map +1 -0
- package/dist/{output-CUIdfYo5.mjs → output-B60Gw5fu.mjs} +1 -1
- package/dist/{output-CUIdfYo5.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
- package/dist/{ref-advancement-CHJ_8HxQ.mjs → ref-advancement-DRh5Nquq.mjs} +1 -1
- package/dist/{ref-advancement-CHJ_8HxQ.mjs.map → ref-advancement-DRh5Nquq.mjs.map} +1 -1
- package/dist/{types-UWB2-rrw.d.mts → types-CEtm6v6a.d.mts} +1 -8
- package/dist/types-CEtm6v6a.d.mts.map +1 -0
- package/dist/{verify-9gDJz6cm.mjs → verify-ktSRQvIS.mjs} +2 -2
- package/dist/{verify-9gDJz6cm.mjs.map → verify-ktSRQvIS.mjs.map} +1 -1
- package/package.json +11 -11
- package/dist/client-a5NJce0-.mjs.map +0 -1
- package/dist/commands/migration-check.mjs.map +0 -1
- package/dist/contract-space-aggregate-loader-EVU3n9YE.mjs +0 -160
- package/dist/contract-space-aggregate-loader-EVU3n9YE.mjs.map +0 -1
- package/dist/migration-list-graph-render-C-daUZLU.d.mts.map +0 -1
- package/dist/migrations-D-UCOGtk.mjs.map +0 -1
- package/dist/types-UWB2-rrw.d.mts.map +0 -1
|
@@ -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":";;;;UAgEiB,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,+BAAA;EAAA,SACnB,YAAA,GAAe,0BAA0B;EAAA,SACzC,OAAA;IAAA,SACE,KAAA;EAAA;EAAA,SAEF,WAAA;IAAA,SAAyB,IAAA;IAAA,SAAuB,IAAA;EAAA;AAAA;AAAA,iBAsS3C,oBAAA,CAAA,GAAwB,OAAO"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { A as mapRefResolutionError, C as errorRuntime, E as errorTargetMigrationNotSupported, O as errorUnexpected, _ as errorPathUnreachable, a as errorContractValidationFailed, c as errorDriverRequired, k as mapMigrationToolsError, l as errorFileNotFound, o as errorDatabaseConnectionRequired, p as errorMarkerMismatch, t as CliStructuredError } from "../cli-errors-DFF1LlfU.mjs";
|
|
3
|
-
import { A as formatStyledHeader,
|
|
4
|
-
import { t as createControlClient } from "../client-
|
|
5
|
-
import { t as
|
|
6
|
-
import {
|
|
3
|
+
import { A as formatStyledHeader, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, m as targetSupportsMigrations, n as collectDeclaredInvariants, o as maskConnectionUrl, t as addGlobalOptions, v as parseGlobalFlagsOrExit, w as handleResult, y as createTerminalUI } from "../command-helpers-CI8P5Xyd.mjs";
|
|
4
|
+
import { t as createControlClient } from "../client-5uvDppD8.mjs";
|
|
5
|
+
import { t as toDeclaredExtensionsFromRaw } from "../extension-pack-inputs-BiY86HbQ.mjs";
|
|
6
|
+
import { n as loadContractSpaceAggregateForCli, r as refuseContractSpaceIntegrity } from "../contract-space-aggregate-loader-CVHGuA35.mjs";
|
|
7
|
+
import { t as formatMigrationApplyCommandOutput } from "../migrations-vzQt9LI2.mjs";
|
|
8
|
+
import { i as readContractIR, r as executeRefAdvancement } from "../ref-advancement-DRh5Nquq.mjs";
|
|
7
9
|
import { Command } from "commander";
|
|
8
10
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
9
11
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
@@ -25,7 +27,7 @@ function mapApplyFailure(failure) {
|
|
|
25
27
|
}
|
|
26
28
|
async function executeMigrateCommand(options, flags, ui, startTime) {
|
|
27
29
|
const config = await loadConfig(options.config);
|
|
28
|
-
const { configPath, migrationsDir,
|
|
30
|
+
const { configPath, migrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(options.config, config);
|
|
29
31
|
const dbConnection = options.db ?? config.db?.connection;
|
|
30
32
|
if (!dbConnection) return notOk(errorDatabaseConnectionRequired({
|
|
31
33
|
why: `Database connection is required for migrate (set db.connection in ${configPath}, or pass --db <url>)`,
|
|
@@ -33,27 +35,7 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
|
|
|
33
35
|
}));
|
|
34
36
|
if (!config.driver) return notOk(errorDriverRequired({ why: "Config.driver is required for migrate" }));
|
|
35
37
|
if (!targetSupportsMigrations(config.target)) return notOk(errorTargetMigrationNotSupported({ why: `Target "${config.target.id}" does not support migrations` }));
|
|
36
|
-
let refEntry;
|
|
37
38
|
const toArg = options.to;
|
|
38
|
-
if (toArg) try {
|
|
39
|
-
const refs = await readRefs(refsDir);
|
|
40
|
-
const { graph } = await loadMigrationPackages(appMigrationsDir);
|
|
41
|
-
const refResult = parseContractRef(toArg, {
|
|
42
|
-
graph,
|
|
43
|
-
refs
|
|
44
|
-
});
|
|
45
|
-
if (!refResult.ok) return notOk(mapRefResolutionError(refResult.failure));
|
|
46
|
-
if (refResult.value.provenance.kind === "ref") {
|
|
47
|
-
const resolved = refs[refResult.value.provenance.refName];
|
|
48
|
-
if (resolved) refEntry = resolved;
|
|
49
|
-
} else refEntry = {
|
|
50
|
-
hash: refResult.value.hash,
|
|
51
|
-
invariants: []
|
|
52
|
-
};
|
|
53
|
-
} catch (error) {
|
|
54
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
55
|
-
throw error;
|
|
56
|
-
}
|
|
57
39
|
const stack = createControlStack(config);
|
|
58
40
|
const familyInstance = config.family.create(stack);
|
|
59
41
|
const contractPathAbsolute = resolveContractPath(config);
|
|
@@ -73,6 +55,36 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
|
|
|
73
55
|
} catch (error) {
|
|
74
56
|
return notOk(errorContractValidationFailed(`Contract at ${contractPathAbsolute} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`, { where: { path: contractPathAbsolute } }));
|
|
75
57
|
}
|
|
58
|
+
const loadedAggregate = await loadContractSpaceAggregateForCli({
|
|
59
|
+
targetId: config.target.targetId,
|
|
60
|
+
migrationsDir,
|
|
61
|
+
appContract: contractRaw,
|
|
62
|
+
extensionPacks: config.extensionPacks ?? [],
|
|
63
|
+
deserializeContract: (json) => familyInstance.deserializeContract(json)
|
|
64
|
+
});
|
|
65
|
+
if (!loadedAggregate.ok) return notOk(loadedAggregate.failure);
|
|
66
|
+
const aggregate = loadedAggregate.value;
|
|
67
|
+
const integrityFailure = refuseContractSpaceIntegrity(aggregate, {
|
|
68
|
+
declaredExtensions: toDeclaredExtensionsFromRaw(config.extensionPacks ?? []),
|
|
69
|
+
checkContracts: true
|
|
70
|
+
});
|
|
71
|
+
if (integrityFailure) return notOk(integrityFailure);
|
|
72
|
+
let refEntry;
|
|
73
|
+
if (toArg) {
|
|
74
|
+
const refs = await readRefs(refsDir);
|
|
75
|
+
const refResult = parseContractRef(toArg, {
|
|
76
|
+
graph: aggregate.app.graph(),
|
|
77
|
+
refs
|
|
78
|
+
});
|
|
79
|
+
if (!refResult.ok) return notOk(mapRefResolutionError(refResult.failure));
|
|
80
|
+
if (refResult.value.provenance.kind === "ref") {
|
|
81
|
+
const resolved = refs[refResult.value.provenance.refName];
|
|
82
|
+
if (resolved) refEntry = resolved;
|
|
83
|
+
} else refEntry = {
|
|
84
|
+
hash: refResult.value.hash,
|
|
85
|
+
invariants: []
|
|
86
|
+
};
|
|
87
|
+
}
|
|
76
88
|
if (!flags.json && !flags.quiet) {
|
|
77
89
|
const details = [{
|
|
78
90
|
label: "config",
|
|
@@ -98,13 +110,8 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
|
|
|
98
110
|
});
|
|
99
111
|
ui.stderr(header);
|
|
100
112
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
appPackages = await loadMigrationPackages(appMigrationsDir);
|
|
104
|
-
} catch (error) {
|
|
105
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
106
|
-
throw error;
|
|
107
|
-
}
|
|
113
|
+
const appGraph = aggregate.app.graph();
|
|
114
|
+
const appBundles = aggregate.app.packages;
|
|
108
115
|
const client = createControlClient({
|
|
109
116
|
family: config.family,
|
|
110
117
|
target: config.target,
|
|
@@ -115,10 +122,9 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
|
|
|
115
122
|
try {
|
|
116
123
|
await client.connect(dbConnection);
|
|
117
124
|
const appMarker = (await client.readAllMarkers()).get("app") ?? null;
|
|
118
|
-
|
|
119
|
-
if (appMarker !== null && !isGraphNode(appMarker.storageHash, graph)) return notOk(errorMarkerMismatch(appMarker.storageHash, [...graph.nodes].sort(), findLatestMigration(graph)?.to ?? null));
|
|
125
|
+
if (appMarker !== null && !isGraphNode(appMarker.storageHash, appGraph)) return notOk(errorMarkerMismatch(appMarker.storageHash, [...appGraph.nodes].sort(), findLatestMigration(appGraph)?.to ?? null));
|
|
120
126
|
if (refEntry && refEntry.invariants.length > 0) {
|
|
121
|
-
const declared = collectDeclaredInvariants(
|
|
127
|
+
const declared = collectDeclaredInvariants(appGraph);
|
|
122
128
|
const known = new Set(declared);
|
|
123
129
|
for (const id of appMarker?.invariants ?? []) known.add(id);
|
|
124
130
|
const unknown = refEntry.invariants.filter((id) => !known.has(id));
|
|
@@ -132,7 +138,6 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
|
|
|
132
138
|
const applyResult = await client.migrationApply({
|
|
133
139
|
contract: contractRaw,
|
|
134
140
|
migrationsDir,
|
|
135
|
-
appMigrationPackages: appPackages.bundles,
|
|
136
141
|
...ifDefined("refHash", refEntry?.hash),
|
|
137
142
|
...refEntry?.invariants ? { refInvariants: refEntry.invariants } : {},
|
|
138
143
|
...refEntry !== void 0 ? ifDefined("refName", toArg) : {}
|
|
@@ -144,7 +149,7 @@ async function executeMigrateCommand(options, flags, ui, startTime) {
|
|
|
144
149
|
let contractJsonPathForSnapshot = contractPathAbsolute;
|
|
145
150
|
let contractJsonForSnapshot = JSON.parse(contractContent);
|
|
146
151
|
if (toArg && refEntry) {
|
|
147
|
-
const matchingBundle =
|
|
152
|
+
const matchingBundle = appBundles.find((p) => p.metadata.to === refEntry.hash);
|
|
148
153
|
if (matchingBundle) {
|
|
149
154
|
const endContractPath = join(matchingBundle.dirPath, "end-contract.json");
|
|
150
155
|
contractJsonPathForSnapshot = endContractPath;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.mjs","names":[],"sources":["../../src/commands/migrate.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { errorUnknownInvariant, MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findLatestMigration, isGraphNode } from '@prisma-next/migration-tools/migration-graph';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type {\n AggregatePerSpaceExecutionEntry,\n MigrationApplyFailure,\n MigrationApplyPathDecision,\n} from '../control-api/types';\nimport {\n CliStructuredError,\n type CliStructuredError as CliStructuredErrorType,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorMarkerMismatch,\n errorPathUnreachable,\n errorRuntime,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n collectDeclaredInvariants,\n loadMigrationPackages,\n maskConnectionUrl,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n targetSupportsMigrations,\n} from '../utils/command-helpers';\nimport { formatMigrationApplyCommandOutput } from '../utils/formatters/migrations';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { executeRefAdvancement, readContractIR } from '../utils/ref-advancement';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrateCommandOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly to?: string;\n readonly advanceRef?: string;\n}\n\nexport interface MigrateResult {\n readonly ok: boolean;\n readonly migrationsApplied: number;\n readonly migrationsTotal: number;\n readonly markerHash: string;\n readonly applied: readonly {\n readonly spaceId: string;\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly operationsExecuted: number;\n }[];\n readonly summary: string;\n readonly perSpace: readonly AggregatePerSpaceExecutionEntry[];\n readonly pathDecision?: MigrationApplyPathDecision;\n readonly timings: {\n readonly total: number;\n };\n readonly advancedRef?: { readonly name: string; readonly hash: string } | null;\n}\n\nfunction mapApplyFailure(failure: MigrationApplyFailure): CliStructuredErrorType {\n if (failure.code === 'MIGRATION_PATH_NOT_FOUND') {\n return errorPathUnreachable(failure);\n }\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Fix the issue and re-run `prisma-next migrate --to <contract>` — previously applied migrations are preserved.',\n meta: failure.meta ?? {},\n });\n}\n\nasync function executeMigrateCommand(\n options: MigrateCommandOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrateResult, CliStructuredErrorType>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative, refsDir } =\n resolveMigrationPaths(options.config, config);\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for migrate (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migrate',\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: 'Config.driver is required for migrate',\n }),\n );\n }\n\n if (!targetSupportsMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n let refEntry: RefEntry | undefined;\n const toArg = options.to;\n\n if (toArg) {\n try {\n const refs = await readRefs(refsDir);\n const { graph } = await loadMigrationPackages(appMigrationsDir);\n const refResult = parseContractRef(toArg, { graph, refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n if (refResult.value.provenance.kind === 'ref') {\n const resolved = refs[refResult.value.provenance.refName];\n if (resolved) refEntry = resolved;\n } else {\n refEntry = { hash: refResult.value.hash, invariants: [] };\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n }\n\n // Construct the family instance up-front so the on-disk contract read\n // crosses the serializer seam (`familyInstance.deserializeContract`) at\n // the read site. The downstream `client.migrationApply({ contract })`\n // re-validates internally (no harm — validation is idempotent), but\n // closing the gap at the read site is what makes the cast-pattern\n // lint enforceable and matches the other CLI commands. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n const contractPathAbsolute = resolveContractPath(config);\n let contractRaw: Contract;\n let contractContent: string;\n try {\n contractContent = 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 a valid contract.json, then retry.',\n }),\n );\n }\n return notOk(\n errorContractValidationFailed(\n `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n try {\n contractRaw = familyInstance.deserializeContract(JSON.parse(contractContent) as unknown);\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract at ${contractPathAbsolute} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ];\n if (typeof dbConnection === 'string') {\n details.push({\n label: 'database',\n value: maskConnectionUrl(dbConnection),\n });\n }\n if (toArg) {\n details.push({ label: 'to', value: toArg });\n }\n const header = formatStyledHeader({\n command: 'migrate',\n description: 'Apply planned migrations to advance the database',\n url: 'https://pris.ly/migrate',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n let appPackages: Awaited<ReturnType<typeof loadMigrationPackages>>;\n try {\n appPackages = await loadMigrationPackages(appMigrationsDir);\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n try {\n await client.connect(dbConnection);\n\n const allMarkers = await client.readAllMarkers();\n const appMarker = allMarkers.get('app') ?? null;\n const { graph } = appPackages;\n\n if (appMarker !== null && !isGraphNode(appMarker.storageHash, graph)) {\n return notOk(\n errorMarkerMismatch(\n appMarker.storageHash,\n [...graph.nodes].sort(),\n findLatestMigration(graph)?.to ?? null,\n ),\n );\n }\n\n if (refEntry && refEntry.invariants.length > 0) {\n const declared = collectDeclaredInvariants(appPackages.graph);\n const known = new Set<string>(declared);\n for (const id of appMarker?.invariants ?? []) known.add(id);\n const unknown = refEntry.invariants.filter((id) => !known.has(id));\n if (unknown.length > 0) {\n return notOk(\n mapMigrationToolsError(\n errorUnknownInvariant({\n ...ifDefined('refName', toArg),\n unknown,\n declared: [...declared].sort(),\n }),\n ),\n );\n }\n }\n\n if (!flags.quiet && !flags.json) {\n ui.step('Loading contract spaces…');\n }\n\n const applyResult = await client.migrationApply({\n contract: contractRaw,\n migrationsDir,\n appMigrationPackages: appPackages.bundles,\n ...ifDefined('refHash', refEntry?.hash),\n ...(refEntry?.invariants ? { refInvariants: refEntry.invariants } : {}),\n ...(refEntry !== undefined ? ifDefined('refName', toArg) : {}),\n });\n\n if (!applyResult.ok) {\n return notOk(mapApplyFailure(applyResult.failure));\n }\n\n const { value } = applyResult;\n\n let advancedRef: { name: string; hash: string } | null = null;\n if (options.advanceRef !== undefined) {\n let contractJsonPathForSnapshot = contractPathAbsolute;\n let contractJsonForSnapshot: Record<string, unknown> = JSON.parse(contractContent) as Record<\n string,\n unknown\n >;\n if (toArg && refEntry) {\n const matchingBundle = appPackages.bundles.find((p) => p.metadata.to === refEntry.hash);\n if (matchingBundle) {\n const endContractPath = join(matchingBundle.dirPath, 'end-contract.json');\n contractJsonPathForSnapshot = endContractPath;\n try {\n const raw = await readFile(endContractPath, 'utf-8');\n contractJsonForSnapshot = JSON.parse(raw) as Record<string, unknown>;\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(endContractPath, {\n why: `Bundle end-contract not found at ${endContractPath}`,\n fix: 'Re-emit the migration bundle or pick a different --to target.',\n }),\n );\n }\n throw error;\n }\n }\n }\n try {\n const contractIR = await readContractIR(\n contractJsonForSnapshot,\n contractJsonPathForSnapshot,\n );\n advancedRef = await executeRefAdvancement(\n refsDir,\n options.advanceRef,\n value.markerHash,\n contractIR,\n );\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n }\n\n return ok({\n ok: true,\n migrationsApplied: value.migrationsApplied,\n migrationsTotal: value.perSpace.length,\n markerHash: value.markerHash,\n applied: value.applied,\n summary: value.summary,\n perSpace: value.perSpace,\n ...ifDefined('pathDecision', value.pathDecision),\n timings: { total: Date.now() - startTime },\n advancedRef,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Unexpected error during migrate: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrateCommand(): Command {\n const command = new Command('migrate');\n setCommandDescriptions(\n command,\n 'Apply planned migrations to advance the database',\n 'Walks every contract space (app + extensions) and applies pending\\n' +\n 'on-disk migrations in canonical order (extensions alphabetically,\\n' +\n 'then app). Graph-walks the on-disk migration graph for every space.\\n' +\n 'Use --to to target a specific contract (hash, ref name, migration dir).',\n );\n setCommandExamples(command, [\n 'prisma-next migrate --db $DATABASE_URL',\n 'prisma-next migrate --to production --db $DATABASE_URL',\n 'prisma-next migrate --to sha256:abc123 --db $DATABASE_URL',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option(\n '--to <contract>',\n 'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option('--advance-ref <name>', 'Advance the named ref to the post-apply marker after success')\n .action(async (options: MigrateCommandOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const startTime = Date.now();\n\n const ui = createTerminalUI(flags);\n\n const result = await executeMigrateCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (migrateResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(migrateResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationApplyCommandOutput(migrateResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migrate.mjs","names":[],"sources":["../../src/commands/migrate.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { createControlStack } from '@prisma-next/framework-components/control';\nimport { errorUnknownInvariant, MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { findLatestMigration, isGraphNode } from '@prisma-next/migration-tools/migration-graph';\nimport { parseContractRef } from '@prisma-next/migration-tools/ref-resolution';\nimport type { RefEntry } from '@prisma-next/migration-tools/refs';\nimport { readRefs } from '@prisma-next/migration-tools/refs';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type {\n AggregatePerSpaceExecutionEntry,\n MigrationApplyFailure,\n MigrationApplyPathDecision,\n} from '../control-api/types';\nimport {\n CliStructuredError,\n type CliStructuredError as CliStructuredErrorType,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorMarkerMismatch,\n errorPathUnreachable,\n errorRuntime,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n mapRefResolutionError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n collectDeclaredInvariants,\n maskConnectionUrl,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n targetSupportsMigrations,\n} from '../utils/command-helpers';\nimport {\n loadContractSpaceAggregateForCli,\n refuseContractSpaceIntegrity,\n} from '../utils/contract-space-aggregate-loader';\nimport { toDeclaredExtensionsFromRaw } from '../utils/extension-pack-inputs';\nimport { formatMigrationApplyCommandOutput } from '../utils/formatters/migrations';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { type GlobalFlags, parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { executeRefAdvancement, readContractIR } from '../utils/ref-advancement';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI, type TerminalUI } from '../utils/terminal-ui';\n\ninterface MigrateCommandOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n readonly to?: string;\n readonly advanceRef?: string;\n}\n\nexport interface MigrateResult {\n readonly ok: boolean;\n readonly migrationsApplied: number;\n readonly migrationsTotal: number;\n readonly markerHash: string;\n readonly applied: readonly {\n readonly spaceId: string;\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly operationsExecuted: number;\n }[];\n readonly summary: string;\n readonly perSpace: readonly AggregatePerSpaceExecutionEntry[];\n readonly pathDecision?: MigrationApplyPathDecision;\n readonly timings: {\n readonly total: number;\n };\n readonly advancedRef?: { readonly name: string; readonly hash: string } | null;\n}\n\nfunction mapApplyFailure(failure: MigrationApplyFailure): CliStructuredErrorType {\n if (failure.code === 'MIGRATION_PATH_NOT_FOUND') {\n return errorPathUnreachable(failure);\n }\n return errorRuntime(failure.summary, {\n why: failure.why ?? 'Migration runner failed',\n fix: 'Fix the issue and re-run `prisma-next migrate --to <contract>` — previously applied migrations are preserved.',\n meta: failure.meta ?? {},\n });\n}\n\nasync function executeMigrateCommand(\n options: MigrateCommandOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<MigrateResult, CliStructuredErrorType>> {\n const config = await loadConfig(options.config);\n const { configPath, migrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for migrate (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: 'migrate',\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: 'Config.driver is required for migrate',\n }),\n );\n }\n\n if (!targetSupportsMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n const toArg = options.to;\n\n // Construct the family instance up-front so the on-disk contract read\n // crosses the serializer seam (`familyInstance.deserializeContract`) at\n // the read site. The downstream `client.migrationApply({ contract })`\n // re-validates internally (no harm — validation is idempotent), but\n // closing the gap at the read site is what makes the cast-pattern\n // lint enforceable and matches the other CLI commands. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n const contractPathAbsolute = resolveContractPath(config);\n let contractRaw: Contract;\n let contractContent: string;\n try {\n contractContent = 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 a valid contract.json, then retry.',\n }),\n );\n }\n return notOk(\n errorContractValidationFailed(\n `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n try {\n contractRaw = familyInstance.deserializeContract(JSON.parse(contractContent) as unknown);\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract at ${contractPathAbsolute} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n\n const loadedAggregate = await loadContractSpaceAggregateForCli({\n targetId: config.target.targetId,\n migrationsDir,\n appContract: contractRaw,\n extensionPacks: config.extensionPacks ?? [],\n deserializeContract: (json) => familyInstance.deserializeContract(json),\n });\n if (!loadedAggregate.ok) {\n return notOk(loadedAggregate.failure);\n }\n const aggregate = loadedAggregate.value;\n const integrityFailure = refuseContractSpaceIntegrity(aggregate, {\n declaredExtensions: toDeclaredExtensionsFromRaw(\n (config.extensionPacks ?? []) as ReadonlyArray<unknown>,\n ),\n checkContracts: true,\n });\n if (integrityFailure) {\n return notOk(integrityFailure);\n }\n\n let refEntry: RefEntry | undefined;\n if (toArg) {\n const refs = await readRefs(refsDir);\n const refResult = parseContractRef(toArg, { graph: aggregate.app.graph(), refs });\n if (!refResult.ok) {\n return notOk(mapRefResolutionError(refResult.failure));\n }\n if (refResult.value.provenance.kind === 'ref') {\n const resolved = refs[refResult.value.provenance.refName];\n if (resolved) refEntry = resolved;\n } else {\n refEntry = { hash: refResult.value.hash, invariants: [] };\n }\n }\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'migrations', value: appMigrationsRelative },\n ];\n if (typeof dbConnection === 'string') {\n details.push({\n label: 'database',\n value: maskConnectionUrl(dbConnection),\n });\n }\n if (toArg) {\n details.push({ label: 'to', value: toArg });\n }\n const header = formatStyledHeader({\n command: 'migrate',\n description: 'Apply planned migrations to advance the database',\n url: 'https://pris.ly/migrate',\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n const appGraph = aggregate.app.graph();\n const appBundles = aggregate.app.packages;\n\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n try {\n await client.connect(dbConnection);\n\n const allMarkers = await client.readAllMarkers();\n const appMarker = allMarkers.get('app') ?? null;\n\n if (appMarker !== null && !isGraphNode(appMarker.storageHash, appGraph)) {\n return notOk(\n errorMarkerMismatch(\n appMarker.storageHash,\n [...appGraph.nodes].sort(),\n findLatestMigration(appGraph)?.to ?? null,\n ),\n );\n }\n\n if (refEntry && refEntry.invariants.length > 0) {\n const declared = collectDeclaredInvariants(appGraph);\n const known = new Set<string>(declared);\n for (const id of appMarker?.invariants ?? []) known.add(id);\n const unknown = refEntry.invariants.filter((id) => !known.has(id));\n if (unknown.length > 0) {\n return notOk(\n mapMigrationToolsError(\n errorUnknownInvariant({\n ...ifDefined('refName', toArg),\n unknown,\n declared: [...declared].sort(),\n }),\n ),\n );\n }\n }\n\n if (!flags.quiet && !flags.json) {\n ui.step('Loading contract spaces…');\n }\n\n const applyResult = await client.migrationApply({\n contract: contractRaw,\n migrationsDir,\n ...ifDefined('refHash', refEntry?.hash),\n ...(refEntry?.invariants ? { refInvariants: refEntry.invariants } : {}),\n ...(refEntry !== undefined ? ifDefined('refName', toArg) : {}),\n });\n\n if (!applyResult.ok) {\n return notOk(mapApplyFailure(applyResult.failure));\n }\n\n const { value } = applyResult;\n\n let advancedRef: { name: string; hash: string } | null = null;\n if (options.advanceRef !== undefined) {\n let contractJsonPathForSnapshot = contractPathAbsolute;\n let contractJsonForSnapshot: Record<string, unknown> = JSON.parse(contractContent) as Record<\n string,\n unknown\n >;\n if (toArg && refEntry) {\n const matchingBundle = appBundles.find((p) => p.metadata.to === refEntry.hash);\n if (matchingBundle) {\n const endContractPath = join(matchingBundle.dirPath, 'end-contract.json');\n contractJsonPathForSnapshot = endContractPath;\n try {\n const raw = await readFile(endContractPath, 'utf-8');\n contractJsonForSnapshot = JSON.parse(raw) as Record<string, unknown>;\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(endContractPath, {\n why: `Bundle end-contract not found at ${endContractPath}`,\n fix: 'Re-emit the migration bundle or pick a different --to target.',\n }),\n );\n }\n throw error;\n }\n }\n }\n try {\n const contractIR = await readContractIR(\n contractJsonForSnapshot,\n contractJsonPathForSnapshot,\n );\n advancedRef = await executeRefAdvancement(\n refsDir,\n options.advanceRef,\n value.markerHash,\n contractIR,\n );\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n }\n\n return ok({\n ok: true,\n migrationsApplied: value.migrationsApplied,\n migrationsTotal: value.perSpace.length,\n markerHash: value.markerHash,\n applied: value.applied,\n summary: value.summary,\n perSpace: value.perSpace,\n ...ifDefined('pathDecision', value.pathDecision),\n timings: { total: Date.now() - startTime },\n advancedRef,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Unexpected error during migrate: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n\nexport function createMigrateCommand(): Command {\n const command = new Command('migrate');\n setCommandDescriptions(\n command,\n 'Apply planned migrations to advance the database',\n 'Walks every contract space (app + extensions) and applies pending\\n' +\n 'on-disk migrations in canonical order (extensions alphabetically,\\n' +\n 'then app). Graph-walks the on-disk migration graph for every space.\\n' +\n 'Use --to to target a specific contract (hash, ref name, migration dir).',\n );\n setCommandExamples(command, [\n 'prisma-next migrate --db $DATABASE_URL',\n 'prisma-next migrate --to production --db $DATABASE_URL',\n 'prisma-next migrate --to sha256:abc123 --db $DATABASE_URL',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option(\n '--to <contract>',\n 'Target contract reference (hash, prefix, ref name, migration dir name, <dir>^, or ./path)',\n )\n .option('--advance-ref <name>', 'Advance the named ref to the post-apply marker after success')\n .action(async (options: MigrateCommandOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const startTime = Date.now();\n\n const ui = createTerminalUI(flags);\n\n const result = await executeMigrateCommand(options, flags, ui, startTime);\n\n const exitCode = handleResult(result, flags, ui, (migrateResult) => {\n if (flags.json) {\n ui.output(JSON.stringify(migrateResult, null, 2));\n } else if (!flags.quiet) {\n ui.log(formatMigrationApplyCommandOutput(migrateResult, flags));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
|
|
3
|
-
//#region src/commands/migration-check.d.ts
|
|
2
|
+
//#region src/utils/integrity-violation-to-check-failure.d.ts
|
|
4
3
|
interface CheckFailure {
|
|
5
4
|
readonly pnCode: string;
|
|
6
5
|
readonly where: string;
|
|
7
6
|
readonly why: string;
|
|
8
7
|
readonly fix: string;
|
|
9
8
|
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/commands/migration-check.d.ts
|
|
10
11
|
interface MigrationCheckResult {
|
|
11
12
|
readonly ok: boolean;
|
|
12
13
|
readonly failures: readonly CheckFailure[];
|
|
@@ -14,5 +15,5 @@ interface MigrationCheckResult {
|
|
|
14
15
|
}
|
|
15
16
|
declare function createMigrationCheckCommand(): Command;
|
|
16
17
|
//#endregion
|
|
17
|
-
export { CheckFailure, MigrationCheckResult, createMigrationCheckCommand };
|
|
18
|
+
export { type CheckFailure, MigrationCheckResult, createMigrationCheckCommand };
|
|
18
19
|
//# sourceMappingURL=migration-check.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-check.d.mts","names":[],"sources":["../../src/commands/migration-check.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration-check.d.mts","names":[],"sources":["../../src/utils/integrity-violation-to-check-failure.ts","../../src/commands/migration-check.ts"],"mappings":";;UAGiB,YAAA;EAAA,SACN,MAAA;EAAA,SACA,KAAA;EAAA,SACA,GAAA;EAAA,SACA,GAAA;AAAA;;;UCgCM,oBAAA;EAAA,SACN,EAAA;EAAA,SACA,QAAA,WAAmB,YAAY;EAAA,SAC/B,OAAA;AAAA;AAAA,iBAsOK,2BAAA,CAAA,GAA+B,OAAO"}
|
|
@@ -1,280 +1,2 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { A as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as createTerminalUI } from "../command-helpers-yLuA78TP.mjs";
|
|
3
|
-
import { Command } from "commander";
|
|
4
|
-
import { join, relative } from "pathe";
|
|
5
|
-
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
6
|
-
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
7
|
-
import { readRefs } from "@prisma-next/migration-tools/refs";
|
|
8
|
-
import { parseMigrationRef } from "@prisma-next/migration-tools/ref-resolution";
|
|
9
|
-
import { verifyMigrationHash } from "@prisma-next/migration-tools/hash";
|
|
10
|
-
//#region src/commands/migration-check.ts
|
|
11
|
-
/**
|
|
12
|
-
* Canonical user-facing locator for a check failure: the cwd-relative path
|
|
13
|
-
* to the migration package directory. Surfacing the same shape across every
|
|
14
|
-
* PN code means `--json` consumers can branch uniformly on `where`.
|
|
15
|
-
*/
|
|
16
|
-
function migrationPathRelative(dirPath) {
|
|
17
|
-
return relative(process.cwd(), dirPath);
|
|
18
|
-
}
|
|
19
|
-
function migrationFileRelative(dirPath, fileName) {
|
|
20
|
-
return join(migrationPathRelative(dirPath), fileName);
|
|
21
|
-
}
|
|
22
|
-
function checkFileExists(dirPath, dirName, fileName) {
|
|
23
|
-
if (!existsSync(join(dirPath, fileName))) return {
|
|
24
|
-
pnCode: "PN-MIG-CHECK-002",
|
|
25
|
-
where: migrationFileRelative(dirPath, fileName),
|
|
26
|
-
why: `${fileName} is missing from ${dirName}`,
|
|
27
|
-
fix: "Re-emit the migration package or restore from version control."
|
|
28
|
-
};
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Within-migration snapshot-consistency check (PN-MIG-CHECK-005).
|
|
33
|
-
*
|
|
34
|
-
* Compares the migration's stored `metadata.to` against the `storageHash`
|
|
35
|
-
* recorded in its on-disk `end-contract.json` snapshot. The two values are
|
|
36
|
-
* independent on-disk records of the same fact (the migration's destination
|
|
37
|
-
* contract); drift between them indicates the package is internally
|
|
38
|
-
* corrupt. Cross-migration consistency (one migration's end-contract.json
|
|
39
|
-
* agreeing with the next migration's start-contract.json) is a separate
|
|
40
|
-
* check that requires shadow execution and is deferred to
|
|
41
|
-
* `migration preflight`.
|
|
42
|
-
*
|
|
43
|
-
* Shared between the graph-wide and per-migration code paths so both report
|
|
44
|
-
* the same failure for the same on-disk state.
|
|
45
|
-
*/
|
|
46
|
-
function checkSnapshotConsistency(pkg) {
|
|
47
|
-
const endContractPath = join(pkg.dirPath, "end-contract.json");
|
|
48
|
-
if (!existsSync(endContractPath)) return null;
|
|
49
|
-
try {
|
|
50
|
-
const snapshotHash = JSON.parse(readFileSync(endContractPath, "utf-8"))["storage"]?.["storageHash"];
|
|
51
|
-
if (typeof snapshotHash === "string" && snapshotHash !== pkg.metadata.to) return {
|
|
52
|
-
pnCode: "PN-MIG-CHECK-005",
|
|
53
|
-
where: migrationPathRelative(pkg.dirPath),
|
|
54
|
-
why: `Migration "${pkg.dirName}" declares to=${pkg.metadata.to} but end-contract.json has storageHash=${snapshotHash}`,
|
|
55
|
-
fix: "Re-emit the migration package so migration.json and end-contract.json agree."
|
|
56
|
-
};
|
|
57
|
-
} catch {
|
|
58
|
-
return {
|
|
59
|
-
pnCode: "PN-MIG-CHECK-006",
|
|
60
|
-
where: migrationPathRelative(pkg.dirPath),
|
|
61
|
-
why: `Migration "${pkg.dirName}" has an unparseable end-contract.json.`,
|
|
62
|
-
fix: "Re-emit the migration package to repair the snapshot file."
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
async function executeMigrationCheckCommand(target, options, flags, ui) {
|
|
68
|
-
const config = await loadConfig(options.config);
|
|
69
|
-
const { configPath, appMigrationsDir, appMigrationsRelative, refsDir } = resolveMigrationPaths(options.config, config);
|
|
70
|
-
if (!flags.json && !flags.quiet) {
|
|
71
|
-
const details = [{
|
|
72
|
-
label: "config",
|
|
73
|
-
value: configPath
|
|
74
|
-
}, {
|
|
75
|
-
label: "migrations",
|
|
76
|
-
value: appMigrationsRelative
|
|
77
|
-
}];
|
|
78
|
-
if (target) details.push({
|
|
79
|
-
label: "target",
|
|
80
|
-
value: target
|
|
81
|
-
});
|
|
82
|
-
const header = formatStyledHeader({
|
|
83
|
-
command: "migration check",
|
|
84
|
-
description: "Verify artifact and graph integrity",
|
|
85
|
-
details,
|
|
86
|
-
flags
|
|
87
|
-
});
|
|
88
|
-
ui.stderr(header);
|
|
89
|
-
}
|
|
90
|
-
const failures = [];
|
|
91
|
-
let bundles;
|
|
92
|
-
let graph;
|
|
93
|
-
try {
|
|
94
|
-
const loaded = await loadMigrationPackages(appMigrationsDir);
|
|
95
|
-
bundles = loaded.bundles;
|
|
96
|
-
graph = loaded.graph;
|
|
97
|
-
} catch (error) {
|
|
98
|
-
if (MigrationToolsError.is(error)) {
|
|
99
|
-
const pnCode = error.code === "MIGRATION.HASH_MISMATCH" ? "PN-MIG-CHECK-001" : "PN-MIG-CHECK-002";
|
|
100
|
-
const rawWhere = error.details?.["dir"] ?? error.details?.["filePath"] ?? null;
|
|
101
|
-
const where = rawWhere ? relative(process.cwd(), rawWhere) : "unknown";
|
|
102
|
-
failures.push({
|
|
103
|
-
pnCode,
|
|
104
|
-
where,
|
|
105
|
-
why: error.why,
|
|
106
|
-
fix: error.fix
|
|
107
|
-
});
|
|
108
|
-
return {
|
|
109
|
-
result: {
|
|
110
|
-
ok: false,
|
|
111
|
-
failures,
|
|
112
|
-
summary: `${failures.length} integrity failure(s)`
|
|
113
|
-
},
|
|
114
|
-
exitCode: 4
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
throw error;
|
|
118
|
-
}
|
|
119
|
-
if (existsSync(appMigrationsDir)) {
|
|
120
|
-
const loadedDirNames = new Set(bundles.map((p) => p.dirName));
|
|
121
|
-
try {
|
|
122
|
-
const entries = readdirSync(appMigrationsDir);
|
|
123
|
-
for (const entry of entries) {
|
|
124
|
-
if (entry.startsWith(".") || entry.startsWith("_") || entry === "refs") continue;
|
|
125
|
-
const entryPath = join(appMigrationsDir, entry);
|
|
126
|
-
try {
|
|
127
|
-
if (!statSync(entryPath).isDirectory()) continue;
|
|
128
|
-
} catch {
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
if (!loadedDirNames.has(entry)) for (const f of ["migration.json", "ops.json"]) {
|
|
132
|
-
const fail = checkFileExists(entryPath, entry, f);
|
|
133
|
-
if (fail) failures.push(fail);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
} catch {}
|
|
137
|
-
}
|
|
138
|
-
if (target) {
|
|
139
|
-
const refs = await readRefs(refsDir);
|
|
140
|
-
const migResult = parseMigrationRef(target, {
|
|
141
|
-
graph,
|
|
142
|
-
refs
|
|
143
|
-
});
|
|
144
|
-
if (!migResult.ok) return {
|
|
145
|
-
result: {
|
|
146
|
-
ok: false,
|
|
147
|
-
failures: [],
|
|
148
|
-
summary: migResult.failure.kind === "not-found" ? `Migration "${target}" does not exist` : migResult.failure.kind === "wrong-grammar" ? migResult.failure.message : `Invalid migration reference: "${target}"`
|
|
149
|
-
},
|
|
150
|
-
exitCode: 2
|
|
151
|
-
};
|
|
152
|
-
const matchedPkg = bundles.find((p) => p.metadata.migrationHash === migResult.value.migrationHash);
|
|
153
|
-
if (!matchedPkg) return {
|
|
154
|
-
result: {
|
|
155
|
-
ok: false,
|
|
156
|
-
failures: [],
|
|
157
|
-
summary: `Migration package for "${target}" not found on disk`
|
|
158
|
-
},
|
|
159
|
-
exitCode: 2
|
|
160
|
-
};
|
|
161
|
-
for (const f of ["migration.json", "ops.json"]) {
|
|
162
|
-
const fail = checkFileExists(matchedPkg.dirPath, matchedPkg.dirName, f);
|
|
163
|
-
if (fail) failures.push(fail);
|
|
164
|
-
}
|
|
165
|
-
const verification = verifyMigrationHash(matchedPkg);
|
|
166
|
-
if (!verification.ok) failures.push({
|
|
167
|
-
pnCode: "PN-MIG-CHECK-001",
|
|
168
|
-
where: migrationFileRelative(matchedPkg.dirPath, "migration.json"),
|
|
169
|
-
why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,
|
|
170
|
-
fix: "Re-emit the migration package or restore from version control."
|
|
171
|
-
});
|
|
172
|
-
const snapshotFailure = checkSnapshotConsistency(matchedPkg);
|
|
173
|
-
if (snapshotFailure) failures.push(snapshotFailure);
|
|
174
|
-
} else {
|
|
175
|
-
for (const pkg of bundles) {
|
|
176
|
-
for (const f of ["migration.json", "ops.json"]) {
|
|
177
|
-
const fail = checkFileExists(pkg.dirPath, pkg.dirName, f);
|
|
178
|
-
if (fail) failures.push(fail);
|
|
179
|
-
}
|
|
180
|
-
const verification = verifyMigrationHash(pkg);
|
|
181
|
-
if (!verification.ok) failures.push({
|
|
182
|
-
pnCode: "PN-MIG-CHECK-001",
|
|
183
|
-
where: migrationFileRelative(pkg.dirPath, "migration.json"),
|
|
184
|
-
why: `Stored hash ${verification.storedHash} does not match recomputed hash ${verification.computedHash}`,
|
|
185
|
-
fix: "Re-emit the migration package or restore from version control."
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
for (const pkg of bundles) {
|
|
189
|
-
const snapshotFailure = checkSnapshotConsistency(pkg);
|
|
190
|
-
if (snapshotFailure) failures.push(snapshotFailure);
|
|
191
|
-
}
|
|
192
|
-
const allToHashes = new Set(bundles.map((p) => p.metadata.to));
|
|
193
|
-
for (const pkg of bundles) if (!(pkg.metadata.from === null || allToHashes.has(pkg.metadata.from) || pkg.metadata.from === "sha256:empty")) failures.push({
|
|
194
|
-
pnCode: "PN-MIG-CHECK-003",
|
|
195
|
-
where: migrationPathRelative(pkg.dirPath),
|
|
196
|
-
why: `Migration "${pkg.dirName}" starts from ${pkg.metadata.from} which no other migration produces`,
|
|
197
|
-
fix: "This migration is unreachable in the graph. Delete it or re-emit a connecting migration."
|
|
198
|
-
});
|
|
199
|
-
try {
|
|
200
|
-
const refs = await readRefs(refsDir);
|
|
201
|
-
for (const [name, entry] of Object.entries(refs)) if (!graph.nodes.has(entry.hash)) failures.push({
|
|
202
|
-
pnCode: "PN-MIG-CHECK-004",
|
|
203
|
-
where: relative(process.cwd(), join(refsDir, `${name}.json`)),
|
|
204
|
-
why: `Ref "${name}" points at ${entry.hash} which does not exist in the migration graph`,
|
|
205
|
-
fix: `Update the ref with \`prisma-next ref set ${name} <valid-hash>\` or delete it.`
|
|
206
|
-
});
|
|
207
|
-
} catch {}
|
|
208
|
-
}
|
|
209
|
-
if (failures.length === 0) return {
|
|
210
|
-
result: {
|
|
211
|
-
ok: true,
|
|
212
|
-
failures: [],
|
|
213
|
-
summary: "All checks passed"
|
|
214
|
-
},
|
|
215
|
-
exitCode: 0
|
|
216
|
-
};
|
|
217
|
-
return {
|
|
218
|
-
result: {
|
|
219
|
-
ok: false,
|
|
220
|
-
failures,
|
|
221
|
-
summary: `${failures.length} integrity failure(s)`
|
|
222
|
-
},
|
|
223
|
-
exitCode: 4
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
function createMigrationCheckCommand() {
|
|
227
|
-
const command = new Command("check");
|
|
228
|
-
setCommandDescriptions(command, "Verify artifact and graph integrity", "Validates that on-disk migration packages are internally consistent\n(hashes match, manifests are complete) and that the graph is well-formed\n(edges connect, refs point at valid nodes). Offline — does not consult\nthe database.");
|
|
229
|
-
setCommandExamples(command, [
|
|
230
|
-
"prisma-next migration check",
|
|
231
|
-
"prisma-next migration check 20260101-add-users",
|
|
232
|
-
"prisma-next migration check --json"
|
|
233
|
-
]);
|
|
234
|
-
setCommandSeeAlso(command, [
|
|
235
|
-
{
|
|
236
|
-
verb: "migration status",
|
|
237
|
-
oneLiner: "Show migration path and pending status"
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
verb: "migration list",
|
|
241
|
-
oneLiner: "List on-disk migrations"
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
verb: "migration graph",
|
|
245
|
-
oneLiner: "Show the migration graph topology"
|
|
246
|
-
}
|
|
247
|
-
]);
|
|
248
|
-
command.exitOverride();
|
|
249
|
-
addGlobalOptions(command).argument("[migration]", "Migration reference (directory name or hash) to check").option("--config <path>", "Path to prisma-next.config.ts").action(async (target, options) => {
|
|
250
|
-
const flags = parseGlobalFlagsOrExit(options);
|
|
251
|
-
const ui = createTerminalUI(flags);
|
|
252
|
-
let result;
|
|
253
|
-
let exitCode;
|
|
254
|
-
try {
|
|
255
|
-
({result, exitCode} = await executeMigrationCheckCommand(target, options, flags, ui));
|
|
256
|
-
} catch (error) {
|
|
257
|
-
result = {
|
|
258
|
-
ok: false,
|
|
259
|
-
failures: [],
|
|
260
|
-
summary: error instanceof Error ? error.message : String(error)
|
|
261
|
-
};
|
|
262
|
-
exitCode = 2;
|
|
263
|
-
}
|
|
264
|
-
if (flags.json) ui.output(JSON.stringify(result, null, 2));
|
|
265
|
-
else if (!flags.quiet) if (result.ok) ui.log(`✔ ${result.summary}`);
|
|
266
|
-
else {
|
|
267
|
-
for (const f of result.failures) {
|
|
268
|
-
ui.log(`✗ [${f.pnCode}] ${f.where}: ${f.why}`);
|
|
269
|
-
ui.log(` fix: ${f.fix}`);
|
|
270
|
-
}
|
|
271
|
-
ui.log(`\n${result.summary}`);
|
|
272
|
-
}
|
|
273
|
-
process.exit(exitCode);
|
|
274
|
-
});
|
|
275
|
-
return command;
|
|
276
|
-
}
|
|
277
|
-
//#endregion
|
|
1
|
+
import { t as createMigrationCheckCommand } from "../migration-check-CzLbAqIQ.mjs";
|
|
278
2
|
export { createMigrationCheckCommand };
|
|
279
|
-
|
|
280
|
-
//# sourceMappingURL=migration-check.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { O as errorUnexpected, k as mapMigrationToolsError } from "../cli-errors-DFF1LlfU.mjs";
|
|
3
|
-
import { A as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, s as readContractEnvelope, t as addGlobalOptions, v as parseGlobalFlagsOrExit, w as handleResult, y as createTerminalUI } from "../command-helpers-
|
|
4
|
-
import { i as migrationGraphToRenderInput, n as graphRenderer } from "../graph-render-
|
|
3
|
+
import { A as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, p as setCommandSeeAlso, s as readContractEnvelope, t as addGlobalOptions, v as parseGlobalFlagsOrExit, w as handleResult, y as createTerminalUI } from "../command-helpers-CI8P5Xyd.mjs";
|
|
4
|
+
import { i as migrationGraphToRenderInput, n as graphRenderer } from "../graph-render-D2FnLpuK.mjs";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
7
|
import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { N as CliStructuredError } from "../types-
|
|
2
|
-
import { t as GlyphMode } from "../migration-list-graph-render-
|
|
1
|
+
import { N as CliStructuredError } from "../types-CEtm6v6a.mjs";
|
|
2
|
+
import { t as GlyphMode } from "../migration-list-graph-render-DKw1AT-e.mjs";
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import { Result } from "@prisma-next/utils/result";
|
|
5
5
|
import { MigrationListResult } from "@prisma-next/migration-tools/migration-list-types";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as renderMigrationListHumanOutput, r as runMigrationList, t as createMigrationListCommand } from "../migration-list-
|
|
1
|
+
import { n as renderMigrationListHumanOutput, r as runMigrationList, t as createMigrationListCommand } from "../migration-list-C2xnaYsT.mjs";
|
|
2
2
|
export { createMigrationListCommand, renderMigrationListHumanOutput, runMigrationList };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
2
|
import { O as errorUnexpected, c as errorDriverRequired, k as mapMigrationToolsError, o as errorDatabaseConnectionRequired, t as CliStructuredError } from "../cli-errors-DFF1LlfU.mjs";
|
|
3
|
-
import { A as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, m as targetSupportsMigrations, o as maskConnectionUrl, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, w as handleResult, y as createTerminalUI } from "../command-helpers-
|
|
4
|
-
import { t as createControlClient } from "../client-
|
|
3
|
+
import { A as formatStyledHeader, a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, m as targetSupportsMigrations, o as maskConnectionUrl, p as setCommandSeeAlso, t as addGlobalOptions, v as parseGlobalFlagsOrExit, w as handleResult, y as createTerminalUI } from "../command-helpers-CI8P5Xyd.mjs";
|
|
4
|
+
import { t as createControlClient } from "../client-5uvDppD8.mjs";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
7
|
import { findPath } from "@prisma-next/migration-tools/migration-graph";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-new.d.mts","names":[],"sources":["../../src/commands/migration-new.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"migration-new.d.mts","names":[],"sources":["../../src/commands/migration-new.ts"],"mappings":";;;iBA2QgB,yBAAA,CAAA,GAA6B,OAAO"}
|