@dxos/app-framework 0.10.0 → 0.11.0

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 (294) hide show
  1. package/.storybook/main.mts +1 -1
  2. package/.storybook/preview.mts +2 -2
  3. package/CHANGELOG.md +93 -0
  4. package/TASKS.md +11 -0
  5. package/dist/lib/chunk-SurfaceManager.mjs +960 -0
  6. package/dist/lib/chunk-SurfaceManager.mjs.map +1 -0
  7. package/dist/lib/chunk-capability.mjs +15 -0
  8. package/dist/lib/chunk-capability.mjs.map +1 -0
  9. package/dist/lib/{browser/chunk-FJ4765WW.mjs → chunk-context.mjs} +4 -5
  10. package/dist/lib/chunk-context.mjs.map +1 -0
  11. package/dist/lib/chunk-history-tracker.mjs +160 -0
  12. package/dist/lib/chunk-history-tracker.mjs.map +1 -0
  13. package/dist/lib/chunk-plugin-manager.mjs +1390 -0
  14. package/dist/lib/chunk-plugin-manager.mjs.map +1 -0
  15. package/dist/lib/chunk-plugin-manifest.mjs +125 -0
  16. package/dist/lib/chunk-plugin-manifest.mjs.map +1 -0
  17. package/dist/lib/chunk-process-manager-capability.mjs +126 -0
  18. package/dist/lib/chunk-process-manager-capability.mjs.map +1 -0
  19. package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
  20. package/dist/lib/chunk-url-loader.mjs +347 -0
  21. package/dist/lib/chunk-url-loader.mjs.map +1 -0
  22. package/dist/lib/cli.mjs +78 -0
  23. package/dist/lib/cli.mjs.map +1 -0
  24. package/dist/lib/common/activation-events.mjs +35 -0
  25. package/dist/lib/common/activation-events.mjs.map +1 -0
  26. package/dist/lib/common/capabilities.mjs +184 -0
  27. package/dist/lib/common/capabilities.mjs.map +1 -0
  28. package/dist/lib/config.mjs +2 -0
  29. package/dist/lib/core/activation-event.mjs +55 -0
  30. package/dist/lib/core/activation-event.mjs.map +1 -0
  31. package/dist/lib/core/capability.mjs +189 -0
  32. package/dist/lib/core/capability.mjs.map +1 -0
  33. package/dist/lib/core/plugin-manager.mjs +2 -0
  34. package/dist/lib/core/plugin.mjs +340 -0
  35. package/dist/lib/core/plugin.mjs.map +1 -0
  36. package/dist/lib/core/url-loader.mjs +2 -0
  37. package/dist/lib/index.mjs +134 -0
  38. package/dist/lib/index.mjs.map +1 -0
  39. package/dist/lib/testing/react.mjs +70 -0
  40. package/dist/lib/testing/react.mjs.map +1 -0
  41. package/dist/lib/testing.mjs +399 -0
  42. package/dist/lib/testing.mjs.map +1 -0
  43. package/dist/lib/ui.mjs +636 -0
  44. package/dist/lib/ui.mjs.map +1 -0
  45. package/dist/lib/vite-plugin.mjs +986 -0
  46. package/dist/lib/vite-plugin.mjs.map +1 -0
  47. package/dist/plugin/node-esm/index.mjs +4 -3
  48. package/dist/plugin/node-esm/index.mjs.map +3 -3
  49. package/dist/plugin/node-esm/meta.json +1 -1
  50. package/dist/types/src/common/Role.d.ts +31 -0
  51. package/dist/types/src/common/Role.d.ts.map +1 -0
  52. package/dist/types/src/common/Role.test.d.ts +2 -0
  53. package/dist/types/src/common/Role.test.d.ts.map +1 -0
  54. package/dist/types/src/common/capabilities.d.ts +11 -2
  55. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  56. package/dist/types/src/common/index.d.ts +1 -0
  57. package/dist/types/src/common/index.d.ts.map +1 -1
  58. package/dist/types/src/core/capability-manager.d.ts +1 -1
  59. package/dist/types/src/core/capability-manager.d.ts.map +1 -1
  60. package/dist/types/src/core/capability.d.ts +38 -5
  61. package/dist/types/src/core/capability.d.ts.map +1 -1
  62. package/dist/types/src/core/plugin-manager.d.ts +1 -1
  63. package/dist/types/src/core/plugin-manager.d.ts.map +1 -1
  64. package/dist/types/src/core/plugin.d.ts +14 -1
  65. package/dist/types/src/core/plugin.d.ts.map +1 -1
  66. package/dist/types/src/core/registry.d.ts +1 -1
  67. package/dist/types/src/core/registry.d.ts.map +1 -1
  68. package/dist/types/src/plugin-process-manager/history/capability.d.ts +1 -1
  69. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts +1 -1
  70. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts.map +1 -1
  71. package/dist/types/src/testing/StorybookErrorFallback.d.ts +15 -0
  72. package/dist/types/src/testing/StorybookErrorFallback.d.ts.map +1 -0
  73. package/dist/types/src/testing/harness.d.ts +1 -1
  74. package/dist/types/src/testing/harness.d.ts.map +1 -1
  75. package/dist/types/src/testing/index.d.ts +2 -0
  76. package/dist/types/src/testing/index.d.ts.map +1 -1
  77. package/dist/types/src/testing/react.d.ts +4 -4
  78. package/dist/types/src/testing/react.d.ts.map +1 -1
  79. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  80. package/dist/types/src/testing/withPluginManager.stories.d.ts +6 -0
  81. package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
  82. package/dist/types/src/testing/withSurfaceDebug.d.ts +10 -0
  83. package/dist/types/src/testing/withSurfaceDebug.d.ts.map +1 -0
  84. package/dist/types/src/ui/components/App/App.d.ts +0 -32
  85. package/dist/types/src/ui/components/App/App.d.ts.map +1 -1
  86. package/dist/types/src/ui/components/App/index.d.ts +1 -0
  87. package/dist/types/src/ui/components/App/index.d.ts.map +1 -1
  88. package/dist/types/src/ui/components/App/loader.d.ts +35 -0
  89. package/dist/types/src/ui/components/App/loader.d.ts.map +1 -0
  90. package/dist/types/src/ui/components/HomeSection/HomeSection.d.ts +26 -0
  91. package/dist/types/src/ui/components/HomeSection/HomeSection.d.ts.map +1 -0
  92. package/dist/types/src/ui/components/HomeSection/HomeSection.stories.d.ts +15 -0
  93. package/dist/types/src/ui/components/HomeSection/HomeSection.stories.d.ts.map +1 -0
  94. package/dist/types/src/ui/components/HomeSection/index.d.ts +2 -0
  95. package/dist/types/src/ui/components/HomeSection/index.d.ts.map +1 -0
  96. package/dist/types/src/ui/components/NamePopover/NamePopover.d.ts +14 -0
  97. package/dist/types/src/ui/components/NamePopover/NamePopover.d.ts.map +1 -0
  98. package/dist/types/src/ui/components/NamePopover/index.d.ts +2 -0
  99. package/dist/types/src/ui/components/NamePopover/index.d.ts.map +1 -0
  100. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts +21 -9
  101. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts.map +1 -1
  102. package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts +4 -1
  103. package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts.map +1 -1
  104. package/dist/types/src/ui/components/Surface/SurfaceComponent.test.d.ts +2 -0
  105. package/dist/types/src/ui/components/Surface/SurfaceComponent.test.d.ts.map +1 -0
  106. package/dist/types/src/ui/components/Surface/SurfaceDebug.d.ts +40 -0
  107. package/dist/types/src/ui/components/Surface/SurfaceDebug.d.ts.map +1 -0
  108. package/dist/types/src/ui/components/Surface/SurfaceManager.d.ts +23 -0
  109. package/dist/types/src/ui/components/Surface/SurfaceManager.d.ts.map +1 -0
  110. package/dist/types/src/ui/components/Surface/SurfaceManagerContext.d.ts +11 -0
  111. package/dist/types/src/ui/components/Surface/SurfaceManagerContext.d.ts.map +1 -0
  112. package/dist/types/src/ui/components/Surface/SurfaceMetrics.d.ts +72 -0
  113. package/dist/types/src/ui/components/Surface/SurfaceMetrics.d.ts.map +1 -0
  114. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts.map +1 -1
  115. package/dist/types/src/ui/components/Surface/index.d.ts +20 -25
  116. package/dist/types/src/ui/components/Surface/index.d.ts.map +1 -1
  117. package/dist/types/src/ui/components/Surface/types.d.ts +56 -52
  118. package/dist/types/src/ui/components/Surface/types.d.ts.map +1 -1
  119. package/dist/types/src/ui/components/index.d.ts +2 -0
  120. package/dist/types/src/ui/components/index.d.ts.map +1 -1
  121. package/dist/types/src/ui/hooks/useApp.d.ts.map +1 -1
  122. package/dist/types/tsconfig.tsbuildinfo +1 -1
  123. package/moon.yml +25 -18
  124. package/package.json +58 -73
  125. package/src/common/Role.test.ts +41 -0
  126. package/src/common/Role.ts +54 -0
  127. package/src/common/capabilities.ts +17 -2
  128. package/src/common/index.ts +1 -0
  129. package/src/core/capability-manager.test.ts +1 -1
  130. package/src/core/capability-manager.ts +1 -1
  131. package/src/core/capability.ts +45 -6
  132. package/src/core/plugin-manager.test.ts +38 -3
  133. package/src/core/plugin-manager.ts +18 -1
  134. package/src/core/plugin.ts +16 -1
  135. package/src/core/registry.ts +1 -1
  136. package/src/plugin-process-manager/process-manager-capability.ts +25 -2
  137. package/src/testing/StorybookErrorFallback.tsx +40 -0
  138. package/src/testing/harness.ts +1 -1
  139. package/src/testing/index.ts +2 -0
  140. package/src/testing/react.test.tsx +2 -1
  141. package/src/testing/react.tsx +14 -8
  142. package/src/testing/withPluginManager.stories.tsx +16 -1
  143. package/src/testing/withPluginManager.tsx +13 -2
  144. package/src/testing/withSurfaceDebug.tsx +22 -0
  145. package/src/ui/components/App/App.tsx +7 -35
  146. package/src/ui/components/App/index.ts +1 -0
  147. package/src/ui/components/App/loader.ts +39 -0
  148. package/src/ui/components/HomeSection/HomeSection.stories.tsx +43 -0
  149. package/src/ui/components/HomeSection/HomeSection.tsx +69 -0
  150. package/src/ui/components/HomeSection/index.ts +5 -0
  151. package/src/ui/components/NamePopover/NamePopover.tsx +70 -0
  152. package/src/ui/components/NamePopover/index.ts +5 -0
  153. package/src/ui/components/Surface/DESIGN.md +136 -0
  154. package/src/ui/components/Surface/SurfaceComponent.stories.tsx +70 -41
  155. package/src/ui/components/Surface/SurfaceComponent.test.tsx +403 -0
  156. package/src/ui/components/Surface/SurfaceComponent.tsx +209 -189
  157. package/src/ui/components/Surface/SurfaceDebug.tsx +435 -0
  158. package/src/ui/components/Surface/SurfaceManager.ts +95 -0
  159. package/src/ui/components/Surface/SurfaceManagerContext.ts +23 -0
  160. package/src/ui/components/Surface/SurfaceMetrics.ts +202 -0
  161. package/src/ui/components/Surface/SurfaceProfilerContext.tsx +12 -2
  162. package/src/ui/components/Surface/index.ts +24 -22
  163. package/src/ui/components/Surface/types.test.ts +47 -54
  164. package/src/ui/components/Surface/types.ts +66 -91
  165. package/src/ui/components/index.ts +2 -0
  166. package/src/ui/hooks/useApp.tsx +7 -3
  167. package/src/vite-plugin/boot-loader/loader-app/boot-loader.css +1 -1
  168. package/tsconfig.json +3 -0
  169. package/vite.config.ts +26 -0
  170. package/dist/lib/browser/capability-S44TE2H7.mjs +0 -35
  171. package/dist/lib/browser/capability-S44TE2H7.mjs.map +0 -7
  172. package/dist/lib/browser/chunk-3NQLTQCP.mjs +0 -47
  173. package/dist/lib/browser/chunk-3NQLTQCP.mjs.map +0 -7
  174. package/dist/lib/browser/chunk-53HJHMS5.mjs +0 -7
  175. package/dist/lib/browser/chunk-53HJHMS5.mjs.map +0 -7
  176. package/dist/lib/browser/chunk-FJ4765WW.mjs.map +0 -7
  177. package/dist/lib/browser/chunk-J5LGTIGS.mjs +0 -10
  178. package/dist/lib/browser/chunk-J5LGTIGS.mjs.map +0 -7
  179. package/dist/lib/browser/chunk-KRJ4KK2W.mjs +0 -505
  180. package/dist/lib/browser/chunk-KRJ4KK2W.mjs.map +0 -7
  181. package/dist/lib/browser/chunk-LUH4Y5F2.mjs +0 -430
  182. package/dist/lib/browser/chunk-LUH4Y5F2.mjs.map +0 -7
  183. package/dist/lib/browser/chunk-NKVRSMFN.mjs +0 -95
  184. package/dist/lib/browser/chunk-NKVRSMFN.mjs.map +0 -7
  185. package/dist/lib/browser/chunk-OO53M5UK.mjs +0 -260
  186. package/dist/lib/browser/chunk-OO53M5UK.mjs.map +0 -7
  187. package/dist/lib/browser/chunk-OPTS3ZSN.mjs +0 -83
  188. package/dist/lib/browser/chunk-OPTS3ZSN.mjs.map +0 -7
  189. package/dist/lib/browser/chunk-Q2GLJTVV.mjs +0 -12
  190. package/dist/lib/browser/chunk-Q2GLJTVV.mjs.map +0 -7
  191. package/dist/lib/browser/chunk-SYXIYT6T.mjs +0 -143
  192. package/dist/lib/browser/chunk-SYXIYT6T.mjs.map +0 -7
  193. package/dist/lib/browser/chunk-U5MESPM5.mjs +0 -603
  194. package/dist/lib/browser/chunk-U5MESPM5.mjs.map +0 -7
  195. package/dist/lib/browser/chunk-UGYCLOXE.mjs +0 -1471
  196. package/dist/lib/browser/chunk-UGYCLOXE.mjs.map +0 -7
  197. package/dist/lib/browser/chunk-VF37YTXJ.mjs +0 -28
  198. package/dist/lib/browser/chunk-VF37YTXJ.mjs.map +0 -7
  199. package/dist/lib/browser/chunk-YUVQIOTB.mjs +0 -60
  200. package/dist/lib/browser/chunk-YUVQIOTB.mjs.map +0 -7
  201. package/dist/lib/browser/cli/index.mjs +0 -74
  202. package/dist/lib/browser/cli/index.mjs.map +0 -7
  203. package/dist/lib/browser/common/activation-events.mjs +0 -20
  204. package/dist/lib/browser/common/activation-events.mjs.map +0 -7
  205. package/dist/lib/browser/common/capabilities.mjs +0 -56
  206. package/dist/lib/browser/common/capabilities.mjs.map +0 -7
  207. package/dist/lib/browser/config/index.mjs +0 -8
  208. package/dist/lib/browser/config/index.mjs.map +0 -7
  209. package/dist/lib/browser/core/activation-event.mjs +0 -20
  210. package/dist/lib/browser/core/activation-event.mjs.map +0 -7
  211. package/dist/lib/browser/core/capability.mjs +0 -32
  212. package/dist/lib/browser/core/capability.mjs.map +0 -7
  213. package/dist/lib/browser/core/plugin-manager.mjs +0 -19
  214. package/dist/lib/browser/core/plugin-manager.mjs.map +0 -7
  215. package/dist/lib/browser/core/plugin.mjs +0 -51
  216. package/dist/lib/browser/core/plugin.mjs.map +0 -7
  217. package/dist/lib/browser/core/url-loader.mjs +0 -24
  218. package/dist/lib/browser/core/url-loader.mjs.map +0 -7
  219. package/dist/lib/browser/index.mjs +0 -98
  220. package/dist/lib/browser/index.mjs.map +0 -7
  221. package/dist/lib/browser/meta.json +0 -1
  222. package/dist/lib/browser/process-manager-capability-QK4BMKMN.mjs +0 -132
  223. package/dist/lib/browser/process-manager-capability-QK4BMKMN.mjs.map +0 -7
  224. package/dist/lib/browser/testing/index.mjs +0 -359
  225. package/dist/lib/browser/testing/index.mjs.map +0 -7
  226. package/dist/lib/browser/testing/react.mjs +0 -78
  227. package/dist/lib/browser/testing/react.mjs.map +0 -7
  228. package/dist/lib/browser/ui/index.mjs +0 -60
  229. package/dist/lib/browser/ui/index.mjs.map +0 -7
  230. package/dist/lib/node-esm/capability-3YRF77LV.mjs +0 -36
  231. package/dist/lib/node-esm/capability-3YRF77LV.mjs.map +0 -7
  232. package/dist/lib/node-esm/chunk-2UPUZXGU.mjs +0 -9
  233. package/dist/lib/node-esm/chunk-2UPUZXGU.mjs.map +0 -7
  234. package/dist/lib/node-esm/chunk-37Z53PXZ.mjs +0 -10
  235. package/dist/lib/node-esm/chunk-37Z53PXZ.mjs.map +0 -7
  236. package/dist/lib/node-esm/chunk-4SE7SX7N.mjs +0 -261
  237. package/dist/lib/node-esm/chunk-4SE7SX7N.mjs.map +0 -7
  238. package/dist/lib/node-esm/chunk-BMW6P6QA.mjs +0 -48
  239. package/dist/lib/node-esm/chunk-BMW6P6QA.mjs.map +0 -7
  240. package/dist/lib/node-esm/chunk-COHOWGGJ.mjs +0 -144
  241. package/dist/lib/node-esm/chunk-COHOWGGJ.mjs.map +0 -7
  242. package/dist/lib/node-esm/chunk-DRT75WGD.mjs +0 -604
  243. package/dist/lib/node-esm/chunk-DRT75WGD.mjs.map +0 -7
  244. package/dist/lib/node-esm/chunk-FKMVORZN.mjs +0 -431
  245. package/dist/lib/node-esm/chunk-FKMVORZN.mjs.map +0 -7
  246. package/dist/lib/node-esm/chunk-FPW45EZH.mjs +0 -14
  247. package/dist/lib/node-esm/chunk-FPW45EZH.mjs.map +0 -7
  248. package/dist/lib/node-esm/chunk-GLH4LGHZ.mjs +0 -84
  249. package/dist/lib/node-esm/chunk-GLH4LGHZ.mjs.map +0 -7
  250. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +0 -11
  251. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +0 -7
  252. package/dist/lib/node-esm/chunk-IL7O7IRX.mjs +0 -1472
  253. package/dist/lib/node-esm/chunk-IL7O7IRX.mjs.map +0 -7
  254. package/dist/lib/node-esm/chunk-ND2HETHD.mjs +0 -506
  255. package/dist/lib/node-esm/chunk-ND2HETHD.mjs.map +0 -7
  256. package/dist/lib/node-esm/chunk-TLKYZKPW.mjs +0 -29
  257. package/dist/lib/node-esm/chunk-TLKYZKPW.mjs.map +0 -7
  258. package/dist/lib/node-esm/chunk-VCPGX7WN.mjs +0 -62
  259. package/dist/lib/node-esm/chunk-VCPGX7WN.mjs.map +0 -7
  260. package/dist/lib/node-esm/chunk-XSZMX53L.mjs +0 -96
  261. package/dist/lib/node-esm/chunk-XSZMX53L.mjs.map +0 -7
  262. package/dist/lib/node-esm/cli/index.mjs +0 -75
  263. package/dist/lib/node-esm/cli/index.mjs.map +0 -7
  264. package/dist/lib/node-esm/common/activation-events.mjs +0 -21
  265. package/dist/lib/node-esm/common/activation-events.mjs.map +0 -7
  266. package/dist/lib/node-esm/common/capabilities.mjs +0 -57
  267. package/dist/lib/node-esm/common/capabilities.mjs.map +0 -7
  268. package/dist/lib/node-esm/config/index.mjs +0 -9
  269. package/dist/lib/node-esm/config/index.mjs.map +0 -7
  270. package/dist/lib/node-esm/core/activation-event.mjs +0 -21
  271. package/dist/lib/node-esm/core/activation-event.mjs.map +0 -7
  272. package/dist/lib/node-esm/core/capability.mjs +0 -33
  273. package/dist/lib/node-esm/core/capability.mjs.map +0 -7
  274. package/dist/lib/node-esm/core/plugin-manager.mjs +0 -20
  275. package/dist/lib/node-esm/core/plugin-manager.mjs.map +0 -7
  276. package/dist/lib/node-esm/core/plugin.mjs +0 -52
  277. package/dist/lib/node-esm/core/plugin.mjs.map +0 -7
  278. package/dist/lib/node-esm/core/url-loader.mjs +0 -25
  279. package/dist/lib/node-esm/core/url-loader.mjs.map +0 -7
  280. package/dist/lib/node-esm/index.mjs +0 -99
  281. package/dist/lib/node-esm/index.mjs.map +0 -7
  282. package/dist/lib/node-esm/meta.json +0 -1
  283. package/dist/lib/node-esm/process-manager-capability-5S7WZ2JR.mjs +0 -133
  284. package/dist/lib/node-esm/process-manager-capability-5S7WZ2JR.mjs.map +0 -7
  285. package/dist/lib/node-esm/testing/index.mjs +0 -360
  286. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  287. package/dist/lib/node-esm/testing/react.mjs +0 -79
  288. package/dist/lib/node-esm/testing/react.mjs.map +0 -7
  289. package/dist/lib/node-esm/ui/index.mjs +0 -61
  290. package/dist/lib/node-esm/ui/index.mjs.map +0 -7
  291. package/dist/types/src/ui/components/Surface/SurfaceInfo.d.ts +0 -11
  292. package/dist/types/src/ui/components/Surface/SurfaceInfo.d.ts.map +0 -1
  293. package/src/ui/components/Surface/SurfaceInfo.tsx +0 -106
  294. package/vitest.config.ts +0 -14
