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

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 (275) hide show
  1. package/README.md +23 -0
  2. package/dist/cjs/backend-federation-build/codegen.js +29 -18
  3. package/dist/cjs/backend-federation-build/config.js +84 -45
  4. package/dist/cjs/backend-federation-build/emit.js +63 -22
  5. package/dist/cjs/build-config/build-environment.js +25 -162
  6. package/dist/cjs/build-config/internal-effect-discovery.js +143 -0
  7. package/dist/cjs/build-config/public.js +2 -5
  8. package/dist/cjs/build-config/remote-address.js +58 -0
  9. package/dist/cjs/cloudflare/artifacts.js +8 -19
  10. package/dist/cjs/cloudflare/delivery-unit.js +125 -43
  11. package/dist/cjs/cloudflare/index.js +14 -4
  12. package/dist/cjs/cloudflare/native-renderer.js +100 -0
  13. package/dist/cjs/cloudflare/renderer-identity.js +106 -0
  14. package/dist/cjs/cloudflare/worker-manifest.js +54 -13
  15. package/dist/cjs/cloudflare/worker-options.js +48 -0
  16. package/dist/cjs/cloudflare/wrangler-config.js +210 -13
  17. package/dist/cjs/cloudflare-builder.js +307 -89
  18. package/dist/cjs/cloudflare-output-contract.js +36 -4
  19. package/dist/cjs/cloudflare-output-verifier/identity.js +112 -23
  20. package/dist/cjs/cloudflare-output-verifier/index.js +10 -0
  21. package/dist/cjs/cloudflare-output-verifier/manifest.js +46 -0
  22. package/dist/cjs/cloudflare-output-verifier/mutation-policy.js +7 -1
  23. package/dist/cjs/cloudflare-output-verifier/worker-bundles.js +10 -5
  24. package/dist/cjs/config.js +10 -5
  25. package/dist/cjs/deploy-output/npmAliases.js +92 -6
  26. package/dist/cjs/deploy-output/plugin.js +27 -6
  27. package/dist/cjs/deploy-output/public-assets.js +146 -0
  28. package/dist/cjs/deploy-output/target.js +57 -1
  29. package/dist/cjs/deploy-output/trace-files.js +99 -0
  30. package/dist/cjs/module-federation-config/exposes.js +70 -0
  31. package/dist/cjs/module-federation-config/index.js +73 -0
  32. package/dist/cjs/module-federation-config/inspect.js +103 -0
  33. package/dist/cjs/module-federation-config/object-literal.js +87 -0
  34. package/dist/cjs/module-federation-config/syntax.js +151 -0
  35. package/dist/cjs/module-federation-config/types.js +18 -0
  36. package/dist/cjs/native-type-checker.js +130 -13
  37. package/dist/cjs/policy-defaults.js +38 -29
  38. package/dist/cjs/release-envelope/canonical.js +2 -9
  39. package/dist/cjs/release-envelope/contract.js +68 -0
  40. package/dist/cjs/release-envelope/framework-output.js +296 -105
  41. package/dist/cjs/release-envelope/index.js +150 -36
  42. package/dist/cjs/release-envelope/plugin.js +24 -15
  43. package/dist/cjs/release-envelope/renderer-output-stamp.js +170 -0
  44. package/dist/cjs/release-envelope/types.js +10 -8
  45. package/dist/cjs/release-identity.js +8 -5
  46. package/dist/cjs/renderer-build-identity.js +134 -0
  47. package/dist/cjs/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
  48. package/dist/cjs/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
  49. package/dist/cjs/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
  50. package/dist/cjs/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
  51. package/dist/cjs/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
  52. package/dist/cjs/templates/cloudflare-worker-route-data.mjs +1069 -0
  53. package/dist/cjs/workspace-topology.js +84 -0
  54. package/dist/esm/backend-federation-build/codegen.mjs +29 -18
  55. package/dist/esm/backend-federation-build/config.mjs +74 -38
  56. package/dist/esm/backend-federation-build/emit.mjs +64 -23
  57. package/dist/esm/build-config/build-environment.mjs +26 -160
  58. package/dist/esm/build-config/internal-effect-discovery.mjs +102 -0
  59. package/dist/esm/build-config/public.mjs +1 -1
  60. package/dist/esm/build-config/remote-address.mjs +20 -0
  61. package/dist/esm/cloudflare/artifacts.mjs +8 -19
  62. package/dist/esm/cloudflare/delivery-unit.mjs +124 -45
  63. package/dist/esm/cloudflare/index.mjs +15 -5
  64. package/dist/esm/cloudflare/native-renderer.mjs +48 -0
  65. package/dist/esm/cloudflare/renderer-identity.mjs +57 -0
  66. package/dist/esm/cloudflare/worker-manifest.mjs +55 -14
  67. package/dist/esm/cloudflare/worker-options.mjs +10 -0
  68. package/dist/esm/cloudflare/wrangler-config.mjs +203 -12
  69. package/dist/esm/cloudflare-builder.mjs +301 -89
  70. package/dist/esm/cloudflare-output-contract.mjs +29 -3
  71. package/dist/esm/cloudflare-output-verifier/identity.mjs +113 -24
  72. package/dist/esm/cloudflare-output-verifier/index.mjs +10 -0
  73. package/dist/esm/cloudflare-output-verifier/manifest.mjs +46 -0
  74. package/dist/esm/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  75. package/dist/esm/cloudflare-output-verifier/worker-bundles.mjs +11 -6
  76. package/dist/esm/config.mjs +3 -1
  77. package/dist/esm/deploy-output/npmAliases.mjs +92 -6
  78. package/dist/esm/deploy-output/plugin.mjs +24 -6
  79. package/dist/esm/deploy-output/public-assets.mjs +82 -0
  80. package/dist/esm/deploy-output/target.mjs +50 -3
  81. package/dist/esm/deploy-output/trace-files.mjs +47 -0
  82. package/dist/esm/module-federation-config/exposes.mjs +18 -0
  83. package/dist/esm/module-federation-config/index.mjs +4 -0
  84. package/dist/esm/module-federation-config/inspect.mjs +65 -0
  85. package/dist/esm/module-federation-config/object-literal.mjs +43 -0
  86. package/dist/esm/module-federation-config/syntax.mjs +101 -0
  87. package/dist/esm/module-federation-config/types.mjs +0 -0
  88. package/dist/esm/native-type-checker.mjs +124 -13
  89. package/dist/esm/policy-defaults.mjs +36 -30
  90. package/dist/esm/release-envelope/canonical.mjs +2 -9
  91. package/dist/esm/release-envelope/contract.mjs +21 -0
  92. package/dist/esm/release-envelope/framework-output.mjs +297 -106
  93. package/dist/esm/release-envelope/index.mjs +149 -38
  94. package/dist/esm/release-envelope/plugin.mjs +24 -15
  95. package/dist/esm/release-envelope/renderer-output-stamp.mjs +112 -0
  96. package/dist/esm/release-envelope/types.mjs +2 -3
  97. package/dist/esm/release-identity.mjs +8 -5
  98. package/dist/esm/renderer-build-identity.mjs +82 -0
  99. package/dist/esm/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
  100. package/dist/esm/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
  101. package/dist/esm/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
  102. package/dist/esm/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
  103. package/dist/esm/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
  104. package/dist/esm/templates/cloudflare-worker-route-data.mjs +1069 -0
  105. package/dist/esm/workspace-topology.mjs +21 -0
  106. package/dist/esm-node/backend-federation-build/codegen.mjs +29 -18
  107. package/dist/esm-node/backend-federation-build/config.mjs +74 -38
  108. package/dist/esm-node/backend-federation-build/emit.mjs +64 -23
  109. package/dist/esm-node/build-config/build-environment.mjs +26 -160
  110. package/dist/esm-node/build-config/internal-effect-discovery.mjs +103 -0
  111. package/dist/esm-node/build-config/public.mjs +1 -1
  112. package/dist/esm-node/build-config/remote-address.mjs +21 -0
  113. package/dist/esm-node/cloudflare/artifacts.mjs +8 -19
  114. package/dist/esm-node/cloudflare/delivery-unit.mjs +124 -45
  115. package/dist/esm-node/cloudflare/index.mjs +15 -5
  116. package/dist/esm-node/cloudflare/native-renderer.mjs +49 -0
  117. package/dist/esm-node/cloudflare/renderer-identity.mjs +58 -0
  118. package/dist/esm-node/cloudflare/worker-manifest.mjs +55 -14
  119. package/dist/esm-node/cloudflare/worker-options.mjs +11 -0
  120. package/dist/esm-node/cloudflare/wrangler-config.mjs +203 -12
  121. package/dist/esm-node/cloudflare-builder.mjs +301 -89
  122. package/dist/esm-node/cloudflare-output-contract.mjs +29 -3
  123. package/dist/esm-node/cloudflare-output-verifier/identity.mjs +113 -24
  124. package/dist/esm-node/cloudflare-output-verifier/index.mjs +10 -0
  125. package/dist/esm-node/cloudflare-output-verifier/manifest.mjs +46 -0
  126. package/dist/esm-node/cloudflare-output-verifier/mutation-policy.mjs +7 -1
  127. package/dist/esm-node/cloudflare-output-verifier/worker-bundles.mjs +11 -6
  128. package/dist/esm-node/config.mjs +3 -1
  129. package/dist/esm-node/deploy-output/npmAliases.mjs +92 -6
  130. package/dist/esm-node/deploy-output/plugin.mjs +24 -6
  131. package/dist/esm-node/deploy-output/public-assets.mjs +83 -0
  132. package/dist/esm-node/deploy-output/target.mjs +50 -3
  133. package/dist/esm-node/deploy-output/trace-files.mjs +48 -0
  134. package/dist/esm-node/module-federation-config/exposes.mjs +19 -0
  135. package/dist/esm-node/module-federation-config/index.mjs +5 -0
  136. package/dist/esm-node/module-federation-config/inspect.mjs +66 -0
  137. package/dist/esm-node/module-federation-config/object-literal.mjs +44 -0
  138. package/dist/esm-node/module-federation-config/syntax.mjs +102 -0
  139. package/dist/esm-node/module-federation-config/types.mjs +1 -0
  140. package/dist/esm-node/native-type-checker.mjs +124 -13
  141. package/dist/esm-node/policy-defaults.mjs +36 -30
  142. package/dist/esm-node/release-envelope/canonical.mjs +2 -9
  143. package/dist/esm-node/release-envelope/contract.mjs +22 -0
  144. package/dist/esm-node/release-envelope/framework-output.mjs +297 -106
  145. package/dist/esm-node/release-envelope/index.mjs +149 -38
  146. package/dist/esm-node/release-envelope/plugin.mjs +24 -15
  147. package/dist/esm-node/release-envelope/renderer-output-stamp.mjs +113 -0
  148. package/dist/esm-node/release-envelope/types.mjs +2 -3
  149. package/dist/esm-node/release-identity.mjs +8 -5
  150. package/dist/esm-node/renderer-build-identity.mjs +83 -0
  151. package/dist/esm-node/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
  152. package/dist/esm-node/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
  153. package/dist/esm-node/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
  154. package/dist/esm-node/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
  155. package/dist/esm-node/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
  156. package/dist/esm-node/templates/cloudflare-worker-route-data.mjs +1069 -0
  157. package/dist/esm-node/workspace-topology.mjs +22 -0
  158. package/dist/types/backend-federation-build/codegen.d.ts +30 -0
  159. package/dist/types/backend-federation-build/config.d.ts +10 -57
  160. package/dist/types/backend-federation-build/emit.d.ts +12 -2
  161. package/dist/types/backend-federation-build/index.d.ts +1 -1
  162. package/dist/types/build-config/build-environment.d.ts +1 -9
  163. package/dist/types/build-config/internal-effect-discovery.d.ts +4 -0
  164. package/dist/types/build-config/public.d.ts +1 -1
  165. package/dist/types/build-config/remote-address.d.ts +3 -0
  166. package/dist/types/cloudflare/artifacts.d.ts +7 -6
  167. package/dist/types/cloudflare/constants.d.ts +1 -1
  168. package/dist/types/cloudflare/delivery-unit.d.ts +38 -7
  169. package/dist/types/cloudflare/native-renderer.d.ts +30 -0
  170. package/dist/types/cloudflare/renderer-identity.d.ts +25 -0
  171. package/dist/types/cloudflare/worker-manifest.d.ts +17 -2
  172. package/dist/types/cloudflare/worker-options.d.ts +20 -0
  173. package/dist/types/cloudflare/wrangler-config.d.ts +55 -2
  174. package/dist/types/cloudflare-builder.d.ts +51 -8
  175. package/dist/types/cloudflare-output-contract.d.ts +5 -3
  176. package/dist/types/cloudflare-output-verifier/identity.d.ts +7 -3
  177. package/dist/types/cloudflare-output-verifier/worker-bundles.d.ts +2 -2
  178. package/dist/types/config.d.ts +98 -13
  179. package/dist/types/deploy-output/plugin.d.ts +29 -9
  180. package/dist/types/deploy-output/public-assets.d.ts +51 -0
  181. package/dist/types/deploy-output/target.d.ts +28 -5
  182. package/dist/types/deploy-output/trace-files.d.ts +17 -0
  183. package/dist/types/module-federation-config/exposes.d.ts +11 -0
  184. package/dist/types/module-federation-config/index.d.ts +5 -0
  185. package/dist/types/module-federation-config/inspect.d.ts +2 -0
  186. package/dist/types/module-federation-config/object-literal.d.ts +4 -0
  187. package/dist/types/module-federation-config/syntax.d.ts +7 -0
  188. package/dist/types/module-federation-config/types.d.ts +20 -0
  189. package/dist/types/native-type-checker.d.ts +26 -3
  190. package/dist/types/policy-defaults.d.ts +12 -2
  191. package/dist/types/release-envelope/canonical.d.ts +5 -5
  192. package/dist/types/release-envelope/contract.d.mts +8 -0
  193. package/dist/types/release-envelope/framework-output.d.ts +23 -13
  194. package/dist/types/release-envelope/index.d.ts +17 -5
  195. package/dist/types/release-envelope/plugin.d.ts +10 -6
  196. package/dist/types/release-envelope/renderer-output-stamp.d.ts +34 -0
  197. package/dist/types/release-envelope/types.d.ts +42 -4
  198. package/dist/types/release-identity.d.ts +3 -2
  199. package/dist/types/renderer-build-identity.d.ts +30 -0
  200. package/dist/types/templates/cloudflare-worker-route-data.d.mts +14 -0
  201. package/dist/types/workspace-topology.d.ts +91 -0
  202. package/package.json +87 -27
  203. package/src/backend-federation-build/codegen.ts +28 -19
  204. package/src/backend-federation-build/config.ts +189 -123
  205. package/src/backend-federation-build/emit.ts +119 -38
  206. package/src/backend-federation-build/index.ts +4 -1
  207. package/src/build-config/build-environment.ts +59 -285
  208. package/src/build-config/internal-effect-discovery.ts +239 -0
  209. package/src/build-config/public.ts +0 -1
  210. package/src/build-config/remote-address.ts +33 -0
  211. package/src/cloudflare/artifacts.ts +22 -43
  212. package/src/cloudflare/delivery-unit.ts +283 -60
  213. package/src/cloudflare/index.ts +35 -19
  214. package/src/cloudflare/native-renderer.ts +117 -0
  215. package/src/cloudflare/renderer-identity.ts +171 -0
  216. package/src/cloudflare/worker-manifest.ts +108 -10
  217. package/src/cloudflare/worker-options.ts +60 -0
  218. package/src/cloudflare/wrangler-config.ts +390 -14
  219. package/src/cloudflare-builder.ts +543 -170
  220. package/src/cloudflare-output-contract.ts +45 -2
  221. package/src/cloudflare-output-verifier/identity.ts +138 -7
  222. package/src/cloudflare-output-verifier/index.ts +20 -0
  223. package/src/cloudflare-output-verifier/manifest.ts +77 -0
  224. package/src/cloudflare-output-verifier/mutation-policy.ts +11 -1
  225. package/src/cloudflare-output-verifier/worker-bundles.ts +27 -11
  226. package/src/config.ts +101 -19
  227. package/src/deploy-output/npmAliases.ts +141 -4
  228. package/src/deploy-output/plugin.ts +55 -18
  229. package/src/deploy-output/public-assets.ts +224 -0
  230. package/src/deploy-output/target.ts +97 -14
  231. package/src/deploy-output/trace-files.ts +80 -0
  232. package/src/module-federation-config/exposes.ts +46 -0
  233. package/src/module-federation-config/index.ts +22 -0
  234. package/src/module-federation-config/inspect.ts +157 -0
  235. package/src/module-federation-config/object-literal.ts +76 -0
  236. package/src/module-federation-config/syntax.ts +212 -0
  237. package/src/module-federation-config/types.ts +22 -0
  238. package/src/native-type-checker.ts +233 -20
  239. package/src/policy-defaults.ts +47 -17
  240. package/src/release-envelope/canonical.ts +6 -18
  241. package/src/release-envelope/contract.mjs +28 -0
  242. package/src/release-envelope/framework-output.ts +681 -156
  243. package/src/release-envelope/index.ts +315 -60
  244. package/src/release-envelope/plugin.ts +54 -38
  245. package/src/release-envelope/renderer-output-stamp.ts +210 -0
  246. package/src/release-envelope/types.ts +75 -6
  247. package/src/release-identity.ts +19 -2
  248. package/src/renderer-build-identity.ts +168 -0
  249. package/src/templates/cloudflare-entry.001-bootstrap-security.mjs +14 -6
  250. package/src/templates/cloudflare-entry.002-assets-routes.mjs +10 -2
  251. package/src/templates/cloudflare-entry.004-rendering-css.mjs +403 -96
  252. package/src/templates/cloudflare-entry.005-worker-dispatch.mjs +530 -103
  253. package/src/templates/cloudflare-entry.006-fetch-handler.mjs +26 -7
  254. package/src/templates/cloudflare-worker-route-data.mjs +1069 -0
  255. package/src/workspace-topology.ts +125 -0
  256. package/dist/cjs/templates/cloudflare-worker-fs-promises.mjs +0 -11
  257. package/dist/cjs/templates/cloudflare-worker-loadable-server.mjs +0 -281
  258. package/dist/cjs/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  259. package/dist/cjs/templates/cloudflare-worker-path.mjs +0 -98
  260. package/dist/esm/templates/cloudflare-worker-fs-promises.mjs +0 -11
  261. package/dist/esm/templates/cloudflare-worker-loadable-server.mjs +0 -281
  262. package/dist/esm/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  263. package/dist/esm/templates/cloudflare-worker-path.mjs +0 -98
  264. package/dist/esm-node/templates/cloudflare-worker-fs-promises.mjs +0 -11
  265. package/dist/esm-node/templates/cloudflare-worker-loadable-server.mjs +0 -281
  266. package/dist/esm-node/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  267. package/dist/esm-node/templates/cloudflare-worker-path.mjs +0 -98
  268. package/dist/types/templates/cloudflare-worker-fs-promises.d.mts +0 -5
  269. package/dist/types/templates/cloudflare-worker-loadable-server.d.mts +0 -48
  270. package/dist/types/templates/cloudflare-worker-mf-ssr-runtime-plugin.d.mts +0 -13
  271. package/dist/types/templates/cloudflare-worker-path.d.mts +0 -21
  272. package/src/templates/cloudflare-worker-fs-promises.mjs +0 -11
  273. package/src/templates/cloudflare-worker-loadable-server.mjs +0 -281
  274. package/src/templates/cloudflare-worker-mf-ssr-runtime-plugin.mjs +0 -14
  275. package/src/templates/cloudflare-worker-path.mjs +0 -98
