@bleedingdev/modern-js-ultramodern-create 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 (442) hide show
  1. package/README.md +43 -74
  2. package/dist/cjs/cli/package-source.cjs +2 -2
  3. package/dist/cjs/cli/project-setup.cjs +2 -22
  4. package/dist/cjs/index.cjs +9 -1
  5. package/dist/cjs/locale/en.cjs +2 -1
  6. package/dist/cjs/locale/zh.cjs +2 -1
  7. package/dist/cjs/ultramodern-package-source.cjs +13 -9
  8. package/dist/cjs/ultramodern-release-cohort.cjs +6 -21
  9. package/dist/cjs/ultramodern-tooling/commands/cloudflare-output-verify.cjs +49 -56
  10. package/dist/cjs/ultramodern-tooling/commands/context.cjs +11 -29
  11. package/dist/cjs/ultramodern-tooling/commands/routes-generate-app.cjs +67 -0
  12. package/dist/cjs/ultramodern-tooling/commands/routes-generate.cjs +24 -53
  13. package/dist/cjs/ultramodern-tooling/commands/validate.cjs +5 -11
  14. package/dist/cjs/ultramodern-tooling/commands.cjs +15 -8
  15. package/dist/cjs/ultramodern-tooling/config/index.cjs +10 -24
  16. package/dist/cjs/ultramodern-tooling/config/load.cjs +12 -10
  17. package/dist/cjs/ultramodern-tooling/config/metadata.cjs +34 -32
  18. package/dist/cjs/ultramodern-tooling/config/normalize.cjs +165 -164
  19. package/dist/cjs/ultramodern-workspace/add-shell.cjs +118 -118
  20. package/dist/cjs/ultramodern-workspace/add-vertical/execute.cjs +121 -25
  21. package/dist/cjs/ultramodern-workspace/add-vertical/plan.cjs +14 -160
  22. package/dist/cjs/ultramodern-workspace/add-vertical/preflight.cjs +16 -48
  23. package/dist/cjs/ultramodern-workspace/add-vertical/preview.cjs +78 -0
  24. package/dist/cjs/ultramodern-workspace/add-vertical/shell-files.cjs +87 -24
  25. package/dist/cjs/ultramodern-workspace/add-vertical/topology.cjs +4 -1
  26. package/dist/cjs/ultramodern-workspace/add-vertical/transaction.cjs +378 -45
  27. package/dist/cjs/ultramodern-workspace/add-vertical/workspace-state.cjs +21 -44
  28. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +0 -9
  29. package/dist/cjs/ultramodern-workspace/api/client.cjs +5 -5
  30. package/dist/cjs/ultramodern-workspace/api/contracts.cjs +2 -2
  31. package/dist/cjs/ultramodern-workspace/api/rpc.cjs +20 -18
  32. package/dist/cjs/ultramodern-workspace/api/service.cjs +49 -24
  33. package/dist/cjs/ultramodern-workspace/api/shared.cjs +28 -18
  34. package/dist/cjs/ultramodern-workspace/app-files.cjs +3 -23
  35. package/dist/cjs/ultramodern-workspace/backend-federation.cjs +27 -27
  36. package/dist/cjs/ultramodern-workspace/contracts.cjs +14 -183
  37. package/dist/cjs/ultramodern-workspace/delivery-unit-schema/surfaces.cjs +85 -0
  38. package/dist/cjs/ultramodern-workspace/delivery-unit-schema/types.cjs +8 -85
  39. package/dist/cjs/ultramodern-workspace/delivery-unit-stamp.cjs +16 -4
  40. package/dist/cjs/ultramodern-workspace/delivery-unit-sync.cjs +27 -17
  41. package/dist/cjs/ultramodern-workspace/delivery-unit.cjs +16 -10
  42. package/dist/cjs/ultramodern-workspace/demo-components.cjs +66 -433
  43. package/dist/cjs/ultramodern-workspace/descriptors.cjs +0 -4
  44. package/dist/cjs/ultramodern-workspace/fs-io.cjs +37 -2
  45. package/dist/cjs/ultramodern-workspace/generation-result.cjs +4 -4
  46. package/dist/cjs/ultramodern-workspace/index.cjs +2 -5
  47. package/dist/cjs/ultramodern-workspace/mf-validation/constants.cjs +0 -6
  48. package/dist/cjs/ultramodern-workspace/mf-validation/discovery.cjs +6 -6
  49. package/dist/cjs/{ultramodern-tooling/commands/migrate-strict-effect/generated-patches.cjs → ultramodern-workspace/mf-validation/exposes.cjs} +13 -17
  50. package/dist/cjs/ultramodern-workspace/mf-validation/inspect.cjs +26 -7
  51. package/dist/cjs/ultramodern-workspace/mf-validation/object-literal.cjs +21 -122
  52. package/dist/cjs/ultramodern-workspace/mf-validation/path-utils.cjs +37 -38
  53. package/dist/cjs/ultramodern-workspace/mf-validation/syntax.cjs +93 -153
  54. package/dist/cjs/ultramodern-workspace/mf-validation.cjs +4 -0
  55. package/dist/cjs/ultramodern-workspace/module-federation/config.cjs +24 -29
  56. package/dist/cjs/ultramodern-workspace/module-federation/reexport-module.cjs +39 -58
  57. package/dist/cjs/ultramodern-workspace/module-federation/remote-refs.cjs +1 -43
  58. package/dist/cjs/ultramodern-workspace/package-json.cjs +63 -37
  59. package/dist/cjs/ultramodern-workspace/patch-inventory.cjs +104 -0
  60. package/dist/cjs/ultramodern-workspace/policy.cjs +3 -577
  61. package/dist/cjs/ultramodern-workspace/public-surface.cjs +3 -3
  62. package/dist/cjs/ultramodern-workspace/routes.cjs +2 -11
  63. package/dist/cjs/ultramodern-workspace/shared-patches.cjs +12 -2
  64. package/dist/cjs/ultramodern-workspace/shells.cjs +0 -70
  65. package/dist/cjs/ultramodern-workspace/tooling-command-catalog.cjs +27 -41
  66. package/dist/cjs/ultramodern-workspace/tsconfigs.cjs +8 -2
  67. package/dist/cjs/ultramodern-workspace/validation/architecture.cjs +397 -0
  68. package/dist/cjs/ultramodern-workspace/validation/assertions.cjs +140 -0
  69. package/dist/cjs/ultramodern-workspace/validation/types.cjs +18 -0
  70. package/dist/cjs/ultramodern-workspace/validation/workspace.cjs +344 -0
  71. package/dist/cjs/ultramodern-workspace/versions.cjs +81 -45
  72. package/dist/cjs/ultramodern-workspace/workspace-artifact-ownership.cjs +183 -0
  73. package/dist/cjs/ultramodern-workspace/workspace-script-plan.cjs +36 -25
  74. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +11 -200
  75. package/dist/cjs/ultramodern-workspace/workspace-validation-contract.cjs +62 -373
  76. package/dist/cjs/ultramodern-workspace/write-app.cjs +19 -11
  77. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +20 -50
  78. package/dist/cjs/ultramodern-workspace/zerops.cjs +2 -0
  79. package/dist/esm/cli/package-source.js +3 -3
  80. package/dist/esm/cli/project-setup.js +2 -22
  81. package/dist/esm/index.js +10 -2
  82. package/dist/esm/locale/en.js +2 -1
  83. package/dist/esm/locale/zh.js +2 -1
  84. package/dist/esm/ultramodern-package-source.js +14 -4
  85. package/dist/esm/ultramodern-release-cohort.js +5 -14
  86. package/dist/esm/ultramodern-tooling/commands/cloudflare-output-verify.js +49 -56
  87. package/dist/esm/ultramodern-tooling/commands/context.js +10 -26
  88. package/dist/esm/ultramodern-tooling/commands/routes-generate-app.js +35 -0
  89. package/dist/esm/ultramodern-tooling/commands/routes-generate.js +25 -54
  90. package/dist/esm/ultramodern-tooling/commands/validate.js +6 -12
  91. package/dist/esm/ultramodern-tooling/commands.js +15 -9
  92. package/dist/esm/ultramodern-tooling/config/index.js +0 -2
  93. package/dist/esm/ultramodern-tooling/config/load.js +9 -9
  94. package/dist/esm/ultramodern-tooling/config/metadata.js +33 -28
  95. package/dist/esm/ultramodern-tooling/config/normalize.js +159 -156
  96. package/dist/esm/ultramodern-workspace/add-shell.js +124 -123
  97. package/dist/esm/ultramodern-workspace/add-vertical/execute.js +119 -27
  98. package/dist/esm/ultramodern-workspace/add-vertical/plan.js +16 -150
  99. package/dist/esm/ultramodern-workspace/add-vertical/preflight.js +15 -47
  100. package/dist/esm/ultramodern-workspace/add-vertical/preview.js +40 -0
  101. package/dist/esm/ultramodern-workspace/add-vertical/shell-files.js +87 -25
  102. package/dist/esm/ultramodern-workspace/add-vertical/topology.js +4 -1
  103. package/dist/esm/ultramodern-workspace/add-vertical/transaction.js +373 -46
  104. package/dist/esm/ultramodern-workspace/add-vertical/workspace-state.js +17 -34
  105. package/dist/esm/ultramodern-workspace/add-vertical.js +1 -1
  106. package/dist/esm/ultramodern-workspace/api/client.js +5 -5
  107. package/dist/esm/ultramodern-workspace/api/contracts.js +2 -2
  108. package/dist/esm/ultramodern-workspace/api/rpc.js +20 -18
  109. package/dist/esm/ultramodern-workspace/api/service.js +49 -24
  110. package/dist/esm/ultramodern-workspace/api/shared.js +28 -18
  111. package/dist/esm/ultramodern-workspace/app-files.js +3 -23
  112. package/dist/esm/ultramodern-workspace/backend-federation.js +5 -5
  113. package/dist/esm/ultramodern-workspace/contracts.js +14 -180
  114. package/dist/esm/ultramodern-workspace/delivery-unit-schema/surfaces.js +41 -0
  115. package/dist/esm/ultramodern-workspace/delivery-unit-schema/types.js +1 -75
  116. package/dist/esm/ultramodern-workspace/delivery-unit-stamp.js +16 -4
  117. package/dist/esm/ultramodern-workspace/delivery-unit-sync.js +28 -18
  118. package/dist/esm/ultramodern-workspace/delivery-unit.js +12 -6
  119. package/dist/esm/ultramodern-workspace/demo-components.js +67 -428
  120. package/dist/esm/ultramodern-workspace/descriptors.js +1 -2
  121. package/dist/esm/ultramodern-workspace/fs-io.js +37 -2
  122. package/dist/esm/ultramodern-workspace/generation-result.js +3 -3
  123. package/dist/esm/ultramodern-workspace/index.js +1 -1
  124. package/dist/esm/ultramodern-workspace/mf-validation/constants.js +1 -4
  125. package/dist/esm/ultramodern-workspace/mf-validation/discovery.js +7 -7
  126. package/dist/esm/ultramodern-workspace/mf-validation/exposes.js +14 -0
  127. package/dist/esm/ultramodern-workspace/mf-validation/inspect.js +27 -8
  128. package/dist/esm/ultramodern-workspace/mf-validation/object-literal.js +22 -123
  129. package/dist/esm/ultramodern-workspace/mf-validation/path-utils.js +36 -34
  130. package/dist/esm/ultramodern-workspace/mf-validation/syntax.js +83 -143
  131. package/dist/esm/ultramodern-workspace/mf-validation.js +1 -0
  132. package/dist/esm/ultramodern-workspace/module-federation/config.js +25 -30
  133. package/dist/esm/ultramodern-workspace/module-federation/reexport-module.js +39 -58
  134. package/dist/esm/ultramodern-workspace/module-federation/remote-refs.js +1 -43
  135. package/dist/esm/ultramodern-workspace/package-json.js +58 -32
  136. package/dist/esm/ultramodern-workspace/patch-inventory.js +66 -0
  137. package/dist/esm/ultramodern-workspace/policy.js +2 -564
  138. package/dist/esm/ultramodern-workspace/public-surface.js +3 -3
  139. package/dist/esm/ultramodern-workspace/routes.js +2 -11
  140. package/dist/esm/ultramodern-workspace/shared-patches.js +2 -2
  141. package/dist/esm/ultramodern-workspace/shells.js +3 -67
  142. package/dist/esm/ultramodern-workspace/tooling-command-catalog.js +22 -37
  143. package/dist/esm/ultramodern-workspace/tsconfigs.js +9 -3
  144. package/dist/esm/ultramodern-workspace/validation/architecture.js +348 -0
  145. package/dist/esm/ultramodern-workspace/validation/assertions.js +65 -0
  146. package/dist/esm/ultramodern-workspace/validation/types.js +0 -0
  147. package/dist/esm/ultramodern-workspace/validation/workspace.js +286 -0
  148. package/dist/esm/ultramodern-workspace/versions.js +74 -29
  149. package/dist/esm/ultramodern-workspace/workspace-artifact-ownership.js +128 -0
  150. package/dist/esm/ultramodern-workspace/workspace-script-plan.js +35 -27
  151. package/dist/esm/ultramodern-workspace/workspace-scripts.js +10 -190
  152. package/dist/esm/ultramodern-workspace/workspace-validation-contract.js +65 -376
  153. package/dist/esm/ultramodern-workspace/write-app.js +18 -10
  154. package/dist/esm/ultramodern-workspace/write-workspace.js +25 -52
  155. package/dist/esm/ultramodern-workspace/zerops.js +2 -0
  156. package/dist/esm-node/cli/package-source.js +3 -3
  157. package/dist/esm-node/cli/project-setup.js +2 -22
  158. package/dist/esm-node/index.js +10 -2
  159. package/dist/esm-node/locale/en.js +2 -1
  160. package/dist/esm-node/locale/zh.js +2 -1
  161. package/dist/esm-node/ultramodern-package-source.js +14 -4
  162. package/dist/esm-node/ultramodern-release-cohort.js +5 -14
  163. package/dist/esm-node/ultramodern-tooling/commands/cloudflare-output-verify.js +49 -56
  164. package/dist/esm-node/ultramodern-tooling/commands/context.js +10 -26
  165. package/dist/esm-node/ultramodern-tooling/commands/routes-generate-app.js +36 -0
  166. package/dist/esm-node/ultramodern-tooling/commands/routes-generate.js +25 -54
  167. package/dist/esm-node/ultramodern-tooling/commands/validate.js +6 -12
  168. package/dist/esm-node/ultramodern-tooling/commands.js +15 -9
  169. package/dist/esm-node/ultramodern-tooling/config/index.js +0 -2
  170. package/dist/esm-node/ultramodern-tooling/config/load.js +9 -9
  171. package/dist/esm-node/ultramodern-tooling/config/metadata.js +33 -28
  172. package/dist/esm-node/ultramodern-tooling/config/normalize.js +159 -156
  173. package/dist/esm-node/ultramodern-workspace/add-shell.js +124 -123
  174. package/dist/esm-node/ultramodern-workspace/add-vertical/execute.js +119 -27
  175. package/dist/esm-node/ultramodern-workspace/add-vertical/plan.js +16 -150
  176. package/dist/esm-node/ultramodern-workspace/add-vertical/preflight.js +15 -47
  177. package/dist/esm-node/ultramodern-workspace/add-vertical/preview.js +41 -0
  178. package/dist/esm-node/ultramodern-workspace/add-vertical/shell-files.js +87 -25
  179. package/dist/esm-node/ultramodern-workspace/add-vertical/topology.js +4 -1
  180. package/dist/esm-node/ultramodern-workspace/add-vertical/transaction.js +373 -46
  181. package/dist/esm-node/ultramodern-workspace/add-vertical/workspace-state.js +17 -34
  182. package/dist/esm-node/ultramodern-workspace/add-vertical.js +1 -1
  183. package/dist/esm-node/ultramodern-workspace/api/client.js +5 -5
  184. package/dist/esm-node/ultramodern-workspace/api/contracts.js +2 -2
  185. package/dist/esm-node/ultramodern-workspace/api/rpc.js +20 -18
  186. package/dist/esm-node/ultramodern-workspace/api/service.js +49 -24
  187. package/dist/esm-node/ultramodern-workspace/api/shared.js +28 -18
  188. package/dist/esm-node/ultramodern-workspace/app-files.js +3 -23
  189. package/dist/esm-node/ultramodern-workspace/backend-federation.js +5 -5
  190. package/dist/esm-node/ultramodern-workspace/contracts.js +14 -180
  191. package/dist/esm-node/ultramodern-workspace/delivery-unit-schema/surfaces.js +42 -0
  192. package/dist/esm-node/ultramodern-workspace/delivery-unit-schema/types.js +1 -75
  193. package/dist/esm-node/ultramodern-workspace/delivery-unit-stamp.js +16 -4
  194. package/dist/esm-node/ultramodern-workspace/delivery-unit-sync.js +28 -18
  195. package/dist/esm-node/ultramodern-workspace/delivery-unit.js +12 -6
  196. package/dist/esm-node/ultramodern-workspace/demo-components.js +67 -428
  197. package/dist/esm-node/ultramodern-workspace/descriptors.js +1 -2
  198. package/dist/esm-node/ultramodern-workspace/fs-io.js +37 -2
  199. package/dist/esm-node/ultramodern-workspace/generation-result.js +3 -3
  200. package/dist/esm-node/ultramodern-workspace/index.js +1 -1
  201. package/dist/esm-node/ultramodern-workspace/mf-validation/constants.js +1 -4
  202. package/dist/esm-node/ultramodern-workspace/mf-validation/discovery.js +7 -7
  203. package/dist/esm-node/ultramodern-workspace/mf-validation/exposes.js +15 -0
  204. package/dist/esm-node/ultramodern-workspace/mf-validation/inspect.js +27 -8
  205. package/dist/esm-node/ultramodern-workspace/mf-validation/object-literal.js +22 -123
  206. package/dist/esm-node/ultramodern-workspace/mf-validation/path-utils.js +36 -34
  207. package/dist/esm-node/ultramodern-workspace/mf-validation/syntax.js +83 -143
  208. package/dist/esm-node/ultramodern-workspace/mf-validation.js +1 -0
  209. package/dist/esm-node/ultramodern-workspace/module-federation/config.js +25 -30
  210. package/dist/esm-node/ultramodern-workspace/module-federation/reexport-module.js +39 -58
  211. package/dist/esm-node/ultramodern-workspace/module-federation/remote-refs.js +1 -43
  212. package/dist/esm-node/ultramodern-workspace/package-json.js +58 -32
  213. package/dist/esm-node/ultramodern-workspace/patch-inventory.js +67 -0
  214. package/dist/esm-node/ultramodern-workspace/policy.js +2 -564
  215. package/dist/esm-node/ultramodern-workspace/public-surface.js +3 -3
  216. package/dist/esm-node/ultramodern-workspace/routes.js +2 -11
  217. package/dist/esm-node/ultramodern-workspace/shared-patches.js +2 -2
  218. package/dist/esm-node/ultramodern-workspace/shells.js +3 -67
  219. package/dist/esm-node/ultramodern-workspace/tooling-command-catalog.js +22 -37
  220. package/dist/esm-node/ultramodern-workspace/tsconfigs.js +9 -3
  221. package/dist/esm-node/ultramodern-workspace/validation/architecture.js +349 -0
  222. package/dist/esm-node/ultramodern-workspace/validation/assertions.js +66 -0
  223. package/dist/esm-node/ultramodern-workspace/validation/types.js +1 -0
  224. package/dist/esm-node/ultramodern-workspace/validation/workspace.js +287 -0
  225. package/dist/esm-node/ultramodern-workspace/versions.js +74 -29
  226. package/dist/esm-node/ultramodern-workspace/workspace-artifact-ownership.js +129 -0
  227. package/dist/esm-node/ultramodern-workspace/workspace-script-plan.js +35 -27
  228. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +10 -190
  229. package/dist/esm-node/ultramodern-workspace/workspace-validation-contract.js +65 -376
  230. package/dist/esm-node/ultramodern-workspace/write-app.js +18 -10
  231. package/dist/esm-node/ultramodern-workspace/write-workspace.js +25 -52
  232. package/dist/esm-node/ultramodern-workspace/zerops.js +2 -0
  233. package/dist/types/cli/project-setup.d.ts +1 -1
  234. package/dist/types/locale/en.d.ts +1 -0
  235. package/dist/types/locale/index.d.ts +2 -0
  236. package/dist/types/locale/zh.d.ts +1 -0
  237. package/dist/types/ultramodern-package-source.d.ts +2 -4
  238. package/dist/types/ultramodern-release-cohort.d.ts +1 -3
  239. package/dist/types/ultramodern-tooling/commands/cloudflare-output-verify.d.ts +2 -2
  240. package/dist/types/ultramodern-tooling/commands/context.d.ts +4 -1
  241. package/dist/types/ultramodern-tooling/commands/routes-generate-app.d.ts +1 -0
  242. package/dist/types/ultramodern-tooling/commands/routes-generate.d.ts +1 -1
  243. package/dist/types/ultramodern-tooling/commands/validate.d.ts +1 -1
  244. package/dist/types/ultramodern-tooling/config/index.d.ts +0 -2
  245. package/dist/types/ultramodern-tooling/config/load.d.ts +10 -2
  246. package/dist/types/ultramodern-tooling/config/metadata.d.ts +2 -2
  247. package/dist/types/ultramodern-tooling/config/normalize.d.ts +19 -19
  248. package/dist/types/ultramodern-tooling/config/types.d.ts +2 -9
  249. package/dist/types/ultramodern-workspace/add-shell.d.ts +1 -1
  250. package/dist/types/ultramodern-workspace/add-vertical/execute.d.ts +1 -0
  251. package/dist/types/ultramodern-workspace/add-vertical/preflight.d.ts +4 -3
  252. package/dist/types/ultramodern-workspace/add-vertical/preview.d.ts +4 -0
  253. package/dist/types/ultramodern-workspace/add-vertical/shell-files.d.ts +7 -2
  254. package/dist/types/ultramodern-workspace/add-vertical/transaction.d.ts +32 -6
  255. package/dist/types/ultramodern-workspace/add-vertical/workspace-state.d.ts +10 -7
  256. package/dist/types/ultramodern-workspace/add-vertical.d.ts +1 -1
  257. package/dist/types/ultramodern-workspace/api/client.d.ts +3 -1
  258. package/dist/types/ultramodern-workspace/api/rpc.d.ts +1 -1
  259. package/dist/types/ultramodern-workspace/api/service.d.ts +3 -1
  260. package/dist/types/ultramodern-workspace/api/shared.d.ts +2 -0
  261. package/dist/types/ultramodern-workspace/backend-federation.d.ts +1 -1
  262. package/dist/types/ultramodern-workspace/contracts.d.ts +1 -3
  263. package/dist/types/ultramodern-workspace/delivery-unit-schema/surfaces.d.ts +17 -0
  264. package/dist/types/ultramodern-workspace/delivery-unit-schema/types.d.ts +3 -68
  265. package/dist/types/ultramodern-workspace/delivery-unit-stamp.d.ts +2 -2
  266. package/dist/types/ultramodern-workspace/delivery-unit.d.ts +3 -3
  267. package/dist/types/ultramodern-workspace/demo-components.d.ts +0 -3
  268. package/dist/types/ultramodern-workspace/descriptors.d.ts +0 -1
  269. package/dist/types/ultramodern-workspace/fs-io.d.ts +1 -1
  270. package/dist/types/ultramodern-workspace/index.d.ts +1 -1
  271. package/dist/types/ultramodern-workspace/mf-validation/constants.d.ts +0 -1
  272. package/dist/types/ultramodern-workspace/mf-validation/exposes.d.ts +11 -0
  273. package/dist/types/ultramodern-workspace/mf-validation/path-utils.d.ts +2 -3
  274. package/dist/types/ultramodern-workspace/mf-validation/syntax.d.ts +4 -3
  275. package/dist/types/ultramodern-workspace/mf-validation/types.d.ts +1 -0
  276. package/dist/types/ultramodern-workspace/mf-validation.d.ts +1 -0
  277. package/dist/types/ultramodern-workspace/module-federation/config.d.ts +1 -1
  278. package/dist/types/ultramodern-workspace/module-federation/reexport-module.d.ts +2 -2
  279. package/dist/types/ultramodern-workspace/package-json.d.ts +1 -1
  280. package/dist/types/ultramodern-workspace/patch-inventory.d.ts +10 -0
  281. package/dist/types/ultramodern-workspace/policy.d.ts +31 -209
  282. package/dist/types/ultramodern-workspace/routes.d.ts +6 -1
  283. package/dist/types/ultramodern-workspace/shells.d.ts +2 -15
  284. package/dist/types/ultramodern-workspace/tooling-command-catalog.d.ts +8 -7
  285. package/dist/types/ultramodern-workspace/types.d.ts +9 -9
  286. package/dist/types/ultramodern-workspace/validation/architecture.d.ts +2 -0
  287. package/dist/types/ultramodern-workspace/validation/assertions.d.ts +14 -0
  288. package/dist/types/ultramodern-workspace/validation/types.d.ts +9 -0
  289. package/dist/types/ultramodern-workspace/validation/workspace.d.ts +6 -0
  290. package/dist/types/ultramodern-workspace/versions.d.ts +73 -28
  291. package/dist/types/ultramodern-workspace/workspace-artifact-ownership.d.ts +18 -0
  292. package/dist/types/ultramodern-workspace/workspace-script-plan.d.ts +4 -5
  293. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +8 -13
  294. package/dist/types/ultramodern-workspace/workspace-validation-contract.d.ts +22 -188
  295. package/dist/types/ultramodern-workspace/write-workspace.d.ts +1 -3
  296. package/package.json +18 -11
  297. package/{template-workspace/.modernjs/release-cohort.json → release-cohort.json} +88 -40
  298. package/template-workspace/.codex/skills/rspack-tracing/scripts/analyze_trace.js +1 -1
  299. package/template-workspace/README.md.handlebars +20 -35
  300. package/template-workspace/oxfmt.config.ts +3 -0
  301. package/template-workspace/pnpm-workspace.yaml.handlebars +0 -24
  302. package/template-workspace/scripts/bootstrap-agent-skills.mjs +4 -4
  303. package/templates/packages/shared-contracts-index.ts +4 -332
  304. package/templates/workspace/apps/modern.config.shared-module-federation.ts.handlebars +10 -0
  305. package/templates/workspace/apps/modern.config.ts.handlebars +13 -27
  306. package/templates/workspace/apps/shared/src/routes/ultramodern-route-metadata.ts.handlebars +21 -11
  307. package/templates/workspace/apps/shell-super-app/src/routes/[lang]/page.tsx.handlebars +20 -20
  308. package/templates/workspace/apps/shell-super-app/src/routes/vertical-components.helpers.tsx.handlebars +4 -6
  309. package/templates/workspace/apps/shell-super-app/src/routes/vertical-components.imports.tsx.handlebars +2 -2
  310. package/templates/workspace/apps/shell-super-app/src/routes/vertical-components.tsx.handlebars +11 -11
  311. package/templates/workspace/apps/shell-super-app/src/routes/vertical-components.worker.helpers.tsx.handlebars +1 -1
  312. package/templates/workspace/apps/shell-super-app/src/routes/vertical-components.worker.imports.tsx.handlebars +1 -1
  313. package/templates/workspace-scripts/generate-node-backend-federation.mjs +68 -77
  314. package/templates/workspace-scripts/generate-public-surface-assets.mjs +107 -207
  315. package/templates/workspace-scripts/materialize-zerops-runtime.mjs +12 -19
  316. package/templates/workspace-scripts/proof-cloudflare-version.mjs +53 -444
  317. package/templates/workspace-scripts/proof-node-backend-federation.mjs +212 -91
  318. package/templates/workspace-scripts/{proof-workerd-ssr.mts → proof-workerd-ssr.mjs} +434 -239
  319. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +25 -7
  320. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +45 -147
  321. package/templates/workspace-scripts/ultramodern-typecheck.mjs +1 -1
  322. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/api-metadata.cjs +0 -212
  323. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/declaration-patches.cjs +0 -47
  324. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/dependency-usage.cjs +0 -112
  325. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-backend-federation.cjs +0 -55
  326. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-build-identity.cjs +0 -102
  327. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-modern-configs.cjs +0 -195
  328. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-oxfmt.cjs +0 -146
  329. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-oxlint.cjs +0 -110
  330. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-removal.cjs +0 -67
  331. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-typescript.cjs +0 -307
  332. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-zerops.cjs +0 -58
  333. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts.cjs +0 -71
  334. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/generated-ui-source.cjs +0 -151
  335. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/help.cjs +0 -67
  336. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/install.cjs +0 -52
  337. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/io.cjs +0 -447
  338. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/package-cohort.cjs +0 -323
  339. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/package-source.cjs +0 -87
  340. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/pnpm-policy.cjs +0 -612
  341. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/pnpm-yaml.cjs +0 -376
  342. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/policy-constants.cjs +0 -73
  343. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/react-router-retirement.cjs +0 -215
  344. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect/toolchain-pins.cjs +0 -135
  345. package/dist/cjs/ultramodern-tooling/commands/migrate-strict-effect.cjs +0 -454
  346. package/dist/cjs/ultramodern-tooling/config/constants.cjs +0 -48
  347. package/dist/cjs/ultramodern-tooling/config/synthesize.cjs +0 -157
  348. package/dist/cjs/ultramodern-workspace/delivery-unit-schema/up-projection.cjs +0 -188
  349. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/api-metadata.js +0 -154
  350. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/declaration-patches.js +0 -9
  351. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/dependency-usage.js +0 -63
  352. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-backend-federation.js +0 -7
  353. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-build-identity.js +0 -47
  354. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-modern-configs.js +0 -146
  355. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-oxfmt.js +0 -97
  356. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-oxlint.js +0 -61
  357. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-removal.js +0 -16
  358. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-typescript.js +0 -258
  359. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-zerops.js +0 -10
  360. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts.js +0 -8
  361. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-patches.js +0 -15
  362. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/generated-ui-source.js +0 -100
  363. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/help.js +0 -29
  364. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/install.js +0 -14
  365. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/io.js +0 -385
  366. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/package-cohort.js +0 -276
  367. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/package-source.js +0 -49
  368. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/pnpm-policy.js +0 -559
  369. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/pnpm-yaml.js +0 -329
  370. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/policy-constants.js +0 -19
  371. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/react-router-retirement.js +0 -148
  372. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect/toolchain-pins.js +0 -80
  373. package/dist/esm/ultramodern-tooling/commands/migrate-strict-effect.js +0 -405
  374. package/dist/esm/ultramodern-tooling/config/constants.js +0 -4
  375. package/dist/esm/ultramodern-tooling/config/synthesize.js +0 -108
  376. package/dist/esm/ultramodern-workspace/delivery-unit-schema/up-projection.js +0 -129
  377. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/api-metadata.js +0 -155
  378. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/declaration-patches.js +0 -10
  379. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/dependency-usage.js +0 -64
  380. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-backend-federation.js +0 -8
  381. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-build-identity.js +0 -48
  382. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-modern-configs.js +0 -147
  383. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-oxfmt.js +0 -98
  384. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-oxlint.js +0 -62
  385. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-removal.js +0 -17
  386. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-typescript.js +0 -259
  387. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-zerops.js +0 -11
  388. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts.js +0 -9
  389. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-patches.js +0 -16
  390. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/generated-ui-source.js +0 -101
  391. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/help.js +0 -30
  392. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/install.js +0 -15
  393. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/io.js +0 -386
  394. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/package-cohort.js +0 -277
  395. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/package-source.js +0 -50
  396. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/pnpm-policy.js +0 -560
  397. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/pnpm-yaml.js +0 -330
  398. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/policy-constants.js +0 -20
  399. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/react-router-retirement.js +0 -149
  400. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect/toolchain-pins.js +0 -81
  401. package/dist/esm-node/ultramodern-tooling/commands/migrate-strict-effect.js +0 -406
  402. package/dist/esm-node/ultramodern-tooling/config/constants.js +0 -5
  403. package/dist/esm-node/ultramodern-tooling/config/synthesize.js +0 -109
  404. package/dist/esm-node/ultramodern-workspace/delivery-unit-schema/up-projection.js +0 -130
  405. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/api-metadata.d.ts +0 -12
  406. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/declaration-patches.d.ts +0 -4
  407. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/dependency-usage.d.ts +0 -1
  408. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-backend-federation.d.ts +0 -3
  409. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-build-identity.d.ts +0 -5
  410. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-modern-configs.d.ts +0 -3
  411. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-oxfmt.d.ts +0 -2
  412. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-oxlint.d.ts +0 -2
  413. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-removal.d.ts +0 -4
  414. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-typescript.d.ts +0 -3
  415. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts-zerops.d.ts +0 -3
  416. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-artifacts.d.ts +0 -8
  417. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-patches.d.ts +0 -3
  418. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/generated-ui-source.d.ts +0 -3
  419. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/help.d.ts +0 -1
  420. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/install.d.ts +0 -2
  421. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/io.d.ts +0 -26
  422. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/package-cohort.d.ts +0 -25
  423. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/package-source.d.ts +0 -3
  424. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/pnpm-policy.d.ts +0 -26
  425. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/pnpm-yaml.d.ts +0 -26
  426. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/policy-constants.d.ts +0 -6
  427. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/react-router-retirement.d.ts +0 -37
  428. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect/toolchain-pins.d.ts +0 -4
  429. package/dist/types/ultramodern-tooling/commands/migrate-strict-effect.d.ts +0 -2
  430. package/dist/types/ultramodern-tooling/config/constants.d.ts +0 -3
  431. package/dist/types/ultramodern-tooling/config/synthesize.d.ts +0 -5
  432. package/dist/types/ultramodern-workspace/delivery-unit-schema/up-projection.d.ts +0 -189
  433. package/template-workspace/patches/@module-federation__bridge-react@2.9.0.patch +0 -47
  434. package/template-workspace/patches/@module-federation__dts-plugin@2.9.0.patch +0 -26
  435. package/template-workspace/patches/@module-federation__modern-js-v3@2.9.0.patch +0 -268
  436. package/template-workspace/patches/@module-federation__runtime-core@2.9.0.patch +0 -13
  437. package/template-workspace/patches/drizzle-orm-ts7-strict-declarations.patch +0 -471
  438. package/template-workspace/patches/msgpackr@2.1.0.patch +0 -30
  439. package/template-workspace/patches/zod@4.5.4.patch +0 -56
  440. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +0 -779
  441. package/templates/workspace-scripts/check-ultramodern-i18n-boundaries.mts +0 -9
  442. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +0 -4109
