@bleedingdev/modern-js-app-tools-extensions 3.9.0-ultramodern.2 → 3.9.0-ultramodern.20

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 (213) hide show
  1. package/dist/cjs/backend-federation-build/codegen.js +267 -0
  2. package/dist/cjs/backend-federation-build/config.js +239 -0
  3. package/dist/cjs/backend-federation-build/emit.js +154 -0
  4. package/dist/cjs/backend-federation-build/index.js +53 -0
  5. package/dist/cjs/build-config/build-environment.js +129 -0
  6. package/dist/cjs/build-config/precompress/plugin.js +124 -0
  7. package/dist/cjs/build-config/precompress/types.js +18 -0
  8. package/dist/cjs/build-config/public.js +43 -0
  9. package/dist/cjs/build-config/remote-address.js +58 -0
  10. package/dist/cjs/cloudflare/artifacts.js +8 -19
  11. package/dist/cjs/cloudflare/constants.js +1 -1
  12. package/dist/cjs/cloudflare/delivery-unit.js +23 -42
  13. package/dist/cjs/cloudflare/index.js +10 -2
  14. package/dist/cjs/cloudflare/worker-manifest.js +13 -4
  15. package/dist/cjs/cloudflare/wrangler-config.js +35 -7
  16. package/dist/cjs/cloudflare-builder.js +251 -75
  17. package/dist/cjs/cloudflare-output-contract.js +69 -3
  18. package/dist/cjs/cloudflare-output-verifier/identity.js +29 -27
  19. package/dist/cjs/cloudflare-output-verifier/index.js +10 -0
  20. package/dist/cjs/cloudflare-output-verifier/manifest.js +46 -0
  21. package/dist/cjs/cloudflare-output-verifier/mutation-policy.js +7 -1
  22. package/dist/cjs/cloudflare-output-verifier/worker-bundles.js +14 -6
  23. package/dist/cjs/config.js +34 -1
  24. package/dist/cjs/deploy-output/npmAliases.js +251 -0
  25. package/dist/cjs/deploy-output/plugin.js +97 -0
  26. package/dist/cjs/deploy-output/public-assets.js +146 -0
  27. package/dist/cjs/deploy-output/target.js +104 -0
  28. package/dist/cjs/deploy-output/trace-files.js +90 -0
  29. package/dist/cjs/native-type-checker.js +193 -0
  30. package/dist/cjs/policy-defaults.js +101 -0
  31. package/dist/cjs/release-envelope/framework-output.js +153 -79
  32. package/dist/cjs/release-envelope/index.js +10 -4
  33. package/dist/cjs/release-envelope/plugin.js +18 -13
  34. package/dist/cjs/release-identity.js +5 -6
  35. package/dist/cjs/runtime-package-resolution.js +118 -0
  36. package/dist/cjs/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  37. package/dist/cjs/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  38. package/dist/cjs/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  39. package/dist/cjs/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  40. package/dist/cjs/templates/cloudflare-worker-route-data.mjs +1069 -0
  41. package/dist/esm/backend-federation-build/codegen.mjs +216 -0
  42. package/dist/esm/backend-federation-build/config.mjs +163 -0
  43. package/dist/esm/backend-federation-build/emit.mjs +103 -0
  44. package/dist/esm/backend-federation-build/index.mjs +1 -0
  45. package/dist/esm/build-config/build-environment.mjs +88 -0
  46. package/dist/esm/build-config/precompress/plugin.mjs +76 -0
  47. package/dist/esm/build-config/precompress/types.mjs +0 -0
  48. package/dist/esm/build-config/public.mjs +1 -0
  49. package/dist/esm/build-config/remote-address.mjs +20 -0
  50. package/dist/esm/cloudflare/artifacts.mjs +8 -19
  51. package/dist/esm/cloudflare/constants.mjs +1 -1
  52. package/dist/esm/cloudflare/delivery-unit.mjs +17 -36
  53. package/dist/esm/cloudflare/index.mjs +10 -2
  54. package/dist/esm/cloudflare/worker-manifest.mjs +13 -4
  55. package/dist/esm/cloudflare/wrangler-config.mjs +35 -7
  56. package/dist/esm/cloudflare-builder.mjs +245 -75
  57. package/dist/esm/cloudflare-output-contract.mjs +59 -2
  58. package/dist/esm/cloudflare-output-verifier/identity.mjs +27 -25
  59. package/dist/esm/cloudflare-output-verifier/index.mjs +10 -0
  60. package/dist/esm/cloudflare-output-verifier/manifest.mjs +46 -0
  61. package/dist/esm/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  62. package/dist/esm/cloudflare-output-verifier/worker-bundles.mjs +15 -7
  63. package/dist/esm/config.mjs +3 -0
  64. package/dist/esm/deploy-output/npmAliases.mjs +199 -0
  65. package/dist/esm/deploy-output/plugin.mjs +46 -0
  66. package/dist/esm/deploy-output/public-assets.mjs +82 -0
  67. package/dist/esm/deploy-output/target.mjs +57 -0
  68. package/dist/esm/deploy-output/trace-files.mjs +38 -0
  69. package/dist/esm/native-type-checker.mjs +142 -0
  70. package/dist/esm/policy-defaults.mjs +45 -0
  71. package/dist/esm/release-envelope/framework-output.mjs +130 -56
  72. package/dist/esm/release-envelope/index.mjs +10 -4
  73. package/dist/esm/release-envelope/plugin.mjs +18 -13
  74. package/dist/esm/release-identity.mjs +5 -6
  75. package/dist/esm/runtime-package-resolution.mjs +60 -0
  76. package/dist/esm/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  77. package/dist/esm/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  78. package/dist/esm/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  79. package/dist/esm/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  80. package/dist/esm/templates/cloudflare-worker-route-data.mjs +1069 -0
  81. package/dist/esm-node/backend-federation-build/codegen.mjs +217 -0
  82. package/dist/esm-node/backend-federation-build/config.mjs +164 -0
  83. package/dist/esm-node/backend-federation-build/emit.mjs +104 -0
  84. package/dist/esm-node/backend-federation-build/index.mjs +2 -0
  85. package/dist/esm-node/build-config/build-environment.mjs +89 -0
  86. package/dist/esm-node/build-config/precompress/plugin.mjs +77 -0
  87. package/dist/esm-node/build-config/precompress/types.mjs +1 -0
  88. package/dist/esm-node/build-config/public.mjs +2 -0
  89. package/dist/esm-node/build-config/remote-address.mjs +21 -0
  90. package/dist/esm-node/cloudflare/artifacts.mjs +8 -19
  91. package/dist/esm-node/cloudflare/constants.mjs +1 -1
  92. package/dist/esm-node/cloudflare/delivery-unit.mjs +17 -36
  93. package/dist/esm-node/cloudflare/index.mjs +10 -2
  94. package/dist/esm-node/cloudflare/worker-manifest.mjs +13 -4
  95. package/dist/esm-node/cloudflare/wrangler-config.mjs +35 -7
  96. package/dist/esm-node/cloudflare-builder.mjs +245 -75
  97. package/dist/esm-node/cloudflare-output-contract.mjs +59 -2
  98. package/dist/esm-node/cloudflare-output-verifier/identity.mjs +27 -25
  99. package/dist/esm-node/cloudflare-output-verifier/index.mjs +10 -0
  100. package/dist/esm-node/cloudflare-output-verifier/manifest.mjs +46 -0
  101. package/dist/esm-node/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  102. package/dist/esm-node/cloudflare-output-verifier/worker-bundles.mjs +15 -7
  103. package/dist/esm-node/config.mjs +3 -0
  104. package/dist/esm-node/deploy-output/npmAliases.mjs +200 -0
  105. package/dist/esm-node/deploy-output/plugin.mjs +49 -0
  106. package/dist/esm-node/deploy-output/public-assets.mjs +83 -0
  107. package/dist/esm-node/deploy-output/target.mjs +58 -0
  108. package/dist/esm-node/deploy-output/trace-files.mjs +39 -0
  109. package/dist/esm-node/native-type-checker.mjs +143 -0
  110. package/dist/esm-node/policy-defaults.mjs +46 -0
  111. package/dist/esm-node/release-envelope/framework-output.mjs +130 -56
  112. package/dist/esm-node/release-envelope/index.mjs +10 -4
  113. package/dist/esm-node/release-envelope/plugin.mjs +18 -13
  114. package/dist/esm-node/release-identity.mjs +5 -6
  115. package/dist/esm-node/runtime-package-resolution.mjs +61 -0
  116. package/dist/esm-node/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  117. package/dist/esm-node/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  118. package/dist/esm-node/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  119. package/dist/esm-node/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  120. package/dist/esm-node/templates/cloudflare-worker-route-data.mjs +1069 -0
  121. package/dist/types/backend-federation-build/codegen.d.ts +116 -0
  122. package/dist/types/backend-federation-build/config.d.ts +121 -0
  123. package/dist/types/backend-federation-build/emit.d.ts +21 -0
  124. package/dist/types/backend-federation-build/index.d.ts +2 -0
  125. package/dist/types/build-config/build-environment.d.ts +14 -0
  126. package/dist/types/build-config/precompress/plugin.d.ts +4 -0
  127. package/dist/types/build-config/precompress/types.d.ts +19 -0
  128. package/dist/types/build-config/public.d.ts +2 -0
  129. package/dist/types/build-config/remote-address.d.ts +3 -0
  130. package/dist/types/cloudflare/artifacts.d.ts +7 -6
  131. package/dist/types/cloudflare/constants.d.ts +1 -1
  132. package/dist/types/cloudflare/delivery-unit.d.ts +3 -3
  133. package/dist/types/cloudflare/worker-manifest.d.ts +2 -2
  134. package/dist/types/cloudflare/wrangler-config.d.ts +6 -0
  135. package/dist/types/cloudflare-builder.d.ts +49 -9
  136. package/dist/types/cloudflare-output-contract.d.ts +4 -1
  137. package/dist/types/cloudflare-output-verifier/identity.d.ts +1 -1
  138. package/dist/types/cloudflare-output-verifier/worker-bundles.d.ts +2 -2
  139. package/dist/types/config.d.ts +29 -1
  140. package/dist/types/deploy-output/npmAliases.d.ts +14 -0
  141. package/dist/types/deploy-output/plugin.d.ts +35 -0
  142. package/dist/types/deploy-output/public-assets.d.ts +51 -0
  143. package/dist/types/deploy-output/target.d.ts +29 -0
  144. package/dist/types/deploy-output/trace-files.d.ts +17 -0
  145. package/dist/types/native-type-checker.d.ts +15 -0
  146. package/dist/types/policy-defaults.d.ts +46 -0
  147. package/dist/types/precompress/LICENSE +20 -0
  148. package/dist/types/precompress/index.d.ts +76 -0
  149. package/dist/types/release-envelope/framework-output.d.ts +8 -3
  150. package/dist/types/release-envelope/plugin.d.ts +7 -7
  151. package/dist/types/runtime-package-resolution.d.ts +28 -0
  152. package/dist/types/templates/cloudflare-worker-route-data.d.mts +14 -0
  153. package/package.json +97 -15
  154. package/src/backend-federation-build/codegen.ts +254 -0
  155. package/src/backend-federation-build/config.ts +492 -0
  156. package/src/backend-federation-build/emit.ts +213 -0
  157. package/src/backend-federation-build/index.ts +2 -0
  158. package/src/build-config/build-environment.ts +160 -0
  159. package/src/build-config/precompress/plugin.ts +140 -0
  160. package/src/build-config/precompress/types.ts +26 -0
  161. package/src/build-config/public.ts +5 -0
  162. package/src/build-config/remote-address.ts +33 -0
  163. package/src/cloudflare/artifacts.ts +22 -43
  164. package/src/cloudflare/constants.ts +1 -1
  165. package/src/cloudflare/delivery-unit.ts +42 -53
  166. package/src/cloudflare/index.ts +24 -11
  167. package/src/cloudflare/worker-manifest.ts +20 -3
  168. package/src/cloudflare/wrangler-config.ts +86 -10
  169. package/src/cloudflare-builder.ts +472 -151
  170. package/src/cloudflare-output-contract.ts +70 -0
  171. package/src/cloudflare-output-verifier/identity.ts +5 -1
  172. package/src/cloudflare-output-verifier/index.ts +20 -0
  173. package/src/cloudflare-output-verifier/manifest.ts +77 -0
  174. package/src/cloudflare-output-verifier/mutation-policy.ts +11 -1
  175. package/src/cloudflare-output-verifier/worker-bundles.ts +32 -14
  176. package/src/config.ts +34 -6
  177. package/src/deploy-output/npmAliases.ts +382 -0
  178. package/src/deploy-output/plugin.ts +86 -0
  179. package/src/deploy-output/public-assets.ts +224 -0
  180. package/src/deploy-output/target.ts +106 -0
  181. package/src/deploy-output/trace-files.ts +67 -0
  182. package/src/native-type-checker.ts +183 -0
  183. package/src/policy-defaults.ts +127 -0
  184. package/src/release-envelope/framework-output.ts +346 -94
  185. package/src/release-envelope/index.ts +26 -5
  186. package/src/release-envelope/plugin.ts +43 -40
  187. package/src/release-identity.ts +13 -2
  188. package/src/runtime-package-resolution.ts +115 -0
  189. package/src/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  190. package/src/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  191. package/src/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  192. package/src/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  193. package/src/templates/cloudflare-worker-route-data.mjs +1069 -0
  194. package/dist/cjs/templates/cloudflare-worker-fs-promises.mjs +0 -11
  195. package/dist/cjs/templates/cloudflare-worker-loadable-server.mjs +0 -281
  196. package/dist/cjs/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  197. package/dist/cjs/templates/cloudflare-worker-path.mjs +0 -98
  198. package/dist/esm/templates/cloudflare-worker-fs-promises.mjs +0 -11
  199. package/dist/esm/templates/cloudflare-worker-loadable-server.mjs +0 -281
  200. package/dist/esm/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  201. package/dist/esm/templates/cloudflare-worker-path.mjs +0 -98
  202. package/dist/esm-node/templates/cloudflare-worker-fs-promises.mjs +0 -11
  203. package/dist/esm-node/templates/cloudflare-worker-loadable-server.mjs +0 -281
  204. package/dist/esm-node/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  205. package/dist/esm-node/templates/cloudflare-worker-path.mjs +0 -98
  206. package/dist/types/templates/cloudflare-worker-fs-promises.d.mts +0 -5
  207. package/dist/types/templates/cloudflare-worker-loadable-server.d.mts +0 -48
  208. package/dist/types/templates/cloudflare-worker-mf-ssr-runtime-plugin.d.mts +0 -13
  209. package/dist/types/templates/cloudflare-worker-path.d.mts +0 -21
  210. package/src/templates/cloudflare-worker-fs-promises.mjs +0 -11
  211. package/src/templates/cloudflare-worker-loadable-server.mjs +0 -281
  212. package/src/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  213. package/src/templates/cloudflare-worker-path.mjs +0 -98
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ const __rslib_import_meta_url__ = /*#__PURE__*/ function() {
3
+ return "u" < typeof document ? new (require('url'.replace('', ''))).URL('file:' + __filename).href : document.currentScript && document.currentScript.src || new URL('main.js', document.baseURI).href;
4
+ }();
5
+ var __webpack_require__ = {};
6
+ (()=>{
7
+ __webpack_require__.d = (exports1, getters, values)=>{
8
+ var define = (defs, kind)=>{
9
+ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
10
+ enumerable: true,
11
+ [kind]: defs[key]
12
+ });
13
+ };
14
+ define(getters, "get");
15
+ define(values, "value");
16
+ };
17
+ })();
18
+ (()=>{
19
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
20
+ })();
21
+ (()=>{
22
+ __webpack_require__.r = (exports1)=>{
23
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
24
+ value: 'Module'
25
+ });
26
+ Object.defineProperty(exports1, '__esModule', {
27
+ value: true
28
+ });
29
+ };
30
+ })();
31
+ var __webpack_exports__ = {};
32
+ __webpack_require__.r(__webpack_exports__);
33
+ __webpack_require__.d(__webpack_exports__, {
34
+ POLICY_DEFAULTS_PLUGIN_NAME: ()=>POLICY_DEFAULTS_PLUGIN_NAME,
35
+ RENDERER_EXTENSIONS_PACKAGE: ()=>RENDERER_EXTENSIONS_PACKAGE,
36
+ RENDERER_EXTENSIONS_PLUGIN_NAME: ()=>RENDERER_EXTENSIONS_PLUGIN_NAME,
37
+ SERVER_EXTENSIONS_PLUGIN_NAME: ()=>SERVER_EXTENSIONS_PLUGIN_NAME,
38
+ applyPolicyDefaults: ()=>applyPolicyDefaults,
39
+ createPolicyDefaultsPlugin: ()=>createPolicyDefaultsPlugin
40
+ });
41
+ const external_runtime_package_resolution_js_namespaceObject = require("./runtime-package-resolution.js");
42
+ const RENDERER_EXTENSIONS_PACKAGE = '@modern-js/runtime-renderer-extensions';
43
+ const RENDERER_EXTENSIONS_PLUGIN_NAME = 'rendererHead';
44
+ const SERVER_EXTENSIONS_PLUGIN_NAME = '@modern-js/app-tools/server-plugin';
45
+ const POLICY_DEFAULTS_PLUGIN_NAME = '@modern-js/ultramodern-policy-defaults';
46
+ const applyPolicyDefaults = (api, options = {})=>{
47
+ if (false !== options.rendererExtensions) {
48
+ api._internalRuntimePlugins(({ entrypoint, plugins })=>{
49
+ if (!plugins.some((plugin)=>plugin.path === RENDERER_EXTENSIONS_PACKAGE)) plugins.push({
50
+ name: RENDERER_EXTENSIONS_PLUGIN_NAME,
51
+ path: RENDERER_EXTENSIONS_PACKAGE,
52
+ config: {}
53
+ });
54
+ return {
55
+ entrypoint,
56
+ plugins
57
+ };
58
+ });
59
+ const moduleDirectories = (0, external_runtime_package_resolution_js_namespaceObject.collectRuntimePackageModuleDirectories)([
60
+ RENDERER_EXTENSIONS_PACKAGE
61
+ ], __rslib_import_meta_url__);
62
+ if (moduleDirectories.length > 0) api.modifyResolvedConfig((config)=>({
63
+ ...config,
64
+ builderPlugins: [
65
+ ...config.builderPlugins ?? [],
66
+ (0, external_runtime_package_resolution_js_namespaceObject.createRuntimePackageResolutionPlugin)(moduleDirectories)
67
+ ]
68
+ }));
69
+ }
70
+ if (false !== options.serverExtensions) api._internalServerPlugins(({ plugins })=>{
71
+ if (!plugins.some((plugin)=>plugin.name === SERVER_EXTENSIONS_PLUGIN_NAME)) plugins.push({
72
+ name: SERVER_EXTENSIONS_PLUGIN_NAME
73
+ });
74
+ return {
75
+ plugins
76
+ };
77
+ });
78
+ };
79
+ const createPolicyDefaultsPlugin = (options = {})=>({
80
+ name: POLICY_DEFAULTS_PLUGIN_NAME,
81
+ setup (api) {
82
+ applyPolicyDefaults(api, options);
83
+ }
84
+ });
85
+ exports.POLICY_DEFAULTS_PLUGIN_NAME = __webpack_exports__.POLICY_DEFAULTS_PLUGIN_NAME;
86
+ exports.RENDERER_EXTENSIONS_PACKAGE = __webpack_exports__.RENDERER_EXTENSIONS_PACKAGE;
87
+ exports.RENDERER_EXTENSIONS_PLUGIN_NAME = __webpack_exports__.RENDERER_EXTENSIONS_PLUGIN_NAME;
88
+ exports.SERVER_EXTENSIONS_PLUGIN_NAME = __webpack_exports__.SERVER_EXTENSIONS_PLUGIN_NAME;
89
+ exports.applyPolicyDefaults = __webpack_exports__.applyPolicyDefaults;
90
+ exports.createPolicyDefaultsPlugin = __webpack_exports__.createPolicyDefaultsPlugin;
91
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
92
+ "POLICY_DEFAULTS_PLUGIN_NAME",
93
+ "RENDERER_EXTENSIONS_PACKAGE",
94
+ "RENDERER_EXTENSIONS_PLUGIN_NAME",
95
+ "SERVER_EXTENSIONS_PLUGIN_NAME",
96
+ "applyPolicyDefaults",
97
+ "createPolicyDefaultsPlugin"
98
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
99
+ Object.defineProperty(exports, '__esModule', {
100
+ value: true
101
+ });
@@ -53,7 +53,7 @@ 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 universal_namespaceObject = require("@modern-js/utils/universal");
56
+ const backend_federation_contracts_namespaceObject = require("@modern-js/backend-federation-contracts");
57
57
  const external_index_js_namespaceObject = require("./index.js");
