@dxos/app-framework 0.8.4-main.f9ba587 → 0.8.4-main.fd6878d

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 (281) hide show
  1. package/.swc/plugins/v7_linux_x86_64_13.0.0/c614d7475354583212fbd7669acbae95b9832c305bf51bdaabe2e6de05abb6bf +0 -0
  2. package/dist/lib/browser/{app-graph-builder-BGGXLD6T.mjs → app-graph-builder-MOVKFH3J.mjs} +3 -3
  3. package/dist/lib/browser/app-graph-builder-MOVKFH3J.mjs.map +7 -0
  4. package/dist/lib/browser/{chunk-2636QSIK.mjs → chunk-NKCIDYDI.mjs} +304 -224
  5. package/dist/lib/browser/chunk-NKCIDYDI.mjs.map +7 -0
  6. package/dist/lib/browser/{chunk-DHZB7HG7.mjs → chunk-OSBZFKMO.mjs} +38 -23
  7. package/dist/lib/browser/chunk-OSBZFKMO.mjs.map +7 -0
  8. package/dist/lib/browser/index.mjs +5 -5
  9. package/dist/lib/browser/index.mjs.map +2 -2
  10. package/dist/lib/browser/{intent-dispatcher-TWKB22NI.mjs → intent-dispatcher-FTTJLVGN.mjs} +2 -2
  11. package/dist/lib/browser/{intent-resolver-O67UANYP.mjs → intent-resolver-ZCGEAG3E.mjs} +2 -2
  12. package/dist/lib/browser/intent-resolver-ZCGEAG3E.mjs.map +7 -0
  13. package/dist/lib/browser/meta.json +1 -1
  14. package/dist/lib/browser/{store-LFKDWHUQ.mjs → store-3QB6Q2BC.mjs} +2 -2
  15. package/dist/lib/browser/{store-LFKDWHUQ.mjs.map → store-3QB6Q2BC.mjs.map} +1 -1
  16. package/dist/lib/browser/testing/index.mjs +2 -2
  17. package/dist/lib/browser/testing/index.mjs.map +2 -2
  18. package/dist/lib/browser/worker.mjs +1 -1
  19. package/dist/lib/node-esm/{app-graph-builder-QHIJUYYW.mjs → app-graph-builder-ODE4B5GT.mjs} +3 -3
  20. package/dist/lib/node-esm/app-graph-builder-ODE4B5GT.mjs.map +7 -0
  21. package/dist/lib/node-esm/{chunk-NJAFK626.mjs → chunk-WU3QN5B6.mjs} +38 -23
  22. package/dist/lib/node-esm/chunk-WU3QN5B6.mjs.map +7 -0
  23. package/dist/lib/node-esm/{chunk-VSKRV3NW.mjs → chunk-YEN7NKTF.mjs} +304 -224
  24. package/dist/lib/node-esm/chunk-YEN7NKTF.mjs.map +7 -0
  25. package/dist/lib/node-esm/index.mjs +5 -5
  26. package/dist/lib/node-esm/index.mjs.map +2 -2
  27. package/dist/lib/node-esm/{intent-dispatcher-5PRM3KGH.mjs → intent-dispatcher-YQIQ55LJ.mjs} +2 -2
  28. package/dist/lib/node-esm/{intent-resolver-K3D4BXQQ.mjs → intent-resolver-KG27L7EQ.mjs} +2 -2
  29. package/dist/lib/node-esm/intent-resolver-KG27L7EQ.mjs.map +7 -0
  30. package/dist/lib/node-esm/meta.json +1 -1
  31. package/dist/lib/node-esm/{store-53XDUBMD.mjs → store-TIJAVO3D.mjs} +2 -2
  32. package/dist/lib/node-esm/{store-53XDUBMD.mjs.map → store-TIJAVO3D.mjs.map} +1 -1
  33. package/dist/lib/node-esm/testing/index.mjs +2 -2
  34. package/dist/lib/node-esm/testing/index.mjs.map +2 -2
  35. package/dist/lib/node-esm/worker.mjs +1 -1
  36. package/dist/types/src/App.d.ts +1 -1
  37. package/dist/types/src/App.d.ts.map +1 -1
  38. package/dist/types/src/common/capabilities.d.ts +82 -7
  39. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  40. package/dist/types/src/common/events.d.ts.map +1 -1
  41. package/dist/types/src/common/surface.d.ts +1 -1
  42. package/dist/types/src/common/surface.d.ts.map +1 -1
  43. package/dist/types/src/core/capabilities.d.ts.map +1 -1
  44. package/dist/types/src/core/manager.d.ts +6 -2
  45. package/dist/types/src/core/manager.d.ts.map +1 -1
  46. package/dist/types/src/playground/generator/Toolbar.d.ts.map +1 -1
  47. package/dist/types/src/playground/generator/generator.d.ts.map +1 -1
  48. package/dist/types/src/playground/logger/Toolbar.d.ts.map +1 -1
  49. package/dist/types/src/playground/logger/plugin.d.ts.map +1 -1
  50. package/dist/types/src/playground/playground.stories.d.ts.map +1 -1
  51. package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -1
  52. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +2 -2
  53. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -1
  54. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -1
  55. package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +1 -1
  56. package/dist/types/src/plugin-settings/intent-resolver.d.ts.map +1 -1
  57. package/dist/types/src/plugin-settings/store.d.ts.map +1 -1
  58. package/dist/types/src/react/ErrorBoundary.d.ts +13 -14
  59. package/dist/types/src/react/ErrorBoundary.d.ts.map +1 -1
  60. package/dist/types/src/react/IntentContext.d.ts.map +1 -1
  61. package/dist/types/src/react/Surface.d.ts.map +1 -1
  62. package/dist/types/src/react/Surface.stories.d.ts.map +1 -1
  63. package/dist/types/src/react/common.d.ts.map +1 -1
  64. package/dist/types/src/react/useCapabilities.d.ts.map +1 -1
  65. package/dist/types/src/testing/withPluginManager.d.ts +2 -0
  66. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  67. package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
  68. package/dist/types/tsconfig.tsbuildinfo +1 -1
  69. package/package.json +28 -24
  70. package/src/App.tsx +12 -4
  71. package/src/common/capabilities.ts +103 -10
  72. package/src/common/events.ts +3 -1
  73. package/src/common/surface.ts +1 -1
  74. package/src/core/capabilities.test.ts +1 -1
  75. package/src/core/capabilities.ts +1 -0
  76. package/src/core/manager.test.ts +4 -3
  77. package/src/core/manager.ts +132 -54
  78. package/src/helpers.test.ts +1 -1
  79. package/src/playground/generator/Toolbar.tsx +2 -1
  80. package/src/playground/generator/generator.ts +2 -2
  81. package/src/playground/layout/plugin.ts +1 -1
  82. package/src/playground/logger/Toolbar.tsx +2 -1
  83. package/src/playground/logger/plugin.ts +3 -2
  84. package/src/playground/playground.stories.tsx +4 -3
  85. package/src/plugin-intent/IntentPlugin.ts +2 -1
  86. package/src/plugin-intent/intent-dispatcher.test.ts +1 -1
  87. package/src/plugin-intent/intent-dispatcher.ts +6 -5
  88. package/src/plugin-settings/SettingsPlugin.ts +3 -2
  89. package/src/plugin-settings/app-graph-builder.ts +4 -3
  90. package/src/plugin-settings/intent-resolver.ts +3 -2
  91. package/src/plugin-settings/store.ts +1 -1
  92. package/src/react/ErrorBoundary.tsx +24 -15
  93. package/src/react/IntentContext.tsx +3 -2
  94. package/src/react/Surface.stories.tsx +3 -2
  95. package/src/react/Surface.tsx +4 -3
  96. package/src/react/common.ts +2 -1
  97. package/src/react/useCapabilities.ts +2 -1
  98. package/src/testing/withPluginManager.stories.tsx +3 -2
  99. package/src/testing/withPluginManager.tsx +8 -5
  100. package/tsconfig.json +4 -1
  101. package/.eslintrc.cjs +0 -9
  102. package/.swc/plugins/v7_linux_x86_64_13.0.0/f45bdff002284d9e8f9ef3f0be909de12da36c049cbcf261ac78fc00abb09a2d +0 -0
  103. package/dist/lib/browser/app-graph-builder-BGGXLD6T.mjs.map +0 -7
  104. package/dist/lib/browser/chunk-2636QSIK.mjs.map +0 -7
  105. package/dist/lib/browser/chunk-DHZB7HG7.mjs.map +0 -7
  106. package/dist/lib/browser/intent-resolver-O67UANYP.mjs.map +0 -7
  107. package/dist/lib/node-esm/app-graph-builder-QHIJUYYW.mjs.map +0 -7
  108. package/dist/lib/node-esm/chunk-NJAFK626.mjs.map +0 -7
  109. package/dist/lib/node-esm/chunk-VSKRV3NW.mjs.map +0 -7
  110. package/dist/lib/node-esm/intent-resolver-K3D4BXQQ.mjs.map +0 -7
  111. package/typedoc/.nojekyll +0 -1
  112. package/typedoc/assets/hierarchy.js +0 -1
  113. package/typedoc/assets/highlight.css +0 -106
  114. package/typedoc/assets/icons.js +0 -18
  115. package/typedoc/assets/icons.svg +0 -1
  116. package/typedoc/assets/main.js +0 -60
  117. package/typedoc/assets/navigation.js +0 -1
  118. package/typedoc/assets/search.js +0 -1
  119. package/typedoc/assets/style.css +0 -1640
  120. package/typedoc/classes/CollaborationActions.InsertContent.html +0 -421
  121. package/typedoc/classes/ErrorBoundary.html +0 -125
  122. package/typedoc/classes/IntentAction.ShowUndo.html +0 -227
  123. package/typedoc/classes/IntentAction.Track.html +0 -266
  124. package/typedoc/classes/LayoutAction.AddToast.html +0 -265
  125. package/typedoc/classes/LayoutAction.Close.html +0 -382
  126. package/typedoc/classes/LayoutAction.Expose.html +0 -265
  127. package/typedoc/classes/LayoutAction.Open.html +0 -1123
  128. package/typedoc/classes/LayoutAction.RevertWorkspace.html +0 -343
  129. package/typedoc/classes/LayoutAction.ScrollIntoView.html +0 -460
  130. package/typedoc/classes/LayoutAction.Set.html +0 -460
  131. package/typedoc/classes/LayoutAction.SetLayoutMode.html +0 -499
  132. package/typedoc/classes/LayoutAction.SwitchWorkspace.html +0 -265
  133. package/typedoc/classes/LayoutAction.UpdateComplementary.html +0 -616
  134. package/typedoc/classes/LayoutAction.UpdateDialog.html +0 -1123
  135. package/typedoc/classes/LayoutAction.UpdateLayout.html +0 -461
  136. package/typedoc/classes/LayoutAction.UpdatePopover.html +0 -1435
  137. package/typedoc/classes/LayoutAction.UpdateSidebar.html +0 -616
  138. package/typedoc/classes/Plugin.html +0 -6
  139. package/typedoc/classes/PluginContext.html +0 -38
  140. package/typedoc/classes/PluginManager.html +0 -43
  141. package/typedoc/classes/PluginModule.html +0 -18
  142. package/typedoc/classes/SettingsAction.Open.html +0 -226
  143. package/typedoc/classes/SettingsAction.OpenPluginRegistry.html +0 -265
  144. package/typedoc/functions/Events.createStateEvent.html +0 -2
  145. package/typedoc/functions/IntentPlugin.html +0 -1
  146. package/typedoc/functions/SettingsPlugin.html +0 -1
  147. package/typedoc/functions/allOf.html +0 -2
  148. package/typedoc/functions/chain.html +0 -3
  149. package/typedoc/functions/contributes.html +0 -2
  150. package/typedoc/functions/createDispatcher.html +0 -3
  151. package/typedoc/functions/createIntent.html +0 -6
  152. package/typedoc/functions/createResolver.html +0 -2
  153. package/typedoc/functions/createSurface.html +0 -2
  154. package/typedoc/functions/defineCapability.html +0 -2
  155. package/typedoc/functions/defineEvent.html +0 -2
  156. package/typedoc/functions/defineModule.html +0 -2
  157. package/typedoc/functions/definePlugin.html +0 -2
  158. package/typedoc/functions/eventKey.html +0 -2
  159. package/typedoc/functions/getEvents.html +0 -2
  160. package/typedoc/functions/isAllOf.html +0 -2
  161. package/typedoc/functions/isOneOf.html +0 -2
  162. package/typedoc/functions/isSurfaceAvailable.html +0 -2
  163. package/typedoc/functions/lazy.html +0 -2
  164. package/typedoc/functions/oneOf.html +0 -2
  165. package/typedoc/functions/useApp.html +0 -6
  166. package/typedoc/functions/useAppGraph.html +0 -1
  167. package/typedoc/functions/useCapabilities.html +0 -3
  168. package/typedoc/functions/useCapability.html +0 -4
  169. package/typedoc/functions/useIntentDispatcher.html +0 -1
  170. package/typedoc/functions/useIntentResolver.html +0 -1
  171. package/typedoc/functions/useLayout.html +0 -1
  172. package/typedoc/functions/usePluginManager.html +0 -2
  173. package/typedoc/hierarchy.html +0 -1
  174. package/typedoc/index.html +0 -12
  175. package/typedoc/interfaces/LayoutAction.Toast.html +0 -10
  176. package/typedoc/media/LICENSE +0 -8
  177. package/typedoc/modules/Capabilities.html +0 -1
  178. package/typedoc/modules/CollaborationActions.html +0 -1
  179. package/typedoc/modules/Events.html +0 -1
  180. package/typedoc/modules/IntentAction.html +0 -1
  181. package/typedoc/modules/LayoutAction.html +0 -2
  182. package/typedoc/modules/SettingsAction.html +0 -1
  183. package/typedoc/modules.html +0 -1
  184. package/typedoc/types/ActivationEvent.html +0 -8
  185. package/typedoc/types/ActivationEvents.html +0 -2
  186. package/typedoc/types/AnyCapability.html +0 -1
  187. package/typedoc/types/AnyIntent.html +0 -1
  188. package/typedoc/types/AnyIntentChain.html +0 -1
  189. package/typedoc/types/AnyIntentEffectResult.html +0 -1
  190. package/typedoc/types/AnyIntentResolver.html +0 -1
  191. package/typedoc/types/AnyIntentResult.html +0 -1
  192. package/typedoc/types/Capabilities.FileUploader.html +0 -1
  193. package/typedoc/types/Capabilities.IntentResolver.html +0 -1
  194. package/typedoc/types/Capabilities.Layout.html +0 -1
  195. package/typedoc/types/Capabilities.Metadata.html +0 -1
  196. package/typedoc/types/Capabilities.ReactContext.html +0 -1
  197. package/typedoc/types/Capabilities.ReactRoot.html +0 -1
  198. package/typedoc/types/Capabilities.ReactSurface.html +0 -1
  199. package/typedoc/types/Capabilities.Settings.html +0 -4
  200. package/typedoc/types/Capability.html +0 -9
  201. package/typedoc/types/CreateAppOptions.html +0 -10
  202. package/typedoc/types/FileInfo.html +0 -1
  203. package/typedoc/types/Intent.html +0 -10
  204. package/typedoc/types/IntentChain.html +0 -6
  205. package/typedoc/types/IntentContext.html +0 -5
  206. package/typedoc/types/IntentData.html +0 -1
  207. package/typedoc/types/IntentDispatcher.html +0 -2
  208. package/typedoc/types/IntentDispatcherResult.html +0 -2
  209. package/typedoc/types/IntentEffectDefinition.html +0 -2
  210. package/typedoc/types/IntentEffectResult.html +0 -15
  211. package/typedoc/types/IntentParams.html +0 -3
  212. package/typedoc/types/IntentResolver.html +0 -2
  213. package/typedoc/types/IntentResultData.html +0 -1
  214. package/typedoc/types/IntentSchema.html +0 -1
  215. package/typedoc/types/IntentUndo.html +0 -2
  216. package/typedoc/types/InterfaceDef.html +0 -4
  217. package/typedoc/types/Label.html +0 -1
  218. package/typedoc/types/NodeSerializer.html +0 -8
  219. package/typedoc/types/PluginManagerOptions.html +0 -6
  220. package/typedoc/types/PluginMeta.html +0 -21
  221. package/typedoc/types/PromiseIntentDispatcher.html +0 -2
  222. package/typedoc/types/PromiseIntentUndo.html +0 -2
  223. package/typedoc/types/Resource.html +0 -1
  224. package/typedoc/types/ResourceKey.html +0 -1
  225. package/typedoc/types/ResourceLanguage.html +0 -1
  226. package/typedoc/types/SerializedNode.html +0 -4
  227. package/typedoc/types/SurfaceComponent.html +0 -2
  228. package/typedoc/types/SurfaceDefinition.html +0 -2
  229. package/typedoc/types/SurfaceProps.html +0 -4
  230. package/typedoc/variables/Capabilities.AnchorSort.html +0 -1
  231. package/typedoc/variables/Capabilities.AppGraph.html +0 -1
  232. package/typedoc/variables/Capabilities.AppGraphBuilder.html +0 -1
  233. package/typedoc/variables/Capabilities.AppGraphSerializer.html +0 -1
  234. package/typedoc/variables/Capabilities.ArtifactDefinition.html +0 -1
  235. package/typedoc/variables/Capabilities.FileUploader.html +0 -1
  236. package/typedoc/variables/Capabilities.IntentDispatcher.html +0 -1
  237. package/typedoc/variables/Capabilities.IntentResolver.html +0 -1
  238. package/typedoc/variables/Capabilities.Layout.html +0 -1
  239. package/typedoc/variables/Capabilities.Metadata.html +0 -1
  240. package/typedoc/variables/Capabilities.Null.html +0 -1
  241. package/typedoc/variables/Capabilities.PluginManager.html +0 -1
  242. package/typedoc/variables/Capabilities.ReactContext.html +0 -1
  243. package/typedoc/variables/Capabilities.ReactRoot.html +0 -1
  244. package/typedoc/variables/Capabilities.ReactSurface.html +0 -1
  245. package/typedoc/variables/Capabilities.RxRegistry.html +0 -1
  246. package/typedoc/variables/Capabilities.Settings.html +0 -1
  247. package/typedoc/variables/Capabilities.SettingsStore.html +0 -1
  248. package/typedoc/variables/Capabilities.Tools.html +0 -1
  249. package/typedoc/variables/Capabilities.Translations.html +0 -1
  250. package/typedoc/variables/Events.AppGraphReady.html +0 -2
  251. package/typedoc/variables/Events.DispatcherReady.html +0 -2
  252. package/typedoc/variables/Events.LayoutReady.html +0 -1
  253. package/typedoc/variables/Events.SettingsReady.html +0 -2
  254. package/typedoc/variables/Events.SetupAppGraph.html +0 -2
  255. package/typedoc/variables/Events.SetupArtifactDefinition.html +0 -2
  256. package/typedoc/variables/Events.SetupIntentResolver.html +0 -2
  257. package/typedoc/variables/Events.SetupMetadata.html +0 -2
  258. package/typedoc/variables/Events.SetupReactSurface.html +0 -2
  259. package/typedoc/variables/Events.SetupSettings.html +0 -2
  260. package/typedoc/variables/Events.SetupTranslations.html +0 -2
  261. package/typedoc/variables/Events.Startup.html +0 -2
  262. package/typedoc/variables/FileInfoSchema.html +0 -1
  263. package/typedoc/variables/INTENT_ACTION.html +0 -1
  264. package/typedoc/variables/INTENT_PLUGIN.html +0 -1
  265. package/typedoc/variables/LAYOUT_ACTION.html +0 -1
  266. package/typedoc/variables/LAYOUT_PLUGIN.html +0 -1
  267. package/typedoc/variables/Label.html +0 -1
  268. package/typedoc/variables/LayoutAction.Toast.html +0 -1
  269. package/typedoc/variables/LayoutAction.UPDATE_LAYOUT.html +0 -1
  270. package/typedoc/variables/PluginManagerProvider.html +0 -2
  271. package/typedoc/variables/Resource.html +0 -2
  272. package/typedoc/variables/ResourceKey.html +0 -1
  273. package/typedoc/variables/ResourceLanguage.html +0 -1
  274. package/typedoc/variables/SETTINGS_ACTION.html +0 -1
  275. package/typedoc/variables/SETTINGS_ID.html +0 -1
  276. package/typedoc/variables/SETTINGS_KEY.html +0 -1
  277. package/typedoc/variables/SETTINGS_PLUGIN.html +0 -1
  278. package/typedoc/variables/Surface.html +0 -2
  279. package/typedoc/variables/defaultFileTypes.html +0 -1
  280. /package/dist/lib/browser/{intent-dispatcher-TWKB22NI.mjs.map → intent-dispatcher-FTTJLVGN.mjs.map} +0 -0
  281. /package/dist/lib/node-esm/{intent-dispatcher-5PRM3KGH.mjs.map → intent-dispatcher-YQIQ55LJ.mjs.map} +0 -0
