prisma-next 0.11.0-dev.7 → 0.11.0-dev.8
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-errors-Bw2GlweY.mjs +175 -0
- package/dist/cli-errors-Bw2GlweY.mjs.map +1 -0
- package/dist/cli.mjs +7 -7
- package/dist/{client-oXO2WCPD.mjs → client-UnIveZxZ.mjs} +4 -4
- package/dist/{client-oXO2WCPD.mjs.map → client-UnIveZxZ.mjs.map} +1 -1
- package/dist/{command-helpers-DtavI0wJ.mjs → command-helpers-CRfjbZRz.mjs} +2 -2
- package/dist/{command-helpers-DtavI0wJ.mjs.map → command-helpers-CRfjbZRz.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.d.mts.map +1 -1
- package/dist/commands/db-init.mjs +33 -6
- package/dist/commands/db-init.mjs.map +1 -1
- package/dist/commands/db-schema.mjs +3 -3
- package/dist/commands/db-sign.mjs +5 -5
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +36 -7
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +5 -1
- package/dist/commands/migrate.d.mts.map +1 -1
- package/dist/commands/migrate.mjs +44 -8
- package/dist/commands/migrate.mjs.map +1 -1
- package/dist/commands/migration-check.mjs +2 -2
- package/dist/commands/migration-graph.mjs +3 -3
- package/dist/commands/migration-list.mjs +2 -2
- package/dist/commands/migration-log.mjs +3 -3
- package/dist/commands/migration-new.mjs +3 -3
- package/dist/commands/migration-plan.d.mts +1 -0
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.mjs +6 -6
- package/dist/commands/migration-status.mjs +7 -7
- package/dist/commands/ref.d.mts +1 -1
- package/dist/commands/ref.d.mts.map +1 -1
- package/dist/commands/ref.mjs +34 -8
- package/dist/commands/ref.mjs.map +1 -1
- package/dist/{contract-emit-o-8VmdQX.mjs → contract-emit-C6rlsljO.mjs} +3 -3
- package/dist/{contract-emit-o-8VmdQX.mjs.map → contract-emit-C6rlsljO.mjs.map} +1 -1
- package/dist/{contract-emit-CmsklifJ.mjs → contract-emit-mqXmapxB.mjs} +4 -4
- package/dist/{contract-emit-CmsklifJ.mjs.map → contract-emit-mqXmapxB.mjs.map} +1 -1
- package/dist/{contract-infer-pKkiCt7C.mjs → contract-infer-C4jxc1aZ.mjs} +3 -3
- package/dist/{contract-infer-pKkiCt7C.mjs.map → contract-infer-C4jxc1aZ.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-BmNQwlws.mjs → contract-space-aggregate-loader-CGakRlKM.mjs} +2 -2
- package/dist/{contract-space-aggregate-loader-BmNQwlws.mjs.map → contract-space-aggregate-loader-CGakRlKM.mjs.map} +1 -1
- package/dist/{db-verify-AoIUriL4.mjs → db-verify-1d8tDoFN.mjs} +5 -5
- package/dist/{db-verify-AoIUriL4.mjs.map → db-verify-1d8tDoFN.mjs.map} +1 -1
- package/dist/exports/control-api.d.mts +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{framework-components-65gOHkHB.mjs → framework-components-Bexd0f4E.mjs} +2 -2
- package/dist/{framework-components-65gOHkHB.mjs.map → framework-components-Bexd0f4E.mjs.map} +1 -1
- package/dist/{graph-render-DJVv0_uf.mjs → graph-render-BE8vmJ_7.mjs} +1 -1
- package/dist/{graph-render-DJVv0_uf.mjs.map → graph-render-BE8vmJ_7.mjs.map} +1 -1
- package/dist/{init-Db5Itt5r.mjs → init-ByoeQphC.mjs} +4 -4
- package/dist/{init-Db5Itt5r.mjs.map → init-ByoeQphC.mjs.map} +1 -1
- package/dist/{inspect-live-schema-LeWvkZVz.mjs → inspect-live-schema-B1Q49RF0.mjs} +4 -4
- package/dist/{inspect-live-schema-LeWvkZVz.mjs.map → inspect-live-schema-B1Q49RF0.mjs.map} +1 -1
- package/dist/{migration-command-scaffold-BtkunvFQ.mjs → migration-command-scaffold-oY4P1Qto.mjs} +4 -4
- package/dist/{migration-command-scaffold-BtkunvFQ.mjs.map → migration-command-scaffold-oY4P1Qto.mjs.map} +1 -1
- package/dist/{migration-plan-C2jeH1J5.mjs → migration-plan-jdAHg_gK.mjs} +346 -87
- package/dist/migration-plan-jdAHg_gK.mjs.map +1 -0
- package/dist/{migrations-CwZMa1Ck.mjs → migrations-B7n518mT.mjs} +10 -1
- package/dist/migrations-B7n518mT.mjs.map +1 -0
- package/dist/{output-BlsrGMEF.mjs → output-CUIdfYo5.mjs} +1 -1
- package/dist/{output-BlsrGMEF.mjs.map → output-CUIdfYo5.mjs.map} +1 -1
- package/dist/ref-advancement-DRh5Nquq.mjs +50 -0
- package/dist/ref-advancement-DRh5Nquq.mjs.map +1 -0
- package/dist/{types-C9FfXb1l.d.mts → types-UWB2-rrw.d.mts} +5 -4
- package/dist/types-UWB2-rrw.d.mts.map +1 -0
- package/dist/{verify-Bom75OYI.mjs → verify-C5UvbrF1.mjs} +1 -1
- package/dist/{verify-Bom75OYI.mjs.map → verify-C5UvbrF1.mjs.map} +1 -1
- package/package.json +11 -11
- package/dist/cli-errors-Czmx92Zy.d.mts +0 -3
- package/dist/cli-errors-Djtz98Vm.mjs +0 -71
- package/dist/cli-errors-Djtz98Vm.mjs.map +0 -1
- package/dist/migration-plan-C2jeH1J5.mjs.map +0 -1
- package/dist/migrations-CwZMa1Ck.mjs.map +0 -1
- package/dist/types-C9FfXb1l.d.mts.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import { c as errorDriverRequired, o as errorDatabaseConnectionRequired, t as CliStructuredError
|
|
3
|
-
import { S as formatStyledHeader, o as maskConnectionUrl, u as sanitizeErrorMessage } from "./command-helpers-
|
|
2
|
+
import { E as errorUnexpected, c as errorDriverRequired, o as errorDatabaseConnectionRequired, t as CliStructuredError } from "./cli-errors-Bw2GlweY.mjs";
|
|
3
|
+
import { S as formatStyledHeader, o as maskConnectionUrl, u as sanitizeErrorMessage } from "./command-helpers-CRfjbZRz.mjs";
|
|
4
4
|
import { t as createProgressAdapter } from "./progress-adapter-DFfvZcYL.mjs";
|
|
5
|
-
import { t as createControlClient } from "./client-
|
|
5
|
+
import { t as createControlClient } from "./client-UnIveZxZ.mjs";
|
|
6
6
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
7
|
import { relative, resolve } from "pathe";
|
|
8
8
|
//#region src/commands/inspect-live-schema.ts
|
|
@@ -87,4 +87,4 @@ async function inspectLiveSchema(options, flags, ui, startTime, context) {
|
|
|
87
87
|
//#endregion
|
|
88
88
|
export { inspectLiveSchema as t };
|
|
89
89
|
|
|
90
|
-
//# sourceMappingURL=inspect-live-schema-
|
|
90
|
+
//# sourceMappingURL=inspect-live-schema-B1Q49RF0.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspect-live-schema-
|
|
1
|
+
{"version":3,"file":"inspect-live-schema-B1Q49RF0.mjs","names":[],"sources":["../src/commands/inspect-live-schema.ts"],"sourcesContent":["import type { CoreSchemaView } from '@prisma-next/framework-components/control';\nimport type { PslDocumentAst } from '@prisma-next/framework-components/psl-ast';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { relative, resolve } from 'pathe';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport {\n CliStructuredError,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorUnexpected,\n} from '../utils/cli-errors';\nimport { maskConnectionUrl, sanitizeErrorMessage } from '../utils/command-helpers';\nimport { formatStyledHeader } from '../utils/formatters/styled';\nimport type { CommonCommandOptions, GlobalFlags } from '../utils/global-flags';\nimport { createProgressAdapter } from '../utils/progress-adapter';\nimport type { TerminalUI } from '../utils/terminal-ui';\n\nexport interface InspectLiveSchemaOptions extends CommonCommandOptions {\n readonly db?: string;\n readonly config?: string;\n}\n\ninterface InspectLiveSchemaContext {\n readonly commandName: string;\n readonly description: string;\n readonly url: string;\n}\n\ntype LoadedCliConfig = Awaited<ReturnType<typeof loadConfig>>;\n\nexport interface InspectLiveSchemaResult {\n readonly config: LoadedCliConfig;\n readonly schema: unknown;\n readonly schemaView: CoreSchemaView | undefined;\n /**\n * PSL AST inferred from the introspected schema, when the configured family\n * implements `PslContractInferCapable`. `undefined` for families that do not\n * support inference (e.g. Mongo today).\n */\n readonly pslContractAst: PslDocumentAst | undefined;\n readonly target: {\n readonly familyId: string;\n readonly id: string;\n };\n readonly meta: {\n readonly configPath?: string;\n readonly dbUrl?: string;\n };\n readonly timings: {\n readonly total: number;\n };\n}\n\nexport async function inspectLiveSchema(\n options: InspectLiveSchemaOptions,\n flags: GlobalFlags,\n ui: TerminalUI,\n startTime: number,\n context: InspectLiveSchemaContext,\n): Promise<Result<InspectLiveSchemaResult, CliStructuredError>> {\n let config: LoadedCliConfig;\n try {\n config = await loadConfig(options.config);\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: 'Failed to load config',\n }),\n );\n }\n\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n ];\n\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n } else if (config.db?.connection && typeof config.db.connection === 'string') {\n details.push({ label: 'database', value: maskConnectionUrl(config.db.connection) });\n }\n\n ui.stderr(\n formatStyledHeader({\n command: context.commandName,\n description: context.description,\n url: context.url,\n details,\n flags,\n }),\n );\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 ${context.commandName} (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: context.commandName,\n }),\n );\n }\n\n if (!config.driver) {\n return notOk(\n errorDriverRequired({\n why: `Config.driver is required for ${context.commandName}`,\n }),\n );\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 const onProgress = createProgressAdapter({ ui, flags });\n\n try {\n const schema = await client.introspect({\n connection: dbConnection,\n onProgress,\n });\n const schemaView = client.toSchemaView(schema);\n const pslContractAst = client.inferPslContract(schema);\n\n const dbUrl = typeof dbConnection === 'string' ? maskConnectionUrl(dbConnection) : undefined;\n\n return ok({\n config,\n schema,\n schemaView,\n pslContractAst,\n target: {\n familyId: config.family.familyId,\n id: config.target.targetId,\n },\n meta: {\n configPath,\n ...(dbUrl ? { dbUrl } : {}),\n },\n timings: {\n total: Date.now() - startTime,\n },\n });\n } catch (error) {\n if (CliStructuredError.is(error)) {\n return notOk(error);\n }\n\n const rawMessage = error instanceof Error ? error.message : String(error);\n const safeMessage = sanitizeErrorMessage(\n rawMessage,\n typeof dbConnection === 'string' ? dbConnection : undefined,\n );\n return notOk(\n errorUnexpected(safeMessage, {\n why: `Unexpected error during ${context.commandName}: ${safeMessage}`,\n }),\n );\n } finally {\n await client.close();\n }\n}\n"],"mappings":";;;;;;;;AAsDA,eAAsB,kBACpB,SACA,OACA,IACA,WACA,SAC8D;CAC9D,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,WAAW,QAAQ,OAAO;UAClC,OAAO;EACd,IAAI,mBAAmB,GAAG,MAAM,EAC9B,OAAO,MAAM,MAAM;EAGrB,OAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,yBACN,CAAC,CACH;;CAGH,MAAM,aAAa,QAAQ,SACvB,SAAS,QAAQ,KAAK,EAAE,QAAQ,QAAQ,OAAO,CAAC,GAChD;CAEJ,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAM,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,CACvC;EAED,IAAI,QAAQ,IACV,QAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;OACpE,IAAI,OAAO,IAAI,cAAc,OAAO,OAAO,GAAG,eAAe,UAClE,QAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,OAAO,GAAG,WAAW;GAAE,CAAC;EAGrF,GAAG,OACD,mBAAmB;GACjB,SAAS,QAAQ;GACjB,aAAa,QAAQ;GACrB,KAAK,QAAQ;GACb;GACA;GACD,CAAC,CACH;;CAGH,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;CAC9C,IAAI,CAAC,cACH,OAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,QAAQ,YAAY,yBAAyB,WAAW;EACpG,aAAa,QAAQ;EACtB,CAAC,CACH;CAGH,IAAI,CAAC,OAAO,QACV,OAAO,MACL,oBAAoB,EAClB,KAAK,iCAAiC,QAAQ,eAC/C,CAAC,CACH;CAGH,MAAM,SAAS,oBAAoB;EACjC,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,gBAAgB,OAAO,kBAAkB,EAAE;EAC5C,CAAC;CACF,MAAM,aAAa,sBAAsB;EAAE;EAAI;EAAO,CAAC;CAEvD,IAAI;EACF,MAAM,SAAS,MAAM,OAAO,WAAW;GACrC,YAAY;GACZ;GACD,CAAC;EACF,MAAM,aAAa,OAAO,aAAa,OAAO;EAC9C,MAAM,iBAAiB,OAAO,iBAAiB,OAAO;EAEtD,MAAM,QAAQ,OAAO,iBAAiB,WAAW,kBAAkB,aAAa,GAAG,KAAA;EAEnF,OAAO,GAAG;GACR;GACA;GACA;GACA;GACA,QAAQ;IACN,UAAU,OAAO,OAAO;IACxB,IAAI,OAAO,OAAO;IACnB;GACD,MAAM;IACJ;IACA,GAAI,QAAQ,EAAE,OAAO,GAAG,EAAE;IAC3B;GACD,SAAS,EACP,OAAO,KAAK,KAAK,GAAG,WACrB;GACF,CAAC;UACK,OAAO;EACd,IAAI,mBAAmB,GAAG,MAAM,EAC9B,OAAO,MAAM,MAAM;EAIrB,MAAM,cAAc,qBADD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAGvE,OAAO,iBAAiB,WAAW,eAAe,KAAA,EACnD;EACD,OAAO,MACL,gBAAgB,aAAa,EAC3B,KAAK,2BAA2B,QAAQ,YAAY,IAAI,eACzD,CAAC,CACH;WACO;EACR,MAAM,OAAO,OAAO"}
|
package/dist/{migration-command-scaffold-BtkunvFQ.mjs → migration-command-scaffold-oY4P1Qto.mjs}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { S as formatStyledHeader, c as resolveContractPath, o as maskConnectionUrl, t as addGlobalOptions } from "./command-helpers-
|
|
2
|
+
import { E as errorUnexpected, a as errorContractValidationFailed, c as errorDriverRequired, l as errorFileNotFound, o as errorDatabaseConnectionRequired, w as errorTargetMigrationNotSupported } from "./cli-errors-Bw2GlweY.mjs";
|
|
3
|
+
import { S as formatStyledHeader, c as resolveContractPath, o as maskConnectionUrl, t as addGlobalOptions } from "./command-helpers-CRfjbZRz.mjs";
|
|
4
4
|
import { t as createProgressAdapter } from "./progress-adapter-DFfvZcYL.mjs";
|
|
5
|
-
import { t as createControlClient } from "./client-
|
|
5
|
+
import { t as createControlClient } from "./client-UnIveZxZ.mjs";
|
|
6
6
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
7
7
|
import { readFile } from "node:fs/promises";
|
|
8
8
|
import { hasMigrations } from "@prisma-next/framework-components/control";
|
|
@@ -101,4 +101,4 @@ function addMigrationCommandOptions(command) {
|
|
|
101
101
|
//#endregion
|
|
102
102
|
export { prepareMigrationContext as n, addMigrationCommandOptions as t };
|
|
103
103
|
|
|
104
|
-
//# sourceMappingURL=migration-command-scaffold-
|
|
104
|
+
//# sourceMappingURL=migration-command-scaffold-oY4P1Qto.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration-command-scaffold-
|
|
1
|
+
{"version":3,"file":"migration-command-scaffold-oY4P1Qto.mjs","names":[],"sources":["../src/utils/migration-command-scaffold.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { relative, resolve } from 'node:path';\nimport { hasMigrations } from '@prisma-next/framework-components/control';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport type { Command } from 'commander';\nimport { loadConfig } from '../config-loader';\nimport { createControlClient } from '../control-api/client';\nimport type { ControlClient } from '../control-api/types';\nimport {\n type CliStructuredError,\n errorContractValidationFailed,\n errorDatabaseConnectionRequired,\n errorDriverRequired,\n errorFileNotFound,\n errorTargetMigrationNotSupported,\n errorUnexpected,\n} from './cli-errors';\nimport { addGlobalOptions, maskConnectionUrl, resolveContractPath } from './command-helpers';\nimport { formatStyledHeader } from './formatters/styled';\nimport type { GlobalFlags } from './global-flags';\nimport { createProgressAdapter } from './progress-adapter';\nimport type { TerminalUI } from './terminal-ui';\n\n/**\n * Resolved context for a migration command.\n * Contains everything needed to invoke a control-api operation.\n */\nexport interface MigrationContext {\n readonly client: ControlClient;\n readonly contractJson: Record<string, unknown>;\n readonly dbConnection: unknown;\n readonly onProgress: ReturnType<typeof createProgressAdapter>;\n readonly configPath: string;\n readonly contractPath: string;\n readonly contractPathAbsolute: string;\n readonly config: Awaited<ReturnType<typeof loadConfig>>;\n}\n\n/**\n * Command-specific configuration for the shared scaffold.\n */\nexport interface MigrationCommandDescriptor {\n readonly commandName: string;\n readonly description: string;\n readonly url: string;\n}\n\n/**\n * Prepares the shared context for migration commands (db init, db update).\n *\n * Handles: config loading, contract file reading, JSON parsing, connection resolution,\n * driver/migration-support validation, client creation, and header output.\n *\n * Returns a Result with either the resolved context or a structured error.\n */\nexport async function prepareMigrationContext(\n options: { readonly db?: string; readonly config?: string; readonly dryRun?: boolean },\n flags: GlobalFlags,\n ui: TerminalUI,\n descriptor: MigrationCommandDescriptor,\n): Promise<Result<MigrationContext, CliStructuredError>> {\n // Load config\n const config = await loadConfig(options.config);\n const configPath = options.config\n ? relative(process.cwd(), resolve(options.config))\n : 'prisma-next.config.ts';\n const contractPathAbsolute = resolveContractPath(config);\n const contractPath = relative(process.cwd(), contractPathAbsolute);\n\n // Output header to stderr (decoration)\n if (!flags.json && !flags.quiet) {\n const details: Array<{ label: string; value: string }> = [\n { label: 'config', value: configPath },\n { label: 'contract', value: contractPath },\n ];\n if (options.db) {\n details.push({ label: 'database', value: maskConnectionUrl(options.db) });\n }\n if (options.dryRun) {\n details.push({ label: 'mode', value: 'dry run' });\n }\n const header = formatStyledHeader({\n command: descriptor.commandName,\n description: descriptor.description,\n url: descriptor.url,\n details,\n flags,\n });\n ui.stderr(header);\n }\n\n // Load contract file\n let contractJsonContent: string;\n try {\n contractJsonContent = await readFile(contractPathAbsolute, 'utf-8');\n } catch (error) {\n if (error instanceof Error && (error as { code?: string }).code === 'ENOENT') {\n return notOk(\n errorFileNotFound(contractPathAbsolute, {\n why: `Contract file not found at ${contractPathAbsolute}`,\n fix: `Run \\`prisma-next contract emit\\` to generate ${contractPath}, or update \\`config.contract.output\\` in ${configPath}`,\n }),\n );\n }\n return notOk(\n errorUnexpected(error instanceof Error ? error.message : String(error), {\n why: `Failed to read contract file: ${error instanceof Error ? error.message : String(error)}`,\n }),\n );\n }\n\n // Parse contract JSON\n let contractJson: Record<string, unknown>;\n try {\n contractJson = JSON.parse(contractJsonContent) as Record<string, unknown>;\n } catch (error) {\n return notOk(\n errorContractValidationFailed(\n `Contract JSON is invalid: ${error instanceof Error ? error.message : String(error)}`,\n { where: { path: contractPathAbsolute } },\n ),\n );\n }\n\n // Resolve database connection (--db flag or config.db.connection)\n const dbConnection = options.db ?? config.db?.connection;\n if (!dbConnection) {\n return notOk(\n errorDatabaseConnectionRequired({\n why: `Database connection is required for ${descriptor.commandName} (set db.connection in ${configPath}, or pass --db <url>)`,\n commandName: descriptor.commandName,\n }),\n );\n }\n\n // Check for driver\n if (!config.driver) {\n return notOk(\n errorDriverRequired({ why: `Config.driver is required for ${descriptor.commandName}` }),\n );\n }\n\n if (!hasMigrations(config.target)) {\n return notOk(\n errorTargetMigrationNotSupported({\n why: `Target \"${config.target.id}\" does not support migrations`,\n }),\n );\n }\n\n // Create control client\n const client = createControlClient({\n family: config.family,\n target: config.target,\n adapter: config.adapter,\n driver: config.driver,\n extensionPacks: config.extensionPacks ?? [],\n });\n\n // Create progress adapter\n const onProgress = createProgressAdapter({ ui, flags });\n\n return ok({\n client,\n contractJson,\n dbConnection,\n onProgress,\n configPath,\n contractPath,\n contractPathAbsolute,\n config,\n });\n}\n\n/**\n * Registers the shared CLI options for migration commands (db init, db update).\n */\nexport function addMigrationCommandOptions(command: Command): Command {\n addGlobalOptions(command);\n return command\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--dry-run', 'Preview planned operations without applying', false);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAuDA,eAAsB,wBACpB,SACA,OACA,IACA,YACuD;CAEvD,MAAM,SAAS,MAAM,WAAW,QAAQ,OAAO;CAC/C,MAAM,aAAa,QAAQ,SACvB,SAAS,QAAQ,KAAK,EAAE,QAAQ,QAAQ,OAAO,CAAC,GAChD;CACJ,MAAM,uBAAuB,oBAAoB,OAAO;CACxD,MAAM,eAAe,SAAS,QAAQ,KAAK,EAAE,qBAAqB;CAGlE,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAM,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,EACtC;GAAE,OAAO;GAAY,OAAO;GAAc,CAC3C;EACD,IAAI,QAAQ,IACV,QAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;EAE3E,IAAI,QAAQ,QACV,QAAQ,KAAK;GAAE,OAAO;GAAQ,OAAO;GAAW,CAAC;EAEnD,MAAM,SAAS,mBAAmB;GAChC,SAAS,WAAW;GACpB,aAAa,WAAW;GACxB,KAAK,WAAW;GAChB;GACA;GACD,CAAC;EACF,GAAG,OAAO,OAAO;;CAInB,IAAI;CACJ,IAAI;EACF,sBAAsB,MAAM,SAAS,sBAAsB,QAAQ;UAC5D,OAAO;EACd,IAAI,iBAAiB,SAAU,MAA4B,SAAS,UAClE,OAAO,MACL,kBAAkB,sBAAsB;GACtC,KAAK,8BAA8B;GACnC,KAAK,iDAAiD,aAAa,4CAA4C;GAChH,CAAC,CACH;EAEH,OAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC7F,CAAC,CACH;;CAIH,IAAI;CACJ,IAAI;EACF,eAAe,KAAK,MAAM,oBAAoB;UACvC,OAAO;EACd,OAAO,MACL,8BACE,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IACnF,EAAE,OAAO,EAAE,MAAM,sBAAsB,EAAE,CAC1C,CACF;;CAIH,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;CAC9C,IAAI,CAAC,cACH,OAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,WAAW,YAAY,yBAAyB,WAAW;EACvG,aAAa,WAAW;EACzB,CAAC,CACH;CAIH,IAAI,CAAC,OAAO,QACV,OAAO,MACL,oBAAoB,EAAE,KAAK,iCAAiC,WAAW,eAAe,CAAC,CACxF;CAGH,IAAI,CAAC,cAAc,OAAO,OAAO,EAC/B,OAAO,MACL,iCAAiC,EAC/B,KAAK,WAAW,OAAO,OAAO,GAAG,gCAClC,CAAC,CACH;CAIH,MAAM,SAAS,oBAAoB;EACjC,QAAQ,OAAO;EACf,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,QAAQ,OAAO;EACf,gBAAgB,OAAO,kBAAkB,EAAE;EAC5C,CAAC;CAGF,MAAM,aAAa,sBAAsB;EAAE;EAAI;EAAO,CAAC;CAEvD,OAAO,GAAG;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;;;;;AAMJ,SAAgB,2BAA2B,SAA2B;CACpE,iBAAiB,QAAQ;CACzB,OAAO,QACJ,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,aAAa,+CAA+C,MAAM"}
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import { t as loadConfig } from "./config-loader-B6sJjXTv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { t as assertFrameworkComponentsCompatible } from "./framework-components-
|
|
2
|
+
import { C as errorSnapshotMissing, D as mapMigrationToolsError, E as errorUnexpected, O as mapRefResolutionError, _ as errorPlanForgotTheFlag, a as errorContractValidationFailed, l as errorFileNotFound, m as errorMigrationPlanningFailed, t as CliStructuredError, w as errorTargetMigrationNotSupported } from "./cli-errors-Bw2GlweY.mjs";
|
|
3
|
+
import { t as assertFrameworkComponentsCompatible } from "./framework-components-Bexd0f4E.mjs";
|
|
4
4
|
import { t as createTerminalUI } from "./terminal-ui-BiB_8KNo.mjs";
|
|
5
|
-
import { S as formatStyledHeader, a as loadMigrationPackages, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, i as getTargetMigrations, l as resolveMigrationPaths, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "./command-helpers-
|
|
6
|
-
import { n as toExtensionInputs, t as buildContractSpaceAggregate } from "./contract-space-aggregate-loader-
|
|
5
|
+
import { S as formatStyledHeader, a as loadMigrationPackages, c as resolveContractPath, d as setCommandDescriptions, f as setCommandExamples, i as getTargetMigrations, l as resolveMigrationPaths, t as addGlobalOptions, v as parseGlobalFlagsOrExit, y as handleResult } from "./command-helpers-CRfjbZRz.mjs";
|
|
6
|
+
import { n as toExtensionInputs, t as buildContractSpaceAggregate } from "./contract-space-aggregate-loader-CGakRlKM.mjs";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
import { getEmittedArtifactPaths } from "@prisma-next/emitter";
|
|
9
9
|
import { notOk, ok } from "@prisma-next/utils/result";
|
|
10
10
|
import { join, relative } from "pathe";
|
|
11
|
-
import { readFile } from "node:fs/promises";
|
|
11
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
12
12
|
import { createControlStack, hasOperationPreview } from "@prisma-next/framework-components/control";
|
|
13
13
|
import { copyFilesWithRename, formatMigrationDirName, materialiseExtensionMigrationPackageIfMissing, writeMigrationPackage } from "@prisma-next/migration-tools/io";
|
|
14
|
-
import { findLatestMigration } from "@prisma-next/migration-tools/migration-graph";
|
|
14
|
+
import { assertHashIsGraphNode, findLatestMigration, isGraphNode } from "@prisma-next/migration-tools/migration-graph";
|
|
15
15
|
import { emitContractSpaceArtefacts, planAllSpaces, readContractSpaceHeadRef, spaceMigrationDirectory } from "@prisma-next/migration-tools/spaces";
|
|
16
16
|
import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
|
|
17
|
+
import { readRefSnapshot, readRefs } from "@prisma-next/migration-tools/refs";
|
|
17
18
|
import { parseContractRef } from "@prisma-next/migration-tools/ref-resolution";
|
|
18
|
-
import { readRefs } from "@prisma-next/migration-tools/refs";
|
|
19
19
|
import { computeMigrationHash } from "@prisma-next/migration-tools/hash";
|
|
20
20
|
import { writeMigrationTs } from "@prisma-next/migration-tools/migration-ts";
|
|
21
|
+
import { canonicalizeJson } from "@prisma-next/framework-components/utils";
|
|
21
22
|
import { deriveProvidedInvariants } from "@prisma-next/migration-tools/invariants";
|
|
22
23
|
//#region src/utils/contract-space-seed-phase.ts
|
|
23
24
|
/**
|
|
@@ -109,6 +110,135 @@ function buildPlaceholderContractDts(spaceId) {
|
|
|
109
110
|
].join("\n");
|
|
110
111
|
}
|
|
111
112
|
//#endregion
|
|
113
|
+
//#region src/utils/plan-resolution.ts
|
|
114
|
+
const FULL_HASH_PATTERN = /^sha256:([0-9a-f]{64}|empty)$/;
|
|
115
|
+
function looksLikeFullHash(input) {
|
|
116
|
+
return FULL_HASH_PATTERN.test(input);
|
|
117
|
+
}
|
|
118
|
+
function graphIsEmpty(bundles) {
|
|
119
|
+
return bundles.length === 0;
|
|
120
|
+
}
|
|
121
|
+
function getReachableRefs(refs, graph) {
|
|
122
|
+
return Object.entries(refs).flatMap(([name, entry]) => entry && isGraphNode(entry.hash, graph) ? [{
|
|
123
|
+
name,
|
|
124
|
+
hash: entry.hash
|
|
125
|
+
}] : []).sort((a, b) => a.name.localeCompare(b.name));
|
|
126
|
+
}
|
|
127
|
+
function assertFromIsGraphNode(fromHash, graph, refs, graphTipHash) {
|
|
128
|
+
try {
|
|
129
|
+
assertHashIsGraphNode(fromHash, graph);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (MigrationToolsError.is(error) && error.code === "MIGRATION.HASH_NOT_IN_GRAPH") throw errorPlanForgotTheFlag(fromHash, getReachableRefs(refs, graph), graphTipHash);
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function deserializeSnapshotContract(familyInstance, contract) {
|
|
136
|
+
try {
|
|
137
|
+
return ok(familyInstance.deserializeContract(contract));
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (CliStructuredError.is(error)) return notOk(error);
|
|
140
|
+
return notOk(errorContractValidationFailed(`Ref snapshot contract failed to deserialize: ${error instanceof Error ? error.message : String(error)}`, { where: { path: "ref-snapshot" } }));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function resolveGraphNodeFromBundle(fromHash, bundles, readBundleEndContract, explicitFromLabel) {
|
|
144
|
+
const matchingBundle = bundles.find((pkg) => pkg.metadata.to === fromHash);
|
|
145
|
+
if (!matchingBundle) return notOk(errorUnexpected(explicitFromLabel ? `No migration bundle found for --from "${explicitFromLabel}" (resolved hash: ${fromHash})` : `No migration bundle found for graph node ${fromHash}`, {
|
|
146
|
+
why: `The hash ${fromHash} is a graph node but no on-disk migration package has an end-contract hash matching it.`,
|
|
147
|
+
fix: "Provide a ref or hash that corresponds to an existing migration package, or run `migration list` to see available migrations."
|
|
148
|
+
}));
|
|
149
|
+
try {
|
|
150
|
+
return ok({
|
|
151
|
+
kind: "graph-node",
|
|
152
|
+
fromHash,
|
|
153
|
+
fromContract: await readBundleEndContract(matchingBundle.dirPath),
|
|
154
|
+
sourceDir: matchingBundle.dirPath
|
|
155
|
+
});
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (CliStructuredError.is(error)) return notOk(error);
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
async function resolveFromRefName(refName, fromHash, input, refs) {
|
|
162
|
+
const { refsDir, bundles, graph, familyInstance, readBundleEndContract } = input;
|
|
163
|
+
const empty = graphIsEmpty(bundles);
|
|
164
|
+
const graphTip = findLatestMigration(graph)?.to ?? null;
|
|
165
|
+
let snapshot;
|
|
166
|
+
try {
|
|
167
|
+
snapshot = await readRefSnapshot(refsDir, refName);
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
if (snapshot) {
|
|
173
|
+
const contractResult = await deserializeSnapshotContract(familyInstance, snapshot.contract);
|
|
174
|
+
if (!contractResult.ok) return contractResult;
|
|
175
|
+
const fromContract = contractResult.value;
|
|
176
|
+
const { contractDts, contract: contractJson } = snapshot;
|
|
177
|
+
if (empty) return ok({
|
|
178
|
+
kind: "auto-baseline",
|
|
179
|
+
fromHash,
|
|
180
|
+
fromContract,
|
|
181
|
+
contractDts,
|
|
182
|
+
contractJson
|
|
183
|
+
});
|
|
184
|
+
try {
|
|
185
|
+
assertFromIsGraphNode(fromHash, graph, refs, graphTip);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
if (CliStructuredError.is(error)) return notOk(error);
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
return ok({
|
|
191
|
+
kind: "snapshot",
|
|
192
|
+
fromHash,
|
|
193
|
+
fromContract,
|
|
194
|
+
contractDts,
|
|
195
|
+
contractJson
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (isGraphNode(fromHash, graph)) return resolveGraphNodeFromBundle(fromHash, bundles, readBundleEndContract);
|
|
199
|
+
return notOk(errorSnapshotMissing(refName));
|
|
200
|
+
}
|
|
201
|
+
async function resolveFromHashProvenance(fromHash, input, _refs, explicitFromLabel) {
|
|
202
|
+
const { bundles, graph } = input;
|
|
203
|
+
if (isGraphNode(fromHash, graph)) return resolveGraphNodeFromBundle(fromHash, bundles, input.readBundleEndContract, explicitFromLabel);
|
|
204
|
+
throw new Error(`resolveFromHashProvenance: non-graph-node hash ${fromHash} should be refused via looksLikeFullHash before this helper is called`);
|
|
205
|
+
}
|
|
206
|
+
async function resolveFromForPlan(input) {
|
|
207
|
+
const { optionsFrom, refsDir, graph } = input;
|
|
208
|
+
let refs;
|
|
209
|
+
try {
|
|
210
|
+
refs = await readRefs(refsDir);
|
|
211
|
+
} catch (error) {
|
|
212
|
+
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
if (optionsFrom === void 0) {
|
|
216
|
+
const dbRef = refs["db"];
|
|
217
|
+
if (!dbRef) return ok({
|
|
218
|
+
kind: "greenfield",
|
|
219
|
+
fromHash: null,
|
|
220
|
+
fromContract: null
|
|
221
|
+
});
|
|
222
|
+
return resolveFromRefName("db", dbRef.hash, input, refs);
|
|
223
|
+
}
|
|
224
|
+
const refResult = parseContractRef(optionsFrom, {
|
|
225
|
+
graph,
|
|
226
|
+
refs
|
|
227
|
+
});
|
|
228
|
+
if (!refResult.ok) {
|
|
229
|
+
if (looksLikeFullHash(optionsFrom)) {
|
|
230
|
+
const empty = graphIsEmpty(input.bundles);
|
|
231
|
+
const graphTip = findLatestMigration(graph)?.to ?? null;
|
|
232
|
+
if (empty) return notOk(errorSnapshotMissing(optionsFrom, { viaRef: false }));
|
|
233
|
+
return notOk(errorPlanForgotTheFlag(optionsFrom, getReachableRefs(refs, graph), graphTip));
|
|
234
|
+
}
|
|
235
|
+
return notOk(mapRefResolutionError(refResult.failure));
|
|
236
|
+
}
|
|
237
|
+
const { hash: fromHash, provenance } = refResult.value;
|
|
238
|
+
if (provenance.kind === "ref") return resolveFromRefName(provenance.refName, fromHash, input, refs);
|
|
239
|
+
return resolveFromHashProvenance(fromHash, input, refs, optionsFrom);
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
112
242
|
//#region src/commands/migration-plan.ts
|
|
113
243
|
/**
|
|
114
244
|
* Load a predecessor migration's destination contract from its sibling
|
|
@@ -148,6 +278,70 @@ async function readPredecessorEndContract(migrationDir, familyInstance) {
|
|
|
148
278
|
throw errorContractValidationFailed(`Predecessor contract at ${path} failed to deserialize: ${error instanceof Error ? error.message : String(error)}`, { where: { path } });
|
|
149
279
|
}
|
|
150
280
|
}
|
|
281
|
+
async function writeSnapshotContractArtifacts(packageDir, contractJson, contractDts, artifactBasename) {
|
|
282
|
+
await mkdir(packageDir, { recursive: true });
|
|
283
|
+
const jsonContent = `${canonicalizeJson(contractJson)}\n`;
|
|
284
|
+
const dtsContent = contractDts.endsWith("\n") ? contractDts : `${contractDts}\n`;
|
|
285
|
+
await writeFile(join(packageDir, `${artifactBasename}.json`), jsonContent);
|
|
286
|
+
await writeFile(join(packageDir, `${artifactBasename}.d.ts`), dtsContent);
|
|
287
|
+
}
|
|
288
|
+
async function writeSnapshotStartContract(packageDir, contractJson, contractDts) {
|
|
289
|
+
await writeSnapshotContractArtifacts(packageDir, contractJson, contractDts, "start-contract");
|
|
290
|
+
}
|
|
291
|
+
async function runPlannerLeg(planner, migrations, frameworkComponents, contract, fromContract, spaceId) {
|
|
292
|
+
const fromSchema = migrations.contractToSchema(fromContract, frameworkComponents);
|
|
293
|
+
const plannerResult = planner.plan({
|
|
294
|
+
contract,
|
|
295
|
+
schema: fromSchema,
|
|
296
|
+
policy: { allowedOperationClasses: [
|
|
297
|
+
"additive",
|
|
298
|
+
"widening",
|
|
299
|
+
"destructive",
|
|
300
|
+
"data"
|
|
301
|
+
] },
|
|
302
|
+
fromContract,
|
|
303
|
+
frameworkComponents,
|
|
304
|
+
spaceId
|
|
305
|
+
});
|
|
306
|
+
if (plannerResult.kind === "failure") return notOk(errorMigrationPlanningFailed({ conflicts: plannerResult.conflicts }));
|
|
307
|
+
let plannedOps = [];
|
|
308
|
+
let hasPlaceholders = false;
|
|
309
|
+
try {
|
|
310
|
+
plannedOps = plannerResult.plan.operations;
|
|
311
|
+
if (plannedOps.length === 0) return notOk(errorMigrationPlanningFailed({ conflicts: [{
|
|
312
|
+
kind: "unsupportedChange",
|
|
313
|
+
summary: "Contract changed but planner produced no operations. This indicates unsupported or ignored changes."
|
|
314
|
+
}] }));
|
|
315
|
+
} catch (e) {
|
|
316
|
+
if (CliStructuredError.is(e) && e.domain === "MIG" && e.code === "2001") hasPlaceholders = true;
|
|
317
|
+
else throw e;
|
|
318
|
+
}
|
|
319
|
+
return ok({
|
|
320
|
+
plannedOps,
|
|
321
|
+
migrationTsContent: plannerResult.plan.renderTypeScript(),
|
|
322
|
+
hasPlaceholders
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
async function writePlannedMigrationPackage(packageDir, fromHash, toHash, createdAt, leg) {
|
|
326
|
+
const opsForWrite = leg.hasPlaceholders ? [] : leg.plannedOps;
|
|
327
|
+
const metadataWithInvariants = {
|
|
328
|
+
from: fromHash,
|
|
329
|
+
to: toHash,
|
|
330
|
+
hints: {
|
|
331
|
+
used: [],
|
|
332
|
+
applied: [],
|
|
333
|
+
plannerVersion: "2.0.0"
|
|
334
|
+
},
|
|
335
|
+
labels: [],
|
|
336
|
+
providedInvariants: deriveProvidedInvariants(opsForWrite),
|
|
337
|
+
createdAt: createdAt.toISOString()
|
|
338
|
+
};
|
|
339
|
+
await writeMigrationPackage(packageDir, {
|
|
340
|
+
...metadataWithInvariants,
|
|
341
|
+
migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite)
|
|
342
|
+
}, opsForWrite);
|
|
343
|
+
await writeMigrationTs(packageDir, leg.migrationTsContent);
|
|
344
|
+
}
|
|
151
345
|
async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
152
346
|
const config = await loadConfig(options.config);
|
|
153
347
|
const { configPath, migrationsDir, appMigrationsDir, appMigrationsRelative } = resolveMigrationPaths(options.config, config);
|
|
@@ -206,36 +400,47 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
206
400
|
const rawStorageHash = toContract.storage?.storageHash;
|
|
207
401
|
if (typeof rawStorageHash !== "string") return notOk(errorContractValidationFailed("Contract is missing storageHash", { where: { path: contractPathAbsolute } }));
|
|
208
402
|
const toStorageHash = rawStorageHash;
|
|
403
|
+
const { refsDir } = resolveMigrationPaths(options.config, config);
|
|
209
404
|
let fromContract = null;
|
|
210
405
|
let fromHash = null;
|
|
211
406
|
let fromContractSourceDir = null;
|
|
407
|
+
let snapshotStartContract = null;
|
|
408
|
+
let isAutoBaseline = false;
|
|
212
409
|
try {
|
|
213
410
|
const { bundles, graph } = await loadMigrationPackages(appMigrationsDir);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
411
|
+
const resolutionResult = await resolveFromForPlan({
|
|
412
|
+
optionsFrom: options.from,
|
|
413
|
+
refsDir,
|
|
414
|
+
bundles,
|
|
415
|
+
graph,
|
|
416
|
+
familyInstance,
|
|
417
|
+
readBundleEndContract: (migrationDir) => readPredecessorEndContract(migrationDir, familyInstance)
|
|
418
|
+
});
|
|
419
|
+
if (!resolutionResult.ok) return notOk(resolutionResult.failure);
|
|
420
|
+
switch (resolutionResult.value.kind) {
|
|
421
|
+
case "greenfield": break;
|
|
422
|
+
case "graph-node":
|
|
423
|
+
fromHash = resolutionResult.value.fromHash;
|
|
424
|
+
fromContract = resolutionResult.value.fromContract;
|
|
425
|
+
fromContractSourceDir = resolutionResult.value.sourceDir;
|
|
426
|
+
break;
|
|
427
|
+
case "snapshot":
|
|
428
|
+
fromHash = resolutionResult.value.fromHash;
|
|
429
|
+
fromContract = resolutionResult.value.fromContract;
|
|
430
|
+
snapshotStartContract = {
|
|
431
|
+
contractJson: resolutionResult.value.contractJson,
|
|
432
|
+
contractDts: resolutionResult.value.contractDts
|
|
433
|
+
};
|
|
434
|
+
break;
|
|
435
|
+
case "auto-baseline":
|
|
436
|
+
fromHash = resolutionResult.value.fromHash;
|
|
437
|
+
fromContract = resolutionResult.value.fromContract;
|
|
438
|
+
snapshotStartContract = {
|
|
439
|
+
contractJson: resolutionResult.value.contractJson,
|
|
440
|
+
contractDts: resolutionResult.value.contractDts
|
|
441
|
+
};
|
|
442
|
+
isAutoBaseline = true;
|
|
443
|
+
break;
|
|
239
444
|
}
|
|
240
445
|
} catch (error) {
|
|
241
446
|
if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
|
|
@@ -257,7 +462,7 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
257
462
|
spaceId: r.spaceId,
|
|
258
463
|
dirName
|
|
259
464
|
})));
|
|
260
|
-
if (fromHash === toStorageHash) return ok({
|
|
465
|
+
if (fromHash === toStorageHash && !isAutoBaseline) return ok({
|
|
261
466
|
ok: true,
|
|
262
467
|
noOp: true,
|
|
263
468
|
from: fromHash,
|
|
@@ -283,58 +488,105 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
283
488
|
config.adapter,
|
|
284
489
|
...config.extensionPacks ?? []
|
|
285
490
|
]);
|
|
286
|
-
const timestamp = /* @__PURE__ */ new Date();
|
|
287
|
-
const packageDir = join(appMigrationsDir, formatMigrationDirName(timestamp, options.name ?? "migration"));
|
|
288
|
-
const baseMetadata = {
|
|
289
|
-
from: fromHash,
|
|
290
|
-
to: toStorageHash,
|
|
291
|
-
hints: {
|
|
292
|
-
used: [],
|
|
293
|
-
applied: [],
|
|
294
|
-
plannerVersion: "2.0.0"
|
|
295
|
-
},
|
|
296
|
-
labels: [],
|
|
297
|
-
createdAt: timestamp.toISOString()
|
|
298
|
-
};
|
|
299
491
|
try {
|
|
300
492
|
const planner = migrations.createPlanner(familyInstance);
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
493
|
+
if (isAutoBaseline && fromHash !== null && fromContract !== null && snapshotStartContract !== null) {
|
|
494
|
+
const baselineTimestamp = /* @__PURE__ */ new Date();
|
|
495
|
+
const deltaTimestamp = new Date(baselineTimestamp.getTime() + 6e4);
|
|
496
|
+
const baselineDirName = formatMigrationDirName(baselineTimestamp, "baseline");
|
|
497
|
+
const deltaDirName = formatMigrationDirName(deltaTimestamp, options.name ?? "migration");
|
|
498
|
+
const baselinePackageDir = join(appMigrationsDir, baselineDirName);
|
|
499
|
+
const deltaPackageDir = join(appMigrationsDir, deltaDirName);
|
|
500
|
+
const baselineLeg = await runPlannerLeg(planner, migrations, frameworkComponents, fromContract, null, aggregate.app.spaceId);
|
|
501
|
+
if (!baselineLeg.ok) return notOk(baselineLeg.failure);
|
|
502
|
+
await writePlannedMigrationPackage(baselinePackageDir, null, fromHash, baselineTimestamp, baselineLeg.value);
|
|
503
|
+
await writeSnapshotContractArtifacts(baselinePackageDir, snapshotStartContract.contractJson, snapshotStartContract.contractDts, "end-contract");
|
|
504
|
+
if (fromHash === toStorageHash) {
|
|
505
|
+
const baselineOps = baselineLeg.value.hasPlaceholders ? [] : baselineLeg.value.plannedOps;
|
|
506
|
+
if (baselineLeg.value.hasPlaceholders) {
|
|
507
|
+
const baselineDir = relative(process.cwd(), baselinePackageDir);
|
|
508
|
+
return ok({
|
|
509
|
+
ok: true,
|
|
510
|
+
noOp: false,
|
|
511
|
+
from: fromHash,
|
|
512
|
+
to: toStorageHash,
|
|
513
|
+
dir: baselineDir,
|
|
514
|
+
baselineDir,
|
|
515
|
+
operations: [],
|
|
516
|
+
emittedExtensionDirs,
|
|
517
|
+
pendingPlaceholders: true,
|
|
518
|
+
summary: "Planned baseline with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit",
|
|
519
|
+
timings: { total: Date.now() - startTime }
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(baselineOps) : void 0;
|
|
523
|
+
return ok({
|
|
524
|
+
ok: true,
|
|
525
|
+
noOp: false,
|
|
526
|
+
from: fromHash,
|
|
527
|
+
to: toStorageHash,
|
|
528
|
+
baselineDir: relative(process.cwd(), baselinePackageDir),
|
|
529
|
+
operations: baselineOps.map((op) => ({
|
|
530
|
+
id: op.id,
|
|
531
|
+
label: op.label,
|
|
532
|
+
operationClass: op.operationClass
|
|
533
|
+
})),
|
|
534
|
+
emittedExtensionDirs,
|
|
535
|
+
...preview !== void 0 ? { preview } : {},
|
|
536
|
+
summary: buildAutoBaselinePlanSummary(0, emittedExtensionDirs.length),
|
|
537
|
+
timings: { total: Date.now() - startTime }
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
const deltaLeg = await runPlannerLeg(planner, migrations, frameworkComponents, aggregate.app.contract, fromContract, aggregate.app.spaceId);
|
|
541
|
+
if (!deltaLeg.ok) return notOk(deltaLeg.failure);
|
|
542
|
+
await writePlannedMigrationPackage(deltaPackageDir, fromHash, toStorageHash, deltaTimestamp, deltaLeg.value);
|
|
543
|
+
const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
|
|
544
|
+
await copyFilesWithRename(deltaPackageDir, [{
|
|
545
|
+
sourcePath: destinationArtifacts.jsonPath,
|
|
546
|
+
destName: "end-contract.json"
|
|
547
|
+
}, {
|
|
548
|
+
sourcePath: destinationArtifacts.dtsPath,
|
|
549
|
+
destName: "end-contract.d.ts"
|
|
550
|
+
}]);
|
|
551
|
+
await writeSnapshotStartContract(deltaPackageDir, snapshotStartContract.contractJson, snapshotStartContract.contractDts);
|
|
552
|
+
const deltaOps = deltaLeg.value.hasPlaceholders ? [] : deltaLeg.value.plannedOps;
|
|
553
|
+
if (deltaLeg.value.hasPlaceholders) return ok({
|
|
554
|
+
ok: true,
|
|
555
|
+
noOp: false,
|
|
556
|
+
from: fromHash,
|
|
557
|
+
to: toStorageHash,
|
|
558
|
+
dir: relative(process.cwd(), deltaPackageDir),
|
|
559
|
+
baselineDir: relative(process.cwd(), baselinePackageDir),
|
|
560
|
+
operations: [],
|
|
561
|
+
emittedExtensionDirs,
|
|
562
|
+
pendingPlaceholders: true,
|
|
563
|
+
summary: "Planned baseline + migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit",
|
|
564
|
+
timings: { total: Date.now() - startTime }
|
|
565
|
+
});
|
|
566
|
+
const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(deltaOps) : void 0;
|
|
567
|
+
return ok({
|
|
568
|
+
ok: true,
|
|
569
|
+
noOp: false,
|
|
570
|
+
from: fromHash,
|
|
571
|
+
to: toStorageHash,
|
|
572
|
+
dir: relative(process.cwd(), deltaPackageDir),
|
|
573
|
+
baselineDir: relative(process.cwd(), baselinePackageDir),
|
|
574
|
+
operations: deltaOps.map((op) => ({
|
|
575
|
+
id: op.id,
|
|
576
|
+
label: op.label,
|
|
577
|
+
operationClass: op.operationClass
|
|
578
|
+
})),
|
|
579
|
+
emittedExtensionDirs,
|
|
580
|
+
...preview !== void 0 ? { preview } : {},
|
|
581
|
+
summary: buildAutoBaselinePlanSummary(deltaOps.length, emittedExtensionDirs.length),
|
|
582
|
+
timings: { total: Date.now() - startTime }
|
|
583
|
+
});
|
|
327
584
|
}
|
|
328
|
-
const
|
|
329
|
-
const
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
};
|
|
334
|
-
await writeMigrationPackage(packageDir, {
|
|
335
|
-
...metadataWithInvariants,
|
|
336
|
-
migrationHash: computeMigrationHash(metadataWithInvariants, opsForWrite)
|
|
337
|
-
}, opsForWrite);
|
|
585
|
+
const timestamp = /* @__PURE__ */ new Date();
|
|
586
|
+
const packageDir = join(appMigrationsDir, formatMigrationDirName(timestamp, options.name ?? "migration"));
|
|
587
|
+
const deltaLeg = await runPlannerLeg(planner, migrations, frameworkComponents, aggregate.app.contract, fromContract, aggregate.app.spaceId);
|
|
588
|
+
if (!deltaLeg.ok) return notOk(deltaLeg.failure);
|
|
589
|
+
await writePlannedMigrationPackage(packageDir, fromHash, toStorageHash, timestamp, deltaLeg.value);
|
|
338
590
|
const destinationArtifacts = getEmittedArtifactPaths(contractPathAbsolute);
|
|
339
591
|
await copyFilesWithRename(packageDir, [{
|
|
340
592
|
sourcePath: destinationArtifacts.jsonPath,
|
|
@@ -352,9 +604,8 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
352
604
|
sourcePath: sourceArtifacts.dtsPath,
|
|
353
605
|
destName: "start-contract.d.ts"
|
|
354
606
|
}]);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (hasPlaceholders) return ok({
|
|
607
|
+
} else if (snapshotStartContract !== null) await writeSnapshotStartContract(packageDir, snapshotStartContract.contractJson, snapshotStartContract.contractDts);
|
|
608
|
+
if (deltaLeg.value.hasPlaceholders) return ok({
|
|
358
609
|
ok: true,
|
|
359
610
|
noOp: false,
|
|
360
611
|
from: fromHash,
|
|
@@ -366,6 +617,7 @@ async function executeMigrationPlanCommand(options, flags, ui, startTime) {
|
|
|
366
617
|
summary: "Planned migration with placeholder(s) — edit migration.ts then run `node migration.ts` to self-emit",
|
|
367
618
|
timings: { total: Date.now() - startTime }
|
|
368
619
|
});
|
|
620
|
+
const plannedOps = deltaLeg.value.plannedOps;
|
|
369
621
|
const preview = hasOperationPreview(familyInstance) ? familyInstance.toOperationPreview(plannedOps) : void 0;
|
|
370
622
|
return ok({
|
|
371
623
|
ok: true,
|
|
@@ -425,6 +677,11 @@ function buildPlanSummary(plannedOpsCount, emittedExtensionDirsCount) {
|
|
|
425
677
|
if (emittedExtensionDirsCount === 0) return base;
|
|
426
678
|
return `${base}; materialised ${emittedExtensionDirsCount} ${emittedExtensionDirsCount === 1 ? "extension-space migration" : "extension-space migrations"}`;
|
|
427
679
|
}
|
|
680
|
+
function buildAutoBaselinePlanSummary(deltaOpsCount, emittedExtensionDirsCount) {
|
|
681
|
+
const base = `Planned baseline + ${deltaOpsCount} operation(s)`;
|
|
682
|
+
if (emittedExtensionDirsCount === 0) return base;
|
|
683
|
+
return `${base}; materialised ${emittedExtensionDirsCount} ${emittedExtensionDirsCount === 1 ? "extension-space migration" : "extension-space migrations"}`;
|
|
684
|
+
}
|
|
428
685
|
function formatMigrationPlanOutput(result, flags) {
|
|
429
686
|
const lines = [];
|
|
430
687
|
const useColor = flags.color !== false;
|
|
@@ -476,10 +733,12 @@ function formatMigrationPlanOutput(result, flags) {
|
|
|
476
733
|
}
|
|
477
734
|
lines.push(dim_(`from: ${result.from}`));
|
|
478
735
|
lines.push(dim_(`to: ${result.to}`));
|
|
736
|
+
if (result.baselineDir) lines.push(dim_(`Baseline → ${result.baselineDir}`));
|
|
479
737
|
if (result.dir) lines.push(dim_(`App space → ${result.dir}`));
|
|
480
738
|
for (const entry of result.emittedExtensionDirs) lines.push(dim_(`Extension space ${entry.spaceId} → migrations/${entry.spaceId}/${entry.dirName}`));
|
|
481
739
|
lines.push("");
|
|
482
|
-
|
|
740
|
+
const reviewTarget = result.baselineDir !== void 0 && result.dir !== void 0 ? `${result.baselineDir} and ${result.dir}` : result.baselineDir ?? result.dir ?? "<dir>";
|
|
741
|
+
lines.push(`Next: review ${green_(reviewTarget)} if needed, then run ${green_("prisma-next migrate")}.`);
|
|
483
742
|
if (result.preview && result.preview.statements.length > 0) {
|
|
484
743
|
const allSql = result.preview.statements.every((s) => s.language === "sql");
|
|
485
744
|
lines.push("");
|
|
@@ -526,4 +785,4 @@ function resolveBundleByPrefix(bundles, needle) {
|
|
|
526
785
|
//#endregion
|
|
527
786
|
export { formatMigrationPlanOutput as n, resolveBundleByPrefix as r, createMigrationPlanCommand as t };
|
|
528
787
|
|
|
529
|
-
//# sourceMappingURL=migration-plan-
|
|
788
|
+
//# sourceMappingURL=migration-plan-jdAHg_gK.mjs.map
|