@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,20 @@
1
+ import { resolveBrowserManifestAddress } from "@modern-js/surface-resolution";
2
+ import { resolveDeployTarget } from "../deploy-output/target.mjs";
3
+ import { getBuildConfigEnvironment } from "./build-environment.mjs";
4
+ function createRemoteManifestUrl(options) {
5
+ const env = {
6
+ ...Object.fromEntries([
7
+ options.manifestEnv,
8
+ options.publicUrlEnv,
9
+ 'ULTRAMODERN_CLOUDFLARE_WORKERS_DEV_SUBDOMAIN'
10
+ ].map((name)=>[
11
+ name,
12
+ getBuildConfigEnvironment(name)
13
+ ])),
14
+ MODERNJS_DEPLOY: resolveDeployTarget().target
15
+ };
16
+ const address = resolveBrowserManifestAddress(env, options, getBuildConfigEnvironment('NODE_ENV') ?? 'production');
17
+ if (!address.ok) throw new Error(`Remote ${options.mfName}: ${address.reason}`);
18
+ return env[options.manifestEnv]?.trim() || `${options.mfName}@${address.manifestUrl}`;
19
+ }
20
+ export { createRemoteManifestUrl };
@@ -1,5 +1,6 @@
1
1
  import node_path from "node:path";
2
2
  import { fs } from "@modern-js/utils";
3
+ import { CLOUDFLARE_PUBLIC_ASSET_SCOPE, normalizeDeclaredPublicAssets, stageDeclaredPublicAssets } from "../deploy-output/public-assets.mjs";
3
4
  import { RESERVED_ARTIFACT_DESTINATION_DIRECTORIES, RESERVED_ARTIFACT_DESTINATION_FILES, ROUTE_SPEC_OUTPUT } from "./constants.mjs";
4
5
  import { normalizeRelativePath } from "./utils.mjs";
5
6
  const normalizeCloudflareArtifact = (artifact, index)=>{
@@ -15,18 +16,7 @@ const normalizeCloudflareArtifact = (artifact, index)=>{
15
16
  };
16
17
  };
17
18
  const getCloudflareArtifacts = (modernConfig)=>(modernConfig.deploy?.worker?.artifacts ?? []).map(normalizeCloudflareArtifact);
18
- const normalizeCloudflarePublicAsset = (asset, index)=>{
19
- const from = normalizeRelativePath(asset.from, `deploy.worker.publicAssets[${index}].from`, 'app root');
20
- const to = normalizeRelativePath(asset.to, `deploy.worker.publicAssets[${index}].to`, 'Cloudflare public output', {
21
- allowRoot: true
22
- });
23
- return {
24
- from,
25
- to,
26
- index
27
- };
28
- };
29
- const getCloudflarePublicAssets = (modernConfig)=>(modernConfig.deploy?.worker?.publicAssets ?? []).map(normalizeCloudflarePublicAsset);
19
+ const getCloudflarePublicAssets = (modernConfig)=>normalizeDeclaredPublicAssets(modernConfig.deploy?.worker?.publicAssets, CLOUDFLARE_PUBLIC_ASSET_SCOPE);
30
20
  const copyCloudflareArtifacts = async (appDirectory, outputDirectory, artifacts)=>{
31
21
  for (const artifact of artifacts){
32
22
  const sourcePath = node_path.join(appDirectory, artifact.from);
@@ -34,13 +24,12 @@ const copyCloudflareArtifacts = async (appDirectory, outputDirectory, artifacts)
34
24
  await fs.copy(sourcePath, node_path.join(outputDirectory, artifact.to));
35
25
  }
36
26
  };