@@ -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
 
@@ -6,12 +6,13 @@ import React, { useCallback } from 'react';
6
6
 
7
7
  import { Button } from '@dxos/react-ui';
8
8
 
9
- import { createGeneratorIntent, createPluginId, Number } from './generator';
10
9
  import { Capabilities } from '../../common';
11
10
  import { contributes } from '../../core';
12
11
  import { createIntent } from '../../plugin-intent';
13
12
  import { useCapabilities, useIntentDispatcher, usePluginManager } from '../../react';
14
13
 
14
+ import { Number, createGeneratorIntent, createPluginId } from './generator';
15
+
15
16
  export const Toolbar = () => {
16
17
  const manager = usePluginManager();
17
18
  const { dispatchPromise: dispatch } = useIntentDispatcher();
@@ -5,8 +5,8 @@
5
5
  import { Schema } from 'effect';
6
6
 
7
7
  import { Capabilities, Events } from '../../common';
8
- import { contributes, defineEvent, defineCapability, defineModule, definePlugin } from '../../core';
9
- import { createResolver, type IntentSchema } from '../../plugin-intent';
8
+ import { contributes, defineCapability, defineEvent, defineModule, definePlugin } from '../../core';
9
+ import { type IntentSchema, createResolver } from '../../plugin-intent';
10
10
 
11
11
  export const Number = defineCapability<number>('dxos.org/test/generator/number');
12
12
 
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { Events } from '../../common';
6
- import { definePlugin, lazy, defineModule } from '../../core';
6
+ import { defineModule, definePlugin, lazy } from '../../core';
7
7
 
8
8
  const Layout = lazy(() => import('./Layout'));
9
9
 
@@ -6,12 +6,13 @@ import React, { useCallback } from 'react';
6
6
 
7
7
  import { Button } from '@dxos/react-ui';
8
8
 
9
- import { Log } from './schema';
10
9
  import { Capabilities, createSurface } from '../../common';
11
10
  import { contributes } from '../../core';
12
11
  import { createIntent } from '../../plugin-intent';
13
12
  import { useIntentDispatcher } from '../../react';
14
13
 
14
+ import { Log } from './schema';
15
+
15
16
  export const Logger = () => {
16
17
  const { dispatchPromise } = useIntentDispatcher();
17
18
  const handleClick = useCallback(() => dispatchPromise(createIntent(Log, { message: 'Hello, world!' })), []);
@@ -4,11 +4,12 @@
4
4
 
5
5
  import { log } from '@dxos/log';
6
6
 
7
- import { Log } from './schema';
8
7
  import { Capabilities, Events } from '../../common';
9
- import { contributes, defineModule, lazy, definePlugin } from '../../core';
8
+ import { contributes, defineModule, definePlugin, lazy } from '../../core';
10
9
  import { createResolver } from '../../plugin-intent';
11
10
 
11
+ import { Log } from './schema';
12
+
12
13
  const Toolbar = lazy(() => import('./Toolbar'));
13
14
 
14
15
  export const LoggerPlugin = () =>
@@ -8,12 +8,13 @@ import React from 'react';
8
8
 
9
9
  import { withLayout, withTheme } from '@dxos/storybook-utils';
10
10
 
11
+ import { useApp } from '../App';
12
+ import { IntentPlugin } from '../plugin-intent';
13
+
11
14
  import { DebugPlugin } from './debug';
12
- import { createNumberPlugin, GeneratorPlugin } from './generator';
15
+ import { GeneratorPlugin, createNumberPlugin } from './generator';
13
16
  import { LayoutPlugin } from './layout';
14
17
  import { LoggerPlugin } from './logger';
15
- import { useApp } from '../App';
16
- import { IntentPlugin } from '../plugin-intent';
17
18
 
18
19
  const plugins = [IntentPlugin(), LayoutPlugin(), DebugPlugin(), LoggerPlugin(), GeneratorPlugin()];
19
20
 
@@ -2,10 +2,11 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { INTENT_PLUGIN } from './actions';
6
5
  import { Events } from '../common';
7
6
  import { defineModule, definePlugin, lazy } from '../core';
8
7
 
8
+ import { INTENT_PLUGIN } from './actions';
9
+
9
10
  export const IntentPlugin = () =>
10
11
  definePlugin({ id: INTENT_PLUGIN, name: 'Intent' }, [
11
12
  defineModule({
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Schema, Effect, Fiber, pipe } from 'effect';
5
+ import { Effect, Fiber, Schema, pipe } from 'effect';
6
6
  import { describe, expect, test } from 'vitest';
7
7
 
8
8
  import { chain, createIntent } from './intent';
@@ -2,17 +2,19 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Effect, Option, pipe, Ref } from 'effect';
5
+ import { Effect, Option, Ref, pipe } from 'effect';
6
6
  import { type Simplify } from 'effect/Types';
7
7
 
8
8
  import { live } from '@dxos/live-object';
9
9
  import { log } from '@dxos/log';
10
- import { byPosition, type MaybePromise, type Position, type GuardedType } from '@dxos/util';
10
+ import { type GuardedType, type MaybePromise, type Position, byPosition } from '@dxos/util';
11
+
12
+ import { Capabilities, Events } from '../common';
13
+ import { type PluginContext, contributes } from '../core';
11
14
 
12
15
  import { IntentAction } from './actions';
13
16
  import { CycleDetectedError, NoResolversError } from './errors';
14
17
  import {
15
- createIntent,
16
18
  type AnyIntent,
17
19
  type AnyIntentChain,
18
20
  type Intent,
@@ -22,9 +24,8 @@ import {
22
24
  type IntentResultData,
23
25
  type IntentSchema,
24
26
  type Label,
27
+ createIntent,
25
28
  } from './intent';
26
- import { Events, Capabilities } from '../common';
27
- import { contributes, type PluginContext } from '../core';
28
29
 
29
30
  const EXECUTION_LIMIT = 100;
30
31
  const HISTORY_LIMIT = 100;
@@ -2,11 +2,12 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { SETTINGS_PLUGIN } from './actions';
6
- import { translations } from './translations';
7
5
  import { Capabilities, Events } from '../common';
8
6
  import { contributes, defineModule, definePlugin, lazy } from '../core';
9
7
 
8
+ import { SETTINGS_PLUGIN } from './actions';
9
+ import { translations } from './translations';
10
+
10
11
  // TODO(wittjosiah): Add options to exclude some modules.
11
12
  export const SettingsPlugin = () =>
12
13
  definePlugin({ id: SETTINGS_PLUGIN, name: 'Settings' }, [
@@ -5,15 +5,16 @@
5
5
  import { Rx } from '@effect-rx/rx-react';
6
6
  import { Option, pipe } from 'effect';
7
7
 
8
- import { createExtension, ROOT_ID } from '@dxos/app-graph';
8
+ import { ROOT_ID, createExtension } from '@dxos/app-graph';
9
9
  import { type SettingsStore, type SettingsValue } from '@dxos/local-storage';
10
10
  import { isNonNullable } from '@dxos/util';
11
11
 
12
- import { SETTINGS_ID, SETTINGS_KEY, SETTINGS_PLUGIN, SettingsAction } from './actions';
13
12
  import { Capabilities } from '../common';
14
- import { contributes, type PluginMeta, type PluginContext } from '../core';
13
+ import { type PluginContext, type PluginMeta, contributes } from '../core';
15
14
  import { createIntent } from '../plugin-intent';
16
15
 
16
+ import { SETTINGS_ID, SETTINGS_KEY, SETTINGS_PLUGIN, SettingsAction } from './actions';
17
+
17
18
  export default (context: PluginContext) =>
18
19
  contributes(Capabilities.AppGraphBuilder, [
19
20
  createExtension({
@@ -4,10 +4,11 @@
4
4
 
5
5
  import { pipe } from 'effect';
6
6
 
7
- import { SETTINGS_ID, SETTINGS_KEY, SettingsAction } from './actions';
8
7
  import { Capabilities, LayoutAction } from '../common';
9
8
  import { contributes } from '../core';
10
- import { createResolver, createIntent, chain } from '../plugin-intent';
9
+ import { chain, createIntent, createResolver } from '../plugin-intent';
10
+
11
+ import { SETTINGS_ID, SETTINGS_KEY, SettingsAction } from './actions';
11
12
 
12
13
  export default () =>
13
14
  contributes(
@@ -5,7 +5,7 @@
5
5
  import { RootSettingsStore } from '@dxos/local-storage';
6
6
 
7
7
  import { Capabilities } from '../common';
8
- import { contributes, type PluginContext } from '../core';
8
+ import { type PluginContext, contributes } from '../core';
9
9
 
10
10
  export default (context: PluginContext) => {
11
11
  // TODO(wittjosiah): Replace with rx?
@@ -2,38 +2,40 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import React, { Component, type FC, type PropsWithChildren } from 'react';
5
+ import React, { Component, type FC, type JSX, type PropsWithChildren, type ReactNode } from 'react';
6
6
 
7
- type Props = PropsWithChildren<{ data?: any; fallback: FC<{ data?: any; error: Error; reset: () => void }> }>;
8
- type State = { error: Error | undefined };
7
+ type State = {
8
+ error: Error | undefined;
9
+ };
10
+
11
+ export type ErrorBoundaryProps = PropsWithChildren<{
12
+ data?: any;
13
+ fallback?: FC<{ data?: any; error: Error }>;
14
+ }>;
9
15
 
10
16
  /**
11
17
  * Surface error boundary.
12
- *
13
18
  * For basic usage prefer providing a fallback component to `Surface`.
14
19
  *
15
- * For more information on error boundaries, see:
16
- * https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary
20
+ * Ref: https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary
17
21
  */
18
- export class ErrorBoundary extends Component<Props, State> {
19
- constructor(props: Props) {
20
- super(props);
21
- this.state = { error: undefined };
22
- }
23
-
22
+ export class ErrorBoundary extends Component<ErrorBoundaryProps, State> {
24
23
  static getDerivedStateFromError(error: Error): { error: Error } {
25
24
  return { error };
26
25
  }
27
26
 
28
- override componentDidUpdate(prevProps: Props): void {
27
+ override state = { error: undefined };
28
+
29
+ override componentDidUpdate(prevProps: ErrorBoundaryProps): void {
29
30
  if (prevProps.data !== this.props.data) {
30
31
  this.resetError();
31
32
  }
32
33
  }
33
34
 
34
- override render(): string | number | boolean | React.JSX.Element | Iterable<React.ReactNode> | null | undefined {
35
+ override render(): string | number | boolean | JSX.Element | Iterable<ReactNode> | null | undefined {
35
36
  if (this.state.error) {
36
- return <this.props.fallback data={this.props.data} error={this.state.error} reset={this.resetError} />;
37
+ const Fallback = this.props.fallback ?? DefaultFallback;
38
+ return <Fallback data={this.props.data} error={this.state.error} />;
37
39
  }
38
40
 
39
41
  return this.props.children;
@@ -43,3 +45,10 @@ export class ErrorBoundary extends Component<Props, State> {
43
45
  this.setState({ error: undefined });
44
46
  }
45
47
  }
48
+
49
+ const DefaultFallback: NonNullable<ErrorBoundaryProps['fallback']> = ({ data, error }) => (
50
+ <div className='flex flex-col gap-2 overflow-hidden border border-red-500 rounded-sm'>
51
+ <pre className='whitespace-pre-wrap font-sm text-xs p-2'>ERROR: {error.message}</pre>
52
+ <pre className='whitespace-pre-wrap font-sm text-xs p-2 text-subdued'>{JSON.stringify(data, null, 2)}</pre>
53
+ </div>
54
+ );
@@ -2,15 +2,16 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type Context, createContext, useContext, type Provider, useEffect } from 'react';
5
+ import { type Context, type Provider, createContext, useContext, useEffect } from 'react';
6
6
 
7
7
  import { raise } from '@dxos/debug';
8
8
  import { pick } from '@dxos/util';
9
9
 
10
- import { usePluginManager } from './PluginManagerProvider';
11
10
  import { Capabilities } from '../common';
12
11
  import { type AnyIntentResolver, type IntentContext } from '../plugin-intent';
13
12
 
13
+ import { usePluginManager } from './PluginManagerProvider';
14
+
14
15
  const IntentContext: Context<IntentContext | undefined> = createContext<IntentContext | undefined>(undefined);
15
16
 
16
17
  export const useIntentDispatcher = (): Pick<IntentContext, 'dispatch' | 'dispatchPromise'> => {
@@ -10,12 +10,13 @@ import { faker } from '@dxos/random';
10
10
  import { Button, List, ListItem } from '@dxos/react-ui';
11
11
  import { withLayout, withTheme } from '@dxos/storybook-utils';
12
12
 
13
- import { PluginManagerProvider, usePluginManager } from './PluginManagerProvider';
14
- import { Surface, useSurfaces } from './Surface';
15
13
  import { Capabilities, createSurface } from '../common';
16
14
  import { type PluginManager } from '../core';
17
15
  import { setupPluginManager } from '../testing';
18
16
 
17
+ import { PluginManagerProvider, usePluginManager } from './PluginManagerProvider';
18
+ import { Surface, useSurfaces } from './Surface';
19
+
19
20
  const randomColor = (): string => {
20
21
  const hue = faker.number.int({ min: 0, max: 360 });
21
22
  const saturation = faker.number.int({ min: 50, max: 90 });
@@ -2,16 +2,17 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React, { memo, forwardRef, Suspense, useMemo, Fragment } from 'react';
5
+ import React, { Fragment, Suspense, forwardRef, memo, useMemo } from 'react';
6
6
 
7
7
  import { useDefaultValue } from '@dxos/react-hooks';
8
8
  import { byPosition } from '@dxos/util';
9
9
 
10
- import { ErrorBoundary } from './ErrorBoundary';
11
- import { useCapabilities } from './useCapabilities';
12
10
  import { Capabilities, type SurfaceDefinition, type SurfaceProps } from '../common';
13
11
  import { type PluginContext } from '../core';
14
12
 
13
+ import { ErrorBoundary } from './ErrorBoundary';
14
+ import { useCapabilities } from './useCapabilities';
15
+
15
16
  const DEFAULT_PLACEHOLDER = <Fragment />;
16
17
 
17
18
  /**
@@ -2,9 +2,10 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useCapability } from './useCapabilities';
6
5
  import { Capabilities } from '../common';
7
6
 
7
+ import { useCapability } from './useCapabilities';
8
+
8
9
  export const useIntentDispatcher = () => useCapability(Capabilities.IntentDispatcher);
9
10
 
10
11
  export const useAppGraph = () => useCapability(Capabilities.AppGraph);