@@ -1,13 +1,69 @@
1
1
  import { execFile } from 'node:child_process';
2
- import { existsSync, realpathSync } from 'node:fs';
2
+ import { randomUUID } from 'node:crypto';
3
+ import {
4
+ existsSync,
5
+ readFileSync,
6
+ realpathSync,
7
+ statSync,
8
+ unlinkSync,
9
+ writeFileSync,
10
+ } from 'node:fs';
3
11
  import path from 'node:path';
4
12
  import { promisify } from 'node:util';
5
13
  import { refreshTsgoCheckerConfig } from '@modern-js/builder';
6
14
  import type { Rspack, RspackChain } from '@rsbuild/core';
15
+ import { type ParseError, parse, printParseErrorCode } from 'jsonc-parser';
7
16
 
8
17
  const execute = promisify(execFile);
9
18
  const name = 'UltramodernNativeTypeChecker';
10
19
 
20
+ export interface NativeTypeCheckerCommand {
21
+ executable: string;
22
+ args: readonly string[];
23
+ }
24
+
25
+ /** Launch the selected stable package through its declared public compiler bin. */
26
+ export function resolveNativeTypeCheckerCommand(
27
+ packageJsonPath: string,
28
+ ): NativeTypeCheckerCommand {
29
+ const manifestFile = realpathSync(packageJsonPath);
30
+ const directory = path.dirname(manifestFile);
31
+ const manifest = JSON.parse(readFileSync(manifestFile, 'utf8')) as {
32
+ name?: unknown;
33
+ version?: unknown;
34
+ bin?: { tsc?: unknown };
35
+ };
36
+ if (manifest.name !== 'typescript' || manifest.version !== '7.0.2') {
37
+ throw new Error(
38
+ `${name} requires typescript@7.0.2; found ${String(manifest.name)}@${String(manifest.version)} at ${manifestFile}.`,
39
+ );
40
+ }
41
+ const bin = manifest.bin?.tsc;
42
+ if (typeof bin !== 'string' || !bin || path.isAbsolute(bin)) {
43
+ throw new Error(`${name} requires the selected package's public tsc bin.`);
44
+ }
45
+ const launcher = realpathSync(path.resolve(directory, bin));
46
+ const relative = path.relative(directory, launcher);
47
+ if (
48
+ !relative ||
49
+ path.isAbsolute(relative) ||
50
+ relative === '..' ||
51
+ relative.startsWith(`..${path.sep}`) ||
52
+ !statSync(launcher).isFile()
53
+ ) {
54
+ throw new Error(
55
+ `${name} public tsc bin must belong to its selected package.`,
56
+ );
57
+ }
58
+ return { executable: process.execPath, args: [launcher] };
59
+ }
60
+
61
+ interface TypeCheckerConfig {
62
+ compilerOptions?: Record<string, unknown>;
63
+ references?: Array<{ path: string }>;
64
+ [key: string]: unknown;
65
+ }
66
+
11
67
  // Windows file events expand 8.3 aliases; register the same native path spelling.
