@dxos/app-framework 0.7.5-main.9cb18ac → 0.7.5-main.9d2a38b

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 (316) hide show
  1. package/dist/lib/browser/chunk-GNLU3GAU.mjs +1595 -0
  2. package/dist/lib/browser/chunk-GNLU3GAU.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +112 -618
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +67 -0
  7. package/dist/lib/browser/testing/index.mjs.map +7 -0
  8. package/dist/lib/node/chunk-FBA4BB3J.cjs +1639 -0
  9. package/dist/lib/node/chunk-FBA4BB3J.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +123 -651
  11. package/dist/lib/node/index.cjs.map +4 -4
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +91 -0
  14. package/dist/lib/node/testing/index.cjs.map +7 -0
  15. package/dist/lib/node-esm/chunk-KPMTPXQI.mjs +1597 -0
  16. package/dist/lib/node-esm/chunk-KPMTPXQI.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +112 -618
  18. package/dist/lib/node-esm/index.mjs.map +4 -4
  19. package/dist/lib/node-esm/meta.json +1 -1
  20. package/dist/lib/node-esm/testing/index.mjs +68 -0
  21. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  22. package/dist/types/src/App.d.ts +22 -13
  23. package/dist/types/src/App.d.ts.map +1 -1
  24. package/dist/types/src/common/capabilities.d.ts +340 -0
  25. package/dist/types/src/common/capabilities.d.ts.map +1 -0
  26. package/dist/types/src/common/events.d.ts +41 -0
  27. package/dist/types/src/common/events.d.ts.map +1 -0
  28. package/dist/types/src/common/file.d.ts +14 -0
  29. package/dist/types/src/common/file.d.ts.map +1 -0
  30. package/dist/types/src/common/graph.d.ts +21 -0
  31. package/dist/types/src/common/graph.d.ts.map +1 -0
  32. package/dist/types/src/{plugins/common → common}/index.d.ts +3 -1
  33. package/dist/types/src/common/index.d.ts.map +1 -0
  34. package/dist/types/src/{plugins/common → common}/layout.d.ts +0 -11
  35. package/dist/types/src/common/layout.d.ts.map +1 -0
  36. package/dist/types/src/{plugins/common → common}/navigation.d.ts +0 -2
  37. package/dist/types/src/common/navigation.d.ts.map +1 -0
  38. package/dist/types/src/{plugins/plugin-surface/SurfaceContext.d.ts → common/surface.d.ts} +12 -29
  39. package/dist/types/src/common/surface.d.ts.map +1 -0
  40. package/dist/types/src/{plugins/common → common}/translations.d.ts +0 -11
  41. package/dist/types/src/common/translations.d.ts.map +1 -0
  42. package/dist/types/src/core/capabilities.d.ts +90 -0
  43. package/dist/types/src/core/capabilities.d.ts.map +1 -0
  44. package/dist/types/src/core/capabilities.test.d.ts +2 -0
  45. package/dist/types/src/core/capabilities.test.d.ts.map +1 -0
  46. package/dist/types/src/core/events.d.ts +58 -0
  47. package/dist/types/src/core/events.d.ts.map +1 -0
  48. package/dist/types/src/core/index.d.ts +5 -0
  49. package/dist/types/src/core/index.d.ts.map +1 -0
  50. package/dist/types/src/core/manager.d.ts +126 -0
  51. package/dist/types/src/core/manager.d.ts.map +1 -0
  52. package/dist/types/src/core/manager.test.d.ts +2 -0
  53. package/dist/types/src/core/manager.test.d.ts.map +1 -0
  54. package/dist/types/src/core/plugin.d.ts +94 -0
  55. package/dist/types/src/core/plugin.d.ts.map +1 -0
  56. package/dist/types/src/helpers.d.ts +10 -0
  57. package/dist/types/src/helpers.d.ts.map +1 -0
  58. package/dist/types/src/helpers.test.d.ts +2 -0
  59. package/dist/types/src/helpers.test.d.ts.map +1 -0
  60. package/dist/types/src/index.d.ts +5 -1
  61. package/dist/types/src/index.d.ts.map +1 -1
  62. package/dist/types/src/playground/debug/Debug.d.ts +6 -0
  63. package/dist/types/src/playground/debug/Debug.d.ts.map +1 -0
  64. package/dist/types/src/playground/debug/index.d.ts +2 -0
  65. package/dist/types/src/playground/debug/index.d.ts.map +1 -0
  66. package/dist/types/src/playground/debug/plugin.d.ts +2 -0
  67. package/dist/types/src/playground/debug/plugin.d.ts.map +1 -0
  68. package/dist/types/src/playground/generator/Main.d.ts +6 -0
  69. package/dist/types/src/playground/generator/Main.d.ts.map +1 -0
  70. package/dist/types/src/playground/generator/Toolbar.d.ts +6 -0
  71. package/dist/types/src/playground/generator/Toolbar.d.ts.map +1 -0
  72. package/dist/types/src/playground/generator/generator.d.ts +5 -0
  73. package/dist/types/src/playground/generator/generator.d.ts.map +1 -0
  74. package/dist/types/src/playground/generator/index.d.ts +3 -0
  75. package/dist/types/src/playground/generator/index.d.ts.map +1 -0
  76. package/dist/types/src/playground/generator/plugin.d.ts +2 -0
  77. package/dist/types/src/playground/generator/plugin.d.ts.map +1 -0
  78. package/dist/types/src/playground/layout/Layout.d.ts +8 -0
  79. package/dist/types/src/playground/layout/Layout.d.ts.map +1 -0
  80. package/dist/types/src/playground/layout/index.d.ts +2 -0
  81. package/dist/types/src/playground/layout/index.d.ts.map +1 -0
  82. package/dist/types/src/playground/layout/plugin.d.ts +2 -0
  83. package/dist/types/src/playground/layout/plugin.d.ts.map +1 -0
  84. package/dist/types/src/playground/logger/Toolbar.d.ts +6 -0
  85. package/dist/types/src/playground/logger/Toolbar.d.ts.map +1 -0
  86. package/dist/types/src/playground/logger/index.d.ts +2 -0
  87. package/dist/types/src/playground/logger/index.d.ts.map +1 -0
  88. package/dist/types/src/playground/logger/plugin.d.ts +2 -0
  89. package/dist/types/src/playground/logger/plugin.d.ts.map +1 -0
  90. package/dist/types/src/playground/logger/schema.d.ts +13 -0
  91. package/dist/types/src/playground/logger/schema.d.ts.map +1 -0
  92. package/dist/types/src/playground/playground.stories.d.ts +10 -0
  93. package/dist/types/src/playground/playground.stories.d.ts.map +1 -0
  94. package/dist/types/src/{plugins/plugin-intent → plugin-intent}/IntentContext.d.ts +1 -1
  95. package/dist/types/src/plugin-intent/IntentContext.d.ts.map +1 -0
  96. package/dist/types/src/plugin-intent/IntentPlugin.d.ts +2 -0
  97. package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -0
  98. package/dist/types/src/plugin-intent/actions.d.ts +23 -0
  99. package/dist/types/src/plugin-intent/actions.d.ts.map +1 -0
  100. package/dist/types/src/plugin-intent/errors.d.ts +16 -0
  101. package/dist/types/src/plugin-intent/errors.d.ts.map +1 -0
  102. package/dist/types/src/plugin-intent/index.d.ts +6 -0
  103. package/dist/types/src/plugin-intent/index.d.ts.map +1 -0
  104. package/dist/types/src/{plugins/plugin-intent → plugin-intent}/intent-dispatcher.d.ts +18 -19
  105. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -0
  106. package/dist/types/src/plugin-intent/intent-dispatcher.test.d.ts.map +1 -0
  107. package/dist/types/src/{plugins/plugin-intent → plugin-intent}/intent.d.ts +5 -25
  108. package/dist/types/src/plugin-intent/intent.d.ts.map +1 -0
  109. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts +2 -0
  110. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -0
  111. package/dist/types/src/{plugins/plugin-settings/provides.d.ts → plugin-settings/actions.d.ts} +1 -10
  112. package/dist/types/src/plugin-settings/actions.d.ts.map +1 -0
  113. package/dist/types/src/plugin-settings/index.d.ts +3 -0
  114. package/dist/types/src/plugin-settings/index.d.ts.map +1 -0
  115. package/dist/types/src/react/ErrorBoundary.d.ts.map +1 -0
  116. package/dist/types/src/react/PluginManagerProvider.d.ts +10 -0
  117. package/dist/types/src/react/PluginManagerProvider.d.ts.map +1 -0
  118. package/dist/types/src/react/Surface.d.ts +12 -0
  119. package/dist/types/src/react/Surface.d.ts.map +1 -0
  120. package/dist/types/src/react/index.d.ts +5 -0
  121. package/dist/types/src/react/index.d.ts.map +1 -0
  122. package/dist/types/src/react/useCapabilities.d.ts +13 -0
  123. package/dist/types/src/react/useCapabilities.d.ts.map +1 -0
  124. package/dist/types/src/testing/index.d.ts +2 -0
  125. package/dist/types/src/testing/index.d.ts.map +1 -0
  126. package/dist/types/src/testing/withPluginManager.d.ts +10 -0
  127. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -0
  128. package/dist/types/src/testing/withPluginManager.stories.d.ts +5 -0
  129. package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -0
  130. package/dist/types/tsconfig.tsbuildinfo +1 -1
  131. package/package.json +28 -15
  132. package/project.json +2 -1
  133. package/src/App.tsx +138 -34
  134. package/src/common/capabilities.ts +82 -0
  135. package/src/common/events.ts +63 -0
  136. package/src/common/file.ts +22 -0
  137. package/src/common/graph.ts +30 -0
  138. package/src/{plugins/common → common}/index.ts +3 -1
  139. package/src/{plugins/common → common}/layout.ts +0 -16
  140. package/src/{plugins/common → common}/navigation.ts +0 -15
  141. package/src/{plugins/plugin-surface/SurfaceContext.ts → common/surface.ts} +6 -37
  142. package/src/common/translations.ts +18 -0
  143. package/src/core/capabilities.test.ts +116 -0
  144. package/src/core/capabilities.ts +213 -0
  145. package/src/core/events.ts +58 -0
  146. package/src/core/index.ts +8 -0
  147. package/src/core/manager.test.ts +567 -0
  148. package/src/core/manager.ts +497 -0
  149. package/src/core/plugin.ts +128 -0
  150. package/src/helpers.test.ts +97 -0
  151. package/src/helpers.ts +45 -0
  152. package/src/index.ts +6 -3
  153. package/src/playground/debug/Debug.tsx +39 -0
  154. package/src/playground/debug/index.ts +5 -0
  155. package/src/playground/debug/plugin.ts +17 -0
  156. package/src/playground/generator/Main.tsx +71 -0
  157. package/src/playground/generator/Toolbar.tsx +46 -0
  158. package/src/playground/generator/generator.ts +23 -0
  159. package/src/playground/generator/index.ts +6 -0
  160. package/src/playground/generator/plugin.ts +18 -0
  161. package/src/playground/layout/Layout.tsx +33 -0
  162. package/src/playground/layout/index.ts +5 -0
  163. package/src/playground/layout/plugin.ts +17 -0
  164. package/src/playground/logger/Toolbar.tsx +28 -0
  165. package/src/playground/logger/index.ts +5 -0
  166. package/src/playground/logger/plugin.ts +33 -0
  167. package/src/playground/logger/schema.ts +12 -0
  168. package/src/playground/playground.stories.tsx +34 -0
  169. package/src/{plugins/plugin-intent → plugin-intent}/IntentContext.tsx +12 -4
  170. package/src/plugin-intent/IntentPlugin.tsx +60 -0
  171. package/src/plugin-intent/actions.ts +22 -0
  172. package/src/plugin-intent/errors.ts +39 -0
  173. package/src/{plugins/plugin-intent → plugin-intent}/index.ts +2 -6
  174. package/src/{plugins/plugin-intent → plugin-intent}/intent-dispatcher.test.ts +36 -35
  175. package/src/{plugins/plugin-intent → plugin-intent}/intent-dispatcher.ts +49 -65
  176. package/src/{plugins/plugin-intent → plugin-intent}/intent.ts +5 -21
  177. package/src/plugin-settings/SettingsPlugin.ts +29 -0
  178. package/src/plugin-settings/actions.ts +17 -0
  179. package/src/plugin-settings/index.ts +6 -0
  180. package/src/react/PluginManagerProvider.ts +22 -0
  181. package/src/react/Surface.tsx +72 -0
  182. package/src/react/index.ts +8 -0
  183. package/src/react/useCapabilities.ts +39 -0
  184. package/src/testing/index.ts +5 -0
  185. package/src/testing/withPluginManager.stories.tsx +47 -0
  186. package/src/testing/withPluginManager.tsx +67 -0
  187. package/tsconfig.json +13 -1
  188. package/dist/lib/browser/chunk-3E7RY3CE.mjs +0 -72
  189. package/dist/lib/browser/chunk-3E7RY3CE.mjs.map +0 -7
  190. package/dist/lib/browser/chunk-QG25ZU2N.mjs +0 -320
  191. package/dist/lib/browser/chunk-QG25ZU2N.mjs.map +0 -7
  192. package/dist/lib/browser/chunk-SPDTXTOV.mjs +0 -163
  193. package/dist/lib/browser/chunk-SPDTXTOV.mjs.map +0 -7
  194. package/dist/lib/browser/chunk-WBOXEHBE.mjs +0 -51
  195. package/dist/lib/browser/chunk-WBOXEHBE.mjs.map +0 -7
  196. package/dist/lib/browser/plugin-intent-T7Y3MJ5C.mjs +0 -32
  197. package/dist/lib/browser/plugin-intent-T7Y3MJ5C.mjs.map +0 -7
  198. package/dist/lib/browser/plugin-settings-5U2L2NRU.mjs +0 -15
  199. package/dist/lib/browser/plugin-settings-5U2L2NRU.mjs.map +0 -7
  200. package/dist/lib/browser/plugin-surface-OKPF3EQI.mjs +0 -24
  201. package/dist/lib/browser/plugin-surface-OKPF3EQI.mjs.map +0 -7
  202. package/dist/lib/node/chunk-BW3RNEVI.cjs +0 -185
  203. package/dist/lib/node/chunk-BW3RNEVI.cjs.map +0 -7
  204. package/dist/lib/node/chunk-FCMHRU3M.cjs +0 -70
  205. package/dist/lib/node/chunk-FCMHRU3M.cjs.map +0 -7
  206. package/dist/lib/node/chunk-QBM42OQ6.cjs +0 -97
  207. package/dist/lib/node/chunk-QBM42OQ6.cjs.map +0 -7
  208. package/dist/lib/node/chunk-VWHAALIN.cjs +0 -344
  209. package/dist/lib/node/chunk-VWHAALIN.cjs.map +0 -7
  210. package/dist/lib/node/plugin-intent-F3TQZIUR.cjs +0 -53
  211. package/dist/lib/node/plugin-intent-F3TQZIUR.cjs.map +0 -7
  212. package/dist/lib/node/plugin-settings-W6UHMH5M.cjs +0 -36
  213. package/dist/lib/node/plugin-settings-W6UHMH5M.cjs.map +0 -7
  214. package/dist/lib/node/plugin-surface-CCSIONYW.cjs +0 -45
  215. package/dist/lib/node/plugin-surface-CCSIONYW.cjs.map +0 -7
  216. package/dist/lib/node-esm/chunk-3T5UIJY3.mjs +0 -53
  217. package/dist/lib/node-esm/chunk-3T5UIJY3.mjs.map +0 -7
  218. package/dist/lib/node-esm/chunk-4GX7V5ZE.mjs +0 -164
  219. package/dist/lib/node-esm/chunk-4GX7V5ZE.mjs.map +0 -7
  220. package/dist/lib/node-esm/chunk-CFOUYXQ6.mjs +0 -321
  221. package/dist/lib/node-esm/chunk-CFOUYXQ6.mjs.map +0 -7
  222. package/dist/lib/node-esm/chunk-EYCTSFEJ.mjs +0 -74
  223. package/dist/lib/node-esm/chunk-EYCTSFEJ.mjs.map +0 -7
  224. package/dist/lib/node-esm/plugin-intent-W2HQC6LC.mjs +0 -33
  225. package/dist/lib/node-esm/plugin-intent-W2HQC6LC.mjs.map +0 -7
  226. package/dist/lib/node-esm/plugin-settings-H5RHNFVC.mjs +0 -16
  227. package/dist/lib/node-esm/plugin-settings-H5RHNFVC.mjs.map +0 -7
  228. package/dist/lib/node-esm/plugin-surface-V3YET3UL.mjs +0 -25
  229. package/dist/lib/node-esm/plugin-surface-V3YET3UL.mjs.map +0 -7
  230. package/dist/types/src/plugins/common/file.d.ts +0 -22
  231. package/dist/types/src/plugins/common/file.d.ts.map +0 -1
  232. package/dist/types/src/plugins/common/graph.d.ts +0 -51
  233. package/dist/types/src/plugins/common/graph.d.ts.map +0 -1
  234. package/dist/types/src/plugins/common/index.d.ts.map +0 -1
  235. package/dist/types/src/plugins/common/layout.d.ts.map +0 -1
  236. package/dist/types/src/plugins/common/metadata.d.ts +0 -16
  237. package/dist/types/src/plugins/common/metadata.d.ts.map +0 -1
  238. package/dist/types/src/plugins/common/navigation.d.ts.map +0 -1
  239. package/dist/types/src/plugins/common/translations.d.ts.map +0 -1
  240. package/dist/types/src/plugins/helpers.d.ts +0 -41
  241. package/dist/types/src/plugins/helpers.d.ts.map +0 -1
  242. package/dist/types/src/plugins/index.d.ts +0 -7
  243. package/dist/types/src/plugins/index.d.ts.map +0 -1
  244. package/dist/types/src/plugins/plugin-host/HostPlugin.d.ts +0 -16
  245. package/dist/types/src/plugins/plugin-host/HostPlugin.d.ts.map +0 -1
  246. package/dist/types/src/plugins/plugin-host/PluginContainer.d.ts +0 -14
  247. package/dist/types/src/plugins/plugin-host/PluginContainer.d.ts.map +0 -1
  248. package/dist/types/src/plugins/plugin-host/PluginContext.d.ts +0 -47
  249. package/dist/types/src/plugins/plugin-host/PluginContext.d.ts.map +0 -1
  250. package/dist/types/src/plugins/plugin-host/index.d.ts +0 -6
  251. package/dist/types/src/plugins/plugin-host/index.d.ts.map +0 -1
  252. package/dist/types/src/plugins/plugin-host/plugin.d.ts +0 -104
  253. package/dist/types/src/plugins/plugin-host/plugin.d.ts.map +0 -1
  254. package/dist/types/src/plugins/plugin-host/plugin.test.d.ts +0 -35
  255. package/dist/types/src/plugins/plugin-host/plugin.test.d.ts.map +0 -1
  256. package/dist/types/src/plugins/plugin-intent/IntentContext.d.ts.map +0 -1
  257. package/dist/types/src/plugins/plugin-intent/IntentPlugin.d.ts +0 -8
  258. package/dist/types/src/plugins/plugin-intent/IntentPlugin.d.ts.map +0 -1
  259. package/dist/types/src/plugins/plugin-intent/index.d.ts +0 -7
  260. package/dist/types/src/plugins/plugin-intent/index.d.ts.map +0 -1
  261. package/dist/types/src/plugins/plugin-intent/intent-dispatcher.d.ts.map +0 -1
  262. package/dist/types/src/plugins/plugin-intent/intent-dispatcher.test.d.ts.map +0 -1
  263. package/dist/types/src/plugins/plugin-intent/intent.d.ts.map +0 -1
  264. package/dist/types/src/plugins/plugin-intent/meta.d.ts +0 -6
  265. package/dist/types/src/plugins/plugin-intent/meta.d.ts.map +0 -1
  266. package/dist/types/src/plugins/plugin-intent/provides.d.ts +0 -16
  267. package/dist/types/src/plugins/plugin-intent/provides.d.ts.map +0 -1
  268. package/dist/types/src/plugins/plugin-settings/SettingsPlugin.d.ts +0 -4
  269. package/dist/types/src/plugins/plugin-settings/SettingsPlugin.d.ts.map +0 -1
  270. package/dist/types/src/plugins/plugin-settings/index.d.ts +0 -4
  271. package/dist/types/src/plugins/plugin-settings/index.d.ts.map +0 -1
  272. package/dist/types/src/plugins/plugin-settings/meta.d.ts +0 -5
  273. package/dist/types/src/plugins/plugin-settings/meta.d.ts.map +0 -1
  274. package/dist/types/src/plugins/plugin-settings/provides.d.ts.map +0 -1
  275. package/dist/types/src/plugins/plugin-surface/ErrorBoundary.d.ts.map +0 -1
  276. package/dist/types/src/plugins/plugin-surface/Surface.d.ts +0 -7
  277. package/dist/types/src/plugins/plugin-surface/Surface.d.ts.map +0 -1
  278. package/dist/types/src/plugins/plugin-surface/SurfaceContext.d.ts.map +0 -1
  279. package/dist/types/src/plugins/plugin-surface/SurfacePlugin.d.ts +0 -7
  280. package/dist/types/src/plugins/plugin-surface/SurfacePlugin.d.ts.map +0 -1
  281. package/dist/types/src/plugins/plugin-surface/helpers.d.ts +0 -21
  282. package/dist/types/src/plugins/plugin-surface/helpers.d.ts.map +0 -1
  283. package/dist/types/src/plugins/plugin-surface/index.d.ts +0 -8
  284. package/dist/types/src/plugins/plugin-surface/index.d.ts.map +0 -1
  285. package/dist/types/src/plugins/plugin-surface/meta.d.ts +0 -5
  286. package/dist/types/src/plugins/plugin-surface/meta.d.ts.map +0 -1
  287. package/dist/types/src/plugins/plugin-surface/provides.d.ts +0 -17
  288. package/dist/types/src/plugins/plugin-surface/provides.d.ts.map +0 -1
  289. package/src/plugins/common/file.ts +0 -36
  290. package/src/plugins/common/graph.ts +0 -70
  291. package/src/plugins/common/metadata.ts +0 -29
  292. package/src/plugins/common/translations.ts +0 -36
  293. package/src/plugins/helpers.ts +0 -92
  294. package/src/plugins/index.ts +0 -11
  295. package/src/plugins/plugin-host/HostPlugin.tsx +0 -88
  296. package/src/plugins/plugin-host/PluginContainer.tsx +0 -120
  297. package/src/plugins/plugin-host/PluginContext.tsx +0 -79
  298. package/src/plugins/plugin-host/index.ts +0 -12
  299. package/src/plugins/plugin-host/plugin.test.ts +0 -158
  300. package/src/plugins/plugin-host/plugin.ts +0 -133
  301. package/src/plugins/plugin-intent/IntentPlugin.tsx +0 -75
  302. package/src/plugins/plugin-intent/meta.ts +0 -11
  303. package/src/plugins/plugin-intent/provides.ts +0 -26
  304. package/src/plugins/plugin-settings/SettingsPlugin.tsx +0 -22
  305. package/src/plugins/plugin-settings/index.ts +0 -9
  306. package/src/plugins/plugin-settings/meta.ts +0 -9
  307. package/src/plugins/plugin-settings/provides.ts +0 -34
  308. package/src/plugins/plugin-surface/Surface.tsx +0 -62
  309. package/src/plugins/plugin-surface/SurfacePlugin.tsx +0 -45
  310. package/src/plugins/plugin-surface/helpers.ts +0 -22
  311. package/src/plugins/plugin-surface/index.ts +0 -14
  312. package/src/plugins/plugin-surface/meta.ts +0 -9
  313. package/src/plugins/plugin-surface/provides.ts +0 -27
  314. /package/dist/types/src/{plugins/plugin-intent → plugin-intent}/intent-dispatcher.test.d.ts +0 -0
  315. /package/dist/types/src/{plugins/plugin-surface → react}/ErrorBoundary.d.ts +0 -0
  316. /package/src/{plugins/plugin-surface → react}/ErrorBoundary.tsx +0 -0
