@prisma-next/cli 0.5.0-dev.36 → 0.5.0-dev.38

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.
Files changed (59) hide show
  1. package/dist/cli.mjs +13 -5
  2. package/dist/cli.mjs.map +1 -1
  3. package/dist/{client-Buy8_40Y.mjs → client-1JqqkiC7.mjs} +3 -2
  4. package/dist/client-1JqqkiC7.mjs.map +1 -0
  5. package/dist/commands/contract-emit.mjs +6 -1
  6. package/dist/commands/contract-infer.mjs +7 -1
  7. package/dist/commands/db-init.mjs +4 -3
  8. package/dist/commands/db-init.mjs.map +1 -1
  9. package/dist/commands/db-schema.mjs +5 -2
  10. package/dist/commands/db-schema.mjs.map +1 -1
  11. package/dist/commands/db-sign.mjs +3 -2
  12. package/dist/commands/db-sign.mjs.map +1 -1
  13. package/dist/commands/db-update.mjs +4 -3
  14. package/dist/commands/db-update.mjs.map +1 -1
  15. package/dist/commands/db-verify.mjs +3 -2
  16. package/dist/commands/db-verify.mjs.map +1 -1
  17. package/dist/commands/migration-apply.d.mts +3 -0
  18. package/dist/commands/migration-apply.d.mts.map +1 -1
  19. package/dist/commands/migration-apply.mjs +47 -23
  20. package/dist/commands/migration-apply.mjs.map +1 -1
  21. package/dist/commands/migration-new.mjs +3 -3
  22. package/dist/commands/migration-new.mjs.map +1 -1
  23. package/dist/commands/migration-plan.mjs +1 -1
  24. package/dist/commands/migration-ref.mjs +1 -1
  25. package/dist/commands/migration-show.mjs +3 -2
  26. package/dist/commands/migration-show.mjs.map +1 -1
  27. package/dist/commands/migration-status.d.mts +18 -1
  28. package/dist/commands/migration-status.d.mts.map +1 -1
  29. package/dist/commands/migration-status.mjs +7 -2
  30. package/dist/{contract-emit-LjzCoicC.mjs → contract-emit-DS5NzZh2.mjs} +2 -0
  31. package/dist/{contract-emit-DWtGQYCD.mjs → contract-emit-rt_Nmdwq.mjs} +2 -2
  32. package/dist/{contract-emit-DWtGQYCD.mjs.map → contract-emit-rt_Nmdwq.mjs.map} +1 -1
  33. package/dist/{contract-infer-DmLiksNp.mjs → contract-infer-Cf5J2wVg.mjs} +3 -3
  34. package/dist/{contract-infer-DmLiksNp.mjs.map → contract-infer-Cf5J2wVg.mjs.map} +1 -1
  35. package/dist/exports/control-api.d.mts +8 -0
  36. package/dist/exports/control-api.d.mts.map +1 -1
  37. package/dist/exports/control-api.mjs +3 -1
  38. package/dist/exports/index.mjs +6 -1
  39. package/dist/exports/index.mjs.map +1 -1
  40. package/dist/{init-C7dE9KOJ.mjs → init-DAbQMxIR.mjs} +2 -2
  41. package/dist/{init-C7dE9KOJ.mjs.map → init-DAbQMxIR.mjs.map} +1 -1
  42. package/dist/{inspect-live-schema-6nsKS6m5.mjs → inspect-live-schema-LWtXfxm_.mjs} +3 -3
  43. package/dist/{inspect-live-schema-6nsKS6m5.mjs.map → inspect-live-schema-LWtXfxm_.mjs.map} +1 -1
  44. package/dist/{migration-command-scaffold-Ck1_lcsf.mjs → migration-command-scaffold-CU452v9h.mjs} +3 -3
  45. package/dist/{migration-command-scaffold-Ck1_lcsf.mjs.map → migration-command-scaffold-CU452v9h.mjs.map} +1 -1
  46. package/dist/{migration-status-DYJIRnK3.mjs → migration-status-DoPrFIOQ.mjs} +103 -34
  47. package/dist/migration-status-DoPrFIOQ.mjs.map +1 -0
  48. package/dist/{result-handler-BmVh8AeV.mjs → result-handler-Ch6hVnOo.mjs} +26 -3
  49. package/dist/{result-handler-BmVh8AeV.mjs.map → result-handler-Ch6hVnOo.mjs.map} +1 -1
  50. package/package.json +14 -14
  51. package/src/commands/migration-apply.ts +72 -16
  52. package/src/commands/migration-new.ts +2 -2
  53. package/src/commands/migration-status.ts +171 -23
  54. package/src/control-api/operations/migration-apply.ts +1 -0
  55. package/src/control-api/types.ts +8 -0
  56. package/src/utils/command-helpers.ts +36 -1
  57. package/src/utils/formatters/graph-migration-mapper.ts +5 -1
  58. package/dist/client-Buy8_40Y.mjs.map +0 -1
  59. package/dist/migration-status-DYJIRnK3.mjs.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { t as loadConfig } from "./config-loader-ih8ViDb_.mjs";
