every-plugin 2.10.0 → 3.0.0-rc.0

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 (462) hide show
  1. package/bin/every-plugin-serve.mjs +12 -0
  2. package/bin/every-plugin.mjs +59 -0
  3. package/dist/_virtual/_rolldown/runtime.cjs +1 -2
  4. package/dist/build/artifact-names.cjs +119 -0
  5. package/dist/build/artifact-names.cjs.map +1 -0
  6. package/dist/build/artifact-names.d.cts +68 -0
  7. package/dist/build/artifact-names.d.cts.map +1 -0
  8. package/dist/build/artifact-names.d.mts +68 -0
  9. package/dist/build/artifact-names.d.mts.map +1 -0
  10. package/dist/build/artifact-names.mjs +102 -0
  11. package/dist/build/artifact-names.mjs.map +1 -0
  12. package/dist/build/contract-types.cjs +89 -0
  13. package/dist/build/contract-types.cjs.map +1 -0
  14. package/dist/build/contract-types.mjs +81 -0
  15. package/dist/build/contract-types.mjs.map +1 -0
  16. package/dist/build/rspack/build-report-plugin.cjs +37 -0
  17. package/dist/build/rspack/build-report-plugin.cjs.map +1 -0
  18. package/dist/build/rspack/build-report-plugin.d.cts +18 -0
  19. package/dist/build/rspack/build-report-plugin.d.cts.map +1 -0
  20. package/dist/build/rspack/build-report-plugin.d.mts +18 -0
  21. package/dist/build/rspack/build-report-plugin.d.mts.map +1 -0
  22. package/dist/build/rspack/build-report-plugin.mjs +37 -0
  23. package/dist/build/rspack/build-report-plugin.mjs.map +1 -0
  24. package/dist/build/rspack/chunk-completeness-plugin.cjs +47 -0
  25. package/dist/build/rspack/chunk-completeness-plugin.cjs.map +1 -0
  26. package/dist/build/rspack/chunk-completeness-plugin.mjs +47 -0
  27. package/dist/build/rspack/chunk-completeness-plugin.mjs.map +1 -0
  28. package/dist/build/rspack/compose.cjs +69 -0
  29. package/dist/build/rspack/compose.cjs.map +1 -0
  30. package/dist/build/rspack/compose.d.cts +20 -0
  31. package/dist/build/rspack/compose.d.cts.map +1 -0
  32. package/dist/build/rspack/compose.d.mts +20 -0
  33. package/dist/build/rspack/compose.d.mts.map +1 -0
  34. package/dist/build/rspack/compose.mjs +65 -0
  35. package/dist/build/rspack/compose.mjs.map +1 -0
  36. package/dist/build/rspack/fix-mf-data-uri-plugin.cjs +11 -11
  37. package/dist/build/rspack/fix-mf-data-uri-plugin.cjs.map +1 -1
  38. package/dist/build/rspack/fix-mf-data-uri-plugin.d.cts +2 -0
  39. package/dist/build/rspack/fix-mf-data-uri-plugin.d.cts.map +1 -1
  40. package/dist/build/rspack/fix-mf-data-uri-plugin.d.mts +2 -0
  41. package/dist/build/rspack/fix-mf-data-uri-plugin.d.mts.map +1 -1
  42. package/dist/build/rspack/fix-mf-data-uri-plugin.mjs +11 -10
  43. package/dist/build/rspack/fix-mf-data-uri-plugin.mjs.map +1 -1
  44. package/dist/build/rspack/generated-config.cjs +35 -0
  45. package/dist/build/rspack/generated-config.cjs.map +1 -0
  46. package/dist/build/rspack/generated-config.mjs +32 -0
  47. package/dist/build/rspack/generated-config.mjs.map +1 -0
  48. package/dist/build/rspack/index.cjs +8 -5
  49. package/dist/build/rspack/index.d.cts +5 -3
  50. package/dist/build/rspack/index.d.mts +5 -3
  51. package/dist/build/rspack/index.mjs +5 -3
  52. package/dist/build/rspack/module-federation.cjs +2 -2
  53. package/dist/build/rspack/module-federation.cjs.map +1 -1
  54. package/dist/build/rspack/module-federation.mjs +1 -1
  55. package/dist/build/rspack/module-federation.mjs.map +1 -1
  56. package/dist/build/rspack/plugin.cjs +44 -69
  57. package/dist/build/rspack/plugin.cjs.map +1 -1
  58. package/dist/build/rspack/plugin.d.cts +4 -13
  59. package/dist/build/rspack/plugin.d.cts.map +1 -1
  60. package/dist/build/rspack/plugin.d.mts +4 -13
  61. package/dist/build/rspack/plugin.d.mts.map +1 -1
  62. package/dist/build/rspack/plugin.mjs +44 -69
  63. package/dist/build/rspack/plugin.mjs.map +1 -1
  64. package/dist/build/rspack/utils.cjs +7 -5
  65. package/dist/build/rspack/utils.cjs.map +1 -1
  66. package/dist/build/rspack/utils.mjs +7 -6
  67. package/dist/build/rspack/utils.mjs.map +1 -1
  68. package/dist/build/ui/factory.cjs +88 -0
  69. package/dist/build/ui/factory.cjs.map +1 -0
  70. package/dist/build/ui/factory.d.cts +11 -0
  71. package/dist/build/ui/factory.d.cts.map +1 -0
  72. package/dist/build/ui/factory.d.mts +11 -0
  73. package/dist/build/ui/factory.d.mts.map +1 -0
  74. package/dist/build/ui/factory.mjs +80 -0
  75. package/dist/build/ui/factory.mjs.map +1 -0
  76. package/dist/build/ui/generated-config.cjs +118 -0
  77. package/dist/build/ui/generated-config.cjs.map +1 -0
  78. package/dist/build/ui/generated-config.d.cts +33 -0
  79. package/dist/build/ui/generated-config.d.cts.map +1 -0
  80. package/dist/build/ui/generated-config.d.mts +33 -0
  81. package/dist/build/ui/generated-config.d.mts.map +1 -0
  82. package/dist/build/ui/generated-config.mjs +111 -0
  83. package/dist/build/ui/generated-config.mjs.map +1 -0
  84. package/dist/build/ui/hash-artifacts-plugin.cjs +61 -0
  85. package/dist/build/ui/hash-artifacts-plugin.cjs.map +1 -0
  86. package/dist/build/ui/hash-artifacts-plugin.d.cts +20 -0
  87. package/dist/build/ui/hash-artifacts-plugin.d.cts.map +1 -0
  88. package/dist/build/ui/hash-artifacts-plugin.d.mts +20 -0
  89. package/dist/build/ui/hash-artifacts-plugin.d.mts.map +1 -0
  90. package/dist/build/ui/hash-artifacts-plugin.mjs +58 -0
  91. package/dist/build/ui/hash-artifacts-plugin.mjs.map +1 -0
  92. package/dist/build/ui/index.cjs +90 -0
  93. package/dist/build/ui/index.cjs.map +1 -0
  94. package/dist/build/ui/index.d.cts +29 -0
  95. package/dist/build/ui/index.d.cts.map +1 -0
  96. package/dist/build/ui/index.d.mts +29 -0
  97. package/dist/build/ui/index.d.mts.map +1 -0
  98. package/dist/build/ui/index.mjs +68 -0
  99. package/dist/build/ui/index.mjs.map +1 -0
  100. package/dist/build/ui/manifest-plugin.cjs +37 -0
  101. package/dist/build/ui/manifest-plugin.cjs.map +1 -0
  102. package/dist/build/ui/manifest-plugin.d.cts +19 -0
  103. package/dist/build/ui/manifest-plugin.d.cts.map +1 -0
  104. package/dist/build/ui/manifest-plugin.d.mts +19 -0
  105. package/dist/build/ui/manifest-plugin.d.mts.map +1 -0
  106. package/dist/build/ui/manifest-plugin.mjs +37 -0
  107. package/dist/build/ui/manifest-plugin.mjs.map +1 -0
  108. package/dist/build/ui/rsbuild-config.cjs +203 -0
  109. package/dist/build/ui/rsbuild-config.cjs.map +1 -0
  110. package/dist/build/ui/rsbuild-config.d.cts +45 -0
  111. package/dist/build/ui/rsbuild-config.d.cts.map +1 -0
  112. package/dist/build/ui/rsbuild-config.d.mts +45 -0
  113. package/dist/build/ui/rsbuild-config.d.mts.map +1 -0
  114. package/dist/build/ui/rsbuild-config.mjs +200 -0
  115. package/dist/build/ui/rsbuild-config.mjs.map +1 -0
  116. package/dist/build/ui/stubs.cjs +107 -0
  117. package/dist/build/ui/stubs.cjs.map +1 -0
  118. package/dist/build/ui/stubs.d.cts +25 -0
  119. package/dist/build/ui/stubs.d.cts.map +1 -0
  120. package/dist/build/ui/stubs.d.mts +25 -0
  121. package/dist/build/ui/stubs.d.mts.map +1 -0
  122. package/dist/build/ui/stubs.mjs +106 -0
  123. package/dist/build/ui/stubs.mjs.map +1 -0
  124. package/dist/cli.cjs +83 -0
  125. package/dist/cli.cjs.map +1 -0
  126. package/dist/cli.d.cts +6 -0
  127. package/dist/cli.d.cts.map +1 -0
  128. package/dist/cli.d.mts +6 -0
  129. package/dist/cli.d.mts.map +1 -0
  130. package/dist/cli.mjs +82 -0
  131. package/dist/cli.mjs.map +1 -0
  132. package/dist/dev/serve.cjs +390 -0
  133. package/dist/dev/serve.cjs.map +1 -0
  134. package/dist/dev/serve.d.cts +23 -0
  135. package/dist/dev/serve.d.cts.map +1 -0
  136. package/dist/dev/serve.d.mts +23 -0
  137. package/dist/dev/serve.d.mts.map +1 -0
  138. package/dist/dev/serve.mjs +384 -0
  139. package/dist/dev/serve.mjs.map +1 -0
  140. package/dist/dev/watch-kill.cjs +39 -0
  141. package/dist/dev/watch-kill.cjs.map +1 -0
  142. package/dist/dev/watch-kill.mjs +38 -0
  143. package/dist/dev/watch-kill.mjs.map +1 -0
  144. package/dist/effect-helpers.cjs +23 -0
  145. package/dist/effect-helpers.cjs.map +1 -0
  146. package/dist/effect-helpers.d.cts +20 -0
  147. package/dist/effect-helpers.d.cts.map +1 -0
  148. package/dist/effect-helpers.d.mts +20 -0
  149. package/dist/effect-helpers.d.mts.map +1 -0
  150. package/dist/effect-helpers.mjs +22 -0
  151. package/dist/effect-helpers.mjs.map +1 -0
  152. package/dist/errors.cjs +49 -69
  153. package/dist/errors.cjs.map +1 -1
  154. package/dist/errors.d.cts +13 -96
  155. package/dist/errors.d.cts.map +1 -1
  156. package/dist/errors.d.mts +13 -96
  157. package/dist/errors.d.mts.map +1 -1
  158. package/dist/errors.mjs +16 -34
  159. package/dist/errors.mjs.map +1 -1
  160. package/dist/identity.cjs +19 -0
  161. package/dist/identity.cjs.map +1 -0
  162. package/dist/identity.d.cts +33 -0
  163. package/dist/identity.d.cts.map +1 -0
  164. package/dist/identity.d.mts +33 -0
  165. package/dist/identity.d.mts.map +1 -0
  166. package/dist/identity.mjs +16 -0
  167. package/dist/identity.mjs.map +1 -0
  168. package/dist/index.cjs +8 -5
  169. package/dist/index.d.cts +8 -6
  170. package/dist/index.d.mts +8 -6
  171. package/dist/index.mjs +6 -4
  172. package/dist/plugin.cjs +12 -26
  173. package/dist/plugin.cjs.map +1 -1
  174. package/dist/plugin.d.cts +44 -25
  175. package/dist/plugin.d.cts.map +1 -1
  176. package/dist/plugin.d.mts +45 -26
  177. package/dist/plugin.d.mts.map +1 -1
  178. package/dist/plugin.mjs +15 -29
  179. package/dist/plugin.mjs.map +1 -1
  180. package/dist/remote-entry.cjs +103 -0
  181. package/dist/remote-entry.cjs.map +1 -0
  182. package/dist/remote-entry.d.cts +53 -0
  183. package/dist/remote-entry.d.cts.map +1 -0
  184. package/dist/remote-entry.d.mts +53 -0
  185. package/dist/remote-entry.d.mts.map +1 -0
  186. package/dist/remote-entry.mjs +98 -0
  187. package/dist/remote-entry.mjs.map +1 -0
  188. package/dist/runtime/errors.cjs +140 -34
  189. package/dist/runtime/errors.cjs.map +1 -1
  190. package/dist/runtime/errors.d.cts +42 -7
  191. package/dist/runtime/errors.d.cts.map +1 -1
  192. package/dist/runtime/errors.d.mts +42 -7
  193. package/dist/runtime/errors.d.mts.map +1 -1
  194. package/dist/runtime/errors.mjs +136 -31
  195. package/dist/runtime/errors.mjs.map +1 -1
  196. package/dist/runtime/index.cjs +95 -23
  197. package/dist/runtime/index.cjs.map +1 -1
  198. package/dist/runtime/index.d.cts +16 -0
  199. package/dist/runtime/index.d.cts.map +1 -1
  200. package/dist/runtime/index.d.mts +16 -0
  201. package/dist/runtime/index.d.mts.map +1 -1
  202. package/dist/runtime/index.mjs +98 -26
  203. package/dist/runtime/index.mjs.map +1 -1
  204. package/dist/runtime/mf-config.cjs +3 -78
  205. package/dist/runtime/mf-config.cjs.map +1 -1
  206. package/dist/runtime/mf-config.d.cts +3 -49
  207. package/dist/runtime/mf-config.d.cts.map +1 -1
  208. package/dist/runtime/mf-config.d.mts +3 -49
  209. package/dist/runtime/mf-config.d.mts.map +1 -1
  210. package/dist/runtime/mf-config.mjs +5 -78
  211. package/dist/runtime/mf-config.mjs.map +1 -1
  212. package/dist/runtime/services/module-federation.service.cjs +63 -12
  213. package/dist/runtime/services/module-federation.service.cjs.map +1 -1
  214. package/dist/runtime/services/module-federation.service.d.cts +4 -13
  215. package/dist/runtime/services/module-federation.service.d.mts +4 -13
  216. package/dist/runtime/services/module-federation.service.mjs +63 -14
  217. package/dist/runtime/services/module-federation.service.mjs.map +1 -1
  218. package/dist/runtime/services/normalize.cjs +2 -22
  219. package/dist/runtime/services/normalize.d.cts +2 -21
  220. package/dist/runtime/services/normalize.d.mts +2 -21
  221. package/dist/runtime/services/normalize.mjs +2 -21
  222. package/dist/runtime/services/plugin-lifecycle.service.cjs +9 -11
  223. package/dist/runtime/services/plugin-lifecycle.service.cjs.map +1 -1
  224. package/dist/runtime/services/plugin-lifecycle.service.d.cts +3 -16
  225. package/dist/runtime/services/plugin-lifecycle.service.d.mts +3 -16
  226. package/dist/runtime/services/plugin-lifecycle.service.mjs +10 -13
  227. package/dist/runtime/services/plugin-lifecycle.service.mjs.map +1 -1
  228. package/dist/runtime/services/plugin-loader.service.cjs +30 -29
  229. package/dist/runtime/services/plugin-loader.service.cjs.map +1 -1
  230. package/dist/runtime/services/plugin-loader.service.d.cts +6 -53
  231. package/dist/runtime/services/plugin-loader.service.d.mts +6 -53
  232. package/dist/runtime/services/plugin-loader.service.mjs +29 -30
  233. package/dist/runtime/services/plugin-loader.service.mjs.map +1 -1
  234. package/dist/runtime/services/plugin.service.cjs +10 -12
  235. package/dist/runtime/services/plugin.service.cjs.map +1 -1
  236. package/dist/runtime/services/plugin.service.d.cts +14 -36
  237. package/dist/runtime/services/plugin.service.d.cts.map +1 -1
  238. package/dist/runtime/services/plugin.service.d.mts +14 -36
  239. package/dist/runtime/services/plugin.service.d.mts.map +1 -1
  240. package/dist/runtime/services/plugin.service.mjs +14 -18
  241. package/dist/runtime/services/plugin.service.mjs.map +1 -1
  242. package/dist/runtime/services/secrets.service.cjs +12 -12
  243. package/dist/runtime/services/secrets.service.cjs.map +1 -1
  244. package/dist/runtime/services/secrets.service.d.cts +3 -15
  245. package/dist/runtime/services/secrets.service.d.mts +3 -15
  246. package/dist/runtime/services/secrets.service.mjs +12 -13
  247. package/dist/runtime/services/secrets.service.mjs.map +1 -1
  248. package/dist/runtime/services/shared-identity.cjs +40 -0
  249. package/dist/runtime/services/shared-identity.cjs.map +1 -0
  250. package/dist/runtime/services/shared-identity.mjs +38 -0
  251. package/dist/runtime/services/shared-identity.mjs.map +1 -0
  252. package/dist/runtime/validation.cjs +2 -2
  253. package/dist/runtime/validation.cjs.map +1 -1
  254. package/dist/runtime/validation.mjs +2 -2
  255. package/dist/runtime/validation.mjs.map +1 -1
  256. package/dist/shared-deps-spec.cjs +384 -0
  257. package/dist/shared-deps-spec.cjs.map +1 -0
  258. package/dist/shared-deps-spec.d.cts +182 -0
  259. package/dist/shared-deps-spec.d.cts.map +1 -0
  260. package/dist/shared-deps-spec.d.mts +182 -0
  261. package/dist/shared-deps-spec.d.mts.map +1 -0
  262. package/dist/shared-deps-spec.mjs +368 -0
  263. package/dist/shared-deps-spec.mjs.map +1 -0
  264. package/dist/types.d.cts +22 -41
  265. package/dist/types.d.cts.map +1 -1
  266. package/dist/types.d.mts +22 -41
  267. package/dist/types.d.mts.map +1 -1
  268. package/dist/ui/manifest/construct.cjs +268 -0
  269. package/dist/ui/manifest/construct.cjs.map +1 -0
  270. package/dist/ui/manifest/construct.d.cts +48 -0
  271. package/dist/ui/manifest/construct.d.cts.map +1 -0
  272. package/dist/ui/manifest/construct.d.mts +48 -0
  273. package/dist/ui/manifest/construct.d.mts.map +1 -0
  274. package/dist/ui/manifest/construct.mjs +268 -0
  275. package/dist/ui/manifest/construct.mjs.map +1 -0
  276. package/dist/ui/manifest/contract.cjs +34 -0
  277. package/dist/ui/manifest/contract.cjs.map +1 -0
  278. package/dist/ui/manifest/contract.d.cts +26 -0
  279. package/dist/ui/manifest/contract.d.cts.map +1 -0
  280. package/dist/ui/manifest/contract.d.mts +26 -0
  281. package/dist/ui/manifest/contract.d.mts.map +1 -0
  282. package/dist/ui/manifest/contract.mjs +26 -0
  283. package/dist/ui/manifest/contract.mjs.map +1 -0
  284. package/dist/ui/manifest/descriptor.cjs +64 -0
  285. package/dist/ui/manifest/descriptor.cjs.map +1 -0
  286. package/dist/ui/manifest/descriptor.d.cts +60 -0
  287. package/dist/ui/manifest/descriptor.d.cts.map +1 -0
  288. package/dist/ui/manifest/descriptor.d.mts +60 -0
  289. package/dist/ui/manifest/descriptor.d.mts.map +1 -0
  290. package/dist/ui/manifest/descriptor.mjs +61 -0
  291. package/dist/ui/manifest/descriptor.mjs.map +1 -0
  292. package/dist/ui/manifest/generator.cjs +128 -0
  293. package/dist/ui/manifest/generator.cjs.map +1 -0
  294. package/dist/ui/manifest/generator.d.cts +41 -0
  295. package/dist/ui/manifest/generator.d.cts.map +1 -0
  296. package/dist/ui/manifest/generator.d.mts +41 -0
  297. package/dist/ui/manifest/generator.d.mts.map +1 -0
  298. package/dist/ui/manifest/generator.mjs +125 -0
  299. package/dist/ui/manifest/generator.mjs.map +1 -0
  300. package/dist/ui/manifest/index.cjs +35 -0
  301. package/dist/ui/manifest/index.d.cts +9 -0
  302. package/dist/ui/manifest/index.d.mts +9 -0
  303. package/dist/ui/manifest/index.mjs +9 -0
  304. package/dist/ui/manifest/manifest-schema.cjs +97 -0
  305. package/dist/ui/manifest/manifest-schema.cjs.map +1 -0
  306. package/dist/ui/manifest/manifest-schema.d.cts +132 -0
  307. package/dist/ui/manifest/manifest-schema.d.cts.map +1 -0
  308. package/dist/ui/manifest/manifest-schema.d.mts +132 -0
  309. package/dist/ui/manifest/manifest-schema.d.mts.map +1 -0
  310. package/dist/ui/manifest/manifest-schema.mjs +90 -0
  311. package/dist/ui/manifest/manifest-schema.mjs.map +1 -0
  312. package/dist/ui/manifest/mount-registry.cjs +52 -0
  313. package/dist/ui/manifest/mount-registry.cjs.map +1 -0
  314. package/dist/ui/manifest/mount-registry.d.cts +61 -0
  315. package/dist/ui/manifest/mount-registry.d.cts.map +1 -0
  316. package/dist/ui/manifest/mount-registry.d.mts +61 -0
  317. package/dist/ui/manifest/mount-registry.d.mts.map +1 -0
  318. package/dist/ui/manifest/mount-registry.mjs +48 -0
  319. package/dist/ui/manifest/mount-registry.mjs.map +1 -0
  320. package/dist/ui/manifest/nav.cjs +13 -0
  321. package/dist/ui/manifest/nav.cjs.map +1 -0
  322. package/dist/ui/manifest/nav.d.cts +34 -0
  323. package/dist/ui/manifest/nav.d.cts.map +1 -0
  324. package/dist/ui/manifest/nav.d.mts +34 -0
  325. package/dist/ui/manifest/nav.d.mts.map +1 -0
  326. package/dist/ui/manifest/nav.mjs +13 -0
  327. package/dist/ui/manifest/nav.mjs.map +1 -0
  328. package/dist/ui/manifest/route-config.cjs +33 -0
  329. package/dist/ui/manifest/route-config.cjs.map +1 -0
  330. package/dist/ui/manifest/route-config.d.cts +40 -0
  331. package/dist/ui/manifest/route-config.d.cts.map +1 -0
  332. package/dist/ui/manifest/route-config.d.mts +40 -0
  333. package/dist/ui/manifest/route-config.d.mts.map +1 -0
  334. package/dist/ui/manifest/route-config.mjs +33 -0
  335. package/dist/ui/manifest/route-config.mjs.map +1 -0
  336. package/dist/version-manifest.cjs +65 -0
  337. package/dist/version-manifest.cjs.map +1 -0
  338. package/dist/version-manifest.d.cts +52 -0
  339. package/dist/version-manifest.d.cts.map +1 -0
  340. package/dist/version-manifest.d.mts +52 -0
  341. package/dist/version-manifest.d.mts.map +1 -0
  342. package/dist/version-manifest.mjs +63 -0
  343. package/dist/version-manifest.mjs.map +1 -0
  344. package/package.json +165 -68
  345. package/skills/plugin-client/SKILL.md +24 -5
  346. package/skills/plugin-development/SKILL.md +79 -47
  347. package/skills/plugin-testing/SKILL.md +41 -12
  348. package/src/build/artifact-names.ts +117 -0
  349. package/src/build/contract-types.ts +101 -0
  350. package/src/build/rspack/build-report-plugin.ts +34 -0
  351. package/src/build/rspack/chunk-completeness-plugin.ts +57 -0
  352. package/src/build/rspack/compose.ts +87 -0
  353. package/src/build/rspack/fix-mf-data-uri-plugin.ts +23 -12
  354. package/src/build/rspack/generated-config.ts +35 -0
  355. package/src/build/rspack/index.ts +10 -5
  356. package/src/build/rspack/module-federation.ts +1 -1
  357. package/src/build/rspack/plugin.ts +103 -105
  358. package/src/build/rspack/utils.ts +8 -2
  359. package/src/build/ui/factory.ts +96 -0
  360. package/src/build/ui/generated-config.ts +133 -0
  361. package/src/build/ui/hash-artifacts-plugin.ts +79 -0
  362. package/src/build/ui/index.ts +98 -0
  363. package/src/build/ui/manifest-plugin.ts +54 -0
  364. package/src/build/ui/rsbuild-config.ts +256 -0
  365. package/src/build/ui/stubs.ts +103 -0
  366. package/src/cli.ts +100 -0
  367. package/src/dev/serve.ts +477 -0
  368. package/src/dev/watch-kill.ts +58 -0
  369. package/src/effect-helpers.ts +25 -0
  370. package/src/errors.ts +16 -18
  371. package/src/identity.ts +36 -0
  372. package/src/index.ts +4 -0
  373. package/src/plugin.ts +70 -92
  374. package/src/remote-entry.ts +171 -0
  375. package/src/runtime/errors.ts +186 -27
  376. package/src/runtime/index.ts +132 -43
  377. package/src/runtime/mf-config.ts +12 -107
  378. package/src/runtime/services/module-federation.service.ts +221 -117
  379. package/src/runtime/services/normalize.ts +1 -18
  380. package/src/runtime/services/plugin-lifecycle.service.ts +66 -75
  381. package/src/runtime/services/plugin-loader.service.ts +239 -212
  382. package/src/runtime/services/plugin.service.ts +61 -43
  383. package/src/runtime/services/secrets.service.ts +20 -15
  384. package/src/runtime/services/shared-identity.ts +68 -0
  385. package/src/runtime/validation.ts +5 -7
  386. package/src/shared-deps-spec.ts +478 -0
  387. package/src/types.ts +22 -48
  388. package/src/ui/manifest/construct.ts +403 -0
  389. package/src/ui/manifest/contract.ts +33 -0
  390. package/src/ui/manifest/descriptor.ts +96 -0
  391. package/src/ui/manifest/generator.ts +238 -0
  392. package/src/ui/manifest/index.ts +55 -0
  393. package/src/ui/manifest/manifest-schema.ts +107 -0
  394. package/src/ui/manifest/mount-registry.ts +50 -0
  395. package/src/ui/manifest/nav.ts +43 -0
  396. package/src/ui/manifest/route-config.ts +82 -0
  397. package/src/version-manifest.ts +88 -0
  398. package/dist/build/rspack/dev-server-middleware.cjs +0 -194
  399. package/dist/build/rspack/dev-server-middleware.cjs.map +0 -1
  400. package/dist/build/rspack/dev-server-middleware.mjs +0 -193
  401. package/dist/build/rspack/dev-server-middleware.mjs.map +0 -1
  402. package/dist/build/shared-deps.cjs +0 -83
  403. package/dist/build/shared-deps.cjs.map +0 -1
  404. package/dist/build/shared-deps.d.cts +0 -67
  405. package/dist/build/shared-deps.d.cts.map +0 -1
  406. package/dist/build/shared-deps.d.mts +0 -67
  407. package/dist/build/shared-deps.d.mts.map +0 -1
  408. package/dist/build/shared-deps.mjs +0 -79
  409. package/dist/build/shared-deps.mjs.map +0 -1
  410. package/dist/effect.cjs +0 -9
  411. package/dist/effect.d.cts +0 -1
  412. package/dist/effect.d.mts +0 -1
  413. package/dist/effect.mjs +0 -3
  414. package/dist/orpc-openapi.cjs +0 -17
  415. package/dist/orpc-openapi.d.cts +0 -2
  416. package/dist/orpc-openapi.d.mts +0 -2
  417. package/dist/orpc-openapi.mjs +0 -5
  418. package/dist/orpc.cjs +0 -46
  419. package/dist/orpc.d.cts +0 -7
  420. package/dist/orpc.d.mts +0 -7
  421. package/dist/orpc.mjs +0 -11
  422. package/dist/package.cjs +0 -23
  423. package/dist/package.cjs.map +0 -1
  424. package/dist/package.mjs +0 -17
  425. package/dist/package.mjs.map +0 -1
  426. package/dist/runtime/services/module-federation.service.d.cts.map +0 -1
  427. package/dist/runtime/services/module-federation.service.d.mts.map +0 -1
  428. package/dist/runtime/services/normalize.cjs.map +0 -1
  429. package/dist/runtime/services/normalize.d.cts.map +0 -1
  430. package/dist/runtime/services/normalize.d.mts.map +0 -1
  431. package/dist/runtime/services/normalize.mjs.map +0 -1
  432. package/dist/runtime/services/plugin-lifecycle.service.d.cts.map +0 -1
  433. package/dist/runtime/services/plugin-lifecycle.service.d.mts.map +0 -1
  434. package/dist/runtime/services/plugin-loader.service.d.cts.map +0 -1
  435. package/dist/runtime/services/plugin-loader.service.d.mts.map +0 -1
  436. package/dist/runtime/services/secrets.service.d.cts.map +0 -1
  437. package/dist/runtime/services/secrets.service.d.mts.map +0 -1
  438. package/dist/testing/index.cjs +0 -57
  439. package/dist/testing/index.cjs.map +0 -1
  440. package/dist/testing/index.d.cts +0 -54
  441. package/dist/testing/index.d.cts.map +0 -1
  442. package/dist/testing/index.d.mts +0 -54
  443. package/dist/testing/index.d.mts.map +0 -1
  444. package/dist/testing/index.mjs +0 -55
  445. package/dist/testing/index.mjs.map +0 -1
  446. package/dist/zod-core.cjs +0 -9
  447. package/dist/zod-core.d.cts +0 -1
  448. package/dist/zod-core.d.mts +0 -1
  449. package/dist/zod-core.mjs +0 -3
  450. package/dist/zod.cjs +0 -11
  451. package/dist/zod.d.cts +0 -2
  452. package/dist/zod.d.mts +0 -2
  453. package/dist/zod.mjs +0 -3
  454. package/src/build/rspack/dev-server-middleware.ts +0 -250
  455. package/src/build/shared-deps.ts +0 -102
  456. package/src/effect.ts +0 -1
  457. package/src/orpc-openapi.ts +0 -2
  458. package/src/orpc.ts +0 -9
  459. package/src/testing/index.ts +0 -87
  460. package/src/testing/mocks/module-federation.service.ts +0 -41
  461. package/src/zod-core.ts +0 -1
  462. package/src/zod.ts +0 -3