58
58
  const MICROVERTICAL_RELEASE_ENVELOPE_PATH = 'release/microvertical-release-envelope.json';
59
59
  const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH = 'release/microvertical-release-identity-carriers.json';
@@ -61,6 +61,21 @@ const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_KIND = 'ultramodern-release-identi
61
61
  const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_SCHEMA_VERSION = 1;
62
62
  const COMPILED_MODULE_PATTERN = /\.(?:c|m)?js$/u;
63
63
  const EFFECT_BFF_WORKER_PATTERN = /^worker\/__modern_bff_effect\.(?:c|m)?js$/u;
64
+ const EFFECT_BFF_WORKER_SUPPORT_PATTERN = /^worker\/__modern_worker_(?:runtime|shared)_*\.(?:c|m)?js$/u;
65
+ const isEffectBffWorkerArtifact = (logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath) || EFFECT_BFF_WORKER_SUPPORT_PATTERN.test(logicalPath);
66
+ const CRAWLER_POLICY_PATH = 'public/robots.txt';
67
+ const isPublicMetadataPath = (logicalPath)=>'public/_headers' === logicalPath || /^public\/\.well-known\/[^/]+\.json$/u.test(logicalPath);
68
+ const PUBLIC_BUILD_ARTIFACT_PATH = `public/${backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE}`;
69
+ const DECLARED_PUBLIC_ASSET_RUNTIME = 'public-asset';
70
+ const resolveDeclaredPublicAssets = (files, declaredPublicAssets, target)=>{
71
+ const staged = new Set(files);
72
+ const declared = new Set();
73
+ for (const logicalPath of declaredPublicAssets){
74
+ 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)}.`);
75
+ declared.add(logicalPath);
76
+ }
77
+ return declared;
78
+ };
64
79
  const isRecord = (value)=>'object' == typeof value && null !== value && !Array.isArray(value);
65
80
  const flattenStrings = (value)=>'string' == typeof value ? [
66
81
  value
@@ -73,6 +88,46 @@ const collectNestedStrings = (value, key)=>{
73
88
  ...collectNestedStrings(entryValue, key)
74
89
  ]);
75
90
  };
91
+ const emptyProducerRouteModules = async (distDirectory, files, manifest, manifestLogicalPath)=>{
92
+ 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 [];
93
+ const publicPath = manifest.metaData.publicPath;
94
+ const safeReference = (value)=>'string' == typeof value && value.length > 0 && !/[\\\\%?#\s]/u.test(value) && !value.split('/').some((segment)=>'.' === segment || '..' === segment);
95
+ if (!safeReference(publicPath)) return [];
96
+ const absoluteBase = /^https?:\/\//u.test(publicPath);
97
+ if ('auto' !== publicPath && (!publicPath.endsWith('/') || !absoluteBase && (!publicPath.startsWith('/') || publicPath.startsWith('//')))) return [];
98
+ if (absoluteBase) {
99
+ const base = new URL(publicPath);
100
+ if (base.username || base.password || base.href !== publicPath) return [];
101
+ }
102
+ const directory = external_node_path_default().posix.dirname(manifestLogicalPath);
103
+ const routesManifest = await readJson(external_node_path_default().join(distDirectory, directory, 'routes-manifest.json'));
104
+ if (!isRecord(routesManifest) || !isRecord(routesManifest.routeAssets)) return [];
105
+ const modules = new Set();
106
+ for (const route of Object.values(routesManifest.routeAssets)){
107
+ if (!isRecord(route) || !Array.isArray(route.assets)) return [];
108
+ for (const reference of route.assets){
109
+ if (!safeReference(reference) || reference.startsWith('//')) return [];
110
+ let relative = reference;
111
+ if (/^https?:\/\//u.test(reference)) {
112
+ if (!absoluteBase || !reference.startsWith(publicPath)) return [];
113
+ relative = reference.slice(publicPath.length);
114
+ } else if (reference.startsWith('/')) {
115
+ const prefix = 'auto' === publicPath ? '/' : absoluteBase ? new URL(publicPath).pathname : publicPath;
116
+ if (!reference.startsWith(prefix)) return [];
117
+ relative = reference.slice(prefix.length);
118
+ }
119
+ if (!/^(?:static|html|public)\/[^:]+$/u.test(relative) || relative.includes('//')) return [];
120
+ const logicalPath = external_node_path_default().posix.join(directory, relative);
121
+ if (!files.includes(logicalPath)) return [];
122
+ const assetStat = await promises_default().lstat(external_node_path_default().join(distDirectory, logicalPath));
123
+ if (!assetStat.isFile()) return [];
124
+ if (COMPILED_MODULE_PATTERN.test(logicalPath)) modules.add(logicalPath);
125
+ }
126
+ }
127
+ return [
128
+ ...modules
129
+ ];
130
+ };
76
131
  const manifestReferencedClientModules = async (distDirectory, files, manifestLogicalPath = 'mf-manifest.json')=>{
77
132
  const manifest = await readJson(external_node_path_default().join(distDirectory, manifestLogicalPath));
78
133
  const references = [
@@ -82,9 +137,10 @@ const manifestReferencedClientModules = async (distDirectory, files, manifestLog
82
137
  ...collectNestedStrings(manifest, 'async')
83
138
  ];
84
139
  const normalizedReferences = new Set(references.filter((value)=>'string' == typeof value).map((value)=>value.replace(/^https?:\/\/[^/]+/u, '')).map((value)=>value.replace(/^\/+/u, '')));
85
- return files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
140
+ const modules = files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
86
141
  ...normalizedReferences
87
142
  ].some((reference)=>reference === logicalPath || reference.endsWith(`/${logicalPath}`) || logicalPath.endsWith(`/${reference}`)));
143
+ return modules.length > 0 ? modules : emptyProducerRouteModules(distDirectory, files, manifest, manifestLogicalPath);
88
144
  };
89
145
  const routeReferencedSsrModules = async (distDirectory, files, target, routeSpecLogicalPath = 'route.json')=>{
90
146
  const routeSpec = await readJson(external_node_path_default().join(distDirectory, routeSpecLogicalPath));
@@ -134,11 +190,14 @@ const writeReleaseEnvelope = async (artifactRoot, envelope)=>{
134
190
  if (!envelopePath) throw new Error('[ultramodern-release-envelope] could not resolve release envelope path.');
135
191
  await promises_default().writeFile(envelopePath, `${(0, external_index_js_namespaceObject.canonicalSerializeMicroVerticalReleaseEnvelope)(envelope)}\n`);
136
192
  };
137
- const readBuildArtifact = async (distDirectory)=>{
138
- const artifactPath = external_node_path_default().join(distDirectory, universal_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE);
193
+ const readBuildArtifact = async (distDirectory, requirePromotable = true)=>{
194
+ const artifactPath = external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE);
139
195
  const artifact = await readJson(artifactPath);
140
- if (!(0, universal_namespaceObject.isUltramodernBuildArtifact)(artifact)) throw new Error(`[ultramodern-release-envelope] ${universal_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE} is missing or invalid.`);
141
- if ('workspace' === artifact.deliveryUnit.sourceRevision) throw new Error('[ultramodern-release-envelope] sourceRevision "workspace" cannot produce a promotable full-stack envelope.');
196
+ 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.`);
197
+ if ('workspace' === artifact.deliveryUnit.sourceRevision) {
198
+ if (!requirePromotable) return;
199
+ throw new Error('[ultramodern-release-envelope] sourceRevision "workspace" cannot produce a promotable envelope.');
200
+ }
142
201
  return artifact;
