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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/cjs/backend-federation-build/codegen.js +267 -0
  2. package/dist/cjs/backend-federation-build/config.js +239 -0
  3. package/dist/cjs/backend-federation-build/emit.js +154 -0
  4. package/dist/cjs/backend-federation-build/index.js +53 -0
  5. package/dist/cjs/build-config/build-environment.js +129 -0
  6. package/dist/cjs/build-config/precompress/plugin.js +124 -0
  7. package/dist/cjs/build-config/precompress/types.js +18 -0
  8. package/dist/cjs/build-config/public.js +43 -0
  9. package/dist/cjs/build-config/remote-address.js +58 -0
  10. package/dist/cjs/cloudflare/artifacts.js +8 -19
  11. package/dist/cjs/cloudflare/constants.js +1 -1
  12. package/dist/cjs/cloudflare/delivery-unit.js +23 -42
  13. package/dist/cjs/cloudflare/index.js +10 -2
  14. package/dist/cjs/cloudflare/worker-manifest.js +13 -4
  15. package/dist/cjs/cloudflare/wrangler-config.js +35 -7
  16. package/dist/cjs/cloudflare-builder.js +252 -75
  17. package/dist/cjs/cloudflare-output-contract.js +69 -3
  18. package/dist/cjs/cloudflare-output-verifier/identity.js +29 -27
  19. package/dist/cjs/cloudflare-output-verifier/index.js +10 -0
  20. package/dist/cjs/cloudflare-output-verifier/manifest.js +46 -0
  21. package/dist/cjs/cloudflare-output-verifier/mutation-policy.js +7 -1
  22. package/dist/cjs/cloudflare-output-verifier/worker-bundles.js +14 -6
  23. package/dist/cjs/config.js +34 -1
  24. package/dist/cjs/deploy-output/npmAliases.js +251 -0
  25. package/dist/cjs/deploy-output/plugin.js +97 -0
  26. package/dist/cjs/deploy-output/public-assets.js +146 -0
  27. package/dist/cjs/deploy-output/target.js +104 -0
  28. package/dist/cjs/deploy-output/trace-files.js +90 -0
  29. package/dist/cjs/native-type-checker.js +193 -0
  30. package/dist/cjs/policy-defaults.js +101 -0
  31. package/dist/cjs/release-envelope/framework-output.js +153 -79
  32. package/dist/cjs/release-envelope/index.js +10 -4
  33. package/dist/cjs/release-envelope/plugin.js +18 -13
  34. package/dist/cjs/release-identity.js +5 -6
  35. package/dist/cjs/runtime-package-resolution.js +118 -0
  36. package/dist/cjs/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
  37. package/dist/cjs/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  38. package/dist/cjs/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  39. package/dist/cjs/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  40. package/dist/cjs/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  41. package/dist/cjs/templates/cloudflare-worker-route-data.mjs +1069 -0
  42. package/dist/esm/backend-federation-build/codegen.mjs +216 -0
  43. package/dist/esm/backend-federation-build/config.mjs +163 -0
  44. package/dist/esm/backend-federation-build/emit.mjs +103 -0
  45. package/dist/esm/backend-federation-build/index.mjs +1 -0
  46. package/dist/esm/build-config/build-environment.mjs +88 -0
  47. package/dist/esm/build-config/precompress/plugin.mjs +76 -0
  48. package/dist/esm/build-config/precompress/types.mjs +0 -0
  49. package/dist/esm/build-config/public.mjs +1 -0
  50. package/dist/esm/build-config/remote-address.mjs +20 -0
  51. package/dist/esm/cloudflare/artifacts.mjs +8 -19
  52. package/dist/esm/cloudflare/constants.mjs +1 -1
  53. package/dist/esm/cloudflare/delivery-unit.mjs +17 -36
  54. package/dist/esm/cloudflare/index.mjs +10 -2
  55. package/dist/esm/cloudflare/worker-manifest.mjs +13 -4
  56. package/dist/esm/cloudflare/wrangler-config.mjs +35 -7
  57. package/dist/esm/cloudflare-builder.mjs +246 -75
  58. package/dist/esm/cloudflare-output-contract.mjs +59 -2
  59. package/dist/esm/cloudflare-output-verifier/identity.mjs +27 -25
  60. package/dist/esm/cloudflare-output-verifier/index.mjs +10 -0
  61. package/dist/esm/cloudflare-output-verifier/manifest.mjs +46 -0
  62. package/dist/esm/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  63. package/dist/esm/cloudflare-output-verifier/worker-bundles.mjs +15 -7
  64. package/dist/esm/config.mjs +3 -0
  65. package/dist/esm/deploy-output/npmAliases.mjs +199 -0
  66. package/dist/esm/deploy-output/plugin.mjs +46 -0
  67. package/dist/esm/deploy-output/public-assets.mjs +82 -0
  68. package/dist/esm/deploy-output/target.mjs +57 -0
  69. package/dist/esm/deploy-output/trace-files.mjs +38 -0
  70. package/dist/esm/native-type-checker.mjs +142 -0
  71. package/dist/esm/policy-defaults.mjs +45 -0
  72. package/dist/esm/release-envelope/framework-output.mjs +130 -56
  73. package/dist/esm/release-envelope/index.mjs +10 -4
  74. package/dist/esm/release-envelope/plugin.mjs +18 -13
  75. package/dist/esm/release-identity.mjs +5 -6
  76. package/dist/esm/runtime-package-resolution.mjs +60 -0
  77. package/dist/esm/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
  78. package/dist/esm/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  79. package/dist/esm/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  80. package/dist/esm/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  81. package/dist/esm/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  82. package/dist/esm/templates/cloudflare-worker-route-data.mjs +1069 -0
  83. package/dist/esm-node/backend-federation-build/codegen.mjs +217 -0
  84. package/dist/esm-node/backend-federation-build/config.mjs +164 -0
  85. package/dist/esm-node/backend-federation-build/emit.mjs +104 -0
  86. package/dist/esm-node/backend-federation-build/index.mjs +2 -0
  87. package/dist/esm-node/build-config/build-environment.mjs +89 -0
  88. package/dist/esm-node/build-config/precompress/plugin.mjs +77 -0
  89. package/dist/esm-node/build-config/precompress/types.mjs +1 -0
  90. package/dist/esm-node/build-config/public.mjs +2 -0
  91. package/dist/esm-node/build-config/remote-address.mjs +21 -0
  92. package/dist/esm-node/cloudflare/artifacts.mjs +8 -19
  93. package/dist/esm-node/cloudflare/constants.mjs +1 -1
  94. package/dist/esm-node/cloudflare/delivery-unit.mjs +17 -36
  95. package/dist/esm-node/cloudflare/index.mjs +10 -2
  96. package/dist/esm-node/cloudflare/worker-manifest.mjs +13 -4
  97. package/dist/esm-node/cloudflare/wrangler-config.mjs +35 -7
  98. package/dist/esm-node/cloudflare-builder.mjs +246 -75
  99. package/dist/esm-node/cloudflare-output-contract.mjs +59 -2
  100. package/dist/esm-node/cloudflare-output-verifier/identity.mjs +27 -25
  101. package/dist/esm-node/cloudflare-output-verifier/index.mjs +10 -0
  102. package/dist/esm-node/cloudflare-output-verifier/manifest.mjs +46 -0
  103. package/dist/esm-node/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  104. package/dist/esm-node/cloudflare-output-verifier/worker-bundles.mjs +15 -7
  105. package/dist/esm-node/config.mjs +3 -0
  106. package/dist/esm-node/deploy-output/npmAliases.mjs +200 -0
  107. package/dist/esm-node/deploy-output/plugin.mjs +49 -0
  108. package/dist/esm-node/deploy-output/public-assets.mjs +83 -0
  109. package/dist/esm-node/deploy-output/target.mjs +58 -0
  110. package/dist/esm-node/deploy-output/trace-files.mjs +39 -0
  111. package/dist/esm-node/native-type-checker.mjs +143 -0
  112. package/dist/esm-node/policy-defaults.mjs +46 -0
  113. package/dist/esm-node/release-envelope/framework-output.mjs +130 -56
  114. package/dist/esm-node/release-envelope/index.mjs +10 -4
  115. package/dist/esm-node/release-envelope/plugin.mjs +18 -13
  116. package/dist/esm-node/release-identity.mjs +5 -6
  117. package/dist/esm-node/runtime-package-resolution.mjs +61 -0
  118. package/dist/esm-node/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
  119. package/dist/esm-node/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  120. package/dist/esm-node/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  121. package/dist/esm-node/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  122. package/dist/esm-node/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  123. package/dist/esm-node/templates/cloudflare-worker-route-data.mjs +1069 -0
  124. package/dist/types/backend-federation-build/codegen.d.ts +116 -0
  125. package/dist/types/backend-federation-build/config.d.ts +121 -0
  126. package/dist/types/backend-federation-build/emit.d.ts +21 -0
  127. package/dist/types/backend-federation-build/index.d.ts +2 -0
  128. package/dist/types/build-config/build-environment.d.ts +14 -0
  129. package/dist/types/build-config/precompress/plugin.d.ts +4 -0
  130. package/dist/types/build-config/precompress/types.d.ts +19 -0
  131. package/dist/types/build-config/public.d.ts +2 -0
  132. package/dist/types/build-config/remote-address.d.ts +3 -0
  133. package/dist/types/cloudflare/artifacts.d.ts +7 -6
  134. package/dist/types/cloudflare/constants.d.ts +1 -1
  135. package/dist/types/cloudflare/delivery-unit.d.ts +3 -3
  136. package/dist/types/cloudflare/worker-manifest.d.ts +2 -2
  137. package/dist/types/cloudflare/wrangler-config.d.ts +6 -0
  138. package/dist/types/cloudflare-builder.d.ts +49 -9
  139. package/dist/types/cloudflare-output-contract.d.ts +4 -1
  140. package/dist/types/cloudflare-output-verifier/identity.d.ts +1 -1
  141. package/dist/types/cloudflare-output-verifier/worker-bundles.d.ts +2 -2
  142. package/dist/types/config.d.ts +29 -1
  143. package/dist/types/deploy-output/npmAliases.d.ts +14 -0
  144. package/dist/types/deploy-output/plugin.d.ts +35 -0
  145. package/dist/types/deploy-output/public-assets.d.ts +51 -0
  146. package/dist/types/deploy-output/target.d.ts +29 -0
  147. package/dist/types/deploy-output/trace-files.d.ts +17 -0
  148. package/dist/types/native-type-checker.d.ts +15 -0
  149. package/dist/types/policy-defaults.d.ts +46 -0
  150. package/dist/types/precompress/LICENSE +20 -0
  151. package/dist/types/precompress/index.d.ts +76 -0
  152. package/dist/types/release-envelope/framework-output.d.ts +8 -3
  153. package/dist/types/release-envelope/plugin.d.ts +7 -7
  154. package/dist/types/runtime-package-resolution.d.ts +28 -0
  155. package/dist/types/templates/cloudflare-worker-route-data.d.mts +14 -0
  156. package/package.json +97 -15
  157. package/src/backend-federation-build/codegen.ts +254 -0
  158. package/src/backend-federation-build/config.ts +492 -0
  159. package/src/backend-federation-build/emit.ts +213 -0
  160. package/src/backend-federation-build/index.ts +2 -0
  161. package/src/build-config/build-environment.ts +160 -0
  162. package/src/build-config/precompress/plugin.ts +140 -0
  163. package/src/build-config/precompress/types.ts +26 -0
  164. package/src/build-config/public.ts +5 -0
  165. package/src/build-config/remote-address.ts +33 -0
  166. package/src/cloudflare/artifacts.ts +22 -43
  167. package/src/cloudflare/constants.ts +1 -1
  168. package/src/cloudflare/delivery-unit.ts +42 -53
  169. package/src/cloudflare/index.ts +24 -11
  170. package/src/cloudflare/worker-manifest.ts +20 -3
  171. package/src/cloudflare/wrangler-config.ts +86 -10
  172. package/src/cloudflare-builder.ts +475 -151
  173. package/src/cloudflare-output-contract.ts +70 -0
  174. package/src/cloudflare-output-verifier/identity.ts +5 -1
  175. package/src/cloudflare-output-verifier/index.ts +20 -0
  176. package/src/cloudflare-output-verifier/manifest.ts +77 -0
  177. package/src/cloudflare-output-verifier/mutation-policy.ts +11 -1
  178. package/src/cloudflare-output-verifier/worker-bundles.ts +32 -14
  179. package/src/config.ts +34 -6
  180. package/src/deploy-output/npmAliases.ts +382 -0
  181. package/src/deploy-output/plugin.ts +86 -0
  182. package/src/deploy-output/public-assets.ts +224 -0
  183. package/src/deploy-output/target.ts +106 -0
  184. package/src/deploy-output/trace-files.ts +67 -0
  185. package/src/native-type-checker.ts +183 -0
  186. package/src/policy-defaults.ts +127 -0
  187. package/src/release-envelope/framework-output.ts +346 -94
  188. package/src/release-envelope/index.ts +26 -5
  189. package/src/release-envelope/plugin.ts +43 -40
  190. package/src/release-identity.ts +13 -2
  191. package/src/runtime-package-resolution.ts +115 -0
  192. package/src/templates/cloudflare-entry.001-bootstrap-security.mjs +0 -3
  193. package/src/templates/cloudflare-entry.002-assets-routes.mjs +1 -1
  194. package/src/templates/cloudflare-entry.004-rendering-css.mjs +5 -1
  195. package/src/templates/cloudflare-entry.005-worker-dispatch.mjs +98 -10
  196. package/src/templates/cloudflare-entry.006-fetch-handler.mjs +9 -2
  197. package/src/templates/cloudflare-worker-route-data.mjs +1069 -0
  198. package/dist/cjs/templates/cloudflare-worker-fs-promises.mjs +0 -11
  199. package/dist/cjs/templates/cloudflare-worker-loadable-server.mjs +0 -281
  200. package/dist/cjs/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  201. package/dist/cjs/templates/cloudflare-worker-path.mjs +0 -98
  202. package/dist/esm/templates/cloudflare-worker-fs-promises.mjs +0 -11
  203. package/dist/esm/templates/cloudflare-worker-loadable-server.mjs +0 -281
  204. package/dist/esm/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  205. package/dist/esm/templates/cloudflare-worker-path.mjs +0 -98
  206. package/dist/esm-node/templates/cloudflare-worker-fs-promises.mjs +0 -11
  207. package/dist/esm-node/templates/cloudflare-worker-loadable-server.mjs +0 -281
  208. package/dist/esm-node/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  209. package/dist/esm-node/templates/cloudflare-worker-path.mjs +0 -98
  210. package/dist/types/templates/cloudflare-worker-fs-promises.d.mts +0 -5
  211. package/dist/types/templates/cloudflare-worker-loadable-server.d.mts +0 -48
  212. package/dist/types/templates/cloudflare-worker-mf-ssr-runtime-plugin.d.mts +0 -13
  213. package/dist/types/templates/cloudflare-worker-path.d.mts +0 -21
  214. package/src/templates/cloudflare-worker-fs-promises.mjs +0 -11
  215. package/src/templates/cloudflare-worker-loadable-server.mjs +0 -281
  216. package/src/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  217. package/src/templates/cloudflare-worker-path.mjs +0 -98