package/moon.yml CHANGED
@@ -2,27 +2,13 @@ layer: library
2
2
  language: typescript
3
3
  tags:
4
4
  - pack
5
- - ts-build
5
+ - ts-vite-build
6
6
  - ts-test
7
7
  - ts-test-storybook
8
8
  - typedoc
9
9
  - storybook
10
10
  tasks:
11
- compile:
12
- args:
13
- - '--entryPoint=src/index.ts'
14
- - '--entryPoint=src/cli/index.ts'
15
- - '--entryPoint=src/core/activation-event.ts'
16
- - '--entryPoint=src/core/capability.ts'
17
- - '--entryPoint=src/core/plugin.ts'
18
- - '--entryPoint=src/core/plugin-manager.ts'
19
- - '--entryPoint=src/common/capabilities.ts'
20
- - '--entryPoint=src/common/activation-events.ts'
21
- - '--entryPoint=src/ui/index.ts'
22
- - '--entryPoint=src/testing/index.ts'
23
- - '--entryPoint=src/testing/react.tsx'
24
- - '--entryPoint=src/core/url-loader.ts'
25
- - '--entryPoint=src/config/index.ts'
11
+ build:
26
12
  deps:
27
13
  - compile-plugin
28
14
  compile-plugin:
@@ -32,7 +18,28 @@ tasks:
32
18
  - '--outputPath=dist/plugin'
