@dxos/app-framework 0.8.4-main.ef1bc66f44 → 0.8.4-main.effb148878

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 (436) hide show
  1. package/.storybook/main.mts +1 -3
  2. package/LICENSE +102 -5
  3. package/README.md +1 -1
  4. package/dist/lib/browser/{capability-DU35RXMD.mjs → capability-C4WE22TJ.mjs} +12 -11
  5. package/dist/lib/browser/capability-C4WE22TJ.mjs.map +7 -0
  6. package/dist/lib/browser/chunk-2ZIYRDAF.mjs +95 -0
  7. package/dist/lib/browser/chunk-2ZIYRDAF.mjs.map +7 -0
  8. package/dist/lib/browser/chunk-5GY3YOEL.mjs +28 -0
  9. package/dist/lib/browser/chunk-5GY3YOEL.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-PKQT6C53.mjs → chunk-66IXTIVK.mjs} +3 -2
  11. package/dist/lib/browser/chunk-66IXTIVK.mjs.map +7 -0
  12. package/dist/lib/browser/chunk-67GCXX5I.mjs +581 -0
  13. package/dist/lib/browser/chunk-67GCXX5I.mjs.map +7 -0
  14. package/dist/lib/browser/chunk-FJ4765WW.mjs +8 -0
  15. package/dist/lib/browser/{chunk-FHQTHCX7.mjs.map → chunk-FJ4765WW.mjs.map} +3 -3
  16. package/dist/lib/browser/chunk-FO3IYSLV.mjs +68 -0
  17. package/dist/lib/browser/chunk-FO3IYSLV.mjs.map +7 -0
  18. package/dist/lib/browser/{chunk-ZQO3UZ4R.mjs → chunk-IW44C7UL.mjs} +10 -4
  19. package/dist/lib/browser/chunk-IW44C7UL.mjs.map +7 -0
  20. package/dist/lib/browser/chunk-KLHQNYJ2.mjs +422 -0
  21. package/dist/lib/browser/chunk-KLHQNYJ2.mjs.map +7 -0
  22. package/dist/lib/browser/{chunk-EIFGKQSA.mjs → chunk-LPWOVOOB.mjs} +14 -42
  23. package/dist/lib/browser/chunk-LPWOVOOB.mjs.map +7 -0
  24. package/dist/lib/browser/{chunk-4DQMLMGU.mjs → chunk-LUQOVTWB.mjs} +13 -14
  25. package/dist/lib/browser/chunk-LUQOVTWB.mjs.map +7 -0
  26. package/dist/lib/browser/{chunk-KWP6PKIU.mjs → chunk-SLX73WRZ.mjs} +92 -19
  27. package/dist/lib/browser/chunk-SLX73WRZ.mjs.map +7 -0
  28. package/dist/lib/browser/chunk-SZMB3K2N.mjs +517 -0
  29. package/dist/lib/browser/chunk-SZMB3K2N.mjs.map +7 -0
  30. package/dist/lib/browser/chunk-VJ5PFAWC.mjs +1446 -0
  31. package/dist/lib/browser/chunk-VJ5PFAWC.mjs.map +7 -0
  32. package/dist/lib/browser/cli/index.mjs +17 -32
  33. package/dist/lib/browser/cli/index.mjs.map +3 -3
  34. package/dist/lib/browser/common/activation-events.mjs +11 -14
  35. package/dist/lib/browser/common/capabilities.mjs +19 -8
  36. package/dist/lib/browser/core/activation-event.mjs +1 -1
  37. package/dist/lib/browser/core/capability.mjs +5 -1
  38. package/dist/lib/browser/core/plugin-manager.mjs +8 -4
  39. package/dist/lib/browser/core/plugin.mjs +16 -4
  40. package/dist/lib/browser/core/url-loader.mjs +24 -0
  41. package/dist/lib/browser/index.mjs +47 -49
  42. package/dist/lib/browser/index.mjs.map +4 -4
  43. package/dist/lib/browser/meta.json +1 -1
  44. package/dist/lib/browser/process-manager-capability-3Q4TA73T.mjs +89 -0
  45. package/dist/lib/browser/process-manager-capability-3Q4TA73T.mjs.map +7 -0
  46. package/dist/lib/browser/testing/index.mjs +199 -52
  47. package/dist/lib/browser/testing/index.mjs.map +4 -4
  48. package/dist/lib/browser/testing/react.mjs +78 -0
  49. package/dist/lib/browser/testing/react.mjs.map +7 -0
  50. package/dist/lib/browser/ui/index.mjs +25 -20
  51. package/dist/lib/node-esm/{capability-SR2EIZFP.mjs → capability-GPN6OS6M.mjs} +12 -11
  52. package/dist/lib/node-esm/capability-GPN6OS6M.mjs.map +7 -0
  53. package/dist/lib/node-esm/{chunk-UEWJDI2L.mjs → chunk-37Z53PXZ.mjs} +2 -2
  54. package/dist/lib/node-esm/{chunk-UEWJDI2L.mjs.map → chunk-37Z53PXZ.mjs.map} +3 -3
  55. package/dist/lib/node-esm/chunk-42UNAKYO.mjs +423 -0
  56. package/dist/lib/node-esm/chunk-42UNAKYO.mjs.map +7 -0
  57. package/dist/lib/node-esm/{chunk-DZ2XLAGI.mjs → chunk-6S45OMUP.mjs} +92 -19
  58. package/dist/lib/node-esm/chunk-6S45OMUP.mjs.map +7 -0
  59. package/dist/lib/node-esm/{chunk-64IMLAS2.mjs → chunk-CTKEZHKF.mjs} +10 -4
  60. package/dist/lib/node-esm/chunk-CTKEZHKF.mjs.map +7 -0
  61. package/dist/lib/node-esm/{chunk-DHSHRYIB.mjs → chunk-FEVJEUD7.mjs} +14 -42
  62. package/dist/lib/node-esm/chunk-FEVJEUD7.mjs.map +7 -0
  63. package/dist/lib/node-esm/chunk-GBHZF46K.mjs +518 -0
  64. package/dist/lib/node-esm/chunk-GBHZF46K.mjs.map +7 -0
  65. package/dist/lib/node-esm/chunk-GUE5V5CG.mjs +582 -0
  66. package/dist/lib/node-esm/chunk-GUE5V5CG.mjs.map +7 -0
  67. package/dist/lib/node-esm/chunk-KFZEB6BV.mjs +29 -0
  68. package/dist/lib/node-esm/chunk-KFZEB6BV.mjs.map +7 -0
  69. package/dist/lib/node-esm/{chunk-J2PHTRHC.mjs → chunk-MXWDXYV2.mjs} +13 -14
  70. package/dist/lib/node-esm/chunk-MXWDXYV2.mjs.map +7 -0
  71. package/dist/lib/node-esm/chunk-QBUGLR4H.mjs +96 -0
  72. package/dist/lib/node-esm/chunk-QBUGLR4H.mjs.map +7 -0
  73. package/dist/lib/node-esm/chunk-SFYCO3PT.mjs +1447 -0
  74. package/dist/lib/node-esm/chunk-SFYCO3PT.mjs.map +7 -0
  75. package/dist/lib/node-esm/chunk-WK7OIQKI.mjs +70 -0
  76. package/dist/lib/node-esm/chunk-WK7OIQKI.mjs.map +7 -0
  77. package/dist/lib/node-esm/{chunk-7OWSHPYK.mjs → chunk-XOCUANHO.mjs} +3 -2
  78. package/dist/lib/node-esm/chunk-XOCUANHO.mjs.map +7 -0
  79. package/dist/lib/node-esm/cli/index.mjs +17 -32
  80. package/dist/lib/node-esm/cli/index.mjs.map +3 -3
  81. package/dist/lib/node-esm/common/activation-events.mjs +11 -14
  82. package/dist/lib/node-esm/common/capabilities.mjs +19 -8
  83. package/dist/lib/node-esm/core/activation-event.mjs +1 -1
  84. package/dist/lib/node-esm/core/capability.mjs +5 -1
  85. package/dist/lib/node-esm/core/plugin-manager.mjs +8 -4
  86. package/dist/lib/node-esm/core/plugin.mjs +16 -4
  87. package/dist/lib/node-esm/core/url-loader.mjs +25 -0
  88. package/dist/lib/node-esm/index.mjs +47 -49
  89. package/dist/lib/node-esm/index.mjs.map +4 -4
  90. package/dist/lib/node-esm/meta.json +1 -1
  91. package/dist/lib/node-esm/process-manager-capability-5KCLSNQM.mjs +90 -0
  92. package/dist/lib/node-esm/process-manager-capability-5KCLSNQM.mjs.map +7 -0
  93. package/dist/lib/node-esm/testing/index.mjs +199 -52
  94. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  95. package/dist/lib/node-esm/testing/react.mjs +79 -0
  96. package/dist/lib/node-esm/testing/react.mjs.map +7 -0
  97. package/dist/lib/node-esm/ui/index.mjs +25 -20
  98. package/dist/plugin/node-esm/index.mjs +893 -0
  99. package/dist/plugin/node-esm/index.mjs.map +7 -0
  100. package/dist/plugin/node-esm/meta.json +1 -0
  101. package/dist/types/src/cli/cli.d.ts +1 -3
  102. package/dist/types/src/cli/cli.d.ts.map +1 -1
  103. package/dist/types/src/common/activation-events.d.ts +10 -13
  104. package/dist/types/src/common/activation-events.d.ts.map +1 -1
  105. package/dist/types/src/common/annotations.d.ts +1 -0
  106. package/dist/types/src/common/annotations.d.ts.map +1 -0
  107. package/dist/types/src/common/capabilities.d.ts +113 -12
  108. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  109. package/dist/types/src/common/operations.d.ts +8 -22
  110. package/dist/types/src/common/operations.d.ts.map +1 -1
  111. package/dist/types/src/core/activation-event.d.ts +5 -5
  112. package/dist/types/src/core/activation-event.d.ts.map +1 -1
  113. package/dist/types/src/core/capability-manager.d.ts +5 -0
  114. package/dist/types/src/core/capability-manager.d.ts.map +1 -1
  115. package/dist/types/src/core/capability.d.ts +19 -8
  116. package/dist/types/src/core/capability.d.ts.map +1 -1
  117. package/dist/types/src/core/edge-registry-plugin-provider.d.ts +30 -0
  118. package/dist/types/src/core/edge-registry-plugin-provider.d.ts.map +1 -0
  119. package/dist/types/src/core/index.d.ts +6 -0
  120. package/dist/types/src/core/index.d.ts.map +1 -1
  121. package/dist/types/src/core/plugin-asset-cache.d.ts +71 -0
  122. package/dist/types/src/core/plugin-asset-cache.d.ts.map +1 -0
  123. package/dist/types/src/core/plugin-manager.d.ts +238 -7
  124. package/dist/types/src/core/plugin-manager.d.ts.map +1 -1
  125. package/dist/types/src/core/plugin-manifest.d.ts +101 -0
  126. package/dist/types/src/core/plugin-manifest.d.ts.map +1 -0
  127. package/dist/types/src/core/plugin-manifest.test.d.ts +2 -0
  128. package/dist/types/src/core/plugin-manifest.test.d.ts.map +1 -0
  129. package/dist/types/src/core/plugin.d.ts +182 -7
  130. package/dist/types/src/core/plugin.d.ts.map +1 -1
  131. package/dist/types/src/core/registry.d.ts +107 -0
  132. package/dist/types/src/core/registry.d.ts.map +1 -0
  133. package/dist/types/src/core/url-loader.d.ts +127 -0
  134. package/dist/types/src/core/url-loader.d.ts.map +1 -0
  135. package/dist/types/src/core/url-loader.test.d.ts +2 -0
  136. package/dist/types/src/core/url-loader.test.d.ts.map +1 -0
  137. package/dist/types/src/helpers.d.ts.map +1 -1
  138. package/dist/types/src/index.d.ts +1 -2
  139. package/dist/types/src/index.d.ts.map +1 -1
  140. package/dist/types/src/plugin-process-manager/ProcessManagerPlugin.d.ts +3 -0
  141. package/dist/types/src/plugin-process-manager/ProcessManagerPlugin.d.ts.map +1 -0
  142. package/dist/types/src/plugin-process-manager/history/capability.d.ts +7 -0
  143. package/dist/types/src/plugin-process-manager/history/capability.d.ts.map +1 -0
  144. package/dist/types/src/plugin-process-manager/history/errors.d.ts +32 -0
  145. package/dist/types/src/plugin-process-manager/history/errors.d.ts.map +1 -0
  146. package/dist/types/src/{plugin-operation → plugin-process-manager}/history/history-tracker.d.ts +1 -1
  147. package/dist/types/src/plugin-process-manager/history/history-tracker.d.ts.map +1 -0
  148. package/dist/types/src/plugin-process-manager/history/history-tracker.test.d.ts.map +1 -0
  149. package/dist/types/src/plugin-process-manager/history/index.d.ts.map +1 -0
  150. package/dist/types/src/{plugin-operation → plugin-process-manager}/history/types.d.ts +1 -1
  151. package/dist/types/src/plugin-process-manager/history/types.d.ts.map +1 -0
  152. package/dist/types/src/{plugin-operation → plugin-process-manager}/history/undo-mapping.d.ts +1 -1
  153. package/dist/types/src/plugin-process-manager/history/undo-mapping.d.ts.map +1 -0
  154. package/dist/types/src/{plugin-operation → plugin-process-manager}/history/undo-registry.d.ts +1 -1
  155. package/dist/types/src/plugin-process-manager/history/undo-registry.d.ts.map +1 -0
  156. package/dist/types/src/plugin-process-manager/history/undo-registry.test.d.ts.map +1 -0
  157. package/dist/types/src/plugin-process-manager/index.d.ts +3 -0
  158. package/dist/types/src/plugin-process-manager/index.d.ts.map +1 -0
  159. package/dist/types/src/plugin-process-manager/meta.d.ts.map +1 -0
  160. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts +8 -0
  161. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts.map +1 -0
  162. package/dist/types/src/plugin-process-manager/testing.d.ts +59 -0
  163. package/dist/types/src/plugin-process-manager/testing.d.ts.map +1 -0
  164. package/dist/types/src/testing/harness.d.ts +79 -0
  165. package/dist/types/src/testing/harness.d.ts.map +1 -0
  166. package/dist/types/src/testing/index.d.ts +1 -0
  167. package/dist/types/src/testing/index.d.ts.map +1 -1
  168. package/dist/types/src/testing/react.d.ts +27 -0
  169. package/dist/types/src/testing/react.d.ts.map +1 -0
  170. package/dist/types/src/testing/react.test.d.ts +2 -0
  171. package/dist/types/src/testing/react.test.d.ts.map +1 -0
  172. package/dist/types/src/testing/service.d.ts.map +1 -1
  173. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  174. package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
  175. package/dist/types/src/ui/components/{App.d.ts → App/App.d.ts} +3 -2
  176. package/dist/types/src/ui/components/App/App.d.ts.map +1 -0
  177. package/dist/types/src/ui/components/{App.stories.d.ts → App/App.stories.d.ts} +6 -1
  178. package/dist/types/src/ui/components/App/App.stories.d.ts.map +1 -0
  179. package/dist/types/src/ui/components/App/index.d.ts +2 -0
  180. package/dist/types/src/ui/components/App/index.d.ts.map +1 -0
  181. package/dist/types/src/ui/components/Placeholder/Placeholder.d.ts +64 -0
  182. package/dist/types/src/ui/components/Placeholder/Placeholder.d.ts.map +1 -0
  183. package/dist/types/src/ui/components/Placeholder/Placeholder.stories.d.ts +19 -0
  184. package/dist/types/src/ui/components/Placeholder/Placeholder.stories.d.ts.map +1 -0
  185. package/dist/types/src/ui/components/Placeholder/index.d.ts +2 -0
  186. package/dist/types/src/ui/components/Placeholder/index.d.ts.map +1 -0
  187. package/dist/types/src/ui/components/PluginManager/PluginManagerContext.stories.d.ts.map +1 -0
  188. package/dist/types/src/ui/components/{PluginManagerProvider.d.ts → PluginManager/PluginManagerProvider.d.ts} +1 -1
  189. package/dist/types/src/ui/components/PluginManager/PluginManagerProvider.d.ts.map +1 -0
  190. package/dist/types/src/ui/components/PluginManager/index.d.ts +2 -0
  191. package/dist/types/src/ui/components/PluginManager/index.d.ts.map +1 -0
  192. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts +24 -0
  193. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts.map +1 -0
  194. package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts.map +1 -0
  195. package/dist/types/src/ui/components/{surface → Surface}/SurfaceInfo.d.ts.map +1 -1
  196. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts +48 -0
  197. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts.map +1 -0
  198. package/dist/types/src/ui/components/{surface → Surface}/context.d.ts.map +1 -1
  199. package/dist/types/src/ui/components/Surface/index.d.ts +36 -0
  200. package/dist/types/src/ui/components/Surface/index.d.ts.map +1 -0
  201. package/dist/types/src/ui/components/Surface/types.d.ts +197 -0
  202. package/dist/types/src/ui/components/Surface/types.d.ts.map +1 -0
  203. package/dist/types/src/ui/components/Surface/types.test.d.ts +2 -0
  204. package/dist/types/src/ui/components/Surface/types.test.d.ts.map +1 -0
  205. package/dist/types/src/ui/components/index.d.ts +3 -3
  206. package/dist/types/src/ui/components/index.d.ts.map +1 -1
  207. package/dist/types/src/ui/hooks/index.d.ts +1 -1
  208. package/dist/types/src/ui/hooks/index.d.ts.map +1 -1
  209. package/dist/types/src/ui/hooks/useApp.d.ts +51 -15
  210. package/dist/types/src/ui/hooks/useApp.d.ts.map +1 -1
  211. package/dist/types/src/ui/hooks/useApp.test.d.ts +2 -0
  212. package/dist/types/src/ui/hooks/useApp.test.d.ts.map +1 -0
  213. package/dist/types/src/ui/hooks/useCapabilities.d.ts.map +1 -1
  214. package/dist/types/src/ui/hooks/useLoading.d.ts.map +1 -1
  215. package/dist/types/src/ui/hooks/useProcessManagerRuntime.d.ts +30 -0
  216. package/dist/types/src/ui/hooks/useProcessManagerRuntime.d.ts.map +1 -0
  217. package/dist/types/src/ui/hooks/useSettingsState.d.ts.map +1 -1
  218. package/dist/types/src/ui/hooks/useSurface.d.ts +2 -2
  219. package/dist/types/src/ui/hooks/useSurface.d.ts.map +1 -1
  220. package/dist/types/src/ui/index.d.ts +0 -1
  221. package/dist/types/src/ui/index.d.ts.map +1 -1
  222. package/dist/types/src/vite-plugin/boot-loader/BootLoader.stories.d.ts +34 -0
  223. package/dist/types/src/vite-plugin/boot-loader/BootLoader.stories.d.ts.map +1 -0
  224. package/dist/types/src/vite-plugin/boot-loader/index.d.ts +2 -0
  225. package/dist/types/src/vite-plugin/boot-loader/index.d.ts.map +1 -0
  226. package/dist/types/src/vite-plugin/boot-loader/loader.d.ts +51 -0
  227. package/dist/types/src/vite-plugin/boot-loader/loader.d.ts.map +1 -0
  228. package/dist/types/src/vite-plugin/composer/index.d.ts +34 -0
  229. package/dist/types/src/vite-plugin/composer/index.d.ts.map +1 -0
  230. package/dist/types/src/vite-plugin/import-map/index.d.ts +28 -0
  231. package/dist/types/src/vite-plugin/import-map/index.d.ts.map +1 -0
  232. package/dist/types/src/vite-plugin/index.d.ts +5 -0
  233. package/dist/types/src/vite-plugin/index.d.ts.map +1 -0
  234. package/dist/types/src/vite-plugin/manifest.d.ts +41 -0
  235. package/dist/types/src/vite-plugin/manifest.d.ts.map +1 -0
  236. package/dist/types/src/vite-plugin/manifest.test.d.ts +2 -0
  237. package/dist/types/src/vite-plugin/manifest.test.d.ts.map +1 -0
  238. package/dist/types/src/vite-plugin/packages.d.ts +13 -0
  239. package/dist/types/src/vite-plugin/packages.d.ts.map +1 -0
  240. package/dist/types/tsconfig.tsbuildinfo +1 -1
  241. package/moon.yml +16 -4
  242. package/package.json +63 -63
  243. package/src/cli/cli.ts +4 -9
  244. package/src/common/activation-events.ts +12 -17
  245. package/src/common/annotations.ts +3 -0
  246. package/src/common/capabilities.ts +160 -29
  247. package/src/common/operations.ts +8 -10
  248. package/src/context.ts +1 -1
  249. package/src/core/activation-event.ts +5 -2
  250. package/src/core/capability-manager.test.ts +1 -1
  251. package/src/core/capability-manager.ts +22 -1
  252. package/src/core/capability.ts +28 -10
  253. package/src/core/edge-registry-plugin-provider.ts +92 -0
  254. package/src/core/index.ts +6 -0
  255. package/src/core/plugin-asset-cache.ts +60 -0
  256. package/src/core/plugin-manager.test.ts +1085 -31
  257. package/src/core/plugin-manager.ts +1180 -189
  258. package/src/core/plugin-manifest.test.ts +75 -0
  259. package/src/core/plugin-manifest.ts +134 -0
  260. package/src/core/plugin.ts +195 -12
  261. package/src/core/registry.ts +163 -0
  262. package/src/core/url-loader.test.ts +221 -0
  263. package/src/core/url-loader.ts +388 -0
  264. package/src/index.ts +1 -2
  265. package/src/plugin-process-manager/ProcessManagerPlugin.ts +24 -0
  266. package/src/{plugin-operation → plugin-process-manager}/history/capability.ts +1 -2
  267. package/src/plugin-process-manager/history/errors.ts +7 -0
  268. package/src/{plugin-operation → plugin-process-manager}/history/history-tracker.test.ts +37 -43
  269. package/src/{plugin-operation → plugin-process-manager}/history/history-tracker.ts +1 -2
  270. package/src/{plugin-operation → plugin-process-manager}/history/types.ts +1 -1
  271. package/src/{plugin-operation → plugin-process-manager}/history/undo-mapping.ts +1 -1
  272. package/src/{plugin-operation → plugin-process-manager}/history/undo-registry.test.ts +3 -4
  273. package/src/{plugin-operation → plugin-process-manager}/history/undo-registry.ts +1 -1
  274. package/src/{plugin-operation → plugin-process-manager}/index.ts +1 -1
  275. package/src/plugin-process-manager/meta.ts +14 -0
  276. package/src/plugin-process-manager/process-manager-capability.ts +178 -0
  277. package/src/{plugin-operation → plugin-process-manager}/testing.ts +26 -45
  278. package/src/testing/harness.ts +247 -0
  279. package/src/testing/index.ts +1 -0
  280. package/src/testing/react.test.tsx +48 -0
  281. package/src/testing/react.tsx +113 -0
  282. package/src/testing/service.ts +4 -4
  283. package/src/testing/withPluginManager.stories.tsx +1 -2
  284. package/src/testing/withPluginManager.tsx +45 -17
  285. package/src/ui/components/App/App.stories.tsx +86 -0
  286. package/src/ui/components/App/App.tsx +81 -0
  287. package/src/{plugin-runtime → ui/components/App}/index.ts +1 -1
  288. package/src/ui/components/Placeholder/Placeholder.stories.tsx +77 -0
  289. package/src/ui/components/Placeholder/Placeholder.tsx +156 -0
  290. package/src/ui/components/Placeholder/index.ts +5 -0
  291. package/src/ui/components/{PluginManagerContext.stories.tsx → PluginManager/PluginManagerContext.stories.tsx} +15 -14
  292. package/src/ui/components/{PluginManagerProvider.ts → PluginManager/PluginManagerProvider.ts} +1 -1
  293. package/src/ui/components/PluginManager/index.ts +5 -0
  294. package/src/ui/components/{surface → Surface}/SurfaceComponent.stories.tsx +25 -23
  295. package/src/ui/components/Surface/SurfaceComponent.tsx +303 -0
  296. package/src/ui/components/{surface → Surface}/SurfaceInfo.tsx +1 -2
  297. package/src/ui/components/Surface/SurfaceProfilerContext.tsx +207 -0
  298. package/src/ui/components/Surface/index.ts +54 -0
  299. package/src/ui/components/Surface/types.test.ts +126 -0
  300. package/src/ui/components/Surface/types.ts +269 -0
  301. package/src/ui/components/index.ts +3 -3
  302. package/src/ui/hooks/index.ts +1 -1
  303. package/src/ui/hooks/useApp.test.tsx +159 -0
  304. package/src/ui/hooks/useApp.tsx +236 -33
  305. package/src/ui/hooks/useCapabilities.ts +2 -1
  306. package/src/ui/hooks/useLoading.tsx +14 -6
  307. package/src/ui/hooks/useProcessManagerRuntime.ts +78 -0
  308. package/src/ui/hooks/useSurface.ts +3 -3
  309. package/src/ui/index.ts +0 -1
  310. package/src/vite-plugin/boot-loader/BootLoader.stories.tsx +270 -0
  311. package/src/vite-plugin/boot-loader/boot-loader.css +320 -0
  312. package/src/vite-plugin/boot-loader/boot-loader.js +325 -0
  313. package/src/vite-plugin/boot-loader/index.ts +5 -0
  314. package/src/vite-plugin/boot-loader/loader.ts +123 -0
  315. package/src/vite-plugin/composer/index.ts +306 -0
  316. package/src/vite-plugin/import-map/index.ts +527 -0
  317. package/src/vite-plugin/index.ts +10 -0
  318. package/src/vite-plugin/manifest.test.ts +46 -0
  319. package/src/vite-plugin/manifest.ts +57 -0
  320. package/src/vite-plugin/packages.ts +187 -0
  321. package/tsconfig.json +28 -1
  322. package/tsconfig.node.json +2 -4
  323. package/typedoc.json +2 -4
  324. package/vitest.config.ts +1 -1
  325. package/.swc/plugins/linux_x86_64_19.0.0/727453fb3a62f7f1d952a41e051ca8a6f88cadc45cee43c6a4d1aa45f9b75665.wasmer-v7 +0 -0
  326. package/dist/lib/browser/capability-7LE5X2NH.mjs +0 -37
  327. package/dist/lib/browser/capability-7LE5X2NH.mjs.map +0 -7
  328. package/dist/lib/browser/capability-DU35RXMD.mjs.map +0 -7
  329. package/dist/lib/browser/chunk-4DQMLMGU.mjs.map +0 -7
  330. package/dist/lib/browser/chunk-EIFGKQSA.mjs.map +0 -7
  331. package/dist/lib/browser/chunk-FHQTHCX7.mjs +0 -8
  332. package/dist/lib/browser/chunk-IGRQWMWW.mjs +0 -80
  333. package/dist/lib/browser/chunk-IGRQWMWW.mjs.map +0 -7
  334. package/dist/lib/browser/chunk-KWP6PKIU.mjs.map +0 -7
  335. package/dist/lib/browser/chunk-NPUEVX42.mjs +0 -34
  336. package/dist/lib/browser/chunk-NPUEVX42.mjs.map +0 -7
  337. package/dist/lib/browser/chunk-PKQT6C53.mjs.map +0 -7
  338. package/dist/lib/browser/chunk-WGWEEBUV.mjs +0 -807
  339. package/dist/lib/browser/chunk-WGWEEBUV.mjs.map +0 -7
  340. package/dist/lib/browser/chunk-YAFEA4GV.mjs +0 -1
  341. package/dist/lib/browser/chunk-YZQ6NFG4.mjs +0 -781
  342. package/dist/lib/browser/chunk-YZQ6NFG4.mjs.map +0 -7
  343. package/dist/lib/browser/chunk-ZQO3UZ4R.mjs.map +0 -7
  344. package/dist/lib/browser/invoker-capability-7QW56NOM.mjs +0 -36
  345. package/dist/lib/browser/invoker-capability-7QW56NOM.mjs.map +0 -7
  346. package/dist/lib/node-esm/capability-OSVYGK4X.mjs +0 -38
  347. package/dist/lib/node-esm/capability-OSVYGK4X.mjs.map +0 -7
  348. package/dist/lib/node-esm/capability-SR2EIZFP.mjs.map +0 -7
  349. package/dist/lib/node-esm/chunk-64IMLAS2.mjs.map +0 -7
  350. package/dist/lib/node-esm/chunk-7OWSHPYK.mjs.map +0 -7
  351. package/dist/lib/node-esm/chunk-DHSHRYIB.mjs.map +0 -7
  352. package/dist/lib/node-esm/chunk-DZ2XLAGI.mjs.map +0 -7
  353. package/dist/lib/node-esm/chunk-J2PHTRHC.mjs.map +0 -7
  354. package/dist/lib/node-esm/chunk-JAZVHID3.mjs +0 -35
  355. package/dist/lib/node-esm/chunk-JAZVHID3.mjs.map +0 -7
  356. package/dist/lib/node-esm/chunk-OQYHRZYF.mjs +0 -81
  357. package/dist/lib/node-esm/chunk-OQYHRZYF.mjs.map +0 -7
  358. package/dist/lib/node-esm/chunk-VV4YHPQQ.mjs +0 -782
  359. package/dist/lib/node-esm/chunk-VV4YHPQQ.mjs.map +0 -7
  360. package/dist/lib/node-esm/chunk-XHAKT6UD.mjs +0 -808
  361. package/dist/lib/node-esm/chunk-XHAKT6UD.mjs.map +0 -7
  362. package/dist/lib/node-esm/chunk-Z4TJPSMP.mjs +0 -2
  363. package/dist/lib/node-esm/invoker-capability-CK4AMF2R.mjs +0 -37
  364. package/dist/lib/node-esm/invoker-capability-CK4AMF2R.mjs.map +0 -7
  365. package/dist/types/src/plugin-operation/OperationPlugin.d.ts +0 -3
  366. package/dist/types/src/plugin-operation/OperationPlugin.d.ts.map +0 -1
  367. package/dist/types/src/plugin-operation/history/capability.d.ts +0 -7
  368. package/dist/types/src/plugin-operation/history/capability.d.ts.map +0 -1
  369. package/dist/types/src/plugin-operation/history/errors.d.ts +0 -5
  370. package/dist/types/src/plugin-operation/history/errors.d.ts.map +0 -1
  371. package/dist/types/src/plugin-operation/history/history-tracker.d.ts.map +0 -1
  372. package/dist/types/src/plugin-operation/history/history-tracker.test.d.ts.map +0 -1
  373. package/dist/types/src/plugin-operation/history/index.d.ts.map +0 -1
  374. package/dist/types/src/plugin-operation/history/types.d.ts.map +0 -1
  375. package/dist/types/src/plugin-operation/history/undo-mapping.d.ts.map +0 -1
  376. package/dist/types/src/plugin-operation/history/undo-registry.d.ts.map +0 -1
  377. package/dist/types/src/plugin-operation/history/undo-registry.test.d.ts.map +0 -1
  378. package/dist/types/src/plugin-operation/index.d.ts +0 -3
  379. package/dist/types/src/plugin-operation/index.d.ts.map +0 -1
  380. package/dist/types/src/plugin-operation/invoker-capability.d.ts +0 -6
  381. package/dist/types/src/plugin-operation/invoker-capability.d.ts.map +0 -1
  382. package/dist/types/src/plugin-operation/meta.d.ts.map +0 -1
  383. package/dist/types/src/plugin-operation/testing.d.ts +0 -109
  384. package/dist/types/src/plugin-operation/testing.d.ts.map +0 -1
  385. package/dist/types/src/plugin-runtime/RuntimePlugin.d.ts +0 -3
  386. package/dist/types/src/plugin-runtime/RuntimePlugin.d.ts.map +0 -1
  387. package/dist/types/src/plugin-runtime/capability.d.ts +0 -6
  388. package/dist/types/src/plugin-runtime/capability.d.ts.map +0 -1
  389. package/dist/types/src/plugin-runtime/index.d.ts +0 -2
  390. package/dist/types/src/plugin-runtime/index.d.ts.map +0 -1
  391. package/dist/types/src/plugin-runtime/meta.d.ts +0 -3
  392. package/dist/types/src/plugin-runtime/meta.d.ts.map +0 -1
  393. package/dist/types/src/ui/components/App.d.ts.map +0 -1
  394. package/dist/types/src/ui/components/App.stories.d.ts.map +0 -1
  395. package/dist/types/src/ui/components/DefaultFallback.d.ts +0 -8
  396. package/dist/types/src/ui/components/DefaultFallback.d.ts.map +0 -1
  397. package/dist/types/src/ui/components/ErrorBoundary.d.ts +0 -30
  398. package/dist/types/src/ui/components/ErrorBoundary.d.ts.map +0 -1
  399. package/dist/types/src/ui/components/PluginManagerContext.stories.d.ts.map +0 -1
  400. package/dist/types/src/ui/components/PluginManagerProvider.d.ts.map +0 -1
  401. package/dist/types/src/ui/components/surface/SurfaceComponent.d.ts +0 -12
  402. package/dist/types/src/ui/components/surface/SurfaceComponent.d.ts.map +0 -1
  403. package/dist/types/src/ui/components/surface/SurfaceComponent.stories.d.ts.map +0 -1
  404. package/dist/types/src/ui/components/surface/index.d.ts +0 -5
  405. package/dist/types/src/ui/components/surface/index.d.ts.map +0 -1
  406. package/dist/types/src/ui/components/surface/types.d.ts +0 -94
  407. package/dist/types/src/ui/components/surface/types.d.ts.map +0 -1
  408. package/dist/types/src/ui/hooks/useOperationResolver.d.ts +0 -19
  409. package/dist/types/src/ui/hooks/useOperationResolver.d.ts.map +0 -1
  410. package/src/plugin-operation/OperationPlugin.ts +0 -25
  411. package/src/plugin-operation/history/errors.ts +0 -11
  412. package/src/plugin-operation/invoker-capability.ts +0 -40
  413. package/src/plugin-operation/meta.ts +0 -11
  414. package/src/plugin-runtime/RuntimePlugin.ts +0 -20
  415. package/src/plugin-runtime/capability.ts +0 -53
  416. package/src/plugin-runtime/meta.ts +0 -11
  417. package/src/ui/components/App.stories.tsx +0 -62
  418. package/src/ui/components/App.tsx +0 -57
  419. package/src/ui/components/DefaultFallback.tsx +0 -26
  420. package/src/ui/components/ErrorBoundary.tsx +0 -56
  421. package/src/ui/components/surface/SurfaceComponent.tsx +0 -262
  422. package/src/ui/components/surface/index.ts +0 -8
  423. package/src/ui/components/surface/types.ts +0 -119
  424. package/src/ui/hooks/useOperationResolver.ts +0 -40
  425. /package/dist/lib/browser/{chunk-YAFEA4GV.mjs.map → core/url-loader.mjs.map} +0 -0
  426. /package/dist/lib/node-esm/{chunk-Z4TJPSMP.mjs.map → core/url-loader.mjs.map} +0 -0
  427. /package/dist/types/src/{plugin-operation → plugin-process-manager}/history/history-tracker.test.d.ts +0 -0
  428. /package/dist/types/src/{plugin-operation → plugin-process-manager}/history/index.d.ts +0 -0
  429. /package/dist/types/src/{plugin-operation → plugin-process-manager}/history/undo-registry.test.d.ts +0 -0
  430. /package/dist/types/src/{plugin-operation → plugin-process-manager}/meta.d.ts +0 -0
  431. /package/dist/types/src/ui/components/{PluginManagerContext.stories.d.ts → PluginManager/PluginManagerContext.stories.d.ts} +0 -0
  432. /package/dist/types/src/ui/components/{surface → Surface}/SurfaceComponent.stories.d.ts +0 -0
  433. /package/dist/types/src/ui/components/{surface → Surface}/SurfaceInfo.d.ts +0 -0
  434. /package/dist/types/src/ui/components/{surface → Surface}/context.d.ts +0 -0
  435. /package/src/{plugin-operation → plugin-process-manager}/history/index.ts +0 -0
  436. /package/src/ui/components/{surface → Surface}/context.ts +0 -0