@@ -3,14 +3,12 @@ import crypto from "node:crypto";
3
3
  import fs from "node:fs";
4
4
  import http from "node:http";
5
5
  import path from "node:path";
6
- import { Log, LogLevel, Miniflare } from "miniflare";
6
+ import { parseEnv } from "node:util";
7
+ import { convertV4MiniflareOptions, Log, LogLevel, Miniflare } from "miniflare";
7
8
 
8
- const workspaceRoot = process.cwd();
9
- const defaultProofRoutes = ["/en"];
10
- const reportPath = path.join(
11
- workspaceRoot,
12
- ".codex/reports/cloudflare-workerd-ssr/composition-proof.json",
13
- );
9
+ const reportRelativePath = ".codex/reports/cloudflare-workerd-ssr/composition-proof.json";
10
+ // Mirrors the public website quality gate default for server-rendered HTML.
11
+ const defaultSsrHtmlMaxBytes = 250_000;
14
12
 
15
13
  const assert = (condition, message) => {
16
14
  if (!condition) {
@@ -120,69 +118,164 @@ const bindExecutedModule = (app, envelope, module) => {
120
118
  };
121
119
  };
122
120
 
123
- const compactConfig = readJson(path.join(workspaceRoot, ".modernjs/ultramodern.json"));
124
- const apps = (compactConfig.topology?.apps ?? []).map((rawApp) => {
125
- const kind = rawApp.kind === "vertical" ? "vertical" : "shell";
126
- const appPath =
127
- typeof rawApp.path === "string"
128
- ? normalizePath(rawApp.path)
129
- : kind === "shell"
130
- ? "apps/shell-super-app"
131
- : `verticals/${rawApp.id}`;
132
- const moduleFederation =
133
- rawApp.moduleFederation && typeof rawApp.moduleFederation === "object"
134
- ? rawApp.moduleFederation
135
- : {};
136
- const configuredProofRoutes = rawApp.deploy?.cloudflare?.distributedSsrProofRoutes;
137
- const proofRoutes = Array.isArray(configuredProofRoutes)
138
- ? [...new Set(configuredProofRoutes.filter(
139
- (route) => typeof route === "string" && route.startsWith("/"),
140
- ))]
141
- : [];
142
- const outputRoot = path.join(workspaceRoot, appPath, ".output");
143
- const wranglerPath = path.join(outputRoot, "wrangler.json");
121
+ const normalizeRoutes = (routes) => [
122
+ ...new Set(
123
+ (Array.isArray(routes) ? routes : []).filter(
124
+ (route) => typeof route === "string" && route.startsWith("/"),
125
+ ),
126
+ ),
127
+ ];
128
+
129
+ // The generator's distributed SSR contract: every expose except the page
130
+ // route is a fragment a host can server-render (see distributedSsrExposes).
131
+ const declaresDistributedSsrExpose = (rawApp) =>
132
+ Array.isArray(rawApp?.moduleFederation?.exposes) &&
133
+ rawApp.moduleFederation.exposes.some(
134
+ (expose) => typeof expose === "string" && expose !== "./Route",
135
+ );
136
+
137
+ /**
138
+ * Derive what the proof must execute from topology/reference-topology.json.
139
+ *
140
+ * - `ssrRoutes`: every route the app itself must server-render on its own
141
+ * Worker (`cloudflare.routes.ssr` plus `cloudflare.distributedSsrProofRoutes`).
142
+ * - `serverRenderedRoutes`: shell routes that must compose distributed SSR
143
+ * boundaries. `cloudflare.distributedSsrProofRoutes` declares them; without
144
+ * it the shell's `cloudflare.routes.ssr` is the composition route. An empty
145
+ * array declares a shell whose MicroVerticals load on the client only.
146
+ * - `serverRenderedRemoteIds`: shell `verticalRefs` whose topology declares a
147
+ * distributed SSR expose, i.e. the boundaries the shell must server-render.
148
+ */
149
+ export const planWorkerdSsrProof = (topology) => {
144
150
  assert(
145
- fs.existsSync(wranglerPath),
146
- `${rawApp.id} Cloudflare output is missing; run pnpm cloudflare:build first`,
147
- );
148
- const wrangler = readJson(wranglerPath);
149
- const executedEnvelope =
150
- kind === "vertical"
151
- ? readExecutionEnvelope(
152
- String(rawApp.id),
153
- outputRoot,
154
- rawApp.deliveryUnit?.unitId,
155
- )
156
- : {};
151
+ topology?.schemaVersion === 1 && topology.shell && Array.isArray(topology.verticals),
152
+ "Invalid topology/reference-topology.json",
153
+ );
154
+ const rawApps = [topology.shell, ...topology.verticals, ...(topology.shells ?? [])];
155
+ const rawAppsById = new Map(rawApps.map((rawApp) => [String(rawApp.id), rawApp]));
156
+ const plans = rawApps.map((rawApp) => {
157
+ const id = String(rawApp.id);
158
+ const kind = rawApp.kind === "vertical" ? "vertical" : "shell";
159
+ const cloudflare = rawApp.cloudflare ?? {};
160
+ const declaredServerRenderedRoutes = cloudflare.distributedSsrProofRoutes;
161
+ const rawVerticalRefs = rawApp.verticalRefs ?? rawApp.moduleFederation?.verticalRefs;
162
+ const verticalRefs = Array.isArray(rawVerticalRefs)
163
+ ? rawVerticalRefs.filter((ref) => typeof ref === "string")
164
+ : [];
165
+ for (const ref of verticalRefs) {
166
+ assert(rawAppsById.has(ref), `${id} references missing MicroVertical ${ref}`);
167
+ }
168
+ const serverRenderedRemoteIds =
169
+ kind === "shell"
170
+ ? verticalRefs.filter((ref) => declaresDistributedSsrExpose(rawAppsById.get(ref)))
171
+ : [];
172
+ assert(
173
+ declaredServerRenderedRoutes === undefined ||
174
+ (Array.isArray(declaredServerRenderedRoutes) &&
175
+ normalizeRoutes(declaredServerRenderedRoutes).length ===
176
+ declaredServerRenderedRoutes.length),
177
+ `${id} cloudflare.distributedSsrProofRoutes must list unique absolute routes`,
178
+ );
179
+ const serverRenderedRoutes =
180
+ kind !== "shell"
181
+ ? []
182
+ : Array.isArray(declaredServerRenderedRoutes)
183
+ ? normalizeRoutes(declaredServerRenderedRoutes)
184
+ : normalizeRoutes([cloudflare.routes?.ssr]);
185
+ const ssrRoutes = normalizeRoutes([
186
+ ...(Array.isArray(declaredServerRenderedRoutes) ? declaredServerRenderedRoutes : []),
187
+ cloudflare.routes?.ssr,
188
+ ]);
189
+ const apiOnly = rawApp.surfaceProfile === "api-only";
190
+ assert(
191
+ apiOnly || normalizeRoutes([cloudflare.routes?.ssr]).length === 1,
192
+ `${id} declares no cloudflare.routes.ssr to prove on its own Worker`,
193
+ );
194
+ return {
195
+ apiOnly,
196
+ id,
197
+ kind,
198
+ serverRenderedRemoteIds:
199
+ serverRenderedRoutes.length > 0 ? serverRenderedRemoteIds : [],
200
+ serverRenderedRoutes,
201
+ ssrRoutes,
202
+ verticalRefs,
203
+ };
204
+ });
205
+ assert(
206
+ plans.some((plan) => plan.kind === "shell"),
207
+ "Workerd SSR proof requires at least one shell",
208
+ );
209
+ assert(
210
+ plans.some((plan) => plan.kind === "vertical"),
211
+ "Workerd SSR proof requires at least one MicroVertical or headless API",
212
+ );
213
+ return { plans, rawApps };
214
+ };
157
215
 
158
- return {
159
- id: String(rawApp.id),
160
- kind,
161
- path: appPath,
162
- mfName: typeof moduleFederation.name === "string" ? moduleFederation.name : String(rawApp.id),
163
- verticalRefs: Array.isArray(moduleFederation.verticalRefs)
164
- ? moduleFederation.verticalRefs.filter((ref) => typeof ref === "string")
165
- : [],
166
- apiPrefix:
167
- typeof rawApp.api?.prefix === "string"
168
- ? rawApp.api.prefix.replace(/\/+$/u, "")
169
- : undefined,
170
- proofRoutes: proofRoutes.length > 0 ? proofRoutes : defaultProofRoutes,
171
- jsonSmokeChecks: Array.isArray(rawApp.deploy?.cloudflare?.jsonSmokeChecks)
172
- ? rawApp.deploy.cloudflare.jsonSmokeChecks
173
- : [],
174
- ...executedEnvelope,
175
- outputRoot,
176
- port: Number(rawApp.port),
177
- wrangler,
178
- };
179
- });
216
+ const readDevVars = (outputRoot) => {
217
+ // Wrangler's local-secret convention: `.dev.vars` beside the executed config.
218
+ const devVarsPath = path.join(outputRoot, ".dev.vars");
219
+ return fs.existsSync(devVarsPath) ? parseEnv(fs.readFileSync(devVarsPath, "utf8")) : {};
220
+ };
180
221
 
