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