@dxos/app-framework 0.7.5-main.9d2a38b → 0.7.5-main.ff8607b
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.
- package/dist/lib/browser/app-graph-builder-F7VZ6LRN.mjs +137 -0
- package/dist/lib/browser/app-graph-builder-F7VZ6LRN.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GNLU3GAU.mjs → chunk-ATRNTMSS.mjs} +623 -819
- package/dist/lib/browser/chunk-ATRNTMSS.mjs.map +7 -0
- package/dist/lib/browser/chunk-LDJ3T4V3.mjs +32 -0
- package/dist/lib/browser/chunk-LDJ3T4V3.mjs.map +7 -0
- package/dist/lib/browser/chunk-WS6SU6HI.mjs +285 -0
- package/dist/lib/browser/chunk-WS6SU6HI.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +57 -74
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/intent-dispatcher-E6J7E5Y5.mjs +11 -0
- package/dist/lib/browser/intent-dispatcher-E6J7E5Y5.mjs.map +7 -0
- package/dist/lib/browser/intent-resolver-XLE4L3LS.mjs +38 -0
- package/dist/lib/browser/intent-resolver-XLE4L3LS.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/store-QU2IKFAI.mjs +19 -0
- package/dist/lib/browser/store-QU2IKFAI.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +10 -3
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/browser/worker.mjs +77 -0
- package/dist/lib/browser/worker.mjs.map +7 -0
- package/dist/lib/node/app-graph-builder-JGBADFF7.cjs +146 -0
- package/dist/lib/node/app-graph-builder-JGBADFF7.cjs.map +7 -0
- package/dist/lib/node/chunk-QLVQ6PND.cjs +58 -0
- package/dist/lib/node/chunk-QLVQ6PND.cjs.map +7 -0
- package/dist/lib/node/chunk-WKC6YMEQ.cjs +1433 -0
- package/dist/lib/node/chunk-WKC6YMEQ.cjs.map +7 -0
- package/dist/lib/node/chunk-WRWRZKZU.cjs +308 -0
- package/dist/lib/node/chunk-WRWRZKZU.cjs.map +7 -0
- package/dist/lib/node/index.cjs +106 -118
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/intent-dispatcher-CFBKDZQR.cjs +32 -0
- package/dist/lib/node/intent-dispatcher-CFBKDZQR.cjs.map +7 -0
- package/dist/lib/node/intent-resolver-3TKCXP4S.cjs +45 -0
- package/dist/lib/node/intent-resolver-3TKCXP4S.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/store-4QMUUU2A.cjs +34 -0
- package/dist/lib/node/store-4QMUUU2A.cjs.map +7 -0
- package/dist/lib/node/testing/index.cjs +15 -8
- package/dist/lib/node/testing/index.cjs.map +3 -3
- package/dist/lib/node/worker.cjs +99 -0
- package/dist/lib/node/worker.cjs.map +7 -0
- package/dist/lib/node-esm/app-graph-builder-2QEX57NX.mjs +138 -0
- package/dist/lib/node-esm/app-graph-builder-2QEX57NX.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-KPMTPXQI.mjs → chunk-44J2VZBB.mjs} +623 -819
- package/dist/lib/node-esm/chunk-44J2VZBB.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-CNJYZNSL.mjs +34 -0
- package/dist/lib/node-esm/chunk-CNJYZNSL.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-HTLXL32I.mjs +286 -0
- package/dist/lib/node-esm/chunk-HTLXL32I.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +57 -74
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/intent-dispatcher-LDQGDZ62.mjs +12 -0
- package/dist/lib/node-esm/intent-dispatcher-LDQGDZ62.mjs.map +7 -0
- package/dist/lib/node-esm/intent-resolver-7VJWN67U.mjs +39 -0
- package/dist/lib/node-esm/intent-resolver-7VJWN67U.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/store-VWDAYUQY.mjs +20 -0
- package/dist/lib/node-esm/store-VWDAYUQY.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +10 -3
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/worker.mjs +78 -0
- package/dist/lib/node-esm/worker.mjs.map +7 -0
- package/dist/types/src/App.d.ts.map +1 -1
- package/dist/types/src/common/capabilities.d.ts +63 -110
- package/dist/types/src/common/capabilities.d.ts.map +1 -1
- package/dist/types/src/common/events.d.ts +8 -1
- package/dist/types/src/common/events.d.ts.map +1 -1
- package/dist/types/src/common/file.d.ts +1 -1
- package/dist/types/src/common/file.d.ts.map +1 -1
- package/dist/types/src/common/graph.d.ts +2 -2
- package/dist/types/src/common/graph.d.ts.map +1 -1
- package/dist/types/src/common/index.d.ts +0 -1
- package/dist/types/src/common/index.d.ts.map +1 -1
- package/dist/types/src/common/layout.d.ts +204 -121
- package/dist/types/src/common/layout.d.ts.map +1 -1
- package/dist/types/src/common/surface.d.ts +3 -3
- package/dist/types/src/common/surface.d.ts.map +1 -1
- package/dist/types/src/common/translations.d.ts +7 -7
- package/dist/types/src/common/translations.d.ts.map +1 -1
- package/dist/types/src/core/capabilities.d.ts +6 -2
- package/dist/types/src/core/capabilities.d.ts.map +1 -1
- package/dist/types/src/core/manager.d.ts +2 -9
- package/dist/types/src/core/manager.d.ts.map +1 -1
- package/dist/types/src/core/plugin.d.ts +5 -2
- package/dist/types/src/core/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/generator/Toolbar.d.ts.map +1 -1
- package/dist/types/src/playground/generator/generator.d.ts +2 -0
- package/dist/types/src/playground/generator/generator.d.ts.map +1 -1
- package/dist/types/src/playground/generator/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/logger/Toolbar.d.ts.map +1 -1
- package/dist/types/src/playground/logger/plugin.d.ts.map +1 -1
- package/dist/types/src/playground/logger/schema.d.ts +1 -1
- package/dist/types/src/playground/logger/schema.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/IntentPlugin.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/actions.d.ts +1 -1
- package/dist/types/src/plugin-intent/actions.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/index.d.ts +0 -1
- package/dist/types/src/plugin-intent/index.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts +27 -20
- package/dist/types/src/plugin-intent/intent-dispatcher.d.ts.map +1 -1
- package/dist/types/src/plugin-intent/intent.d.ts +3 -3
- package/dist/types/src/plugin-intent/intent.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/SettingsPlugin.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/actions.d.ts +11 -1
- package/dist/types/src/plugin-settings/actions.d.ts.map +1 -1
- package/dist/types/src/plugin-settings/app-graph-builder.d.ts +197 -0
- package/dist/types/src/plugin-settings/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/intent-resolver.d.ts +4 -0
- package/dist/types/src/plugin-settings/intent-resolver.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/store.d.ts +5 -0
- package/dist/types/src/plugin-settings/store.d.ts.map +1 -0
- package/dist/types/src/plugin-settings/translations.d.ts +11 -0
- package/dist/types/src/plugin-settings/translations.d.ts.map +1 -0
- package/dist/types/src/{plugin-intent → react}/IntentContext.d.ts +1 -1
- package/dist/types/src/react/IntentContext.d.ts.map +1 -0
- package/dist/types/src/react/Surface.d.ts.map +1 -1
- package/dist/types/src/react/Surface.stories.d.ts +16 -0
- package/dist/types/src/react/Surface.stories.d.ts.map +1 -0
- package/dist/types/src/react/common.d.ts +12 -0
- package/dist/types/src/react/common.d.ts.map +1 -0
- package/dist/types/src/react/index.d.ts +2 -0
- package/dist/types/src/react/index.d.ts.map +1 -1
- package/dist/types/src/react/useIntentResolver.d.ts +3 -0
- package/dist/types/src/react/useIntentResolver.d.ts.map +1 -0
- package/dist/types/src/testing/withPluginManager.d.ts +1 -1
- package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
- package/dist/types/src/worker.d.ts +4 -0
- package/dist/types/src/worker.d.ts.map +1 -0
- package/package.json +26 -20
- package/project.json +3 -3
- package/src/App.tsx +15 -14
- package/src/common/capabilities.ts +20 -11
- package/src/common/events.ts +10 -1
- package/src/common/file.ts +1 -1
- package/src/common/graph.ts +2 -2
- package/src/common/index.ts +0 -1
- package/src/common/layout.ts +194 -126
- package/src/common/surface.ts +2 -2
- package/src/common/translations.ts +7 -8
- package/src/core/capabilities.ts +16 -7
- package/src/core/manager.test.ts +22 -73
- package/src/core/manager.ts +105 -91
- package/src/core/plugin.ts +6 -3
- package/src/playground/debug/plugin.ts +1 -1
- package/src/playground/generator/Toolbar.tsx +11 -11
- package/src/playground/generator/generator.ts +25 -0
- package/src/playground/generator/plugin.ts +6 -1
- package/src/playground/layout/plugin.ts +1 -1
- package/src/playground/logger/Toolbar.tsx +2 -1
- package/src/playground/logger/plugin.ts +6 -3
- package/src/playground/logger/schema.ts +1 -1
- package/src/plugin-intent/IntentPlugin.tsx +3 -43
- package/src/plugin-intent/actions.ts +1 -1
- package/src/plugin-intent/index.ts +0 -1
- package/src/plugin-intent/intent-dispatcher.test.ts +48 -29
- package/src/plugin-intent/intent-dispatcher.ts +76 -41
- package/src/plugin-intent/intent.ts +5 -5
- package/src/plugin-settings/SettingsPlugin.ts +19 -13
- package/src/plugin-settings/actions.ts +11 -1
- package/src/plugin-settings/app-graph-builder.ts +122 -0
- package/src/plugin-settings/intent-resolver.ts +28 -0
- package/src/plugin-settings/store.ts +20 -0
- package/src/plugin-settings/translations.ts +17 -0
- package/src/{plugin-intent → react}/IntentContext.tsx +2 -2
- package/src/react/Surface.stories.tsx +96 -0
- package/src/react/Surface.tsx +11 -8
- package/src/react/common.ts +12 -0
- package/src/react/index.ts +2 -0
- package/src/react/useIntentResolver.ts +22 -0
- package/src/testing/withPluginManager.tsx +11 -3
- package/src/worker.ts +11 -0
- package/tsconfig.json +3 -3
- package/dist/lib/browser/chunk-GNLU3GAU.mjs.map +0 -7
- package/dist/lib/node/chunk-FBA4BB3J.cjs +0 -1639
- package/dist/lib/node/chunk-FBA4BB3J.cjs.map +0 -7
- package/dist/lib/node-esm/chunk-KPMTPXQI.mjs.map +0 -7
- package/dist/types/src/common/navigation.d.ts +0 -241
- package/dist/types/src/common/navigation.d.ts.map +0 -1
- package/dist/types/src/plugin-intent/IntentContext.d.ts.map +0 -1
- package/src/common/navigation.ts +0 -199
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { Schema as S } from '@effect/schema';
|
|
6
|
+
|
|
7
|
+
import { Capabilities, Events } from '../../common';
|
|
5
8
|
import { contributes, defineEvent, defineCapability, defineModule, definePlugin } from '../../core';
|
|
9
|
+
import { createResolver, type IntentSchema } from '../../plugin-intent';
|
|
6
10
|
|
|
7
11
|
export const Number = defineCapability<number>('dxos.org/test/generator/number');
|
|
8
12
|
|
|
@@ -10,6 +14,15 @@ export const CountEvent = defineEvent('dxos.org/test/generator/count');
|
|
|
10
14
|
|
|
11
15
|
export const createPluginId = (id: string) => `dxos.org/test/generator/${id}`;
|
|
12
16
|
|
|
17
|
+
export const createGeneratorIntent = (id: string) => {
|
|
18
|
+
class Alert extends S.TaggedClass<Alert>()(`${createPluginId(id)}/action/alert`, {
|
|
19
|
+
input: S.Void,
|
|
20
|
+
output: S.Void,
|
|
21
|
+
}) {}
|
|
22
|
+
|
|
23
|
+
return Alert as unknown as IntentSchema<any, any>;
|
|
24
|
+
};
|
|
25
|
+
|
|
13
26
|
export const createNumberPlugin = (id: string) => {
|
|
14
27
|
const number = Math.floor(Math.random() * 100);
|
|
15
28
|
|
|
@@ -19,5 +32,17 @@ export const createNumberPlugin = (id: string) => {
|
|
|
19
32
|
activatesOn: CountEvent,
|
|
20
33
|
activate: () => contributes(Number, number),
|
|
21
34
|
}),
|
|
35
|
+
defineModule({
|
|
36
|
+
id: `${id}/intent-resolver`,
|
|
37
|
+
activatesOn: Events.SetupIntents,
|
|
38
|
+
activate: () =>
|
|
39
|
+
contributes(
|
|
40
|
+
Capabilities.IntentResolver,
|
|
41
|
+
createResolver({
|
|
42
|
+
intent: createGeneratorIntent(id),
|
|
43
|
+
resolve: () => window.alert(JSON.stringify({ number })),
|
|
44
|
+
}),
|
|
45
|
+
),
|
|
46
|
+
}),
|
|
22
47
|
]);
|
|
23
48
|
};
|
|
@@ -13,6 +13,11 @@ export const GeneratorPlugin = () =>
|
|
|
13
13
|
defineModule({
|
|
14
14
|
id: 'dxos.org/test/generator/main',
|
|
15
15
|
activatesOn: Events.Startup,
|
|
16
|
-
activate:
|
|
16
|
+
activate: Main,
|
|
17
|
+
}),
|
|
18
|
+
defineModule({
|
|
19
|
+
id: 'dxos.org/test/generator/toolbar',
|
|
20
|
+
activatesOn: Events.Startup,
|
|
21
|
+
activate: Toolbar,
|
|
17
22
|
}),
|
|
18
23
|
]);
|
|
@@ -9,7 +9,8 @@ import { Button } from '@dxos/react-ui';
|
|
|
9
9
|
import { Log } from './schema';
|
|
10
10
|
import { Capabilities, createSurface } from '../../common';
|
|
11
11
|
import { contributes } from '../../core';
|
|
12
|
-
import { createIntent
|
|
12
|
+
import { createIntent } from '../../plugin-intent';
|
|
13
|
+
import { useIntentDispatcher } from '../../react';
|
|
13
14
|
|
|
14
15
|
export const Logger = () => {
|
|
15
16
|
const { dispatchPromise } = useIntentDispatcher();
|
|
@@ -19,8 +19,11 @@ export const LoggerPlugin = () =>
|
|
|
19
19
|
activate: () => [
|
|
20
20
|
contributes(
|
|
21
21
|
Capabilities.IntentResolver,
|
|
22
|
-
createResolver(
|
|
23
|
-
|
|
22
|
+
createResolver({
|
|
23
|
+
intent: Log,
|
|
24
|
+
resolve: ({ message }) => {
|
|
25
|
+
log.info(message);
|
|
26
|
+
},
|
|
24
27
|
}),
|
|
25
28
|
),
|
|
26
29
|
],
|
|
@@ -28,6 +31,6 @@ export const LoggerPlugin = () =>
|
|
|
28
31
|
defineModule({
|
|
29
32
|
id: 'dxos.org/test/logger/surfaces',
|
|
30
33
|
activatesOn: Events.Startup,
|
|
31
|
-
activate:
|
|
34
|
+
activate: Toolbar,
|
|
32
35
|
}),
|
|
33
36
|
]);
|
|
@@ -2,19 +2,9 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Effect } from 'effect';
|
|
6
|
-
import React from 'react';
|
|
7
|
-
|
|
8
|
-
import { create } from '@dxos/live-object';
|
|
9
|
-
|
|
10
|
-
import { IntentProvider } from './IntentContext';
|
|
11
5
|
import { INTENT_PLUGIN } from './actions';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { contributes, defineModule, definePlugin } from '../core';
|
|
15
|
-
|
|
16
|
-
const defaultEffect = () => Effect.fail(new Error('Intent runtime not ready'));
|
|
17
|
-
const defaultPromise = () => Effect.runPromise(defaultEffect());
|
|
6
|
+
import { Events } from '../common';
|
|
7
|
+
import { defineModule, definePlugin, lazy } from '../core';
|
|
18
8
|
|
|
19
9
|
export const IntentPlugin = () =>
|
|
20
10
|
definePlugin({ id: INTENT_PLUGIN }, [
|
|
@@ -24,37 +14,7 @@ export const IntentPlugin = () =>
|
|
|
24
14
|
// This is fine for now because it's how it worked prior to capabilities api anyways.
|
|
25
15
|
// In the future, the intent dispatcher should be able to be reset without resetting the entire app.
|
|
26
16
|
activatesOn: Events.Startup,
|
|
27
|
-
activatesBefore: [Events.SetupIntents],
|
|
28
17
|
activatesAfter: [Events.DispatcherReady],
|
|
29
|
-
activate: (
|
|
30
|
-
const state = create<IntentContext>({
|
|
31
|
-
dispatch: defaultEffect,
|
|
32
|
-
dispatchPromise: defaultPromise,
|
|
33
|
-
undo: defaultEffect,
|
|
34
|
-
undoPromise: defaultPromise,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// TODO(wittjosiah): Make getResolver callback async and allow resolvers to be requested on demand.
|
|
38
|
-
const { dispatch, dispatchPromise, undo, undoPromise } = createDispatcher((module) =>
|
|
39
|
-
context
|
|
40
|
-
.requestCapabilities(Capabilities.IntentResolver, (c, moduleId): c is AnyIntentResolver => {
|
|
41
|
-
return module ? moduleId === module : true;
|
|
42
|
-
})
|
|
43
|
-
.flat(),
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
state.dispatch = dispatch;
|
|
47
|
-
state.dispatchPromise = dispatchPromise;
|
|
48
|
-
state.undo = undo;
|
|
49
|
-
state.undoPromise = undoPromise;
|
|
50
|
-
|
|
51
|
-
return [
|
|
52
|
-
contributes(Capabilities.IntentDispatcher, state),
|
|
53
|
-
contributes(Capabilities.ReactContext, {
|
|
54
|
-
id: INTENT_PLUGIN,
|
|
55
|
-
context: ({ children }) => <IntentProvider value={state}>{children}</IntentProvider>,
|
|
56
|
-
}),
|
|
57
|
-
];
|
|
58
|
-
},
|
|
18
|
+
activate: lazy(() => import('./intent-dispatcher')),
|
|
59
19
|
}),
|
|
60
20
|
]);
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { Schema as S } from '@effect/schema';
|
|
5
6
|
import { Effect, Fiber, pipe } from 'effect';
|
|
6
7
|
import { describe, expect, test } from 'vitest';
|
|
7
8
|
|
|
8
|
-
import { S } from '@dxos/echo-schema';
|
|
9
|
-
|
|
10
9
|
import { chain, createIntent } from './intent';
|
|
11
10
|
import { type AnyIntentResolver, createDispatcher, createResolver } from './intent-dispatcher';
|
|
12
11
|
|
|
@@ -108,8 +107,8 @@ describe('Intent dispatcher', () => {
|
|
|
108
107
|
const { dispatch } = createDispatcher(() => [computeResolver, toStringResolver, concatResolver]);
|
|
109
108
|
const intent = pipe(createIntent(Compute, { value: 1 }), chain(ToString, {}), chain(Concat, { plus: '!' }));
|
|
110
109
|
|
|
111
|
-
expect(intent.first.
|
|
112
|
-
expect(intent.last.
|
|
110
|
+
expect(intent.first.id).toBe(Compute._tag);
|
|
111
|
+
expect(intent.last.id).toBe(Concat._tag);
|
|
113
112
|
expect(intent.all.length).toBe(3);
|
|
114
113
|
|
|
115
114
|
const program = Effect.gen(function* () {
|
|
@@ -137,7 +136,10 @@ describe('Intent dispatcher', () => {
|
|
|
137
136
|
});
|
|
138
137
|
|
|
139
138
|
test('filter resolvers by plugin', async () => {
|
|
140
|
-
const otherComputeResolver = createResolver(
|
|
139
|
+
const otherComputeResolver = createResolver({
|
|
140
|
+
intent: Compute,
|
|
141
|
+
resolve: async (data) => ({ data: { value: data?.value * 3 } }),
|
|
142
|
+
});
|
|
141
143
|
const { dispatch } = createDispatcher((module) => (module === 'test' ? [computeResolver] : [otherComputeResolver]));
|
|
142
144
|
const program = Effect.gen(function* () {
|
|
143
145
|
const a = yield* dispatch(createIntent(Compute, { value: 1 }));
|
|
@@ -153,8 +155,10 @@ describe('Intent dispatcher', () => {
|
|
|
153
155
|
});
|
|
154
156
|
|
|
155
157
|
test('filter resolvers by predicate', async () => {
|
|
156
|
-
const conditionalComputeResolver = createResolver(
|
|
158
|
+
const conditionalComputeResolver = createResolver({
|
|
159
|
+
intent: Compute,
|
|
157
160
|
filter: (data): data is { value: number } => data?.value > 1,
|
|
161
|
+
resolve: async (data) => ({ data: { value: data?.value * 3 } }),
|
|
158
162
|
});
|
|
159
163
|
const { dispatch } = createDispatcher(() => [conditionalComputeResolver, computeResolver]);
|
|
160
164
|
const program = Effect.gen(function* () {
|
|
@@ -171,8 +175,10 @@ describe('Intent dispatcher', () => {
|
|
|
171
175
|
});
|
|
172
176
|
|
|
173
177
|
test('hoist resolvers', async () => {
|
|
174
|
-
const hoistedComputeResolver = createResolver(
|
|
175
|
-
|
|
178
|
+
const hoistedComputeResolver = createResolver({
|
|
179
|
+
intent: Compute,
|
|
180
|
+
position: 'hoist',
|
|
181
|
+
resolve: async (data) => ({ data: { value: data?.value * 3 } }),
|
|
176
182
|
});
|
|
177
183
|
const { dispatchPromise } = createDispatcher(() => [computeResolver, hoistedComputeResolver]);
|
|
178
184
|
const { data } = await dispatchPromise(createIntent(Compute, { value: 1 }));
|
|
@@ -180,13 +186,17 @@ describe('Intent dispatcher', () => {
|
|
|
180
186
|
});
|
|
181
187
|
|
|
182
188
|
test('fallback resolvers', async () => {
|
|
183
|
-
const conditionalComputeResolver = createResolver(
|
|
189
|
+
const conditionalComputeResolver = createResolver({
|
|
190
|
+
intent: Compute,
|
|
184
191
|
filter: (data): data is { value: number } => data?.value === 1,
|
|
192
|
+
resolve: async (data) => ({ data: { value: data?.value * 2 } }),
|
|
185
193
|
});
|
|
186
|
-
const fallbackComputeResolver = createResolver(
|
|
187
|
-
|
|
194
|
+
const fallbackComputeResolver = createResolver({
|
|
195
|
+
intent: Compute,
|
|
196
|
+
position: 'fallback',
|
|
197
|
+
resolve: async (data) => ({ data: { value: data?.value * 3 } }),
|
|
188
198
|
});
|
|
189
|
-
const { dispatch } = createDispatcher(() => [
|
|
199
|
+
const { dispatch } = createDispatcher(() => [conditionalComputeResolver, fallbackComputeResolver]);
|
|
190
200
|
const program = Effect.gen(function* () {
|
|
191
201
|
const a = yield* dispatch(createIntent(Compute, { value: 1 }));
|
|
192
202
|
|
|
@@ -224,8 +234,9 @@ class ToString extends S.TaggedClass<ToString>()('ToString', {
|
|
|
224
234
|
}),
|
|
225
235
|
}) {}
|
|
226
236
|
|
|
227
|
-
const toStringResolver = createResolver(
|
|
228
|
-
|
|
237
|
+
const toStringResolver = createResolver({
|
|
238
|
+
intent: ToString,
|
|
239
|
+
resolve: async (data) => ({ data: { string: data.value.toString() } }),
|
|
229
240
|
});
|
|
230
241
|
|
|
231
242
|
class Compute extends S.TaggedClass<Compute>()('Compute', {
|
|
@@ -237,16 +248,19 @@ class Compute extends S.TaggedClass<Compute>()('Compute', {
|
|
|
237
248
|
}),
|
|
238
249
|
}) {}
|
|
239
250
|
|
|
240
|
-
const computeResolver = createResolver(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
251
|
+
const computeResolver = createResolver({
|
|
252
|
+
intent: Compute,
|
|
253
|
+
resolve: (data, undo) => {
|
|
254
|
+
return Effect.gen(function* () {
|
|
255
|
+
if (undo) {
|
|
256
|
+
return { data: { value: data.value / 2 } };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
yield* Effect.sleep(data.value * 10);
|
|
260
|
+
const value = data.value * 2;
|
|
261
|
+
return { data: { value }, undoable: { message: 'test', data: { value } } };
|
|
262
|
+
});
|
|
263
|
+
},
|
|
250
264
|
});
|
|
251
265
|
|
|
252
266
|
class Concat extends S.TaggedClass<Concat>()('Concat', {
|
|
@@ -259,8 +273,9 @@ class Concat extends S.TaggedClass<Concat>()('Concat', {
|
|
|
259
273
|
}),
|
|
260
274
|
}) {}
|
|
261
275
|
|
|
262
|
-
const concatResolver = createResolver(
|
|
263
|
-
|
|
276
|
+
const concatResolver = createResolver({
|
|
277
|
+
intent: Concat,
|
|
278
|
+
resolve: async (data) => ({ data: { string: data.string + data.plus } }),
|
|
264
279
|
});
|
|
265
280
|
|
|
266
281
|
class Add extends S.TaggedClass<Add>()('Add', {
|
|
@@ -268,8 +283,9 @@ class Add extends S.TaggedClass<Add>()('Add', {
|
|
|
268
283
|
output: S.Number,
|
|
269
284
|
}) {}
|
|
270
285
|
|
|
271
|
-
const addResolver = createResolver(
|
|
272
|
-
|
|
286
|
+
const addResolver = createResolver({
|
|
287
|
+
intent: Add,
|
|
288
|
+
resolve: async (data) => ({ data: data[0] + data[1] }),
|
|
273
289
|
});
|
|
274
290
|
|
|
275
291
|
class SideEffect extends S.TaggedClass<SideEffect>()('SideEffect', {
|
|
@@ -277,4 +293,7 @@ class SideEffect extends S.TaggedClass<SideEffect>()('SideEffect', {
|
|
|
277
293
|
output: S.Void,
|
|
278
294
|
}) {}
|
|
279
295
|
|
|
280
|
-
const sideEffectResolver = createResolver(
|
|
296
|
+
const sideEffectResolver = createResolver({
|
|
297
|
+
intent: SideEffect,
|
|
298
|
+
resolve: async () => {},
|
|
299
|
+
});
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
import { Effect, Option, pipe, Ref } from 'effect';
|
|
6
6
|
import { type Simplify } from 'effect/Types';
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import { create } from '@dxos/live-object';
|
|
9
|
+
import { byPosition, type MaybePromise, type Position, type GuardedType } from '@dxos/util';
|
|
9
10
|
|
|
10
11
|
import { IntentAction } from './actions';
|
|
11
12
|
import { CycleDetectedError, NoResolversError } from './errors';
|
|
@@ -21,6 +22,8 @@ import {
|
|
|
21
22
|
type IntentSchema,
|
|
22
23
|
type Label,
|
|
23
24
|
} from './intent';
|
|
25
|
+
import { Events, Capabilities } from '../common';
|
|
26
|
+
import { contributes, type PluginsContext } from '../core';
|
|
24
27
|
|
|
25
28
|
const EXECUTION_LIMIT = 100;
|
|
26
29
|
const HISTORY_LIMIT = 100;
|
|
@@ -28,13 +31,13 @@ const HISTORY_LIMIT = 100;
|
|
|
28
31
|
/**
|
|
29
32
|
* The return value of an intent effect.
|
|
30
33
|
*/
|
|
31
|
-
export type IntentEffectResult<
|
|
34
|
+
export type IntentEffectResult<Input, Output> = {
|
|
32
35
|
/**
|
|
33
36
|
* The output of the action that was performed.
|
|
34
37
|
*
|
|
35
38
|
* If the intent is apart of a chain of intents, the data will be passed to the next intent.
|
|
36
39
|
*/
|
|
37
|
-
data?:
|
|
40
|
+
data?: Output;
|
|
38
41
|
|
|
39
42
|
/**
|
|
40
43
|
* If provided, the action will be undoable.
|
|
@@ -48,7 +51,7 @@ export type IntentEffectResult<Fields extends IntentParams> = {
|
|
|
48
51
|
/**
|
|
49
52
|
* Will be merged with the original intent data when firing the undo intent.
|
|
50
53
|
*/
|
|
51
|
-
data?: Partial<
|
|
54
|
+
data?: Partial<Input>;
|
|
52
55
|
};
|
|
53
56
|
|
|
54
57
|
/**
|
|
@@ -66,33 +69,32 @@ export type IntentEffectResult<Fields extends IntentParams> = {
|
|
|
66
69
|
intents?: AnyIntentChain[];
|
|
67
70
|
};
|
|
68
71
|
|
|
69
|
-
export type AnyIntentEffectResult = IntentEffectResult<any>;
|
|
72
|
+
export type AnyIntentEffectResult = IntentEffectResult<any, any>;
|
|
70
73
|
|
|
71
74
|
/**
|
|
72
75
|
* The result of an intent dispatcher.
|
|
73
76
|
*/
|
|
74
|
-
export type IntentDispatcherResult<
|
|
77
|
+
export type IntentDispatcherResult<Input, Output> = Pick<IntentEffectResult<Input, Output>, 'data' | 'error'>;
|
|
75
78
|
|
|
76
79
|
/**
|
|
77
80
|
* The implementation of an intent effect.
|
|
78
81
|
*/
|
|
79
|
-
export type IntentEffectDefinition<
|
|
80
|
-
data:
|
|
82
|
+
export type IntentEffectDefinition<Input, Output> = (
|
|
83
|
+
data: Input,
|
|
81
84
|
undo: boolean,
|
|
82
|
-
) => MaybePromise<IntentEffectResult<
|
|
85
|
+
) => MaybePromise<IntentEffectResult<Input, Output> | void> | Effect.Effect<IntentEffectResult<Input, Output> | void>;
|
|
83
86
|
|
|
84
87
|
/**
|
|
85
88
|
* Intent resolver to match intents to their effects.
|
|
86
89
|
*/
|
|
87
|
-
export type IntentResolver<Tag extends string, Fields extends IntentParams
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
effect: IntentEffectDefinition<Fields>;
|
|
90
|
+
export type IntentResolver<Tag extends string, Fields extends IntentParams, Data = IntentData<Fields>> = Readonly<{
|
|
91
|
+
intent: IntentSchema<Tag, Fields>;
|
|
92
|
+
position?: Position;
|
|
93
|
+
filter?: (data: IntentData<Fields>) => data is Data;
|
|
94
|
+
resolve: IntentEffectDefinition<GuardedType<IntentResolver<Tag, Fields, Data>['filter']>, IntentResultData<Fields>>;
|
|
93
95
|
}>;
|
|
94
96
|
|
|
95
|
-
export type AnyIntentResolver = IntentResolver<any, any>;
|
|
97
|
+
export type AnyIntentResolver = IntentResolver<any, any, any>;
|
|
96
98
|
|
|
97
99
|
/**
|
|
98
100
|
* Creates an intent resolver to match intents to their effects.
|
|
@@ -101,22 +103,16 @@ export type AnyIntentResolver = IntentResolver<any, any>;
|
|
|
101
103
|
* @param params.disposition Determines the priority of the resolver when multiple are resolved.
|
|
102
104
|
* @param params.filter Optional filter to determine if the resolver should be used.
|
|
103
105
|
*/
|
|
104
|
-
export const createResolver = <Tag extends string, Fields extends IntentParams
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
params: Pick<IntentResolver<Tag, Fields>, 'disposition' | 'filter'> = {},
|
|
108
|
-
): IntentResolver<Tag, Fields> => ({
|
|
109
|
-
action: schema._tag,
|
|
110
|
-
effect,
|
|
111
|
-
...params,
|
|
112
|
-
});
|
|
106
|
+
export const createResolver = <Tag extends string, Fields extends IntentParams, Data = IntentData<Fields>>(
|
|
107
|
+
resolver: IntentResolver<Tag, Fields, Data>,
|
|
108
|
+
) => resolver;
|
|
113
109
|
|
|
114
110
|
/**
|
|
115
111
|
* Invokes intents and returns the result.
|
|
116
112
|
*/
|
|
117
113
|
export type PromiseIntentDispatcher = <Fields extends IntentParams>(
|
|
118
114
|
intent: IntentChain<any, any, any, Fields>,
|
|
119
|
-
) => Promise<Simplify<IntentDispatcherResult<Fields
|
|
115
|
+
) => Promise<Simplify<IntentDispatcherResult<IntentData<Fields>, IntentResultData<Fields>>>>;
|
|
120
116
|
|
|
121
117
|
/**
|
|
122
118
|
* Creates an effect for intents.
|
|
@@ -124,9 +120,15 @@ export type PromiseIntentDispatcher = <Fields extends IntentParams>(
|
|
|
124
120
|
export type IntentDispatcher = <Fields extends IntentParams>(
|
|
125
121
|
intent: IntentChain<any, any, any, Fields>,
|
|
126
122
|
depth?: number,
|
|
127
|
-
) => Effect.Effect<
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
) => Effect.Effect<
|
|
124
|
+
Simplify<Required<IntentDispatcherResult<IntentData<Fields>, IntentResultData<Fields>>>['data']>,
|
|
125
|
+
Error
|
|
126
|
+
>;
|
|
127
|
+
|
|
128
|
+
type IntentResult<Tag extends string, Fields extends IntentParams> = IntentEffectResult<
|
|
129
|
+
IntentData<Fields>,
|
|
130
|
+
IntentResultData<Fields>
|
|
131
|
+
> & {
|
|
130
132
|
_intent: Intent<Tag, Fields>;
|
|
131
133
|
};
|
|
132
134
|
|
|
@@ -135,7 +137,7 @@ export type AnyIntentResult = IntentResult<any, any>;
|
|
|
135
137
|
/**
|
|
136
138
|
* Invokes the most recent undoable intent with undo flags.
|
|
137
139
|
*/
|
|
138
|
-
export type PromiseIntentUndo = () => Promise<IntentDispatcherResult<any>>;
|
|
140
|
+
export type PromiseIntentUndo = () => Promise<IntentDispatcherResult<any, any>>;
|
|
139
141
|
|
|
140
142
|
/**
|
|
141
143
|
* Creates an effect which undoes the last intent.
|
|
@@ -158,7 +160,7 @@ export type IntentContext = {
|
|
|
158
160
|
/**
|
|
159
161
|
* Sets of an intent dispatcher.
|
|
160
162
|
*
|
|
161
|
-
* @param
|
|
163
|
+
* @param getResolvers A function that returns an array of available intent resolvers.
|
|
162
164
|
* @param params.historyLimit The maximum number of intent results to keep in history.
|
|
163
165
|
* @param params.executionLimit The maximum recursion depth of intent chains.
|
|
164
166
|
*/
|
|
@@ -168,24 +170,20 @@ export const createDispatcher = (
|
|
|
168
170
|
): IntentContext => {
|
|
169
171
|
const historyRef = Effect.runSync(Ref.make<AnyIntentResult[][]>([]));
|
|
170
172
|
|
|
171
|
-
const handleIntent = (intent: AnyIntent) =>
|
|
172
|
-
|
|
173
|
+
const handleIntent = (intent: AnyIntent) =>
|
|
174
|
+
Effect.gen(function* () {
|
|
173
175
|
const candidates = getResolvers(intent.module)
|
|
174
|
-
.filter((r) => r.
|
|
176
|
+
.filter((r) => r.intent._tag === intent.id)
|
|
175
177
|
.filter((r) => !r.filter || r.filter(intent.data))
|
|
176
|
-
.toSorted(
|
|
178
|
+
.toSorted(byPosition);
|
|
177
179
|
if (candidates.length === 0) {
|
|
178
|
-
|
|
179
|
-
_intent: intent,
|
|
180
|
-
error: new NoResolversError(intent.action),
|
|
181
|
-
} as AnyIntentResult;
|
|
180
|
+
yield* Effect.fail(new NoResolversError(intent.id));
|
|
182
181
|
}
|
|
183
182
|
|
|
184
|
-
const effect = candidates[0].
|
|
183
|
+
const effect = candidates[0].resolve(intent.data, intent.undo ?? false);
|
|
185
184
|
const result = Effect.isEffect(effect) ? yield* effect : yield* Effect.promise(async () => effect);
|
|
186
185
|
return { _intent: intent, ...result } as AnyIntentResult;
|
|
187
186
|
});
|
|
188
|
-
};
|
|
189
187
|
|
|
190
188
|
const dispatch: IntentDispatcher = (intentChain, depth = 0) => {
|
|
191
189
|
return Effect.gen(function* () {
|
|
@@ -267,3 +265,40 @@ export const createDispatcher = (
|
|
|
267
265
|
|
|
268
266
|
return { dispatch, dispatchPromise, undo, undoPromise };
|
|
269
267
|
};
|
|
268
|
+
|
|
269
|
+
const defaultEffect = () => Effect.fail(new Error('Intent runtime not ready'));
|
|
270
|
+
const defaultPromise = () => Effect.runPromise(defaultEffect());
|
|
271
|
+
|
|
272
|
+
export default (context: PluginsContext) => {
|
|
273
|
+
const state = create<IntentContext>({
|
|
274
|
+
dispatch: defaultEffect,
|
|
275
|
+
dispatchPromise: defaultPromise,
|
|
276
|
+
undo: defaultEffect,
|
|
277
|
+
undoPromise: defaultPromise,
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// TODO(wittjosiah): Make getResolver callback async and allow resolvers to be requested on demand.
|
|
281
|
+
const { dispatch, dispatchPromise, undo, undoPromise } = createDispatcher((module) =>
|
|
282
|
+
context
|
|
283
|
+
.requestCapabilities(Capabilities.IntentResolver, (c, moduleId): c is AnyIntentResolver => {
|
|
284
|
+
return module ? moduleId === module : true;
|
|
285
|
+
})
|
|
286
|
+
.flat(),
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
const manager = context.requestCapability(Capabilities.PluginManager);
|
|
290
|
+
state.dispatch = (intentChain, depth) => {
|
|
291
|
+
return Effect.gen(function* () {
|
|
292
|
+
yield* manager._activate(Events.SetupIntents);
|
|
293
|
+
return yield* dispatch(intentChain, depth);
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
state.dispatchPromise = async (intentChain) => {
|
|
297
|
+
await manager.activate(Events.SetupIntents);
|
|
298
|
+
return await dispatchPromise(intentChain);
|
|
299
|
+
};
|
|
300
|
+
state.undo = undo;
|
|
301
|
+
state.undoPromise = undoPromise;
|
|
302
|
+
|
|
303
|
+
return contributes(Capabilities.IntentDispatcher, state);
|
|
304
|
+
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { S } from '@
|
|
5
|
+
import { Schema as S } from '@effect/schema';
|
|
6
6
|
|
|
7
7
|
export type IntentParams = {
|
|
8
8
|
readonly input: S.Schema.All;
|
|
@@ -25,9 +25,9 @@ export type Intent<Tag extends string, Fields extends IntentParams> = {
|
|
|
25
25
|
_schema: IntentSchema<Tag, Fields>;
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* The
|
|
28
|
+
* The id of the intent.
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
id: Tag;
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Any data needed to perform the desired action.
|
|
@@ -84,7 +84,7 @@ export const createIntent = <Tag extends string, Fields extends IntentParams>(
|
|
|
84
84
|
const intent = {
|
|
85
85
|
...params,
|
|
86
86
|
_schema: schema,
|
|
87
|
-
|
|
87
|
+
id: schema._tag,
|
|
88
88
|
data,
|
|
89
89
|
} satisfies Intent<Tag, Fields>;
|
|
90
90
|
|
|
@@ -122,7 +122,7 @@ export const chain =
|
|
|
122
122
|
const last = {
|
|
123
123
|
...params,
|
|
124
124
|
_schema: schema,
|
|
125
|
-
|
|
125
|
+
id: schema._tag,
|
|
126
126
|
data,
|
|
127
127
|
} satisfies Intent<NextTag, NextFields>;
|
|
128
128
|
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { RootSettingsStore } from '@dxos/local-storage';
|
|
6
|
-
|
|
7
5
|
import { SETTINGS_PLUGIN } from './actions';
|
|
6
|
+
import translations from './translations';
|
|
8
7
|
import { Capabilities, Events } from '../common';
|
|
9
|
-
import { contributes, defineModule, definePlugin } from '../core';
|
|
8
|
+
import { contributes, defineModule, definePlugin, lazy } from '../core';
|
|
10
9
|
|
|
10
|
+
// TODO(wittjosiah): Add options to exclude some modules.
|
|
11
11
|
export const SettingsPlugin = () =>
|
|
12
12
|
definePlugin({ id: SETTINGS_PLUGIN }, [
|
|
13
13
|
defineModule({
|
|
@@ -15,15 +15,21 @@ export const SettingsPlugin = () =>
|
|
|
15
15
|
activatesOn: Events.Startup,
|
|
16
16
|
activatesBefore: [Events.SetupSettings],
|
|
17
17
|
activatesAfter: [Events.SettingsReady],
|
|
18
|
-
activate: (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
activate: lazy(() => import('./store')),
|
|
19
|
+
}),
|
|
20
|
+
defineModule({
|
|
21
|
+
id: `${SETTINGS_PLUGIN}/module/translations`,
|
|
22
|
+
activatesOn: Events.SetupTranslations,
|
|
23
|
+
activate: () => contributes(Capabilities.Translations, translations),
|
|
24
|
+
}),
|
|
25
|
+
defineModule({
|
|
26
|
+
id: `${SETTINGS_PLUGIN}/module/intent-resolver`,
|
|
27
|
+
activatesOn: Events.SetupIntents,
|
|
28
|
+
activate: lazy(() => import('./intent-resolver')),
|
|
29
|
+
}),
|
|
30
|
+
defineModule({
|
|
31
|
+
id: `${SETTINGS_PLUGIN}/module/app-graph-builder`,
|
|
32
|
+
activatesOn: Events.SetupAppGraph,
|
|
33
|
+
activate: lazy(() => import('./app-graph-builder')),
|
|
28
34
|
}),
|
|
29
35
|
]);
|