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,16 +1,17 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import { C as errorRuntime, E as errorTargetMigrationNotSupported, O as errorUnexpected,
|
|
2
|
+
import { C as errorRuntime, E as errorTargetMigrationNotSupported, O as errorUnexpected, l as errorFileNotFound, t as CliStructuredError } from "../cli-errors-DFF1LlfU.mjs";
|
|
3
3
|
import { t as assertFrameworkComponentsCompatible } from "../framework-components-DTcjouhS.mjs";
|
|
4
|
-
import { A as formatStyledHeader, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, i as getTargetMigrations, l as resolveMigrationPaths, t as addGlobalOptions, v as parseGlobalFlagsOrExit, w as handleResult, y as createTerminalUI } from "../command-helpers-
|
|
4
|
+
import { A as formatStyledHeader, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, i as getTargetMigrations, l as resolveMigrationPaths, t as addGlobalOptions, v as parseGlobalFlagsOrExit, w as handleResult, y as createTerminalUI } from "../command-helpers-CI8P5Xyd.mjs";
|
|
5
|
+
import { i as refusePackageCorruptionOnAggregate } from "../contract-space-aggregate-loader-CVHGuA35.mjs";
|
|
5
6
|
import { Command } from "commander";
|
|
6
7
|
import { getEmittedArtifactPaths } from "@prisma-next/emitter";
|
|
7
8
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
8
9
|
import { join, relative } from "pathe";
|
|
9
10
|
import { readFile } from "node:fs/promises";
|
|
10
11
|
import { APP_SPACE_ID, createControlStack } from "@prisma-next/framework-components/control";
|
|
11
|
-
import { copyFilesWithRename, formatMigrationDirName,
|
|
12
|
-
import { findLatestMigration
|
|
13
|
-
import {
|
|
12
|
+
import { copyFilesWithRename, formatMigrationDirName, writeMigrationPackage } from "@prisma-next/migration-tools/io";
|
|
13
|
+
import { findLatestMigration } from "@prisma-next/migration-tools/migration-graph";
|
|
14
|
+
import { loadContractSpaceAggregate } from "@prisma-next/migration-tools/aggregate";
|
|
14
15
|
import { computeMigrationHash } from "@prisma-next/migration-tools/hash";
|
|
15
16
|
import { writeMigrationTs } from "@prisma-next/migration-tools/migration-ts";
|
|
16
17
|
//#region src/commands/migration-new.ts
|
|
@@ -25,7 +26,7 @@ import { writeMigrationTs } from "@prisma-next/migration-tools/migration-ts";
|
|
|
25
26
|
*/
|
|
26
27
|
async function executeMigrationNewCommand(options) {
|
|
27
28
|
const config = await loadConfig(options.config);
|
|
28
|
-
const { appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);
|
|
29
|
+
const { migrationsDir, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);
|
|
29
30
|
const stack = createControlStack(config);
|
|
30
31
|
const familyInstance = config.family.create(stack);
|
|
31
32
|
const contractPathAbsolute = resolveContractPath(config);
|
|
@@ -41,7 +42,8 @@ async function executeMigrationNewCommand(options) {
|
|
|
41
42
|
}
|
|
42
43
|
let toContract;
|
|
43
44
|
try {
|
|
44
|
-
|
|
45
|
+
const parsedContract = JSON.parse(contractJsonContent);
|
|
46
|
+
toContract = familyInstance.deserializeContract(parsedContract);
|
|
45
47
|
} catch (error) {
|
|
46
48
|
return notOk(errorRuntime("Contract JSON is invalid", {
|
|
47
49
|
why: `Failed to deserialize ${contractPathAbsolute}: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -53,32 +55,32 @@ async function executeMigrationNewCommand(options) {
|
|
|
53
55
|
why: `Contract at ${contractPathAbsolute} has no storageHash`,
|
|
54
56
|
fix: "Run `prisma-next contract emit` to regenerate the contract"
|
|
55
57
|
}));
|
|
58
|
+
const aggregate = await loadContractSpaceAggregate({
|
|
59
|
+
migrationsDir,
|
|
60
|
+
deserializeContract: (json) => familyInstance.deserializeContract(json),
|
|
61
|
+
appContract: toContract
|
|
62
|
+
});
|
|
63
|
+
const packageCorruptionFailure = refusePackageCorruptionOnAggregate(aggregate);
|
|
64
|
+
if (packageCorruptionFailure) return notOk(packageCorruptionFailure);
|
|
65
|
+
const packages = aggregate.app.packages;
|
|
66
|
+
const graph = aggregate.app.graph();
|
|
56
67
|
let fromHash = null;
|
|
57
68
|
let fromContractSourceDir = null;
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (latestMigration) {
|
|
73
|
-
fromHash = latestMigration.to;
|
|
74
|
-
const leafPkg = packages.find((p) => p.metadata.migrationHash === latestMigration.migrationHash);
|
|
75
|
-
if (leafPkg) fromContractSourceDir = leafPkg.dirPath;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
69
|
+
if (packages.length > 0) if (options.from) {
|
|
70
|
+
const match = packages.find((p) => p.metadata.to.startsWith(options.from));
|
|
71
|
+
if (!match) return notOk(errorRuntime("Starting contract not found", {
|
|
72
|
+
why: `No migration with to hash matching "${options.from}" exists in ${appMigrationsRelative}`,
|
|
73
|
+
fix: "Check that the --from hash matches a known migration target hash."
|
|
74
|
+
}));
|
|
75
|
+
fromHash = match.metadata.to;
|
|
76
|
+
fromContractSourceDir = match.dirPath;
|
|
77
|
+
} else {
|
|
78
|
+
const latestMigration = findLatestMigration(graph);
|
|
79
|
+
if (latestMigration) {
|
|
80
|
+
fromHash = latestMigration.to;
|
|
81
|
+
const leafPkg = packages.find((p) => p.metadata.migrationHash === latestMigration.migrationHash);
|
|
82
|
+
if (leafPkg) fromContractSourceDir = leafPkg.dirPath;
|
|
78
83
|
}
|
|
79
|
-
} catch (error) {
|
|
80
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
81
|
-
throw error;
|
|
82
84
|
}
|
|
83
85
|
if (fromHash === toStorageHash && !options.from) return notOk(errorRuntime("No changes detected", {
|
|
84
86
|
why: "The from and to contract hashes are identical — there is nothing to migrate.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-new.mjs","names":[],"sources":["../../src/commands/migration-new.ts"],"sourcesContent":["/**\n * `migration new` — scaffolds a migration package with a `migration.ts` file\n * for manual authoring.\n *\n * The planner's `emptyMigration(context)` returns a\n * `MigrationPlanWithAuthoringSurface`, whose `renderTypeScript()` produces\n * the target-appropriate empty stub. The CLI writes the returned source\n * verbatim.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport { APP_SPACE_ID, createControlStack } from '@prisma-next/framework-components/control';\nimport { MigrationToolsError } from '@prisma-next/migration-tools/errors';\nimport { computeMigrationHash } from '@prisma-next/migration-tools/hash';\nimport {\n copyFilesWithRename,\n formatMigrationDirName,\n readMigrationsDir,\n writeMigrationPackage,\n} from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport {\n findLatestMigration,\n reconstructGraph,\n} from '@prisma-next/migration-tools/migration-graph';\nimport { writeMigrationTs } from '@prisma-next/migration-tools/migration-ts';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join, relative } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport {\n CliStructuredError,\n errorFileNotFound,\n errorRuntime,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n mapMigrationToolsError,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n getTargetMigrations,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport { assertFrameworkComponentsCompatible } from '../utils/framework-components';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationNewOptions extends CommonCommandOptions {\n readonly name?: string;\n readonly from?: string;\n readonly config?: string;\n}\n\ninterface MigrationNewResult {\n readonly ok: true;\n readonly dir: string;\n readonly from: string | null;\n readonly to: string;\n readonly summary: string;\n}\n\nasync function executeMigrationNewCommand(\n options: MigrationNewOptions,\n): Promise<Result<MigrationNewResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);\n\n // Construct the family instance up-front so the on-disk contract read\n // below crosses the serializer seam (`familyInstance.deserializeContract`)\n // at the read site, not somewhere downstream. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n const contractPathAbsolute = resolveContractPath(config);\n\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorRuntime(`Contract file not found at ${contractPathAbsolute}`, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: 'Run `prisma-next contract emit` first to generate the contract',\n }),\n );\n }\n throw error;\n }\n\n let toContract: Contract;\n try {\n toContract = familyInstance.deserializeContract(JSON.parse(contractJsonContent) as unknown);\n } catch (error) {\n return notOk(\n errorRuntime('Contract JSON is invalid', {\n why: `Failed to deserialize ${contractPathAbsolute}: ${error instanceof Error ? error.message : String(error)}`,\n fix: 'Run `prisma-next contract emit` to regenerate the contract',\n }),\n );\n }\n\n const toStorageHash = toContract.storage?.storageHash;\n if (typeof toStorageHash !== 'string') {\n return notOk(\n errorRuntime('Contract is missing storageHash', {\n why: `Contract at ${contractPathAbsolute} has no storageHash`,\n fix: 'Run `prisma-next contract emit` to regenerate the contract',\n }),\n );\n }\n\n let fromHash: string | null = null;\n let fromContractSourceDir: string | null = null;\n\n try {\n const packages = await readMigrationsDir(appMigrationsDir);\n\n if (packages.length > 0) {\n const graph = reconstructGraph(packages);\n\n if (options.from) {\n const match = packages.find((p) => p.metadata.to.startsWith(options.from!));\n if (!match) {\n return notOk(\n errorRuntime('Starting contract not found', {\n why: `No migration with to hash matching \"${options.from}\" exists in ${appMigrationsRelative}`,\n fix: 'Check that the --from hash matches a known migration target hash.',\n }),\n );\n }\n fromHash = match.metadata.to;\n fromContractSourceDir = match.dirPath;\n } else {\n const latestMigration = findLatestMigration(graph);\n if (latestMigration) {\n fromHash = latestMigration.to;\n const leafPkg = packages.find(\n (p) => p.metadata.migrationHash === latestMigration.migrationHash,\n );\n if (leafPkg) {\n fromContractSourceDir = leafPkg.dirPath;\n }\n }\n }\n }\n } catch (error) {\n if (MigrationToolsError.is(error)) {\n return notOk(mapMigrationToolsError(error));\n }\n throw error;\n }\n\n if (fromHash === toStorageHash && !options.from) {\n return notOk(\n errorRuntime('No changes detected', {\n why: 'The from and to contract hashes are identical — there is nothing to migrate.',\n fix: 'Change the contract and run `prisma-next contract emit` before creating a new migration. To author a data-only migration on the current contract hash, pass `--from <hash>` explicitly.',\n }),\n );\n }\n\n const timestamp = new Date();\n const slug = options.name ?? 'migration';\n const dirName = formatMigrationDirName(timestamp, slug);\n const packageDir = join(appMigrationsDir, dirName);\n\n // `migration new` scaffolds an empty `migration.ts` for the user to\n // fill, so we attest over `ops: []`. Re-running self-emit after the\n // user adds operations will produce a different `migrationHash` (over\n // the real ops). This is intentional — there is no on-disk draft.\n const baseMetadata: Omit<MigrationMetadata, 'migrationHash'> = {\n from: fromHash,\n to: toStorageHash,\n providedInvariants: [],\n createdAt: timestamp.toISOString(),\n };\n const metadata: MigrationMetadata = {\n ...baseMetadata,\n migrationHash: computeMigrationHash(baseMetadata, []),\n };\n\n const migrations = getTargetMigrations(config.target);\n if (!migrations) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.targetId}\" does not support migrations`,\n }),\n );\n }\n\n try {\n assertFrameworkComponentsCompatible(config.family.familyId, config.target.targetId, [\n config.target,\n config.adapter,\n ...(config.extensionPacks ?? []),\n ]);\n\n await writeMigrationPackage(packageDir, metadata, []);\n const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);\n await copyFilesWithRename(packageDir, [\n { sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },\n { sourcePath: destinationArtifacts.dtsPath, destName: 'end-contract.d.ts' },\n ]);\n if (fromContractSourceDir !== null) {\n const sourceArtifacts = getEmittedArtifactPaths(\n join(fromContractSourceDir, 'end-contract.json'),\n );\n try {\n await copyFilesWithRename(packageDir, [\n { sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },\n { sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },\n ]);\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(sourceArtifacts.jsonPath, {\n why: `Predecessor migration is missing its destination contract snapshot at ${sourceArtifacts.jsonPath}`,\n fix: 'Re-emit the predecessor migration (`prisma-next migration plan` from its source) so its sibling `end-contract.json` is restored, then re-run this command.',\n }),\n );\n }\n throw error;\n }\n }\n\n const planner = migrations.createPlanner(familyInstance);\n const emptyPlan = planner.emptyMigration(\n {\n packageDir,\n contractJsonPath: join(packageDir, 'end-contract.json'),\n fromHash,\n toHash: toStorageHash,\n },\n APP_SPACE_ID,\n );\n await writeMigrationTs(packageDir, emptyPlan.renderTypeScript());\n\n return ok({\n ok: true as const,\n dir: relative(process.cwd(), packageDir),\n from: fromHash,\n to: toStorageHash,\n summary: `Scaffolded migration at ${relative(process.cwd(), packageDir)}`,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to scaffold migration: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n}\n\nexport function createMigrationNewCommand(): Command {\n const command = new Command('new');\n setCommandDescriptions(\n command,\n 'Scaffold a new migration for manual authoring',\n 'Creates a migration package with a migration.ts file for manual authoring.\\n' +\n 'Write the migration body in migration.ts, then run the file with Node\\n' +\n '(`node migration.ts`) to self-emit ops.json and attest the package.',\n );\n setCommandExamples(command, [\n 'prisma-next migration new --name split-name',\n 'prisma-next migration new --name custom-fk --from sha256:abc...',\n ]);\n addGlobalOptions(command)\n .option('--name <slug>', 'Migration name (used in directory name)')\n .option('--from <hash>', 'Starting contract hash (default: latest migration target)')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationNewOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration new',\n description: 'Scaffold a new migration',\n details: [],\n flags,\n });\n ui.stderr(header);\n }\n\n const result = await executeMigrationNewCommand(options);\n\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value, null, 2));\n } else if (!flags.quiet) {\n ui.output(`\\nScaffolded migration at ${value.dir}`);\n ui.output(` from: ${value.from}`);\n ui.output(` to: ${value.to}`);\n ui.output(\n `\\nEdit migration.ts, then run it directly (\\`node \"${value.dir}/migration.ts\"\\`) to self-emit and attest.`,\n );\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"migration-new.mjs","names":[],"sources":["../../src/commands/migration-new.ts"],"sourcesContent":["/**\n * `migration new` — scaffolds a migration package with a `migration.ts` file\n * for manual authoring.\n *\n * The planner's `emptyMigration(context)` returns a\n * `MigrationPlanWithAuthoringSurface`, whose `renderTypeScript()` produces\n * the target-appropriate empty stub. The CLI writes the returned source\n * verbatim.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport type { Contract } from '@prisma-next/contract/types';\nimport { getEmittedArtifactPaths } from '@prisma-next/emitter';\nimport { APP_SPACE_ID, createControlStack } from '@prisma-next/framework-components/control';\nimport { loadContractSpaceAggregate } from '@prisma-next/migration-tools/aggregate';\nimport { computeMigrationHash } from '@prisma-next/migration-tools/hash';\nimport {\n copyFilesWithRename,\n formatMigrationDirName,\n writeMigrationPackage,\n} from '@prisma-next/migration-tools/io';\nimport type { MigrationMetadata } from '@prisma-next/migration-tools/metadata';\nimport { findLatestMigration } from '@prisma-next/migration-tools/migration-graph';\nimport { writeMigrationTs } from '@prisma-next/migration-tools/migration-ts';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { join, relative } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport {\n CliStructuredError,\n errorFileNotFound,\n errorRuntime,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n} from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n getTargetMigrations,\n resolveContractPath,\n resolveMigrationPaths,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { refusePackageCorruptionOnAggregate } from '../utils/contract-space-aggregate-loader';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport { assertFrameworkComponentsCompatible } from '../utils/framework-components';\nimport type { CommonCommandOptions } from '../utils/global-flags';\nimport { parseGlobalFlagsOrExit } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { createTerminalUI } from '../utils/terminal-ui';\n\ninterface MigrationNewOptions extends CommonCommandOptions {\n readonly name?: string;\n readonly from?: string;\n readonly config?: string;\n}\n\ninterface MigrationNewResult {\n readonly ok: true;\n readonly dir: string;\n readonly from: string | null;\n readonly to: string;\n readonly summary: string;\n}\n\nasync function executeMigrationNewCommand(\n options: MigrationNewOptions,\n): Promise<Result<MigrationNewResult, CliStructuredError>> {\n const config = await loadConfig(options.config);\n const { migrationsDir, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(\n options.config,\n config,\n );\n\n // Construct the family instance up-front so the on-disk contract read\n // below crosses the serializer seam (`familyInstance.deserializeContract`)\n // at the read site, not somewhere downstream. See TML-2536.\n const stack = createControlStack(config);\n const familyInstance = config.family.create(stack);\n\n const contractPathAbsolute = resolveContractPath(config);\n\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorRuntime(`Contract file not found at ${contractPathAbsolute}`, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: 'Run `prisma-next contract emit` first to generate the contract',\n }),\n );\n }\n throw error;\n }\n\n let toContract: Contract;\n try {\n const parsedContract: unknown = JSON.parse(contractJsonContent);\n toContract = familyInstance.deserializeContract(parsedContract);\n } catch (error) {\n return notOk(\n errorRuntime('Contract JSON is invalid', {\n why: `Failed to deserialize ${contractPathAbsolute}: ${error instanceof Error ? error.message : String(error)}`,\n fix: 'Run `prisma-next contract emit` to regenerate the contract',\n }),\n );\n }\n\n const toStorageHash = toContract.storage?.storageHash;\n if (typeof toStorageHash !== 'string') {\n return notOk(\n errorRuntime('Contract is missing storageHash', {\n why: `Contract at ${contractPathAbsolute} has no storageHash`,\n fix: 'Run `prisma-next contract emit` to regenerate the contract',\n }),\n );\n }\n\n const aggregate = await loadContractSpaceAggregate({\n migrationsDir,\n deserializeContract: (json) => familyInstance.deserializeContract(json),\n appContract: toContract,\n });\n const packageCorruptionFailure = refusePackageCorruptionOnAggregate(aggregate);\n if (packageCorruptionFailure) {\n return notOk(packageCorruptionFailure);\n }\n\n const packages = aggregate.app.packages;\n const graph = aggregate.app.graph();\n\n let fromHash: string | null = null;\n let fromContractSourceDir: string | null = null;\n\n if (packages.length > 0) {\n if (options.from) {\n const match = packages.find((p) => p.metadata.to.startsWith(options.from!));\n if (!match) {\n return notOk(\n errorRuntime('Starting contract not found', {\n why: `No migration with to hash matching \"${options.from}\" exists in ${appMigrationsRelative}`,\n fix: 'Check that the --from hash matches a known migration target hash.',\n }),\n );\n }\n fromHash = match.metadata.to;\n fromContractSourceDir = match.dirPath;\n } else {\n const latestMigration = findLatestMigration(graph);\n if (latestMigration) {\n fromHash = latestMigration.to;\n const leafPkg = packages.find(\n (p) => p.metadata.migrationHash === latestMigration.migrationHash,\n );\n if (leafPkg) {\n fromContractSourceDir = leafPkg.dirPath;\n }\n }\n }\n }\n\n if (fromHash === toStorageHash && !options.from) {\n return notOk(\n errorRuntime('No changes detected', {\n why: 'The from and to contract hashes are identical — there is nothing to migrate.',\n fix: 'Change the contract and run `prisma-next contract emit` before creating a new migration. To author a data-only migration on the current contract hash, pass `--from <hash>` explicitly.',\n }),\n );\n }\n\n const timestamp = new Date();\n const slug = options.name ?? 'migration';\n const dirName = formatMigrationDirName(timestamp, slug);\n const packageDir = join(appMigrationsDir, dirName);\n\n // `migration new` scaffolds an empty `migration.ts` for the user to\n // fill, so we attest over `ops: []`. Re-running self-emit after the\n // user adds operations will produce a different `migrationHash` (over\n // the real ops). This is intentional — there is no on-disk draft.\n const baseMetadata: Omit<MigrationMetadata, 'migrationHash'> = {\n from: fromHash,\n to: toStorageHash,\n providedInvariants: [],\n createdAt: timestamp.toISOString(),\n };\n const metadata: MigrationMetadata = {\n ...baseMetadata,\n migrationHash: computeMigrationHash(baseMetadata, []),\n };\n\n const migrations = getTargetMigrations(config.target);\n if (!migrations) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.targetId}\" does not support migrations`,\n }),\n );\n }\n\n try {\n assertFrameworkComponentsCompatible(config.family.familyId, config.target.targetId, [\n config.target,\n config.adapter,\n ...(config.extensionPacks ?? []),\n ]);\n\n await writeMigrationPackage(packageDir, metadata, []);\n const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);\n await copyFilesWithRename(packageDir, [\n { sourcePath: destinationArtifacts.jsonPath, destName: 'end-contract.json' },\n { sourcePath: destinationArtifacts.dtsPath, destName: 'end-contract.d.ts' },\n ]);\n if (fromContractSourceDir !== null) {\n const sourceArtifacts = getEmittedArtifactPaths(\n join(fromContractSourceDir, 'end-contract.json'),\n );\n try {\n await copyFilesWithRename(packageDir, [\n { sourcePath: sourceArtifacts.jsonPath, destName: 'start-contract.json' },\n { sourcePath: sourceArtifacts.dtsPath, destName: 'start-contract.d.ts' },\n ]);\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(sourceArtifacts.jsonPath, {\n why: `Predecessor migration is missing its destination contract snapshot at ${sourceArtifacts.jsonPath}`,\n fix: 'Re-emit the predecessor migration (`prisma-next migration plan` from its source) so its sibling `end-contract.json` is restored, then re-run this command.',\n }),\n );\n }\n throw error;\n }\n }\n\n const planner = migrations.createPlanner(familyInstance);\n const emptyPlan = planner.emptyMigration(\n {\n packageDir,\n contractJsonPath: join(packageDir, 'end-contract.json'),\n fromHash,\n toHash: toStorageHash,\n },\n APP_SPACE_ID,\n );\n await writeMigrationTs(packageDir, emptyPlan.renderTypeScript());\n\n return ok({\n ok: true as const,\n dir: relative(process.cwd(), packageDir),\n from: fromHash,\n to: toStorageHash,\n summary: `Scaffolded migration at ${relative(process.cwd(), packageDir)}`,\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to scaffold migration: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n}\n\nexport function createMigrationNewCommand(): Command {\n const command = new Command('new');\n setCommandDescriptions(\n command,\n 'Scaffold a new migration for manual authoring',\n 'Creates a migration package with a migration.ts file for manual authoring.\\n' +\n 'Write the migration body in migration.ts, then run the file with Node\\n' +\n '(`node migration.ts`) to self-emit ops.json and attest the package.',\n );\n setCommandExamples(command, [\n 'prisma-next migration new --name split-name',\n 'prisma-next migration new --name custom-fk --from sha256:abc...',\n ]);\n addGlobalOptions(command)\n .option('--name <slug>', 'Migration name (used in directory name)')\n .option('--from <hash>', 'Starting contract hash (default: latest migration target)')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .action(async (options: MigrationNewOptions) => {\n const flags = parseGlobalFlagsOrExit(options);\n const ui = createTerminalUI(flags);\n\n if (!flags.json && !flags.quiet) {\n const header = formatStyledHeader({\n command: 'migration new',\n description: 'Scaffold a new migration',\n details: [],\n flags,\n });\n ui.stderr(header);\n }\n\n const result = await executeMigrationNewCommand(options);\n\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value, null, 2));\n } else if (!flags.quiet) {\n ui.output(`\\nScaffolded migration at ${value.dir}`);\n ui.output(` from: ${value.from}`);\n ui.output(` to: ${value.to}`);\n ui.output(\n `\\nEdit migration.ts, then run it directly (\\`node \"${value.dir}/migration.ts\"\\`) to self-emit and attest.`,\n );\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as GlobalFlags } from "../global-flags-
|
|
1
|
+
import { t as GlobalFlags } from "../global-flags-DWsQ6SSI.mjs";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { Result } from "@prisma-next/utils/result";
|
|
4
4
|
import { OperationPreview } from "@prisma-next/framework-components/control";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as formatMigrationPlanOutput, r as resolveBundleByPrefix, t as createMigrationPlanCommand } from "../migration-plan-
|
|
1
|
+
import { n as formatMigrationPlanOutput, r as resolveBundleByPrefix, t as createMigrationPlanCommand } from "../migration-plan-BLvOmNCu.mjs";
|
|
2
2
|
export { createMigrationPlanCommand, formatMigrationPlanOutput, resolveBundleByPrefix };
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import { N as CliStructuredError } from "../types-
|
|
1
|
+
import { N as CliStructuredError } from "../types-CEtm6v6a.mjs";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { Result } from "@prisma-next/utils/result";
|
|
4
4
|
import { OperationPreview } from "@prisma-next/framework-components/control";
|
|
5
|
-
import { OnDiskMigrationPackage } from "@prisma-next/migration-tools/package";
|
|
6
5
|
|
|
7
6
|
//#region src/commands/migration-show.d.ts
|
|
8
|
-
|
|
9
|
-
* Details of one space's latest (or targeted) migration package.
|
|
10
|
-
*/
|
|
11
|
-
interface MigrationShowSpacePresent {
|
|
12
|
-
readonly kind: 'present';
|
|
7
|
+
interface MigrationShowPresent {
|
|
13
8
|
readonly spaceId: string;
|
|
14
9
|
readonly dirName: string;
|
|
15
10
|
readonly dirPath: string;
|
|
@@ -22,61 +17,15 @@ interface MigrationShowSpacePresent {
|
|
|
22
17
|
readonly label: string;
|
|
23
18
|
readonly operationClass: string;
|
|
24
19
|
}[];
|
|
25
|
-
/**
|
|
26
|
-
* Family-agnostic textual preview of the migration's operations. Always
|
|
27
|
-
* defined; statements is empty for a no-op migration or a family that does
|
|
28
|
-
* not implement the `OperationPreviewCapable` capability.
|
|
29
|
-
*/
|
|
30
20
|
readonly preview: OperationPreview;
|
|
31
21
|
readonly summary: string;
|
|
32
22
|
}
|
|
33
|
-
/**
|
|
34
|
-
* Placeholder for a loaded contract space that has no on-disk migration
|
|
35
|
-
* package — the extension descriptor declared the space but no migrations
|
|
36
|
-
* directory has been materialised for it yet. Surfaces the space in the
|
|
37
|
-
* response so JSON consumers see every loaded extension instead of having
|
|
38
|
-
* silently-skipped entries.
|
|
39
|
-
*/
|
|
40
|
-
interface MigrationShowSpaceMissing {
|
|
41
|
-
readonly kind: 'missing';
|
|
42
|
-
readonly spaceId: string;
|
|
43
|
-
readonly summary: string;
|
|
44
|
-
}
|
|
45
|
-
type MigrationShowSpaceResult = MigrationShowSpacePresent | MigrationShowSpaceMissing;
|
|
46
23
|
interface MigrationShowResult {
|
|
47
24
|
readonly ok: true;
|
|
48
|
-
|
|
49
|
-
* Per-space results, ordered: app first, then extensions alphabetically
|
|
50
|
-
* (matching the aggregate's canonical ordering).
|
|
51
|
-
*/
|
|
52
|
-
readonly spaces: readonly MigrationShowSpaceResult[];
|
|
25
|
+
readonly migration: MigrationShowPresent;
|
|
53
26
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Validate that a path-like `migration show` target resolves inside the app
|
|
56
|
-
* migrations directory. The returned result is always emitted under
|
|
57
|
-
* `aggregate.app.spaceId`, so accepting an extension-space (or otherwise
|
|
58
|
-
* external) path here would silently mislabel the result. Returns the
|
|
59
|
-
* resolved absolute path on success.
|
|
60
|
-
*
|
|
61
|
-
* `pathe.relative` can return an absolute path when the target cannot be
|
|
62
|
-
* expressed relative to the base (e.g. on Windows when `target` is on a
|
|
63
|
-
* different drive than `appMigrationsDir`). That case does not start with
|
|
64
|
-
* `..`, so the absolute-check below is required to reject cross-drive
|
|
65
|
-
* targets rather than mislabeling them as app-space.
|
|
66
|
-
*/
|
|
67
27
|
declare function resolveAppTargetPath(target: string, appMigrationsDir: string, appMigrationsRelative: string): Result<string, CliStructuredError>;
|
|
68
|
-
declare function resolveByHashPrefix(packages: readonly OnDiskMigrationPackage[], prefix: string): Result<OnDiskMigrationPackage, CliStructuredError>;
|
|
69
|
-
/**
|
|
70
|
-
* Resolve the latest migration from a space directory.
|
|
71
|
-
*
|
|
72
|
-
* Returns `ok(null)` only when the directory is empty or absent (ENOENT is
|
|
73
|
-
* absorbed by `readMigrationsDir`). If `readMigrationsDir` returned packages
|
|
74
|
-
* but `findLatestMigration` cannot pick a leaf, the on-disk history is
|
|
75
|
-
* corrupt — return a runtime error rather than collapsing it to a `missing`
|
|
76
|
-
* placeholder, which would hide the corruption from the caller.
|
|
77
|
-
*/
|
|
78
|
-
declare function resolveLatestFromDir(spaceDir: string): Promise<Result<OnDiskMigrationPackage | null, CliStructuredError>>;
|
|
79
28
|
declare function createMigrationShowCommand(): Command;
|
|
80
29
|
//#endregion
|
|
81
|
-
export {
|
|
30
|
+
export { MigrationShowPresent, MigrationShowResult, createMigrationShowCommand, resolveAppTargetPath };
|
|
82
31
|
//# sourceMappingURL=migration-show.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-show.d.mts","names":[],"sources":["../../src/commands/migration-show.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"migration-show.d.mts","names":[],"sources":["../../src/commands/migration-show.ts"],"mappings":";;;;;;UA6CiB,oBAAA;EAAA,SACN,OAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,aAAA;EAAA,SACA,SAAA;EAAA,SACA,UAAA;IAAA,SACE,EAAA;IAAA,SACA,KAAA;IAAA,SACA,cAAA;EAAA;EAAA,SAEF,OAAA,EAAS,gBAAgB;EAAA,SACzB,OAAA;AAAA;AAAA,UAGM,mBAAA;EAAA,SACN,EAAA;EAAA,SACA,SAAA,EAAW,oBAAoB;AAAA;AAAA,iBAO1B,oBAAA,CACd,MAAA,UACA,gBAAA,UACA,qBAAA,WACC,MAAM,SAAS,kBAAA;AAAA,iBAqLF,0BAAA,CAAA,GAA8B,OAAO"}
|
|
@@ -1,38 +1,21 @@
|
|
|
1
1
|
import { t as loadConfig } from "../config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import { A as mapRefResolutionError, C as errorRuntime, O as errorUnexpected, a as errorContractValidationFailed,
|
|
3
|
-
import { A as formatStyledHeader, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, 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-
|
|
5
|
-
import {
|
|
6
|
-
import { a as formatMigrationShowOutput } from "../migrations-D-UCOGtk.mjs";
|
|
2
|
+
import { A as mapRefResolutionError, C as errorRuntime, O as errorUnexpected, a as errorContractValidationFailed, l as errorFileNotFound } from "../cli-errors-DFF1LlfU.mjs";
|
|
3
|
+
import { A as formatStyledHeader, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, l as resolveMigrationPaths, 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
|
+
import { a as formatMigrationShowOutput } from "../migrations-vzQt9LI2.mjs";
|
|
7
6
|
import { Command } from "commander";
|
|
8
7
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
9
8
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
10
9
|
import { isAbsolute, relative, resolve } from "pathe";
|
|
11
10
|
import { readFile } from "node:fs/promises";
|
|
12
11
|
import { APP_SPACE_ID, createControlStack } from "@prisma-next/framework-components/control";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { spaceMigrationDirectory } from "@prisma-next/migration-tools/spaces";
|
|
16
|
-
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
17
|
-
import { readRefs } from "@prisma-next/migration-tools/refs";
|
|
12
|
+
import { loadContractSpaceAggregate } from "@prisma-next/migration-tools/aggregate";
|
|
13
|
+
import { castAs } from "@prisma-next/utils/casts";
|
|
18
14
|
import { parseMigrationRef } from "@prisma-next/migration-tools/ref-resolution";
|
|
19
15
|
//#region src/commands/migration-show.ts
|
|
20
16
|
function looksLikePath(target) {
|
|
21
17
|
return target.includes("/") || target.includes("\\");
|
|
22
18
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Validate that a path-like `migration show` target resolves inside the app
|
|
25
|
-
* migrations directory. The returned result is always emitted under
|
|
26
|
-
* `aggregate.app.spaceId`, so accepting an extension-space (or otherwise
|
|
27
|
-
* external) path here would silently mislabel the result. Returns the
|
|
28
|
-
* resolved absolute path on success.
|
|
29
|
-
*
|
|
30
|
-
* `pathe.relative` can return an absolute path when the target cannot be
|
|
31
|
-
* expressed relative to the base (e.g. on Windows when `target` is on a
|
|
32
|
-
* different drive than `appMigrationsDir`). That case does not start with
|
|
33
|
-
* `..`, so the absolute-check below is required to reject cross-drive
|
|
34
|
-
* targets rather than mislabeling them as app-space.
|
|
35
|
-
*/
|
|
36
19
|
function resolveAppTargetPath(target, appMigrationsDir, appMigrationsRelative) {
|
|
37
20
|
const targetPath = resolve(target);
|
|
38
21
|
const relativeToApp = relative(appMigrationsDir, targetPath);
|
|
@@ -42,48 +25,10 @@ function resolveAppTargetPath(target, appMigrationsDir, appMigrationsRelative) {
|
|
|
42
25
|
}));
|
|
43
26
|
return ok(targetPath);
|
|
44
27
|
}
|
|
45
|
-
function
|
|
46
|
-
const
|
|
47
|
-
const matches = packages.filter((p) => p.metadata.migrationHash.startsWith(normalizedPrefix));
|
|
48
|
-
if (matches.length === 1) return ok(matches[0]);
|
|
49
|
-
if (matches.length === 0) return notOk(errorRuntime("No migration found matching prefix", {
|
|
50
|
-
why: `No migration has a migrationHash starting with "${normalizedPrefix}"`,
|
|
51
|
-
fix: "Run `prisma-next migration show` (no argument) to see the latest migration, or check the migrations directory for available packages."
|
|
52
|
-
}));
|
|
53
|
-
return notOk(errorRuntime("Ambiguous hash prefix", {
|
|
54
|
-
why: `Multiple migrations match prefix "${normalizedPrefix}":\n${matches.map((p) => ` ${p.dirName} ${p.metadata.migrationHash}`).join("\n")}`,
|
|
55
|
-
fix: "Provide a longer prefix to uniquely identify the migration."
|
|
56
|
-
}));
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Resolve the latest migration from a space directory.
|
|
60
|
-
*
|
|
61
|
-
* Returns `ok(null)` only when the directory is empty or absent (ENOENT is
|
|
62
|
-
* absorbed by `readMigrationsDir`). If `readMigrationsDir` returned packages
|
|
63
|
-
* but `findLatestMigration` cannot pick a leaf, the on-disk history is
|
|
64
|
-
* corrupt — return a runtime error rather than collapsing it to a `missing`
|
|
65
|
-
* placeholder, which would hide the corruption from the caller.
|
|
66
|
-
*/
|
|
67
|
-
async function resolveLatestFromDir(spaceDir) {
|
|
68
|
-
try {
|
|
69
|
-
const allPackages = await readMigrationsDir(spaceDir);
|
|
70
|
-
if (allPackages.length === 0) return ok(null);
|
|
71
|
-
const latestMigration = findLatestMigration(reconstructGraph(allPackages));
|
|
72
|
-
if (!latestMigration) return notOk(errorRuntime("Could not resolve latest migration", {
|
|
73
|
-
why: `No latest migration found in ${relative(process.cwd(), spaceDir)}`,
|
|
74
|
-
fix: "The migrations directory may be corrupted. Inspect the migration.json files."
|
|
75
|
-
}));
|
|
76
|
-
return ok(allPackages.find((p) => p.metadata.migrationHash === latestMigration.migrationHash) ?? null);
|
|
77
|
-
} catch (error) {
|
|
78
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
79
|
-
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read migrations: ${error instanceof Error ? error.message : String(error)}` }));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function pkgToSpaceResult(spaceId, pkg, client) {
|
|
83
|
-
const ops = pkg.ops;
|
|
28
|
+
function pkgToPresent(spaceId, pkg, client) {
|
|
29
|
+
const ops = castAs(pkg.ops);
|
|
84
30
|
const preview = client.toOperationPreview(ops) ?? { statements: [] };
|
|
85
31
|
return {
|
|
86
|
-
kind: "present",
|
|
87
32
|
spaceId,
|
|
88
33
|
dirName: pkg.dirName,
|
|
89
34
|
dirPath: relative(process.cwd(), pkg.dirPath),
|
|
@@ -100,34 +45,37 @@ function pkgToSpaceResult(spaceId, pkg, client) {
|
|
|
100
45
|
summary: `${ops.length} operation(s)`
|
|
101
46
|
};
|
|
102
47
|
}
|
|
48
|
+
function findPackageByDirPath(packages, resolvedDirPath) {
|
|
49
|
+
const normalized = resolve(resolvedDirPath);
|
|
50
|
+
return packages.find((p) => resolve(p.dirPath) === normalized);
|
|
51
|
+
}
|
|
103
52
|
async function executeMigrationShowCommand(target, options, flags, ui) {
|
|
104
53
|
const config = await loadConfig(options.config);
|
|
105
|
-
const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative
|
|
54
|
+
const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);
|
|
106
55
|
const contractPathAbsolute = resolveContractPath(config);
|
|
107
56
|
const contractPath = relative(process.cwd(), contractPathAbsolute);
|
|
108
57
|
if (!flags.json && !flags.quiet) {
|
|
109
|
-
const details = [
|
|
110
|
-
{
|
|
111
|
-
label: "config",
|
|
112
|
-
value: configPath
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
label: "contract",
|
|
116
|
-
value: contractPath
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
label: "migrations",
|
|
120
|
-
value: appMigrationsRelative
|
|
121
|
-
}
|
|
122
|
-
];
|
|
123
|
-
if (target) details.push({
|
|
124
|
-
label: "target",
|
|
125
|
-
value: target
|
|
126
|
-
});
|
|
127
58
|
const header = formatStyledHeader({
|
|
128
59
|
command: "migration show",
|
|
129
60
|
description: "Display migration package contents",
|
|
130
|
-
details
|
|
61
|
+
details: [
|
|
62
|
+
{
|
|
63
|
+
label: "config",
|
|
64
|
+
value: configPath
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
label: "contract",
|
|
68
|
+
value: contractPath
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
label: "migrations",
|
|
72
|
+
value: appMigrationsRelative
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
label: "target",
|
|
76
|
+
value: target
|
|
77
|
+
}
|
|
78
|
+
],
|
|
131
79
|
flags
|
|
132
80
|
});
|
|
133
81
|
ui.stderr(header);
|
|
@@ -139,38 +87,6 @@ async function executeMigrationShowCommand(target, options, flags, ui) {
|
|
|
139
87
|
...ifDefined("driver", config.driver),
|
|
140
88
|
extensionPacks: config.extensionPacks ?? []
|
|
141
89
|
});
|
|
142
|
-
if (target) try {
|
|
143
|
-
let appPkg;
|
|
144
|
-
if (looksLikePath(target)) {
|
|
145
|
-
const resolved = resolveAppTargetPath(target, appMigrationsDir, appMigrationsRelative);
|
|
146
|
-
if (!resolved.ok) return resolved;
|
|
147
|
-
appPkg = await readMigrationPackage(resolved.value);
|
|
148
|
-
} else {
|
|
149
|
-
const allPackages = await readMigrationsDir(appMigrationsDir);
|
|
150
|
-
if (allPackages.length === 0) return notOk(errorRuntime("No migrations found", {
|
|
151
|
-
why: `No migration packages found in ${appMigrationsRelative}`,
|
|
152
|
-
fix: "Run `prisma-next migration plan` to create a migration first."
|
|
153
|
-
}));
|
|
154
|
-
const migResult = parseMigrationRef(target, {
|
|
155
|
-
graph: reconstructGraph(allPackages),
|
|
156
|
-
refs: await readRefs(refsDir)
|
|
157
|
-
});
|
|
158
|
-
if (!migResult.ok) return notOk(mapRefResolutionError(migResult.failure));
|
|
159
|
-
const matchedPkg = allPackages.find((p) => p.metadata.migrationHash === migResult.value.migrationHash);
|
|
160
|
-
if (!matchedPkg) return notOk(errorRuntime("Migration package not found", {
|
|
161
|
-
why: `Resolved migration "${migResult.value.dirName}" but the package was not loaded`,
|
|
162
|
-
fix: "The migrations directory may be corrupted. Inspect the migration.json files."
|
|
163
|
-
}));
|
|
164
|
-
appPkg = matchedPkg;
|
|
165
|
-
}
|
|
166
|
-
return ok({
|
|
167
|
-
ok: true,
|
|
168
|
-
spaces: [pkgToSpaceResult(APP_SPACE_ID, appPkg, client)]
|
|
169
|
-
});
|
|
170
|
-
} catch (error) {
|
|
171
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
172
|
-
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read app-space migration: ${error instanceof Error ? error.message : String(error)}` }));
|
|
173
|
-
}
|
|
174
90
|
let contractJsonContent;
|
|
175
91
|
try {
|
|
176
92
|
contractJsonContent = await readFile(contractPathAbsolute, "utf-8");
|
|
@@ -185,60 +101,54 @@ async function executeMigrationShowCommand(target, options, flags, ui) {
|
|
|
185
101
|
const familyInstance = config.family.create(stack);
|
|
186
102
|
let appContract;
|
|
187
103
|
try {
|
|
188
|
-
appContract = familyInstance.deserializeContract(JSON.parse(contractJsonContent));
|
|
104
|
+
appContract = familyInstance.deserializeContract(castAs(JSON.parse(contractJsonContent)));
|
|
189
105
|
} catch (error) {
|
|
190
106
|
return notOk(errorContractValidationFailed(`Contract at ${contractPathAbsolute} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`, { where: { path: contractPathAbsolute } }));
|
|
191
107
|
}
|
|
192
|
-
const
|
|
193
|
-
targetId: config.target.targetId,
|
|
108
|
+
const aggregate = await loadContractSpaceAggregate({
|
|
194
109
|
migrationsDir,
|
|
195
110
|
appContract,
|
|
196
|
-
extensionPacks: config.extensionPacks ?? [],
|
|
197
111
|
deserializeContract: (json) => familyInstance.deserializeContract(json)
|
|
198
112
|
});
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
113
|
+
const packages = aggregate.app.packages;
|
|
114
|
+
const graph = aggregate.app.graph();
|
|
115
|
+
const refs = aggregate.app.refs;
|
|
116
|
+
let appPkg;
|
|
117
|
+
if (looksLikePath(target)) {
|
|
118
|
+
const resolved = resolveAppTargetPath(target, appMigrationsDir, appMigrationsRelative);
|
|
119
|
+
if (!resolved.ok) return resolved;
|
|
120
|
+
const matched = findPackageByDirPath(packages, resolved.value);
|
|
121
|
+
if (!matched) return notOk(errorRuntime("Migration package not found", {
|
|
122
|
+
why: `No loaded migration package at ${relative(process.cwd(), resolved.value)}`,
|
|
123
|
+
fix: "Pass a directory name, hash prefix, or path to an on-disk app-space migration package."
|
|
124
|
+
}));
|
|
125
|
+
appPkg = matched;
|
|
126
|
+
} else {
|
|
127
|
+
if (packages.length === 0) return notOk(errorRuntime("No migrations found", {
|
|
205
128
|
why: `No migration packages found in ${appMigrationsRelative}`,
|
|
206
129
|
fix: "Run `prisma-next migration plan` to create a migration first."
|
|
207
130
|
}));
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const
|
|
214
|
-
if (!
|
|
215
|
-
why: `
|
|
131
|
+
const migResult = parseMigrationRef(target, {
|
|
132
|
+
graph,
|
|
133
|
+
refs
|
|
134
|
+
});
|
|
135
|
+
if (!migResult.ok) return notOk(mapRefResolutionError(migResult.failure));
|
|
136
|
+
const matchedPkg = packages.find((p) => p.metadata.migrationHash === migResult.value.migrationHash);
|
|
137
|
+
if (!matchedPkg) return notOk(errorRuntime("Migration package not found", {
|
|
138
|
+
why: `Resolved migration "${migResult.value.dirName}" but the package was not loaded`,
|
|
216
139
|
fix: "The migrations directory may be corrupted. Inspect the migration.json files."
|
|
217
140
|
}));
|
|
218
|
-
|
|
219
|
-
} catch (error) {
|
|
220
|
-
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
221
|
-
return notOk(errorUnexpected(error instanceof Error ? error.message : String(error), { why: `Failed to read app-space migration: ${error instanceof Error ? error.message : String(error)}` }));
|
|
222
|
-
}
|
|
223
|
-
for (const ext of aggregate.extensions) {
|
|
224
|
-
const extPkgResult = await resolveLatestFromDir(spaceMigrationDirectory(migrationsDir, ext.spaceId));
|
|
225
|
-
if (!extPkgResult.ok) return extPkgResult;
|
|
226
|
-
if (extPkgResult.value !== null) spaces.push(pkgToSpaceResult(ext.spaceId, extPkgResult.value, client));
|
|
227
|
-
else spaces.push({
|
|
228
|
-
kind: "missing",
|
|
229
|
-
spaceId: ext.spaceId,
|
|
230
|
-
summary: "No on-disk migration package for this space"
|
|
231
|
-
});
|
|
141
|
+
appPkg = matchedPkg;
|
|
232
142
|
}
|
|
233
143
|
return ok({
|
|
234
144
|
ok: true,
|
|
235
|
-
|
|
145
|
+
migration: pkgToPresent(APP_SPACE_ID, appPkg, client)
|
|
236
146
|
});
|
|
237
147
|
}
|
|
238
148
|
function createMigrationShowCommand() {
|
|
239
149
|
const command = new Command("show");
|
|
240
|
-
setCommandDescriptions(command, "Display migration package contents", "Shows the operations, statement preview, and metadata for
|
|
241
|
-
setCommandExamples(command, ["prisma-next migration show", "prisma-next migration show sha256:a1b2c3"]);
|
|
150
|
+
setCommandDescriptions(command, "Display migration package contents", "Shows the operations, statement preview, and metadata for one app-space migration.\nAccepts a directory path, directory name, or hash prefix.");
|
|
151
|
+
setCommandExamples(command, ["prisma-next migration show 20260101_100000_add_user", "prisma-next migration show sha256:a1b2c3"]);
|
|
242
152
|
setCommandSeeAlso(command, [
|
|
243
153
|
{
|
|
244
154
|
verb: "migration status",
|
|
@@ -257,7 +167,7 @@ function createMigrationShowCommand() {
|
|
|
257
167
|
oneLiner: "Show the migration graph topology"
|
|
258
168
|
}
|
|
259
169
|
]);
|
|
260
|
-
addGlobalOptions(command).argument("
|
|
170
|
+
addGlobalOptions(command).argument("<target>", "Migration reference: directory name, hash/prefix, or path").option("--config <path>", "Path to prisma-next.config.ts").action(async (target, options) => {
|
|
261
171
|
const flags = parseGlobalFlagsOrExit(options);
|
|
262
172
|
const ui = createTerminalUI(flags);
|
|
263
173
|
const exitCode = handleResult(await executeMigrationShowCommand(target, options, flags, ui), flags, ui, (showResult) => {
|
|
@@ -269,6 +179,6 @@ function createMigrationShowCommand() {
|
|
|
269
179
|
return command;
|
|
270
180
|
}
|
|
271
181
|
//#endregion
|
|
272
|
-
export { createMigrationShowCommand, resolveAppTargetPath
|
|
182
|
+
export { createMigrationShowCommand, resolveAppTargetPath };
|
|
273
183
|
|
|
274
184
|
//# sourceMappingURL=migration-show.mjs.map
|