143
202
  };
144
203
  const assertIdentityBlock = (value, identity, location, includeReleaseVersion)=>{
@@ -154,7 +213,7 @@ const assertIdentityBlock = (value, identity, location, includeReleaseVersion)=>
154
213
  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])}.`);
155
214
  };
156
215
  const readBackendManifest = async (distDirectory, identity)=>{
157
- const manifest = await readJson(external_node_path_default().join(distDirectory, universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE));
216
+ const manifest = await readJson(external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE));
158
217
  if (!isRecord(manifest) || !isRecord(manifest.backendFederation)) throw new Error('[ultramodern-release-envelope] backend federation manifest is missing backendFederation metadata.');
159
218
  assertIdentityBlock(manifest.backendFederation.deliveryUnit, identity, 'backendFederation.deliveryUnit', true);
160
219
  const versionBoundary = manifest.backendFederation.versionBoundary;
@@ -207,7 +266,7 @@ const releaseArtifact = (logicalPath, runtime)=>({
207
266
  const writeReleaseIdentityCarrierMetadata = async (artifactRoot, identity, carrierPaths)=>{
208
267
  const surfacesByPath = new Map();
209
268
  for (const [surface, logicalPaths] of Object.entries(carrierPaths)){
210
- if (0 === logicalPaths.length) throw new Error(`[ultramodern-release-envelope] ${surface} has no declared release-identity carrier artifact.`);
269
+ if (0 === logicalPaths.length && 'ssr' !== surface && 'uiClient' !== surface) throw new Error(`[ultramodern-release-envelope] ${surface} has no declared release-identity carrier artifact.`);
211
270
  for (const logicalPath of logicalPaths){
212
271
  const surfaces = surfacesByPath.get(logicalPath) ?? new Set();
213
272
  surfaces.add(surface);
@@ -247,12 +306,12 @@ const writeReleaseIdentityCarrierMetadata = async (artifactRoot, identity, carri
247
306
  }, null, 2)}\n`);