package/src/App.tsx CHANGED
@@ -1,63 +1,167 @@
1
1
  //
2
- // Copyright 2023 DXOS.org
2
+ // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import React from 'react';
5
+ import { effect } from '@preact/signals-core';
6
+ import React, { type PropsWithChildren, type ReactNode } from 'react';
6
7
 
7
8
  import { invariant } from '@dxos/invariant';
9
+ import { create } from '@dxos/live-object';
8
10
 
9
- import { type HostPluginParams, Plugin, HostPlugin } from './plugins';
10
- import IntentMeta from './plugins/plugin-intent/meta';
11
- import SettingsMeta from './plugins/plugin-settings/meta';
12
- import SurfaceMeta from './plugins/plugin-surface/meta';
11
+ import { Capabilities, Events } from './common';
12
+ import { PluginManager, type PluginManagerOptions, type Plugin } from './core';
13
+ import { topologicalSort } from './helpers';
14
+ import { ErrorBoundary, PluginManagerProvider } from './react';
15
+
16
+ const ENABLED_KEY = 'dxos.org/app-framework/enabled';
17
+
18
+ export type CreateAppOptions = {
19
+ pluginManager?: PluginManager;
20
+ pluginLoader?: PluginManagerOptions['pluginLoader'];
21
+ plugins?: Plugin[];
22
+ core?: string[];
23
+ defaults?: string[];
24
+ placeholder?: ReactNode;
25
+ fallback?: ErrorBoundary['props']['fallback'];
26
+ cacheEnabled?: boolean;
27
+ };
13
28
 