33
19
  - '--platform=node'
34
20
  deps:
35
- - ^:compile
36
- - dx-compile:compile
21
+ - ^:build
22
+ - dx-compile:build
37
23
  outputs:
38
24
  - dist/plugin
25
+ check-module-structure:
26
+ # Verify headless entrypoints resolve under workerd conditions (post-build artifacts
27
+ # must exist — catches stale `./workerd` export paths like the removed browser bundle).
28
+ # Then fail when the root export pulls in React; React lives only behind `./ui`.
29
+ script: |
30
+ pnpm exec dx-trace-imports \
31
+ --export . \
32
+ --to "{react,react-dom}" \
33
+ --conditions workerd,worker,node \
34
+ --fail-on present
35
+ deps:
36
+ - dx-trace-imports:build
37
+ - build
38
+ inputs:
39
+ - tsconfig.json
40
+ - package.json
41
+ - '@group(production)'
42
+ - '^@group(production)'
43
+ - /pnpm-lock.yaml
44
+ options:
45
+ timeout: 60
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/app-framework",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "A framework for building applications from composible plugins.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -15,89 +15,73 @@
15
15
  "exports": {
16
16
  ".": {
17
17
  "source": "./src/index.ts",
18
- "browser": "./dist/lib/browser/index.mjs",
19
- "node": "./dist/lib/node-esm/index.mjs",
20
- "workerd": "./dist/lib/browser/index.mjs",
21
- "types": "./dist/types/src/index.d.ts"
22
- },
23
- "./workerd": {
24
18
  "types": "./dist/types/src/index.d.ts",
25
- "default": "./dist/lib/browser/index.mjs"
19
+ "import": "./dist/lib/index.mjs"
26
20
  },
27
21
  "./ActivationEvent": {
28
22
  "source": "./src/core/activation-event.ts",
29
- "browser": "./dist/lib/browser/activation-event/index.mjs",
30
- "node": "./dist/lib/node-esm/activation-event/index.mjs",
31
- "types": "./dist/types/src/activation-event/index.d.ts"
23
+ "types": "./dist/types/src/core/activation-event.d.ts",
24
+ "import": "./dist/lib/core/activation-event.mjs"
32
25
  },
33
26
  "./ActivationEvents": {
34
27
  "source": "./src/common/activation-events.ts",
35
- "browser": "./dist/lib/browser/common/activation-events.mjs",
36
- "node": "./dist/lib/node-esm/common/activation-events.mjs",
37
- "types": "./dist/types/src/common/activation-events.d.ts"
28
+ "types": "./dist/types/src/common/activation-events.d.ts",
29
+ "import": "./dist/lib/common/activation-events.mjs"
38
30
  },
39
31
  "./Capabilities": {
40
32
  "source": "./src/common/capabilities.ts",
41
- "browser": "./dist/lib/browser/common/capabilities.mjs",
42
- "node": "./dist/lib/node-esm/common/capabilities.mjs",
43
- "types": "./dist/types/src/common/capabilities.d.ts"
33
+ "types": "./dist/types/src/common/capabilities.d.ts",
34
+ "import": "./dist/lib/common/capabilities.mjs"
44
35
  },
45
36
  "./Capability": {
46
37
  "source": "./src/core/capability.ts",
47
- "browser": "./dist/lib/browser/capability/index.mjs",
48
- "node": "./dist/lib/node-esm/capability/index.mjs",
49
- "types": "./dist/types/src/capability/index.d.ts"
38
+ "types": "./dist/types/src/core/capability.d.ts",
39
+ "import": "./dist/lib/core/capability.mjs"
50
40
  },
51
41
  "./Plugin": {
52
42
  "source": "./src/core/plugin.ts",
53
- "browser": "./dist/lib/browser/plugin/index.mjs",
54
- "node": "./dist/lib/node-esm/plugin/index.mjs",
55
- "types": "./dist/types/src/plugin/index.d.ts"
43
+ "types": "./dist/types/src/core/plugin.d.ts",
44
+ "import": "./dist/lib/core/plugin.mjs"
56
45
  },
57
46
  "./PluginManager": {
58
47
  "source": "./src/core/plugin-manager.ts",
59
- "browser": "./dist/lib/browser/plugin-manager/index.mjs",
60
- "node": "./dist/lib/node-esm/plugin-manager/index.mjs",
61
- "types": "./dist/types/src/plugin-manager/index.d.ts"
48
+ "types": "./dist/types/src/core/plugin-manager.d.ts",
49
+ "import": "./dist/lib/core/plugin-manager.mjs"
62
50
  },
63
51
  "./UrlLoader": {
64
52
  "source": "./src/core/url-loader.ts",
65
- "browser": "./dist/lib/browser/url-loader/index.mjs",
66
- "node": "./dist/lib/node-esm/url-loader/index.mjs",
67
- "types": "./dist/types/src/url-loader/index.d.ts"
53
+ "types": "./dist/types/src/core/url-loader.d.ts",
54
+ "import": "./dist/lib/core/url-loader.mjs"
68
55
  },
69
56
  "./config": {
70
- "browser": "./dist/lib/browser/config/index.mjs",
71
- "node": "./dist/lib/node-esm/config/index.mjs",
72
- "types": "./dist/types/src/config/index.d.ts"
57
+ "source": "./src/config/index.ts",
58
+ "types": "./dist/types/src/config/index.d.ts",
59
+ "import": "./dist/lib/config.mjs"
73
60
  },
74
61
  "./vite-plugin": {
75
- "import": "./dist/plugin/node-esm/index.mjs",
76
- "types": "./dist/types/src/vite-plugin/index.d.ts"
62
+ "source": "./src/vite-plugin/index.ts",
63
+ "types": "./dist/types/src/vite-plugin/index.d.ts",
64
+ "import": "./dist/lib/vite-plugin.mjs"
77
65
  },
78
66
  "./cli": {
79
67
  "source": "./src/cli/index.ts",
80
- "browser": "./dist/lib/browser/cli/index.mjs",
81
- "node": "./dist/lib/node-esm/cli/index.mjs",
82
- "types": "./dist/types/src/cli/index.d.ts"
68
+ "types": "./dist/types/src/cli/index.d.ts",
69
+ "import": "./dist/lib/cli.mjs"
83
70
  },
84
71
  "./testing": {
85
72
  "source": "./src/testing/index.ts",
86
- "browser": "./dist/lib/browser/testing/index.mjs",
87
- "node": "./dist/lib/node-esm/testing/index.mjs",
88
- "types": "./dist/types/src/testing/index.d.ts"
73
+ "types": "./dist/types/src/testing/index.d.ts",
74
+ "import": "./dist/lib/testing.mjs"
89
75
  },
90
76
  "./testing-react": {
91
77
  "source": "./src/testing/react.tsx",
92
- "browser": "./dist/lib/browser/testing/react.mjs",
93
- "node": "./dist/lib/node-esm/testing/react.mjs",
94
- "types": "./dist/types/src/testing/react.d.ts"
78
+ "types": "./dist/types/src/testing/react.d.ts",
79
+ "import": "./dist/lib/testing/react.mjs"
95
80
  },
96
81
  "./ui": {
97
82
  "source": "./src/ui/index.ts",
98
- "browser": "./dist/lib/browser/ui/index.mjs",
99
- "node": "./dist/lib/node-esm/ui/index.mjs",
100
- "types": "./dist/types/src/ui/index.d.ts"
83
+ "types": "./dist/types/src/ui/index.d.ts",
84
+ "import": "./dist/lib/ui.mjs"
101
85
  }
102
86
  },