37
- const copyCloudflarePublicAssets = async (appDirectory, publicDirectory, publicAssets)=>{
38
- for (const asset of publicAssets){
39
- const sourcePath = node_path.join(appDirectory, asset.from);
40
- if (!await fs.pathExists(sourcePath)) throw new Error(`deploy.worker.publicAssets[${asset.index}].from does not exist: ${asset.from}`);
41
- await fs.copy(sourcePath, node_path.join(publicDirectory, asset.to));
42
- }
43
- };
27
+ const copyCloudflarePublicAssets = async (appDirectory, outputDirectory, publicAssets)=>stageDeclaredPublicAssets({
28
+ appDirectory,
29
+ outputDirectory,
30
+ assets: publicAssets,
31
+ scope: CLOUDFLARE_PUBLIC_ASSET_SCOPE
32
+ });
44
33
  const copyCloudflareD1Migrations = async (appDirectory, outputDirectory, modernConfig)=>{
45
34
  for (const [index, database] of (modernConfig.deploy?.worker?.d1Databases ?? []).entries()){
46
35
  if (!database.migrationsDir) continue;
@@ -18,7 +18,7 @@ const DEFAULT_SERVER_ONLY_PUBLIC_ASSET_EXCLUDES = [
18
18
  ];
19
19
  const BFF_EFFECT_WORKER_ENTRY = `${WORKER_BUNDLE_DIRECTORY}/__modern_bff_effect.js`;
20
20
  const BFF_EFFECT_WORKER_DISPATCHER_EXPORT = '__modern_create_effect_bff_dispatcher';
21
- const EFFECT_BFF_CLOUDFLARE_IMPORT_GUIDANCE = 'Ensure the Effect API entry exists at api/index.ts or bff.effect.entry, and import Cloudflare edge handlers from @modern-js/plugin-bff/effect-edge instead of lambda/Hono server helpers.';
21
+ const EFFECT_BFF_CLOUDFLARE_IMPORT_GUIDANCE = 'Ensure the Effect API entry exists at api/index.ts or bff.effect.entry, and import Cloudflare edge handlers from @modern-js/bff-effect/effect-edge instead of lambda/Hono server helpers.';
22
22
  const DEFAULT_COMPATIBILITY_DATE = '2026-06-02';
23
23
  const COMPATIBILITY_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/u;
24
24
  const REQUIRED_COMPATIBILITY_FLAGS = CLOUDFLARE_REQUIRED_COMPATIBILITY_FLAGS;
@@ -1,13 +1,13 @@
1
1
  import node_path from "node:path";
2
+ import { ULTRAMODERN_BUILD_ARTIFACT_PATH, isUltramodernBuildArtifact, nonEmptyString, toDeliveryUnitIdentity } from "@modern-js/backend-federation-contracts";
2
3
  import { fs } from "@modern-js/utils";
3
- import { ULTRAMODERN_BUILD_ARTIFACT_PATH, ULTRAMODERN_BUILD_MODULE_PATH, isUltramodernBuildArtifact, nonEmptyString, toDeliveryUnitIdentity } from "@modern-js/utils/universal";
4
4
  import { resolveUltramodernReleaseIdentity } from "../release-identity.mjs";
5
5
  import { isRecord } from "./utils.mjs";
6
- const COMPACT_CONFIG_PATH = '.modernjs/ultramodern.json';
6
+ const TOPOLOGY_PATH = 'topology/reference-topology.json';
7
7
  const findWorkspaceRoot = async (appDirectory)=>{
8
8
  let current = node_path.resolve(appDirectory);
9
9
  for(;;){
10
- if (await fs.pathExists(node_path.join(current, COMPACT_CONFIG_PATH))) return current;
10
+ if (await fs.pathExists(node_path.join(current, TOPOLOGY_PATH))) return current;
11
11
  const parent = node_path.dirname(current);
12
12
  if (parent === current) return;
13
13
  current = parent;
@@ -24,36 +24,25 @@ const stampReleaseIdentity = (identity, workspaceRoot)=>{
24
24
  })
25
25
  };
26
26
  };
27
- const resolveCompactApp = async (appDirectory)=>{
27
+ const resolveTopologyApp = async (appDirectory)=>{
28
28
  const workspaceRoot = await findWorkspaceRoot(appDirectory);
29
29
  if (!workspaceRoot) return;
30
- let compactConfig;
31
- try {
32
- compactConfig = await fs.readJSON(node_path.join(workspaceRoot, COMPACT_CONFIG_PATH));
33
- } catch {
34
- return {
35
- workspaceRoot
36
- };
37
- }
38
- if (!isRecord(compactConfig)) return {
39
- workspaceRoot
40
- };
41
- const topology = isRecord(compactConfig.topology) ? compactConfig.topology : void 0;
42
- const apps = Array.isArray(topology?.apps) ? topology.apps : void 0;
43
- if (!apps) return {
44
- app: compactConfig,
45
- workspaceRoot
46
- };
30
+ const topology = await fs.readJSON(node_path.join(workspaceRoot, TOPOLOGY_PATH));
31
+ if (!isRecord(topology) || !isRecord(topology.shell) || !Array.isArray(topology.verticals) || void 0 !== topology.shells && !Array.isArray(topology.shells)) throw new Error('[cloudflare-delivery-unit] Invalid declared reference topology.');
32
+ const apps = [
33
+ topology.shell,
34
+ ...topology.verticals,
35
+ ...Array.isArray(topology.shells) ? topology.shells : []
36
+ ];
47
37
  const resolvedAppDirectory = node_path.resolve(appDirectory);
48
38
  const app = apps.find((candidate)=>{
49
39
  if (!isRecord(candidate)) return false;
50
40
  const appPath = nonEmptyString(candidate.path);
51
41
  return void 0 !== appPath && node_path.resolve(workspaceRoot, appPath.replace(/^\.\/+/u, '')) === resolvedAppDirectory;
52
42
  });
43
+ if (!isRecord(app)) throw new Error(`[cloudflare-delivery-unit] ${appDirectory} is missing from the declared reference topology.`);
53
44
  return {
54
- ...isRecord(app) ? {
55
- app
56
- } : {},
45
+ app,
57
46
  workspaceRoot
58
47
  };
59
48
  };
@@ -80,30 +69,22 @@ const createDeliveryUnitStamp = (identity, app)=>{
80
69
  };
81
70
  };
82
71
  const resolveTopologyDeliveryUnit = async (appDirectory)=>{
83
- const resolved = await resolveCompactApp(appDirectory);
72
+ const resolved = await resolveTopologyApp(appDirectory);
84
73
  if (!resolved?.app) return;
85
74
  const identity = toDeliveryUnitIdentity(resolved.app.deliveryUnit);
86
- return identity ? createDeliveryUnitStamp(stampReleaseIdentity(identity, resolved.workspaceRoot), resolved.app) : void 0;
75
+ if (!identity) throw new Error('[cloudflare-delivery-unit] Declared app is missing a valid delivery-unit identity.');
76
+ return createDeliveryUnitStamp(stampReleaseIdentity(identity, resolved.workspaceRoot), resolved.app);
87
77
  };
88
78
  const resolveWorkerDeliveryUnitStamp = async (appDirectory)=>{
89
79
  const buildArtifactPath = node_path.join(appDirectory, ULTRAMODERN_BUILD_ARTIFACT_PATH);
90
- const buildModulePath = node_path.join(appDirectory, ULTRAMODERN_BUILD_MODULE_PATH);
91
80
  let identity;
92
81
  if (await fs.pathExists(buildArtifactPath)) {
93
82
  const artifact = await fs.readJSON(buildArtifactPath);
94
83
  if (!isUltramodernBuildArtifact(artifact)) return;
95
84
  identity = toDeliveryUnitIdentity(artifact.deliveryUnit);
96
- } else if (await fs.pathExists(buildModulePath)) {
97
- console.warn(`[cloudflare] ${buildArtifactPath} missing; falling back to legacy regex parsing of ${buildModulePath}. Regenerate the workspace to emit ultramodern-build.json.`);
98
- const source = await fs.readFile(buildModulePath, 'utf8');
99
- identity = toDeliveryUnitIdentity({
100
- buildMarker: source.match(/\bbuild:\s*['"]([^'"]+)['"]/u)?.[1],
101
- unitId: source.match(/\bunitId:\s*['"]([^'"]+)['"]/u)?.[1],
102
- sourceRevision: source.match(/\bsourceRevision:\s*['"]([^'"]+)['"]/u)?.[1]
103
- });
104
85
  }
105
86
  if (!identity) return;
106
- const resolved = await resolveCompactApp(appDirectory);
87
+ const resolved = await resolveTopologyApp(appDirectory);
107
88
  if (resolved) identity = stampReleaseIdentity(identity, resolved.workspaceRoot);
108
89
  return createDeliveryUnitStamp(identity, resolved?.app);
109
90
  };
@@ -1,4 +1,5 @@
1
1
  import node_path from "node:path";
2
+ import { BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_REMOTE_ENTRY_FILE, ULTRAMODERN_BUILD_ARTIFACT_FILE } from "@modern-js/backend-federation-contracts";
2
3
  import { fs } from "@modern-js/utils";
3
4
  import { createCloudflareOutputPlan } from "../cloudflare-output-plan.mjs";
4
5
  import { assertCloudflareOutput } from "../cloudflare-output-verifier/index.mjs";
@@ -31,12 +32,13 @@ const createCloudflarePreset = ({ api, appContext, modernConfig })=>{
31
32
  const publicAssetExcludes = getPublicAssetExcludes(appDirectory, modernConfig);
32
33
  const releaseEnvelopeEnabled = api.isPluginExists('@modern-js/ultramodern-release-envelope');
33
34
  let hasReleaseEnvelope = false;
35
+ let declaredPublicAssets = [];
34
36
  return {
35
37
  async prepare () {
36
38
  await fs.remove(outputDirectory);
37
39
  },
38
40
  async writeOutput () {
39
- if (releaseEnvelopeEnabled && await fs.pathExists(node_path.join(distDirectory, MICROVERTICAL_RELEASE_ENVELOPE_PATH))) await emitFrameworkMicroVerticalReleaseEnvelope({
41
+ if (releaseEnvelopeEnabled) await emitFrameworkMicroVerticalReleaseEnvelope({
40
42
  apiOnly,
41
43
  distDirectory,
42
44
  target: 'cloudflare'
@@ -45,6 +47,11 @@ const createCloudflarePreset = ({ api, appContext, modernConfig })=>{
45
47
  await fs.copy(distDirectory, publicDirectory, {
46
48
  filter: (src)=>{
47
49
  const relativePath = node_path.relative(distDirectory, src).replace(/\\/gu, '/');
50
+ if (apiOnly && '' !== relativePath && ![
51
+ BACKEND_FEDERATION_MANIFEST_FILE,
52
+ BACKEND_FEDERATION_REMOTE_ENTRY_FILE,
53
+ ULTRAMODERN_BUILD_ARTIFACT_FILE
54
+ ].includes(relativePath)) return false;
48
55
  return 'release' !== relativePath && !relativePath.startsWith('release/') && 'public' !== relativePath && !relativePath.startsWith('public/') && shouldCopyToPublicAssets(src, distDirectory, publicAssetExcludes);
49
56
  }
50
57
  });
@@ -68,7 +75,7 @@ const createCloudflarePreset = ({ api, appContext, modernConfig })=>{
68
75
  await fs.writeJSON(outputPlan.paths.workerPackage, outputPlan.packages.worker);
69
76
  }
70
77
  await copyCloudflareArtifacts(appDirectory, outputDirectory, cloudflareArtifacts);
71
- await copyCloudflarePublicAssets(appDirectory, publicDirectory, getCloudflarePublicAssets(modernConfig));
78
+ declaredPublicAssets = await copyCloudflarePublicAssets(appDirectory, outputDirectory, getCloudflarePublicAssets(modernConfig));
72
79
  await copyCloudflareD1Migrations(appDirectory, outputDirectory, modernConfig);
73
80
  await fs.writeJSON(wranglerConfigPath, createWranglerConfig(appDirectory, modernConfig), {
74
81
  spaces: 2
@@ -97,6 +104,7 @@ const createCloudflarePreset = ({ api, appContext, modernConfig })=>{
97
104
  });
98
105
  if (hasReleaseEnvelope) {
99
106
  await emitCloudflareStagedReleaseEnvelope({
107
+ declaredPublicAssets,
100
108
  distDirectory,
101
109
  outputDirectory
102
110
  });
@@ -1,5 +1,6 @@
1
1
  import node_path from "node:path";
2
2
  import { fs } from "@modern-js/utils";
3
+ import { getCloudflareWorkerRouteDataEntryName } from "../cloudflare-output-contract.mjs";
3
4
  import { readRouteSpec } from "./artifacts.mjs";
4
5
  import { ASSETS_BINDING, BFF_EFFECT_WORKER_DISPATCHER_EXPORT, BFF_EFFECT_WORKER_ENTRY, CLOUDFLARE_RUNTIME_TYPE, CLOUDFLARE_WORKER_BUNDLE_FORMAT, DEFAULT_SERVER_ONLY_PUBLIC_ASSET_EXCLUDES, EFFECT_BFF_CLOUDFLARE_IMPORT_GUIDANCE, LOADABLE_STATS_FILE, PUBLIC_ASSETS_DIRECTORY, ROUTE_MANIFEST_FILE, ROUTE_SPEC_FILE, ROUTE_SPEC_OUTPUT, SERVER_BUNDLE_DIRECTORY, WORKER_BUNDLE_DIRECTORY, WORKER_ENTRY } from "./constants.mjs";
5
6
  import { createI18nWorkerManifest } from "./i18n-worker.mjs";
@@ -65,13 +66,18 @@ const createWorkerManifest = async (outputDirectory, modernConfig, appContext, d
65
66
  const routeSpec = await readRouteSpec(outputDirectory);
66
67
  const routes = await Promise.all(routeSpec.routes.map(async (route)=>{
67
68
  const worker = 'string' == typeof route.worker ? route.worker : void 0;
69
+ const routeDataWorker = route.isSSR && 'string' == typeof route.entryName ? `${WORKER_BUNDLE_DIRECTORY}/${getCloudflareWorkerRouteDataEntryName(route.entryName)}.js` : void 0;
70
+ const hasRouteDataWorker = routeDataWorker ? await fs.pathExists(node_path.join(outputDirectory, routeDataWorker)) : false;
68
71
  return {
69
72
  urlPath: route.urlPath,
70
73
  entryName: route.entryName,
71
74
  entryPath: route.entryPath,
72
75
  isSSR: Boolean(route.isSSR),
73
76
  worker,
74
- workerExists: worker ? await fs.pathExists(node_path.join(outputDirectory, worker)) : false
77
+ workerExists: worker ? await fs.pathExists(node_path.join(outputDirectory, worker)) : false,
78
+ ...hasRouteDataWorker ? {
79
+ routeDataWorker
80
+ } : {}
75
81
  };
76
82
  }));
77
83
  const bffPrefix = modernConfig.bff?.prefix;
@@ -131,9 +137,12 @@ const createWorkerManifest = async (outputDirectory, modernConfig, appContext, d
131
137
  };
132
138
  const createWorkerModuleLoaders = (manifest)=>{
133
139
  const imports = new Map();
134
- for (const route of manifest.routeSpec.routes)if (route.worker && route.workerExists) {
135
- const importPath = `../${String(route.worker).replace(/^\/+/u, '')}`;
136
- imports.set(route.worker, `() => import(${JSON.stringify(importPath)})`);
140
+ for (const route of manifest.routeSpec.routes)for (const worker of [
141
+ route.workerExists ? route.worker : void 0,
142
+ route.routeDataWorker
143
+ ])if (worker) {
144
+ const importPath = `../${String(worker).replace(/^\/+/u, '')}`;
145
+ imports.set(worker, `() => import(${JSON.stringify(importPath)})`);
137
146
  }
138
147
  if (manifest.bff?.worker) {
139
148
  const importPath = `../${String(manifest.bff.worker).replace(/^\/+/u, '')}`;
@@ -1,12 +1,16 @@
1
1
  import node_path from "node:path";
2
2
  import { ASSETS_BINDING, COMPATIBILITY_DATE_PATTERN, DEFAULT_COMPATIBILITY_DATE, PUBLIC_ASSETS_DIRECTORY, REQUIRED_COMPATIBILITY_FLAGS, WORKER_ENTRY } from "./constants.mjs";
3
3
  import { isJsonRecord, normalizeRelativePath } from "./utils.mjs";
4
- const getCompatibilityDate = (modernConfig)=>{
5
- const configuredDate = modernConfig.deploy?.worker?.compatibilityDate?.trim();
6
- const compatibilityDate = configuredDate || DEFAULT_COMPATIBILITY_DATE;
7
- if (!COMPATIBILITY_DATE_PATTERN.test(compatibilityDate)) throw new Error(`deploy.worker.compatibilityDate must use YYYY-MM-DD, received ${JSON.stringify(compatibilityDate)}.`);
4
+ const assertSupportedCompatibilityDate = (compatibilityDate, label)=>{
5
+ if ('string' != typeof compatibilityDate) throw new Error(`${label} must be a YYYY-MM-DD string.`);
6
+ if (!COMPATIBILITY_DATE_PATTERN.test(compatibilityDate)) throw new Error(`${label} must use YYYY-MM-DD, received ${JSON.stringify(compatibilityDate)}.`);
7
+ if (compatibilityDate < DEFAULT_COMPATIBILITY_DATE) throw new Error(`${label} must be ${DEFAULT_COMPATIBILITY_DATE} or later, the date the Cloudflare worker Node.js built-in contract is verified against; received ${JSON.stringify(compatibilityDate)}.`);
8
8
  return compatibilityDate;
9
9
  };
10
+ const getCompatibilityDate = (modernConfig, wranglerCompatibilityDate)=>{
11
+ if (void 0 !== wranglerCompatibilityDate) return assertSupportedCompatibilityDate(wranglerCompatibilityDate, 'deploy.worker.wrangler.compatibility_date');
12
+ return assertSupportedCompatibilityDate(modernConfig.deploy?.worker?.compatibilityDate?.trim() || DEFAULT_COMPATIBILITY_DATE, 'deploy.worker.compatibilityDate');
13
+ };
10
14
  const getWorkerName = (appDirectory)=>{
11
15
  const basename = node_path.basename(appDirectory);
12
16
  return basename.replace(/[^a-zA-Z0-9-_]/g, '-') || 'modern-cloudflare-worker';
@@ -21,11 +25,11 @@ const getConfiguredWrangler = (modernConfig)=>{
21
25
  if (!isJsonRecord(wrangler)) throw new Error('deploy.worker.wrangler must be a JSON object.');
22
26
  return wrangler;
23
27
  };
24
- const createWranglerCompatibilityFlags = (configuredFlags)=>{
28
+ const createWranglerCompatibilityFlags = (configuredFlags, label = 'deploy.worker.wrangler.compatibility_flags')=>{
25
29
  if (void 0 === configuredFlags) return [
26
30
  ...REQUIRED_COMPATIBILITY_FLAGS
27
31
  ];
28
- if (!Array.isArray(configuredFlags) || configuredFlags.some((flag)=>'string' != typeof flag)) throw new Error('deploy.worker.wrangler.compatibility_flags must be an array of strings.');
32
+ if (!Array.isArray(configuredFlags) || configuredFlags.some((flag)=>'string' != typeof flag)) throw new Error(`${label} must be an array of strings.`);
29
33
  return [
30
34
  ...new Set([
31
35
  ...configuredFlags,
@@ -33,6 +37,26 @@ const createWranglerCompatibilityFlags = (configuredFlags)=>{
33
37
  ])
34
38
  ];
35
39
  };
40
+ const createWranglerEnvironments = (wranglerEnv)=>{
41
+ if (void 0 === wranglerEnv) return;
42
+ if (!isJsonRecord(wranglerEnv)) throw new Error('deploy.worker.wrangler.env must be an object.');
43
+ return Object.fromEntries(Object.entries(wranglerEnv).map(([name, environment])=>{
44
+ const label = `deploy.worker.wrangler.env.${name}`;
45
+ if (!isJsonRecord(environment)) throw new Error(`${label} must be an object.`);
46
+ return [
47
+ name,
48
+ {
49
+ ...environment,
50
+ ...void 0 === environment.compatibility_date ? {} : {
51
+ compatibility_date: assertSupportedCompatibilityDate(environment.compatibility_date, `${label}.compatibility_date`)
52
+ },
53
+ ...void 0 === environment.compatibility_flags ? {} : {
54
+ compatibility_flags: createWranglerCompatibilityFlags(environment.compatibility_flags, `${label}.compatibility_flags`)
55
+ }
56
+ }
57
+ ];
58
+ }));
59
+ };
36
60
  const createWranglerAssetsConfig = (configuredAssets)=>{
37
61
  if (void 0 !== configuredAssets && !isJsonRecord(configuredAssets)) throw new Error('deploy.worker.wrangler.assets must be an object.');
38
62
  return {
@@ -129,17 +153,21 @@ const createWorkerManifestServiceBindings = (serviceBindings)=>{
129
153
  };
130
154
  const createWranglerConfig = (appDirectory, modernConfig)=>{
131
155
  const wrangler = getConfiguredWrangler(modernConfig);
156
+ const environments = createWranglerEnvironments(wrangler.env);
132
157
  const d1Databases = createWranglerD1Databases(modernConfig, wrangler.d1_databases);
133
158
  const serviceBindings = createWorkerServiceBindings(modernConfig, wrangler.services);
134
159
  const wranglerServices = createWranglerServices(serviceBindings);
135
160
  return {
136
161
  $schema: 'node_modules/wrangler/config-schema.json',
137
162
  name: getConfiguredWorkerName(appDirectory, modernConfig),
138
- compatibility_date: getCompatibilityDate(modernConfig),
139
163
  ...wrangler,
164
+ compatibility_date: getCompatibilityDate(modernConfig, wrangler.compatibility_date),
140
165
  main: WORKER_ENTRY,
141
166
  compatibility_flags: createWranglerCompatibilityFlags(wrangler.compatibility_flags),
142
167
  assets: createWranglerAssetsConfig(wrangler.assets),
168
+ ...void 0 === environments ? {} : {
169
+ env: environments
170
+ },
143
171
  ...void 0 === d1Databases ? {} : {
144
172
  d1_databases: d1Databases
145
173
  },