@dxos/app-framework 0.8.4-main.8360d9e660 → 0.8.4-main.8baae0fced
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/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/browser/{capability-5OFLR7J4.mjs → capability-K5XIVCQU.mjs} +12 -11
- package/dist/lib/browser/capability-K5XIVCQU.mjs.map +7 -0
- package/dist/lib/browser/{chunk-WEBSGU5L.mjs → chunk-5AHASNDW.mjs} +20 -5
- package/dist/lib/browser/chunk-5AHASNDW.mjs.map +7 -0
- package/dist/lib/browser/chunk-5GY3YOEL.mjs +28 -0
- package/dist/lib/browser/chunk-5GY3YOEL.mjs.map +7 -0
- package/dist/lib/browser/{chunk-272IPLHQ.mjs → chunk-66IXTIVK.mjs} +3 -2
- package/dist/lib/browser/chunk-66IXTIVK.mjs.map +7 -0
- package/dist/lib/browser/{chunk-JGWCBVKJ.mjs → chunk-BRK6GYNB.mjs} +14 -42
- package/dist/lib/browser/chunk-BRK6GYNB.mjs.map +7 -0
- package/dist/lib/browser/{chunk-TGX63LTL.mjs → chunk-FJ4765WW.mjs} +1 -1
- package/dist/lib/browser/{chunk-TGX63LTL.mjs.map → chunk-FJ4765WW.mjs.map} +2 -2
- package/dist/lib/browser/chunk-FO3IYSLV.mjs +68 -0
- package/dist/lib/browser/chunk-FO3IYSLV.mjs.map +7 -0
- package/dist/lib/browser/{chunk-YNFPIQGB.mjs → chunk-IW44C7UL.mjs} +9 -2
- package/dist/lib/browser/chunk-IW44C7UL.mjs.map +7 -0
- package/dist/lib/browser/{chunk-TIEBZMTF.mjs → chunk-KFDF7KR3.mjs} +9 -11
- package/dist/lib/browser/{chunk-TIEBZMTF.mjs.map → chunk-KFDF7KR3.mjs.map} +3 -3
- package/dist/lib/browser/chunk-KLHQNYJ2.mjs +422 -0
- package/dist/lib/browser/chunk-KLHQNYJ2.mjs.map +7 -0
- package/dist/lib/browser/chunk-QLML5QFJ.mjs +581 -0
- package/dist/lib/browser/chunk-QLML5QFJ.mjs.map +7 -0
- package/dist/lib/browser/{chunk-GH3M2LIW.mjs → chunk-SLX73WRZ.mjs} +85 -15
- package/dist/lib/browser/chunk-SLX73WRZ.mjs.map +7 -0
- package/dist/lib/browser/chunk-UVTGHZQF.mjs +513 -0
- package/dist/lib/browser/chunk-UVTGHZQF.mjs.map +7 -0
- package/dist/lib/browser/chunk-VJ5PFAWC.mjs +1446 -0
- package/dist/lib/browser/chunk-VJ5PFAWC.mjs.map +7 -0
- package/dist/lib/browser/cli/index.mjs +15 -30
- package/dist/lib/browser/cli/index.mjs.map +3 -3
- package/dist/lib/browser/common/activation-events.mjs +11 -14
- package/dist/lib/browser/common/capabilities.mjs +19 -8
- package/dist/lib/browser/core/activation-event.mjs +1 -1
- package/dist/lib/browser/core/capability.mjs +5 -1
- package/dist/lib/browser/core/plugin-manager.mjs +8 -4
- package/dist/lib/browser/core/plugin.mjs +12 -2
- package/dist/lib/browser/core/url-loader.mjs +24 -0
- package/dist/lib/browser/index.mjs +47 -49
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/process-manager-capability-JIWLN7SU.mjs +89 -0
- package/dist/lib/browser/process-manager-capability-JIWLN7SU.mjs.map +7 -0
- package/dist/lib/browser/testing/index.mjs +164 -34
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/browser/testing/react.mjs +78 -0
- package/dist/lib/browser/testing/react.mjs.map +7 -0
- package/dist/lib/browser/ui/index.mjs +24 -15
- package/dist/lib/node-esm/{capability-CRHZKL6T.mjs → capability-RLKFFLTB.mjs} +12 -11
- package/dist/lib/node-esm/capability-RLKFFLTB.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-FKE4Z3D6.mjs → chunk-37Z53PXZ.mjs} +1 -1
- package/dist/lib/node-esm/{chunk-FKE4Z3D6.mjs.map → chunk-37Z53PXZ.mjs.map} +2 -2
- package/dist/lib/node-esm/chunk-42UNAKYO.mjs +423 -0
- package/dist/lib/node-esm/chunk-42UNAKYO.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-LHCJGNXK.mjs → chunk-6S45OMUP.mjs} +85 -15
- package/dist/lib/node-esm/chunk-6S45OMUP.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-3D66SZHP.mjs → chunk-BYHYYJZH.mjs} +14 -42
- package/dist/lib/node-esm/chunk-BYHYYJZH.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-SB5ODNPX.mjs → chunk-CTKEZHKF.mjs} +9 -2
- package/dist/lib/node-esm/chunk-CTKEZHKF.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-JNT72ZCN.mjs +514 -0
- package/dist/lib/node-esm/chunk-JNT72ZCN.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-KFZEB6BV.mjs +29 -0
- package/dist/lib/node-esm/chunk-KFZEB6BV.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-LJNUFNDO.mjs +582 -0
- package/dist/lib/node-esm/chunk-LJNUFNDO.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-SCDGIGGU.mjs → chunk-OUEMWPIW.mjs} +9 -11
- package/dist/lib/node-esm/{chunk-SCDGIGGU.mjs.map → chunk-OUEMWPIW.mjs.map} +3 -3
- package/dist/lib/node-esm/{chunk-SQICGJBW.mjs → chunk-PW2VYGOS.mjs} +20 -5
- package/dist/lib/node-esm/chunk-PW2VYGOS.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-SFYCO3PT.mjs +1447 -0
- package/dist/lib/node-esm/chunk-SFYCO3PT.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-WK7OIQKI.mjs +70 -0
- package/dist/lib/node-esm/chunk-WK7OIQKI.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-6REV5DE7.mjs → chunk-XOCUANHO.mjs} +3 -2
- package/dist/lib/node-esm/chunk-XOCUANHO.mjs.map +7 -0
- package/dist/lib/node-esm/cli/index.mjs +15 -30
- package/dist/lib/node-esm/cli/index.mjs.map +3 -3
- package/dist/lib/node-esm/common/activation-events.mjs +11 -14
- package/dist/lib/node-esm/common/capabilities.mjs +19 -8
- package/dist/lib/node-esm/core/activation-event.mjs +1 -1
- package/dist/lib/node-esm/core/capability.mjs +5 -1
- package/dist/lib/node-esm/core/plugin-manager.mjs +8 -4
- package/dist/lib/node-esm/core/plugin.mjs +12 -2
- package/dist/lib/node-esm/core/url-loader.mjs +25 -0
- package/dist/lib/node-esm/index.mjs +47 -49
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/process-manager-capability-PHKLO2BL.mjs +90 -0
- package/dist/lib/node-esm/process-manager-capability-PHKLO2BL.mjs.map +7 -0
- package/dist/lib/node-esm/testing/index.mjs +164 -34
- package/dist/lib/node-esm/testing/index.mjs.map +4 -4
- package/dist/lib/node-esm/testing/react.mjs +79 -0
- package/dist/lib/node-esm/testing/react.mjs.map +7 -0
- package/dist/lib/node-esm/ui/index.mjs +24 -15
- package/dist/plugin/node-esm/index.mjs +893 -0
- package/dist/plugin/node-esm/index.mjs.map +7 -0
- package/dist/plugin/node-esm/meta.json +1 -0
- package/dist/types/src/cli/cli.d.ts +1 -3
- package/dist/types/src/cli/cli.d.ts.map +1 -1
- package/dist/types/src/common/activation-events.d.ts +10 -13
- package/dist/types/src/common/activation-events.d.ts.map +1 -1
- package/dist/types/src/common/annotations.d.ts +1 -0
- package/dist/types/src/common/annotations.d.ts.map +1 -0
- package/dist/types/src/common/capabilities.d.ts +113 -12
- package/dist/types/src/common/capabilities.d.ts.map +1 -1
- package/dist/types/src/common/operations.d.ts +8 -22
- package/dist/types/src/common/operations.d.ts.map +1 -1
- package/dist/types/src/core/activation-event.d.ts +4 -4
- package/dist/types/src/core/activation-event.d.ts.map +1 -1
- package/dist/types/src/core/capability-manager.d.ts +5 -0
- package/dist/types/src/core/capability-manager.d.ts.map +1 -1
- package/dist/types/src/core/capability.d.ts +13 -2
- package/dist/types/src/core/capability.d.ts.map +1 -1
- package/dist/types/src/core/edge-registry-plugin-provider.d.ts +30 -0
- package/dist/types/src/core/edge-registry-plugin-provider.d.ts.map +1 -0
- package/dist/types/src/core/index.d.ts +6 -0
- package/dist/types/src/core/index.d.ts.map +1 -1
- package/dist/types/src/core/plugin-asset-cache.d.ts +71 -0
- package/dist/types/src/core/plugin-asset-cache.d.ts.map +1 -0
- package/dist/types/src/core/plugin-manager.d.ts +232 -7
- package/dist/types/src/core/plugin-manager.d.ts.map +1 -1
- package/dist/types/src/core/plugin-manifest.d.ts +101 -0
- package/dist/types/src/core/plugin-manifest.d.ts.map +1 -0
- package/dist/types/src/core/plugin-manifest.test.d.ts +2 -0
- package/dist/types/src/core/plugin-manifest.test.d.ts.map +1 -0
- package/dist/types/src/core/plugin.d.ts +176 -6
- package/dist/types/src/core/plugin.d.ts.map +1 -1
- package/dist/types/src/core/registry.d.ts +107 -0
- package/dist/types/src/core/registry.d.ts.map +1 -0
- package/dist/types/src/core/url-loader.d.ts +127 -0
- package/dist/types/src/core/url-loader.d.ts.map +1 -0
- package/dist/types/src/core/url-loader.test.d.ts +2 -0
- package/dist/types/src/core/url-loader.test.d.ts.map +1 -0
- package/dist/types/src/helpers.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/plugin-process-manager/ProcessManagerPlugin.d.ts +3 -0
- package/dist/types/src/plugin-process-manager/ProcessManagerPlugin.d.ts.map +1 -0
- package/dist/types/src/plugin-process-manager/history/capability.d.ts.map +1 -0
- package/dist/types/src/plugin-process-manager/history/errors.d.ts +32 -0
- package/dist/types/src/plugin-process-manager/history/errors.d.ts.map +1 -0
- package/dist/types/src/{plugin-operation → plugin-process-manager}/history/history-tracker.d.ts +1 -1
- package/dist/types/src/plugin-process-manager/history/history-tracker.d.ts.map +1 -0
- package/dist/types/src/plugin-process-manager/history/history-tracker.test.d.ts.map +1 -0
- package/dist/types/src/plugin-process-manager/history/index.d.ts.map +1 -0
- package/dist/types/src/{plugin-operation → plugin-process-manager}/history/types.d.ts +1 -1
- package/dist/types/src/plugin-process-manager/history/types.d.ts.map +1 -0
- package/dist/types/src/{plugin-operation → plugin-process-manager}/history/undo-mapping.d.ts +1 -1
- package/dist/types/src/plugin-process-manager/history/undo-mapping.d.ts.map +1 -0
- package/dist/types/src/{plugin-operation → plugin-process-manager}/history/undo-registry.d.ts +1 -1
- package/dist/types/src/plugin-process-manager/history/undo-registry.d.ts.map +1 -0
- package/dist/types/src/plugin-process-manager/history/undo-registry.test.d.ts.map +1 -0
- package/dist/types/src/plugin-process-manager/index.d.ts +3 -0
- package/dist/types/src/plugin-process-manager/index.d.ts.map +1 -0
- package/dist/types/src/plugin-process-manager/meta.d.ts.map +1 -0
- package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts +8 -0
- package/dist/types/src/plugin-process-manager/process-manager-capability.d.ts.map +1 -0
- package/dist/types/src/plugin-process-manager/testing.d.ts +59 -0
- package/dist/types/src/plugin-process-manager/testing.d.ts.map +1 -0
- package/dist/types/src/testing/harness.d.ts +79 -0
- package/dist/types/src/testing/harness.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/react.d.ts +27 -0
- package/dist/types/src/testing/react.d.ts.map +1 -0
- package/dist/types/src/testing/react.test.d.ts +2 -0
- package/dist/types/src/testing/react.test.d.ts.map +1 -0
- package/dist/types/src/testing/service.d.ts.map +1 -1
- package/dist/types/src/testing/withPluginManager.d.ts.map +1 -1
- package/dist/types/src/testing/withPluginManager.stories.d.ts.map +1 -1
- package/dist/types/src/ui/components/App/App.d.ts +3 -2
- package/dist/types/src/ui/components/App/App.d.ts.map +1 -1
- package/dist/types/src/ui/components/App/App.stories.d.ts +2 -2
- package/dist/types/src/ui/components/App/App.stories.d.ts.map +1 -1
- package/dist/types/src/ui/components/Placeholder/Placeholder.d.ts +64 -0
- package/dist/types/src/ui/components/Placeholder/Placeholder.d.ts.map +1 -0
- package/dist/types/src/ui/components/Placeholder/Placeholder.stories.d.ts +19 -0
- package/dist/types/src/ui/components/Placeholder/Placeholder.stories.d.ts.map +1 -0
- package/dist/types/src/ui/components/Placeholder/index.d.ts +2 -0
- package/dist/types/src/ui/components/Placeholder/index.d.ts.map +1 -0
- package/dist/types/src/ui/components/PluginManager/PluginManagerContext.stories.d.ts.map +1 -1
- package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts +16 -4
- package/dist/types/src/ui/components/Surface/SurfaceComponent.d.ts.map +1 -1
- package/dist/types/src/ui/components/Surface/SurfaceComponent.stories.d.ts.map +1 -1
- package/dist/types/src/ui/components/Surface/SurfaceInfo.d.ts.map +1 -1
- package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts +48 -0
- package/dist/types/src/ui/components/Surface/SurfaceProfilerContext.d.ts.map +1 -0
- package/dist/types/src/ui/components/Surface/index.d.ts +22 -6
- package/dist/types/src/ui/components/Surface/index.d.ts.map +1 -1
- package/dist/types/src/ui/components/Surface/types.d.ts +110 -9
- package/dist/types/src/ui/components/Surface/types.d.ts.map +1 -1
- package/dist/types/src/ui/components/Surface/types.test.d.ts +2 -0
- package/dist/types/src/ui/components/Surface/types.test.d.ts.map +1 -0
- package/dist/types/src/ui/components/index.d.ts +1 -0
- package/dist/types/src/ui/components/index.d.ts.map +1 -1
- package/dist/types/src/ui/hooks/index.d.ts +1 -1
- package/dist/types/src/ui/hooks/index.d.ts.map +1 -1
- package/dist/types/src/ui/hooks/useApp.d.ts +47 -11
- package/dist/types/src/ui/hooks/useApp.d.ts.map +1 -1
- package/dist/types/src/ui/hooks/useCapabilities.d.ts.map +1 -1
- package/dist/types/src/ui/hooks/useLoading.d.ts.map +1 -1
- package/dist/types/src/ui/hooks/useProcessManagerRuntime.d.ts +24 -0
- package/dist/types/src/ui/hooks/useProcessManagerRuntime.d.ts.map +1 -0
- package/dist/types/src/ui/hooks/useSettingsState.d.ts.map +1 -1
- package/dist/types/src/vite-plugin/boot-loader/BootLoader.stories.d.ts +34 -0
- package/dist/types/src/vite-plugin/boot-loader/BootLoader.stories.d.ts.map +1 -0
- package/dist/types/src/vite-plugin/boot-loader/index.d.ts +2 -0
- package/dist/types/src/vite-plugin/boot-loader/index.d.ts.map +1 -0
- package/dist/types/src/vite-plugin/boot-loader/loader.d.ts +51 -0
- package/dist/types/src/vite-plugin/boot-loader/loader.d.ts.map +1 -0
- package/dist/types/src/vite-plugin/composer/index.d.ts +34 -0
- package/dist/types/src/vite-plugin/composer/index.d.ts.map +1 -0
- package/dist/types/src/vite-plugin/import-map/index.d.ts +28 -0
- package/dist/types/src/vite-plugin/import-map/index.d.ts.map +1 -0
- package/dist/types/src/vite-plugin/index.d.ts +5 -0
- package/dist/types/src/vite-plugin/index.d.ts.map +1 -0
- package/dist/types/src/vite-plugin/manifest.d.ts +41 -0
- package/dist/types/src/vite-plugin/manifest.d.ts.map +1 -0
- package/dist/types/src/vite-plugin/manifest.test.d.ts +2 -0
- package/dist/types/src/vite-plugin/manifest.test.d.ts.map +1 -0
- package/dist/types/src/vite-plugin/packages.d.ts +13 -0
- package/dist/types/src/vite-plugin/packages.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/moon.yml +15 -0
- package/package.json +53 -54
- package/src/cli/cli.ts +2 -7
- package/src/common/activation-events.ts +10 -15
- package/src/common/annotations.ts +3 -0
- package/src/common/capabilities.ts +147 -16
- package/src/common/operations.ts +5 -8
- package/src/core/activation-event.ts +4 -1
- package/src/core/capability-manager.test.ts +1 -1
- package/src/core/capability-manager.ts +22 -1
- package/src/core/capability.ts +20 -2
- package/src/core/edge-registry-plugin-provider.ts +92 -0
- package/src/core/index.ts +6 -0
- package/src/core/plugin-asset-cache.ts +60 -0
- package/src/core/plugin-manager.test.ts +816 -10
- package/src/core/plugin-manager.ts +865 -46
- package/src/core/plugin-manifest.test.ts +75 -0
- package/src/core/plugin-manifest.ts +134 -0
- package/src/core/plugin.ts +185 -10
- package/src/core/registry.ts +163 -0
- package/src/core/url-loader.test.ts +221 -0
- package/src/core/url-loader.ts +388 -0
- package/src/index.ts +1 -2
- package/src/plugin-process-manager/ProcessManagerPlugin.ts +24 -0
- package/src/{plugin-operation → plugin-process-manager}/history/capability.ts +1 -2
- package/src/plugin-process-manager/history/errors.ts +7 -0
- package/src/{plugin-operation → plugin-process-manager}/history/history-tracker.test.ts +37 -43
- package/src/{plugin-operation → plugin-process-manager}/history/history-tracker.ts +1 -2
- package/src/{plugin-operation → plugin-process-manager}/history/types.ts +1 -1
- package/src/{plugin-operation → plugin-process-manager}/history/undo-mapping.ts +1 -1
- package/src/{plugin-operation → plugin-process-manager}/history/undo-registry.test.ts +3 -4
- package/src/{plugin-operation → plugin-process-manager}/history/undo-registry.ts +1 -1
- package/src/{plugin-operation → plugin-process-manager}/index.ts +1 -1
- package/src/plugin-process-manager/meta.ts +14 -0
- package/src/plugin-process-manager/process-manager-capability.ts +178 -0
- package/src/{plugin-operation → plugin-process-manager}/testing.ts +26 -45
- package/src/testing/harness.ts +247 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/react.test.tsx +48 -0
- package/src/testing/react.tsx +113 -0
- package/src/testing/service.ts +2 -2
- package/src/testing/withPluginManager.stories.tsx +1 -2
- package/src/testing/withPluginManager.tsx +5 -4
- package/src/ui/components/App/App.stories.tsx +5 -11
- package/src/ui/components/App/App.tsx +29 -5
- package/src/ui/components/Placeholder/Placeholder.stories.tsx +77 -0
- package/src/ui/components/Placeholder/Placeholder.tsx +155 -0
- package/src/{plugin-runtime → ui/components/Placeholder}/index.ts +1 -1
- package/src/ui/components/PluginManager/PluginManagerContext.stories.tsx +5 -4
- package/src/ui/components/Surface/SurfaceComponent.stories.tsx +16 -15
- package/src/ui/components/Surface/SurfaceComponent.tsx +111 -55
- package/src/ui/components/Surface/SurfaceInfo.tsx +0 -1
- package/src/ui/components/Surface/SurfaceProfilerContext.tsx +207 -0
- package/src/ui/components/Surface/index.ts +35 -1
- package/src/ui/components/Surface/types.test.ts +126 -0
- package/src/ui/components/Surface/types.ts +164 -12
- package/src/ui/components/index.ts +1 -0
- package/src/ui/hooks/index.ts +1 -1
- package/src/ui/hooks/useApp.test.tsx +2 -2
- package/src/ui/hooks/useApp.tsx +216 -17
- package/src/ui/hooks/useLoading.tsx +14 -6
- package/src/ui/hooks/useProcessManagerRuntime.ts +68 -0
- package/src/vite-plugin/boot-loader/BootLoader.stories.tsx +270 -0
- package/src/vite-plugin/boot-loader/boot-loader.css +320 -0
- package/src/vite-plugin/boot-loader/boot-loader.js +325 -0
- package/src/vite-plugin/boot-loader/index.ts +5 -0
- package/src/vite-plugin/boot-loader/loader.ts +123 -0
- package/src/vite-plugin/composer/index.ts +306 -0
- package/src/vite-plugin/import-map/index.ts +527 -0
- package/src/vite-plugin/index.ts +10 -0
- package/src/vite-plugin/manifest.test.ts +46 -0
- package/src/vite-plugin/manifest.ts +57 -0
- package/src/vite-plugin/packages.ts +187 -0
- package/tsconfig.json +25 -1
- package/tsconfig.node.json +1 -1
- package/.swc/plugins/linux_x86_64_19.0.0/727453fb3a62f7f1d952a41e051ca8a6f88cadc45cee43c6a4d1aa45f9b75665.wasmer-v7 +0 -0
- package/dist/lib/browser/capability-5OFLR7J4.mjs.map +0 -7
- package/dist/lib/browser/capability-ZHQDZRP5.mjs +0 -37
- package/dist/lib/browser/capability-ZHQDZRP5.mjs.map +0 -7
- package/dist/lib/browser/chunk-272IPLHQ.mjs.map +0 -7
- package/dist/lib/browser/chunk-3VXJONTI.mjs +0 -933
- package/dist/lib/browser/chunk-3VXJONTI.mjs.map +0 -7
- package/dist/lib/browser/chunk-7AL6SKIV.mjs +0 -728
- package/dist/lib/browser/chunk-7AL6SKIV.mjs.map +0 -7
- package/dist/lib/browser/chunk-GH3M2LIW.mjs.map +0 -7
- package/dist/lib/browser/chunk-JGWCBVKJ.mjs.map +0 -7
- package/dist/lib/browser/chunk-M5IC326L.mjs +0 -34
- package/dist/lib/browser/chunk-M5IC326L.mjs.map +0 -7
- package/dist/lib/browser/chunk-WEBSGU5L.mjs.map +0 -7
- package/dist/lib/browser/chunk-YAFEA4GV.mjs +0 -1
- package/dist/lib/browser/chunk-YNFPIQGB.mjs.map +0 -7
- package/dist/lib/browser/invoker-capability-YTTQ2OBB.mjs +0 -36
- package/dist/lib/browser/invoker-capability-YTTQ2OBB.mjs.map +0 -7
- package/dist/lib/node-esm/capability-CRHZKL6T.mjs.map +0 -7
- package/dist/lib/node-esm/capability-W5C5464H.mjs +0 -38
- package/dist/lib/node-esm/capability-W5C5464H.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-3D66SZHP.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-6REV5DE7.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-CMDON4NG.mjs +0 -934
- package/dist/lib/node-esm/chunk-CMDON4NG.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-I7FZT4A7.mjs +0 -729
- package/dist/lib/node-esm/chunk-I7FZT4A7.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-LHCJGNXK.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-NHXBSAQR.mjs +0 -35
- package/dist/lib/node-esm/chunk-NHXBSAQR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-SB5ODNPX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-SQICGJBW.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-Z4TJPSMP.mjs +0 -2
- package/dist/lib/node-esm/invoker-capability-BU26474T.mjs +0 -37
- package/dist/lib/node-esm/invoker-capability-BU26474T.mjs.map +0 -7
- package/dist/types/src/plugin-operation/OperationPlugin.d.ts +0 -3
- package/dist/types/src/plugin-operation/OperationPlugin.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/history/capability.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/history/errors.d.ts +0 -5
- package/dist/types/src/plugin-operation/history/errors.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/history/history-tracker.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/history/history-tracker.test.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/history/index.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/history/types.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/history/undo-mapping.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/history/undo-registry.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/history/undo-registry.test.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/index.d.ts +0 -3
- package/dist/types/src/plugin-operation/index.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/invoker-capability.d.ts +0 -6
- package/dist/types/src/plugin-operation/invoker-capability.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/meta.d.ts.map +0 -1
- package/dist/types/src/plugin-operation/testing.d.ts +0 -109
- package/dist/types/src/plugin-operation/testing.d.ts.map +0 -1
- package/dist/types/src/plugin-runtime/RuntimePlugin.d.ts +0 -3
- package/dist/types/src/plugin-runtime/RuntimePlugin.d.ts.map +0 -1
- package/dist/types/src/plugin-runtime/capability.d.ts +0 -6
- package/dist/types/src/plugin-runtime/capability.d.ts.map +0 -1
- package/dist/types/src/plugin-runtime/index.d.ts +0 -2
- package/dist/types/src/plugin-runtime/index.d.ts.map +0 -1
- package/dist/types/src/plugin-runtime/meta.d.ts +0 -3
- package/dist/types/src/plugin-runtime/meta.d.ts.map +0 -1
- package/dist/types/src/ui/hooks/useOperationResolver.d.ts +0 -19
- package/dist/types/src/ui/hooks/useOperationResolver.d.ts.map +0 -1
- package/src/plugin-operation/OperationPlugin.ts +0 -25
- package/src/plugin-operation/history/errors.ts +0 -11
- package/src/plugin-operation/invoker-capability.ts +0 -40
- package/src/plugin-operation/meta.ts +0 -11
- package/src/plugin-runtime/RuntimePlugin.ts +0 -20
- package/src/plugin-runtime/capability.ts +0 -53
- package/src/plugin-runtime/meta.ts +0 -11
- package/src/ui/hooks/useOperationResolver.ts +0 -40
- /package/dist/lib/browser/{chunk-YAFEA4GV.mjs.map → core/url-loader.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-Z4TJPSMP.mjs.map → core/url-loader.mjs.map} +0 -0
- /package/dist/types/src/{plugin-operation → plugin-process-manager}/history/capability.d.ts +0 -0
- /package/dist/types/src/{plugin-operation → plugin-process-manager}/history/history-tracker.test.d.ts +0 -0
- /package/dist/types/src/{plugin-operation → plugin-process-manager}/history/index.d.ts +0 -0
- /package/dist/types/src/{plugin-operation → plugin-process-manager}/history/undo-registry.test.d.ts +0 -0
- /package/dist/types/src/{plugin-operation → plugin-process-manager}/meta.d.ts +0 -0
- /package/src/{plugin-operation → plugin-process-manager}/history/index.ts +0 -0
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { afterEach, assert, describe, it } from '@effect/vitest';
|
|
6
5
|
import { type Atom, Registry } from '@effect-atom/atom-react';
|
|
6
|
+
import { afterEach, assert, describe, it } from '@effect/vitest';
|
|
7
7
|
import * as Cause from 'effect/Cause';
|
|
8
|
-
import * as Exit from 'effect/Exit';
|
|
9
8
|
import * as Duration from 'effect/Duration';
|
|
10
9
|
import * as Effect from 'effect/Effect';
|
|
10
|
+
import * as Exit from 'effect/Exit';
|
|
11
11
|
import * as Fiber from 'effect/Fiber';
|
|
12
12
|
import * as Match from 'effect/Match';
|
|
13
13
|
import * as PubSub from 'effect/PubSub';
|
|
@@ -18,7 +18,6 @@ import { invariant } from '@dxos/invariant';
|
|
|
18
18
|
import { type LogConfig, type LogEntry, LogLevel, log } from '@dxos/log';
|
|
19
19
|
|
|
20
20
|
import { ActivationEvents } from '../common';
|
|
21
|
-
|
|
22
21
|
import * as ActivationEvent from './activation-event';
|
|
23
22
|
import * as Capability from './capability';
|
|
24
23
|
import type * as CapabilityManager from './capability-manager';
|
|
@@ -62,7 +61,7 @@ describe('PluginManager', () => {
|
|
|
62
61
|
const pluginLoader = Effect.fn(function* (id: string) {
|
|
63
62
|
const plugin = plugins.find((plugin) => plugin.meta.id === id);
|
|
64
63
|
invariant(plugin, `Plugin not found: ${id}`);
|
|
65
|
-
return plugin;
|
|
64
|
+
return { plugin };
|
|
66
65
|
});
|
|
67
66
|
|
|
68
67
|
afterEach(() => {
|
|
@@ -77,14 +76,138 @@ describe('PluginManager', () => {
|
|
|
77
76
|
|
|
78
77
|
const manager = PluginManager.make({ pluginLoader });
|
|
79
78
|
const added = yield* manager.add(testMeta.id);
|
|
80
|
-
assert.
|
|
79
|
+
assert.strictEqual(added, testPlugin);
|
|
81
80
|
assert.deepStrictEqual(manager.getPlugins(), [testPlugin]);
|
|
82
|
-
|
|
81
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
82
|
+
const removed = yield* manager.remove(testMeta.id);
|
|
83
83
|
assert.isTrue(removed);
|
|
84
84
|
assert.deepStrictEqual(manager.getPlugins(), []);
|
|
85
85
|
}),
|
|
86
86
|
);
|
|
87
87
|
|
|
88
|
+
it.effect('should add plugin when locator differs from meta.id', () =>
|
|
89
|
+
Effect.gen(function* () {
|
|
90
|
+
const Test = Plugin.make(Plugin.define(testMeta));
|
|
91
|
+
const testPlugin = Test();
|
|
92
|
+
|
|
93
|
+
const urlLocator = 'https://example.com/plugin.mjs';
|
|
94
|
+
const urlLoader = Effect.fn(function* (locator: string) {
|
|
95
|
+
if (locator === urlLocator) {
|
|
96
|
+
return { plugin: testPlugin };
|
|
97
|
+
}
|
|
98
|
+
return yield* Effect.fail(new Error(`Unknown locator: ${locator}`));
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const manager = PluginManager.make({ pluginLoader: urlLoader });
|
|
102
|
+
const added = yield* manager.add(urlLocator);
|
|
103
|
+
assert.strictEqual(added, testPlugin);
|
|
104
|
+
assert.deepStrictEqual(manager.getPlugins(), [testPlugin]);
|
|
105
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
106
|
+
yield* manager.enable(added.meta.id);
|
|
107
|
+
assert.deepStrictEqual(manager.getEnabled(), [testMeta.id]);
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
it.effect('dev plugin shadows an existing plugin with the same id', () =>
|
|
112
|
+
Effect.gen(function* () {
|
|
113
|
+
const productionPlugin = Plugin.make(
|
|
114
|
+
Plugin.define(testMeta).pipe(
|
|
115
|
+
Plugin.addModule({
|
|
116
|
+
id: 'Prod',
|
|
117
|
+
activatesOn: ActivationEvents.Startup,
|
|
118
|
+
activate: () => Effect.succeed(Capability.contributes(String, { string: 'prod' })),
|
|
119
|
+
}),
|
|
120
|
+
),
|
|
121
|
+
)();
|
|
122
|
+
const devPlugin = Plugin.make(
|
|
123
|
+
Plugin.define(testMeta).pipe(
|
|
124
|
+
Plugin.addModule({
|
|
125
|
+
id: 'Dev',
|
|
126
|
+
activatesOn: ActivationEvents.Startup,
|
|
127
|
+
activate: () => Effect.succeed(Capability.contributes(String, { string: 'dev' })),
|
|
128
|
+
}),
|
|
129
|
+
),
|
|
130
|
+
)();
|
|
131
|
+
|
|
132
|
+
const loader = Effect.fn(function* (locator: string) {
|
|
133
|
+
if (locator === 'prod') {
|
|
134
|
+
return { plugin: productionPlugin };
|
|
135
|
+
}
|
|
136
|
+
if (locator === 'dev') {
|
|
137
|
+
return { plugin: devPlugin, dev: true };
|
|
138
|
+
}
|
|
139
|
+
return yield* Effect.fail(new Error(`Unknown locator: ${locator}`));
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const manager = PluginManager.make({ pluginLoader: loader });
|
|
143
|
+
yield* manager.add('prod');
|
|
144
|
+
yield* manager.enable(testMeta.id);
|
|
145
|
+
yield* manager.activate(ActivationEvents.Startup);
|
|
146
|
+
assert.deepStrictEqual(
|
|
147
|
+
manager.capabilities.getAll(String).map((value) => value.string),
|
|
148
|
+
['prod'],
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Loading the dev plugin with the same id swaps it into the id slot.
|
|
152
|
+
yield* manager.add('dev');
|
|
153
|
+
yield* manager.enable(testMeta.id);
|
|
154
|
+
assert.strictEqual(
|
|
155
|
+
manager.getPlugins().find((plugin) => plugin.meta.id === testMeta.id),
|
|
156
|
+
devPlugin,
|
|
157
|
+
);
|
|
158
|
+
yield* manager.reset(ActivationEvents.Startup);
|
|
159
|
+
assert.deepStrictEqual(
|
|
160
|
+
manager.capabilities.getAll(String).map((value) => value.string),
|
|
161
|
+
['dev'],
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Removing the dev plugin restores the original and re-enables it
|
|
165
|
+
// because it was enabled at shadow time.
|
|
166
|
+
yield* manager.remove(testMeta.id);
|
|
167
|
+
assert.strictEqual(
|
|
168
|
+
manager.getPlugins().find((plugin) => plugin.meta.id === testMeta.id),
|
|
169
|
+
productionPlugin,
|
|
170
|
+
);
|
|
171
|
+
assert.isTrue(manager.getEnabled().includes(testMeta.id));
|
|
172
|
+
yield* manager.reset(ActivationEvents.Startup);
|
|
173
|
+
assert.deepStrictEqual(
|
|
174
|
+
manager.capabilities.getAll(String).map((value) => value.string),
|
|
175
|
+
['prod'],
|
|
176
|
+
);
|
|
177
|
+
}),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
it.effect('dev plugin add does not auto-enable a previously-disabled shadow target', () =>
|
|
181
|
+
Effect.gen(function* () {
|
|
182
|
+
const productionPlugin = Plugin.make(Plugin.define(testMeta))();
|
|
183
|
+
const devPlugin = Plugin.make(Plugin.define(testMeta))();
|
|
184
|
+
const loader = Effect.fn(function* (locator: string) {
|
|
185
|
+
if (locator === 'prod') {
|
|
186
|
+
return { plugin: productionPlugin };
|
|
187
|
+
}
|
|
188
|
+
if (locator === 'dev') {
|
|
189
|
+
return { plugin: devPlugin, dev: true };
|
|
190
|
+
}
|
|
191
|
+
return yield* Effect.fail(new Error(`Unknown locator: ${locator}`));
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const manager = PluginManager.make({ pluginLoader: loader });
|
|
195
|
+
yield* manager.add('prod');
|
|
196
|
+
// Production plugin is registered but explicitly NOT enabled.
|
|
197
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
198
|
+
|
|
199
|
+
yield* manager.add('dev');
|
|
200
|
+
yield* manager.remove(testMeta.id);
|
|
201
|
+
|
|
202
|
+
// Original is restored but stays disabled, matching its pre-shadow state.
|
|
203
|
+
assert.strictEqual(
|
|
204
|
+
manager.getPlugins().find((plugin) => plugin.meta.id === testMeta.id),
|
|
205
|
+
productionPlugin,
|
|
206
|
+
);
|
|
207
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
208
|
+
}),
|
|
209
|
+
);
|
|
210
|
+
|
|
88
211
|
it.effect('should support factory pattern with options', () =>
|
|
89
212
|
Effect.gen(function* () {
|
|
90
213
|
type TestPluginOptions = { count: number };
|
|
@@ -105,7 +228,7 @@ describe('PluginManager', () => {
|
|
|
105
228
|
const plugin = TestPluginFactory({ count: 5 });
|
|
106
229
|
plugins = [plugin];
|
|
107
230
|
|
|
108
|
-
const manager = PluginManager.make({ plugins: [plugin],
|
|
231
|
+
const manager = PluginManager.make({ plugins: [plugin], pluginLoader });
|
|
109
232
|
yield* manager.enable(testMeta.id);
|
|
110
233
|
yield* manager.activate(ActivationEvents.Startup);
|
|
111
234
|
const strings = manager.capabilities.getAll(String);
|
|
@@ -127,7 +250,7 @@ describe('PluginManager', () => {
|
|
|
127
250
|
);
|
|
128
251
|
|
|
129
252
|
const testPlugin = Test();
|
|
130
|
-
const manager = PluginManager.make({ plugins: [testPlugin],
|
|
253
|
+
const manager = PluginManager.make({ plugins: [testPlugin], pluginLoader });
|
|
131
254
|
yield* manager.enable(testMeta.id);
|
|
132
255
|
assert.deepStrictEqual(manager.getEnabled(), [Test.meta.id]);
|
|
133
256
|
assert.deepStrictEqual(manager.getModules(), [testPlugin.modules[0]]);
|
|
@@ -199,6 +322,7 @@ describe('PluginManager', () => {
|
|
|
199
322
|
|
|
200
323
|
const manager = PluginManager.make({ pluginLoader });
|
|
201
324
|
yield* manager.add(testMeta.id);
|
|
325
|
+
yield* manager.enable(testMeta.id);
|
|
202
326
|
const error = yield* Effect.flip(manager.activate(FailEvent));
|
|
203
327
|
assert.strictEqual(error.message, 'test');
|
|
204
328
|
}),
|
|
@@ -231,6 +355,7 @@ describe('PluginManager', () => {
|
|
|
231
355
|
|
|
232
356
|
const manager = PluginManager.make({ pluginLoader });
|
|
233
357
|
yield* manager.add(testMeta.id);
|
|
358
|
+
yield* manager.enable(testMeta.id);
|
|
234
359
|
const error = yield* Effect.flip(manager.activate(DefectEvent));
|
|
235
360
|
|
|
236
361
|
// Verify the error was caught and propagated.
|
|
@@ -277,6 +402,7 @@ describe('PluginManager', () => {
|
|
|
277
402
|
|
|
278
403
|
const manager = PluginManager.make({ pluginLoader });
|
|
279
404
|
yield* manager.add(testMeta.id);
|
|
405
|
+
yield* manager.enable(testMeta.id);
|
|
280
406
|
const error = yield* Effect.flip(manager.activate(DefectEvent));
|
|
281
407
|
|
|
282
408
|
// Verify the error was caught and propagated.
|
|
@@ -341,6 +467,7 @@ describe('PluginManager', () => {
|
|
|
341
467
|
);
|
|
342
468
|
|
|
343
469
|
yield* manager.add(testMeta.id);
|
|
470
|
+
yield* manager.enable(testMeta.id);
|
|
344
471
|
yield* manager.activate(ActivationEvents.Startup);
|
|
345
472
|
yield* activating.await;
|
|
346
473
|
yield* activated.await;
|
|
@@ -391,6 +518,7 @@ describe('PluginManager', () => {
|
|
|
391
518
|
|
|
392
519
|
{
|
|
393
520
|
yield* manager.add(testMeta.id);
|
|
521
|
+
yield* manager.enable(testMeta.id);
|
|
394
522
|
const result = yield* manager.activate(ActivationEvents.Startup);
|
|
395
523
|
assert.isTrue(result);
|
|
396
524
|
assert.deepStrictEqual(manager.getActive(), [testPlugin.modules[0].id]);
|
|
@@ -455,16 +583,19 @@ describe('PluginManager', () => {
|
|
|
455
583
|
assert.strictEqual(manager.capabilities.getAll(Number).length, 0);
|
|
456
584
|
|
|
457
585
|
yield* manager.add(Plugin1.meta.id);
|
|
586
|
+
yield* manager.enable(Plugin1.meta.id);
|
|
458
587
|
yield* manager.activate(CountEvent);
|
|
459
588
|
assert.deepStrictEqual(manager.getActive(), [plugin1.modules[0].id]);
|
|
460
589
|
assert.strictEqual(manager.capabilities.getAll(Number).length, 1);
|
|
461
590
|
|
|
462
591
|
yield* manager.add(Plugin2.meta.id);
|
|
592
|
+
yield* manager.enable(Plugin2.meta.id);
|
|
463
593
|
yield* manager.activate(CountEvent);
|
|
464
594
|
assert.deepStrictEqual(manager.getActive(), [plugin1.modules[0].id, plugin2.modules[0].id]);
|
|
465
595
|
assert.strictEqual(manager.capabilities.getAll(Number).length, 2);
|
|
466
596
|
|
|
467
597
|
yield* manager.add(Plugin3.meta.id);
|
|
598
|
+
yield* manager.enable(Plugin3.meta.id);
|
|
468
599
|
yield* manager.activate(CountEvent);
|
|
469
600
|
assert.deepStrictEqual(manager.getActive(), [
|
|
470
601
|
plugin1.modules[0].id,
|
|
@@ -495,6 +626,7 @@ describe('PluginManager', () => {
|
|
|
495
626
|
assert.strictEqual(manager.capabilities.getAll(String).length, 0);
|
|
496
627
|
|
|
497
628
|
yield* manager.add(testMeta.id);
|
|
629
|
+
yield* manager.enable(testMeta.id);
|
|
498
630
|
yield* manager.activate(ActivationEvents.Startup);
|
|
499
631
|
assert.deepStrictEqual(manager.getActive(), []);
|
|
500
632
|
assert.strictEqual(manager.capabilities.getAll(String).length, 0);
|
|
@@ -528,6 +660,7 @@ describe('PluginManager', () => {
|
|
|
528
660
|
assert.strictEqual(count, 0);
|
|
529
661
|
|
|
530
662
|
yield* manager.add(testMeta.id);
|
|
663
|
+
yield* manager.enable(testMeta.id);
|
|
531
664
|
yield* manager.activate(CountEvent);
|
|
532
665
|
assert.deepStrictEqual(manager.getActive(), [testPlugin.modules[0].id]);
|
|
533
666
|
assert.strictEqual(manager.capabilities.getAll(String).length, 1);
|
|
@@ -552,7 +685,7 @@ describe('PluginManager', () => {
|
|
|
552
685
|
Plugin.addModule({
|
|
553
686
|
id: 'Count',
|
|
554
687
|
activatesOn: ActivationEvents.Startup,
|
|
555
|
-
|
|
688
|
+
firesBeforeActivation: [CountEvent],
|
|
556
689
|
activate: Effect.fnUntraced(function* () {
|
|
557
690
|
const capabilityManager = yield* Capability.Service;
|
|
558
691
|
computeTotal(capabilityManager);
|
|
@@ -587,7 +720,9 @@ describe('PluginManager', () => {
|
|
|
587
720
|
const manager = PluginManager.make({ pluginLoader });
|
|
588
721
|
{
|
|
589
722
|
yield* manager.add(Test.meta.id);
|
|
723
|
+
yield* manager.enable(Test.meta.id);
|
|
590
724
|
yield* manager.add(Count.meta.id);
|
|
725
|
+
yield* manager.enable(Count.meta.id);
|
|
591
726
|
yield* manager.activate(ActivationEvents.Startup);
|
|
592
727
|
assert.deepStrictEqual(manager.getActive(), [
|
|
593
728
|
...testPlugin.modules.map((m) => m.id),
|
|
@@ -670,6 +805,7 @@ describe('PluginManager', () => {
|
|
|
670
805
|
assert.strictEqual(pendingResetUpdates.count, 0);
|
|
671
806
|
|
|
672
807
|
yield* manager.add(Plugin1.meta.id);
|
|
808
|
+
yield* manager.enable(Plugin1.meta.id);
|
|
673
809
|
assert.strictEqual(pluginUpdates.count, 1);
|
|
674
810
|
assert.strictEqual(enabledUpdates.count, 1);
|
|
675
811
|
assert.strictEqual(modulesUpdates.count, 1);
|
|
@@ -686,6 +822,7 @@ describe('PluginManager', () => {
|
|
|
686
822
|
assert.strictEqual(pendingResetUpdates.count, 0);
|
|
687
823
|
|
|
688
824
|
yield* manager.add(Plugin2.meta.id);
|
|
825
|
+
yield* manager.enable(Plugin2.meta.id);
|
|
689
826
|
assert.strictEqual(pluginUpdates.count, 2);
|
|
690
827
|
assert.strictEqual(enabledUpdates.count, 2);
|
|
691
828
|
assert.strictEqual(modulesUpdates.count, 2);
|
|
@@ -702,6 +839,7 @@ describe('PluginManager', () => {
|
|
|
702
839
|
assert.strictEqual(pendingResetUpdates.count, 2);
|
|
703
840
|
|
|
704
841
|
yield* manager.add(Plugin3.meta.id);
|
|
842
|
+
yield* manager.enable(Plugin3.meta.id);
|
|
705
843
|
assert.strictEqual(pluginUpdates.count, 3);
|
|
706
844
|
assert.strictEqual(enabledUpdates.count, 3);
|
|
707
845
|
assert.strictEqual(modulesUpdates.count, 3);
|
|
@@ -726,7 +864,7 @@ describe('PluginManager', () => {
|
|
|
726
864
|
assert.strictEqual(eventsFiredUpdates.count, 1);
|
|
727
865
|
assert.strictEqual(pendingResetUpdates.count, 4);
|
|
728
866
|
|
|
729
|
-
manager.remove(Plugin1.meta.id);
|
|
867
|
+
yield* manager.remove(Plugin1.meta.id);
|
|
730
868
|
assert.strictEqual(pluginUpdates.count, 4);
|
|
731
869
|
assert.strictEqual(enabledUpdates.count, 4);
|
|
732
870
|
assert.strictEqual(modulesUpdates.count, 4);
|
|
@@ -773,6 +911,7 @@ describe('PluginManager', () => {
|
|
|
773
911
|
|
|
774
912
|
const manager = PluginManager.make({ pluginLoader });
|
|
775
913
|
yield* manager.add(SlowPlugin.meta.id);
|
|
914
|
+
yield* manager.enable(SlowPlugin.meta.id);
|
|
776
915
|
|
|
777
916
|
// Fork the activation so we can control time with TestClock.
|
|
778
917
|
const activationFiber = yield* Effect.fork(manager.activate(SlowEvent));
|
|
@@ -821,6 +960,7 @@ describe('PluginManager', () => {
|
|
|
821
960
|
|
|
822
961
|
const manager = PluginManager.make({ pluginLoader });
|
|
823
962
|
yield* manager.add(ConcurrentPlugin.meta.id);
|
|
963
|
+
yield* manager.enable(ConcurrentPlugin.meta.id);
|
|
824
964
|
|
|
825
965
|
// Fork two concurrent activations with DIFFERENT events.
|
|
826
966
|
// Both events trigger the same module, so both will try to call _loadModule.
|
|
@@ -869,7 +1009,9 @@ describe('PluginManager', () => {
|
|
|
869
1009
|
|
|
870
1010
|
const manager = PluginManager.make({ pluginLoader });
|
|
871
1011
|
yield* manager.add(Plugin1.meta.id);
|
|
1012
|
+
yield* manager.enable(Plugin1.meta.id);
|
|
872
1013
|
yield* manager.add(Plugin2.meta.id);
|
|
1014
|
+
yield* manager.enable(Plugin2.meta.id);
|
|
873
1015
|
yield* manager.activate(ActivationEvents.Startup);
|
|
874
1016
|
assert.strictEqual(manager.getActive().length, 2);
|
|
875
1017
|
assert.strictEqual(manager.capabilities.getAll(String).length, 1);
|
|
@@ -906,6 +1048,7 @@ describe('PluginManager', () => {
|
|
|
906
1048
|
|
|
907
1049
|
const manager = PluginManager.make({ pluginLoader });
|
|
908
1050
|
yield* manager.add(testMeta.id);
|
|
1051
|
+
yield* manager.enable(testMeta.id);
|
|
909
1052
|
yield* manager.activate(ActivationEvents.Startup);
|
|
910
1053
|
assert.isFalse(deactivated);
|
|
911
1054
|
|
|
@@ -951,7 +1094,9 @@ describe('PluginManager', () => {
|
|
|
951
1094
|
|
|
952
1095
|
const manager = PluginManager.make({ pluginLoader });
|
|
953
1096
|
yield* manager.add(Plugin1.meta.id);
|
|
1097
|
+
yield* manager.enable(Plugin1.meta.id);
|
|
954
1098
|
yield* manager.add(Plugin2.meta.id);
|
|
1099
|
+
yield* manager.enable(Plugin2.meta.id);
|
|
955
1100
|
yield* manager.activate(ActivationEvents.Startup);
|
|
956
1101
|
|
|
957
1102
|
yield* manager.shutdown();
|
|
@@ -974,6 +1119,7 @@ describe('PluginManager', () => {
|
|
|
974
1119
|
|
|
975
1120
|
const manager = PluginManager.make({ pluginLoader });
|
|
976
1121
|
yield* manager.add(testMeta.id);
|
|
1122
|
+
yield* manager.enable(testMeta.id);
|
|
977
1123
|
yield* manager.activate(ActivationEvents.Startup);
|
|
978
1124
|
assert.isTrue(manager.getEventsFired().length > 0);
|
|
979
1125
|
|
|
@@ -1006,6 +1152,7 @@ describe('PluginManager', () => {
|
|
|
1006
1152
|
|
|
1007
1153
|
const manager = PluginManager.make({ pluginLoader });
|
|
1008
1154
|
yield* manager.add(testMeta.id);
|
|
1155
|
+
yield* manager.enable(testMeta.id);
|
|
1009
1156
|
|
|
1010
1157
|
const activationFiber = yield* Effect.fork(manager.activate(ActivationEvents.Startup));
|
|
1011
1158
|
yield* activationStarted.await;
|
|
@@ -1042,6 +1189,7 @@ describe('PluginManager', () => {
|
|
|
1042
1189
|
|
|
1043
1190
|
const manager = PluginManager.make({ pluginLoader });
|
|
1044
1191
|
yield* manager.add(testMeta.id);
|
|
1192
|
+
yield* manager.enable(testMeta.id);
|
|
1045
1193
|
yield* manager.activate(ActivationEvents.Startup);
|
|
1046
1194
|
|
|
1047
1195
|
const pluginsBefore = manager.getPlugins();
|
|
@@ -1077,6 +1225,7 @@ describe('PluginManager', () => {
|
|
|
1077
1225
|
|
|
1078
1226
|
const manager = PluginManager.make({ pluginLoader });
|
|
1079
1227
|
yield* manager.add(testMeta.id);
|
|
1228
|
+
yield* manager.enable(testMeta.id);
|
|
1080
1229
|
yield* manager.activate(ActivationEvents.Startup);
|
|
1081
1230
|
assert.strictEqual(activateCount, 1);
|
|
1082
1231
|
assert.deepStrictEqual(manager.getActive(), [testPlugin.modules[0].id]);
|
|
@@ -1090,4 +1239,661 @@ describe('PluginManager', () => {
|
|
|
1090
1239
|
assert.strictEqual(manager.capabilities.getAll(String).length, 1);
|
|
1091
1240
|
}),
|
|
1092
1241
|
);
|
|
1242
|
+
|
|
1243
|
+
describe('Plugin.lazy', () => {
|
|
1244
|
+
const lazyMeta = { id: 'org.dxos.plugin.lazy', name: 'Lazy' };
|
|
1245
|
+
|
|
1246
|
+
it('exposes meta synchronously without invoking the loader', () => {
|
|
1247
|
+
let loaderCalls = 0;
|
|
1248
|
+
const Real = Plugin.make(Plugin.define<void>(lazyMeta));
|
|
1249
|
+
const LazyTest = Plugin.lazy(lazyMeta, () => {
|
|
1250
|
+
loaderCalls++;
|
|
1251
|
+
return Promise.resolve({ default: Real });
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
assert.strictEqual(LazyTest.meta.id, lazyMeta.id);
|
|
1255
|
+
assert.strictEqual(LazyTest.meta.name, 'Lazy');
|
|
1256
|
+
assert.strictEqual(loaderCalls, 0);
|
|
1257
|
+
|
|
1258
|
+
const stub = LazyTest();
|
|
1259
|
+
assert.strictEqual(stub.meta.id, lazyMeta.id);
|
|
1260
|
+
assert.deepStrictEqual([...stub.modules], []);
|
|
1261
|
+
assert.isTrue(Plugin.isLazy(stub));
|
|
1262
|
+
assert.strictEqual(loaderCalls, 0);
|
|
1263
|
+
});
|
|
1264
|
+
|
|
1265
|
+
it.effect('resolves the loader on enable and registers the real plugin modules', () =>
|
|
1266
|
+
Effect.gen(function* () {
|
|
1267
|
+
let loaderCalls = 0;
|
|
1268
|
+
const Real = Plugin.define(lazyMeta).pipe(
|
|
1269
|
+
Plugin.addModule({
|
|
1270
|
+
id: 'Hello',
|
|
1271
|
+
activatesOn: ActivationEvents.Startup,
|
|
1272
|
+
activate: () => Effect.succeed(Capability.contributes(String, { string: 'hello' })),
|
|
1273
|
+
}),
|
|
1274
|
+
Plugin.make,
|
|
1275
|
+
);
|
|
1276
|
+
const LazyTest = Plugin.lazy(lazyMeta, () => {
|
|
1277
|
+
loaderCalls++;
|
|
1278
|
+
return Promise.resolve({ default: Real });
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1281
|
+
const lazyStub = LazyTest();
|
|
1282
|
+
plugins = [lazyStub];
|
|
1283
|
+
|
|
1284
|
+
const manager = PluginManager.make({ pluginLoader });
|
|
1285
|
+
yield* manager.add(lazyMeta.id);
|
|
1286
|
+
// Loader has not been invoked yet — only meta is exposed.
|
|
1287
|
+
assert.strictEqual(loaderCalls, 0);
|
|
1288
|
+
assert.deepStrictEqual(manager.getModules(), []);
|
|
1289
|
+
|
|
1290
|
+
yield* manager.enable(lazyMeta.id);
|
|
1291
|
+
assert.strictEqual(loaderCalls, 1);
|
|
1292
|
+
// After enable the registered plugin should be the real one (not the stub),
|
|
1293
|
+
// and its modules should be registered with the manager.
|
|
1294
|
+
const registered = manager.getPlugins().find((p) => p.meta.id === lazyMeta.id);
|
|
1295
|
+
assert.isDefined(registered);
|
|
1296
|
+
assert.isFalse(Plugin.isLazy(registered!));
|
|
1297
|
+
assert.strictEqual(registered!.modules.length, 1);
|
|
1298
|
+
|
|
1299
|
+
yield* manager.activate(ActivationEvents.Startup);
|
|
1300
|
+
assert.strictEqual(manager.capabilities.getAll(String).length, 1);
|
|
1301
|
+
}),
|
|
1302
|
+
);
|
|
1303
|
+
|
|
1304
|
+
it.effect('does not invoke the loader if the plugin is never enabled', () =>
|
|
1305
|
+
Effect.gen(function* () {
|
|
1306
|
+
let loaderCalls = 0;
|
|
1307
|
+
const Real = Plugin.make(Plugin.define<void>(lazyMeta));
|
|
1308
|
+
const LazyTest = Plugin.lazy(lazyMeta, () => {
|
|
1309
|
+
loaderCalls++;
|
|
1310
|
+
return Promise.resolve({ default: Real });
|
|
1311
|
+
});
|
|
1312
|
+
const lazyStub = LazyTest();
|
|
1313
|
+
plugins = [lazyStub];
|
|
1314
|
+
|
|
1315
|
+
const manager = PluginManager.make({ pluginLoader });
|
|
1316
|
+
yield* manager.add(lazyMeta.id);
|
|
1317
|
+
|
|
1318
|
+
// Activate an event that has no listeners — the lazy plugin must not load.
|
|
1319
|
+
yield* manager.activate(ActivationEvents.Startup);
|
|
1320
|
+
assert.strictEqual(loaderCalls, 0);
|
|
1321
|
+
}),
|
|
1322
|
+
);
|
|
1323
|
+
|
|
1324
|
+
it.effect('forwards factory options to the real plugin factory', () =>
|
|
1325
|
+
Effect.gen(function* () {
|
|
1326
|
+
type Opts = { greeting: string };
|
|
1327
|
+
const RealFactory = (opts: Opts) =>
|
|
1328
|
+
Plugin.define(lazyMeta).pipe(
|
|
1329
|
+
Plugin.addModule({
|
|
1330
|
+
id: 'Hello',
|
|
1331
|
+
activatesOn: ActivationEvents.Startup,
|
|
1332
|
+
activate: () => Effect.succeed(Capability.contributes(String, { string: opts.greeting })),
|
|
1333
|
+
}),
|
|
1334
|
+
Plugin.make,
|
|
1335
|
+
)(undefined as void);
|
|
1336
|
+
|
|
1337
|
+
const RealFactoryWithMeta = Object.assign(RealFactory, { meta: lazyMeta });
|
|
1338
|
+
|
|
1339
|
+
const LazyTest = Plugin.lazy<Opts>(lazyMeta, () => Promise.resolve({ default: RealFactoryWithMeta }));
|
|
1340
|
+
const lazyStub = LazyTest({ greeting: 'hola' });
|
|
1341
|
+
plugins = [lazyStub];
|
|
1342
|
+
|
|
1343
|
+
const manager = PluginManager.make({ pluginLoader });
|
|
1344
|
+
yield* manager.add(lazyMeta.id);
|
|
1345
|
+
yield* manager.enable(lazyMeta.id);
|
|
1346
|
+
yield* manager.activate(ActivationEvents.Startup);
|
|
1347
|
+
|
|
1348
|
+
const all = manager.capabilities.getAll(String);
|
|
1349
|
+
assert.strictEqual(all.length, 1);
|
|
1350
|
+
assert.strictEqual(all[0].string, 'hola');
|
|
1351
|
+
}),
|
|
1352
|
+
);
|
|
1353
|
+
|
|
1354
|
+
it.effect('wraps loader rejections in a descriptive error', () =>
|
|
1355
|
+
Effect.gen(function* () {
|
|
1356
|
+
const LazyTest = Plugin.lazy(lazyMeta, () =>
|
|
1357
|
+
Promise.reject<{ default: Plugin.PluginFactory }>(new Error('boom')),
|
|
1358
|
+
);
|
|
1359
|
+
const lazyStub = LazyTest();
|
|
1360
|
+
plugins = [lazyStub];
|
|
1361
|
+
|
|
1362
|
+
const manager = PluginManager.make({ pluginLoader });
|
|
1363
|
+
yield* manager.add(lazyMeta.id);
|
|
1364
|
+
|
|
1365
|
+
const exit = yield* Effect.exit(manager.enable(lazyMeta.id));
|
|
1366
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1367
|
+
if (Exit.isFailure(exit)) {
|
|
1368
|
+
const failure = Cause.failureOption(exit.cause);
|
|
1369
|
+
assert.isTrue(failure._tag === 'Some');
|
|
1370
|
+
if (failure._tag === 'Some') {
|
|
1371
|
+
assert.isTrue(Plugin.LazyPluginError.is(failure.value));
|
|
1372
|
+
assert.strictEqual((failure.value as Plugin.LazyPluginError).context.id, lazyMeta.id);
|
|
1373
|
+
assert.strictEqual((failure.value as Plugin.LazyPluginError).context.reason, 'load-failed');
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}),
|
|
1377
|
+
);
|
|
1378
|
+
|
|
1379
|
+
it.effect('publishes a lazy:<id> error message when resolution fails', () =>
|
|
1380
|
+
Effect.gen(function* () {
|
|
1381
|
+
const LazyTest = Plugin.lazy(lazyMeta, () =>
|
|
1382
|
+
Promise.reject<{ default: Plugin.PluginFactory }>(new Error('boom')),
|
|
1383
|
+
);
|
|
1384
|
+
const lazyStub = LazyTest();
|
|
1385
|
+
plugins = [lazyStub];
|
|
1386
|
+
|
|
1387
|
+
const manager = PluginManager.make({ pluginLoader });
|
|
1388
|
+
// Subscribe first so we don't miss the activating/error pair.
|
|
1389
|
+
const queue = yield* PubSub.subscribe(manager.activation);
|
|
1390
|
+
yield* manager.add(lazyMeta.id);
|
|
1391
|
+
yield* Effect.exit(manager.enable(lazyMeta.id));
|
|
1392
|
+
const messages = yield* Queue.takeAll(queue);
|
|
1393
|
+
|
|
1394
|
+
const errorMessage = [...messages].find((m) => m.module === `lazy:${lazyMeta.id}` && m.state === 'error');
|
|
1395
|
+
assert.isDefined(errorMessage);
|
|
1396
|
+
assert.isDefined(errorMessage!.error);
|
|
1397
|
+
}).pipe(Effect.scoped),
|
|
1398
|
+
);
|
|
1399
|
+
|
|
1400
|
+
it.effect('coalesces concurrent lazy resolutions of the same plugin id', () =>
|
|
1401
|
+
Effect.gen(function* () {
|
|
1402
|
+
let factoryCalls = 0;
|
|
1403
|
+
// System-tagged so the constructor's core derivation picks it up,
|
|
1404
|
+
// forcing an implicit enable that races the explicit one below.
|
|
1405
|
+
const coreLazyMeta = { ...lazyMeta, tags: ['system'] };
|
|
1406
|
+
const Real = (() => {
|
|
1407
|
+
const inner = Plugin.make(
|
|
1408
|
+
Plugin.define<void>(coreLazyMeta).pipe(
|
|
1409
|
+
Plugin.addModule({
|
|
1410
|
+
id: 'Hello',
|
|
1411
|
+
activatesOn: ActivationEvents.Startup,
|
|
1412
|
+
activate: () => Effect.succeed(Capability.contributes(String, { string: 'hello' })),
|
|
1413
|
+
}),
|
|
1414
|
+
),
|
|
1415
|
+
);
|
|
1416
|
+
const factory = (() => {
|
|
1417
|
+
factoryCalls++;
|
|
1418
|
+
return inner();
|
|
1419
|
+
}) as Plugin.PluginFactory;
|
|
1420
|
+
return Object.assign(factory, { meta: coreLazyMeta });
|
|
1421
|
+
})();
|
|
1422
|
+
const LazyTest = Plugin.lazy(coreLazyMeta, () => Promise.resolve({ default: Real }));
|
|
1423
|
+
const lazyStub = LazyTest();
|
|
1424
|
+
// `manager.enable(id)` is implicitly called twice — once from the
|
|
1425
|
+
// constructor's core/enabled chain, once from our explicit call. With
|
|
1426
|
+
// coalescing, the underlying factory should still run exactly once.
|
|
1427
|
+
plugins = [lazyStub];
|
|
1428
|
+
const manager = PluginManager.make({ pluginLoader, plugins });
|
|
1429
|
+
yield* manager.enable(coreLazyMeta.id);
|
|
1430
|
+
assert.strictEqual(factoryCalls, 1);
|
|
1431
|
+
}),
|
|
1432
|
+
);
|
|
1433
|
+
|
|
1434
|
+
it.effect('fails with a tagged error when the factory output is not a Plugin', () =>
|
|
1435
|
+
Effect.gen(function* () {
|
|
1436
|
+
const BadFactory = Object.assign(() => ({ not: 'a plugin' }) as any, { meta: lazyMeta });
|
|
1437
|
+
const LazyTest = Plugin.lazy(lazyMeta, () => Promise.resolve({ default: BadFactory }));
|
|
1438
|
+
const lazyStub = LazyTest();
|
|
1439
|
+
plugins = [lazyStub];
|
|
1440
|
+
|
|
1441
|
+
const manager = PluginManager.make({ pluginLoader });
|
|
1442
|
+
yield* manager.add(lazyMeta.id);
|
|
1443
|
+
|
|
1444
|
+
const exit = yield* Effect.exit(manager.enable(lazyMeta.id));
|
|
1445
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1446
|
+
if (Exit.isFailure(exit)) {
|
|
1447
|
+
const failure = Cause.failureOption(exit.cause);
|
|
1448
|
+
assert.isTrue(failure._tag === 'Some');
|
|
1449
|
+
if (failure._tag === 'Some') {
|
|
1450
|
+
assert.isTrue(Plugin.LazyPluginError.is(failure.value));
|
|
1451
|
+
assert.strictEqual((failure.value as Plugin.LazyPluginError).context.reason, 'invalid-plugin');
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
}),
|
|
1455
|
+
);
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
describe('timeouts and failure tracking', () => {
|
|
1459
|
+
// Atom subscriptions fire synchronously when the registry's `_set` runs,
|
|
1460
|
+
// even from a forked fiber on the default runtime. Wrapping in
|
|
1461
|
+
// `Effect.async` lets a TestClock-driven test wait for state produced by
|
|
1462
|
+
// a background `_runForkedFiber` (e.g. the auto-disable triggered when a
|
|
1463
|
+
// module activation times out) without relying on real-time `sleep`.
|
|
1464
|
+
const waitFor = <T>(registry: Registry.Registry, atom: Atom.Atom<T>, predicate: (value: T) => boolean) =>
|
|
1465
|
+
Effect.async<void>((resume) => {
|
|
1466
|
+
if (predicate(registry.get(atom))) {
|
|
1467
|
+
resume(Effect.void);
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
let resolved = false;
|
|
1471
|
+
const dispose = registry.subscribe(atom, () => {
|
|
1472
|
+
if (!resolved && predicate(registry.get(atom))) {
|
|
1473
|
+
resolved = true;
|
|
1474
|
+
dispose();
|
|
1475
|
+
resume(Effect.void);
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
return Effect.sync(() => {
|
|
1479
|
+
if (!resolved) {
|
|
1480
|
+
dispose();
|
|
1481
|
+
}
|
|
1482
|
+
});
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1485
|
+
it.effect('records and auto-disables a plugin whose module exceeds the activation timeout', () =>
|
|
1486
|
+
Effect.gen(function* () {
|
|
1487
|
+
const SlowEvent = ActivationEvent.make('org.dxos.test.activation-timeout');
|
|
1488
|
+
const SlowPlugin = Plugin.define({ id: 'org.dxos.test.slow-activation', name: 'Slow Activation' }).pipe(
|
|
1489
|
+
Plugin.addModule({
|
|
1490
|
+
id: 'Slow',
|
|
1491
|
+
activatesOn: SlowEvent,
|
|
1492
|
+
activate: Effect.fnUntraced(function* () {
|
|
1493
|
+
yield* Effect.sleep(Duration.seconds(60));
|
|
1494
|
+
return Capability.contributes(String, { string: 'never' });
|
|
1495
|
+
}),
|
|
1496
|
+
}),
|
|
1497
|
+
Plugin.make,
|
|
1498
|
+
);
|
|
1499
|
+
plugins = [SlowPlugin()];
|
|
1500
|
+
|
|
1501
|
+
const registry = Registry.make();
|
|
1502
|
+
const manager = PluginManager.make({
|
|
1503
|
+
pluginLoader,
|
|
1504
|
+
registry,
|
|
1505
|
+
activationTimeout: Duration.seconds(2),
|
|
1506
|
+
});
|
|
1507
|
+
yield* manager.add(SlowPlugin.meta.id);
|
|
1508
|
+
yield* manager.enable(SlowPlugin.meta.id);
|
|
1509
|
+
|
|
1510
|
+
const fiber = yield* Effect.fork(manager.activate(SlowEvent));
|
|
1511
|
+
// Push past the 2s activation timeout. The forked module fiber is on
|
|
1512
|
+
// TestClock too, so the timeout fires deterministically.
|
|
1513
|
+
yield* TestClock.adjust(Duration.seconds(3));
|
|
1514
|
+
const exit = yield* Fiber.await(fiber);
|
|
1515
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1516
|
+
|
|
1517
|
+
const failed = manager.getFailed();
|
|
1518
|
+
assert.strictEqual(failed.length, 1);
|
|
1519
|
+
assert.strictEqual(failed[0].id, SlowPlugin.meta.id);
|
|
1520
|
+
assert.strictEqual(failed[0].phase, 'activation');
|
|
1521
|
+
assert.strictEqual(failed[0].reason, 'timeout');
|
|
1522
|
+
|
|
1523
|
+
// Auto-disable runs in a forked fiber on the default runtime; wait for
|
|
1524
|
+
// the `enabled` atom to settle to the disabled state.
|
|
1525
|
+
yield* waitFor(registry, manager.enabled, (ids) => !ids.includes(SlowPlugin.meta.id));
|
|
1526
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
1527
|
+
}),
|
|
1528
|
+
);
|
|
1529
|
+
|
|
1530
|
+
it.effect('records and auto-disables a lazy plugin whose loader exceeds the load timeout', () =>
|
|
1531
|
+
Effect.gen(function* () {
|
|
1532
|
+
const lazyMeta = { id: 'org.dxos.test.slow-load', name: 'Slow Load' };
|
|
1533
|
+
// The dynamic import never resolves; the manager's load timeout should
|
|
1534
|
+
// surface this as a `LazyPluginError` whose `cause` is `PluginTimeoutError`.
|
|
1535
|
+
const LazyTest = Plugin.lazy(lazyMeta, () => new Promise<{ default: Plugin.PluginFactory }>(() => {}));
|
|
1536
|
+
plugins = [LazyTest()];
|
|
1537
|
+
|
|
1538
|
+
const registry = Registry.make();
|
|
1539
|
+
const manager = PluginManager.make({
|
|
1540
|
+
pluginLoader,
|
|
1541
|
+
registry,
|
|
1542
|
+
loadTimeout: Duration.seconds(1),
|
|
1543
|
+
});
|
|
1544
|
+
yield* manager.add(lazyMeta.id);
|
|
1545
|
+
|
|
1546
|
+
const enableFiber = yield* Effect.fork(manager.enable(lazyMeta.id));
|
|
1547
|
+
yield* TestClock.adjust(Duration.seconds(2));
|
|
1548
|
+
const exit = yield* Fiber.await(enableFiber);
|
|
1549
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1550
|
+
|
|
1551
|
+
// The wrapped `LazyPluginError` carries the timeout error as its cause.
|
|
1552
|
+
if (Exit.isFailure(exit)) {
|
|
1553
|
+
const failure = Cause.failureOption(exit.cause);
|
|
1554
|
+
if (failure._tag === 'Some') {
|
|
1555
|
+
assert.isTrue(Plugin.LazyPluginError.is(failure.value));
|
|
1556
|
+
const lazyError = failure.value as Plugin.LazyPluginError;
|
|
1557
|
+
assert.isTrue(PluginManager.PluginTimeoutError.is(lazyError.cause as Error));
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
const failed = manager.getFailed();
|
|
1562
|
+
assert.strictEqual(failed.length, 1);
|
|
1563
|
+
assert.strictEqual(failed[0].id, lazyMeta.id);
|
|
1564
|
+
assert.strictEqual(failed[0].phase, 'load');
|
|
1565
|
+
assert.strictEqual(failed[0].reason, 'timeout');
|
|
1566
|
+
|
|
1567
|
+
// The plugin was added to `enabled` before the lazy resolution failed,
|
|
1568
|
+
// so the auto-disable fork should clear it.
|
|
1569
|
+
yield* waitFor(registry, manager.enabled, (ids) => !ids.includes(lazyMeta.id));
|
|
1570
|
+
}),
|
|
1571
|
+
);
|
|
1572
|
+
|
|
1573
|
+
it.effect('records non-timeout activation errors as reason: error', () =>
|
|
1574
|
+
Effect.gen(function* () {
|
|
1575
|
+
const FailingEvent = ActivationEvent.make('org.dxos.test.activation-error');
|
|
1576
|
+
const FailingPlugin = Plugin.define({ id: 'org.dxos.test.failing', name: 'Failing' }).pipe(
|
|
1577
|
+
Plugin.addModule({
|
|
1578
|
+
id: 'Boom',
|
|
1579
|
+
activatesOn: FailingEvent,
|
|
1580
|
+
activate: () => Effect.fail(new Error('boom')),
|
|
1581
|
+
}),
|
|
1582
|
+
Plugin.make,
|
|
1583
|
+
);
|
|
1584
|
+
plugins = [FailingPlugin()];
|
|
1585
|
+
|
|
1586
|
+
const registry = Registry.make();
|
|
1587
|
+
const manager = PluginManager.make({ pluginLoader, registry });
|
|
1588
|
+
yield* manager.add(FailingPlugin.meta.id);
|
|
1589
|
+
yield* manager.enable(FailingPlugin.meta.id);
|
|
1590
|
+
|
|
1591
|
+
const exit = yield* Effect.exit(manager.activate(FailingEvent));
|
|
1592
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1593
|
+
|
|
1594
|
+
const failed = manager.getFailed();
|
|
1595
|
+
assert.strictEqual(failed.length, 1);
|
|
1596
|
+
assert.strictEqual(failed[0].reason, 'error');
|
|
1597
|
+
assert.strictEqual(failed[0].error.message, 'boom');
|
|
1598
|
+
|
|
1599
|
+
yield* waitFor(registry, manager.enabled, (ids) => !ids.includes(FailingPlugin.meta.id));
|
|
1600
|
+
}),
|
|
1601
|
+
);
|
|
1602
|
+
|
|
1603
|
+
it.effect('does not auto-disable a core plugin even though the failure is recorded', () =>
|
|
1604
|
+
Effect.gen(function* () {
|
|
1605
|
+
const FailingEvent = ActivationEvent.make('org.dxos.test.core-fail');
|
|
1606
|
+
const CorePlugin = Plugin.define({ id: 'org.dxos.test.core', name: 'Core', tags: ['system'] }).pipe(
|
|
1607
|
+
Plugin.addModule({
|
|
1608
|
+
id: 'Boom',
|
|
1609
|
+
activatesOn: FailingEvent,
|
|
1610
|
+
activate: () => Effect.fail(new Error('boom')),
|
|
1611
|
+
}),
|
|
1612
|
+
Plugin.make,
|
|
1613
|
+
);
|
|
1614
|
+
const corePlugin = CorePlugin();
|
|
1615
|
+
plugins = [corePlugin];
|
|
1616
|
+
|
|
1617
|
+
const manager = PluginManager.make({
|
|
1618
|
+
pluginLoader,
|
|
1619
|
+
plugins: [corePlugin],
|
|
1620
|
+
});
|
|
1621
|
+
// Core is auto-enabled via the constructor's enable chain.
|
|
1622
|
+
const exit = yield* Effect.exit(manager.activate(FailingEvent));
|
|
1623
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1624
|
+
|
|
1625
|
+
assert.strictEqual(manager.getFailed().length, 1);
|
|
1626
|
+
// Core stays enabled; host opted into it being non-removable.
|
|
1627
|
+
assert.deepStrictEqual(manager.getEnabled(), [corePlugin.meta.id]);
|
|
1628
|
+
}),
|
|
1629
|
+
);
|
|
1630
|
+
|
|
1631
|
+
it.effect('clearFailure removes the failure record and re-enable starts fresh', () =>
|
|
1632
|
+
Effect.gen(function* () {
|
|
1633
|
+
let shouldFail = true;
|
|
1634
|
+
const Event = ActivationEvent.make('org.dxos.test.flaky');
|
|
1635
|
+
const FlakyPlugin = Plugin.define({ id: 'org.dxos.test.flaky', name: 'Flaky' }).pipe(
|
|
1636
|
+
Plugin.addModule({
|
|
1637
|
+
id: 'Maybe',
|
|
1638
|
+
activatesOn: Event,
|
|
1639
|
+
activate: () =>
|
|
1640
|
+
shouldFail
|
|
1641
|
+
? Effect.fail(new Error('first try'))
|
|
1642
|
+
: Effect.succeed(Capability.contributes(String, { string: 'ok' })),
|
|
1643
|
+
}),
|
|
1644
|
+
Plugin.make,
|
|
1645
|
+
);
|
|
1646
|
+
const flakyPlugin = FlakyPlugin();
|
|
1647
|
+
plugins = [flakyPlugin];
|
|
1648
|
+
|
|
1649
|
+
const registry = Registry.make();
|
|
1650
|
+
const manager = PluginManager.make({ pluginLoader, registry });
|
|
1651
|
+
yield* manager.add(flakyPlugin.meta.id);
|
|
1652
|
+
yield* manager.enable(flakyPlugin.meta.id);
|
|
1653
|
+
|
|
1654
|
+
yield* Effect.exit(manager.activate(Event));
|
|
1655
|
+
assert.strictEqual(manager.getFailed().length, 1);
|
|
1656
|
+
yield* waitFor(registry, manager.enabled, (ids) => !ids.includes(flakyPlugin.meta.id));
|
|
1657
|
+
|
|
1658
|
+
// Calling `enable` again clears the prior failure record before
|
|
1659
|
+
// attempting resolution; verify the explicit API does too.
|
|
1660
|
+
assert.isTrue(manager.clearFailure(flakyPlugin.meta.id));
|
|
1661
|
+
assert.strictEqual(manager.getFailed().length, 0);
|
|
1662
|
+
assert.isFalse(manager.clearFailure(flakyPlugin.meta.id));
|
|
1663
|
+
|
|
1664
|
+
// Retry: enable + reset the activation event so the module re-runs.
|
|
1665
|
+
shouldFail = false;
|
|
1666
|
+
yield* manager.enable(flakyPlugin.meta.id);
|
|
1667
|
+
yield* manager.reset(Event);
|
|
1668
|
+
assert.strictEqual(manager.getFailed().length, 0);
|
|
1669
|
+
assert.strictEqual(manager.capabilities.getAll(String).length, 1);
|
|
1670
|
+
}),
|
|
1671
|
+
);
|
|
1672
|
+
});
|
|
1673
|
+
|
|
1674
|
+
describe('plugin dependencies (dependsOn)', () => {
|
|
1675
|
+
// Build a small plugin with a `dependsOn` chain. The helper keeps each test
|
|
1676
|
+
// focused on the dependency semantics rather than module wiring.
|
|
1677
|
+
const makePlugin = (id: string, dependsOn?: string[], tags?: string[]) =>
|
|
1678
|
+
Plugin.make(Plugin.define({ id, name: id, dependsOn, tags }))();
|
|
1679
|
+
|
|
1680
|
+
it.effect('enable resolves the transitive closure in dependency-first order', () =>
|
|
1681
|
+
Effect.gen(function* () {
|
|
1682
|
+
const a = makePlugin('a');
|
|
1683
|
+
const b = makePlugin('b', ['a']);
|
|
1684
|
+
const c = makePlugin('c', ['b']);
|
|
1685
|
+
const manager = PluginManager.make({ plugins: [a, b, c], pluginLoader });
|
|
1686
|
+
|
|
1687
|
+
const ok = yield* manager.enable('c');
|
|
1688
|
+
assert.isTrue(ok);
|
|
1689
|
+
// `a` enables first, then `b`, then `c`.
|
|
1690
|
+
assert.deepStrictEqual(manager.getEnabled(), ['a', 'b', 'c']);
|
|
1691
|
+
}),
|
|
1692
|
+
);
|
|
1693
|
+
|
|
1694
|
+
it.effect('enable is idempotent when dependencies are already enabled', () =>
|
|
1695
|
+
Effect.gen(function* () {
|
|
1696
|
+
const a = makePlugin('a');
|
|
1697
|
+
const b = makePlugin('b', ['a']);
|
|
1698
|
+
const manager = PluginManager.make({ plugins: [a, b], pluginLoader });
|
|
1699
|
+
|
|
1700
|
+
yield* manager.enable('a');
|
|
1701
|
+
yield* manager.enable('b');
|
|
1702
|
+
assert.deepStrictEqual(manager.getEnabled(), ['a', 'b']);
|
|
1703
|
+
// Re-enabling shouldn't duplicate entries.
|
|
1704
|
+
yield* manager.enable('b');
|
|
1705
|
+
assert.deepStrictEqual(manager.getEnabled(), ['a', 'b']);
|
|
1706
|
+
}),
|
|
1707
|
+
);
|
|
1708
|
+
|
|
1709
|
+
it.effect('enable with a missing declared dependency records a PluginDependencyError', () =>
|
|
1710
|
+
Effect.gen(function* () {
|
|
1711
|
+
const dependent = makePlugin('dependent', ['org.dxos.missing']);
|
|
1712
|
+
const manager = PluginManager.make({ plugins: [dependent], pluginLoader });
|
|
1713
|
+
|
|
1714
|
+
const ok = yield* manager.enable('dependent');
|
|
1715
|
+
assert.isFalse(ok);
|
|
1716
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
1717
|
+
const failures = manager.getFailed();
|
|
1718
|
+
assert.strictEqual(failures.length, 1);
|
|
1719
|
+
assert.strictEqual(failures[0].id, 'dependent');
|
|
1720
|
+
assert.instanceOf(failures[0].error, Plugin.PluginDependencyError);
|
|
1721
|
+
}),
|
|
1722
|
+
);
|
|
1723
|
+
|
|
1724
|
+
it.effect('enable detects A↔B cycle and records a cycle failure', () =>
|
|
1725
|
+
Effect.gen(function* () {
|
|
1726
|
+
const a = makePlugin('a', ['b']);
|
|
1727
|
+
const b = makePlugin('b', ['a']);
|
|
1728
|
+
const manager = PluginManager.make({ plugins: [a, b], pluginLoader });
|
|
1729
|
+
|
|
1730
|
+
const ok = yield* manager.enable('a');
|
|
1731
|
+
assert.isFalse(ok);
|
|
1732
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
1733
|
+
const failures = manager.getFailed();
|
|
1734
|
+
assert.strictEqual(failures.length, 1);
|
|
1735
|
+
assert.instanceOf(failures[0].error, Plugin.PluginDependencyError);
|
|
1736
|
+
}),
|
|
1737
|
+
);
|
|
1738
|
+
|
|
1739
|
+
it.effect('enable with resolveDependencies: false skips closure walk and missing-dep check', () =>
|
|
1740
|
+
Effect.gen(function* () {
|
|
1741
|
+
// Dependent declares a dep that is intentionally unregistered — the
|
|
1742
|
+
// caller has accepted responsibility for satisfying it some other way.
|
|
1743
|
+
const dependent = makePlugin('dependent', ['org.dxos.alt-impl']);
|
|
1744
|
+
const manager = PluginManager.make({ plugins: [dependent], pluginLoader });
|
|
1745
|
+
|
|
1746
|
+
const ok = yield* manager.enable('dependent', { resolveDependencies: false });
|
|
1747
|
+
assert.isTrue(ok);
|
|
1748
|
+
assert.deepStrictEqual(manager.getEnabled(), ['dependent']);
|
|
1749
|
+
assert.strictEqual(manager.getFailed().length, 0);
|
|
1750
|
+
}),
|
|
1751
|
+
);
|
|
1752
|
+
|
|
1753
|
+
it.effect('disable cascades to transitive dependents by default', () =>
|
|
1754
|
+
Effect.gen(function* () {
|
|
1755
|
+
const a = makePlugin('a');
|
|
1756
|
+
const b = makePlugin('b', ['a']);
|
|
1757
|
+
const c = makePlugin('c', ['b']);
|
|
1758
|
+
const manager = PluginManager.make({ plugins: [a, b, c], pluginLoader });
|
|
1759
|
+
|
|
1760
|
+
yield* manager.enable('c');
|
|
1761
|
+
assert.deepStrictEqual(manager.getEnabled(), ['a', 'b', 'c']);
|
|
1762
|
+
|
|
1763
|
+
const ok = yield* manager.disable('a');
|
|
1764
|
+
assert.isTrue(ok);
|
|
1765
|
+
// Cascade tears down `c` (leaf) and `b` before `a`.
|
|
1766
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
1767
|
+
}),
|
|
1768
|
+
);
|
|
1769
|
+
|
|
1770
|
+
it.effect('default disable refuses when a transitive dependent is core', () =>
|
|
1771
|
+
Effect.gen(function* () {
|
|
1772
|
+
const lib = makePlugin('lib');
|
|
1773
|
+
const coreClient = makePlugin('coreClient', ['lib'], ['system']);
|
|
1774
|
+
const manager = PluginManager.make({
|
|
1775
|
+
plugins: [lib, coreClient],
|
|
1776
|
+
enabled: ['lib'],
|
|
1777
|
+
pluginLoader,
|
|
1778
|
+
});
|
|
1779
|
+
|
|
1780
|
+
const exit = yield* Effect.exit(manager.disable('lib'));
|
|
1781
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1782
|
+
// No state mutation when cascade is refused for a core dependent.
|
|
1783
|
+
assert.isTrue(manager.getEnabled().includes('lib'));
|
|
1784
|
+
assert.isTrue(manager.getEnabled().includes('coreClient'));
|
|
1785
|
+
}),
|
|
1786
|
+
);
|
|
1787
|
+
|
|
1788
|
+
it.effect('disable with cascade: false disables only the target', () =>
|
|
1789
|
+
Effect.gen(function* () {
|
|
1790
|
+
const a = makePlugin('a');
|
|
1791
|
+
const b = makePlugin('b', ['a']);
|
|
1792
|
+
const manager = PluginManager.make({ plugins: [a, b], pluginLoader });
|
|
1793
|
+
|
|
1794
|
+
yield* manager.enable('b');
|
|
1795
|
+
const ok = yield* manager.disable('a', { cascade: false });
|
|
1796
|
+
assert.isTrue(ok);
|
|
1797
|
+
// `b` is left enabled-but-broken (no `a` to satisfy its declared dep).
|
|
1798
|
+
assert.deepStrictEqual(manager.getEnabled(), ['b']);
|
|
1799
|
+
}),
|
|
1800
|
+
);
|
|
1801
|
+
|
|
1802
|
+
it.effect('getDependencies and getDependents reflect the declared graph', () =>
|
|
1803
|
+
Effect.gen(function* () {
|
|
1804
|
+
const a = makePlugin('a');
|
|
1805
|
+
const b = makePlugin('b', ['a']);
|
|
1806
|
+
const c = makePlugin('c', ['b']);
|
|
1807
|
+
const manager = PluginManager.make({ plugins: [a, b, c], pluginLoader });
|
|
1808
|
+
|
|
1809
|
+
assert.deepStrictEqual([...manager.getDependencies('c', { transitive: false })], ['b']);
|
|
1810
|
+
assert.deepStrictEqual([...manager.getDependencies('c', { transitive: true })], ['a', 'b']);
|
|
1811
|
+
|
|
1812
|
+
assert.deepStrictEqual([...manager.getDependents('a', { transitive: false })], ['b']);
|
|
1813
|
+
assert.deepStrictEqual([...manager.getDependents('a', { transitive: true })], ['c', 'b']);
|
|
1814
|
+
|
|
1815
|
+
yield* manager.enable('b');
|
|
1816
|
+
assert.deepStrictEqual([...manager.getDependents('a', { transitive: true, enabledOnly: true })], ['b']);
|
|
1817
|
+
}),
|
|
1818
|
+
);
|
|
1819
|
+
|
|
1820
|
+
it.effect('enable installs a catalog-only dependency via add() before enabling it', () =>
|
|
1821
|
+
Effect.gen(function* () {
|
|
1822
|
+
// The "remote" plugin is not pre-registered; the loader knows about
|
|
1823
|
+
// it, simulating a fetch from the registry.
|
|
1824
|
+
const remote = makePlugin('remote');
|
|
1825
|
+
const dependent = makePlugin('dependent', ['remote']);
|
|
1826
|
+
const remoteLoader = Effect.fn(function* (id: string) {
|
|
1827
|
+
if (id === 'remote') {
|
|
1828
|
+
return { plugin: remote };
|
|
1829
|
+
}
|
|
1830
|
+
throw new Error(`Unknown id: ${id}`);
|
|
1831
|
+
});
|
|
1832
|
+
|
|
1833
|
+
const registry = Registry.make();
|
|
1834
|
+
const manager = PluginManager.make({
|
|
1835
|
+
plugins: [dependent],
|
|
1836
|
+
pluginLoader: remoteLoader,
|
|
1837
|
+
registry,
|
|
1838
|
+
});
|
|
1839
|
+
// Seed the catalog with the remote entry so the dependency walk can
|
|
1840
|
+
// discover it.
|
|
1841
|
+
registry.set(manager.pluginRegistry.plugins, {
|
|
1842
|
+
entries: [
|
|
1843
|
+
{
|
|
1844
|
+
id: 'remote',
|
|
1845
|
+
name: 'Remote',
|
|
1846
|
+
moduleUrl: 'about:blank',
|
|
1847
|
+
repo: 'example/remote',
|
|
1848
|
+
version: 'v0.0.0',
|
|
1849
|
+
},
|
|
1850
|
+
],
|
|
1851
|
+
loading: false,
|
|
1852
|
+
error: null,
|
|
1853
|
+
});
|
|
1854
|
+
|
|
1855
|
+
const ok = yield* manager.enable('dependent');
|
|
1856
|
+
assert.isTrue(ok);
|
|
1857
|
+
assert.deepStrictEqual(manager.getEnabled(), ['remote', 'dependent']);
|
|
1858
|
+
assert.isTrue(manager.getPlugins().some((plugin) => plugin.meta.id === 'remote'));
|
|
1859
|
+
}),
|
|
1860
|
+
);
|
|
1861
|
+
|
|
1862
|
+
it.effect('enable records install-failed when a catalog-only dep fails to load', () =>
|
|
1863
|
+
Effect.gen(function* () {
|
|
1864
|
+
const dependent = makePlugin('dependent', ['remote-broken']);
|
|
1865
|
+
const failingLoader = Effect.fn(function* (_id: string) {
|
|
1866
|
+
return yield* Effect.fail(new Error('fetch failed'));
|
|
1867
|
+
});
|
|
1868
|
+
|
|
1869
|
+
const registry = Registry.make();
|
|
1870
|
+
const manager = PluginManager.make({
|
|
1871
|
+
plugins: [dependent],
|
|
1872
|
+
pluginLoader: failingLoader,
|
|
1873
|
+
registry,
|
|
1874
|
+
});
|
|
1875
|
+
registry.set(manager.pluginRegistry.plugins, {
|
|
1876
|
+
entries: [
|
|
1877
|
+
{
|
|
1878
|
+
id: 'remote-broken',
|
|
1879
|
+
name: 'Broken',
|
|
1880
|
+
moduleUrl: 'about:blank',
|
|
1881
|
+
repo: 'example/broken',
|
|
1882
|
+
version: 'v0.0.0',
|
|
1883
|
+
},
|
|
1884
|
+
],
|
|
1885
|
+
loading: false,
|
|
1886
|
+
error: null,
|
|
1887
|
+
});
|
|
1888
|
+
|
|
1889
|
+
const ok = yield* manager.enable('dependent');
|
|
1890
|
+
assert.isFalse(ok);
|
|
1891
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
1892
|
+
const failures = manager.getFailed();
|
|
1893
|
+
assert.strictEqual(failures.length, 1);
|
|
1894
|
+
assert.strictEqual(failures[0].id, 'dependent');
|
|
1895
|
+
assert.instanceOf(failures[0].error, Plugin.PluginDependencyError);
|
|
1896
|
+
}),
|
|
1897
|
+
);
|
|
1898
|
+
});
|
|
1093
1899
|
});
|