@dxos/app-framework 0.8.4-main.5ea62a8 → 0.8.4-main.72ec0f3

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 (192) hide show
  1. package/.storybook/main.mts +11 -0
  2. package/.storybook/preview.mts +8 -0
  3. package/dist/lib/browser/{app-graph-builder-AFFC6VB2.mjs → app-graph-builder-OIEZZC45.mjs} +31 -30
  4. package/dist/lib/browser/app-graph-builder-OIEZZC45.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-ORWHM7CO.mjs → chunk-SCPE4ZO2.mjs} +11 -8
  6. package/dist/lib/browser/chunk-SCPE4ZO2.mjs.map +7 -0
  7. package/dist/lib/browser/{chunk-DND4XMN4.mjs → chunk-VFUKEZIN.mjs} +233 -191
  8. package/dist/lib/browser/chunk-VFUKEZIN.mjs.map +7 -0
  9. package/dist/lib/browser/{chunk-OZY7HV2A.mjs → chunk-WPW5VVAX.mjs} +281 -273
  10. package/dist/lib/browser/chunk-WPW5VVAX.mjs.map +7 -0
  11. package/dist/lib/browser/index.mjs +14 -56
  12. package/dist/lib/browser/index.mjs.map +3 -3
  13. package/dist/lib/browser/{intent-dispatcher-QG7UPGQX.mjs → intent-dispatcher-LZ4AE66E.mjs} +2 -2
  14. package/dist/lib/browser/{intent-resolver-4S4PSTM5.mjs → intent-resolver-QVCKRX6G.mjs} +7 -7
  15. package/dist/lib/browser/intent-resolver-QVCKRX6G.mjs.map +7 -0
  16. package/dist/lib/browser/meta.json +1 -1
  17. package/dist/lib/browser/react/index.mjs +34 -0
  18. package/dist/lib/browser/{store-6E33KLGK.mjs → store-CNPHOYTJ.mjs} +5 -5
  19. package/dist/lib/browser/store-CNPHOYTJ.mjs.map +7 -0
  20. package/dist/lib/browser/testing/index.mjs +14 -16
  21. package/dist/lib/browser/testing/index.mjs.map +3 -3
  22. package/dist/lib/node-esm/{app-graph-builder-S4OAULX5.mjs → app-graph-builder-EBU4NVWD.mjs} +31 -30
  23. package/dist/lib/node-esm/app-graph-builder-EBU4NVWD.mjs.map +7 -0
  24. package/dist/lib/node-esm/{chunk-E2TK7Z4P.mjs → chunk-IJOHO66N.mjs} +233 -191
  25. package/dist/lib/node-esm/chunk-IJOHO66N.mjs.map +7 -0
  26. package/dist/lib/node-esm/{chunk-F63ZRXMK.mjs → chunk-XJZGUJ3H.mjs} +281 -273
  27. package/dist/lib/node-esm/chunk-XJZGUJ3H.mjs.map +7 -0
  28. package/dist/lib/node-esm/{chunk-UMZQERLE.mjs → chunk-ZX63QUGE.mjs} +11 -8
  29. package/dist/lib/node-esm/chunk-ZX63QUGE.mjs.map +7 -0
  30. package/dist/lib/node-esm/index.mjs +14 -56
  31. package/dist/lib/node-esm/index.mjs.map +3 -3
  32. package/dist/lib/node-esm/{intent-dispatcher-NXBGPJOX.mjs → intent-dispatcher-MGOJ3CHD.mjs} +2 -2
  33. package/dist/lib/node-esm/{intent-resolver-2ZKXI5ET.mjs → intent-resolver-URF3HN3G.mjs} +7 -7
  34. package/dist/lib/node-esm/intent-resolver-URF3HN3G.mjs.map +7 -0
  35. package/dist/lib/node-esm/meta.json +1 -1
  36. package/dist/lib/node-esm/react/index.mjs +35 -0
  37. package/dist/lib/node-esm/{store-QQUTQHHT.mjs → store-RK5B4XEL.mjs} +5 -5
  38. package/dist/lib/node-esm/store-RK5B4XEL.mjs.map +7 -0
  39. package/dist/lib/node-esm/testing/index.mjs +14 -16
  40. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  41. package/dist/types/src/common/capabilities.d.ts +41 -37
  42. package/dist/types/src/common/capabilities.d.ts.map +1 -1
  43. package/dist/types/src/common/collaboration.d.ts +1 -1
  44. package/dist/types/src/common/collaboration.d.ts.map +1 -1
  45. package/dist/types/src/common/file.d.ts +1 -1
  46. package/dist/types/src/common/file.d.ts.map +1 -1
  47. package/dist/types/src/common/layout.d.ts +1 -3
  48. package/dist/types/src/common/layout.d.ts.map +1 -1
  49. package/dist/types/src/common/surface.d.ts +19 -16
  50. package/dist/types/src/common/surface.d.ts.map +1 -1
  51. package/dist/types/src/common/translations.d.ts +1 -1
  52. package/dist/types/src/common/translations.d.ts.map +1 -1
  53. package/dist/types/src/core/capabilities.d.ts +15 -15
  54. package/dist/types/src/core/capabilities.d.ts.map +1 -1
  55. package/dist/types/src/core/manager.d.ts +1 -1
  56. package/dist/types/src/core/manager.d.ts.map +1 -1
  57. package/dist/types/src/core/plugin.d.ts +8 -1
  58. package/dist/types/src/core/plugin.d.ts.map +1 -1
  59. package/dist/types/src/index.d.ts +0 -2
  60. package/dist/types/src/index.d.ts.map +1 -1
  61. package/dist/types/src/playground/debug/plugin.d.ts +1 -1
  62. package/dist/types/src/playground/debug/plugin.d.ts.map +1 -1
  63. package/dist/types/src/playground/generator/Main.d.ts.map +1 -1
  64. package/dist/types/src/playground/generator/generator.d.ts +1 -1
  65. package/dist/types/src/playground/generator/generator.d.ts.map +1 -1
  66. package/dist/types/src/playground/generator/plugin.d.ts +1 -1
  67. package/dist/types/src/playground/generator/plugin.d.ts.map +1 -1
  68. package/dist/types/src/playground/layout/plugin.d.ts +1 -1
  69. package/dist/types/src/playground/layout/plugin.d.ts.map +1 -1
  70. package/dist/types/src/playground/logger/plugin.d.ts +1 -1
  71. package/dist/types/src/playground/logger/plugin.d.ts.map +1 -1
  72. package/dist/types/src/playground/logger/schema.d.ts +1 -1
  73. package/dist/types/src/playground/logger/schema.d.ts.map +1 -1
  74. package/dist/types/src/playground/playground.stories.d.ts +0 -1
  75. package/dist/types/src/playground/playground.stories.d.ts.map +1 -1
  76. package/dist/types/src/plugin-intent/IntentPlugin.d.ts +1 -1
  77. package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -1
  78. package/dist/types/src/plugin-intent/actions.d.ts +5 -7
  79. package/dist/types/src/plugin-intent/actions.d.ts.map +1 -1
  80. package/dist/types/src/plugin-intent/errors.d.ts.map +1 -1
  81. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +4 -4
  82. package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -1
  83. package/dist/types/src/plugin-intent/intent.d.ts +1 -1
  84. package/dist/types/src/plugin-intent/intent.d.ts.map +1 -1
  85. package/dist/types/src/plugin-intent/meta.d.ts +3 -0
  86. package/dist/types/src/plugin-intent/meta.d.ts.map +1 -0
  87. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts +1 -1
  88. package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -1
  89. package/dist/types/src/plugin-settings/actions.d.ts +5 -7
  90. package/dist/types/src/plugin-settings/actions.d.ts.map +1 -1
  91. package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +1 -1
  92. package/dist/types/src/plugin-settings/meta.d.ts +3 -0
  93. package/dist/types/src/plugin-settings/meta.d.ts.map +1 -0
  94. package/dist/types/src/plugin-settings/translations.d.ts +2 -1
  95. package/dist/types/src/plugin-settings/translations.d.ts.map +1 -1
  96. package/dist/types/src/react/App.d.ts +10 -0
  97. package/dist/types/src/react/App.d.ts.map +1 -0
  98. package/dist/types/src/react/App.stories.d.ts +14 -0
  99. package/dist/types/src/react/App.stories.d.ts.map +1 -0
  100. package/dist/types/src/react/DefaultFallback.d.ts +8 -0
  101. package/dist/types/src/react/DefaultFallback.d.ts.map +1 -0
  102. package/dist/types/src/react/ErrorBoundary.d.ts +2 -2
  103. package/dist/types/src/react/ErrorBoundary.d.ts.map +1 -1
  104. package/dist/types/src/react/Surface.d.ts +5 -5
  105. package/dist/types/src/react/Surface.d.ts.map +1 -1
  106. package/dist/types/src/react/Surface.stories.d.ts +3 -7
  107. package/dist/types/src/react/Surface.stories.d.ts.map +1 -1
  108. package/dist/types/src/react/index.d.ts +2 -0
  109. package/dist/types/src/react/index.d.ts.map +1 -1
  110. package/dist/types/src/react/types.d.ts +14 -0
  111. package/dist/types/src/react/types.d.ts.map +1 -0
  112. package/dist/types/src/{App.d.ts → react/useApp.d.ts} +7 -6
  113. package/dist/types/src/react/useApp.d.ts.map +1 -0
  114. package/dist/types/src/react/useLoading.d.ts +19 -0
  115. package/dist/types/src/react/useLoading.d.ts.map +1 -0
  116. package/dist/types/src/testing/withPluginManager.d.ts +7 -8
  117. package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
  118. package/dist/types/tsconfig.tsbuildinfo +1 -1
  119. package/moon.yml +5 -1
  120. package/package.json +44 -40
  121. package/src/common/capabilities.ts +34 -19
  122. package/src/common/collaboration.ts +3 -3
  123. package/src/common/file.ts +1 -1
  124. package/src/common/layout.ts +3 -4
  125. package/src/common/surface.ts +23 -21
  126. package/src/common/translations.ts +1 -1
  127. package/src/core/capabilities.test.ts +2 -2
  128. package/src/core/capabilities.ts +26 -22
  129. package/src/core/manager.test.ts +19 -19
  130. package/src/core/manager.ts +14 -7
  131. package/src/core/plugin.ts +13 -2
  132. package/src/index.ts +0 -2
  133. package/src/playground/debug/Debug.tsx +1 -1
  134. package/src/playground/debug/plugin.ts +7 -8
  135. package/src/playground/generator/Main.tsx +0 -1
  136. package/src/playground/generator/generator.ts +2 -2
  137. package/src/playground/generator/plugin.ts +12 -13
  138. package/src/playground/layout/plugin.ts +9 -8
  139. package/src/playground/logger/plugin.ts +27 -23
  140. package/src/playground/logger/schema.ts +1 -1
  141. package/src/playground/playground.stories.tsx +6 -7
  142. package/src/plugin-intent/IntentPlugin.ts +12 -13
  143. package/src/plugin-intent/actions.ts +4 -6
  144. package/src/plugin-intent/errors.ts +2 -1
  145. package/src/plugin-intent/intent-dispatcher.test.ts +10 -3
  146. package/src/plugin-intent/intent-dispatcher.ts +13 -6
  147. package/src/plugin-intent/intent.ts +1 -1
  148. package/src/plugin-intent/meta.ts +10 -0
  149. package/src/plugin-settings/SettingsPlugin.ts +25 -27
  150. package/src/plugin-settings/actions.ts +9 -13
  151. package/src/plugin-settings/app-graph-builder.ts +22 -20
  152. package/src/plugin-settings/intent-resolver.ts +2 -2
  153. package/src/plugin-settings/meta.ts +10 -0
  154. package/src/plugin-settings/store.ts +2 -2
  155. package/src/plugin-settings/translations.ts +4 -4
  156. package/src/react/App.stories.tsx +33 -0
  157. package/src/react/App.tsx +59 -0
  158. package/src/react/DefaultFallback.tsx +26 -0
  159. package/src/react/ErrorBoundary.tsx +10 -8
  160. package/src/react/Surface.stories.tsx +70 -49
  161. package/src/react/Surface.tsx +67 -36
  162. package/src/react/index.ts +4 -0
  163. package/src/react/types.ts +37 -0
  164. package/src/{App.tsx → react/useApp.tsx} +35 -150
  165. package/src/react/useCapabilities.ts +2 -2
  166. package/src/react/useLoading.tsx +70 -0
  167. package/src/testing/withPluginManager.stories.tsx +1 -1
  168. package/src/testing/withPluginManager.tsx +24 -23
  169. package/tsconfig.json +11 -9
  170. package/vitest.config.ts +8 -6
  171. package/dist/lib/browser/app-graph-builder-AFFC6VB2.mjs.map +0 -7
  172. package/dist/lib/browser/chunk-DND4XMN4.mjs.map +0 -7
  173. package/dist/lib/browser/chunk-ORWHM7CO.mjs.map +0 -7
  174. package/dist/lib/browser/chunk-OZY7HV2A.mjs.map +0 -7
  175. package/dist/lib/browser/intent-resolver-4S4PSTM5.mjs.map +0 -7
  176. package/dist/lib/browser/store-6E33KLGK.mjs.map +0 -7
  177. package/dist/lib/browser/worker.mjs +0 -85
  178. package/dist/lib/node-esm/app-graph-builder-S4OAULX5.mjs.map +0 -7
  179. package/dist/lib/node-esm/chunk-E2TK7Z4P.mjs.map +0 -7
  180. package/dist/lib/node-esm/chunk-F63ZRXMK.mjs.map +0 -7
  181. package/dist/lib/node-esm/chunk-UMZQERLE.mjs.map +0 -7
  182. package/dist/lib/node-esm/intent-resolver-2ZKXI5ET.mjs.map +0 -7
  183. package/dist/lib/node-esm/store-QQUTQHHT.mjs.map +0 -7
  184. package/dist/lib/node-esm/worker.mjs +0 -86
  185. package/dist/types/src/App.d.ts.map +0 -1
  186. package/dist/types/src/worker.d.ts +0 -4
  187. package/dist/types/src/worker.d.ts.map +0 -1
  188. package/src/worker.ts +0 -11
  189. /package/dist/lib/browser/{intent-dispatcher-QG7UPGQX.mjs.map → intent-dispatcher-LZ4AE66E.mjs.map} +0 -0
  190. /package/dist/lib/browser/{worker.mjs.map → react/index.mjs.map} +0 -0
  191. /package/dist/lib/node-esm/{intent-dispatcher-NXBGPJOX.mjs.map → intent-dispatcher-MGOJ3CHD.mjs.map} +0 -0
  192. /package/dist/lib/node-esm/{worker.mjs.map → react/index.mjs.map} +0 -0