103
87
  "types": "dist/types/src/index.d.ts",
@@ -112,27 +96,28 @@
112
96
  "esbuild": "0.28.1",
113
97
  "idb-keyval": "^6.2.1",
114
98
  "solid-js": "^1.9.11",
115
- "@dxos/async": "0.10.0",
116
- "@dxos/compute-runtime": "0.10.0",
117
- "@dxos/debug": "0.10.0",
118
- "@dxos/effect": "0.10.0",
119
- "@dxos/edge-client": "0.10.0",
120
- "@dxos/errors": "0.10.0",
121
- "@dxos/keys": "0.10.0",
122
- "@dxos/log": "0.10.0",
123
- "@dxos/invariant": "0.10.0",
124
- "@dxos/operation": "0.10.0",
125
- "@dxos/protocols": "0.10.0",
126
- "@dxos/react-error-boundary": "0.10.0",
127
- "@dxos/react-hooks": "0.10.0",
128
- "@dxos/react-ui": "0.10.0",
129
- "@dxos/react-ui-list": "0.10.0",
130
- "@dxos/ui-theme": "0.10.0",
131
- "@dxos/util": "0.10.0",
132
- "@dxos/web-context": "0.10.0",
133
- "@dxos/web-context-react": "0.10.0",
134
- "@dxos/compute": "0.10.0",
135
- "@dxos/context": "0.10.0"
99
+ "@dxos/async": "0.11.0",
100
+ "@dxos/compute": "0.11.0",
101
+ "@dxos/compute-runtime": "0.11.0",
102
+ "@dxos/context": "0.11.0",
103
+ "@dxos/debug": "0.11.0",
104
+ "@dxos/edge-client": "0.11.0",
105
+ "@dxos/effect": "0.11.0",
106
+ "@dxos/errors": "0.11.0",
107
+ "@dxos/invariant": "0.11.0",
108
+ "@dxos/keys": "0.11.0",
109
+ "@dxos/log": "0.11.0",
110
+ "@dxos/operation": "0.11.0",
111
+ "@dxos/protocols": "0.11.0",
112
+ "@dxos/react-error-boundary": "0.11.0",
113
+ "@dxos/react-hooks": "0.11.0",
114
+ "@dxos/react-ui": "0.11.0",
115
+ "@dxos/react-ui-list": "0.11.0",
116
+ "@dxos/storybook-addon-logger": "0.11.0",
117
+ "@dxos/ui-theme": "0.11.0",
118
+ "@dxos/util": "0.11.0",
119
+ "@dxos/web-context": "0.11.0",
120
+ "@dxos/web-context-react": "0.11.0"
136
121
  },
