@dxos/app-framework 0.8.4-main.dedc0f3 → 0.8.4-main.dfabb4ec29

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 (577) hide show
  1. package/.storybook/main.mts +9 -0
  2. package/.storybook/preview.mts +8 -0
  3. package/dist/lib/browser/capability-5RRH3WIB.mjs +35 -0
  4. package/dist/lib/browser/capability-5RRH3WIB.mjs.map +7 -0
  5. package/dist/lib/browser/capability-LUKGKUQH.mjs +38 -0
  6. package/dist/lib/browser/capability-LUKGKUQH.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-23D4SJUE.mjs +42 -0
  8. package/dist/lib/browser/chunk-23D4SJUE.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-3JWJXGLK.mjs +79 -0
  10. package/dist/lib/browser/chunk-3JWJXGLK.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-45CHLTBV.mjs +34 -0
  12. package/dist/lib/browser/chunk-45CHLTBV.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-66IXTIVK.mjs +48 -0
  14. package/dist/lib/browser/chunk-66IXTIVK.mjs.map +7 -0
  15. package/dist/lib/browser/chunk-7VZJR2OA.mjs +581 -0
  16. package/dist/lib/browser/chunk-7VZJR2OA.mjs.map +7 -0
  17. package/dist/lib/browser/chunk-CZ4BIAHH.mjs +422 -0
  18. package/dist/lib/browser/chunk-CZ4BIAHH.mjs.map +7 -0
  19. package/dist/lib/browser/chunk-FJ4765WW.mjs +8 -0
  20. package/dist/lib/browser/chunk-FJ4765WW.mjs.map +7 -0
  21. package/dist/lib/browser/chunk-FO3IYSLV.mjs +68 -0
  22. package/dist/lib/browser/chunk-FO3IYSLV.mjs.map +7 -0
  23. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  24. package/dist/lib/browser/chunk-JD3Z5NEF.mjs +469 -0
  25. package/dist/lib/browser/chunk-JD3Z5NEF.mjs.map +7 -0
  26. package/dist/lib/browser/chunk-NBXPP7JR.mjs +1174 -0
  27. package/dist/lib/browser/chunk-NBXPP7JR.mjs.map +7 -0
  28. package/dist/lib/browser/chunk-WBHCSOBW.mjs +80 -0
  29. package/dist/lib/browser/chunk-WBHCSOBW.mjs.map +7 -0
  30. package/dist/lib/browser/chunk-Z55LVAGN.mjs +213 -0
  31. package/dist/lib/browser/chunk-Z55LVAGN.mjs.map +7 -0
  32. package/dist/lib/browser/chunk-ZGJAZSNE.mjs +142 -0
  33. package/dist/lib/browser/chunk-ZGJAZSNE.mjs.map +7 -0
  34. package/dist/lib/browser/cli/index.mjs +76 -0
  35. package/dist/lib/browser/cli/index.mjs.map +7 -0
  36. package/dist/lib/browser/common/activation-events.mjs +24 -0
  37. package/dist/lib/browser/common/capabilities.mjs +46 -0
  38. package/dist/lib/browser/core/activation-event.mjs +20 -0
  39. package/dist/lib/browser/core/capability.mjs +30 -0
  40. package/dist/lib/browser/core/capability.mjs.map +7 -0
  41. package/dist/lib/browser/core/plugin-manager.mjs +19 -0
  42. package/dist/lib/browser/core/plugin-manager.mjs.map +7 -0
  43. package/dist/lib/browser/core/plugin.mjs +37 -0
  44. package/dist/lib/browser/core/plugin.mjs.map +7 -0
  45. package/dist/lib/browser/core/url-loader.mjs +24 -0
  46. package/dist/lib/browser/core/url-loader.mjs.map +7 -0
  47. package/dist/lib/browser/index.mjs +108 -162
  48. package/dist/lib/browser/index.mjs.map +4 -4
  49. package/dist/lib/browser/invoker-capability-K4GHUFXF.mjs +44 -0
  50. package/dist/lib/browser/invoker-capability-K4GHUFXF.mjs.map +7 -0
  51. package/dist/lib/browser/meta.json +1 -1
  52. package/dist/lib/browser/testing/index.mjs +235 -48
  53. package/dist/lib/browser/testing/index.mjs.map +4 -4
  54. package/dist/lib/browser/testing/react.mjs +78 -0
  55. package/dist/lib/browser/testing/react.mjs.map +7 -0
  56. package/dist/lib/browser/ui/index.mjs +48 -0
  57. package/dist/lib/browser/ui/index.mjs.map +7 -0
  58. package/dist/lib/node-esm/capability-FCGZVIEG.mjs +39 -0
  59. package/dist/lib/node-esm/capability-FCGZVIEG.mjs.map +7 -0
  60. package/dist/lib/node-esm/capability-JOIQ2MQE.mjs +36 -0
  61. package/dist/lib/node-esm/capability-JOIQ2MQE.mjs.map +7 -0
  62. package/dist/lib/node-esm/chunk-37Z53PXZ.mjs +10 -0
  63. package/dist/lib/node-esm/chunk-37Z53PXZ.mjs.map +7 -0
  64. package/dist/lib/node-esm/chunk-6XW6LET6.mjs +35 -0
  65. package/dist/lib/node-esm/chunk-6XW6LET6.mjs.map +7 -0
  66. package/dist/lib/node-esm/chunk-D347W3KO.mjs +143 -0
  67. package/dist/lib/node-esm/chunk-D347W3KO.mjs.map +7 -0
  68. package/dist/lib/node-esm/chunk-DRZKO5UZ.mjs +470 -0
  69. package/dist/lib/node-esm/chunk-DRZKO5UZ.mjs.map +7 -0
  70. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  71. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  72. package/dist/lib/node-esm/chunk-HTBJU5FX.mjs +214 -0
  73. package/dist/lib/node-esm/chunk-HTBJU5FX.mjs.map +7 -0
  74. package/dist/lib/node-esm/chunk-M3HKPRPO.mjs +423 -0
  75. package/dist/lib/node-esm/chunk-M3HKPRPO.mjs.map +7 -0
  76. package/dist/lib/node-esm/chunk-MUVUQC3G.mjs +1175 -0
  77. package/dist/lib/node-esm/chunk-MUVUQC3G.mjs.map +7 -0
  78. package/dist/lib/node-esm/chunk-SBS2YMPT.mjs +43 -0
  79. package/dist/lib/node-esm/chunk-SBS2YMPT.mjs.map +7 -0
  80. package/dist/lib/node-esm/chunk-SDJ4B2LU.mjs +80 -0
  81. package/dist/lib/node-esm/chunk-SDJ4B2LU.mjs.map +7 -0
  82. package/dist/lib/node-esm/chunk-V24UWT36.mjs +582 -0
  83. package/dist/lib/node-esm/chunk-V24UWT36.mjs.map +7 -0
  84. package/dist/lib/node-esm/chunk-WFSRZKBP.mjs +81 -0
  85. package/dist/lib/node-esm/chunk-WFSRZKBP.mjs.map +7 -0
  86. package/dist/lib/node-esm/chunk-WK7OIQKI.mjs +70 -0
  87. package/dist/lib/node-esm/chunk-WK7OIQKI.mjs.map +7 -0
  88. package/dist/lib/node-esm/chunk-XOCUANHO.mjs +49 -0
  89. package/dist/lib/node-esm/chunk-XOCUANHO.mjs.map +7 -0
  90. package/dist/lib/node-esm/cli/index.mjs +77 -0
  91. package/dist/lib/node-esm/cli/index.mjs.map +7 -0
  92. package/dist/lib/node-esm/common/activation-events.mjs +25 -0
  93. package/dist/lib/node-esm/common/activation-events.mjs.map +7 -0
  94. package/dist/lib/node-esm/common/capabilities.mjs +47 -0
  95. package/dist/lib/node-esm/common/capabilities.mjs.map +7 -0
  96. package/dist/lib/node-esm/core/activation-event.mjs +21 -0
  97. package/dist/lib/node-esm/core/activation-event.mjs.map +7 -0
  98. package/dist/lib/node-esm/core/capability.mjs +31 -0
  99. package/dist/lib/node-esm/core/capability.mjs.map +7 -0
  100. package/dist/lib/node-esm/core/plugin-manager.mjs +20 -0
  101. package/dist/lib/node-esm/core/plugin-manager.mjs.map +7 -0
  102. package/dist/lib/node-esm/core/plugin.mjs +38 -0
  103. package/dist/lib/node-esm/core/plugin.mjs.map +7 -0
  104. package/dist/lib/node-esm/core/url-loader.mjs +25 -0
  105. package/dist/lib/node-esm/core/url-loader.mjs.map +7 -0
  106. package/dist/lib/node-esm/index.mjs +108 -162
  107. package/dist/lib/node-esm/index.mjs.map +4 -4
  108. package/dist/lib/node-esm/invoker-capability-XEPW5LMJ.mjs +45 -0
  109. package/dist/lib/node-esm/invoker-capability-XEPW5LMJ.mjs.map +7 -0
  110. package/dist/lib/node-esm/meta.json +1 -1
  111. package/dist/lib/node-esm/testing/index.mjs +235 -48
  112. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  113. package/dist/lib/node-esm/testing/react.mjs +79 -0
  114. package/dist/lib/node-esm/testing/react.mjs.map +7 -0
  115. package/dist/lib/node-esm/ui/index.mjs +49 -0
  116. package/dist/lib/node-esm/ui/index.mjs.map +7 -0
  117. package/dist/plugin/node-esm/index.mjs +893 -0
  118. package/dist/plugin/node-esm/index.mjs.map +7 -0
  119. package/dist/plugin/node-esm/meta.json +1 -0
  120. package/dist/types/src/cli/cli.d.ts +39 -0
  121. package/dist/types/src/cli/cli.d.ts.map +1 -0
  122. package/dist/types/src/cli/index.d.ts +2 -0
  123. package/dist/types/src/cli/index.d.ts.map +1 -0
  124. package/dist/types/src/common/activation-events.d.ts +27 -0
  125. package/dist/types/src/common/activation-events.d.ts.map +1 -0
  126. package/dist/types/src/common/annotations.d.ts +1 -0
  127. package/dist/types/src/common/annotations.d.ts.map +1 -0
  128. package/dist/types/src/common/capabilities.d.ts +110 -190
  129. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  130. package/dist/types/src/common/index.d.ts +4 -8
  131. package/dist/types/src/common/index.d.ts.map +1 -1
  132. package/dist/types/src/common/operations.d.ts +19 -0
  133. package/dist/types/src/common/operations.d.ts.map +1 -0
  134. package/dist/types/src/common/translations.d.ts +8 -8
  135. package/dist/types/src/common/translations.d.ts.map +1 -1
  136. package/dist/types/src/context.d.ts +5 -0
  137. package/dist/types/src/context.d.ts.map +1 -0
  138. package/dist/types/src/core/{events.d.ts → activation-event.d.ts} +11 -11
  139. package/dist/types/src/core/activation-event.d.ts.map +1 -0
  140. package/dist/types/src/core/capability-manager.d.ts +48 -0
  141. package/dist/types/src/core/capability-manager.d.ts.map +1 -0
  142. package/dist/types/src/core/capability-manager.test.d.ts +2 -0
  143. package/dist/types/src/core/capability-manager.test.d.ts.map +1 -0
  144. package/dist/types/src/core/capability.d.ts +156 -0
  145. package/dist/types/src/core/capability.d.ts.map +1 -0
  146. package/dist/types/src/core/edge-registry-plugin-provider.d.ts +30 -0
  147. package/dist/types/src/core/edge-registry-plugin-provider.d.ts.map +1 -0
  148. package/dist/types/src/core/index.d.ts +11 -4
  149. package/dist/types/src/core/index.d.ts.map +1 -1
  150. package/dist/types/src/core/plugin-asset-cache.d.ts +71 -0
  151. package/dist/types/src/core/plugin-asset-cache.d.ts.map +1 -0
  152. package/dist/types/src/core/plugin-manager.d.ts +239 -0
  153. package/dist/types/src/core/plugin-manager.d.ts.map +1 -0
  154. package/dist/types/src/core/plugin-manager.test.d.ts +2 -0
  155. package/dist/types/src/core/plugin-manager.test.d.ts.map +1 -0
  156. package/dist/types/src/core/plugin-manifest.d.ts +101 -0
  157. package/dist/types/src/core/plugin-manifest.d.ts.map +1 -0
  158. package/dist/types/src/core/plugin-manifest.test.d.ts +2 -0
  159. package/dist/types/src/core/plugin-manifest.test.d.ts.map +1 -0
  160. package/dist/types/src/core/plugin.d.ts +208 -37
  161. package/dist/types/src/core/plugin.d.ts.map +1 -1
  162. package/dist/types/src/core/registry.d.ts +101 -0
  163. package/dist/types/src/core/registry.d.ts.map +1 -0
  164. package/dist/types/src/core/url-loader.d.ts +127 -0
  165. package/dist/types/src/core/url-loader.d.ts.map +1 -0
  166. package/dist/types/src/core/url-loader.test.d.ts +2 -0
  167. package/dist/types/src/core/url-loader.test.d.ts.map +1 -0
  168. package/dist/types/src/helpers.d.ts.map +1 -1
  169. package/dist/types/src/index.d.ts +3 -4
  170. package/dist/types/src/index.d.ts.map +1 -1
  171. package/dist/types/src/plugin-operation/OperationPlugin.d.ts +3 -0
  172. package/dist/types/src/plugin-operation/OperationPlugin.d.ts.map +1 -0
  173. package/dist/types/src/plugin-operation/history/capability.d.ts +7 -0
  174. package/dist/types/src/plugin-operation/history/capability.d.ts.map +1 -0
  175. package/dist/types/src/plugin-operation/history/errors.d.ts +32 -0
  176. package/dist/types/src/plugin-operation/history/errors.d.ts.map +1 -0
  177. package/dist/types/src/plugin-operation/history/history-tracker.d.ts +18 -0
  178. package/dist/types/src/plugin-operation/history/history-tracker.d.ts.map +1 -0
  179. package/dist/types/src/plugin-operation/history/history-tracker.test.d.ts +2 -0
  180. package/dist/types/src/plugin-operation/history/history-tracker.test.d.ts.map +1 -0
  181. package/dist/types/src/plugin-operation/history/index.d.ts +6 -0
  182. package/dist/types/src/plugin-operation/history/index.d.ts.map +1 -0
  183. package/dist/types/src/plugin-operation/history/types.d.ts +13 -0
  184. package/dist/types/src/plugin-operation/history/types.d.ts.map +1 -0
  185. package/dist/types/src/plugin-operation/history/undo-mapping.d.ts +101 -0
  186. package/dist/types/src/plugin-operation/history/undo-mapping.d.ts.map +1 -0
  187. package/dist/types/src/plugin-operation/history/undo-registry.d.ts +23 -0
  188. package/dist/types/src/plugin-operation/history/undo-registry.d.ts.map +1 -0
  189. package/dist/types/src/plugin-operation/history/undo-registry.test.d.ts +2 -0
  190. package/dist/types/src/plugin-operation/history/undo-registry.test.d.ts.map +1 -0
  191. package/dist/types/src/plugin-operation/index.d.ts +3 -0
  192. package/dist/types/src/plugin-operation/index.d.ts.map +1 -0
  193. package/dist/types/src/plugin-operation/invoker-capability.d.ts +6 -0
  194. package/dist/types/src/plugin-operation/invoker-capability.d.ts.map +1 -0
  195. package/dist/types/src/plugin-operation/meta.d.ts +3 -0
  196. package/dist/types/src/plugin-operation/meta.d.ts.map +1 -0
  197. package/dist/types/src/plugin-operation/testing.d.ts +59 -0
  198. package/dist/types/src/plugin-operation/testing.d.ts.map +1 -0
  199. package/dist/types/src/plugin-runtime/RuntimePlugin.d.ts +3 -0
  200. package/dist/types/src/plugin-runtime/RuntimePlugin.d.ts.map +1 -0
  201. package/dist/types/src/plugin-runtime/capability.d.ts +6 -0
  202. package/dist/types/src/plugin-runtime/capability.d.ts.map +1 -0
  203. package/dist/types/src/plugin-runtime/index.d.ts +2 -0
  204. package/dist/types/src/plugin-runtime/index.d.ts.map +1 -0
  205. package/dist/types/src/plugin-runtime/meta.d.ts +3 -0
  206. package/dist/types/src/plugin-runtime/meta.d.ts.map +1 -0
  207. package/dist/types/src/testing/harness.d.ts +67 -0
  208. package/dist/types/src/testing/harness.d.ts.map +1 -0
  209. package/dist/types/src/testing/index.d.ts +2 -0
  210. package/dist/types/src/testing/index.d.ts.map +1 -1
  211. package/dist/types/src/testing/react.d.ts +27 -0
  212. package/dist/types/src/testing/react.d.ts.map +1 -0
  213. package/dist/types/src/testing/react.test.d.ts +2 -0
  214. package/dist/types/src/testing/react.test.d.ts.map +1 -0
  215. package/dist/types/src/testing/service.d.ts +8 -0
  216. package/dist/types/src/testing/service.d.ts.map +1 -0
  217. package/dist/types/src/testing/withPluginManager.d.ts +8 -9
  218. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  219. package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
  220. package/dist/types/src/ui/components/App/App.d.ts +9 -0
  221. package/dist/types/src/ui/components/App/App.d.ts.map +1 -0
  222. package/dist/types/src/ui/components/App/App.stories.d.ts +19 -0
  223. package/dist/types/src/ui/components/App/App.stories.d.ts.map +1 -0
  224. package/dist/types/src/ui/components/App/index.d.ts +2 -0
  225. package/dist/types/src/ui/components/App/index.d.ts.map +1 -0
  226. package/dist/types/src/ui/components/Placeholder/Placeholder.d.ts +64 -0
  227. package/dist/types/src/ui/components/Placeholder/Placeholder.d.ts.map +1 -0
  228. package/dist/types/src/ui/components/Placeholder/Placeholder.stories.d.ts +19 -0
  229. package/dist/types/src/ui/components/Placeholder/Placeholder.stories.d.ts.map +1 -0
  230. package/dist/types/src/ui/components/Placeholder/index.d.ts +2 -0
  231. package/dist/types/src/ui/components/Placeholder/index.d.ts.map +1 -0
  232. package/dist/types/src/{playground/playground.stories.d.ts → ui/components/PluginManager/PluginManagerContext.stories.d.ts} +5 -4
  233. package/dist/types/src/ui/components/PluginManager/PluginManagerContext.stories.d.ts.map +1 -0
  234. package/dist/types/src/ui/components/PluginManager/PluginManagerProvider.d.ts +10 -0
  235. package/dist/types/src/ui/components/PluginManager/PluginManagerProvider.d.ts.map +1 -0
  236. package/dist/types/src/ui/components/PluginManager/index.d.ts +2 -0
  237. package/dist/types/src/ui/components/PluginManager/index.d.ts.map +1 -0
  238. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts +24 -0
  239. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts.map +1 -0
  240. package/dist/types/src/{components/App.stories.d.ts → ui/components/Surface/SurfaceComponent.stories.d.ts} +1 -2
  241. package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts.map +1 -0
  242. package/dist/types/src/ui/components/Surface/SurfaceInfo.d.ts +11 -0
  243. package/dist/types/src/ui/components/Surface/SurfaceInfo.d.ts.map +1 -0
  244. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts +48 -0
  245. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts.map +1 -0
  246. package/dist/types/src/ui/components/Surface/context.d.ts +5 -0
  247. package/dist/types/src/ui/components/Surface/context.d.ts.map +1 -0
  248. package/dist/types/src/ui/components/Surface/index.d.ts +36 -0
  249. package/dist/types/src/ui/components/Surface/index.d.ts.map +1 -0
  250. package/dist/types/src/ui/components/Surface/types.d.ts +197 -0
  251. package/dist/types/src/ui/components/Surface/types.d.ts.map +1 -0
  252. package/dist/types/src/ui/components/Surface/types.test.d.ts +2 -0
  253. package/dist/types/src/ui/components/Surface/types.test.d.ts.map +1 -0
  254. package/dist/types/src/ui/components/index.d.ts +5 -0
  255. package/dist/types/src/ui/components/index.d.ts.map +1 -0
  256. package/dist/types/src/ui/hooks/index.d.ts +6 -0
  257. package/dist/types/src/ui/hooks/index.d.ts.map +1 -0
  258. package/dist/types/src/ui/hooks/useApp.d.ts +89 -0
  259. package/dist/types/src/ui/hooks/useApp.d.ts.map +1 -0
  260. package/dist/types/src/ui/hooks/useApp.test.d.ts +2 -0
  261. package/dist/types/src/ui/hooks/useApp.test.d.ts.map +1 -0
  262. package/dist/types/src/ui/hooks/useCapabilities.d.ts +31 -0
  263. package/dist/types/src/ui/hooks/useCapabilities.d.ts.map +1 -0
  264. package/dist/types/src/{components → ui/hooks}/useLoading.d.ts +1 -2
  265. package/dist/types/src/ui/hooks/useLoading.d.ts.map +1 -0
  266. package/dist/types/src/ui/hooks/useSettingsState.d.ts +10 -0
  267. package/dist/types/src/ui/hooks/useSettingsState.d.ts.map +1 -0
  268. package/dist/types/src/ui/hooks/useSurface.d.ts +3 -0
  269. package/dist/types/src/ui/hooks/useSurface.d.ts.map +1 -0
  270. package/dist/types/src/ui/index.d.ts +3 -0
  271. package/dist/types/src/ui/index.d.ts.map +1 -0
  272. package/dist/types/src/vite-plugin/boot-loader/BootLoader.stories.d.ts +34 -0
  273. package/dist/types/src/vite-plugin/boot-loader/BootLoader.stories.d.ts.map +1 -0
  274. package/dist/types/src/vite-plugin/boot-loader/index.d.ts +2 -0
  275. package/dist/types/src/vite-plugin/boot-loader/index.d.ts.map +1 -0
  276. package/dist/types/src/vite-plugin/boot-loader/loader.d.ts +51 -0
  277. package/dist/types/src/vite-plugin/boot-loader/loader.d.ts.map +1 -0
  278. package/dist/types/src/vite-plugin/composer/index.d.ts +34 -0
  279. package/dist/types/src/vite-plugin/composer/index.d.ts.map +1 -0
  280. package/dist/types/src/vite-plugin/import-map/index.d.ts +28 -0
  281. package/dist/types/src/vite-plugin/import-map/index.d.ts.map +1 -0
  282. package/dist/types/src/vite-plugin/index.d.ts +5 -0
  283. package/dist/types/src/vite-plugin/index.d.ts.map +1 -0
  284. package/dist/types/src/vite-plugin/manifest.d.ts +41 -0
  285. package/dist/types/src/vite-plugin/manifest.d.ts.map +1 -0
  286. package/dist/types/src/vite-plugin/manifest.test.d.ts +2 -0
  287. package/dist/types/src/vite-plugin/manifest.test.d.ts.map +1 -0
  288. package/dist/types/src/vite-plugin/packages.d.ts +13 -0
  289. package/dist/types/src/vite-plugin/packages.d.ts.map +1 -0
  290. package/dist/types/tsconfig.tsbuildinfo +1 -1
  291. package/moon.yml +26 -3
  292. package/package.json +114 -54
  293. package/src/cli/cli.ts +107 -0
  294. package/src/{playground/logger → cli}/index.ts +1 -1
  295. package/src/common/activation-events.ts +44 -0
  296. package/src/{components/index.ts → common/annotations.ts} +0 -2
  297. package/src/common/capabilities.ts +169 -195
  298. package/src/common/index.ts +4 -8
  299. package/src/common/operations.ts +35 -0
  300. package/src/common/translations.ts +18 -10
  301. package/src/context.ts +9 -0
  302. package/src/core/{events.ts → activation-event.ts} +10 -7
  303. package/src/core/capability-manager.test.ts +151 -0
  304. package/src/core/capability-manager.ts +192 -0
  305. package/src/core/capability.ts +247 -0
  306. package/src/core/edge-registry-plugin-provider.ts +92 -0
  307. package/src/core/index.ts +11 -4
  308. package/src/core/plugin-asset-cache.ts +60 -0
  309. package/src/core/plugin-manager.test.ts +1671 -0
  310. package/src/core/plugin-manager.ts +1335 -0
  311. package/src/core/plugin-manifest.test.ts +75 -0
  312. package/src/core/plugin-manifest.ts +134 -0
  313. package/src/core/plugin.ts +369 -43
  314. package/src/core/registry.ts +157 -0
  315. package/src/core/url-loader.test.ts +221 -0
  316. package/src/core/url-loader.ts +388 -0
  317. package/src/index.ts +3 -4
  318. package/src/plugin-operation/OperationPlugin.ts +24 -0
  319. package/src/plugin-operation/history/capability.ts +36 -0
  320. package/src/plugin-operation/history/errors.ts +7 -0
  321. package/src/plugin-operation/history/history-tracker.test.ts +374 -0
  322. package/src/plugin-operation/history/history-tracker.ts +128 -0
  323. package/src/plugin-operation/history/index.ts +9 -0
  324. package/src/plugin-operation/history/types.ts +17 -0
  325. package/src/plugin-operation/history/undo-mapping.ts +135 -0
  326. package/src/plugin-operation/history/undo-registry.test.ts +72 -0
  327. package/src/plugin-operation/history/undo-registry.ts +54 -0
  328. package/src/plugin-operation/index.ts +6 -0
  329. package/src/plugin-operation/invoker-capability.ts +55 -0
  330. package/src/plugin-operation/meta.ts +12 -0
  331. package/src/plugin-operation/testing.ts +155 -0
  332. package/src/plugin-runtime/RuntimePlugin.ts +19 -0
  333. package/src/plugin-runtime/capability.ts +53 -0
  334. package/src/plugin-runtime/index.ts +5 -0
  335. package/src/plugin-runtime/meta.ts +12 -0
  336. package/src/testing/harness.ts +229 -0
  337. package/src/testing/index.ts +2 -0
  338. package/src/testing/react.test.tsx +48 -0
  339. package/src/testing/react.tsx +113 -0
  340. package/src/testing/service.ts +52 -0
  341. package/src/testing/withPluginManager.stories.tsx +9 -10
  342. package/src/testing/withPluginManager.tsx +74 -50
  343. package/src/ui/components/App/App.stories.tsx +88 -0
  344. package/src/ui/components/App/App.tsx +81 -0
  345. package/src/{playground/layout → ui/components/App}/index.ts +1 -1
  346. package/src/ui/components/Placeholder/Placeholder.stories.tsx +77 -0
  347. package/src/ui/components/Placeholder/Placeholder.tsx +155 -0
  348. package/src/{playground/debug → ui/components/Placeholder}/index.ts +1 -1
  349. package/src/ui/components/PluginManager/PluginManagerContext.stories.tsx +185 -0
  350. package/src/{react → ui/components/PluginManager}/PluginManagerProvider.ts +3 -3
  351. package/src/ui/components/PluginManager/index.ts +5 -0
  352. package/src/ui/components/Surface/SurfaceComponent.stories.tsx +144 -0
  353. package/src/ui/components/Surface/SurfaceComponent.tsx +303 -0
  354. package/src/ui/components/Surface/SurfaceInfo.tsx +106 -0
  355. package/src/ui/components/Surface/SurfaceProfilerContext.tsx +207 -0
  356. package/src/ui/components/Surface/context.ts +12 -0
  357. package/src/ui/components/Surface/index.ts +54 -0
  358. package/src/ui/components/Surface/types.test.ts +126 -0
  359. package/src/ui/components/Surface/types.ts +269 -0
  360. package/src/ui/components/index.ts +8 -0
  361. package/src/ui/hooks/index.ts +9 -0
  362. package/src/ui/hooks/useApp.test.tsx +159 -0
  363. package/src/ui/hooks/useApp.tsx +424 -0
  364. package/src/ui/hooks/useCapabilities.ts +67 -0
  365. package/src/{components → ui/hooks}/useLoading.tsx +16 -10
  366. package/src/ui/hooks/useSettingsState.ts +26 -0
  367. package/src/ui/hooks/useSurface.ts +13 -0
  368. package/src/ui/index.ts +6 -0
  369. package/src/vite-plugin/boot-loader/BootLoader.stories.tsx +270 -0
  370. package/src/vite-plugin/boot-loader/boot-loader.css +320 -0
  371. package/src/vite-plugin/boot-loader/boot-loader.js +325 -0
  372. package/src/vite-plugin/boot-loader/index.ts +5 -0
  373. package/src/vite-plugin/boot-loader/loader.ts +123 -0
  374. package/src/vite-plugin/composer/index.ts +306 -0
  375. package/src/vite-plugin/import-map/index.ts +527 -0
  376. package/src/vite-plugin/index.ts +10 -0
  377. package/src/vite-plugin/manifest.test.ts +46 -0
  378. package/src/vite-plugin/manifest.ts +57 -0
  379. package/src/vite-plugin/packages.ts +187 -0
  380. package/tsconfig.json +24 -15
  381. package/tsconfig.node.json +2 -4
  382. package/typedoc.json +2 -4
  383. package/vitest.config.ts +8 -6
  384. package/.swc/plugins/linux_x86_64_19.0.0/727453fb3a62f7f1d952a41e051ca8a6f88cadc45cee43c6a4d1aa45f9b75665.wasmer-v7 +0 -0
  385. package/.swc/plugins/linux_x86_64_19.0.0/fce1bdb8e20a094e4af08bad09cc81497ed0e2e7c51223b07d371063cca18429.wasmer-v7 +0 -0
  386. package/dist/lib/browser/app-graph-builder-AFFC6VB2.mjs +0 -137
  387. package/dist/lib/browser/app-graph-builder-AFFC6VB2.mjs.map +0 -7
  388. package/dist/lib/browser/chunk-ORWHM7CO.mjs +0 -32
  389. package/dist/lib/browser/chunk-ORWHM7CO.mjs.map +0 -7
  390. package/dist/lib/browser/chunk-OZY7HV2A.mjs +0 -1643
  391. package/dist/lib/browser/chunk-OZY7HV2A.mjs.map +0 -7
  392. package/dist/lib/browser/chunk-T6M7JB7M.mjs +0 -471
  393. package/dist/lib/browser/chunk-T6M7JB7M.mjs.map +0 -7
  394. package/dist/lib/browser/intent-dispatcher-QG7UPGQX.mjs +0 -11
  395. package/dist/lib/browser/intent-resolver-4S4PSTM5.mjs +0 -39
  396. package/dist/lib/browser/intent-resolver-4S4PSTM5.mjs.map +0 -7
  397. package/dist/lib/browser/store-6E33KLGK.mjs +0 -30
  398. package/dist/lib/browser/store-6E33KLGK.mjs.map +0 -7
  399. package/dist/lib/browser/worker.mjs +0 -85
  400. package/dist/lib/node-esm/app-graph-builder-S4OAULX5.mjs +0 -138
  401. package/dist/lib/node-esm/app-graph-builder-S4OAULX5.mjs.map +0 -7
  402. package/dist/lib/node-esm/chunk-F63ZRXMK.mjs +0 -1645
  403. package/dist/lib/node-esm/chunk-F63ZRXMK.mjs.map +0 -7
  404. package/dist/lib/node-esm/chunk-HJFU7QOR.mjs +0 -472
  405. package/dist/lib/node-esm/chunk-HJFU7QOR.mjs.map +0 -7
  406. package/dist/lib/node-esm/chunk-UMZQERLE.mjs +0 -34
  407. package/dist/lib/node-esm/chunk-UMZQERLE.mjs.map +0 -7
  408. package/dist/lib/node-esm/intent-dispatcher-NXBGPJOX.mjs +0 -12
  409. package/dist/lib/node-esm/intent-resolver-2ZKXI5ET.mjs +0 -40
  410. package/dist/lib/node-esm/intent-resolver-2ZKXI5ET.mjs.map +0 -7
  411. package/dist/lib/node-esm/store-QQUTQHHT.mjs +0 -31
  412. package/dist/lib/node-esm/store-QQUTQHHT.mjs.map +0 -7
  413. package/dist/lib/node-esm/worker.mjs +0 -86
  414. package/dist/types/src/common/collaboration.d.ts +0 -20
  415. package/dist/types/src/common/collaboration.d.ts.map +0 -1
  416. package/dist/types/src/common/events.d.ts +0 -52
  417. package/dist/types/src/common/events.d.ts.map +0 -1
  418. package/dist/types/src/common/file.d.ts +0 -14
  419. package/dist/types/src/common/file.d.ts.map +0 -1
  420. package/dist/types/src/common/graph.d.ts +0 -21
  421. package/dist/types/src/common/graph.d.ts.map +0 -1
  422. package/dist/types/src/common/layout.d.ts +0 -281
  423. package/dist/types/src/common/layout.d.ts.map +0 -1
  424. package/dist/types/src/common/surface.d.ts +0 -65
  425. package/dist/types/src/common/surface.d.ts.map +0 -1
  426. package/dist/types/src/components/App.d.ts +0 -10
  427. package/dist/types/src/components/App.d.ts.map +0 -1
  428. package/dist/types/src/components/App.stories.d.ts.map +0 -1
  429. package/dist/types/src/components/DefaultFallback.d.ts +0 -8
  430. package/dist/types/src/components/DefaultFallback.d.ts.map +0 -1
  431. package/dist/types/src/components/index.d.ts +0 -2
  432. package/dist/types/src/components/index.d.ts.map +0 -1
  433. package/dist/types/src/components/useApp.d.ts +0 -44
  434. package/dist/types/src/components/useApp.d.ts.map +0 -1
  435. package/dist/types/src/components/useLoading.d.ts.map +0 -1
  436. package/dist/types/src/core/capabilities.d.ts +0 -117
  437. package/dist/types/src/core/capabilities.d.ts.map +0 -1
  438. package/dist/types/src/core/capabilities.test.d.ts +0 -2
  439. package/dist/types/src/core/capabilities.test.d.ts.map +0 -1
  440. package/dist/types/src/core/events.d.ts.map +0 -1
  441. package/dist/types/src/core/manager.d.ts +0 -126
  442. package/dist/types/src/core/manager.d.ts.map +0 -1
  443. package/dist/types/src/core/manager.test.d.ts +0 -2
  444. package/dist/types/src/core/manager.test.d.ts.map +0 -1
  445. package/dist/types/src/playground/debug/Debug.d.ts +0 -6
  446. package/dist/types/src/playground/debug/Debug.d.ts.map +0 -1
  447. package/dist/types/src/playground/debug/index.d.ts +0 -2
  448. package/dist/types/src/playground/debug/index.d.ts.map +0 -1
  449. package/dist/types/src/playground/debug/plugin.d.ts +0 -2
  450. package/dist/types/src/playground/debug/plugin.d.ts.map +0 -1
  451. package/dist/types/src/playground/generator/Main.d.ts +0 -6
  452. package/dist/types/src/playground/generator/Main.d.ts.map +0 -1
  453. package/dist/types/src/playground/generator/Toolbar.d.ts +0 -6
  454. package/dist/types/src/playground/generator/Toolbar.d.ts.map +0 -1
  455. package/dist/types/src/playground/generator/generator.d.ts +0 -7
  456. package/dist/types/src/playground/generator/generator.d.ts.map +0 -1
  457. package/dist/types/src/playground/generator/index.d.ts +0 -3
  458. package/dist/types/src/playground/generator/index.d.ts.map +0 -1
  459. package/dist/types/src/playground/generator/plugin.d.ts +0 -2
  460. package/dist/types/src/playground/generator/plugin.d.ts.map +0 -1
  461. package/dist/types/src/playground/layout/Layout.d.ts +0 -8
  462. package/dist/types/src/playground/layout/Layout.d.ts.map +0 -1
  463. package/dist/types/src/playground/layout/index.d.ts +0 -2
  464. package/dist/types/src/playground/layout/index.d.ts.map +0 -1
  465. package/dist/types/src/playground/layout/plugin.d.ts +0 -2
  466. package/dist/types/src/playground/layout/plugin.d.ts.map +0 -1
  467. package/dist/types/src/playground/logger/Toolbar.d.ts +0 -6
  468. package/dist/types/src/playground/logger/Toolbar.d.ts.map +0 -1
  469. package/dist/types/src/playground/logger/index.d.ts +0 -2
  470. package/dist/types/src/playground/logger/index.d.ts.map +0 -1
  471. package/dist/types/src/playground/logger/plugin.d.ts +0 -2
  472. package/dist/types/src/playground/logger/plugin.d.ts.map +0 -1
  473. package/dist/types/src/playground/logger/schema.d.ts +0 -13
  474. package/dist/types/src/playground/logger/schema.d.ts.map +0 -1
  475. package/dist/types/src/playground/playground.stories.d.ts.map +0 -1
  476. package/dist/types/src/plugin-intent/IntentPlugin.d.ts +0 -2
  477. package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +0 -1
  478. package/dist/types/src/plugin-intent/actions.d.ts +0 -38
  479. package/dist/types/src/plugin-intent/actions.d.ts.map +0 -1
  480. package/dist/types/src/plugin-intent/errors.d.ts +0 -16
  481. package/dist/types/src/plugin-intent/errors.d.ts.map +0 -1
  482. package/dist/types/src/plugin-intent/index.d.ts +0 -6
  483. package/dist/types/src/plugin-intent/index.d.ts.map +0 -1
  484. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +0 -139
  485. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +0 -1
  486. package/dist/types/src/plugin-intent/intent-dispatcher.test.d.ts +0 -2
  487. package/dist/types/src/plugin-intent/intent-dispatcher.test.d.ts.map +0 -1
  488. package/dist/types/src/plugin-intent/intent.d.ts +0 -63
  489. package/dist/types/src/plugin-intent/intent.d.ts.map +0 -1
  490. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts +0 -2
  491. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +0 -1
  492. package/dist/types/src/plugin-settings/actions.d.ts +0 -27
  493. package/dist/types/src/plugin-settings/actions.d.ts.map +0 -1
  494. package/dist/types/src/plugin-settings/app-graph-builder.d.ts +0 -4
  495. package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +0 -1
  496. package/dist/types/src/plugin-settings/index.d.ts +0 -3
  497. package/dist/types/src/plugin-settings/index.d.ts.map +0 -1
  498. package/dist/types/src/plugin-settings/intent-resolver.d.ts +0 -4
  499. package/dist/types/src/plugin-settings/intent-resolver.d.ts.map +0 -1
  500. package/dist/types/src/plugin-settings/store.d.ts +0 -5
  501. package/dist/types/src/plugin-settings/store.d.ts.map +0 -1
  502. package/dist/types/src/plugin-settings/translations.d.ts +0 -10
  503. package/dist/types/src/plugin-settings/translations.d.ts.map +0 -1
  504. package/dist/types/src/react/ErrorBoundary.d.ts +0 -30
  505. package/dist/types/src/react/ErrorBoundary.d.ts.map +0 -1
  506. package/dist/types/src/react/IntentContext.d.ts +0 -8
  507. package/dist/types/src/react/IntentContext.d.ts.map +0 -1
  508. package/dist/types/src/react/PluginManagerProvider.d.ts +0 -10
  509. package/dist/types/src/react/PluginManagerProvider.d.ts.map +0 -1
  510. package/dist/types/src/react/Surface.d.ts +0 -12
  511. package/dist/types/src/react/Surface.d.ts.map +0 -1
  512. package/dist/types/src/react/Surface.stories.d.ts +0 -18
  513. package/dist/types/src/react/Surface.stories.d.ts.map +0 -1
  514. package/dist/types/src/react/common.d.ts +0 -13
  515. package/dist/types/src/react/common.d.ts.map +0 -1
  516. package/dist/types/src/react/index.d.ts +0 -7
  517. package/dist/types/src/react/index.d.ts.map +0 -1
  518. package/dist/types/src/react/useCapabilities.d.ts +0 -13
  519. package/dist/types/src/react/useCapabilities.d.ts.map +0 -1
  520. package/dist/types/src/react/useIntentResolver.d.ts +0 -3
  521. package/dist/types/src/react/useIntentResolver.d.ts.map +0 -1
  522. package/dist/types/src/worker.d.ts +0 -4
  523. package/dist/types/src/worker.d.ts.map +0 -1
  524. package/src/common/collaboration.ts +0 -18
  525. package/src/common/events.ts +0 -79
  526. package/src/common/file.ts +0 -22
  527. package/src/common/graph.ts +0 -30
  528. package/src/common/layout.ts +0 -278
  529. package/src/common/surface.ts +0 -86
  530. package/src/components/App.stories.tsx +0 -35
  531. package/src/components/App.tsx +0 -59
  532. package/src/components/DefaultFallback.tsx +0 -26
  533. package/src/components/useApp.tsx +0 -166
  534. package/src/core/capabilities.test.ts +0 -136
  535. package/src/core/capabilities.ts +0 -259
  536. package/src/core/manager.test.ts +0 -516
  537. package/src/core/manager.ts +0 -597
  538. package/src/playground/debug/Debug.tsx +0 -39
  539. package/src/playground/debug/plugin.ts +0 -17
  540. package/src/playground/generator/Main.tsx +0 -71
  541. package/src/playground/generator/Toolbar.tsx +0 -47
  542. package/src/playground/generator/generator.ts +0 -48
  543. package/src/playground/generator/index.ts +0 -6
  544. package/src/playground/generator/plugin.ts +0 -23
  545. package/src/playground/layout/Layout.tsx +0 -33
  546. package/src/playground/layout/plugin.ts +0 -17
  547. package/src/playground/logger/Toolbar.tsx +0 -30
  548. package/src/playground/logger/plugin.ts +0 -37
  549. package/src/playground/logger/schema.ts +0 -12
  550. package/src/playground/playground.stories.tsx +0 -47
  551. package/src/plugin-intent/IntentPlugin.ts +0 -21
  552. package/src/plugin-intent/actions.ts +0 -33
  553. package/src/plugin-intent/errors.ts +0 -39
  554. package/src/plugin-intent/index.ts +0 -9
  555. package/src/plugin-intent/intent-dispatcher.test.ts +0 -279
  556. package/src/plugin-intent/intent-dispatcher.ts +0 -335
  557. package/src/plugin-intent/intent.ts +0 -154
  558. package/src/plugin-settings/SettingsPlugin.ts +0 -36
  559. package/src/plugin-settings/actions.ts +0 -29
  560. package/src/plugin-settings/app-graph-builder.ts +0 -158
  561. package/src/plugin-settings/index.ts +0 -6
  562. package/src/plugin-settings/intent-resolver.ts +0 -35
  563. package/src/plugin-settings/store.ts +0 -33
  564. package/src/plugin-settings/translations.ts +0 -19
  565. package/src/react/ErrorBoundary.tsx +0 -54
  566. package/src/react/IntentContext.tsx +0 -35
  567. package/src/react/Surface.stories.tsx +0 -104
  568. package/src/react/Surface.tsx +0 -78
  569. package/src/react/common.ts +0 -13
  570. package/src/react/index.ts +0 -10
  571. package/src/react/useCapabilities.ts +0 -31
  572. package/src/react/useIntentResolver.ts +0 -22
  573. package/src/worker.ts +0 -11
  574. /package/dist/lib/{node-esm/worker.mjs.map → browser/chunk-J5LGTIGS.mjs.map} +0 -0
  575. /package/dist/lib/{node-esm/intent-dispatcher-NXBGPJOX.mjs.map → browser/common/activation-events.mjs.map} +0 -0
  576. /package/dist/lib/browser/{worker.mjs.map → common/capabilities.mjs.map} +0 -0
  577. /package/dist/lib/browser/{intent-dispatcher-QG7UPGQX.mjs.map → core/activation-event.mjs.map} +0 -0