@@ -12,36 +12,76 @@ import React, { type FC, useCallback, useEffect, useMemo, useRef, useState } fro
12
12
  import { runAndForwardErrors } from '@dxos/effect';
13
13
  import { invariant } from '@dxos/invariant';
14
14
  import { log } from '@dxos/log';
15
+ import { ErrorBoundary, ErrorFallback, type FallbackProps } from '@dxos/react-error-boundary';
15
16
  import { useAsyncEffect, useDefaultValue } from '@dxos/react-hooks';
16
17
  import { ContextProtocolProvider } from '@dxos/web-context-react';
17
18
 
18
19
  import { ActivationEvents, Capabilities } from '../../common';
19
20
  import { PluginManagerContext } from '../../context';
20
21
  import { type ActivationEvent, type Plugin, PluginManager } from '../../core';
21
- import { App } from '../components/App';
22
- import { DefaultFallback } from '../components/DefaultFallback';
23
- import { ErrorBoundary } from '../components/ErrorBoundary';
24
- import { PluginManagerProvider } from '../components/PluginManagerProvider';
22
+ import { App, PluginManagerProvider } from '../components';
25
23
 
26
- const ENABLED_KEY = 'dxos.org/app-framework/enabled';
24
+ const ENABLED_KEY = 'org.dxos.app-framework.enabled';
25
+
26
+ export type StartupProgress = {
27
+ /** Number of modules that have been activated. */
28
+ activated: number;
29
+ /** Total number of modules registered. */
30
+ total: number;
31
+ /** Fractional progress (0-1). */
32
+ progress: number;
33
+ /**
34
+ * Raw activation event key (e.g. `org.dxos.app-framework.event.startup`).
35
+ * Set on event-level transitions, *and* on module-level transitions where
36
+ * it carries the parent activation event that first triggered the
37
+ * module's load (plumbed through `_loadCapabilitiesForModules` →
38
+ * `_loadModule`). Consumers can use this either as the primary id (when
39
+ * {@link module} is absent) or as an extra "context" field alongside
40
+ * {@link module}.
41
+ */
42
+ event?: string;
43
+ /**
44
+ * Raw module id (e.g. `org.dxos.plugin.observability.module.ReactSurface`)
45
+ * when the in-flight activation is module-level. When present,
46
+ * {@link event} may also be set, identifying the parent activation that
47
+ * triggered this module's load.
48
+ */
49
+ module?: string;
50
+ /**
51
+ * Pre-humanized label for the currently surfaced transition (module
52
+ * label if {@link module} is set, otherwise the event label), supplied
53
+ * for consumers that want a sensible default. Hosts that prefer to
54
+ * render their own label can read the raw {@link event}/{@link module}
55
+ * fields and ignore this — the framework leaves the policy choice
56
+ * (which transitions to surface, how to format them, whether to drop
57
+ * sub-modules entirely) to the host's `Placeholder`.
58
+ */
59
+ humanizedName?: string;
60
+ };
61
+
62
+ export type PlaceholderProps = {
63
+ stage?: number;
64
+ progress?: StartupProgress;
65
+ };
27
66
 