@@ -0,0 +1,160 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import {
4
+ accessSync,
5
+ chmodSync,
6
+ constants,
7
+ lstatSync,
8
+ mkdirSync,
9
+ readFileSync,
10
+ realpathSync,
11
+ renameSync,
12
+ rmSync,
13
+ writeFileSync,
14
+ } from 'node:fs';
15
+ import { createRequire } from 'node:module';
16
+ import { tmpdir } from 'node:os';
17
+ import { basename, dirname, join, resolve } from 'node:path';
18
+ import type { URL } from 'node:url';
19
+
20
+ const EFFECT_TSGO_PACKAGE = '@effect/tsgo';
21
+ const EFFECT_TSGO_BIN = 'effect-tsgo';
22
+ const EFFECT_TSGO_RESOLUTION_ERROR =
23
+ 'Unable to resolve the Effect TS-Go compiler. Install "@effect/tsgo" and a native TypeScript backend for this build config, or set EFFECT_TSGO_BIN.';
24
+ const executableEffectTsgoCompilers = new Map<string, string>();
25
+
26
+ type PackageJson = {
27
+ bin?: Record<string, string> | string;
28
+ };
29
+
30
+ function resolveEffectTsgoCli(from: string | URL): string {
31
+ const projectRequire = createRequire(from);
32
+ const packageJsonPath = projectRequire.resolve(
33
+ `${EFFECT_TSGO_PACKAGE}/package.json`,
34
+ );
35
+ const packageJson = JSON.parse(
36
+ readFileSync(packageJsonPath, 'utf-8'),
37
+ ) as PackageJson;
38
+ const bin =
39
+ typeof packageJson.bin === 'string'
40
+ ? packageJson.bin
41
+ : packageJson.bin?.[EFFECT_TSGO_BIN];
42
+
43
+ if (!bin) {
44
+ throw new Error(EFFECT_TSGO_RESOLUTION_ERROR);
45
+ }
46
+
47
+ return resolve(dirname(packageJsonPath), bin);
48
+ }
49
+
50
+ function resolveExecutableEffectTsgoCompiler(compilerPath: string): string {
51
+ if (process.platform === 'win32') {
52
+ return compilerPath;
53
+ }
54
+
55
+ const sourcePath = realpathSync(compilerPath);
56
+ const source = lstatSync(sourcePath);
57
+ if (!source.isFile()) {
58
+ throw new Error(EFFECT_TSGO_RESOLUTION_ERROR);
59
+ }
60
+
61
+ try {
62
+ accessSync(sourcePath, constants.X_OK);
63
+ return compilerPath;
64
+ } catch {
65
+ // npm currently publishes Effect TS-Go's native Unix files without an
66
+ // execute bit. Keep node_modules immutable and materialize a private copy.
67
+ }
68
+
69
+ const cachedCompiler = executableEffectTsgoCompilers.get(sourcePath);
70
+ if (cachedCompiler) {
71
+ try {
72
+ accessSync(cachedCompiler, constants.X_OK);
73
+ return cachedCompiler;
74
+ } catch {
75
+ executableEffectTsgoCompilers.delete(sourcePath);
76
+ }
77
+ }
78
+
79
+ const compilerBytes = readFileSync(sourcePath);
80
+ const compilerDigest = createHash('sha256')
81
+ .update(compilerBytes)
82
+ .digest('hex');
83
+ const compilerDirectory = join(
84
+ tmpdir(),
85
+ 'modern-js',
86
+ 'effect-tsgo',
87
+ compilerDigest,
88
+ );
89
+ mkdirSync(compilerDirectory, { recursive: true, mode: 0o700 });
90
+ const executableCompiler = join(compilerDirectory, basename(sourcePath));
91
+ try {
92
+ accessSync(executableCompiler, constants.X_OK);
93
+ } catch {
94
+ const temporaryCompiler = join(
95
+ compilerDirectory,
96
+ `.${basename(sourcePath)}.${process.pid}.tmp`,
97
+ );
98
+ rmSync(temporaryCompiler, { force: true });
99
+ try {
100
+ writeFileSync(temporaryCompiler, compilerBytes, {
101
+ flag: 'wx',
102
+ mode: 0o700,
103
+ });
104
+ chmodSync(temporaryCompiler, 0o700);
105
+ renameSync(temporaryCompiler, executableCompiler);
106
+ } finally {
107
+ rmSync(temporaryCompiler, { force: true });
108
+ }
109
+ }
110
+ accessSync(executableCompiler, constants.X_OK);
111
+ executableEffectTsgoCompilers.set(sourcePath, executableCompiler);
112
+ return executableCompiler;
113
+ }
114
+
115
+ /**
116
+ * Reads an environment variable while keeping generated build configs free of
117
+ * direct process access.
118
+ */
119
+ export function getBuildConfigEnvironment(name: string): string | undefined {
120
+ return process.env[name];
121
+ }
122
+
123
+ export type ResolveEffectTsgoCompilerOptions = {
124
+ /** Module URL or absolute filename used to resolve the consumer's compiler. */
125
+ from: string | URL;
126
+ };
127
+
128
+ /**
129
+ * Resolves the Effect TS-Go executable used by Module Federation DTS builds.
130
+ */
131
+ export function resolveEffectTsgoCompiler(
132
+ options: ResolveEffectTsgoCompilerOptions,
133
+ ): string {
134
+ const configuredCompiler =
135
+ getBuildConfigEnvironment('EFFECT_TSGO_BIN')?.trim();
136
+
137
+ if (configuredCompiler) {
138
+ try {
139
+ return resolveExecutableEffectTsgoCompiler(configuredCompiler);
140
+ } catch {
141
+ throw new Error(EFFECT_TSGO_RESOLUTION_ERROR);
142
+ }
143
+ }
144
+
145
+ try {
146
+ const compiler = execFileSync(
147
+ process.execPath,
148
+ [resolveEffectTsgoCli(options.from), 'get-exe-path'],
149
+ { encoding: 'utf-8' },
150
+ ).trim();
151
+
152
+ if (compiler) {
153
+ return resolveExecutableEffectTsgoCompiler(compiler);
154
+ }
155
+ } catch {
156
+ // Use one stable error for package, platform-binary, and CLI failures.
157
+ }
158
+
159
+ throw new Error(EFFECT_TSGO_RESOLUTION_ERROR);
160
+ }
@@ -0,0 +1,140 @@
1
+ import { constants as zlibConstants } from 'node:zlib';
2
+ import type { RsbuildPlugin } from '@rsbuild/core';
3
+ import CompressionPlugin from 'compression-webpack-plugin';
4
+ import type { PrecompressConfig } from './types';
5
+
6
+ export type { PrecompressCodecOptions, PrecompressConfig } from './types';
7
+
8
+ type CompressionPluginOptions = NonNullable<
9
+ ConstructorParameters<typeof CompressionPlugin>[0]
10
+ >;
11
+
12
+ const DEFAULT_PRECOMPRESS_TEST = /\.(js|mjs|cjs|css|html|svg|json|map)$/i;
13
+ const DEFAULT_PRECOMPRESS_THRESHOLD = 10 * 1024;
14
+ const DEFAULT_PRECOMPRESS_MIN_RATIO = 0.8;
15
+
16
+ const createDefaultGzipOptions = (): CompressionPluginOptions => ({
17
+ algorithm: 'gzip',
18
+ filename: '[path][base].gz',
19
+ test: DEFAULT_PRECOMPRESS_TEST,
20
+ threshold: DEFAULT_PRECOMPRESS_THRESHOLD,
21
+ minRatio: DEFAULT_PRECOMPRESS_MIN_RATIO,
22
+ compressionOptions: {
23
+ level: 6,
24
+ },
25
+ });
26
+
27
+ const createDefaultBrotliOptions = (): CompressionPluginOptions => ({
28
+ algorithm: 'brotliCompress',
29
+ filename: '[path][base].br',
30
+ test: DEFAULT_PRECOMPRESS_TEST,
31
+ threshold: DEFAULT_PRECOMPRESS_THRESHOLD,
32
+ minRatio: DEFAULT_PRECOMPRESS_MIN_RATIO,
33
+ compressionOptions: {
34
+ params: {
35
+ [zlibConstants.BROTLI_PARAM_QUALITY]: 9,
36
+ },
37
+ },
38
+ });
39
+
40
+ const mergeCompressionOptions = (
41
+ base: CompressionPluginOptions,
42
+ next: Partial<CompressionPluginOptions>,
43
+ ): CompressionPluginOptions => {
44
+ const merged = {
45
+ ...base,
46
+ ...next,
47
+ };
48
+
49
+ if (base.compressionOptions || next.compressionOptions) {
50
+ const baseCompressionOptions = base.compressionOptions as
51
+ | Record<string, unknown>
52
+ | undefined;
53
+ const nextCompressionOptions = next.compressionOptions as
54
+ | Record<string, unknown>
55
+ | undefined;
56
+ const mergedCompressionOptions = {
57
+ ...baseCompressionOptions,
58
+ ...nextCompressionOptions,
59
+ };
60
+
61
+ if (baseCompressionOptions?.params || nextCompressionOptions?.params) {
62
+ mergedCompressionOptions.params = {
63
+ ...(baseCompressionOptions?.params as Record<string, unknown>),
64
+ ...(nextCompressionOptions?.params as Record<string, unknown>),
65
+ };
66
+ }
67
+
68
+ merged.compressionOptions = mergedCompressionOptions;
69
+ }
70
+
71
+ return merged;
72
+ };
73
+
74
+ const resolveCodecOptions = (
75
+ codecConfig: PrecompressConfig['gzip'] | PrecompressConfig['brotli'],
76
+ createDefaultOptions: () => CompressionPluginOptions,
77
+ ): CompressionPluginOptions | null => {
78
+ if (codecConfig === false) {
79
+ return null;
80
+ }
81
+
82
+ if (codecConfig === undefined || codecConfig === true) {
83
+ return createDefaultOptions();
84
+ }
85
+
86
+ return mergeCompressionOptions(createDefaultOptions(), codecConfig);
87
+ };
88
+
89
+ const resolvePrecompressConfig = (
90
+ precompress: boolean | PrecompressConfig | undefined,
91
+ ): PrecompressConfig | false => {
92
+ if (precompress === false || precompress === undefined) {
93
+ return false;
94
+ }
95
+
96
+ if (precompress === true) {
97
+ return {};
98
+ }
99
+
100
+ return precompress;
101
+ };
102
+
103
+ export const builderPluginAdapterPrecompress = (
104
+ precompress: boolean | PrecompressConfig | undefined,
105
+ ): RsbuildPlugin => ({
106
+ name: 'builder-plugin-adapter-modern-precompress',
107
+
108
+ setup(api) {
109
+ api.modifyBundlerChain((chain, { isProd, target }) => {
110
+ if (!isProd || target !== 'web') {
111
+ return;
112
+ }
113
+
114
+ const precompressConfig = resolvePrecompressConfig(precompress);
115
+ if (precompressConfig === false) {
116
+ return;
117
+ }
118
+
119
+ const gzipOptions = resolveCodecOptions(
120
+ precompressConfig.gzip,
121
+ createDefaultGzipOptions,
122
+ );
123
+ if (gzipOptions) {
124
+ chain
125
+ .plugin('modern-precompress-gzip')
126
+ .use(CompressionPlugin, [gzipOptions]);
127
+ }
128
+
129
+ const brotliOptions = resolveCodecOptions(
130
+ precompressConfig.brotli,
131
+ createDefaultBrotliOptions,
132
+ );
133
+ if (brotliOptions) {
134
+ chain
135
+ .plugin('modern-precompress-brotli')
136
+ .use(CompressionPlugin, [brotliOptions]);
137
+ }
138
+ });
139
+ },
140
+ });
@@ -0,0 +1,26 @@
1
+ import type CompressionPlugin from 'compression-webpack-plugin';
2
+
3
+ type CompressionPluginOptions = NonNullable<
4
+ ConstructorParameters<typeof CompressionPlugin>[0]
5
+ >;
6
+
7
+ export type PrecompressCodecOptions =
8
+ | boolean
9
+ | Partial<CompressionPluginOptions>;
10
+
11
+ export interface PrecompressConfig {
12
+ /**
13
+ * Configure gzip precompression options.
14
+ * `true` means using default options.
15
+ * `false` means disabling gzip precompression.
16
+ * @default true
17
+ */
18
+ gzip?: PrecompressCodecOptions;
19
+ /**
20
+ * Configure brotli precompression options.
21
+ * `true` means using default options.
22
+ * `false` means disabling brotli precompression.
23
+ * @default true
24
+ */
25
+ brotli?: PrecompressCodecOptions;
26
+ }
@@ -0,0 +1,5 @@
1
+ export type { ResolveEffectTsgoCompilerOptions } from './build-environment';
2
+ export {
3
+ getBuildConfigEnvironment,
4
+ resolveEffectTsgoCompiler,
5
+ } from './build-environment';
@@ -0,0 +1,33 @@
1
+ import {
2
+ type BrowserManifestAddressOptions,
3
+ resolveBrowserManifestAddress,
4
+ } from '@modern-js/surface-resolution';
5
+ import { resolveDeployTarget } from '../deploy-output/target';
6
+ import { getBuildConfigEnvironment } from './build-environment';
7
+
8
+ /** Adapt build environment leases and MF's name@URL syntax to discovery policy. */
9
+ export function createRemoteManifestUrl(
10
+ options: BrowserManifestAddressOptions,
11
+ ): string {
12
+ const env: Record<string, string | undefined> = {
13
+ ...Object.fromEntries(
14
+ [
15
+ options.manifestEnv,
16
+ options.publicUrlEnv,
17
+ 'ULTRAMODERN_CLOUDFLARE_WORKERS_DEV_SUBDOMAIN',
18
+ ].map(name => [name, getBuildConfigEnvironment(name)]),
19
+ ),
20
+ MODERNJS_DEPLOY: resolveDeployTarget().target,
21
+ };
22
+ const address = resolveBrowserManifestAddress(
23
+ env,
24
+ options,
25
+ getBuildConfigEnvironment('NODE_ENV') ?? 'production',
26
+ );
27
+ if (!address.ok)
28
+ throw new Error(`Remote ${options.mfName}: ${address.reason}`);
29
+ return (
30
+ env[options.manifestEnv]?.trim() ||
31
+ `${options.mfName}@${address.manifestUrl}`
32
+ );
33
+ }
@@ -1,9 +1,11 @@
1
1
  import path from 'node:path';