137
122
  "devDependencies": {
138
123
  "@effect-atom/atom-react": "^0.5.0",
@@ -144,13 +129,13 @@
144
129
  "react": "~19.2.7",
145
130
  "react-dom": "~19.2.7",
146
131
  "typedoc": "0.28.1",
147
- "vite": "^8.0.16",
132
+ "vite": "^8.1.4",
148
133
  "vite-plugin-solid": "^2.11.12",
149
- "@dxos/brand": "0.10.0",
150
- "@dxos/echo-client": "0.10.0",
151
- "@dxos/storybook-utils": "0.10.0",
152
- "@dxos/test-utils": "0.10.0",
153
- "@dxos/random": "0.10.0"
134
+ "@dxos/brand": "0.11.0",
135
+ "@dxos/echo-client": "0.11.0",
136
+ "@dxos/random": "0.11.0",
137
+ "@dxos/storybook-utils": "0.11.0",
138
+ "@dxos/test-utils": "0.11.0"
154
139
  },
155
140
  "peerDependencies": {
156
141
  "@effect-atom/atom-react": "^0.5.0",
@@ -0,0 +1,41 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import * as Role from './Role';
8
+
9
+ describe('Role.make', () => {
10
+ test('creates a role token with the given NSID', ({ expect }) => {
11
+ const token = Role.make<{ subject: string }>('org.dxos.test.role.testRole');
12
+ expect(token.role).toBe('org.dxos.test.role.testRole');
13
+ });
14
+
15
+ test('tokens with the same role are independent objects (identity-by-role)', ({ expect }) => {
16
+ const tokenOne = Role.make<{ x: number }>('org.dxos.test.role.shared');
17
+ const tokenTwo = Role.make<{ x: number }>('org.dxos.test.role.shared');
18
+ expect(tokenOne).not.toBe(tokenTwo);
19
+ expect(tokenOne.role).toBe(tokenTwo.role);
20
+ });
21
+
22
+ test('throws on invalid NSID at runtime (hyphenated final segment)', ({ expect }) => {
23
+ expect(() => Role.make('org.dxos.test.role.bad-name' as any)).toThrow();
24
+ });
25
+
26
+ test('throws on single-segment NSID', ({ expect }) => {
27
+ expect(() => Role.make('article' as any)).toThrow();
28
+ });
29
+
30
+ test('throws on two-segment NSID (below the three-segment minimum)', ({ expect }) => {
31
+ expect(() => Role.make('org.article' as any)).toThrow();
32
+ });
33
+ });
34
+
35
+ describe('role token typing', () => {
36
+ test('make preserves TData through token use-sites', ({ expect }) => {
37
+ // Type-level smoke test: if TS compiles, we're fine.
38
+ const token: Role.Role<{ subject: number }> = Role.make('org.dxos.test.role.numeric');
39
+ expect(token.role).toBe('org.dxos.test.role.numeric');
40
+ });
41
+ });
@@ -0,0 +1,54 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ // @import-as-namespace
6
+
7
+ import type { DXN } from '@dxos/keys';
8
+
9
+ /**
10
+ * A typed role token. Carries a role NSID for runtime dispatch plus a phantom
11
+ * data type so consumers using `type={SomeToken}` and providers using
12
+ * `AppSurface.object(SomeToken, ...)` share a single type-level contract.
13
+ *
14
+ * Mint via {@link make}. The `role` field holds the bare NSID (e.g.
15
+ * `org.dxos.role.article`) — the dispatch key, `data-role` attribute value,
16
+ * and what `.role` comparisons inside matched components see.
17
+ */
18
+ export type Role<TData> = {
19
+ readonly role: string;
20
+ /** Covariant phantom; never accessed at runtime. */
21
+ readonly _phantom?: TData;
22
+ };
23
+
24
+ /**
25
+ * Narrow data type carried by a role token.
26
+ */
27
+ export type Data<T> = T extends Role<infer D> ? D : never;
28
+
29
+ /**
30
+ * Mints a typed role token. The NSID is validated at compile time via
31
+ * {@link DXN.Name}: the final segment must be camelCase (no hyphens).
32
+ * Dynamic NSIDs (template-literal / runtime strings) are validated at runtime.
33
+ *
34
+ * Identity is structural; all tokens with the same `role` string are
35
+ * interchangeable at runtime.
36
+ */
37
+ export const make: {
38
+ <TData = unknown, T extends string = string>(
39
+ nsid: [DXN.Name<T>] extends [never] ? `Invalid NSID "${T}": final segment must be camelCase (no hyphens)` : T,
40
+ ): Role<TData>;
41
+ } = <TData>(nsid: string): Role<TData> => {
42
+ // Runtime guard for dynamic NSIDs that bypass the compile-time DXN.Name<T> check.
43
+ if (
44
+ typeof nsid !== 'string' ||
45
+ !/^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z][a-zA-Z0-9]{0,62})$/.test(
46
+ nsid,
47
+ )
48
+ ) {
49
+ throw new Error(
50
+ `Invalid role NSID: "${nsid}". Must be a dotted name with a camelCase final segment (no hyphens in the last segment).`,
51
+ );
52
+ }
53
+ return { role: nsid };
54
+ };
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Atom, type Registry } from '@effect-atom/atom-react';
5
+ import { type Atom, type Registry } from '@effect-atom/atom';
6
6
  import type * as Command$ from '@effect/cli/Command';