28
67
  export type UseAppOptions = {
29
68
  pluginManager?: PluginManager.PluginManager;
30
69
  pluginLoader?: PluginManager.ManagerOptions['pluginLoader'];
70
+ onPluginRemove?: PluginManager.ManagerOptions['onRemove'];
71
+ pluginRegistryProvider?: PluginManager.ManagerOptions['pluginRegistryProvider'];
31
72
  plugins?: Plugin.Plugin[];
32
- core?: string[];
33
73
  defaults?: string[];
34
74
  /**
35
75
  * Additional activation events to fire before startup.
36
76
  * These are fired alongside SetupReactSurface before the Startup event.
37
77
  */
38
78
  setupEvents?: ActivationEvent.ActivationEvent[];
39
- placeholder?: FC<{ stage: number }>;
40
- fallback?: ErrorBoundary['props']['fallback'];
41
79
  cacheEnabled?: boolean;
42
80
  safeMode?: boolean;
43
81
  debounce?: number;
44
82
  timeout?: number;
83
+ fallback?: FC<FallbackProps>;
84
+ placeholder?: FC<PlaceholderProps>;
45
85
  };
46
86
 
47
87
  /**
@@ -50,10 +90,9 @@ export type UseAppOptions = {
50
90
  *
51
91
  * @example
52
92
  * const plugins = [LayoutPlugin(), MyPlugin()];
53
- * const core = [LayoutPluginId];
54
- * const default = [MyPluginId];
55
- * const fallback = <div>Initializing Plugins...</div>;
56
- * const App = useApp({ plugins, core, default, fallback });
93
+ * const defaults = [MyPluginId];
94
+ * const fallback = () => <div>Initializing Plugins...</div>;
95
+ * const App = useApp({ plugins, defaults, fallback });
57
96
  * createRoot(document.getElementById('root')!).render(
58
97
  * <StrictMode>
59
98
  * <App />
@@ -61,34 +100,32 @@ export type UseAppOptions = {
61
100
  * );
62
101
  *
63
102
  * @param params.pluginLoader A function which loads new plugins.
64
- * @param params.plugins All plugins available to the application.
65
- * @param params.core Core plugins which will always be enabled.
103
+ * @param params.plugins All plugins available to the application. Plugins whose `meta.tags` includes `'system'` are treated as core (force-enabled, not user-toggleable).
66
104
  * @param params.defaults Default plugins are enabled by default but can be disabled by the user.
67
- * @param params.placeholder Placeholder component to render during startup.
68
- * @param params.fallback Fallback component to render if an error occurs during startup.
69
105
  * @param params.cacheEnabled Whether to cache enabled plugins in localStorage.
70
106
  * @param params.safeMode Whether to enable safe mode, which disables optional plugins.
107
+ * @param params.fallback Fallback component to render if an error occurs during startup.
108
+ * @param params.placeholder Placeholder component to render during startup.
71
109
  */