@@ -0,0 +1,75 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import * as PluginManifest from './plugin-manifest';
8
+
9
+ describe('PluginManifest', () => {
10
+ describe('parse', () => {
11
+ test('resolves entry and assets relative to manifest URL', ({ expect }) => {
12
+ const resolved = PluginManifest.parse('https://example.com/plugins/foo/manifest.json', {
13
+ id: 'com.example.foo',
14
+ name: 'Foo',
15
+ version: '1.0.0',
16
+ assets: ['index.mjs', 'style.css', 'chunks/lib-abc.js'],
17
+ });
18
+ expect(resolved.id).toBe('com.example.foo');
19
+ expect(resolved.dev).toBe(false);
20
+ expect(resolved.entryUrl).toBe('https://example.com/plugins/foo/index.mjs');
21
+ expect(resolved.assetUrls).toEqual([
22
+ 'https://example.com/plugins/foo/index.mjs',
23
+ 'https://example.com/plugins/foo/style.css',
24
+ 'https://example.com/plugins/foo/chunks/lib-abc.js',
25
+ ]);
26
+ });
27
+
28
+ test('throws if the canonical entry filename is not listed in assets', ({ expect }) => {
29
+ expect(() =>
30
+ PluginManifest.parse('https://example.com/manifest.json', {
31
+ id: 'a',
32
+ name: 'A',
33
+ version: '0.0.1',
34
+ assets: ['style.css'],
35
+ }),
36
+ ).toThrow();
37
+ });
38
+
39
+ test('throws on missing required fields', ({ expect }) => {
40
+ expect(() =>
41
+ PluginManifest.parse('https://example.com/manifest.json', {
42
+ name: 'A',
43
+ version: '0.0.1',
44
+ assets: ['index.mjs'],
45
+ }),
46
+ ).toThrow();
47
+ });
48
+
49
+ test('devEntry flips dev mode and resolves the entry against the manifest URL', ({ expect }) => {
50
+ const resolved = PluginManifest.parse('http://localhost:3967/manifest.json', {
51
+ id: 'com.example.foo',
52
+ name: 'Foo',
53
+ version: '0.0.0-dev',
54
+ assets: [],
55
+ devEntry: 'src/plugin.tsx',
56
+ });
57
+ expect(resolved.dev).toBe(true);
58
+ expect(resolved.entryUrl).toBe('http://localhost:3967/src/plugin.tsx');
59
+ expect(resolved.assetUrls).toEqual([]);
60
+ });
61
+
62
+ test('devEntry waives the canonical-entry-in-assets requirement', ({ expect }) => {
63
+ // No `index.mjs` in assets — would throw without devEntry.
64
+ expect(() =>
65
+ PluginManifest.parse('http://localhost:3967/manifest.json', {
66
+ id: 'a',
67
+ name: 'A',
68
+ version: '0.0.0-dev',
69
+ assets: [],
70
+ devEntry: 'src/plugin.tsx',
71
+ }),
72
+ ).not.toThrow();
73
+ });
74
+ });
75
+ });
@@ -0,0 +1,134 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as FetchHttpClient from '@effect/platform/FetchHttpClient';
6
+ import * as HttpClient from '@effect/platform/HttpClient';
7
+ import * as HttpClientRequest from '@effect/platform/HttpClientRequest';
8
+ import * as HttpClientResponse from '@effect/platform/HttpClientResponse';
9
+ import * as Effect from 'effect/Effect';
10
+ import * as Schema from 'effect/Schema';
11
+
12
+ import { BaseError } from '@dxos/errors';
13
+ import { PLUGIN_ENTRY_FILENAME } from '@dxos/protocols';
14
+
15
+ /**
16
+ * Default port the Vite plugin (`composerPlugin`) binds the dev server to.
17
+ *
18
+ * Shared single source of truth — `composerPlugin` reads it as the default
19
+ * port, and the host's "Load Dev Plugin" affordance pre-fills the manifest URL
20
+ * with `http://localhost:${PLUGIN_DEV_SERVER_PORT}/manifest.json`. Lives in
21
+ * app-framework rather than `@dxos/protocols` because the constant is a
22
+ * client-side convention (host loader + Vite plugin) rather than a wire-level
23
+ * protocol.
24
+ */
25
+ export const PLUGIN_DEV_SERVER_PORT = 3967;
26
+
27
+ /**
28
+ * Tagged error for manifest fetch / parse failures. Construction sites set
29
+ * `context.manifestUrl` and `context.reason` (one of `'fetch-failed' |
30
+ * 'http-error' | 'parse-failed' | 'invalid'`) so handlers can route on the
31
+ * specific failure mode.
32
+ */
33
+ export class PluginManifestError extends BaseError.extend('PluginManifestError', 'Plugin manifest is invalid') {}
34
+
35
+ /**
36
+ * Schema for a third-party plugin manifest.
37
+ *
38
+ * Production manifests are published as a sibling of the plugin's entry module
39
+ * ({@link PLUGIN_ENTRY_FILENAME}) and advertise every file the plugin needs at
40
+ * runtime so the host can eagerly cache them for offline use.
41
+ *
42
+ * Dev manifests (served by `vite dev` via {@link composerPlugin}) set `devEntry`
43
+ * to point at the unbundled source entry. The host's loader treats the presence
44
+ * of `devEntry` as the dev-mode signal: it imports the entry directly from the
45
+ * dev server, skips eager asset caching, and skips static stylesheet injection
46
+ * (Vite handles CSS via runtime `<style>` injection during HMR). `assets` is not
47
+ * required to enumerate every file in dev mode — chunks and styles flow through
48
+ * the dev server on demand.
49
+ */
50
+ export const Manifest = Schema.Struct({
51
+ id: Schema.String,
52
+ name: Schema.String,
53
+ version: Schema.String,
54
+ assets: Schema.Array(Schema.String),
55
+ devEntry: Schema.String.pipe(Schema.optional),
56
+ });
57
+
58
+ export type Manifest = Schema.Schema.Type<typeof Manifest>;
59
+
60
+ /**
61
+ * Resolved manifest with all asset paths converted to absolute URLs.
62
+ *
63
+ * `dev` reflects whether the source manifest declared a `devEntry`. Loaders branch
64
+ * on this to skip offline caching and stylesheet injection — both are no-ops (or
65
+ * actively wrong) when the plugin is being served by a Vite dev server.
66
+ */
67
+ export type ResolvedManifest = {
68
+ id: string;
69
+ name: string;
70
+ version: string;
71
+ entryUrl: string;
72
+ assetUrls: readonly string[];
73
+ dev: boolean;
74
+ };
75
+
76
+ /**
77
+ * Resolves a parsed manifest's relative asset paths against the manifest's URL.
78
+ * In dev mode the entry comes from `devEntry`; otherwise it's the canonical
79
+ * {@link PLUGIN_ENTRY_FILENAME} sitting next to the manifest.
80
+ */
81
+ const resolve = (manifestUrl: string, manifest: Manifest): ResolvedManifest => {
82
+ const dev = manifest.devEntry !== undefined;
83
+ return {
84
+ id: manifest.id,
85
+ name: manifest.name,
86
+ version: manifest.version,
87
+ entryUrl: new URL(dev ? manifest.devEntry! : PLUGIN_ENTRY_FILENAME, manifestUrl).toString(),
88
+ assetUrls: manifest.assets.map((asset) => new URL(asset, manifestUrl).toString()),
89
+ dev,
90
+ };
91
+ };
92
+
93
+ /**
94
+ * Synchronous decode + validate + resolve for an in-memory manifest payload. Used
95
+ * by tests and tooling that have the manifest body already loaded; the runtime
96
+ * path goes through {@link fetchManifest}.
97
+ */
98
+ export const parse = (manifestUrl: string, payload: unknown): ResolvedManifest => {
99
+ const manifest = Schema.decodeUnknownSync(Manifest)(payload);
100
+ if (manifest.devEntry === undefined && !manifest.assets.includes(PLUGIN_ENTRY_FILENAME)) {
101
+ throw new Error(`Manifest at ${manifestUrl} does not list ${PLUGIN_ENTRY_FILENAME} in assets.`);
102
+ }
103
+ return resolve(manifestUrl, manifest);
104
+ };
105
+
106
+ /**
107
+ * Fetches and parses a manifest from the given URL via Effect's HTTP client and
108
+ * Schema-driven JSON decoding. All failure modes surface as a single tagged
109
+ * {@link PluginManifestError}; callers route on `error.context.reason`.
110
+ */
111
+ export const fetchManifest = (manifestUrl: string): Effect.Effect<ResolvedManifest, PluginManifestError> =>
112
+ Effect.gen(function* () {
113
+ const response = yield* HttpClientRequest.get(manifestUrl).pipe(
114
+ HttpClient.execute,
115
+ Effect.mapError((cause) => new PluginManifestError({ context: { manifestUrl, reason: 'fetch-failed' }, cause })),
116
+ );
117
+ if (response.status >= 400) {
118
+ return yield* Effect.fail(
119
+ new PluginManifestError({ context: { manifestUrl, reason: 'http-error', status: response.status } }),
120
+ );
121
+ }
122
+ const manifest = yield* HttpClientResponse.schemaBodyJson(Manifest)(response).pipe(
123
+ Effect.mapError((cause) => new PluginManifestError({ context: { manifestUrl, reason: 'parse-failed' }, cause })),
124
+ );
125
+ if (manifest.devEntry === undefined && !manifest.assets.includes(PLUGIN_ENTRY_FILENAME)) {
126
+ return yield* Effect.fail(
127
+ new PluginManifestError({
128
+ context: { manifestUrl, reason: 'invalid' },
129
+ cause: `assets does not include ${PLUGIN_ENTRY_FILENAME}`,
130
+ }),
131
+ );
132
+ }
133
+ return resolve(manifestUrl, manifest);
134
+ }).pipe(Effect.scoped, Effect.provide(FetchHttpClient.layer));
@@ -2,12 +2,83 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type MaybePromise } from '@dxos/util';
5
+ import * as Context from 'effect/Context';
6
+ import * as Effect from 'effect/Effect';
7
+ import * as Option from 'effect/Option';
8
+ import * as Pipeable from 'effect/Pipeable';
6
9
 
