@prisma/composer 0.25.0 → 0.26.0-dev.2

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 (58) hide show
  1. package/dist/{app-config-joXc-BKm-CdcXqNMD.mjs → app-config-CGJHcFb--CIEFCG4V.mjs} +3 -3
  2. package/dist/{app-config-joXc-BKm-CdcXqNMD.mjs.map → app-config-CGJHcFb--CIEFCG4V.mjs.map} +1 -1
  3. package/dist/{app-config-jGcCcxK4-DnzGGbDS.d.mts → app-config-DyCMnkDr-CguUhanl.d.mts} +4 -4
  4. package/dist/{app-config-jGcCcxK4-DnzGGbDS.d.mts.map → app-config-DyCMnkDr-CguUhanl.d.mts.map} +1 -1
  5. package/dist/config-CdxvLFzg.mjs.map +1 -1
  6. package/dist/config-i9yR7YWi.d.mts +1 -0
  7. package/dist/config.d.mts +2 -2
  8. package/dist/config.mjs +1 -1
  9. package/dist/control.d.mts +63 -44
  10. package/dist/control.d.mts.map +1 -1
  11. package/dist/control.mjs +10 -42
  12. package/dist/control.mjs.map +1 -1
  13. package/dist/deploy-i9yR7YWi.d.mts +1 -0
  14. package/dist/deploy.d.mts +2 -2
  15. package/dist/deploy.mjs +1 -1
  16. package/dist/deploy.mjs.map +1 -1
  17. package/dist/deployment-summary-37e6WEuh-BOTJynIi.mjs +168 -0
  18. package/dist/deployment-summary-37e6WEuh-BOTJynIi.mjs.map +1 -0
  19. package/dist/deployment-summary-CU-eVvJM-c3AqO52N.d.mts +26 -0
  20. package/dist/deployment-summary-CU-eVvJM-c3AqO52N.d.mts.map +1 -0
  21. package/dist/dev-Bmq-eLnv-DsenQNJM.mjs +154 -0
  22. package/dist/dev-Bmq-eLnv-DsenQNJM.mjs.map +1 -0
  23. package/dist/{execute-deploy-destroy-CvKCwVkD-Di3Ooeip.mjs → execute-deploy-destroy-c0eko3AO-BoK0-r1U.mjs} +43 -32
  24. package/dist/execute-deploy-destroy-c0eko3AO-BoK0-r1U.mjs.map +1 -0
  25. package/dist/{execute-dev-BLCK5wF7-CJvkj5wl.mjs → execute-dev-BICPaq1g-DQccw8kr.mjs} +180 -131
  26. package/dist/{execute-dev-BLCK5wF7-CJvkj5wl.mjs.map → execute-dev-BICPaq1g-DQccw8kr.mjs.map} +1 -1
  27. package/dist/{execute-log-B_zCJ17b-CE954g1a.mjs → execute-log-DivzSDBL-CBdSN2Vv.mjs} +7 -10
  28. package/dist/execute-log-DivzSDBL-CBdSN2Vv.mjs.map +1 -0
  29. package/dist/{local-target-DnA2E8IN.mjs → local-target-B4xoiDAV.mjs} +2 -2
  30. package/dist/{local-target-DnA2E8IN.mjs.map → local-target-B4xoiDAV.mjs.map} +1 -1
  31. package/dist/local-target.d.mts +1 -1
  32. package/dist/local-target.mjs +2 -2
  33. package/dist/nextjs-control.d.mts +4 -4
  34. package/dist/nextjs-control.mjs +2 -2
  35. package/dist/nextjs-control.mjs.map +1 -1
  36. package/dist/node-control.d.mts +4 -4
  37. package/dist/node-control.mjs +2 -2
  38. package/dist/node-control.mjs.map +1 -1
  39. package/dist/{pipeline-C7gNjMzJ-CzM8DNS_.mjs → pipeline-DYvl561J-DDtnkFPh.mjs} +278 -311
  40. package/dist/pipeline-DYvl561J-DDtnkFPh.mjs.map +1 -0
  41. package/dist/report.d.mts +4 -3
  42. package/dist/report.d.mts.map +1 -1
  43. package/dist/report.mjs +2 -2
  44. package/dist/report.mjs.map +1 -1
  45. package/dist/{run-alchemy-pANK8XNX-CgCpXLkG.mjs → run-alchemy-BEvB2sYQ-Cy2fhbcu.mjs} +2 -2
  46. package/dist/{run-alchemy-pANK8XNX-CgCpXLkG.mjs.map → run-alchemy-BEvB2sYQ-Cy2fhbcu.mjs.map} +1 -1
  47. package/package.json +11 -12
  48. package/skills/prisma-composer-core-concepts/SKILL.md +116 -45
  49. package/src/exports/testing.ts +1 -1
  50. package/dist/config-BGtKERz-.d.mts +0 -1
  51. package/dist/deploy-BGtKERz-.d.mts +0 -1
  52. package/dist/deployment-summary-DswOl_9E-B9MhYYDt.mjs +0 -70
  53. package/dist/deployment-summary-DswOl_9E-B9MhYYDt.mjs.map +0 -1
  54. package/dist/execute-deploy-destroy-CvKCwVkD-Di3Ooeip.mjs.map +0 -1
  55. package/dist/execute-log-B_zCJ17b-CE954g1a.mjs.map +0 -1
  56. package/dist/pipeline-C7gNjMzJ-CzM8DNS_.mjs.map +0 -1
  57. package/dist/result-CQIOBgdW.mjs +0 -247
  58. package/dist/result-CQIOBgdW.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-DYvl561J-DDtnkFPh.mjs","names":["fs","path","path","fs"],"sources":["../../../0-framework/3-tooling/cli/dist/composer-config-CY9fET8H.mjs","../../../0-framework/3-tooling/assemble/dist/index.mjs","../../../0-framework/3-tooling/cli/dist/pipeline-DYvl561J.mjs"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n//#region src/composer-config.ts\n/**\n* What makes a `composer` section valid, shared by the CLI's section validator and the programmatic operations.\n* It imports nothing from the CLI engine, because `@prisma/composer` must not depend on it.\n*/\nconst SECTION_FIX = \"Write `composer: composer({ extensions: [...], state: ... })` in prisma.config.ts, with `import { defineConfig as composer } from '@prisma/composer/config'`.\";\nconst MOVE_TO_SECTION_FIX = `${SECTION_FIX} If the project has a prisma-composer.config.ts, move its extensions and state into that section and delete the file.`;\nconst SECTION_IS_THE_ONLY_SOURCE = \"Composer reads its configuration only from the `composer` section of prisma.config.ts.\";\nconst DESCRIPTOR_FIX = \"Use the descriptor the extension factory returns, unchanged, instead of building one by hand.\";\nconst RETIRED_FILE_NAMES = [\n\t\"ts\",\n\t\"mts\",\n\t\"mjs\",\n\t\"js\"\n].map((extension) => `prisma-composer.config.${extension}`);\nconst sectionMissing = {\n\tcode: \"CONFIG.SECTION_MISSING\",\n\tsummary: \"No loaded prisma.config.ts declares a `composer` section.\",\n\twhy: `${SECTION_IS_THE_ONLY_SOURCE} A prisma-composer.config.ts file is no longer read.`,\n\tfix: MOVE_TO_SECTION_FIX\n};\n/** What the generated stack file throws when the file it imports has no `composer` export. */\nfunction noComposerExportMessage(configFile) {\n\treturn `${configFile} declares no \\`composer\\` section. Pass the prisma.config.ts that declares it.`;\n}\nfunction configFileMissing(file) {\n\treturn {\n\t\tcode: \"CONFIG.FILE_MISSING\",\n\t\tsummary: `${file} does not exist.`,\n\t\tfix: \"Pass the path of the prisma.config.ts that declares the `composer` section.\",\n\t\twhere: file\n\t};\n}\n/** A prisma-composer.config.* beside the declaring file would otherwise be silently ignored. */\n/** The path with symlinks resolved; the path itself when it cannot be resolved, so the check never throws. */\nfunction realPath(file) {\n\ttry {\n\t\treturn fs.realpathSync(file);\n\t} catch {\n\t\treturn file;\n\t}\n}\nfunction retiredFileFinding(configFile) {\n\tconst directory = path.dirname(realPath(configFile));\n\tconst found = RETIRED_FILE_NAMES.map((name) => path.join(directory, name)).find((file) => fs.existsSync(file));\n\tif (found === void 0) return void 0;\n\treturn {\n\t\tcode: \"CONFIG.FILE_RETIRED\",\n\t\tsummary: `${found} is no longer read.`,\n\t\twhy: SECTION_IS_THE_ONLY_SOURCE,\n\t\tfix: MOVE_TO_SECTION_FIX,\n\t\twhere: found\n\t};\n}\nfunction isObject(value) {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\nfunction isExtensionDescriptor(value) {\n\treturn isObject(value) && typeof value[\"id\"] === \"string\" && value[\"id\"].length > 0 && isObject(value[\"nodes\"]);\n}\nfunction isStateDescriptor(value) {\n\treturn isObject(value) && typeof value[\"extension\"] === \"string\" && typeof value[\"create\"] === \"function\";\n}\nconst stateInvalid = {\n\tcode: \"CONFIG.FIELD_INVALID\",\n\tsummary: \"`composer.state` must be a state descriptor with a string `extension` and a `create` function.\",\n\tfix: \"Set `state` to the state descriptor an extension provides, e.g. `state: prismaState()`.\",\n\tfield: \"state\"\n};\nfunction unknownField(key) {\n\treturn {\n\t\tcode: \"CONFIG.FIELD_UNKNOWN\",\n\t\tsummary: `The \\`composer\\` section has no field \\`${key}\\`.`,\n\t\tfix: key === \"composer\" ? \"Pass the `composer` property of the prisma.config.ts export, not the whole export. The section takes only `extensions` and `state`.\" : `Remove \\`${key}\\`. The section takes only \\`extensions\\` and \\`state\\`.`,\n\t\tfield: key\n\t};\n}\nfunction checkExtensions(value) {\n\tif (!Array.isArray(value)) return {\n\t\textensions: [],\n\t\tfindings: [{\n\t\t\tcode: \"CONFIG.FIELD_INVALID\",\n\t\t\tsummary: \"`composer.extensions` must be an array of extension descriptors.\",\n\t\t\tfix: \"Set `extensions` to the descriptors your extensions provide, e.g. `extensions: [nodeBuild()]`.\",\n\t\t\tfield: \"extensions\"\n\t\t}]\n\t};\n\tconst findings = [];\n\tconst extensions = [];\n\tconst seen = /* @__PURE__ */ new Set();\n\tfor (const [index, entry] of value.entries()) {\n\t\tconst field = `extensions[${index}]`;\n\t\tif (!isObject(entry)) {\n\t\t\tfindings.push({\n\t\t\t\tcode: \"CONFIG.FIELD_INVALID\",\n\t\t\t\tsummary: `\\`composer.${field}\\` must be an extension descriptor object.`,\n\t\t\t\tfix: \"Put the descriptor an extension factory returns here, e.g. `nodeBuild()`, not the factory itself.\",\n\t\t\t\tfield\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst id = entry[\"id\"];\n\t\tif (typeof id !== \"string\" || id.length === 0) findings.push({\n\t\t\tcode: \"CONFIG.FIELD_INVALID\",\n\t\t\tsummary: `\\`composer.${field}.id\\` must be a non-empty string (the extension package name).`,\n\t\t\tfix: DESCRIPTOR_FIX,\n\t\t\tfield: `${field}.id`\n\t\t});\n\t\telse if (seen.has(id)) findings.push({\n\t\t\tcode: \"CONFIG.EXTENSION_DUPLICATE\",\n\t\t\tsummary: `Extension \"${id}\" is listed more than once in \\`composer.extensions\\`.`,\n\t\t\tfix: `Remove the repeated \"${id}\" entry from \\`extensions\\`.`,\n\t\t\tfield: `${field}.id`\n\t\t});\n\t\telse seen.add(id);\n\t\tif (!isObject(entry[\"nodes\"])) findings.push({\n\t\t\tcode: \"CONFIG.FIELD_INVALID\",\n\t\t\tsummary: `\\`composer.${field}.nodes\\` must be an object (the node-ID → control registry).`,\n\t\t\tfix: DESCRIPTOR_FIX,\n\t\t\tfield: `${field}.nodes`\n\t\t});\n\t\tif (isExtensionDescriptor(entry)) extensions.push(entry);\n\t}\n\treturn {\n\t\tfindings,\n\t\textensions\n\t};\n}\nfunction checkFields(section) {\n\tif (Object.hasOwn(section, \"configPath\")) return {\n\t\tok: false,\n\t\tfindings: [{\n\t\t\tcode: \"CONFIG.FIELD_RETIRED\",\n\t\t\tsummary: \"`composer.configPath` is no longer supported: prisma-composer.config.ts is no longer read.\",\n\t\t\twhy: SECTION_IS_THE_ONLY_SOURCE,\n\t\t\tfix: `Replace \\`configPath\\` with the section itself. ${MOVE_TO_SECTION_FIX}`,\n\t\t\tfield: \"configPath\"\n\t\t}]\n\t};\n\tif (Object.hasOwn(section, \"composer\")) return {\n\t\tok: false,\n\t\tfindings: [unknownField(\"composer\")]\n\t};\n\tconst findings = Object.keys(section).filter((key) => key !== \"extensions\" && key !== \"state\").map(unknownField);\n\tconst checked = checkExtensions(section[\"extensions\"]);\n\tfindings.push(...checked.findings);\n\tconst state = section[\"state\"];\n\tif (!isStateDescriptor(state)) findings.push(stateInvalid);\n\tconst [first, ...rest] = findings;\n\tif (first === void 0 && isStateDescriptor(state)) return {\n\t\tok: true,\n\t\tvalue: {\n\t\t\textensions: checked.extensions,\n\t\t\tstate\n\t\t}\n\t};\n\treturn {\n\t\tok: false,\n\t\tfindings: [first ?? stateInvalid, ...rest]\n\t};\n}\n/**\n* Checks the fields that identify each descriptor and returns the descriptors as the config file's own objects.\n* Never throws: a section's values are user code, and a throwing getter or Proxy trap becomes a finding.\n*/\nfunction checkComposerSection(raw) {\n\tif (!isObject(raw)) return {\n\t\tok: false,\n\t\tfindings: [{\n\t\t\tcode: \"CONFIG.FIELD_INVALID\",\n\t\t\tsummary: \"The `composer` section of prisma.config.ts must be an object.\",\n\t\t\tfix: SECTION_FIX\n\t\t}]\n\t};\n\ttry {\n\t\treturn checkFields({ ...raw });\n\t} catch (cause) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tfindings: [{\n\t\t\t\tcode: \"CONFIG.FIELD_INVALID\",\n\t\t\t\tsummary: \"The `composer` section of prisma.config.ts could not be read.\",\n\t\t\t\twhy: `Reading it threw: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t\tfix: SECTION_FIX\n\t\t\t}]\n\t\t};\n\t}\n}\n/**\n* The whole check, shared by the section validator and the programmatic operations so both report the same findings in the same order: the retired file beside the declaring `configFile` (resolved through symlinks), then every field finding.\n*/\nfunction checkComposerConfig(raw, configFile) {\n\tconst retired = retiredFileFinding(configFile);\n\tconst checked = checkComposerSection(raw);\n\tif (retired === void 0) return checked;\n\treturn {\n\t\tok: false,\n\t\tfindings: checked.ok ? [retired] : [retired, ...checked.findings]\n\t};\n}\n//#endregion\nexport { sectionMissing as i, configFileMissing as n, noComposerExportMessage as r, checkComposerConfig as t };\n\n//# sourceMappingURL=composer-config-CY9fET8H.mjs.map","import { CliStructuredError } from \"@internal/foundation/errors\";\n//#region src/assemble-error.ts\n/**\n* A user-facing assembly failure, structured at origin (base-type rule 6):\n* a `CliStructuredError` whose code names which way assembly went wrong.\n* This package's second consumer is the programmatic deploy API, not just\n* the CLI — hosts branch on `error.code`, the CLI renders the envelope.\n*/\nvar AssembleError = class extends CliStructuredError {\n\tconstructor(code, summary, options) {\n\t\tsuper(code, summary, options);\n\t}\n};\n//#endregion\n//#region src/assemble-services.ts\n/**\n* The registry route for one service's build: extension by\n* `build.extension`, node descriptor by `build.type`, kind must be \"build\".\n* The CLI's coverage validation reports the same misses earlier with the\n* config fix; these errors are the backstop for programmatic callers.\n*/\nfunction buildDescriptorAssemble(config, node, address, cwd) {\n\tconst { extension, type } = node.build;\n\tconst extensionDescriptor = config.extensions.find((candidate) => candidate.id === extension);\n\tif (extensionDescriptor === void 0) throw new AssembleError(\"ASSEMBLE.EXTENSION_MISSING\", `No extension \"${extension}\" is configured (needed by service \"${node.name}\"'s build).`, { fix: \"Add it to `extensions` in the `composer` section of prisma.config.ts.\" });\n\tconst nodeDescriptor = extensionDescriptor.nodes[type];\n\tif (nodeDescriptor === void 0) throw new AssembleError(\"ASSEMBLE.DESCRIPTOR_MISSING\", `Extension \"${extension}\" has no descriptor for build type \"${type}\".`, { why: `Known types: ${Object.keys(extensionDescriptor.nodes).join(\", \")}.` });\n\tif (nodeDescriptor.kind !== \"build\") throw new AssembleError(\"ASSEMBLE.DESCRIPTOR_KIND_MISMATCH\", `Extension \"${extension}\"'s descriptor for type \"${type}\" is a \"${nodeDescriptor.kind}\" descriptor.`, { why: \"Assembling a service build needs a \\\"build\\\" descriptor.\" });\n\treturn nodeDescriptor.assemble({\n\t\tbuild: node.build,\n\t\taddress,\n\t\tcwd\n\t});\n}\nasync function assembleServices(graph, config, cwd, run) {\n\tconst runAssembler = run ?? ((node, address, nodeCwd) => buildDescriptorAssemble(config, node, address, nodeCwd));\n\tconst serviceNodes = graph.nodes.filter((n) => n.node.kind === \"service\");\n\tif (serviceNodes.length === 0) throw new AssembleError(\"ASSEMBLE.SERVICE_MISSING\", \"The loaded graph has no service to assemble.\");\n\tconst bundles = {};\n\tfor (const { id, node } of serviceNodes) try {\n\t\tbundles[id] = await runAssembler(node, id, cwd);\n\t} catch (error) {\n\t\tif (CliStructuredError.is(error)) throw error;\n\t\tthrow new AssembleError(\"ASSEMBLE.BUILD_FAILED\", error instanceof Error ? error.message : String(error), {\n\t\t\tmeta: { address: id },\n\t\t\tcause: error\n\t\t});\n\t}\n\treturn { bundles };\n}\n//#endregion\nexport { AssembleError, assembleServices };\n\n//# sourceMappingURL=index.mjs.map","import { n as configFileMissing, t as checkComposerConfig } from \"./composer-config-CY9fET8H.mjs\";\nimport * as mod from \"node:module\";\nimport * as fs from \"node:fs\";\nimport { existsSync } from \"node:fs\";\nimport { blindCast } from \"@internal/foundation/casts\";\nimport { CliStructuredError } from \"@internal/foundation/errors\";\nimport * as path from \"node:path\";\nimport { assembleServices } from \"@internal/assemble\";\nimport { Load, isNode } from \"@internal/core\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\n//#region src/entry-resolution.ts\n/**\n* Synchronous Node resolve hook so that entry modules may import relative\n* files using the specifier forms TypeScript accepts by default —\n* extensionless `./service` and `./service.js` for a `.ts` source file —\n* without requiring `allowImportingTsExtensions` in every consumer's tsconfig.\n*\n* Resolution only; uses TypeScript's own documented mapping: for a specifier\n* Node could not resolve, strip any JS-family extension and probe the\n* corresponding TypeScript source; first candidate that exists on disk wins.\n* Format-specific rules: `.mjs` → `.mts`; `.cjs` → `.cts`; `.js` and\n* extensionless → `.ts`, `.mts`, `.tsx`, then `./index.ts`. Bare and package\n* specifiers are never touched. Existing `./x.ts` imports keep working —\n* Node resolves them before the hook fires (ADR-0005: no transform, no\n* guessing, deterministic TypeScript rule).\n*\n* Bun resolves `./x.js` and `./x` to `x.ts` natively, so the hook is a\n* no-op under Bun. Nothing is registered there.\n*/\nlet registered = false;\n/**\n* Registers the resolve hook once (idempotent). Call at the start of\n* `loadEntry` so every module in the entry graph benefits, including those\n* imported lazily after the entry itself loads.\n*/\nfunction registerEntryResolution() {\n\tif (registered || typeof process.versions.bun === \"string\") return;\n\tif (typeof mod.registerHooks !== \"function\") return;\n\tregistered = true;\n\tmod.registerHooks({ resolve(specifier, context, nextResolve) {\n\t\ttry {\n\t\t\treturn nextResolve(specifier, context);\n\t\t} catch (error) {\n\t\t\tif (!isRelativeSpecifier(specifier) || context.parentURL === void 0 || !isModuleNotFoundError(error)) throw error;\n\t\t\tfor (const candidate of sourceCandidates(new URL(specifier, context.parentURL))) if (existsSync(fileURLToPath(candidate))) return nextResolve(candidate.href, context);\n\t\t\tthrow error;\n\t\t}\n\t} });\n}\n/**\n* TypeScript's extension mapping: for a JS-family or extensionless URL,\n* produce the source candidates to probe. Format-specific: `.mjs` maps only\n* to `.mts`; `.cjs` maps only to `.cts`; `.js` and extensionless probe\n* `.ts`, `.mts`, `.tsx` (keeping `.tsx` so the JSX diagnostic fires), then\n* `./index.ts`.\n*/\nfunction sourceCandidates(resolved) {\n\tconst href = resolved.href;\n\tif (href.endsWith(\".mjs\")) {\n\t\tconst base = href.slice(0, -4);\n\t\treturn [new URL(`${base}.mts`)];\n\t}\n\tif (href.endsWith(\".cjs\")) {\n\t\tconst base = href.slice(0, -4);\n\t\treturn [new URL(`${base}.cts`)];\n\t}\n\tconst base = href.endsWith(\".js\") ? href.slice(0, -3) : href;\n\treturn [\n\t\tnew URL(`${base}.ts`),\n\t\tnew URL(`${base}.mts`),\n\t\tnew URL(`${base}.tsx`),\n\t\tnew URL(`${base}/index.ts`)\n\t];\n}\nfunction isRelativeSpecifier(specifier) {\n\treturn specifier.startsWith(\"./\") || specifier.startsWith(\"../\");\n}\nfunction isModuleNotFoundError(error) {\n\tif (!(error instanceof Error)) return false;\n\tif (!(\"code\" in error)) return false;\n\treturn error.code === \"ERR_MODULE_NOT_FOUND\";\n}\n//#endregion\n//#region src/jsx-load-error.ts\n/**\n* `loadEntry` imports a user's topology with the host runtime's own module\n* loader — under node (the CLI's shebang runtime), that loader strips\n* TypeScript types but has no JSX transform (ADR-0005: the framework\n* doesn't bundle or transform the app's code; deploy loading is no\n* exception). A `.tsx`/`.jsx` file anywhere in the topology's import graph\n* dies with node's raw `ERR_UNKNOWN_FILE_EXTENSION`, which names the file\n* but not the cause or the fix. This turns that one case into structured\n* error parts (summary/why/fix) that do — every other load failure (syntax\n* errors, missing files, non-JSX unknown extensions) is untouched.\n*/\nconst UNKNOWN_EXTENSION_CODE = \"ERR_UNKNOWN_FILE_EXTENSION\";\nconst JSX_EXTENSIONS = [\".tsx\", \".jsx\"];\nfunction errorCode(error) {\n\treturn \"code\" in error && typeof error.code === \"string\" ? error.code : void 0;\n}\nfunction unknownExtensionPath(error) {\n\tif (!(error instanceof Error)) return void 0;\n\tif (errorCode(error) !== UNKNOWN_EXTENSION_CODE) return void 0;\n\treturn /Unknown file extension \"\\.\\w+\" for (.+)$/.exec(error.message)?.[1];\n}\n/**\n* Returns structured error parts when `error` is node's\n* `ERR_UNKNOWN_FILE_EXTENSION` for a `.tsx`/`.jsx` file — `undefined` for\n* every other error (including unknown-extension failures for some other\n* extension), so the caller can fall through to its normal rethrow.\n*/\nfunction explainJsxLoadError(error, entryPath) {\n\tconst offendingPath = unknownExtensionPath(error);\n\tif (offendingPath === void 0) return void 0;\n\tif (!JSX_EXTENSIONS.some((ext) => offendingPath.endsWith(ext))) return void 0;\n\treturn {\n\t\tsummary: `\"${offendingPath}\" can't be loaded.`,\n\t\twhy: `deploy loads \"${entryPath}\"'s topology with node's own module loader, which strips TypeScript types but has no JSX transform — so a .tsx/.jsx file can't sit anywhere in that import graph.`,\n\t\tfix: \"Precompile that file in your own build (transform the JSX away, keep the real npm packages external) and import the compiled output instead of the raw .tsx/.jsx — see examples/email/scripts/build.ts in the prisma/composer repo for a worked example.\"\n\t};\n}\n//#endregion\n//#region src/load-entry.ts\n/**\n* Pipeline step 1 (deploy-cli.md § The pipeline): import the entry module\n* (resolved against cwd) and require its default export to be a node — a\n* service or module, branded by core's factories. Whatever this module exports\n* IS the application; nothing else marks a root (ADR-0003).\n*/\nasync function loadEntry(entryArg, cwd) {\n\tregisterEntryResolution();\n\tconst resolvedPath = path.resolve(cwd, entryArg);\n\tlet mod;\n\ttry {\n\t\tmod = await import(pathToFileURL(resolvedPath).href);\n\t} catch (error) {\n\t\tconst explained = explainJsxLoadError(error, resolvedPath);\n\t\tif (explained !== void 0) throw new CliStructuredError(\"COMPOSE.ENTRY_UNLOADABLE\", explained.summary, {\n\t\t\twhy: explained.why,\n\t\t\tfix: explained.fix,\n\t\t\twhere: { path: resolvedPath },\n\t\t\tcause: error\n\t\t});\n\t\tthrow new CliStructuredError(\"COMPOSE.ENTRY_UNLOADABLE\", `Failed to import entry module \"${resolvedPath}\": ${error instanceof Error ? error.message : String(error)}`, {\n\t\t\twhere: { path: resolvedPath },\n\t\t\tcause: error\n\t\t});\n\t}\n\tconst root = blindCast(mod).default;\n\tif (!isNode(root) || root.kind === \"dependency\" || root.kind === \"resource\") throw new CliStructuredError(\"COMPOSE.ENTRY_EXPORT_INVALID\", `Entry module \"${resolvedPath}\" must default-export a node (a service or a module).`, {\n\t\tfix: \"Construct it with service() or module() from @prisma/composer.\",\n\t\twhere: { path: resolvedPath }\n\t});\n\treturn {\n\t\tpath: resolvedPath,\n\t\troot: blindCast(root)\n\t};\n}\n//#endregion\n//#region src/validate-coverage.ts\nfunction lookup(extensions, extension, type, expectedKind, what) {\n\tconst ext = extensions.get(extension);\n\tif (ext === void 0) throw new CliStructuredError(\"CONFIG.EXTENSION_MISSING\", `No extension \"${extension}\" is configured (needed by ${what}).`, {\n\t\tfix: \"Add it to `extensions` in the `composer` section of prisma.config.ts (import its /control entry and list its descriptor).\",\n\t\tmeta: {\n\t\t\textension,\n\t\t\ttype\n\t\t}\n\t});\n\tconst descriptor = ext.nodes[type];\n\tif (descriptor === void 0) throw new CliStructuredError(\"CONFIG.DESCRIPTOR_MISSING\", `Extension \"${extension}\" has no descriptor for node type \"${type}\" (needed by ${what}).`, {\n\t\twhy: `Known types: ${Object.keys(ext.nodes).join(\", \")}.`,\n\t\tmeta: {\n\t\t\textension,\n\t\t\ttype\n\t\t}\n\t});\n\tif (descriptor.kind !== expectedKind) throw new CliStructuredError(\"CONFIG.DESCRIPTOR_KIND_MISMATCH\", `Extension \"${extension}\"'s descriptor for node type \"${type}\" is a \"${descriptor.kind}\" descriptor — ${what} needs a \"${expectedKind}\" descriptor.`, { meta: {\n\t\textension,\n\t\ttype,\n\t\tkind: descriptor.kind\n\t} });\n}\n/** Throws a structured CONFIG.* error on the first uncovered `(extension, type)`; silent when the config covers the whole graph. */\nfunction validateRegistryCoverage(graph, config) {\n\tconst extensions = new Map(config.extensions.map((descriptor) => [descriptor.id, descriptor]));\n\tfor (const { id, node } of graph.nodes) {\n\t\tif (node.kind === \"resource\") {\n\t\t\tlookup(extensions, node.extension, node.type, \"resource\", `resource node \"${id}\"`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (node.kind !== \"service\") continue;\n\t\tlookup(extensions, node.extension, node.type, \"service\", `service node \"${id}\"`);\n\t\tlookup(extensions, node.build.extension, node.build.type, \"build\", `service node \"${id}\"'s build descriptor`);\n\t}\n}\n//#endregion\n//#region src/pipeline.ts\n/**\n* The shared prefix of `deploy`/`destroy`/`dev` (deploy-cli.md § The\n* pipeline; local-dev spec § 6): entry load, Load,\n* registry coverage validation, name resolution, assemble. Deploy and dev\n* diverge after this — deploy resolves containers/preflight/stack file\n* against the hosted providers, dev against the local ones — so everything\n* up to and including assemble lives here once, consumed verbatim by both\n* `run()` (main.ts) and `runDev()` (dev/run-dev.ts), so the two pipelines\n* cannot drift.\n*/\nfunction configError(findings, file) {\n\tconst [first] = findings;\n\treturn new CliStructuredError(first.code, first.summary, {\n\t\t...first.why === void 0 ? {} : { why: first.why },\n\t\tfix: first.fix,\n\t\twhere: { path: first.where ?? file },\n\t\tmeta: {\n\t\t\t...first.field === void 0 ? {} : { field: first.field },\n\t\t\tfindings\n\t\t}\n\t});\n}\n/**\n* Refuses a caller's config with the same findings, in the same order, as the CLI's section validator.\n* The error is the first finding and carries all of them in `meta.findings`. Returns the config with `file` resolved against `cwd`.\n*/\nfunction checkConfigSource(source, cwd) {\n\tconst file = path.resolve(cwd, source.file);\n\tif (!fs.existsSync(file)) throw configError([configFileMissing(file)], file);\n\tconst checked = checkComposerConfig(source.value, file);\n\tif (!checked.ok) throw configError(checked.findings, file);\n\treturn {\n\t\tvalue: checked.value,\n\t\tfile\n\t};\n}\n/**\n* The pipeline's front — entry load and name resolution —\n* WITHOUT Load, coverage, or assemble. `log` needs only who the app is (its\n* config and resolved name) to reach the already-running local instance; it\n* neither builds nor provisions, so it must not require the user's built\n* output the way the full pipeline does.\n*/\nasync function resolveAppIdentity(entry, overrideName, cwd, config) {\n\tconst { value } = checkConfigSource(config, cwd);\n\tconst entryModule = await loadEntry(entry, cwd);\n\tconst name = overrideName ?? entryModule.root.name;\n\tif (name.length === 0) throw new CliStructuredError(\"COMPOSE.NAME_MISSING\", \"The root node has no name.\", { fix: \"Name it at authoring, or pass --name.\" });\n\treturn {\n\t\tconfig: value,\n\t\tname\n\t};\n}\n/**\n* Runs entry load, Load, registry coverage, name resolution, and assemble — steps 1–5 of `run()`. `onAssembleError`, when\n* given, lets a caller decorate an assemble failure with command-specific\n* guidance (destroy's \"build first\" hint) without this shared step knowing\n* about any one command.\n*/\nasync function runPipeline(entry, overrideName, cwd, source, deps = {}, onAssembleError) {\n\tconst configSource = checkConfigSource(source, cwd);\n\tconst config = configSource.value;\n\tconst entryModule = await loadEntry(entry, cwd);\n\tconst graph = Load(entryModule.root);\n\tif (graph.root.node.kind !== \"module\") throw new CliStructuredError(\"COMPOSE.ROOT_NOT_MODULE\", \"The deploy root must be a module.\", { fix: \"Wrap your service, e.g. export default module('name', ({ provision }) => { provision(service); }).\" });\n\tvalidateRegistryCoverage(graph, config);\n\tconst name = overrideName ?? entryModule.root.name;\n\tif (name.length === 0) throw new CliStructuredError(\"COMPOSE.NAME_MISSING\", \"The root node has no name.\", { fix: \"Name it at authoring, or pass --name.\" });\n\tlet assembled;\n\ttry {\n\t\tassembled = await assembleServices(graph, config, cwd, deps.runAssembler);\n\t} catch (error) {\n\t\tif (onAssembleError !== void 0 && error instanceof Error) throw onAssembleError(error);\n\t\tthrow error;\n\t}\n\treturn {\n\t\tconfigSource,\n\t\tentryModule,\n\t\tgraph,\n\t\tname,\n\t\tassembled\n\t};\n}\n//#endregion\nexport { runPipeline as n, resolveAppIdentity as t };\n\n//# sourceMappingURL=pipeline-DYvl561J.mjs.map"],"mappings":";;;;;;;;;;;;;;AAOA,MAAM,cAAc;AACpB,MAAM,sBAAsB,GAAG,YAAY;AAC3C,MAAM,6BAA6B;AACnC,MAAM,iBAAiB;AACvB,MAAM,qBAAqB;CAC1B;CACA;CACA;CACA;AACD,CAAC,CAAC,KAAK,cAAc,0BAA0B,WAAW;;AAQ1D,SAAS,wBAAwB,YAAY;CAC5C,OAAO,GAAG,WAAW;AACtB;AACA,SAAS,kBAAkB,MAAM;CAChC,OAAO;EACN,MAAM;EACN,SAAS,GAAG,KAAK;EACjB,KAAK;EACL,OAAO;CACR;AACD;;;AAGA,SAAS,SAAS,MAAM;CACvB,IAAI;EACH,OAAOA,KAAG,aAAa,IAAI;CAC5B,QAAQ;EACP,OAAO;CACR;AACD;AACA,SAAS,mBAAmB,YAAY;CACvC,MAAM,YAAYC,OAAK,QAAQ,SAAS,UAAU,CAAC;CACnD,MAAM,QAAQ,mBAAmB,KAAK,SAASA,OAAK,KAAK,WAAW,IAAI,CAAC,CAAC,CAAC,MAAM,SAASD,KAAG,WAAW,IAAI,CAAC;CAC7G,IAAI,UAAU,KAAK,GAAG,OAAO,KAAK;CAClC,OAAO;EACN,MAAM;EACN,SAAS,GAAG,MAAM;EAClB,KAAK;EACL,KAAK;EACL,OAAO;CACR;AACD;AACA,SAAS,SAAS,OAAO;CACxB,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC3E;AACA,SAAS,sBAAsB,OAAO;CACrC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,UAAU,YAAY,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,MAAM,QAAQ;AAC/G;AACA,SAAS,kBAAkB,OAAO;CACjC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,iBAAiB,YAAY,OAAO,MAAM,cAAc;AAChG;AACA,MAAM,eAAe;CACpB,MAAM;CACN,SAAS;CACT,KAAK;CACL,OAAO;AACR;AACA,SAAS,aAAa,KAAK;CAC1B,OAAO;EACN,MAAM;EACN,SAAS,2CAA2C,IAAI;EACxD,KAAK,QAAQ,aAAa,wIAAwI,YAAY,IAAI;EAClL,OAAO;CACR;AACD;AACA,SAAS,gBAAgB,OAAO;CAC/B,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO;EACjC,YAAY,CAAC;EACb,UAAU,CAAC;GACV,MAAM;GACN,SAAS;GACT,KAAK;GACL,OAAO;EACR,CAAC;CACF;CACA,MAAM,WAAW,CAAC;CAClB,MAAM,aAAa,CAAC;CACpB,MAAM,uBAAuB,IAAI,IAAI;CACrC,KAAK,MAAM,CAAC,OAAO,UAAU,MAAM,QAAQ,GAAG;EAC7C,MAAM,QAAQ,cAAc,MAAM;EAClC,IAAI,CAAC,SAAS,KAAK,GAAG;GACrB,SAAS,KAAK;IACb,MAAM;IACN,SAAS,cAAc,MAAM;IAC7B,KAAK;IACL;GACD,CAAC;GACD;EACD;EACA,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO,OAAO,YAAY,GAAG,WAAW,GAAG,SAAS,KAAK;GAC5D,MAAM;GACN,SAAS,cAAc,MAAM;GAC7B,KAAK;GACL,OAAO,GAAG,MAAM;EACjB,CAAC;OACI,IAAI,KAAK,IAAI,EAAE,GAAG,SAAS,KAAK;GACpC,MAAM;GACN,SAAS,cAAc,GAAG;GAC1B,KAAK,wBAAwB,GAAG;GAChC,OAAO,GAAG,MAAM;EACjB,CAAC;OACI,KAAK,IAAI,EAAE;EAChB,IAAI,CAAC,SAAS,MAAM,QAAQ,GAAG,SAAS,KAAK;GAC5C,MAAM;GACN,SAAS,cAAc,MAAM;GAC7B,KAAK;GACL,OAAO,GAAG,MAAM;EACjB,CAAC;EACD,IAAI,sBAAsB,KAAK,GAAG,WAAW,KAAK,KAAK;CACxD;CACA,OAAO;EACN;EACA;CACD;AACD;AACA,SAAS,YAAY,SAAS;CAC7B,IAAI,OAAO,OAAO,SAAS,YAAY,GAAG,OAAO;EAChD,IAAI;EACJ,UAAU,CAAC;GACV,MAAM;GACN,SAAS;GACT,KAAK;GACL,KAAK,mDAAmD;GACxD,OAAO;EACR,CAAC;CACF;CACA,IAAI,OAAO,OAAO,SAAS,UAAU,GAAG,OAAO;EAC9C,IAAI;EACJ,UAAU,CAAC,aAAa,UAAU,CAAC;CACpC;CACA,MAAM,WAAW,OAAO,KAAK,OAAO,CAAC,CAAC,QAAQ,QAAQ,QAAQ,gBAAgB,QAAQ,OAAO,CAAC,CAAC,IAAI,YAAY;CAC/G,MAAM,UAAU,gBAAgB,QAAQ,aAAa;CACrD,SAAS,KAAK,GAAG,QAAQ,QAAQ;CACjC,MAAM,QAAQ,QAAQ;CACtB,IAAI,CAAC,kBAAkB,KAAK,GAAG,SAAS,KAAK,YAAY;CACzD,MAAM,CAAC,OAAO,GAAG,QAAQ;CACzB,IAAI,UAAU,KAAK,KAAK,kBAAkB,KAAK,GAAG,OAAO;EACxD,IAAI;EACJ,OAAO;GACN,YAAY,QAAQ;GACpB;EACD;CACD;CACA,OAAO;EACN,IAAI;EACJ,UAAU,CAAC,SAAS,cAAc,GAAG,IAAI;CAC1C;AACD;;;;;AAKA,SAAS,qBAAqB,KAAK;CAClC,IAAI,CAAC,SAAS,GAAG,GAAG,OAAO;EAC1B,IAAI;EACJ,UAAU,CAAC;GACV,MAAM;GACN,SAAS;GACT,KAAK;EACN,CAAC;CACF;CACA,IAAI;EACH,OAAO,YAAY,EAAE,GAAG,IAAI,CAAC;CAC9B,SAAS,OAAO;EACf,OAAO;GACN,IAAI;GACJ,UAAU,CAAC;IACV,MAAM;IACN,SAAS;IACT,KAAK,qBAAqB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC/E,KAAK;GACN,CAAC;EACF;CACD;AACD;;;;AAIA,SAAS,oBAAoB,KAAK,YAAY;CAC7C,MAAM,UAAU,mBAAmB,UAAU;CAC7C,MAAM,UAAU,qBAAqB,GAAG;CACxC,IAAI,YAAY,KAAK,GAAG,OAAO;CAC/B,OAAO;EACN,IAAI;EACJ,UAAU,QAAQ,KAAK,CAAC,OAAO,IAAI,CAAC,SAAS,GAAG,QAAQ,QAAQ;CACjE;AACD;;;;;;;;;ACjMA,IAAI,gBAAgB,cAAc,mBAAmB;CACpD,YAAY,MAAM,SAAS,SAAS;EACnC,MAAM,MAAM,SAAS,OAAO;CAC7B;AACD;;;;;;;AASA,SAAS,wBAAwB,QAAQ,MAAM,SAAS,KAAK;CAC5D,MAAM,EAAE,WAAW,SAAS,KAAK;CACjC,MAAM,sBAAsB,OAAO,WAAW,MAAM,cAAc,UAAU,OAAO,SAAS;CAC5F,IAAI,wBAAwB,KAAK,GAAG,MAAM,IAAI,cAAc,8BAA8B,iBAAiB,UAAU,sCAAsC,KAAK,KAAK,cAAc,EAAE,KAAK,wEAAwE,CAAC;CACnQ,MAAM,iBAAiB,oBAAoB,MAAM;CACjD,IAAI,mBAAmB,KAAK,GAAG,MAAM,IAAI,cAAc,+BAA+B,cAAc,UAAU,sCAAsC,KAAK,KAAK,EAAE,KAAK,gBAAgB,OAAO,KAAK,oBAAoB,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,GAAG,CAAC;CAC3O,IAAI,eAAe,SAAS,SAAS,MAAM,IAAI,cAAc,qCAAqC,cAAc,UAAU,2BAA2B,KAAK,UAAU,eAAe,KAAK,gBAAgB,EAAE,KAAK,2DAA2D,CAAC;CAC3Q,OAAO,eAAe,SAAS;EAC9B,OAAO,KAAK;EACZ;EACA;CACD,CAAC;AACF;AACA,eAAe,iBAAiB,OAAO,QAAQ,KAAK,KAAK;CACxD,MAAM,eAAe,SAAS,MAAM,SAAS,YAAY,wBAAwB,QAAQ,MAAM,SAAS,OAAO;CAC/G,MAAM,eAAe,MAAM,MAAM,QAAQ,MAAM,EAAE,KAAK,SAAS,SAAS;CACxE,IAAI,aAAa,WAAW,GAAG,MAAM,IAAI,cAAc,4BAA4B,8CAA8C;CACjI,MAAM,UAAU,CAAC;CACjB,KAAK,MAAM,EAAE,IAAI,UAAU,cAAc,IAAI;EAC5C,QAAQ,MAAM,MAAM,aAAa,MAAM,IAAI,GAAG;CAC/C,SAAS,OAAO;EACf,IAAI,mBAAmB,GAAG,KAAK,GAAG,MAAM;EACxC,MAAM,IAAI,cAAc,yBAAyB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;GACxG,MAAM,EAAE,SAAS,GAAG;GACpB,OAAO;EACR,CAAC;CACF;CACA,OAAO,EAAE,QAAQ;AAClB;;;;;;;;;;;;;;;;;;;;;ACpBA,IAAI,aAAa;;;;;;AAMjB,SAAS,0BAA0B;CAClC,IAAI,cAAc,OAAO,QAAQ,SAAS,QAAQ,UAAU;CAC5D,IAAI,OAAO,IAAI,kBAAkB,YAAY;CAC7C,aAAa;CACb,IAAI,cAAc,EAAE,QAAQ,WAAW,SAAS,aAAa;EAC5D,IAAI;GACH,OAAO,YAAY,WAAW,OAAO;EACtC,SAAS,OAAO;GACf,IAAI,CAAC,oBAAoB,SAAS,KAAK,QAAQ,cAAc,KAAK,KAAK,CAAC,sBAAsB,KAAK,GAAG,MAAM;GAC5G,KAAK,MAAM,aAAa,iBAAiB,IAAI,IAAI,WAAW,QAAQ,SAAS,CAAC,GAAG,IAAI,WAAW,cAAc,SAAS,CAAC,GAAG,OAAO,YAAY,UAAU,MAAM,OAAO;GACrK,MAAM;EACP;CACD,EAAE,CAAC;AACJ;;;;;;;;AAQA,SAAS,iBAAiB,UAAU;CACnC,MAAM,OAAO,SAAS;CACtB,IAAI,KAAK,SAAS,MAAM,GAAG;EAC1B,MAAM,OAAO,KAAK,MAAM,GAAG,EAAE;EAC7B,OAAO,CAAC,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC;CAC/B;CACA,IAAI,KAAK,SAAS,MAAM,GAAG;EAC1B,MAAM,OAAO,KAAK,MAAM,GAAG,EAAE;EAC7B,OAAO,CAAC,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC;CAC/B;CACA,MAAM,OAAO,KAAK,SAAS,KAAK,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;CACxD,OAAO;EACN,IAAI,IAAI,GAAG,KAAK,IAAI;EACpB,IAAI,IAAI,GAAG,KAAK,KAAK;EACrB,IAAI,IAAI,GAAG,KAAK,KAAK;EACrB,IAAI,IAAI,GAAG,KAAK,UAAU;CAC3B;AACD;AACA,SAAS,oBAAoB,WAAW;CACvC,OAAO,UAAU,WAAW,IAAI,KAAK,UAAU,WAAW,KAAK;AAChE;AACA,SAAS,sBAAsB,OAAO;CACrC,IAAI,EAAE,iBAAiB,QAAQ,OAAO;CACtC,IAAI,EAAE,UAAU,QAAQ,OAAO;CAC/B,OAAO,MAAM,SAAS;AACvB;;;;;;;;;;;;AAcA,MAAM,yBAAyB;AAC/B,MAAM,iBAAiB,CAAC,QAAQ,MAAM;AACtC,SAAS,UAAU,OAAO;CACzB,OAAO,UAAU,SAAS,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,KAAK;AAC9E;AACA,SAAS,qBAAqB,OAAO;CACpC,IAAI,EAAE,iBAAiB,QAAQ,OAAO,KAAK;CAC3C,IAAI,UAAU,KAAK,MAAM,wBAAwB,OAAO,KAAK;CAC7D,OAAO,2CAA2C,KAAK,MAAM,OAAO,CAAC,GAAG;AACzE;;;;;;;AAOA,SAAS,oBAAoB,OAAO,WAAW;CAC9C,MAAM,gBAAgB,qBAAqB,KAAK;CAChD,IAAI,kBAAkB,KAAK,GAAG,OAAO,KAAK;CAC1C,IAAI,CAAC,eAAe,MAAM,QAAQ,cAAc,SAAS,GAAG,CAAC,GAAG,OAAO,KAAK;CAC5E,OAAO;EACN,SAAS,IAAI,cAAc;EAC3B,KAAK,iBAAiB,UAAU;EAChC,KAAK;CACN;AACD;;;;;;;AASA,eAAe,UAAU,UAAU,KAAK;CACvC,wBAAwB;CACxB,MAAM,eAAeE,OAAK,QAAQ,KAAK,QAAQ;CAC/C,IAAI;CACJ,IAAI;EACH,MAAM,MAAM,OAAO,cAAc,YAAY,CAAC,CAAC;CAChD,SAAS,OAAO;EACf,MAAM,YAAY,oBAAoB,OAAO,YAAY;EACzD,IAAI,cAAc,KAAK,GAAG,MAAM,IAAI,mBAAmB,4BAA4B,UAAU,SAAS;GACrG,KAAK,UAAU;GACf,KAAK,UAAU;GACf,OAAO,EAAE,MAAM,aAAa;GAC5B,OAAO;EACR,CAAC;EACD,MAAM,IAAI,mBAAmB,4BAA4B,kCAAkC,aAAa,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,KAAK;GACtK,OAAO,EAAE,MAAM,aAAa;GAC5B,OAAO;EACR,CAAC;CACF;CACA,MAAM,OAAO,UAAU,GAAG,CAAC,CAAC;CAC5B,IAAI,CAAC,OAAO,IAAI,KAAK,KAAK,SAAS,gBAAgB,KAAK,SAAS,YAAY,MAAM,IAAI,mBAAmB,gCAAgC,iBAAiB,aAAa,wDAAwD;EAC/N,KAAK;EACL,OAAO,EAAE,MAAM,aAAa;CAC7B,CAAC;CACD,OAAO;EACN,MAAM;EACN,MAAM,UAAU,IAAI;CACrB;AACD;AAGA,SAAS,OAAO,YAAY,WAAW,MAAM,cAAc,MAAM;CAChE,MAAM,MAAM,WAAW,IAAI,SAAS;CACpC,IAAI,QAAQ,KAAK,GAAG,MAAM,IAAI,mBAAmB,4BAA4B,iBAAiB,UAAU,6BAA6B,KAAK,KAAK;EAC9I,KAAK;EACL,MAAM;GACL;GACA;EACD;CACD,CAAC;CACD,MAAM,aAAa,IAAI,MAAM;CAC7B,IAAI,eAAe,KAAK,GAAG,MAAM,IAAI,mBAAmB,6BAA6B,cAAc,UAAU,qCAAqC,KAAK,eAAe,KAAK,KAAK;EAC/K,KAAK,gBAAgB,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE;EACvD,MAAM;GACL;GACA;EACD;CACD,CAAC;CACD,IAAI,WAAW,SAAS,cAAc,MAAM,IAAI,mBAAmB,mCAAmC,cAAc,UAAU,gCAAgC,KAAK,UAAU,WAAW,KAAK,iBAAiB,KAAK,YAAY,aAAa,gBAAgB,EAAE,MAAM;EACnQ;EACA;EACA,MAAM,WAAW;CAClB,EAAE,CAAC;AACJ;;AAEA,SAAS,yBAAyB,OAAO,QAAQ;CAChD,MAAM,aAAa,IAAI,IAAI,OAAO,WAAW,KAAK,eAAe,CAAC,WAAW,IAAI,UAAU,CAAC,CAAC;CAC7F,KAAK,MAAM,EAAE,IAAI,UAAU,MAAM,OAAO;EACvC,IAAI,KAAK,SAAS,YAAY;GAC7B,OAAO,YAAY,KAAK,WAAW,KAAK,MAAM,YAAY,kBAAkB,GAAG,EAAE;GACjF;EACD;EACA,IAAI,KAAK,SAAS,WAAW;EAC7B,OAAO,YAAY,KAAK,WAAW,KAAK,MAAM,WAAW,iBAAiB,GAAG,EAAE;EAC/E,OAAO,YAAY,KAAK,MAAM,WAAW,KAAK,MAAM,MAAM,SAAS,iBAAiB,GAAG,qBAAqB;CAC7G;AACD;;;;;;;;;;;AAaA,SAAS,YAAY,UAAU,MAAM;CACpC,MAAM,CAAC,SAAS;CAChB,OAAO,IAAI,mBAAmB,MAAM,MAAM,MAAM,SAAS;EACxD,GAAG,MAAM,QAAQ,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,MAAM,IAAI;EAChD,KAAK,MAAM;EACX,OAAO,EAAE,MAAM,MAAM,SAAS,KAAK;EACnC,MAAM;GACL,GAAG,MAAM,UAAU,KAAK,IAAI,CAAC,IAAI,EAAE,OAAO,MAAM,MAAM;GACtD;EACD;CACD,CAAC;AACF;;;;;AAKA,SAAS,kBAAkB,QAAQ,KAAK;CACvC,MAAM,OAAOA,OAAK,QAAQ,KAAK,OAAO,IAAI;CAC1C,IAAI,CAACC,KAAG,WAAW,IAAI,GAAG,MAAM,YAAY,CAAC,kBAAkB,IAAI,CAAC,GAAG,IAAI;CAC3E,MAAM,UAAU,oBAAoB,OAAO,OAAO,IAAI;CACtD,IAAI,CAAC,QAAQ,IAAI,MAAM,YAAY,QAAQ,UAAU,IAAI;CACzD,OAAO;EACN,OAAO,QAAQ;EACf;CACD;AACD;;;;;;;;AAQA,eAAe,mBAAmB,OAAO,cAAc,KAAK,QAAQ;CACnE,MAAM,EAAE,UAAU,kBAAkB,QAAQ,GAAG;CAC/C,MAAM,cAAc,MAAM,UAAU,OAAO,GAAG;CAC9C,MAAM,OAAO,gBAAgB,YAAY,KAAK;CAC9C,IAAI,KAAK,WAAW,GAAG,MAAM,IAAI,mBAAmB,wBAAwB,8BAA8B,EAAE,KAAK,wCAAwC,CAAC;CAC1J,OAAO;EACN,QAAQ;EACR;CACD;AACD;;;;;;;AAOA,eAAe,YAAY,OAAO,cAAc,KAAK,QAAQ,OAAO,CAAC,GAAG,iBAAiB;CACxF,MAAM,eAAe,kBAAkB,QAAQ,GAAG;CAClD,MAAM,SAAS,aAAa;CAC5B,MAAM,cAAc,MAAM,UAAU,OAAO,GAAG;CAC9C,MAAM,QAAQ,KAAK,YAAY,IAAI;CACnC,IAAI,MAAM,KAAK,KAAK,SAAS,UAAU,MAAM,IAAI,mBAAmB,2BAA2B,qCAAqC,EAAE,KAAK,qGAAqG,CAAC;CACjP,yBAAyB,OAAO,MAAM;CACtC,MAAM,OAAO,gBAAgB,YAAY,KAAK;CAC9C,IAAI,KAAK,WAAW,GAAG,MAAM,IAAI,mBAAmB,wBAAwB,8BAA8B,EAAE,KAAK,wCAAwC,CAAC;CAC1J,IAAI;CACJ,IAAI;EACH,YAAY,MAAM,iBAAiB,OAAO,QAAQ,KAAK,KAAK,YAAY;CACzE,SAAS,OAAO;EACf,IAAI,oBAAoB,KAAK,KAAK,iBAAiB,OAAO,MAAM,gBAAgB,KAAK;EACrF,MAAM;CACP;CACA,OAAO;EACN;EACA;EACA;EACA;EACA;CACD;AACD"}