14
29
  /**
15
30
  * Expected usage is for this to be the entrypoint of the application.
16
31
  * Initializes plugins and renders the root components.
17
32
  *
18
33
  * @example
19
- * const meta = [LayoutMeta, MyPluginMeta];
20
- * const plugins = {
21
- * [LayoutMeta.id]: Plugin.lazy(() => import('./plugins/LayoutPlugin/plugin')),
22
- * [MyPluginMeta.id]: Plugin.lazy(() => import('./plugins/MyPlugin/plugin')),
23
- * };
24
- * const core = [LayoutMeta.id];
25
- * const default = [MyPluginMeta.id];
34
+ * const plugins = [LayoutPlugin(), MyPlugin()];
35
+ * const core = [LayoutPluginId];
36
+ * const default = [MyPluginId];
26
37
  * const fallback = <div>Initializing Plugins...</div>;
27
- * const App = createApp({ order, plugins, core, default, fallback });
38
+ * const App = createApp({ plugins, core, default, fallback });
28
39
  * createRoot(document.getElementById('root')!).render(
29
40
  * <StrictMode>
30
41
  * <App />
31
42
  * </StrictMode>,
32
43
  * );
33
44
  *
45
+ * @param params.pluginLoader A function which loads new plugins.
34
46
  * @param params.plugins All plugins available to the application.
35
- * @param params.meta All plugin metadata.
36
47
  * @param params.core Core plugins which will always be enabled.
37
48
  * @param params.defaults Default plugins are enabled by default but can be disabled by the user.
38
- * @param params.fallback Fallback component to render while plugins are initializing.
49
+ * @param params.placeholder Placeholder component to render during startup.
50
+ * @param params.fallback Fallback component to render if an error occurs during startup.
51
+ * @param params.cacheEnabled Whether to cache enabled plugins in localStorage.
39
52
  */
