@dxos/app-framework 0.8.4-main.fffef41 → 0.9.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 (569) hide show
  1. package/.storybook/main.mts +2 -4
  2. package/.storybook/preview.mts +2 -2
  3. package/LICENSE +102 -5
  4. package/README.md +1 -1
  5. package/dist/lib/browser/capability-BOPAKKWG.mjs +35 -0
  6. package/dist/lib/browser/capability-BOPAKKWG.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-5GY3YOEL.mjs +28 -0
  8. package/dist/lib/browser/chunk-5GY3YOEL.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-66IXTIVK.mjs +48 -0
  10. package/dist/lib/browser/chunk-66IXTIVK.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-CO3XLNUX.mjs +95 -0
  12. package/dist/lib/browser/chunk-CO3XLNUX.mjs.map +7 -0
  13. package/dist/lib/browser/chunk-DC3WRPBV.mjs +227 -0
  14. package/dist/lib/browser/chunk-DC3WRPBV.mjs.map +7 -0
  15. package/dist/lib/browser/chunk-FJ4765WW.mjs +8 -0
  16. package/dist/lib/browser/chunk-FJ4765WW.mjs.map +7 -0
  17. package/dist/lib/browser/chunk-FO3IYSLV.mjs +68 -0
  18. package/dist/lib/browser/chunk-FO3IYSLV.mjs.map +7 -0
  19. package/dist/lib/browser/chunk-HFLKXMT7.mjs +587 -0
  20. package/dist/lib/browser/chunk-HFLKXMT7.mjs.map +7 -0
  21. package/dist/lib/browser/chunk-IW44C7UL.mjs +83 -0
  22. package/dist/lib/browser/chunk-IW44C7UL.mjs.map +7 -0
  23. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  24. package/dist/lib/browser/chunk-KZUDO43J.mjs +422 -0
  25. package/dist/lib/browser/chunk-KZUDO43J.mjs.map +7 -0
  26. package/dist/lib/browser/chunk-Q2GLJTVV.mjs +12 -0
  27. package/dist/lib/browser/chunk-Q2GLJTVV.mjs.map +7 -0
  28. package/dist/lib/browser/chunk-SYXIYT6T.mjs +143 -0
  29. package/dist/lib/browser/chunk-SYXIYT6T.mjs.map +7 -0
  30. package/dist/lib/browser/chunk-XHS5KDNX.mjs +1471 -0
  31. package/dist/lib/browser/chunk-XHS5KDNX.mjs.map +7 -0
  32. package/dist/lib/browser/chunk-Y66ELD4U.mjs +476 -0
  33. package/dist/lib/browser/chunk-Y66ELD4U.mjs.map +7 -0
  34. package/dist/lib/browser/cli/index.mjs +74 -0
  35. package/dist/lib/browser/cli/index.mjs.map +7 -0
  36. package/dist/lib/browser/common/activation-events.mjs +20 -0
  37. package/dist/lib/browser/common/capabilities.mjs +56 -0
  38. package/dist/lib/browser/core/activation-event.mjs +20 -0
  39. package/dist/lib/browser/core/capability.mjs +32 -0
  40. package/dist/lib/browser/core/capability.mjs.map +7 -0
  41. package/dist/lib/browser/core/plugin-manager.mjs +19 -0
  42. package/dist/lib/browser/core/plugin-manager.mjs.map +7 -0
  43. package/dist/lib/browser/core/plugin.mjs +41 -0
  44. package/dist/lib/browser/core/plugin.mjs.map +7 -0
  45. package/dist/lib/browser/core/url-loader.mjs +24 -0
  46. package/dist/lib/browser/core/url-loader.mjs.map +7 -0
  47. package/dist/lib/browser/index.mjs +86 -122
  48. package/dist/lib/browser/index.mjs.map +4 -4
  49. package/dist/lib/browser/meta.json +1 -1
  50. package/dist/lib/browser/process-manager-capability-GXNUO7AR.mjs +132 -0
  51. package/dist/lib/browser/process-manager-capability-GXNUO7AR.mjs.map +7 -0
  52. package/dist/lib/browser/testing/index.mjs +316 -47
  53. package/dist/lib/browser/testing/index.mjs.map +4 -4
  54. package/dist/lib/browser/testing/react.mjs +78 -0
  55. package/dist/lib/browser/testing/react.mjs.map +7 -0
  56. package/dist/lib/browser/ui/index.mjs +52 -0
  57. package/dist/lib/browser/ui/index.mjs.map +7 -0
  58. package/dist/lib/node-esm/capability-KZWRTX7R.mjs +36 -0
  59. package/dist/lib/node-esm/capability-KZWRTX7R.mjs.map +7 -0
  60. package/dist/lib/node-esm/chunk-37Z53PXZ.mjs +10 -0
  61. package/dist/lib/node-esm/chunk-37Z53PXZ.mjs.map +7 -0
  62. package/dist/lib/node-esm/chunk-A5CHGAZE.mjs +588 -0
  63. package/dist/lib/node-esm/chunk-A5CHGAZE.mjs.map +7 -0
  64. package/dist/lib/node-esm/chunk-COHOWGGJ.mjs +144 -0
  65. package/dist/lib/node-esm/chunk-COHOWGGJ.mjs.map +7 -0
  66. package/dist/lib/node-esm/chunk-CTKEZHKF.mjs +84 -0
  67. package/dist/lib/node-esm/chunk-CTKEZHKF.mjs.map +7 -0
  68. package/dist/lib/node-esm/chunk-FPW45EZH.mjs +14 -0
  69. package/dist/lib/node-esm/chunk-FPW45EZH.mjs.map +7 -0
  70. package/dist/lib/node-esm/chunk-FSVGKTF6.mjs +477 -0
  71. package/dist/lib/node-esm/chunk-FSVGKTF6.mjs.map +7 -0
  72. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  73. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  74. package/dist/lib/node-esm/chunk-KFZEB6BV.mjs +29 -0
  75. package/dist/lib/node-esm/chunk-KFZEB6BV.mjs.map +7 -0
  76. package/dist/lib/node-esm/chunk-NULBHQYS.mjs +96 -0
  77. package/dist/lib/node-esm/chunk-NULBHQYS.mjs.map +7 -0
  78. package/dist/lib/node-esm/chunk-SX5NVETP.mjs +1472 -0
  79. package/dist/lib/node-esm/chunk-SX5NVETP.mjs.map +7 -0
  80. package/dist/lib/node-esm/chunk-WK7OIQKI.mjs +70 -0
  81. package/dist/lib/node-esm/chunk-WK7OIQKI.mjs.map +7 -0
  82. package/dist/lib/node-esm/chunk-XGBUKRCK.mjs +423 -0
  83. package/dist/lib/node-esm/chunk-XGBUKRCK.mjs.map +7 -0
  84. package/dist/lib/node-esm/chunk-XIGPWXCQ.mjs +228 -0
  85. package/dist/lib/node-esm/chunk-XIGPWXCQ.mjs.map +7 -0
  86. package/dist/lib/node-esm/chunk-XOCUANHO.mjs +49 -0
  87. package/dist/lib/node-esm/chunk-XOCUANHO.mjs.map +7 -0
  88. package/dist/lib/node-esm/cli/index.mjs +75 -0
  89. package/dist/lib/node-esm/cli/index.mjs.map +7 -0
  90. package/dist/lib/node-esm/common/activation-events.mjs +21 -0
  91. package/dist/lib/node-esm/common/activation-events.mjs.map +7 -0
  92. package/dist/lib/node-esm/common/capabilities.mjs +57 -0
  93. package/dist/lib/node-esm/common/capabilities.mjs.map +7 -0
  94. package/dist/lib/node-esm/core/activation-event.mjs +21 -0
  95. package/dist/lib/node-esm/core/activation-event.mjs.map +7 -0
  96. package/dist/lib/node-esm/core/capability.mjs +33 -0
  97. package/dist/lib/node-esm/core/capability.mjs.map +7 -0
  98. package/dist/lib/node-esm/core/plugin-manager.mjs +20 -0
  99. package/dist/lib/node-esm/core/plugin-manager.mjs.map +7 -0
  100. package/dist/lib/node-esm/core/plugin.mjs +42 -0
  101. package/dist/lib/node-esm/core/plugin.mjs.map +7 -0
  102. package/dist/lib/node-esm/core/url-loader.mjs +25 -0
  103. package/dist/lib/node-esm/core/url-loader.mjs.map +7 -0
  104. package/dist/lib/node-esm/index.mjs +86 -122
  105. package/dist/lib/node-esm/index.mjs.map +4 -4
  106. package/dist/lib/node-esm/meta.json +1 -1
  107. package/dist/lib/node-esm/process-manager-capability-TX5TA6YN.mjs +133 -0
  108. package/dist/lib/node-esm/process-manager-capability-TX5TA6YN.mjs.map +7 -0
  109. package/dist/lib/node-esm/testing/index.mjs +316 -47
  110. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  111. package/dist/lib/node-esm/testing/react.mjs +79 -0
  112. package/dist/lib/node-esm/testing/react.mjs.map +7 -0
  113. package/dist/lib/node-esm/ui/index.mjs +53 -0
  114. package/dist/lib/node-esm/ui/index.mjs.map +7 -0
  115. package/dist/plugin/node-esm/index.mjs +977 -0
  116. package/dist/plugin/node-esm/index.mjs.map +7 -0
  117. package/dist/plugin/node-esm/meta.json +1 -0
  118. package/dist/types/src/cli/cli.d.ts +37 -0
  119. package/dist/types/src/cli/cli.d.ts.map +1 -0
  120. package/dist/types/src/cli/index.d.ts +2 -0
  121. package/dist/types/src/cli/index.d.ts.map +1 -0
  122. package/dist/types/src/common/activation-events.d.ts +24 -0
  123. package/dist/types/src/common/activation-events.d.ts.map +1 -0
  124. package/dist/types/src/common/annotations.d.ts +1 -0
  125. package/dist/types/src/common/annotations.d.ts.map +1 -0
  126. package/dist/types/src/common/capabilities.d.ts +214 -193
  127. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  128. package/dist/types/src/common/index.d.ts +3 -8
  129. package/dist/types/src/common/index.d.ts.map +1 -1
  130. package/dist/types/src/common/translations.d.ts +7 -7
  131. package/dist/types/src/common/translations.d.ts.map +1 -1
  132. package/dist/types/src/context.d.ts +5 -0
  133. package/dist/types/src/context.d.ts.map +1 -0
  134. package/dist/types/src/core/{events.d.ts → activation-event.d.ts} +11 -11
  135. package/dist/types/src/core/activation-event.d.ts.map +1 -0
  136. package/dist/types/src/core/capability-manager.d.ts +52 -0
  137. package/dist/types/src/core/capability-manager.d.ts.map +1 -0
  138. package/dist/types/src/core/capability-manager.test.d.ts +2 -0
  139. package/dist/types/src/core/capability-manager.test.d.ts.map +1 -0
  140. package/dist/types/src/core/capability.d.ts +161 -0
  141. package/dist/types/src/core/capability.d.ts.map +1 -0
  142. package/dist/types/src/core/edge-registry-plugin-provider.d.ts +30 -0
  143. package/dist/types/src/core/edge-registry-plugin-provider.d.ts.map +1 -0
  144. package/dist/types/src/core/index.d.ts +11 -4
  145. package/dist/types/src/core/index.d.ts.map +1 -1
  146. package/dist/types/src/core/plugin-asset-cache.d.ts +71 -0
  147. package/dist/types/src/core/plugin-asset-cache.d.ts.map +1 -0
  148. package/dist/types/src/core/plugin-manager.d.ts +297 -0
  149. package/dist/types/src/core/plugin-manager.d.ts.map +1 -0
  150. package/dist/types/src/core/plugin-manager.test.d.ts +2 -0
  151. package/dist/types/src/core/plugin-manager.test.d.ts.map +1 -0
  152. package/dist/types/src/core/plugin-manifest.d.ts +101 -0
  153. package/dist/types/src/core/plugin-manifest.d.ts.map +1 -0
  154. package/dist/types/src/core/plugin-manifest.test.d.ts +2 -0
  155. package/dist/types/src/core/plugin-manifest.test.d.ts.map +1 -0
  156. package/dist/types/src/core/plugin.d.ts +303 -43
  157. package/dist/types/src/core/plugin.d.ts.map +1 -1
  158. package/dist/types/src/core/registry.d.ts +107 -0
  159. package/dist/types/src/core/registry.d.ts.map +1 -0
  160. package/dist/types/src/core/url-loader.d.ts +127 -0
  161. package/dist/types/src/core/url-loader.d.ts.map +1 -0
  162. package/dist/types/src/core/url-loader.test.d.ts +2 -0
  163. package/dist/types/src/core/url-loader.test.d.ts.map +1 -0
  164. package/dist/types/src/helpers.d.ts.map +1 -1
  165. package/dist/types/src/index.d.ts +2 -2
  166. package/dist/types/src/index.d.ts.map +1 -1
  167. package/dist/types/src/plugin-process-manager/ProcessManagerPlugin.d.ts +3 -0
  168. package/dist/types/src/plugin-process-manager/ProcessManagerPlugin.d.ts.map +1 -0
  169. package/dist/types/src/plugin-process-manager/history/capability.d.ts +7 -0
  170. package/dist/types/src/plugin-process-manager/history/capability.d.ts.map +1 -0
  171. package/dist/types/src/plugin-process-manager/history/errors.d.ts +32 -0
  172. package/dist/types/src/plugin-process-manager/history/errors.d.ts.map +1 -0
  173. package/dist/types/src/plugin-process-manager/history/history-tracker.d.ts +32 -0
  174. package/dist/types/src/plugin-process-manager/history/history-tracker.d.ts.map +1 -0
  175. package/dist/types/src/plugin-process-manager/history/history-tracker.test.d.ts +2 -0
  176. package/dist/types/src/plugin-process-manager/history/history-tracker.test.d.ts.map +1 -0
  177. package/dist/types/src/plugin-process-manager/history/index.d.ts +6 -0
  178. package/dist/types/src/plugin-process-manager/history/index.d.ts.map +1 -0
  179. package/dist/types/src/plugin-process-manager/history/types.d.ts +13 -0
  180. package/dist/types/src/plugin-process-manager/history/types.d.ts.map +1 -0
  181. package/dist/types/src/plugin-process-manager/history/undo-mapping.d.ts +101 -0
  182. package/dist/types/src/plugin-process-manager/history/undo-mapping.d.ts.map +1 -0
  183. package/dist/types/src/plugin-process-manager/history/undo-registry.d.ts +23 -0
  184. package/dist/types/src/plugin-process-manager/history/undo-registry.d.ts.map +1 -0
  185. package/dist/types/src/plugin-process-manager/history/undo-registry.test.d.ts +2 -0
  186. package/dist/types/src/plugin-process-manager/history/undo-registry.test.d.ts.map +1 -0
  187. package/dist/types/src/plugin-process-manager/idb-key-value-store.d.ts +10 -0
  188. package/dist/types/src/plugin-process-manager/idb-key-value-store.d.ts.map +1 -0
  189. package/dist/types/src/plugin-process-manager/index.d.ts +3 -0
  190. package/dist/types/src/plugin-process-manager/index.d.ts.map +1 -0
  191. package/dist/types/src/plugin-process-manager/meta.d.ts +3 -0
  192. package/dist/types/src/plugin-process-manager/meta.d.ts.map +1 -0
  193. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts +8 -0
  194. package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts.map +1 -0
  195. package/dist/types/src/plugin-process-manager/testing.d.ts +59 -0
  196. package/dist/types/src/plugin-process-manager/testing.d.ts.map +1 -0
  197. package/dist/types/src/testing/harness.d.ts +79 -0
  198. package/dist/types/src/testing/harness.d.ts.map +1 -0
  199. package/dist/types/src/testing/index.d.ts +3 -0
  200. package/dist/types/src/testing/index.d.ts.map +1 -1
  201. package/dist/types/src/testing/operationCapture.d.ts +64 -0
  202. package/dist/types/src/testing/operationCapture.d.ts.map +1 -0
  203. package/dist/types/src/testing/react.d.ts +27 -0
  204. package/dist/types/src/testing/react.d.ts.map +1 -0
  205. package/dist/types/src/testing/react.test.d.ts +2 -0
  206. package/dist/types/src/testing/react.test.d.ts.map +1 -0
  207. package/dist/types/src/testing/service.d.ts +8 -0
  208. package/dist/types/src/testing/service.d.ts.map +1 -0
  209. package/dist/types/src/testing/withPluginManager.d.ts +4 -4
  210. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  211. package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
  212. package/dist/types/src/ui/components/App/App.d.ts +41 -0
  213. package/dist/types/src/ui/components/App/App.d.ts.map +1 -0
  214. package/dist/types/src/ui/components/App/App.stories.d.ts +19 -0
  215. package/dist/types/src/ui/components/App/App.stories.d.ts.map +1 -0
  216. package/dist/types/src/ui/components/App/index.d.ts +2 -0
  217. package/dist/types/src/ui/components/App/index.d.ts.map +1 -0
  218. package/dist/types/src/{react/Surface.stories.d.ts → ui/components/PluginManager/PluginManagerContext.stories.d.ts} +2 -3
  219. package/dist/types/src/ui/components/PluginManager/PluginManagerContext.stories.d.ts.map +1 -0
  220. package/dist/types/src/ui/components/PluginManager/PluginManagerProvider.d.ts +10 -0
  221. package/dist/types/src/ui/components/PluginManager/PluginManagerProvider.d.ts.map +1 -0
  222. package/dist/types/src/ui/components/PluginManager/index.d.ts +2 -0
  223. package/dist/types/src/ui/components/PluginManager/index.d.ts.map +1 -0
  224. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts +24 -0
  225. package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts.map +1 -0
  226. package/dist/types/src/{react/App.stories.d.ts → ui/components/Surface/SurfaceComponent.stories.d.ts} +1 -1
  227. package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts.map +1 -0
  228. package/dist/types/src/ui/components/Surface/SurfaceInfo.d.ts +11 -0
  229. package/dist/types/src/ui/components/Surface/SurfaceInfo.d.ts.map +1 -0
  230. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts +48 -0
  231. package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts.map +1 -0
  232. package/dist/types/src/ui/components/Surface/context.d.ts +5 -0
  233. package/dist/types/src/ui/components/Surface/context.d.ts.map +1 -0
  234. package/dist/types/src/ui/components/Surface/index.d.ts +36 -0
  235. package/dist/types/src/ui/components/Surface/index.d.ts.map +1 -0
  236. package/dist/types/src/ui/components/Surface/types.d.ts +197 -0
  237. package/dist/types/src/ui/components/Surface/types.d.ts.map +1 -0
  238. package/dist/types/src/ui/components/Surface/types.test.d.ts +2 -0
  239. package/dist/types/src/ui/components/Surface/types.test.d.ts.map +1 -0
  240. package/dist/types/src/ui/components/index.d.ts +4 -0
  241. package/dist/types/src/ui/components/index.d.ts.map +1 -0
  242. package/dist/types/src/ui/hooks/index.d.ts +7 -0
  243. package/dist/types/src/ui/hooks/index.d.ts.map +1 -0
  244. package/dist/types/src/ui/hooks/useApp.d.ts +80 -0
  245. package/dist/types/src/ui/hooks/useApp.d.ts.map +1 -0
  246. package/dist/types/src/ui/hooks/useApp.test.d.ts +2 -0
  247. package/dist/types/src/ui/hooks/useApp.test.d.ts.map +1 -0
  248. package/dist/types/src/ui/hooks/useCapabilities.d.ts +31 -0
  249. package/dist/types/src/ui/hooks/useCapabilities.d.ts.map +1 -0
  250. package/dist/types/src/{react → ui/hooks}/useLoading.d.ts +1 -2
  251. package/dist/types/src/ui/hooks/useLoading.d.ts.map +1 -0
  252. package/dist/types/src/ui/hooks/useProcessManagerRuntime.d.ts +30 -0
  253. package/dist/types/src/ui/hooks/useProcessManagerRuntime.d.ts.map +1 -0
  254. package/dist/types/src/ui/hooks/useSettingsState.d.ts +10 -0
  255. package/dist/types/src/ui/hooks/useSettingsState.d.ts.map +1 -0
  256. package/dist/types/src/ui/hooks/useSurface.d.ts +3 -0
  257. package/dist/types/src/ui/hooks/useSurface.d.ts.map +1 -0
  258. package/dist/types/src/ui/index.d.ts +3 -0
  259. package/dist/types/src/ui/index.d.ts.map +1 -0
  260. package/dist/types/src/vite-plugin/boot-loader/index.d.ts +2 -0
  261. package/dist/types/src/vite-plugin/boot-loader/index.d.ts.map +1 -0
  262. package/dist/types/src/vite-plugin/boot-loader/loader.d.ts +59 -0
  263. package/dist/types/src/vite-plugin/boot-loader/loader.d.ts.map +1 -0
  264. package/dist/types/src/vite-plugin/composer/index.d.ts +34 -0
  265. package/dist/types/src/vite-plugin/composer/index.d.ts.map +1 -0
  266. package/dist/types/src/vite-plugin/import-map/index.d.ts +28 -0
  267. package/dist/types/src/vite-plugin/import-map/index.d.ts.map +1 -0
  268. package/dist/types/src/vite-plugin/index.d.ts +5 -0
  269. package/dist/types/src/vite-plugin/index.d.ts.map +1 -0
  270. package/dist/types/src/vite-plugin/manifest.d.ts +41 -0
  271. package/dist/types/src/vite-plugin/manifest.d.ts.map +1 -0
  272. package/dist/types/src/vite-plugin/manifest.test.d.ts +2 -0
  273. package/dist/types/src/vite-plugin/manifest.test.d.ts.map +1 -0
  274. package/dist/types/src/vite-plugin/packages.d.ts +13 -0
  275. package/dist/types/src/vite-plugin/packages.d.ts.map +1 -0
  276. package/dist/types/tsconfig.tsbuildinfo +1 -1
  277. package/moon.yml +25 -6
  278. package/package.json +125 -59
  279. package/src/cli/cli.ts +102 -0
  280. package/src/{playground/debug → cli}/index.ts +1 -1
  281. package/src/common/activation-events.ts +39 -0
  282. package/src/{playground/logger/index.ts → common/annotations.ts} +0 -2
  283. package/src/common/capabilities.ts +287 -192
  284. package/src/common/index.ts +3 -8
  285. package/src/common/translations.ts +17 -9
  286. package/src/context.ts +9 -0
  287. package/src/core/{events.ts → activation-event.ts} +10 -7
  288. package/src/core/capability-manager.test.ts +154 -0
  289. package/src/core/capability-manager.ts +213 -0
  290. package/src/core/capability.ts +254 -0
  291. package/src/core/edge-registry-plugin-provider.ts +92 -0
  292. package/src/core/index.ts +11 -4
  293. package/src/core/plugin-asset-cache.ts +60 -0
  294. package/src/core/plugin-manager.test.ts +1929 -0
  295. package/src/core/plugin-manager.ts +1696 -0
  296. package/src/core/plugin-manifest.test.ts +75 -0
  297. package/src/core/plugin-manifest.ts +134 -0
  298. package/src/core/plugin.ts +449 -48
  299. package/src/core/registry.ts +163 -0
  300. package/src/core/url-loader.test.ts +222 -0
  301. package/src/core/url-loader.ts +388 -0
  302. package/src/index.ts +2 -2
  303. package/src/plugin-process-manager/ProcessManagerPlugin.ts +24 -0
  304. package/src/plugin-process-manager/history/capability.ts +36 -0
  305. package/src/plugin-process-manager/history/errors.ts +7 -0
  306. package/src/plugin-process-manager/history/history-tracker.test.ts +353 -0
  307. package/src/plugin-process-manager/history/history-tracker.ts +144 -0
  308. package/src/plugin-process-manager/history/index.ts +9 -0
  309. package/src/plugin-process-manager/history/types.ts +17 -0
  310. package/src/plugin-process-manager/history/undo-mapping.ts +135 -0
  311. package/src/plugin-process-manager/history/undo-registry.test.ts +74 -0
  312. package/src/plugin-process-manager/history/undo-registry.ts +54 -0
  313. package/src/plugin-process-manager/idb-key-value-store.ts +64 -0
  314. package/src/plugin-process-manager/index.ts +6 -0
  315. package/src/plugin-process-manager/meta.ts +16 -0
  316. package/src/plugin-process-manager/process-manager-capability.ts +178 -0
  317. package/src/plugin-process-manager/testing.ts +156 -0
  318. package/src/testing/harness.ts +247 -0
  319. package/src/testing/index.ts +3 -0
  320. package/src/testing/operationCapture.ts +144 -0
  321. package/src/testing/react.test.tsx +50 -0
  322. package/src/testing/react.tsx +113 -0
  323. package/src/testing/service.ts +52 -0
  324. package/src/testing/withPluginManager.stories.tsx +8 -9
  325. package/src/testing/withPluginManager.tsx +69 -42
  326. package/src/ui/components/App/App.stories.tsx +84 -0
  327. package/src/ui/components/App/App.tsx +144 -0
  328. package/src/{playground/layout → ui/components/App}/index.ts +1 -1
  329. package/src/ui/components/PluginManager/PluginManagerContext.stories.tsx +179 -0
  330. package/src/{react → ui/components/PluginManager}/PluginManagerProvider.ts +3 -3
  331. package/src/ui/components/PluginManager/index.ts +5 -0
  332. package/src/ui/components/Surface/SurfaceComponent.stories.tsx +144 -0
  333. package/src/ui/components/Surface/SurfaceComponent.tsx +303 -0
  334. package/src/ui/components/Surface/SurfaceInfo.tsx +106 -0
  335. package/src/ui/components/Surface/SurfaceProfilerContext.tsx +207 -0
  336. package/src/ui/components/Surface/context.ts +12 -0
  337. package/src/ui/components/Surface/index.ts +54 -0
  338. package/src/ui/components/Surface/types.test.ts +126 -0
  339. package/src/ui/components/Surface/types.ts +290 -0
  340. package/src/ui/components/index.ts +7 -0
  341. package/src/ui/hooks/index.ts +10 -0
  342. package/src/ui/hooks/useApp.test.tsx +161 -0
  343. package/src/ui/hooks/useApp.tsx +404 -0
  344. package/src/ui/hooks/useCapabilities.ts +68 -0
  345. package/src/{react → ui/hooks}/useLoading.tsx +16 -10
  346. package/src/ui/hooks/useProcessManagerRuntime.ts +78 -0
  347. package/src/ui/hooks/useSettingsState.ts +26 -0
  348. package/src/ui/hooks/useSurface.ts +13 -0
  349. package/src/ui/index.ts +6 -0
  350. package/src/vite-plugin/boot-loader/BootLoader.solid-stories.tsx +198 -0
  351. package/src/vite-plugin/boot-loader/index.ts +5 -0
  352. package/src/vite-plugin/boot-loader/loader-app/Loader.tsx +166 -0
  353. package/src/vite-plugin/boot-loader/loader-app/boot-loader.css +311 -0
  354. package/src/vite-plugin/boot-loader/loader-app/bridge.ts +25 -0
  355. package/src/vite-plugin/boot-loader/loader-app/entry.tsx +21 -0
  356. package/src/vite-plugin/boot-loader/loader-app/mount.tsx +70 -0
  357. package/src/vite-plugin/boot-loader/loader-app/store.test.ts +137 -0
  358. package/src/vite-plugin/boot-loader/loader-app/store.ts +149 -0
  359. package/src/vite-plugin/boot-loader/loader-app/tsconfig.json +11 -0
  360. package/src/vite-plugin/boot-loader/loader-app/types.ts +78 -0
  361. package/src/vite-plugin/boot-loader/loader.ts +204 -0
  362. package/src/vite-plugin/composer/index.ts +306 -0
  363. package/src/vite-plugin/import-map/index.ts +527 -0
  364. package/src/vite-plugin/index.ts +10 -0
  365. package/src/vite-plugin/manifest.test.ts +55 -0
  366. package/src/vite-plugin/manifest.ts +63 -0
  367. package/src/vite-plugin/packages.ts +187 -0
  368. package/tsconfig.json +27 -22
  369. package/tsconfig.node.json +2 -4
  370. package/typedoc.json +2 -4
  371. package/vitest.config.ts +1 -1
  372. package/.swc/plugins/linux_x86_64_19.0.0/727453fb3a62f7f1d952a41e051ca8a6f88cadc45cee43c6a4d1aa45f9b75665.wasmer-v7 +0 -0
  373. package/.swc/plugins/linux_x86_64_19.0.0/fce1bdb8e20a094e4af08bad09cc81497ed0e2e7c51223b07d371063cca18429.wasmer-v7 +0 -0
  374. package/dist/lib/browser/app-graph-builder-OIEZZC45.mjs +0 -138
  375. package/dist/lib/browser/app-graph-builder-OIEZZC45.mjs.map +0 -7
  376. package/dist/lib/browser/chunk-6XKO24JP.mjs +0 -483
  377. package/dist/lib/browser/chunk-6XKO24JP.mjs.map +0 -7
  378. package/dist/lib/browser/chunk-SCPE4ZO2.mjs +0 -35
  379. package/dist/lib/browser/chunk-SCPE4ZO2.mjs.map +0 -7
  380. package/dist/lib/browser/chunk-WPW5VVAX.mjs +0 -1651
  381. package/dist/lib/browser/chunk-WPW5VVAX.mjs.map +0 -7
  382. package/dist/lib/browser/intent-dispatcher-LZ4AE66E.mjs +0 -11
  383. package/dist/lib/browser/intent-resolver-QVCKRX6G.mjs +0 -39
  384. package/dist/lib/browser/intent-resolver-QVCKRX6G.mjs.map +0 -7
  385. package/dist/lib/browser/react/index.mjs +0 -34
  386. package/dist/lib/browser/store-CNPHOYTJ.mjs +0 -30
  387. package/dist/lib/browser/store-CNPHOYTJ.mjs.map +0 -7
  388. package/dist/lib/node-esm/app-graph-builder-EBU4NVWD.mjs +0 -139
  389. package/dist/lib/node-esm/app-graph-builder-EBU4NVWD.mjs.map +0 -7
  390. package/dist/lib/node-esm/chunk-3UPX5OIS.mjs +0 -484
  391. package/dist/lib/node-esm/chunk-3UPX5OIS.mjs.map +0 -7
  392. package/dist/lib/node-esm/chunk-XJZGUJ3H.mjs +0 -1653
  393. package/dist/lib/node-esm/chunk-XJZGUJ3H.mjs.map +0 -7
  394. package/dist/lib/node-esm/chunk-ZX63QUGE.mjs +0 -37
  395. package/dist/lib/node-esm/chunk-ZX63QUGE.mjs.map +0 -7
  396. package/dist/lib/node-esm/intent-dispatcher-MGOJ3CHD.mjs +0 -12
  397. package/dist/lib/node-esm/intent-resolver-URF3HN3G.mjs +0 -40
  398. package/dist/lib/node-esm/intent-resolver-URF3HN3G.mjs.map +0 -7
  399. package/dist/lib/node-esm/react/index.mjs +0 -35
  400. package/dist/lib/node-esm/store-RK5B4XEL.mjs +0 -31
  401. package/dist/lib/node-esm/store-RK5B4XEL.mjs.map +0 -7
  402. package/dist/types/src/common/collaboration.d.ts +0 -20
  403. package/dist/types/src/common/collaboration.d.ts.map +0 -1
  404. package/dist/types/src/common/events.d.ts +0 -52
  405. package/dist/types/src/common/events.d.ts.map +0 -1
  406. package/dist/types/src/common/file.d.ts +0 -14
  407. package/dist/types/src/common/file.d.ts.map +0 -1
  408. package/dist/types/src/common/graph.d.ts +0 -21
  409. package/dist/types/src/common/graph.d.ts.map +0 -1
  410. package/dist/types/src/common/layout.d.ts +0 -279
  411. package/dist/types/src/common/layout.d.ts.map +0 -1
  412. package/dist/types/src/common/surface.d.ts +0 -68
  413. package/dist/types/src/common/surface.d.ts.map +0 -1
  414. package/dist/types/src/core/capabilities.d.ts +0 -117
  415. package/dist/types/src/core/capabilities.d.ts.map +0 -1
  416. package/dist/types/src/core/capabilities.test.d.ts +0 -2
  417. package/dist/types/src/core/capabilities.test.d.ts.map +0 -1
  418. package/dist/types/src/core/events.d.ts.map +0 -1
  419. package/dist/types/src/core/manager.d.ts +0 -126
  420. package/dist/types/src/core/manager.d.ts.map +0 -1
  421. package/dist/types/src/core/manager.test.d.ts +0 -2
  422. package/dist/types/src/core/manager.test.d.ts.map +0 -1
  423. package/dist/types/src/playground/debug/Debug.d.ts +0 -6
  424. package/dist/types/src/playground/debug/Debug.d.ts.map +0 -1
  425. package/dist/types/src/playground/debug/index.d.ts +0 -2
  426. package/dist/types/src/playground/debug/index.d.ts.map +0 -1
  427. package/dist/types/src/playground/debug/plugin.d.ts +0 -2
  428. package/dist/types/src/playground/debug/plugin.d.ts.map +0 -1
  429. package/dist/types/src/playground/generator/Main.d.ts +0 -6
  430. package/dist/types/src/playground/generator/Main.d.ts.map +0 -1
  431. package/dist/types/src/playground/generator/Toolbar.d.ts +0 -6
  432. package/dist/types/src/playground/generator/Toolbar.d.ts.map +0 -1
  433. package/dist/types/src/playground/generator/generator.d.ts +0 -7
  434. package/dist/types/src/playground/generator/generator.d.ts.map +0 -1
  435. package/dist/types/src/playground/generator/index.d.ts +0 -3
  436. package/dist/types/src/playground/generator/index.d.ts.map +0 -1
  437. package/dist/types/src/playground/generator/plugin.d.ts +0 -2
  438. package/dist/types/src/playground/generator/plugin.d.ts.map +0 -1
  439. package/dist/types/src/playground/layout/Layout.d.ts +0 -8
  440. package/dist/types/src/playground/layout/Layout.d.ts.map +0 -1
  441. package/dist/types/src/playground/layout/index.d.ts +0 -2
  442. package/dist/types/src/playground/layout/index.d.ts.map +0 -1
  443. package/dist/types/src/playground/layout/plugin.d.ts +0 -2
  444. package/dist/types/src/playground/layout/plugin.d.ts.map +0 -1
  445. package/dist/types/src/playground/logger/Toolbar.d.ts +0 -6
  446. package/dist/types/src/playground/logger/Toolbar.d.ts.map +0 -1
  447. package/dist/types/src/playground/logger/index.d.ts +0 -2
  448. package/dist/types/src/playground/logger/index.d.ts.map +0 -1
  449. package/dist/types/src/playground/logger/plugin.d.ts +0 -2
  450. package/dist/types/src/playground/logger/plugin.d.ts.map +0 -1
  451. package/dist/types/src/playground/logger/schema.d.ts +0 -13
  452. package/dist/types/src/playground/logger/schema.d.ts.map +0 -1
  453. package/dist/types/src/playground/playground.stories.d.ts +0 -11
  454. package/dist/types/src/playground/playground.stories.d.ts.map +0 -1
  455. package/dist/types/src/plugin-intent/IntentPlugin.d.ts +0 -2
  456. package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +0 -1
  457. package/dist/types/src/plugin-intent/actions.d.ts +0 -36
  458. package/dist/types/src/plugin-intent/actions.d.ts.map +0 -1
  459. package/dist/types/src/plugin-intent/errors.d.ts +0 -16
  460. package/dist/types/src/plugin-intent/errors.d.ts.map +0 -1
  461. package/dist/types/src/plugin-intent/index.d.ts +0 -6
  462. package/dist/types/src/plugin-intent/index.d.ts.map +0 -1
  463. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +0 -139
  464. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +0 -1
  465. package/dist/types/src/plugin-intent/intent-dispatcher.test.d.ts +0 -2
  466. package/dist/types/src/plugin-intent/intent-dispatcher.test.d.ts.map +0 -1
  467. package/dist/types/src/plugin-intent/intent.d.ts +0 -63
  468. package/dist/types/src/plugin-intent/intent.d.ts.map +0 -1
  469. package/dist/types/src/plugin-intent/meta.d.ts +0 -3
  470. package/dist/types/src/plugin-intent/meta.d.ts.map +0 -1
  471. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts +0 -2
  472. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +0 -1
  473. package/dist/types/src/plugin-settings/actions.d.ts +0 -25
  474. package/dist/types/src/plugin-settings/actions.d.ts.map +0 -1
  475. package/dist/types/src/plugin-settings/app-graph-builder.d.ts +0 -4
  476. package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +0 -1
  477. package/dist/types/src/plugin-settings/index.d.ts +0 -3
  478. package/dist/types/src/plugin-settings/index.d.ts.map +0 -1
  479. package/dist/types/src/plugin-settings/intent-resolver.d.ts +0 -4
  480. package/dist/types/src/plugin-settings/intent-resolver.d.ts.map +0 -1
  481. package/dist/types/src/plugin-settings/meta.d.ts +0 -3
  482. package/dist/types/src/plugin-settings/meta.d.ts.map +0 -1
  483. package/dist/types/src/plugin-settings/store.d.ts +0 -5
  484. package/dist/types/src/plugin-settings/store.d.ts.map +0 -1
  485. package/dist/types/src/plugin-settings/translations.d.ts +0 -11
  486. package/dist/types/src/plugin-settings/translations.d.ts.map +0 -1
  487. package/dist/types/src/react/App.d.ts +0 -10
  488. package/dist/types/src/react/App.d.ts.map +0 -1
  489. package/dist/types/src/react/App.stories.d.ts.map +0 -1
  490. package/dist/types/src/react/DefaultFallback.d.ts +0 -8
  491. package/dist/types/src/react/DefaultFallback.d.ts.map +0 -1
  492. package/dist/types/src/react/ErrorBoundary.d.ts +0 -30
  493. package/dist/types/src/react/ErrorBoundary.d.ts.map +0 -1
  494. package/dist/types/src/react/IntentContext.d.ts +0 -8
  495. package/dist/types/src/react/IntentContext.d.ts.map +0 -1
  496. package/dist/types/src/react/PluginManagerProvider.d.ts +0 -10
  497. package/dist/types/src/react/PluginManagerProvider.d.ts.map +0 -1
  498. package/dist/types/src/react/Surface.d.ts +0 -12
  499. package/dist/types/src/react/Surface.d.ts.map +0 -1
  500. package/dist/types/src/react/Surface.stories.d.ts.map +0 -1
  501. package/dist/types/src/react/common.d.ts +0 -13
  502. package/dist/types/src/react/common.d.ts.map +0 -1
  503. package/dist/types/src/react/index.d.ts +0 -9
  504. package/dist/types/src/react/index.d.ts.map +0 -1
  505. package/dist/types/src/react/types.d.ts +0 -14
  506. package/dist/types/src/react/types.d.ts.map +0 -1
  507. package/dist/types/src/react/useApp.d.ts +0 -44
  508. package/dist/types/src/react/useApp.d.ts.map +0 -1
  509. package/dist/types/src/react/useCapabilities.d.ts +0 -13
  510. package/dist/types/src/react/useCapabilities.d.ts.map +0 -1
  511. package/dist/types/src/react/useIntentResolver.d.ts +0 -3
  512. package/dist/types/src/react/useIntentResolver.d.ts.map +0 -1
  513. package/dist/types/src/react/useLoading.d.ts.map +0 -1
  514. package/src/common/collaboration.ts +0 -18
  515. package/src/common/events.ts +0 -79
  516. package/src/common/file.ts +0 -22
  517. package/src/common/graph.ts +0 -30
  518. package/src/common/layout.ts +0 -277
  519. package/src/common/surface.ts +0 -88
  520. package/src/core/capabilities.test.ts +0 -136
  521. package/src/core/capabilities.ts +0 -263
  522. package/src/core/manager.test.ts +0 -516
  523. package/src/core/manager.ts +0 -604
  524. package/src/playground/debug/Debug.tsx +0 -39
  525. package/src/playground/debug/plugin.ts +0 -16
  526. package/src/playground/generator/Main.tsx +0 -70
  527. package/src/playground/generator/Toolbar.tsx +0 -47
  528. package/src/playground/generator/generator.ts +0 -48
  529. package/src/playground/generator/index.ts +0 -6
  530. package/src/playground/generator/plugin.ts +0 -22
  531. package/src/playground/layout/Layout.tsx +0 -33
  532. package/src/playground/layout/plugin.ts +0 -18
  533. package/src/playground/logger/Toolbar.tsx +0 -30
  534. package/src/playground/logger/plugin.ts +0 -41
  535. package/src/playground/logger/schema.ts +0 -12
  536. package/src/playground/playground.stories.tsx +0 -46
  537. package/src/plugin-intent/IntentPlugin.ts +0 -20
  538. package/src/plugin-intent/actions.ts +0 -31
  539. package/src/plugin-intent/errors.ts +0 -40
  540. package/src/plugin-intent/index.ts +0 -9
  541. package/src/plugin-intent/intent-dispatcher.test.ts +0 -286
  542. package/src/plugin-intent/intent-dispatcher.ts +0 -342
  543. package/src/plugin-intent/intent.ts +0 -154
  544. package/src/plugin-intent/meta.ts +0 -10
  545. package/src/plugin-settings/SettingsPlugin.ts +0 -34
  546. package/src/plugin-settings/actions.ts +0 -25
  547. package/src/plugin-settings/app-graph-builder.ts +0 -160
  548. package/src/plugin-settings/index.ts +0 -6
  549. package/src/plugin-settings/intent-resolver.ts +0 -35
  550. package/src/plugin-settings/meta.ts +0 -10
  551. package/src/plugin-settings/store.ts +0 -33
  552. package/src/plugin-settings/translations.ts +0 -19
  553. package/src/react/App.stories.tsx +0 -33
  554. package/src/react/App.tsx +0 -59
  555. package/src/react/DefaultFallback.tsx +0 -26
  556. package/src/react/ErrorBoundary.tsx +0 -56
  557. package/src/react/IntentContext.tsx +0 -35
  558. package/src/react/Surface.stories.tsx +0 -125
  559. package/src/react/Surface.tsx +0 -109
  560. package/src/react/common.ts +0 -13
  561. package/src/react/index.ts +0 -14
  562. package/src/react/types.ts +0 -38
  563. package/src/react/useApp.tsx +0 -165
  564. package/src/react/useCapabilities.ts +0 -31
  565. package/src/react/useIntentResolver.ts +0 -22
  566. /package/dist/lib/browser/{intent-dispatcher-LZ4AE66E.mjs.map → chunk-J5LGTIGS.mjs.map} +0 -0
  567. /package/dist/lib/browser/{react/index.mjs.map → common/activation-events.mjs.map} +0 -0
  568. /package/dist/lib/{node-esm/intent-dispatcher-MGOJ3CHD.mjs.map → browser/common/capabilities.mjs.map} +0 -0
  569. /package/dist/lib/{node-esm/react/index.mjs.map → browser/core/activation-event.mjs.map} +0 -0
