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

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 (217) 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 +252 -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.001-bootstrap-security.mjs +0 -3
  37. package/dist/cjs/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  38. package/dist/cjs/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  39. package/dist/cjs/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  40. package/dist/cjs/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  41. package/dist/cjs/templates/cloudflare-worker-route-data.mjs +1069 -0
  42. package/dist/esm/backend-federation-build/codegen.mjs +216 -0
  43. package/dist/esm/backend-federation-build/config.mjs +163 -0
  44. package/dist/esm/backend-federation-build/emit.mjs +103 -0
  45. package/dist/esm/backend-federation-build/index.mjs +1 -0
  46. package/dist/esm/build-config/build-environment.mjs +88 -0
  47. package/dist/esm/build-config/precompress/plugin.mjs +76 -0
  48. package/dist/esm/build-config/precompress/types.mjs +0 -0
  49. package/dist/esm/build-config/public.mjs +1 -0
  50. package/dist/esm/build-config/remote-address.mjs +20 -0
  51. package/dist/esm/cloudflare/artifacts.mjs +8 -19
  52. package/dist/esm/cloudflare/constants.mjs +1 -1
  53. package/dist/esm/cloudflare/delivery-unit.mjs +17 -36
  54. package/dist/esm/cloudflare/index.mjs +10 -2
  55. package/dist/esm/cloudflare/worker-manifest.mjs +13 -4
  56. package/dist/esm/cloudflare/wrangler-config.mjs +35 -7
  57. package/dist/esm/cloudflare-builder.mjs +246 -75
  58. package/dist/esm/cloudflare-output-contract.mjs +59 -2
  59. package/dist/esm/cloudflare-output-verifier/identity.mjs +27 -25
  60. package/dist/esm/cloudflare-output-verifier/index.mjs +10 -0
  61. package/dist/esm/cloudflare-output-verifier/manifest.mjs +46 -0
  62. package/dist/esm/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  63. package/dist/esm/cloudflare-output-verifier/worker-bundles.mjs +15 -7
  64. package/dist/esm/config.mjs +3 -0
  65. package/dist/esm/deploy-output/npmAliases.mjs +199 -0
  66. package/dist/esm/deploy-output/plugin.mjs +46 -0
  67. package/dist/esm/deploy-output/public-assets.mjs +82 -0
  68. package/dist/esm/deploy-output/target.mjs +57 -0
  69. package/dist/esm/deploy-output/trace-files.mjs +38 -0
  70. package/dist/esm/native-type-checker.mjs +142 -0
  71. package/dist/esm/policy-defaults.mjs +45 -0
  72. package/dist/esm/release-envelope/framework-output.mjs +130 -56
  73. package/dist/esm/release-envelope/index.mjs +10 -4
  74. package/dist/esm/release-envelope/plugin.mjs +18 -13
  75. package/dist/esm/release-identity.mjs +5 -6
  76. package/dist/esm/runtime-package-resolution.mjs +60 -0
  77. package/dist/esm/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
  78. package/dist/esm/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  79. package/dist/esm/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  80. package/dist/esm/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  81. package/dist/esm/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  82. package/dist/esm/templates/cloudflare-worker-route-data.mjs +1069 -0
  83. package/dist/esm-node/backend-federation-build/codegen.mjs +217 -0
  84. package/dist/esm-node/backend-federation-build/config.mjs +164 -0
  85. package/dist/esm-node/backend-federation-build/emit.mjs +104 -0
  86. package/dist/esm-node/backend-federation-build/index.mjs +2 -0
  87. package/dist/esm-node/build-config/build-environment.mjs +89 -0
  88. package/dist/esm-node/build-config/precompress/plugin.mjs +77 -0
  89. package/dist/esm-node/build-config/precompress/types.mjs +1 -0
  90. package/dist/esm-node/build-config/public.mjs +2 -0
  91. package/dist/esm-node/build-config/remote-address.mjs +21 -0
  92. package/dist/esm-node/cloudflare/artifacts.mjs +8 -19
  93. package/dist/esm-node/cloudflare/constants.mjs +1 -1
  94. package/dist/esm-node/cloudflare/delivery-unit.mjs +17 -36
  95. package/dist/esm-node/cloudflare/index.mjs +10 -2
  96. package/dist/esm-node/cloudflare/worker-manifest.mjs +13 -4
  97. package/dist/esm-node/cloudflare/wrangler-config.mjs +35 -7
  98. package/dist/esm-node/cloudflare-builder.mjs +246 -75
  99. package/dist/esm-node/cloudflare-output-contract.mjs +59 -2
  100. package/dist/esm-node/cloudflare-output-verifier/identity.mjs +27 -25
  101. package/dist/esm-node/cloudflare-output-verifier/index.mjs +10 -0
  102. package/dist/esm-node/cloudflare-output-verifier/manifest.mjs +46 -0
  103. package/dist/esm-node/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  104. package/dist/esm-node/cloudflare-output-verifier/worker-bundles.mjs +15 -7
  105. package/dist/esm-node/config.mjs +3 -0
  106. package/dist/esm-node/deploy-output/npmAliases.mjs +200 -0
  107. package/dist/esm-node/deploy-output/plugin.mjs +49 -0
  108. package/dist/esm-node/deploy-output/public-assets.mjs +83 -0
  109. package/dist/esm-node/deploy-output/target.mjs +58 -0
  110. package/dist/esm-node/deploy-output/trace-files.mjs +39 -0
  111. package/dist/esm-node/native-type-checker.mjs +143 -0
  112. package/dist/esm-node/policy-defaults.mjs +46 -0
  113. package/dist/esm-node/release-envelope/framework-output.mjs +130 -56
  114. package/dist/esm-node/release-envelope/index.mjs +10 -4
  115. package/dist/esm-node/release-envelope/plugin.mjs +18 -13
  116. package/dist/esm-node/release-identity.mjs +5 -6
  117. package/dist/esm-node/runtime-package-resolution.mjs +61 -0
  118. package/dist/esm-node/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
  119. package/dist/esm-node/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  120. package/dist/esm-node/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  121. package/dist/esm-node/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  122. package/dist/esm-node/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  123. package/dist/esm-node/templates/cloudflare-worker-route-data.mjs +1069 -0
  124. package/dist/types/backend-federation-build/codegen.d.ts +116 -0
  125. package/dist/types/backend-federation-build/config.d.ts +121 -0
  126. package/dist/types/backend-federation-build/emit.d.ts +21 -0
  127. package/dist/types/backend-federation-build/index.d.ts +2 -0
  128. package/dist/types/build-config/build-environment.d.ts +14 -0
  129. package/dist/types/build-config/precompress/plugin.d.ts +4 -0
  130. package/dist/types/build-config/precompress/types.d.ts +19 -0
  131. package/dist/types/build-config/public.d.ts +2 -0
  132. package/dist/types/build-config/remote-address.d.ts +3 -0
  133. package/dist/types/cloudflare/artifacts.d.ts +7 -6
  134. package/dist/types/cloudflare/constants.d.ts +1 -1
  135. package/dist/types/cloudflare/delivery-unit.d.ts +3 -3
  136. package/dist/types/cloudflare/worker-manifest.d.ts +2 -2
  137. package/dist/types/cloudflare/wrangler-config.d.ts +6 -0
  138. package/dist/types/cloudflare-builder.d.ts +49 -9
  139. package/dist/types/cloudflare-output-contract.d.ts +4 -1
  140. package/dist/types/cloudflare-output-verifier/identity.d.ts +1 -1
  141. package/dist/types/cloudflare-output-verifier/worker-bundles.d.ts +2 -2
  142. package/dist/types/config.d.ts +29 -1
  143. package/dist/types/deploy-output/npmAliases.d.ts +14 -0
  144. package/dist/types/deploy-output/plugin.d.ts +35 -0
  145. package/dist/types/deploy-output/public-assets.d.ts +51 -0
  146. package/dist/types/deploy-output/target.d.ts +29 -0
  147. package/dist/types/deploy-output/trace-files.d.ts +17 -0
  148. package/dist/types/native-type-checker.d.ts +15 -0
  149. package/dist/types/policy-defaults.d.ts +46 -0
  150. package/dist/types/precompress/LICENSE +20 -0
  151. package/dist/types/precompress/index.d.ts +76 -0
  152. package/dist/types/release-envelope/framework-output.d.ts +8 -3
  153. package/dist/types/release-envelope/plugin.d.ts +7 -7
  154. package/dist/types/runtime-package-resolution.d.ts +28 -0
  155. package/dist/types/templates/cloudflare-worker-route-data.d.mts +14 -0
  156. package/package.json +97 -15
  157. package/src/backend-federation-build/codegen.ts +254 -0
  158. package/src/backend-federation-build/config.ts +492 -0
  159. package/src/backend-federation-build/emit.ts +213 -0
  160. package/src/backend-federation-build/index.ts +2 -0
  161. package/src/build-config/build-environment.ts +160 -0
  162. package/src/build-config/precompress/plugin.ts +140 -0
  163. package/src/build-config/precompress/types.ts +26 -0
  164. package/src/build-config/public.ts +5 -0
  165. package/src/build-config/remote-address.ts +33 -0
  166. package/src/cloudflare/artifacts.ts +22 -43
  167. package/src/cloudflare/constants.ts +1 -1
  168. package/src/cloudflare/delivery-unit.ts +42 -53
  169. package/src/cloudflare/index.ts +24 -11
  170. package/src/cloudflare/worker-manifest.ts +20 -3
  171. package/src/cloudflare/wrangler-config.ts +86 -10
  172. package/src/cloudflare-builder.ts +475 -151
  173. package/src/cloudflare-output-contract.ts +70 -0
  174. package/src/cloudflare-output-verifier/identity.ts +5 -1
  175. package/src/cloudflare-output-verifier/index.ts +20 -0
  176. package/src/cloudflare-output-verifier/manifest.ts +77 -0
  177. package/src/cloudflare-output-verifier/mutation-policy.ts +11 -1
  178. package/src/cloudflare-output-verifier/worker-bundles.ts +32 -14
  179. package/src/config.ts +34 -6
  180. package/src/deploy-output/npmAliases.ts +382 -0
  181. package/src/deploy-output/plugin.ts +86 -0
  182. package/src/deploy-output/public-assets.ts +224 -0
  183. package/src/deploy-output/target.ts +106 -0
  184. package/src/deploy-output/trace-files.ts +67 -0
  185. package/src/native-type-checker.ts +183 -0
  186. package/src/policy-defaults.ts +127 -0
  187. package/src/release-envelope/framework-output.ts +346 -94
  188. package/src/release-envelope/index.ts +26 -5
  189. package/src/release-envelope/plugin.ts +43 -40
  190. package/src/release-identity.ts +13 -2
  191. package/src/runtime-package-resolution.ts +115 -0
  192. package/src/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
  193. package/src/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  194. package/src/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  195. package/src/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  196. package/src/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  197. package/src/templates/cloudflare-worker-route-data.mjs +1069 -0
  198. package/dist/cjs/templates/cloudflare-worker-fs-promises.mjs +0 -11
  199. package/dist/cjs/templates/cloudflare-worker-loadable-server.mjs +0 -281
  200. package/dist/cjs/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  201. package/dist/cjs/templates/cloudflare-worker-path.mjs +0 -98
  202. package/dist/esm/templates/cloudflare-worker-fs-promises.mjs +0 -11
  203. package/dist/esm/templates/cloudflare-worker-loadable-server.mjs +0 -281
  204. package/dist/esm/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  205. package/dist/esm/templates/cloudflare-worker-path.mjs +0 -98
  206. package/dist/esm-node/templates/cloudflare-worker-fs-promises.mjs +0 -11
  207. package/dist/esm-node/templates/cloudflare-worker-loadable-server.mjs +0 -281
  208. package/dist/esm-node/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  209. package/dist/esm-node/templates/cloudflare-worker-path.mjs +0 -98
  210. package/dist/types/templates/cloudflare-worker-fs-promises.d.mts +0 -5
  211. package/dist/types/templates/cloudflare-worker-loadable-server.d.mts +0 -48
  212. package/dist/types/templates/cloudflare-worker-mf-ssr-runtime-plugin.d.mts +0 -13
  213. package/dist/types/templates/cloudflare-worker-path.d.mts +0 -21
  214. package/src/templates/cloudflare-worker-fs-promises.mjs +0 -11
  215. package/src/templates/cloudflare-worker-loadable-server.mjs +0 -281
  216. package/src/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  217. package/src/templates/cloudflare-worker-path.mjs +0 -98
