@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.9 → 3.9.3-ultramodern.1

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 (275) hide show
  1. package/README.md +23 -0
  2. package/dist/cjs/backend-federation-build/codegen.js +29 -18
  3. package/dist/cjs/backend-federation-build/config.js +84 -45
  4. package/dist/cjs/backend-federation-build/emit.js +63 -22
  5. package/dist/cjs/build-config/build-environment.js +25 -162
  6. package/dist/cjs/build-config/internal-effect-discovery.js +143 -0
  7. package/dist/cjs/build-config/public.js +2 -5
  8. package/dist/cjs/build-config/remote-address.js +58 -0
  9. package/dist/cjs/cloudflare/artifacts.js +8 -19
  10. package/dist/cjs/cloudflare/delivery-unit.js +125 -43
  11. package/dist/cjs/cloudflare/index.js +14 -4
  12. package/dist/cjs/cloudflare/native-renderer.js +100 -0
  13. package/dist/cjs/cloudflare/renderer-identity.js +106 -0
  14. package/dist/cjs/cloudflare/worker-manifest.js +54 -13
  15. package/dist/cjs/cloudflare/worker-options.js +48 -0
  16. package/dist/cjs/cloudflare/wrangler-config.js +210 -13
  17. package/dist/cjs/cloudflare-builder.js +307 -89
  18. package/dist/cjs/cloudflare-output-contract.js +36 -4
  19. package/dist/cjs/cloudflare-output-verifier/identity.js +112 -23
  20. package/dist/cjs/cloudflare-output-verifier/index.js +10 -0
  21. package/dist/cjs/cloudflare-output-verifier/manifest.js +46 -0
  22. package/dist/cjs/cloudflare-output-verifier/mutation-policy.js +7 -1
  23. package/dist/cjs/cloudflare-output-verifier/worker-bundles.js +10 -5
  24. package/dist/cjs/config.js +10 -5
  25. package/dist/cjs/deploy-output/npmAliases.js +92 -6
  26. package/dist/cjs/deploy-output/plugin.js +27 -6
  27. package/dist/cjs/deploy-output/public-assets.js +146 -0
  28. package/dist/cjs/deploy-output/target.js +57 -1
  29. package/dist/cjs/deploy-output/trace-files.js +99 -0
  30. package/dist/cjs/module-federation-config/exposes.js +70 -0
  31. package/dist/cjs/module-federation-config/index.js +73 -0
  32. package/dist/cjs/module-federation-config/inspect.js +103 -0
  33. package/dist/cjs/module-federation-config/object-literal.js +87 -0
  34. package/dist/cjs/module-federation-config/syntax.js +151 -0
  35. package/dist/cjs/module-federation-config/types.js +18 -0
  36. package/dist/cjs/native-type-checker.js +130 -13
  37. package/dist/cjs/policy-defaults.js +38 -29
  38. package/dist/cjs/release-envelope/canonical.js +2 -9
  39. package/dist/cjs/release-envelope/contract.js +68 -0
  40. package/dist/cjs/release-envelope/framework-output.js +296 -105
  41. package/dist/cjs/release-envelope/index.js +150 -36
  42. package/dist/cjs/release-envelope/plugin.js +24 -15
  43. package/dist/cjs/release-envelope/renderer-output-stamp.js +170 -0
  44. package/dist/cjs/release-envelope/types.js +10 -8
  45. package/dist/cjs/release-identity.js +8 -5
  46. package/dist/cjs/renderer-build-identity.js +134 -0
  47. package/dist/cjs/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
  48. package/dist/cjs/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
  49. package/dist/cjs/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
  50. package/dist/cjs/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
  51. package/dist/cjs/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
  52. package/dist/cjs/templates/cloudflare-worker-route-data.mjs +1069 -0
  53. package/dist/cjs/workspace-topology.js +84 -0
  54. package/dist/esm/backend-federation-build/codegen.mjs +29 -18
  55. package/dist/esm/backend-federation-build/config.mjs +74 -38
  56. package/dist/esm/backend-federation-build/emit.mjs +64 -23
  57. package/dist/esm/build-config/build-environment.mjs +26 -160
  58. package/dist/esm/build-config/internal-effect-discovery.mjs +102 -0
  59. package/dist/esm/build-config/public.mjs +1 -1
  60. package/dist/esm/build-config/remote-address.mjs +20 -0
  61. package/dist/esm/cloudflare/artifacts.mjs +8 -19
  62. package/dist/esm/cloudflare/delivery-unit.mjs +124 -45
  63. package/dist/esm/cloudflare/index.mjs +15 -5
  64. package/dist/esm/cloudflare/native-renderer.mjs +48 -0
  65. package/dist/esm/cloudflare/renderer-identity.mjs +57 -0
  66. package/dist/esm/cloudflare/worker-manifest.mjs +55 -14
  67. package/dist/esm/cloudflare/worker-options.mjs +10 -0
  68. package/dist/esm/cloudflare/wrangler-config.mjs +203 -12
  69. package/dist/esm/cloudflare-builder.mjs +301 -89
  70. package/dist/esm/cloudflare-output-contract.mjs +29 -3
  71. package/dist/esm/cloudflare-output-verifier/identity.mjs +113 -24
  72. package/dist/esm/cloudflare-output-verifier/index.mjs +10 -0
  73. package/dist/esm/cloudflare-output-verifier/manifest.mjs +46 -0
  74. package/dist/esm/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  75. package/dist/esm/cloudflare-output-verifier/worker-bundles.mjs +11 -6
  76. package/dist/esm/config.mjs +3 -1
  77. package/dist/esm/deploy-output/npmAliases.mjs +92 -6
  78. package/dist/esm/deploy-output/plugin.mjs +24 -6
  79. package/dist/esm/deploy-output/public-assets.mjs +82 -0
  80. package/dist/esm/deploy-output/target.mjs +50 -3
  81. package/dist/esm/deploy-output/trace-files.mjs +47 -0
  82. package/dist/esm/module-federation-config/exposes.mjs +18 -0
  83. package/dist/esm/module-federation-config/index.mjs +4 -0
  84. package/dist/esm/module-federation-config/inspect.mjs +65 -0
  85. package/dist/esm/module-federation-config/object-literal.mjs +43 -0
  86. package/dist/esm/module-federation-config/syntax.mjs +101 -0
  87. package/dist/esm/module-federation-config/types.mjs +0 -0
  88. package/dist/esm/native-type-checker.mjs +124 -13
  89. package/dist/esm/policy-defaults.mjs +36 -30
  90. package/dist/esm/release-envelope/canonical.mjs +2 -9
  91. package/dist/esm/release-envelope/contract.mjs +21 -0
  92. package/dist/esm/release-envelope/framework-output.mjs +297 -106
  93. package/dist/esm/release-envelope/index.mjs +149 -38
  94. package/dist/esm/release-envelope/plugin.mjs +24 -15
  95. package/dist/esm/release-envelope/renderer-output-stamp.mjs +112 -0
  96. package/dist/esm/release-envelope/types.mjs +2 -3
  97. package/dist/esm/release-identity.mjs +8 -5
  98. package/dist/esm/renderer-build-identity.mjs +82 -0
  99. package/dist/esm/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
  100. package/dist/esm/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
  101. package/dist/esm/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
  102. package/dist/esm/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
  103. package/dist/esm/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
  104. package/dist/esm/templates/cloudflare-worker-route-data.mjs +1069 -0
  105. package/dist/esm/workspace-topology.mjs +21 -0
  106. package/dist/esm-node/backend-federation-build/codegen.mjs +29 -18
  107. package/dist/esm-node/backend-federation-build/config.mjs +74 -38
  108. package/dist/esm-node/backend-federation-build/emit.mjs +64 -23
  109. package/dist/esm-node/build-config/build-environment.mjs +26 -160
  110. package/dist/esm-node/build-config/internal-effect-discovery.mjs +103 -0
  111. package/dist/esm-node/build-config/public.mjs +1 -1
  112. package/dist/esm-node/build-config/remote-address.mjs +21 -0
  113. package/dist/esm-node/cloudflare/artifacts.mjs +8 -19
  114. package/dist/esm-node/cloudflare/delivery-unit.mjs +124 -45
  115. package/dist/esm-node/cloudflare/index.mjs +15 -5
  116. package/dist/esm-node/cloudflare/native-renderer.mjs +49 -0
  117. package/dist/esm-node/cloudflare/renderer-identity.mjs +58 -0
  118. package/dist/esm-node/cloudflare/worker-manifest.mjs +55 -14
  119. package/dist/esm-node/cloudflare/worker-options.mjs +11 -0
  120. package/dist/esm-node/cloudflare/wrangler-config.mjs +203 -12
  121. package/dist/esm-node/cloudflare-builder.mjs +301 -89
  122. package/dist/esm-node/cloudflare-output-contract.mjs +29 -3
  123. package/dist/esm-node/cloudflare-output-verifier/identity.mjs +113 -24
  124. package/dist/esm-node/cloudflare-output-verifier/index.mjs +10 -0
  125. package/dist/esm-node/cloudflare-output-verifier/manifest.mjs +46 -0
  126. package/dist/esm-node/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  127. package/dist/esm-node/cloudflare-output-verifier/worker-bundles.mjs +11 -6
  128. package/dist/esm-node/config.mjs +3 -1
  129. package/dist/esm-node/deploy-output/npmAliases.mjs +92 -6
  130. package/dist/esm-node/deploy-output/plugin.mjs +24 -6
  131. package/dist/esm-node/deploy-output/public-assets.mjs +83 -0
  132. package/dist/esm-node/deploy-output/target.mjs +50 -3
  133. package/dist/esm-node/deploy-output/trace-files.mjs +48 -0
  134. package/dist/esm-node/module-federation-config/exposes.mjs +19 -0
  135. package/dist/esm-node/module-federation-config/index.mjs +5 -0
  136. package/dist/esm-node/module-federation-config/inspect.mjs +66 -0
  137. package/dist/esm-node/module-federation-config/object-literal.mjs +44 -0
  138. package/dist/esm-node/module-federation-config/syntax.mjs +102 -0
  139. package/dist/esm-node/module-federation-config/types.mjs +1 -0
  140. package/dist/esm-node/native-type-checker.mjs +124 -13
  141. package/dist/esm-node/policy-defaults.mjs +36 -30
  142. package/dist/esm-node/release-envelope/canonical.mjs +2 -9
  143. package/dist/esm-node/release-envelope/contract.mjs +22 -0
  144. package/dist/esm-node/release-envelope/framework-output.mjs +297 -106
  145. package/dist/esm-node/release-envelope/index.mjs +149 -38
  146. package/dist/esm-node/release-envelope/plugin.mjs +24 -15
  147. package/dist/esm-node/release-envelope/renderer-output-stamp.mjs +113 -0
  148. package/dist/esm-node/release-envelope/types.mjs +2 -3
  149. package/dist/esm-node/release-identity.mjs +8 -5
  150. package/dist/esm-node/renderer-build-identity.mjs +83 -0
  151. package/dist/esm-node/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
  152. package/dist/esm-node/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
  153. package/dist/esm-node/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
  154. package/dist/esm-node/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
  155. package/dist/esm-node/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
  156. package/dist/esm-node/templates/cloudflare-worker-route-data.mjs +1069 -0
  157. package/dist/esm-node/workspace-topology.mjs +22 -0
  158. package/dist/types/backend-federation-build/codegen.d.ts +30 -0
  159. package/dist/types/backend-federation-build/config.d.ts +10 -57
  160. package/dist/types/backend-federation-build/emit.d.ts +12 -2
  161. package/dist/types/backend-federation-build/index.d.ts +1 -1
  162. package/dist/types/build-config/build-environment.d.ts +1 -9
  163. package/dist/types/build-config/internal-effect-discovery.d.ts +4 -0
  164. package/dist/types/build-config/public.d.ts +1 -1
  165. package/dist/types/build-config/remote-address.d.ts +3 -0
  166. package/dist/types/cloudflare/artifacts.d.ts +7 -6
  167. package/dist/types/cloudflare/constants.d.ts +1 -1
  168. package/dist/types/cloudflare/delivery-unit.d.ts +38 -7
  169. package/dist/types/cloudflare/native-renderer.d.ts +30 -0
  170. package/dist/types/cloudflare/renderer-identity.d.ts +25 -0
  171. package/dist/types/cloudflare/worker-manifest.d.ts +17 -2
  172. package/dist/types/cloudflare/worker-options.d.ts +20 -0
  173. package/dist/types/cloudflare/wrangler-config.d.ts +55 -2
  174. package/dist/types/cloudflare-builder.d.ts +51 -8
  175. package/dist/types/cloudflare-output-contract.d.ts +5 -3
  176. package/dist/types/cloudflare-output-verifier/identity.d.ts +7 -3
  177. package/dist/types/cloudflare-output-verifier/worker-bundles.d.ts +2 -2
  178. package/dist/types/config.d.ts +98 -13
  179. package/dist/types/deploy-output/plugin.d.ts +29 -9
  180. package/dist/types/deploy-output/public-assets.d.ts +51 -0
  181. package/dist/types/deploy-output/target.d.ts +28 -5
  182. package/dist/types/deploy-output/trace-files.d.ts +17 -0
  183. package/dist/types/module-federation-config/exposes.d.ts +11 -0
  184. package/dist/types/module-federation-config/index.d.ts +5 -0
  185. package/dist/types/module-federation-config/inspect.d.ts +2 -0
  186. package/dist/types/module-federation-config/object-literal.d.ts +4 -0
  187. package/dist/types/module-federation-config/syntax.d.ts +7 -0
  188. package/dist/types/module-federation-config/types.d.ts +20 -0
  189. package/dist/types/native-type-checker.d.ts +26 -3
  190. package/dist/types/policy-defaults.d.ts +12 -2
  191. package/dist/types/release-envelope/canonical.d.ts +5 -5
  192. package/dist/types/release-envelope/contract.d.mts +8 -0
  193. package/dist/types/release-envelope/framework-output.d.ts +23 -13
  194. package/dist/types/release-envelope/index.d.ts +17 -5
  195. package/dist/types/release-envelope/plugin.d.ts +10 -6
  196. package/dist/types/release-envelope/renderer-output-stamp.d.ts +34 -0
  197. package/dist/types/release-envelope/types.d.ts +42 -4
  198. package/dist/types/release-identity.d.ts +3 -2
  199. package/dist/types/renderer-build-identity.d.ts +30 -0
  200. package/dist/types/templates/cloudflare-worker-route-data.d.mts +14 -0
  201. package/dist/types/workspace-topology.d.ts +91 -0
  202. package/package.json +87 -27
  203. package/src/backend-federation-build/codegen.ts +28 -19
  204. package/src/backend-federation-build/config.ts +189 -123
  205. package/src/backend-federation-build/emit.ts +119 -38
  206. package/src/backend-federation-build/index.ts +4 -1
  207. package/src/build-config/build-environment.ts +59 -285
  208. package/src/build-config/internal-effect-discovery.ts +239 -0
  209. package/src/build-config/public.ts +0 -1
  210. package/src/build-config/remote-address.ts +33 -0
  211. package/src/cloudflare/artifacts.ts +22 -43
  212. package/src/cloudflare/delivery-unit.ts +283 -60
  213. package/src/cloudflare/index.ts +35 -19
  214. package/src/cloudflare/native-renderer.ts +117 -0
  215. package/src/cloudflare/renderer-identity.ts +171 -0
  216. package/src/cloudflare/worker-manifest.ts +108 -10
  217. package/src/cloudflare/worker-options.ts +60 -0
  218. package/src/cloudflare/wrangler-config.ts +390 -14
  219. package/src/cloudflare-builder.ts +543 -170
  220. package/src/cloudflare-output-contract.ts +45 -2
  221. package/src/cloudflare-output-verifier/identity.ts +138 -7
  222. package/src/cloudflare-output-verifier/index.ts +20 -0
  223. package/src/cloudflare-output-verifier/manifest.ts +77 -0
  224. package/src/cloudflare-output-verifier/mutation-policy.ts +11 -1
  225. package/src/cloudflare-output-verifier/worker-bundles.ts +27 -11
  226. package/src/config.ts +101 -19
  227. package/src/deploy-output/npmAliases.ts +141 -4
  228. package/src/deploy-output/plugin.ts +55 -18
  229. package/src/deploy-output/public-assets.ts +224 -0
  230. package/src/deploy-output/target.ts +97 -14
  231. package/src/deploy-output/trace-files.ts +80 -0
  232. package/src/module-federation-config/exposes.ts +46 -0
  233. package/src/module-federation-config/index.ts +22 -0
  234. package/src/module-federation-config/inspect.ts +157 -0
  235. package/src/module-federation-config/object-literal.ts +76 -0
  236. package/src/module-federation-config/syntax.ts +212 -0
  237. package/src/module-federation-config/types.ts +22 -0
  238. package/src/native-type-checker.ts +233 -20
  239. package/src/policy-defaults.ts +47 -17
  240. package/src/release-envelope/canonical.ts +6 -18
  241. package/src/release-envelope/contract.mjs +28 -0
  242. package/src/release-envelope/framework-output.ts +681 -156
  243. package/src/release-envelope/index.ts +315 -60
  244. package/src/release-envelope/plugin.ts +54 -38
  245. package/src/release-envelope/renderer-output-stamp.ts +210 -0
  246. package/src/release-envelope/types.ts +75 -6
  247. package/src/release-identity.ts +19 -2
  248. package/src/renderer-build-identity.ts +168 -0
  249. package/src/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
  250. package/src/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
  251. package/src/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
  252. package/src/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
  253. package/src/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
  254. package/src/templates/cloudflare-worker-route-data.mjs +1069 -0
  255. package/src/workspace-topology.ts +125 -0
  256. package/dist/cjs/templates/cloudflare-worker-fs-promises.mjs +0 -11
  257. package/dist/cjs/templates/cloudflare-worker-loadable-server.mjs +0 -281
  258. package/dist/cjs/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  259. package/dist/cjs/templates/cloudflare-worker-path.mjs +0 -98
  260. package/dist/esm/templates/cloudflare-worker-fs-promises.mjs +0 -11
  261. package/dist/esm/templates/cloudflare-worker-loadable-server.mjs +0 -281
  262. package/dist/esm/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  263. package/dist/esm/templates/cloudflare-worker-path.mjs +0 -98
  264. package/dist/esm-node/templates/cloudflare-worker-fs-promises.mjs +0 -11
  265. package/dist/esm-node/templates/cloudflare-worker-loadable-server.mjs +0 -281
  266. package/dist/esm-node/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  267. package/dist/esm-node/templates/cloudflare-worker-path.mjs +0 -98
  268. package/dist/types/templates/cloudflare-worker-fs-promises.d.mts +0 -5
  269. package/dist/types/templates/cloudflare-worker-loadable-server.d.mts +0 -48
  270. package/dist/types/templates/cloudflare-worker-mf-ssr-runtime-plugin.d.mts +0 -13
  271. package/dist/types/templates/cloudflare-worker-path.d.mts +0 -21
  272. package/src/templates/cloudflare-worker-fs-promises.mjs +0 -11
  273. package/src/templates/cloudflare-worker-loadable-server.mjs +0 -281
  274. package/src/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  275. package/src/templates/cloudflare-worker-path.mjs +0 -98
