@dxos/app-framework 0.8.3 → 0.8.4-main.1f223c7

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 (352) hide show
  1. package/.swc/plugins/linux_x86_64_19.0.0/727453fb3a62f7f1d952a41e051ca8a6f88cadc45cee43c6a4d1aa45f9b75665.wasmer-v7 +0 -0
  2. package/.swc/plugins/linux_x86_64_19.0.0/fce1bdb8e20a094e4af08bad09cc81497ed0e2e7c51223b07d371063cca18429.wasmer-v7 +0 -0
  3. package/README.md +0 -8
  4. package/dist/lib/browser/{app-graph-builder-BI4VVKSW.mjs → app-graph-builder-AFFC6VB2.mjs} +5 -5
  5. package/dist/lib/browser/app-graph-builder-AFFC6VB2.mjs.map +7 -0
  6. package/dist/lib/browser/{chunk-WWEJRWFX.mjs → chunk-ORWHM7CO.mjs} +2 -2
  7. package/dist/lib/browser/{chunk-EHM4UI3V.mjs → chunk-OZY7HV2A.mjs} +396 -271
  8. package/dist/lib/browser/chunk-OZY7HV2A.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-DIBVO47Z.mjs → chunk-T6M7JB7M.mjs} +194 -129
  10. package/dist/lib/browser/chunk-T6M7JB7M.mjs.map +7 -0
  11. package/dist/lib/browser/index.mjs +16 -10
  12. package/dist/lib/browser/index.mjs.map +3 -3
  13. package/dist/lib/browser/{intent-dispatcher-XVBOMF2Y.mjs → intent-dispatcher-QG7UPGQX.mjs} +2 -2
  14. package/dist/lib/browser/{intent-resolver-3QMBXLIY.mjs → intent-resolver-4S4PSTM5.mjs} +4 -4
  15. package/dist/lib/browser/intent-resolver-4S4PSTM5.mjs.map +7 -0
  16. package/dist/lib/browser/meta.json +1 -1
  17. package/dist/lib/browser/{store-5H7XPJGA.mjs → store-6E33KLGK.mjs} +3 -3
  18. package/dist/lib/browser/{store-5H7XPJGA.mjs.map → store-6E33KLGK.mjs.map} +1 -1
  19. package/dist/lib/browser/testing/index.mjs +6 -8
  20. package/dist/lib/browser/testing/index.mjs.map +3 -3
  21. package/dist/lib/browser/worker.mjs +7 -1
  22. package/dist/lib/node-esm/{app-graph-builder-NROP6RPQ.mjs → app-graph-builder-S4OAULX5.mjs} +5 -5
  23. package/dist/lib/node-esm/app-graph-builder-S4OAULX5.mjs.map +7 -0
  24. package/dist/lib/node-esm/{chunk-2J6FVECI.mjs → chunk-F63ZRXMK.mjs} +396 -271
  25. package/dist/lib/node-esm/chunk-F63ZRXMK.mjs.map +7 -0
  26. package/dist/lib/node-esm/{chunk-FHNZZWP4.mjs → chunk-HJFU7QOR.mjs} +194 -129
  27. package/dist/lib/node-esm/chunk-HJFU7QOR.mjs.map +7 -0
  28. package/dist/lib/node-esm/{chunk-I6BVZMAH.mjs → chunk-UMZQERLE.mjs} +2 -2
  29. package/dist/lib/node-esm/index.mjs +16 -10
  30. package/dist/lib/node-esm/index.mjs.map +3 -3
  31. package/dist/lib/node-esm/{intent-dispatcher-7JPGLCQ5.mjs → intent-dispatcher-NXBGPJOX.mjs} +2 -2
  32. package/dist/lib/node-esm/{intent-resolver-VY4X5UHN.mjs → intent-resolver-2ZKXI5ET.mjs} +4 -4
  33. package/dist/lib/node-esm/intent-resolver-2ZKXI5ET.mjs.map +7 -0
  34. package/dist/lib/node-esm/meta.json +1 -1
  35. package/dist/lib/node-esm/{store-UKD2R2KA.mjs → store-QQUTQHHT.mjs} +3 -3
  36. package/dist/lib/node-esm/{store-UKD2R2KA.mjs.map → store-QQUTQHHT.mjs.map} +1 -1
  37. package/dist/lib/node-esm/testing/index.mjs +6 -8
  38. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  39. package/dist/lib/node-esm/worker.mjs +7 -1
  40. package/dist/types/src/common/capabilities.d.ts +78 -9
  41. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  42. package/dist/types/src/common/collaboration.d.ts +9 -8
  43. package/dist/types/src/common/collaboration.d.ts.map +1 -1
  44. package/dist/types/src/common/events.d.ts.map +1 -1
  45. package/dist/types/src/common/surface.d.ts +1 -1
  46. package/dist/types/src/common/surface.d.ts.map +1 -1
  47. package/dist/types/src/components/App.d.ts +10 -0
  48. package/dist/types/src/components/App.d.ts.map +1 -0
  49. package/dist/types/src/components/App.stories.d.ts +15 -0
  50. package/dist/types/src/components/App.stories.d.ts.map +1 -0
  51. package/dist/types/src/components/DefaultFallback.d.ts +8 -0
  52. package/dist/types/src/components/DefaultFallback.d.ts.map +1 -0
  53. package/dist/types/src/components/index.d.ts +2 -0
  54. package/dist/types/src/components/index.d.ts.map +1 -0
  55. package/dist/types/src/{App.d.ts → components/useApp.d.ts} +7 -6
  56. package/dist/types/src/components/useApp.d.ts.map +1 -0
  57. package/dist/types/src/components/useLoading.d.ts +19 -0
  58. package/dist/types/src/components/useLoading.d.ts.map +1 -0
  59. package/dist/types/src/core/capabilities.d.ts +4 -1
  60. package/dist/types/src/core/capabilities.d.ts.map +1 -1
  61. package/dist/types/src/core/manager.d.ts +6 -2
  62. package/dist/types/src/core/manager.d.ts.map +1 -1
  63. package/dist/types/src/index.d.ts +1 -1
  64. package/dist/types/src/index.d.ts.map +1 -1
  65. package/dist/types/src/playground/debug/Debug.d.ts +1 -1
  66. package/dist/types/src/playground/generator/Main.d.ts +1 -1
  67. package/dist/types/src/playground/generator/Toolbar.d.ts +1 -1
  68. package/dist/types/src/playground/generator/Toolbar.d.ts.map +1 -1
  69. package/dist/types/src/playground/generator/generator.d.ts.map +1 -1
  70. package/dist/types/src/playground/layout/Layout.d.ts +2 -2
  71. package/dist/types/src/playground/logger/Toolbar.d.ts +1 -1
  72. package/dist/types/src/playground/logger/Toolbar.d.ts.map +1 -1
  73. package/dist/types/src/playground/logger/plugin.d.ts.map +1 -1
  74. package/dist/types/src/playground/playground.stories.d.ts +5 -3
  75. package/dist/types/src/playground/playground.stories.d.ts.map +1 -1
  76. package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -1
  77. package/dist/types/src/plugin-intent/index.d.ts +1 -0
  78. package/dist/types/src/plugin-intent/index.d.ts.map +1 -1
  79. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +3 -3
  80. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -1
  81. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -1
  82. package/dist/types/src/plugin-settings/app-graph-builder.d.ts +1 -1
  83. package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +1 -1
  84. package/dist/types/src/plugin-settings/intent-resolver.d.ts +1 -1
  85. package/dist/types/src/plugin-settings/intent-resolver.d.ts.map +1 -1
  86. package/dist/types/src/plugin-settings/store.d.ts +1 -1
  87. package/dist/types/src/plugin-settings/store.d.ts.map +1 -1
  88. package/dist/types/src/plugin-settings/translations.d.ts +7 -8
  89. package/dist/types/src/plugin-settings/translations.d.ts.map +1 -1
  90. package/dist/types/src/react/ErrorBoundary.d.ts +13 -14
  91. package/dist/types/src/react/ErrorBoundary.d.ts.map +1 -1
  92. package/dist/types/src/react/IntentContext.d.ts.map +1 -1
  93. package/dist/types/src/react/Surface.d.ts.map +1 -1
  94. package/dist/types/src/react/Surface.stories.d.ts +6 -4
  95. package/dist/types/src/react/Surface.stories.d.ts.map +1 -1
  96. package/dist/types/src/react/common.d.ts.map +1 -1
  97. package/dist/types/src/react/useCapabilities.d.ts.map +1 -1
  98. package/dist/types/src/testing/withPluginManager.d.ts +4 -2
  99. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  100. package/dist/types/src/testing/withPluginManager.stories.d.ts +9 -3
  101. package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
  102. package/dist/types/tsconfig.tsbuildinfo +1 -1
  103. package/moon.yml +14 -0
  104. package/package.json +32 -28
  105. package/src/common/capabilities.ts +98 -11
  106. package/src/common/collaboration.ts +5 -8
  107. package/src/common/events.ts +3 -1
  108. package/src/common/surface.ts +1 -1
  109. package/src/components/App.stories.tsx +35 -0
  110. package/src/components/App.tsx +59 -0
  111. package/src/components/DefaultFallback.tsx +26 -0
  112. package/src/components/index.ts +5 -0
  113. package/src/{App.tsx → components/useApp.tsx} +20 -130
  114. package/src/components/useLoading.tsx +70 -0
  115. package/src/core/capabilities.test.ts +1 -1
  116. package/src/core/capabilities.ts +11 -6
  117. package/src/core/manager.test.ts +5 -5
  118. package/src/core/manager.ts +132 -54
  119. package/src/helpers.test.ts +1 -1
  120. package/src/index.ts +1 -1
  121. package/src/playground/debug/Debug.tsx +1 -1
  122. package/src/playground/generator/Toolbar.tsx +2 -1
  123. package/src/playground/generator/generator.ts +2 -2
  124. package/src/playground/layout/plugin.ts +1 -1
  125. package/src/playground/logger/Toolbar.tsx +2 -1
  126. package/src/playground/logger/plugin.ts +3 -2
  127. package/src/playground/playground.stories.tsx +15 -10
  128. package/src/plugin-intent/IntentPlugin.ts +2 -1
  129. package/src/plugin-intent/index.ts +1 -0
  130. package/src/plugin-intent/intent-dispatcher.test.ts +1 -1
  131. package/src/plugin-intent/intent-dispatcher.ts +10 -8
  132. package/src/plugin-settings/SettingsPlugin.ts +3 -2
  133. package/src/plugin-settings/app-graph-builder.ts +4 -3
  134. package/src/plugin-settings/intent-resolver.ts +3 -2
  135. package/src/plugin-settings/store.ts +1 -1
  136. package/src/plugin-settings/translations.ts +4 -2
  137. package/src/react/ErrorBoundary.tsx +24 -15
  138. package/src/react/IntentContext.tsx +3 -2
  139. package/src/react/Surface.stories.tsx +21 -13
  140. package/src/react/Surface.tsx +4 -3
  141. package/src/react/common.ts +2 -1
  142. package/src/react/useCapabilities.ts +2 -1
  143. package/src/testing/withPluginManager.stories.tsx +9 -5
  144. package/src/testing/withPluginManager.tsx +13 -13
  145. package/tsconfig.json +5 -9
  146. package/vitest.config.ts +5 -2
  147. package/.eslintrc.cjs +0 -9
  148. package/README.yml +0 -5
  149. package/dist/lib/browser/app-graph-builder-BI4VVKSW.mjs.map +0 -7
  150. package/dist/lib/browser/chunk-DIBVO47Z.mjs.map +0 -7
  151. package/dist/lib/browser/chunk-EHM4UI3V.mjs.map +0 -7
  152. package/dist/lib/browser/intent-resolver-3QMBXLIY.mjs.map +0 -7
  153. package/dist/lib/node/app-graph-builder-H7QVE4MJ.cjs +0 -146
  154. package/dist/lib/node/app-graph-builder-H7QVE4MJ.cjs.map +0 -7
  155. package/dist/lib/node/chunk-G774ASXO.cjs +0 -58
  156. package/dist/lib/node/chunk-G774ASXO.cjs.map +0 -7
  157. package/dist/lib/node/chunk-VSOSVDQ3.cjs +0 -1551
  158. package/dist/lib/node/chunk-VSOSVDQ3.cjs.map +0 -7
  159. package/dist/lib/node/chunk-YGAY3H34.cjs +0 -429
  160. package/dist/lib/node/chunk-YGAY3H34.cjs.map +0 -7
  161. package/dist/lib/node/index.cjs +0 -193
  162. package/dist/lib/node/index.cjs.map +0 -7
  163. package/dist/lib/node/intent-dispatcher-C3SVKJ62.cjs +0 -32
  164. package/dist/lib/node/intent-dispatcher-C3SVKJ62.cjs.map +0 -7
  165. package/dist/lib/node/intent-resolver-IOJDYO34.cjs +0 -46
  166. package/dist/lib/node/intent-resolver-IOJDYO34.cjs.map +0 -7
  167. package/dist/lib/node/meta.json +0 -1
  168. package/dist/lib/node/store-ESF5VR57.cjs +0 -45
  169. package/dist/lib/node/store-ESF5VR57.cjs.map +0 -7
  170. package/dist/lib/node/testing/index.cjs +0 -119
  171. package/dist/lib/node/testing/index.cjs.map +0 -7
  172. package/dist/lib/node/worker.cjs +0 -101
  173. package/dist/lib/node/worker.cjs.map +0 -7
  174. package/dist/lib/node-esm/app-graph-builder-NROP6RPQ.mjs.map +0 -7
  175. package/dist/lib/node-esm/chunk-2J6FVECI.mjs.map +0 -7
  176. package/dist/lib/node-esm/chunk-FHNZZWP4.mjs.map +0 -7
  177. package/dist/lib/node-esm/intent-resolver-VY4X5UHN.mjs.map +0 -7
  178. package/dist/types/src/App.d.ts.map +0 -1
  179. package/project.json +0 -29
  180. package/typedoc/.nojekyll +0 -1
  181. package/typedoc/assets/hierarchy.js +0 -1
  182. package/typedoc/assets/highlight.css +0 -106
  183. package/typedoc/assets/icons.js +0 -18
  184. package/typedoc/assets/icons.svg +0 -1
  185. package/typedoc/assets/main.js +0 -60
  186. package/typedoc/assets/navigation.js +0 -1
  187. package/typedoc/assets/search.js +0 -1
  188. package/typedoc/assets/style.css +0 -1640
  189. package/typedoc/classes/CollaborationActions.InsertContent.html +0 -421
  190. package/typedoc/classes/ErrorBoundary.html +0 -125
  191. package/typedoc/classes/IntentAction.ShowUndo.html +0 -227
  192. package/typedoc/classes/IntentAction.Track.html +0 -266
  193. package/typedoc/classes/LayoutAction.AddToast.html +0 -265
  194. package/typedoc/classes/LayoutAction.Close.html +0 -382
  195. package/typedoc/classes/LayoutAction.Expose.html +0 -265
  196. package/typedoc/classes/LayoutAction.Open.html +0 -1123
  197. package/typedoc/classes/LayoutAction.RevertWorkspace.html +0 -343
  198. package/typedoc/classes/LayoutAction.ScrollIntoView.html +0 -460
  199. package/typedoc/classes/LayoutAction.Set.html +0 -460
  200. package/typedoc/classes/LayoutAction.SetLayoutMode.html +0 -499
  201. package/typedoc/classes/LayoutAction.SwitchWorkspace.html +0 -265
  202. package/typedoc/classes/LayoutAction.UpdateComplementary.html +0 -616
  203. package/typedoc/classes/LayoutAction.UpdateDialog.html +0 -1123
  204. package/typedoc/classes/LayoutAction.UpdateLayout.html +0 -461
  205. package/typedoc/classes/LayoutAction.UpdatePopover.html +0 -1435
  206. package/typedoc/classes/LayoutAction.UpdateSidebar.html +0 -616
  207. package/typedoc/classes/Plugin.html +0 -6
  208. package/typedoc/classes/PluginContext.html +0 -38
  209. package/typedoc/classes/PluginManager.html +0 -43
  210. package/typedoc/classes/PluginModule.html +0 -18
  211. package/typedoc/classes/SettingsAction.Open.html +0 -226
  212. package/typedoc/classes/SettingsAction.OpenPluginRegistry.html +0 -265
  213. package/typedoc/functions/Events.createStateEvent.html +0 -2
  214. package/typedoc/functions/IntentPlugin.html +0 -1
  215. package/typedoc/functions/SettingsPlugin.html +0 -1
  216. package/typedoc/functions/allOf.html +0 -2
  217. package/typedoc/functions/chain.html +0 -3
  218. package/typedoc/functions/contributes.html +0 -2
  219. package/typedoc/functions/createDispatcher.html +0 -3
  220. package/typedoc/functions/createIntent.html +0 -6
  221. package/typedoc/functions/createResolver.html +0 -2
  222. package/typedoc/functions/createSurface.html +0 -2
  223. package/typedoc/functions/defineCapability.html +0 -2
  224. package/typedoc/functions/defineEvent.html +0 -2
  225. package/typedoc/functions/defineModule.html +0 -2
  226. package/typedoc/functions/definePlugin.html +0 -2
  227. package/typedoc/functions/eventKey.html +0 -2
  228. package/typedoc/functions/getEvents.html +0 -2
  229. package/typedoc/functions/isAllOf.html +0 -2
  230. package/typedoc/functions/isOneOf.html +0 -2
  231. package/typedoc/functions/isSurfaceAvailable.html +0 -2
  232. package/typedoc/functions/lazy.html +0 -2
  233. package/typedoc/functions/oneOf.html +0 -2
  234. package/typedoc/functions/useApp.html +0 -6
  235. package/typedoc/functions/useAppGraph.html +0 -1
  236. package/typedoc/functions/useCapabilities.html +0 -3
  237. package/typedoc/functions/useCapability.html +0 -4
  238. package/typedoc/functions/useIntentDispatcher.html +0 -1
  239. package/typedoc/functions/useIntentResolver.html +0 -1
  240. package/typedoc/functions/useLayout.html +0 -1
  241. package/typedoc/functions/usePluginManager.html +0 -2
  242. package/typedoc/hierarchy.html +0 -1
  243. package/typedoc/index.html +0 -16
  244. package/typedoc/interfaces/LayoutAction.Toast.html +0 -10
  245. package/typedoc/media/LICENSE +0 -8
  246. package/typedoc/modules/Capabilities.html +0 -1
  247. package/typedoc/modules/CollaborationActions.html +0 -1
  248. package/typedoc/modules/Events.html +0 -1
  249. package/typedoc/modules/IntentAction.html +0 -1
  250. package/typedoc/modules/LayoutAction.html +0 -2
  251. package/typedoc/modules/SettingsAction.html +0 -1
  252. package/typedoc/modules.html +0 -1
  253. package/typedoc/types/ActivationEvent.html +0 -8
  254. package/typedoc/types/ActivationEvents.html +0 -2
  255. package/typedoc/types/AnyCapability.html +0 -1
  256. package/typedoc/types/AnyIntent.html +0 -1
  257. package/typedoc/types/AnyIntentChain.html +0 -1
  258. package/typedoc/types/AnyIntentEffectResult.html +0 -1
  259. package/typedoc/types/AnyIntentResolver.html +0 -1
  260. package/typedoc/types/AnyIntentResult.html +0 -1
  261. package/typedoc/types/Capabilities.FileUploader.html +0 -1
  262. package/typedoc/types/Capabilities.IntentResolver.html +0 -1
  263. package/typedoc/types/Capabilities.Layout.html +0 -1
  264. package/typedoc/types/Capabilities.Metadata.html +0 -1
  265. package/typedoc/types/Capabilities.ReactContext.html +0 -1
  266. package/typedoc/types/Capabilities.ReactRoot.html +0 -1
  267. package/typedoc/types/Capabilities.ReactSurface.html +0 -1
  268. package/typedoc/types/Capabilities.Settings.html +0 -4
  269. package/typedoc/types/Capability.html +0 -9
  270. package/typedoc/types/CreateAppOptions.html +0 -10
  271. package/typedoc/types/FileInfo.html +0 -1
  272. package/typedoc/types/Intent.html +0 -10
  273. package/typedoc/types/IntentChain.html +0 -6
  274. package/typedoc/types/IntentContext.html +0 -5
  275. package/typedoc/types/IntentData.html +0 -1
  276. package/typedoc/types/IntentDispatcher.html +0 -2
  277. package/typedoc/types/IntentDispatcherResult.html +0 -2
  278. package/typedoc/types/IntentEffectDefinition.html +0 -2
  279. package/typedoc/types/IntentEffectResult.html +0 -15
  280. package/typedoc/types/IntentParams.html +0 -3
  281. package/typedoc/types/IntentResolver.html +0 -2
  282. package/typedoc/types/IntentResultData.html +0 -1
  283. package/typedoc/types/IntentSchema.html +0 -1
  284. package/typedoc/types/IntentUndo.html +0 -2
  285. package/typedoc/types/InterfaceDef.html +0 -4
  286. package/typedoc/types/Label.html +0 -1
  287. package/typedoc/types/NodeSerializer.html +0 -8
  288. package/typedoc/types/PluginManagerOptions.html +0 -6
  289. package/typedoc/types/PluginMeta.html +0 -21
  290. package/typedoc/types/PromiseIntentDispatcher.html +0 -2
  291. package/typedoc/types/PromiseIntentUndo.html +0 -2
  292. package/typedoc/types/Resource.html +0 -1
  293. package/typedoc/types/ResourceKey.html +0 -1
  294. package/typedoc/types/ResourceLanguage.html +0 -1
  295. package/typedoc/types/SerializedNode.html +0 -4
  296. package/typedoc/types/SurfaceComponent.html +0 -2
  297. package/typedoc/types/SurfaceDefinition.html +0 -2
  298. package/typedoc/types/SurfaceProps.html +0 -4
  299. package/typedoc/variables/Capabilities.AnchorSort.html +0 -1
  300. package/typedoc/variables/Capabilities.AppGraph.html +0 -1
  301. package/typedoc/variables/Capabilities.AppGraphBuilder.html +0 -1
  302. package/typedoc/variables/Capabilities.AppGraphSerializer.html +0 -1
  303. package/typedoc/variables/Capabilities.ArtifactDefinition.html +0 -1
  304. package/typedoc/variables/Capabilities.FileUploader.html +0 -1
  305. package/typedoc/variables/Capabilities.IntentDispatcher.html +0 -1
  306. package/typedoc/variables/Capabilities.IntentResolver.html +0 -1
  307. package/typedoc/variables/Capabilities.Layout.html +0 -1
  308. package/typedoc/variables/Capabilities.Metadata.html +0 -1
  309. package/typedoc/variables/Capabilities.Null.html +0 -1
  310. package/typedoc/variables/Capabilities.PluginManager.html +0 -1
  311. package/typedoc/variables/Capabilities.ReactContext.html +0 -1
  312. package/typedoc/variables/Capabilities.ReactRoot.html +0 -1
  313. package/typedoc/variables/Capabilities.ReactSurface.html +0 -1
  314. package/typedoc/variables/Capabilities.RxRegistry.html +0 -1
  315. package/typedoc/variables/Capabilities.Settings.html +0 -1
  316. package/typedoc/variables/Capabilities.SettingsStore.html +0 -1
  317. package/typedoc/variables/Capabilities.Tools.html +0 -1
  318. package/typedoc/variables/Capabilities.Translations.html +0 -1
  319. package/typedoc/variables/Events.AppGraphReady.html +0 -2
  320. package/typedoc/variables/Events.DispatcherReady.html +0 -2
  321. package/typedoc/variables/Events.LayoutReady.html +0 -1
  322. package/typedoc/variables/Events.SettingsReady.html +0 -2
  323. package/typedoc/variables/Events.SetupAppGraph.html +0 -2
  324. package/typedoc/variables/Events.SetupArtifactDefinition.html +0 -2
  325. package/typedoc/variables/Events.SetupIntentResolver.html +0 -2
  326. package/typedoc/variables/Events.SetupMetadata.html +0 -2
  327. package/typedoc/variables/Events.SetupReactSurface.html +0 -2
  328. package/typedoc/variables/Events.SetupSettings.html +0 -2
  329. package/typedoc/variables/Events.SetupTranslations.html +0 -2
  330. package/typedoc/variables/Events.Startup.html +0 -2
  331. package/typedoc/variables/FileInfoSchema.html +0 -1
  332. package/typedoc/variables/INTENT_ACTION.html +0 -1
  333. package/typedoc/variables/INTENT_PLUGIN.html +0 -1
  334. package/typedoc/variables/LAYOUT_ACTION.html +0 -1
  335. package/typedoc/variables/LAYOUT_PLUGIN.html +0 -1
  336. package/typedoc/variables/Label.html +0 -1
  337. package/typedoc/variables/LayoutAction.Toast.html +0 -1
  338. package/typedoc/variables/LayoutAction.UPDATE_LAYOUT.html +0 -1
  339. package/typedoc/variables/PluginManagerProvider.html +0 -2
  340. package/typedoc/variables/Resource.html +0 -2
  341. package/typedoc/variables/ResourceKey.html +0 -1
  342. package/typedoc/variables/ResourceLanguage.html +0 -1
  343. package/typedoc/variables/SETTINGS_ACTION.html +0 -1
  344. package/typedoc/variables/SETTINGS_ID.html +0 -1
  345. package/typedoc/variables/SETTINGS_KEY.html +0 -1
  346. package/typedoc/variables/SETTINGS_PLUGIN.html +0 -1
  347. package/typedoc/variables/Surface.html +0 -2
  348. package/typedoc/variables/defaultFileTypes.html +0 -1
  349. /package/dist/lib/browser/{chunk-WWEJRWFX.mjs.map → chunk-ORWHM7CO.mjs.map} +0 -0
  350. /package/dist/lib/browser/{intent-dispatcher-XVBOMF2Y.mjs.map → intent-dispatcher-QG7UPGQX.mjs.map} +0 -0
  351. /package/dist/lib/node-esm/{chunk-I6BVZMAH.mjs.map → chunk-UMZQERLE.mjs.map} +0 -0
  352. /package/dist/lib/node-esm/{intent-dispatcher-7JPGLCQ5.mjs.map → intent-dispatcher-NXBGPJOX.mjs.map} +0 -0