248
307
  return releaseArtifact(MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH, 'release-identity-metadata');
249
308
  };
250
- const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
309
+ const createReleaseArtifactInputs = async (distDirectory, identity, target, apiOnly)=>{
251
310
  const files = await collectFiles(distDirectory);
252
- 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.');
311
+ 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.');
253
312
  const uiClientPaths = files.filter((logicalPath)=>{
254
313
  const topLevel = logicalPath.split('/')[0];
255
- return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel || [
314
+ return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel && logicalPath !== CRAWLER_POLICY_PATH && !isPublicMetadataPath(logicalPath) || [
256
315
  'index.html',
257
316
  'mf-manifest.json',
258
317
  'mf-stats.json',
@@ -261,16 +320,17 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
261
320
  'loadable-stats.json'
262
321
  ].includes(logicalPath);
263
322
  });
264
- 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));
323
+ 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) && !isEffectBffWorkerArtifact(logicalPath));
265
324
  const nodeApiEntryPaths = files.filter((logicalPath)=>logicalPath.startsWith('api/') && COMPILED_MODULE_PATTERN.test(logicalPath));
266
- 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));
267
- if (0 === uiClientPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no UI/client artifacts.`);
268
- if (0 === ssrPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no ${'node' === target ? 'Node' : 'workerd'} SSR artifacts.`);
269
- 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'}.`);
270
- const clientExecutionPaths = await manifestReferencedClientModules(distDirectory, files);
271
- if (0 === clientExecutionPaths.length) throw new Error('[ultramodern-release-envelope] UI/client manifest references no compiled execution module.');
272
- const ssrExecutionPaths = await routeReferencedSsrModules(distDirectory, files, target);
273
- if (0 === ssrExecutionPaths.length) throw new Error(`[ultramodern-release-envelope] route manifest references no emitted ${'node' === target ? 'Node' : 'Cloudflare'} SSR execution module.`);
325
+ const apiBackendPaths = 'node' === target ? files.filter((logicalPath)=>(logicalPath.startsWith('api/') || logicalPath.startsWith('shared/')) && COMPILED_MODULE_PATTERN.test(logicalPath)) : files.filter(isEffectBffWorkerArtifact);
326
+ 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.');
327
+ if (!apiOnly && 0 === uiClientPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no UI/client artifacts.`);
328
+ if (!apiOnly && 0 === ssrPaths.length) throw new Error(`[ultramodern-release-envelope] ${target} full-stack MicroVertical has no ${'node' === target ? 'Node' : 'workerd'} SSR artifacts.`);
329
+ if ('node' === target && 0 === nodeApiEntryPaths.length || 'cloudflare' === target && !files.some((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath)) || 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'}.`);
330
+ const clientExecutionPaths = apiOnly ? [] : await manifestReferencedClientModules(distDirectory, files);
331
+ if (!apiOnly && 0 === clientExecutionPaths.length) throw new Error('[ultramodern-release-envelope] UI/client manifest references no compiled execution module.');
332
+ const ssrExecutionPaths = apiOnly ? [] : await routeReferencedSsrModules(distDirectory, files, target);
333
+ if (!apiOnly && 0 === ssrExecutionPaths.length) throw new Error(`[ultramodern-release-envelope] route manifest references no emitted ${'node' === target ? 'Node' : 'Cloudflare'} SSR execution module.`);
274
334
  const runtimeByPath = new Map();