@@ -53,14 +53,34 @@ const promises_namespaceObject = require("node:fs/promises");
53
53
  var promises_default = /*#__PURE__*/ __webpack_require__.n(promises_namespaceObject);
54
54
  const external_node_path_namespaceObject = require("node:path");
55
55
  var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
56
+ const external_node_util_namespaceObject = require("node:util");
56
57
  const backend_federation_contracts_namespaceObject = require("@modern-js/backend-federation-contracts");
58
+ const config_js_namespaceObject = require("../backend-federation-build/config.js");
59
+ const delivery_unit_js_namespaceObject = require("../cloudflare/delivery-unit.js");
57
60
  const external_index_js_namespaceObject = require("./index.js");
61
+ const external_types_js_namespaceObject = require("./types.js");
58
62
  const MICROVERTICAL_RELEASE_ENVELOPE_PATH = 'release/microvertical-release-envelope.json';
59
63
  const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH = 'release/microvertical-release-identity-carriers.json';
60
64
  const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_KIND = 'ultramodern-release-identity-carriers';
61
65
  const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_SCHEMA_VERSION = 1;
62
66
  const COMPILED_MODULE_PATTERN = /\.(?:c|m)?js$/u;
63
67
  const EFFECT_BFF_WORKER_PATTERN = /^worker\/__modern_bff_effect\.(?:c|m)?js$/u;