2
2
  import { fs as fse } from '@modern-js/utils';
3
- import type {
4
- CloudflareWorkerArtifactConfig,
5
- CloudflareWorkerPublicAssetConfig,
6
- } from '../config';
3
+ import type { CloudflareWorkerArtifactConfig } from '../config';
4
+ import {
5
+ CLOUDFLARE_PUBLIC_ASSET_SCOPE,
6
+ normalizeDeclaredPublicAssets,
7
+ stageDeclaredPublicAssets,
8
+ } from '../deploy-output/public-assets';
7
9
  import {
8
10
  RESERVED_ARTIFACT_DESTINATION_DIRECTORIES,
9
11
  RESERVED_ARTIFACT_DESTINATION_FILES,
@@ -54,34 +56,12 @@ export const getCloudflareArtifacts = (modernConfig: CloudflareModernConfig) =>
54
56
  normalizeCloudflareArtifact,
55
57
  );
56
58
 
57
- const normalizeCloudflarePublicAsset = (
58
- asset: CloudflareWorkerPublicAssetConfig,
59
- index: number,
60
- ) => {
61
- const from = normalizeRelativePath(
62
- asset.from,
63
- `deploy.worker.publicAssets[${index}].from`,
64
- 'app root',
65
- );
66
- const to = normalizeRelativePath(
67
- asset.to,
68
- `deploy.worker.publicAssets[${index}].to`,
69
- 'Cloudflare public output',
70
- { allowRoot: true },
71
- );
72
-
73
- return {
74
- from,
75
- to,
76
- index,
77
- };
78
- };
79
-
80
59
  export const getCloudflarePublicAssets = (
81
60
  modernConfig: CloudflareModernConfig,
82
61
  ) =>