7
7
  import * as Effect from 'effect/Effect';
8
8
  import type * as Exit$ from 'effect/Exit';
@@ -20,7 +20,10 @@ import type {
20
20
  ServiceResolver as ServiceResolver$,
21
21
  Trace as Trace$,
22
22
  } from '@dxos/compute';
23
- import type { ProcessManager as ProcessManager$ } from '@dxos/compute-runtime';
23
+ import type {
24
+ ProcessManager as ProcessManager$,
25
+ RemoteTraceMonitor as RemoteTraceMonitor$,
26
+ } from '@dxos/compute-runtime';
24
27
  import { OperationInvoker as OperationInvoker$ } from '@dxos/operation';
25
28
 
26
29
  import { Capability as Capability$, Plugin as Plugin$, type PluginManager as PluginManager$ } from '../core';
@@ -135,6 +138,18 @@ export type TraceSinkFactory = (ctx: TraceSinkFactoryContext) => Trace$.Sink;
135
138
  */
136
139
  export const TraceSink = Capability$.make<TraceSinkFactory>('org.dxos.app-framework.capability.traceSink');
137
140
 
141
+ /**
142
+ * Source of ephemeral trace messages broadcast by remote runtimes over the space swarm (DX-1125).
143
+ * Contributed by a client-aware plugin; the process-manager capability wires the first contribution
144
+ * (or a no-op) into the aggregate {@link ProcessMonitor} so its `subscribeToTraceMessages` surfaces
145
+ * remote progress alongside local.
146
+ *
147
+ * @category Capability
148
+ */
149
+ export const RemoteTraceMonitor = Capability$.make<RemoteTraceMonitor$.Monitor>(
150
+ 'org.dxos.app-framework.capability.remoteTraceMonitor',
151
+ );
152
+
138
153
  /**
139
154
  * Service resolver backing the shared {@link ProcessManagerRuntime}.
140
155
  *
@@ -4,4 +4,5 @@
4
4
 
5
5
  export * as Capabilities from './capabilities';
6
6
  export * as ActivationEvents from './activation-events';
7
+ export * as Role from './Role';
7
8
  export { Label } from './translations';
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Registry } from '@effect-atom/atom-react';
5
+ import { Registry } from '@effect-atom/atom';
6
6
  import { describe, expect, it, onTestFinished } from '@effect/vitest';
7
7
  import * as Effect from 'effect/Effect';
8
8
 
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Atom, type Registry } from '@effect-atom/atom-react';
5
+ import { Atom, type Registry } from '@effect-atom/atom';
6
6
  import * as Deferred from 'effect/Deferred';
7
7
  import * as Effect from 'effect/Effect';
8
8
 
@@ -2,10 +2,12 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Atom } from '@effect-atom/atom-react';
5
+ import { type Atom } from '@effect-atom/atom';
6
6
  import * as Context from 'effect/Context';
7
7
  import * as Effect from 'effect/Effect';
8
8
  import * as Layer from 'effect/Layer';
9
+ import * as Option from 'effect/Option';
10
+ import type * as Scope from 'effect/Scope';
9
11
 
10
12
  import type { DXN } from '@dxos/keys';
11
13
 
@@ -49,6 +51,16 @@ export const get = <T>(interfaceDef: InterfaceDef<T>): Effect.Effect<T, Error, S
49
51
  export const getAll = <T>(interfaceDef: InterfaceDef<T>): Effect.Effect<T[], never, Service> =>
50
52
  Effect.map(Service, (manager) => manager.getAll(interfaceDef));
51
53
 
54
+ /**
55
+ * Get a single capability from the capability manager, if one is contributed.
56
+ * Never fails — use this over {@link get} when the capability's absence (e.g. an optional plugin
57
+ * isn't loaded) is a legitimate case to handle rather than an error.
58
+ * @param interfaceDef The interface definition of the capability.
59
+ * @returns The first capability implementation, or `Option.none()` if none is contributed.
60
+ */
61
+ export const getOption = <T>(interfaceDef: InterfaceDef<T>): Effect.Effect<Option.Option<T>, never, Service> =>
62
+ Effect.map(getAll(interfaceDef), (all) => Option.fromNullable(all[0]));
63
+
52
64
  /**
53
65
  * Wait for a capability to be available.
54
66
  * @param interfaceDef The interface definition of the capability.
@@ -81,6 +93,24 @@ export const atomByModule = <T>(
81
93
  export const asLayer = <T, I>(interfaceDef: InterfaceDef<T>, tag: Context.Tag<I, T>): Layer.Layer<I, never, Service> =>
82
94
  Layer.effect(tag, get(interfaceDef).pipe(Effect.orDie));
83
95
 
96
+ /**
97
+ * Constructs a layer from a capability by resolving it from the capability manager and passing the
98
+ * value to `build`. Lets a consumer depend on a canonical service (e.g. `Identity.Service`) and
99
+ * have it provided from a capability without the consumer referencing the capability system:
100
+ *
101
+ * ```ts
102
+ * effect.pipe(
103
+ * Effect.provide(Capability.layerWith(ClientCapabilities.IdentityService, (service) =>
104
+ * Layer.succeed(Identity.Service, service),
105
+ * )),
106
+ * );
107
+ * ```
108
+ */
109
+ export const layerWith = <T, A, E, R>(
110
+ interfaceDef: InterfaceDef<T>,
111
+ build: (value: T) => Layer.Layer<A, E, R>,
112
+ ): Layer.Layer<A, E, R | Service> => Layer.unwrapEffect(get(interfaceDef).pipe(Effect.orDie, Effect.map(build)));
113
+
84
114
  const InterfaceDefTypeId: unique symbol = Symbol.for('InterfaceDefTypeId');
