@prisma-next/cli 0.5.0-dev.2 → 0.5.0-dev.21

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 (153) hide show
  1. package/README.md +54 -21
  2. package/dist/agent-skill-mongo.md +63 -31
  3. package/dist/agent-skill-postgres.md +1 -1
  4. package/dist/{cli-errors-C0JhVj0c.d.mts → cli-errors-BJLUczXT.d.mts} +1 -0
  5. package/dist/cli-errors-By1iVE3z.mjs +34 -0
  6. package/dist/cli-errors-By1iVE3z.mjs.map +1 -0
  7. package/dist/cli.mjs +127 -13
  8. package/dist/cli.mjs.map +1 -1
  9. package/dist/{client-TG7rbCWT.mjs → client-enZIahga.mjs} +20 -5
  10. package/dist/client-enZIahga.mjs.map +1 -0
  11. package/dist/commands/contract-emit.d.mts.map +1 -1
  12. package/dist/commands/contract-emit.mjs +7 -2
  13. package/dist/commands/contract-infer.mjs +8 -2
  14. package/dist/commands/db-init.mjs +9 -8
  15. package/dist/commands/db-init.mjs.map +1 -1
  16. package/dist/commands/db-schema.mjs +8 -5
  17. package/dist/commands/db-schema.mjs.map +1 -1
  18. package/dist/commands/db-sign.mjs +8 -7
  19. package/dist/commands/db-sign.mjs.map +1 -1
  20. package/dist/commands/db-update.mjs +9 -8
  21. package/dist/commands/db-update.mjs.map +1 -1
  22. package/dist/commands/db-verify.mjs +10 -9
  23. package/dist/commands/db-verify.mjs.map +1 -1
  24. package/dist/commands/migration-apply.d.mts +1 -1
  25. package/dist/commands/migration-apply.d.mts.map +1 -1
  26. package/dist/commands/migration-apply.mjs +15 -38
  27. package/dist/commands/migration-apply.mjs.map +1 -1
  28. package/dist/commands/migration-new.d.mts.map +1 -1
  29. package/dist/commands/migration-new.mjs +24 -28
  30. package/dist/commands/migration-new.mjs.map +1 -1
  31. package/dist/commands/migration-plan.d.mts +6 -3
  32. package/dist/commands/migration-plan.d.mts.map +1 -1
  33. package/dist/commands/migration-plan.mjs +38 -38
  34. package/dist/commands/migration-plan.mjs.map +1 -1
  35. package/dist/commands/migration-ref.d.mts +6 -4
  36. package/dist/commands/migration-ref.d.mts.map +1 -1
  37. package/dist/commands/migration-ref.mjs +31 -40
  38. package/dist/commands/migration-ref.mjs.map +1 -1
  39. package/dist/commands/migration-show.d.mts +4 -4
  40. package/dist/commands/migration-show.d.mts.map +1 -1
  41. package/dist/commands/migration-show.mjs +19 -26
  42. package/dist/commands/migration-show.mjs.map +1 -1
  43. package/dist/commands/migration-status.d.mts +5 -4
  44. package/dist/commands/migration-status.d.mts.map +1 -1
  45. package/dist/commands/migration-status.mjs +7 -2
  46. package/dist/{config-loader-_W4T21X1.mjs → config-loader-ih8ViDb_.mjs} +2 -2
  47. package/dist/config-loader-ih8ViDb_.mjs.map +1 -0
  48. package/dist/config-loader.mjs +1 -1
  49. package/dist/contract-emit-DS5NzZh2.mjs +6 -0
  50. package/dist/contract-emit-DWtGQYCD.mjs +150 -0
  51. package/dist/contract-emit-DWtGQYCD.mjs.map +1 -0
  52. package/dist/contract-emit-RZBWzkop.mjs +329 -0
  53. package/dist/contract-emit-RZBWzkop.mjs.map +1 -0
  54. package/dist/{contract-enrichment-CGW6mm-E.mjs → contract-enrichment-4Ptgw3Pe.mjs} +1 -1
  55. package/dist/{contract-enrichment-CGW6mm-E.mjs.map → contract-enrichment-4Ptgw3Pe.mjs.map} +1 -1
  56. package/dist/{contract-infer-BP3DrGgz.mjs → contract-infer-BjzkcwQt.mjs} +5 -5
  57. package/dist/{contract-infer-BP3DrGgz.mjs.map → contract-infer-BjzkcwQt.mjs.map} +1 -1
  58. package/dist/exports/control-api.d.mts +41 -16
  59. package/dist/exports/control-api.d.mts.map +1 -1
  60. package/dist/exports/control-api.mjs +7 -5
  61. package/dist/exports/index.mjs +8 -3
  62. package/dist/exports/index.mjs.map +1 -1
  63. package/dist/exports/init-output.d.mts +39 -0
  64. package/dist/exports/init-output.d.mts.map +1 -0
  65. package/dist/exports/init-output.mjs +3 -0
  66. package/dist/{extract-operation-statements-DZUJNmL3.mjs → extract-operation-statements-CU-Pp4-N.mjs} +2 -2
  67. package/dist/{extract-operation-statements-DZUJNmL3.mjs.map → extract-operation-statements-CU-Pp4-N.mjs.map} +1 -1
  68. package/dist/{extract-sql-ddl-DDMX-9mz.mjs → extract-sql-ddl-Bm0Mm0IT.mjs} +1 -1
  69. package/dist/{extract-sql-ddl-DDMX-9mz.mjs.map → extract-sql-ddl-Bm0Mm0IT.mjs.map} +1 -1
  70. package/dist/{framework-components-DfZKQBQ2.mjs → framework-components-Bgcre3Z6.mjs} +2 -2
  71. package/dist/{framework-components-DfZKQBQ2.mjs.map → framework-components-Bgcre3Z6.mjs.map} +1 -1
  72. package/dist/init-C-H-if1m.mjs +2062 -0
  73. package/dist/init-C-H-if1m.mjs.map +1 -0
  74. package/dist/{inspect-live-schema-DWzf4Q_m.mjs → inspect-live-schema-QklSDLt_.mjs} +6 -6
  75. package/dist/{inspect-live-schema-DWzf4Q_m.mjs.map → inspect-live-schema-QklSDLt_.mjs.map} +1 -1
  76. package/dist/migration-cli.mjs +15 -8
  77. package/dist/migration-cli.mjs.map +1 -1
  78. package/dist/{migration-command-scaffold-CLMD302g.mjs → migration-command-scaffold-BfloSWPZ.mjs} +7 -7
  79. package/dist/{migration-command-scaffold-CLMD302g.mjs.map → migration-command-scaffold-BfloSWPZ.mjs.map} +1 -1
  80. package/dist/{migration-status-B0HLF7So.mjs → migration-status-C5VYA5r9.mjs} +21 -35
  81. package/dist/migration-status-C5VYA5r9.mjs.map +1 -0
  82. package/dist/{migrations-B0dOQlk0.mjs → migrations-CSaDHNpB.mjs} +3 -3
  83. package/dist/migrations-CSaDHNpB.mjs.map +1 -0
  84. package/dist/output-BiO7kt87.mjs +103 -0
  85. package/dist/output-BiO7kt87.mjs.map +1 -0
  86. package/dist/{progress-adapter-B-YvmcDu.mjs → progress-adapter-DgRGldpT.mjs} +1 -1
  87. package/dist/{progress-adapter-B-YvmcDu.mjs.map → progress-adapter-DgRGldpT.mjs.map} +1 -1
  88. package/dist/quick-reference-mongo.md +34 -13
  89. package/dist/quick-reference-postgres.md +11 -9
  90. package/dist/{result-handler-CIyu0Pdt.mjs → result-handler-BmVh8AeV.mjs} +12 -93
  91. package/dist/result-handler-BmVh8AeV.mjs.map +1 -0
  92. package/dist/{terminal-ui-C5k88MmW.mjs → terminal-ui-u2YgKghu.mjs} +76 -2
  93. package/dist/terminal-ui-u2YgKghu.mjs.map +1 -0
  94. package/dist/{verify-BxiVp50b.mjs → verify-BumcH6Ry.mjs} +2 -2
  95. package/dist/{verify-BxiVp50b.mjs.map → verify-BumcH6Ry.mjs.map} +1 -1
  96. package/package.json +20 -15
  97. package/src/commands/contract-emit.ts +67 -163
  98. package/src/commands/init/detect-pnpm-catalog.ts +141 -0
  99. package/src/commands/init/errors.ts +254 -0
  100. package/src/commands/init/exit-codes.ts +62 -0
  101. package/src/commands/init/hygiene-gitattributes.ts +97 -0
  102. package/src/commands/init/hygiene-gitignore.ts +48 -0
  103. package/src/commands/init/hygiene-package-scripts.ts +91 -0
  104. package/src/commands/init/index.ts +112 -7
  105. package/src/commands/init/init.ts +766 -144
  106. package/src/commands/init/inputs.ts +421 -0
  107. package/src/commands/init/output.ts +147 -0
  108. package/src/commands/init/probe-db.ts +308 -0
  109. package/src/commands/init/reinit-cleanup.ts +83 -0
  110. package/src/commands/init/templates/agent-skill-mongo.md +63 -31
  111. package/src/commands/init/templates/agent-skill-postgres.md +1 -1
  112. package/src/commands/init/templates/agent-skill.ts +25 -3
  113. package/src/commands/init/templates/code-templates.ts +125 -32
  114. package/src/commands/init/templates/env.ts +80 -0
  115. package/src/commands/init/templates/quick-reference-mongo.md +34 -13
  116. package/src/commands/init/templates/quick-reference-postgres.md +11 -9
  117. package/src/commands/init/templates/quick-reference.ts +42 -3
  118. package/src/commands/init/templates/tsconfig.ts +167 -5
  119. package/src/commands/migration-apply.ts +15 -50
  120. package/src/commands/migration-new.ts +24 -28
  121. package/src/commands/migration-plan.ts +58 -42
  122. package/src/commands/migration-ref.ts +40 -54
  123. package/src/commands/migration-show.ts +27 -28
  124. package/src/commands/migration-status.ts +33 -50
  125. package/src/config-path-validation.ts +0 -1
  126. package/src/control-api/operations/contract-emit.ts +198 -115
  127. package/src/control-api/operations/migration-apply.ts +15 -0
  128. package/src/control-api/types.ts +22 -3
  129. package/src/exports/control-api.ts +2 -1
  130. package/src/exports/init-output.ts +10 -0
  131. package/src/migration-cli.ts +16 -9
  132. package/src/utils/cli-errors.ts +45 -1
  133. package/src/utils/command-helpers.ts +13 -26
  134. package/src/utils/emit-queue.ts +26 -0
  135. package/src/utils/formatters/graph-migration-mapper.ts +2 -2
  136. package/src/utils/formatters/migrations.ts +2 -2
  137. package/src/utils/publish-contract-artifact-pair.ts +134 -0
  138. package/dist/cli-errors-DHq6GQGu.mjs +0 -5
  139. package/dist/client-TG7rbCWT.mjs.map +0 -1
  140. package/dist/config-loader-_W4T21X1.mjs.map +0 -1
  141. package/dist/contract-emit-CNYyzJwF.mjs +0 -195
  142. package/dist/contract-emit-CNYyzJwF.mjs.map +0 -1
  143. package/dist/contract-emit-CQfj7xJn.mjs +0 -122
  144. package/dist/contract-emit-CQfj7xJn.mjs.map +0 -1
  145. package/dist/contract-emit-fhNwwhkQ.mjs +0 -4
  146. package/dist/init-CQfo_4Ro.mjs +0 -430
  147. package/dist/init-CQfo_4Ro.mjs.map +0 -1
  148. package/dist/migration-status-B0HLF7So.mjs.map +0 -1
  149. package/dist/migrations-B0dOQlk0.mjs.map +0 -1
  150. package/dist/result-handler-CIyu0Pdt.mjs.map +0 -1
  151. package/dist/terminal-ui-C5k88MmW.mjs.map +0 -1
  152. package/dist/validate-contract-deps-esa-VQ0h.mjs +0 -37
  153. package/dist/validate-contract-deps-esa-VQ0h.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"contract-infer-BP3DrGgz.mjs","names":[],"sources":["../src/commands/contract-infer-paths.ts","../src/commands/contract-infer.ts"],"sourcesContent":["import { dirname, resolve } from 'pathe';\n\ninterface ContractInferPathOptions {\n readonly output?: string;\n readonly config?: string;\n}\n\n/**\n * Resolves the output path for the inferred PSL contract.\n *\n * Priority:\n * 1. --output <path> flag (resolved relative to cwd)\n * 2. contract.prisma next to config.contract.output\n * 3. Canonical default: contract.prisma in the config directory\n */\nexport function resolveContractInferOutputPath(\n options: ContractInferPathOptions,\n contractOutput: string | undefined,\n): string {\n const configDir = options.config\n ? dirname(resolve(process.cwd(), options.config))\n : process.cwd();\n\n if (options.output) {\n return resolve(process.cwd(), options.output);\n }\n if (contractOutput) {\n const contractPath = resolve(configDir, contractOutput);\n return resolve(dirname(contractPath), 'contract.prisma');\n }\n return resolve(configDir, 'contract.prisma');\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { errorRuntime } from '@prisma-next/errors/execution';\nimport { printPsl, validatePrintableSqlSchemaIR } from '@prisma-next/psl-printer';\nimport {\n createPostgresDefaultMapping,\n createPostgresTypeMap,\n extractEnumInfo,\n parseRawDefault,\n} from '@prisma-next/psl-printer/postgres';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { dirname, relative } from 'pathe';\nimport type { CliStructuredError } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\nimport { resolveContractInferOutputPath } from './contract-infer-paths';\nimport {\n type InspectLiveSchemaOptions,\n type InspectLiveSchemaResult,\n inspectLiveSchema,\n} from './inspect-live-schema';\n\ninterface ContractInferOptions extends InspectLiveSchemaOptions {\n readonly output?: string;\n}\n\ninterface ContractInferSuccessResult {\n readonly ok: true;\n readonly summary: string;\n readonly target: InspectLiveSchemaResult['target'];\n readonly psl: {\n readonly path: string;\n };\n readonly meta: InspectLiveSchemaResult['meta'];\n readonly timings: {\n readonly total: number;\n };\n}\n\nasync function executeContractInferCommand(\n options: ContractInferOptions,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<ContractInferSuccessResult, CliStructuredError>> {\n const flags = parseGlobalFlags(options);\n const inspectResult = await inspectLiveSchema(options, flags, ui, startTime, {\n commandName: 'contract infer',\n description: 'Infer a PSL contract from the live database schema',\n url: 'https://pris.ly/contract-infer',\n });\n\n if (!inspectResult.ok) {\n return inspectResult;\n }\n\n const { config, target, meta } = inspectResult.value;\n\n if (target.familyId !== 'sql') {\n return notOk(\n errorRuntime(`contract infer is not supported for family \"${target.familyId}\"`, {\n why: 'contract infer currently supports SQL targets only',\n fix: 'Use an SQL target (e.g. Postgres) with this command',\n }),\n );\n }\n\n const schema = validatePrintableSqlSchemaIR(inspectResult.value.schema);\n const outputPath = resolveContractInferOutputPath(options, config.contract?.output);\n const enumInfo = extractEnumInfo(schema.annotations);\n const pslContent = printPsl(schema, {\n defaultMapping: createPostgresDefaultMapping(),\n typeMap: createPostgresTypeMap(enumInfo.typeNames),\n enumInfo,\n parseRawDefault,\n });\n\n if (existsSync(outputPath) && !flags.json && !flags.quiet) {\n ui.stderr(`\\u26A0 Overwriting existing file: ${relative(process.cwd(), outputPath)}`);\n }\n\n mkdirSync(dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, pslContent, 'utf-8');\n\n const pslPath = relative(process.cwd(), outputPath);\n if (!flags.json && !flags.quiet) {\n ui.stderr(`\\u2714 Contract written to ${pslPath}`);\n }\n\n return ok({\n ok: true,\n summary: 'Contract inferred successfully',\n target,\n psl: {\n path: pslPath,\n },\n meta,\n timings: {\n total: Date.now() - startTime,\n },\n });\n}\n\nexport function createContractInferCommand(): Command {\n const command = new Command('infer');\n setCommandDescriptions(\n command,\n 'Infer a PSL contract from the live database schema',\n 'Reads the live database schema and writes an inferred PSL contract to disk.\\n' +\n 'This command stops at `contract.prisma`; follow it with `contract emit` and\\n' +\n '`db sign` as separate steps.',\n );\n setCommandExamples(command, [\n 'prisma-next contract infer --db $DATABASE_URL',\n 'prisma-next contract infer --db $DATABASE_URL --output ./prisma/contract.prisma',\n 'prisma-next contract infer --db $DATABASE_URL --json',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--output <path>', 'Write the inferred PSL contract to the specified path')\n .action(async (options: ContractInferOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const startTime = Date.now();\n\n const result = await executeContractInferCommand(options, ui, startTime);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value, null, 2));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAeA,SAAgB,+BACd,SACA,gBACQ;CACR,MAAM,YAAY,QAAQ,SACtB,QAAQ,QAAQ,QAAQ,KAAK,EAAE,QAAQ,OAAO,CAAC,GAC/C,QAAQ,KAAK;AAEjB,KAAI,QAAQ,OACV,QAAO,QAAQ,QAAQ,KAAK,EAAE,QAAQ,OAAO;AAE/C,KAAI,eAEF,QAAO,QAAQ,QADM,QAAQ,WAAW,eAAe,CACnB,EAAE,kBAAkB;AAE1D,QAAO,QAAQ,WAAW,kBAAkB;;;;;ACe9C,eAAe,4BACb,SACA,IACA,WACiE;CACjE,MAAM,QAAQ,iBAAiB,QAAQ;CACvC,MAAM,gBAAgB,MAAM,kBAAkB,SAAS,OAAO,IAAI,WAAW;EAC3E,aAAa;EACb,aAAa;EACb,KAAK;EACN,CAAC;AAEF,KAAI,CAAC,cAAc,GACjB,QAAO;CAGT,MAAM,EAAE,QAAQ,QAAQ,SAAS,cAAc;AAE/C,KAAI,OAAO,aAAa,MACtB,QAAO,MACL,aAAa,+CAA+C,OAAO,SAAS,IAAI;EAC9E,KAAK;EACL,KAAK;EACN,CAAC,CACH;CAGH,MAAM,SAAS,6BAA6B,cAAc,MAAM,OAAO;CACvE,MAAM,aAAa,+BAA+B,SAAS,OAAO,UAAU,OAAO;CACnF,MAAM,WAAW,gBAAgB,OAAO,YAAY;CACpD,MAAM,aAAa,SAAS,QAAQ;EAClC,gBAAgB,8BAA8B;EAC9C,SAAS,sBAAsB,SAAS,UAAU;EAClD;EACA;EACD,CAAC;AAEF,KAAI,WAAW,WAAW,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,MAClD,IAAG,OAAO,qCAAqC,SAAS,QAAQ,KAAK,EAAE,WAAW,GAAG;AAGvF,WAAU,QAAQ,WAAW,EAAE,EAAE,WAAW,MAAM,CAAC;AACnD,eAAc,YAAY,YAAY,QAAQ;CAE9C,MAAM,UAAU,SAAS,QAAQ,KAAK,EAAE,WAAW;AACnD,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,MACxB,IAAG,OAAO,8BAA8B,UAAU;AAGpD,QAAO,GAAG;EACR,IAAI;EACJ,SAAS;EACT;EACA,KAAK,EACH,MAAM,SACP;EACD;EACA,SAAS,EACP,OAAO,KAAK,KAAK,GAAG,WACrB;EACF,CAAC;;AAGJ,SAAgB,6BAAsC;CACpD,MAAM,UAAU,IAAI,QAAQ,QAAQ;AACpC,wBACE,SACA,sDACA,yLAGD;AACD,oBAAmB,SAAS;EAC1B;EACA;EACA;EACD,CAAC;AACF,kBAAiB,QAAQ,CACtB,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,mBAAmB,wDAAwD,CAClF,OAAO,OAAO,YAAkC;EAC/C,MAAM,QAAQ,iBAAiB,QAAQ;EACvC,MAAM,KAAK,IAAI,WAAW;GAAE,OAAO,MAAM;GAAO,aAAa,MAAM;GAAa,CAAC;EAIjF,MAAM,WAAW,aADF,MAAM,4BAA4B,SAAS,IAFxC,KAAK,KAAK,CAE4C,EAClC,OAAO,KAAK,UAAU;AAC1D,OAAI,MAAM,KACR,IAAG,OAAO,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;IAE3C;AAEF,UAAQ,KAAK,SAAS;GACtB;AAEJ,QAAO"}
