@dxos/app-framework 0.3.11-main.f5e7551 → 0.3.11-main.f7c1031
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/{chunk-C2K6M6WC.mjs → chunk-7MQ2DVDI.mjs} +19 -2
- package/dist/lib/browser/chunk-7MQ2DVDI.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +186 -148
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/plugin-PGPBA2JO.mjs +111 -0
- package/dist/lib/browser/plugin-PGPBA2JO.mjs.map +7 -0
- package/dist/lib/node/{chunk-BOQBLWMX.cjs → chunk-FETX4EGX.cjs} +26 -7
- package/dist/lib/node/chunk-FETX4EGX.cjs.map +7 -0
- package/dist/lib/node/index.cjs +183 -147
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/{plugin-WDNRX2SR.cjs → plugin-HLGHD6N5.cjs} +63 -14
- package/dist/lib/node/plugin-HLGHD6N5.cjs.map +7 -0
- package/dist/types/src/plugins/IntentPlugin/IntentContext.d.ts +10 -2
- package/dist/types/src/plugins/IntentPlugin/IntentContext.d.ts.map +1 -1
- package/dist/types/src/plugins/IntentPlugin/intent.d.ts +34 -1
- package/dist/types/src/plugins/IntentPlugin/intent.d.ts.map +1 -1
- package/dist/types/src/plugins/IntentPlugin/plugin.d.ts.map +1 -1
- package/dist/types/src/plugins/IntentPlugin/provides.d.ts +2 -2
- package/dist/types/src/plugins/IntentPlugin/provides.d.ts.map +1 -1
- package/dist/types/src/plugins/PluginHost/PluginHost.d.ts +4 -2
- package/dist/types/src/plugins/PluginHost/PluginHost.d.ts.map +1 -1
- package/dist/types/src/plugins/PluginHost/plugin.d.ts +1 -1
- package/dist/types/src/plugins/PluginHost/plugin.d.ts.map +1 -1
- package/dist/types/src/plugins/SurfacePlugin/Surface.d.ts +4 -5
- package/dist/types/src/plugins/SurfacePlugin/Surface.d.ts.map +1 -1
- package/dist/types/src/plugins/common/layout.d.ts +17 -15
- package/dist/types/src/plugins/common/layout.d.ts.map +1 -1
- package/package.json +8 -7
- package/project.json +3 -1
- package/src/plugins/IntentPlugin/IntentContext.tsx +27 -3
- package/src/plugins/IntentPlugin/intent.ts +41 -1
- package/src/plugins/IntentPlugin/plugin.tsx +60 -7
- package/src/plugins/IntentPlugin/provides.ts +2 -2
- package/src/plugins/PluginHost/PluginHost.tsx +92 -57
- package/src/plugins/PluginHost/plugin.ts +2 -1
- package/src/plugins/SurfacePlugin/Surface.tsx +15 -21
- package/src/plugins/common/layout.ts +16 -14
- package/src/vite-env.d.ts +5 -0
- package/tsconfig.json +3 -0
- package/dist/lib/browser/chunk-C2K6M6WC.mjs.map +0 -7
- package/dist/lib/browser/plugin-CBPJO5NB.mjs +0 -63
- package/dist/lib/browser/plugin-CBPJO5NB.mjs.map +0 -7
- package/dist/lib/node/chunk-BOQBLWMX.cjs.map +0 -7
- package/dist/lib/node/plugin-WDNRX2SR.cjs.map +0 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/IntentPlugin/plugin.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/IntentPlugin/plugin.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,oBAAoB,EAA0D,MAAM,YAAY,CAAC;AAC/G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAKtD;;;GAGG;AACH,QAAA,MAAM,YAAY,QAAO,iBAAiB,oBAAoB,CAsF7D,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type IntentContext } from './IntentContext';
|
|
2
|
-
import { type
|
|
2
|
+
import { type IntentResolver } from './intent';
|
|
3
3
|
import { type Plugin } from '../PluginHost';
|
|
4
4
|
export type IntentResolverProvides = {
|
|
5
5
|
intent: {
|
|
6
|
-
resolver:
|
|
6
|
+
resolver: IntentResolver;
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
export type IntentPluginProvides = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provides.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/IntentPlugin/provides.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"provides.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/IntentPlugin/provides.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE;QACN,QAAQ,EAAE,cAAc,CAAC;KAC1B,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,aAAa,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,iBAAiB,WAAY,MAAM,6CACkD,CAAC;AAEnG,eAAO,MAAM,yBAAyB,WAAY,MAAM,+CAC4C,CAAC"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import { type PluginContext } from './PluginContext';
|
|
3
3
|
import { type Plugin, type PluginDefinition } from './plugin';
|
|
4
|
+
import { ErrorBoundary } from '../SurfacePlugin';
|
|
4
5
|
export type BootstrapPluginsParams = {
|
|
5
6
|
order: PluginDefinition['meta'][];
|
|
6
7
|
plugins: Record<string, () => Promise<PluginDefinition>>;
|
|
7
8
|
core?: string[];
|
|
8
9
|
defaults?: string[];
|
|
9
|
-
fallback?:
|
|
10
|
+
fallback?: ErrorBoundary['props']['fallback'];
|
|
11
|
+
placeholder?: ReactNode;
|
|
10
12
|
};
|
|
11
13
|
export type PluginHostProvides = {
|
|
12
14
|
plugins: PluginContext;
|
|
@@ -15,7 +17,7 @@ export declare const parsePluginHost: (plugin: Plugin) => Plugin<PluginHostProvi
|
|
|
15
17
|
/**
|
|
16
18
|
* Bootstraps an application by initializing plugins and rendering root components.
|
|
17
19
|
*/
|
|
18
|
-
export declare const PluginHost: ({ order, plugins: definitions, core, defaults, fallback, }: BootstrapPluginsParams) => PluginDefinition<PluginHostProvides>;
|
|
20
|
+
export declare const PluginHost: ({ order, plugins: definitions, core, defaults, fallback, placeholder, }: BootstrapPluginsParams) => PluginDefinition<PluginHostProvides>;
|
|
19
21
|
/**
|
|
20
22
|
* Resolve a `PluginDefinition` into a fully initialized `Plugin`.
|
|
21
23
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginHost.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/PluginHost/PluginHost.tsx"],"names":[],"mappings":"AAKA,OAAc,EAA8C,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"PluginHost.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/PluginHost/PluginHost.tsx"],"names":[],"mappings":"AAKA,OAAc,EAA8C,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAKpG,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,gBAAgB,EAAuB,MAAM,UAAU,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACzD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;IAC9C,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,eAAe,WAAY,MAAM,2CACwD,CAAC;AAIvG;;GAEG;AACH,eAAO,MAAM,UAAU,4EAOpB,sBAAsB,KAAG,iBAAiB,kBAAkB,CAkC9D,CAAC;AAmFF;;GAEG;AACH,eAAO,MAAM,gBAAgB,4EAS5B,CAAC"}
|
|
@@ -70,7 +70,7 @@ export type PluginDefinition<TProvides = {}, TInitializeProvides = {}> = Omit<Pl
|
|
|
70
70
|
*
|
|
71
71
|
* @return Capabilities provided by the plugin which are merged with base capabilities.
|
|
72
72
|
*/
|
|
73
|
-
initialize?: () => Promise<PluginProvides<TInitializeProvides
|
|
73
|
+
initialize?: () => Promise<PluginProvides<TInitializeProvides> | void>;
|
|
74
74
|
/**
|
|
75
75
|
* Called once all plugins have been initialized.
|
|
76
76
|
* This is the place to do any initialization which requires other plugins to be ready.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/PluginHost/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEnD;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,SAAS,IAAI,SAAS,GAAG;IAClD;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAKhC,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,MAAM,CAAC,SAAS,GAAG,EAAE,IAAI;IACnC,IAAI,EAAE;QACJ;;;;;;WAMG;QACH,EAAE,EAAE,MAAM,CAAC;QAEX;;;;WAIG;QAEH,OAAO,CAAC,EAAE,MAAM,CAAC;QAEjB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,CAAC;QAEd;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;WAEG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAElB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAEhB;;WAEG;QAEH,aAAa,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;KAC/B,CAAC;IAEF;;OAEG;IACH,QAAQ,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;CACrC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,SAAS,GAAG,EAAE,EAAE,mBAAmB,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG;IAClG;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC;IAEzC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/PluginHost/plugin.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEnD;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,SAAS,IAAI,SAAS,GAAG;IAClD;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAKhC,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC;CAC9B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,MAAM,CAAC,SAAS,GAAG,EAAE,IAAI;IACnC,IAAI,EAAE;QACJ;;;;;;WAMG;QACH,EAAE,EAAE,MAAM,CAAC;QAEX;;;;WAIG;QAEH,OAAO,CAAC,EAAE,MAAM,CAAC;QAEjB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,CAAC;QAEd;;WAEG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;WAEG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAC;QAElB;;WAEG;QACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAEhB;;WAEG;QAEH,aAAa,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;KAC/B,CAAC;IAEF;;OAEG;IACH,QAAQ,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC;CACrC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,SAAS,GAAG,EAAE,EAAE,mBAAmB,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG;IAClG;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,CAAC;IAEzC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC,CAAC;IAEvE;;;;;OAKG;IAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,UAAU,SAAU,MAAM,CAAC,MAAM,CAAC;IAlF3C;;;;;;OAMG;QACC,MAAM;IAEV;;;;OAIG;;IAIH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;CA2CiD,CAAC;AAEzD,KAAK,UAAU,CAAC,CAAC,IAAI,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,gBAAgB,CAAA;CAAE,CAAC,CAAC;AAEhF,yBAAiB,MAAM,CAAC;IACf,MAAM,IAAI,yFAKhB,CAAC;CACH"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { type
|
|
1
|
+
import React, { type ReactNode, type PropsWithChildren } from 'react';
|
|
2
2
|
import { ErrorBoundary } from './ErrorBoundary';
|
|
3
3
|
/**
|
|
4
4
|
* Direction determines how multiple components are laid out.
|
|
@@ -28,11 +28,10 @@ export type SurfaceProps = PropsWithChildren<{
|
|
|
28
28
|
*/
|
|
29
29
|
fallback?: ErrorBoundary['props']['fallback'];
|
|
30
30
|
/**
|
|
31
|
-
* If specified,
|
|
32
|
-
*
|
|
33
|
-
* @deprecated Provide a component with `disposition: 'fallback'` instead.
|
|
31
|
+
* If specified, the Surface will be wrapped in a suspense boundary.
|
|
32
|
+
* The placeholder component will be rendered while the surface component is loading.
|
|
34
33
|
*/
|
|
35
|
-
|
|
34
|
+
placeholder?: ReactNode;
|
|
36
35
|
/**
|
|
37
36
|
* If more than one component is resolved, the limit determines how many are rendered.
|
|
38
37
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Surface.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/SurfacePlugin/Surface.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAEZ,KAAK,
|
|
1
|
+
{"version":3,"file":"Surface.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/SurfacePlugin/Surface.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAEZ,KAAK,SAAS,EAGd,KAAK,iBAAiB,EAGvB,MAAM,OAAO,CAAC;AAGf,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,gBAAgB,GAAG,OAAO,GAAG,eAAe,CAAC;AAEhF,MAAM,MAAM,YAAY,GAAG,iBAAiB,CAAC;IAC3C;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE/B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC;IAEnE;;;OAGG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;IAE9C;;;OAGG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IAExB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB;;;OAGG;IACH,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,OAAO,yGAiBnB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { type IntentData } from '../IntentPlugin';
|
|
2
3
|
import type { Plugin } from '../PluginHost';
|
|
3
4
|
/**
|
|
4
5
|
* Basic state provided by a layout plugin.
|
|
@@ -56,34 +57,35 @@ export declare enum LayoutAction {
|
|
|
56
57
|
CLOSE_DIALOG = "dxos.org/plugin/layout/close-dialog",
|
|
57
58
|
OPEN_POPOVER = "dxos.org/plugin/layout/open-popover",
|
|
58
59
|
CLOSE_POPOVER = "dxos.org/plugin/layout/close-popover",
|
|
59
|
-
ACTIVATE = "dxos.org/plugin/layout/activate"
|
|
60
|
+
ACTIVATE = "dxos.org/plugin/layout/activate",
|
|
61
|
+
FOCUS = "dxos.org/plugin/layout/focus"
|
|
60
62
|
}
|
|
61
63
|
/**
|
|
62
64
|
* Expected payload for layout actions.
|
|
63
65
|
*/
|
|
64
66
|
export declare namespace LayoutAction {
|
|
65
|
-
type ToggleFullscreen = {
|
|
67
|
+
type ToggleFullscreen = IntentData<{
|
|
66
68
|
state?: boolean;
|
|
67
|
-
}
|
|
68
|
-
type ToggleSidebar = {
|
|
69
|
+
}>;
|
|
70
|
+
type ToggleSidebar = IntentData<{
|
|
69
71
|
state?: boolean;
|
|
70
|
-
}
|
|
71
|
-
type ToggleComplementarySidebar = {
|
|
72
|
+
}>;
|
|
73
|
+
type ToggleComplementarySidebar = IntentData<{
|
|
72
74
|
state?: boolean;
|
|
73
|
-
}
|
|
74
|
-
type OpenDialog = {
|
|
75
|
+
}>;
|
|
76
|
+
type OpenDialog = IntentData<{
|
|
75
77
|
component: string;
|
|
76
78
|
subject: any;
|
|
77
|
-
}
|
|
78
|
-
type CloseDialog = {}
|
|
79
|
-
type OpenPopover = {
|
|
79
|
+
}>;
|
|
80
|
+
type CloseDialog = IntentData<{}>;
|
|
81
|
+
type OpenPopover = IntentData<{
|
|
80
82
|
anchorId: string;
|
|
81
83
|
component: string;
|
|
82
84
|
subject: any;
|
|
83
|
-
}
|
|
84
|
-
type ClosePopover = {}
|
|
85
|
-
type Activate = {
|
|
85
|
+
}>;
|
|
86
|
+
type ClosePopover = IntentData<{}>;
|
|
87
|
+
type Activate = IntentData<{
|
|
86
88
|
id: string;
|
|
87
|
-
}
|
|
89
|
+
}>;
|
|
88
90
|
}
|
|
89
91
|
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/common/layout.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAM5C;;GAEG;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBjB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,WAAY,MAAM,uCAG/C,CAAC;AAQF,oBAAY,YAAY;IACtB,iBAAiB,6CAAuC;IACxD,cAAc,0CAAoC;IAClD,4BAA4B,wDAAkD;IAC9E,WAAW,uCAAiC;IAC5C,YAAY,wCAAkC;IAC9C,YAAY,wCAAkC;IAC9C,aAAa,yCAAmC;IAChD,QAAQ,oCAA8B;
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/plugins/common/layout.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAM5C;;GAEG;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBjB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,WAAY,MAAM,uCAG/C,CAAC;AAQF,oBAAY,YAAY;IACtB,iBAAiB,6CAAuC;IACxD,cAAc,0CAAoC;IAClD,4BAA4B,wDAAkD;IAC9E,WAAW,uCAAiC;IAC5C,YAAY,wCAAkC;IAC9C,YAAY,wCAAkC;IAC9C,aAAa,yCAAmC;IAChD,QAAQ,oCAA8B;IACtC,KAAK,iCAA2B;CACjC;AAED;;GAEG;AACH,yBAAiB,YAAY,CAAC;IAC5B,KAAY,gBAAgB,GAAG,UAAU,CAAC;QACxC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC,CAAC;IAEH,KAAY,aAAa,GAAG,UAAU,CAAC;QACrC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC,CAAC;IAEH,KAAY,0BAA0B,GAAG,UAAU,CAAC;QAClD,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC,CAAC;IAEH,KAAY,UAAU,GAAG,UAAU,CAAC;QAClC,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,GAAG,CAAC;KACd,CAAC,CAAC;IAEH,KAAY,WAAW,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;IAEzC,KAAY,WAAW,GAAG,UAAU,CAAC;QACnC,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,GAAG,CAAC;KACd,CAAC,CAAC;IAEH,KAAY,YAAY,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;IAE1C,KAAY,QAAQ,GAAG,UAAU,CAAC;QAChC,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC,CAAC;CACJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/app-framework",
|
|
3
|
-
"version": "0.3.11-main.
|
|
3
|
+
"version": "0.3.11-main.f7c1031",
|
|
4
4
|
"description": "A framework for building applications from composible plugins.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -16,12 +16,13 @@
|
|
|
16
16
|
"@preact/signals-react": "^1.3.6",
|
|
17
17
|
"deepsignal": "1.4.0-shallow.0",
|
|
18
18
|
"zod": "^3.22.4",
|
|
19
|
-
"@dxos/
|
|
20
|
-
"@dxos/
|
|
21
|
-
"@dxos/
|
|
22
|
-
"@dxos/
|
|
23
|
-
"@dxos/
|
|
24
|
-
"@dxos/log": "0.3.11-main.
|
|
19
|
+
"@dxos/app-graph": "0.3.11-main.f7c1031",
|
|
20
|
+
"@dxos/debug": "0.3.11-main.f7c1031",
|
|
21
|
+
"@dxos/async": "0.3.11-main.f7c1031",
|
|
22
|
+
"@dxos/local-storage": "0.3.11-main.f7c1031",
|
|
23
|
+
"@dxos/invariant": "0.3.11-main.f7c1031",
|
|
24
|
+
"@dxos/log": "0.3.11-main.f7c1031",
|
|
25
|
+
"@dxos/util": "0.3.11-main.f7c1031"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"@types/react": "^18.0.21",
|
package/project.json
CHANGED
|
@@ -3,15 +3,39 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type Context, createContext, useContext, type Provider } from 'react';
|
|
6
|
+
import { useEffect } from 'react';
|
|
6
7
|
|
|
7
|
-
import { type
|
|
8
|
+
import { type UnsubscribeCallback } from '@dxos/async';
|
|
9
|
+
|
|
10
|
+
import { type IntentDispatcher, type IntentResolver } from './intent';
|
|
8
11
|
|
|
9
12
|
export type IntentContext = {
|
|
10
|
-
dispatch:
|
|
13
|
+
dispatch: IntentDispatcher;
|
|
14
|
+
registerResolver: (pluginId: string, resolver: IntentResolver) => UnsubscribeCallback;
|
|
11
15
|
};
|
|
12
16
|
|
|
13
|
-
const IntentContext: Context<IntentContext> = createContext<IntentContext>({
|
|
17
|
+
const IntentContext: Context<IntentContext> = createContext<IntentContext>({
|
|
18
|
+
dispatch: async () => ({}),
|
|
19
|
+
registerResolver: () => () => {},
|
|
20
|
+
});
|
|
14
21
|
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated
|
|
24
|
+
* TODO(burdon): Use useIntentDispatcher.
|
|
25
|
+
*/
|
|
15
26
|
export const useIntent = () => useContext(IntentContext);
|
|
16
27
|
|
|
28
|
+
// TODO(burdon): Dispatch or Dispatcher?
|
|
29
|
+
export const useIntentDispatcher = (): IntentDispatcher => {
|
|
30
|
+
const { dispatch } = useIntent();
|
|
31
|
+
return dispatch;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const useIntentResolver = (plugin: string, resolver: IntentResolver) => {
|
|
35
|
+
const { registerResolver } = useIntent();
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
return registerResolver(plugin, resolver);
|
|
38
|
+
}, [plugin, resolver]);
|
|
39
|
+
};
|
|
40
|
+
|
|
17
41
|
export const IntentProvider: Provider<IntentContext> = IntentContext.Provider;
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import type { MaybePromise } from '@dxos/util';
|
|
6
|
+
|
|
7
|
+
import type { Plugin } from '../PluginHost';
|
|
8
|
+
|
|
9
|
+
export type IntentData<T extends Record<string, any> = Record<string, any>> = T & {
|
|
10
|
+
/**
|
|
11
|
+
* The data from the result of the previous intent.
|
|
12
|
+
*/
|
|
13
|
+
result?: any;
|
|
14
|
+
};
|
|
15
|
+
|
|
5
16
|
/**
|
|
6
17
|
* An intent is an abstract description of an operation to be performed.
|
|
7
18
|
* Intents allow actions to be performed across plugins.
|
|
@@ -22,7 +33,28 @@ export type Intent = {
|
|
|
22
33
|
/**
|
|
23
34
|
* Any data needed to perform the desired action.
|
|
24
35
|
*/
|
|
36
|
+
data?: IntentData;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type IntentResult = {
|
|
40
|
+
/**
|
|
41
|
+
* The output of the action that was performed.
|
|
42
|
+
*
|
|
43
|
+
* If the intent is apart of a chain of intents, the data will be passed to the next intent.
|
|
44
|
+
*/
|
|
25
45
|
data?: any;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* An error that occurred while performing the action.
|
|
49
|
+
*
|
|
50
|
+
* If the intent is apart of a chain of intents and an error occurs, the chain will be aborted.
|
|
51
|
+
*/
|
|
52
|
+
error?: Error;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Other intent chains to be triggered.
|
|
56
|
+
*/
|
|
57
|
+
intents?: Intent[][];
|
|
26
58
|
};
|
|
27
59
|
|
|
28
60
|
/**
|
|
@@ -31,4 +63,12 @@ export type Intent = {
|
|
|
31
63
|
*
|
|
32
64
|
* @returns The result of the last intent.
|
|
33
65
|
*/
|
|
34
|
-
export type
|
|
66
|
+
export type IntentDispatcher = (intent: Intent | Intent[]) => Promise<IntentResult | void>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Resolves an intent that was dispatched.
|
|
70
|
+
* If the intent is not handled, nothing should be returned.
|
|
71
|
+
*
|
|
72
|
+
* @returns The result of the intent.
|
|
73
|
+
*/
|
|
74
|
+
export type IntentResolver = (intent: Intent, plugins: Plugin[]) => MaybePromise<IntentResult | void>;
|
|
@@ -5,19 +5,25 @@
|
|
|
5
5
|
import { deepSignal } from 'deepsignal/react';
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
|
+
import { log } from '@dxos/log';
|
|
9
|
+
|
|
8
10
|
import { type IntentContext, IntentProvider } from './IntentContext';
|
|
9
|
-
import type { Intent } from './intent';
|
|
11
|
+
import type { Intent, IntentResolver, IntentResult } from './intent';
|
|
10
12
|
import IntentMeta from './meta';
|
|
11
13
|
import { type IntentPluginProvides, type IntentResolverProvides, parseIntentResolverPlugin } from './provides';
|
|
12
14
|
import type { PluginDefinition } from '../PluginHost';
|
|
13
15
|
import { filterPlugins, findPlugin } from '../helpers';
|
|
14
16
|
|
|
17
|
+
const EXECUTION_LIMIT = 1000;
|
|
18
|
+
|
|
15
19
|
/**
|
|
16
20
|
* Allows plugins to register intent handlers and routes sent intents to the appropriate plugin.
|
|
17
21
|
* Inspired by https://developer.android.com/reference/android/content/Intent.
|
|
18
22
|
*/
|
|
19
23
|
const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
|
|
20
|
-
const state = deepSignal<IntentContext>({ dispatch: async () => {} });
|
|
24
|
+
const state = deepSignal<IntentContext>({ dispatch: async () => ({}), registerResolver: () => () => {} });
|
|
25
|
+
|
|
26
|
+
const dynamicResolvers = new Set<{ plugin: string; resolver: IntentResolver }>();
|
|
21
27
|
|
|
22
28
|
return {
|
|
23
29
|
meta: IntentMeta,
|
|
@@ -25,8 +31,25 @@ const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
|
|
|
25
31
|
// Dispatch intent to associated plugin.
|
|
26
32
|
const dispatch = async (intent: Intent) => {
|
|
27
33
|
if (intent.plugin) {
|
|
34
|
+
for (const entry of dynamicResolvers) {
|
|
35
|
+
if (entry.plugin === intent.plugin) {
|
|
36
|
+
const result = await entry.resolver(intent, plugins);
|
|
37
|
+
if (result) {
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
28
43
|
const plugin = findPlugin<IntentResolverProvides>(plugins, intent.plugin);
|
|
29
|
-
|
|
44
|
+
const result = plugin?.provides.intent.resolver(intent, plugins);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
for (const entry of dynamicResolvers) {
|
|
49
|
+
const result = await entry.resolver(intent, plugins);
|
|
50
|
+
if (result) {
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
30
53
|
}
|
|
31
54
|
|
|
32
55
|
// Return resolved value from first plugin that handles the intent.
|
|
@@ -36,17 +59,47 @@ const IntentPlugin = (): PluginDefinition<IntentPluginProvides> => {
|
|
|
36
59
|
return result;
|
|
37
60
|
}
|
|
38
61
|
}
|
|
62
|
+
|
|
63
|
+
// https://vitejs.dev/guide/env-and-mode#env-variables
|
|
64
|
+
// TODO(wittjosiah): How to handle this more generically?
|
|
65
|
+
if (import.meta?.env?.DEV) {
|
|
66
|
+
log.warn('No plugin found to handle intent', intent);
|
|
67
|
+
}
|
|
39
68
|
};
|
|
40
69
|
|
|
41
70
|
// Sequentially dispatch array of invents.
|
|
42
|
-
|
|
43
|
-
|
|
71
|
+
const dispatchChain = async (intentOrArray: Intent | Intent[], depth = 0) => {
|
|
72
|
+
if (depth > EXECUTION_LIMIT) {
|
|
73
|
+
return {
|
|
74
|
+
error: new Error(
|
|
75
|
+
`Intent execution limit exceeded (${EXECUTION_LIMIT} iterations). This is likely due to an infinite loop within intent resolvers.`,
|
|
76
|
+
),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let result: IntentResult | undefined;
|
|
44
81
|
for (const intent of Array.isArray(intentOrArray) ? intentOrArray : [intentOrArray]) {
|
|
45
|
-
const data = intent.data ? {
|
|
46
|
-
result = await dispatch({ ...intent, data });
|
|
82
|
+
const data = intent.data ? { result: result?.data, ...intent.data } : result?.data;
|
|
83
|
+
result = (await dispatch({ ...intent, data })) ?? undefined;
|
|
84
|
+
|
|
85
|
+
if (result?.error) {
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
result?.intents?.forEach((intents) => {
|
|
90
|
+
void dispatchChain(intents, depth + 1);
|
|
91
|
+
});
|
|
47
92
|
}
|
|
93
|
+
|
|
48
94
|
return result;
|
|
49
95
|
};
|
|
96
|
+
|
|
97
|
+
state.dispatch = dispatchChain;
|
|
98
|
+
state.registerResolver = (plugin, resolver) => {
|
|
99
|
+
const entry = { plugin, resolver };
|
|
100
|
+
dynamicResolvers.add(entry);
|
|
101
|
+
return () => dynamicResolvers.delete(entry);
|
|
102
|
+
};
|
|
50
103
|
},
|
|
51
104
|
provides: {
|
|
52
105
|
intent: state,
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { type IntentContext } from './IntentContext';
|
|
6
|
-
import { type
|
|
6
|
+
import { type IntentResolver } from './intent';
|
|
7
7
|
import { type Plugin } from '../PluginHost';
|
|
8
8
|
|
|
9
9
|
export type IntentResolverProvides = {
|
|
10
10
|
intent: {
|
|
11
|
-
resolver:
|
|
11
|
+
resolver: IntentResolver;
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -3,20 +3,22 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { shallow } from 'deepsignal/react';
|
|
6
|
-
import React, { useEffect, type FC, type PropsWithChildren, type ReactNode } from 'react';
|
|
6
|
+
import React, { useEffect, type FC, type PropsWithChildren, type ReactNode, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { LocalStorageStore } from '@dxos/local-storage';
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
|
|
11
11
|
import { type PluginContext, PluginProvider } from './PluginContext';
|
|
12
12
|
import { type Plugin, type PluginDefinition, type PluginProvides } from './plugin';
|
|
13
|
+
import { ErrorBoundary } from '../SurfacePlugin';
|
|
13
14
|
|
|
14
15
|
export type BootstrapPluginsParams = {
|
|
15
16
|
order: PluginDefinition['meta'][];
|
|
16
17
|
plugins: Record<string, () => Promise<PluginDefinition>>;
|
|
17
18
|
core?: string[];
|
|
18
19
|
defaults?: string[];
|
|
19
|
-
fallback?:
|
|
20
|
+
fallback?: ErrorBoundary['props']['fallback'];
|
|
21
|
+
placeholder?: ReactNode;
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
export type PluginHostProvides = {
|
|
@@ -36,7 +38,8 @@ export const PluginHost = ({
|
|
|
36
38
|
plugins: definitions,
|
|
37
39
|
core = [],
|
|
38
40
|
defaults = [],
|
|
39
|
-
fallback =
|
|
41
|
+
fallback = DefaultFallback,
|
|
42
|
+
placeholder = null,
|
|
40
43
|
}: BootstrapPluginsParams): PluginDefinition<PluginHostProvides> => {
|
|
41
44
|
const state = new LocalStorageStore<PluginContext>(PLUGIN_HOST, {
|
|
42
45
|
ready: false,
|
|
@@ -63,65 +66,97 @@ export const PluginHost = ({
|
|
|
63
66
|
plugins: state.values,
|
|
64
67
|
context: ({ children }) => <PluginProvider value={state.values}>{children}</PluginProvider>,
|
|
65
68
|
root: () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const indexB = order.findIndex(({ id }) => id === b);
|
|
72
|
-
return indexA - indexB;
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
const enabled = await Promise.all(
|
|
76
|
-
enabledIds
|
|
77
|
-
.map((id) => definitions[id])
|
|
78
|
-
// If local storage indicates a plugin is enabled, but it is not available, ignore it.
|
|
79
|
-
.filter((definition): definition is () => Promise<PluginDefinition> => Boolean(definition))
|
|
80
|
-
.map((definition) => definition()),
|
|
81
|
-
);
|
|
82
|
-
|
|
83
|
-
const plugins = await Promise.all(
|
|
84
|
-
enabled.map(async (definition) => {
|
|
85
|
-
const plugin = await initializePlugin(definition).catch((err) => {
|
|
86
|
-
console.error('Failed to initialize plugin:', definition.meta.id, err);
|
|
87
|
-
return undefined;
|
|
88
|
-
});
|
|
89
|
-
return plugin;
|
|
90
|
-
}),
|
|
91
|
-
).then((plugins) => plugins.filter((plugin): plugin is Plugin => Boolean(plugin)));
|
|
92
|
-
log('plugins initialized', { plugins });
|
|
93
|
-
|
|
94
|
-
await Promise.all(
|
|
95
|
-
enabled.map(async (pluginDefinition) => {
|
|
96
|
-
await pluginDefinition.ready?.(plugins);
|
|
97
|
-
}),
|
|
98
|
-
);
|
|
99
|
-
log('plugins ready', { plugins });
|
|
100
|
-
|
|
101
|
-
state.values.plugins = shallow(plugins);
|
|
102
|
-
state.values.ready = true;
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
return () => {
|
|
106
|
-
clearTimeout(timeout);
|
|
107
|
-
state.values.ready = false;
|
|
108
|
-
// TODO(wittjosiah): Does this ever need to be called prior to having dynamic plugins?
|
|
109
|
-
// void Promise.all(enabled.map((definition) => definition.unload?.()));
|
|
110
|
-
};
|
|
111
|
-
}, []);
|
|
112
|
-
|
|
113
|
-
if (!state.values.ready) {
|
|
114
|
-
return <>{fallback}</>;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const ComposedContext = composeContext(state.values.plugins);
|
|
118
|
-
|
|
119
|
-
return <ComposedContext>{rootComponents(state.values.plugins)}</ComposedContext>;
|
|
69
|
+
return (
|
|
70
|
+
<ErrorBoundary fallback={fallback}>
|
|
71
|
+
<Root order={order} core={core} definitions={definitions} state={state.values} placeholder={placeholder} />
|
|
72
|
+
</ErrorBoundary>
|
|
73
|
+
);
|
|
120
74
|
},
|
|
121
75
|
},
|
|
122
76
|
};
|
|
123
77
|
};
|
|
124
78
|
|
|
79
|
+
const DefaultFallback = ({ error }: { error: Error }) => {
|
|
80
|
+
return (
|
|
81
|
+
<div style={{ padding: '1rem' }}>
|
|
82
|
+
{/* TODO(wittjosiah): Link to docs for replacing default. */}
|
|
83
|
+
<h1 style={{ fontSize: '1.2rem', fontWeight: 700, margin: '0.5rem 0' }}>{error.message}</h1>
|
|
84
|
+
<pre>{error.stack}</pre>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
type RootProps = {
|
|
90
|
+
order: PluginDefinition['meta'][];
|
|
91
|
+
state: PluginContext;
|
|
92
|
+
definitions: Record<string, () => Promise<PluginDefinition>>;
|
|
93
|
+
core: string[];
|
|
94
|
+
placeholder: ReactNode;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const Root = ({ order, core: corePluginIds, definitions, state, placeholder }: RootProps) => {
|
|
98
|
+
const [error, setError] = useState<unknown>();
|
|
99
|
+
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
log('initializing plugins', { enabled: state.enabled });
|
|
102
|
+
const timeout = setTimeout(async () => {
|
|
103
|
+
try {
|
|
104
|
+
const enabledIds = [...corePluginIds, ...state.enabled].sort((a, b) => {
|
|
105
|
+
const indexA = order.findIndex(({ id }) => id === a);
|
|
106
|
+
const indexB = order.findIndex(({ id }) => id === b);
|
|
107
|
+
return indexA - indexB;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const enabled = await Promise.all(
|
|
111
|
+
enabledIds
|
|
112
|
+
.map((id) => definitions[id])
|
|
113
|
+
// If local storage indicates a plugin is enabled, but it is not available, ignore it.
|
|
114
|
+
.filter((definition): definition is () => Promise<PluginDefinition> => Boolean(definition))
|
|
115
|
+
.map((definition) => definition()),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const plugins = await Promise.all(
|
|
119
|
+
enabled.map(async (definition) => {
|
|
120
|
+
const plugin = await initializePlugin(definition).catch((err) => {
|
|
121
|
+
console.error('Failed to initialize plugin:', definition.meta.id, err);
|
|
122
|
+
return undefined;
|
|
123
|
+
});
|
|
124
|
+
return plugin;
|
|
125
|
+
}),
|
|
126
|
+
).then((plugins) => plugins.filter((plugin): plugin is Plugin => Boolean(plugin)));
|
|
127
|
+
log('plugins initialized', { plugins });
|
|
128
|
+
|
|
129
|
+
await Promise.all(enabled.map((pluginDefinition) => pluginDefinition.ready?.(plugins)));
|
|
130
|
+
log('plugins ready', { plugins });
|
|
131
|
+
|
|
132
|
+
state.plugins = shallow(plugins);
|
|
133
|
+
state.ready = true;
|
|
134
|
+
} catch (err) {
|
|
135
|
+
setError(err);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return () => {
|
|
140
|
+
clearTimeout(timeout);
|
|
141
|
+
state.ready = false;
|
|
142
|
+
// TODO(wittjosiah): Does this ever need to be called prior to having dynamic plugins?
|
|
143
|
+
// void Promise.all(enabled.map((definition) => definition.unload?.()));
|
|
144
|
+
};
|
|
145
|
+
}, []);
|
|
146
|
+
|
|
147
|
+
if (error) {
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!state.ready) {
|
|
152
|
+
return <>{placeholder}</>;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const ComposedContext = composeContext(state.plugins);
|
|
156
|
+
|
|
157
|
+
return <ComposedContext>{rootComponents(state.plugins)}</ComposedContext>;
|
|
158
|
+
};
|
|
159
|
+
|
|
125
160
|
/**
|
|
126
161
|
* Resolve a `PluginDefinition` into a fully initialized `Plugin`.
|
|
127
162
|
*/
|
|
@@ -91,7 +91,7 @@ export type PluginDefinition<TProvides = {}, TInitializeProvides = {}> = Omit<Pl
|
|
|
91
91
|
*
|
|
92
92
|
* @return Capabilities provided by the plugin which are merged with base capabilities.
|
|
93
93
|
*/
|
|
94
|
-
initialize?: () => Promise<PluginProvides<TInitializeProvides
|
|
94
|
+
initialize?: () => Promise<PluginProvides<TInitializeProvides> | void>;
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
97
|
* Called once all plugins have been initialized.
|
|
@@ -99,6 +99,7 @@ export type PluginDefinition<TProvides = {}, TInitializeProvides = {}> = Omit<Pl
|
|
|
99
99
|
*
|
|
100
100
|
* @param plugins All plugins which successfully initialized.
|
|
101
101
|
*/
|
|
102
|
+
// TODO(wittjosiah): Rename `ready` to a verb?
|
|
102
103
|
ready?: (plugins: Plugin[]) => Promise<void>;
|
|
103
104
|
|
|
104
105
|
/**
|