72
110
  export const useApp = ({
73
111
  pluginManager,
74
112
  pluginLoader: pluginLoaderProp,
113
+ onPluginRemove,
114
+ pluginRegistryProvider,
75
115
  plugins: pluginsProp,
76
- core: coreProp,
77
116
  defaults: defaultsProp,
78
117
  setupEvents: setupEventsProp,
79
118
  placeholder,
80
- fallback = DefaultFallback,
119
+ fallback = ErrorFallback,
81
120
  cacheEnabled = false,
82
121
  safeMode = false,
83
122
  debounce = 0,
84
123
  timeout = 30_000,
85
124
  }: UseAppOptions) => {
86
125
  const plugins = useDefaultValue(pluginsProp, () => []);
87
- const core = useDefaultValue(coreProp, () => plugins.map(({ meta }) => meta.id));
88
126
  const defaults = useDefaultValue(defaultsProp, () => []);
89
127
  const setupEvents = useDefaultValue(setupEventsProp, () => []);
90
128
 
91
- // TODO(wittjosiah): Provide a custom plugin loader which supports loading via url.
92
129
  const pluginLoader = useMemo(
93
130
  () =>
94
131
  pluginLoaderProp ??
@@ -96,7 +133,7 @@ export const useApp = ({
96
133
  Effect.sync(() => {
97
134
  const plugin = plugins.find((plugin) => plugin.meta.id === id);
98
135
  invariant(plugin, `Plugin not found: ${id}`);
99
- return plugin;
136
+ return { plugin };
100
137
  })),
101
138
  [pluginLoaderProp, plugins],
102
139
  );
@@ -105,16 +142,31 @@ export const useApp = ({
105
142
  const [ready, setReady] = useState(false);
106
143
  const errorRef = useRef<unknown>(null);
107
144
  const [error, setError] = useState<unknown>(null);
145
+ const [startupProgress, setStartupProgress] = useState<StartupProgress>({
146
+ activated: 0,
147
+ total: 0,
148
+ progress: 0,
149
+ });
108
150
  // TODO(wittjosiah): Migrate to Atom.kvs for isomorphic storage.
109
151
  const cached: string[] = useMemo(() => JSON.parse(localStorage.getItem(ENABLED_KEY) ?? '[]'), []);
110
152
  const enabled = useMemo(
111
153
  () => (safeMode ? [] : cacheEnabled && cached.length > 0 ? cached : defaults),
112
154
  [safeMode, cacheEnabled, cached, defaults],
113
155
  );
114
- const manager = useMemo(
115
- () => pluginManager ?? PluginManager.make({ pluginLoader, plugins, core, enabled }),
116
- [pluginManager, pluginLoader, plugins, core, enabled],
117
- );
156
+ const isExternalManager = !!pluginManager;
157
+ const manager = useMemo(() => {
158
+ const mgr =
159
+ pluginManager ??
160
+ PluginManager.make({
161
+ pluginLoader,
162
+ plugins,
163
+ enabled,
164
+ onRemove: onPluginRemove,
165
+ pluginRegistryProvider,
166
+ });
167
+ log('useApp: useMemo created/reused manager', { provided: !!pluginManager });
168
+ return mgr;
169
+ }, [pluginManager, pluginLoader, plugins, enabled, onPluginRemove, pluginRegistryProvider]);
118
170
 
119
171
  useEffect(() => {
120
172
  if (!cacheEnabled) {
@@ -130,28 +182,103 @@ export const useApp = ({
130
182
  }, [manager]);
131
183
 
132
184
  useAsyncEffect(async () => {
185
+ log('useApp: effect mount');
186
+
133
187
  manager.capabilities.contribute({
134
188
  interface: Capabilities.PluginManager,
135
189
  implementation: manager,
136
- module: 'dxos.org/app-framework/plugin-manager',
190
+ module: 'org.dxos.app-framework.plugin-manager',
137
191
  });
138
192
 
139
193
  manager.capabilities.contribute({
140
194
  interface: Capabilities.AtomRegistry,
141
195
  implementation: manager.registry,
142
- module: 'dxos.org/app-framework/atom-registry',
196
+ module: 'org.dxos.app-framework.atom-registry',
143
197
  });
144
198
 
145
199
  const fiber = Effect.gen(function* () {
146
200
  const queue = yield* PubSub.subscribe(manager.activation);
147
201
  const listener = yield* Effect.forkDaemon(
148
202
  Queue.take(queue).pipe(
149
- Effect.tap(({ event, state, error: error$ }) =>
203
+ Effect.tap(({ event, state, module, error: error$ }) =>
150
204
  Effect.sync(() => {
151
- if (event === ActivationEvents.Startup.id && state === 'activated') {
205
+ // Event-level Startup activated (no `module` field) fires once,
206
+ // after every module triggered by Startup has finished. Module
207
+ // activations now also carry their parent event id (so the trace
208
+ // can attribute a module to its triggering event), which means
209
+ // each module activated under Startup publishes
210
+ // `{ event: 'startup', state: 'activated', module: <id> }`. Without
211
+ // the `!module` guard the listener would mark the app ready on
212
+ // the *first* such module rather than waiting for the event-level
213
+ // completion — leaving downstream capabilities (operation-invoker,
214
+ // app-graph, …) un-registered when the placeholder dismisses.
215
+ if (event === ActivationEvents.Startup.id && state === 'activated' && !module) {
152
216
  clearTimeout(timeoutId);
153
217
  setReady(true);
154
218
  readyRef.current = true;
219
+ // Trigger startup profiler dump if available.
220
+ (globalThis as any).composer?.profiler?.dump();
221
+ // Notify any host observability layer that startup completed.
222
+ // A `CustomEvent` keeps this generic — app-framework doesn't
223
+ // import a provider, and consumers can capture the startup
224
+ // summary without us picking one.
225
+ if (typeof window !== 'undefined') {
226
+ window.dispatchEvent(new CustomEvent('app-framework:startup-activated'));
227
+ }
228
+ return;
229
+ }
230
+ // `activating` is the start-of-load signal. Surface the raw
231
+ // `module` (or `event`) plus a pre-humanized label so the
232
+ // host placeholder can decide what to render — show
233
+ // everything, suppress noisy sub-modules, group by plugin,
234
+ // or apply its own formatting. We intentionally do NOT touch
235
+ // these fields on `activated`: pairing the two would cause
236
+ // back-to-back identical updates to the host's effect, which
237
+ // the boot loader treats as a re-trigger because
238
+ // `progress.progress` moved. Leaving the label alone on
239
+ // completion keeps it accurate ("now activating X") until
240
+ // the next module starts.
241
+ if (module && state === 'activating' && !readyRef.current) {
242
+ setStartupProgress((current) => ({
243
+ ...current,
244
+ // `event` here is the activation event that first
245
+ // triggered this module load (plumbed through
246
+ // `_loadCapabilitiesForModules` → `_loadModule`).
247
+ // Falsy/empty falls back to undefined so consumers can
248
+ // tell "no parent context" from "parent context: <X>".
249
+ event: event || undefined,
250
+ module,
251
+ humanizedName: humanizeModuleId(module),
252
+ }));
253
+ }
254
+ // Update the activation count when a module commits. The
255
+ // ring's fraction comes from this; `event`/`module`/
256
+ // `humanizedName` were set by the matching `activating`
257
+ // message above and are left alone so the count can advance
258
+ // without re-firing the host's status callback.
259
+ if (module && state === 'activated' && !readyRef.current) {
260
+ const active = manager.getActive();
261
+ const total = manager.getModules().length;
262
+ setStartupProgress((current) => ({
263
+ ...current,
264
+ activated: active.length,
265
+ total,
266
+ progress: total > 0 ? active.length / total : 0,
267
+ }));
268
+ }
269
+ // Event-level `activating` (no `module`) — fired at the start
270
+ // of `_activateModulesForEvent` and recursively for each
271
+ // before/after event. Surfaces a label during the gap before
272
+ // the first module-level message lands; subsequent module
273
+ // updates immediately overwrite this with a more specific
274
+ // label.
275
+ if (event && !module && state === 'activating' && !readyRef.current) {
276
+ setStartupProgress((current) => ({
277
+ ...current,
278
+ event,
279
+ module: undefined,
280
+ humanizedName: humanizeEventKey(event),
281
+ }));
155
282
  }
156
283
  if (error$ && !readyRef.current) {
157
284
  setError(error$);
@@ -186,20 +313,31 @@ export const useApp = ({
186
313
  }, timeout);
187
314
 
188
315
  return () => {
316
+ log('useApp: effect cleanup');
189
317
  clearTimeout(timeoutId);
190
318
  void runAndForwardErrors(Fiber.interrupt(fiber));
191
- manager.capabilities.remove(Capabilities.PluginManager, manager);
192
- manager.capabilities.remove(Capabilities.AtomRegistry, manager.registry);
319
+ if (!isExternalManager) {
320
+ void runAndForwardErrors(manager.shutdown());
321
+ }
193
322
  };
194
323
  }, [manager]);
195
324
 
325
+ const progressRef = useRef(startupProgress);
326
+ progressRef.current = startupProgress;
327
+
196
328
  return useCallback(
197
329
  () => (
198
- <ErrorBoundary fallback={fallback}>
330
+ <ErrorBoundary name='app' FallbackComponent={fallback}>
199
331
  <PluginManagerProvider value={manager}>
200
332
  <ContextProtocolProvider value={manager} context={PluginManagerContext}>
201
333
  <RegistryContext.Provider value={manager.registry}>
202
- <App placeholder={placeholder} ready={ready} error={error} debounce={debounce} />
334
+ <App
335
+ placeholder={placeholder}
336
+ ready={ready}
337
+ error={error}
338
+ debounce={debounce}
339
+ progress={progressRef.current}
340
+ />
203
341
  </RegistryContext.Provider>
204
342
  </ContextProtocolProvider>
205
343
  </PluginManagerProvider>
@@ -213,3 +351,68 @@ const setupDevtools = (manager: PluginManager.PluginManager) => {
213
351
  (globalThis as any).composer ??= {};
214
352
  (globalThis as any).composer.manager = manager;
215
353
  };
354
+
355
+ /**
356
+ * Extracts a human-readable label from a module ID.
357
+ *
358
+ * Module IDs follow `org.dxos.plugin.<plugin-slug>.module.<module-name>`,
359
+ * where `<plugin-slug>` is kebab-case and `<module-name>` is either an
360
+ * explicit string (often kebab-case, e.g. `'observability'`, `'namespace'`)
361
+ * or a capability tag in PascalCase from `Capability.getModuleTag(...)`
362
+ * (e.g. `'ReactSurface'`, `'AppGraphBuilder'`). The output is
363
+ * `"Title Case Plugin: kebab-module"` so the visible status names both the
364
+ * plugin and the aspect being activated, helping disambiguate the multiple
365
+ * modules a plugin contributes.
366
+ *
367
+ * Examples:
368
+ * - "org.dxos.plugin.markdown.module.ReactSurface" → "Markdown: react-surface"
369
+ * - "org.dxos.plugin.observability.module.AppGraphBuilder" → "Observability: app-graph-builder"
370
+ * - "org.dxos.plugin.observability.module.observability" → "Observability"
371
+ * (the module name matches the plugin slug — collapsed to avoid
372
+ * "Observability: observability" noise.)
373
+ */
374
+ const humanizeModuleId = (moduleId: string): string => {
375
+ const match = moduleId.match(/\.plugin\.([^.]+)\.module\.(.+)$/);
376
+ if (!match) {
377
+ // Fallback: use the last segment.
378
+ const parts = moduleId.split('.');
379
+ return parts[parts.length - 1];
380
+ }
381
+ const [, pluginSlug, moduleName] = match;
382
+ const pluginLabel = pluginSlug
383
+ .split('-')
384
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
385
+ .join(' ');
386
+ // Normalise the module name to kebab-case so PascalCase capability tags
387
+ // ("ReactSurface") read consistently with explicit kebab IDs
388
+ // ("operation-handler"). The two-step substitution handles consecutive
389
+ // uppercase runs (`URLLoader` → `url-loader`) without splitting them
390
+ // mid-acronym.
391
+ const moduleLabel = moduleName
392
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
393
+ .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
394
+ .toLowerCase();
395
+ // Capability modules whose name matches the plugin slug (e.g. the
396
+ // observability plugin's `observability` capability module) would render
397
+ // as "Observability: observability" — drop the redundant suffix.
398
+ if (moduleLabel === pluginSlug) {
399
+ return pluginLabel;
400
+ }
401
+ return `${pluginLabel}: ${moduleLabel}`;
402
+ };
403
+
404
+ /**
405
+ * Extracts a human-readable label from an activation event key.
406
+ * E.g., "org.dxos.app-framework.event.setup-react-surface" → "Setup React Surface".
407
+ */
408
+ const humanizeEventKey = (eventKey: string): string => {
409
+ // Strip a leading specifier (composite key form: "<id>:<specifier>").
410
+ const id = eventKey.split(':')[0];
411
+ // Match the trailing segment after `.event.`.
412
+ const match = id.match(/\.event\.(.+)$/);
413
+ const slug = match ? match[1] : (id.split('.').pop() ?? id);
414
+ return slug
415
+ .split('-')
416
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
417
+ .join(' ');
418
+ };
@@ -9,7 +9,7 @@ import { invariant } from '@dxos/invariant';
9
9
 
10
10
  import { Capabilities } from '../../common';
11
11
  import { type Capability } from '../../core';
12
- import { usePluginManager } from '../components/PluginManagerProvider';
12
+ import { usePluginManager } from '../components';
13
13
 
14
14
  /**
15
15
  * Hook to request capabilities from the plugin context.
@@ -25,6 +25,7 @@ export const useCapabilities = <T>(interfaceDef: Capability.InterfaceDef<T>) =>
25
25
  * @returns The capability.
26
26
  * @throws If no capability is found.
27
27
  */
28
+ // TODO(burdon): Option not to throw?
28
29
  export const useCapability = <T>(interfaceDef: Capability.InterfaceDef<T>) => {
29
30
  const capabilities = useCapabilities(interfaceDef);
30
31
  invariant(capabilities.length > 0, `No capability found for ${interfaceDef.identifier}`);
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useEffect, useState } from 'react';
5
+ import { useEffect, useRef, useState } from 'react';
6
6
 
7
7
  export enum LoadingState {
8
8
  Loading = 0,
@@ -23,6 +23,14 @@ export enum LoadingState {
23
23
  */
24
24
  export const useLoading = (ready: boolean, debounce = 0) => {
25
25
  const [stage, setStage] = useState<LoadingState>(LoadingState.Loading);
26
+ // Mirror `ready` into a ref so the interval's `setStage` callback can read
27
+ // the latest value without depending on the effect re-running. The pure
28
+ // closure-capture pattern (with `ready` in deps) sticks the FSM at
29
+ // `FadeIn` whenever HMR doesn't propagate the dep change end-to-end —
30
+ // a ref sidesteps that entirely and fires the read on every tick.
31
+ const readyRef = useRef(ready);
32
+ readyRef.current = ready;
33
+
26
34
  useEffect(() => {
27
35
  if (!debounce) {
28
36
  return;
@@ -30,18 +38,18 @@ export const useLoading = (ready: boolean, debounce = 0) => {
30
38
 
31
39
  const i = setInterval(() => {
32
40
  setStage((stage) => {
41
+ const isReady = readyRef.current;
33
42
  switch (stage) {
34
43
  case LoadingState.Loading: {
35
- if (!ready) {
44
+ if (!isReady) {
36
45
  return LoadingState.FadeIn;
37
- } else {
38
- clearInterval(i);
39
- return LoadingState.Done;
40
46
  }
47
+ clearInterval(i);
48
+ return LoadingState.Done;
41
49
  }
42
50
 
43
51
  case LoadingState.FadeIn: {
44
- if (ready) {
52
+ if (isReady) {
45
53
  return LoadingState.FadeOut;
46
54
  }
47
55
  break;
@@ -0,0 +1,78 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Context from 'effect/Context';
6
+ import * as Effect from 'effect/Effect';
7
+ import * as Layer from 'effect/Layer';
8
+ import { type DependencyList, use, useCallback, useMemo } from 'react';
9
+
10
+ import { Operation, ServiceResolver } from '@dxos/compute';
11
+ import { unwrapExit } from '@dxos/effect';
12
+ import type { SpaceId } from '@dxos/keys';
13
+
14
+ import { Capabilities } from '../../common';
15
+ import { useCapability } from './useCapabilities';
16
+
17
+ /**
18
+ * Resolve the shared {@link Capabilities.ProcessManagerRuntime} from the plugin context.
19
+ */
20
+ export const useProcessManagerRuntime = (): Capabilities.ProcessManagerRuntime =>
21
+ useCapability(Capabilities.ProcessManagerRuntime);
22
+
23
+ /**
24
+ * Build a callback that runs an effect on the {@link Capabilities.ProcessManagerRuntime}
25
+ * with space-scoped services resolved via {@link ServiceResolver.provide}.
26
+ *
27
+ * The `tags` tuple must list every service the effect requires (beyond the
28
+ * fixed {@link Capabilities.ProcessManagerRuntimeServices}); these services are
29
+ * resolved for the given `spaceId` through the runtime's service resolver.
30
+ *
31
+ * Nested `Operation.invoke` / `Operation.schedule` calls within the effect
32
+ * inherit `spaceId` as a default {@link Operation.InvokeOptions} so that
33
+ * spawned operation processes have a space context (and therefore can resolve
34
+ * space-scoped services like `Database.Service`) without each call site having
35
+ * to thread the id through manually.
36
+ */
37
+ export const useSpaceCallback = <const Tags extends readonly Context.Tag<any, any>[], T>(
38
+ spaceId: SpaceId | undefined,
39
+ tags: Tags,
40
+ fn: () => Effect.Effect<T, any, Context.Tag.Identifier<Tags[number]> | Capabilities.ProcessManagerRuntimeServices>,
41
+ deps?: DependencyList,
42
+ ): (() => Promise<T>) => {
43
+ const runtime = useProcessManagerRuntime();
44
+ return useCallback(() => {
45
+ if (spaceId === undefined) {
46
+ throw new TypeError('Space not provided to useSpaceCallback');
47
+ }
48
+ const layer = Layer.merge(
49
+ ServiceResolver.provide({ space: spaceId }, ...tags),
50
+ Operation.withInvocationOptions({ spaceId }),
51
+ );
52
+ return runtime.runPromise(fn().pipe(Effect.provide(layer)) as Effect.Effect<T, any, any>);
53
+ // eslint-disable-next-line react-hooks/exhaustive-deps
54
+ }, [runtime, spaceId, ...(deps ?? [])]);
55
+ };
56
+
57
+ /**
58
+ * Suspensefully resolve a single space-scoped service via the
59
+ * {@link Capabilities.ProcessManagerRuntime}'s service resolver.
60
+ */
61
+ export const useSpaceService = <T extends Context.Tag<any, any>>(
62
+ tag: T,
63
+ spaceId: SpaceId | undefined,
64
+ ): Context.Tag.Service<T> | undefined => {
65
+ const runtime = useProcessManagerRuntime();
66
+ const promise = useMemo(() => {
67
+ if (spaceId === undefined) {
68
+ return undefined;
69
+ }
70
+ const layer = ServiceResolver.provide({ space: spaceId }, tag);
71
+ const effect = Effect.flatMap(tag, (service) => Effect.succeed(service)).pipe(Effect.provide(layer));
72
+ return runtime.runPromiseExit(effect as Effect.Effect<Context.Tag.Service<T>, any, any>);
73
+ }, [runtime, spaceId, tag]);
74
+ if (!promise) {
75
+ return undefined;
76
+ }
77
+ return unwrapExit(use(promise));
78
+ };
@@ -6,8 +6,8 @@ import { useContext } from 'react';
6
6
 
7
7
  import { raise } from '@dxos/debug';
8
8
 
9
- import { SurfaceContext } from '../components/surface/context';
9
+ import { Surface } from '../components';
10
10
 
11
- export const useSurface = (): SurfaceContext => {
12
- return useContext(SurfaceContext) ?? raise(new Error('Missing SurfaceContext'));
11
+ export const useSurface = (): Surface.Context => {
12
+ return useContext(Surface.Context) ?? raise(new Error('Missing SurfaceContext'));
13
13
  };
package/src/ui/index.ts CHANGED
@@ -4,4 +4,3 @@
4
4
 
5
5
  export * from './components';
6
6
  export * from './hooks';
7
- export * as Surface from './components/surface';