@@ -2,7 +2,7 @@
2
2
  name: plugin-development
3
3
  description: Build every-plugin modules with oRPC contracts, Effect services, and Module Federation. Use when creating or modifying plugins under plugins/ or the _template scaffold.
4
4
  metadata:
5
- sources: "src/plugin.ts,src/orpc.ts,src/errors.ts,src/zod.ts,src/types.ts"
5
+ sources: "src/plugin.ts,src/errors.ts,src/types.ts,src/runtime/errors.ts,src/runtime/services/module-federation.service.ts,src/runtime/index.ts,plugins/_template/src/index.ts"
6
6
  ---
7
7
 
8
8
  # every-plugin Development
@@ -24,13 +24,13 @@ plugins/your-plugin/
24
24
  └── tsconfig.json
25
25
  ```
26
26
 
27
- ## Step 1: Define the Contract
27
+ Import `zod`, `effect`, and `@orpc/*` directly — the `every-plugin/zod`, `every-plugin/orpc`, and `every-plugin/effect` facade barrels no longer exist. The build pins zod via the workspace catalog, so version skew between plugin and framework is not a concern.
28
28
 
29
- Import from `every-plugin` subpath exports — not from `@orpc/*` or `zod` directly:
29
+ ## Step 1: Define the Contract
30
30
 
31
31
  ```typescript
32
- import { eventIterator, oc } from "every-plugin/orpc";
33
- import { z } from "every-plugin/zod";
32
+ import { eventIterator, oc } from "@orpc/contract";
33
+ import { z } from "zod";
34
34
 
35
35
  const Errors = {
36
36
  UNAUTHORIZED: { status: 401, message: "Auth required" },
@@ -58,17 +58,17 @@ export type ContractType = typeof contract;
58
58
  ```
59
59
 
60
60
  Key points:
61
- - Always import `oc` from `every-plugin/orpc`, `z` from `every-plugin/zod`, `Effect` from `every-plugin/effect`
61
+ - Import `oc`/`eventIterator` from `@orpc/contract`, `z` from `zod`, `Effect`/`Layer`/`Context` from `effect`
62
62
  - Use `eventIterator(schema)` for streaming responses
63
63
  - Define error objects with `status` + `message` and pass via `.errors()`
64
- - Use `CommonPluginErrors` from `every-plugin/errors` for standard UNAUTHORIZED/FORBIDDEN/NOT_FOUND/BAD_REQUEST
64
+ - Use `PluginErrors` from `every-plugin/errors` for standard UNAUTHORIZED/FORBIDDEN/NOT_FOUND/BAD_REQUEST
65
65
 
66
66
  ## Step 2: Create the Service
67
67
 
68
68
  Plain TypeScript class with Effect error handling:
69
69
 
70
70
  ```typescript
71
- import { Effect } from "every-plugin/effect";
71
+ import { Effect } from "effect";
72
72
 
73
73
  export class MyService {
74
74
  constructor(private baseUrl: string, private apiKey: string) {}
@@ -93,10 +93,10 @@ export class MyService {
93
93
  ## Step 3: Wire with createPlugin
94
94
 
95
95
  ```typescript
96
+ import { ORPCError } from "@orpc/server";
97
+ import { Effect, Layer } from "effect";
96
98
  import { createPlugin } from "every-plugin";
97
- import { Effect } from "every-plugin/effect";
98
- import { ORPCError } from "every-plugin/orpc";
99
- import { z } from "every-plugin/zod";
99
+ import { z } from "zod";
100
100
  import { contract } from "./contract";
101
101
  import { MyService } from "./service";
102
102
 
@@ -109,35 +109,37 @@ export default createPlugin({
109
109
  }),
110
110
  contract,
111
111
 
112
- initialize: (config, _plugins, tools) =>
112
+ initialize: (config, _plugins) =>
113
113
  Effect.gen(function* () {
114
114
  const service = new MyService(config.variables.baseUrl, config.secrets.apiKey);
115
115
  yield* service.ping();
116
- return { service };
117
- }),
118
116
 
119
- shutdown: () => Effect.void,
120
-
121
- createRouter: (deps, builder) => {
122
- const { service } = deps;
117
+ return Layer.succeed(MyServiceTag, service);
118
+ }),
123
119
 
124
- const requireAuth = builder.middleware(async ({ context, next }) => {
125
- if (!context.userId) throw new ORPCError("UNAUTHORIZED", { message: "Auth required" });
126
- return next({ context: { ...context, userId: context.userId } });
127
- });
120
+ createRouter: (builder) => ({
121
+ getById: builder.getById.effect(function* ({ input, context, errors }) {
122
+ if (!context.userId) {
123
+ return yield* Effect.fail(errors.UNAUTHORIZED({ message: "Auth required" }));
124
+ }
125
+ const service = yield* MyServiceTag;
126
+ return yield* service.getById(input.id);
127
+ }),
128
128
 
129
- return {
130
- getById: builder.getById.use(requireAuth).handler(async ({ input, context }) => {
131
- return await Effect.runPromise(service.getById(input.id));
132
- }),
133
- ping: builder.ping.handler(async () => {
134
- return await Effect.runPromise(service.ping());
135
- }),
136
- };
137
- },
129
+ ping: builder.ping.effect(function* () {
130
+ const service = yield* MyServiceTag;
131
+ return yield* service.ping();
132
+ }),
133
+ }),
138
134
  });
139
135
  ```
140
136
 
137
+ Key points:
138
+ - `initialize` returns an `Effect` producing a `Layer` — services built in it are provided to `.effect()` handlers via the plugin's lifecycle scope
139
+ - Teardown lives in Layer finalizers — there is no `shutdown` option
140
+ - Handlers access services with `yield* Tag` (Effect-native generators)
141
+ - For streaming handlers (async generators), use `Context.get(context["effect/context"], Tag)`
142
+
141
143
  ## Plugin Composition (withPlugins)
142
144
 
143
145
  When an API plugin needs to call other plugins in-process:
@@ -148,9 +150,9 @@ import type { PluginsClient } from "./lib/plugins-types.gen";
148
150
  export default createPlugin.withPlugins<PluginsClient>()({
149
151
  variables: z.object({ demoMessage: z.string().optional() }),
150
152
  contract,
151
- initialize: (config, plugins, _tools) =>
153
+ initialize: (config, plugins) =>
152
154
  Effect.sync(() => ({ plugins, demoMessage: config.variables.demoMessage ?? "not configured" })),
153
- createRouter: (deps, builder) => ({
155
+ createRouter: (builder) => ({
154
156
  pluginDemo: builder.pluginDemo.handler(async () => {
155
157
  const status = await deps.plugins.registry().getRegistryStatus();
156
158
  return { apiVariable: deps.demoMessage, registryStatus: status };
@@ -165,17 +167,17 @@ export default createPlugin.withPlugins<PluginsClient>()({
165
167
 
166
168
  ## Long-Lived Scoped Resources
167
169
 
168
- For database pools, caches, publisher channels, or any resource that should live for the plugin's lifetime, use `tools.buildService(tag, layer)` inside `initialize`:
170
+ For database pools, caches, publisher channels, or any resource that should live for the plugin's lifetime, use `buildScoped(tag, layer)` inside `initialize` (or `buildScopedContext(layer)` for multi-service layers):
169
171
 
170
172
  ```typescript
171
- import { createPlugin } from "every-plugin";
172
- import { Effect, Layer } from "every-plugin/effect";
173
+ import { Effect, Layer } from "effect";
174
+ import { buildScoped, createPlugin } from "every-plugin";
173
175
 
174
176
  export default createPlugin({
175
177
  // ...
176
- initialize: (config, _plugins, tools) =>
178
+ initialize: (config, _plugins) =>
177
179
  Effect.gen(function* () {
178
- const repo = yield* tools.buildService(
180
+ const repo = yield* buildScoped(
179
181
  MyRepoTag,
180
182
  MyRepoLive.pipe(Layer.provide(DatabaseLive(config.secrets.MY_DATABASE_URL))),
181
183
  );
@@ -188,9 +190,19 @@ export default createPlugin({
188
190
  });
189
191
  ```
190
192
 
191
- `tools.buildService(tag, layer)` binds the layer's resources to the plugin's lifecycle scope.
193
+ `buildScoped(tag, layer)` builds the layer with the plugin's lifecycle scope and resolves the service from the built context.
192
194
  Resources persist until the plugin shuts down and are automatically cleaned up during `runtime.shutdown()`.
193
195
 
196
+ For layers that provide several services at once, use `buildScopedContext` and resolve each tag:
197
+
198
+ ```typescript
199
+ const services = yield* buildScopedContext(
200
+ Layer.mergeAll(TenantsLive, NodesLive).pipe(Layer.provide(database)),
201
+ );
202
+
203
+ const tenants = Context.get(services, TenantsTag);
204
+ ```
205
+
194
206
  **Bad — creates a transient scope that closes immediately:**
195
207
  ```typescript
196
208
  const svc = yield* Effect.provide(MyTag, MyLive.pipe(Layer.provide(DatabaseLive(url))))
@@ -198,15 +210,14 @@ const svc = yield* Effect.provide(MyTag, MyLive.pipe(Layer.provide(DatabaseLive(
198
210
 
199
211
  **Good — resources persist for the plugin's lifetime:**
200
212
  ```typescript
201
- const svc = yield* tools.buildService(MyTag, MyLive.pipe(Layer.provide(DatabaseLive(url))))
213
+ const svc = yield* buildScoped(MyTag, MyLive.pipe(Layer.provide(DatabaseLive(url))))
202
214
  ```
203
215
 
204
216
  Key rules:
205
- - Use `tools.buildService(...)` for any `Layer.scoped(...)` resource that should survive initialization
217
+ - Use `buildScoped(...)` for any `Layer.scoped(...)` resource that should survive initialization
206
218
  - Plain class construction (new Service(...)) is still fine directly in `initialize`
207
- - `createRouter(deps)` receives whatever `initialize` returns — same mental model as before
219
+ - Handlers access services via the injected oRPC context (`yield* Tag` in `.effect()` handlers), not from initialize's return value
208
220
  - Do not use `Effect.provide(Tag, Layer.scoped(...))` for persistent dependencies inside `initialize`
209
- - `tools` is provided by the framework and does not need to be imported
210
221
 
211
222
  ## Dev Server Config (plugin.dev.ts)
212
223
 
@@ -215,7 +226,6 @@ import type { PluginConfigInput } from "every-plugin";
215
226
  import Plugin from "./src/index";
216
227
 
217
228
  export default {
218
- pluginId: "my-plugin",
219
229
  port: 3010,
220
230
  config: {
221
231
  variables: {
@@ -228,6 +238,10 @@ export default {
228
238
  };
229
239
  ```
230
240
 
241
+ No `pluginId` field — the dev server derives the plugin id from the workspace
242
+ itself (the `plugins/<key>` layout key and the package.json name); it never
243
+ reads one from this file.
244
+
231
245
  Port assignments: host=3000, api=3001, auth=3002, ui=3003, ui-ssr=3004, plugins=3010+.
232
246
 
233
247
  ## Build Config (rspack.config.js)
@@ -254,9 +268,27 @@ export default {
254
268
 
255
269
  ## Common Mistakes
256
270
 
257
- - Importing `oc` from `@orpc/contract` instead of `every-plugin/orpc` — will cause version mismatches in Module Federation
258
- - Importing `z` from `zod` instead of `every-plugin/zod` — may cause Vitest CJS/ESM interop issues; always use `every-plugin/zod`
271
+ - Importing `z`/`oc`/`Effect` from `every-plugin/zod`, `every-plugin/orpc`, or `every-plugin/effect` — those facade barrels were deleted; import from `zod`, `@orpc/contract`, and `effect` directly
259
272
  - Forgetting `.errors(Errors)` on routes that can throw ORPCError — untyped errors
260
273
  - Using `Effect.runPromise` inside `Effect.gen` — use `yield*` instead for proper error channel
261
274
  - Putting business logic in `createRouter` — keep it in the service class, router is just glue
262
- - Using `Effect.provide(Tag, Layer.scoped(...))` inside `initialize` for long-lived resources — creates a transient scope that releases the resource immediately after initialization. Use `tools.buildService(Tag, Layer.scoped(...))` instead
275
+ - Using `Effect.provide(Tag, Layer.scoped(...))` inside `initialize` for long-lived resources — creates a transient scope that releases the resource immediately after initialization. Use `buildScoped(Tag, Layer.scoped(...))` instead
276
+
277
+ ## The tasks you will actually be given
278
+
279
+ **"Add a route to a plugin"** — e.g. a `deleteItem` procedure. Add it to `plugins/<your-plugin>/src/contract.ts` (`.route({ method: "DELETE", path: "/items/{id}" }).input(...).errors(Errors)`), add a method on the service class, then wire it in `src/index.ts` as `deleteItem: builder.deleteItem.effect(function* ({ input, context, errors }) { ... })` — check `context.userId` first and fail with `errors.UNAUTHORIZED(...)` / `errors.NOT_FOUND(...)` inside the generator, mirroring `plugins/_template/src/index.ts` (`getById`, `deleteThing`). Verify with `cd plugins/<your-plugin> && pnpm test`, then `pnpm run typecheck` (regenerates `plugins-types.gen.ts` for cross-plugin consumers).
280
+
281
+ **"Ship a new plugin"** — copy `plugins/_template/` to `plugins/<key>/`, set `name` in its package.json (this is the registry id tests use), fill in `plugin.dev.ts` (port; plugins start at 3010), and register it in the authored config with `Plugin("<key>").path("plugins/<key>", { ... })` (see `bos.app.ts`). Run `bos types gen` or restart `pnpm run dev`, then deploy with `cd plugins/<key> && bos plugin publish <key>`.
282
+
283
+ **"A plugin fails to load in the host"** — capture the error words and match them in the table below; shared-identity failures are confirmed with `bos mf check` and fixed by rebuilding/redeploying the one plugin.
284
+
285
+ ## What comes back when it fails
286
+
287
+ | Error word / shape you see | Meaning | Action |
288
+ |---|---|---|
289
+ | `ModuleFederationError` with "shared identity mismatch" (or the plugin's `mf-manifest.json` reports an older `pluginVersion` than the host) | plugin bundle built against a different `@module-federation/runtime`, or missing a `shared[]` dep the host requires | rebuild + redeploy that one plugin (`cd plugins/<key> && bos plugin publish <key>`); confirm with `bos mf check`. Stop editing code — this is a build/deploy problem |
290
+ | `No valid plugin constructor found for '<id>'` / `missing the required 'binding' property` | the remote module's export was not created by `createPlugin()` | `export default createPlugin({...})` from `src/index.ts`, rebuild |
291
+ | `PluginRuntimeError` with operation `validate-config` or `validate-secrets` and a Zod cause | runtime config violates the plugin's `variables`/`secrets` schemas (secrets hydrate into variables, then re-validate) | fix `plugin.dev.ts` in dev, or the runtime config entry; read the Zod issue paths in the error |
292
+ | `Plugin ID '<id>' not found in registry.` | registry key mismatch | align the key used with the plugins/ directory key and package.json `name` |
293
+ | 401 `UNAUTHORIZED` with data `{ apiKeyProvided: boolean, ... }` | no session or API key reached the handler (see `every-plugin/errors`) | caller-side problem — sign in or send `x-api-key`; do not catch it in the plugin |
294
+ | 503 `SERVICE_UNAVAILABLE` / 502 `CONNECTION_ERROR` shapes from `every-plugin/errors` | upstream dependency of the service failed | surface them via `.errors(...)` on the contract, not ad-hoc ORPCError codes |
@@ -2,7 +2,7 @@
2
2
  name: plugin-testing
3
3
  description: Test every-plugin modules with vitest and the plugin runtime. Use when writing or modifying plugin tests under plugins/*/src/__tests__/ or plugins/*/tests/.
4
4
  metadata:
5
- sources: "src/testing/index.ts,src/runtime/index.ts"
5
+ sources: "src/index.ts,src/runtime/index.ts,src/runtime/errors.ts,plugins/_template/tests/setup.ts"
6
6
  ---
7
7
 
8
8
  # every-plugin Testing
@@ -23,7 +23,7 @@ Test the service class directly without the plugin runtime:
23
23
 
24
24
  ```typescript
25
25
  import { describe, expect, it } from "vitest";
26
- import { Effect } from "every-plugin/effect";
26
+ import { Effect } from "effect";
27
27
  import { MyService } from "../service";
28
28
 
29
29
  describe("MyService", () => {
@@ -126,16 +126,27 @@ describe("API with mock registry", () => {
126
126
 
127
127
  ## Testing Scope Lifecycle
128
128
 
129
- When a plugin uses `tools.buildService(...)` inside `initialize`, verify that scoped resources persist after initialization and are released during shutdown:
129
+ When a plugin uses `buildScoped(...)` inside `initialize`, verify that scoped resources persist after initialization and are released during shutdown:
130
130
 
131
131
  ```typescript
132
132
  import { afterAll, beforeAll, describe, expect, it } from "vitest";
133
133
  import { createPlugin, createPluginRuntime } from "every-plugin";
134
- import { Context, Effect, Layer } from "every-plugin/effect";
134
+ import { Context, Effect, Layer } from "effect";
135
135
 
136
136
  let released = false;
137
137
 
138
- class TestTag extends Context.Tag("TestTag")<TestTag, { value: string }>() {}
138
+ class TestTag extends Context.Service<TestTag, { value: string }>()("TestTag") {}
139
+
140
+ const TestLive = Layer.effect(
141
+ TestTag,
142
+ Effect.acquireRelease(
143
+ Effect.sync(() => ({ value: "live" })),
144
+ () =>
145
+ Effect.sync(() => {
146
+ released = true;
147
+ }),
148
+ ),
149
+ );
139
150
 
140
151
  describe("scope lifecycle", () => {
141
152
  let runtime: ReturnType<typeof createPluginRuntime>;
@@ -143,12 +154,11 @@ describe("scope lifecycle", () => {
143
154
  beforeAll(async () => {
144
155
  const plugin = createPlugin({
145
156
  // ... variables, secrets, contract ...
146
- initialize: (_config, _plugins, tools) =>
147
- Effect.gen(function* () {
148
- const svc = yield* tools.buildService(TestTag, TestLive);
149
- return { svc };
150
- }),
151
- createRouter: (deps) => ({
157
+ initialize: () =>
158
+ Effect.succeed(
159
+ TestLive,
160
+ ),
161
+ createRouter: (builder) => ({
152
162
  // ... routes ...
153
163
  }),
154
164
  });
@@ -212,6 +222,25 @@ export default defineConfig({
212
222
 
213
223
  - Not calling `runtime.shutdown()` in `afterAll` — leaves plugin scopes/resources running
214
224
  - Using `vi.fn()` without `.mockResolvedValue()` — unhandled promise rejections
215
- - Forgetting `vite-tsconfig-paths` plugin — path aliases like `every-plugin/orpc` won't resolve
225
+ - Forgetting `vite-tsconfig-paths` plugin — package subpath imports like `every-plugin/errors` won't resolve
216
226
  - Omitting the `registry` object when calling `createPluginRuntime(...)` — the runtime requires explicit plugin entries
217
227
  - Testing only happy paths — always test error channels (Effect failures, ORPCError throws)
228
+
229
+ ## The tasks you will actually be given
230
+
231
+ **"Add an integration test for a new route"** — in `plugins/<your-plugin>/tests/integration/plugin.test.ts`, follow the `_template` pattern (`plugins/_template/tests/setup.ts`): call `await getPluginClient({ userId: "user123" })` — it boots `createPluginRuntime` with the registry keyed by the package.json `name`, config from `plugin.dev.ts`, and an HTTP server that maps `x-test-user`/`x-test-session` headers to context. Then drive the route through the client and assert the response. Run with `cd plugins/<your-plugin> && pnpm test` (script `vitest run`, `testTimeout: 30000` in `vitest.config.ts`).
232
+
233
+ **"Prove a service method fails with the right ORPC code"** — follow `plugins/_template/tests/unit/things-service.test.ts`: build a fresh layer with `DatabaseLive('pglite:<mkdtemp dir>')` and `Layer.succeed(PluginIdTag, "<pluginId>")`, run the failing effect through `Effect.runPromiseExit` + `Cause.squash`, then `expect(error).toBeInstanceOf(ORPCError)` and `expect(error.code).toBe("CONFLICT")` (or `NOT_FOUND`). Clean the temp dir in `afterEach`.
234
+
235
+ **"A test fails at `usePlugin` with a validation error"** — the config comes from `plugin.dev.ts` via `tests/setup.ts` (`TEST_CONFIG`). The runtime validates `variables` and `secrets` against the plugin's zod schemas (`validate-config` / `validate-secrets` → `PluginRuntimeError` with a `zodError` cause). Fix the config in `plugin.dev.ts`, not the test.
236
+
237
+ ## What comes back when it fails
238
+
239
+ | Error word / shape you see | Meaning | Action |
240
+ |---|---|---|
241
+ | `Plugin ID '<id>' not found in registry.` (`PluginRuntimeError`, operation `validate-plugin-id`) | the `usePlugin` key does not match a registry entry | make the registry key the package.json `name` (as `tests/setup.ts` does), then read again |
242
+ | `PluginRuntimeError` with operation `validate-config` / `validate-secrets` and a Zod cause | `TEST_CONFIG` violates the plugin's schemas | fix `plugin.dev.ts`; do not loosen the schemas to make tests pass |
243
+ | `ModuleFederationError` | only when loading a remote URL — in-process tests (`module: Plugin`) never produce it | if you see it, your registry entry points at a URL instead of the imported module |
244
+ | `Cannot find module` for `every-plugin/...` subpaths | `vite-tsconfig-paths` missing from `vitest.config.ts` plugins | add it (see the Vitest Config section) |
245
+ | Test hangs past 30s | default `testTimeout: 30000`; a streaming handler's `for await` never terminates | pass `signal`/`maxResults` limits like `_template`'s `listenBackground`, or abort the iterator |
246
+ | Scoped resource still alive after tests finish | `runtime.shutdown()` (or `_template`'s `teardown()`) never ran | call it in `afterAll` |
@@ -0,0 +1,117 @@
1
+ import crypto from "node:crypto";
2
+ import { z } from "zod";
3
+
4
+ /** Dev-mode entry names: the in-memory dev server serves these exact names,
5
+ * and dev consumers (the host's html shell, the compose client payload, the
6
+ * readiness probe) append them — dev has no build report to discover hashed
7
+ * names from. */
8
+ export const DEV_ENTRY_FILENAME = "remoteEntry.js";
9
+ export const DEV_SERVER_ENTRY_FILENAME = "remoteEntry.server.js";
10
+ /** Fixed-name build outputs that get additive immutable hashed copies. */
11
+ export const MF_MANIFEST_FILENAME = "mf-manifest.json";
12
+ export const STYLE_FILENAME = "style.css";
13
+ export const HASHED_ENTRY_PATTERN = "remoteEntry.[contenthash].js";
14
+ export const HASHED_SERVER_ENTRY_PATTERN = "remoteEntry.server.[contenthash].js";
15
+
16
+ /** The dev-stack signal: everything a dev server spawns (watch or no-watch
17
+ * one-shot builds) serves the fixed dev entry names, because every dev
18
+ * consumer appends them and no build report exists to discover hashed names
19
+ * from. Every other invocation — local builds, host-test production builds,
20
+ * regression container builds, deploys — is a build and emits content-hashed
21
+ * entries + build reports. NODE_ENV cannot carry this decision (vitest runs
22
+ * as "test", bundler CLIs default "production" even for dev watches), and
23
+ * DEPLOY=true only marks deploy builds — so the dev server stamps its own
24
+ * children. */
25
+ export function isBuildInvocation(): boolean {
26
+ return process.env.BOS_DEV_SERVER !== "1";
27
+ }
28
+
29
+ export function uiEntryFilename(input: { isBuild: boolean; server?: boolean }): string {
30
+ if (!input.isBuild) return input.server ? DEV_SERVER_ENTRY_FILENAME : DEV_ENTRY_FILENAME;
31
+ return input.server ? HASHED_SERVER_ENTRY_PATTERN : HASHED_ENTRY_PATTERN;
32
+ }
33
+
34
+ const HASH_SEGMENT_PATTERN = /\.[a-f0-9]{8,}\./;
35
+
36
+ /**
37
+ * Serving classification for bundle objects: anything whose name carries a
38
+ * content-hash segment (including hashed entrypoints like
39
+ * `remoteEntry.8f3a….js`) is immutable by construction; fixed-name
40
+ * entrypoints and non-hashed files a redeploy replaces in place must
41
+ * revalidate.
42
+ */
43
+ export function isImmutableBundlePath(name: string): boolean {
44
+ const base = name.split("/").pop() ?? name;
45
+ return HASH_SEGMENT_PATTERN.test(base);
46
+ }
47
+
48
+ export function cacheControlOf(name: string): string {
49
+ return isImmutableBundlePath(name)
50
+ ? "public, max-age=31536000, immutable"
51
+ : "public, max-age=0, must-revalidate";
52
+ }
53
+
54
+ /** Short content hash used to mint additive hashed copies of fixed-name artifacts. */
55
+ export function contentHashOf(content: string | Uint8Array): string {
56
+ return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
57
+ }
58
+
59
+ export function hashedArtifactName(base: string, hash: string, ext: string): string {
60
+ return `${base}.${hash}.${ext.replace(/^\./, "")}`;
61
+ }
62
+
63
+ /** Find the content-hashed entry asset for a base name ("remoteEntry", "remoteEntry.server"). */
64
+ export function findHashedEntry(assetNames: string[], base: string): string | null {
65
+ const hashed = assetNames.find((name) => {
66
+ const rest = name.startsWith(`${base}.`) ? name.slice(base.length + 1) : null;
67
+ if (rest === null) return false;
68
+ const hash = rest.slice(0, -3);
69
+ return name.endsWith(".js") && /^[a-f0-9]{8,}$/.test(hash);
70
+ });
71
+ return hashed ?? null;
72
+ }
73
+
74
+ export const BuildEntryReportSchema = z.object({
75
+ entry: z.string().min(1),
76
+ browserManifest: z.string().min(1).optional(),
77
+ css: z.string().min(1).optional(),
78
+ });
79
+ export type BuildEntryReport = z.infer<typeof BuildEntryReportSchema>;
80
+
81
+ export interface ArtifactCopy {
82
+ from: string;
83
+ to: string;
84
+ }
85
+
86
+ /**
87
+ * The additive-copy plan for one compiled dist root: each supplied fixed-name
88
+ * artifact gets an immutable hashed copy. The hashed entry itself needs no
89
+ * copy — the build report carries its name to the deploy leg. Returns null
90
+ * when the build predates hashed entry names (only fixed names emitted).
91
+ */
92
+ export function planArtifactCopies(input: {
93
+ assetNames: string[];
94
+ entryBase: string;
95
+ contents?: Record<string, string | Uint8Array | undefined>;
96
+ }): { copies: Array<ArtifactCopy>; report: BuildEntryReport } | null {
97
+ const entry = findHashedEntry(input.assetNames, input.entryBase);
98
+ if (!entry) return null;
99
+
100
+ const copies: Array<ArtifactCopy> = [];
101
+ const report: BuildEntryReport = { entry };
102
+
103
+ const hashedCopy = (fixedName: string, reportField: "browserManifest" | "css") => {
104
+ const content = input.contents?.[fixedName];
105
+ if (content === undefined) return;
106
+ const dot = fixedName.lastIndexOf(".");
107
+ const base = fixedName.slice(0, dot);
108
+ const ext = fixedName.slice(dot + 1);
109
+ const hashed = hashedArtifactName(base, contentHashOf(content), ext);
110
+ copies.push({ from: fixedName, to: hashed });
111
+ report[reportField] = hashed;
112
+ };
113
+ hashedCopy(MF_MANIFEST_FILENAME, "browserManifest");
114
+ hashedCopy(STYLE_FILENAME, "css");
115
+
116
+ return { copies, report };
117
+ }
@@ -0,0 +1,101 @@
1
+ import { execFile } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
5
+ import { promisify } from "node:util";
6
+
7
+ const execFileAsync = promisify(execFile);
8
+
9
+ export type ContractTypesStatus = "generated" | "up-to-date" | "skipped";
10
+
11
+ export const CONTRACT_ENTRY = path.join("src", "contract.ts");
12
+ export const CONTRACT_TYPES_DIR = "types";
13
+ export const CONTRACT_TYPES_FILE = path.join("types", "contract.d.ts");
14
+
15
+ export function contractTypesUpToDate(cwd: string): boolean {
16
+ const entry = path.join(cwd, CONTRACT_ENTRY);
17
+ const outFile = path.join(cwd, CONTRACT_TYPES_FILE);
18
+ if (!fs.existsSync(entry) || !fs.existsSync(outFile)) return false;
19
+ return fs.statSync(outFile).mtimeMs >= fs.statSync(entry).mtimeMs;
20
+ }
21
+
22
+ export function resolveTscBinary(cwd: string): string {
23
+ for (const from of [
24
+ path.join(cwd, "package.json"),
25
+ path.join(import.meta.dirname, "..", "..", "..", "package.json"),
26
+ ]) {
27
+ try {
28
+ const req = createRequire(path.resolve(from));
29
+ const pkgJsonPath = req.resolve("typescript/package.json");
30
+ return path.join(path.dirname(pkgJsonPath), "bin", "tsc");
31
+ } catch {
32
+ // try the next resolution root
33
+ }
34
+ }
35
+ return "tsc";
36
+ }
37
+
38
+ /**
39
+ * Regenerates types/contract.d.ts for a plugin workspace by invoking the
40
+ * workspace's TypeScript 7 binary with explicit flags — no tsconfig file
41
+ * involved, so emit layout is deterministic and there is nothing to sync.
42
+ *
43
+ * - "skipped": the workspace has no src/contract.ts
44
+ * - "up-to-date": types/contract.d.ts is newer than src/contract.ts
45
+ * - "generated": declarations were re-emitted (types/ is cleaned first, so
46
+ * stale nested layouts never survive)
47
+ */
48
+ export async function generateContractTypes(
49
+ cwd: string = process.cwd(),
50
+ ): Promise<ContractTypesStatus> {
51
+ const entry = path.join(cwd, CONTRACT_ENTRY);
52
+ if (!fs.existsSync(entry)) {
53
+ return "skipped";
54
+ }
55
+
56
+ if (contractTypesUpToDate(cwd)) {
57
+ return "up-to-date";
58
+ }
59
+
60
+ const outDir = path.join(cwd, CONTRACT_TYPES_DIR);
61
+ fs.rmSync(outDir, { recursive: true, force: true });
62
+ fs.mkdirSync(outDir, { recursive: true });
63
+
64
+ const tsc = resolveTscBinary(cwd);
65
+ const args = [
66
+ "--ignoreConfig",
67
+ "--emitDeclarationOnly",
68
+ "--declaration",
69
+ "--rootDir",
70
+ "src",
71
+ "--outDir",
72
+ CONTRACT_TYPES_DIR,
73
+ "--target",
74
+ "esnext",
75
+ "--module",
76
+ "esnext",
77
+ "--moduleResolution",
78
+ "bundler",
79
+ "--strict",
80
+ "--skipLibCheck",
81
+ CONTRACT_ENTRY,
82
+ ];
83
+
84
+ try {
85
+ await execFileAsync(process.execPath, [tsc, ...args], { cwd });
86
+ } catch (error) {
87
+ const err = error as { message?: string; stdout?: string; stderr?: string };
88
+ const detail = [err.stderr, err.stdout, err.message].filter(Boolean).join("\n").trim();
89
+ throw new Error(
90
+ `Contract type generation failed for ${path.basename(cwd)} — tsc exited non-zero:\n${detail}`,
91
+ );
92
+ }
93
+
94
+ if (!fs.existsSync(path.join(cwd, CONTRACT_TYPES_FILE))) {
95
+ throw new Error(
96
+ `Contract type generation produced no output — expected ${path.join(cwd, CONTRACT_TYPES_FILE)}`,
97
+ );
98
+ }
99
+
100
+ return "generated";
101
+ }
@@ -0,0 +1,34 @@
1
+ import type { Compiler, RspackPluginInstance } from "@rspack/core";
2
+ import { BuildEntryReportSchema, findHashedEntry } from "../artifact-names";
3
+
4
+ /**
5
+ * Emits `build-report.json` for the deploy leg: the container entry is hashed
6
+ * by the build's filename template (`remoteEntry.[contenthash].js`), and the
7
+ * report names it — in-compilation, so watch-mode cleans can't open a window
8
+ * where the report 404s (mirrors the `output.clean` rationale on the build
9
+ * plugin).
10
+ */
11
+ export class BuildReportPlugin implements RspackPluginInstance {
12
+ name = "BuildReportPlugin";
13
+
14
+ constructor(private entryBase = "remoteEntry") {}
15
+
16
+ apply(compiler: Compiler) {
17
+ compiler.hooks.thisCompilation.tap(this.name, (compilation) => {
18
+ const webpack = (compiler as Compiler & { webpack?: any }).webpack;
19
+ const rawSource = webpack?.sources?.RawSource;
20
+ const stage = webpack?.Compilation?.PROCESS_ASSETS_STAGE_ADDITIONS ?? 1000;
21
+
22
+ compilation.hooks.processAssets.tap({ name: this.name, stage }, (assets) => {
23
+ const entry = findHashedEntry(Object.keys(assets), this.entryBase);
24
+ if (!entry || !rawSource) return;
25
+
26
+ const report = BuildEntryReportSchema.parse({ entry });
27
+ compilation.emitAsset(
28
+ "build-report.json",
29
+ new rawSource(`${JSON.stringify(report, null, 2)}\n`),
30
+ );
31
+ });
32
+ });
33
+ }
34
+ }
@@ -0,0 +1,57 @@
1
+ import type { Compiler, RspackPluginInstance } from "@rspack/core";
2
+ import { findHashedEntry } from "../artifact-names";
3
+
4
+ /**
5
+ * Fails the build when a container entry's eager chunk references
6
+ * (`Promise.all([__webpack_require__.e(N), …])` in get factories) point at
7
+ * chunk files the compilation never emits. Rspack 2.x splitChunks re-ids the
8
+ * final chunk graph while the federation get-factory codegen can keep
9
+ * pre-split ids — the emitted entry then 404s its own chunks at load time and
10
+ * the failure surfaces downstream as `__webpack_modules__[r] is not a
11
+ * function`. SplitChunks is disabled in the composition for exactly this
12
+ * reason; this gate catches any regression loudly at build time instead.
13
+ */
14
+ export class ChunkCompletenessPlugin implements RspackPluginInstance {
15
+ name = "ChunkCompletenessPlugin";
16
+
17
+ constructor(private entryBase = "remoteEntry") {}
18
+
19
+ apply(compiler: Compiler) {
20
+ compiler.hooks.thisCompilation.tap(this.name, (compilation) => {
21
+ const webpack = (compiler as Compiler & { webpack?: any }).webpack;
22
+ const stage = webpack?.Compilation?.PROCESS_ASSETS_STAGE_ADDITIONS ?? 1000;
23
+
24
+ compilation.hooks.processAssets.tap({ name: this.name, stage }, (assets) => {
25
+ const names = Object.keys(assets);
26
+ const entry =
27
+ findHashedEntry(names, this.entryBase) ?? names.find((n) => n === `${this.entryBase}.js`);
28
+ if (!entry) return;
29
+
30
+ const jsFiles = new Set(names.filter((n) => n.endsWith(".js")));
31
+ const source = assets[entry].source().toString();
32
+
33
+ const special = new Map<string, string>();
34
+ const u = source.match(/\.u\s*=\s*(\w+)=>([^,;]+)/);
35
+ if (u) {
36
+ for (const m of u[2].matchAll(/(\d+)\s*===\s*\w+\s*\?\s*"([^"]+)"/g)) {
37
+ special.set(m[1], m[2]);
38
+ }
39
+ }
40
+
41
+ for (const pa of source.matchAll(/Promise\.all\(\[([^\]]*)\]\)/g)) {
42
+ for (const m of pa[1].matchAll(/(?:__webpack_require__|\w+)\.e\((\d+)\)/g)) {
43
+ const id = m[1];
44
+ const file = special.has(id) ? `${special.get(id)}.js` : `${id}.js`;
45
+ if (!jsFiles.has(file)) {
46
+ compilation.errors.push(
47
+ new Error(
48
+ `[${this.name}] entry ${entry} eagerly loads chunk ${id} (${file}) but the compilation never emitted it — the built remote would fail at load time with "__webpack_modules__[r] is not a function".`,
49
+ ),
50
+ );
51
+ }
52
+ }
53
+ }
54
+ });
55
+ });
56
+ }
57
+ }