@bleedingdev/modern-js-app-tools 3.8.2-ultramodern.9 → 3.8.3-ultramodern.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 (242) hide show
  1. package/bin/modern-bundle-docs.js +11 -0
  2. package/bin/modern.js +11 -0
  3. package/dist/cjs/builder/generator/getBuilderEnvironments.js +13 -241
  4. package/dist/cjs/builder/generator/index.js +0 -1
  5. package/dist/cjs/builder/shared/builderPlugins/adapterSSR.js +37 -9
  6. package/dist/cjs/builder/shared/builderPlugins/index.js +6 -13
  7. package/dist/cjs/builder/shared/bundlerPlugins/index.js +6 -13
  8. package/dist/cjs/builder/shared/lazyCompilation.js +9 -9
  9. package/dist/cjs/bundleDocs.js +1 -1
  10. package/dist/cjs/index.js +59 -60
  11. package/dist/cjs/plugins/analyze/getServerRoutes.js +1 -1
  12. package/dist/cjs/plugins/analyze/isDefaultExportFunction.js +1 -9
  13. package/dist/cjs/plugins/backend-federation/codegen.js +2 -1
  14. package/dist/cjs/plugins/backend-federation/config.js +2 -2
  15. package/dist/cjs/plugins/backend-federation/emit.js +6 -4
  16. package/dist/cjs/plugins/deploy/index.js +4 -4
  17. package/dist/cjs/plugins/deploy/platforms/cloudflare-output-verifier/index.js +23 -149
  18. package/dist/cjs/plugins/deploy/platforms/templates/netlify-entry.cjs +41 -62
  19. package/dist/cjs/plugins/deploy/platforms/templates/netlify-entry.mjs +41 -63
  20. package/dist/cjs/plugins/deploy/platforms/templates/node-entry.cjs +35 -52
  21. package/dist/cjs/plugins/deploy/platforms/templates/node-entry.mjs +35 -53
  22. package/dist/cjs/plugins/deploy/platforms/templates/vercel-entry.cjs +41 -61
  23. package/dist/cjs/plugins/deploy/platforms/templates/vercel-entry.mjs +40 -61
  24. package/dist/cjs/plugins/ultramodernReleaseEnvelope.js +3 -59
  25. package/dist/cjs/presetUltramodern.js +15 -8
  26. package/dist/cjs/run/index.js +9 -9
  27. package/dist/cjs/utils/env.js +1 -1
  28. package/dist/cjs/utils/register.js +6 -3
  29. package/dist/esm/builder/generator/getBuilderEnvironments.mjs +12 -231
  30. package/dist/esm/builder/generator/index.mjs +1 -2
  31. package/dist/esm/builder/shared/builderPlugins/adapterSSR.mjs +34 -9
  32. package/dist/esm/builder/shared/builderPlugins/index.mjs +0 -1
  33. package/dist/esm/builder/shared/bundlerPlugins/index.mjs +0 -1
  34. package/dist/esm/builder/shared/lazyCompilation.mjs +4 -4
  35. package/dist/esm/bundleDocs.mjs +1 -1
  36. package/dist/esm/index.mjs +3 -3
  37. package/dist/esm/plugins/analyze/getServerRoutes.mjs +1 -1
  38. package/dist/esm/plugins/analyze/isDefaultExportFunction.mjs +1 -9
  39. package/dist/esm/plugins/backend-federation/codegen.mjs +2 -1
  40. package/dist/esm/plugins/backend-federation/config.mjs +1 -1
  41. package/dist/esm/plugins/backend-federation/emit.mjs +5 -3
  42. package/dist/esm/plugins/deploy/index.mjs +1 -1
  43. package/dist/esm/plugins/deploy/platforms/cloudflare-output-verifier/index.mjs +1 -133
  44. package/dist/esm/plugins/deploy/platforms/templates/netlify-entry.cjs +41 -62
  45. package/dist/esm/plugins/deploy/platforms/templates/netlify-entry.mjs +41 -63
  46. package/dist/esm/plugins/deploy/platforms/templates/node-entry.cjs +35 -52
  47. package/dist/esm/plugins/deploy/platforms/templates/node-entry.mjs +35 -53
  48. package/dist/esm/plugins/deploy/platforms/templates/vercel-entry.cjs +41 -61
  49. package/dist/esm/plugins/deploy/platforms/templates/vercel-entry.mjs +40 -61
  50. package/dist/esm/plugins/ultramodernReleaseEnvelope.mjs +3 -49
  51. package/dist/esm/presetUltramodern.mjs +8 -5
  52. package/dist/esm/run/index.mjs +9 -9
  53. package/dist/esm/utils/env.mjs +1 -1
  54. package/dist/esm/utils/register.mjs +6 -3
  55. package/dist/esm-node/builder/generator/getBuilderEnvironments.mjs +12 -234
  56. package/dist/esm-node/builder/generator/index.mjs +1 -2
  57. package/dist/esm-node/builder/shared/builderPlugins/adapterSSR.mjs +34 -9
  58. package/dist/esm-node/builder/shared/builderPlugins/index.mjs +0 -1
  59. package/dist/esm-node/builder/shared/bundlerPlugins/index.mjs +0 -1
  60. package/dist/esm-node/builder/shared/lazyCompilation.mjs +4 -4
  61. package/dist/esm-node/bundleDocs.mjs +1 -1
  62. package/dist/esm-node/index.mjs +3 -3
  63. package/dist/esm-node/plugins/analyze/getServerRoutes.mjs +1 -1
  64. package/dist/esm-node/plugins/analyze/isDefaultExportFunction.mjs +1 -9
  65. package/dist/esm-node/plugins/backend-federation/codegen.mjs +2 -1
  66. package/dist/esm-node/plugins/backend-federation/config.mjs +1 -1
  67. package/dist/esm-node/plugins/backend-federation/emit.mjs +5 -3
  68. package/dist/esm-node/plugins/deploy/index.mjs +1 -1
  69. package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-verifier/index.mjs +1 -133
  70. package/dist/esm-node/plugins/deploy/platforms/templates/netlify-entry.cjs +41 -62
  71. package/dist/esm-node/plugins/deploy/platforms/templates/netlify-entry.mjs +41 -63
  72. package/dist/esm-node/plugins/deploy/platforms/templates/node-entry.cjs +35 -52
  73. package/dist/esm-node/plugins/deploy/platforms/templates/node-entry.mjs +35 -53
  74. package/dist/esm-node/plugins/deploy/platforms/templates/vercel-entry.cjs +41 -61
  75. package/dist/esm-node/plugins/deploy/platforms/templates/vercel-entry.mjs +40 -61
  76. package/dist/esm-node/plugins/ultramodernReleaseEnvelope.mjs +3 -49
  77. package/dist/esm-node/presetUltramodern.mjs +8 -5
  78. package/dist/esm-node/run/index.mjs +9 -9
  79. package/dist/esm-node/utils/env.mjs +1 -1
  80. package/dist/esm-node/utils/register.mjs +6 -3
  81. package/dist/types/builder/generator/getBuilderEnvironments.d.ts +0 -29
  82. package/dist/types/builder/shared/builderPlugins/adapterSSR.d.ts +11 -0
  83. package/dist/types/builder/shared/builderPlugins/index.d.ts +0 -1
  84. package/dist/types/builder/shared/bundlerPlugins/index.d.ts +0 -1
  85. package/dist/types/builder/shared/lazyCompilation.d.ts +7 -7
  86. package/dist/types/plugins/analyze/getServerRoutes.d.ts +1 -1
  87. package/dist/types/plugins/backend-federation/codegen.d.ts +4 -1
  88. package/dist/types/plugins/deploy/platforms/cloudflare-output-verifier/index.d.ts +1 -18
  89. package/dist/types/presetUltramodern.d.ts +23 -2
  90. package/dist/types/types/config/deploy.d.ts +2 -2
  91. package/docs/community/showcase.md +3 -5
  92. package/docs/configure/app/bff/effect.md +7 -7
  93. package/docs/guides/advanced-features/bff/frameworks.md +1 -1
  94. package/docs/guides/basic-features/deploy.md +2 -2
  95. package/docs/guides/get-started/quick-start.md +10 -9
  96. package/docs/guides/get-started/tech-stack.md +1 -1
  97. package/docs/guides/get-started/ultramodern.md +123 -38
  98. package/docs/guides/troubleshooting/cli.md +1 -1
  99. package/docs/llms.txt +2 -2
  100. package/docs/tutorials/examples/csr-auth.md +1 -1
  101. package/package.json +16 -28
  102. package/rslib.config.mts +4 -7
  103. package/dist/cjs/builder/shared/builderPlugins/adapterLazyCompilation.js +0 -74
  104. package/dist/cjs/builder/shared/bundlerPlugins/CssExtractRuntimePlugin.js +0 -72
  105. package/dist/cjs/plugins/deploy/platforms/cloudflare/artifacts.js +0 -127
  106. package/dist/cjs/plugins/deploy/platforms/cloudflare/constants.js +0 -141
  107. package/dist/cjs/plugins/deploy/platforms/cloudflare/delivery-unit.js +0 -139
  108. package/dist/cjs/plugins/deploy/platforms/cloudflare/i18n-worker.js +0 -135
  109. package/dist/cjs/plugins/deploy/platforms/cloudflare/index.js +0 -150
  110. package/dist/cjs/plugins/deploy/platforms/cloudflare/security-policies.js +0 -205
  111. package/dist/cjs/plugins/deploy/platforms/cloudflare/types.js +0 -18
  112. package/dist/cjs/plugins/deploy/platforms/cloudflare/utils.js +0 -66
  113. package/dist/cjs/plugins/deploy/platforms/cloudflare/worker-manifest.js +0 -208
  114. package/dist/cjs/plugins/deploy/platforms/cloudflare/wrangler-config.js +0 -204
  115. package/dist/cjs/plugins/deploy/platforms/cloudflare-output-contract.js +0 -108
  116. package/dist/cjs/plugins/deploy/platforms/cloudflare-output-plan.js +0 -93
  117. package/dist/cjs/plugins/deploy/platforms/cloudflare-output-verifier/identity.js +0 -83
  118. package/dist/cjs/plugins/deploy/platforms/cloudflare-output-verifier/issues.js +0 -54
  119. package/dist/cjs/plugins/deploy/platforms/cloudflare-output-verifier/manifest.js +0 -89
  120. package/dist/cjs/plugins/deploy/platforms/cloudflare-output-verifier/mutation-policy.js +0 -151
  121. package/dist/cjs/plugins/deploy/platforms/cloudflare-output-verifier/worker-bundles.js +0 -378
  122. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -251
  123. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.002-assets-routes.mjs +0 -191
  124. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.003-i18n-locales.mjs +0 -514
  125. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.004-rendering-css.mjs +0 -1012
  126. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.005-worker-dispatch.mjs +0 -363
  127. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-entry.006-fetch-handler.mjs +0 -93
  128. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-worker-fs-promises.mjs +0 -11
  129. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-worker-loadable-server.mjs +0 -281
  130. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  131. package/dist/cjs/plugins/deploy/platforms/templates/cloudflare-worker-path.mjs +0 -98
  132. package/dist/cjs/types/config/cloudflareDeploy.js +0 -18
  133. package/dist/cjs/ultramodern-release-envelope/canonical.js +0 -68
  134. package/dist/cjs/ultramodern-release-envelope/framework-output.js +0 -649
  135. package/dist/cjs/ultramodern-release-envelope/index.js +0 -399
  136. package/dist/cjs/ultramodern-release-envelope/types.js +0 -51
  137. package/dist/cjs/ultramodern-release-identity.js +0 -110
  138. package/dist/esm/builder/shared/builderPlugins/adapterLazyCompilation.mjs +0 -36
  139. package/dist/esm/builder/shared/bundlerPlugins/CssExtractRuntimePlugin.mjs +0 -30
  140. package/dist/esm/plugins/deploy/platforms/cloudflare/artifacts.mjs +0 -64
  141. package/dist/esm/plugins/deploy/platforms/cloudflare/constants.mjs +0 -34
  142. package/dist/esm/plugins/deploy/platforms/cloudflare/delivery-unit.mjs +0 -88
  143. package/dist/esm/plugins/deploy/platforms/cloudflare/i18n-worker.mjs +0 -97
  144. package/dist/esm/plugins/deploy/platforms/cloudflare/index.mjs +0 -102
  145. package/dist/esm/plugins/deploy/platforms/cloudflare/security-policies.mjs +0 -167
  146. package/dist/esm/plugins/deploy/platforms/cloudflare/types.mjs +0 -0
  147. package/dist/esm/plugins/deploy/platforms/cloudflare/utils.mjs +0 -12
  148. package/dist/esm/plugins/deploy/platforms/cloudflare/worker-manifest.mjs +0 -148
  149. package/dist/esm/plugins/deploy/platforms/cloudflare/wrangler-config.mjs +0 -150
  150. package/dist/esm/plugins/deploy/platforms/cloudflare-output-contract.mjs +0 -31
  151. package/dist/esm/plugins/deploy/platforms/cloudflare-output-plan.mjs +0 -45
  152. package/dist/esm/plugins/deploy/platforms/cloudflare-output-verifier/identity.mjs +0 -45
  153. package/dist/esm/plugins/deploy/platforms/cloudflare-output-verifier/issues.mjs +0 -10
  154. package/dist/esm/plugins/deploy/platforms/cloudflare-output-verifier/manifest.mjs +0 -51
  155. package/dist/esm/plugins/deploy/platforms/cloudflare-output-verifier/mutation-policy.mjs +0 -99
  156. package/dist/esm/plugins/deploy/platforms/cloudflare-output-verifier/worker-bundles.mjs +0 -313
  157. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -251
  158. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.002-assets-routes.mjs +0 -191
  159. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.003-i18n-locales.mjs +0 -514
  160. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.004-rendering-css.mjs +0 -1012
  161. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.005-worker-dispatch.mjs +0 -363
  162. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-entry.006-fetch-handler.mjs +0 -93
  163. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-worker-fs-promises.mjs +0 -11
  164. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-worker-loadable-server.mjs +0 -281
  165. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  166. package/dist/esm/plugins/deploy/platforms/templates/cloudflare-worker-path.mjs +0 -98
  167. package/dist/esm/types/config/cloudflareDeploy.mjs +0 -0
  168. package/dist/esm/ultramodern-release-envelope/canonical.mjs +0 -21
  169. package/dist/esm/ultramodern-release-envelope/framework-output.mjs +0 -573
  170. package/dist/esm/ultramodern-release-envelope/index.mjs +0 -335
  171. package/dist/esm/ultramodern-release-envelope/types.mjs +0 -7
  172. package/dist/esm/ultramodern-release-identity.mjs +0 -66
  173. package/dist/esm-node/builder/shared/builderPlugins/adapterLazyCompilation.mjs +0 -37
  174. package/dist/esm-node/builder/shared/bundlerPlugins/CssExtractRuntimePlugin.mjs +0 -31
  175. package/dist/esm-node/plugins/deploy/platforms/cloudflare/artifacts.mjs +0 -65
  176. package/dist/esm-node/plugins/deploy/platforms/cloudflare/constants.mjs +0 -35
  177. package/dist/esm-node/plugins/deploy/platforms/cloudflare/delivery-unit.mjs +0 -89
  178. package/dist/esm-node/plugins/deploy/platforms/cloudflare/i18n-worker.mjs +0 -98
  179. package/dist/esm-node/plugins/deploy/platforms/cloudflare/index.mjs +0 -103
  180. package/dist/esm-node/plugins/deploy/platforms/cloudflare/security-policies.mjs +0 -168
  181. package/dist/esm-node/plugins/deploy/platforms/cloudflare/types.mjs +0 -1
  182. package/dist/esm-node/plugins/deploy/platforms/cloudflare/utils.mjs +0 -13
  183. package/dist/esm-node/plugins/deploy/platforms/cloudflare/worker-manifest.mjs +0 -149
  184. package/dist/esm-node/plugins/deploy/platforms/cloudflare/wrangler-config.mjs +0 -151
  185. package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-contract.mjs +0 -32
  186. package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-plan.mjs +0 -46
  187. package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-verifier/identity.mjs +0 -46
  188. package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-verifier/issues.mjs +0 -11
  189. package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-verifier/manifest.mjs +0 -52
  190. package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-verifier/mutation-policy.mjs +0 -100
  191. package/dist/esm-node/plugins/deploy/platforms/cloudflare-output-verifier/worker-bundles.mjs +0 -314
  192. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -251
  193. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.002-assets-routes.mjs +0 -191
  194. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.003-i18n-locales.mjs +0 -514
  195. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.004-rendering-css.mjs +0 -1012
  196. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.005-worker-dispatch.mjs +0 -363
  197. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-entry.006-fetch-handler.mjs +0 -93
  198. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-worker-fs-promises.mjs +0 -11
  199. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-worker-loadable-server.mjs +0 -281
  200. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  201. package/dist/esm-node/plugins/deploy/platforms/templates/cloudflare-worker-path.mjs +0 -98
  202. package/dist/esm-node/types/config/cloudflareDeploy.mjs +0 -1
  203. package/dist/esm-node/ultramodern-release-envelope/canonical.mjs +0 -22
  204. package/dist/esm-node/ultramodern-release-envelope/framework-output.mjs +0 -574
  205. package/dist/esm-node/ultramodern-release-envelope/index.mjs +0 -336
  206. package/dist/esm-node/ultramodern-release-envelope/types.mjs +0 -8
  207. package/dist/esm-node/ultramodern-release-identity.mjs +0 -67
  208. package/dist/types/builder/shared/builderPlugins/adapterLazyCompilation.d.ts +0 -3
  209. package/dist/types/builder/shared/bundlerPlugins/CssExtractRuntimePlugin.d.ts +0 -6
  210. package/dist/types/plugins/deploy/platforms/cloudflare/artifacts.d.ts +0 -15
  211. package/dist/types/plugins/deploy/platforms/cloudflare/constants.d.ts +0 -24
  212. package/dist/types/plugins/deploy/platforms/cloudflare/delivery-unit.d.ts +0 -23
  213. package/dist/types/plugins/deploy/platforms/cloudflare/i18n-worker.d.ts +0 -22
  214. package/dist/types/plugins/deploy/platforms/cloudflare/index.d.ts +0 -2
  215. package/dist/types/plugins/deploy/platforms/cloudflare/security-policies.d.ts +0 -51
  216. package/dist/types/plugins/deploy/platforms/cloudflare/types.d.ts +0 -5
  217. package/dist/types/plugins/deploy/platforms/cloudflare/utils.d.ts +0 -6
  218. package/dist/types/plugins/deploy/platforms/cloudflare/worker-manifest.d.ts +0 -122
  219. package/dist/types/plugins/deploy/platforms/cloudflare/wrangler-config.d.ts +0 -46
  220. package/dist/types/plugins/deploy/platforms/cloudflare-output-contract.d.ts +0 -14
  221. package/dist/types/plugins/deploy/platforms/cloudflare-output-plan.d.ts +0 -34
  222. package/dist/types/plugins/deploy/platforms/cloudflare-output-verifier/identity.d.ts +0 -4
  223. package/dist/types/plugins/deploy/platforms/cloudflare-output-verifier/issues.d.ts +0 -14
  224. package/dist/types/plugins/deploy/platforms/cloudflare-output-verifier/manifest.d.ts +0 -2
  225. package/dist/types/plugins/deploy/platforms/cloudflare-output-verifier/mutation-policy.d.ts +0 -14
  226. package/dist/types/plugins/deploy/platforms/cloudflare-output-verifier/worker-bundles.d.ts +0 -20
  227. package/dist/types/plugins/deploy/platforms/templates/cloudflare-entry.001-bootstrap-security.d.mts +0 -1
  228. package/dist/types/plugins/deploy/platforms/templates/cloudflare-entry.002-assets-routes.d.mts +0 -1
  229. package/dist/types/plugins/deploy/platforms/templates/cloudflare-entry.003-i18n-locales.d.mts +0 -1
  230. package/dist/types/plugins/deploy/platforms/templates/cloudflare-entry.004-rendering-css.d.mts +0 -1
  231. package/dist/types/plugins/deploy/platforms/templates/cloudflare-entry.005-worker-dispatch.d.mts +0 -1
  232. package/dist/types/plugins/deploy/platforms/templates/cloudflare-entry.006-fetch-handler.d.mts +0 -4
  233. package/dist/types/plugins/deploy/platforms/templates/cloudflare-worker-fs-promises.d.mts +0 -5
  234. package/dist/types/plugins/deploy/platforms/templates/cloudflare-worker-loadable-server.d.mts +0 -48
  235. package/dist/types/plugins/deploy/platforms/templates/cloudflare-worker-mf-ssr-runtime-plugin.d.mts +0 -13
  236. package/dist/types/plugins/deploy/platforms/templates/cloudflare-worker-path.d.mts +0 -21
  237. package/dist/types/types/config/cloudflareDeploy.d.ts +0 -161
  238. package/dist/types/ultramodern-release-envelope/canonical.d.ts +0 -5
  239. package/dist/types/ultramodern-release-envelope/framework-output.d.ts +0 -32
  240. package/dist/types/ultramodern-release-envelope/index.d.ts +0 -6
  241. package/dist/types/ultramodern-release-envelope/types.d.ts +0 -62
  242. package/dist/types/ultramodern-release-identity.d.ts +0 -16