181
- const shells = apps.filter((app) => app.kind === "shell");
182
- assert(shells.length > 0, "Workerd SSR proof requires at least one shell");
183
- if (process.env.ULTRAMODERN_KEEP_WORKERD === "1") {
184
- assert(shells.length === 1, "Browser workerd proof requires exactly one shell");
185
- }
222
+ const loadApps = (workspaceRoot, topology, overlay) => {
223
+ const { plans, rawApps } = planWorkerdSsrProof(topology);
224
+ return rawApps.map((rawApp, index) => {
225
+ const plan = plans[index];
226
+ const hasApiSurface = plan.kind === "vertical" && rawApp.surfaceProfile !== "ui-only";
227
+ const appPath = rawApp.path;
228
+ assert(typeof appPath === "string" && appPath.length > 0, `${plan.id} topology path is missing`);
229
+ const outputRoot = path.join(workspaceRoot, appPath, ".output");
230
+ const wranglerPath = path.join(outputRoot, "wrangler.json");
231
+ assert(
232
+ fs.existsSync(wranglerPath),
233
+ `${plan.id} Cloudflare output is missing; run pnpm cloudflare:build first`,
234
+ );
235
+ const wrangler = readJson(wranglerPath);
236
+ const executedEnvelope = hasApiSurface
237
+ ? readExecutionEnvelope(plan.id, outputRoot, rawApp.deliveryUnit?.unitId)
238
+ : {};
239
+ const domain = rawApp.domain ?? rawApp.id;
240
+ const portEnv = rawApp.portEnv ??
241
+ (plan.kind === "vertical"
242
+ ? `VERTICAL_${String(domain).replace(/[^a-zA-Z0-9]/gu, "_").toUpperCase()}_PORT`
243
+ : undefined);
244
+ assert(typeof portEnv === "string" && portEnv.length > 0, `${plan.id} has no declared port environment name`);
245
+ const configuredPort = process.env[portEnv];
246
+ const port = configuredPort === undefined
247
+ ? Number(overlay.ports?.[plan.id])
248
+ : Number(configuredPort);
249
+ assert(
250
+ Number.isInteger(port) && port > 0 && port <= 65535,
251
+ `${plan.id} has an invalid local proof port from ${portEnv}`,
252
+ );
253
+
254
+ return {
255
+ ...plan,
256
+ hasApiSurface,
257
+ path: appPath,
258
+ apiPrefix:
259
+ typeof rawApp.api?.bff?.prefix === "string"
260
+ ? rawApp.api.bff.prefix.replace(/\/+$/u, "")
261
+ : undefined,
262
+ apiProtocol: rawApp.api?.protocol ?? "rest",
263
+ rpcRoute: rawApp.api?.protocol === "rpc" ? rawApp.cloudflare?.routes?.rpc : undefined,
264
+ ssrHtmlMaxBytes: Number(
265
+ rawApp.cloudflare?.qualityGates?.budgets?.ssrHtmlMaxBytes ??
266
+ defaultSsrHtmlMaxBytes,
267
+ ),
268
+ jsonSmokeChecks: Array.isArray(rawApp.cloudflare?.jsonSmokeChecks)
269
+ ? rawApp.cloudflare.jsonSmokeChecks
270
+ : [],
271
+ ...executedEnvelope,
272
+ devVars: readDevVars(outputRoot),
273
+ outputRoot,
274
+ port,
275
+ wrangler,
276
+ };
277
+ });
278
+ };
186
279
 