83
- (modernConfig.deploy?.worker?.publicAssets ?? []).map(
84
- normalizeCloudflarePublicAsset,
62
+ normalizeDeclaredPublicAssets(
63
+ modernConfig.deploy?.worker?.publicAssets,
64
+ CLOUDFLARE_PUBLIC_ASSET_SCOPE,
85
65
  );
86
66
 
87
67
  export const copyCloudflareArtifacts = async (
@@ -102,23 +82,22 @@ export const copyCloudflareArtifacts = async (
102
82
  }
103
83
  };
104
84
 
85
+ /**
86
+ * Stage `deploy.worker.publicAssets` into Worker Static Assets.
87
+ *
88
+ * @returns the staged files relative to the Cloudflare output root.
89
+ */
105
90
  export const copyCloudflarePublicAssets = async (
106
91
  appDirectory: string,
107
- publicDirectory: string,
92
+ outputDirectory: string,
108
93
  publicAssets: ReturnType<typeof getCloudflarePublicAssets>,
109
- ) => {
110
- for (const asset of publicAssets) {
111
- const sourcePath = path.join(appDirectory, asset.from);
112
-
113
- if (!(await fse.pathExists(sourcePath))) {
114
- throw new Error(
115
- `deploy.worker.publicAssets[${asset.index}].from does not exist: ${asset.from}`,
116
- );
117
- }
118
-
119
- await fse.copy(sourcePath, path.join(publicDirectory, asset.to));
120
- }
121
- };
94
+ ) =>
95
+ stageDeclaredPublicAssets({
96
+ appDirectory,
97
+ outputDirectory,
98
+ assets: publicAssets,
99
+ scope: CLOUDFLARE_PUBLIC_ASSET_SCOPE,
100
+ });
122
101
 