@@ -1,574 +0,0 @@
1
- import "node:module";
2
- import { createHash } from "node:crypto";
3
- import promises from "node:fs/promises";
4
- import node_path from "node:path";
5
- import { BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_REMOTE_ENTRY_FILE, ULTRAMODERN_BUILD_ARTIFACT_FILE, isUltramodernBuildArtifact } from "@modern-js/utils/universal";
6
- import { canonicalSerializeMicroVerticalReleaseEnvelope, createMicroVerticalReleaseEnvelope, verifyMicroVerticalReleaseEnvelope } from "./index.mjs";
7
- const MICROVERTICAL_RELEASE_ENVELOPE_PATH = 'release/microvertical-release-envelope.json';
8
- const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH = 'release/microvertical-release-identity-carriers.json';
9
- const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_KIND = 'ultramodern-release-identity-carriers';
10
- const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_SCHEMA_VERSION = 1;
11
- const COMPILED_MODULE_PATTERN = /\.(?:c|m)?js$/u;
12
- const EFFECT_BFF_WORKER_PATTERN = /^worker\/__modern_bff_effect\.(?:c|m)?js$/u;
13
- const isRecord = (value)=>'object' == typeof value && null !== value && !Array.isArray(value);
14
- const flattenStrings = (value)=>'string' == typeof value ? [
15
- value
16
- ] : Array.isArray(value) ? value.flatMap(flattenStrings) : [];
17
- const collectNestedStrings = (value, key)=>{
18
- if (Array.isArray(value)) return value.flatMap((item)=>collectNestedStrings(item, key));
19
- if (!isRecord(value)) return [];
20
- return Object.entries(value).flatMap(([entryKey, entryValue])=>[
21
- ...entryKey === key ? flattenStrings(entryValue) : [],
22
- ...collectNestedStrings(entryValue, key)
23
- ]);
24
- };
25
- const manifestReferencedClientModules = async (distDirectory, files, manifestLogicalPath = 'mf-manifest.json')=>{
26
- const manifest = await readJson(node_path.join(distDirectory, manifestLogicalPath));
27
- const references = [
28
- ...collectNestedStrings(manifest, 'path'),
29
- ...collectNestedStrings(manifest, 'name'),
30
- ...collectNestedStrings(manifest, 'sync'),
31
- ...collectNestedStrings(manifest, 'async')
32
- ];
33
- const normalizedReferences = new Set(references.filter((value)=>'string' == typeof value).map((value)=>value.replace(/^https?:\/\/[^/]+/u, '')).map((value)=>value.replace(/^\/+/u, '')));
34
- return files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
35
- ...normalizedReferences
36
- ].some((reference)=>reference === logicalPath || reference.endsWith(`/${logicalPath}`) || logicalPath.endsWith(`/${reference}`)));
37
- };
38
- const routeReferencedSsrModules = async (distDirectory, files, target, routeSpecLogicalPath = 'route.json')=>{
39
- const routeSpec = await readJson(node_path.join(distDirectory, routeSpecLogicalPath));
40
- const field = 'node' === target ? 'bundle' : 'worker';
41
- const references = collectNestedStrings(routeSpec, field).map((value)=>value.replace(/^\/+/u, ''));
42
- return files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && references.includes(logicalPath));
43
- };
44
- const readJson = async (filePath)=>JSON.parse(await promises.readFile(filePath, 'utf8'));
45
- const isFilesystemPathInside = (root, candidate)=>{
46
- const relative = node_path.relative(root, candidate);
47
- return '' === relative || !relative.startsWith(`..${node_path.sep}`) && '..' !== relative && !node_path.isAbsolute(relative);
48
- };
49
- const isMissingPathError = (error)=>isRecord(error) && 'ENOENT' === error.code;
50
- const resolveSafeReleaseEnvelopePath = async ({ artifactRoot, createDirectory })=>{
51
- const resolvedRoot = node_path.resolve(artifactRoot);
52
- const realRoot = await promises.realpath(resolvedRoot);
53
- const releaseDirectory = node_path.join(resolvedRoot, 'release');
54
- let releaseStat;
55
- try {
56
- releaseStat = await promises.lstat(releaseDirectory);
57
- } catch (error) {
58
- if (!isMissingPathError(error)) throw error;
59
- if (!createDirectory) return;
60
- await promises.mkdir(releaseDirectory);
61
- releaseStat = await promises.lstat(releaseDirectory);
62
- }
63
- if (releaseStat.isSymbolicLink() || !releaseStat.isDirectory()) throw new Error('[ultramodern-release-envelope] release must be a real directory inside artifactRoot, not a symlink or file.');
64
- const realReleaseDirectory = await promises.realpath(releaseDirectory);
65
- if (!isFilesystemPathInside(realRoot, realReleaseDirectory)) throw new Error('[ultramodern-release-envelope] release directory resolves outside artifactRoot.');
66
- const envelopePath = node_path.join(releaseDirectory, node_path.basename(MICROVERTICAL_RELEASE_ENVELOPE_PATH));
67
- try {
68
- const envelopeStat = await promises.lstat(envelopePath);
69
- if (envelopeStat.isSymbolicLink() || !envelopeStat.isFile()) throw new Error('[ultramodern-release-envelope] release envelope must be a real file inside artifactRoot, not a symlink or directory.');
70
- const realEnvelopePath = await promises.realpath(envelopePath);
71
- if (!isFilesystemPathInside(realRoot, realEnvelopePath)) throw new Error('[ultramodern-release-envelope] release envelope resolves outside artifactRoot.');
72
- } catch (error) {
73
- if (!isMissingPathError(error)) throw error;
74
- if (!createDirectory) return;
75
- }
76
- return envelopePath;
77
- };
78
- const writeReleaseEnvelope = async (artifactRoot, envelope)=>{
79
- const envelopePath = await resolveSafeReleaseEnvelopePath({
80
- artifactRoot,
81
- createDirectory: true
82
- });
83
- if (!envelopePath) throw new Error('[ultramodern-release-envelope] could not resolve release envelope path.');
84
- await promises.writeFile(envelopePath, `${canonicalSerializeMicroVerticalReleaseEnvelope(envelope)}\n`);
85
- };
86
- const readBuildArtifact = async (distDirectory)=>{
87
- const artifactPath = node_path.join(distDirectory, ULTRAMODERN_BUILD_ARTIFACT_FILE);
88
- const artifact = await readJson(artifactPath);
89
- if (!isUltramodernBuildArtifact(artifact)) throw new Error(`[ultramodern-release-envelope] ${ULTRAMODERN_BUILD_ARTIFACT_FILE} is missing or invalid.`);
90
- if ('workspace' === artifact.deliveryUnit.sourceRevision) throw new Error('[ultramodern-release-envelope] sourceRevision "workspace" cannot produce a promotable full-stack envelope.');
91
- return artifact;
92
- };
93
- const assertIdentityBlock = (value, identity, location, includeReleaseVersion)=>{
94
- if (!isRecord(value)) throw new Error(`[ultramodern-release-envelope] ${location} is missing delivery identity.`);
95
- const expected = {
96
- unitId: identity.unitId,
97
- buildMarker: identity.buildMarker,
98
- sourceRevision: identity.sourceRevision,
99
- ...includeReleaseVersion ? {
100
- version: identity.releaseVersion
101
- } : void 0
102
- };
103
- for (const [field, expectedValue] of Object.entries(expected))if (value[field] !== expectedValue) throw new Error(`[ultramodern-release-envelope] ${location}.${field} must match ${expectedValue}; received ${String(value[field])}.`);
104
- };
105
- const readBackendManifest = async (distDirectory, identity)=>{
106
- const manifest = await readJson(node_path.join(distDirectory, BACKEND_FEDERATION_MANIFEST_FILE));
107
- if (!isRecord(manifest) || !isRecord(manifest.backendFederation)) throw new Error('[ultramodern-release-envelope] backend federation manifest is missing backendFederation metadata.');
108
- assertIdentityBlock(manifest.backendFederation.deliveryUnit, identity, 'backendFederation.deliveryUnit', true);
109
- const versionBoundary = manifest.backendFederation.versionBoundary;
110
- assertIdentityBlock(isRecord(versionBoundary) ? versionBoundary.deliveryUnit : void 0, identity, 'backendFederation.versionBoundary.deliveryUnit', false);
111
- };
112
- const collectFiles = async (root)=>{
113
- const resolvedRoot = node_path.resolve(root);
114
- const realRoot = await promises.realpath(resolvedRoot);
115
- const collectDirectory = async (relativeDirectory)=>{
116
- const directory = node_path.join(resolvedRoot, ...relativeDirectory.split('/').filter(Boolean));
117
- const entries = await promises.readdir(directory, {
118
- withFileTypes: true
119
- });
120
- const files = [];
121
- for (const entry of entries){
122
- const logicalPath = node_path.posix.join(relativeDirectory, entry.name);
123
- if ('release' === logicalPath || logicalPath.startsWith('release/')) continue;
124
- if (entry.isDirectory()) {
125
- files.push(...await collectDirectory(logicalPath));
126
- continue;
127
- }
128
- if (entry.isFile()) {
129
- files.push(logicalPath);
130
- continue;
131
- }
132
- if (!entry.isSymbolicLink()) continue;
133
- const lexicalPath = node_path.join(resolvedRoot, ...logicalPath.split('/'));
134
- let realPath;
135
- try {
136
- realPath = await promises.realpath(lexicalPath);
137
- } catch {
138
- throw new Error(`[ultramodern-release-envelope] symbolic link ${logicalPath} cannot be resolved.`);
139
- }
140
- if (!isFilesystemPathInside(realRoot, realPath)) throw new Error(`[ultramodern-release-envelope] symbolic link ${logicalPath} resolves outside artifactRoot.`);
141
- const targetStat = await promises.stat(realPath);
142
- if (!targetStat.isFile() && !targetStat.isDirectory()) throw new Error(`[ultramodern-release-envelope] symbolic link ${logicalPath} must resolve to a file or directory.`);
143
- const targetLogicalPath = node_path.relative(realRoot, realPath).split(node_path.sep).join('/');
144
- if ('release' === targetLogicalPath || targetLogicalPath.startsWith('release/')) throw new Error(`[ultramodern-release-envelope] symbolic link ${logicalPath} targets private release metadata.`);
145
- if (targetStat.isDirectory() && isFilesystemPathInside(realPath, await promises.realpath(node_path.dirname(lexicalPath)))) throw new Error(`[ultramodern-release-envelope] symbolic link ${logicalPath} targets an ancestor directory.`);
146
- files.push(logicalPath);
147
- }
148
- return files;
149
- };
150
- return (await collectDirectory('')).sort();
151
- };
152
- const releaseArtifact = (logicalPath, runtime)=>({
153
- logicalPath,
154
- runtime
155
- });
156
- const writeReleaseIdentityCarrierMetadata = async (artifactRoot, identity, carrierPaths)=>{
157
- const surfacesByPath = new Map();
158
- for (const [surface, logicalPaths] of Object.entries(carrierPaths)){
159
- if (0 === logicalPaths.length) throw new Error(`[ultramodern-release-envelope] ${surface} has no declared release-identity carrier artifact.`);
160
- for (const logicalPath of logicalPaths){
161
- const surfaces = surfacesByPath.get(logicalPath) ?? new Set();
162
- surfaces.add(surface);
163
- surfacesByPath.set(logicalPath, surfaces);
164
- }
165
- }
166
- const carriers = await Promise.all([
167
- ...surfacesByPath
168
- ].sort(([left], [right])=>left.localeCompare(right)).map(async ([logicalPath, surfaces])=>{
169
- const bytes = await promises.readFile(node_path.join(artifactRoot, logicalPath));
170
- return {
171
- logicalPath,
172
- byteLength: bytes.byteLength,
173
- sha256: createHash('sha256').update(bytes).digest('hex'),
174
- surfaces: [
175
- ...surfaces
176
- ].sort((left, right)=>left.localeCompare(right))
177
- };
178
- }));
179
- const releaseEnvelopePath = await resolveSafeReleaseEnvelopePath({
180
- artifactRoot,
181
- createDirectory: true
182
- });
183
- if (!releaseEnvelopePath) throw new Error('[ultramodern-release-envelope] could not resolve private release metadata directory.');
184
- const metadataPath = node_path.join(node_path.dirname(releaseEnvelopePath), node_path.basename(MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH));
185
- try {
186
- const metadataStat = await promises.lstat(metadataPath);
187
- if (metadataStat.isSymbolicLink() || !metadataStat.isFile()) throw new Error('[ultramodern-release-envelope] release identity carrier metadata must be a real file inside artifactRoot.');
188
- } catch (error) {
189
- if (!isMissingPathError(error)) throw error;
190
- }
191
- await promises.writeFile(metadataPath, `${JSON.stringify({
192
- schemaVersion: MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_SCHEMA_VERSION,
193
- kind: MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_KIND,
194
- identity,
195
- carriers
196
- }, null, 2)}\n`);
197
- return releaseArtifact(MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH, 'release-identity-metadata');
198
- };
199
- const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
200
- const files = await collectFiles(distDirectory);
201
- 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.');
202
- const uiClientPaths = files.filter((logicalPath)=>{
203
- const topLevel = logicalPath.split('/')[0];
204
- return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel || [
205
- 'index.html',
206
- 'mf-manifest.json',
207
- 'mf-stats.json',
208
- 'remoteEntry.js',
209
- 'routes-manifest.json',
210
- 'loadable-stats.json'
211
- ].includes(logicalPath);
212
- });
213
- 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));
214
- const nodeApiEntryPaths = files.filter((logicalPath)=>logicalPath.startsWith('api/') && COMPILED_MODULE_PATTERN.test(logicalPath));
215
- 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));
216
- if (0 === uiClientPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no UI/client artifacts.`);
217
- if (0 === ssrPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no ${'node' === target ? 'Node' : 'workerd'} SSR artifacts.`);
218
- 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'}.`);
219
- const clientExecutionPaths = await manifestReferencedClientModules(distDirectory, files);
220
- if (0 === clientExecutionPaths.length) throw new Error('[ultramodern-release-envelope] UI/client manifest references no compiled execution module.');
221
- const ssrExecutionPaths = await routeReferencedSsrModules(distDirectory, files, target);
222
- if (0 === ssrExecutionPaths.length) throw new Error(`[ultramodern-release-envelope] route manifest references no emitted ${'node' === target ? 'Node' : 'Cloudflare'} SSR execution module.`);
223
- const runtimeByPath = new Map();
224
- const add = (paths, runtime)=>{
225
- for (const logicalPath of paths){
226
- const existing = runtimeByPath.get(logicalPath);
227
- if (existing && existing !== runtime) throw new Error(`[ultramodern-release-envelope] artifact "${logicalPath}" cannot carry conflicting runtimes "${existing}" and "${runtime}".`);
228
- runtimeByPath.set(logicalPath, runtime);
229
- }
230
- };
231
- add(uiClientPaths, 'browser');
232
- add(ssrPaths, 'node' === target ? 'nodejs' : 'workerd');
233
- add(apiBackendPaths, 'node' === target ? 'nodejs' : 'workerd-effect');
234
- add([
235
- BACKEND_FEDERATION_MANIFEST_FILE
236
- ], 'module-federation-manifest');
237
- add([
238
- BACKEND_FEDERATION_REMOTE_ENTRY_FILE
239
- ], 'node' === target ? 'nodejs' : 'commonjs-module');
240
- const surfaces = {
241
- uiClient: [
242
- ...uiClientPaths
243
- ].sort((left, right)=>left.localeCompare(right)),
244
- ssr: [
245
- ...ssrPaths
246
- ].sort((left, right)=>left.localeCompare(right)),
247
- apiBackend: [
248
- ...apiBackendPaths
249
- ].sort((left, right)=>left.localeCompare(right)),
250
- backendFederation: {
251
- manifest: BACKEND_FEDERATION_MANIFEST_FILE,
252
- container: BACKEND_FEDERATION_REMOTE_ENTRY_FILE
253
- }
254
- };
255
- const artifacts = [
256
- ...runtimeByPath
257
- ].map(([logicalPath, runtime])=>releaseArtifact(logicalPath, runtime)).sort((left, right)=>left.logicalPath.localeCompare(right.logicalPath));
258
- const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(distDirectory, identity, {
259
- apiBackend: apiBackendPaths,
260
- backendFederation: [
261
- BACKEND_FEDERATION_MANIFEST_FILE,
262
- BACKEND_FEDERATION_REMOTE_ENTRY_FILE
263
- ],
264
- ssr: [
265
- ...new Set([
266
- ...ssrExecutionPaths,
267
- ...ssrPaths
268
- ])
269
- ],
270
- uiClient: uiClientPaths.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath))
271
- });
272
- return {
273
- artifacts: [
274
- ...artifacts,
275
- identityCarrierMetadata
276
- ].sort((left, right)=>left.logicalPath.localeCompare(right.logicalPath)),
277
- surfaces
278
- };
279
- };
280
- const pathExists = async (filePath)=>{
281
- try {
282
- await promises.access(filePath);
283
- return true;
284
- } catch {
285
- return false;
286
- }
287
- };
288
- const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, distDirectory, target })=>{
289
- if (apiOnly) return;
290
- const backendManifestPath = node_path.join(distDirectory, BACKEND_FEDERATION_MANIFEST_FILE);
291
- const backendContainerPath = node_path.join(distDirectory, BACKEND_FEDERATION_REMOTE_ENTRY_FILE);
292
- const [hasBackendManifest, hasBackendContainer] = await Promise.all([
293
- pathExists(backendManifestPath),
294
- pathExists(backendContainerPath)
295
- ]);
296
- if (!hasBackendManifest && !hasBackendContainer) return;
297
- if (!hasBackendManifest || !hasBackendContainer) throw new Error('[ultramodern-release-envelope] full-stack MicroVertical backend federation manifest and container must be emitted together.');
298
- const buildArtifact = await readBuildArtifact(distDirectory);
299
- const identity = {
300
- unitId: buildArtifact.deliveryUnit.unitId,
301
- buildMarker: buildArtifact.deliveryUnit.buildMarker,
302
- sourceRevision: buildArtifact.deliveryUnit.sourceRevision,
303
- releaseVersion: buildArtifact.deliveryUnit.version
304
- };
305
- await readBackendManifest(distDirectory, identity);
306
- const { artifacts, surfaces } = await createReleaseArtifactInputs(distDirectory, identity, target);
307
- const envelope = await createMicroVerticalReleaseEnvelope({
308
- artifactRoot: distDirectory,
309
- target,
310
- identity,
311
- artifacts,
312
- surfaces
313
- });
314
- await writeReleaseEnvelope(distDirectory, envelope);
315
- return envelope;
316
- };
317
- const readFrameworkMicroVerticalReleaseEnvelope = async ({ artifactRoot, expectedTarget, logicalPathForArtifact, required = false })=>{
318
- const envelopePath = await resolveSafeReleaseEnvelopePath({
319
- artifactRoot,
320
- createDirectory: false
321
- });
322
- if (!envelopePath) {
323
- if (required) throw new Error(`[ultramodern-release-envelope] required envelope is missing at ${MICROVERTICAL_RELEASE_ENVELOPE_PATH}.`);
324
- return;
325
- }
326
- return verifyMicroVerticalReleaseEnvelope(await readJson(envelopePath), {
327
- artifactRoot,
328
- ...expectedTarget ? {
329
- expectedTarget
330
- } : {},
331
- ...logicalPathForArtifact ? {
332
- logicalPathForArtifact
333
- } : {}
334
- });
335
- };
336
- const verifyBuildOutputReleaseEnvelope = async (distDirectory, expectedTarget)=>{
337
- const [hasEnvelope, hasBuildArtifact, hasBackendManifest, hasBackendEntry] = await Promise.all([
338
- pathExists(node_path.join(distDirectory, MICROVERTICAL_RELEASE_ENVELOPE_PATH)),
339
- pathExists(node_path.join(distDirectory, ULTRAMODERN_BUILD_ARTIFACT_FILE)),
340
- pathExists(node_path.join(distDirectory, BACKEND_FEDERATION_MANIFEST_FILE)),
341
- pathExists(node_path.join(distDirectory, BACKEND_FEDERATION_REMOTE_ENTRY_FILE))
342
- ]);
343
- const isFullStackMicroVertical = hasBuildArtifact && (hasBackendManifest || hasBackendEntry);
344
- return readFrameworkMicroVerticalReleaseEnvelope({
345
- artifactRoot: distDirectory,
346
- ...expectedTarget ? {
347
- expectedTarget
348
- } : {},
349
- required: hasEnvelope || isFullStackMicroVertical
350
- });
351
- };
352
- const verifyNodeReleaseEnvelopeStaging = async ({ outputDirectory })=>readFrameworkMicroVerticalReleaseEnvelope({
353
- artifactRoot: outputDirectory,
354
- expectedTarget: 'node',
355
- required: true
356
- });
357
- const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=>{
358
- const files = await collectFiles(outputDirectory);
359
- for (const requiredPath of [
360
- 'index.js',
361
- 'package.json',
362
- BACKEND_FEDERATION_MANIFEST_FILE,
363
- BACKEND_FEDERATION_REMOTE_ENTRY_FILE
364
- ])if (!files.includes(requiredPath)) throw new Error(`[ultramodern-release-envelope] final Node staging is missing ${requiredPath}.`);
365
- const backendFederationPaths = new Set([
366
- BACKEND_FEDERATION_MANIFEST_FILE,
367
- BACKEND_FEDERATION_REMOTE_ENTRY_FILE
368
- ]);
369
- const uiClientPaths = files.filter((logicalPath)=>{
370
- const topLevel = logicalPath.split('/')[0];
371
- return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel || [
372
- 'index.html',
373
- 'mf-manifest.json',
374
- 'mf-stats.json',
375
- 'remoteEntry.js',
376
- 'routes-manifest.json',
377
- 'loadable-stats.json'
378
- ].includes(logicalPath);
379
- });
380
- const ssrPaths = files.filter((logicalPath)=>'index.js' === logicalPath || logicalPath.startsWith('bundles/') && COMPILED_MODULE_PATTERN.test(logicalPath));
381
- const apiBackendPaths = files.filter((logicalPath)=>(logicalPath.startsWith('api/') || logicalPath.startsWith('shared/')) && COMPILED_MODULE_PATTERN.test(logicalPath));
382
- for (const [surface, paths] of [
383
- [
384
- 'UI/client',
385
- uiClientPaths
386
- ],
387
- [
388
- 'Node SSR',
389
- ssrPaths
390
- ],
391
- [
392
- 'Node API/backend',
393
- apiBackendPaths
394
- ]
395
- ])if (0 === paths.length) throw new Error(`[ultramodern-release-envelope] final Node staging has no ${surface} artifacts.`);
396
- const clientExecutionPaths = await manifestReferencedClientModules(outputDirectory, files);
397
- const ssrExecutionPaths = await routeReferencedSsrModules(outputDirectory, files, 'node');
398
- 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.');
399
- const runtimeByPath = new Map(files.filter((logicalPath)=>!backendFederationPaths.has(logicalPath)).map((logicalPath)=>[
400
- logicalPath,
401
- 'nodejs-deployment'
402
- ]));
403
- for (const logicalPath of uiClientPaths)runtimeByPath.set(logicalPath, 'browser');
404
- for (const logicalPath of ssrPaths)runtimeByPath.set(logicalPath, 'nodejs');
405
- for (const logicalPath of apiBackendPaths)runtimeByPath.set(logicalPath, 'nodejs');
406
- runtimeByPath.set(BACKEND_FEDERATION_MANIFEST_FILE, 'module-federation-manifest');
407
- runtimeByPath.set(BACKEND_FEDERATION_REMOTE_ENTRY_FILE, 'nodejs');
408
- const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(outputDirectory, identity, {
409
- apiBackend: apiBackendPaths,
410
- backendFederation: [
411
- BACKEND_FEDERATION_MANIFEST_FILE,
412
- BACKEND_FEDERATION_REMOTE_ENTRY_FILE
413
- ],
414
- ssr: [
415
- ...new Set([
416
- ...ssrExecutionPaths,
417
- ...ssrPaths.filter((logicalPath)=>'index.js' !== logicalPath)
418
- ])
419
- ],
420
- uiClient: uiClientPaths.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath))
421
- });
422
- return {
423
- artifacts: [
424
- ...[
425
- ...runtimeByPath
426
- ].map(([logicalPath, runtime])=>releaseArtifact(logicalPath, runtime)),
427
- identityCarrierMetadata
428
- ].sort((left, right)=>left.logicalPath.localeCompare(right.logicalPath)),
429
- surfaces: {
430
- uiClient: [
431
- ...uiClientPaths
432
- ].sort((left, right)=>left.localeCompare(right)),
433
- ssr: [
434
- ...ssrPaths
435
- ].sort((left, right)=>left.localeCompare(right)),
436
- apiBackend: [
437
- ...apiBackendPaths
438
- ].sort((left, right)=>left.localeCompare(right)),
439
- backendFederation: {
440
- manifest: BACKEND_FEDERATION_MANIFEST_FILE,
441
- container: BACKEND_FEDERATION_REMOTE_ENTRY_FILE
442
- }
443
- }
444
- };
445
- };
446
- const emitNodeStagedReleaseEnvelope = async ({ distDirectory, outputDirectory })=>{
447
- const source = await verifyBuildOutputReleaseEnvelope(distDirectory, 'node');
448
- if (!source) return;
449
- const { artifacts, surfaces } = await createNodeStagedReleaseArtifactInputs(outputDirectory, source.identity);
450
- const staged = await createMicroVerticalReleaseEnvelope({
451
- artifactRoot: outputDirectory,
452
- target: 'node',
453
- identity: source.identity,
454
- artifacts,
455
- surfaces
456
- });
457
- await writeReleaseEnvelope(outputDirectory, staged);
458
- return staged;
459
- };
460
- const stageCloudflareReleaseEnvelope = async ({ distDirectory, outputDirectory })=>{
461
- const source = await verifyBuildOutputReleaseEnvelope(distDirectory, 'cloudflare');
462
- if (!source) return;
463
- const stagedEnvelopePath = node_path.join(outputDirectory, MICROVERTICAL_RELEASE_ENVELOPE_PATH);
464
- if (await pathExists(stagedEnvelopePath)) throw new Error('[ultramodern-release-envelope] Cloudflare staging contains a stale envelope before final output generation.');
465
- return source;
466
- };
467
- const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, identity)=>{
468
- const files = await collectFiles(outputDirectory);
469
- for (const requiredPath of [
470
- 'server/index.mjs',
471
- 'server/modern-worker-manifest.json',
472
- 'wrangler.json',
473
- 'package.json',
474
- 'worker/package.json'
475
- ])if (!files.includes(requiredPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${requiredPath}.`);
476
- 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.');
477
- const backendManifestPath = `public/${BACKEND_FEDERATION_MANIFEST_FILE}`;
478
- const backendContainerPath = `public/${BACKEND_FEDERATION_REMOTE_ENTRY_FILE}`;
479
- const apiBackendPaths = files.filter((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath));
480
- const ssrPaths = files.filter((logicalPath)=>(logicalPath.startsWith('server/') || logicalPath.startsWith('worker/')) && COMPILED_MODULE_PATTERN.test(logicalPath) && !EFFECT_BFF_WORKER_PATTERN.test(logicalPath));
481
- const uiClientPaths = files.filter((logicalPath)=>logicalPath.startsWith('public/') && logicalPath !== backendManifestPath && logicalPath !== backendContainerPath);
482
- for (const [surface, paths] of [
483
- [
484
- 'UI/client',
485
- uiClientPaths
486
- ],
487
- [
488
- 'Cloudflare SSR',
489
- ssrPaths
490
- ],
491
- [
492
- 'Cloudflare API/backend',
493
- apiBackendPaths
494
- ]
495
- ])if (0 === paths.length) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging has no ${surface} artifacts.`);
496
- for (const logicalPath of [
497
- backendManifestPath,
498
- backendContainerPath
499
- ])if (!files.includes(logicalPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${logicalPath}.`);
500
- const clientExecutionPaths = await manifestReferencedClientModules(outputDirectory, files, 'public/mf-manifest.json');
501
- const ssrExecutionPaths = await routeReferencedSsrModules(outputDirectory, files, 'cloudflare', 'server/route.json');
502
- 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.');
503
- const runtimeByPath = new Map();
504
- for (const logicalPath of files)runtimeByPath.set(logicalPath, 'cloudflare-deployment');
505
- const add = (paths, runtime)=>{
506
- for (const logicalPath of paths)runtimeByPath.set(logicalPath, runtime);
507
- };
508
- add(uiClientPaths, 'browser');
509
- add(ssrPaths, 'workerd');
510
- add(apiBackendPaths, 'workerd-effect');
511
- add([
512
- backendManifestPath
513
- ], 'module-federation-manifest');
514
- add([
515
- backendContainerPath
516
- ], 'commonjs-module');
517
- const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(outputDirectory, identity, {
518
- apiBackend: apiBackendPaths,
519
- backendFederation: [
520
- backendManifestPath,
521
- backendContainerPath
522
- ],
523
- ssr: [
524
- ...new Set([
525
- ...ssrExecutionPaths,
526
- ...ssrPaths.filter((logicalPath)=>logicalPath.startsWith('worker/'))
527
- ])
528
- ],
529
- uiClient: uiClientPaths.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath))
530
- });
531
- return {
532
- artifacts: [
533
- ...[
534
- ...runtimeByPath
535
- ].map(([logicalPath, runtime])=>releaseArtifact(logicalPath, runtime)),
536
- identityCarrierMetadata
537
- ].sort((left, right)=>left.logicalPath.localeCompare(right.logicalPath)),
538
- surfaces: {
539
- uiClient: [
540
- ...uiClientPaths
541
- ].sort((left, right)=>left.localeCompare(right)),
542
- ssr: [
543
- ...ssrPaths
544
- ].sort((left, right)=>left.localeCompare(right)),
545
- apiBackend: [
546
- ...apiBackendPaths
547
- ].sort((left, right)=>left.localeCompare(right)),
548
- backendFederation: {
549
- manifest: backendManifestPath,
550
- container: backendContainerPath
551
- }
552
- }
553
- };
554
- };
555
- const emitCloudflareStagedReleaseEnvelope = async ({ distDirectory, outputDirectory })=>{
556
- const source = await verifyBuildOutputReleaseEnvelope(distDirectory, 'cloudflare');
557
- if (!source) return;
558
- const { artifacts, surfaces } = await createCloudflareStagedReleaseArtifactInputs(outputDirectory, source.identity);
559
- const staged = await createMicroVerticalReleaseEnvelope({
560
- artifactRoot: outputDirectory,
561
- target: 'cloudflare',
562
- identity: source.identity,
563
- artifacts,
564
- surfaces
565
- });
566
- await writeReleaseEnvelope(outputDirectory, staged);
567
- return staged;
568
- };
569
- const verifyCloudflareReleaseEnvelopeStaging = async (outputDirectory)=>readFrameworkMicroVerticalReleaseEnvelope({
570
- artifactRoot: outputDirectory,
571
- expectedTarget: 'cloudflare',
572
- required: true
573
- });
574
- export { MICROVERTICAL_RELEASE_ENVELOPE_PATH, MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH, emitCloudflareStagedReleaseEnvelope, emitFrameworkMicroVerticalReleaseEnvelope, emitNodeStagedReleaseEnvelope, readFrameworkMicroVerticalReleaseEnvelope, stageCloudflareReleaseEnvelope, verifyBuildOutputReleaseEnvelope, verifyCloudflareReleaseEnvelopeStaging, verifyNodeReleaseEnvelopeStaging };