@@ -4,20 +4,22 @@
4
4
 
5
5
  import { RegistryContext } from '@effect-rx/rx-react';
6
6
  import { effect } from '@preact/signals-core';
7
- import React, { useCallback, useEffect, useMemo, useState, type FC, type PropsWithChildren } from 'react';
7
+ import React, { type FC, useCallback, useEffect, useMemo } from 'react';
8
8
 
9
9
  import { invariant } from '@dxos/invariant';
10
10
  import { live } from '@dxos/live-object';
11
- import { useDefaultValue } from '@dxos/react-hooks';
11
+ import { useAsyncEffect, useDefaultValue } from '@dxos/react-hooks';
12
12
 
13
- import { Capabilities, Events } from './common';
14
- import { PluginManager, type PluginManagerOptions, type Plugin } from './core';
15
- import { topologicalSort } from './helpers';
16
- import { ErrorBoundary, PluginManagerProvider, useCapabilities } from './react';
13
+ import { Capabilities, Events } from '../common';
14
+ import { type Plugin, PluginManager, type PluginManagerOptions } from '../core';
15
+ import { ErrorBoundary, PluginManagerProvider } from '../react';
16
+
17
+ import { App } from './App';
18
+ import { DefaultFallback } from './DefaultFallback';
17
19
 