12
68
  // A path that does not exist yet (a project tsconfig mid-edit) cannot be
13
69
  // realpathed; it is registered as spelled so its return still triggers a build.
@@ -20,17 +76,151 @@ const watchDependencyPath = (file: string): string => {
20
76
  }
21
77
  };
22
78
 
79
+ /**
80
+ * TS2875 means JSX compiles against a jsxImportSource whose runtime is not
81
+ * installed: usually components still authored for a previous renderer.
82
+ */
83
+ export function missingJsxRuntimeHint(diagnostics: string): string {
84
+ const source =
85
+ /error TS2875: This JSX tag requires the module path '(.+?)\/jsx-(?:dev-)?runtime'/u.exec(
86
+ diagnostics,
87
+ )?.[1];
88
+ if (!source) return '';
89
+ return `\nHint: JSX compiles against jsxImportSource '${source}', the selected renderer's runtime, but '${source}/jsx-runtime' cannot be resolved from this app. If you changed \`renderer\` in modern.config, install that renderer's packages and port components authored for the previous renderer, or switch \`renderer\` back.\n`;
90
+ }
91
+
23
92
  export class UltramodernNativeTypeChecker {
24
93
  constructor(
25
94
  private readonly options: {
26
- compiler: () => string;
95
+ compiler: () => string | NativeTypeCheckerCommand;
27
96
  configFile: string;
28
97
  build: boolean;
98
+ configOverwrite?: TypeCheckerConfig;
29
99
  },
30
100
  ) {}
31
101
 
32
102
  async check(): Promise<void> {
33
- const { configFile, build } = this.options;
103
+ const configFile = await this.projectConfigFile();
104
+ try {
105
+ await this.checkProject(configFile);
106
+ } finally {
107
+ this.removeProjection(configFile);
108
+ }
109
+ }
110
+
111
+ private async projectConfigFile(): Promise<string> {
112
+ const { configFile, configOverwrite } = this.options;
113
+ if (!configOverwrite) return configFile;
114
+ // Merge before native parsing: an overwrite may supply the inputs that
115
+ // make an otherwise empty project valid. A same-directory projection
116
+ // preserves the original extends, relative paths and project references.
117
+ const errors: ParseError[] = [];
118
+ const source = readFileSync(configFile, 'utf8');
119
+ const project: TypeCheckerConfig = parse(
120
+ source.charCodeAt(0) === 0xfeff ? source.slice(1) : source,
121
+ errors,
122
+ { allowTrailingComma: true },
123
+ );
124
+ if (errors.length) {
125
+ throw new Error(
126
+ `${name} requires valid JSONC in ${configFile}: ${errors
127
+ .map(
128
+ error => `${printParseErrorCode(error.error)} at ${error.offset}`,
129
+ )
130
+ .join(', ')}`,
131
+ );
132
+ }
133
+ if (!project || typeof project !== 'object' || Array.isArray(project)) {
134
+ throw new Error(`${name} requires a JSONC object in ${configFile}.`);
135
+ }
136
+ const projectedConfig: TypeCheckerConfig = {
137
+ ...project,
138
+ ...configOverwrite,
139
+ compilerOptions: {
140
+ ...project.compilerOptions,
141
+ ...configOverwrite.compilerOptions,
142
+ },
143
+ };
144
+ const projected = path.join(
145
+ path.dirname(configFile),
146
+ `.ultramodern-native-checker.${randomUUID()}.json`,
147
+ );
148
+ writeFileSync(projected, `${JSON.stringify(projectedConfig, null, 2)}\n`, {
149
+ flag: 'wx',
150
+ });
151
+ try {
152
+ const resolved: TypeCheckerConfig = JSON.parse(
153
+ await this.run(['--showConfig', '--project', projected]),
154
+ );
155
+ const options = resolved.compilerOptions ?? {};
156
+ if (
157
+ (this.options.build ||
158
+ options.incremental === true ||
159
+ options.composite === true) &&
160
+ !options.tsBuildInfoFile
161
+ ) {
162
+ // Native TypeScript derives the default from the config filename.
163
+ // Retain that original identity while this invocation-private config
164
+ // is alive; referenced projects still use their own configurations.
165
+ const original = configFile.slice(
166
+ 0,
167
+ configFile.length - path.extname(configFile).length,
168
+ );
169
+ let buildInfo = original;
170
+ if (typeof options.outDir === 'string') {
171
+ const outDir = path.resolve(path.dirname(configFile), options.outDir);
172
+ buildInfo =
173
+ typeof options.rootDir === 'string'
174
+ ? path.resolve(
175
+ outDir,
176
+ path.relative(
177
+ path.resolve(path.dirname(configFile), options.rootDir),
178
+ original,
179
+ ),
180
+ )
181
+ : path.join(outDir, path.basename(original));
182
+ }
183
+ projectedConfig.compilerOptions = {
184
+ ...projectedConfig.compilerOptions,
185
+ tsBuildInfoFile: `${buildInfo}.tsbuildinfo`,
186
+ };
187
+ writeFileSync(
188
+ projected,
189
+ `${JSON.stringify(projectedConfig, null, 2)}\n`,
190
+ );
191
+ }
192
+ return projected;
193
+ } catch (error) {
194
+ unlinkSync(projected);
195
+ throw error;
196
+ }
197
+ }
198
+
199
+ private removeProjection(configFile: string): void {
200
+ if (configFile !== this.options.configFile) unlinkSync(configFile);
201
+ }
202
+
203
+ private async checkProject(configFile: string): Promise<void> {
204
+ const { build } = this.options;
205
+ if (!build) {
206
+ const config = JSON.parse(
207
+ await this.run(['--showConfig', '--project', configFile]),
208
+ ) as { references?: { path: string }[] };
209
+ // Project mode consumes referenced declarations but never builds them.
210
+ // Prepare only the references using their own emit contracts, then keep
211
+ // the app itself in no-emit mode. This also refreshes stale declarations.
212
+ if (config.references?.length) {
213
+ await this.run([
214
+ '--build',
215
+ ...config.references.map(reference =>
216
+ path.resolve(path.dirname(configFile), reference.path),
217
+ ),
218
+ '--stopBuildOnErrors',
219
+ '--pretty',
220
+ 'false',
221
+ ]);
222
+ }
223
+ }
34
224
  const args = build
35
225
  ? ['--build', configFile, '--stopBuildOnErrors']
36
226
  : ['--project', configFile, '--noEmit'];
@@ -39,28 +229,37 @@ export class UltramodernNativeTypeChecker {
39
229
 
40
230
  private async run(args: string[]): Promise<string> {
41
231
  try {
42
- const result = await execute(this.options.compiler(), args, {
43
- cwd: path.dirname(this.options.configFile),
44
- maxBuffer: 16 * 1024 * 1024,
45
- });
232
+ const selected = this.options.compiler();
233
+ const command =
234
+ typeof selected === 'string'
235
+ ? { executable: selected, args: [] }
236
+ : selected;
237
+ const result = await execute(
238
+ command.executable,
239
+ [...command.args, ...args],
240
+ {
241
+ cwd: path.dirname(this.options.configFile),
242
+ maxBuffer: 16 * 1024 * 1024,
243
+ },
244
+ );
46
245
  return result.stdout;
47
246
  } catch (cause) {
48
247
  const output = cause as { stdout?: string; stderr?: string };
49
248
  const diagnostics = `${output.stdout ?? ''}${output.stderr ?? ''}`;
50
249
  throw new Error(
51
- `${name} failed:\n${diagnostics || (cause instanceof Error ? cause.message : String(cause))}`,
250
+ `${name} failed:\n${diagnostics || (cause instanceof Error ? cause.message : String(cause))}${missingJsxRuntimeHint(diagnostics)}`,
52
251
  { cause },
53
252
  );
54
253
  }
55
254
  }
56
255
 
57
- private async watchInputs(): Promise<{
256
+ private async watchInputs(configFile: string): Promise<{
58
257
  inputs: Set<string>;
59
258
  missing: Set<string>;
60
259
  }> {
61
260
  const inputs = new Set<string>();
62
261
  const missing = new Set<string>();
63
- const projects = [this.options.configFile];
262
+ const projects = [configFile];
64
263
  const visited = new Set<string>();
65
264
  for (const configFile of projects) {
66
265
  if (visited.has(configFile)) continue;
@@ -68,7 +267,8 @@ export class UltramodernNativeTypeChecker {
68
267
  // Registered before it is parsed: a referenced config that is absent or
69
268
  // unparsable right now must still be watched, or creating or repairing
70
269
  // it never re-triggers the compilation. `check()` reports the error.
71
- inputs.add(configFile);
270
+ if (configFile === this.options.configFile || configFile !== projects[0])
271
+ inputs.add(configFile);
72
272
  if (!existsSync(configFile)) {
73
273
  missing.add(configFile);
74
274
  continue;
@@ -120,12 +320,17 @@ export class UltramodernNativeTypeChecker {
120
320
  compilation.missingDependencies.add(watched);
121
321
  }
122
322
  }
123
- const { inputs, missing } = await this.watchInputs();
124
- for (const file of inputs)
125
- compilation.fileDependencies.add(watchDependencyPath(file));
126
- for (const file of missing)
127
- compilation.missingDependencies.add(watchDependencyPath(file));
128
- await this.check();
323
+ const configFile = await this.projectConfigFile();
324
+ try {
325
+ const { inputs, missing } = await this.watchInputs(configFile);
326
+ for (const file of inputs)
327
+ compilation.fileDependencies.add(watchDependencyPath(file));
328
+ for (const file of missing)
329
+ compilation.missingDependencies.add(watchDependencyPath(file));
330
+ await this.checkProject(configFile);
331
+ } finally {
332
+ this.removeProjection(configFile);
333
+ }
129
334
  } catch (cause) {
130
335
  compilation.errors.push(
131
336
  new Error(cause instanceof Error ? cause.message : String(cause), {
@@ -138,15 +343,22 @@ export class UltramodernNativeTypeChecker {
138
343
  }
139
344
  }
140
345
 
141
- /** Preserve project-reference emit contracts in the native Effect compiler. */
346
+ /** Preserve project-reference emit contracts in the selected native compiler. */
142
347
  export function configureUltramodernTypeChecker(
143
348
  chain: RspackChain,
144
349
  pluginId: string,
145
- resolveCompiler: (configFile: string) => string,
350
+ resolveCompiler: (configFile: string) => string | NativeTypeCheckerCommand,
146
351
  ): void {
147
352
  if (!chain.plugins.has(pluginId)) return;
148
353
  const options = chain.plugin(pluginId).get('args')?.[0] as
149
- | { typescript?: { configFile?: string; build?: boolean; tsgo?: boolean } }
354
+ | {
355
+ typescript?: {
356
+ configFile?: string;
357
+ build?: boolean;
358
+ tsgo?: boolean;
359
+ configOverwrite?: TypeCheckerConfig;
360
+ };
361
+ }
150
362
  | undefined;
151
363
  const typescript = options?.typescript;
152
364
  if (typescript?.tsgo === false) return;
@@ -159,6 +371,7 @@ export function configureUltramodernTypeChecker(
159
371
  build: typescript.build === true,
160
372
  compiler: () => resolveCompiler(configFile),
161
373
  configFile,
374
+ configOverwrite: typescript.configOverwrite,
162
375
  },
163
376
  ]);
164
377
  }
@@ -22,6 +22,9 @@ export const RENDERER_EXTENSIONS_PLUGIN_NAME = 'rendererHead';
22
22
  export const SERVER_EXTENSIONS_PLUGIN_NAME =
23
23
  '@modern-js/app-tools/server-plugin';
24
24
 
25
+ export const ULTRAMODERN_SERVER_EXTENSIONS_PLUGIN_NAME =
26
+ '@modern-js/ultramodern-app-tools/server-plugin';
27
+
25
28
  export interface PolicyDefaultsOptions {
26
29
  /** Default `true`. Set to `false` to drop the fork's renderer policy. */
27
30
  rendererExtensions?: boolean;
@@ -29,6 +32,16 @@ export interface PolicyDefaultsOptions {
29
32
  serverExtensions?: boolean;
30
33
  }
31
34
 
35
+ /** The native package that explicitly composes the policy. */
36
+ export interface PolicyDefaultsComposition {
37
+ pluginName?: string;
38
+ serverPluginName?: string;
39
+ /** Additional runtime packages that share the resolution fallback. */
40
+ runtimePackages?: readonly string[];
41
+ /** Resolve runtime packages from the composing package. */
42
+ registrarUrl?: string;
43
+ }
44
+
32
45
  type RuntimePluginDescriptor = {
33
46
  name?: string;
34
47
  path: string;
@@ -62,6 +75,7 @@ export const POLICY_DEFAULTS_PLUGIN_NAME =
62
75
  export const applyPolicyDefaults = (
63
76
  api: PolicyDefaultsPluginApi,
64
77
  options: PolicyDefaultsOptions = {},
78
+ composition: PolicyDefaultsComposition = {},
65
79
  ): void => {
66
80
  if (options.rendererExtensions !== false) {
67
81
  api._internalRuntimePlugins(
@@ -80,28 +94,43 @@ export const applyPolicyDefaults = (
80
94
  return { entrypoint, plugins };
81
95
  },
82
96
  );
97
+ }
83
98
 
84
- const moduleDirectories = collectRuntimePackageModuleDirectories(
85
- [RENDERER_EXTENSIONS_PACKAGE],
86
- import.meta.url,
87
- );
88
- if (moduleDirectories.length > 0) {
89
- api.modifyResolvedConfig(config => ({
90
- ...config,
91
- builderPlugins: [
92
- ...(config.builderPlugins ?? []),
93
- createRuntimePackageResolutionPlugin(moduleDirectories),
94
- ],
95
- }));
96
- }
99
+ const runtimePackages = [
100
+ ...(options.rendererExtensions !== false
101
+ ? [RENDERER_EXTENSIONS_PACKAGE]
102
+ : []),
103
+ ...(composition.runtimePackages ?? []).filter(
104
+ packageName => packageName !== RENDERER_EXTENSIONS_PACKAGE,
105
+ ),
106
+ ];
107
+ const moduleDirectories = collectRuntimePackageModuleDirectories(
108
+ runtimePackages,
109
+ composition.registrarUrl ?? import.meta.url,
110
+ );
111
+ if (moduleDirectories.length > 0) {
112
+ api.modifyResolvedConfig(config => ({
113
+ ...config,
114
+ builderPlugins: [
115
+ ...(config.builderPlugins ?? []),
116
+ createRuntimePackageResolutionPlugin(moduleDirectories),
117
+ ],
118
+ }));
97
119
  }
98
120
 
99
121
  if (options.serverExtensions !== false) {
122
+ const serverPluginName =
123
+ composition.serverPluginName ?? SERVER_EXTENSIONS_PLUGIN_NAME;
100
124
  api._internalServerPlugins(({ plugins }: ServerPluginsInput) => {
101
125
  if (
102
- !plugins.some(plugin => plugin.name === SERVER_EXTENSIONS_PLUGIN_NAME)
126
+ !plugins.some(
127
+ plugin =>
128
+ plugin.name === serverPluginName ||
129
+ plugin.name === SERVER_EXTENSIONS_PLUGIN_NAME ||
130
+ plugin.name === ULTRAMODERN_SERVER_EXTENSIONS_PLUGIN_NAME,
131
+ )
103
132
  ) {
104
- plugins.push({ name: SERVER_EXTENSIONS_PLUGIN_NAME });
133
+ plugins.push({ name: serverPluginName });
105
134
  }
106
135
  return { plugins };
107
136
  });
@@ -119,9 +148,10 @@ export const applyPolicyDefaults = (
119
148
  */
120
149
  export const createPolicyDefaultsPlugin = (
121
150
  options: PolicyDefaultsOptions = {},
151
+ composition: PolicyDefaultsComposition = {},
122
152
  ) => ({
123
- name: POLICY_DEFAULTS_PLUGIN_NAME,
153
+ name: composition.pluginName ?? POLICY_DEFAULTS_PLUGIN_NAME,
124
154
  setup(api: PolicyDefaultsPluginApi) {
125
- applyPolicyDefaults(api, options);
155
+ applyPolicyDefaults(api, options, composition);
126
156
  },
127
157
  });
@@ -1,8 +1,7 @@
1
1
  import { createHash } from 'node:crypto';
2
- import type {
3
- MicroVerticalReleaseEnvelope,
4
- MicroVerticalReleaseEnvelopePayload,
5
- } from './types';
2
+ import type { ReleaseEnvelope, ReleaseEnvelopePayload } from './types';
3
+
4
+ export { releaseEnvelopePayload } from './contract.mjs';
6
5
 
7
6
  type CanonicalValue =
8
7
  | null
@@ -31,27 +30,16 @@ const serializeCanonicalValue = (value: CanonicalValue): string => {
31
30
  .join(',')}}`;
32
31
  };
33
32
 
34
- export const releaseEnvelopePayload = (
35
- envelope: MicroVerticalReleaseEnvelope,
36
- ): MicroVerticalReleaseEnvelopePayload => ({
37
- schemaVersion: envelope.schemaVersion,
38
- kind: envelope.kind,
39
- target: envelope.target,
40
- identity: envelope.identity,
41
- artifacts: envelope.artifacts,
42
- surfaces: envelope.surfaces,
43
- });
44
-
45
33
  export const canonicalSerializeMicroVerticalReleaseEnvelopePayload = (
46
- payload: MicroVerticalReleaseEnvelopePayload,
34
+ payload: ReleaseEnvelopePayload,
47
35
  ) => serializeCanonicalValue(payload as unknown as CanonicalValue);
48
36
 
49
37
  export const canonicalSerializeMicroVerticalReleaseEnvelope = (
50
- envelope: MicroVerticalReleaseEnvelope,
38
+ envelope: ReleaseEnvelope,
51
39
  ) => serializeCanonicalValue(envelope as unknown as CanonicalValue);
52
40
 
53
41
  export const digestMicroVerticalReleaseEnvelopePayload = (
54
- payload: MicroVerticalReleaseEnvelopePayload,
42
+ payload: ReleaseEnvelopePayload,
55
43
  ) =>
56
44
  createHash('sha256')
57
45
  .update(canonicalSerializeMicroVerticalReleaseEnvelopePayload(payload))
@@ -0,0 +1,28 @@
1
+ export const MICROVERTICAL_RELEASE_ENVELOPE_SCHEMA_VERSION =
2
+ /** @type {const} */ (5);
3
+
4
+ export const MICROVERTICAL_RELEASE_ENVELOPE_KIND = /** @type {const} */ (
5
+ 'ultramodern-target-microvertical-release-envelope'
6
+ );
7
+
8
+ export const SHELL_RELEASE_ENVELOPE_KIND = /** @type {const} */ (
9
+ 'ultramodern-target-shell-release-envelope'
10
+ );
11
+
12
+ /**
13
+ * @param {import('./types.js').ReleaseEnvelope} envelope
14
+ * @returns {import('./types.js').ReleaseEnvelopePayload}
15
+ */
16
+ export const releaseEnvelopePayload = envelope => {
17
+ const payload = {
18
+ schemaVersion: envelope.schemaVersion,
19
+ target: envelope.target,
20
+ identity: envelope.identity,
21
+ ...(envelope.ui ? { ui: envelope.ui } : {}),
22
+ artifacts: envelope.artifacts,
23
+ };
24
+ if (envelope.kind === SHELL_RELEASE_ENVELOPE_KIND) {
25
+ return { ...payload, kind: envelope.kind, surfaces: envelope.surfaces };
26
+ }
27
+ return { ...payload, kind: envelope.kind, surfaces: envelope.surfaces };
28
+ };