package/dist/report.d.mts CHANGED
@@ -1,5 +1,6 @@
1
- import { f as DeploymentResult } from "./app-config-jGcCcxK4-DnzGGbDS.mjs";
2
- import "./deploy-BGtKERz-.mjs";
1
+ import { f as DeploymentResult } from "./app-config-DyCMnkDr-CguUhanl.mjs";
2
+ import "./deploy-i9yR7YWi.mjs";
3
+ import { r as captureEngineFailure } from "./deployment-summary-CU-eVvJM-c3AqO52N.mjs";
3
4
  //#region ../../0-framework/3-tooling/cli/dist/report.d.mts
4
5
  //#region src/render-deployment.d.ts
5
6
  /**
@@ -14,5 +15,5 @@ declare function renderDeployment(result: DeploymentResult): string;
14
15
  */
15
16
  declare function deploymentReport(result: DeploymentResult): void;
16
17
  //#endregion
17
- export { deploymentReport, renderDeployment };
18
+ export { captureEngineFailure, deploymentReport, renderDeployment };
18
19
  //# sourceMappingURL=report.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.mts","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/report.d.mts"],"mappings":";;;;;;;;iBAMiB,iBAAiB,QAAQ;;;;;;iBAMzB,iBAAiB,QAAQ"}
1
+ {"version":3,"file":"report.d.mts","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/report.d.mts"],"mappings":";;;;;;;;;iBAOiB,iBAAiB,QAAQ;;;;;;iBAMzB,iBAAiB,QAAQ"}
package/dist/report.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { r as writeDeploymentSummaryFile } from "./deployment-summary-DswOl_9E-B9MhYYDt.mjs";
1
+ import { n as captureEngineFailure, o as writeDeploymentSummaryFile } from "./deployment-summary-37e6WEuh-BOTJynIi.mjs";
2
2
  //#region ../../0-framework/3-tooling/cli/dist/report.mjs
