@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,4 +1,9 @@
1
1
  import path from 'node:path';
2
+ import {
3
+ BACKEND_FEDERATION_MANIFEST_FILE,
4
+ BACKEND_FEDERATION_REMOTE_ENTRY_FILE,
5
+ ULTRAMODERN_BUILD_ARTIFACT_FILE,
6
+ } from '@modern-js/backend-federation-contracts';
2
7
  import { fs as fse } from '@modern-js/utils';
3
8
  import { createCloudflareOutputPlan } from '../cloudflare-output-plan';
4
9
  import { assertCloudflareOutput } from '../cloudflare-output-verifier/index';
@@ -22,9 +27,6 @@ import {
22
27
  ROUTE_SPEC_FILE,
23
28
  ROUTE_SPEC_OUTPUT,
24
29
  WORKER_BUNDLE_DIRECTORY,
25
- WORKER_ENTRY,
26
- WORKER_MANIFEST,
27
- WRANGLER_CONFIG_FILE,
28
30
  } from './constants';
29
31
  import {
30
32
  resolveTopologyDeliveryUnit,
@@ -87,18 +89,14 @@ export const createCloudflarePreset: CreateCloudflarePreset = ({
87
89
  '@modern-js/ultramodern-release-envelope',
88
90
  );
89
91
  let hasReleaseEnvelope = false;
92
+ let declaredPublicAssets: string[] = [];
90
93
 
91
94
  return {
92
95
  async prepare() {
93
96
  await fse.remove(outputDirectory);
94
97
  },
95
98
  async writeOutput() {
96
- if (
97
- releaseEnvelopeEnabled &&
98
- (await fse.pathExists(
99
- path.join(distDirectory, MICROVERTICAL_RELEASE_ENVELOPE_PATH),
100
- ))
101
- ) {
99
+ if (releaseEnvelopeEnabled) {
102
100
  await emitFrameworkMicroVerticalReleaseEnvelope({
103
101
  apiOnly,
104
102
  distDirectory,
@@ -113,6 +111,20 @@ export const createCloudflarePreset: CreateCloudflarePreset = ({
113
111
  const relativePath = path
114
112
  .relative(distDirectory, src)
115
113
  .replace(/\\/gu, '/');
114
+ // API-only builds emit server modules at arbitrary paths under dist,
115
+ // including transitive imports outside api/. Only the framework's
116
+ // published backend contract belongs beside the explicit public tree.
117
+ if (
118
+ apiOnly &&
119
+ relativePath !== '' &&
120
+ ![
121
+ BACKEND_FEDERATION_MANIFEST_FILE,
122
+ BACKEND_FEDERATION_REMOTE_ENTRY_FILE,
123
+ ULTRAMODERN_BUILD_ARTIFACT_FILE,
124
+ ].includes(relativePath)
125
+ ) {
126
+ return false;
127
+ }
116
128
  return (
117
129
  relativePath !== 'release' &&
118
130
  !relativePath.startsWith('release/') &&
@@ -173,9 +185,9 @@ export const createCloudflarePreset: CreateCloudflarePreset = ({
173
185
  outputDirectory,
174
186
  cloudflareArtifacts,
175
187
  );
176
- await copyCloudflarePublicAssets(
188
+ declaredPublicAssets = await copyCloudflarePublicAssets(
177
189
  appDirectory,
178
- publicDirectory,
190
+ outputDirectory,
179
191
  getCloudflarePublicAssets(modernConfig),
180
192
  );
181
193
  await copyCloudflareD1Migrations(
@@ -241,6 +253,7 @@ export const createCloudflarePreset: CreateCloudflarePreset = ({
241
253
  });
242
254
  if (hasReleaseEnvelope) {
243
255
  await emitCloudflareStagedReleaseEnvelope({
256
+ declaredPublicAssets,
244
257
  distDirectory,
245
258
  outputDirectory,
246
259
  });
@@ -1,5 +1,7 @@
1
1
  import path from 'node:path';
2
+ import type {} from '@modern-js/server-runtime-extensions/server-config';
2
3
  import { fs as fse } from '@modern-js/utils';
4
+ import { getCloudflareWorkerRouteDataEntryName } from '../cloudflare-output-contract';
3
5
  import { readRouteSpec } from './artifacts';
4
6
  import {
5
7
  ASSETS_BINDING,
@@ -131,6 +133,15 @@ export const createWorkerManifest = async (
131
133
  routeSpec.routes.map(async (route: Record<string, any>) => {
132
134
  const worker =
133
135
  typeof route.worker === 'string' ? route.worker : undefined;
136
+ const routeDataWorker =
137
+ route.isSSR && typeof route.entryName === 'string'
138
+ ? `${WORKER_BUNDLE_DIRECTORY}/${getCloudflareWorkerRouteDataEntryName(
139
+ route.entryName,
140
+ )}.js`
141
+ : undefined;
142
+ const hasRouteDataWorker = routeDataWorker
143
+ ? await fse.pathExists(path.join(outputDirectory, routeDataWorker))
144
+ : false;
134
145
 
135
146
  return {
136
147
  urlPath: route.urlPath,
@@ -141,6 +152,7 @@ export const createWorkerManifest = async (
141
152
  workerExists: worker
142
153
  ? await fse.pathExists(path.join(outputDirectory, worker))
143
154
  : false,
155
+ ...(hasRouteDataWorker ? { routeDataWorker } : {}),
144
156
  };
145
157
  }),
146
158
  );
@@ -217,9 +229,14 @@ export const createWorkerModuleLoaders = (manifest: any) => {
217
229
  const imports = new Map<string, string>();
218
230
 
219
231
  for (const route of manifest.routeSpec.routes) {
220
- if (route.worker && route.workerExists) {
221
- const importPath = `../${String(route.worker).replace(/^\/+/u, '')}`;
222
- imports.set(route.worker, `() => import(${JSON.stringify(importPath)})`);
232
+ for (const worker of [
233
+ route.workerExists ? route.worker : undefined,
234
+ route.routeDataWorker,
235
+ ]) {
236
+ if (worker) {
237
+ const importPath = `../${String(worker).replace(/^\/+/u, '')}`;
238
+ imports.set(worker, `() => import(${JSON.stringify(importPath)})`);
239
+ }
223
240
  }
224
241
  }
225
242
 
@@ -15,21 +15,51 @@ import {
15
15
  import type { CloudflareModernConfig } from './types';
16
16
  import { isJsonRecord, normalizeRelativePath } from './utils';
17
17
 
18
- const getCompatibilityDate = (modernConfig: CloudflareModernConfig) => {
19
- const configuredDate = modernConfig.deploy?.worker?.compatibilityDate?.trim();
20
- const compatibilityDate = configuredDate || DEFAULT_COMPATIBILITY_DATE;
21
-
18
+ // Workers only add Node.js built-ins at later dates, and the bundler
19
+ // externalizes the set probed at DEFAULT_COMPATIBILITY_DATE; an earlier date
20
+ // could leave an externalized built-in unresolvable at deploy time.
21
+ const assertSupportedCompatibilityDate = (
22
+ compatibilityDate: JsonValue | undefined,
23
+ label: string,
24
+ ) => {
25
+ if (typeof compatibilityDate !== 'string') {
26
+ throw new Error(`${label} must be a YYYY-MM-DD string.`);
27
+ }
22
28
  if (!COMPATIBILITY_DATE_PATTERN.test(compatibilityDate)) {
23
29
  throw new Error(
24
- `deploy.worker.compatibilityDate must use YYYY-MM-DD, received ${JSON.stringify(
30
+ `${label} must use YYYY-MM-DD, received ${JSON.stringify(
31
+ compatibilityDate,
32
+ )}.`,
33
+ );
34
+ }
35
+ if (compatibilityDate < DEFAULT_COMPATIBILITY_DATE) {
36
+ throw new Error(
37
+ `${label} must be ${DEFAULT_COMPATIBILITY_DATE} or later, the date the Cloudflare worker Node.js built-in contract is verified against; received ${JSON.stringify(
25
38
  compatibilityDate,
26
39
  )}.`,
27
40
  );
28
41
  }
29
-
30
42
  return compatibilityDate;
31
43
  };
32
44
 
45
+ const getCompatibilityDate = (
46
+ modernConfig: CloudflareModernConfig,
47
+ wranglerCompatibilityDate: JsonValue | undefined,
48
+ ) => {
49
+ if (wranglerCompatibilityDate !== undefined) {
50
+ // A raw Wrangler override is the effective date, so it is validated too.
51
+ return assertSupportedCompatibilityDate(
52
+ wranglerCompatibilityDate,
53
+ 'deploy.worker.wrangler.compatibility_date',
54
+ );
55
+ }
56
+ return assertSupportedCompatibilityDate(
57
+ modernConfig.deploy?.worker?.compatibilityDate?.trim() ||
58
+ DEFAULT_COMPATIBILITY_DATE,
59
+ 'deploy.worker.compatibilityDate',
60
+ );
61
+ };
62
+
33
63
  const getWorkerName = (appDirectory: string) => {
34
64
  const basename = path.basename(appDirectory);
35
65
  return basename.replace(/[^a-zA-Z0-9-_]/g, '-') || 'modern-cloudflare-worker';
@@ -59,6 +89,7 @@ const getConfiguredWrangler = (modernConfig: CloudflareModernConfig) => {
59
89
 
60
90
  const createWranglerCompatibilityFlags = (
61
91
  configuredFlags: JsonValue | undefined,
92
+ label = 'deploy.worker.wrangler.compatibility_flags',
62
93
  ) => {
63
94
  if (configuredFlags === undefined) {
64
95
  return [...REQUIRED_COMPATIBILITY_FLAGS];
@@ -68,14 +99,54 @@ const createWranglerCompatibilityFlags = (
68
99
  !Array.isArray(configuredFlags) ||
69
100
  configuredFlags.some(flag => typeof flag !== 'string')
70
101
  ) {
71
- throw new Error(
72
- 'deploy.worker.wrangler.compatibility_flags must be an array of strings.',
73
- );
102
+ throw new Error(`${label} must be an array of strings.`);
74
103
  }
75
104
 
76
105
  return [...new Set([...configuredFlags, ...REQUIRED_COMPATIBILITY_FLAGS])];
77
106
  };
78
107
 
108
+ // `wrangler deploy --env <name>` uses an environment's own compatibility_date
109
+ // and compatibility_flags instead of the top-level values, so each override
110
+ // is held to the same verified date floor and required flags.
111
+ const createWranglerEnvironments = (wranglerEnv: JsonValue | undefined) => {
112
+ if (wranglerEnv === undefined) {
113
+ return undefined;
114
+ }
115
+ if (!isJsonRecord(wranglerEnv)) {
116
+ throw new Error('deploy.worker.wrangler.env must be an object.');
117
+ }
118
+ return Object.fromEntries(
119
+ Object.entries(wranglerEnv).map(([name, environment]) => {
120
+ const label = `deploy.worker.wrangler.env.${name}`;
121
+ if (!isJsonRecord(environment)) {
122
+ throw new Error(`${label} must be an object.`);
123
+ }
124
+ return [
125
+ name,
126
+ {
127
+ ...environment,
128
+ ...(environment.compatibility_date === undefined
129
+ ? {}
130
+ : {
131
+ compatibility_date: assertSupportedCompatibilityDate(
132
+ environment.compatibility_date,
133
+ `${label}.compatibility_date`,
134
+ ),
135
+ }),
136
+ ...(environment.compatibility_flags === undefined
137
+ ? {}
138
+ : {
139
+ compatibility_flags: createWranglerCompatibilityFlags(
140
+ environment.compatibility_flags,
141
+ `${label}.compatibility_flags`,
142
+ ),
143
+ }),
144
+ },
145
+ ];
146
+ }),
147
+ );
148
+ };
149
+
79
150
  const createWranglerAssetsConfig = (
80
151
  configuredAssets: JsonValue | undefined,
81
152
  ) => {
@@ -312,6 +383,7 @@ export const createWranglerConfig = (
312
383
  modernConfig: CloudflareModernConfig,
313
384
  ) => {
314
385
  const wrangler = getConfiguredWrangler(modernConfig);
386
+ const environments = createWranglerEnvironments(wrangler.env);
315
387
  const d1Databases = createWranglerD1Databases(
316
388
  modernConfig,
317
389
  wrangler.d1_databases,
@@ -325,13 +397,17 @@ export const createWranglerConfig = (
325
397
  return {
326
398
  $schema: 'node_modules/wrangler/config-schema.json',
327
399
  name: getConfiguredWorkerName(appDirectory, modernConfig),
328
- compatibility_date: getCompatibilityDate(modernConfig),
329
400
  ...wrangler,
401
+ compatibility_date: getCompatibilityDate(
402
+ modernConfig,
403
+ wrangler.compatibility_date,
404
+ ),
330
405
  main: WORKER_ENTRY,
331
406
  compatibility_flags: createWranglerCompatibilityFlags(
332
407
  wrangler.compatibility_flags,
333
408
  ),
334
409
  assets: createWranglerAssetsConfig(wrangler.assets),
410
+ ...(environments === undefined ? {} : { env: environments }),
335
411
  ...(d1Databases === undefined ? {} : { d1_databases: d1Databases }),
336
412
  ...(wranglerServices === undefined ? {} : { services: wranglerServices }),
337
413
  };