@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
@@ -10,19 +10,89 @@ export const CLOUDFLARE_RUNTIME_TYPE = 'cloudflare-module-worker';
10
10
  export const CLOUDFLARE_OUTPUT_PACKAGE_TYPE = 'module';
11
11
  export const CLOUDFLARE_WORKER_PACKAGE_TYPE = 'commonjs';
12
12
  export const CLOUDFLARE_WORKER_BUNDLE_FORMAT = 'commonjs';
13
+ // Each SSR entry with route data loaders gets a worker bundle that answers
14
+ // `?__loader=` route data requests through this export.
15
+ export const CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT = 'handleRouteDataRequest';
16
+ export const getCloudflareWorkerRouteDataEntryName = (entryName: string) =>
17
+ `${entryName}-server-loaders`;
18
+ // Every Node.js built-in that workerd resolves for the default 2026-06-02
19
+ // nodejs_compat target (tests/cloudflare-worker-node-builtins.test.ts probes
20
+ // workerd against Node's own `builtinModules`). Names are listed without the
21
+ // `node:` scheme; bare-name imports are only valid where Node itself accepts
22
+ // them (`isBuiltin`), so prefix-only modules such as `sqlite` and `test` are
23
+ // externalized solely as `node:sqlite` and `node:test`. Some modules are
24
+ // runtime-provided stubs whose unsupported operations throw. Earlier
25
+ // compatibility dates are rejected when the Wrangler config is generated.
13
26
  export const CLOUDFLARE_WORKER_NODE_BUILTINS = [
27
+ '_http_agent',
28
+ '_http_client',
29
+ '_http_common',
30
+ '_http_incoming',
31
+ '_http_outgoing',
32
+ '_http_server',
33
+ '_tls_common',
34
+ '_tls_wrap',
35
+ 'assert',
36
+ 'assert/strict',
14
37
  'async_hooks',
15
38
  'buffer',
39
+ 'child_process',
40
+ 'cluster',
41
+ 'console',
42
+ 'constants',
16
43
  'crypto',
44
+ 'dgram',
45
+ 'diagnostics_channel',
46
+ 'dns',
47
+ 'dns/promises',
48
+ 'domain',
17
49
  'events',
50
+ 'fs',
18
51
  'fs/promises',
52
+ 'http',
53
+ 'http2',
54
+ 'https',
55
+ 'inspector',
56
+ 'inspector/promises',
19
57
  'module',
58
+ 'net',
59
+ 'os',
20
60
  'path',
61
+ 'path/posix',
62
+ 'path/win32',
63
+ 'perf_hooks',
21
64
  'process',
65
+ 'punycode',
66
+ 'querystring',
67
+ 'readline',
68
+ 'readline/promises',
69
+ 'repl',
70
+ 'sqlite',
22
71
  'stream',
72
+ 'stream/consumers',
73
+ 'stream/promises',
74
+ 'stream/web',
23
75
  'string_decoder',
76
+ 'sys',
77
+ 'test',
78
+ 'timers',
79
+ 'timers/promises',
80
+ 'tls',
81
+ 'trace_events',
82
+ 'tty',
24
83
  'url',
25
84
  'util',
85
+ 'util/types',
86
+ 'v8',
87
+ 'vm',
88
+ 'wasi',
89
+ 'worker_threads',
90
+ 'zlib',
91
+ ] as const;
92
+ // Platform imports available with the default 2026-06-02 nodejs_compat target.
93
+ // Import availability does not imply support for every Node API operation.
94
+ export const CLOUDFLARE_WORKER_PLATFORM_MODULES = [
95
+ 'cloudflare:sockets',
26
96
  ] as const;
27
97
  export const CLOUDFLARE_REQUIRED_COMPATIBILITY_FLAGS = [
28
98
  'nodejs_compat',
@@ -2,7 +2,7 @@ import {
2
2
  DELIVERY_UNIT_IDENTITY_FIELDS,
3
3
  type DeliveryUnitIdentity,
4
4
  deliveryUnitIdentityFieldValue,
5
- } from '@modern-js/utils/universal';
5
+ } from '@modern-js/backend-federation-contracts';
6
6
  import type { CloudflareOutputVerifierIssue, JsonObject } from './issues';
7
7
  import { addIssue, assertEqual } from './issues';
8
8
 