3
3
  /** Gap between the deepest tree label and the entity column. */
4
4
  const LABEL_GAP = 3;
@@ -81,6 +81,6 @@ function deploymentReport(result) {
81
81
  writeDeploymentSummaryFile(result);
82
82
  }
83
83
  //#endregion
84
- export { deploymentReport, renderDeployment };
84
+ export { captureEngineFailure, deploymentReport, renderDeployment };
85
85
 
86
86
  //# sourceMappingURL=report.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.mjs","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/report.mjs"],"sourcesContent":["import { r as writeDeploymentSummaryFile } from \"./deployment-summary-DswOl_9E.mjs\";\n//#region src/render-deployment.ts\n/** Gap between the deepest tree label and the entity column. */\nconst LABEL_GAP = 3;\nconst emptyNode = (segment) => ({\n\tsegment,\n\tchildren: /* @__PURE__ */ new Map()\n});\n/** Builds the address tree, splitting each dot-address into its segments. */\nfunction buildTree(nodes) {\n\tconst root = emptyNode(\"\");\n\tfor (const deployed of nodes) {\n\t\tlet node = root;\n\t\tfor (const segment of deployed.address.split(\".\")) {\n\t\t\tlet child = node.children.get(segment);\n\t\t\tif (child === void 0) {\n\t\t\t\tchild = emptyNode(segment);\n\t\t\t\tnode.children.set(segment, child);\n\t\t\t}\n\t\t\tnode = child;\n\t\t}\n\t\tnode.deployed = deployed;\n\t}\n\treturn root;\n}\n/** Flattens the tree to rows in address order, drawing the box guides. */\nfunction toRows(node, guides, rows) {\n\tconst children = Array.from(node.children.values());\n\tchildren.forEach((child, index) => {\n\t\tconst isLast = index === children.length - 1;\n\t\trows.push({\n\t\t\tlabel: `${guides}${isLast ? \"└─ \" : \"├─ \"}${child.segment}`,\n\t\t\tcontinuation: `${guides}${isLast ? \" \" : \"│ \"}`,\n\t\t\tdeployed: child.deployed\n\t\t});\n\t\ttoRows(child, `${guides}${isLast ? \" \" : \"│ \"}`, rows);\n\t});\n}\n/** `kind id` — the one line an entity gets. */\nconst entityLine = (entity) => `${entity.kind} ${entity.id}`;\n/** Pads `prefix` out to `width`, so every entity starts in the same column. */\nconst pad = (prefix, width) => prefix.padEnd(width, \" \");\n/**\n* Renders a deploy's result as the app's own topology. Pure — returns the\n* string; the caller prints.\n*/\nfunction renderDeployment(result) {\n\tconst rows = [];\n\ttoRows(buildTree(result.nodes), \"\", rows);\n\tconst column = Math.max(0, ...rows.map((row) => row.label.length)) + LABEL_GAP;\n\tconst lines = [result.app];\n\tfor (const row of rows) {\n\t\tif (row.deployed === void 0) {\n\t\t\tlines.push(row.label);\n\t\t\tcontinue;\n\t\t}\n\t\tif (row.deployed.entities.length === 0) {\n\t\t\tlines.push(`${pad(row.label, column)}(no entities reported)`);\n\t\t\tcontinue;\n\t\t}\n\t\trow.deployed.entities.forEach((entity, index) => {\n\t\t\tconst prefix = index === 0 ? row.label : row.continuation;\n\t\t\tlines.push(`${pad(prefix, column)}${entityLine(entity)}`);\n\t\t\tif (entity.url !== void 0) lines.push(`${pad(row.continuation, column)}${entity.url}`);\n\t\t\tfor (const [key, value] of Object.entries(entity.details ?? {})) {\n\t\t\t\tif (value === \"\") continue;\n\t\t\t\tfor (const line of value.split(\"\\n\")) lines.push(`${pad(row.continuation, column)}${key} ${line}`);\n\t\t\t}\n\t\t});\n\t}\n\treturn lines.join(\"\\n\");\n}\n/**\n* The report hook the generated stack file wires into `LowerOptions`. Prints a\n* leading blank line so the summary separates from alchemy's own apply output,\n* then hands the result to the cross-process writer (deployment-summary.ts).\n*/\nfunction deploymentReport(result) {\n\tconsole.log(\"\");\n\tconsole.log(renderDeployment(result));\n\twriteDeploymentSummaryFile(result);\n}\n//#endregion\nexport { deploymentReport, renderDeployment };\n\n//# sourceMappingURL=report.mjs.map"],"mappings":";;;AAGA,MAAM,YAAY;AAClB,MAAM,aAAa,aAAa;CAC/B;CACA,0BAA0B,IAAI,IAAI;AACnC;;AAEA,SAAS,UAAU,OAAO;CACzB,MAAM,OAAO,UAAU,EAAE;CACzB,KAAK,MAAM,YAAY,OAAO;EAC7B,IAAI,OAAO;EACX,KAAK,MAAM,WAAW,SAAS,QAAQ,MAAM,GAAG,GAAG;GAClD,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO;GACrC,IAAI,UAAU,KAAK,GAAG;IACrB,QAAQ,UAAU,OAAO;IACzB,KAAK,SAAS,IAAI,SAAS,KAAK;GACjC;GACA,OAAO;EACR;EACA,KAAK,WAAW;CACjB;CACA,OAAO;AACR;;AAEA,SAAS,OAAO,MAAM,QAAQ,MAAM;CACnC,MAAM,WAAW,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC;CAClD,SAAS,SAAS,OAAO,UAAU;EAClC,MAAM,SAAS,UAAU,SAAS,SAAS;EAC3C,KAAK,KAAK;GACT,OAAO,GAAG,SAAS,SAAS,QAAQ,QAAQ,MAAM;GAClD,cAAc,GAAG,SAAS,SAAS,QAAQ;GAC3C,UAAU,MAAM;EACjB,CAAC;EACD,OAAO,OAAO,GAAG,SAAS,SAAS,QAAQ,SAAS,IAAI;CACzD,CAAC;AACF;;AAEA,MAAM,cAAc,WAAW,GAAG,OAAO,KAAK,GAAG,OAAO;;AAExD,MAAM,OAAO,QAAQ,UAAU,OAAO,OAAO,OAAO,GAAG;;;;;AAKvD,SAAS,iBAAiB,QAAQ;CACjC,MAAM,OAAO,CAAC;CACd,OAAO,UAAU,OAAO,KAAK,GAAG,IAAI,IAAI;CACxC,MAAM,SAAS,KAAK,IAAI,GAAG,GAAG,KAAK,KAAK,QAAQ,IAAI,MAAM,MAAM,CAAC,IAAI;CACrE,MAAM,QAAQ,CAAC,OAAO,GAAG;CACzB,KAAK,MAAM,OAAO,MAAM;EACvB,IAAI,IAAI,aAAa,KAAK,GAAG;GAC5B,MAAM,KAAK,IAAI,KAAK;GACpB;EACD;EACA,IAAI,IAAI,SAAS,SAAS,WAAW,GAAG;GACvC,MAAM,KAAK,GAAG,IAAI,IAAI,OAAO,MAAM,EAAE,uBAAuB;GAC5D;EACD;EACA,IAAI,SAAS,SAAS,SAAS,QAAQ,UAAU;GAChD,MAAM,SAAS,UAAU,IAAI,IAAI,QAAQ,IAAI;GAC7C,MAAM,KAAK,GAAG,IAAI,QAAQ,MAAM,IAAI,WAAW,MAAM,GAAG;GACxD,IAAI,OAAO,QAAQ,KAAK,GAAG,MAAM,KAAK,GAAG,IAAI,IAAI,cAAc,MAAM,IAAI,OAAO,KAAK;GACrF,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,WAAW,CAAC,CAAC,GAAG;IAChE,IAAI,UAAU,IAAI;IAClB,KAAK,MAAM,QAAQ,MAAM,MAAM,IAAI,GAAG,MAAM,KAAK,GAAG,IAAI,IAAI,cAAc,MAAM,IAAI,IAAI,GAAG,MAAM;GAClG;EACD,CAAC;CACF;CACA,OAAO,MAAM,KAAK,IAAI;AACvB;;;;;;AAMA,SAAS,iBAAiB,QAAQ;CACjC,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,iBAAiB,MAAM,CAAC;CACpC,2BAA2B,MAAM;AAClC"}