40
- export const createApp = ({ meta, plugins, core, ...params }: HostPluginParams) => {
41
- const hostPlugin = HostPlugin({
42
- plugins: {
43
- ...plugins,
44
- [IntentMeta.id]: Plugin.lazy(() => import('./plugins/plugin-intent')),
45
- [SettingsMeta.id]: Plugin.lazy(() => import('./plugins/plugin-settings')),
46
- [SurfaceMeta.id]: Plugin.lazy(() => import('./plugins/plugin-surface')),
47
- },
48
- meta: [IntentMeta, SettingsMeta, SurfaceMeta, ...meta],
49
- core: [IntentMeta.id, SettingsMeta.id, SurfaceMeta.id, ...core],
50
- ...params,
53
+ export const createApp = ({
54
+ pluginManager,
55
+ pluginLoader: _pluginLoader,
56
+ plugins = [],
57
+ core = plugins.map(({ meta }) => meta.id),
58
+ defaults = [],
59
+ placeholder = null,
60
+ fallback = DefaultFallback,
61
+ cacheEnabled = false,
62
+ }: CreateAppOptions) => {
63
+ // TODO(wittjosiah): Provide a custom plugin loader which supports loading via url.
64
+ const pluginLoader =
65
+ _pluginLoader ??
66
+ ((id: string) => {
67
+ const plugin = plugins.find((plugin) => plugin.meta.id === id);
68
+ invariant(plugin, `Plugin not found: ${id}`);
69
+ return plugin;
70
+ });
71
+
72
+ const state = create({ ready: false, error: null });
73
+ const cached: string[] = JSON.parse(localStorage.getItem(ENABLED_KEY) ?? '[]');
74
+ const enabled = cacheEnabled && cached.length > 0 ? cached : defaults;
75
+ const manager = pluginManager ?? new PluginManager({ pluginLoader, plugins, core, enabled });
76
+
77
+ manager.activation.on(({ event, state: _state, error }) => {
78
+ if (event === Events.Startup.id) {
79
+ state.ready = _state === 'activated';
80
+ }
81
+
82
+ if (error && !state.ready && !state.error) {
83
+ state.error = error;
84
+ }
85
+ });
86
+
87
+ effect(() => {
88
+ cacheEnabled && localStorage.setItem(ENABLED_KEY, JSON.stringify(manager.enabled));
89
+ });
90
+
91
+ manager.context.contributeCapability({
92
+ interface: Capabilities.PluginManager,
93
+ implementation: manager,
94
+ module: 'dxos.org/app-framework/plugin-manager',
51
95
  });
52
96
 
53
- invariant(hostPlugin.provides);
54
- const { context: Context, root: Root } = hostPlugin.provides;
55
- invariant(Context);
56
- invariant(Root);
97
+ setupDevtools(manager);
98
+
99
+ void manager.activate(Events.Startup);
57
100
 
58
101
  return () => (
59
- <Context>
60
- <Root />
61
- </Context>
102
+ <ErrorBoundary fallback={fallback}>
103
+ <App placeholder={placeholder} manager={manager} state={state} />
104
+ </ErrorBoundary>
62
105
  );
63
106
  };
107
+
108
+ type AppProps = Required<Pick<CreateAppOptions, 'placeholder'>> & {
109
+ manager: PluginManager;
110
+ state: { ready: boolean; error: unknown };
111
+ };
112
+
113
+ const App = ({ placeholder, manager, state }: AppProps) => {
114
+ if (state.error) {
115
+ // This trigger the error boundary to provide UI feedback for the startup error.
116
+ throw state.error;
117
+ }
118
+
119
+ // TODO(wittjosiah): Consider using Suspense instead?
120
+ if (!state.ready) {
121
+ return <>{placeholder}</>;
122
+ }
123
+
124
+ const reactContexts = manager.context.requestCapabilities(Capabilities.ReactContext);
125
+ const reactRoots = manager.context.requestCapabilities(Capabilities.ReactRoot);
126
+
127
+ const ComposedContext = composeContexts(reactContexts);
128
+ return (
129
+ <PluginManagerProvider value={manager}>
130
+ <ComposedContext>
131
+ {reactRoots.map(({ id, root: Component }) => (
132
+ <Component key={id} />
133
+ ))}
134
+ </ComposedContext>
135
+ </PluginManagerProvider>
136
+ );
137
+ };
138
+
139
+ // Default fallback does not use tailwind or theme.
140
+ const DefaultFallback = ({ error }: { error: Error }) => {
141
+ return (
142
+ <div style={{ padding: '1rem' }}>
143
+ {/* TODO(wittjosiah): Link to docs for replacing default. */}
144
+ <h1 style={{ fontSize: '1.2rem', fontWeight: 700, margin: '0.5rem 0' }}>{error.message}</h1>
145
+ <pre>{error.stack}</pre>
146
+ </div>
147
+ );
148
+ };
149
+
150
+ const composeContexts = (contexts: Capabilities.ReactContext[]) => {
151
+ if (contexts.length === 0) {
152
+ return ({ children }: PropsWithChildren) => <>{children}</>;
153
+ }
154
+
155
+ return topologicalSort(contexts)
156
+ .map(({ context }) => context)
157
+ .reduce((Acc, Next) => ({ children }) => (
158
+ <Acc>
159
+ <Next>{children}</Next>
160
+ </Acc>
161
+ ));
162
+ };
163
+
164
+ const setupDevtools = (manager: PluginManager) => {
165
+ (globalThis as any).composer ??= {};
166
+ (globalThis as any).composer.manager = manager;
167
+ };
@@ -0,0 +1,82 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type FC, type PropsWithChildren } from 'react';
6
+
7
+ import { type GraphBuilder } from '@dxos/app-graph';
8
+ import { type Space } from '@dxos/client-protocol';
9
+ import { type S } from '@dxos/echo-schema';
10
+ import { type RootSettingsStore } from '@dxos/local-storage';
11
+ import { type DeepReadonly } from '@dxos/util';
12
+
13
+ import { type FileInfo } from './file';
14
+ import { type NodeSerializer } from './graph';
15
+ import { type Layout } from './layout';
16
+ import { type LayoutParts } from './navigation';
17
+ import { type SurfaceDefinition } from './surface';
18
+ import { type Resource } from './translations';
19
+ import { defineCapability, type PluginManager } from '../core';
20
+ import { type AnyIntentResolver, type IntentContext } from '../plugin-intent';
21
+
22
+ export namespace Capabilities {
23
+ export const PluginManager = defineCapability<PluginManager>('dxos.org/app-framework/capability/plugin-manager');
24
+
25
+ export const Null = defineCapability<null>('dxos.org/app-framework/capability/null');
26
+
27
+ export type ReactContext = Readonly<{ id: string; dependsOn?: string[]; context: FC<PropsWithChildren> }>;
28
+ export const ReactContext = defineCapability<ReactContext>('dxos.org/app-framework/capability/react-context');
29
+
30
+ export type ReactRoot = Readonly<{ id: string; root: FC<PropsWithChildren> }>;
31
+ export const ReactRoot = defineCapability<ReactRoot>('dxos.org/app-framework/capability/react-root');
32
+
33
+ export type ReactSurface = SurfaceDefinition | readonly SurfaceDefinition[];
34
+ export const ReactSurface = defineCapability<ReactSurface>('dxos.org/app-framework/common/react-surface');
35
+
36
+ export type IntentResolver = AnyIntentResolver | readonly AnyIntentResolver[];
37
+ export const IntentResolver = defineCapability<IntentResolver>('dxos.org/app-framework/capability/intent-resolver');
38
+
39
+ export const IntentDispatcher = defineCapability<IntentContext>(
40
+ 'dxos.org/app-framework/capability/intent-dispatcher',
41
+ );
42
+
43
+ export const Layout = defineCapability<Readonly<Layout>>('dxos.org/app-framework/capability/layout');
44
+ export const MutableLayout = defineCapability<Layout>('dxos.org/app-framework/capability/layout');
45
+
46
+ export type MutableLocation = { active: LayoutParts; closed: string[] };
47
+ export type Location = DeepReadonly<MutableLocation>;
48
+ export const Location = defineCapability<Location>('dxos.org/app-framework/capability/location');
49
+ export const MutableLocation = defineCapability<MutableLocation>('dxos.org/app-framework/capability/location');
50
+
51
+ export const Translations = defineCapability<Readonly<Resource[]>>('dxos.org/app-framework/capability/translations');
52
+
53
+ export const AppGraph = defineCapability<Readonly<Pick<GraphBuilder, 'graph' | 'explore'>>>(
54
+ 'dxos.org/app-framework/capability/app-graph',
55
+ );
56
+
57
+ export const AppGraphBuilder = defineCapability<Parameters<GraphBuilder['addExtension']>[0]>(
58
+ 'dxos.org/app-framework/capability/app-graph-builder',
59
+ );
60
+
61
+ export const AppGraphSerializer = defineCapability<NodeSerializer[]>(
62
+ 'dxos.org/app-framework/capability/app-graph-serializer',
63
+ );
64
+
65
+ export const SettingsStore = defineCapability<RootSettingsStore>('dxos.org/app-framework/capability/settings-store');
66
+
67
+ // TODO(wittjosiah): The generics caused type inference issues for schemas when contributing settings.
68
+ // export type Settings = Parameters<RootSettingsStore['createStore']>[0];
69
+ // export type Settings<T extends SettingsValue = SettingsValue> = SettingsProps<T>;
70
+ export type Settings = {
71
+ schema: S.Schema.All;
72
+ prefix: string;
73
+ value?: Record<string, any>;
74
+ };
75
+ export const Settings = defineCapability<Settings>('dxos.org/app-framework/capability/settings');
76
+
77
+ export type Metadata = Readonly<{ id: string; metadata: Record<string, any> }>;
78
+ export const Metadata = defineCapability<Metadata>('dxos.org/app-framework/capability/metadata');
79
+
80
+ export type FileUploader = (file: File, space: Space) => Promise<FileInfo | undefined>;
81
+ export const FileUploader = defineCapability<FileUploader>('dxos.org/app-framework/capability/file-uploader');
82
+ }
@@ -0,0 +1,63 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Capabilities } from './capabilities';
6
+ import { defineEvent } from '../core';
7
+
8
+ export namespace Events {
9
+ /**
10
+ * Fired when the app is started.
11
+ */
12
+ export const Startup = defineEvent('dxos.org/app-framework/event/startup');
13
+
14
+ //
15
+ // Dependent Events
16
+ //
17
+
18
+ /**
19
+ * Fired before the intent dispatcher is activated.
20
+ */
21
+ export const SetupIntents = defineEvent('dxos.org/app-framework/event/setup-intents');
22
+
23
+ /**
24
+ * Fired before the settings store is activated.
25
+ */
26
+ export const SetupSettings = defineEvent('dxos.org/app-framework/event/setup-settings');
27
+
28
+ /**
29
+ * Fired before the graph is created.
30
+ */
31
+ export const SetupAppGraph = defineEvent('dxos.org/app-framework/event/setup-graph');
32
+
33
+ /**
34
+ * Fired before the translations provider is created.
35
+ */
36
+ export const SetupTranslations = defineEvent('dxos.org/app-framework/event/setup-translations');
37
+
38
+ //
39
+ // Triggered Events
40
+ //
41
+
42
+ /**
43
+ * Fired after the intent dispatcher is ready.
44
+ */
45
+ export const DispatcherReady = defineEvent('dxos.org/app-framework/event/dispatcher-ready');
46
+
47
+ /**
48
+ * Fired after the settings store is ready.
49
+ */
50
+ export const SettingsReady = defineEvent('dxos.org/app-framework/event/settings-ready');
51
+
52
+ /**
53
+ * Fired when the graph is ready.
54
+ */
55
+ export const AppGraphReady = defineEvent('dxos.org/app-framework/event/graph-ready');
56
+
57
+ /**
58
+ * Fired when plugin state is ready.
59
+ */
60
+ export const createStateEvent = (specifier: string) => defineEvent('dxos.org/app-framework/event/state', specifier);
61
+ export const LayoutReady = createStateEvent(Capabilities.Layout.identifier);
62
+ export const LocationReady = createStateEvent(Capabilities.Location.identifier);
63
+ }
@@ -0,0 +1,22 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { S } from '@dxos/echo-schema';
6
+
7
+ // TODO(burdon): See Accept attribute (uses MIME types).
8
+ // E.g., 'image/*': ['.jpg', '.jpeg', '.png', '.gif'],
9
+ export const defaultFileTypes = {
10
+ images: ['png', 'jpg', 'jpeg', 'gif'],
11
+ media: ['mp3', 'mp4', 'mov', 'avi'],
12
+ text: ['pdf', 'txt', 'md'],
13
+ };
14
+
15
+ export const FileInfoSchema = S.Struct({
16
+ name: S.String,
17
+ type: S.String,
18
+ url: S.optional(S.String),
19
+ cid: S.optional(S.String), // TODO(burdon): Meta key? Or other common properties with other file management system? (e.g., WNFS).
20
+ });
21
+
22
+ export type FileInfo = S.Schema.Type<typeof FileInfoSchema>;
@@ -0,0 +1,30 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import type { Node } from '@dxos/app-graph';
6
+ import { type MaybePromise } from '@dxos/util';
7
+
8
+ // TODO(wittjosiah): Factor out.
9
+ export type SerializedNode = {
10
+ name: string;
11
+ data: string;
12
+ type?: string;
13
+ };
14
+
15
+ // TODO(wittjosiah): Factor out.
16
+ export type NodeSerializer<T = any> = {
17
+ inputType: string;
18
+ outputType: string;
19
+ disposition?: 'hoist' | 'fallback';
20
+
21
+ /**
22
+ * Takes a node and serializes it into a format that can be stored.
23
+ */
24
+ serialize: (node: Node<T>) => MaybePromise<SerializedNode>;
25
+
26
+ /**
27
+ * Takes a serialized node and deserializes it into the application.
28
+ */
29
+ deserialize: (data: SerializedNode, ancestors: unknown[]) => MaybePromise<T>;
30
+ };
@@ -2,9 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
+ export * from './capabilities';
6
+ export * from './events';
5
7
  export * from './file';
6
8
  export * from './graph';
7
9
  export * from './layout';
8
- export * from './metadata';
9
10
  export * from './navigation';
11
+ export * from './surface';
10
12
  export * from './translations';
@@ -4,7 +4,6 @@
4
4
 
5
5
  import { S } from '@dxos/echo-schema';
6
6
 
7
- import { type Plugin } from '../plugin-host';
8
7
  import { Label } from '../plugin-intent';
9
8
 
10
9
  //
@@ -76,21 +75,6 @@ export const Layout = S.mutable(
76
75
 
77
76
  export type Layout = S.Schema.Type<typeof Layout>;
78
77
 
79
- /**
80
- * Provides for a plugin that can manage the app layout.
81
- */
82
- export type LayoutProvides = {
83
- layout: Readonly<Layout>;
84
- };
85
-
86
- /**
87
- * Type guard for layout plugins.
88
- */
89
- export const parseLayoutPlugin = (plugin: Plugin) => {
90
- const success = S.is(Layout)((plugin.provides as any).layout);
91
- return success ? (plugin as Plugin<LayoutProvides>) : undefined;
92
- };
93
-
94
78
  //
95
79
  // Intents
96
80
  //
@@ -6,8 +6,6 @@ import { Schema as S } from '@effect/schema';
6
6
 
7
7
  import { pick } from '@dxos/util';
8
8
 
9
- import { type Plugin } from '../plugin-host';
10
-
11
9
  // NOTE(thure): These are chosen from RFC 1738’s `safe` characters: http://www.faqs.org/rfcs/rfc1738.html
12
10
  export const SLUG_LIST_SEPARATOR = '+';
13
11
  export const SLUG_ENTRY_SEPARATOR = '_';
@@ -84,19 +82,6 @@ export const isLayoutAdjustment = (value: unknown): value is LayoutAdjustment =>
84
82
  return S.is(LayoutAdjustmentSchema)(value);
85
83
  };
86
84
 
87
- export const parseNavigationPlugin = (plugin: Plugin): Plugin<LocationProvides> | undefined => {
88
- const location = (plugin.provides as any)?.location;
89
- if (!location) {
90
- return undefined;
91
- }
92
-
93
- if (S.is(LocationProvidesSchema)({ location })) {
94
- return plugin as Plugin<LocationProvides>;
95
- }
96
-
97
- return undefined;
98
- };
99
-
100
85
  /**
101
86
  * Utilities.
102
87
  */
@@ -2,12 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { createContext, useContext, type JSX, type ForwardedRef, type PropsWithChildren, type ReactNode } from 'react';
5
+ import { type JSX, type ForwardedRef, type PropsWithChildren, type ReactNode } from 'react';
6
6
 
7
- import { raise } from '@dxos/debug';
8
- import { type GuardedType, type MakeOptional } from '@dxos/util';
7
+ import { type GuardedType, type MakeOptional, type Disposition } from '@dxos/util';
9
8
 
10
- import { type ErrorBoundary } from './ErrorBoundary';
9
+ import { type ErrorBoundary } from '../react';
11
10
 
12
11
  /**
13
12
  * SurfaceProps are the props that are passed to the Surface component.
@@ -68,45 +67,15 @@ export type SurfaceComponent<T extends Record<string, any> = Record<string, unkn
68
67
  forwardedRef: ForwardedRef<HTMLElement>,
69
68
  ) => JSX.Element | null;
70
69
 
71
- /**
72
- * Determines the priority of the surface when multiple components are resolved.
73
- *
74
- * - `static` - The component is rendered in the order it was resolved.
75
- * - `hoist` - The component is rendered before `static` components.
76
- * - `fallback` - The component is rendered after `static` components.
77
- */
78
- export type SurfaceDisposition = 'static' | 'hoist' | 'fallback';
79
-
80
70
  /**
81
71
  * Definition of when a SurfaceComponent should be rendered.
82
72
  */
83
- export type SurfaceDefinition<T extends Record<string, any> = any> = {
73
+ export type SurfaceDefinition<T extends Record<string, any> = any> = Readonly<{
84
74
  id: string;
85
75
  role: string | string[];
86
- disposition?: SurfaceDisposition;
76
+ disposition?: Disposition;
87
77
  filter?: (data: Record<string, unknown>) => data is T;
88
78
  component: SurfaceComponent<GuardedType<SurfaceDefinition<T>['filter']>>;
89
- };
79
+ }>;
90
80
 
91
81
  export const createSurface = <T extends Record<string, any> = any>(definition: SurfaceDefinition<T>) => definition;
92
-
93
- /**
94
- * Surface debug info.
95
- * NOTE: Short-term measure to track perf issues.
96
- */
97
- export type DebugInfo = {
98
- id: string;
99
- created: number;
100
- renderCount: number;
101
- } & Pick<SurfaceProps, 'role'>;
102
-
103
- export type SurfaceContextValue = {
104
- surfaces: Record<string, SurfaceDefinition>;
105
- debugInfo?: Map<string, DebugInfo>;
106
- };
107
-
108
- const SurfaceContext = createContext<SurfaceContextValue | undefined>(undefined);
109
-
110
- export const useSurfaceRoot = () => useContext(SurfaceContext) ?? raise(new Error('Missing SurfaceContext'));
111
-
112
- export const SurfaceProvider = SurfaceContext.Provider;
@@ -0,0 +1,18 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { z } from 'zod';
6
+
7
+ // TODO(burdon): Replace zod with effect.
8
+ export const ResourceKey = z.union([z.string(), z.record(z.any())]);
9
+ export type ResourceKey = z.infer<typeof ResourceKey>;
10
+
11
+ export const ResourceLanguage = z.record(ResourceKey);
12
+ export type ResourceLanguage = z.infer<typeof ResourceLanguage>;
13
+
14
+ /**
15
+ * A resource is a collection of translations for a language.
16
+ */
17
+ export const Resource = z.record(ResourceLanguage);
18
+ export type Resource = z.infer<typeof Resource>;
@@ -0,0 +1,116 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { describe, expect, it } from 'vitest';
6
+
7
+ import { updateCounter } from '@dxos/echo-schema/testing';
8
+ import { registerSignalsRuntime } from '@dxos/echo-signals';
9
+
10
+ import { defineCapability, PluginsContext } from './capabilities';
11
+
12
+ registerSignalsRuntime();
13
+
14
+ const defaultOptions = {
15
+ activate: () => Promise.resolve(false),
16
+ reset: () => Promise.resolve(false),
17
+ };
18
+
19
+ describe('PluginsContext', () => {
20
+ it('should return empty array if no capabilities are contributed', () => {
21
+ const context = new PluginsContext(defaultOptions);
22
+ const interfaceDef = defineCapability<{ example: string }>('@dxos/app-framework/test/example');
23
+ expect(context.requestCapabilities(interfaceDef)).toEqual([]);
24
+ });
25
+
26
+ it('should be able to contribute and request capabilities', () => {
27
+ const context = new PluginsContext(defaultOptions);
28
+ const interfaceDef = defineCapability<{ example: string }>('@dxos/app-framework/test/example');
29
+ const implementation = { example: 'identifier' };
30
+ context.contributeCapability({ interface: interfaceDef, implementation, module: 'test' });
31
+ expect(context.requestCapabilities(interfaceDef)).toEqual([implementation]);
32
+ });
33
+
34
+ it('should be able to remove capabilities', () => {
35
+ const context = new PluginsContext(defaultOptions);
36
+ const interfaceDef = defineCapability<{ example: string }>('@dxos/app-framework/test/example');
37
+ const implementation = { example: 'identifier' };
38
+ context.contributeCapability({ interface: interfaceDef, implementation, module: 'test' });
39
+ expect(context.requestCapabilities(interfaceDef)).toEqual([implementation]);
40
+ context.removeCapability(interfaceDef, implementation);
41
+ expect(context.requestCapabilities(interfaceDef)).toEqual([]);
42
+ });
43
+
44
+ it('should be able to contribute and request multiple implementations', () => {
45
+ const context = new PluginsContext(defaultOptions);
46
+ const interfaceDef = defineCapability<{ example: string }>('@dxos/app-framework/test/example');
47
+ const implementation1 = { example: 'first' };
48
+ const implementation2 = { example: 'second' };
49
+ context.contributeCapability({ interface: interfaceDef, implementation: implementation1, module: 'test' });
50
+ context.contributeCapability({ interface: interfaceDef, implementation: implementation2, module: 'test' });
51
+ expect(context.requestCapabilities(interfaceDef)).toEqual([implementation1, implementation2]);
52
+ });
53
+
54
+ it('should be able to request multiple capabilities', () => {
55
+ const context = new PluginsContext(defaultOptions);
56
+ const interfaceDef1 = defineCapability<{ one: number }>('@dxos/app-framework/test/one');
57
+ const interfaceDef2 = defineCapability<{ two: number }>('@dxos/app-framework/test/two');
58
+ const implementation1 = { one: 1 };
59
+ const implementation2 = { two: 2 };
60
+ context.contributeCapability({ interface: interfaceDef1, implementation: implementation1, module: 'test' });
61
+ context.contributeCapability({ interface: interfaceDef2, implementation: implementation2, module: 'test' });
62
+ expect(context.requestCapabilities(interfaceDef1)).toEqual([implementation1]);
63
+ expect(context.requestCapabilities(interfaceDef2)).toEqual([implementation2]);
64
+ });
65
+
66
+ it('should be reactive', () => {
67
+ const context = new PluginsContext(defaultOptions);
68
+ const interfaceDef = defineCapability<{ example: string }>('@dxos/app-framework/test/example');
69
+
70
+ using updates = updateCounter(() => {
71
+ context.requestCapabilities(interfaceDef);
72
+ });
73
+
74
+ expect(updates.count).toEqual(0);
75
+
76
+ const implementation = { example: 'identifier' };
77
+ context.contributeCapability({ interface: interfaceDef, implementation, module: 'test' });
78
+ expect(updates.count).toEqual(1);
79
+
80
+ context.removeCapability(interfaceDef, implementation);
81
+ expect(updates.count).toEqual(2);
82
+ });
83
+
84
+ it('should not be reactive to changes within the implementation', () => {
85
+ const context = new PluginsContext(defaultOptions);
86
+ const interfaceDef = defineCapability<{ example: string }>('@dxos/app-framework/test/example');
87
+
88
+ using updates = updateCounter(() => {
89
+ context.requestCapabilities(interfaceDef);
90
+ });
91
+
92
+ expect(updates.count).toEqual(0);
93
+
94
+ const implementation = { example: 'identifier' };
95
+ context.contributeCapability({ interface: interfaceDef, implementation, module: 'test' });
96
+ expect(updates.count).toEqual(1);
97
+
98
+ implementation.example = 'updated';
99
+ expect(updates.count).toEqual(1);
100
+
101
+ const capabilities = context.requestCapabilities(interfaceDef);
102
+ expect(capabilities).toEqual([implementation]);
103
+ expect(capabilities[0].example).toEqual('updated');
104
+ expect(updates.count).toEqual(1);
105
+ });
106
+
107
+ it('should be able to wait for a capability', async () => {
108
+ const context = new PluginsContext(defaultOptions);
109
+ const interfaceDef = defineCapability<{ example: string }>('@dxos/app-framework/test/example');
110
+ const implementation = { example: 'identifier' };
111
+ const promise = context.waitForCapability(interfaceDef);
112
+ context.contributeCapability({ interface: interfaceDef, implementation, module: 'test' });
113
+ const capability = await promise;
114
+ expect(capability).toEqual(implementation);
115
+ });
116
+ });