@@ -51,6 +51,10 @@ export const verifyDeliveryUnitIdentity = (
51
51
  const marker = stamped.surfaces[surface];
52
52
  const expected = declared?.surfaces?.[surface];
53
53
 
54
+ if (!expected && !marker) {
55
+ continue;
56
+ }
57
+
54
58
  if (declared?.surfaces && !expected) {
55
59
  if (marker) {
56
60
  addIssue(issues, {
@@ -174,6 +174,26 @@ export const verifyCloudflareOutput = async (
174
174
  }
175
175
 
176
176
  if (wrangler) {
177
+ if (
178
+ typeof wrangler.name !== 'string' ||
179
+ wrangler.name.trim().length === 0
180
+ ) {
181
+ addIssue(issues, {
182
+ code: 'invalid-wrangler',
183
+ message: 'wrangler.json name must be a non-empty worker name.',
184
+ path: wranglerPath,
185
+ });
186
+ }
187
+ if (
188
+ typeof wrangler.compatibility_date !== 'string' ||
189
+ !/^\d{4}-\d{2}-\d{2}$/u.test(wrangler.compatibility_date)
190
+ ) {
191
+ addIssue(issues, {
192
+ code: 'invalid-wrangler',
193
+ message: 'wrangler.json compatibility_date must use YYYY-MM-DD.',
194
+ path: wranglerPath,
195
+ });
196
+ }
177
197
  assertEqual(issues, wrangler.main, outputPlan.wrangler.main, {
178
198
  code: 'invalid-wrangler',
179
199
  message: `wrangler.json main must be ${outputPlan.wrangler.main}.`,
@@ -61,6 +61,83 @@ export const verifyManifestShape = (
61
61
  path: manifestPath,
62
62
  });
63
63
  }
64
+ const security = manifest.security;
65
+ if (
66
+ !security ||
67
+ typeof security !== 'object' ||
68
+ typeof security.enabled !== 'boolean'
69
+ ) {
70
+ addIssue(issues, {
71
+ code: 'invalid-manifest',
72
+ message: 'Cloudflare output manifest security.enabled must be a boolean.',
73
+ path: manifestPath,
74
+ });
75
+ } else {
76
+ const cors = security.cors;
77
+ if (
78
+ !cors ||
79
+ typeof cors !== 'object' ||
80
+ typeof cors.assets !== 'boolean' ||
81
+ !Array.isArray(cors.allowedOrigins) ||
82
+ !Array.isArray(cors.allowedMethods) ||
83
+ !Array.isArray(cors.allowedHeaders)
84
+ ) {
85
+ addIssue(issues, {
86
+ code: 'invalid-manifest',
87
+ message: 'Cloudflare output manifest security.cors is incomplete.',
88
+ path: manifestPath,
89
+ });
90
+ }
91
+ if (security.enabled) {
92
+ const headers = security.headers;
93
+ const csp = security.contentSecurityPolicy;
94
+ const noindex = security.noindex;
95
+ if (
96
+ !headers ||
97
+ typeof headers !== 'object' ||
98
+ !['string', 'boolean'].includes(typeof headers.referrerPolicy) ||
99
+ !['string', 'boolean'].includes(typeof headers.contentTypeOptions) ||
100
+ !['string', 'boolean'].includes(typeof headers.permissionsPolicy)
101
+ ) {
102
+ addIssue(issues, {
103
+ code: 'invalid-manifest',
104
+ message: 'Cloudflare output manifest security.headers is incomplete.',
105
+ path: manifestPath,
106
+ });
107
+ }
108
+ if (
109
+ !csp ||
110
+ !['off', 'report-only', 'enforce'].includes(csp.mode) ||
111
+ !csp.directives ||
112
+ typeof csp.directives !== 'object' ||
113
+ Array.isArray(csp.directives) ||
114
+ Object.values(csp.directives).some(
115
+ value =>
116
+ !Array.isArray(value) ||
117
+ value.some(entry => typeof entry !== 'string'),
118
+ )
119
+ ) {
120
+ addIssue(issues, {
121
+ code: 'invalid-manifest',
122
+ message:
123
+ 'Cloudflare output manifest security.contentSecurityPolicy is invalid.',
124
+ path: manifestPath,
125
+ });
126
+ }
127
+ if (
128
+ !noindex ||
129
+ typeof noindex.workersDev !== 'boolean' ||
130
+ typeof noindex.localhost !== 'boolean' ||
131
+ !Array.isArray(noindex.previewHostnames)
132
+ ) {
133
+ addIssue(issues, {
134
+ code: 'invalid-manifest',
135
+ message: 'Cloudflare output manifest security.noindex is incomplete.',
136
+ path: manifestPath,
137
+ });
138
+ }
139
+ }
140
+ }
64
141
  if (manifest.bff?.runtimeFramework === 'effect') {
65
142
  assertEqual(
66
143
  issues,
@@ -140,7 +140,17 @@ export const verifyCloudflareOutputMutationPolicy = async (
140
140
  if (excludedFiles.has(file)) {
141
141
  continue;
142
142
  }
143
- const source = await fs.readFile(file, 'utf-8');
143
+ let source: string;
144
+ try {
145
+ source = await fs.readFile(file, 'utf-8');
146
+ } catch (error) {
147
+ // Concurrent sibling builds delete transient files (for example tsgo
148
+ // resolved configs) between the walk and the read.
149
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
150
+ continue;
151
+ }
152
+ throw error;
153
+ }
144
154
  for (const forbidden of FORBIDDEN_MUTATION_PATTERNS) {
145
155
  if (forbidden.pattern.test(source)) {
146
156
  addIssue(issues, {
@@ -5,15 +5,17 @@ import { isDeepStrictEqual } from 'node:util';
5
5
  import { parse } from '@babel/parser';
6
6
  import traverse, { type NodePath } from '@babel/traverse';
7
7
  import {
8
+ CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT,
8
9
  CLOUDFLARE_WORKER_BUNDLE_DIRECTORY,
9
10
  CLOUDFLARE_WORKER_NODE_BUILTINS,
11
+ CLOUDFLARE_WORKER_PLATFORM_MODULES,
10
12
  } from '../cloudflare-output-contract';
11
13
  import type { CloudflareOutputVerifierIssue, JsonObject } from './issues';
12
14
  import { addIssue } from './issues';
13
15
 
14
16
  interface WorkerBundleReference {
15
17
  dispatcherExport?: string;
16
- kind: 'effect-bff' | 'route';
18
+ kind: 'effect-bff' | 'route' | 'route-data';
17
19
  reference: string;
18
20
  }
19
21
 
@@ -21,12 +23,15 @@ interface ResolvedWorkerBundleReference extends WorkerBundleReference {
21
23
  path: string;
22
24
  }
23
25
 
24
- const getReferencedRouteWorkers = (manifest: JsonObject) =>
26
+ const getReferencedRouteWorkers = (
27
+ manifest: JsonObject,
28
+ field: 'routeDataWorker' | 'worker',
29
+ ) =>
25
30
  Array.isArray(manifest?.routeSpec?.routes)
26
31
  ? manifest.routeSpec.routes
27
32
  .map((route: any) =>
28
- typeof route?.worker === 'string' && route.worker.length > 0
29
- ? route.worker
33
+ typeof route?.[field] === 'string' && route[field].length > 0
34
+ ? route[field]
30
35
  : undefined,
31
36
  )
32
37
  .filter(
@@ -57,10 +62,19 @@ export const getWorkerBundleReferences = (
57
62
  },
58
63
  ]
59
64
  : []),
60
- ...getReferencedRouteWorkers(manifest).map((reference: string) => ({
61
- kind: 'route' as const,
62
- reference,
63
- })),
65
+ ...getReferencedRouteWorkers(manifest, 'worker').map(
66
+ (reference: string) => ({
67
+ kind: 'route' as const,
68
+ reference,
69
+ }),
70
+ ),
71
+ ...getReferencedRouteWorkers(manifest, 'routeDataWorker').map(
72
+ (reference: string) => ({
73
+ dispatcherExport: CLOUDFLARE_ROUTE_DATA_HANDLER_EXPORT,
74
+ kind: 'route-data' as const,
75
+ reference,
76
+ }),
77
+ ),
64
78
  ];
65
79
  };
66
80
 
@@ -100,7 +114,9 @@ export const resolveWorkerBundleReference = (
100
114
  export const missingWorkerBundleMessage = (reference: WorkerBundleReference) =>
101
115
  reference.kind === 'effect-bff'
102
116
  ? 'Cloudflare Effect BFF manifest points to a missing worker bundle.'
103
- : 'Cloudflare route worker manifest points to a missing worker bundle.';
117
+ : reference.kind === 'route-data'
118
+ ? 'Cloudflare route data worker manifest points to a missing worker bundle.'
119
+ : 'Cloudflare route worker manifest points to a missing worker bundle.';
104
120
 
105
121
  interface AstNode {
106
122
  type: string;
@@ -436,9 +452,10 @@ const getPackageName = (specifier: string) =>
436
452
  ? specifier.split('/').slice(0, 2).join('/')
437
453
  : specifier.split('/')[0];
438
454
 
439
- const CLOUDFLARE_WORKER_NODE_BUILTIN_SPECIFIERS = new Set(
440
- CLOUDFLARE_WORKER_NODE_BUILTINS.map(builtin => `node:${builtin}`),
441
- );
455
+ const CLOUDFLARE_WORKER_NODE_BUILTIN_SPECIFIERS = new Set([
456
+ ...CLOUDFLARE_WORKER_NODE_BUILTINS.map(builtin => `node:${builtin}`),
457
+ ...CLOUDFLARE_WORKER_PLATFORM_MODULES,
458
+ ]);
442
459
 
443
460
  const isInsideDirectory = (directory: string, filePath: string) => {
444
461
  const relative = path.relative(directory, filePath);
@@ -609,14 +626,15 @@ export const verifyWorkerBundleReferences = async (
609
626
  contract,
610
627
  );
611
628
  if (
612
- worker.kind === 'effect-bff' &&
613
629
  typeof worker.dispatcherExport === 'string' &&
614
630
  !entryAnalysis?.exports.has(worker.dispatcherExport)
615
631
  ) {
616
632
  addIssue(issues, {
617
633
  code: 'invalid-worker-bundle',
618
634
  message:
619
- 'Cloudflare Effect BFF worker bundle must expose its manifest dispatcherExport.',
635
+ worker.kind === 'route-data'
636
+ ? `Cloudflare route data worker bundle must expose ${worker.dispatcherExport}.`
637
+ : 'Cloudflare Effect BFF worker bundle must expose its manifest dispatcherExport.',
620
638
  path: worker.path,
621
639
  });
622
640
  }
package/src/config.ts CHANGED
@@ -1,9 +1,11 @@
1
- export type DeployTarget =
2
- | 'node'
3
- | 'vercel'
4
- | 'netlify'
5
- | 'ghPages'
6
- | 'cloudflare';
1
+ export type { ResolveEffectTsgoCompilerOptions } from './build-config/public';
2
+ export {
3
+ getBuildConfigEnvironment,
4
+ resolveEffectTsgoCompiler,
5
+ } from './build-config/public';
6
+ export { createRemoteManifestUrl } from './build-config/remote-address';
7
+ export type { DeployTarget } from './deploy-output/target';
8
+ export { resolveDeployTarget } from './deploy-output/target';
7
9
 
8
10
  export type CloudflareWorkerSecurityCspMode = 'enforce' | 'report-only' | 'off';
9
11
 
@@ -39,6 +41,18 @@ export interface CloudflareWorkerPublicAssetConfig {
39
41
  to: string;
40
42
  }
41
43
 
44
+ export interface NodePublicAssetConfig {
45
+ /**
46
+ * Source file or directory, relative to the app root, to copy into the
47
+ * Node deploy output's public directory.
48
+ */
49
+ from: string;
50
+ /**
51
+ * Destination path relative to `.output/public`.
52
+ */
53
+ to: string;
54
+ }
55
+
42
56
  export interface CloudflareWorkerD1DatabaseConfig {
43
57
  /**
44
58
  * Worker binding name, for example `DB`.
@@ -194,3 +208,17 @@ export interface CloudflareDeployConfig {
194
208
  publicAssetExcludes?: string[];
195
209
  };
196
210
  }
211
+
212
+ export interface NodeDeployConfig {
213
+ node?: {
214
+ /**
215
+ * Additional app-root files or directories to stage under
216
+ * `.output/public` when `modern deploy` targets Node, the counterpart of
217
+ * `deploy.worker.publicAssets`. The Node server does not route these
218
+ * files; serve them from the app, for example from an API handler.
219
+ * Release envelopes record them as declared public assets, so API-only
220
+ * units may ship them.
221
+ */
222
+ publicAssets?: NodePublicAssetConfig[];
223
+ };
224
+ }