1
+ {"version":3,"file":"report.mjs","names":[],"sources":["../../../0-framework/3-tooling/cli/dist/report.mjs"],"sourcesContent":["import { n as captureEngineFailure, o as writeDeploymentSummaryFile } from \"./deployment-summary-37e6WEuh.mjs\";\n//#region src/render-deployment.ts\n/** Gap between the deepest tree label and the entity column. */\nconst LABEL_GAP = 3;\nconst emptyNode = (segment) => ({\n\tsegment,\n\tchildren: /* @__PURE__ */ new Map()\n});\n/** Builds the address tree, splitting each dot-address into its segments. */\nfunction buildTree(nodes) {\n\tconst root = emptyNode(\"\");\n\tfor (const deployed of nodes) {\n\t\tlet node = root;\n\t\tfor (const segment of deployed.address.split(\".\")) {\n\t\t\tlet child = node.children.get(segment);\n\t\t\tif (child === void 0) {\n\t\t\t\tchild = emptyNode(segment);\n\t\t\t\tnode.children.set(segment, child);\n\t\t\t}\n\t\t\tnode = child;\n\t\t}\n\t\tnode.deployed = deployed;\n\t}\n\treturn root;\n}\n/** Flattens the tree to rows in address order, drawing the box guides. */\nfunction toRows(node, guides, rows) {\n\tconst children = Array.from(node.children.values());\n\tchildren.forEach((child, index) => {\n\t\tconst isLast = index === children.length - 1;\n\t\trows.push({\n\t\t\tlabel: `${guides}${isLast ? \"└─ \" : \"├─ \"}${child.segment}`,\n\t\t\tcontinuation: `${guides}${isLast ? \" \" : \"│ \"}`,\n\t\t\tdeployed: child.deployed\n\t\t});\n\t\ttoRows(child, `${guides}${isLast ? \" \" : \"│ \"}`, rows);\n\t});\n}\n/** `kind id` — the one line an entity gets. */\nconst entityLine = (entity) => `${entity.kind} ${entity.id}`;\n/** Pads `prefix` out to `width`, so every entity starts in the same column. */\nconst pad = (prefix, width) => prefix.padEnd(width, \" \");\n/**\n* Renders a deploy's result as the app's own topology. Pure — returns the\n* string; the caller prints.\n*/\nfunction renderDeployment(result) {\n\tconst rows = [];\n\ttoRows(buildTree(result.nodes), \"\", rows);\n\tconst column = Math.max(0, ...rows.map((row) => row.label.length)) + LABEL_GAP;\n\tconst lines = [result.app];\n\tfor (const row of rows) {\n\t\tif (row.deployed === void 0) {\n\t\t\tlines.push(row.label);\n\t\t\tcontinue;\n\t\t}\n\t\tif (row.deployed.entities.length === 0) {\n\t\t\tlines.push(`${pad(row.label, column)}(no entities reported)`);\n\t\t\tcontinue;\n\t\t}\n\t\trow.deployed.entities.forEach((entity, index) => {\n\t\t\tconst prefix = index === 0 ? row.label : row.continuation;\n\t\t\tlines.push(`${pad(prefix, column)}${entityLine(entity)}`);\n\t\t\tif (entity.url !== void 0) lines.push(`${pad(row.continuation, column)}${entity.url}`);\n\t\t\tfor (const [key, value] of Object.entries(entity.details ?? {})) {\n\t\t\t\tif (value === \"\") continue;\n\t\t\t\tfor (const line of value.split(\"\\n\")) lines.push(`${pad(row.continuation, column)}${key} ${line}`);\n\t\t\t}\n\t\t});\n\t}\n\treturn lines.join(\"\\n\");\n}\n/**\n* The report hook the generated stack file wires into `LowerOptions`. Prints a\n* leading blank line so the summary separates from alchemy's own apply output,\n* then hands the result to the cross-process writer (deployment-summary.ts).\n*/\nfunction deploymentReport(result) {\n\tconsole.log(\"\");\n\tconsole.log(renderDeployment(result));\n\twriteDeploymentSummaryFile(result);\n}\n//#endregion\nexport { captureEngineFailure, deploymentReport, renderDeployment };\n\n//# sourceMappingURL=report.mjs.map"],"mappings":";;;AAGA,MAAM,YAAY;AAClB,MAAM,aAAa,aAAa;CAC/B;CACA,0BAA0B,IAAI,IAAI;AACnC;;AAEA,SAAS,UAAU,OAAO;CACzB,MAAM,OAAO,UAAU,EAAE;CACzB,KAAK,MAAM,YAAY,OAAO;EAC7B,IAAI,OAAO;EACX,KAAK,MAAM,WAAW,SAAS,QAAQ,MAAM,GAAG,GAAG;GAClD,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO;GACrC,IAAI,UAAU,KAAK,GAAG;IACrB,QAAQ,UAAU,OAAO;IACzB,KAAK,SAAS,IAAI,SAAS,KAAK;GACjC;GACA,OAAO;EACR;EACA,KAAK,WAAW;CACjB;CACA,OAAO;AACR;;AAEA,SAAS,OAAO,MAAM,QAAQ,MAAM;CACnC,MAAM,WAAW,MAAM,KAAK,KAAK,SAAS,OAAO,CAAC;CAClD,SAAS,SAAS,OAAO,UAAU;EAClC,MAAM,SAAS,UAAU,SAAS,SAAS;EAC3C,KAAK,KAAK;GACT,OAAO,GAAG,SAAS,SAAS,QAAQ,QAAQ,MAAM;GAClD,cAAc,GAAG,SAAS,SAAS,QAAQ;GAC3C,UAAU,MAAM;EACjB,CAAC;EACD,OAAO,OAAO,GAAG,SAAS,SAAS,QAAQ,SAAS,IAAI;CACzD,CAAC;AACF;;AAEA,MAAM,cAAc,WAAW,GAAG,OAAO,KAAK,GAAG,OAAO;;AAExD,MAAM,OAAO,QAAQ,UAAU,OAAO,OAAO,OAAO,GAAG;;;;;AAKvD,SAAS,iBAAiB,QAAQ;CACjC,MAAM,OAAO,CAAC;CACd,OAAO,UAAU,OAAO,KAAK,GAAG,IAAI,IAAI;CACxC,MAAM,SAAS,KAAK,IAAI,GAAG,GAAG,KAAK,KAAK,QAAQ,IAAI,MAAM,MAAM,CAAC,IAAI;CACrE,MAAM,QAAQ,CAAC,OAAO,GAAG;CACzB,KAAK,MAAM,OAAO,MAAM;EACvB,IAAI,IAAI,aAAa,KAAK,GAAG;GAC5B,MAAM,KAAK,IAAI,KAAK;GACpB;EACD;EACA,IAAI,IAAI,SAAS,SAAS,WAAW,GAAG;GACvC,MAAM,KAAK,GAAG,IAAI,IAAI,OAAO,MAAM,EAAE,uBAAuB;GAC5D;EACD;EACA,IAAI,SAAS,SAAS,SAAS,QAAQ,UAAU;GAChD,MAAM,SAAS,UAAU,IAAI,IAAI,QAAQ,IAAI;GAC7C,MAAM,KAAK,GAAG,IAAI,QAAQ,MAAM,IAAI,WAAW,MAAM,GAAG;GACxD,IAAI,OAAO,QAAQ,KAAK,GAAG,MAAM,KAAK,GAAG,IAAI,IAAI,cAAc,MAAM,IAAI,OAAO,KAAK;GACrF,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,WAAW,CAAC,CAAC,GAAG;IAChE,IAAI,UAAU,IAAI;IAClB,KAAK,MAAM,QAAQ,MAAM,MAAM,IAAI,GAAG,MAAM,KAAK,GAAG,IAAI,IAAI,cAAc,MAAM,IAAI,IAAI,GAAG,MAAM;GAClG;EACD,CAAC;CACF;CACA,OAAO,MAAM,KAAK,IAAI;AACvB;;;;;;AAMA,SAAS,iBAAiB,QAAQ;CACjC,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,iBAAiB,MAAM,CAAC;CACpC,2BAA2B,MAAM;AAClC"}
@@ -2,7 +2,7 @@ import { t as CliStructuredError } from "./errors-0e8IVwzi.mjs";
2
2
  import * as fs$1 from "node:fs";