68
+ const EFFECT_BFF_WORKER_SUPPORT_PATTERN = /^worker\/__modern_worker_(?:runtime|shared)_*\.(?:c|m)?js$/u;
69
+ const isEffectBffWorkerArtifact = (logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath) || EFFECT_BFF_WORKER_SUPPORT_PATTERN.test(logicalPath);
70
+ const effectBffWorkerArtifacts = (files)=>files.some((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath)) ? files.filter(isEffectBffWorkerArtifact) : [];
71
+ const CRAWLER_POLICY_PATH = 'public/robots.txt';
72
+ const isPublicMetadataPath = (logicalPath)=>'public/_headers' === logicalPath || /^public\/\.well-known\/[^/]+\.json$/u.test(logicalPath);
73
+ const PUBLIC_BUILD_ARTIFACT_PATH = `public/${backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE}`;
74
+ const DECLARED_PUBLIC_ASSET_RUNTIME = 'public-asset';
75
+ const resolveDeclaredPublicAssets = (files, declaredPublicAssets, target)=>{
76
+ const staged = new Set(files);
77
+ const declared = new Set();
78
+ for (const logicalPath of declaredPublicAssets){
79
+ if (!logicalPath.startsWith('public/') || !staged.has(logicalPath)) throw new Error(`[ultramodern-release-envelope] final ${target} staging has no declared public asset file ${JSON.stringify(logicalPath)}.`);
80
+ declared.add(logicalPath);
81
+ }
82
+ return declared;
83
+ };
64
84
  const isRecord = (value)=>'object' == typeof value && null !== value && !Array.isArray(value);
65
85
  const flattenStrings = (value)=>'string' == typeof value ? [
66
86
  value
@@ -74,7 +94,12 @@ const collectNestedStrings = (value, key)=>{
74
94
  ]);
75
95
  };