187
280
  const workerName = (app) => {
188
281
  assert(
@@ -192,7 +285,7 @@ const workerName = (app) => {
192
285
  return app.wrangler.name;
193
286
  };
194
287
 
195
- const createWorkerOptions = (app, extra = {}) => {
288
+ const createWorkerOptions = (app, workspaceRoot, extra = {}) => {
196
289
  const main = typeof app.wrangler.main === "string" ? app.wrangler.main : "server/index.mjs";
197
290
  const assets =
198
291
  app.wrangler.assets && typeof app.wrangler.assets === "object" ? app.wrangler.assets : {};
@@ -222,7 +315,7 @@ const createWorkerOptions = (app, extra = {}) => {
222
315
  const apiBackend = app.envelope?.surfaces?.apiBackend;
223
316
  const ssr = app.envelope?.surfaces?.ssr;
224
317
  assert(
225
- app.kind !== "vertical" ||
318
+ !app.hasApiSurface ||
226
319
  (Array.isArray(apiBackend) &&
227
320
  apiBackend.length > 0 &&
228
321
  apiBackend.every((logicalPath) =>
@@ -231,13 +324,16 @@ const createWorkerOptions = (app, extra = {}) => {
231
324
  `${app.id} BFF worker surface is not selected by Miniflare`,
232
325
  );
233
326
  assert(
234
- app.kind !== "vertical" ||
327
+ !app.hasApiSurface ||
235
328
  (Array.isArray(ssr) &&
236
- ssr.includes(mainLogicalPath) &&
329
+ (app.apiOnly
330
+ ? ssr.length === 0 && mainLogicalPath === "server/index.mjs"
331
+ : ssr.includes(mainLogicalPath)) &&
237
332
  boundModules.every((module) =>
238
- [...ssr, ...(apiBackend ?? [])].includes(module.logicalPath),
333
+ [...ssr, ...(apiBackend ?? []), ...(app.apiOnly ? [mainLogicalPath] : [])]
334
+ .includes(module.logicalPath),
239
335
  )),
240
- `${app.id} Miniflare main/SSR modules are not envelope-bound SSR surfaces`,
336
+ `${app.id} Miniflare main/SSR modules do not match its envelope surfaces`,
241
337
  );
242
338
 
243
339
  return {
@@ -259,8 +355,8 @@ const createWorkerOptions = (app, extra = {}) => {
259
355
  modulesRoot: app.outputRoot,
260
356
  compatibilityDate: app.wrangler.compatibility_date,
261
357
  compatibilityFlags: app.wrangler.compatibility_flags,
358
+ bindings: { ...app.wrangler.vars, ...app.devVars },
262
359
  assets: {
263
- workerName: workerName(app),
264
360
  binding: typeof assets.binding === "string" ? assets.binding : "ASSETS",
265
361
  directory: path.resolve(app.outputRoot, directory),
266
362
  routerConfig: {
@@ -295,7 +391,10 @@ const findReleaseMarkers = (value, markers = []) => {
295
391
  return markers;
296
392
  };
297
393
 
298
- const responseEvidence = async (app, response) => {
394
+ const jsonPathValue = (value, key) =>
395
+ String(key).split(".").reduce((current, segment) => current?.[segment], value);
396
+
397
+ const responseEvidence = async (app, response, check) => {
299
398
  const bytes = Buffer.from(await response.arrayBuffer());
300
399
  let body;
301
400
  try {
@@ -303,19 +402,36 @@ const responseEvidence = async (app, response) => {
303
402
  } catch (error) {
304
403
  throw new Error(`${app.id} API response is not JSON: ${error.message}`);
305
404
  }
306
- const markers = findReleaseMarkers(body);
307
- const marker = markers.find(
308
- (candidate) =>
309
- candidate.appId === app.id &&
310
- candidate.build === app.envelope.identity.buildMarker &&
311
- candidate.version === app.envelope.identity.releaseVersion,
312
- );
313
- assert(marker, `${app.id} API response is not tied to its executed release identity`);
314
405
  assert(response.ok, `${app.id} API response returned HTTP ${response.status}`);
406
+ let marker;
407
+ if (app.apiProtocol === "rpc") {
408
+ assert(
409
+ typeof app.rpcRoute === "string" && app.rpcRoute.startsWith("/") &&
410
+ check.route === app.rpcRoute && String(check.method).toUpperCase() === "POST" &&
411
+ check.body?.jsonrpc === "2.0" && check.body?.id !== undefined &&
412
+ body?.jsonrpc === "2.0" && body.id === check.body.id,
413
+ `${app.id} RPC response does not match its declared POST request`,
414
+ );
415
+ assert(
416
+ check.expect && Object.keys(check.expect).length > 0 &&
417
+ Object.entries(check.expect).every(([key, expected]) =>
418
+ JSON.stringify(jsonPathValue(body, key)) === JSON.stringify(expected)),
419
+ `${app.id} RPC response does not satisfy its declared JSON smoke check`,
420
+ );
421
+ } else {
422
+ const markers = findReleaseMarkers(body);
423
+ marker = markers.find(
424
+ (candidate) =>
425
+ candidate.appId === app.id &&
426
+ candidate.build === app.envelope.identity.buildMarker &&
427
+ candidate.version === app.envelope.identity.releaseVersion,
428
+ );
429
+ assert(marker, `${app.id} API response is not tied to its executed release identity`);
430
+ }
315
431
  return {
316
432
  bodyBase64: bytes.toString("base64"),
317
433
  byteLength: bytes.byteLength,
318
- releaseMarker: marker,
434
+ ...(marker ? { releaseMarker: marker } : {}),
319
435
  sha256: sha256(bytes),
320
436
  status: response.status,
321
437
  };
@@ -348,9 +464,9 @@ const resolveApiSmokeChecks = (app, shell) => {
348
464
  return [...uniqueChecks.values()];
349
465
  };
350
466
 
351
- const runApiProofs = async (miniflare, shell, executionByAppId) => {
467
+ const runApiProofs = async (apps, miniflare, shell, executionByAppId) => {
352
468
  const results = [];
353
- for (const app of apps.filter((candidate) => candidate.kind === "vertical")) {
469
+ for (const app of apps.filter((candidate) => candidate.hasApiSurface)) {
354
470
  const jsonSmokeChecks = resolveApiSmokeChecks(app, shell);
355
471
  assert(
356
472
  jsonSmokeChecks.length > 0,
@@ -359,7 +475,10 @@ const runApiProofs = async (miniflare, shell, executionByAppId) => {
359
475
  const binding = (shell.wrangler.services ?? []).find(
360
476
  (candidate) => candidate.service === workerName(app),
361
477
  );
362
- assert(binding, `${shell.id} has no service binding for ${app.id}`);
478
+ assert(
479
+ binding || (app.apiOnly && !shell.verticalRefs.includes(app.id)),
480
+ `${shell.id} has no service binding for ${app.id}`,
481
+ );
363
482
  for (const check of jsonSmokeChecks) {
364
483
  const method = String(check.method ?? "GET").toUpperCase();
365
484
  const headers = {};
@@ -373,31 +492,39 @@ const runApiProofs = async (miniflare, shell, executionByAppId) => {
373
492
  await (
374
493
  await miniflare.getWorker(workerName(app))
375
494
  ).fetch(`https://${workerName(app)}.invalid${check.route}`, init),
495
+ check,
376
496
  );
377
- const throughShell = await responseEvidence(
378
- app,
379
- await miniflare.dispatchFetch(
380
- `https://${workerName(shell)}.invalid${check.route}`,
381
- init,
382
- ),
383
- );
384
- assert(
385
- direct.sha256 === throughShell.sha256,
386
- `${app.id} direct and service-binding API responses differ`,
387
- );
497
+ const throughShell = binding
498
+ ? await responseEvidence(
499
+ app,
500
+ await miniflare.dispatchFetch(
501
+ `https://${workerName(shell)}.invalid${check.route}`,
502
+ init,
503
+ ),
504
+ check,
505
+ )
506
+ : undefined;
507
+ if (throughShell) {
508
+ assert(
509
+ direct.sha256 === throughShell.sha256,
510
+ `${app.id} direct and service-binding API responses differ`,
511
+ );
512
+ }
513
+ const target = {
514
+ appId: app.id,
515
+ envelopeDigest: executionByAppId.get(app.id).envelopeDigest,
516
+ worker: workerName(app),
517
+ };
388
518
  results.push({
389
519
  appId: app.id,
390
- binding: binding.binding,
391
- bindingTarget: {
392
- appId: app.id,
393
- envelopeDigest: executionByAppId.get(app.id).envelopeDigest,
394
- worker: workerName(app),
395
- },
520
+ shellId: shell.id,
521
+ ...(binding
522
+ ? { binding: binding.binding, bindingTarget: target, throughShell }
523
+ : { directTarget: target }),
396
524
  direct,
397
525
  id: check.id,
398
526
  method,
399
527
  route: check.route,
400
- throughShell,
401
528
  });
402
529
  }
403
530
  }
@@ -427,6 +554,7 @@ const closeServer = (server) =>
427
554
  });
428
555
 
429
556
  const startWorkerdTargetServers = async (
557
+ apps,
430
558
  miniflare,
431
559
  failedServices,
432
560
  workerConfigurations,
@@ -440,16 +568,9 @@ const startWorkerdTargetServers = async (
440
568
  Number.isInteger(app.port) && app.port > 0,
441
569
  `${app.id} requires a configured local port for all-workerd browser proof`,
442
570
  );
443
- // Miniflare 4 currently assigns one shared assets storage service inside
444
- // a multi-worker instance. Keep the shell composition runtime intact,
445
- // but give every directly browsed MicroVertical its own runtime so its
446
- // static assets and MF manifest cannot resolve from a sibling Worker.
447
571
  const runtime =
448
572
  app.kind === "vertical"
449
- ? new Miniflare({
450
- log: new Log(LogLevel.ERROR),
451
- workers: [workerConfigurations[index]],
452
- })
573
+ ? createIsolatedRuntime(workerConfigurations[index])
453
574
  : miniflare;
454
575
  if (runtime !== miniflare) {
455
576
  isolatedVerticalRuntimes.push(runtime);
@@ -597,9 +718,22 @@ const decodeDistributedSsrFragmentRequest = (request) => {
597
718
  };
598
719
  };
599
720
 
721
+ // Miniflare assigns one shared assets storage service inside a multi-worker
722
+ // instance. Keep the shell composition runtime intact, but give every directly
723
+ // requested MicroVertical its own runtime so its static assets and MF manifest
724
+ // cannot resolve from a sibling Worker. Its service bindings still resolve
725
+ // through the shared composition runtime.
726
+ const createIsolatedRuntime = (workerOptions) =>
727
+ new Miniflare(
728
+ convertV4MiniflareOptions({
729
+ log: new Log(LogLevel.ERROR),
730
+ workers: [workerOptions],
731
+ }),
732
+ );
733
+
600
734
  const createServiceBindings = (
601
735
  caller,
602
- { apiBindingRequests, failedServices, fragmentBindingRequests },
736
+ { apiBindingRequests, composition, failedServices, fragmentBindingRequests },
603
737
  ) => {
604
738
  const services = Array.isArray(caller.wrangler.services) ? caller.wrangler.services : [];
605
739
  return Object.fromEntries(
@@ -610,7 +744,7 @@ const createServiceBindings = (
610
744
  );
611
745
  return [
612
746
  service.binding,
613
- async (request, miniflare) => {
747
+ async (request) => {
614
748
  if (failedServices.has(service.service)) {
615
749
  throw new Error(
616
750
  `Injected unavailable service binding ${service.binding} -> ${service.service}`,
@@ -647,7 +781,7 @@ const createServiceBindings = (
647
781
  };
648
782
  apiBindingRequests.push(apiBindingRequest);
649
783
  }
650
- const target = await miniflare.getWorker(service.service);
784
+ const target = await composition.miniflare.getWorker(service.service);
651
785
  const response = await target.fetch(request);
652
786
  if (apiBindingRequest !== undefined) {
653
787
  apiBindingRequest.response = {
@@ -662,11 +796,96 @@ const createServiceBindings = (
662
796
  );
663
797
  };
664
798
 
665
- const proofs = [];
666
- const apiProofs = [];
667
- let executions = [];
799
+ const proveRoute = async (app, route, fetchRoute, apps, recorders) => {
800
+ const apiBindingRequestStart = recorders.apiBindingRequests.length;
801
+ const fragmentBindingRequestStart = recorders.fragmentBindingRequests.length;
802
+ const outboundRequestStart = recorders.outboundRequests.length;
803
+ const response = await fetchRoute(`https://${workerName(app)}.invalid${route}`, {
804
+ headers: { accept: "text/html" },
805
+ });
806
+ const html = await response.text();
807
+ const htmlBytes = Buffer.byteLength(html);
808
+ const routeOutboundRequests = recorders.outboundRequests.slice(outboundRequestStart);
809
+ assert(
810
+ response.status === 200,
811
+ `${app.id} returned HTTP ${response.status} for ${route} in workerd; outbound requests: ${JSON.stringify(routeOutboundRequests)}; response: ${html.slice(0, 500)}`,
812
+ );
813
+ assert(
814
+ response.headers.get("content-type")?.includes("text/html") === true,
815
+ `${app.id} did not return HTML for ${route} in workerd`,
816
+ );
817
+ // Runaway server rendering (for example a worker re-rendering its own
818
+ // route data requests) can still end in an oversized document.
819
+ assert(
820
+ htmlBytes <= app.ssrHtmlMaxBytes,
821
+ `${app.id} rendered ${htmlBytes} bytes for ${route} in workerd, over the ${app.ssrHtmlMaxBytes} byte ssrHtmlMaxBytes budget`,
822
+ );
823
+ assert(
824
+ !html.includes('data-modern-distributed-ssr-status="degraded"'),
825
+ `${app.id} rendered a degraded MicroVertical fallback for ${route} in workerd`,
826
+ );
827
+
828
+ const boundaries = collectDistributedBoundaries(html);
829
+ const routeApiBindingRequests = recorders.apiBindingRequests.slice(apiBindingRequestStart);
830
+ const routeFragmentBindingRequests = recorders.fragmentBindingRequests.slice(
831
+ fragmentBindingRequestStart,
832
+ );
833
+ for (const boundary of boundaries) {
834
+ assert(
835
+ boundary.status === "ready",
836
+ `${app.id} did not mark ${boundary.key} as ready for ${route}`,
837
+ );
838
+ assert(
839
+ typeof boundary.buildMarker === "string" && boundary.buildMarker.length > 0,
840
+ `${app.id} ${boundary.key} is missing immutable build provenance`,
841
+ );
842
+ assert(
843
+ /^[a-f\d]{64}$/u.test(boundary.digest ?? ""),
844
+ `${app.id} ${boundary.key} is missing a verified SHA-256 digest`,
845
+ );
846
+ const remote = apps.find((candidate) => candidate.id === boundary.remote);
847
+ assert(remote, `${app.id} rendered unknown remote ${boundary.remote}`);
848
+ const requests = routeFragmentBindingRequests.filter(
849
+ (request) =>
850
+ request.service === workerName(remote) &&
851
+ request.remote === boundary.remote &&
852
+ request.expose === boundary.expose,
853
+ );
854
+ const renderedCount = boundaries.filter(
855
+ (candidate) => candidate.key === boundary.key,
856
+ ).length;
857
+ assert(
858
+ requests.length === renderedCount &&
859
+ requests.every((request) => request.pathname.includes("/_mf/fragment/")),
860
+ `${app.id} must compose each ${boundary.key} occurrence through its remote service binding`,
861
+ );
862
+ }
863
+
864
+ const stylesheetHrefs = collectStylesheetHrefs(html);
865
+ assert(
866
+ new Set(stylesheetHrefs).size === stylesheetHrefs.length,
867
+ `${app.id} rendered duplicate distributed SSR stylesheets for ${route}`,
868
+ );
869
+ assert(
870
+ !routeOutboundRequests.some(({ url }) => /(?:remoteEntry|\.m?js(?:\?|$))/u.test(url)),
871
+ `${app.id} attempted to fetch remote JavaScript during ${route} server rendering`,
872
+ );
668
873
 
669
- const writeReport = () => {
874
+ return {
875
+ worker: workerName(app),
876
+ route,
877
+ status: response.status,
878
+ htmlBytes,
879
+ boundaries,
880
+ fragmentBindingRequests: routeFragmentBindingRequests,
881
+ apiBindingRequests: routeApiBindingRequests,
882
+ outboundRequests: routeOutboundRequests,
883
+ stylesheetHrefs,
884
+ degradedBoundaryCount: count(html, 'data-modern-distributed-ssr-status="degraded"'),
885
+ };
886
+ };
887
+
888
+ const writeReport = (reportPath, report) => {
670
889
  fs.mkdirSync(path.dirname(reportPath), { recursive: true });
671
890
  fs.writeFileSync(
672
891
  reportPath,
@@ -674,10 +893,8 @@ const writeReport = () => {
674
893
  {
675
894
  schemaVersion: 3,
676
895
  runtime: "workerd",
677
- routes: [...new Set(proofs.map((proof) => proof.route))],
678
- executions,
679
- apiProofs,
680
- proofs,
896
+ routes: [...new Set(report.proofs.map((proof) => proof.route))],
897
+ ...report,
681
898
  },
682
899
  null,
683
900
  2,
@@ -685,150 +902,125 @@ const writeReport = () => {
685
902
  );
686
903
  };
687
904
 
688
- for (const shell of shells) {
689
- const expectedRemotes = shell.verticalRefs.map((ref) => {
690
- const remote = apps.find((app) => app.id === ref);
691
- assert(remote, `${shell.id} references missing MicroVertical ${ref}`);
692
- return remote;
693
- });
694
- assert(expectedRemotes.length > 0, `${shell.id} has no MicroVerticals to prove`);
905
+ const main = async () => {
906
+ const workspaceRoot = path.resolve(process.env.ULTRAMODERN_WORKSPACE_ROOT ?? process.cwd());
907
+ const reportPath = path.join(workspaceRoot, reportRelativePath);
908
+ const keepWorkerd = process.env.ULTRAMODERN_KEEP_WORKERD === "1";
909
+ const apps = loadApps(
910
+ workspaceRoot,
911
+ readJson(path.join(workspaceRoot, "topology/reference-topology.json")),
912
+ readJson(path.join(workspaceRoot, "topology/local-overlays/development.json")),
913
+ );
914
+ const shells = apps.filter((app) => app.kind === "shell");
915
+ assert(!keepWorkerd || shells.length === 1, "Browser workerd proof requires exactly one shell");
695
916
 
696
- const apiBindingRequests = [];
917
+ const recorders = {
918
+ apiBindingRequests: [],
919
+ fragmentBindingRequests: [],
920
+ outboundRequests: [],
921
+ };
697
922
  const failedServices = new Set();
698
- const fragmentBindingRequests = [];
699
- const outboundRequests = [];
923
+ const composition = {};
700
924
  const workerConfigurations = apps.map((app) =>
701
- createWorkerOptions(app, {
702
- serviceBindings: createServiceBindings(app, {
703
- apiBindingRequests,
704
- failedServices,
705
- fragmentBindingRequests,
706
- }),
925
+ createWorkerOptions(app, workspaceRoot, {
926
+ serviceBindings: createServiceBindings(app, { ...recorders, composition, failedServices }),
707
927
  async outboundService(request) {
708
928
  const requestUrl = new URL(request.url);
709
- outboundRequests.push({ callerId: app.id, url: requestUrl.href });
929
+ recorders.outboundRequests.push({ callerId: app.id, url: requestUrl.href });
710
930
  return new Response("External network disabled by SSR proof", {
711
931
  status: 502,
712
932
  });
713
933
  },
714
934
  }),
715
935
  );
716
- executions = workerConfigurations.map((configuration) => configuration.executionEvidence);
717
- const executionByAppId = new Map(
718
- apps.map((app, index) => [app.id, executions[index]]),
719
- );
936
+ const executions = workerConfigurations.map((configuration) => configuration.executionEvidence);
937
+ const executionByAppId = new Map(apps.map((app, index) => [app.id, executions[index]]));
720
938
  const workers = workerConfigurations.map(
721
939
  ({ executionEvidence: _executionEvidence, ...configuration }) => configuration,
722
940
  );
723
- const miniflare = new Miniflare({
724
- log: new Log(LogLevel.ERROR),
725
- workers,
726
- });
727
- const renderedRemoteIds = new Set();
941
+ const miniflare = new Miniflare(
942
+ convertV4MiniflareOptions({
943
+ log: new Log(LogLevel.ERROR),
944
+ workers,
945
+ }),
946
+ );
947
+ composition.miniflare = miniflare;
948
+ const report = { executions, apiProofs: [], proofs: [], verticalProofs: [] };
728
949
 
729
950
  try {
730
- for (const route of shell.proofRoutes) {
731
- const apiBindingRequestStart = apiBindingRequests.length;
732
- const fragmentBindingRequestStart = fragmentBindingRequests.length;
733
- const outboundRequestStart = outboundRequests.length;
734
- const response = await miniflare.dispatchFetch(
735
- `https://${workerName(shell)}.invalid${route}`,
736
- { headers: { accept: "text/html" } },
737
- );
738
- const html = await response.text();
739
- assert(
740
- response.status === 200,
741
- `${shell.id} returned HTTP ${response.status} for ${route} in workerd`,
742
- );
743
- assert(
744
- !html.includes('data-modern-distributed-ssr-status="degraded"'),
745
- `${shell.id} rendered a degraded MicroVertical fallback for ${route} in workerd`,
746
- );
747
-
748
- const boundaries = collectDistributedBoundaries(html);
749
- assert(
750
- boundaries.length > 0,
751
- `${shell.id} rendered no distributed SSR boundaries for ${route}`,
752
- );
753
- const routeApiBindingRequests = apiBindingRequests.slice(
754
- apiBindingRequestStart,
755
- );
756
- const routeFragmentBindingRequests = fragmentBindingRequests.slice(
757
- fragmentBindingRequestStart,
758
- );
759
- const routeOutboundRequests = outboundRequests.slice(outboundRequestStart);
760
- for (const boundary of boundaries) {
761
- renderedRemoteIds.add(boundary.remote);
762
- assert(
763
- boundary.status === "ready",
764
- `${shell.id} did not mark ${boundary.key} as ready for ${route}`,
951
+ for (const shell of shells) {
952
+ // Shell routes compose declared server-rendered boundaries through the
953
+ // shell's entry Worker exactly as a browser request would.
954
+ const renderedRemoteIds = new Set();
955
+ for (const route of shell.ssrRoutes) {
956
+ const proof = await proveRoute(
957
+ shell,
958
+ route,
959
+ (url, init) => miniflare.dispatchFetch(url, init),
960
+ apps,
961
+ recorders,
765
962
  );
766
963
  assert(
767
- typeof boundary.buildMarker === "string" && boundary.buildMarker.length > 0,
768
- `${shell.id} ${boundary.key} is missing immutable build provenance`,
964
+ shell.serverRenderedRoutes.length > 0 || proof.boundaries.length === 0,
965
+ `${shell.id} declares client composition but rendered distributed SSR boundaries for ${route}`,
769
966
  );
967
+ if (shell.serverRenderedRoutes.includes(route)) {
968
+ assert(
969
+ shell.serverRenderedRemoteIds.length === 0 || proof.boundaries.length > 0,
970
+ `${shell.id} rendered no distributed SSR boundaries for ${route}`,
971
+ );
972
+ for (const boundary of proof.boundaries) {
973
+ renderedRemoteIds.add(boundary.remote);
974
+ }
975
+ }
976
+ report.proofs.push({ shellId: shell.id, ...proof });
977
+ }
978
+ for (const remoteId of shell.serverRenderedRemoteIds) {
770
979
  assert(
771
- /^[a-f\d]{64}$/u.test(boundary.digest ?? ""),
772
- `${shell.id} ${boundary.key} is missing a verified SHA-256 digest`,
773
- );
774
- const remote = apps.find((app) => app.id === boundary.remote);
775
- assert(remote, `${shell.id} rendered unknown remote ${boundary.remote}`);
776
- const requests = routeFragmentBindingRequests.filter(
777
- (request) =>
778
- request.service === workerName(remote) &&
779
- request.remote === boundary.remote &&
780
- request.expose === boundary.expose,
781
- );
782
- const renderedCount = boundaries.filter(
783
- (candidate) => candidate.key === boundary.key,
784
- ).length;
785
- assert(
786
- requests.length === renderedCount &&
787
- requests.every((request) => request.pathname.includes("/_mf/fragment/")),
788
- `${shell.id} must compose each ${boundary.key} occurrence through its remote service binding`,
980
+ renderedRemoteIds.has(remoteId),
981
+ `${shell.id} proof routes are missing independently rendered ${remoteId} content`,
789
982
  );
790
983
  }
791
-
792
- const stylesheetHrefs = collectStylesheetHrefs(html);
793
- assert(
794
- new Set(stylesheetHrefs).size === stylesheetHrefs.length,
795
- `${shell.id} rendered duplicate distributed SSR stylesheets for ${route}`,
984
+ report.apiProofs.push(
985
+ ...(await runApiProofs(apps, miniflare, shell, executionByAppId)),
796
986
  );
797
- assert(
798
- !routeOutboundRequests.some(({ url }) => /(?:remoteEntry|\.m?js(?:\?|$))/u.test(url)),
799
- `${shell.id} attempted to fetch remote JavaScript during ${route} server composition`,
800
- );
801
-
802
- proofs.push({
803
- shellId: shell.id,
804
- worker: workerName(shell),
805
- route,
806
- status: response.status,
807
- boundaries,
808
- fragmentBindingRequests: routeFragmentBindingRequests,
809
- apiBindingRequests: routeApiBindingRequests,
810
- outboundRequests: routeOutboundRequests,
811
- stylesheetHrefs,
812
- degradedBoundaryCount: count(html, 'data-modern-distributed-ssr-status="degraded"'),
813
- });
814
987
  }
815
988
 
816
- for (const remote of expectedRemotes) {
817
- assert(
818
- renderedRemoteIds.has(remote.id),
819
- `${shell.id} proof routes are missing independently rendered ${remote.id} content`,
820
- );
989
+ // Every UI MicroVertical proves its own Worker at its declared SSR routes,
990
+ // whether or not a shell also composes it on the server.
991
+ for (const [index, vertical] of apps.entries()) {
992
+ if (vertical.kind !== "vertical" || vertical.ssrRoutes.length === 0) {
993
+ continue;
994
+ }
995
+ const runtime = createIsolatedRuntime(workers[index]);
996
+ try {
997
+ for (const route of vertical.ssrRoutes) {
998
+ report.verticalProofs.push({
999
+ appId: vertical.id,
1000
+ ...(await proveRoute(
1001
+ vertical,
1002
+ route,
1003
+ (url, init) => runtime.dispatchFetch(url, init),
1004
+ apps,
1005
+ recorders,
1006
+ )),
1007
+ });
1008
+ }
1009
+ } finally {
1010
+ await runtime.dispose();
1011
+ }
821
1012
  }
822
- apiProofs.push(...(await runApiProofs(miniflare, shell, executionByAppId)));
823
- if (process.env.ULTRAMODERN_KEEP_WORKERD === "1") {
824
- writeReport();
1013
+
1014
+ writeReport(reportPath, report);
1015
+ if (keepWorkerd) {
825
1016
  const targetServers = await startWorkerdTargetServers(
1017
+ apps,
826
1018
  miniflare,
827
1019
  failedServices,
828
1020
  workers,
829
1021
  );
830
1022
  console.log(`WORKERD_TARGET_URLS=${JSON.stringify(targetServers.targetUrls)}`);
831
- console.log(`WORKERD_URL=${targetServers.targetUrls[shell.id]}`);
1023
+ console.log(`WORKERD_URL=${targetServers.targetUrls[shells[0].id]}`);
832
1024
  try {
833
1025
  await new Promise((resolve) => {
834
1026
  process.once("SIGINT", resolve);
@@ -841,7 +1033,10 @@ for (const shell of shells) {
841
1033
  } finally {
842
1034
  await miniflare.dispose();
843
1035
  }
844
- }
845
1036
 
846
- writeReport();
847
- console.log(`Workerd SSR composition proof passed for ${shells.length} shell(s): ${reportPath}`);
1037
+ console.log(`Workerd SSR composition proof passed for ${shells.length} shell(s): ${reportPath}`);
1038
+ };
1039
+
1040
+ if (import.meta.main) {
1041
+ await main();
1042
+ }