3
3
  import * as path$1 from "node:path";
4
4
  import spawn from "cross-spawn";
5
- //#region ../../0-framework/3-tooling/cli/dist/run-alchemy-pANK8XNX.mjs
5
+ //#region ../../0-framework/3-tooling/cli/dist/run-alchemy-BEvB2sYQ.mjs
6
6
  /**
7
7
  * Pipeline step 7 (deploy-cli.md § The pipeline; design-notes.md's "Driving
8
8
  * Alchemy" call): hand the terminal to the generated stack file.
@@ -96,4 +96,4 @@ const spawnAlchemy = async (invocation) => {
96
96
  //#endregion
97
97
  export { spawnAlchemy as n, alchemyInvocation as t };
98
98
 
99
- //# sourceMappingURL=run-alchemy-pANK8XNX-CgCpXLkG.mjs.map
99
+ //# sourceMappingURL=run-alchemy-BEvB2sYQ-Cy2fhbcu.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-alchemy-pANK8XNX-CgCpXLkG.mjs","names":["path","fs"],"sources":["../../../0-framework/3-tooling/cli/dist/run-alchemy-pANK8XNX.mjs"],"sourcesContent":["import { CliStructuredError } from \"@internal/foundation/errors\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport spawn from \"cross-spawn\";\n//#region src/run-alchemy.ts\n/**\n* Pipeline step 7 (deploy-cli.md § The pipeline; design-notes.md's \"Driving\n* Alchemy\" call): hand the terminal to the generated stack file.\n*\n* Resolves the installed `alchemy` bin and launches package-manager shims with\n* cross-spawn.\n*\n* This module composes the invocation; it does not decide how the child is\n* started. Under the CLI the engine starts it (`ctx.spawn`), which is what\n* makes Ctrl-C reach the child natively and keeps signal policy in one place.\n* `spawnAlchemy` is the default for programmatic hosts driving\n* `@prisma/composer/control`, which have no engine to borrow.\n*/\n/** Walks up from `startDir` looking for the installed Alchemy executable. */\nfunction resolveAlchemyBin(startDir) {\n\tconst names = process.platform === \"win32\" ? [\n\t\t\"alchemy.exe\",\n\t\t\"alchemy.cmd\",\n\t\t\"alchemy\"\n\t] : [\"alchemy\"];\n\tlet dir = startDir;\n\twhile (true) {\n\t\tfor (const name of names) {\n\t\t\tconst candidate = path.join(dir, \"node_modules\", \".bin\", name);\n\t\t\tif (fs.existsSync(candidate)) return candidate;\n\t\t}\n\t\tconst parent = path.dirname(dir);\n\t\tif (parent === dir) throw new CliStructuredError(\"DEPLOY.ALCHEMY_BIN_MISSING\", `Could not find an installed \\`alchemy\\` bin above \"${startDir}\".`, { fix: \"Add \\\"alchemy\\\" as a dependency of your app.\" });\n\t\tdir = parent;\n\t}\n}\n/**\n* Resolves the invocation against this machine — the step every adapter takes\n* and no caller should. Raises DEPLOY.ALCHEMY_BIN_MISSING when the app has no\n* alchemy installed.\n*/\nfunction alchemyCommandLine(invocation) {\n\treturn {\n\t\tcommand: resolveAlchemyBin(invocation.cwd),\n\t\targs: [\n\t\t\tinvocation.action,\n\t\t\tinvocation.stackFileRelativePath,\n\t\t\t\"--yes\",\n\t\t\t\"--stage\",\n\t\t\tinvocation.stage\n\t\t],\n\t\tcwd: invocation.cwd,\n\t\tenv: invocation.env\n\t};\n}\n/** What becomes `alchemy deploy|destroy <stack file> --yes --stage <stage>`. */\nfunction alchemyInvocation(input) {\n\treturn {\n\t\taction: input.command,\n\t\tstackFileRelativePath: input.stackFileRelativePath,\n\t\tcwd: input.cwd,\n\t\tstage: input.stage,\n\t\tenv: {\n\t\t\t...input.containerEnv,\n\t\t\t...input.preflightEnv,\n\t\t\t...input.env\n\t\t}\n\t};\n}\n/**\n* The default runner for hosts with no engine: inherited stdio, the caller's\n* own process group, and the child's status returned verbatim. It does not\n* collapse a signal into an exit code — that collapse is what made a\n* Ctrl-C'd deploy report itself as a failure.\n*/\nconst spawnAlchemy = async (invocation) => {\n\tconst line = alchemyCommandLine(invocation);\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(line.command, [...line.args], {\n\t\t\tcwd: line.cwd,\n\t\t\tstdio: \"inherit\",\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\t...line.env\n\t\t\t}\n\t\t});\n\t\tchild.on(\"error\", reject);\n\t\tchild.on(\"close\", (exitCode, signal) => {\n\t\t\tresolve({\n\t\t\t\texitCode,\n\t\t\t\tsignal\n\t\t\t});\n\t\t});\n\t});\n};\n//#endregion\nexport { spawnAlchemy as i, alchemyInvocation as n, resolveAlchemyBin as r, alchemyCommandLine as t };\n\n//# sourceMappingURL=run-alchemy-pANK8XNX.mjs.map"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,SAAS,kBAAkB,UAAU;CACpC,MAAM,QAAQ,QAAQ,aAAa,UAAU;EAC5C;EACA;EACA;CACD,IAAI,CAAC,SAAS;CACd,IAAI,MAAM;CACV,OAAO,MAAM;EACZ,KAAK,MAAM,QAAQ,OAAO;GACzB,MAAM,YAAYA,OAAK,KAAK,KAAK,gBAAgB,QAAQ,IAAI;GAC7D,IAAIC,KAAG,WAAW,SAAS,GAAG,OAAO;EACtC;EACA,MAAM,SAASD,OAAK,QAAQ,GAAG;EAC/B,IAAI,WAAW,KAAK,MAAM,IAAI,mBAAmB,8BAA8B,sDAAsD,SAAS,KAAK,EAAE,KAAK,+CAA+C,CAAC;EAC1M,MAAM;CACP;AACD;;;;;;AAMA,SAAS,mBAAmB,YAAY;CACvC,OAAO;EACN,SAAS,kBAAkB,WAAW,GAAG;EACzC,MAAM;GACL,WAAW;GACX,WAAW;GACX;GACA;GACA,WAAW;EACZ;EACA,KAAK,WAAW;EAChB,KAAK,WAAW;CACjB;AACD;;AAEA,SAAS,kBAAkB,OAAO;CACjC,OAAO;EACN,QAAQ,MAAM;EACd,uBAAuB,MAAM;EAC7B,KAAK,MAAM;EACX,OAAO,MAAM;EACb,KAAK;GACJ,GAAG,MAAM;GACT,GAAG,MAAM;GACT,GAAG,MAAM;EACV;CACD;AACD;;;;;;;AAOA,MAAM,eAAe,OAAO,eAAe;CAC1C,MAAM,OAAO,mBAAmB,UAAU;CAC1C,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,MAAM,QAAQ,MAAM,KAAK,SAAS,CAAC,GAAG,KAAK,IAAI,GAAG;GACjD,KAAK,KAAK;GACV,OAAO;GACP,KAAK;IACJ,GAAG,QAAQ;IACX,GAAG,KAAK;GACT;EACD,CAAC;EACD,MAAM,GAAG,SAAS,MAAM;EACxB,MAAM,GAAG,UAAU,UAAU,WAAW;GACvC,QAAQ;IACP;IACA;GACD,CAAC;EACF,CAAC;CACF,CAAC;AACF"}
1
+ {"version":3,"file":"run-alchemy-BEvB2sYQ-Cy2fhbcu.mjs","names":["path","fs"],"sources":["../../../0-framework/3-tooling/cli/dist/run-alchemy-BEvB2sYQ.mjs"],"sourcesContent":["import * as fs from \"node:fs\";\nimport { CliStructuredError } from \"@internal/foundation/errors\";\nimport * as path from \"node:path\";\nimport spawn from \"cross-spawn\";\n//#region src/run-alchemy.ts\n/**\n* Pipeline step 7 (deploy-cli.md § The pipeline; design-notes.md's \"Driving\n* Alchemy\" call): hand the terminal to the generated stack file.\n*\n* Resolves the installed `alchemy` bin and launches package-manager shims with\n* cross-spawn.\n*\n* This module composes the invocation; it does not decide how the child is\n* started. Under the CLI the engine starts it (`ctx.spawn`), which is what\n* makes Ctrl-C reach the child natively and keeps signal policy in one place.\n* `spawnAlchemy` is the default for programmatic hosts driving\n* `@prisma/composer/control`, which have no engine to borrow.\n*/\n/** Walks up from `startDir` looking for the installed Alchemy executable. */\nfunction resolveAlchemyBin(startDir) {\n\tconst names = process.platform === \"win32\" ? [\n\t\t\"alchemy.exe\",\n\t\t\"alchemy.cmd\",\n\t\t\"alchemy\"\n\t] : [\"alchemy\"];\n\tlet dir = startDir;\n\twhile (true) {\n\t\tfor (const name of names) {\n\t\t\tconst candidate = path.join(dir, \"node_modules\", \".bin\", name);\n\t\t\tif (fs.existsSync(candidate)) return candidate;\n\t\t}\n\t\tconst parent = path.dirname(dir);\n\t\tif (parent === dir) throw new CliStructuredError(\"DEPLOY.ALCHEMY_BIN_MISSING\", `Could not find an installed \\`alchemy\\` bin above \"${startDir}\".`, { fix: \"Add \\\"alchemy\\\" as a dependency of your app.\" });\n\t\tdir = parent;\n\t}\n}\n/**\n* Resolves the invocation against this machine — the step every adapter takes\n* and no caller should. Raises DEPLOY.ALCHEMY_BIN_MISSING when the app has no\n* alchemy installed.\n*/\nfunction alchemyCommandLine(invocation) {\n\treturn {\n\t\tcommand: resolveAlchemyBin(invocation.cwd),\n\t\targs: [\n\t\t\tinvocation.action,\n\t\t\tinvocation.stackFileRelativePath,\n\t\t\t\"--yes\",\n\t\t\t\"--stage\",\n\t\t\tinvocation.stage\n\t\t],\n\t\tcwd: invocation.cwd,\n\t\tenv: invocation.env\n\t};\n}\n/** What becomes `alchemy deploy|destroy <stack file> --yes --stage <stage>`. */\nfunction alchemyInvocation(input) {\n\treturn {\n\t\taction: input.command,\n\t\tstackFileRelativePath: input.stackFileRelativePath,\n\t\tcwd: input.cwd,\n\t\tstage: input.stage,\n\t\tenv: {\n\t\t\t...input.containerEnv,\n\t\t\t...input.preflightEnv,\n\t\t\t...input.env\n\t\t}\n\t};\n}\n/**\n* The default runner for hosts with no engine: inherited stdio, the caller's\n* own process group, and the child's status returned verbatim. It does not\n* collapse a signal into an exit code — that collapse is what made a\n* Ctrl-C'd deploy report itself as a failure.\n*/\nconst spawnAlchemy = async (invocation) => {\n\tconst line = alchemyCommandLine(invocation);\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = spawn(line.command, [...line.args], {\n\t\t\tcwd: line.cwd,\n\t\t\tstdio: \"inherit\",\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\t...line.env\n\t\t\t}\n\t\t});\n\t\tchild.on(\"error\", reject);\n\t\tchild.on(\"close\", (exitCode, signal) => {\n\t\t\tresolve({\n\t\t\t\texitCode,\n\t\t\t\tsignal\n\t\t\t});\n\t\t});\n\t});\n};\n//#endregion\nexport { alchemyInvocation as n, spawnAlchemy as r, alchemyCommandLine as t };\n\n//# sourceMappingURL=run-alchemy-BEvB2sYQ.mjs.map"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,SAAS,kBAAkB,UAAU;CACpC,MAAM,QAAQ,QAAQ,aAAa,UAAU;EAC5C;EACA;EACA;CACD,IAAI,CAAC,SAAS;CACd,IAAI,MAAM;CACV,OAAO,MAAM;EACZ,KAAK,MAAM,QAAQ,OAAO;GACzB,MAAM,YAAYA,OAAK,KAAK,KAAK,gBAAgB,QAAQ,IAAI;GAC7D,IAAIC,KAAG,WAAW,SAAS,GAAG,OAAO;EACtC;EACA,MAAM,SAASD,OAAK,QAAQ,GAAG;EAC/B,IAAI,WAAW,KAAK,MAAM,IAAI,mBAAmB,8BAA8B,sDAAsD,SAAS,KAAK,EAAE,KAAK,+CAA+C,CAAC;EAC1M,MAAM;CACP;AACD;;;;;;AAMA,SAAS,mBAAmB,YAAY;CACvC,OAAO;EACN,SAAS,kBAAkB,WAAW,GAAG;EACzC,MAAM;GACL,WAAW;GACX,WAAW;GACX;GACA;GACA,WAAW;EACZ;EACA,KAAK,WAAW;EAChB,KAAK,WAAW;CACjB;AACD;;AAEA,SAAS,kBAAkB,OAAO;CACjC,OAAO;EACN,QAAQ,MAAM;EACd,uBAAuB,MAAM;EAC7B,KAAK,MAAM;EACX,OAAO,MAAM;EACb,KAAK;GACJ,GAAG,MAAM;GACT,GAAG,MAAM;GACT,GAAG,MAAM;EACV;CACD;AACD;;;;;;;AAOA,MAAM,eAAe,OAAO,eAAe;CAC1C,MAAM,OAAO,mBAAmB,UAAU;CAC1C,OAAO,IAAI,SAAS,SAAS,WAAW;EACvC,MAAM,QAAQ,MAAM,KAAK,SAAS,CAAC,GAAG,KAAK,IAAI,GAAG;GACjD,KAAK,KAAK;GACV,OAAO;GACP,KAAK;IACJ,GAAG,QAAQ;IACX,GAAG,KAAK;GACT;EACD,CAAC;EACD,MAAM,GAAG,SAAS,MAAM;EACxB,MAAM,GAAG,UAAU,UAAU,WAAW;GACvC,QAAQ;IACP;IACA;GACD,CAAC;EACF,CAAC;CACF,CAAC;AACF"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@prisma/composer",
3
- "version": "0.25.0",
3
+ "version": "0.26.0-dev.2",
4
4
  "type": "module",
5
- "description": "Prisma Composer — build a Prisma App by composing Modules. Core authoring, deploy pipeline, and the service-rpc/node/nextjs authoring surfaces. The `prisma-composer` CLI lives in @prisma/composer-cli.",
5
+ "description": "Prisma Composer — build a Prisma App by composing Modules. Core authoring, deploy pipeline, and the service-rpc/node/nextjs authoring surfaces. The command family the `prisma` CLI mounts lives in @prisma/composer-cli.",
6
6
  "exports": {
7
7
  ".": "./dist/index.mjs",
8
8
  "./config": "./dist/config.mjs",
@@ -33,22 +33,21 @@
33
33
  "@standard-schema/spec": "^1.1.0",
34
34
  "alchemy": "2.0.0-beta.78",
35
35
  "arktype": "^2.2.3",
36
- "c12": "^3.3.4",
37
36
  "cross-spawn": "^7.0.6",
38
37
  "effect": "4.0.0-rc.115",
39
38
  "esbuild": "^0.28.1",
40
39
  "@prisma/management-api-sdk": "^1.80.0"
41
40
  },
42
41
  "devDependencies": {
43
- "@internal/assemble": "0.25.0",
44
- "@internal/cli": "0.25.0",
45
- "@internal/core": "0.25.0",
46
- "@internal/foundation": "0.25.0",
47
- "@internal/lowering": "0.25.0",
48
- "@internal/nextjs": "0.25.0",
49
- "@internal/node": "0.25.0",
50
- "@internal/service-rpc": "0.25.0",
51
- "@internal/tsdown-config": "0.25.0",
42
+ "@internal/assemble": "0.26.0-dev.2",
43
+ "@internal/cli": "0.26.0-dev.2",
44
+ "@internal/core": "0.26.0-dev.2",
45
+ "@internal/foundation": "0.26.0-dev.2",
46
+ "@internal/lowering": "0.26.0-dev.2",
47
+ "@internal/nextjs": "0.26.0-dev.2",
48
+ "@internal/node": "0.26.0-dev.2",
49
+ "@internal/service-rpc": "0.26.0-dev.2",
50
+ "@internal/tsdown-config": "0.26.0-dev.2",
52
51
  "@types/node": "^26.0.1",
53
52
  "tsdown": "^0.22.7",
54
53
  "typescript": "^6.0.3"
@@ -2,27 +2,27 @@
2
2
  name: prisma-composer-core-concepts
3
3
  metadata:
4
4
  library: "@prisma/composer"
5
- library_version: "0.25.0"
5
+ library_version: "0.26.0-dev.2"
6
6
  version: 2026.9.1
7
7
  description: >-
8
8
  Use when deploying or managing an app that uses Prisma Composer
9
9
  (`@prisma/composer`): wiring its services and Modules, running it locally,
10
10
  testing composed services, or standing up / tearing down an environment.
11
- Triggers on "prisma composer", "@prisma/composer", "prisma app", the
12
- `prisma-composer` CLI, `compute()`, `module()`, `contract()`,
11
+ Triggers on "prisma composer", "@prisma/composer", "prisma app",
12
+ `prisma deploy`, `prisma dev`, `compute()`, `module()`, `contract()`,
13
13
  `service.load()`, `mockService`, `bootstrapService`.
14
14
  ---
15
15
 
16
16
  # Prisma Composer core concepts
17
17
 
18
18
  A **Prisma App** is a tree of typed declarations composed in TypeScript and
19
- handed to the `prisma-composer` CLI. This file covers structures,
20
- hierarchies, relationships, and workflows: the concepts you cannot observe
21
- from the code or the CLI's help output. It is not a CLI reference; discover
22
- any individual command and its flags with `--help`. Commands named here
23
- belong to the `prisma-composer` CLI itself; a host CLI that embeds Composer
24
- may not carry every verb, so confirm a command exists via `--help` rather
25
- than inferring it. The Prisma platform moves fast, so treat this file as the
19
+ handed to the `prisma` CLI, which has two Composer commands: `prisma deploy`
20
+ and `prisma dev`. Teardown and logs are not commands; they are the `destroy`
21
+ and `log` operations of `@prisma/composer/control`, called from a script.
22
+ This file covers structures, hierarchies, relationships, and workflows: the
23
+ concepts you cannot observe from the code or the CLI's help output. It is not
24
+ a CLI reference; discover each command's flags with `prisma <command> --help`
25
+ rather than inferring them. The Prisma platform moves fast, so treat this file as the
26
26
  stable conceptual core and find current, fuller documentation at
27
27
  <https://www.prisma.io/docs>. For working code, read `examples/` in the
28
28
  prisma/composer repo.
@@ -87,8 +87,8 @@ is a couple of lines.
87
87
  Within the entry graph (everything reachable from `module.ts`), write
88
88
  relative imports with explicit `.ts` extensions (`./service.ts`, with
89
89
  `allowImportingTsExtensions` in tsconfig): that form resolves everywhere.
90
- The `prisma-composer` CLI also maps `./service.js` and extensionless
91
- `./service` to the `.ts` source, but other hosts may not.
90
+ `prisma deploy` and `prisma dev` also map `./service.js` and extensionless
91
+ `./service` to the `.ts` source, but other tools may not.
92
92
 
93
93
  ## The service node is the only doorway
94
94
 
@@ -216,13 +216,37 @@ deploy. Rules that bite:
216
216
  runtime env for prerendered routes.
217
217
  4. **Always build before `deploy` or `dev`.** Neither builds for you.
218
218
 
219
- Deploy configuration lives in `prisma-composer.config.ts` (or `.mts`, `.mjs`,
220
- `.js`; nearest ancestor of the entry wins, `.ts` first within a directory).
221
- It registers extensions (`prismaCloud()`, `nodeBuild()`, `nextjsBuild()` when
222
- the app has a Next.js service) and the deploy-state backend
223
- (`prismaState()`). It is read by the CLI's operations (deploy, destroy, and
224
- dev; a `dev` run without one refuses, naming the missing file) and never
225
- imported by app code.
219
+ Deploy configuration is the `composer` section of `prisma.config.ts`, and
220
+ nothing else. It registers extensions (`prismaCloud()`, `nodeBuild()`,
221
+ `nextjsBuild()` when the app has a Next.js service) and the deploy-state
222
+ backend (`prismaState()`):
223
+
224
+ ```ts
225
+ // prisma.config.ts
226
+ import { defineConfig as composer } from '@prisma/composer/config';
227
+ import { nodeBuild } from '@prisma/composer/node/control';
228
+ import { prismaCloud, prismaState } from '@prisma/composer-prisma-cloud/control';
229
+ import { definePrismaConfig } from 'prisma/config';
230
+
231
+ export default definePrismaConfig({
232
+ composer: composer({ extensions: [prismaCloud(), nodeBuild()], state: prismaState() }),
233
+ });
234
+ ```
235
+
236
+ The commands find `prisma.config.ts` from the directory they run in, walking up
237
+ to the repository root; the nearest file that declares `composer` wins, and its
238
+ section is used whole, never merged key by key. Only `extensions` and `state`
239
+ are allowed; any other key is an error. App code never imports the file.
240
+
241
+ A separate `prisma-composer.config.ts` is no longer read, and the old setup is
242
+ refused, never silently ignored: `CONFIG.SECTION_MISSING` when no loaded
243
+ `prisma.config.ts` declares a `composer` section, `CONFIG.FIELD_RETIRED` when
244
+ the section still has `configPath`, `CONFIG.FILE_RETIRED` when a
245
+ `prisma-composer.config.*` sits next to the declaring `prisma.config.ts`; all
246
+ three under the CLI's `CLI.CONFIG_SECTION_INVALID`. The fix for all three is to move the old
247
+ file's `extensions` and `state` into the section and delete the old file.
248
+ `@prisma/composer-cli/family` no longer exports `ComposerSection`; the
249
+ section's type is `PrismaAppConfig` from `@prisma/composer/config`.
226
250
 
227
251
  ## Databases and migrations
228
252
 
@@ -252,6 +276,11 @@ including the first schema of a new database, follows one loop:
252
276
  4. Commit `migrations/` with the change, then deploy. A fresh database
253
277
  replays the whole path from empty.
254
278
 
279
+ Every service that uses the database deploys only after its migration
280
+ completes: a failed migration means the new code does not ship. The old
281
+ code serves against the new schema until the new deployment is live, so
282
+ keep each migration compatible with the code it replaces.
283
+
255
284
  If no authored path reaches the target contract, deploy (and `dev` against a
256
285
  stale local database) refuses with `MIGRATION_PATH_NOT_FOUND`; its message
257
286
  lists the two ways out: author the missing migration, or, when iterating
@@ -267,9 +296,14 @@ complete pattern.
267
296
 
268
297
  Deploy compares the declared topology against recorded deploy state and
269
298
  applies only the difference. Re-deploying with nothing changed is a no-op;
270
- removing a node removes its deployed resource. The Prisma Cloud target
271
- requires exactly two environment variables: `PRISMA_SERVICE_TOKEN` and
272
- `PRISMA_WORKSPACE_ID`. There is no interactive login.
299
+ removing a node removes its deployed resource. `prisma deploy` needs a signed-in
300
+ identity: `prisma auth login` stores a session on a developer machine, and
301
+ `PRISMA_SERVICE_TOKEN` overrides it in CI. The `/control` operations, and so
302
+ a destroy script, never use that session: `deploy` and `destroy` read
303
+ `PRISMA_SERVICE_TOKEN` and `PRISMA_WORKSPACE_ID` from the environment (both
304
+ in the workspace's Console settings); `dev` and `log` read neither. The
305
+ `prisma` bin starts under Node; when the modules `module.ts` imports use Bun
306
+ APIs, run it under Bun (`bun node_modules/.bin/prisma deploy module.ts`).
273
307
 
274
308
  **Stages.** A stage is an environment name chosen on the command line at
275
309
  deploy time, never written in the topology. The identical graph deploys
@@ -278,8 +312,14 @@ stage is a Branch of it, with its own running services, its own empty
278
312
  database, its own configuration. A stage name must be a valid git ref name;
279
313
  an invalid name is a hard error.
280
314
 
281
- **Destroy** always requires an explicit target: a bare destroy is an error,
282
- and naming a stage and production together is too. Destroying a stage
315
+ **Destroy** is the `destroy` operation, and its `target` is required:
316
+ `{ kind: 'stage', stage }` or `{ kind: 'production' }`, never a default:
317
+
318
+ ```ts
319
+ await destroy({ entry: 'module.ts', target: { kind: 'stage', stage: 'pr-42' }, config });
320
+ ```
321
+
322
+ Destroying a stage
283
323
  deletes its Branch after removing its resources. Destroying production
284
324
  removes only the resources inside the production Branch, never the Branch
285
325
  itself directly; once the Project is empty it is deleted too, and that
@@ -295,7 +335,7 @@ ancestor directories. Windows resolves `alchemy.exe`, then `alchemy.cmd`,
295
335
  then the extensionless shim; POSIX resolves `alchemy`. No global Alchemy
296
336
  installation is needed.
297
337
 
298
- 1. Deploy and destroy write the pipeline's results to a generated, gitignored
338
+ 1. The deploy and destroy operations write the pipeline's results to a generated, gitignored
299
339
  stack file at `.prisma-composer/alchemy.run.ts`, then run the alchemy CLI
300
340
  against it as a child process; `dev` does the same at
301
341
  `.prisma-composer/dev/alchemy.run.ts` with local providers. The file
@@ -306,8 +346,9 @@ installation is needed.
306
346
  path; running `alchemy deploy .prisma-composer/alchemy.run.ts` directly
307
347
  separates "the framework computed the wrong thing" from "the engine or
308
348
  platform rejected the right thing". An engine failure surfaces as
309
- `DEPLOY.ENGINE_FAILED` carrying the exit code and that reproduce command;
310
- the child's live output streams to the terminal either way.
349
+ `DEPLOY.ENGINE_FAILED` carrying the exit code, the engine's own error
350
+ lines (credentials redacted, capped at 1000 characters) and that reproduce
351
+ command; the child's live output streams to the terminal either way.
311
352
  3. Destroy evaluates the same stack program as deploy, and evaluating it
312
353
  packages the assembled bundles, so **an app must be built before it can
313
354
  be torn down**.
@@ -336,17 +377,27 @@ and crash the consumer at boot). Fix whichever end is wrong; don't mark the
336
377
  param `optional` unless absent really is legal. Only reachable if you
337
378
  authored the connection or an extension on one side.
338
379
 
339
- **Driving deploys from code.** `@prisma/composer/control` exposes typed
340
- `deploy`, `destroy`, `dev`, and `log` returning structured results. Failures
341
- come back as `{ ok: false, failure }` with a dotted `failure.code` from a
342
- closed registry (e.g. `ASSEMBLE.BUILD_FAILED`, `DEPLOY.ENGINE_FAILED`,
343
- `DEPS.EFFECT_VERSION_CONFLICT`); branch on the code, not the message. A
380
+ **Driving deploys from code.** A script imports only
381
+ `@prisma/composer/control`; the extensions' `/control` entries are imported
382
+ only by `prisma.config.ts` (ADR-0017). `@prisma/composer/control` exposes typed
383
+ `deploy`, `destroy`, `dev`, and `log` returning structured results;
384
+ `prisma deploy` and `prisma dev` render `deploy` and `dev`. Each takes
385
+ a required `config: { value, file }` (`ComposerConfigSource`): the `composer`
386
+ export of your `prisma.config.ts` and that file's path; a relative `file`
387
+ resolves against `cwd`, so build it from `import.meta.url`. The operations
388
+ never look for a config file, but refuse what the CLI refuses before any work
389
+ starts (`CONFIG.FIELD_UNKNOWN` for the whole export instead of its `composer`
390
+ property, `CONFIG.FILE_RETIRED`, `CONFIG.FILE_MISSING`); the deploy re-imports
391
+ `file`, so `value` must be its `composer` export. Failures come back as
392
+ `{ ok: false, failure }` with a dotted `failure.code` from a closed registry
393
+ (e.g. `ASSEMBLE.BUILD_FAILED`, `DEPLOY.ENGINE_FAILED`,
394
+ `DEPS.EXECUTOR_UNLOADABLE`); branch on the code, not the message. A
344
395
  non-structured rejection out of an operation is a bug in composer, not an
345
396
  expected failure.
346
397
 
347
398
  ## Local development
348
399
 
349
- The `dev` command runs the whole app on this machine, wired as it deploys,
400
+ `prisma dev` runs the whole app on this machine, wired as it deploys,
350
401
  against local emulators. No cloud credentials are needed or read. Concepts
351
402
  that surprise:
352
403
 
@@ -356,13 +407,30 @@ that surprise:
356
407
  2. Ctrl-C stops the app's processes but leaves local databases, buckets, and
357
408
  their data up: the next `dev` is a warm start. Starting clean, wiping
358
409
  this app's local instances and data first, is an explicit opt-in flag.
359
- 3. `dev` does not print service logs; `log` is a separate, read-only command
360
- that follows the already-running app's merged logs. It never builds,
361
- provisions, starts, or stops anything.
362
- 4. An unset secret doesn't block a local run: it becomes a placeholder plus a
410
+ 3. `dev` does not print service logs. The `log` operation follows the
411
+ already-running app's merged logs; it never builds, provisions, starts, or
412
+ stops anything:
413
+
414
+ ```ts
415
+ const attached = await log({ entry: 'module.ts', config, tail: 20, signal });
416
+ if (attached.ok) for await (const { service, line } of attached.value.lines) console.log(service, line);
417
+ ```
418
+ 4. `dev` reads `prisma.config.ts` once, at start, and watches it: after an
419
+ edit it says so and pauses rebuilds until you restart `dev`.
420
+ 5. An unset secret doesn't block a local run: it becomes a placeholder plus a
363
421
  warning, and only the code path that spends it fails, at the external
364
422
  service it calls.
365
- 5. Windows isn't supported yet.
423
+ 6. The emulators are machine-wide daemons shared by every `dev`, registered
424
+ under `~/.prisma-composer/emulators`. Set `PRISMA_COMPOSER_EMULATORS_DIR`
425
+ to an absolute directory to give a checkout or CI job its own compute and
426
+ buckets daemons, registry and data; a relative path (or an unexpanded `~`)
427
+ fails with `DEV.EMULATORS_DIR_INVALID`. It does not isolate local Postgres:
428
+ servers are named after the app and database, so two checkouts of one app
429
+ share a server, and `--fresh` or teardown in either stops it and deletes
430
+ the database for both. `emulatorRegistryRoot()` from
431
+ `@prisma/composer-prisma-cloud/local-target` returns the directory in
432
+ effect.
433
+ 7. Windows isn't supported yet.
366
434
 
367
435
  Local Postgres runs on `@prisma/dev`, which `@prisma/composer-prisma-cloud`
368
436
  declares as its own dependency (`^0.25.2`) and resolves from its own package.
@@ -432,10 +500,12 @@ today the blocks above plus your own Modules are the whole set, so verify a
432
500
 
433
501
  ## Failure modes quick reference
434
502
 
435
- 1. **Every `prisma-composer` command halts at start-up on an `effect`
436
- version conflict** (`Dependency conflict: alchemy resolves effect@...`).
437
- The app, or one of its dependencies, pins a different `effect` and the
438
- package manager hoisted it over Composer's pin. Match the app's own
503
+ 1. **`prisma deploy` and `prisma dev` stop with `CLI.CONFIG_UNREADABLE` on an
504
+ `effect` version conflict** (`prisma.config.ts could not be evaluated:`
505
+ followed by a module error from inside alchemy, such as
506
+ `Schema.TaggedError is not a function`). The extensions in the `composer`
507
+ section import alchemy, and the app, or one of its dependencies, pins a
508
+ different `effect` that the package manager hoisted over Composer's pin. Match the app's own
439
509
  `effect` to `@prisma/composer`'s exact pin, or force it with
440
510
  `"overrides": { "effect": "<pin>" }` in the app's `package.json` (yarn:
441
511
  `resolutions`; pnpm: `pnpm.overrides`), then reinstall. A plain Composer
@@ -486,9 +556,10 @@ today the blocks above plus your own Modules are the whole set, so verify a
486
556
 
487
557
  Name the gap instead of inventing an API:
488
558
 
489
- 1. **No interactive auth in the `prisma-composer` CLI.** Its deploys
490
- authenticate only via a static
491
- `PRISMA_SERVICE_TOKEN`; there is no `login` flow.
559
+ 1. **No `prisma` command for teardown or logs.** Use the `destroy` and `log`
560
+ operations of `@prisma/composer/control` from a script. A destroy script
561
+ cannot use the `prisma auth login` session; it needs `PRISMA_SERVICE_TOKEN`
562
+ and `PRISMA_WORKSPACE_ID` in the environment.
492
563
  2. **No in-memory contract bindings.** A dependency can't yet be wired to a
493
564
  co-located handler without HTTP; use `bootstrapService` with a loopback
494
565
  fake.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Public surface (the `./testing` subpath): `mockService`, the application
3
- * unit-test seam for composed services. The command family's control double
3
+ * unit-test seam for composed services. The command family's operations double
4
4
  * lives in `@prisma/composer-cli/testing`.
5
5
  */
6
6
  export * from '@internal/core/testing';
@@ -1 +0,0 @@
1
- import "./app-config-jGcCcxK4-DnzGGbDS.mjs";
@@ -1 +0,0 @@
1
- import "./app-config-jGcCcxK4-DnzGGbDS.mjs";
@@ -1,70 +0,0 @@
1
- import { t as blindCast } from "./casts-DpaahrlC-C5XMnP9S.mjs";
2
- import * as fs$1 from "node:fs";
3
- //#region ../../0-framework/3-tooling/cli/dist/deployment-summary-DswOl_9E.mjs
4
- /**
5
- * The deploy result's cross-process protocol, whole in one place: the
6
- * serializable shape, the env var that names the carrier file, the writer the
7
- * report hook calls from inside the alchemy child, and the reader the deploy
8
- * operation runs after the child exits. `DeploymentResult` itself cannot
9
- * cross the boundary — its `DeployedNode` entries hold live graph-node
10
- * references (ADR-0033) — so the writer projects it down to what CAN.
11
- *
12
- * The summary is best-effort by contract: the writer never fails the child
13
- * over it, and the reader maps absent or malformed to `undefined`.
14
- */
15
- /** Env var the deploy operation sets on the alchemy child: when present,
16
- * the report hook also writes the JSON DeploymentSummary there. */
17
- const DEPLOYMENT_RESULT_FILE_ENV = "PRISMA_COMPOSER_DEPLOYMENT_RESULT_FILE";
18
- /** Pure projection: keeps app + each node's address/entities, drops the in-process `node`. */
19
- function toDeploymentSummary(result) {
20
- return {
21
- app: result.app,
22
- nodes: result.nodes.map((node) => ({
23
- address: node.address,
24
- entities: node.entities
25
- }))
26
- };
27
- }
28
- /**
29
- * Writer half, called by the report hook inside the alchemy child: when the
30
- * env var names a file, write the summary there. Best-effort — a write
31
- * failure must not fail a deploy that already converged, so it is swallowed.
32
- */
33
- function writeDeploymentSummaryFile(result) {
34
- const file = process.env[DEPLOYMENT_RESULT_FILE_ENV];
35
- if (file === void 0 || file.length === 0) return;
36
- try {
37
- fs$1.writeFileSync(file, JSON.stringify(toDeploymentSummary(result)));
38
- } catch {}
39
- }
40
- function isRecord(value) {
41
- return typeof value === "object" && value !== null;
42
- }
43
- /**
44
- * Reader half, run by the deploy operation after the child exits. Absent or
45
- * malformed → undefined — the summary is best-effort, never a deploy failure.
46
- */
47
- function readDeploymentSummary(resultFilePath) {
48
- let raw;
49
- try {
50
- raw = fs$1.readFileSync(resultFilePath, "utf8");
51
- } catch {
52
- return;
53
- }
54
- let parsed;
55
- try {
56
- parsed = JSON.parse(raw);
57
- } catch {
58
- return;
59
- }
60
- if (!isRecord(parsed) || typeof parsed["app"] !== "string" || !Array.isArray(parsed["nodes"])) return;
61
- for (const node of parsed["nodes"]) {
62
- if (!isRecord(node) || typeof node["address"] !== "string" || !Array.isArray(node["entities"])) return;
63
- for (const entity of node["entities"]) if (!isRecord(entity) || typeof entity["kind"] !== "string" || typeof entity["id"] !== "string") return;
64
- }
65
- return blindCast(parsed);
66
- }
67
- //#endregion
68
- export { readDeploymentSummary as n, writeDeploymentSummaryFile as r, DEPLOYMENT_RESULT_FILE_ENV as t };
69
-
70
- //# sourceMappingURL=deployment-summary-DswOl_9E-B9MhYYDt.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deployment-summary-DswOl_9E-B9MhYYDt.mjs","names":["fs"],"sources":["../../../0-framework/3-tooling/cli/dist/deployment-summary-DswOl_9E.mjs"],"sourcesContent":["import * as fs from \"node:fs\";\nimport { blindCast } from \"@internal/foundation/casts\";\n//#region src/deployment-summary.ts\n/**\n* The deploy result's cross-process protocol, whole in one place: the\n* serializable shape, the env var that names the carrier file, the writer the\n* report hook calls from inside the alchemy child, and the reader the deploy\n* operation runs after the child exits. `DeploymentResult` itself cannot\n* cross the boundary — its `DeployedNode` entries hold live graph-node\n* references (ADR-0033) — so the writer projects it down to what CAN.\n*\n* The summary is best-effort by contract: the writer never fails the child\n* over it, and the reader maps absent or malformed to `undefined`.\n*/\n/** Env var the deploy operation sets on the alchemy child: when present,\n* the report hook also writes the JSON DeploymentSummary there. */\nconst DEPLOYMENT_RESULT_FILE_ENV = \"PRISMA_COMPOSER_DEPLOYMENT_RESULT_FILE\";\n/** Pure projection: keeps app + each node's address/entities, drops the in-process `node`. */\nfunction toDeploymentSummary(result) {\n\treturn {\n\t\tapp: result.app,\n\t\tnodes: result.nodes.map((node) => ({\n\t\t\taddress: node.address,\n\t\t\tentities: node.entities\n\t\t}))\n\t};\n}\n/**\n* Writer half, called by the report hook inside the alchemy child: when the\n* env var names a file, write the summary there. Best-effort — a write\n* failure must not fail a deploy that already converged, so it is swallowed.\n*/\nfunction writeDeploymentSummaryFile(result) {\n\tconst file = process.env[DEPLOYMENT_RESULT_FILE_ENV];\n\tif (file === void 0 || file.length === 0) return;\n\ttry {\n\t\tfs.writeFileSync(file, JSON.stringify(toDeploymentSummary(result)));\n\t} catch {}\n}\nfunction isRecord(value) {\n\treturn typeof value === \"object\" && value !== null;\n}\n/**\n* Reader half, run by the deploy operation after the child exits. Absent or\n* malformed → undefined — the summary is best-effort, never a deploy failure.\n*/\nfunction readDeploymentSummary(resultFilePath) {\n\tlet raw;\n\ttry {\n\t\traw = fs.readFileSync(resultFilePath, \"utf8\");\n\t} catch {\n\t\treturn;\n\t}\n\tlet parsed;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch {\n\t\treturn;\n\t}\n\tif (!isRecord(parsed) || typeof parsed[\"app\"] !== \"string\" || !Array.isArray(parsed[\"nodes\"])) return;\n\tfor (const node of parsed[\"nodes\"]) {\n\t\tif (!isRecord(node) || typeof node[\"address\"] !== \"string\" || !Array.isArray(node[\"entities\"])) return;\n\t\tfor (const entity of node[\"entities\"]) if (!isRecord(entity) || typeof entity[\"kind\"] !== \"string\" || typeof entity[\"id\"] !== \"string\") return;\n\t}\n\treturn blindCast(parsed);\n}\n//#endregion\nexport { readDeploymentSummary as n, writeDeploymentSummaryFile as r, DEPLOYMENT_RESULT_FILE_ENV as t };\n\n//# sourceMappingURL=deployment-summary-DswOl_9E.mjs.map"],"mappings":";;;;;;;;;;;;;;;;AAgBA,MAAM,6BAA6B;;AAEnC,SAAS,oBAAoB,QAAQ;CACpC,OAAO;EACN,KAAK,OAAO;EACZ,OAAO,OAAO,MAAM,KAAK,UAAU;GAClC,SAAS,KAAK;GACd,UAAU,KAAK;EAChB,EAAE;CACH;AACD;;;;;;AAMA,SAAS,2BAA2B,QAAQ;CAC3C,MAAM,OAAO,QAAQ,IAAI;CACzB,IAAI,SAAS,KAAK,KAAK,KAAK,WAAW,GAAG;CAC1C,IAAI;EACH,KAAG,cAAc,MAAM,KAAK,UAAU,oBAAoB,MAAM,CAAC,CAAC;CACnE,QAAQ,CAAC;AACV;AACA,SAAS,SAAS,OAAO;CACxB,OAAO,OAAO,UAAU,YAAY,UAAU;AAC/C;;;;;AAKA,SAAS,sBAAsB,gBAAgB;CAC9C,IAAI;CACJ,IAAI;EACH,MAAMA,KAAG,aAAa,gBAAgB,MAAM;CAC7C,QAAQ;EACP;CACD;CACA,IAAI;CACJ,IAAI;EACH,SAAS,KAAK,MAAM,GAAG;CACxB,QAAQ;EACP;CACD;CACA,IAAI,CAAC,SAAS,MAAM,KAAK,OAAO,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,OAAO,QAAQ,GAAG;CAC/F,KAAK,MAAM,QAAQ,OAAO,UAAU;EACnC,IAAI,CAAC,SAAS,IAAI,KAAK,OAAO,KAAK,eAAe,YAAY,CAAC,MAAM,QAAQ,KAAK,WAAW,GAAG;EAChG,KAAK,MAAM,UAAU,KAAK,aAAa,IAAI,CAAC,SAAS,MAAM,KAAK,OAAO,OAAO,YAAY,YAAY,OAAO,OAAO,UAAU,UAAU;CACzI;CACA,OAAO,UAAU,MAAM;AACxB"}