18
20
  const ENABLED_KEY = 'dxos.org/app-framework/enabled';
19
21
 
20
- export type CreateAppOptions = {
22
+ export type UseAppOptions = {
21
23
  pluginManager?: PluginManager;
22
24
  pluginLoader?: PluginManagerOptions['pluginLoader'];
23
25
  plugins?: Plugin[];
@@ -27,6 +29,7 @@ export type CreateAppOptions = {
27
29
  fallback?: ErrorBoundary['props']['fallback'];
28
30
  cacheEnabled?: boolean;
29
31
  safeMode?: boolean;
32
+ debounce?: number;
30
33
  };
31
34
 
32
35
  /**
@@ -38,7 +41,7 @@ export type CreateAppOptions = {
38
41
  * const core = [LayoutPluginId];
39
42
  * const default = [MyPluginId];
40
43
  * const fallback = <div>Initializing Plugins...</div>;
41
- * const App = createApp({ plugins, core, default, fallback });
44
+ * const App = useApp({ plugins, core, default, fallback });
42
45
  * createRoot(document.getElementById('root')!).render(
43
46
  * <StrictMode>
44
47
  * <App />
@@ -64,7 +67,8 @@ export const useApp = ({
64
67
  fallback = DefaultFallback,
65
68
  cacheEnabled = false,
66
69
  safeMode = false,
67
- }: CreateAppOptions) => {
70
+ debounce = 0,
71
+ }: UseAppOptions) => {
68
72
  const plugins = useDefaultValue(_plugins, () => []);
69
73
  const core = useDefaultValue(_core, () => plugins.map(({ meta }) => meta.id));
70
74
  const defaults = useDefaultValue(_defaults, () => []);
@@ -134,16 +138,12 @@ export const useApp = ({
134
138
  setupDevtools(manager);
135
139
  }, [manager]);
136
140
 
137
- useEffect(() => {
138
- const timeout = setTimeout(async () => {
139
- await Promise.all([
140
- // TODO(wittjosiah): Factor out such that this could be called per surface role when attempting to render.
141
- manager.activate(Events.SetupReactSurface),
142
- manager.activate(Events.Startup),
143
- ]);
144
- });
145
-
146
- return () => clearTimeout(timeout);
141
+ useAsyncEffect(async () => {
142
+ await Promise.all([
143
+ // TODO(wittjosiah): Factor out such that this could be called per surface role when attempting to render.
144
+ manager.activate(Events.SetupReactSurface),
145
+ manager.activate(Events.Startup),
146
+ ]);
147
147
  }, [manager]);
148
148
 
149
149
  return useCallback(
@@ -151,7 +151,7 @@ export const useApp = ({
151
151
  <ErrorBoundary fallback={fallback}>
152
152
  <PluginManagerProvider value={manager}>
153
153
  <RegistryContext.Provider value={manager.registry}>
154
- <App placeholder={placeholder} state={state} />
154
+ <App placeholder={placeholder} state={state} debounce={debounce} />
155
155
  </RegistryContext.Provider>
156
156
  </PluginManagerProvider>
157
157
  </ErrorBoundary>
@@ -160,116 +160,6 @@ export const useApp = ({
160
160
  );
161
161
  };
162
162
 
163
- const DELAY_PLACEHOLDER = 2_000;
164
-
165
- enum LoadingState {
166
- Loading = 0,
167
- FadeIn = 1,
168
- FadeOut = 2,
169
- Done = 3,
170
- }
171
-
172
- /**
173
- * To avoid "flashing" the placeholder, we wait a period of time before starting the loading animation.
174
- * If loading completes during this time the placehoder is not shown, otherwise is it displayed for a minimum period of time.
175
- *
176
- * States:
177
- * 0: Loading - Wait for a period of time before starting the loading animation.
178
- * 1: Fade-in - Display a loading animation.
179
- * 2: Fade-out - Fade out the loading animation.
180
- * 3: Done - Remove the placeholder.
181
- */
182
- const useLoading = (state: AppProps['state']) => {
183
- const [stage, setStage] = useState<LoadingState>(LoadingState.Loading);
184
- useEffect(() => {
185
- const i = setInterval(() => {
186
- setStage((tick) => {
187
- switch (tick) {
188
- case LoadingState.Loading:
189
- if (!state.ready) {
190
- return LoadingState.FadeIn;
191
- } else {
192
- clearInterval(i);
193
- return LoadingState.Done;
194
- }
195
- case LoadingState.FadeIn:
196
- if (state.ready) {
197
- return LoadingState.FadeOut;
198
- }
199
- break;
200
- case LoadingState.FadeOut:
201
- clearInterval(i);
202
- return LoadingState.Done;
203
- }
204
-
205
- return tick;
206
- });
207
- }, DELAY_PLACEHOLDER);
208
-
209
- return () => clearInterval(i);
210
- }, []);
211
-
212
- return stage;
213
- };
214
-
215
- type AppProps = Pick<CreateAppOptions, 'placeholder'> & {
216
- state: { ready: boolean; error: unknown };
217
- };
218
-
219
- const App = ({ placeholder: Placeholder, state }: AppProps) => {
220
- const reactContexts = useCapabilities(Capabilities.ReactContext);
221
- const reactRoots = useCapabilities(Capabilities.ReactRoot);
222
- const stage = useLoading(state);
223
-
224
- if (state.error) {
225
- // This triggers the error boundary to provide UI feedback for the startup error.
226
- throw state.error;
227
- }
228
-
229
- // TODO(wittjosiah): Consider using Suspense instead?
230
- if (stage < LoadingState.Done) {
231
- if (!Placeholder) {
232
- return null;
233
- }
234
-
235
- return <Placeholder stage={stage} />;
236
- }
237
-
238
- const ComposedContext = composeContexts(reactContexts);
239
- return (
240
- <ComposedContext>
241
- {reactRoots.map(({ id, root: Component }) => (
242
- <Component key={id} />
243
- ))}
244
- </ComposedContext>
245
- );
246
- };
247
-
248
- // Default fallback does not use tailwind or theme.
249
- const DefaultFallback = ({ error }: { error: Error }) => {
250
- return (
251
- <div style={{ padding: '1rem' }}>
252
- {/* TODO(wittjosiah): Link to docs for replacing default. */}
253
- <h1 style={{ fontSize: '1.2rem', fontWeight: 700, margin: '0.5rem 0' }}>{error.message}</h1>
254
- <pre>{error.stack}</pre>
255
- </div>
256
- );
257
- };
258
-
259
- const composeContexts = (contexts: Capabilities.ReactContext[]) => {
260
- if (contexts.length === 0) {
261
- return ({ children }: PropsWithChildren) => <>{children}</>;
262
- }
263
-
264
- return topologicalSort(contexts)
265
- .map(({ context }) => context)
266
- .reduce((Acc, Next) => ({ children }) => (
267
- <Acc>
268
- <Next>{children}</Next>
269
- </Acc>
270
- ));
271
- };
272
-
273
163
  const setupDevtools = (manager: PluginManager) => {
274
164
  (globalThis as any).composer ??= {};
275
165
  (globalThis as any).composer.manager = manager;
@@ -0,0 +1,70 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useEffect, useState } from 'react';
6
+
7
+ import { type AppProps } from './App';
8
+
9
+ export enum LoadingState {
10
+ Loading = 0,
11
+ FadeIn = 1,
12
+ FadeOut = 2,
13
+ Done = 3,
14
+ }
15
+
16
+ /**
17
+ * To avoid "flashing" the placeholder, we wait a period of time before starting the loading animation.
18
+ * If loading completes during this time the placehoder is not shown, otherwise is it displayed for a minimum period of time.
19
+ *
20
+ * States:
21
+ * 0: Loading - Wait for a period of time before starting the loading animation.
22
+ * 1: Fade-in - Display a loading animation.
23
+ * 2: Fade-out - Fade out the loading animation.
24
+ * 3: Done - Remove the placeholder.
25
+ */
26
+ export const useLoading = (state: AppProps['state'], debounce = 0) => {
27
+ const [stage, setStage] = useState<LoadingState>(LoadingState.Loading);
28
+ useEffect(() => {
29
+ if (!debounce) {
30
+ return;
31
+ }
32
+
33
+ const i = setInterval(() => {
34
+ setStage((stage) => {
35
+ switch (stage) {
36
+ case LoadingState.Loading: {
37
+ if (!state.ready) {
38
+ return LoadingState.FadeIn;
39
+ } else {
40
+ clearInterval(i);
41
+ return LoadingState.Done;
42
+ }
43
+ }
44
+
45
+ case LoadingState.FadeIn: {
46
+ if (state.ready) {
47
+ return LoadingState.FadeOut;
48
+ }
49
+ break;
50
+ }
51
+
52
+ case LoadingState.FadeOut: {
53
+ clearInterval(i);
54
+ return LoadingState.Done;
55
+ }
56
+ }
57
+
58
+ return stage;
59
+ });
60
+ }, debounce);
61
+
62
+ return () => clearInterval(i);
63
+ }, [debounce]);
64
+
65
+ if (!debounce) {
66
+ return state.ready ? LoadingState.Done : LoadingState.Loading;
67
+ }
68
+
69
+ return stage;
70
+ };
@@ -6,7 +6,7 @@ import { Registry } from '@effect-rx/rx-react';
6
6
  import { Effect } from 'effect';
7
7
  import { describe, expect, it, onTestFinished } from 'vitest';
8
8
 
9
- import { defineCapability, PluginContext } from './capabilities';
9
+ import { PluginContext, defineCapability } from './capabilities';
10
10
 
11
11
  const defaultOptions = {
12
12
  activate: () => Effect.succeed(false),
@@ -22,6 +22,10 @@ export type InterfaceDef<T> = {
22
22
  identifier: string;
23
23
  };
24
24
 
25
+ export namespace InterfaceDef {
26
+ export type Implementation<I extends InterfaceDef<any>> = I extends InterfaceDef<infer T> ? T : never;
27
+ }
28
+
25
29
  /**
26
30
  * Helper to define the interface of a capability.
27
31
  */
@@ -69,16 +73,17 @@ class CapabilityImpl<T> {
69
73
  /**
70
74
  * Helper to define the implementation of a capability.
71
75
  */
72
- export const contributes = <T>(
73
- interfaceDef: Capability<T>['interface'],
74
- implementation: Capability<T>['implementation'],
75
- deactivate?: Capability<T>['deactivate'],
76
- ): Capability<T> => {
77
- return { interface: interfaceDef, implementation, deactivate } satisfies Capability<T>;
76
+ export const contributes = <I extends InterfaceDef<any>>(
77
+ interfaceDef: I,
78
+ implementation: Capability<InterfaceDef.Implementation<I>>['implementation'],
79
+ deactivate?: Capability<InterfaceDef.Implementation<I>>['deactivate'],
80
+ ): Capability<I> => {
81
+ return { interface: interfaceDef, implementation, deactivate } satisfies Capability<I>;
78
82
  };
79
83
 
80
84
  type LoadCapability<T, U> = () => Promise<{ default: (props: T) => MaybePromise<Capability<U>> }>;
81
85
  type LoadCapabilities<T> = () => Promise<{ default: (props: T) => MaybePromise<AnyCapability[]> }>;
86
+
82
87
  // TODO(wittjosiah): Not having the array be `any` causes type errors when using the lazy capability.
83
88
  type LazyCapability<T, U> = (props?: T) => Promise<() => Promise<Capability<U> | AnyCapability[]>>;
84
89
 
@@ -3,8 +3,7 @@
3
3
  //
4
4
 
5
5
  import { effect } from '@preact/signals-core';
6
- import { afterEach } from 'node:test';
7
- import { describe, expect, it } from 'vitest';
6
+ import { afterEach, describe, expect, it } from 'vitest';
8
7
 
9
8
  import { Trigger } from '@dxos/async';
10
9
  import { raise } from '@dxos/debug';
@@ -13,11 +12,12 @@ import { registerSignalsRuntime } from '@dxos/echo-signals';
13
12
  import { invariant } from '@dxos/invariant';
14
13
  import { live } from '@dxos/live-object';
15
14
 
16
- import { contributes, defineCapability, type PluginContext } from './capabilities';
15
+ import { Events } from '../common';
16
+
17
+ import { type PluginContext, contributes, defineCapability } from './capabilities';
17
18
  import { allOf, defineEvent, oneOf } from './events';
18
19
  import { PluginManager } from './manager';
19
- import { definePlugin, defineModule, type Plugin } from './plugin';
20
- import { Events } from '../common';
20
+ import { type Plugin, defineModule, definePlugin } from './plugin';
21
21
 
22
22
  registerSignalsRuntime();
23
23
 
@@ -4,16 +4,16 @@
4
4
 
5
5
  import { Registry } from '@effect-rx/rx-react';
6
6
  import { untracked } from '@preact/signals-core';
7
- import { Array as A, Effect, Either, Match, pipe } from 'effect';
7
+ import { Array, Duration, Effect, Fiber, HashSet, Match, Ref, pipe } from 'effect';
8
8
 
9
9
  import { Event } from '@dxos/async';
10
- import { live, type Live } from '@dxos/live-object';
10
+ import { type Live, live } from '@dxos/live-object';
11
11
  import { log } from '@dxos/log';
12
12
  import { type MaybePromise } from '@dxos/util';
13
13
 
14
14
  import { type AnyCapability, PluginContext } from './capabilities';
15
15
  import { type ActivationEvent, eventKey, getEvents, isAllOf } from './events';
16
- import { type PluginModule, type Plugin } from './plugin';
16
+ import { type Plugin, type PluginModule } from './plugin';
17
17
 
18
18
  // TODO(wittjosiah): Factor out?
19
19
  const isPromise = (value: unknown): value is Promise<unknown> => {
@@ -52,6 +52,9 @@ export class PluginManager {
52
52
  private readonly _state: Live<PluginManagerState>;
53
53
  private readonly _pluginLoader: PluginManagerOptions['pluginLoader'];
54
54
  private readonly _capabilities = new Map<string, AnyCapability[]>();
55
+ private readonly _moduleMemoMap = new Map<PluginModule['id'], Promise<AnyCapability[]>>();
56
+ private readonly _activatingEvents = Effect.runSync(Ref.make<string[]>([]));
57
+ private readonly _activatingModules = Effect.runSync(Ref.make<string[]>([]));
55
58
 
56
59
  constructor({
57
60
  pluginLoader,
@@ -74,8 +77,8 @@ export class PluginManager {
74
77
  enabled,
75
78
  modules: [],
76
79
  active: [],
77
- pendingReset: [],
78
80
  eventsFired: [],
81
+ pendingReset: [],
79
82
  });
80
83
  plugins.forEach((plugin) => this._addPlugin(plugin));
81
84
  core.forEach((id) => this.enable(id));
@@ -268,6 +271,7 @@ export class PluginManager {
268
271
  private _addPlugin(plugin: Plugin): void {
269
272
  untracked(() => {
270
273
  log('add plugin', { id: plugin.meta.id });
274
+ // TODO(wittjosiah): Find a way to add a warning for duplicate plugins that doesn't cause log spam.
271
275
  if (!this._state.plugins.includes(plugin)) {
272
276
  this._state.plugins.push(plugin);
273
277
  }
@@ -287,6 +291,7 @@ export class PluginManager {
287
291
  private _addModule(module: PluginModule): void {
288
292
  untracked(() => {
289
293
  log('add module', { id: module.id });
294
+ // TODO(wittjosiah): Find a way to add a warning for duplicate modules that doesn't cause log spam.
290
295
  if (!this._state.modules.includes(module)) {
291
296
  this._state.modules.push(module);
292
297
  }
@@ -329,7 +334,7 @@ export class PluginManager {
329
334
  .map(eventKey)
330
335
  .filter((key) => this._state.eventsFired.includes(key));
331
336
 
332
- const pendingReset = Array.from(new Set(activationEvents)).filter(
337
+ const pendingReset = Array.fromIterable(new Set(activationEvents)).filter(
333
338
  (event) => !this._state.pendingReset.includes(event),
334
339
  );
335
340
  if (pendingReset.length > 0) {
@@ -343,24 +348,42 @@ export class PluginManager {
343
348
  * @internal
344
349
  */
345
350
  // TODO(wittjosiah): Improve error typing.
346
- _activate(event: ActivationEvent | string): Effect.Effect<boolean, Error> {
351
+ _activate(
352
+ event: ActivationEvent | string,
353
+ params?: { before?: string; after?: string },
354
+ ): Effect.Effect<boolean, Error> {
347
355
  return Effect.gen(this, function* () {
348
356
  const key = typeof event === 'string' ? event : eventKey(event);
349
- log('activating', { key });
357
+ log('activating', { key, ...params });
358
+ yield* Ref.update(this._activatingEvents, (activating) => Array.append(activating, key));
350
359
  const pendingIndex = this._state.pendingReset.findIndex((event) => event === key);
351
360
  if (pendingIndex !== -1) {
352
361
  this._state.pendingReset.splice(pendingIndex, 1);
353
362
  }
354
363
 
364
+ const activatingEvents = yield* this._activatingEvents;
365
+ const activatingModules = yield* this._activatingModules;
355
366
  const modules = this._getInactiveModulesByEvent(key).filter((module) => {
356
367
  const allOf = isAllOf(module.activatesOn);
357
368
  if (!allOf) {
358
369
  return true;
359
370
  }
360
371
 
372
+ // Check to see if all of the events in the `allOf` have been fired.
373
+ // An event can be considered "fired" if it is in the `eventsFired` list or if it is currently being activated.
361
374
  const events = module.activatesOn.events.filter((event) => eventKey(event) !== key);
362
- return events.every((event) => this._state.eventsFired.includes(eventKey(event)));
375
+ return (
376
+ events.every(
377
+ (event) => this._state.eventsFired.includes(eventKey(event)) || activatingEvents.includes(eventKey(event)),
378
+ ) && !activatingModules.includes(module.id)
379
+ );
363
380
  });
381
+ yield* Ref.update(this._activatingModules, (activating) =>
382
+ Array.appendAll(
383
+ activating,
384
+ modules.map((module) => module.id),
385
+ ),
386
+ );
364
387
  if (modules.length === 0) {
365
388
  log('no modules to activate', { key });
366
389
  if (!this._state.eventsFired.includes(key)) {
@@ -372,31 +395,53 @@ export class PluginManager {
372
395
  log('activating modules', { key, modules: modules.map((module) => module.id) });
373
396
  this.activation.emit({ event: key, state: 'activating' });
374
397
 
398
+ // Fire activatesBefore events.
399
+ yield* pipe(
400
+ modules,
401
+ Array.flatMap((module) => module.activatesBefore ?? []),
402
+ HashSet.fromIterable,
403
+ HashSet.toValues,
404
+ Array.filter((event) => !activatingEvents.includes(eventKey(event))),
405
+ Array.map((event) => this._activate(event, { before: key })),
406
+ Effect.allWith({ concurrency: 'unbounded' }),
407
+ );
408
+
375
409
  // Concurrently triggers loading of lazy capabilities.
376
- const getCapabilities = yield* Effect.all(
377
- modules.map(({ activate }) =>
378
- Effect.tryPromise({
379
- try: async () => activate(this.context),
380
- catch: (error) => error as Error,
381
- }),
382
- ),
383
- { concurrency: 'unbounded' },
410
+ const getCapabilities = yield* pipe(
411
+ modules,
412
+ Array.map((mod) => this._loadModule(mod)),
413
+ Effect.allWith({ concurrency: 'unbounded' }),
414
+ Effect.catchAll((error) => {
415
+ this.activation.emit({ event: key, state: 'error', error });
416
+ return Effect.fail(error);
417
+ }),
384
418
  );
385
419
 
386
- const result = yield* pipe(
420
+ // Contribute the capabilities from the activated modules.
421
+ yield* pipe(
387
422
  modules,
388
- A.zip(getCapabilities),
389
- A.map(([module, getCapabilities]) => this._activateModule(module, getCapabilities)),
423
+ Array.zip(getCapabilities),
424
+ Array.map(([module, capabilities]) => this._contributeCapabilities(module, capabilities)),
390
425
  // TODO(wittjosiah): This currently can't be run in parallel.
391
426
  // Running this with concurrency causes races with `allOf` activation events.
392
427
  Effect.all,
393
- Effect.either,
394
428
  );
395
429
 
396
- if (Either.isLeft(result)) {
397
- this.activation.emit({ event: key, state: 'error', error: result.left });
398
- yield* Effect.fail(result.left);
399
- }
430
+ // Fire activatesAfter events.
431
+ yield* pipe(
432
+ modules,
433
+ Array.flatMap((module) => module.activatesAfter ?? []),
434
+ HashSet.fromIterable,
435
+ HashSet.toValues,
436
+ Array.filter((event) => !activatingEvents.includes(eventKey(event))),
437
+ Array.map((event) => this._activate(event, { after: key })),
438
+ Effect.allWith({ concurrency: 'unbounded' }),
439
+ );
440
+
441
+ yield* Ref.update(this._activatingEvents, (activating) => Array.filter(activating, (event) => event !== key));
442
+ yield* Ref.update(this._activatingModules, (activating) =>
443
+ Array.filter(activating, (module) => !modules.map((module) => module.id).includes(module)),
444
+ );
400
445
 
401
446
  if (!this._state.eventsFired.includes(key)) {
402
447
  this._state.eventsFired.push(key);
@@ -409,43 +454,60 @@ export class PluginManager {
409
454
  });
410
455
  }
411
456
 
412
- private _activateModule(
413
- module: PluginModule,
414
- getCapabilities: AnyCapability | AnyCapability[] | (() => Promise<AnyCapability | AnyCapability[]>),
415
- ): Effect.Effect<void, Error> {
416
- return Effect.gen(this, function* () {
417
- yield* Effect.all(module.activatesBefore?.map((event) => this._activate(event)) ?? [], {
418
- concurrency: 'unbounded',
419
- });
457
+ // Memoized with _moduleMemoMap
458
+ private _loadModule = (mod: PluginModule): Effect.Effect<AnyCapability[], Error> =>
459
+ Effect.tryPromise({
460
+ try: async () => {
461
+ const entry = this._moduleMemoMap.get(mod.id);
462
+ if (entry) {
463
+ return entry;
464
+ }
420
465
 
421
- log('activating module...', { module: module.id });
422
- // TODO(wittjosiah): This is not handling errors thrown if this is synchronous.
423
- const maybeCapabilities = typeof getCapabilities === 'function' ? getCapabilities() : getCapabilities;
424
- const resolvedCapabilities = yield* Match.value(maybeCapabilities).pipe(
425
- // TODO(wittjosiah): Activate with an effect?
426
- // Match.when(Effect.isEffect, (effect) => effect),
427
- Match.when(isPromise, (promise) =>
428
- Effect.tryPromise({
429
- try: () => promise,
430
- catch: (error) => error as Error,
431
- }),
466
+ const promise = (async () => {
467
+ const start = performance.now();
468
+ let failed = false;
469
+ try {
470
+ log('loading module', { module: mod.id });
471
+ // TODO(wittjosiah): Support activation with an effect.
472
+ let activationResult = await mod.activate(this.context);
473
+ if (typeof activationResult === 'function') {
474
+ activationResult = await activationResult();
475
+ }
476
+ return Array.isArray(activationResult) ? activationResult : [activationResult];
477
+ } catch (error) {
478
+ failed = true;
479
+ throw error;
480
+ } finally {
481
+ performance.measure('activate-module', {
482
+ start,
483
+ end: performance.now(),
484
+ detail: {
485
+ module: mod.id,
486
+ },
487
+ });
488
+ log('loaded module', { module: mod.id, elapsed: performance.now() - start, failed });
489
+ }
490
+ })();
491
+ this._moduleMemoMap.set(mod.id, promise);
492
+ return promise;
493
+ },
494
+ catch: (error) => error as Error,
495
+ }).pipe(
496
+ Effect.withSpan('PluginManager._loadModule'),
497
+ together(
498
+ Effect.sleep(Duration.seconds(10)).pipe(
499
+ Effect.andThen(Effect.sync(() => log.warn(`module is taking a long time to activate`, { module: mod.id }))),
432
500
  ),
433
- Match.orElse((program) => Effect.succeed(program)),
434
- );
435
- const capabilities = Match.value(resolvedCapabilities).pipe(
436
- Match.when(Array.isArray, (array) => array),
437
- Match.orElse((value) => [value]),
438
- );
501
+ ),
502
+ );
503
+
504
+ private _contributeCapabilities(module: PluginModule, capabilities: AnyCapability[]): Effect.Effect<void, Error> {
505
+ return Effect.gen(this, function* () {
439
506
  capabilities.forEach((capability) => {
440
507
  this.context.contributeCapability({ module: module.id, ...capability });
441
508
  });
442
509
  this._state.active.push(module.id);
443
510
  this._capabilities.set(module.id, capabilities);
444
- log('activated module', { module: module.id });
445
-
446
- yield* Effect.all(module.activatesAfter?.map((event) => this._activate(event)) ?? [], {
447
- concurrency: 'unbounded',
448
- });
449
511
  });
450
512
  }
451
513
 
@@ -469,6 +531,7 @@ export class PluginManager {
469
531
  return Effect.gen(this, function* () {
470
532
  const id = module.id;
471
533
  log('deactivating', { id });
534
+ this._moduleMemoMap.delete(id);
472
535
 
473
536
  const capabilities = this._capabilities.get(id);
474
537
  if (capabilities) {
@@ -517,3 +580,18 @@ export class PluginManager {
517
580
  });
518
581
  }
519
582
  }
583
+
584
+ /**
585
+ * Runs an effect concurrently with another effect.
586
+ * If the first effect completes, the second effect is interrupted.
587
+ */
588
+ // TODO(dmaretskyi): Effect.race > Effect.asVoid
589
+ const together =
590
+ <R1>(togetherEffect: Effect.Effect<void, never, R1>) =>
591
+ <A, E, R2>(effect: Effect.Effect<A, E, R2>): Effect.Effect<A, E, R1 | R2> =>
592
+ Effect.gen(function* () {
593
+ const togetherFiber = yield* Effect.fork(togetherEffect);
594
+ const result = yield* effect;
595
+ yield* Fiber.interrupt(togetherFiber);
596
+ return result;
597
+ });
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { describe, it, expect } from 'vitest';
5
+ import { describe, expect, it } from 'vitest';
6
6
 
7
7
  import { topologicalSort } from './helpers';
8
8
 
package/src/index.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './App';
6
5
  export * from './common';
6
+ export * from './components';
7
7
  export * from './core';
8
8
  export * from './plugin-intent';
9
9
  export * from './plugin-settings';
@@ -22,7 +22,7 @@ export const Debug = () => {
22
22
  };
23
23
 
24
24
  return (
25
- <SyntaxHighlighter language='json' classNames='flex w-full text-xs opacity-75 rounded'>
25
+ <SyntaxHighlighter language='json' classNames='text-xs opacity-75 rounded'>
26
26
  {JSON.stringify(object, undefined, 2)}
27
27
  </SyntaxHighlighter>
28
28
  );