275
335
  const add = (paths, runtime)=>{
276
336
  for (const logicalPath of paths){
@@ -280,13 +340,15 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
280
340
  }
281
341
  };
282
342
  add(uiClientPaths, 'browser');
343
+ add(files.filter((logicalPath)=>logicalPath === CRAWLER_POLICY_PATH), 'crawler-policy');
344
+ add(files.filter(isPublicMetadataPath), 'public-metadata');
283
345
  add(ssrPaths, 'node' === target ? 'nodejs' : 'workerd');
284
346
  add(apiBackendPaths, 'node' === target ? 'nodejs' : 'workerd-effect');
285
347
  add([
286
- universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE
348
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE
287
349
  ], 'module-federation-manifest');
288
350
  add([
289
- universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
351
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
290
352
  ], 'node' === target ? 'nodejs' : 'commonjs-module');
291
353
  const surfaces = {
292
354
  uiClient: [
@@ -299,8 +361,8 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
299
361
  ...apiBackendPaths
300
362
  ].sort((left, right)=>left.localeCompare(right)),
301
363
  backendFederation: {
302
- manifest: universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
303
- container: universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
364
+ manifest: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
365
+ container: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
304
366
  }
305
367
  };
306
368
  const artifacts = [
@@ -309,8 +371,8 @@ const createReleaseArtifactInputs = async (distDirectory, identity, target)=>{
309
371
  const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(distDirectory, identity, {
310
372
  apiBackend: apiBackendPaths,
311
373
  backendFederation: [
312
- universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
313
- universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
374
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
375
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
314
376
  ],
315
377
  ssr: [
316
378
  ...new Set([
@@ -336,17 +398,17 @@ const pathExists = async (filePath)=>{
336
398
  return false;
337
399
  }
338
400
  };
339
- const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, distDirectory, target })=>{
340
- if (apiOnly) return;
341
- const backendManifestPath = external_node_path_default().join(distDirectory, universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE);
342
- const backendContainerPath = external_node_path_default().join(distDirectory, universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE);
401
+ const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, distDirectory, requirePromotable = true, target })=>{
402
+ const backendManifestPath = external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE);
403
+ const backendContainerPath = external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE);
343
404
  const [hasBackendManifest, hasBackendContainer] = await Promise.all([
344
405
  pathExists(backendManifestPath),
345
406
  pathExists(backendContainerPath)
346
407
  ]);
347
- if (!hasBackendManifest && !hasBackendContainer) return;
348
- if (!hasBackendManifest || !hasBackendContainer) throw new Error('[ultramodern-release-envelope] full-stack MicroVertical backend federation manifest and container must be emitted together.');
349
- const buildArtifact = await readBuildArtifact(distDirectory);
408
+ if (!hasBackendManifest && !hasBackendContainer && !apiOnly) return;
409
+ if (!hasBackendManifest || !hasBackendContainer) throw new Error('[ultramodern-release-envelope] MicroVertical backend federation manifest and container must be emitted together.');
410
+ const buildArtifact = await readBuildArtifact(distDirectory, requirePromotable);
411
+ if (!buildArtifact) return;
350
412
  const identity = {
351
413
  unitId: buildArtifact.deliveryUnit.unitId,
352
414
  buildMarker: buildArtifact.deliveryUnit.buildMarker,
@@ -354,7 +416,7 @@ const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, distDirector
354
416
  releaseVersion: buildArtifact.deliveryUnit.version
355
417
  };
356
418
  await readBackendManifest(distDirectory, identity);
357
- const { artifacts, surfaces } = await createReleaseArtifactInputs(distDirectory, identity, target);
419
+ const { artifacts, surfaces } = await createReleaseArtifactInputs(distDirectory, identity, target, apiOnly);
358
420
  const envelope = await (0, external_index_js_namespaceObject.createMicroVerticalReleaseEnvelope)({
359
421
  artifactRoot: distDirectory,
360
422
  target,
@@ -385,19 +447,16 @@ const readFrameworkMicroVerticalReleaseEnvelope = async ({ artifactRoot, expecte
385
447
  });
386
448
  };
387
449
  const verifyBuildOutputReleaseEnvelope = async (distDirectory, expectedTarget)=>{
388
- const [hasEnvelope, hasBuildArtifact, hasBackendManifest, hasBackendEntry] = await Promise.all([
450
+ const [hasEnvelope, hasBuildArtifact] = await Promise.all([
389
451
  pathExists(external_node_path_default().join(distDirectory, MICROVERTICAL_RELEASE_ENVELOPE_PATH)),
390
- pathExists(external_node_path_default().join(distDirectory, universal_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE)),
391
- pathExists(external_node_path_default().join(distDirectory, universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE)),
392
- pathExists(external_node_path_default().join(distDirectory, universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE))
452
+ pathExists(external_node_path_default().join(distDirectory, backend_federation_contracts_namespaceObject.ULTRAMODERN_BUILD_ARTIFACT_FILE))
393
453
  ]);
394
- const isFullStackMicroVertical = hasBuildArtifact && (hasBackendManifest || hasBackendEntry);
395
454
  return readFrameworkMicroVerticalReleaseEnvelope({
396
455
  artifactRoot: distDirectory,
397
456
  ...expectedTarget ? {
398
457
  expectedTarget
399
458
  } : {},
400
- required: hasEnvelope || isFullStackMicroVertical
459
+ required: hasEnvelope || hasBuildArtifact
401
460
  });
402
461
  };
403
462
  const verifyNodeReleaseEnvelopeStaging = async ({ outputDirectory })=>readFrameworkMicroVerticalReleaseEnvelope({
@@ -405,21 +464,22 @@ const verifyNodeReleaseEnvelopeStaging = async ({ outputDirectory })=>readFramew
405
464
  expectedTarget: 'node',
406
465
  required: true
407
466
  });
408
- const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=>{
467
+ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity, apiOnly, declaredPublicAssets)=>{
409
468
  const files = await collectFiles(outputDirectory);
469
+ const declaredPublicAssetPaths = resolveDeclaredPublicAssets(files, declaredPublicAssets, 'Node');
410
470
  for (const requiredPath of [
411
471
  'index.js',
412
472
  'package.json',
413
- universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
414
- universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
473
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
474
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
415
475
  ])if (!files.includes(requiredPath)) throw new Error(`[ultramodern-release-envelope] final Node staging is missing ${requiredPath}.`);
416
476
  const backendFederationPaths = new Set([
417
- universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
418
- universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
477
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
478
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
419
479
  ]);
420
480
  const uiClientPaths = files.filter((logicalPath)=>{
421
481
  const topLevel = logicalPath.split('/')[0];
422
- return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel || [
482
+ return 'static' === topLevel || 'html' === topLevel || 'public' === topLevel && logicalPath !== CRAWLER_POLICY_PATH && !isPublicMetadataPath(logicalPath) && !declaredPublicAssetPaths.has(logicalPath) || [
423
483
  'index.html',
424
484
  'mf-manifest.json',
425
485
  'mf-stats.json',
@@ -430,6 +490,7 @@ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=
430
490
  });
431
491
  const ssrPaths = files.filter((logicalPath)=>'index.js' === logicalPath || logicalPath.startsWith('bundles/') && COMPILED_MODULE_PATTERN.test(logicalPath));
432
492
  const apiBackendPaths = files.filter((logicalPath)=>(logicalPath.startsWith('api/') || logicalPath.startsWith('shared/')) && COMPILED_MODULE_PATTERN.test(logicalPath));
493
+ 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.');
433
494
  for (const [surface, paths] of [
434
495
  [
435
496
  'UI/client',
@@ -437,32 +498,35 @@ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=
437
498
  ],
438
499
  [
439
500
  'Node SSR',
440
- ssrPaths
501
+ apiOnly ? [] : ssrPaths
441
502
  ],
442
503
  [
443
504
  'Node API/backend',
444
505
  apiBackendPaths
445
506
  ]
446
- ])if (0 === paths.length) throw new Error(`[ultramodern-release-envelope] final Node staging has no ${surface} artifacts.`);
447
- const clientExecutionPaths = await manifestReferencedClientModules(outputDirectory, files);
448
- const ssrExecutionPaths = await routeReferencedSsrModules(outputDirectory, files, 'node');
449
- 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.');
507
+ ])if (0 === paths.length && (!apiOnly || 'Node API/backend' === surface)) throw new Error(`[ultramodern-release-envelope] final Node staging has no ${surface} artifacts.`);
508
+ const clientExecutionPaths = apiOnly ? [] : await manifestReferencedClientModules(outputDirectory, files);
509
+ const ssrExecutionPaths = apiOnly ? [] : await routeReferencedSsrModules(outputDirectory, files, 'node');
510
+ 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.');
450
511
  const runtimeByPath = new Map(files.filter((logicalPath)=>!backendFederationPaths.has(logicalPath)).map((logicalPath)=>[
451
512
  logicalPath,
452
513
  'nodejs-deployment'
453
514
  ]));
454
515
  for (const logicalPath of uiClientPaths)runtimeByPath.set(logicalPath, 'browser');
455
- for (const logicalPath of ssrPaths)runtimeByPath.set(logicalPath, 'nodejs');
516
+ for (const logicalPath of declaredPublicAssetPaths)runtimeByPath.set(logicalPath, DECLARED_PUBLIC_ASSET_RUNTIME);
517
+ if (files.includes(CRAWLER_POLICY_PATH)) runtimeByPath.set(CRAWLER_POLICY_PATH, 'crawler-policy');
518
+ for (const logicalPath of files.filter(isPublicMetadataPath))runtimeByPath.set(logicalPath, 'public-metadata');
519
+ for (const logicalPath of apiOnly ? [] : ssrPaths)runtimeByPath.set(logicalPath, 'nodejs');
456
520
  for (const logicalPath of apiBackendPaths)runtimeByPath.set(logicalPath, 'nodejs');
457
- runtimeByPath.set(universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE, 'module-federation-manifest');
458
- runtimeByPath.set(universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE, 'nodejs');
521
+ runtimeByPath.set(backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE, 'module-federation-manifest');
522
+ runtimeByPath.set(backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE, 'nodejs');
459
523
  const identityCarrierMetadata = await writeReleaseIdentityCarrierMetadata(outputDirectory, identity, {
460
524
  apiBackend: apiBackendPaths,
461
525
  backendFederation: [
462
- universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
463
- universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
526
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
527
+ backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
464
528
  ],
465
- ssr: [
529
+ ssr: apiOnly ? [] : [
466
530
  ...new Set([
467
531
  ...ssrExecutionPaths,
468
532
  ...ssrPaths.filter((logicalPath)=>'index.js' !== logicalPath)
@@ -481,23 +545,23 @@ const createNodeStagedReleaseArtifactInputs = async (outputDirectory, identity)=
481
545
  uiClient: [
482
546
  ...uiClientPaths
483
547
  ].sort((left, right)=>left.localeCompare(right)),
484
- ssr: [
548
+ ssr: apiOnly ? [] : [
485
549
  ...ssrPaths
486
550
  ].sort((left, right)=>left.localeCompare(right)),
487
551
  apiBackend: [
488
552
  ...apiBackendPaths
489
553
  ].sort((left, right)=>left.localeCompare(right)),
490
554
  backendFederation: {
491
- manifest: universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
492
- container: universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
555
+ manifest: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE,
556
+ container: backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE
493
557
  }
494
558
  }
495
559
  };
496
560
  };
497
- const emitNodeStagedReleaseEnvelope = async ({ distDirectory, outputDirectory })=>{
561
+ const emitNodeStagedReleaseEnvelope = async ({ declaredPublicAssets = [], distDirectory, outputDirectory })=>{
498
562
  const source = await verifyBuildOutputReleaseEnvelope(distDirectory, 'node');
499
563
  if (!source) return;
500
- const { artifacts, surfaces } = await createNodeStagedReleaseArtifactInputs(outputDirectory, source.identity);
564
+ const { artifacts, surfaces } = await createNodeStagedReleaseArtifactInputs(outputDirectory, source.identity, 0 === source.surfaces.uiClient.length, declaredPublicAssets);
501
565
  const staged = await (0, external_index_js_namespaceObject.createMicroVerticalReleaseEnvelope)({
502
566
  artifactRoot: outputDirectory,
503
567
  target: 'node',
@@ -515,21 +579,26 @@ const stageCloudflareReleaseEnvelope = async ({ distDirectory, outputDirectory }
515
579
  if (await pathExists(stagedEnvelopePath)) throw new Error('[ultramodern-release-envelope] Cloudflare staging contains a stale envelope before final output generation.');
516
580
  return source;
517
581
  };
518
- const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, identity)=>{
582
+ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, identity, apiOnly, declaredPublicAssets)=>{
519
583
  const files = await collectFiles(outputDirectory);
584
+ const declaredPublicAssetPaths = resolveDeclaredPublicAssets(files, declaredPublicAssets, 'Cloudflare');
520
585
  for (const requiredPath of [
521
586
  'server/index.mjs',
522
587
  'server/modern-worker-manifest.json',
523
588
  'wrangler.json',
524
589
  'package.json',
525
- 'worker/package.json'
590
+ ...apiOnly ? [] : [
591
+ 'worker/package.json'
592
+ ]
526
593
  ])if (!files.includes(requiredPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${requiredPath}.`);
527
594
  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.');
528
- const backendManifestPath = `public/${universal_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE}`;
529
- const backendContainerPath = `public/${universal_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE}`;
530
- const apiBackendPaths = files.filter((logicalPath)=>EFFECT_BFF_WORKER_PATTERN.test(logicalPath));
531
- const ssrPaths = files.filter((logicalPath)=>(logicalPath.startsWith('server/') || logicalPath.startsWith('worker/')) && COMPILED_MODULE_PATTERN.test(logicalPath) && !EFFECT_BFF_WORKER_PATTERN.test(logicalPath));
532
- const uiClientPaths = files.filter((logicalPath)=>logicalPath.startsWith('public/') && logicalPath !== backendManifestPath && logicalPath !== backendContainerPath);
595
+ const backendManifestPath = `public/${backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_MANIFEST_FILE}`;
596
+ const backendContainerPath = `public/${backend_federation_contracts_namespaceObject.BACKEND_FEDERATION_REMOTE_ENTRY_FILE}`;
597
+ const apiBackendPaths = files.filter(isEffectBffWorkerArtifact);
598
+ if (!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.');
599
+ const ssrPaths = files.filter((logicalPath)=>(logicalPath.startsWith('server/') || logicalPath.startsWith('worker/')) && COMPILED_MODULE_PATTERN.test(logicalPath) && !isEffectBffWorkerArtifact(logicalPath));
600
+ 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);
601
+ 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.');
533
602
  for (const [surface, paths] of [
534
603
  [
535
604
  'UI/client',
@@ -537,27 +606,32 @@ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, iden
537
606
  ],
538
607
  [
539
608
  'Cloudflare SSR',
540
- ssrPaths
609
+ apiOnly ? [] : ssrPaths
541
610
  ],
542
611
  [
543
612
  'Cloudflare API/backend',
544
613
  apiBackendPaths
545
614
  ]
546
- ])if (0 === paths.length) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging has no ${surface} artifacts.`);
615
+ ])if (0 === paths.length && (!apiOnly || 'Cloudflare API/backend' === surface)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging has no ${surface} artifacts.`);
547
616
  for (const logicalPath of [
548
617
  backendManifestPath,
549
618
  backendContainerPath
550
619
  ])if (!files.includes(logicalPath)) throw new Error(`[ultramodern-release-envelope] final Cloudflare staging is missing ${logicalPath}.`);
551
- const clientExecutionPaths = await manifestReferencedClientModules(outputDirectory, files, 'public/mf-manifest.json');
552
- const ssrExecutionPaths = await routeReferencedSsrModules(outputDirectory, files, 'cloudflare', 'server/route.json');
553
- 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.');
620
+ const clientExecutionPaths = apiOnly ? [] : await manifestReferencedClientModules(outputDirectory, files, 'public/mf-manifest.json');
621
+ const ssrExecutionPaths = apiOnly ? [] : await routeReferencedSsrModules(outputDirectory, files, 'cloudflare', 'server/route.json');
622
+ 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.');
554
623
  const runtimeByPath = new Map();
555
624
  for (const logicalPath of files)runtimeByPath.set(logicalPath, 'cloudflare-deployment');
556
625
  const add = (paths, runtime)=>{
557
626
  for (const logicalPath of paths)runtimeByPath.set(logicalPath, runtime);
558
627
  };
559
628
  add(uiClientPaths, 'browser');
560
- add(ssrPaths, 'workerd');
629
+ add([
630
+ ...declaredPublicAssetPaths
631
+ ], DECLARED_PUBLIC_ASSET_RUNTIME);
632
+ if (files.includes(CRAWLER_POLICY_PATH)) runtimeByPath.set(CRAWLER_POLICY_PATH, 'crawler-policy');
633
+ add(files.filter(isPublicMetadataPath), 'public-metadata');
634
+ add(apiOnly ? [] : ssrPaths, 'workerd');
561
635
  add(apiBackendPaths, 'workerd-effect');
562
636
  add([
563
637
  backendManifestPath
@@ -571,7 +645,7 @@ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, iden
571
645
  backendManifestPath,
572
646
  backendContainerPath
573
647
  ],
574
- ssr: [
648
+ ssr: apiOnly ? [] : [
575
649
  ...new Set([
576
650
  ...ssrExecutionPaths,
577
651
  ...ssrPaths.filter((logicalPath)=>logicalPath.startsWith('worker/'))
@@ -590,7 +664,7 @@ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, iden
590
664
  uiClient: [
591
665
  ...uiClientPaths
592
666
  ].sort((left, right)=>left.localeCompare(right)),
593
- ssr: [
667
+ ssr: apiOnly ? [] : [
594
668
  ...ssrPaths
595
669
  ].sort((left, right)=>left.localeCompare(right)),
596
670
  apiBackend: [
@@ -603,10 +677,10 @@ const createCloudflareStagedReleaseArtifactInputs = async (outputDirectory, iden
603
677
  }
604
678
  };
605
679
  };
606
- const emitCloudflareStagedReleaseEnvelope = async ({ distDirectory, outputDirectory })=>{
680
+ const emitCloudflareStagedReleaseEnvelope = async ({ declaredPublicAssets = [], distDirectory, outputDirectory })=>{
607
681
  const source = await verifyBuildOutputReleaseEnvelope(distDirectory, 'cloudflare');
608
682
  if (!source) return;
609
- const { artifacts, surfaces } = await createCloudflareStagedReleaseArtifactInputs(outputDirectory, source.identity);
683
+ const { artifacts, surfaces } = await createCloudflareStagedReleaseArtifactInputs(outputDirectory, source.identity, 0 === source.surfaces.uiClient.length, declaredPublicAssets);
610
684
  const staged = await (0, external_index_js_namespaceObject.createMicroVerticalReleaseEnvelope)({
611
685
  artifactRoot: outputDirectory,
612
686
  target: 'cloudflare',
@@ -232,7 +232,7 @@ const assertUniqueSortedArtifacts = (artifacts, location)=>{
232
232
  if (paths.some((logicalPath, index)=>logicalPath !== sorted[index])) throw new Error(`${location} must be sorted by logicalPath.`);
233
233
  };
234
234
  const assertSurfacePaths = (value, location)=>{
235
- if (!Array.isArray(value) || 0 === value.length) throw new Error(`${location} must contain at least one artifact path.`);
235
+ if (!Array.isArray(value)) throw new Error(`${location} must be an array of artifact paths.`);
236
236
  const paths = value.map((item, index)=>assertNormalizedLogicalPath(item, `${location}[${index}]`));
237
237
  const sorted = [
238
238
  ...paths
@@ -254,10 +254,16 @@ const assertSurfaces = (value)=>{
254
254
  'manifest',
255
255
  'container'
256
256
  ], 'surfaces.backendFederation');
257
+ const uiClient = assertSurfacePaths(surfaces.uiClient, 'surfaces.uiClient');
258
+ const ssr = assertSurfacePaths(surfaces.ssr, 'surfaces.ssr');
259
+ const apiBackend = assertSurfacePaths(surfaces.apiBackend, 'surfaces.apiBackend');
260
+ if (uiClient.length > 0 && 0 === ssr.length) throw new Error('surfaces.ssr must contain at least one artifact path when UI/client is declared.');
261
+ if (ssr.length > 0 && 0 === uiClient.length) throw new Error('surfaces.uiClient must contain at least one artifact path when SSR is declared.');
262
+ if (0 === apiBackend.length) throw new Error('surfaces.apiBackend must contain at least one artifact path.');
257
263
  return {
258
- uiClient: assertSurfacePaths(surfaces.uiClient, 'surfaces.uiClient'),
259
- ssr: assertSurfacePaths(surfaces.ssr, 'surfaces.ssr'),
260
- apiBackend: assertSurfacePaths(surfaces.apiBackend, 'surfaces.apiBackend'),
264
+ uiClient,
265
+ ssr,
266
+ apiBackend,
261
267
  backendFederation: {
262
268
  manifest: assertNormalizedLogicalPath(backendFederation.manifest, 'surfaces.backendFederation.manifest'),
263
269
  container: assertNormalizedLogicalPath(backendFederation.container, 'surfaces.backendFederation.container')