@@ -0,0 +1,353 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { it } from '@effect/vitest';
6
+ import * as Effect from 'effect/Effect';
7
+ import * as Fiber from 'effect/Fiber';
8
+ import * as Layer from 'effect/Layer';
9
+ import * as ManagedRuntime from 'effect/ManagedRuntime';
10
+ import * as PubSub from 'effect/PubSub';
11
+ import * as Queue from 'effect/Queue';
12
+ import * as TestClock from 'effect/TestClock';
13
+ import { describe, expect } from 'vitest';
14
+
15
+ import { Operation } from '@dxos/compute';
16
+ import { OperationInvoker } from '@dxos/operation';
17
+
18
+ const testRuntime = ManagedRuntime.make(Layer.empty) as unknown as ManagedRuntime.ManagedRuntime<any, any>;
19
+
20
+ import {
21
+ Compute,
22
+ HalveCompute,
23
+ ToString,
24
+ computeHandler,
25
+ createEventCollector,
26
+ halveComputeHandler,
27
+ toStringHandler,
28
+ waitUntil,
29
+ } from '../testing';
30
+ import * as HistoryTracker from './history-tracker';
31
+ import * as UndoMapping from './undo-mapping';
32
+ import * as UndoRegistry from './undo-registry';
33
+
34
+ describe('HistoryTracker', () => {
35
+ it.effect('tracks undoable operations', () =>
36
+ Effect.gen(function* () {
37
+ const undoMapping = UndoMapping.make({
38
+ operation: Compute,
39
+ inverse: HalveCompute,
40
+ deriveContext: (_input, output) => ({ value: output.value }),
41
+ });
42
+
43
+ const invoker = OperationInvoker.make(() => Effect.succeed([computeHandler, halveComputeHandler]), testRuntime);
44
+ const undoRegistry = UndoRegistry.make(() => [undoMapping]);
45
+ const tracker = HistoryTracker.make(invoker, undoRegistry);
46
+
47
+ expect(tracker.canUndo()).toBe(false);
48
+
49
+ // Fork compute operation and advance clock.
50
+ const fiber = yield* Effect.fork(invoker.invoke(Compute, { value: 2 }));
51
+ yield* TestClock.adjust('20 millis');
52
+ yield* Fiber.join(fiber);
53
+
54
+ // Wait until the tracker has processed the event.
55
+ yield* waitUntil(() => tracker.canUndo());
56
+
57
+ expect(tracker.canUndo()).toBe(true);
58
+ }),
59
+ );
60
+
61
+ it.effect('does not track operations without undo mapping', () =>
62
+ Effect.gen(function* () {
63
+ const invoker = OperationInvoker.make(() => Effect.succeed([toStringHandler]), testRuntime);
64
+ const undoRegistry = UndoRegistry.make(() => []);
65
+ const tracker = HistoryTracker.make(invoker, undoRegistry);
66
+ const collector = yield* createEventCollector(invoker);
67
+
68
+ yield* invoker.invoke(ToString, { value: 42 });
69
+
70
+ // Wait for the pending + success events to be processed.
71
+ yield* collector.waitForEvents(1);
72
+
73
+ // Without an undo mapping, canUndo should remain false.
74
+ expect(tracker.canUndo()).toBe(false);
75
+
76
+ yield* collector.dispose;
77
+ }),
78
+ );
79
+
80
+ it.effect('undo invokes inverse operation', () =>
81
+ Effect.gen(function* () {
82
+ const undoMapping = UndoMapping.make({
83
+ operation: Compute,
84
+ inverse: HalveCompute,
85
+ deriveContext: (_input, output) => ({ value: output.value }),
86
+ });
87
+
88
+ let halveWasCalled = false;
89
+ const trackingHalveHandler = Operation.withHandler(HalveCompute, (data) => {
90
+ halveWasCalled = true;
91
+ return Effect.succeed({ value: data.value / 2 });
92
+ });
93
+
94
+ const invoker = OperationInvoker.make(() => Effect.succeed([computeHandler, trackingHalveHandler]), testRuntime);
95
+ const undoRegistry = UndoRegistry.make(() => [undoMapping]);
96
+ const tracker = HistoryTracker.make(invoker, undoRegistry);
97
+
98
+ // Fork compute operation: 2 * 2 = 4.
99
+ const fiber = yield* Effect.fork(invoker.invoke(Compute, { value: 2 }));
100
+ yield* TestClock.adjust('20 millis');
101
+ yield* Fiber.join(fiber);
102
+
103
+ // Wait until the tracker has processed the event.
104
+ yield* waitUntil(() => tracker.canUndo());
105
+ expect(tracker.canUndo()).toBe(true);
106
+
107
+ // Undo should invoke halve with { value: 4 }.
108
+ yield* tracker.undo();
109
+ expect(halveWasCalled).toBe(true);
110
+ expect(tracker.canUndo()).toBe(false);
111
+ }),
112
+ );
113
+
114
+ it.effect('undo uses _invokeCore to skip event emission', () =>
115
+ Effect.gen(function* () {
116
+ const undoMapping = UndoMapping.make({
117
+ operation: Compute,
118
+ inverse: HalveCompute,
119
+ deriveContext: (_input, output) => ({ value: output.value }),
120
+ });
121
+
122
+ const invoker = OperationInvoker.make(() => Effect.succeed([computeHandler, halveComputeHandler]), testRuntime);
123
+ const undoRegistry = UndoRegistry.make(() => [undoMapping]);
124
+ const tracker = HistoryTracker.make(invoker, undoRegistry);
125
+ const collector = yield* createEventCollector(invoker);
126
+
127
+ // Fork compute operation (emits one success event).
128
+ const fiber = yield* Effect.fork(invoker.invoke(Compute, { value: 2 }));
129
+ yield* TestClock.adjust('20 millis');
130
+ yield* Fiber.join(fiber);
131
+
132
+ yield* collector.waitForEvents(1);
133
+ expect(collector.events.length).toBe(1);
134
+
135
+ // Wait until the tracker has processed the event.
136
+ yield* waitUntil(() => tracker.canUndo());
137
+
138
+ // Undo (should NOT emit events because it uses _invokeCore).
139
+ yield* tracker.undo();
140
+
141
+ // Verify no new events were emitted.
142
+ expect(collector.events.length).toBe(1);
143
+
144
+ yield* collector.dispose;
145
+ }),
146
+ );
147
+
148
+ it.effect('multiple undos work in LIFO order', () =>
149
+ Effect.gen(function* () {
150
+ const undoMapping = UndoMapping.make({
151
+ operation: Compute,
152
+ inverse: HalveCompute,
153
+ deriveContext: (_input, output) => ({ value: output.value }),
154
+ });
155
+
156
+ const halveInputs: number[] = [];
157
+ const trackingHalveHandler = Operation.withHandler(HalveCompute, (data) => {
158
+ halveInputs.push(data.value);
159
+ return Effect.succeed({ value: data.value / 2 });
160
+ });
161
+
162
+ const invoker = OperationInvoker.make(() => Effect.succeed([computeHandler, trackingHalveHandler]), testRuntime);
163
+ const undoRegistry = UndoRegistry.make(() => [undoMapping]);
164
+ const tracker = HistoryTracker.make(invoker, undoRegistry);
165
+ const collector = yield* createEventCollector(invoker);
166
+
167
+ // Fork compute with 2 → 4.
168
+ const fiber1 = yield* Effect.fork(invoker.invoke(Compute, { value: 2 }));
169
+ yield* TestClock.adjust('20 millis');
170
+ yield* Fiber.join(fiber1);
171
+
172
+ // Fork compute with 3 → 6.
173
+ const fiber2 = yield* Effect.fork(invoker.invoke(Compute, { value: 3 }));
174
+ yield* TestClock.adjust('30 millis');
175
+ yield* Fiber.join(fiber2);
176
+
177
+ // Each invoke emits one success event.
178
+ yield* collector.waitForEvents(2);
179
+
180
+ // First undo should halve 6 (the output of the second compute).
181
+ yield* tracker.undo();
182
+ expect(halveInputs[0]).toBe(6);
183
+
184
+ // Second undo should halve 4 (the output of the first compute).
185
+ yield* tracker.undo();
186
+ expect(halveInputs[1]).toBe(4);
187
+
188
+ expect(tracker.canUndo()).toBe(false);
189
+
190
+ yield* collector.dispose;
191
+ }),
192
+ );
193
+
194
+ it.effect('undo on empty history returns error', () =>
195
+ Effect.gen(function* () {
196
+ const invoker = OperationInvoker.make(() => Effect.succeed([]), testRuntime);
197
+ const tracker = HistoryTracker.make(
198
+ invoker,
199
+ UndoRegistry.make(() => []),
200
+ );
201
+
202
+ const result = yield* tracker.undo().pipe(Effect.either);
203
+ expect(result._tag).toBe('Left');
204
+ if (result._tag === 'Left') {
205
+ expect(result.left.message).toContain('empty');
206
+ }
207
+ }),
208
+ );
209
+
210
+ it.effect('publishes an undoable event with the resolved message', () =>
211
+ Effect.gen(function* () {
212
+ const testMessage: [string, { ns: string }] = ['test-undo.message', { ns: 'test' }];
213
+ const undoMapping = UndoMapping.make({
214
+ operation: Compute,
215
+ inverse: HalveCompute,
216
+ deriveContext: (_input, output) => ({ value: output.value }),
217
+ message: testMessage,
218
+ });
219
+
220
+ const invoker = OperationInvoker.make(() => Effect.succeed([computeHandler, halveComputeHandler]), testRuntime);
221
+ const undoRegistry = UndoRegistry.make(() => [undoMapping]);
222
+ const tracker = HistoryTracker.make(invoker, undoRegistry);
223
+
224
+ yield* Effect.scoped(
225
+ Effect.gen(function* () {
226
+ const undoables = yield* PubSub.subscribe(tracker.undoable);
227
+
228
+ // Fork compute operation and advance clock.
229
+ const fiber = yield* Effect.fork(invoker.invoke(Compute, { value: 2 }));
230
+ yield* TestClock.adjust('20 millis');
231
+ yield* Fiber.join(fiber);
232
+
233
+ const undoable = yield* Queue.take(undoables);
234
+ expect(undoable.message).toEqual(testMessage);
235
+ }),
236
+ );
237
+ expect(tracker.canUndo()).toBe(true);
238
+ }),
239
+ );
240
+
241
+ it.effect('undo message can be derived from input and output', () =>
242
+ Effect.gen(function* () {
243
+ // Dynamic message that depends on input/output.
244
+ const dynamicMessage = (input: { value: number }, output: { value: number }): [string, { ns: string }] => [
245
+ `computed-${input.value}-to-${output.value}`,
246
+ { ns: 'test' },
247
+ ];
248
+ const undoMapping = UndoMapping.make({
249
+ operation: Compute,
250
+ inverse: HalveCompute,
251
+ deriveContext: (_input, output) => ({ value: output.value }),
252
+ message: dynamicMessage,
253
+ });
254
+
255
+ const invoker = OperationInvoker.make(() => Effect.succeed([computeHandler, halveComputeHandler]), testRuntime);
256
+ const undoRegistry = UndoRegistry.make(() => [undoMapping]);
257
+ const tracker = HistoryTracker.make(invoker, undoRegistry);
258
+
259
+ yield* Effect.scoped(
260
+ Effect.gen(function* () {
261
+ const undoables = yield* PubSub.subscribe(tracker.undoable);
262
+
263
+ // Fork compute operation and advance clock (2 * 2 = 4).
264
+ const fiber = yield* Effect.fork(invoker.invoke(Compute, { value: 2 }));
265
+ yield* TestClock.adjust('20 millis');
266
+ yield* Fiber.join(fiber);
267
+
268
+ const undoable = yield* Queue.take(undoables);
269
+ expect(undoable.message).toEqual(['computed-2-to-4', { ns: 'test' }]);
270
+ }),
271
+ );
272
+ }),
273
+ );
274
+
275
+ it.effect('does not track operations when deriveContext returns undefined', () =>
276
+ Effect.gen(function* () {
277
+ // Undo mapping that conditionally returns undefined to indicate not undoable.
278
+ const undoMapping = UndoMapping.make({
279
+ operation: Compute,
280
+ inverse: HalveCompute,
281
+ deriveContext: (_input, output) => {
282
+ // Return undefined for values less than 10 to indicate not undoable.
283
+ if (output.value < 10) {
284
+ return undefined;
285
+ }
286
+ return { value: output.value };
287
+ },
288
+ });
289
+
290
+ const invoker = OperationInvoker.make(() => Effect.succeed([computeHandler, halveComputeHandler]), testRuntime);
291
+ const undoRegistry = UndoRegistry.make(() => [undoMapping]);
292
+ const tracker = HistoryTracker.make(invoker, undoRegistry);
293
+ const collector = yield* createEventCollector(invoker);
294
+
295
+ expect(tracker.canUndo()).toBe(false);
296
+
297
+ // Compute 2 * 2 = 4, which is < 10, so deriveContext returns undefined.
298
+ const fiber = yield* Effect.fork(invoker.invoke(Compute, { value: 2 }));
299
+ yield* TestClock.adjust('20 millis');
300
+ yield* Fiber.join(fiber);
301
+
302
+ // Wait for the pending + success events to be processed.
303
+ yield* collector.waitForEvents(1);
304
+
305
+ // Even though there's an undo mapping, deriveContext returned undefined,
306
+ // so this operation should not be tracked as undoable.
307
+ expect(tracker.canUndo()).toBe(false);
308
+
309
+ yield* collector.dispose;
310
+ }),
311
+ );
312
+
313
+ it.effect('tracks operations when deriveContext returns a value', () =>
314
+ Effect.gen(function* () {
315
+ // Undo mapping that conditionally returns undefined to indicate not undoable.
316
+ const undoMapping = UndoMapping.make({
317
+ operation: Compute,
318
+ inverse: HalveCompute,
319
+ deriveContext: (_input, output) => {
320
+ // Return undefined for values less than 10 to indicate not undoable.
321
+ if (output.value < 10) {
322
+ return undefined;
323
+ }
324
+ return { value: output.value };
325
+ },
326
+ });
327
+
328
+ const invoker = OperationInvoker.make(() => Effect.succeed([computeHandler, halveComputeHandler]), testRuntime);
329
+ const undoRegistry = UndoRegistry.make(() => [undoMapping]);
330
+ const tracker = HistoryTracker.make(invoker, undoRegistry);
331
+ const collector = yield* createEventCollector(invoker);
332
+
333
+ expect(tracker.canUndo()).toBe(false);
334
+
335
+ // Compute 5 * 2 = 10, which is >= 10, so deriveContext returns a value.
336
+ // Handler sleeps for value * 10 = 50ms.
337
+ const fiber = yield* Effect.fork(invoker.invoke(Compute, { value: 5 }));
338
+ yield* TestClock.adjust('50 millis');
339
+ yield* Fiber.join(fiber);
340
+
341
+ // Wait for the pending + success events to be processed.
342
+ yield* collector.waitForEvents(1);
343
+
344
+ // Wait until the tracker has processed the event.
345
+ yield* waitUntil(() => tracker.canUndo());
346
+
347
+ // This operation should be tracked as undoable.
348
+ expect(tracker.canUndo()).toBe(true);
349
+
350
+ yield* collector.dispose;
351
+ }),
352
+ );
353
+ });
@@ -0,0 +1,144 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as PubSub from 'effect/PubSub';
7
+ import * as Stream from 'effect/Stream';
8
+
9
+ import { EffectEx } from '@dxos/effect';
10
+ import { log } from '@dxos/log';
11
+ import { OperationInvoker } from '@dxos/operation';
12
+
13
+ import { type Label } from '../../common';
14
+ import { EmptyHistoryError } from './errors';
15
+ import type { HistoryEntry } from './types';
16
+ import { resolveMessage } from './undo-mapping';
17
+ import type { UndoRegistry } from './undo-registry';
18
+
19
+ const HISTORY_LIMIT = 100;
20
+
21
+ //
22
+ // Public Interface
23
+ //
24
+
25
+ /**
26
+ * Emitted when a new undoable action is recorded; consumed by the UI to surface an undo affordance
27
+ * (e.g. the deck notification tracker's undo toast).
28
+ */
29
+ export type UndoableEvent = {
30
+ /** Message describing the undoable action. */
31
+ message?: Label;
32
+ };
33
+
34
+ /**
35
+ * HistoryTracker interface - tracks operation history and provides undo.
36
+ */
37
+ export interface HistoryTracker {
38
+ undo: () => Effect.Effect<void, Error>;
39
+ undoPromise: () => Promise<{ error?: Error }>;
40
+ canUndo: () => boolean;
41
+ /** Stream of undoable actions, published as they are recorded. */
42
+ undoable: PubSub.PubSub<UndoableEvent>;
43
+ }
44
+
45
+ //
46
+ // Factory
47
+ //
48
+
49
+ /**
50
+ * Creates a HistoryTracker that subscribes to (successful) invocation events, derives undoability from
51
+ * the undo registry, maintains the undo stack, and publishes an {@link UndoableEvent} for each undoable
52
+ * action so the UI can offer an undo affordance. The invoker itself is undo-agnostic.
53
+ */
54
+ export const make = (
55
+ invoker: OperationInvoker.OperationInvokerInternal,
56
+ undoRegistry: UndoRegistry,
57
+ ): HistoryTracker => {
58
+ const history: HistoryEntry[] = [];
59
+ const undoable = Effect.runSync(PubSub.unbounded<UndoableEvent>());
60
+
61
+ // Record an invocation; returns the undoable event to publish, or undefined if not undoable.
62
+ const recordInvocation = (event: OperationInvoker.InvocationEvent): UndoableEvent | undefined => {
63
+ const mapping = undoRegistry.lookup(event.operation);
64
+ if (!mapping) {
65
+ // Operation is not undoable.
66
+ return undefined;
67
+ }
68
+
69
+ const inverseInput = mapping.deriveContext(event.input, event.output);
70
+ if (inverseInput === undefined) {
71
+ // Operation is conditionally not undoable (deriveContext returned undefined).
72
+ return undefined;
73
+ }
74
+
75
+ const entry: HistoryEntry = {
76
+ operation: event.operation,
77
+ input: event.input,
78
+ output: event.output,
79
+ inverse: mapping.inverse,
80
+ inverseInput,
81
+ timestamp: event.timestamp,
82
+ };
83
+
84
+ history.push(entry);
85
+ log('history entry added', { key: event.operation.meta.key, historyLength: history.length });
86
+
87
+ // Trim history if it exceeds limit.
88
+ if (history.length > HISTORY_LIMIT) {
89
+ history.splice(0, history.length - HISTORY_LIMIT);
90
+ }
91
+
92
+ return { message: resolveMessage(mapping.message, event.input, event.output) };
93
+ };
94
+
95
+ // Fork a fiber to consume the invocation stream.
96
+ Effect.runFork(
97
+ Stream.fromPubSub(invoker.invocations).pipe(
98
+ Stream.runForEach((event) =>
99
+ Effect.gen(function* () {
100
+ const undoableEvent = recordInvocation(event);
101
+ if (undoableEvent) {
102
+ yield* PubSub.publish(undoable, undoableEvent);
103
+ }
104
+ }),
105
+ ),
106
+ ),
107
+ );
108
+
109
+ const undo = (): Effect.Effect<void, Error> => {
110
+ return Effect.gen(function* () {
111
+ const entry = history.pop();
112
+ if (!entry) {
113
+ return yield* Effect.fail(new EmptyHistoryError());
114
+ }
115
+
116
+ log('undoing operation', { key: entry.operation.meta.key, inverseKey: entry.inverse.meta.key });
117
+
118
+ // Use _invokeCore to skip event emission (avoid undo-of-undo loops).
119
+ yield* invoker._invokeCore(entry.inverse, entry.inverseInput);
120
+
121
+ log('undo completed', { key: entry.operation.meta.key });
122
+ });
123
+ };
124
+
125
+ const undoPromise = async (): Promise<{ error?: Error }> => {
126
+ return EffectEx.runAndForwardErrors(undo())
127
+ .then(() => ({}))
128
+ .catch((error) => {
129
+ log.catch(error);
130
+ return { error };
131
+ });
132
+ };
133
+
134
+ const canUndo = (): boolean => {
135
+ return history.length > 0;
136
+ };
137
+
138
+ return {
139
+ undo,
140
+ undoPromise,
141
+ canUndo,
142
+ undoable,
143
+ };
144
+ };
@@ -0,0 +1,9 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './errors';
6
+ export * from './types';
7
+ export * as UndoMapping from './undo-mapping';
8
+ export * as UndoRegistry from './undo-registry';
9
+ export * as HistoryTracker from './history-tracker';
@@ -0,0 +1,17 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import type { Operation } from '@dxos/compute';
6
+
7
+ /**
8
+ * History entry stored by HistoryTracker.
9
+ */
10
+ export type HistoryEntry = {
11
+ operation: Operation.Definition<any, any>;
12
+ input: any;
13
+ output: any;
14
+ inverse: Operation.Definition<any, any>;
15
+ inverseInput: any;
16
+ timestamp: number;
17
+ };
@@ -0,0 +1,135 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import type { Operation } from '@dxos/compute';
6
+
7
+ /**
8
+ * Label type for translatable text (canonical definition in @dxos/app-toolkit).
9
+ */
10
+ type Label = string | [string, { ns: string | readonly string[]; count?: number; defaultValue?: string }];
11
+
12
+ /**
13
+ * Extract the input type from an OperationDefinition.
14
+ */
15
+ export type InputOf<T> = T extends Operation.Definition<infer I, any> ? I : never;
16
+
17
+ /**
18
+ * Extract the output type from an OperationDefinition.
19
+ */
20
+ export type OutputOf<T> = T extends Operation.Definition<any, infer O> ? O : never;
21
+
22
+ /**
23
+ * Message provider for undo toast.
24
+ * Can be a static Label or a function that derives the message from input/output.
25
+ */
26
+ export type MessageProvider<Op extends Operation.Definition<any, any>> =
27
+ | Label
28
+ | ((input: InputOf<Op>, output: OutputOf<Op>) => Label);
29
+
30
+ /**
31
+ * Undo mapping that links a forward operation to its inverse.
32
+ * Type parameters ensure deriveContext has correctly typed arguments.
33
+ *
34
+ * @template Op - The forward operation definition type.
35
+ * @template Inv - The inverse operation definition type.
36
+ */
37
+ export interface UndoMapping<
38
+ Op extends Operation.Definition<any, any> = Operation.Definition<any, any>,
39
+ Inv extends Operation.Definition<any, any> = Operation.Definition<any, any>,
40
+ > {
41
+ /** The forward operation. */
42
+ readonly operation: Op;
43
+
44
+ /** The inverse operation to invoke for undo. */
45
+ readonly inverse: Inv;
46
+
47
+ /**
48
+ * Derives the input for the inverse operation from the forward operation's input and output.
49
+ * @param input - The input that was passed to the forward operation.
50
+ * @param output - The output that was returned by the forward operation.
51
+ * @returns The input to pass to the inverse operation, or undefined to indicate the operation is not undoable.
52
+ */
53
+ readonly deriveContext: (input: InputOf<Op>, output: OutputOf<Op>) => InputOf<Inv> | undefined;
54
+
55
+ /**
56
+ * Optional message to show in the undo toast.
57
+ * Can be a static Label or a function that derives the message from input/output.
58
+ */
59
+ readonly message?: MessageProvider<Op>;
60
+ }
61
+
62
+ /**
63
+ * Props for creating an UndoMapping.
64
+ */
65
+ export interface UndoMappingProps<
66
+ Op extends Operation.Definition<any, any>,
67
+ Inv extends Operation.Definition<any, any>,
68
+ > {
69
+ /** The forward operation. */
70
+ operation: Op;
71
+
72
+ /** The inverse operation to invoke for undo. */
73
+ inverse: Inv;
74
+
75
+ /**
76
+ * Derives the input for the inverse operation from the forward operation's input and output.
77
+ * Return undefined to indicate the operation is not undoable.
78
+ */
79
+ deriveContext: (input: InputOf<Op>, output: OutputOf<Op>) => InputOf<Inv> | undefined;
80
+
81
+ /**
82
+ * Optional message to show in the undo toast.
83
+ * Can be a static Label or a function that derives the message from input/output.
84
+ */
85
+ message?: MessageProvider<Op>;
86
+ }
87
+
88
+ /**
89
+ * Creates a type-safe undo mapping.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * // Static message
94
+ * const mapping = UndoMapping.make({
95
+ * operation: DeleteThread,
96
+ * inverse: RestoreThread,
97
+ * deriveContext: (input, output) => ({
98
+ * thread: output.thread,
99
+ * anchor: output.anchor,
100
+ * }),
101
+ * message: ['thread deleted label', { ns: '@dxos/plugin-thread' }],
102
+ * });
103
+ *
104
+ * // Dynamic message based on input/output
105
+ * const mapping = UndoMapping.make({
106
+ * operation: RemoveObjects,
107
+ * inverse: RestoreObjects,
108
+ * deriveContext: (_input, output) => output,
109
+ * message: (input, _output) =>
110
+ * input.objects.length === 1
111
+ * ? ['object deleted label', { ns: getTypename(input.objects[0]) }]
112
+ * : ['objects deleted label', { ns: '@dxos/plugin-space' }],
113
+ * });
114
+ * ```
115
+ */
116
+ export const make = <Op extends Operation.Definition<any, any>, Inv extends Operation.Definition<any, any>>(
117
+ props: UndoMappingProps<Op, Inv>,
118
+ ): UndoMapping<Op, Inv> => props;
119
+
120
+ /**
121
+ * Resolves a message provider to a Label.
122
+ */
123
+ export const resolveMessage = <Op extends Operation.Definition<any, any>>(
124
+ message: MessageProvider<Op> | undefined,
125
+ input: InputOf<Op>,
126
+ output: OutputOf<Op>,
127
+ ): Label | undefined => {
128
+ if (message === undefined) {
129
+ return undefined;
130
+ }
131
+ if (typeof message === 'function') {
132
+ return message(input, output);
133
+ }
134
+ return message;
135
+ };