123
102
  export const copyCloudflareD1Migrations = async (
124
103
  appDirectory: string,
@@ -34,7 +34,7 @@ export const BFF_EFFECT_WORKER_ENTRY = `${WORKER_BUNDLE_DIRECTORY}/__modern_bff_
34
34
  export const BFF_EFFECT_WORKER_DISPATCHER_EXPORT =
35
35
  '__modern_create_effect_bff_dispatcher';
36
36
  export const EFFECT_BFF_CLOUDFLARE_IMPORT_GUIDANCE =
37
- 'Ensure the Effect API entry exists at api/index.ts or bff.effect.entry, and import Cloudflare edge handlers from @modern-js/plugin-bff/effect-edge instead of lambda/Hono server helpers.';
37
+ 'Ensure the Effect API entry exists at api/index.ts or bff.effect.entry, and import Cloudflare edge handlers from @modern-js/bff-effect/effect-edge instead of lambda/Hono server helpers.';
38
38
  export const DEFAULT_COMPATIBILITY_DATE = '2026-06-02';
39
39
  export const COMPATIBILITY_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/u;
40
40
  export const REQUIRED_COMPATIBILITY_FLAGS =
@@ -1,17 +1,16 @@
1
1
  import path from 'node:path';
2
- import { fs as fse } from '@modern-js/utils';
3
2
  import {
4
3
  type DeliveryUnitIdentity,
5
4
  isUltramodernBuildArtifact,
6
5
  nonEmptyString,
7
6
  toDeliveryUnitIdentity,
8
7
  ULTRAMODERN_BUILD_ARTIFACT_PATH,
9
- ULTRAMODERN_BUILD_MODULE_PATH,
10
- } from '@modern-js/utils/universal';
8
+ } from '@modern-js/backend-federation-contracts';
9
+ import { fs as fse } from '@modern-js/utils';
11
10
  import { resolveUltramodernReleaseIdentity } from '../release-identity';
12
11
  import { isRecord } from './utils';
13
12
 
14
- const COMPACT_CONFIG_PATH = '.modernjs/ultramodern.json';
13
+ const TOPOLOGY_PATH = 'topology/reference-topology.json';
15
14
 
16
15
  export type DeliveryUnitStamp = DeliveryUnitIdentity & {
17
16
  surfaces: {
@@ -20,7 +19,7 @@ export type DeliveryUnitStamp = DeliveryUnitIdentity & {
20
19
  };
21
20
  };
22
21
 
23
- type CompactAppResolution = {
22
+ type TopologyAppResolution = {
24
23
  app?: Record<string, unknown>;
25
24
  workspaceRoot: string;
26
25
  };
@@ -31,7 +30,7 @@ const findWorkspaceRoot = async (
31
30
  let current = path.resolve(appDirectory);
32
31
 
33
32
  for (;;) {
34
- if (await fse.pathExists(path.join(current, COMPACT_CONFIG_PATH))) {
33
+ if (await fse.pathExists(path.join(current, TOPOLOGY_PATH))) {
35
34
  return current;
36
35
  }
37
36
 
@@ -61,34 +60,32 @@ const stampReleaseIdentity = (
61
60
  };
62
61
  };
63
62
 
64
- const resolveCompactApp = async (
63
+ const resolveTopologyApp = async (
65
64
  appDirectory: string,
66
- ): Promise<CompactAppResolution | undefined> => {
65
+ ): Promise<TopologyAppResolution | undefined> => {
67
66
  const workspaceRoot = await findWorkspaceRoot(appDirectory);
68
67
  if (!workspaceRoot) {
69
68
  return undefined;
70
69
  }
71
70
 
72
- let compactConfig: unknown;
73
- try {
74
- compactConfig = await fse.readJSON(
75
- path.join(workspaceRoot, COMPACT_CONFIG_PATH),
71
+ const topology: unknown = await fse.readJSON(
72
+ path.join(workspaceRoot, TOPOLOGY_PATH),
73
+ );
74
+ if (
75
+ !isRecord(topology) ||
76
+ !isRecord(topology.shell) ||
77
+ !Array.isArray(topology.verticals) ||
78
+ (topology.shells !== undefined && !Array.isArray(topology.shells))
79
+ ) {
80
+ throw new Error(
81
+ '[cloudflare-delivery-unit] Invalid declared reference topology.',
76
82
  );
77
- } catch {
78
- return { workspaceRoot };
79
- }
80
-
81
- if (!isRecord(compactConfig)) {
82
- return { workspaceRoot };
83
- }
84
-
85
- const topology = isRecord(compactConfig.topology)
86
- ? compactConfig.topology
87
- : undefined;
88
- const apps = Array.isArray(topology?.apps) ? topology.apps : undefined;
89
- if (!apps) {
90
- return { app: compactConfig, workspaceRoot };
91
83
  }
84
+ const apps = [
85
+ topology.shell,
86
+ ...topology.verticals,
87
+ ...(Array.isArray(topology.shells) ? topology.shells : []),
88
+ ];
92
89
 
93
90
  const resolvedAppDirectory = path.resolve(appDirectory);
94
91
  const app = apps.find(candidate => {
@@ -102,8 +99,13 @@ const resolveCompactApp = async (
102
99
  resolvedAppDirectory
103
100
  );
104
101
  });
102
+ if (!isRecord(app)) {
103
+ throw new Error(
104
+ `[cloudflare-delivery-unit] ${appDirectory} is missing from the declared reference topology.`,
105
+ );
106
+ }
105
107
  return {
106
- ...(isRecord(app) ? { app } : {}),
108
+ app,
107
109
  workspaceRoot,
108
110
  };
109
111
  };
@@ -127,28 +129,31 @@ const createDeliveryUnitStamp = (
127
129
 
128
130
  /**
129
131
  * Resolve the delivery-unit record declared for this app by the workspace
130
- * compact config (`.modernjs/ultramodern.json`). This is the topology source
132
+ * reference topology. This is the topology source
131
133
  * of truth the Cloudflare worker snapshot is verified against.
132
134
  */
133
135
  export const resolveTopologyDeliveryUnit = async (
134
136
  appDirectory: string,
135
137
  ): Promise<DeliveryUnitStamp | undefined> => {
136
- const resolved = await resolveCompactApp(appDirectory);
138
+ const resolved = await resolveTopologyApp(appDirectory);
137
139
  if (!resolved?.app) {
138
140
  return undefined;
139
141
  }
140
142
  const identity = toDeliveryUnitIdentity(resolved.app.deliveryUnit);
141
- return identity
142
- ? createDeliveryUnitStamp(
143
- stampReleaseIdentity(identity, resolved.workspaceRoot),
144
- resolved.app,
145
- )
146
- : undefined;
143
+ if (!identity) {
144
+ throw new Error(
145
+ '[cloudflare-delivery-unit] Declared app is missing a valid delivery-unit identity.',
146
+ );
147
+ }
148
+ return createDeliveryUnitStamp(
149
+ stampReleaseIdentity(identity, resolved.workspaceRoot),
150
+ resolved.app,
151
+ );
147
152
  };
148
153
 
149
154
  /**
150
155
  * Resolve the delivery-unit identity actually bundled into the worker by
151
- * parsing the generated `shared/ultramodern-build.ts` module. This is the
156
+ * reading the generated `shared/ultramodern-build.json` artifact. This is the
152
157
  * worker snapshot / declared surface source that gets stamped into the manifest.
153
158
  */
154
159
  export const resolveWorkerDeliveryUnitStamp = async (
@@ -158,10 +163,6 @@ export const resolveWorkerDeliveryUnitStamp = async (
158
163
  appDirectory,
159
164
  ULTRAMODERN_BUILD_ARTIFACT_PATH,
160
165
  );
161
- const buildModulePath = path.join(
162
- appDirectory,
163
- ULTRAMODERN_BUILD_MODULE_PATH,
164
- );
165
166
  let identity: DeliveryUnitIdentity | undefined;
166
167
 
167
168
  if (await fse.pathExists(buildArtifactPath)) {
@@ -170,24 +171,12 @@ export const resolveWorkerDeliveryUnitStamp = async (
170
171
  return undefined;
171
172
  }
172
173
  identity = toDeliveryUnitIdentity(artifact.deliveryUnit);
173
- } else if (await fse.pathExists(buildModulePath)) {
174
- console.warn(
175
- `[cloudflare] ${buildArtifactPath} missing; falling back to legacy regex parsing of ${buildModulePath}. Regenerate the workspace to emit ultramodern-build.json.`,
176
- );
177
- const source = await fse.readFile(buildModulePath, 'utf8');
178
- identity = toDeliveryUnitIdentity({
179
- buildMarker: source.match(/\bbuild:\s*['"]([^'"]+)['"]/u)?.[1],
180
- unitId: source.match(/\bunitId:\s*['"]([^'"]+)['"]/u)?.[1],
181
- sourceRevision: source.match(
182
- /\bsourceRevision:\s*['"]([^'"]+)['"]/u,
183
- )?.[1],
184
- });
185
174
  }
186
175
 
187
176
  if (!identity) {
188
177
  return undefined;
189
178
  }
190
- const resolved = await resolveCompactApp(appDirectory);
179
+ const resolved = await resolveTopologyApp(appDirectory);
191
180
  if (resolved) {
192
181
  identity = stampReleaseIdentity(identity, resolved.workspaceRoot);
193
182
  }