@@ -1,17 +1,53 @@
1
1
  import "node:module";
2
2
  import node_fs from "node:fs";
3
- import { createRequire } from "node:module";
3
+ import { createRequire, isBuiltin } from "node:module";
4
4
  import node_path from "node:path";
5
5
  import { SERVICE_WORKER_ENVIRONMENT_NAME } from "@modern-js/builder";
6
6
  import { isProd } from "@modern-js/utils";
7
- import { provider } from "std-env";
8
- import { CLOUDFLARE_WORKER_NODE_BUILTINS } from "./cloudflare-output-contract.mjs";
7
+ import { CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT, CLOUDFLARE_WORKER_NODE_BUILTINS, CLOUDFLARE_WORKER_PLATFORM_MODULES, getCloudflareWorkerRouteDataEntryName } from "./cloudflare-output-contract.mjs";
9
8
  import { getTemplatePath } from "./read-template.mjs";
10
9
  const moduleRequire = createRequire(import.meta.url);
11
10
  const BFF_EFFECT_WORKER_ENTRY_NAME = '__modern_bff_effect';
12
11
  const BFF_EFFECT_WORKER_RUNTIME_QUERY = 'modern-bff-runtime';
13
- const MF_SSR_DATA_FETCH_RUNTIME_PLUGIN = '@module-federation/modern-js-v3/ssr-inject-data-fetch-function-plugin';
14
- const MF_SSR_DEV_RUNTIME_PLUGIN = '@module-federation/modern-js-v3/ssr-dev-plugin';
12
+ const SERVER_LOADER_COMBINED_FILE = 'server-loader-combined.js';
13
+ const ROUTE_SERVER_LOADERS_FILE = 'route-server-loaders.js';
14
+ const WORKER_ROUTE_DATA_FILE = 'cloudflare-worker-route-data.js';
15
+ const WORKER_ROUTE_DATA_TEMPLATE = 'cloudflare-worker-route-data.mjs';
16
+ const DATA_LOADER_CLIENT_TRANSFORM = /plugin-data-loader[\\/](?:.+[\\/])?loader\.[cm]?js$/u;
17
+ const WORKER_DEPENDENCY_CONDITIONS = [
18
+ [
19
+ 'esm',
20
+ 'import'
21
+ ],
22
+ [
23
+ 'wasm',
24
+ 'import'
25
+ ],
26
+ [
27
+ 'loaderImport',
28
+ 'import'
29
+ ],
30
+ [
31
+ 'worker',
32
+ 'import'
33
+ ],
34
+ [
35
+ 'commonjs',
36
+ 'require'
37
+ ],
38
+ [
39
+ 'amd',
40
+ 'require'
41
+ ],
42
+ [
43
+ 'loader',
44
+ 'require'
45
+ ],
46
+ [
47
+ 'unknown',
48
+ 'require'
49
+ ]
50
+ ];
15
51
  const JS_OR_TS_EXTENSIONS = new Set([
16
52
  '.js',
17
53
  '.jsx',
@@ -71,19 +107,154 @@ const resolvePackageFile = (packageName, filePath, paths)=>{
71
107
  const setAliasIfPresent = (alias, name, value)=>{
72
108
  if (value) alias.set(name, value);
73
109
  };
74
- const getCloudflareWorkerNodeExternals = ()=>Object.fromEntries(CLOUDFLARE_WORKER_NODE_BUILTINS.flatMap((builtin)=>{
75
- const nodeBuiltin = `node:${builtin}`;
110
+ const getCloudflareWorkerNodeExternals = ()=>Object.fromEntries([
111
+ ...CLOUDFLARE_WORKER_NODE_BUILTINS.flatMap((builtin)=>{
112
+ const nodeBuiltin = `node:${builtin}`;
113
+ const external = `module-import ${nodeBuiltin}`;
114
+ return isBuiltin(builtin) ? [
115
+ [
116
+ builtin,
117
+ external
118
+ ],
119
+ [
120
+ nodeBuiltin,
121
+ external
122
+ ]
123
+ ] : [
124
+ [
125
+ nodeBuiltin,
126
+ external
127
+ ]
128
+ ];
129
+ }),
130
+ ...CLOUDFLARE_WORKER_PLATFORM_MODULES.map((platformModule)=>[
131
+ platformModule,
132
+ `module-import ${platformModule}`
133
+ ])
134
+ ]);
135
+ const getPackageNameFromRequest = (request)=>{
136
+ if (request.startsWith('.') || request.startsWith('/') || request.includes(':') || node_path.isAbsolute(request)) return;
137
+ const segments = request.split('/');
138
+ return request.startsWith('@') ? segments.length > 1 ? `${segments[0]}/${segments[1]}` : void 0 : segments[0];
139
+ };
140
+ const isRedirectedByAliasField = (manifest, aliasFields, request)=>aliasFields.some((field)=>{
141
+ let value = manifest;
142
+ for (const key of 'string' == typeof field ? [
143
+ field
144
+ ] : field)value = value && 'object' == typeof value ? value[key] : void 0;
145
+ return 'object' == typeof value && null !== value && Object.hasOwn(value, request);
146
+ });
147
+ const findOwningPackageManifest = (directory, cache)=>{
148
+ if (cache.has(directory)) return cache.get(directory);
149
+ let manifest;
150
+ const packageJsonPath = node_path.join(directory, 'package.json');
151
+ if (node_fs.existsSync(packageJsonPath)) try {
152
+ manifest = JSON.parse(node_fs.readFileSync(packageJsonPath, 'utf-8'));
153
+ } catch {
154
+ manifest = void 0;
155
+ }
156
+ else if (node_path.dirname(directory) !== directory) manifest = findOwningPackageManifest(node_path.dirname(directory), cache);
157
+ cache.set(directory, manifest);
158
+ return manifest;
159
+ };
160
+ const isPackageInstalled = (packageName, directory, moduleDirectories)=>moduleDirectories.some((moduleDirectory)=>{
161
+ if (node_path.isAbsolute(moduleDirectory)) return node_fs.existsSync(node_path.join(moduleDirectory, packageName));
162
+ let current = directory;
163
+ while(true){
164
+ if (node_fs.existsSync(node_path.join(current, moduleDirectory, packageName))) return true;
165
+ const parent = node_path.dirname(current);
166
+ if (parent === current) return false;
167
+ current = parent;
168
+ }
169
+ });
170
+ const createAbsentOptionalDependencyFilter = (isRedirected = ()=>false, moduleDirectories = [
171
+ 'node_modules'
172
+ ], aliasFields = [])=>{
173
+ const manifests = new Map();
174
+ return (request, context)=>{
175
+ const packageName = getPackageNameFromRequest(request);
176
+ if (!packageName || !context || isRedirected(request)) return false;
177
+ const manifest = findOwningPackageManifest(context, manifests);
178
+ if (!manifest) return false;
179
+ const optional = manifest.peerDependenciesMeta?.[packageName]?.optional === true || Object.hasOwn(manifest.optionalDependencies ?? {}, packageName);
180
+ return optional && !isRedirectedByAliasField(manifest, aliasFields, request) && !isPackageInstalled(packageName, context, moduleDirectories);
181
+ };
182
+ };
183
+ const getAliasNames = (alias)=>alias ? Array.isArray(alias) ? alias.map((entry)=>entry.onlyModule ? `${entry.name}$` : entry.name) : Object.keys(alias) : [];
184
+ const getExternalMatchers = (externals)=>{
185
+ if (Array.isArray(externals)) return externals.flatMap(getExternalMatchers);
186
+ if ('string' == typeof externals) return [
187
+ (request)=>request === externals
188
+ ];
189
+ if (externals instanceof RegExp) return [
190
+ (request)=>{
191
+ externals.lastIndex = 0;
192
+ return externals.test(request);
193
+ }
194
+ ];
195
+ if (externals && 'object' == typeof externals) {
196
+ const names = new Set(Object.entries(externals).filter(([, value])=>false !== value).map(([name])=>name));
76
197
  return [
77
- [
78
- builtin,
79
- `module-import ${nodeBuiltin}`
80
- ],
81
- [
82
- nodeBuiltin,
83
- `module-import ${nodeBuiltin}`
84
- ]
198
+ (request)=>names.has(request)
85
199
  ];
86
- }));
200
+ }
201
+ return [];
202
+ };
203
+ const createRequestRedirectMatcher = (options)=>{
204
+ const aliasNames = [
205
+ ...getAliasNames(options.resolve?.alias),
206
+ ...getAliasNames(options.resolve?.fallback)
207
+ ];
208
+ const externalMatchers = getExternalMatchers(options.externals);
209
+ return (request)=>externalMatchers.some((matches)=>matches(request)) || aliasNames.some((name)=>name.endsWith('$') ? request === name.slice(0, -1) : request === name || request.startsWith(`${name}/`));
210
+ };
211
+ const getFunctionExternals = (externals)=>Array.isArray(externals) ? externals.flatMap(getFunctionExternals) : 'function' == typeof externals ? [
212
+ externals
213
+ ] : [];
214
+ const callFunctionExternal = (external, data)=>new Promise((resolve, reject)=>{
215
+ const returned = external(data, (error, result)=>error ? reject(error) : resolve(result));
216
+ if (null !== returned && 'object' == typeof returned && 'function' == typeof returned.then) returned.then(resolve, reject);
217
+ else if (1 === external.length) resolve(returned);
218
+ });
219
+ const claimsByFunctionExternal = async (externals, data)=>{
220
+ for (const external of externals)try {
221
+ const result = await callFunctionExternal(external, data);
222
+ if (null != result && false !== result) return true;
223
+ } catch {
224
+ return true;
225
+ }
226
+ return false;
227
+ };
228
+ const PLUGIN_NAME = 'AbsentOptionalDependencyPlugin';
229
+ class AbsentOptionalDependencyPlugin {
230
+ apply(compiler) {
231
+ const isAbsent = createAbsentOptionalDependencyFilter(createRequestRedirectMatcher(compiler.options), compiler.options.resolve.modules, compiler.options.resolve.aliasFields);
232
+ const functionExternals = getFunctionExternals(compiler.options.externals);
233
+ compiler.hooks.normalModuleFactory.tap(PLUGIN_NAME, (factory)=>{
234
+ factory.hooks.beforeResolve.tapPromise(PLUGIN_NAME, async (data)=>{
235
+ if (!isAbsent(data.request, data.context)) return;
236
+ const claimed = await claimsByFunctionExternal(functionExternals, {
237
+ context: data.context,
238
+ contextInfo: {
239
+ issuer: data.contextInfo.issuer,
240
+ issuerLayer: data.contextInfo.issuerLayer ?? null
241
+ },
242
+ getResolve: (options)=>{
243
+ const resolver = factory.getResolver('normal', options ?? {});
244
+ return (context, request, callback)=>{
245
+ if (callback) return void resolver.resolve({}, context, request, {}, callback);
246
+ return new Promise((resolve, reject)=>{
247
+ resolver.resolve({}, context, request, {}, (error, result)=>error ? reject(error) : resolve(result || void 0));
248
+ });
249
+ };
250
+ },
251
+ request: data.request
252
+ });
253
+ return claimed ? void 0 : false;
254
+ });
255
+ });
256
+ }
257
+ }
87
258
  const normalizeWorkerOutputName = (name)=>node_path.posix.normalize(name.replace(/\\/gu, '/')).toLowerCase();
88
259
  const reserveWorkerChunkName = (baseName, reservedOutputNames)=>{
89
260
  let name = baseName;
@@ -133,11 +304,8 @@ function applyCloudflareWorkerRspackConfig(chain, workerEntryNames) {
133
304
  chain.optimization.runtimeChunk(config.optimization.runtimeChunk);
134
305
  chain.optimization.splitChunks(config.optimization.splitChunks);
135
306
  }
136
- function applyCloudflareWorkerMfRuntimeBoundary(chain) {
137
- const runtimePlugin = getTemplatePath('cloudflare-worker-mf-ssr-runtime-plugin.mjs');
138
- chain.plugins.delete('plugin-module-federation');
139
- chain.resolve.alias.set(`${MF_SSR_DATA_FETCH_RUNTIME_PLUGIN}$`, runtimePlugin);
140
- chain.resolve.alias.set(`${MF_SSR_DEV_RUNTIME_PLUGIN}$`, runtimePlugin);
307
+ function removeCloudflareWorkerDataLoaderClientTransform(chain) {
308
+ for (const [name, rule] of Object.entries(chain.module.rules.entries() ?? {}))if (rule.uses.values().some((use)=>DATA_LOADER_CLIENT_TRANSFORM.test(String(use.get('loader'))))) chain.module.rules.delete(name);
141
309
  }
142
310
  const getEffectBffEntry = (normalizedConfig, appContext)=>{
143
311
  if (!normalizedConfig.bff || 'hono' === normalizedConfig.bff.runtimeFramework) return;
@@ -148,18 +316,6 @@ const getEffectBffEntry = (normalizedConfig, appContext)=>{
148
316
  }
149
317
  return resolveJsOrTsEntry(node_path.resolve(appContext.apiDirectory, 'index'));
150
318
  };
151
- const CLOUDFLARE_DEPLOY_PROVIDERS = new Set([
152
- 'cloudflare',
153
- 'cloudflare_pages',
154
- 'cloudflare_workers'
155
- ]);
156
- const resolveStdEnvDeployProvider = ()=>provider;
157
- const isCloudflareWorkerDeploy = (normalizedConfig, resolveDeployProvider)=>{
158
- const explicitTarget = normalizedConfig.deploy?.target || process.env.MODERNJS_DEPLOY;
159
- if (explicitTarget) return 'cloudflare' === explicitTarget;
160
- const detectedProvider = resolveDeployProvider();
161
- return detectedProvider ? CLOUDFLARE_DEPLOY_PROVIDERS.has(detectedProvider) : false;
162
- };
163
319
  const rewriteWorkerEntryPath = (entry)=>entry.replace('index.jsx', 'index.server.jsx').replace('bootstrap.server.jsx', 'index.server.jsx').replace('bootstrap.jsx', 'index.server.jsx');
164
320
  const rewriteWorkerEntryDescription = (description)=>{
165
321
  const entryImport = description.import;
@@ -204,11 +360,40 @@ const prependBundlerChain = (environment, handler)=>{
204
360
  }
205
361
  };
206
362
  };
363
+ const createWorkerRouteDataModule = ()=>[
364
+ `import { routes } from './${ROUTE_SERVER_LOADERS_FILE}';`,
365
+ `import { createRouteDataRequestHandler } from ${JSON.stringify(getTemplatePath(WORKER_ROUTE_DATA_TEMPLATE))};`,
366
+ '',
367
+ `export const ${CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT} =`,
368
+ ' createRouteDataRequestHandler(routes);',
369
+ ''
370
+ ].join('\n');
371
+ const getWorkerRouteDataEntries = (appContext)=>{
372
+ const { entrypoints, internalDirectory } = appContext;
373
+ if (!entrypoints || !internalDirectory) return {};
374
+ return Object.fromEntries(entrypoints.flatMap(({ entryName })=>{
375
+ const entryDirectory = node_path.join(internalDirectory, entryName);
376
+ if (!node_fs.existsSync(node_path.join(entryDirectory, SERVER_LOADER_COMBINED_FILE)) || !node_fs.existsSync(node_path.join(entryDirectory, ROUTE_SERVER_LOADERS_FILE))) return [];
377
+ const routeDataFile = node_path.join(entryDirectory, WORKER_ROUTE_DATA_FILE);
378
+ node_fs.writeFileSync(routeDataFile, createWorkerRouteDataModule());
379
+ return [
380
+ [
381
+ getCloudflareWorkerRouteDataEntryName(entryName),
382
+ [
383
+ routeDataFile
384
+ ]
385
+ ]
386
+ ];
387
+ }));
388
+ };
207
389
  const getWorkerEntries = (environment, normalizedConfig, appContext)=>{
208
390
  const configuredEntries = environment.source?.entry;
209
- if (!configuredEntries) return;
210
- const entries = rewriteWorkerEntries(configuredEntries);
211
391
  const effectApiEntry = getEffectBffEntry(normalizedConfig, appContext);
392
+ if (!configuredEntries && !effectApiEntry) return;
393
+ const entries = configuredEntries ? {
394
+ ...rewriteWorkerEntries(configuredEntries),
395
+ ...getWorkerRouteDataEntries(appContext)
396
+ } : {};
212
397
  return effectApiEntry ? {
213
398
  ...entries,
214
399
  [BFF_EFFECT_WORKER_ENTRY_NAME]: [
@@ -221,9 +406,6 @@ const createCloudflareBundlerChain = (appContext, workerEntryNames)=>{
221
406
  appContext.appDirectory,
222
407
  process.cwd()
223
408
  ];
224
- const tanstackRouterSsrServerFile = resolvePackageFile('@tanstack/router-core', 'dist/esm/ssr/ssr-server.js', resolvePaths);
225
- const runtimeRscWorkerFile = resolvePackageFile('@modern-js/runtime', 'dist/esm/rsc/server.worker.mjs', resolvePaths);
226
- const renderRscWorkerFile = resolvePackageFile('@modern-js/render', 'dist/esm/rscWorker.mjs', resolvePaths);
227
409
  const reactFile = resolvePackageFile('react', 'index.js', resolvePaths);
228
410
  const reactJsxRuntimeFile = resolvePackageFile('react', 'jsx-runtime.js', resolvePaths);
229
411
  const reactJsxDevRuntimeFile = resolvePackageFile('react', 'jsx-dev-runtime.js', resolvePaths);
@@ -233,62 +415,49 @@ const createCloudflareBundlerChain = (appContext, workerEntryNames)=>{
233
415
  ...resolvePaths,
234
416
  getTemplatePath('')
235
417
  ]);
236
- const loadableServerWorkerFile = getTemplatePath('cloudflare-worker-loadable-server.mjs');
237
- const fsPromisesWorkerFile = getTemplatePath('cloudflare-worker-fs-promises.mjs');
238
- const pathWorkerFile = getTemplatePath('cloudflare-worker-path.mjs');
239
418
  const entryNames = [
240
419
  ...workerEntryNames
241
420
  ];
242
421
  return (chain)=>{
243
422
  applyCloudflareWorkerRspackConfig(chain, entryNames);
423
+ removeCloudflareWorkerDataLoaderClientTransform(chain);
244
424
  chain.output.module(true).library({
245
425
  type: 'module'
246
426
  }).publicPath('/').chunkFormat('module').chunkLoading('import').workerChunkLoading('import');
427
+ chain.node.set('__dirname', 'mock').set('__filename', 'mock');
247
428
  for (const condition of [
248
429
  'workerd',
249
430
  'worker',
250
431
  'webpack',
251
432
  isProd() ? 'production' : 'development',
252
- 'import',
253
- 'require',
254
433
  'module'
255
434
  ])chain.resolve.conditionNames.add(condition);
256
- applyCloudflareWorkerMfRuntimeBoundary(chain);
257
- if (tanstackRouterSsrServerFile) {
258
- chain.resolve.alias.set('@tanstack/router-core/ssr/server$', tanstackRouterSsrServerFile);
259
- chain.resolve.alias.set('@tanstack/router-core/ssr/server', tanstackRouterSsrServerFile);
260
- }
261
- if (runtimeRscWorkerFile) {
262
- chain.resolve.alias.set('@modern-js/runtime/rsc/server$', runtimeRscWorkerFile);
263
- chain.resolve.alias.set('@modern-js/runtime/rsc/server', runtimeRscWorkerFile);
264
- }
265
- if (renderRscWorkerFile) {
266
- chain.resolve.alias.set('@modern-js/render/rsc$', renderRscWorkerFile);
267
- chain.resolve.alias.set('@modern-js/render/rsc', renderRscWorkerFile);
268
- chain.resolve.alias.set('@modern-js/render/rsc-worker$', renderRscWorkerFile);
269
- }
435
+ for (const [dependencyType, condition] of WORKER_DEPENDENCY_CONDITIONS)chain.resolve.byDependency.set(dependencyType, {
436
+ conditionNames: [
437
+ condition,
438
+ '...'
439
+ ]
440
+ });
441
+ chain.plugin('cloudflare-worker-absent-optional-dependencies').use(AbsentOptionalDependencyPlugin);
442
+ chain.plugins.delete('plugin-module-federation');
270
443
  setAliasIfPresent(chain.resolve.alias, 'react$', reactFile);
271
444
  setAliasIfPresent(chain.resolve.alias, 'react/jsx-runtime$', reactJsxRuntimeFile);
272
445
  setAliasIfPresent(chain.resolve.alias, 'react/jsx-dev-runtime$', reactJsxDevRuntimeFile);
273
446
  setAliasIfPresent(chain.resolve.alias, 'react-dom$', reactDomFile);
274
447
  setAliasIfPresent(chain.resolve.alias, 'react-dom/server.edge$', reactDomServerEdgeFile);
275
448
  setAliasIfPresent(chain.resolve.alias, '@loadable/component$', loadableComponentFile);
276
- setAliasIfPresent(chain.resolve.alias, '@loadable/server$', loadableServerWorkerFile);
277
- setAliasIfPresent(chain.resolve.alias, 'fs/promises$', fsPromisesWorkerFile);
278
- setAliasIfPresent(chain.resolve.alias, 'node:fs/promises$', fsPromisesWorkerFile);
279
- setAliasIfPresent(chain.resolve.alias, 'path$', pathWorkerFile);
280
- setAliasIfPresent(chain.resolve.alias, 'node:path$', pathWorkerFile);
281
- chain.resolve.alias.set('react-server-dom-rspack/server.node$', 'react-server-dom-rspack/server.edge');
282
- chain.resolve.alias.set('react-server-dom-rspack/server.node', 'react-server-dom-rspack/server.edge');
283
- chain.resolve.alias.set('react-server-dom-rspack/client.node$', 'react-server-dom-rspack/client.edge');
284
- chain.resolve.alias.set('react-server-dom-rspack/client.node', 'react-server-dom-rspack/client.edge');
285
- chain.resolve.fallback.set('fs', false);
286
- chain.resolve.fallback.set('node:fs', false);
287
449
  };
288
450
  };
289
- function getCloudflareBuilderEnvironments({ appContext, environments, normalizedConfig, resolveDeployProvider = resolveStdEnvDeployProvider }) {
290
- if (!isCloudflareWorkerDeploy(normalizedConfig, resolveDeployProvider)) return environments;
291
- const workerEnvironment = environments[SERVICE_WORKER_ENVIRONMENT_NAME];
451
+ function getCloudflareBuilderEnvironments({ appContext, environments, normalizedConfig }) {
452
+ if (appContext.deployTarget?.target !== 'cloudflare') return environments;
453
+ const workerEnvironment = environments[SERVICE_WORKER_ENVIRONMENT_NAME] ?? (appContext.apiOnly ? {
454
+ output: {
455
+ target: 'web-worker'
456
+ },
457
+ source: {
458
+ entry: {}
459
+ }
460
+ } : void 0);
292
461
  if (!workerEnvironment) return environments;
293
462
  const workerEntries = getWorkerEntries(workerEnvironment, normalizedConfig, appContext);
294
463
  if (!workerEntries) return environments;
@@ -304,6 +473,9 @@ function getCloudflareBuilderEnvironments({ appContext, environments, normalized
304
473
  entry: workerEntries
305
474
  }
306
475
  }, createCloudflareBundlerChain(appContext, Object.keys(workerEntries)));
476
+ if (appContext.apiOnly) return {
477
+ [SERVICE_WORKER_ENVIRONMENT_NAME]: cloudflareWorkerEnvironment
478
+ };
307
479
  return {
308
480
  ...environments,
309
481
  [SERVICE_WORKER_ENVIRONMENT_NAME]: cloudflareWorkerEnvironment
@@ -314,15 +486,14 @@ function applyCloudflareBuilderEnvironments(options) {
314
486
  environments: getCloudflareBuilderEnvironments(options)
315
487
  };
316
488
  }
317
- const createCloudflareBuilderPlugin = (resolveDeployProvider = resolveStdEnvDeployProvider)=>({
489
+ const createCloudflareBuilderPlugin = ()=>({
318
490
  name: '@modern-js/cloudflare-builder',
319
491
  setup (api) {
320
492
  api.modifyBuilderEnvironments(({ environments })=>applyCloudflareBuilderEnvironments({
321
493
  appContext: api.getAppContext(),
322
494
  environments,
323
- normalizedConfig: api.getNormalizedConfig(),
324
- resolveDeployProvider
495
+ normalizedConfig: api.getNormalizedConfig()
325
496
  }));
326
497
  }
327
498
  });
328
- export { applyCloudflareBuilderEnvironments, applyCloudflareWorkerMfRuntimeBoundary, applyCloudflareWorkerRspackConfig, createCloudflareBuilderPlugin, getCloudflareBuilderEnvironments, getCloudflareWorkerRspackConfig };
499
+ export { applyCloudflareBuilderEnvironments, applyCloudflareWorkerRspackConfig, claimsByFunctionExternal, createAbsentOptionalDependencyFilter, createCloudflareBuilderPlugin, createRequestRedirectMatcher, getCloudflareBuilderEnvironments, getCloudflareWorkerRspackConfig };
@@ -11,22 +11,79 @@ const CLOUDFLARE_RUNTIME_TYPE = 'cloudflare-module-worker';
11
11
  const CLOUDFLARE_OUTPUT_PACKAGE_TYPE = 'module';
12
12
  const CLOUDFLARE_WORKER_PACKAGE_TYPE = 'commonjs';
13
13
  const CLOUDFLARE_WORKER_BUNDLE_FORMAT = 'commonjs';
14
+ const CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT = 'handleRouteDataRequest';
15
+ const getCloudflareWorkerRouteDataEntryName = (entryName)=>`${entryName}-server-loaders`;
14
16
  const CLOUDFLARE_WORKER_NODE_BUILTINS = [
17
+ '_http_agent',
18
+ '_http_client',
19
+ '_http_common',
20
+ '_http_incoming',
21
+ '_http_outgoing',
22
+ '_http_server',
23
+ '_tls_common',
24
+ '_tls_wrap',
25
+ 'assert',
26
+ 'assert/strict',
15
27
  'async_hooks',
16
28
  'buffer',
29
+ 'child_process',
30
+ 'cluster',
31
+ 'console',
32
+ 'constants',
17
33
  'crypto',
34
+ 'dgram',
35
+ 'diagnostics_channel',
36
+ 'dns',
37
+ 'dns/promises',
38
+ 'domain',
18
39
  'events',
40
+ 'fs',
19
41
  'fs/promises',
42
+ 'http',
43
+ 'http2',
44
+ 'https',
45
+ 'inspector',
46
+ 'inspector/promises',
20
47
  'module',
48
+ 'net',
49
+ 'os',
21
50
  'path',
51
+ 'path/posix',
52
+ 'path/win32',
53
+ 'perf_hooks',
22
54
  'process',
55
+ 'punycode',
56
+ 'querystring',
57
+ 'readline',
58
+ 'readline/promises',
59
+ 'repl',
60
+ 'sqlite',
23
61
  'stream',
62
+ 'stream/consumers',
63
+ 'stream/promises',
64
+ 'stream/web',
24
65
  'string_decoder',
66
+ 'sys',
67
+ 'test',
68
+ 'timers',
69
+ 'timers/promises',
70
+ 'tls',
71
+ 'trace_events',
72
+ 'tty',
25
73
  'url',
26
- 'util'
74
+ 'util',
75
+ 'util/types',
76
+ 'v8',
77
+ 'vm',
78
+ 'wasi',
79
+ 'worker_threads',
80
+ 'zlib'
81
+ ];
82
+ const CLOUDFLARE_WORKER_PLATFORM_MODULES = [
83
+ 'cloudflare:sockets'
27
84
  ];
28
85
  const CLOUDFLARE_REQUIRED_COMPATIBILITY_FLAGS = [
29
86
  'nodejs_compat',
30
87
  'global_fetch_strictly_public'
31
88
  ];
32
- export { CLOUDFLARE_ASSETS_BINDING, CLOUDFLARE_OUTPUT_PACKAGE_FILE, CLOUDFLARE_OUTPUT_PACKAGE_TYPE, CLOUDFLARE_PUBLIC_ASSETS_DIRECTORY, CLOUDFLARE_REQUIRED_COMPATIBILITY_FLAGS, CLOUDFLARE_RUNTIME_TYPE, CLOUDFLARE_WORKER_BUNDLE_DIRECTORY, CLOUDFLARE_WORKER_BUNDLE_FORMAT, CLOUDFLARE_WORKER_ENTRY, CLOUDFLARE_WORKER_MANIFEST, CLOUDFLARE_WORKER_NODE_BUILTINS, CLOUDFLARE_WORKER_PACKAGE_FILE, CLOUDFLARE_WORKER_PACKAGE_TYPE, CLOUDFLARE_WRANGLER_CONFIG_FILE };
89
+ export { CLOUDFLARE_ASSETS_BINDING, CLOUDFLARE_OUTPUT_PACKAGE_FILE, CLOUDFLARE_OUTPUT_PACKAGE_TYPE, CLOUDFLARE_PUBLIC_ASSETS_DIRECTORY, CLOUDFLARE_REQUIRED_COMPATIBILITY_FLAGS, CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT, CLOUDFLARE_RUNTIME_TYPE, CLOUDFLARE_WORKER_BUNDLE_DIRECTORY, CLOUDFLARE_WORKER_BUNDLE_FORMAT, CLOUDFLARE_WORKER_ENTRY, CLOUDFLARE_WORKER_MANIFEST, CLOUDFLARE_WORKER_NODE_BUILTINS, CLOUDFLARE_WORKER_PACKAGE_FILE, CLOUDFLARE_WORKER_PACKAGE_TYPE, CLOUDFLARE_WORKER_PLATFORM_MODULES, CLOUDFLARE_WRANGLER_CONFIG_FILE, getCloudflareWorkerRouteDataEntryName };
@@ -1,5 +1,5 @@
1
1
  import "node:module";
2
- import { DELIVERY_UNIT_IDENTITY_FIELDS, deliveryUnitIdentityFieldValue } from "@modern-js/utils/universal";
2
+ import { DELIVERY_UNIT_IDENTITY_FIELDS, deliveryUnitIdentityFieldValue } from "@modern-js/backend-federation-contracts";
3
3
  import { addIssue, assertEqual } from "./issues.mjs";
4
4
  const verifyDeliveryUnitIdentity = (issues, manifest, manifestPath, declared)=>{
5
5
  const stamped = manifest?.deliveryUnit;
@@ -25,30 +25,32 @@ const verifyDeliveryUnitIdentity = (issues, manifest, manifestPath, declared)=>{
25
25
  ]){
26
26
  const marker = stamped.surfaces[surface];
27
27
  const expected = declared?.surfaces?.[surface];
28
- if (declared?.surfaces && !expected) {
29
- if (marker) addIssue(issues, {
30
- code: 'delivery-unit-drift',
31
- message: `Cloudflare worker manifest declares an unexpected ${surface} delivery-unit surface for this topology profile.`,
32
- path: manifestPath
33
- });
34
- continue;
35
- }
36
- if (!marker || 'object' != typeof marker) {
37
- addIssue(issues, {
38
- code: 'missing-delivery-unit',
39
- message: `Cloudflare worker manifest is missing the ${surface} delivery-unit surface marker.`,
40
- path: manifestPath
41
- });
42
- continue;
43
- }
44
- for (const field of DELIVERY_UNIT_IDENTITY_FIELDS){
45
- const markerValue = deliveryUnitIdentityFieldValue(marker, field);
46
- const stampedValue = deliveryUnitIdentityFieldValue(stamped, field);
47
- assertEqual(issues, markerValue, stampedValue, {
48
- code: 'delivery-unit-drift',
49
- message: `Cloudflare worker manifest ${surface} surface deliveryUnit.${field} must derive from one delivery-unit record (expected ${stampedValue ?? 'undefined'}, received ${markerValue ?? 'undefined'}).`,
50
- path: manifestPath
51
- });
28
+ if (expected || marker) {
29
+ if (declared?.surfaces && !expected) {
30
+ if (marker) addIssue(issues, {
31
+ code: 'delivery-unit-drift',
32
+ message: `Cloudflare worker manifest declares an unexpected ${surface} delivery-unit surface for this topology profile.`,
33
+ path: manifestPath
34
+ });
35
+ continue;
36
+ }
37
+ if (!marker || 'object' != typeof marker) {
38
+ addIssue(issues, {
39
+ code: 'missing-delivery-unit',
40
+ message: `Cloudflare worker manifest is missing the ${surface} delivery-unit surface marker.`,
41
+ path: manifestPath
42
+ });
43
+ continue;
44
+ }
45
+ for (const field of DELIVERY_UNIT_IDENTITY_FIELDS){
46
+ const markerValue = deliveryUnitIdentityFieldValue(marker, field);
47
+ const stampedValue = deliveryUnitIdentityFieldValue(stamped, field);
48
+ assertEqual(issues, markerValue, stampedValue, {
49
+ code: 'delivery-unit-drift',
50
+ message: `Cloudflare worker manifest ${surface} surface deliveryUnit.${field} must derive from one delivery-unit record (expected ${stampedValue ?? 'undefined'}, received ${markerValue ?? 'undefined'}).`,
51
+ path: manifestPath
52
+ });
53
+ }
52
54
  }
53
55
  }
54
56
  };
@@ -73,6 +73,16 @@ const verifyCloudflareOutput = async (options)=>{
73
73
  }
74
74
  }
75
75
  if (wrangler) {
76
+ if ('string' != typeof wrangler.name || 0 === wrangler.name.trim().length) addIssue(issues, {
77
+ code: 'invalid-wrangler',
78
+ message: 'wrangler.json name must be a non-empty worker name.',
79
+ path: wranglerPath
80
+ });
81
+ if ('string' != typeof wrangler.compatibility_date || !/^\d{4}-\d{2}-\d{2}$/u.test(wrangler.compatibility_date)) addIssue(issues, {
82
+ code: 'invalid-wrangler',
83
+ message: 'wrangler.json compatibility_date must use YYYY-MM-DD.',
84
+ path: wranglerPath
85
+ });
76
86
  assertEqual(issues, wrangler.main, outputPlan.wrangler.main, {
77
87
  code: 'invalid-wrangler',
78
88
  message: `wrangler.json main must be ${outputPlan.wrangler.main}.`,
@@ -43,6 +43,52 @@ const verifyManifestShape = (issues, manifest, manifestPath)=>{
43
43
  message: 'Cloudflare output manifest routeSpec.routes must be array.',
44
44
  path: manifestPath
45
45
  });
46
+ const security = manifest.security;
47
+ if (security && 'object' == typeof security && 'boolean' == typeof security.enabled) {
48
+ const cors = security.cors;
49
+ if (!cors || 'object' != typeof cors || 'boolean' != typeof cors.assets || !Array.isArray(cors.allowedOrigins) || !Array.isArray(cors.allowedMethods) || !Array.isArray(cors.allowedHeaders)) addIssue(issues, {
50
+ code: 'invalid-manifest',
51
+ message: 'Cloudflare output manifest security.cors is incomplete.',
52
+ path: manifestPath
53
+ });
54
+ if (security.enabled) {
55
+ const headers = security.headers;
56
+ const csp = security.contentSecurityPolicy;
57
+ const noindex = security.noindex;
58
+ if (!headers || 'object' != typeof headers || ![
59
+ 'string',
60
+ 'boolean'
61
+ ].includes(typeof headers.referrerPolicy) || ![
62
+ 'string',
63
+ 'boolean'
64
+ ].includes(typeof headers.contentTypeOptions) || ![
65
+ 'string',
66
+ 'boolean'
67
+ ].includes(typeof headers.permissionsPolicy)) addIssue(issues, {
68
+ code: 'invalid-manifest',
69
+ message: 'Cloudflare output manifest security.headers is incomplete.',
70
+ path: manifestPath
71
+ });
72
+ if (!csp || ![
73
+ 'off',
74
+ 'report-only',
75
+ 'enforce'
76
+ ].includes(csp.mode) || !csp.directives || 'object' != typeof csp.directives || Array.isArray(csp.directives) || Object.values(csp.directives).some((value)=>!Array.isArray(value) || value.some((entry)=>'string' != typeof entry))) addIssue(issues, {
77
+ code: 'invalid-manifest',
78
+ message: 'Cloudflare output manifest security.contentSecurityPolicy is invalid.',
79
+ path: manifestPath
80
+ });
81
+ if (!noindex || 'boolean' != typeof noindex.workersDev || 'boolean' != typeof noindex.localhost || !Array.isArray(noindex.previewHostnames)) addIssue(issues, {
82
+ code: 'invalid-manifest',
83
+ message: 'Cloudflare output manifest security.noindex is incomplete.',
84
+ path: manifestPath
85
+ });
86
+ }
87
+ } else addIssue(issues, {
88
+ code: 'invalid-manifest',
89
+ message: 'Cloudflare output manifest security.enabled must be a boolean.',
90
+ path: manifestPath
91
+ });
46
92
  if (manifest.bff?.runtimeFramework === 'effect') assertEqual(issues, manifest.bff.dispatcherExport, BFF_EFFECT_WORKER_DISPATCHER_EXPORT, {
47
93
  code: 'invalid-manifest',
48
94
  message: `Cloudflare Effect BFF manifest dispatcherExport must be ${BFF_EFFECT_WORKER_DISPATCHER_EXPORT}.`,
@@ -85,7 +85,13 @@ const verifyCloudflareOutputMutationPolicy = async (options)=>{
85
85
  const files = (await Promise.all(options.scanRoots.map((scanRoot)=>walkFiles(node_path.resolve(scanRoot))))).flat();
86
86
  for (const file of files){
87
87
  if (excludedFiles.has(file)) continue;
88
- const source = await promises.readFile(file, 'utf-8');
88
+ let source;
89
+ try {
90
+ source = await promises.readFile(file, 'utf-8');
91
+ } catch (error) {
92
+ if ('ENOENT' === error.code) continue;
93
+ throw error;
94
+ }
89
95
  for (const forbidden of FORBIDDEN_MUTATION_PATTERNS)if (forbidden.pattern.test(source)) addIssue(issues, {
90
96
  code: forbidden.code,
91
97
  message: forbidden.message,