1
+ {"version":3,"file":"contract-infer-BjzkcwQt.mjs","names":[],"sources":["../src/commands/contract-infer-paths.ts","../src/commands/contract-infer.ts"],"sourcesContent":["import { dirname, resolve } from 'pathe';\n\ninterface ContractInferPathOptions {\n readonly output?: string;\n readonly config?: string;\n}\n\n/**\n * Resolves the output path for the inferred PSL contract.\n *\n * Priority:\n * 1. --output <path> flag (resolved relative to cwd)\n * 2. contract.prisma next to config.contract.output\n * 3. Canonical default: contract.prisma in the config directory\n */\nexport function resolveContractInferOutputPath(\n options: ContractInferPathOptions,\n contractOutput: string | undefined,\n): string {\n const configDir = options.config\n ? dirname(resolve(process.cwd(), options.config))\n : process.cwd();\n\n if (options.output) {\n return resolve(process.cwd(), options.output);\n }\n if (contractOutput) {\n const contractPath = resolve(configDir, contractOutput);\n return resolve(dirname(contractPath), 'contract.prisma');\n }\n return resolve(configDir, 'contract.prisma');\n}\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { errorRuntime } from '@prisma-next/errors/execution';\nimport { printPsl, validatePrintableSqlSchemaIR } from '@prisma-next/psl-printer';\nimport {\n createPostgresDefaultMapping,\n createPostgresTypeMap,\n extractEnumInfo,\n parseRawDefault,\n} from '@prisma-next/psl-printer/postgres';\nimport { notOk, ok, type Result } from '@prisma-next/utils/result';\nimport { Command } from 'commander';\nimport { dirname, relative } from 'pathe';\nimport type { CliStructuredError } from '../utils/cli-errors';\nimport {\n addGlobalOptions,\n setCommandDescriptions,\n setCommandExamples,\n} from '../utils/command-helpers';\nimport { parseGlobalFlags } from '../utils/global-flags';\nimport { handleResult } from '../utils/result-handler';\nimport { TerminalUI } from '../utils/terminal-ui';\nimport { resolveContractInferOutputPath } from './contract-infer-paths';\nimport {\n type InspectLiveSchemaOptions,\n type InspectLiveSchemaResult,\n inspectLiveSchema,\n} from './inspect-live-schema';\n\ninterface ContractInferOptions extends InspectLiveSchemaOptions {\n readonly output?: string;\n}\n\ninterface ContractInferSuccessResult {\n readonly ok: true;\n readonly summary: string;\n readonly target: InspectLiveSchemaResult['target'];\n readonly psl: {\n readonly path: string;\n };\n readonly meta: InspectLiveSchemaResult['meta'];\n readonly timings: {\n readonly total: number;\n };\n}\n\nasync function executeContractInferCommand(\n options: ContractInferOptions,\n ui: TerminalUI,\n startTime: number,\n): Promise<Result<ContractInferSuccessResult, CliStructuredError>> {\n const flags = parseGlobalFlags(options);\n const inspectResult = await inspectLiveSchema(options, flags, ui, startTime, {\n commandName: 'contract infer',\n description: 'Infer a PSL contract from the live database schema',\n url: 'https://pris.ly/contract-infer',\n });\n\n if (!inspectResult.ok) {\n return inspectResult;\n }\n\n const { config, target, meta } = inspectResult.value;\n\n if (target.familyId !== 'sql') {\n return notOk(\n errorRuntime(`contract infer is not supported for family \"${target.familyId}\"`, {\n why: 'contract infer currently supports SQL targets only',\n fix: 'Use an SQL target (e.g. Postgres) with this command',\n }),\n );\n }\n\n const schema = validatePrintableSqlSchemaIR(inspectResult.value.schema);\n const outputPath = resolveContractInferOutputPath(options, config.contract?.output);\n const enumInfo = extractEnumInfo(schema.annotations);\n const pslContent = printPsl(schema, {\n defaultMapping: createPostgresDefaultMapping(),\n typeMap: createPostgresTypeMap(enumInfo.typeNames),\n enumInfo,\n parseRawDefault,\n });\n\n if (existsSync(outputPath) && !flags.json && !flags.quiet) {\n ui.stderr(`\\u26A0 Overwriting existing file: ${relative(process.cwd(), outputPath)}`);\n }\n\n mkdirSync(dirname(outputPath), { recursive: true });\n writeFileSync(outputPath, pslContent, 'utf-8');\n\n const pslPath = relative(process.cwd(), outputPath);\n if (!flags.json && !flags.quiet) {\n ui.stderr(`\\u2714 Contract written to ${pslPath}`);\n }\n\n return ok({\n ok: true,\n summary: 'Contract inferred successfully',\n target,\n psl: {\n path: pslPath,\n },\n meta,\n timings: {\n total: Date.now() - startTime,\n },\n });\n}\n\nexport function createContractInferCommand(): Command {\n const command = new Command('infer');\n setCommandDescriptions(\n command,\n 'Infer a PSL contract from the live database schema',\n 'Reads the live database schema and writes an inferred PSL contract to disk.\\n' +\n 'This command stops at `contract.prisma`; follow it with `contract emit` and\\n' +\n '`db sign` as separate steps.',\n );\n setCommandExamples(command, [\n 'prisma-next contract infer --db $DATABASE_URL',\n 'prisma-next contract infer --db $DATABASE_URL --output ./prisma/contract.prisma',\n 'prisma-next contract infer --db $DATABASE_URL --json',\n ]);\n addGlobalOptions(command)\n .option('--db <url>', 'Database connection string')\n .option('--config <path>', 'Path to prisma-next.config.ts')\n .option('--output <path>', 'Write the inferred PSL contract to the specified path')\n .action(async (options: ContractInferOptions) => {\n const flags = parseGlobalFlags(options);\n const ui = new TerminalUI({ color: flags.color, interactive: flags.interactive });\n const startTime = Date.now();\n\n const result = await executeContractInferCommand(options, ui, startTime);\n const exitCode = handleResult(result, flags, ui, (value) => {\n if (flags.json) {\n ui.output(JSON.stringify(value, null, 2));\n }\n });\n\n process.exit(exitCode);\n });\n\n return command;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAeA,SAAgB,+BACd,SACA,gBACQ;CACR,MAAM,YAAY,QAAQ,SACtB,QAAQ,QAAQ,QAAQ,KAAK,EAAE,QAAQ,OAAO,CAAC,GAC/C,QAAQ,KAAK;AAEjB,KAAI,QAAQ,OACV,QAAO,QAAQ,QAAQ,KAAK,EAAE,QAAQ,OAAO;AAE/C,KAAI,eAEF,QAAO,QAAQ,QADM,QAAQ,WAAW,eAAe,CACnB,EAAE,kBAAkB;AAE1D,QAAO,QAAQ,WAAW,kBAAkB;;;;;ACe9C,eAAe,4BACb,SACA,IACA,WACiE;CACjE,MAAM,QAAQ,iBAAiB,QAAQ;CACvC,MAAM,gBAAgB,MAAM,kBAAkB,SAAS,OAAO,IAAI,WAAW;EAC3E,aAAa;EACb,aAAa;EACb,KAAK;EACN,CAAC;AAEF,KAAI,CAAC,cAAc,GACjB,QAAO;CAGT,MAAM,EAAE,QAAQ,QAAQ,SAAS,cAAc;AAE/C,KAAI,OAAO,aAAa,MACtB,QAAO,MACL,aAAa,+CAA+C,OAAO,SAAS,IAAI;EAC9E,KAAK;EACL,KAAK;EACN,CAAC,CACH;CAGH,MAAM,SAAS,6BAA6B,cAAc,MAAM,OAAO;CACvE,MAAM,aAAa,+BAA+B,SAAS,OAAO,UAAU,OAAO;CACnF,MAAM,WAAW,gBAAgB,OAAO,YAAY;CACpD,MAAM,aAAa,SAAS,QAAQ;EAClC,gBAAgB,8BAA8B;EAC9C,SAAS,sBAAsB,SAAS,UAAU;EAClD;EACA;EACD,CAAC;AAEF,KAAI,WAAW,WAAW,IAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,MAClD,IAAG,OAAO,qCAAqC,SAAS,QAAQ,KAAK,EAAE,WAAW,GAAG;AAGvF,WAAU,QAAQ,WAAW,EAAE,EAAE,WAAW,MAAM,CAAC;AACnD,eAAc,YAAY,YAAY,QAAQ;CAE9C,MAAM,UAAU,SAAS,QAAQ,KAAK,EAAE,WAAW;AACnD,KAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,MACxB,IAAG,OAAO,8BAA8B,UAAU;AAGpD,QAAO,GAAG;EACR,IAAI;EACJ,SAAS;EACT;EACA,KAAK,EACH,MAAM,SACP;EACD;EACA,SAAS,EACP,OAAO,KAAK,KAAK,GAAG,WACrB;EACF,CAAC;;AAGJ,SAAgB,6BAAsC;CACpD,MAAM,UAAU,IAAI,QAAQ,QAAQ;AACpC,wBACE,SACA,sDACA,yLAGD;AACD,oBAAmB,SAAS;EAC1B;EACA;EACA;EACD,CAAC;AACF,kBAAiB,QAAQ,CACtB,OAAO,cAAc,6BAA6B,CAClD,OAAO,mBAAmB,gCAAgC,CAC1D,OAAO,mBAAmB,wDAAwD,CAClF,OAAO,OAAO,YAAkC;EAC/C,MAAM,QAAQ,iBAAiB,QAAQ;EACvC,MAAM,KAAK,IAAI,WAAW;GAAE,OAAO,MAAM;GAAO,aAAa,MAAM;GAAa,CAAC;EAIjF,MAAM,WAAW,aADF,MAAM,4BAA4B,SAAS,IAFxC,KAAK,KAAK,CAE4C,EAClC,OAAO,KAAK,UAAU;AAC1D,OAAI,MAAM,KACR,IAAG,OAAO,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;IAE3C;AAEF,UAAQ,KAAK,SAAS;GACtB;AAEJ,QAAO"}
@@ -427,17 +427,30 @@ interface MigrationApplyFailure {
427
427
  type MigrationApplyResult = Result<MigrationApplySuccess, MigrationApplyFailure>;
428
428
  /**
429
429
  * Options for the standalone executeContractEmit function.
430
- * Used by tooling (e.g., Vite plugin) that needs to emit contracts
431
- * without the full ControlClient infrastructure.
430
+ *
431
+ * `executeContractEmit` is the canonical publication path for both the
432
+ * `prisma-next contract emit` CLI command and the `@prisma-next/vite-plugin-contract-emit`
433
+ * Vite plugin. Do not duplicate the load → emit → publish dance elsewhere; if a
434
+ * caller needs additional behavior, extend this options shape and update the
435
+ * single implementation rather than building a parallel publication path.
436
+ *
437
+ * Concurrent calls for the same output JSON path are serialized per-output via
438
+ * a FIFO queue; concurrent calls for distinct outputs run in parallel.
432
439
  */
433
440
  interface ContractEmitOptions {
434
441
  /** Path to the prisma-next.config.ts file */
435
442
  readonly configPath: string;
436
- /** Optional AbortSignal for cancellation support */
443
+ /** Optional AbortSignal for cancelling the in-flight emit */
437
444
  readonly signal?: AbortSignal;
445
+ /** Optional progress callback for observing source-resolution and emit spans */
446
+ readonly onProgress?: OnControlProgress;
438
447
  }
439
448
  /**
440
449
  * Result from the standalone executeContractEmit function.
450
+ *
451
+ * Always describes the bytes that were just published to disk. Failures throw
452
+ * (config / source-resolution / emit / publish) — callers do not need to
453
+ * branch on a result discriminator.
441
454
  */
442
455
  interface ContractEmitResult {
443
456
  /** Hash of the storage contract (schema-level) */
@@ -453,6 +466,12 @@ interface ContractEmitResult {
453
466
  /** Path to the emitted contract.d.ts file */
454
467
  readonly dts: string;
455
468
  };
469
+ /**
470
+ * Warning surfaced by `validateContractDeps` after a successful publication.
471
+ * Callers (CLI, Vite plugin) decide how to render this; the operation does
472
+ * not write to stderr itself. Undefined when no warning was raised.
473
+ */
474
+ readonly validationWarning?: string;
456
475
  }
457
476
  /**
458
477
  * Programmatic control client for Prisma Next operations.
@@ -602,23 +621,29 @@ declare function enrichContract(ir: Contract, components: ReadonlyArray<TargetBo
602
621
  //#endregion
603
622
  //#region src/control-api/operations/contract-emit.d.ts
604
623
  /**
605
- * Executes the contract emit operation.
624
+ * Canonical contract emit operation.
606
625
  *
607
- * This is an offline operation that:
608
- * 1. Loads the Prisma Next config from the specified path
609
- * 2. Resolves the contract source from config
610
- * 3. Creates a control plane stack and family instance
611
- * 4. Emits contract artifacts (JSON and DTS)
612
- * 5. Writes files to the paths specified in config
626
+ * This is the SINGLE publication path used by both the CLI command
627
+ * (`prisma-next contract emit`) and the Vite plugin
628
+ * (`@prisma-next/vite-plugin-contract-emit`). New callers must go through this
629
+ * function rather than re-implementing load emit publish.
613
630
  *
614
- * Supports AbortSignal for cancellation, enabling "last change wins" behavior.
631
+ * The whole flow (load config resolve source → emit bytes → atomic publish)
632
+ * is serialized per output JSON path via `queueEmitByOutput`. Concurrent calls
633
+ * for the same output line up FIFO; the user-visible outcome is "last
634
+ * submission wins on disk" without any supersession bookkeeping. Within a
635
+ * single emit, `publishContractArtifactPair` stages temp files, renames
636
+ * `contract.d.ts` before `contract.json`, and attempts to restore the previous
637
+ * pair if either rename fails — so type-only consumers never observe a
638
+ * mismatched pair.
615
639
  *
616
- * @param options - Options including configPath and optional signal
617
- * @returns File paths and hashes of emitted artifacts
618
- * @throws If config loading fails, contract is invalid, or file I/O fails
619
- * @throws signal.reason if cancelled via AbortSignal (typically DOMException with name 'AbortError')
640
+ * @throws {CliStructuredError} on config/source/validation problems
641
+ * @throws {DOMException} `AbortError` if cancelled via `signal`
620
642
  */
621
643
  declare function executeContractEmit(options: ContractEmitOptions): Promise<ContractEmitResult>;
622
644
  //#endregion
623
- export { type ContractEmitOptions, type ContractEmitResult, type ControlActionName, type ControlClient, type ControlClientOptions, type ControlProgressEvent, type ControlStack, type DbInitFailure, type DbInitFailureCode, type DbInitOptions, type DbInitResult, type DbInitSuccess, type DbUpdateFailure, type DbUpdateFailureCode, type DbUpdateOptions, type DbUpdateResult, type DbUpdateSuccess, type EmitContractConfig, type EmitFailure, type EmitFailureCode, type EmitOptions, type EmitResult, type EmitSuccess, type IntrospectOptions, type OnControlProgress, type SchemaVerifyOptions, type SignDatabaseResult, type SignOptions, type VerifyDatabaseResult, type VerifyDatabaseSchemaResult, type VerifyOptions, createControlClient, enrichContract, executeContractEmit };
645
+ //#region src/utils/emit-queue.d.ts
646
+ declare function disposeEmitQueue(outputJsonPath: string): void;
647
+ //#endregion
648
+ export { type ContractEmitOptions, type ContractEmitResult, type ControlActionName, type ControlClient, type ControlClientOptions, type ControlProgressEvent, type ControlStack, type DbInitFailure, type DbInitFailureCode, type DbInitOptions, type DbInitResult, type DbInitSuccess, type DbUpdateFailure, type DbUpdateFailureCode, type DbUpdateOptions, type DbUpdateResult, type DbUpdateSuccess, type EmitContractConfig, type EmitFailure, type EmitFailureCode, type EmitOptions, type EmitResult, type EmitSuccess, type IntrospectOptions, type OnControlProgress, type SchemaVerifyOptions, type SignDatabaseResult, type SignOptions, type VerifyDatabaseResult, type VerifyDatabaseSchemaResult, type VerifyOptions, createControlClient, disposeEmitQueue, enrichContract, executeContractEmit };
624
649
  //# sourceMappingURL=control-api.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"control-api.d.mts","names":[],"sources":["../../src/control-api/types.ts","../../src/control-api/client.ts","../../src/control-api/contract-enrichment.ts","../../src/control-api/operations/contract-emit.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"control-api.d.mts","names":[],"sources":["../../src/control-api/types.ts","../../src/control-api/client.ts","../../src/control-api/contract-enrichment.ts","../../src/control-api/operations/contract-emit.ts","../../src/utils/emit-queue.ts"],"sourcesContent":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
- import "../config-loader-_W4T21X1.mjs";
2
- import { t as enrichContract } from "../contract-enrichment-CGW6mm-E.mjs";
3
- import { t as createControlClient } from "../client-TG7rbCWT.mjs";
4
- import { t as executeContractEmit } from "../contract-emit-CQfj7xJn.mjs";
1
+ import "../config-loader-ih8ViDb_.mjs";
2
+ import "../cli-errors-By1iVE3z.mjs";
3
+ import { n as disposeEmitQueue, t as executeContractEmit } from "../contract-emit-RZBWzkop.mjs";
4
+ import "../framework-components-Bgcre3Z6.mjs";
5
+ import { t as enrichContract } from "../contract-enrichment-4Ptgw3Pe.mjs";
6
+ import { t as createControlClient } from "../client-enZIahga.mjs";
5
7
 
6
- export { createControlClient, enrichContract, executeContractEmit };
8
+ export { createControlClient, disposeEmitQueue, enrichContract, executeContractEmit };
@@ -1,7 +1,12 @@
1
- import "../config-loader-_W4T21X1.mjs";
2
- import { t as createContractEmitCommand } from "../contract-emit-CNYyzJwF.mjs";
3
- import { existsSync, unlinkSync, writeFileSync } from "node:fs";
1
+ import "../config-loader-ih8ViDb_.mjs";
2
+ import "../cli-errors-By1iVE3z.mjs";
3
+ import "../contract-emit-RZBWzkop.mjs";
4
+ import "../framework-components-Bgcre3Z6.mjs";
5
+ import "../terminal-ui-u2YgKghu.mjs";
6
+ import "../result-handler-BmVh8AeV.mjs";
7
+ import { t as createContractEmitCommand } from "../contract-emit-DWtGQYCD.mjs";
4
8
  import { join } from "pathe";
9
+ import { existsSync, unlinkSync, writeFileSync } from "node:fs";
5
10
  import { tmpdir } from "node:os";
6
11
  import { pathToFileURL } from "node:url";
7
12
  import { build } from "esbuild";
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["value","disallowedImports: string[]","contract: unknown"],"sources":["../../src/load-ts-contract.ts"],"sourcesContent":["import { existsSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { pathToFileURL } from 'node:url';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { Plugin } from 'esbuild';\nimport { build } from 'esbuild';\nimport { join } from 'pathe';\n\nexport interface LoadTsContractOptions {\n readonly allowlist?: ReadonlyArray<string>;\n}\n\nconst DEFAULT_ALLOWLIST = ['@prisma-next/*', 'node:crypto'];\n\nfunction isAllowedImport(importPath: string, allowlist: ReadonlyArray<string>): boolean {\n for (const pattern of allowlist) {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n if (importPath === prefix || importPath.startsWith(`${prefix}/`)) {\n return true;\n }\n } else if (pattern.endsWith('*')) {\n const prefix = pattern.slice(0, -1);\n if (importPath.startsWith(prefix)) {\n return true;\n }\n } else if (importPath === pattern) {\n return true;\n }\n }\n return false;\n}\n\nfunction validatePurity(value: unknown): void {\n if (typeof value !== 'object' || value === null) {\n return;\n }\n\n const path = new WeakSet();\n\n function check(value: unknown): void {\n if (value === null || typeof value !== 'object') {\n return;\n }\n\n if (path.has(value)) {\n throw new Error('Contract export contains circular references');\n }\n path.add(value);\n\n try {\n for (const key in value) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (descriptor && (descriptor.get || descriptor.set)) {\n throw new Error(`Contract export contains getter/setter at key \"${key}\"`);\n }\n if (descriptor && typeof descriptor.value === 'function') {\n throw new Error(`Contract export contains function at key \"${key}\"`);\n }\n check((value as Record<string, unknown>)[key]);\n }\n } finally {\n path.delete(value);\n }\n }\n\n try {\n check(value);\n JSON.stringify(value);\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('getter') || error.message.includes('circular')) {\n throw error;\n }\n throw new Error(`Contract export is not JSON-serializable: ${error.message}`);\n }\n throw new Error('Contract export is not JSON-serializable');\n }\n}\n\nfunction createImportAllowlistPlugin(allowlist: ReadonlyArray<string>, entryPath: string): Plugin {\n return {\n name: 'import-allowlist',\n setup(build) {\n build.onResolve({ filter: /.*/ }, (args) => {\n if (args.kind === 'entry-point') {\n return undefined;\n }\n if (args.path.startsWith('.') || args.path.startsWith('/')) {\n return undefined;\n }\n const isFromEntryPoint = args.importer === entryPath || args.importer === '<stdin>';\n if (isFromEntryPoint && !isAllowedImport(args.path, allowlist)) {\n return {\n path: args.path,\n external: true,\n };\n }\n return undefined;\n });\n },\n };\n}\n\n/**\n * Loads a contract from a TypeScript file and returns it as Contract.\n *\n * **Responsibility: Parsing Only**\n * This function loads and parses a TypeScript contract file. It does NOT normalize the contract.\n * The contract should already be normalized if it was built using the contract builder.\n *\n * Normalization must happen in the contract builder when the contract is created.\n * This function only validates that the contract is JSON-serializable and returns it as-is.\n *\n * @param entryPath - Path to the TypeScript contract file\n * @param options - Optional configuration (import allowlist)\n * @returns The contract as Contract (should already be normalized)\n * @throws Error if the contract cannot be loaded or is not JSON-serializable\n */\nexport async function loadContractFromTs(\n entryPath: string,\n options?: LoadTsContractOptions,\n): Promise<Contract> {\n const allowlist = options?.allowlist ?? DEFAULT_ALLOWLIST;\n\n if (!existsSync(entryPath)) {\n throw new Error(`Contract file not found: ${entryPath}`);\n }\n\n const tempFile = join(\n tmpdir(),\n `prisma-next-contract-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`,\n );\n\n try {\n const result = await build({\n entryPoints: [entryPath],\n bundle: true,\n format: 'esm',\n platform: 'node',\n target: 'es2022',\n outfile: tempFile,\n write: false,\n metafile: true,\n plugins: [createImportAllowlistPlugin(allowlist, entryPath)],\n logLevel: 'error',\n });\n\n if (result.errors.length > 0) {\n const errorMessages = result.errors.map((e: { text: string }) => e.text).join('\\n');\n throw new Error(`Failed to bundle contract file: ${errorMessages}`);\n }\n\n if (!result.outputFiles || result.outputFiles.length === 0) {\n throw new Error('No output files generated from bundling');\n }\n\n const disallowedImports: string[] = [];\n if (result.metafile) {\n const inputs = result.metafile.inputs;\n for (const [, inputData] of Object.entries(inputs)) {\n const imports =\n (inputData as { imports?: Array<{ path: string; external?: boolean }> }).imports || [];\n for (const imp of imports) {\n if (\n imp.external &&\n !imp.path.startsWith('.') &&\n !imp.path.startsWith('/') &&\n !isAllowedImport(imp.path, allowlist)\n ) {\n disallowedImports.push(imp.path);\n }\n }\n }\n }\n\n if (disallowedImports.length > 0) {\n throw new Error(\n `Disallowed imports detected. Only imports matching the allowlist are permitted:\\n Allowlist: ${allowlist.join(', ')}\\n Disallowed imports: ${disallowedImports.join(', ')}\\n\\nOnly @prisma-next/* packages are allowed in contract files.`,\n );\n }\n\n const bundleContent = result.outputFiles[0]?.text;\n if (bundleContent === undefined) {\n throw new Error('Bundle content is undefined');\n }\n writeFileSync(tempFile, bundleContent, 'utf-8');\n\n const module = (await import(/* @vite-ignore */ pathToFileURL(tempFile).href)) as {\n default?: unknown;\n contract?: unknown;\n };\n unlinkSync(tempFile);\n\n let contract: unknown;\n\n if (module.default !== undefined) {\n contract = module.default;\n } else if (module.contract !== undefined) {\n contract = module.contract;\n } else {\n throw new Error(\n `Contract file must export a contract as default export or named export 'contract'. Found exports: ${Object.keys(module as Record<string, unknown>).join(', ') || 'none'}`,\n );\n }\n\n if (typeof contract !== 'object' || contract === null) {\n throw new Error(`Contract export must be an object, got ${typeof contract}`);\n }\n\n validatePurity(contract);\n\n return contract as Contract;\n } catch (error) {\n try {\n if (tempFile) {\n unlinkSync(tempFile);\n }\n } catch {\n // Ignore cleanup errors\n }\n\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Failed to load contract from ${entryPath}: ${String(error)}`);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["value","disallowedImports: string[]","contract: unknown"],"sources":["../../src/load-ts-contract.ts"],"sourcesContent":["import { existsSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { pathToFileURL } from 'node:url';\nimport type { Contract } from '@prisma-next/contract/types';\nimport type { Plugin } from 'esbuild';\nimport { build } from 'esbuild';\nimport { join } from 'pathe';\n\nexport interface LoadTsContractOptions {\n readonly allowlist?: ReadonlyArray<string>;\n}\n\nconst DEFAULT_ALLOWLIST = ['@prisma-next/*', 'node:crypto'];\n\nfunction isAllowedImport(importPath: string, allowlist: ReadonlyArray<string>): boolean {\n for (const pattern of allowlist) {\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2);\n if (importPath === prefix || importPath.startsWith(`${prefix}/`)) {\n return true;\n }\n } else if (pattern.endsWith('*')) {\n const prefix = pattern.slice(0, -1);\n if (importPath.startsWith(prefix)) {\n return true;\n }\n } else if (importPath === pattern) {\n return true;\n }\n }\n return false;\n}\n\nfunction validatePurity(value: unknown): void {\n if (typeof value !== 'object' || value === null) {\n return;\n }\n\n const path = new WeakSet();\n\n function check(value: unknown): void {\n if (value === null || typeof value !== 'object') {\n return;\n }\n\n if (path.has(value)) {\n throw new Error('Contract export contains circular references');\n }\n path.add(value);\n\n try {\n for (const key in value) {\n const descriptor = Object.getOwnPropertyDescriptor(value, key);\n if (descriptor && (descriptor.get || descriptor.set)) {\n throw new Error(`Contract export contains getter/setter at key \"${key}\"`);\n }\n if (descriptor && typeof descriptor.value === 'function') {\n throw new Error(`Contract export contains function at key \"${key}\"`);\n }\n check((value as Record<string, unknown>)[key]);\n }\n } finally {\n path.delete(value);\n }\n }\n\n try {\n check(value);\n JSON.stringify(value);\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes('getter') || error.message.includes('circular')) {\n throw error;\n }\n throw new Error(`Contract export is not JSON-serializable: ${error.message}`);\n }\n throw new Error('Contract export is not JSON-serializable');\n }\n}\n\nfunction createImportAllowlistPlugin(allowlist: ReadonlyArray<string>, entryPath: string): Plugin {\n return {\n name: 'import-allowlist',\n setup(build) {\n build.onResolve({ filter: /.*/ }, (args) => {\n if (args.kind === 'entry-point') {\n return undefined;\n }\n if (args.path.startsWith('.') || args.path.startsWith('/')) {\n return undefined;\n }\n const isFromEntryPoint = args.importer === entryPath || args.importer === '<stdin>';\n if (isFromEntryPoint && !isAllowedImport(args.path, allowlist)) {\n return {\n path: args.path,\n external: true,\n };\n }\n return undefined;\n });\n },\n };\n}\n\n/**\n * Loads a contract from a TypeScript file and returns it as Contract.\n *\n * **Responsibility: Parsing Only**\n * This function loads and parses a TypeScript contract file. It does NOT normalize the contract.\n * The contract should already be normalized if it was built using the contract builder.\n *\n * Normalization must happen in the contract builder when the contract is created.\n * This function only validates that the contract is JSON-serializable and returns it as-is.\n *\n * @param entryPath - Path to the TypeScript contract file\n * @param options - Optional configuration (import allowlist)\n * @returns The contract as Contract (should already be normalized)\n * @throws Error if the contract cannot be loaded or is not JSON-serializable\n */\nexport async function loadContractFromTs(\n entryPath: string,\n options?: LoadTsContractOptions,\n): Promise<Contract> {\n const allowlist = options?.allowlist ?? DEFAULT_ALLOWLIST;\n\n if (!existsSync(entryPath)) {\n throw new Error(`Contract file not found: ${entryPath}`);\n }\n\n const tempFile = join(\n tmpdir(),\n `prisma-next-contract-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`,\n );\n\n try {\n const result = await build({\n entryPoints: [entryPath],\n bundle: true,\n format: 'esm',\n platform: 'node',\n target: 'es2022',\n outfile: tempFile,\n write: false,\n metafile: true,\n plugins: [createImportAllowlistPlugin(allowlist, entryPath)],\n logLevel: 'error',\n });\n\n if (result.errors.length > 0) {\n const errorMessages = result.errors.map((e: { text: string }) => e.text).join('\\n');\n throw new Error(`Failed to bundle contract file: ${errorMessages}`);\n }\n\n if (!result.outputFiles || result.outputFiles.length === 0) {\n throw new Error('No output files generated from bundling');\n }\n\n const disallowedImports: string[] = [];\n if (result.metafile) {\n const inputs = result.metafile.inputs;\n for (const [, inputData] of Object.entries(inputs)) {\n const imports =\n (inputData as { imports?: Array<{ path: string; external?: boolean }> }).imports || [];\n for (const imp of imports) {\n if (\n imp.external &&\n !imp.path.startsWith('.') &&\n !imp.path.startsWith('/') &&\n !isAllowedImport(imp.path, allowlist)\n ) {\n disallowedImports.push(imp.path);\n }\n }\n }\n }\n\n if (disallowedImports.length > 0) {\n throw new Error(\n `Disallowed imports detected. Only imports matching the allowlist are permitted:\\n Allowlist: ${allowlist.join(', ')}\\n Disallowed imports: ${disallowedImports.join(', ')}\\n\\nOnly @prisma-next/* packages are allowed in contract files.`,\n );\n }\n\n const bundleContent = result.outputFiles[0]?.text;\n if (bundleContent === undefined) {\n throw new Error('Bundle content is undefined');\n }\n writeFileSync(tempFile, bundleContent, 'utf-8');\n\n const module = (await import(/* @vite-ignore */ pathToFileURL(tempFile).href)) as {\n default?: unknown;\n contract?: unknown;\n };\n unlinkSync(tempFile);\n\n let contract: unknown;\n\n if (module.default !== undefined) {\n contract = module.default;\n } else if (module.contract !== undefined) {\n contract = module.contract;\n } else {\n throw new Error(\n `Contract file must export a contract as default export or named export 'contract'. Found exports: ${Object.keys(module as Record<string, unknown>).join(', ') || 'none'}`,\n );\n }\n\n if (typeof contract !== 'object' || contract === null) {\n throw new Error(`Contract export must be an object, got ${typeof contract}`);\n }\n\n validatePurity(contract);\n\n return contract as Contract;\n } catch (error) {\n try {\n if (tempFile) {\n unlinkSync(tempFile);\n }\n } catch {\n // Ignore cleanup errors\n }\n\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Failed to load contract from ${entryPath}: ${String(error)}`);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import "@clack/prompts";
2
+ import * as arktype_internal_variants_object_ts0 from "arktype/internal/variants/object.ts";
3
+
4
+ //#region src/commands/init/output.d.ts
5
+
6
+ /**
7
+ * arktype schema for the structured success document `init --json` writes
8
+ * to stdout (FR1.5). The same shape backs the human-readable outro
9
+ * renderer (FR10), so the two output modes carry identical information.
10
+ *
11
+ * `target` is normalised to the user-facing flag value (`mongodb` rather
12
+ * than the internal `mongo`) so consumers can round-trip the document
13
+ * straight into a follow-up `--target` invocation.
14
+ *
15
+ * The `ok: true` literal is the documented success/error discriminator —
16
+ * see [Style Guide § JSON Semantics](../../../../../../../docs/CLI%20Style%20Guide.md#json-semantics).
17
+ * Error envelopes (`CliErrorEnvelope`) carry `ok: false` so consumers can
18
+ * branch with `if (doc.ok)` without inspecting the rest of the structure.
19
+ */
20
+ declare const InitOutputSchema: arktype_internal_variants_object_ts0.ObjectType<{
21
+ ok: true;
22
+ target: "postgres" | "mongodb";
23
+ authoring: "psl" | "typescript";
24
+ schemaPath: string;
25
+ filesWritten: string[];
26
+ filesDeleted: string[];
27
+ packagesInstalled: {
28
+ skipped: boolean;
29
+ deps: string[];
30
+ devDeps: string[];
31
+ };
32
+ contractEmitted: boolean;
33
+ nextSteps: string[];
34
+ warnings: string[];
35
+ }, {}>;
36
+ type InitOutput = typeof InitOutputSchema.infer;
37
+ //#endregion
38
+ export { type InitOutput, InitOutputSchema };
39
+ //# sourceMappingURL=init-output.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-output.d.mts","names":[],"sources":["../../src/commands/init/output.ts"],"sourcesContent":[],"mappings":";;;;;;;AAkBA;AAwBA;;;;;;;;;;;cAxBa,kBAsBX,oCAAA,CAtB2B;;;;;;;;;;;;;;;;KAwBjB,UAAA,UAAoB,gBAAA,CAAiB"}
@@ -0,0 +1,3 @@
1
+ import { t as InitOutputSchema } from "../output-BiO7kt87.mjs";
2
+
3
+ export { InitOutputSchema };
@@ -1,4 +1,4 @@
1
- import { t as extractSqlDdl } from "./extract-sql-ddl-DDMX-9mz.mjs";
1
+ import { t as extractSqlDdl } from "./extract-sql-ddl-Bm0Mm0IT.mjs";
2
2
 
3
3
  //#region src/control-api/operations/extract-operation-statements.ts
4
4
  function extractOperationStatements(familyId, operations) {
@@ -10,4 +10,4 @@ function extractOperationStatements(familyId, operations) {
10
10
 
11
11
  //#endregion
12
12
  export { extractOperationStatements as t };
13
- //# sourceMappingURL=extract-operation-statements-DZUJNmL3.mjs.map
13
+ //# sourceMappingURL=extract-operation-statements-CU-Pp4-N.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extract-operation-statements-DZUJNmL3.mjs","names":[],"sources":["../src/control-api/operations/extract-operation-statements.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { extractSqlDdl } from './extract-sql-ddl';\n\nexport function extractOperationStatements(\n familyId: string,\n operations: readonly MigrationPlanOperation[],\n): string[] | undefined {\n switch (familyId) {\n case 'sql':\n return extractSqlDdl(operations);\n default:\n return undefined;\n }\n}\n"],"mappings":";;;AAGA,SAAgB,2BACd,UACA,YACsB;AACtB,SAAQ,UAAR;EACE,KAAK,MACH,QAAO,cAAc,WAAW;EAClC,QACE"}
1
+ {"version":3,"file":"extract-operation-statements-CU-Pp4-N.mjs","names":[],"sources":["../src/control-api/operations/extract-operation-statements.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\nimport { extractSqlDdl } from './extract-sql-ddl';\n\nexport function extractOperationStatements(\n familyId: string,\n operations: readonly MigrationPlanOperation[],\n): string[] | undefined {\n switch (familyId) {\n case 'sql':\n return extractSqlDdl(operations);\n default:\n return undefined;\n }\n}\n"],"mappings":";;;AAGA,SAAgB,2BACd,UACA,YACsB;AACtB,SAAQ,UAAR;EACE,KAAK,MACH,QAAO,cAAc,WAAW;EAClC,QACE"}
@@ -23,4 +23,4 @@ function extractSqlDdl(operations) {
23
23
 
24
24
  //#endregion
25
25
  export { extractSqlDdl as t };
26
- //# sourceMappingURL=extract-sql-ddl-DDMX-9mz.mjs.map
26
+ //# sourceMappingURL=extract-sql-ddl-Bm0Mm0IT.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extract-sql-ddl-DDMX-9mz.mjs","names":["statements: string[]"],"sources":["../src/control-api/operations/extract-sql-ddl.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\n\n/**\n * Shape of an SQL execute step on SqlMigrationPlanOperation.\n * Used for runtime type narrowing without importing the concrete SQL type.\n */\ninterface SqlExecuteStep {\n readonly sql: string;\n}\n\nfunction isDdlStatement(sqlStatement: string): boolean {\n const trimmed = sqlStatement.trim().toLowerCase();\n return (\n trimmed.startsWith('create ') || trimmed.startsWith('alter ') || trimmed.startsWith('drop ')\n );\n}\n\nfunction hasExecuteSteps(\n operation: MigrationPlanOperation,\n): operation is MigrationPlanOperation & { readonly execute: readonly SqlExecuteStep[] } {\n const candidate = operation as unknown as Record<string, unknown>;\n if (!('execute' in candidate) || !Array.isArray(candidate['execute'])) {\n return false;\n }\n return candidate['execute'].every(\n (step: unknown) => typeof step === 'object' && step !== null && 'sql' in step,\n );\n}\n\n/**\n * Extracts a best-effort SQL DDL preview for CLI plan output.\n * This helper is presentation-only and is never used to decide migration correctness.\n */\nexport function extractSqlDdl(operations: readonly MigrationPlanOperation[]): string[] {\n const statements: string[] = [];\n for (const operation of operations) {\n if (!hasExecuteSteps(operation)) {\n continue;\n }\n for (const step of operation.execute) {\n if (typeof step.sql === 'string' && isDdlStatement(step.sql)) {\n statements.push(step.sql.trim());\n }\n }\n }\n return statements;\n}\n"],"mappings":";AAUA,SAAS,eAAe,cAA+B;CACrD,MAAM,UAAU,aAAa,MAAM,CAAC,aAAa;AACjD,QACE,QAAQ,WAAW,UAAU,IAAI,QAAQ,WAAW,SAAS,IAAI,QAAQ,WAAW,QAAQ;;AAIhG,SAAS,gBACP,WACuF;CACvF,MAAM,YAAY;AAClB,KAAI,EAAE,aAAa,cAAc,CAAC,MAAM,QAAQ,UAAU,WAAW,CACnE,QAAO;AAET,QAAO,UAAU,WAAW,OACzB,SAAkB,OAAO,SAAS,YAAY,SAAS,QAAQ,SAAS,KAC1E;;;;;;AAOH,SAAgB,cAAc,YAAyD;CACrF,MAAMA,aAAuB,EAAE;AAC/B,MAAK,MAAM,aAAa,YAAY;AAClC,MAAI,CAAC,gBAAgB,UAAU,CAC7B;AAEF,OAAK,MAAM,QAAQ,UAAU,QAC3B,KAAI,OAAO,KAAK,QAAQ,YAAY,eAAe,KAAK,IAAI,CAC1D,YAAW,KAAK,KAAK,IAAI,MAAM,CAAC;;AAItC,QAAO"}
1
+ {"version":3,"file":"extract-sql-ddl-Bm0Mm0IT.mjs","names":["statements: string[]"],"sources":["../src/control-api/operations/extract-sql-ddl.ts"],"sourcesContent":["import type { MigrationPlanOperation } from '@prisma-next/framework-components/control';\n\n/**\n * Shape of an SQL execute step on SqlMigrationPlanOperation.\n * Used for runtime type narrowing without importing the concrete SQL type.\n */\ninterface SqlExecuteStep {\n readonly sql: string;\n}\n\nfunction isDdlStatement(sqlStatement: string): boolean {\n const trimmed = sqlStatement.trim().toLowerCase();\n return (\n trimmed.startsWith('create ') || trimmed.startsWith('alter ') || trimmed.startsWith('drop ')\n );\n}\n\nfunction hasExecuteSteps(\n operation: MigrationPlanOperation,\n): operation is MigrationPlanOperation & { readonly execute: readonly SqlExecuteStep[] } {\n const candidate = operation as unknown as Record<string, unknown>;\n if (!('execute' in candidate) || !Array.isArray(candidate['execute'])) {\n return false;\n }\n return candidate['execute'].every(\n (step: unknown) => typeof step === 'object' && step !== null && 'sql' in step,\n );\n}\n\n/**\n * Extracts a best-effort SQL DDL preview for CLI plan output.\n * This helper is presentation-only and is never used to decide migration correctness.\n */\nexport function extractSqlDdl(operations: readonly MigrationPlanOperation[]): string[] {\n const statements: string[] = [];\n for (const operation of operations) {\n if (!hasExecuteSteps(operation)) {\n continue;\n }\n for (const step of operation.execute) {\n if (typeof step.sql === 'string' && isDdlStatement(step.sql)) {\n statements.push(step.sql.trim());\n }\n }\n }\n return statements;\n}\n"],"mappings":";AAUA,SAAS,eAAe,cAA+B;CACrD,MAAM,UAAU,aAAa,MAAM,CAAC,aAAa;AACjD,QACE,QAAQ,WAAW,UAAU,IAAI,QAAQ,WAAW,SAAS,IAAI,QAAQ,WAAW,QAAQ;;AAIhG,SAAS,gBACP,WACuF;CACvF,MAAM,YAAY;AAClB,KAAI,EAAE,aAAa,cAAc,CAAC,MAAM,QAAQ,UAAU,WAAW,CACnE,QAAO;AAET,QAAO,UAAU,WAAW,OACzB,SAAkB,OAAO,SAAS,YAAY,SAAS,QAAQ,SAAS,KAC1E;;;;;;AAOH,SAAgB,cAAc,YAAyD;CACrF,MAAMA,aAAuB,EAAE;AAC/B,MAAK,MAAM,aAAa,YAAY;AAClC,MAAI,CAAC,gBAAgB,UAAU,CAC7B;AAEF,OAAK,MAAM,QAAQ,UAAU,QAC3B,KAAI,OAAO,KAAK,QAAQ,YAAY,eAAe,KAAK,IAAI,CAC1D,YAAW,KAAK,KAAK,IAAI,MAAM,CAAC;;AAItC,QAAO"}
@@ -1,4 +1,4 @@
1
- import { r as errorConfigValidation } from "./cli-errors-DHq6GQGu.mjs";
1
+ import { r as errorConfigValidation } from "./cli-errors-By1iVE3z.mjs";
2
2
  import "@prisma-next/framework-components/components";
3
3
 
4
4
  //#region src/utils/framework-components.ts
@@ -56,4 +56,4 @@ function assertFrameworkComponentsCompatible(expectedFamilyId, expectedTargetId,
56
56
 
57
57
  //#endregion
58
58
  export { assertFrameworkComponentsCompatible as t };
59
- //# sourceMappingURL=framework-components-DfZKQBQ2.mjs.map
59
+ //# sourceMappingURL=framework-components-Bgcre3Z6.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"framework-components-DfZKQBQ2.mjs","names":[],"sources":["../src/utils/framework-components.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport {\n checkContractComponentRequirements,\n type TargetBoundComponentDescriptor,\n} from '@prisma-next/framework-components/components';\nimport type { ControlStack } from '@prisma-next/framework-components/control';\nimport { errorConfigValidation, errorContractMissingExtensionPacks } from './cli-errors';\n\n/**\n * Asserts that all framework components are compatible with the expected family and target.\n *\n * This function validates that each component in the framework components array:\n * - Has kind 'target', 'adapter', 'extension', or 'driver'\n * - Has familyId matching expectedFamilyId\n * - Has targetId matching expectedTargetId\n *\n * This validation happens at the CLI composition boundary, before passing components\n * to typed planner/runner instances. It fills the gap between runtime validation\n * (via `validateConfig()`) and compile-time type enforcement.\n *\n * @param expectedFamilyId - The expected family ID (e.g., 'sql')\n * @param expectedTargetId - The expected target ID (e.g., 'postgres')\n * @param frameworkComponents - Array of framework components to validate\n * @returns The same array typed as TargetBoundComponentDescriptor\n * @throws CliStructuredError if any component is incompatible\n *\n * @example\n * ```ts\n * const config = await loadConfig();\n * const frameworkComponents = [config.target, config.adapter, ...(config.extensionPacks ?? [])];\n *\n * // Validate and type-narrow components before passing to planner\n * const typedComponents = assertFrameworkComponentsCompatible(\n * config.family.familyId,\n * config.target.targetId,\n * frameworkComponents\n * );\n *\n * const planner = target.migrations.createPlanner(familyInstance);\n * planner.plan({ contract, schema, policy, frameworkComponents: typedComponents });\n * ```\n */\nexport function assertFrameworkComponentsCompatible<\n TFamilyId extends string,\n TTargetId extends string,\n>(\n expectedFamilyId: TFamilyId,\n expectedTargetId: TTargetId,\n frameworkComponents: ReadonlyArray<unknown>,\n): ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>> {\n for (let i = 0; i < frameworkComponents.length; i++) {\n const component = frameworkComponents[i];\n\n // Check that component is an object\n if (typeof component !== 'object' || component === null) {\n throw errorConfigValidation('frameworkComponents[]', {\n why: `Framework component at index ${i} must be an object`,\n });\n }\n\n const record = component as Record<string, unknown>;\n\n // Check kind\n if (!Object.hasOwn(record, 'kind')) {\n throw errorConfigValidation('frameworkComponents[].kind', {\n why: `Framework component at index ${i} must have 'kind' property`,\n });\n }\n\n const kind = record['kind'];\n if (kind !== 'target' && kind !== 'adapter' && kind !== 'extension' && kind !== 'driver') {\n throw errorConfigValidation('frameworkComponents[].kind', {\n why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')`,\n });\n }\n\n // Check familyId\n if (!Object.hasOwn(record, 'familyId')) {\n throw errorConfigValidation('frameworkComponents[].familyId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property`,\n });\n }\n\n const familyId = record['familyId'];\n if (familyId !== expectedFamilyId) {\n throw errorConfigValidation('frameworkComponents[].familyId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'`,\n });\n }\n\n // Check targetId\n if (!Object.hasOwn(record, 'targetId')) {\n throw errorConfigValidation('frameworkComponents[].targetId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property`,\n });\n }\n\n const targetId = record['targetId'];\n if (targetId !== expectedTargetId) {\n throw errorConfigValidation('frameworkComponents[].targetId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'`,\n });\n }\n }\n\n // Type assertion is safe because we've validated all components above\n return frameworkComponents as ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n}\n\n/**\n * Validates that a contract is compatible with the configured target, adapter,\n * and extension packs. Throws on family/target mismatches or missing extension packs.\n *\n * This check ensures the emitted contract matches the CLI config before running\n * commands that depend on the contract (e.g., db verify, db sign).\n *\n * @param contract - The contract to validate (must include targetFamily, target, extensionPacks).\n * @param stack - The control plane stack (target, adapter, driver, extensionPacks).\n *\n * @throws {CliStructuredError} errorConfigValidation when contract.targetFamily or contract.target\n * doesn't match the configured family/target.\n * @throws {CliStructuredError} errorContractMissingExtensionPacks when the contract requires\n * extension packs that are not provided in the config (includes all missing packs in error.meta).\n *\n * @example\n * ```ts\n * import { assertContractRequirementsSatisfied } from './framework-components';\n *\n * const config = await loadConfig();\n * const contract = await loadContractJson(config.contract.output);\n * const stack = createControlStack({ family: config.family, target: config.target, adapter: config.adapter, ... });\n *\n * // Throws if contract is incompatible with config\n * assertContractRequirementsSatisfied({ contract, stack });\n * ```\n */\nexport function assertContractRequirementsSatisfied<\n TFamilyId extends string,\n TTargetId extends string,\n>({\n contract,\n stack,\n}: {\n readonly contract: Pick<Contract, 'targetFamily' | 'target' | 'extensionPacks'>;\n readonly stack: ControlStack<TFamilyId, TTargetId>;\n}): void {\n const providedComponentIds = new Set<string>([\n stack.target.id,\n ...(stack.adapter ? [stack.adapter.id] : []),\n ]);\n for (const extension of stack.extensionPacks) {\n providedComponentIds.add(extension.id);\n }\n\n const result = checkContractComponentRequirements({\n contract,\n expectedTargetFamily: stack.target.familyId,\n expectedTargetId: stack.target.targetId,\n providedComponentIds,\n });\n\n if (result.familyMismatch) {\n throw errorConfigValidation('contract.targetFamily', {\n why: `Contract was emitted for family '${result.familyMismatch.actual}' but CLI config is wired to '${result.familyMismatch.expected}'.`,\n });\n }\n\n if (result.targetMismatch) {\n throw errorConfigValidation('contract.target', {\n why: `Contract target '${result.targetMismatch.actual}' does not match CLI target '${result.targetMismatch.expected}'.`,\n });\n }\n\n if (result.missingExtensionPackIds.length > 0) {\n throw errorContractMissingExtensionPacks({\n missingExtensionPacks: result.missingExtensionPackIds,\n providedComponentIds: [...providedComponentIds],\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,oCAId,kBACA,kBACA,qBACqE;AACrE,MAAK,IAAI,IAAI,GAAG,IAAI,oBAAoB,QAAQ,KAAK;EACnD,MAAM,YAAY,oBAAoB;AAGtC,MAAI,OAAO,cAAc,YAAY,cAAc,KACjD,OAAM,sBAAsB,yBAAyB,EACnD,KAAK,gCAAgC,EAAE,qBACxC,CAAC;EAGJ,MAAM,SAAS;AAGf,MAAI,CAAC,OAAO,OAAO,QAAQ,OAAO,CAChC,OAAM,sBAAsB,8BAA8B,EACxD,KAAK,gCAAgC,EAAE,6BACxC,CAAC;EAGJ,MAAM,OAAO,OAAO;AACpB,MAAI,SAAS,YAAY,SAAS,aAAa,SAAS,eAAe,SAAS,SAC9E,OAAM,sBAAsB,8BAA8B,EACxD,KAAK,gCAAgC,EAAE,qBAAqB,OAAO,KAAK,CAAC,4DAC1E,CAAC;AAIJ,MAAI,CAAC,OAAO,OAAO,QAAQ,WAAW,CACpC,OAAM,sBAAsB,kCAAkC,EAC5D,KAAK,gCAAgC,EAAE,UAAU,OAAO,KAAK,CAAC,kCAC/D,CAAC;EAGJ,MAAM,WAAW,OAAO;AACxB,MAAI,aAAa,iBACf,OAAM,sBAAsB,kCAAkC,EAC5D,KAAK,gCAAgC,EAAE,UAAU,OAAO,KAAK,CAAC,kBAAkB,OAAO,SAAS,CAAC,kBAAkB,iBAAiB,IACrI,CAAC;AAIJ,MAAI,CAAC,OAAO,OAAO,QAAQ,WAAW,CACpC,OAAM,sBAAsB,kCAAkC,EAC5D,KAAK,gCAAgC,EAAE,UAAU,OAAO,KAAK,CAAC,kCAC/D,CAAC;EAGJ,MAAM,WAAW,OAAO;AACxB,MAAI,aAAa,iBACf,OAAM,sBAAsB,kCAAkC,EAC5D,KAAK,gCAAgC,EAAE,UAAU,OAAO,KAAK,CAAC,kBAAkB,OAAO,SAAS,CAAC,kBAAkB,iBAAiB,IACrI,CAAC;;AAKN,QAAO"}
1
+ {"version":3,"file":"framework-components-Bgcre3Z6.mjs","names":[],"sources":["../src/utils/framework-components.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport {\n checkContractComponentRequirements,\n type TargetBoundComponentDescriptor,\n} from '@prisma-next/framework-components/components';\nimport type { ControlStack } from '@prisma-next/framework-components/control';\nimport { errorConfigValidation, errorContractMissingExtensionPacks } from './cli-errors';\n\n/**\n * Asserts that all framework components are compatible with the expected family and target.\n *\n * This function validates that each component in the framework components array:\n * - Has kind 'target', 'adapter', 'extension', or 'driver'\n * - Has familyId matching expectedFamilyId\n * - Has targetId matching expectedTargetId\n *\n * This validation happens at the CLI composition boundary, before passing components\n * to typed planner/runner instances. It fills the gap between runtime validation\n * (via `validateConfig()`) and compile-time type enforcement.\n *\n * @param expectedFamilyId - The expected family ID (e.g., 'sql')\n * @param expectedTargetId - The expected target ID (e.g., 'postgres')\n * @param frameworkComponents - Array of framework components to validate\n * @returns The same array typed as TargetBoundComponentDescriptor\n * @throws CliStructuredError if any component is incompatible\n *\n * @example\n * ```ts\n * const config = await loadConfig();\n * const frameworkComponents = [config.target, config.adapter, ...(config.extensionPacks ?? [])];\n *\n * // Validate and type-narrow components before passing to planner\n * const typedComponents = assertFrameworkComponentsCompatible(\n * config.family.familyId,\n * config.target.targetId,\n * frameworkComponents\n * );\n *\n * const planner = target.migrations.createPlanner(familyInstance);\n * planner.plan({ contract, schema, policy, frameworkComponents: typedComponents });\n * ```\n */\nexport function assertFrameworkComponentsCompatible<\n TFamilyId extends string,\n TTargetId extends string,\n>(\n expectedFamilyId: TFamilyId,\n expectedTargetId: TTargetId,\n frameworkComponents: ReadonlyArray<unknown>,\n): ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>> {\n for (let i = 0; i < frameworkComponents.length; i++) {\n const component = frameworkComponents[i];\n\n // Check that component is an object\n if (typeof component !== 'object' || component === null) {\n throw errorConfigValidation('frameworkComponents[]', {\n why: `Framework component at index ${i} must be an object`,\n });\n }\n\n const record = component as Record<string, unknown>;\n\n // Check kind\n if (!Object.hasOwn(record, 'kind')) {\n throw errorConfigValidation('frameworkComponents[].kind', {\n why: `Framework component at index ${i} must have 'kind' property`,\n });\n }\n\n const kind = record['kind'];\n if (kind !== 'target' && kind !== 'adapter' && kind !== 'extension' && kind !== 'driver') {\n throw errorConfigValidation('frameworkComponents[].kind', {\n why: `Framework component at index ${i} has invalid kind '${String(kind)}' (must be 'target', 'adapter', 'extension', or 'driver')`,\n });\n }\n\n // Check familyId\n if (!Object.hasOwn(record, 'familyId')) {\n throw errorConfigValidation('frameworkComponents[].familyId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'familyId' property`,\n });\n }\n\n const familyId = record['familyId'];\n if (familyId !== expectedFamilyId) {\n throw errorConfigValidation('frameworkComponents[].familyId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) has familyId '${String(familyId)}' but expected '${expectedFamilyId}'`,\n });\n }\n\n // Check targetId\n if (!Object.hasOwn(record, 'targetId')) {\n throw errorConfigValidation('frameworkComponents[].targetId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) must have 'targetId' property`,\n });\n }\n\n const targetId = record['targetId'];\n if (targetId !== expectedTargetId) {\n throw errorConfigValidation('frameworkComponents[].targetId', {\n why: `Framework component at index ${i} (kind: ${String(kind)}) has targetId '${String(targetId)}' but expected '${expectedTargetId}'`,\n });\n }\n }\n\n // Type assertion is safe because we've validated all components above\n return frameworkComponents as ReadonlyArray<TargetBoundComponentDescriptor<TFamilyId, TTargetId>>;\n}\n\n/**\n * Validates that a contract is compatible with the configured target, adapter,\n * and extension packs. Throws on family/target mismatches or missing extension packs.\n *\n * This check ensures the emitted contract matches the CLI config before running\n * commands that depend on the contract (e.g., db verify, db sign).\n *\n * @param contract - The contract to validate (must include targetFamily, target, extensionPacks).\n * @param stack - The control plane stack (target, adapter, driver, extensionPacks).\n *\n * @throws {CliStructuredError} errorConfigValidation when contract.targetFamily or contract.target\n * doesn't match the configured family/target.\n * @throws {CliStructuredError} errorContractMissingExtensionPacks when the contract requires\n * extension packs that are not provided in the config (includes all missing packs in error.meta).\n *\n * @example\n * ```ts\n * import { assertContractRequirementsSatisfied } from './framework-components';\n *\n * const config = await loadConfig();\n * const contract = await loadContractJson(config.contract.output);\n * const stack = createControlStack({ family: config.family, target: config.target, adapter: config.adapter, ... });\n *\n * // Throws if contract is incompatible with config\n * assertContractRequirementsSatisfied({ contract, stack });\n * ```\n */\nexport function assertContractRequirementsSatisfied<\n TFamilyId extends string,\n TTargetId extends string,\n>({\n contract,\n stack,\n}: {\n readonly contract: Pick<Contract, 'targetFamily' | 'target' | 'extensionPacks'>;\n readonly stack: ControlStack<TFamilyId, TTargetId>;\n}): void {\n const providedComponentIds = new Set<string>([\n stack.target.id,\n ...(stack.adapter ? [stack.adapter.id] : []),\n ]);\n for (const extension of stack.extensionPacks) {\n providedComponentIds.add(extension.id);\n }\n\n const result = checkContractComponentRequirements({\n contract,\n expectedTargetFamily: stack.target.familyId,\n expectedTargetId: stack.target.targetId,\n providedComponentIds,\n });\n\n if (result.familyMismatch) {\n throw errorConfigValidation('contract.targetFamily', {\n why: `Contract was emitted for family '${result.familyMismatch.actual}' but CLI config is wired to '${result.familyMismatch.expected}'.`,\n });\n }\n\n if (result.targetMismatch) {\n throw errorConfigValidation('contract.target', {\n why: `Contract target '${result.targetMismatch.actual}' does not match CLI target '${result.targetMismatch.expected}'.`,\n });\n }\n\n if (result.missingExtensionPackIds.length > 0) {\n throw errorContractMissingExtensionPacks({\n missingExtensionPacks: result.missingExtensionPackIds,\n providedComponentIds: [...providedComponentIds],\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAgB,oCAId,kBACA,kBACA,qBACqE;AACrE,MAAK,IAAI,IAAI,GAAG,IAAI,oBAAoB,QAAQ,KAAK;EACnD,MAAM,YAAY,oBAAoB;AAGtC,MAAI,OAAO,cAAc,YAAY,cAAc,KACjD,OAAM,sBAAsB,yBAAyB,EACnD,KAAK,gCAAgC,EAAE,qBACxC,CAAC;EAGJ,MAAM,SAAS;AAGf,MAAI,CAAC,OAAO,OAAO,QAAQ,OAAO,CAChC,OAAM,sBAAsB,8BAA8B,EACxD,KAAK,gCAAgC,EAAE,6BACxC,CAAC;EAGJ,MAAM,OAAO,OAAO;AACpB,MAAI,SAAS,YAAY,SAAS,aAAa,SAAS,eAAe,SAAS,SAC9E,OAAM,sBAAsB,8BAA8B,EACxD,KAAK,gCAAgC,EAAE,qBAAqB,OAAO,KAAK,CAAC,4DAC1E,CAAC;AAIJ,MAAI,CAAC,OAAO,OAAO,QAAQ,WAAW,CACpC,OAAM,sBAAsB,kCAAkC,EAC5D,KAAK,gCAAgC,EAAE,UAAU,OAAO,KAAK,CAAC,kCAC/D,CAAC;EAGJ,MAAM,WAAW,OAAO;AACxB,MAAI,aAAa,iBACf,OAAM,sBAAsB,kCAAkC,EAC5D,KAAK,gCAAgC,EAAE,UAAU,OAAO,KAAK,CAAC,kBAAkB,OAAO,SAAS,CAAC,kBAAkB,iBAAiB,IACrI,CAAC;AAIJ,MAAI,CAAC,OAAO,OAAO,QAAQ,WAAW,CACpC,OAAM,sBAAsB,kCAAkC,EAC5D,KAAK,gCAAgC,EAAE,UAAU,OAAO,KAAK,CAAC,kCAC/D,CAAC;EAGJ,MAAM,WAAW,OAAO;AACxB,MAAI,aAAa,iBACf,OAAM,sBAAsB,kCAAkC,EAC5D,KAAK,gCAAgC,EAAE,UAAU,OAAO,KAAK,CAAC,kBAAkB,OAAO,SAAS,CAAC,kBAAkB,iBAAiB,IACrI,CAAC;;AAKN,QAAO"}