85
115
 
86
116
  /**
@@ -159,10 +189,10 @@ export const contributes = <I extends InterfaceDef<any>>(
159
189
  };
160
190
 
161
191
  type LoadCapability<Props, Capabilities extends ModuleReturn = ModuleReturn> = () => Promise<{
162
- default: (props: Props) => Effect.Effect<Capabilities, Error, Service | Plugin.Service | never>;
192
+ default: (props: Props) => Effect.Effect<Capabilities, Error, Service | Plugin.Service | Scope.Scope | never>;
163
193
  }>;
164
194
  type LoadCapabilities<Props, Capabilities extends ModuleReturn = ModuleReturn> = () => Promise<{
165
- default: (props: Props) => Effect.Effect<Capabilities, Error, Service | Plugin.Service | never>;
195
+ default: (props: Props) => Effect.Effect<Capabilities, Error, Service | Plugin.Service | Scope.Scope | never>;
166
196
  }>;
167
197
 
168
198
  type NormalizeReturn<R> = R extends readonly (infer A)[]
@@ -175,7 +205,7 @@ type NormalizeReturn<R> = R extends readonly (infer A)[]
175
205
 
176
206
  export type LazyCapability<Props = void, Capabilities extends ModuleReturn = ModuleReturn, E extends Error = Error> = (
177
207
  props: Props,
178
- ) => Effect.Effect<NormalizeReturn<Capabilities>, E, Service | Plugin.Service | never>;
208
+ ) => Effect.Effect<NormalizeReturn<Capabilities>, E, Service | Plugin.Service | Scope.Scope | never>;
179
209
 
180
210
  /**
181
211
  * Helper to define a lazily loaded implementation of a capability.
@@ -254,6 +284,15 @@ export const getModuleTag = (capability: unknown): string | undefined => {
254
284
  * return contributes(Capabilities.OperationHandler, ...);
255
285
  * })
256
286
  * );
287
+ *
288
+ * // Module with scoped resources (closed automatically on deactivation)
289
+ * export default Capability.makeModule(
290
+ * Effect.fnUntraced(function* () {
291
+ * const scope = yield* Scope.Scope;
292
+ * yield* Scope.addFinalizer(scope, Effect.sync(() => cleanup()));
293
+ * return contributes(Capabilities.MyCapability, implementation);
294
+ * })
295
+ * );
257
296
  * ```
258
297
  */