@@ -7,7 +7,7 @@ import { afterEach, describe, expect, it } from 'vitest';
7
7
 
8
8
  import { Trigger } from '@dxos/async';
9
9
  import { raise } from '@dxos/debug';
10
- import { updateCounter } from '@dxos/echo-schema/testing';
10
+ import { updateCounter } from '@dxos/echo/testing';
11
11
  import { registerSignalsRuntime } from '@dxos/echo-signals';
12
12
  import { invariant } from '@dxos/invariant';
13
13
  import { live } from '@dxos/live-object';
@@ -17,7 +17,7 @@ import { Events } from '../common';
17
17
  import { type PluginContext, contributes, defineCapability } from './capabilities';
18
18
  import { allOf, defineEvent, oneOf } from './events';
19
19
  import { PluginManager } from './manager';
20
- import { type Plugin, defineModule, definePlugin } from './plugin';
20
+ import { Plugin, defineModule } from './plugin';
21
21
 
22
22
  registerSignalsRuntime();
23
23
 
@@ -43,7 +43,7 @@ describe('PluginManager', () => {
43
43
  });
44
44
 
45
45
  it('should be able to add and remove plugins', async () => {
46
- const Test = definePlugin(testMeta, []);
46
+ const Test = new Plugin(testMeta, []);
47
47
  plugins = [Test];
48
48
 
49
49
  const manager = new PluginManager({ pluginLoader });
@@ -59,7 +59,7 @@ describe('PluginManager', () => {
59
59
  activatesOn: Events.Startup,
60
60
  activate: () => contributes(String, { string: 'hello' }),
61
61
  });
62
- const Test = definePlugin(testMeta, [Hello]);
62
+ const Test = new Plugin(testMeta, [Hello]);
63
63
 
64
64
  const manager = new PluginManager({ plugins: [Test], core: [], pluginLoader });
65
65
  await manager.enable(testMeta.id);
@@ -76,7 +76,7 @@ describe('PluginManager', () => {
76
76
  activatesOn: Events.Startup,
77
77
  activate: () => contributes(String, { string: 'hello' }),
78
78
  });
79
- const Test = definePlugin(testMeta, [Hello]);
79
+ const Test = new Plugin(testMeta, [Hello]);
80
80
 
81
81
  const manager = new PluginManager({ plugins: [Test], enabled: [Test.meta.id], pluginLoader });
82
82
  expect(manager.plugins).toEqual([Test]);
@@ -95,7 +95,7 @@ describe('PluginManager', () => {
95
95
  activatesOn: FailEvent,
96
96
  activate: async () => raise(new Error('test')),
97
97
  });
98
- plugins = [definePlugin(testMeta, [Fail])];
98
+ plugins = [new Plugin(testMeta, [Fail])];
99
99
 
100
100
  const manager = new PluginManager({ pluginLoader });
101
101
  await manager.add(testMeta.id);
@@ -114,7 +114,7 @@ describe('PluginManager', () => {
114
114
  // TODO(wittjosiah): Test and catch more failure modes.
115
115
  activate: async () => async () => raise(new Error('test')),
116
116
  });
117
- plugins = [definePlugin(testMeta, [Hello, Fail])];
117
+ plugins = [new Plugin(testMeta, [Hello, Fail])];
118
118
 
119
119
  const manager = new PluginManager({ pluginLoader });
120
120
  const activating = new Trigger<boolean>();
@@ -149,7 +149,7 @@ describe('PluginManager', () => {
149
149
  return contributes(String, { string: 'hello' });
150
150
  },
151
151
  });
152
- plugins = [definePlugin(testMeta, [Hello])];
152
+ plugins = [new Plugin(testMeta, [Hello])];
153
153
 
154
154
  const manager = new PluginManager({ pluginLoader });
155
155
 
@@ -180,21 +180,21 @@ describe('PluginManager', () => {
180
180
  });
181
181
 
182
182
  it('should be able to fire custom activation events', async () => {
183
- const Plugin1 = definePlugin({ id: 'dxos.org/test/plugin-1', name: 'Plugin 1' }, [
183
+ const Plugin1 = new Plugin({ id: 'dxos.org/test/plugin-1', name: 'Plugin 1' }, [
184
184
  defineModule({
185
185
  id: 'dxos.org/test/plugin-1',
186
186
  activatesOn: CountEvent,
187
187
  activate: () => [contributes(Number, { number: 1 })],
188
188
  }),
189
189
  ]);
190
- const Plugin2 = definePlugin({ id: 'dxos.org/test/plugin-2', name: 'Plugin 2' }, [
190
+ const Plugin2 = new Plugin({ id: 'dxos.org/test/plugin-2', name: 'Plugin 2' }, [
191
191
  defineModule({
192
192
  id: 'dxos.org/test/plugin-2',
193
193
  activatesOn: CountEvent,
194
194
  activate: () => [contributes(Number, { number: 2 })],
195
195
  }),
196
196
  ]);
197
- const Plugin3 = definePlugin({ id: 'dxos.org/test/plugin-3', name: 'Plugin 3' }, [
197
+ const Plugin3 = new Plugin({ id: 'dxos.org/test/plugin-3', name: 'Plugin 3' }, [
198
198
  defineModule({
199
199
  id: 'dxos.org/test/plugin-3',
200
200
  activatesOn: CountEvent,
@@ -231,7 +231,7 @@ describe('PluginManager', () => {
231
231
  return contributes(String, { string: 'hello' });
232
232
  },
233
233
  });
234
- plugins = [definePlugin(testMeta, [Hello])];
234
+ plugins = [new Plugin(testMeta, [Hello])];
235
235
 
236
236
  const manager = new PluginManager({ pluginLoader });
237
237
  expect(manager.active).toEqual([]);
@@ -257,7 +257,7 @@ describe('PluginManager', () => {
257
257
  return contributes(String, { string: 'hello' });
258
258
  },
259
259
  });
260
- plugins = [definePlugin(testMeta, [Hello])];
260
+ plugins = [new Plugin(testMeta, [Hello])];
261
261
 
262
262
  const manager = new PluginManager({ pluginLoader });
263
263
  expect(manager.active).toEqual([]);
@@ -283,7 +283,7 @@ describe('PluginManager', () => {
283
283
  state.total = numbers.reduce((acc, n) => acc + n.number, 0);
284
284
  };
285
285
 
286
- const Count = definePlugin({ id: 'dxos.org/test/count', name: 'Count' }, [
286
+ const Count = new Plugin({ id: 'dxos.org/test/count', name: 'Count' }, [
287
287
  defineModule({
288
288
  id: 'dxos.org/test/count',
289
289
  activatesOn: Events.Startup,
@@ -295,7 +295,7 @@ describe('PluginManager', () => {
295
295
  }),
296
296
  ]);
297
297
 
298
- const Test = definePlugin(testMeta, [
298
+ const Test = new Plugin(testMeta, [
299
299
  defineModule({
300
300
  id: 'dxos.org/test/plugin-1',
301
301
  activatesOn: CountEvent,
@@ -353,7 +353,7 @@ describe('PluginManager', () => {
353
353
  const id = 'dxos.org/test/counter';
354
354
  const stateEvent = Events.createStateEvent(id);
355
355
 
356
- const Test = definePlugin(testMeta, [
356
+ const Test = new Plugin(testMeta, [
357
357
  defineModule({
358
358
  id,
359
359
  activatesOn: Events.Startup,
@@ -390,21 +390,21 @@ describe('PluginManager', () => {
390
390
  });
391
391
 
392
392
  it('should be reactive', async () => {
393
- const Plugin1 = definePlugin({ id: 'dxos.org/test/plugin-1', name: 'Plugin 1' }, [
393
+ const Plugin1 = new Plugin({ id: 'dxos.org/test/plugin-1', name: 'Plugin 1' }, [
394
394
  defineModule({
395
395
  id: 'dxos.org/test/plugin-1',
396
396
  activatesOn: CountEvent,
397
397
  activate: () => [contributes(Number, { number: 1 })],
398
398
  }),
399
399
  ]);
400
- const Plugin2 = definePlugin({ id: 'dxos.org/test/plugin-2', name: 'Plugin 2' }, [
400
+ const Plugin2 = new Plugin({ id: 'dxos.org/test/plugin-2', name: 'Plugin 2' }, [
401
401
  defineModule({
402
402
  id: 'dxos.org/test/plugin-2',
403
403
  activatesOn: CountEvent,
404
404
  activate: () => [contributes(Number, { number: 2 })],
405
405
  }),
406
406
  ]);
407
- const Plugin3 = definePlugin({ id: 'dxos.org/test/plugin-3', name: 'Plugin 3' }, [
407
+ const Plugin3 = new Plugin({ id: 'dxos.org/test/plugin-3', name: 'Plugin 3' }, [
408
408
  defineModule({
409
409
  id: 'dxos.org/test/plugin-3',
410
410
  activatesOn: CountEvent,
@@ -2,9 +2,16 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Registry } from '@effect-rx/rx-react';
5
+ import { Registry } from '@effect-atom/atom-react';
6
6
  import { untracked } from '@preact/signals-core';
7
- import { Array, Duration, Effect, Fiber, HashSet, Match, Ref, pipe } from 'effect';
7
+ import * as Array from 'effect/Array';
8
+ import * as Duration from 'effect/Duration';
9
+ import * as Effect from 'effect/Effect';
10
+ import * as Fiber from 'effect/Fiber';
11
+ import * as Function from 'effect/Function';
12
+ import * as HashSet from 'effect/HashSet';
13
+ import * as Match from 'effect/Match';
14
+ import * as Ref from 'effect/Ref';
8
15
 
9
16
  import { Event } from '@dxos/async';
10
17
  import { type Live, live } from '@dxos/live-object';
@@ -48,7 +55,7 @@ export class PluginManager {
48
55
  readonly context: PluginContext;
49
56
  readonly registry: Registry.Registry;
50
57
 
51
- // TODO(wittjosiah): Replace with Rx.
58
+ // TODO(wittjosiah): Replace with Atom.
52
59
  private readonly _state: Live<PluginManagerState>;
53
60
  private readonly _pluginLoader: PluginManagerOptions['pluginLoader'];
54
61
  private readonly _capabilities = new Map<string, AnyCapability[]>();
@@ -396,7 +403,7 @@ export class PluginManager {
396
403
  this.activation.emit({ event: key, state: 'activating' });
397
404
 
398
405
  // Fire activatesBefore events.
399
- yield* pipe(
406
+ yield* Function.pipe(
400
407
  modules,
401
408
  Array.flatMap((module) => module.activatesBefore ?? []),
402
409
  HashSet.fromIterable,
@@ -407,7 +414,7 @@ export class PluginManager {
407
414
  );
408
415
 
409
416
  // Concurrently triggers loading of lazy capabilities.
410
- const getCapabilities = yield* pipe(
417
+ const getCapabilities = yield* Function.pipe(
411
418
  modules,
412
419
  Array.map((mod) => this._loadModule(mod)),
413
420
  Effect.allWith({ concurrency: 'unbounded' }),
@@ -418,7 +425,7 @@ export class PluginManager {
418
425
  );
419
426
 
420
427
  // Contribute the capabilities from the activated modules.
421
- yield* pipe(
428
+ yield* Function.pipe(
422
429
  modules,
423
430
  Array.zip(getCapabilities),
424
431
  Array.map(([module, capabilities]) => this._contributeCapabilities(module, capabilities)),
@@ -428,7 +435,7 @@ export class PluginManager {
428
435
  );
429
436
 
430
437
  // Fire activatesAfter events.
431
- yield* pipe(
438
+ yield* Function.pipe(
432
439
  modules,
433
440
  Array.flatMap((module) => module.activatesAfter ?? []),
434
441
  HashSet.fromIterable,
@@ -110,6 +110,11 @@ export type PluginMeta = {
110
110
  * A grep-able symbol string which can be resolved to an icon asset by @ch-ui/icons, via @ch-ui/vite-plugin-icons.
111
111
  */
112
112
  icon?: string;
113
+
114
+ /**
115
+ * Icon hue (ChromaticPalette).
116
+ */
117
+ iconHue?: string;
113
118
  };
114
119
 
115
120
  /**
@@ -124,9 +129,15 @@ export class Plugin {
124
129
  ) {}
125
130
  }
126
131
 
132
+ export type PluginFactory<T = void> = ((args: T) => Plugin) & { meta: PluginMeta };
133
+
127
134
  /**
128
135
  * Helper to define a plugin.
129
136
  */
130
- export const definePlugin = (meta: PluginMeta, modules: PluginModule[]) => {
131
- return new Plugin(meta, modules);
137
+ export const definePlugin = <T = void>(meta: PluginMeta, provider: (args: T) => PluginModule[]): PluginFactory<T> => {
138
+ const factory = (args: T) => {
139
+ return new Plugin(meta, provider(args));
140
+ };
141
+
142
+ return Object.assign(factory, { meta });
132
143
  };
package/src/index.ts CHANGED
@@ -2,9 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './App';
6
5
  export * from './common';
7
6
  export * from './core';
8
7
  export * from './plugin-intent';
9
8
  export * from './plugin-settings';
10
- export * from './react';
@@ -22,7 +22,7 @@ export const Debug = () => {
22
22
  };
23
23
 
24
24
  return (
25
- <SyntaxHighlighter language='json' classNames='flex w-full text-xs opacity-75 rounded'>
25
+ <SyntaxHighlighter language='json' classNames='text-xs opacity-75 rounded'>
26
26
  {JSON.stringify(object, undefined, 2)}
27
27
  </SyntaxHighlighter>
28
28
  );
@@ -7,11 +7,10 @@ import { defineModule, definePlugin, lazy } from '../../core';
7
7
 
8
8
  const Debug = lazy(() => import('./Debug'));
9
9
 
10
- export const DebugPlugin = () =>
11
- definePlugin({ id: 'dxos.org/test/plugin-debug', name: 'Debug' }, [
12
- defineModule({
13
- id: 'dxos.org/test/debug/main',
14
- activatesOn: Events.Startup,
15
- activate: Debug,
16
- }),
17
- ]);
10
+ export const DebugPlugin = definePlugin({ id: 'dxos.org/test/plugin-debug', name: 'Debug' }, () => [
11
+ defineModule({
12
+ id: 'dxos.org/test/debug/main',
13
+ activatesOn: Events.Startup,
14
+ activate: Debug,
15
+ }),
16
+ ]);
@@ -30,7 +30,6 @@ const Item = ({
30
30
  variant='ghost'
31
31
  icon='ph--x--regular'
32
32
  label='Remove'
33
- size={5}
34
33
  disabled={disabled}
35
34
  onClick={handleRemove}
36
35
  />
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
 
7
7
  import { Capabilities, Events } from '../../common';
8
8
  import { contributes, defineCapability, defineEvent, defineModule, definePlugin } from '../../core';
@@ -26,7 +26,7 @@ export const createGeneratorIntent = (id: string) => {
26
26
  export const createNumberPlugin = (id: string) => {
27
27
  const number = Math.floor(Math.random() * 100);
28
28
 
29
- return definePlugin({ id, name: `Plugin ${id}` }, [
29
+ return definePlugin({ id, name: `Plugin ${id}` }, () => [
30
30
  defineModule({
31
31
  id: `${id}/main`,
32
32
  activatesOn: CountEvent,
@@ -8,16 +8,15 @@ import { defineModule, definePlugin, lazy } from '../../core';
8
8
  const Main = lazy(() => import('./Main'));
9
9
  const Toolbar = lazy(() => import('./Toolbar'));
10
10
 
11
- export const GeneratorPlugin = () =>
12
- definePlugin({ id: 'dxos.org/test/generator', name: 'Generator' }, [
13
- defineModule({
14
- id: 'dxos.org/test/generator/main',
15
- activatesOn: Events.Startup,
16
- activate: Main,
17
- }),
18
- defineModule({
19
- id: 'dxos.org/test/generator/toolbar',
20
- activatesOn: Events.Startup,
21
- activate: Toolbar,
22
- }),
23
- ]);
11
+ export const GeneratorPlugin = definePlugin({ id: 'dxos.org/test/generator', name: 'Generator' }, () => [
12
+ defineModule({
13
+ id: 'dxos.org/test/generator/main',
14
+ activatesOn: Events.Startup,
15
+ activate: Main,
16
+ }),
17
+ defineModule({
18
+ id: 'dxos.org/test/generator/toolbar',
19
+ activatesOn: Events.Startup,
20
+ activate: Toolbar,
21
+ }),
22
+ ]);
@@ -7,11 +7,12 @@ import { defineModule, definePlugin, lazy } from '../../core';
7
7
 
8
8
  const Layout = lazy(() => import('./Layout'));
9
9
 
10
- export const LayoutPlugin = () =>
11
- definePlugin({ id: 'dxos.org/test/layout', name: 'Layout' }, [
12
- defineModule({
13
- id: 'dxos.org/test/layout/root',
14
- activatesOn: Events.Startup,
15
- activate: Layout,
16
- }),
17
- ]);
10
+ const meta = { id: 'dxos.org/test/layout', name: 'Layout' };
11
+
12
+ export const LayoutPlugin = definePlugin(meta, () => [
13
+ defineModule({
14
+ id: 'dxos.org/test/layout/root',
15
+ activatesOn: Events.Startup,
16
+ activate: Layout,
17
+ }),
18
+ ]);
@@ -12,26 +12,30 @@ import { Log } from './schema';
12
12
 
13
13
  const Toolbar = lazy(() => import('./Toolbar'));
14
14
 
15
- export const LoggerPlugin = () =>
16
- definePlugin({ id: 'dxos.org/test/logger', name: 'Logger' }, [
17
- defineModule({
18
- id: 'dxos.org/test/logger/intents',
19
- activatesOn: Events.SetupIntentResolver,
20
- activate: () => [
21
- contributes(
22
- Capabilities.IntentResolver,
23
- createResolver({
24
- intent: Log,
25
- resolve: ({ message }) => {
26
- log.info(message);
27
- },
28
- }),
29
- ),
30
- ],
31
- }),
32
- defineModule({
33
- id: 'dxos.org/test/logger/surfaces',
34
- activatesOn: Events.Startup,
35
- activate: Toolbar,
36
- }),
37
- ]);
15
+ const meta = {
16
+ id: 'dxos.org/test/logger',
17
+ name: 'Logger',
18
+ };
19
+
20
+ export const LoggerPlugin = definePlugin(meta, () => [
21
+ defineModule({
22
+ id: 'dxos.org/test/logger/intents',
23
+ activatesOn: Events.SetupIntentResolver,
24
+ activate: () => [
25
+ contributes(
26
+ Capabilities.IntentResolver,
27
+ createResolver({
28
+ intent: Log,
29
+ resolve: ({ message }) => {
30
+ log.info(message);
31
+ },
32
+ }),
33
+ ),
34
+ ],
35
+ }),
36
+ defineModule({
37
+ id: 'dxos.org/test/logger/surfaces',
38
+ activatesOn: Events.Startup,
39
+ activate: Toolbar,
40
+ }),
41
+ ]);
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
 
7
7
  export class Log extends Schema.TaggedClass<Log>()('dxos.org/test/logger/log', {
8
8
  input: Schema.Struct({
@@ -2,22 +2,21 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
8
6
  import React from 'react';
9
7
 
10
- import { withLayout, withTheme } from '@dxos/storybook-utils';
8
+ import { withTheme } from '@dxos/react-ui/testing';
11
9
 
12
- import { useApp } from '../App';
13
10
  import { IntentPlugin } from '../plugin-intent';
11
+ import { useApp } from '../react';
14
12
 
15
13
  import { DebugPlugin } from './debug';
16
14
  import { GeneratorPlugin, createNumberPlugin } from './generator';
17
15
  import { LayoutPlugin } from './layout';
18
16
  import { LoggerPlugin } from './logger';
19
17
 
20
- const plugins = [IntentPlugin(), LayoutPlugin(), DebugPlugin(), LoggerPlugin(), GeneratorPlugin()];
18
+ const pluginFactories = [IntentPlugin, LayoutPlugin, DebugPlugin(), LoggerPlugin(), GeneratorPlugin()];
19
+ const plugins = pluginFactories.map((factory) => (typeof factory === 'function' ? factory() : factory));
21
20
 
22
21
  const Placeholder = () => {
23
22
  return <div>Loading...</div>;
@@ -25,7 +24,7 @@ const Placeholder = () => {
25
24
 
26
25
  const DefaultStory = () => {
27
26
  const App = useApp({
28
- pluginLoader: (id) => createNumberPlugin(id),
27
+ pluginLoader: (id) => createNumberPlugin(id)(),
29
28
  plugins,
30
29
  core: plugins.map((plugin) => plugin.meta.id),
31
30
  placeholder: Placeholder,
@@ -37,7 +36,7 @@ const DefaultStory = () => {
37
36
  const meta = {
38
37
  title: 'sdk/app-framework/playground',
39
38
  render: DefaultStory,
40
- decorators: [withTheme, withLayout()],
39
+ decorators: [withTheme],
41
40
  } satisfies Meta<typeof DefaultStory>;
42
41
 
43
42
  export default meta;
@@ -5,17 +5,16 @@
5
5
  import { Events } from '../common';
6
6
  import { defineModule, definePlugin, lazy } from '../core';
7
7
 
8
- import { INTENT_PLUGIN } from './actions';
8
+ import { meta } from './meta';
9
9
 
10
- export const IntentPlugin = () =>
11
- definePlugin({ id: INTENT_PLUGIN, name: 'Intent' }, [
12
- defineModule({
13
- id: `${INTENT_PLUGIN}/module/dispatcher`,
14
- // TODO(wittjosiah): This will mean that startup needs to be reset when intents are added or removed.
15
- // This is fine for now because it's how it worked prior to capabilities api anyways.
16
- // In the future, the intent dispatcher should be able to be reset without resetting the entire app.
17
- activatesOn: Events.Startup,
18
- activatesAfter: [Events.DispatcherReady],
19
- activate: lazy(() => import('./intent-dispatcher')),
20
- }),
21
- ]);
10
+ export const IntentPlugin = definePlugin(meta, () => [
11
+ defineModule({
12
+ id: `${meta.id}/module/dispatcher`,
13
+ // TODO(wittjosiah): This will mean that startup needs to be reset when intents are added or removed.
14
+ // This is fine for now because it's how it worked prior to capabilities api anyways.
15
+ // In the future, the intent dispatcher should be able to be reset without resetting the entire app.
16
+ activatesOn: Events.Startup,
17
+ activatesAfter: [Events.DispatcherReady],
18
+ activate: lazy(() => import('./intent-dispatcher')),
19
+ }),
20
+ ]);
@@ -2,18 +2,16 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Schema } from 'effect';
5
+ import * as Schema from 'effect/Schema';
6
6
 
7
7
  import { Label } from './intent';
8
-
9
- export const INTENT_PLUGIN = 'dxos.org/plugin/intent';
10
- export const INTENT_ACTION = `${INTENT_PLUGIN}/action`;
8
+ import { meta } from './meta';
11
9
 
12
10
  export namespace IntentAction {
13
11
  /**
14
12
  * Log an intent.
15
13
  */
16
- export class Track extends Schema.TaggedClass<Track>()(`${INTENT_ACTION}/track`, {
14
+ export class Track extends Schema.TaggedClass<Track>()(`${meta.id}/action/track`, {
17
15
  input: Schema.Struct({
18
16
  intents: Schema.Array(Schema.String),
19
17
  error: Schema.optional(Schema.String),
@@ -24,7 +22,7 @@ export namespace IntentAction {
24
22
  /**
25
23
  * Fired after an intent is dispatched if the intent is undoable.
26
24
  */
27
- export class ShowUndo extends Schema.TaggedClass<ShowUndo>()(`${INTENT_ACTION}/show-undo`, {
25
+ export class ShowUndo extends Schema.TaggedClass<ShowUndo>()(`${meta.id}/action/show-undo`, {
28
26
  input: Schema.Struct({
29
27
  message: Label,
30
28
  }),
@@ -24,10 +24,11 @@ export class BaseError extends Error {
24
24
 
25
25
  export class NoResolversError extends BaseError {
26
26
  constructor(action: string) {
27
- super('NO_RESOLVERS', 'No resolvers were found for the action', { action });
27
+ super('NO_RESOLVERS', `No resolvers were found for the action: ${action}`, { action });
28
28
  }
29
29
  }
30
30
 
31
+ // TODO(burdon): Detect loops.
31
32
  export class CycleDetectedError extends BaseError {
32
33
  constructor(context?: Record<string, any>) {
33
34
  super(
@@ -2,7 +2,10 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Effect, Fiber, Schema, pipe } from 'effect';
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Fiber from 'effect/Fiber';
7
+ import * as Function from 'effect/Function';
8
+ import * as Schema from 'effect/Schema';
6
9
  import { describe, expect, test } from 'vitest';
7
10
 
8
11
  import { chain, createIntent } from './intent';
@@ -104,7 +107,11 @@ describe('Intent dispatcher', () => {
104
107
 
105
108
  test('chain intents', async () => {
106
109
  const { dispatch } = createDispatcher(() => [computeResolver, toStringResolver, concatResolver]);
107
- const intent = pipe(createIntent(Compute, { value: 1 }), chain(ToString, {}), chain(Concat, { plus: '!' }));
110
+ const intent = Function.pipe(
111
+ createIntent(Compute, { value: 1 }),
112
+ chain(ToString, {}),
113
+ chain(Concat, { plus: '!' }),
114
+ );
108
115
 
109
116
  expect(intent.first.id).toBe(Compute._tag);
110
117
  expect(intent.last.id).toBe(Concat._tag);
@@ -120,7 +127,7 @@ describe('Intent dispatcher', () => {
120
127
 
121
128
  test('undo chained intent', async () => {
122
129
  const { dispatch, undo } = createDispatcher(() => [computeResolver, toStringResolver, concatResolver]);
123
- const intent = pipe(createIntent(Compute, { value: 1 }), chain(Compute, {}), chain(Compute, {}));
130
+ const intent = Function.pipe(createIntent(Compute, { value: 1 }), chain(Compute, {}), chain(Compute, {}));
124
131
  const program = Effect.gen(function* () {
125
132
  const a = yield* dispatch(intent);
126
133