76
96
  const emptyProducerRouteModules = async (distDirectory, files, manifest, manifestLogicalPath)=>{
77
- if (!isRecord(manifest) || !Array.isArray(manifest.exposes) || 0 !== manifest.exposes.length || !Array.isArray(manifest.remotes) || 0 !== manifest.remotes.length || !isRecord(manifest.metaData) || !isRecord(manifest.metaData.remoteEntry) || '' !== manifest.metaData.remoteEntry.name || '' !== manifest.metaData.remoteEntry.path || 'global' !== manifest.metaData.remoteEntry.type) return [];
97
+ if (!isRecord(manifest) || !Array.isArray(manifest.exposes) || 0 !== manifest.exposes.length || !Array.isArray(manifest.remotes) || manifest.remotes.some((remote)=>!isRecord(remote) || [
98
+ 'federationContainerName',
99
+ 'moduleName',
100
+ 'alias',
101
+ 'entry'
102
+ ].some((key)=>'string' != typeof remote[key] || 0 === remote[key].trim().length)) || !isRecord(manifest.metaData) || !isRecord(manifest.metaData.remoteEntry) || '' !== manifest.metaData.remoteEntry.name || '' !== manifest.metaData.remoteEntry.path || 'global' !== manifest.metaData.remoteEntry.type) return [];
78
103
  const publicPath = manifest.metaData.publicPath;
79
104
  const safeReference = (value)=>'string' == typeof value && value.length > 0 && !/[\\\\%?#\s]/u.test(value) && !value.split('/').some((segment)=>'.' === segment || '..' === segment);
80
105
  if (!safeReference(publicPath)) return [];
@@ -175,11 +200,14 @@ const writeReleaseEnvelope = async (artifactRoot, envelope)=>{
175
200
  if (!envelopePath) throw new Error('[ultramodern-release-envelope] could not resolve release envelope path.');
176
201
  await promises_default().writeFile(envelopePath, `${(0, external_index_js_namespaceObject.canonicalSerializeMicroVerticalReleaseEnvelope)(envelope)}\n`);
177
202
  };
178
- const readBuildArtifact = async (distDirectory)=>{
203
+ const readBuildArtifact = async (distDirectory, requirePromotable = true)=>{
179
204
  const artifactPath = external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE);
180
205
  const artifact = await readJson(artifactPath);
181
206
  if (!(0, backend_federation_contracts_namespaceObject.isUltramodernBuildArtifact)(artifact)) throw new Error(`[ultramodern-release-envelope] ${backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE} is missing or invalid.`);
182
- if ('workspace' === artifact.deliveryUnit.sourceRevision) throw new Error('[ultramodern-release-envelope] sourceRevision "workspace" cannot produce a promotable full-stack envelope.');
207
+ if ('workspace' === artifact.deliveryUnit.sourceRevision) {
208
+ if (!requirePromotable) return;
209
+ throw new Error('[ultramodern-release-envelope] sourceRevision "workspace" cannot produce a promotable envelope.');
210
+ }
183
211
  return artifact;
184
212
  };
185
213
  const assertIdentityBlock = (value, identity, location, includeReleaseVersion)=>{
@@ -248,7 +276,7 @@ const releaseArtifact = (logicalPath, runtime)=>({
248
276
  const writeReleaseIdentityCarrierMetadata = async (artifactRoot, identity, carrierPaths)=>{
249
277
  const surfacesByPath = new Map();
250
278
  for (const [surface, logicalPaths] of Object.entries(carrierPaths)){
251
- if (0 === logicalPaths.length) throw new Error(`[ultramodern-release-envelope] ${surface} has no declared release-identity carrier artifact.`);
279
+ if (0 === logicalPaths.length && 'ssr' !== surface && 'uiClient' !== surface) throw new Error(`[ultramodern-release-envelope] ${surface} has no declared release-identity carrier artifact.`);
252
280
  for (const logicalPath of logicalPaths){
253
281
  const surfaces = surfacesByPath.get(logicalPath) ?? new Set();
254
282
  surfaces.add(surface);
@@ -288,12 +316,14 @@ const writeReleaseIdentityCarrierMetadata = async (artifactRoot, identity, carri
288
316
  }, null, 2)}\n`);
289
317
  return releaseArtifact(MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH, 'release-identity-metadata');
290
318
  };
291
- const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
319
+ const createReleaseArtifactInputs = async (distDirectory, identity, target, apiOnly, uiOnly, shellConsumer)=>{
320
+ const backendProducer = !uiOnly && !shellConsumer;
292
321
  const files = await collectFiles(distDirectory);
293
- if ('node' === target && files.some((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath))) throw new Error('[ultramodern-release-envelope] Node target conflicts with a Cloudflare Effect API/BFF worker artifact; resolve the canonical deploy target instead of emitting a Node envelope for Cloudflare output.');
322
+ const effectWorkerPaths = effectBffWorkerArtifacts(files);
323
+ if ('node' === target && files.some(isEffectBffWorkerArtifact)) throw new Error('[ultramodern-release-envelope] Node target conflicts with a Cloudflare Effect API/BFF worker artifact; resolve the canonical deploy target instead of emitting a Node envelope for Cloudflare output.');
294
324
  const uiClientPaths = files.filter((logicalPath)=>{
295
325
  const topLevel = logicalPath.split('/')[0];
296
- return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel || [
326
+ return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel && logicalPath !== CRAWLER_POLICY_PATH && logicalPath !== PUBLIC_BUILD_ARTIFACT_PATH && !isPublicMetadataPath(logicalPath) || [
297
327
  'index.html',
298
328
  'mf-manifest.json',
299
329
  'mf-stats.json',
@@ -302,16 +332,19 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
302
332
  'loadable-stats.json'
303
333
  ].includes(logicalPath);
304
334
  });
305
- const ssrPaths = 'node' === target ? files.filter((logicalPath)=>logicalPath.startsWith('bundles/') && COMPILED_MODULE_PATTERN.test(logicalPath)) : files.filter((logicalPath)=>logicalPath.startsWith('worker/') && COMPILED_MODULE_PATTERN.test(logicalPath) && !EFFECT_BFF_WORKER_PATTERN.test(logicalPath));
335
+ const ssrPaths = 'node' === target ? files.filter((logicalPath)=>logicalPath.startsWith('bundles/') && COMPILED_MODULE_PATTERN.test(logicalPath)) : files.filter((logicalPath)=>logicalPath.startsWith('worker/') && COMPILED_MODULE_PATTERN.test(logicalPath) && !effectWorkerPaths.includes(logicalPath));
306
336
  const nodeApiEntryPaths = files.filter((logicalPath)=>logicalPath.startsWith('api/') && COMPILED_MODULE_PATTERN.test(logicalPath));
307
- const apiBackendPaths = 'node' === target ? files.filter((logicalPath)=>(logicalPath.startsWith('api/') || logicalPath.startsWith('shared/')) && COMPILED_MODULE_PATTERN.test(logicalPath)) : files.filter((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath));
308
- if (0 === uiClientPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no UI/client artifacts.`);
309
- if (0 === ssrPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no ${'node' === target ? 'Node' : 'workerd'} SSR artifacts.`);
310
- if ('node' === target && 0 === nodeApiEntryPaths.length || 0 === apiBackendPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no actual ${'node' === target ? 'compiled Node Effect API artifact' : 'Effect API/BFF worker artifact'}.`);
311
- const clientExecutionPaths = await manifestReferencedClientModules(distDirectory, files);
312
- if (0 === clientExecutionPaths.length) throw new Error('[ultramodern-release-envelope] UI/client manifest references no compiled execution module.');
313
- const ssrExecutionPaths = await routeReferencedSsrModules(distDirectory, files, target);
314
- if (0 === ssrExecutionPaths.length) throw new Error(`[ultramodern-release-envelope] route manifest references no emitted ${'node' === target ? 'Node' : 'Cloudflare'} SSR execution module.`);
337
+ const apiBackendPaths = 'node' === target ? files.filter((logicalPath)=>(logicalPath.startsWith('api/') || logicalPath.startsWith('shared/')) && COMPILED_MODULE_PATTERN.test(logicalPath)) : effectWorkerPaths;
338
+ if (backendProducer && 'cloudflare' === target && 0 === effectWorkerPaths.length) throw new Error('[ultramodern-release-envelope] cloudflare MicroVertical has no actual Effect API/BFF worker artifact.');
339
+ if (apiOnly && (uiClientPaths.length > 0 || ssrPaths.length > 0)) throw new Error('[ultramodern-release-envelope] API-only MicroVertical emitted an undeclared UI/client or SSR surface.');
340
+ if (!apiOnly && 0 === uiClientPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no UI/client artifacts.`);
341
+ if (!apiOnly && 0 === ssrPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no ${'node' === target ? 'Node' : 'workerd'} SSR artifacts.`);
342
+ if (uiOnly && (apiBackendPaths.length > 0 || nodeApiEntryPaths.length > 0)) throw new Error('[ultramodern-release-envelope] UI-only application emitted an undeclared API/backend artifact.');
343
+ if (backendProducer && ('node' === target && 0 === nodeApiEntryPaths.length || 0 === apiBackendPaths.length)) throw new Error(`[ultramodern-release-envelope] ${target} MicroVertical has no actual ${'node' === target ? 'compiled Node Effect API artifact' : 'Effect API/BFF worker artifact'}.`);
344
+ const clientExecutionPaths = apiOnly ? [] : await manifestReferencedClientModules(distDirectory, files);
345
+ if (!apiOnly && 0 === clientExecutionPaths.length) throw new Error('[ultramodern-release-envelope] UI/client manifest references no compiled execution module.');
346
+ const ssrExecutionPaths = apiOnly ? [] : await routeReferencedSsrModules(distDirectory, files, target);
347
+ if (!apiOnly && 0 === ssrExecutionPaths.length) throw new Error(`[ultramodern-release-envelope] route manifest references no emitted ${'node' === target ? 'Node' : 'Cloudflare'} SSR execution module.`);
315
348
  const runtimeByPath = new Map();
316
349
  const add = (paths, runtime)=>{
317
350
  for (const logicalPath of paths){
@@ -321,14 +354,25 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
321
354
  }
322
355
  };
323
356
  add(uiClientPaths, 'browser');
357
+ add(files.filter((logicalPath)=>logicalPath === CRAWLER_POLICY_PATH), 'crawler-policy');
358
+ add(files.filter(isPublicMetadataPath), 'public-metadata');
324
359
  add(ssrPaths, 'node' === target ? 'nodejs' : 'workerd');
325
360
  add(apiBackendPaths, 'node' === target ? 'nodejs' : 'workerd-effect');
326
361
  add([
327
- backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE
328
- ], 'module-federation-manifest');
329
- add([
330
- backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
331
- ], 'node' === target ? 'nodejs' : 'commonjs-module');
362
+ backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE
363
+ ], 'release-identity-metadata');
364
+ add(files.filter((logicalPath)=>logicalPath === PUBLIC_BUILD_ARTIFACT_PATH), 'release-identity-metadata');
365
+ if (backendProducer) {
366
+ add([
367
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE
368
+ ], 'module-federation-manifest');
369
+ add([
370
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
371
+ ], 'node' === target ? 'nodejs' : 'commonjs-module');
372
+ }
373
+ if (shellConsumer) {
374
+ for (const logicalPath of files)if (!runtimeByPath.has(logicalPath)) runtimeByPath.set(logicalPath, `${target}-deployment`);
375
+ }
332
376
  const surfaces = {
333
377
  uiClient: [
334
378
  ...uiClientPaths
@@ -339,20 +383,26 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
339
383
  apiBackend: [
340
384
  ...apiBackendPaths
341
385
  ].sort((left, right)=>left.localeCompare(right)),
342
- backendFederation: {
343
- manifest: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
344
- container: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
345
- }
386
+ ...backendProducer ? {
387
+ backendFederation: {
388
+ manifest: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
389
+ container: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
390
+ }
391
+ } : {}
346
392
  };
347
393
  const artifacts = [
348
394
  ...runtimeByPath
349
395
  ].map(([logicalPath, runtime])=>releaseArtifact(logicalPath, runtime)).sort((left, right)=>left.logicalPath.localeCompare(right.logicalPath));
350
396
  const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(distDirectory, identity, {
351
- apiBackend: apiBackendPaths,
352
- backendFederation: [
353
- backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
354
- backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
355
- ],
397
+ ...apiBackendPaths.length > 0 ? {
398
+ apiBackend: apiBackendPaths
399
+ } : {},
400
+ ...backendProducer ? {
401
+ backendFederation: [
402
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
403
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
404
+ ]
405
+ } : {},
356
406
  ssr: [
357
407
  ...new Set([
358
408
  ...ssrExecutionPaths,
@@ -369,6 +419,25 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
369
419
  surfaces
370
420
  };
371
421
  };
422
+ const releaseEnvelopeSurfaces = (surfaces, shellConsumer)=>{
423
+ if (!shellConsumer) return {
424
+ surfaces
425
+ };
426
+ const { uiClient, ssr, apiBackend } = surfaces;
427
+ return {
428
+ kind: external_types_js_namespaceObject.SHELL_RELEASE_ENVELOPE_KIND,
429
+ surfaces: {
430
+ uiClient,
431
+ ssr,
432
+ apiBackend
433
+ }
434
+ };
435
+ };
436
+ const assertShellBuildIdentity = async (appDirectory, distDirectory)=>{
437
+ const source = await (0, config_js_namespaceObject.readBuildIdentity)(appDirectory);
438
+ const finalized = await pathExists(external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE)) ? await (0, delivery_unit_js_namespaceObject.resolveWorkerDeliveryUnitStamp)(appDirectory, distDirectory) : void 0;
439
+ if (!source.artifact || !finalized || finalized.unitId !== source.unitId) throw new Error('[ultramodern-release-envelope] Shell is missing its native compiled delivery-unit identity.');
440
+ };
372
441
  const pathExists = async (filePath)=>{
373
442
  try {
374
443
  await promises_default().access(filePath);
@@ -377,36 +446,79 @@ const pathExists = async (filePath)=>{
377
446
  return false;
378
447
  }
379
448
  };
380
- const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, distDirectory, target })=>{
381
- if (apiOnly) return;
449
+ const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, appDirectory, distDirectory, requirePromotable = true, expectedRendererProfile, role, target })=>{
450
+ const declaredRole = appDirectory ? await (0, delivery_unit_js_namespaceObject.resolveTopologyReleaseRole)(appDirectory) : void 0;
451
+ if (void 0 !== role && void 0 !== declaredRole && role !== declaredRole) throw new Error('[ultramodern-release-envelope] Configured release role disagrees with the declared topology app.');
452
+ const shellConsumer = (declaredRole ?? role ?? 'microvertical') === 'shell';
382
453
  const backendManifestPath = external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE);
383
454
  const backendContainerPath = external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE);
384
455
  const [hasBackendManifest, hasBackendContainer] = await Promise.all([
385
456
  pathExists(backendManifestPath),
386
457
  pathExists(backendContainerPath)
387
458
  ]);
388
- if (!hasBackendManifest && !hasBackendContainer) return;
389
- if (!hasBackendManifest || !hasBackendContainer) throw new Error('[ultramodern-release-envelope] full-stack MicroVertical backend federation manifest and container must be emitted together.');
390
- const buildArtifact = await readBuildArtifact(distDirectory);
459
+ if (shellConsumer) {
460
+ if (apiOnly || hasBackendManifest || hasBackendContainer || !appDirectory) throw new Error('[ultramodern-release-envelope] Shell requires a full-stack application source and cannot declare a backend federation producer.');
461
+ await assertShellBuildIdentity(appDirectory, distDirectory);
462
+ } else if (!apiOnly && !hasBackendManifest && !hasBackendContainer) {
463
+ const source = appDirectory ? external_node_path_default().join(appDirectory, backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_PATH) : void 0;
464
+ const participationPaths = [
465
+ external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE),
466
+ backendManifestPath,
467
+ backendContainerPath,
468
+ ...source ? [
469
+ source,
470
+ source.replace(/\.json$/u, '.ts')
471
+ ] : []
472
+ ];
473
+ const hasParticipationEntry = (await Promise.all(participationPaths.map(async (filePath)=>{
474
+ try {
475
+ await promises_default().lstat(filePath);
476
+ return true;
477
+ } catch (error) {
478
+ if (isMissingPathError(error)) return false;
479
+ throw error;
480
+ }
481
+ }))).some(Boolean);
482
+ if (!hasParticipationEntry && (!appDirectory || !await (0, delivery_unit_js_namespaceObject.resolveTopologyDeliveryUnit)(appDirectory))) return;
483
+ }
484
+ const buildArtifact = await readBuildArtifact(distDirectory, requirePromotable);
485
+ const declared = appDirectory && buildArtifact ? await (0, delivery_unit_js_namespaceObject.resolveWorkerDeliveryUnitStamp)(appDirectory, distDirectory) : void 0;
486
+ const uiOnly = Boolean(declared?.surfaces.ui && !declared.surfaces.api);
487
+ if (uiOnly && (apiOnly || hasBackendManifest || hasBackendContainer)) throw new Error('[ultramodern-release-envelope] UI-only application cannot declare API-only configuration or backend federation output.');
488
+ if (!hasBackendManifest && !hasBackendContainer && !apiOnly && !buildArtifact) return;
489
+ if (!shellConsumer && !uiOnly && (!hasBackendManifest || !hasBackendContainer)) throw new Error('[ultramodern-release-envelope] MicroVertical backend federation manifest and container must be emitted together.');
490
+ if (!buildArtifact) return;
491
+ const builtUi = buildArtifact.surfaces.ui;
492
+ if (Boolean(builtUi) === apiOnly) throw new Error('[ultramodern-release-envelope] build artifact UI surface must match the configured application surface.');
493
+ if (void 0 !== expectedRendererProfile) (0, backend_federation_contracts_namespaceObject.assertRendererProfileCompatibility)(expectedRendererProfile, builtUi?.rendererProfile);
494
+ const ui = builtUi ? {
495
+ rendererIdentity: builtUi.rendererIdentity,
496
+ rendererProfile: builtUi.rendererProfile,
497
+ routerBindings: builtUi.routerBindings
498
+ } : void 0;
391
499
  const identity = {
392
500
  unitId: buildArtifact.deliveryUnit.unitId,
393
501
  buildMarker: buildArtifact.deliveryUnit.buildMarker,
394
502
  sourceRevision: buildArtifact.deliveryUnit.sourceRevision,
395
503
  releaseVersion: buildArtifact.deliveryUnit.version
396
504
  };
397
- await readBackendManifest(distDirectory, identity);
398
- const { artifacts, surfaces } = await createReleaseArtifactInputs(distDirectory, identity, target);
505
+ if (!shellConsumer && !uiOnly) await readBackendManifest(distDirectory, identity);
506
+ const { artifacts, surfaces } = await createReleaseArtifactInputs(distDirectory, identity, target, apiOnly, uiOnly, shellConsumer);
399
507
  const envelope = await (0, external_index_js_namespaceObject.createMicroVerticalReleaseEnvelope)({
400
508
  artifactRoot: distDirectory,
401
509
  target,
402
510
  identity,
511
+ ...ui ? {
512
+ ui
513
+ } : {},
403
514
  artifacts,
404
- surfaces
515
+ ...releaseEnvelopeSurfaces(surfaces, shellConsumer)
405
516
  });
517
+ await verifyBuildArtifactCarriers(distDirectory, envelope);
406
518
  await writeReleaseEnvelope(distDirectory, envelope);
407
519
  return envelope;
408
520
  };
409
- const readFrameworkMicroVerticalReleaseEnvelope = async ({ artifactRoot, expectedTarget, logicalPathForArtifact, required = false })=>{
521
+ const readFrameworkMicroVerticalReleaseEnvelope = async ({ artifactRoot, expectedTarget, logicalPathForArtifact, expectedRendererProfile, required = false })=>{
410
522
  const envelopePath = await resolveSafeReleaseEnvelopePath({
411
523
  artifactRoot,
412
524
  createDirectory: false
@@ -415,30 +527,55 @@ const readFrameworkMicroVerticalReleaseEnvelope = async ({ artifactRoot, expecte
415
527
  if (required) throw new Error(`[ultramodern-release-envelope] required envelope is missing at ${MICROVERTICAL_RELEASE_ENVELOPE_PATH}.`);
416
528
  return;
417
529
  }
418
- return (0, external_index_js_namespaceObject.verifyMicroVerticalReleaseEnvelope)(await readJson(envelopePath), {
530
+ const envelope = await (0, external_index_js_namespaceObject.verifyMicroVerticalReleaseEnvelope)(await readJson(envelopePath), {
419
531
  artifactRoot,
420
532
  ...expectedTarget ? {
421
533
  expectedTarget
422
534
  } : {},
423
535
  ...logicalPathForArtifact ? {
424
536
  logicalPathForArtifact
537
+ } : {},
538
+ ...expectedRendererProfile ? {
539
+ expectedRendererProfile
425
540
  } : {}
426
541
  });
542
+ await verifyBuildArtifactCarriers(artifactRoot, envelope, logicalPathForArtifact);
543
+ return envelope;
544
+ };
545
+ const verifyBuildArtifactCarriers = async (artifactRoot, envelope, logicalPathForArtifact)=>{
546
+ const carriers = envelope.artifacts.filter((artifact)=>artifact.logicalPath === backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE || artifact.logicalPath === PUBLIC_BUILD_ARTIFACT_PATH);
547
+ if (0 === carriers.length) throw new Error('[ultramodern-release-envelope] immutable build artifact must be bound to the release envelope.');
548
+ for (const artifact of carriers){
549
+ if ('file' !== artifact.kind || 'release-identity-metadata' !== artifact.runtime) throw new Error('[ultramodern-release-envelope] immutable build artifact must be a real file with runtime "release-identity-metadata".');
550
+ const logicalPath = logicalPathForArtifact?.(artifact) ?? artifact.logicalPath;
551
+ const built = await readJson(external_node_path_default().join(artifactRoot, logicalPath));
552
+ if (!(0, backend_federation_contracts_namespaceObject.isUltramodernBuildArtifact)(built)) throw new Error('[ultramodern-release-envelope] bound build artifact is invalid.');
553
+ assertIdentityBlock(built.deliveryUnit, envelope.identity, 'buildArtifact.deliveryUnit', true);
554
+ if (Boolean(built.surfaces.ui) !== Boolean(envelope.ui)) throw new Error('[ultramodern-release-envelope] bound build artifact UI surface differs from the release envelope.');
555
+ if (envelope.ui && built.surfaces.ui) {
556
+ if (!(0, external_node_util_namespaceObject.isDeepStrictEqual)(envelope.ui.routerBindings, built.surfaces.ui.routerBindings)) throw new Error('[ultramodern-release-envelope] buildArtifact.ui.routerBindings differ from the release envelope.');
557
+ (0, backend_federation_contracts_namespaceObject.assertRendererProfileCompatibility)(envelope.ui.rendererProfile, built.surfaces.ui.rendererProfile);
558
+ for (const field of [
559
+ 'renderer',
560
+ 'protocolVersion',
561
+ 'appId',
562
+ 'entryName',
563
+ 'buildId'
564
+ ])if (envelope.ui.rendererIdentity[field] !== built.surfaces.ui.rendererIdentity[field]) throw new Error(`[ultramodern-release-envelope] buildArtifact.ui.rendererIdentity.${field} differs from the release envelope.`);
565
+ }
566
+ }
427
567
  };
428
568
  const verifyBuildOutputReleaseEnvelope = async (distDirectory, expectedTarget)=>{
429
- const [hasEnvelope, hasBuildArtifact, hasBackendManifest, hasBackendEntry] = await Promise.all([
569
+ const [hasEnvelope, hasBuildArtifact] = await Promise.all([
430
570
  pathExists(external_node_path_default().join(distDirectory, MICROVERTICAL_RELEASE_ENVELOPE_PATH)),
431
- pathExists(external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE)),
432
- pathExists(external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE)),
433
- pathExists(external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE))
571
+ pathExists(external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE))
434
572
  ]);
435
- const isFullStackMicroVertical = hasBuildArtifact && (hasBackendManifest || hasBackendEntry);
436
573
  return readFrameworkMicroVerticalReleaseEnvelope({
437
574
  artifactRoot: distDirectory,
438
575
  ...expectedTarget ? {
439
576
  expectedTarget
440
577
  } : {},
441
- required: hasEnvelope || isFullStackMicroVertical
578
+ required: hasEnvelope || hasBuildArtifact
442
579
  });
443
580
  };
444
581
  const verifyNodeReleaseEnvelopeStaging = async ({ outputDirectory })=>readFrameworkMicroVerticalReleaseEnvelope({
@@ -446,21 +583,26 @@ const verifyNodeReleaseEnvelopeStaging = async ({ outputDirectory })=>readFramew
446
583
  expectedTarget: 'node',
447
584
  required: true
448
585
  });
449
- const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=>{
586
+ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity, apiOnly, uiOnly, declaredPublicAssets, shellConsumer)=>{
587
+ const backendProducer = !uiOnly && !shellConsumer;
450
588
  const files = await collectFiles(outputDirectory);
589
+ const declaredPublicAssetPaths = resolveDeclaredPublicAssets(files, declaredPublicAssets, 'Node');
451
590
  for (const requiredPath of [
452
591
  'index.js',
453
592
  'package.json',
454
- backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
455
- backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
593
+ ...backendProducer ? [
594
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
595
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
596
+ ] : []
456
597
  ])if (!files.includes(requiredPath)) throw new Error(`[ultramodern-release-envelope] final Node staging is missing ${requiredPath}.`);
457
598
  const backendFederationPaths = new Set([
458
599
  backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
459
600
  backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
460
601
  ]);
602
+ if (shellConsumer && files.some((logicalPath)=>backendFederationPaths.has(logicalPath))) throw new Error('[ultramodern-release-envelope] final Shell Node staging cannot contain a backend federation producer artifact.');
461
603
  const uiClientPaths = files.filter((logicalPath)=>{
462
604
  const topLevel = logicalPath.split('/')[0];
463
- return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel || [
605
+ return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel && logicalPath !== CRAWLER_POLICY_PATH && logicalPath !== PUBLIC_BUILD_ARTIFACT_PATH && !isPublicMetadataPath(logicalPath) && !declaredPublicAssetPaths.has(logicalPath) || [
464
606
  'index.html',
465
607
  'mf-manifest.json',
466
608
  'mf-stats.json',
@@ -471,6 +613,8 @@ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=
471
613
  });
472
614
  const ssrPaths = files.filter((logicalPath)=>'index.js' === logicalPath || logicalPath.startsWith('bundles/') && COMPILED_MODULE_PATTERN.test(logicalPath));
473
615
  const apiBackendPaths = files.filter((logicalPath)=>(logicalPath.startsWith('api/') || logicalPath.startsWith('shared/')) && COMPILED_MODULE_PATTERN.test(logicalPath));
616
+ if (uiOnly && (apiBackendPaths.length > 0 || files.some((logicalPath)=>backendFederationPaths.has(logicalPath)))) throw new Error('[ultramodern-release-envelope] final UI-only Node staging contains an undeclared API/backend or backend federation artifact.');
617
+ if (apiOnly && (uiClientPaths.length > 0 || ssrPaths.some((path)=>'index.js' !== path))) throw new Error('[ultramodern-release-envelope] final API-only Node staging contains an undeclared UI/client or SSR surface.');
474
618
  for (const [surface, paths] of [
475
619
  [
476
620
  'UI/client',
@@ -478,32 +622,45 @@ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=
478
622
  ],
479
623
  [
480
624
  'Node SSR',
481
- ssrPaths
625
+ apiOnly ? [] : ssrPaths
482
626
  ],
483
627
  [
484
628
  'Node API/backend',
485
629
  apiBackendPaths
486
630
  ]
487
- ])if (0 === paths.length) throw new Error(`[ultramodern-release-envelope] final Node staging has no ${surface} artifacts.`);
488
- const clientExecutionPaths = await manifestReferencedClientModules(outputDirectory, files);
489
- const ssrExecutionPaths = await routeReferencedSsrModules(outputDirectory, files, 'node');
490
- if (0 === clientExecutionPaths.length || 0 === ssrExecutionPaths.length) throw new Error('[ultramodern-release-envelope] final Node manifests must reference emitted UI/client and SSR execution modules.');
631
+ ])if (0 === paths.length && ('Node API/backend' === surface ? backendProducer : !apiOnly)) throw new Error(`[ultramodern-release-envelope] final Node staging has no ${surface} artifacts.`);
632
+ const clientExecutionPaths = apiOnly ? [] : await manifestReferencedClientModules(outputDirectory, files);
633
+ const ssrExecutionPaths = apiOnly ? [] : await routeReferencedSsrModules(outputDirectory, files, 'node');
634
+ if (!apiOnly && (0 === clientExecutionPaths.length || 0 === ssrExecutionPaths.length)) throw new Error('[ultramodern-release-envelope] final Node manifests must reference emitted UI/client and SSR execution modules.');
491
635
  const runtimeByPath = new Map(files.filter((logicalPath)=>!backendFederationPaths.has(logicalPath)).map((logicalPath)=>[
492
636
  logicalPath,
493
637
  'nodejs-deployment'
494
638
  ]));
495
639
  for (const logicalPath of uiClientPaths)runtimeByPath.set(logicalPath, 'browser');
496
- for (const logicalPath of ssrPaths)runtimeByPath.set(logicalPath, 'nodejs');
640
+ for (const logicalPath of declaredPublicAssetPaths)runtimeByPath.set(logicalPath, DECLARED_PUBLIC_ASSET_RUNTIME);
641
+ if (files.includes(CRAWLER_POLICY_PATH)) runtimeByPath.set(CRAWLER_POLICY_PATH, 'crawler-policy');
642
+ for (const logicalPath of files.filter(isPublicMetadataPath))runtimeByPath.set(logicalPath, 'public-metadata');
643
+ for (const logicalPath of apiOnly ? [] : ssrPaths)runtimeByPath.set(logicalPath, 'nodejs');
497
644
  for (const logicalPath of apiBackendPaths)runtimeByPath.set(logicalPath, 'nodejs');
498
- runtimeByPath.set(backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE, 'module-federation-manifest');
499
- runtimeByPath.set(backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE, 'nodejs');
645
+ if (backendProducer) {
646
+ runtimeByPath.set(backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE, 'module-federation-manifest');
647
+ runtimeByPath.set(backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE, 'nodejs');
648
+ }
649
+ for (const logicalPath of [
650
+ backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE,
651
+ PUBLIC_BUILD_ARTIFACT_PATH
652
+ ])if (files.includes(logicalPath)) runtimeByPath.set(logicalPath, 'release-identity-metadata');
500
653
  const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(outputDirectory, identity, {
501
- apiBackend: apiBackendPaths,
502
- backendFederation: [
503
- backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
504
- backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
505
- ],
506
- ssr: [
654
+ ...apiBackendPaths.length > 0 ? {
655
+ apiBackend: apiBackendPaths
656
+ } : {},
657
+ ...backendProducer ? {
658
+ backendFederation: [
659
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
660
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
661
+ ]
662
+ } : {},
663
+ ssr: apiOnly ? [] : [
507
664
  ...new Set([
508
665
  ...ssrExecutionPaths,
509
666
  ...ssrPaths.filter((logicalPath)=>'index.js' !== logicalPath)
@@ -522,30 +679,37 @@ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=
522
679
  uiClient: [
523
680
  ...uiClientPaths
524
681
  ].sort((left, right)=>left.localeCompare(right)),
525
- ssr: [
682
+ ssr: apiOnly ? [] : [
526
683
  ...ssrPaths
527
684
  ].sort((left, right)=>left.localeCompare(right)),
528
685
  apiBackend: [
529
686
  ...apiBackendPaths
530
687
  ].sort((left, right)=>left.localeCompare(right)),
531
- backendFederation: {
532
- manifest: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
533
- container: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
534
- }
688
+ ...backendProducer ? {
689
+ backendFederation: {
690
+ manifest: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
691
+ container: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
692
+ }
693
+ } : {}
535
694
  }
536
695
  };
537
696
  };
538
- const emitNodeStagedReleaseEnvelope = async ({ distDirectory, outputDirectory })=>{
697
+ const emitNodeStagedReleaseEnvelope = async ({ declaredPublicAssets = [], distDirectory, outputDirectory })=>{
539
698
  const source = await verifyBuildOutputReleaseEnvelope(distDirectory, 'node');
540
699
  if (!source) return;
541
- const { artifacts, surfaces } = await createNodeStagedReleaseArtifactInputs(outputDirectory, source.identity);
700
+ const shellConsumer = source.kind === external_types_js_namespaceObject.SHELL_RELEASE_ENVELOPE_KIND;
701
+ const { artifacts, surfaces } = await createNodeStagedReleaseArtifactInputs(outputDirectory, source.identity, 0 === source.surfaces.uiClient.length, 0 === source.surfaces.apiBackend.length, declaredPublicAssets, shellConsumer);
542
702
  const staged = await (0, external_index_js_namespaceObject.createMicroVerticalReleaseEnvelope)({
543
703
  artifactRoot: outputDirectory,
544
704
  target: 'node',
545
705
  identity: source.identity,
706
+ ...source.ui ? {
707
+ ui: source.ui
708
+ } : {},
546
709
  artifacts,
547
- surfaces
710
+ ...releaseEnvelopeSurfaces(surfaces, shellConsumer)
548
711
  });
712
+ await verifyBuildArtifactCarriers(outputDirectory, staged);
549
713
  await writeReleaseEnvelope(outputDirectory, staged);
550
714
  return staged;
551
715
  };
@@ -556,21 +720,29 @@ const stageCloudflareReleaseEnvelope = async ({ distDirectory, outputDirectory }
556
720
  if (await pathExists(stagedEnvelopePath)) throw new Error('[ultramodern-release-envelope] Cloudflare staging contains a stale envelope before final output generation.');
557
721
  return source;
558
722
  };
559
- const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, identity)=>{
723
+ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, identity, apiOnly, uiOnly, declaredPublicAssets, shellConsumer)=>{
724
+ const backendProducer = !uiOnly && !shellConsumer;
560
725
  const files = await collectFiles(outputDirectory);
726
+ const declaredPublicAssetPaths = resolveDeclaredPublicAssets(files, declaredPublicAssets, 'Cloudflare');
561
727
  for (const requiredPath of [
562
728
  'server/index.mjs',
563
729
  'server/modern-worker-manifest.json',
564
730
  'wrangler.json',
565
731
  'package.json',
566
- 'worker/package.json'
732
+ ...apiOnly ? [] : [
733
+ 'worker/package.json'
734
+ ]
567
735
  ])if (!files.includes(requiredPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${requiredPath}.`);
568
736
  if (files.some((logicalPath)=>'public/release' === logicalPath || logicalPath.startsWith('public/release/'))) throw new Error('[ultramodern-release-envelope] final Cloudflare envelope must remain private and cannot be staged under public/release.');
569
737
  const backendManifestPath = `public/${backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE}`;
570
738
  const backendContainerPath = `public/${backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE}`;
571
- const apiBackendPaths = files.filter((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath));
572
- const ssrPaths = files.filter((logicalPath)=>(logicalPath.startsWith('server/') || logicalPath.startsWith('worker/')) && COMPILED_MODULE_PATTERN.test(logicalPath) && !EFFECT_BFF_WORKER_PATTERN.test(logicalPath));
573
- const uiClientPaths = files.filter((logicalPath)=>logicalPath.startsWith('public/') && logicalPath !== backendManifestPath && logicalPath !== backendContainerPath);
739
+ const apiBackendPaths = effectBffWorkerArtifacts(files);
740
+ if (backendProducer && !files.some((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath))) throw new Error('[ultramodern-release-envelope] final Cloudflare staging has no actual Effect API/BFF worker artifact.');
741
+ const ssrPaths = files.filter((logicalPath)=>(logicalPath.startsWith('server/') || logicalPath.startsWith('worker/')) && COMPILED_MODULE_PATTERN.test(logicalPath) && !apiBackendPaths.includes(logicalPath));
742
+ const uiClientPaths = files.filter((logicalPath)=>logicalPath.startsWith('public/') && logicalPath !== CRAWLER_POLICY_PATH && !isPublicMetadataPath(logicalPath) && !declaredPublicAssetPaths.has(logicalPath) && logicalPath !== PUBLIC_BUILD_ARTIFACT_PATH && logicalPath !== backendManifestPath && logicalPath !== backendContainerPath);
743
+ if (shellConsumer && files.some((logicalPath)=>logicalPath === backendManifestPath || logicalPath === backendContainerPath)) throw new Error('[ultramodern-release-envelope] final Shell Cloudflare staging cannot contain a backend federation producer artifact.');
744
+ if (uiOnly && (apiBackendPaths.length > 0 || files.some((logicalPath)=>logicalPath === backendManifestPath || logicalPath === backendContainerPath || logicalPath.startsWith('api/') && COMPILED_MODULE_PATTERN.test(logicalPath)))) throw new Error('[ultramodern-release-envelope] final UI-only Cloudflare staging contains an undeclared API/backend or backend federation artifact.');
745
+ if (apiOnly && (uiClientPaths.length > 0 || ssrPaths.some((path)=>'server/index.mjs' !== path))) throw new Error('[ultramodern-release-envelope] final API-only Cloudflare staging contains an undeclared UI/client or SSR surface.');
574
746
  for (const [surface, paths] of [
575
747
  [
576
748
  'UI/client',
@@ -578,41 +750,53 @@ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, iden
578
750
  ],
579
751
  [
580
752
  'Cloudflare SSR',
581
- ssrPaths
753
+ apiOnly ? [] : ssrPaths
582
754
  ],
583
755
  [
584
756
  'Cloudflare API/backend',
585
757
  apiBackendPaths
586
758
  ]
587
- ])if (0 === paths.length) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging has no ${surface} artifacts.`);
588
- for (const logicalPath of [
759
+ ])if (0 === paths.length && ('Cloudflare API/backend' === surface ? backendProducer : !apiOnly)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging has no ${surface} artifacts.`);
760
+ for (const logicalPath of backendProducer ? [
589
761
  backendManifestPath,
590
762
  backendContainerPath
591
- ])if (!files.includes(logicalPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${logicalPath}.`);
592
- const clientExecutionPaths = await manifestReferencedClientModules(outputDirectory, files, 'public/mf-manifest.json');
593
- const ssrExecutionPaths = await routeReferencedSsrModules(outputDirectory, files, 'cloudflare', 'server/route.json');
594
- if (0 === clientExecutionPaths.length || 0 === ssrExecutionPaths.length) throw new Error('[ultramodern-release-envelope] final Cloudflare manifests must reference emitted UI/client and SSR execution modules.');
763
+ ] : [])if (!files.includes(logicalPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${logicalPath}.`);
764
+ const clientExecutionPaths = apiOnly ? [] : await manifestReferencedClientModules(outputDirectory, files, 'public/mf-manifest.json');
765
+ const ssrExecutionPaths = apiOnly ? [] : await routeReferencedSsrModules(outputDirectory, files, 'cloudflare', 'server/route.json');
766
+ if (!apiOnly && (0 === clientExecutionPaths.length || 0 === ssrExecutionPaths.length)) throw new Error('[ultramodern-release-envelope] final Cloudflare manifests must reference emitted UI/client and SSR execution modules.');
595
767
  const runtimeByPath = new Map();
596
768
  for (const logicalPath of files)runtimeByPath.set(logicalPath, 'cloudflare-deployment');
597
769
  const add = (paths, runtime)=>{
598
770
  for (const logicalPath of paths)runtimeByPath.set(logicalPath, runtime);
599
771
  };
600
772
  add(uiClientPaths, 'browser');
601
- add(ssrPaths, 'workerd');
602
- add(apiBackendPaths, 'workerd-effect');
603
773
  add([
604
- backendManifestPath
605
- ], 'module-federation-manifest');
606
- add([
607
- backendContainerPath
608
- ], 'commonjs-module');
609
- const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(outputDirectory, identity, {
610
- apiBackend: apiBackendPaths,
611
- backendFederation: [
612
- backendManifestPath,
774
+ ...declaredPublicAssetPaths
775
+ ], DECLARED_PUBLIC_ASSET_RUNTIME);
776
+ if (files.includes(CRAWLER_POLICY_PATH)) runtimeByPath.set(CRAWLER_POLICY_PATH, 'crawler-policy');
777
+ add(files.filter(isPublicMetadataPath), 'public-metadata');
778
+ add(apiOnly ? [] : ssrPaths, 'workerd');
779
+ add(apiBackendPaths, 'workerd-effect');
780
+ if (backendProducer) {
781
+ add([
782
+ backendManifestPath
783
+ ], 'module-federation-manifest');
784
+ add([
613
785
  backendContainerPath
614
- ],
615
- ssr: [
786
+ ], 'commonjs-module');
787
+ }
788
+ add(files.filter((logicalPath)=>logicalPath === backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE || logicalPath === PUBLIC_BUILD_ARTIFACT_PATH), 'release-identity-metadata');
789
+ const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(outputDirectory, identity, {
790
+ ...apiBackendPaths.length > 0 ? {
791
+ apiBackend: apiBackendPaths
792
+ } : {},
793
+ ...backendProducer ? {
794
+ backendFederation: [
795
+ backendManifestPath,
796
+ backendContainerPath
797
+ ]
798
+ } : {},
799
+ ssr: apiOnly ? [] : [
616
800
  ...new Set([
617
801
  ...ssrExecutionPaths,
618
802
  ...ssrPaths.filter((logicalPath)=>logicalPath.startsWith('worker/'))
@@ -631,30 +815,37 @@ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, iden
631
815
  uiClient: [
632
816
  ...uiClientPaths
633
817
  ].sort((left, right)=>left.localeCompare(right)),
634
- ssr: [
818
+ ssr: apiOnly ? [] : [
635
819
  ...ssrPaths
636
820
  ].sort((left, right)=>left.localeCompare(right)),
637
821
  apiBackend: [
638
822
  ...apiBackendPaths
639
823
  ].sort((left, right)=>left.localeCompare(right)),
640
- backendFederation: {
641
- manifest: backendManifestPath,
642
- container: backendContainerPath
643
- }
824
+ ...backendProducer ? {
825
+ backendFederation: {
826
+ manifest: backendManifestPath,
827
+ container: backendContainerPath
828
+ }
829
+ } : {}
644
830
  }
645
831
  };
646
832
  };
647
- const emitCloudflareStagedReleaseEnvelope = async ({ distDirectory, outputDirectory })=>{
833
+ const emitCloudflareStagedReleaseEnvelope = async ({ declaredPublicAssets = [], distDirectory, outputDirectory })=>{
648
834
  const source = await verifyBuildOutputReleaseEnvelope(distDirectory, 'cloudflare');
649
835
  if (!source) return;
650
- const { artifacts, surfaces } = await createCloudflareStagedReleaseArtifactInputs(outputDirectory, source.identity);
836
+ const shellConsumer = source.kind === external_types_js_namespaceObject.SHELL_RELEASE_ENVELOPE_KIND;
837
+ const { artifacts, surfaces } = await createCloudflareStagedReleaseArtifactInputs(outputDirectory, source.identity, 0 === source.surfaces.uiClient.length, 0 === source.surfaces.apiBackend.length, declaredPublicAssets, shellConsumer);
651
838
  const staged = await (0, external_index_js_namespaceObject.createMicroVerticalReleaseEnvelope)({
652
839
  artifactRoot: outputDirectory,
653
840
  target: 'cloudflare',
654
841
  identity: source.identity,
842
+ ...source.ui ? {
843
+ ui: source.ui
844
+ } : {},
655
845
  artifacts,
656
- surfaces
846
+ ...releaseEnvelopeSurfaces(surfaces, shellConsumer)
657
847
  });
848
+ await verifyBuildArtifactCarriers(outputDirectory, staged);
658
849
  await writeReleaseEnvelope(outputDirectory, staged);
659
850
  return staged;
660
851
  };