259
298
  export const makeModule = <
@@ -262,5 +301,5 @@ export const makeModule = <
262
301
  E extends Error = Error,
263
302
  R extends Service | Plugin.Service | never = Service,
264
303
  >(
265
- fn: (props: TProps) => Effect.Effect<TReturn, E, R>,
266
- ): ((props: TProps) => Effect.Effect<TReturn, E, R>) => fn;
304
+ fn: (props: TProps) => Effect.Effect<TReturn, E, R | Scope.Scope>,
305
+ ): ((props: TProps) => Effect.Effect<TReturn, E, R | Scope.Scope>) => fn;
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type Atom, Registry } from '@effect-atom/atom-react';
5
+ import { type Atom, Registry } from '@effect-atom/atom';
6
6
  import { afterEach, assert, describe, it } from '@effect/vitest';
7
7
  import * as Cause from 'effect/Cause';
8
8
  import * as Duration from 'effect/Duration';
@@ -12,6 +12,7 @@ import * as Fiber from 'effect/Fiber';
12
12
  import * as Match from 'effect/Match';
13
13
  import * as PubSub from 'effect/PubSub';
14
14
  import * as Queue from 'effect/Queue';
15
+ import * as Scope from 'effect/Scope';
15
16
  import * as TestClock from 'effect/TestClock';
16
17
 
17
18
  import { invariant } from '@dxos/invariant';
@@ -390,11 +391,10 @@ describe('PluginManager', () => {
390
391
  Plugin.addModule({
391
392
  activatesOn: DefectEvent,
392
393
  id: 'DefectImmediate',
393
- activate: () => {
394
+ activate: (): Effect.Effect<void> => {
394
395
  // This throws immediately before even returning an Effect.
395
396
  // This is the most severe type of defect.
396
397
  throw new Error('immediate throw before Effect');
397
- return Effect.succeed(undefined);
398
398
  },
399
399
  }),
400
400
  Plugin.make,
@@ -1033,6 +1033,41 @@ describe('PluginManager', () => {
1033
1033
  }),
1034
1034
  );
1035
1035
 
1036
+ it.effect('should close module scope during deactivation', () =>
1037
+ Effect.gen(function* () {
1038
+ let scopeClosed = false;
1039
+ const Test = Plugin.define(testMeta).pipe(
1040
+ Plugin.addModule({
1041
+ id: 'WithScope',
1042
+ activatesOn: ActivationEvents.Startup,
1043
+ activate: () =>
1044
+ Effect.gen(function* () {
1045
+ const scope = yield* Scope.Scope;
1046
+ yield* Scope.addFinalizer(
1047
+ scope,
1048
+ Effect.sync(() => {
1049
+ scopeClosed = true;
1050
+ }),
1051
+ );
1052
+ return Capability.contributes(String, { string: 'hello' });
1053
+ }),
1054
+ }),
1055
+ Plugin.make,
1056
+ );
1057
+ const testPlugin = Test();
1058
+ plugins = [testPlugin];
1059
+
1060
+ const manager = PluginManager.make({ pluginLoader });
1061
+ yield* manager.add(testMeta.profile.key);
1062
+ yield* manager.enable(testMeta.profile.key);
1063
+ yield* manager.activate(ActivationEvents.Startup);
1064
+ assert.isFalse(scopeClosed);
1065
+
1066
+ yield* manager.shutdown();
1067
+ assert.isTrue(scopeClosed);
1068
+ }),
1069
+ );
1070
+
1036
1071
  it.effect('should run capability deactivate hooks during shutdown', () =>
1037
1072
  Effect.gen(function* () {
1038
1073
  let deactivated = false;