2
2
  import { _ as errorUnexpected, c as errorDriverRequired, o as errorDatabaseConnectionRequired, t as CliStructuredError } from "./cli-errors-By1iVE3z.mjs";
3
- import { _ as formatStyledHeader, a as maskConnectionUrl, l as sanitizeErrorMessage } from "./result-handler-BmVh8AeV.mjs";
3
+ import { o as maskConnectionUrl, u as sanitizeErrorMessage, y as formatStyledHeader } from "./result-handler-Ch6hVnOo.mjs";
4
4
  import { t as createProgressAdapter } from "./progress-adapter-DgRGldpT.mjs";
5
- import { t as createControlClient } from "./client-Buy8_40Y.mjs";
5
+ import { t as createControlClient } from "./client-1JqqkiC7.mjs";
6
6
  import { notOk, ok } from "@prisma-next/utils/result";
7
7
  import { relative, resolve } from "pathe";
8
8
 
@@ -88,4 +88,4 @@ async function inspectLiveSchema(options, flags, ui, startTime, context) {
88
88
 
89
89
  //#endregion
90
90
  export { inspectLiveSchema as t };
91
- //# sourceMappingURL=inspect-live-schema-6nsKS6m5.mjs.map
91
+ //# sourceMappingURL=inspect-live-schema-LWtXfxm_.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-live-schema-6nsKS6m5.mjs","names":["config: LoadedCliConfig","details: Array<{ label: string; value: string }>"],"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,IAAIA;AACJ,KAAI;AACF,WAAS,MAAM,WAAW,QAAQ,OAAO;UAClC,OAAO;AACd,MAAI,mBAAmB,GAAG,MAAM,CAC9B,QAAO,MAAM,MAAM;AAGrB,SAAO,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;AAEJ,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAMC,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,CACvC;AAED,MAAI,QAAQ,GACV,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;WAChE,OAAO,IAAI,cAAc,OAAO,OAAO,GAAG,eAAe,SAClE,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,OAAO,GAAG,WAAW;GAAE,CAAC;AAGrF,KAAG,OACD,mBAAmB;GACjB,SAAS,QAAQ;GACjB,aAAa,QAAQ;GACrB,KAAK,QAAQ;GACb;GACA;GACD,CAAC,CACH;;CAGH,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;AAC9C,KAAI,CAAC,aACH,QAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,QAAQ,YAAY,yBAAyB,WAAW;EACpG,aAAa,QAAQ;EACtB,CAAC,CACH;AAGH,KAAI,CAAC,OAAO,OACV,QAAO,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;AAEvD,KAAI;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;AAEnF,SAAO,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;AACd,MAAI,mBAAmB,GAAG,MAAM,CAC9B,QAAO,MAAM,MAAM;EAIrB,MAAM,cAAc,qBADD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAGvE,OAAO,iBAAiB,WAAW,eAAe,OACnD;AACD,SAAO,MACL,gBAAgB,aAAa,EAC3B,KAAK,2BAA2B,QAAQ,YAAY,IAAI,eACzD,CAAC,CACH;WACO;AACR,QAAM,OAAO,OAAO"}
1
+ {"version":3,"file":"inspect-live-schema-LWtXfxm_.mjs","names":["config: LoadedCliConfig","details: Array<{ label: string; value: string }>"],"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,IAAIA;AACJ,KAAI;AACF,WAAS,MAAM,WAAW,QAAQ,OAAO;UAClC,OAAO;AACd,MAAI,mBAAmB,GAAG,MAAM,CAC9B,QAAO,MAAM,MAAM;AAGrB,SAAO,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;AAEJ,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAMC,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,CACvC;AAED,MAAI,QAAQ,GACV,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;WAChE,OAAO,IAAI,cAAc,OAAO,OAAO,GAAG,eAAe,SAClE,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,OAAO,GAAG,WAAW;GAAE,CAAC;AAGrF,KAAG,OACD,mBAAmB;GACjB,SAAS,QAAQ;GACjB,aAAa,QAAQ;GACrB,KAAK,QAAQ;GACb;GACA;GACD,CAAC,CACH;;CAGH,MAAM,eAAe,QAAQ,MAAM,OAAO,IAAI;AAC9C,KAAI,CAAC,aACH,QAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,QAAQ,YAAY,yBAAyB,WAAW;EACpG,aAAa,QAAQ;EACtB,CAAC,CACH;AAGH,KAAI,CAAC,OAAO,OACV,QAAO,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;AAEvD,KAAI;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;AAEnF,SAAO,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;AACd,MAAI,mBAAmB,GAAG,MAAM,CAC9B,QAAO,MAAM,MAAM;EAIrB,MAAM,cAAc,qBADD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAGvE,OAAO,iBAAiB,WAAW,eAAe,OACnD;AACD,SAAO,MACL,gBAAgB,aAAa,EAC3B,KAAK,2BAA2B,QAAQ,YAAY,IAAI,eACzD,CAAC,CACH;WACO;AACR,QAAM,OAAO,OAAO"}
@@ -1,8 +1,8 @@
1
1
  import { t as loadConfig } from "./config-loader-ih8ViDb_.mjs";
2
2
  import { _ as errorUnexpected, a as errorContractValidationFailed, c as errorDriverRequired, h as errorTargetMigrationNotSupported, l as errorFileNotFound, o as errorDatabaseConnectionRequired } from "./cli-errors-By1iVE3z.mjs";
3
- import { _ as formatStyledHeader, a as maskConnectionUrl, n as addGlobalOptions, s as resolveContractPath } from "./result-handler-BmVh8AeV.mjs";
3
+ import { c as resolveContractPath, n as addGlobalOptions, o as maskConnectionUrl, y as formatStyledHeader } from "./result-handler-Ch6hVnOo.mjs";
4
4
  import { t as createProgressAdapter } from "./progress-adapter-DgRGldpT.mjs";
5
- import { t as createControlClient } from "./client-Buy8_40Y.mjs";
5
+ import { t as createControlClient } from "./client-1JqqkiC7.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";
@@ -102,4 +102,4 @@ function addMigrationCommandOptions(command) {
102
102
 
103
103
  //#endregion
104
104
  export { prepareMigrationContext as n, addMigrationCommandOptions as t };
105
- //# sourceMappingURL=migration-command-scaffold-Ck1_lcsf.mjs.map
105
+ //# sourceMappingURL=migration-command-scaffold-CU452v9h.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"migration-command-scaffold-Ck1_lcsf.mjs","names":["details: Array<{ label: string; value: string }>","contractJsonContent: string","contractJson: Record<string, unknown>"],"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;AAGlE,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAMA,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,EACtC;GAAE,OAAO;GAAY,OAAO;GAAc,CAC3C;AACD,MAAI,QAAQ,GACV,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;AAE3E,MAAI,QAAQ,OACV,SAAQ,KAAK;GAAE,OAAO;GAAQ,OAAO;GAAW,CAAC;EAEnD,MAAM,SAAS,mBAAmB;GAChC,SAAS,WAAW;GACpB,aAAa,WAAW;GACxB,KAAK,WAAW;GAChB;GACA;GACD,CAAC;AACF,KAAG,OAAO,OAAO;;CAInB,IAAIC;AACJ,KAAI;AACF,wBAAsB,MAAM,SAAS,sBAAsB,QAAQ;UAC5D,OAAO;AACd,MAAI,iBAAiB,SAAU,MAA4B,SAAS,SAClE,QAAO,MACL,kBAAkB,sBAAsB;GACtC,KAAK,8BAA8B;GACnC,KAAK,iDAAiD,aAAa,4CAA4C;GAChH,CAAC,CACH;AAEH,SAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC7F,CAAC,CACH;;CAIH,IAAIC;AACJ,KAAI;AACF,iBAAe,KAAK,MAAM,oBAAoB;UACvC,OAAO;AACd,SAAO,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;AAC9C,KAAI,CAAC,aACH,QAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,WAAW,YAAY,yBAAyB,WAAW;EACvG,aAAa,WAAW;EACzB,CAAC,CACH;AAIH,KAAI,CAAC,OAAO,OACV,QAAO,MACL,oBAAoB,EAAE,KAAK,iCAAiC,WAAW,eAAe,CAAC,CACxF;AAGH,KAAI,CAAC,cAAc,OAAO,OAAO,CAC/B,QAAO,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;AAEvD,QAAO,GAAG;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;;;;;AAMJ,SAAgB,2BAA2B,SAA2B;AACpE,kBAAiB,QAAQ;AACzB,QAAO,QACJ,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,aAAa,+CAA+C,MAAM"}
1
+ {"version":3,"file":"migration-command-scaffold-CU452v9h.mjs","names":["details: Array<{ label: string; value: string }>","contractJsonContent: string","contractJson: Record<string, unknown>"],"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;AAGlE,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,OAAO;EAC/B,MAAMA,UAAmD,CACvD;GAAE,OAAO;GAAU,OAAO;GAAY,EACtC;GAAE,OAAO;GAAY,OAAO;GAAc,CAC3C;AACD,MAAI,QAAQ,GACV,SAAQ,KAAK;GAAE,OAAO;GAAY,OAAO,kBAAkB,QAAQ,GAAG;GAAE,CAAC;AAE3E,MAAI,QAAQ,OACV,SAAQ,KAAK;GAAE,OAAO;GAAQ,OAAO;GAAW,CAAC;EAEnD,MAAM,SAAS,mBAAmB;GAChC,SAAS,WAAW;GACpB,aAAa,WAAW;GACxB,KAAK,WAAW;GAChB;GACA;GACD,CAAC;AACF,KAAG,OAAO,OAAO;;CAInB,IAAIC;AACJ,KAAI;AACF,wBAAsB,MAAM,SAAS,sBAAsB,QAAQ;UAC5D,OAAO;AACd,MAAI,iBAAiB,SAAU,MAA4B,SAAS,SAClE,QAAO,MACL,kBAAkB,sBAAsB;GACtC,KAAK,8BAA8B;GACnC,KAAK,iDAAiD,aAAa,4CAA4C;GAChH,CAAC,CACH;AAEH,SAAO,MACL,gBAAgB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACtE,KAAK,iCAAiC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC7F,CAAC,CACH;;CAIH,IAAIC;AACJ,KAAI;AACF,iBAAe,KAAK,MAAM,oBAAoB;UACvC,OAAO;AACd,SAAO,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;AAC9C,KAAI,CAAC,aACH,QAAO,MACL,gCAAgC;EAC9B,KAAK,uCAAuC,WAAW,YAAY,yBAAyB,WAAW;EACvG,aAAa,WAAW;EACzB,CAAC,CACH;AAIH,KAAI,CAAC,OAAO,OACV,QAAO,MACL,oBAAoB,EAAE,KAAK,iCAAiC,WAAW,eAAe,CAAC,CACxF;AAGH,KAAI,CAAC,cAAc,OAAO,OAAO,CAC/B,QAAO,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;AAEvD,QAAO,GAAG;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;;;;;AAMJ,SAAgB,2BAA2B,SAA2B;AACpE,kBAAiB,QAAQ;AACzB,QAAO,QACJ,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,aAAa,+CAA+C,MAAM"}
@@ -1,15 +1,15 @@
1
1
  import { t as loadConfig } from "./config-loader-ih8ViDb_.mjs";
2
2
  import { _ as errorUnexpected, m as errorRuntime, v as mapMigrationToolsError } from "./cli-errors-By1iVE3z.mjs";
3
3
  import { t as TerminalUI } from "./terminal-ui-u2YgKghu.mjs";
4
- import { _ as formatStyledHeader, a as maskConnectionUrl, c as resolveMigrationPaths, d as setCommandExamples, i as loadMigrationPackages, m as parseGlobalFlags, n as addGlobalOptions, o as readContractEnvelope, p as toPathDecisionResult, t as handleResult, u as setCommandDescriptions } from "./result-handler-BmVh8AeV.mjs";
5
- import { t as createControlClient } from "./client-Buy8_40Y.mjs";
4
+ import { a as loadMigrationPackages, d as setCommandDescriptions, f as setCommandExamples, g as parseGlobalFlags, h as toStructuralEdge, l as resolveMigrationPaths, m as toPathDecisionResult, n as addGlobalOptions, o as maskConnectionUrl, r as collectDeclaredInvariants, s as readContractEnvelope, t as handleResult, y as formatStyledHeader } from "./result-handler-Ch6hVnOo.mjs";
5
+ import { t as createControlClient } from "./client-1JqqkiC7.mjs";
6
6
  import { Command } from "commander";
7
7
  import { ifDefined } from "@prisma-next/utils/defined";
8
8
  import { notOk, ok } from "@prisma-next/utils/result";
9
9
  import { findPath, findPathWithDecision, findReachableLeaves } from "@prisma-next/migration-tools/migration-graph";
10
10
  import { bold, cyan, dim, magenta, yellow } from "colorette";
11
11
  import { EMPTY_CONTRACT_HASH } from "@prisma-next/migration-tools/constants";
12
- import { MigrationToolsError } from "@prisma-next/migration-tools/errors";
12
+ import { MigrationToolsError, errorNoInvariantPath, errorUnknownInvariant } from "@prisma-next/migration-tools/errors";
13
13
  import { readRefs, resolveRef } from "@prisma-next/migration-tools/refs";
14
14
  import dagre from "@dagrejs/dagre";
15
15
 
@@ -100,7 +100,8 @@ function migrationGraphToRenderInput(input) {
100
100
  for (const [, entries] of graph.forwardChain) for (const entry of entries) {
101
101
  const status = statusByDirName.get(entry.dirName);
102
102
  const icon = status ? STATUS_ICON[status] : "";
103
- const label = `${entry.dirName}${icon}`;
103
+ const invariantsSuffix = entry.invariants.length > 0 ? ` provides [${entry.invariants.map((id) => JSON.stringify(id)).join(", ")}]` : "";
104
+ const label = `${entry.dirName}${icon}${invariantsSuffix}`;
104
105
  edgeList.push({
105
106
  from: toShortId(entry.from),
106
107
  to: toShortId(entry.to),
@@ -1246,6 +1247,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1246
1247
  const hasDriver = !!config.driver;
1247
1248
  let activeRefName;
1248
1249
  let activeRefHash;
1250
+ let activeRefEntry;
1249
1251
  let allRefs = {};
1250
1252
  try {
1251
1253
  allRefs = await readRefs(refsDir);
@@ -1256,12 +1258,14 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1256
1258
  if (options.ref) {
1257
1259
  activeRefName = options.ref;
1258
1260
  try {
1259
- activeRefHash = resolveRef(allRefs, activeRefName).hash;
1261
+ activeRefEntry = resolveRef(allRefs, activeRefName);
1262
+ activeRefHash = activeRefEntry.hash;
1260
1263
  } catch (error) {
1261
1264
  if (MigrationToolsError.is(error)) return notOk(mapMigrationToolsError(error));
1262
1265
  throw error;
1263
1266
  }
1264
1267
  }
1268
+ const requiredInvariants = [...activeRefEntry?.invariants ?? []].sort();
1265
1269
  const statusRefs = Object.entries(allRefs).map(([name, entry]) => ({
1266
1270
  name,
1267
1271
  hash: entry.hash,
@@ -1283,6 +1287,10 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1283
1287
  label: "ref",
1284
1288
  value: activeRefName
1285
1289
  });
1290
+ if (activeRefEntry && activeRefEntry.invariants.length > 0) details.push({
1291
+ label: "required",
1292
+ value: formatInvariantList(activeRefEntry.invariants)
1293
+ });
1286
1294
  const header = formatStyledHeader({
1287
1295
  command: "migration status",
1288
1296
  description: "Show migration history and applied status",
@@ -1325,7 +1333,8 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1325
1333
  targetHash: EMPTY_CONTRACT_HASH,
1326
1334
  contractHash,
1327
1335
  summary: "No migrations found",
1328
- diagnostics
1336
+ diagnostics,
1337
+ requiredInvariants
1329
1338
  });
1330
1339
  }
1331
1340
  let targetHash;
@@ -1342,6 +1351,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1342
1351
  });
1343
1352
  }
1344
1353
  let markerHash;
1354
+ let markerInvariants = [];
1345
1355
  let mode = "offline";
1346
1356
  if (dbConnection && hasDriver) {
1347
1357
  const client = createControlClient({
@@ -1353,7 +1363,9 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1353
1363
  });
1354
1364
  try {
1355
1365
  await client.connect(dbConnection);
1356
- markerHash = (await client.readMarker())?.storageHash;
1366
+ const marker = await client.readMarker();
1367
+ markerHash = marker?.storageHash;
1368
+ markerInvariants = marker?.invariants ?? [];
1357
1369
  mode = "online";
1358
1370
  } catch {
1359
1371
  if (!flags.json && !flags.quiet) ui.warn("Could not connect to database — showing offline status");
@@ -1361,6 +1373,17 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1361
1373
  await client.close();
1362
1374
  }
1363
1375
  }
1376
+ if (activeRefEntry && activeRefEntry.invariants.length > 0) {
1377
+ const declared = collectDeclaredInvariants(graph);
1378
+ const known = new Set(declared);
1379
+ if (mode === "online") for (const id of markerInvariants) known.add(id);
1380
+ const unknown = activeRefEntry.invariants.filter((id) => !known.has(id));
1381
+ if (unknown.length > 0) return notOk(mapMigrationToolsError(errorUnknownInvariant({
1382
+ ...ifDefined("refName", activeRefName),
1383
+ unknown,
1384
+ declared: [...declared].sort()
1385
+ })));
1386
+ }
1364
1387
  if (mode === "online" && markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash !== contractHash) {
1365
1388
  const hints = [];
1366
1389
  if (graph.nodes.has(contractHash)) hints.push("Run 'prisma-next db sign' to overwrite the marker if the database already matches the contract", "Run 'prisma-next db update' to push the current contract to the database", "Run 'prisma-next contract infer' to make your contract match the database", "Run 'prisma-next db verify' to inspect the database state");
@@ -1380,6 +1403,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1380
1403
  summary: `${bundles.length} migration(s) on disk`,
1381
1404
  diagnostics,
1382
1405
  markerHash,
1406
+ requiredInvariants,
1383
1407
  ...statusRefs.length > 0 ? { refs: statusRefs } : {}
1384
1408
  });
1385
1409
  }
@@ -1404,6 +1428,7 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1404
1428
  summary: `${bundles.length} migration(s) on disk`,
1405
1429
  diagnostics,
1406
1430
  ...ifDefined("markerHash", markerHash),
1431
+ requiredInvariants,
1407
1432
  ...statusRefs.length > 0 ? { refs: statusRefs } : {},
1408
1433
  graph,
1409
1434
  bundles,
@@ -1418,35 +1443,68 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1418
1443
  const entries = buildMigrationEntries(chain, bundles, mode, markerHash, edgeStatuses);
1419
1444
  const pendingCount = edgeStatuses.filter((e) => e.status === "pending").length;
1420
1445
  const appliedCount = edgeStatuses.filter((e) => e.status === "applied").length;
1446
+ let appliedInvariants;
1447
+ let missingInvariants;
1448
+ let effectiveRequired = /* @__PURE__ */ new Set();
1449
+ if (mode === "online") {
1450
+ const markerSet = new Set(markerInvariants);
1451
+ effectiveRequired = new Set(requiredInvariants.filter((id) => !markerSet.has(id)));
1452
+ appliedInvariants = requiredInvariants.filter((id) => markerSet.has(id));
1453
+ missingInvariants = [...effectiveRequired].sort();
1454
+ }
1455
+ const hasInvariantWork = effectiveRequired.size > 0;
1456
+ const missingList = [...effectiveRequired].sort().join(", ");
1421
1457
  let summary;
1422
1458
  if (mode === "online") if (markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash === contractHash) summary = `${bundles.length} migration(s) on disk`;
1423
- else if (activeRefHash && markerHash !== void 0) summary = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName);
1424
- else if (pendingCount === 0) summary = `Database is up to date (${appliedCount} migration${appliedCount !== 1 ? "s" : ""} applied)`;
1459
+ else if (activeRefHash && markerHash !== void 0) {
1460
+ const distance = summarizeRefDistance(graph, markerHash, activeRefHash, activeRefName);
1461
+ summary = hasInvariantWork ? `${distance} — missing invariant(s): ${missingList}` : distance;
1462
+ } else if (pendingCount === 0 && !hasInvariantWork) summary = `Database is up to date (${appliedCount} migration${appliedCount !== 1 ? "s" : ""} applied)`;
1463
+ else if (pendingCount === 0 && hasInvariantWork) summary = `Missing invariant(s): ${missingList} — run 'prisma-next migration apply --ref ${activeRefName ?? "<ref>"}' to apply`;
1425
1464
  else if (markerHash === void 0) summary = `${pendingCount} pending migration(s) — database has no marker`;
1426
1465
  else summary = `${pendingCount} pending migration(s) — run 'prisma-next migration apply' to apply`;
1427
1466
  else summary = `${entries.length} migration(s) on disk`;
1428
- if (mode === "online") if (markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash === contractHash) diagnostics.push({
1429
- code: "MIGRATION.MARKER_NOT_IN_HISTORY",
1430
- severity: "warn",
1431
- message: "Database matches the current contract but was updated directly (not via migration apply)",
1432
- hints: ["Run 'prisma-next migration plan' to plan a migration to your current contract"]
1433
- });
1434
- else if (pendingCount > 0) diagnostics.push({
1435
- code: "MIGRATION.DATABASE_BEHIND",
1436
- severity: "info",
1437
- message: `${pendingCount} migration(s) pending`,
1438
- hints: ["Run 'prisma-next migration apply' to apply pending migrations"]
1439
- });
1440
- else diagnostics.push({
1441
- code: "MIGRATION.UP_TO_DATE",
1442
- severity: "info",
1443
- message: "Database is up to date",
1444
- hints: []
1445
- });
1446
1467
  let pathDecision;
1447
- if (mode === "online" && markerHash !== void 0) {
1448
- const decision = findPathWithDecision(graph, markerHash, targetHash, activeRefName);
1449
- if (decision) pathDecision = toPathDecisionResult(decision);
1468
+ let routingUnreachable = false;
1469
+ if (mode === "online") {
1470
+ const outcome = findPathWithDecision(graph, markerHash ?? EMPTY_CONTRACT_HASH, targetHash, {
1471
+ ...ifDefined("refName", activeRefName),
1472
+ required: effectiveRequired
1473
+ });
1474
+ if (outcome.kind === "ok") pathDecision = toPathDecisionResult(outcome.decision);
1475
+ else if (outcome.kind === "unsatisfiable") return notOk(mapMigrationToolsError(errorNoInvariantPath({
1476
+ ...ifDefined("refName", activeRefName),
1477
+ required: [...effectiveRequired].sort(),
1478
+ missing: outcome.missing,
1479
+ structuralPath: outcome.structuralPath.map(toStructuralEdge)
1480
+ })));
1481
+ else routingUnreachable = true;
1482
+ }
1483
+ if (mode === "online") {
1484
+ if (markerHash !== void 0 && !graph.nodes.has(markerHash) && markerHash === contractHash) diagnostics.push({
1485
+ code: "MIGRATION.MARKER_NOT_IN_HISTORY",
1486
+ severity: "warn",
1487
+ message: "Database matches the current contract but was updated directly (not via migration apply)",
1488
+ hints: ["Run 'prisma-next migration plan' to plan a migration to your current contract"]
1489
+ });
1490
+ else if (pendingCount > 0) diagnostics.push({
1491
+ code: "MIGRATION.DATABASE_BEHIND",
1492
+ severity: "info",
1493
+ message: `${pendingCount} migration(s) pending`,
1494
+ hints: ["Run 'prisma-next migration apply' to apply pending migrations"]
1495
+ });
1496
+ else if (hasInvariantWork) diagnostics.push({
1497
+ code: "MIGRATION.INVARIANTS_PENDING",
1498
+ severity: "info",
1499
+ message: `Missing required invariant(s): ${missingList}`,
1500
+ hints: [`Run 'prisma-next migration apply --ref ${activeRefName ?? "<ref>"}' to apply a path that covers the required invariants`]
1501
+ });
1502
+ else if (!routingUnreachable) diagnostics.push({
1503
+ code: "MIGRATION.UP_TO_DATE",
1504
+ severity: "info",
1505
+ message: "Database is up to date",
1506
+ hints: []
1507
+ });
1450
1508
  }
1451
1509
  return ok({
1452
1510
  ok: true,
@@ -1457,6 +1515,9 @@ async function executeMigrationStatusCommand(options, flags, ui) {
1457
1515
  summary,
1458
1516
  diagnostics,
1459
1517
  ...ifDefined("markerHash", markerHash),
1518
+ requiredInvariants,
1519
+ ...ifDefined("appliedInvariants", appliedInvariants),
1520
+ ...ifDefined("missingInvariants", missingInvariants),
1460
1521
  ...statusRefs.length > 0 ? { refs: statusRefs } : {},
1461
1522
  ...ifDefined("pathDecision", pathDecision),
1462
1523
  graph,
@@ -1478,7 +1539,7 @@ function createMigrationStatusCommand() {
1478
1539
  });
1479
1540
  const exitCode = handleResult(await executeMigrationStatusCommand(options, flags, ui), flags, ui, (statusResult) => {
1480
1541
  if (flags.json) {
1481
- const { graph: _g, bundles: _b, edgeStatuses: _es, activeRefHash: _arh, activeRefName: _arn, diverged: _d, ...jsonResult } = statusResult;
1542
+ const { graph: _graph, bundles: _bundles, edgeStatuses: _edgeStatuses, activeRefHash: _activeRefHash, activeRefName: _activeRefName, diverged: _diverged, ...jsonResult } = statusResult;
1482
1543
  ui.output(JSON.stringify(jsonResult, null, 2));
1483
1544
  } else if (!flags.quiet) {
1484
1545
  const colorize = flags.color !== false;
@@ -1528,10 +1589,15 @@ function formatStatusSummary(result, colorize) {
1528
1589
  const hasUnknown = result.migrations.some((e) => e.status === "unknown");
1529
1590
  const pendingCount = result.migrations.filter((e) => e.status === "pending").length;
1530
1591
  const hasWarnings = result.diagnostics?.some((d) => d.severity === "warn") ?? false;
1592
+ const hasInvariantPending = result.diagnostics?.some((d) => d.code === "MIGRATION.INVARIANTS_PENDING") ?? false;
1531
1593
  if (result.mode === "online") if (hasUnknown || hasWarnings) lines.push(`${c(yellow, "⚠")} ${result.summary}`);
1532
- else if (pendingCount === 0) lines.push(`${c(cyan, "✔")} ${result.summary}`);
1594
+ else if (pendingCount === 0 && !hasInvariantPending) lines.push(`${c(cyan, "✔")} ${result.summary}`);
1533
1595
  else lines.push(`${c(yellow, "⧗")} ${result.summary}`);
1534
1596
  else lines.push(result.summary);
1597
+ if (result.requiredInvariants.length > 0) if (result.appliedInvariants !== void 0 && result.missingInvariants !== void 0) {
1598
+ lines.push(`${c(dim, "applied ")}${formatInvariantList(result.appliedInvariants)}`);
1599
+ lines.push(`${c(dim, "missing ")}${formatInvariantList(result.missingInvariants)}`);
1600
+ } else lines.push(`${c(dim, "applied ")}(unknown — connect a database to evaluate)`);
1535
1601
  const warnings = result.diagnostics?.filter((d) => d.severity === "warn") ?? [];
1536
1602
  for (const diag of warnings) {
1537
1603
  lines.push(`${c(yellow, "⚠")} ${diag.message}`);
@@ -1539,6 +1605,9 @@ function formatStatusSummary(result, colorize) {
1539
1605
  }
1540
1606
  return lines.join("\n");
1541
1607
  }
1608
+ function formatInvariantList(ids) {
1609
+ return ids.length === 0 ? "(none)" : ids.join(", ");
1610
+ }
1542
1611
  function summarizeRefDistance(graph, markerHash, refHash, refName) {
1543
1612
  if (markerHash === refHash) return `At ref "${refName}" target`;
1544
1613
  const pathToRef = findPath(graph, markerHash, refHash);
@@ -1549,5 +1618,5 @@ function summarizeRefDistance(graph, markerHash, refHash, refName) {
1549
1618
  }
1550
1619
 
1551
1620
  //#endregion
1552
- export { deriveEdgeStatuses as n, createMigrationStatusCommand as t };
1553
- //# sourceMappingURL=migration-status-DYJIRnK3.mjs.map
1621
+ export { deriveEdgeStatuses as n, formatStatusSummary as r, createMigrationStatusCommand as t };
1622
+ //# sourceMappingURL=migration-status-DoPrFIOQ.mjs.map