7
- import { type AnyCapability, type PluginContext } from './capabilities';
8
- import { type ActivationEvent, type ActivationEvents } from './events';
10
+ import { BaseError } from '@dxos/errors';
11
+ import { invariant } from '@dxos/invariant';
9
12
 
10
- interface PluginModuleInterface {
13
+ import type * as ActivationEvent from './activation-event';
14
+ import * as Capability from './capability';
15
+ import type * as PluginManager from './plugin-manager';
16
+
17
+ //
18
+ // Plugin Service Layer
19
+ //
20
+
21
+ /**
22
+ * Effect Context.Tag for accessing PluginManager via the Effect layer system.
23
+ * This allows lifecycle operations to access the plugin manager without having it passed as an argument.
24
+ */
25
+ export class Service extends Context.Tag('@dxos/app-framework/PluginManager')<Service, PluginManager.PluginManager>() {}
26
+
27
+ //
28
+ // Lifecycle Functions
29
+ //
30
+
31
+ /**
32
+ * Activates plugins based on the activation event.
33
+ * Accesses the PluginManager via the Effect layer system.
34
+ * @param event The activation event.
35
+ * @returns Whether the activation was successful.
36
+ */
37
+ export const activate = (event: ActivationEvent.ActivationEvent): Effect.Effect<boolean, Error, Service> =>
38
+ Effect.flatMap(Service, (manager) => manager.activate(event));
39
+
40
+ /**
41
+ * Re-activates the modules that were activated by the event.
42
+ * Accesses the PluginManager via the Effect layer system.
43
+ * @param event The activation event.
44
+ * @returns Whether the reset was successful.
45
+ */
46
+ export const reset = (event: ActivationEvent.ActivationEvent): Effect.Effect<boolean, Error, Service> =>
47
+ Effect.flatMap(Service, (manager) => manager.reset(event));
48
+
49
+ /**
50
+ * Shuts down the plugin manager, deactivating all active modules and clearing lifecycle state.
51
+ * Accesses the PluginManager via the Effect layer system.
52
+ */
53
+ export const shutdown = (): Effect.Effect<boolean, Error, Service> =>
54
+ Effect.flatMap(Service, (manager) => manager.shutdown());
55
+
56
+ /**
57
+ * Computes a module ID from plugin ID and export name.
58
+ */
59
+ const computeModuleId = (pluginId: string, moduleName: string): string => {
60
+ return `${pluginId}.module.${moduleName}`;
61
+ };
62
+
63
+ /**
64
+ * Identifier denoting a PluginModule.
65
+ */
66
+ export const PluginModuleTypeId: unique symbol = Symbol.for('@dxos/app-framework/PluginModule');
67
+ export type PluginModuleTypeId = typeof PluginModuleTypeId;
68
+
69
+ /**
70
+ * Type guard to check if a value is a PluginModule.
71
+ */
72
+ export const isPluginModule = (value: unknown): value is PluginModule => {
73
+ return typeof value === 'object' && value !== null && PluginModuleTypeId in value;
74
+ };
75
+
76
+ /**
77
+ * A unit of containment of modular functionality that can be provided to an application.
78
+ * Activation of a module is async allowing for code to split and loaded lazily.
79
+ */
80
+ export interface PluginModule {
81
+ readonly [PluginModuleTypeId]: PluginModuleTypeId;
11
82
  /**
12
83
  * Unique id of the module.
13
84
  */
@@ -16,63 +87,73 @@ interface PluginModuleInterface {
16
87
  /**
17
88
  * Events for which the module will be activated.
18
89
  */
19
- activatesOn: ActivationEvents;
90
+ activatesOn: ActivationEvent.Events;
20
91
 
21
92
  /**
22
- * Events which the plugin depends on being activated.
23
- * Plugin is marked as needing reset a plugin activated by a dependent event is removed.
24
- * Events are automatically activated before activation of the plugin.
93
+ * Events that this module fires *before* its own activation runs.
94
+ *
95
+ * When this module is asked to activate (via {@link activatesOn}), the
96
+ * plugin manager first activates every event listed here, ensuring any
97
+ * other modules that contribute to those events have completed before
98
+ * this module's {@link activate} body executes. These events are fired
99
+ * by the framework on this module's behalf — the module does not need
100
+ * to wait for some other code to fire them.
101
+ *
102
+ * The module is marked as needing reset if a module activated by one
103
+ * of these events is later removed.
104
+ *
105
+ * Read as: "this module fires these events before [its] activation".
25
106
  */
26
- activatesBefore?: ActivationEvent[];
107
+ firesBeforeActivation?: ActivationEvent.ActivationEvent[];
27
108
 
28
109
  /**
29
- * Events which this plugin triggers upon activation.
110
+ * Events that this module fires *after* its own activation completes.
111
+ *
112
+ * Once this module's {@link activate} body has finished executing, the
113
+ * plugin manager activates every event listed here, causing any modules
114
+ * listening on those events to run. These events are fired by the
115
+ * framework on this module's behalf as part of this module's lifecycle.
116
+ *
117
+ * Read as: "this module fires these events after [its] activation".
30
118
  */
31
- activatesAfter?: ActivationEvent[];
119
+ firesAfterActivation?: ActivationEvent.ActivationEvent[];
32
120
 
33
121
  /**
34
122
  * Called when the module is activated.
35
- * @param context The plugin context.
123
+ * CapabilityManager is accessed via the Effect layer system (Capability.Service).
124
+ * PluginManager is accessed via Plugin.Service.
125
+ * @param props Optional props passed to the module.
36
126
  * @returns The capabilities of the module.
37
127
  */
38
- activate: (
39
- context: PluginContext,
40
- ) => MaybePromise<AnyCapability | AnyCapability[]> | Promise<() => Promise<AnyCapability | AnyCapability[]>>;
128
+ activate: (props?: any) => Effect.Effect<Capability.ModuleReturn, Error, Capability.Service | Service | never>;
41
129
  }
42
130
 
43
- /**
44
- * A unit of containment of modular functionality that can be provided to an application.
45
- * Activation of a module is async allowing for code to split and loaded lazily.
46
- */
47
- // NOTE: This is implemented as a class to prevent it from being proxied by PluginManager state.
48
- export class PluginModule implements PluginModuleInterface {
49
- readonly id: PluginModuleInterface['id'];
50
- readonly activatesOn: PluginModuleInterface['activatesOn'];
51
- readonly activatesBefore?: PluginModuleInterface['activatesBefore'];
52
- readonly activatesAfter?: PluginModuleInterface['activatesAfter'];
53
- readonly activate: PluginModuleInterface['activate'];
131
+ export type PluginModuleOptions = Omit<PluginModule, 'id' | typeof PluginModuleTypeId> & { id?: string };
54
132
 
55
- constructor(options: PluginModuleInterface) {
133
+ class PluginModuleImpl implements PluginModule {
134
+ readonly [PluginModuleTypeId]: PluginModuleTypeId = PluginModuleTypeId;
135
+ readonly id: PluginModule['id'];
136
+ readonly activatesOn: PluginModule['activatesOn'];
137
+ readonly firesBeforeActivation?: PluginModule['firesBeforeActivation'];
138
+ readonly firesAfterActivation?: PluginModule['firesAfterActivation'];
139
+ readonly activate: PluginModule['activate'];
140
+
141
+ constructor(options: Omit<PluginModule, typeof PluginModuleTypeId>) {
56
142
  this.id = options.id;
57
143
  this.activatesOn = options.activatesOn;
58
- this.activatesBefore = options.activatesBefore;
59
- this.activatesAfter = options.activatesAfter;
144
+ this.firesBeforeActivation = options.firesBeforeActivation;
145
+ this.firesAfterActivation = options.firesAfterActivation;
60
146
  this.activate = options.activate;
61
147
  }
62
148
  }
63
149
 
64
- /**
65
- * Helper to define a module.
66
- */
67
- export const defineModule = (options: PluginModuleInterface) => new PluginModule(options);
68
-
69
- export type PluginMeta = {
150
+ export type Meta = {
70
151
  /**
71
152
  * Globally unique ID.
72
153
  *
73
154
  * Expected to be in the form of a valid URL.
74
155
  *
75
- * @example dxos.org/plugin/example
156
+ * @example org.dxos.plugin.example
76
157
  */
77
158
  id: string;
78
159
 
@@ -86,6 +167,11 @@ export type PluginMeta = {
86
167
  */
87
168
  description?: string;
88
169
 
170
+ /**
171
+ * Name of the author or organization that created the plugin.
172
+ */
173
+ author?: string;
174
+
89
175
  /**
90
176
  * URL of home page.
91
177
  */
@@ -110,23 +196,263 @@ export type PluginMeta = {
110
196
  * A grep-able symbol string which can be resolved to an icon asset by @ch-ui/icons, via @ch-ui/vite-plugin-icons.
111
197
  */
112
198
  icon?: string;
199
+
200
+ /**
201
+ * Icon hue (ChromaticPalette).
202
+ */
203
+ iconHue?: string;
204
+ };
205
+
206
+ /**
207
+ * Identifier denoting a Plugin.
208
+ */
209
+ export const PluginTypeId: unique symbol = Symbol.for('@dxos/app-framework/Plugin');
210
+ export type PluginTypeId = typeof PluginTypeId;
211
+
212
+ /**
213
+ * Type guard to check if a value is a Plugin.
214
+ */
215
+ export const isPlugin = (value: unknown): value is Plugin => {
216
+ return typeof value === 'object' && value !== null && PluginTypeId in value;
113
217
  };
114
218
 
115
219
  /**
116
220
  * A collection of modules that are be enabled/disabled as a unit.
117
221
  * Plugins provide things such as components, state, actions, etc. to the application.
118
222
  */
119
- // NOTE: This is implemented as a class to prevent it from being proxied by PluginManager state.
120
- export class Plugin {
223
+ // TODO(burdon): Convert to ECHO schema.
224
+ export interface Plugin {
225
+ readonly [PluginTypeId]: PluginTypeId;
226
+ readonly meta: Readonly<Meta>;
227
+ readonly modules: ReadonlyArray<PluginModule>;
228
+ }
229
+
230
+ /**
231
+ * Internal implementation of Plugin.
232
+ * @internal
233
+ */
234
+ class PluginImpl implements Plugin {
235
+ readonly [PluginTypeId]: PluginTypeId = PluginTypeId;
236
+
121
237
  constructor(
122
- readonly meta: PluginMeta,
123
- readonly modules: PluginModule[],
238
+ private readonly _meta: Meta,
239
+ private readonly _modules: PluginModule[],
124
240
  ) {}
241
+
242
+ get meta(): Readonly<Meta> {
243
+ return this._meta;
244
+ }
245
+
246
+ get modules(): ReadonlyArray<PluginModule> {
247
+ return this._modules;
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Builder interface for creating plugins incrementally.
253
+ */
254
+ export interface PluginBuilder<T = void> extends Pipeable.Pipeable {
255
+ readonly meta: Meta;
256
+ readonly modules: ReadonlyArray<PluginModuleOptions | ((options: T) => PluginModuleOptions)>;
257
+ addModule(moduleOptions: PluginModuleOptions | ((options: T) => PluginModuleOptions)): PluginBuilder<T>;
125
258
  }
126
259
 
127
260
  /**
128
- * Helper to define a plugin.
261
+ * Builder implementation for creating plugins incrementally.
129
262
  */
130
- export const definePlugin = (meta: PluginMeta, modules: PluginModule[]) => {
131
- return new Plugin(meta, modules);
263
+ class PluginBuilderImpl<T = void> implements PluginBuilder<T> {
264
+ readonly meta: Meta;
265
+ private readonly _modules: Array<PluginModuleOptions | ((options: T) => PluginModuleOptions)> = [];
266
+
267
+ constructor(meta: Meta) {
268
+ this.meta = meta;
269
+ }
270
+
271
+ get modules(): ReadonlyArray<PluginModuleOptions | ((options: T) => PluginModuleOptions)> {
272
+ return this._modules;
273
+ }
274
+
275
+ addModule(moduleOptions: PluginModuleOptions | ((options: T) => PluginModuleOptions)): PluginBuilder<T> {
276
+ this._modules.push(moduleOptions);
277
+ return this;
278
+ }
279
+
280
+ pipe() {
281
+ // eslint-disable-next-line prefer-rest-params
282
+ return Pipeable.pipeArguments(this, arguments);
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Creates a new PluginBuilder to start building a plugin.
288
+ */
289
+ export const define = <T = void>(meta: Meta): PluginBuilder<T> => new PluginBuilderImpl<T>(meta);
290
+
291
+ /**
292
+ * Adds a module to a plugin builder.
293
+ * Supports both pipeline and direct call styles.
294
+ * Modules can be either PluginModuleOptions or functions that receive options.
295
+ */
296
+ export function addModule<T>(
297
+ moduleOptions: PluginModuleOptions | ((options: T) => PluginModuleOptions),
298
+ ): (builder: PluginBuilder<T>) => PluginBuilder<T>;
299
+ export function addModule<T>(
300
+ builder: PluginBuilder<T>,
301
+ moduleOptions: PluginModuleOptions | ((options: T) => PluginModuleOptions),
302
+ ): PluginBuilder<T>;
303
+ export function addModule<T>(
304
+ moduleOptionsOrBuilder: PluginModuleOptions | ((options: T) => PluginModuleOptions) | PluginBuilder<T>,
305
+ moduleOptions?: PluginModuleOptions | ((options: T) => PluginModuleOptions),
306
+ ): ((builder: PluginBuilder<T>) => PluginBuilder<T>) | PluginBuilder<T> {
307
+ // If second arg is provided, it's the direct call style: addModule(builder, moduleOptions)
308
+ if (moduleOptions !== undefined) {
309
+ return (moduleOptionsOrBuilder as PluginBuilder<T>).addModule(moduleOptions);
310
+ }
311
+ // Otherwise it's pipeline style: addModule(moduleOptions) returns a function
312
+ const moduleOpts = moduleOptionsOrBuilder as PluginModuleOptions | ((options: T) => PluginModuleOptions);
313
+ return (builder: PluginBuilder<T>) => builder.addModule(moduleOpts);
314
+ }
315
+
316
+ export type PluginFactory<T = void> = ((options: T) => Plugin) & { meta: Meta };
317
+
318
+ /**
319
+ * Resolves a module from either PluginModuleOptions or a function that returns PluginModuleOptions.
320
+ */
321
+ const resolveModule = (
322
+ meta: Meta,
323
+ module: PluginModuleOptions | ((options: any) => PluginModuleOptions),
324
+ options?: any,
325
+ ): PluginModuleImpl => {
326
+ const moduleOptions = typeof module === 'function' ? module(options) : module;
327
+ const id = Option.fromNullable(moduleOptions.id).pipe(
328
+ Option.match({
329
+ onNone: () => {
330
+ const exportName = Capability.getModuleTag(moduleOptions.activate);
331
+ invariant(exportName, `Plugin module missing name. Plugin: ${meta.id}`);
332
+ return computeModuleId(meta.id, exportName);
333
+ },
334
+ onSome: (id) => computeModuleId(meta.id, id),
335
+ }),
336
+ );
337
+ return new PluginModuleImpl({ ...moduleOptions, id });
338
+ };
339
+
340
+ /**
341
+ * Creates a Plugin from a builder.
342
+ * Supports both pipeline and direct call styles.
343
+ * Always returns a factory function (options: T) => Plugin.
344
+ * When T is void, the function takes no arguments: () => Plugin.
345
+ */
346
+ export function make<T>(builder: PluginBuilder<T>): PluginFactory<T>;
347
+ export function make<T>(builder: PluginBuilder<T>): PluginFactory<T> {
348
+ const meta = builder.meta;
349
+
350
+ const factory = (options: T) => {
351
+ const modules = builder.modules.map((module) => resolveModule(meta, module, options));
352
+ return new PluginImpl(meta, modules);
353
+ };
354
+
355
+ return Object.assign(factory, { meta });
356
+ }
357
+
358
+ //
359
+ // Lazy plugin loading
360
+ //
361
+
362
+ /**
363
+ * Symbol used to tag lazy plugin stubs with their loader closure.
364
+ * Hidden from enumeration so plugin manager iteration / serialization paths
365
+ * don't trip over it.
366
+ */
367
+ const LazyTag: unique symbol = Symbol.for('@dxos/app-framework/Plugin/Lazy');
368
+
369
+ /**
370
+ * Async loader for a lazy plugin's real implementation.
371
+ * The default export of the loaded module must be a `PluginFactory<T>` —
372
+ * i.e. the same shape `Plugin.make` produces.
373
+ */
374
+ export type LazyLoader<T = void> = () => Promise<{ default: PluginFactory<T> }>;
375
+
376
+ /** Internal: payload carried on a lazy stub. */
377
+ type LazyPayload = { loader: LazyLoader<any>; options: unknown };
378
+
379
+ /**
380
+ * Defines a lazy plugin whose body is loaded on first enable.
381
+ *
382
+ * The returned factory produces a stub `Plugin` that exposes `meta`
383
+ * synchronously (so callers can read `Plugin.meta.id` for free) but defers
384
+ * loading the real plugin's modules until the manager calls
385
+ * `Plugin.resolveLazy`. This lets the plugin's main entry point ship as a
386
+ * tiny meta-only chunk — the heavy capabilities, schema, React surfaces,
387
+ * etc. live behind the dynamic `import()` and become a separate Rollup
388
+ * chunk that is only fetched when the plugin is enabled.
389
+ *
390
+ * @example
391
+ * ```ts
392
+ * // plugin-markdown/src/index.ts
393
+ * import { Plugin } from '@dxos/app-framework';
394
+ * import { meta } from './meta';
395
+ *
396
+ * export const MarkdownPlugin = Plugin.lazy(meta, () => import('./MarkdownPlugin'));
397
+ *
398
+ * // plugin-markdown/src/MarkdownPlugin.tsx
399
+ * export const MarkdownPlugin = Plugin.define(meta).pipe(...heavy modules..., Plugin.make);
400
+ * export default MarkdownPlugin;
401
+ * ```
402
+ */
403
+ export const lazy = <T = void>(meta: Meta, loader: LazyLoader<T>): PluginFactory<T> => {
404
+ const factory = (options: T): Plugin => {
405
+ const stub = new PluginImpl(meta, []);
406
+ Object.defineProperty(stub, LazyTag, {
407
+ value: { loader, options } satisfies LazyPayload,
408
+ enumerable: false,
409
+ });
410
+ return stub;
411
+ };
412
+ return Object.assign(factory, { meta });
132
413
  };
414
+
415
+ /**
416
+ * Type guard for lazy plugin stubs produced by {@link lazy}.
417
+ */
418
+ export const isLazy = (plugin: Plugin): boolean => LazyTag in plugin;
419
+
420
+ /**
421
+ * Tagged error for failures during lazy plugin resolution. `context.id` is
422
+ * the lazy plugin's `meta.id`; `context.reason` discriminates the failure
423
+ * mode (`'load-failed' | 'missing-default' | 'invalid-plugin' |
424
+ * 'meta-mismatch'`) so callers can route on it.
425
+ */
426
+ export class LazyPluginError extends BaseError.extend('LazyPluginError', 'Failed to resolve lazy plugin') {}
427
+
428
+ /**
429
+ * Resolves a lazy plugin stub to its real plugin.
430
+ * Returns the plugin unchanged if it is not lazy. Failures surface as
431
+ * {@link LazyPluginError} with `context.reason` indicating the failure mode
432
+ * and (for loader failures) `cause` set to the original error.
433
+ */
434
+ export const resolveLazy = (plugin: Plugin): Effect.Effect<Plugin, LazyPluginError> =>
435
+ Effect.gen(function* () {
436
+ if (!isLazy(plugin)) {
437
+ return plugin;
438
+ }
439
+ const id = plugin.meta.id;
440
+ const { loader, options } = (plugin as unknown as { [LazyTag]: LazyPayload })[LazyTag];
441
+ const mod = yield* Effect.tryPromise({
442
+ try: loader,
443
+ catch: (error) => new LazyPluginError({ context: { id, reason: 'load-failed' }, cause: error }),
444
+ });
445
+ if (!mod || typeof mod.default !== 'function') {
446
+ return yield* Effect.fail(new LazyPluginError({ context: { id, reason: 'missing-default' } }));
447
+ }
448
+ const result = mod.default(options);
449
+ if (!isPlugin(result)) {
450
+ return yield* Effect.fail(new LazyPluginError({ context: { id, reason: 'invalid-plugin' } }));
451
+ }
452
+ if (result.meta.id !== id) {
453
+ return yield* Effect.fail(
454
+ new LazyPluginError({ context: { id, reason: 'meta-mismatch', returnedId: result.meta.id } }),
455
+ );
456
+ }
457
+ return result;
458
+ });