@dxos/app-framework 0.8.4-main.74a063c4e0 → 0.8.4-main.765dc60934
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-OP63CD5N.mjs → capability-HRFPP52W.mjs} +11 -11
- package/dist/lib/browser/capability-HRFPP52W.mjs.map +7 -0
- package/dist/lib/browser/{capability-BBBBAPDI.mjs → capability-VQ236TY5.mjs} +10 -10
- package/dist/lib/browser/{chunk-T3Y4AEKX.mjs → chunk-23D4SJUE.mjs} +3 -3
- package/dist/lib/browser/{chunk-T3Y4AEKX.mjs.map → chunk-23D4SJUE.mjs.map} +1 -1
- package/dist/lib/browser/{chunk-2CKCJ6PN.mjs → chunk-3JWJXGLK.mjs} +1 -1
- package/dist/lib/browser/{chunk-2CKCJ6PN.mjs.map → chunk-3JWJXGLK.mjs.map} +1 -1
- package/dist/lib/browser/{chunk-I34GF4NG.mjs → chunk-45CHLTBV.mjs} +2 -2
- package/dist/lib/browser/{chunk-QSXYHXCE.mjs → chunk-66IXTIVK.mjs} +1 -1
- package/dist/lib/browser/{chunk-QSXYHXCE.mjs.map → chunk-66IXTIVK.mjs.map} +2 -2
- package/dist/lib/browser/chunk-6GZYCP73.mjs +422 -0
- package/dist/lib/browser/chunk-6GZYCP73.mjs.map +7 -0
- package/dist/lib/browser/chunk-7VZJR2OA.mjs +581 -0
- package/dist/lib/browser/chunk-7VZJR2OA.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-FU4GAFUQ.mjs → chunk-G6Q2M2M5.mjs} +85 -15
- package/dist/lib/browser/chunk-G6Q2M2M5.mjs.map +7 -0
- package/dist/lib/browser/chunk-J43JDWAV.mjs +1445 -0
- package/dist/lib/browser/chunk-J43JDWAV.mjs.map +7 -0
- package/dist/lib/browser/{chunk-JKWMHZP6.mjs → chunk-WBHCSOBW.mjs} +2 -2
- package/dist/lib/browser/chunk-WBHCSOBW.mjs.map +7 -0
- package/dist/lib/browser/chunk-XLYULXAO.mjs +469 -0
- package/dist/lib/browser/chunk-XLYULXAO.mjs.map +7 -0
- package/dist/lib/browser/{chunk-F7FW2RK2.mjs → chunk-ZGJAZSNE.mjs} +7 -32
- package/dist/lib/browser/chunk-ZGJAZSNE.mjs.map +7 -0
- package/dist/lib/browser/cli/index.mjs +14 -28
- package/dist/lib/browser/cli/index.mjs.map +3 -3
- package/dist/lib/browser/common/activation-events.mjs +7 -7
- package/dist/lib/browser/common/capabilities.mjs +7 -7
- package/dist/lib/browser/core/activation-event.mjs +1 -1
- package/dist/lib/browser/core/capability.mjs +1 -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 +17 -5
- package/dist/lib/browser/index.mjs +38 -21
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/{invoker-capability-H5PPENOC.mjs → invoker-capability-CEL2L6GX.mjs} +12 -11
- package/dist/lib/browser/invoker-capability-CEL2L6GX.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +149 -28
- 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 +18 -14
- package/dist/lib/node-esm/{capability-AWBEMRYR.mjs → capability-GS3XJH74.mjs} +10 -10
- package/dist/lib/node-esm/{capability-WFEG6CIZ.mjs → capability-I5P7ACFL.mjs} +11 -11
- package/dist/lib/node-esm/capability-I5P7ACFL.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-4RJL37GN.mjs +423 -0
- package/dist/lib/node-esm/chunk-4RJL37GN.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-WZCSOX5Q.mjs → chunk-6XW6LET6.mjs} +2 -2
- package/dist/lib/node-esm/{chunk-URWHJQT2.mjs → chunk-D347W3KO.mjs} +7 -32
- package/dist/lib/node-esm/chunk-D347W3KO.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-DW45NFLW.mjs +1446 -0
- package/dist/lib/node-esm/chunk-DW45NFLW.mjs.map +7 -0
- package/dist/lib/node-esm/chunk-EI4LYXFY.mjs +470 -0
- package/dist/lib/node-esm/chunk-EI4LYXFY.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-ULUEXB7Q.mjs → chunk-KIFOQXD4.mjs} +85 -15
- package/dist/lib/node-esm/chunk-KIFOQXD4.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-VKHGNEDB.mjs → chunk-SBS2YMPT.mjs} +3 -3
- package/dist/lib/node-esm/{chunk-VKHGNEDB.mjs.map → chunk-SBS2YMPT.mjs.map} +1 -1
- package/dist/lib/node-esm/{chunk-42KBWDE4.mjs → chunk-SDJ4B2LU.mjs} +1 -1
- package/dist/lib/node-esm/{chunk-42KBWDE4.mjs.map → chunk-SDJ4B2LU.mjs.map} +1 -1
- package/dist/lib/node-esm/chunk-V24UWT36.mjs +582 -0
- package/dist/lib/node-esm/chunk-V24UWT36.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-G3RTFSNG.mjs → chunk-WFSRZKBP.mjs} +2 -2
- package/dist/lib/node-esm/chunk-WFSRZKBP.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-ZZ7CKK6W.mjs → chunk-XOCUANHO.mjs} +1 -1
- package/dist/lib/node-esm/{chunk-ZZ7CKK6W.mjs.map → chunk-XOCUANHO.mjs.map} +2 -2
- package/dist/lib/node-esm/cli/index.mjs +14 -28
- package/dist/lib/node-esm/cli/index.mjs.map +3 -3
- package/dist/lib/node-esm/common/activation-events.mjs +7 -7
- package/dist/lib/node-esm/common/capabilities.mjs +7 -7
- package/dist/lib/node-esm/core/activation-event.mjs +1 -1
- package/dist/lib/node-esm/core/capability.mjs +1 -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 +17 -5
- package/dist/lib/node-esm/index.mjs +38 -21
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/{invoker-capability-S3ZA527J.mjs → invoker-capability-QKUKN2MF.mjs} +12 -11
- package/dist/lib/node-esm/invoker-capability-QKUKN2MF.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +149 -28
- 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 +18 -14
- package/dist/plugin/node-esm/index.mjs +542 -33
- package/dist/plugin/node-esm/index.mjs.map +4 -4
- package/dist/plugin/node-esm/meta.json +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 +2 -1
- package/dist/types/src/common/capabilities.d.ts.map +1 -1
- package/dist/types/src/common/operations.d.ts +1 -1
- 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.map +1 -1
- package/dist/types/src/core/capability.d.ts +2 -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 +5 -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 +230 -5
- 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 +164 -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 +105 -3
- package/dist/types/src/core/url-loader.d.ts.map +1 -1
- package/dist/types/src/helpers.d.ts.map +1 -1
- package/dist/types/src/plugin-operation/history/capability.d.ts.map +1 -1
- package/dist/types/src/plugin-operation/history/errors.d.ts +6 -6
- package/dist/types/src/plugin-operation/history/errors.d.ts.map +1 -1
- package/dist/types/src/plugin-operation/history/history-tracker.d.ts +1 -1
- package/dist/types/src/plugin-operation/history/history-tracker.d.ts.map +1 -1
- package/dist/types/src/plugin-operation/history/types.d.ts +1 -1
- package/dist/types/src/plugin-operation/history/types.d.ts.map +1 -1
- package/dist/types/src/plugin-operation/history/undo-mapping.d.ts +1 -1
- package/dist/types/src/plugin-operation/history/undo-mapping.d.ts.map +1 -1
- package/dist/types/src/plugin-operation/history/undo-registry.d.ts +1 -1
- package/dist/types/src/plugin-operation/history/undo-registry.d.ts.map +1 -1
- package/dist/types/src/plugin-operation/invoker-capability.d.ts +1 -1
- package/dist/types/src/plugin-operation/invoker-capability.d.ts.map +1 -1
- package/dist/types/src/plugin-operation/meta.d.ts.map +1 -1
- package/dist/types/src/plugin-operation/testing.d.ts +2 -1
- package/dist/types/src/plugin-operation/testing.d.ts.map +1 -1
- package/dist/types/src/plugin-runtime/capability.d.ts +1 -1
- package/dist/types/src/plugin-runtime/capability.d.ts.map +1 -1
- package/dist/types/src/plugin-runtime/meta.d.ts.map +1 -1
- package/dist/types/src/testing/harness.d.ts +67 -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.map +1 -1
- 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.map +1 -1
- package/dist/types/src/ui/components/Surface/index.d.ts +16 -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/useApp.d.ts +30 -3
- 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/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 +4 -2
- package/dist/types/src/vite-plugin/index.d.ts.map +1 -1
- 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 +10 -4
- package/dist/types/src/vite-plugin/packages.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/moon.yml +1 -0
- package/package.json +36 -60
- package/src/cli/cli.ts +1 -1
- package/src/common/annotations.ts +3 -0
- package/src/common/capabilities.ts +2 -1
- package/src/common/operations.ts +1 -1
- package/src/core/capability.ts +1 -1
- package/src/core/edge-registry-plugin-provider.ts +92 -0
- package/src/core/index.ts +5 -0
- package/src/core/plugin-asset-cache.ts +60 -0
- package/src/core/plugin-manager.test.ts +793 -7
- package/src/core/plugin-manager.ts +846 -44
- package/src/core/plugin-manifest.test.ts +75 -0
- package/src/core/plugin-manifest.ts +134 -0
- package/src/core/plugin.ts +170 -10
- package/src/core/registry.ts +163 -0
- package/src/core/url-loader.test.ts +148 -6
- package/src/core/url-loader.ts +284 -44
- package/src/plugin-operation/OperationPlugin.ts +2 -2
- package/src/plugin-operation/history/capability.ts +1 -1
- package/src/plugin-operation/history/history-tracker.test.ts +2 -1
- package/src/plugin-operation/history/history-tracker.ts +1 -1
- package/src/plugin-operation/history/types.ts +1 -1
- package/src/plugin-operation/history/undo-mapping.ts +1 -1
- package/src/plugin-operation/history/undo-registry.ts +1 -1
- package/src/plugin-operation/invoker-capability.ts +2 -1
- package/src/plugin-operation/meta.ts +1 -0
- package/src/plugin-operation/testing.ts +2 -1
- package/src/plugin-runtime/RuntimePlugin.ts +2 -2
- package/src/plugin-runtime/meta.ts +1 -0
- package/src/testing/harness.ts +229 -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 +1 -1
- package/src/testing/withPluginManager.stories.tsx +1 -1
- package/src/testing/withPluginManager.tsx +0 -2
- package/src/ui/components/App/App.stories.tsx +2 -6
- package/src/ui/components/App/App.tsx +25 -2
- package/src/ui/components/Placeholder/Placeholder.stories.tsx +77 -0
- package/src/ui/components/Placeholder/Placeholder.tsx +155 -0
- package/src/ui/components/Placeholder/index.ts +5 -0
- package/src/ui/components/PluginManager/PluginManagerContext.stories.tsx +4 -2
- package/src/ui/components/Surface/SurfaceComponent.stories.tsx +1 -1
- package/src/ui/components/Surface/SurfaceComponent.tsx +85 -48
- package/src/ui/components/Surface/SurfaceInfo.tsx +0 -1
- package/src/ui/components/Surface/index.ts +20 -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/useApp.test.tsx +1 -1
- package/src/ui/hooks/useApp.tsx +177 -42
- package/src/ui/hooks/useLoading.tsx +14 -6
- package/src/vite-plugin/boot-loader/BootLoader.stories.tsx +270 -0
- package/src/vite-plugin/boot-loader/boot-loader.css +321 -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 +6 -2
- package/src/vite-plugin/manifest.test.ts +46 -0
- package/src/vite-plugin/manifest.ts +57 -0
- package/src/vite-plugin/packages.ts +168 -10
- package/tsconfig.json +16 -1
- package/.swc/plugins/linux_x86_64_19.0.0/727453fb3a62f7f1d952a41e051ca8a6f88cadc45cee43c6a4d1aa45f9b75665.wasmer-v7 +0 -0
- package/dist/lib/browser/capability-OP63CD5N.mjs.map +0 -7
- package/dist/lib/browser/chunk-F7FW2RK2.mjs.map +0 -7
- package/dist/lib/browser/chunk-FU4GAFUQ.mjs.map +0 -7
- package/dist/lib/browser/chunk-GX4TUNM6.mjs +0 -963
- package/dist/lib/browser/chunk-GX4TUNM6.mjs.map +0 -7
- package/dist/lib/browser/chunk-JKWMHZP6.mjs.map +0 -7
- package/dist/lib/browser/chunk-LVJW5EFU.mjs +0 -157
- package/dist/lib/browser/chunk-LVJW5EFU.mjs.map +0 -7
- package/dist/lib/browser/chunk-RFSO3JRG.mjs +0 -1
- package/dist/lib/browser/chunk-RFSO3JRG.mjs.map +0 -7
- package/dist/lib/browser/chunk-WPE6AL7I.mjs +0 -905
- package/dist/lib/browser/chunk-WPE6AL7I.mjs.map +0 -7
- package/dist/lib/browser/invoker-capability-H5PPENOC.mjs.map +0 -7
- package/dist/lib/node-esm/capability-WFEG6CIZ.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-4A3ZCMI3.mjs +0 -158
- package/dist/lib/node-esm/chunk-4A3ZCMI3.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-BCEOLX47.mjs +0 -964
- package/dist/lib/node-esm/chunk-BCEOLX47.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-EL3R25OQ.mjs +0 -2
- package/dist/lib/node-esm/chunk-EL3R25OQ.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-G3RTFSNG.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-LQKOTNJW.mjs +0 -906
- package/dist/lib/node-esm/chunk-LQKOTNJW.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-ULUEXB7Q.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-URWHJQT2.mjs.map +0 -7
- package/dist/lib/node-esm/invoker-capability-S3ZA527J.mjs.map +0 -7
- package/dist/types/src/vite-plugin/composer-plugin.d.ts +0 -18
- package/dist/types/src/vite-plugin/composer-plugin.d.ts.map +0 -1
- package/dist/types/src/vite-plugin/import-map-plugin.d.ts +0 -16
- package/dist/types/src/vite-plugin/import-map-plugin.d.ts.map +0 -1
- package/src/vite-plugin/composer-plugin.ts +0 -128
- package/src/vite-plugin/import-map-plugin.ts +0 -314
- /package/dist/lib/browser/{capability-BBBBAPDI.mjs.map → capability-VQ236TY5.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-I34GF4NG.mjs.map → chunk-45CHLTBV.mjs.map} +0 -0
- /package/dist/lib/node-esm/{capability-AWBEMRYR.mjs.map → capability-GS3XJH74.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-WZCSOX5Q.mjs.map → chunk-6XW6LET6.mjs.map} +0 -0
|
@@ -61,7 +61,7 @@ describe('PluginManager', () => {
|
|
|
61
61
|
const pluginLoader = Effect.fn(function* (id: string) {
|
|
62
62
|
const plugin = plugins.find((plugin) => plugin.meta.id === id);
|
|
63
63
|
invariant(plugin, `Plugin not found: ${id}`);
|
|
64
|
-
return plugin;
|
|
64
|
+
return { plugin };
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
afterEach(() => {
|
|
@@ -76,9 +76,10 @@ describe('PluginManager', () => {
|
|
|
76
76
|
|
|
77
77
|
const manager = PluginManager.make({ pluginLoader });
|
|
78
78
|
const added = yield* manager.add(testMeta.id);
|
|
79
|
-
assert.
|
|
79
|
+
assert.strictEqual(added, testPlugin);
|
|
80
80
|
assert.deepStrictEqual(manager.getPlugins(), [testPlugin]);
|
|
81
|
-
|
|
81
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
82
|
+
const removed = yield* manager.remove(testMeta.id);
|
|
82
83
|
assert.isTrue(removed);
|
|
83
84
|
assert.deepStrictEqual(manager.getPlugins(), []);
|
|
84
85
|
}),
|
|
@@ -92,19 +93,121 @@ describe('PluginManager', () => {
|
|
|
92
93
|
const urlLocator = 'https://example.com/plugin.mjs';
|
|
93
94
|
const urlLoader = Effect.fn(function* (locator: string) {
|
|
94
95
|
if (locator === urlLocator) {
|
|
95
|
-
return testPlugin;
|
|
96
|
+
return { plugin: testPlugin };
|
|
96
97
|
}
|
|
97
98
|
return yield* Effect.fail(new Error(`Unknown locator: ${locator}`));
|
|
98
99
|
});
|
|
99
100
|
|
|
100
101
|
const manager = PluginManager.make({ pluginLoader: urlLoader });
|
|
101
102
|
const added = yield* manager.add(urlLocator);
|
|
102
|
-
assert.
|
|
103
|
+
assert.strictEqual(added, testPlugin);
|
|
103
104
|
assert.deepStrictEqual(manager.getPlugins(), [testPlugin]);
|
|
105
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
106
|
+
yield* manager.enable(added.meta.id);
|
|
104
107
|
assert.deepStrictEqual(manager.getEnabled(), [testMeta.id]);
|
|
105
108
|
}),
|
|
106
109
|
);
|
|
107
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
|
+
|
|
108
211
|
it.effect('should support factory pattern with options', () =>
|
|
109
212
|
Effect.gen(function* () {
|
|
110
213
|
type TestPluginOptions = { count: number };
|
|
@@ -219,6 +322,7 @@ describe('PluginManager', () => {
|
|
|
219
322
|
|
|
220
323
|
const manager = PluginManager.make({ pluginLoader });
|
|
221
324
|
yield* manager.add(testMeta.id);
|
|
325
|
+
yield* manager.enable(testMeta.id);
|
|
222
326
|
const error = yield* Effect.flip(manager.activate(FailEvent));
|
|
223
327
|
assert.strictEqual(error.message, 'test');
|
|
224
328
|
}),
|
|
@@ -251,6 +355,7 @@ describe('PluginManager', () => {
|
|
|
251
355
|
|
|
252
356
|
const manager = PluginManager.make({ pluginLoader });
|
|
253
357
|
yield* manager.add(testMeta.id);
|
|
358
|
+
yield* manager.enable(testMeta.id);
|
|
254
359
|
const error = yield* Effect.flip(manager.activate(DefectEvent));
|
|
255
360
|
|
|
256
361
|
// Verify the error was caught and propagated.
|
|
@@ -297,6 +402,7 @@ describe('PluginManager', () => {
|
|
|
297
402
|
|
|
298
403
|
const manager = PluginManager.make({ pluginLoader });
|
|
299
404
|
yield* manager.add(testMeta.id);
|
|
405
|
+
yield* manager.enable(testMeta.id);
|
|
300
406
|
const error = yield* Effect.flip(manager.activate(DefectEvent));
|
|
301
407
|
|
|
302
408
|
// Verify the error was caught and propagated.
|
|
@@ -361,6 +467,7 @@ describe('PluginManager', () => {
|
|
|
361
467
|
);
|
|
362
468
|
|
|
363
469
|
yield* manager.add(testMeta.id);
|
|
470
|
+
yield* manager.enable(testMeta.id);
|
|
364
471
|
yield* manager.activate(ActivationEvents.Startup);
|
|
365
472
|
yield* activating.await;
|
|
366
473
|
yield* activated.await;
|
|
@@ -411,6 +518,7 @@ describe('PluginManager', () => {
|
|
|
411
518
|
|
|
412
519
|
{
|
|
413
520
|
yield* manager.add(testMeta.id);
|
|
521
|
+
yield* manager.enable(testMeta.id);
|
|
414
522
|
const result = yield* manager.activate(ActivationEvents.Startup);
|
|
415
523
|
assert.isTrue(result);
|
|
416
524
|
assert.deepStrictEqual(manager.getActive(), [testPlugin.modules[0].id]);
|
|
@@ -475,16 +583,19 @@ describe('PluginManager', () => {
|
|
|
475
583
|
assert.strictEqual(manager.capabilities.getAll(Number).length, 0);
|
|
476
584
|
|
|
477
585
|
yield* manager.add(Plugin1.meta.id);
|
|
586
|
+
yield* manager.enable(Plugin1.meta.id);
|
|
478
587
|
yield* manager.activate(CountEvent);
|
|
479
588
|
assert.deepStrictEqual(manager.getActive(), [plugin1.modules[0].id]);
|
|
480
589
|
assert.strictEqual(manager.capabilities.getAll(Number).length, 1);
|
|
481
590
|
|
|
482
591
|
yield* manager.add(Plugin2.meta.id);
|
|
592
|
+
yield* manager.enable(Plugin2.meta.id);
|
|
483
593
|
yield* manager.activate(CountEvent);
|
|
484
594
|
assert.deepStrictEqual(manager.getActive(), [plugin1.modules[0].id, plugin2.modules[0].id]);
|
|
485
595
|
assert.strictEqual(manager.capabilities.getAll(Number).length, 2);
|
|
486
596
|
|
|
487
597
|
yield* manager.add(Plugin3.meta.id);
|
|
598
|
+
yield* manager.enable(Plugin3.meta.id);
|
|
488
599
|
yield* manager.activate(CountEvent);
|
|
489
600
|
assert.deepStrictEqual(manager.getActive(), [
|
|
490
601
|
plugin1.modules[0].id,
|
|
@@ -515,6 +626,7 @@ describe('PluginManager', () => {
|
|
|
515
626
|
assert.strictEqual(manager.capabilities.getAll(String).length, 0);
|
|
516
627
|
|
|
517
628
|
yield* manager.add(testMeta.id);
|
|
629
|
+
yield* manager.enable(testMeta.id);
|
|
518
630
|
yield* manager.activate(ActivationEvents.Startup);
|
|
519
631
|
assert.deepStrictEqual(manager.getActive(), []);
|
|
520
632
|
assert.strictEqual(manager.capabilities.getAll(String).length, 0);
|
|
@@ -548,6 +660,7 @@ describe('PluginManager', () => {
|
|
|
548
660
|
assert.strictEqual(count, 0);
|
|
549
661
|
|
|
550
662
|
yield* manager.add(testMeta.id);
|
|
663
|
+
yield* manager.enable(testMeta.id);
|
|
551
664
|
yield* manager.activate(CountEvent);
|
|
552
665
|
assert.deepStrictEqual(manager.getActive(), [testPlugin.modules[0].id]);
|
|
553
666
|
assert.strictEqual(manager.capabilities.getAll(String).length, 1);
|
|
@@ -572,7 +685,7 @@ describe('PluginManager', () => {
|
|
|
572
685
|
Plugin.addModule({
|
|
573
686
|
id: 'Count',
|
|
574
687
|
activatesOn: ActivationEvents.Startup,
|
|
575
|
-
|
|
688
|
+
firesBeforeActivation: [CountEvent],
|
|
576
689
|
activate: Effect.fnUntraced(function* () {
|
|
577
690
|
const capabilityManager = yield* Capability.Service;
|
|
578
691
|
computeTotal(capabilityManager);
|
|
@@ -607,7 +720,9 @@ describe('PluginManager', () => {
|
|
|
607
720
|
const manager = PluginManager.make({ pluginLoader });
|
|
608
721
|
{
|
|
609
722
|
yield* manager.add(Test.meta.id);
|
|
723
|
+
yield* manager.enable(Test.meta.id);
|
|
610
724
|
yield* manager.add(Count.meta.id);
|
|
725
|
+
yield* manager.enable(Count.meta.id);
|
|
611
726
|
yield* manager.activate(ActivationEvents.Startup);
|
|
612
727
|
assert.deepStrictEqual(manager.getActive(), [
|
|
613
728
|
...testPlugin.modules.map((m) => m.id),
|
|
@@ -690,6 +805,7 @@ describe('PluginManager', () => {
|
|
|
690
805
|
assert.strictEqual(pendingResetUpdates.count, 0);
|
|
691
806
|
|
|
692
807
|
yield* manager.add(Plugin1.meta.id);
|
|
808
|
+
yield* manager.enable(Plugin1.meta.id);
|
|
693
809
|
assert.strictEqual(pluginUpdates.count, 1);
|
|
694
810
|
assert.strictEqual(enabledUpdates.count, 1);
|
|
695
811
|
assert.strictEqual(modulesUpdates.count, 1);
|
|
@@ -706,6 +822,7 @@ describe('PluginManager', () => {
|
|
|
706
822
|
assert.strictEqual(pendingResetUpdates.count, 0);
|
|
707
823
|
|
|
708
824
|
yield* manager.add(Plugin2.meta.id);
|
|
825
|
+
yield* manager.enable(Plugin2.meta.id);
|
|
709
826
|
assert.strictEqual(pluginUpdates.count, 2);
|
|
710
827
|
assert.strictEqual(enabledUpdates.count, 2);
|
|
711
828
|
assert.strictEqual(modulesUpdates.count, 2);
|
|
@@ -722,6 +839,7 @@ describe('PluginManager', () => {
|
|
|
722
839
|
assert.strictEqual(pendingResetUpdates.count, 2);
|
|
723
840
|
|
|
724
841
|
yield* manager.add(Plugin3.meta.id);
|
|
842
|
+
yield* manager.enable(Plugin3.meta.id);
|
|
725
843
|
assert.strictEqual(pluginUpdates.count, 3);
|
|
726
844
|
assert.strictEqual(enabledUpdates.count, 3);
|
|
727
845
|
assert.strictEqual(modulesUpdates.count, 3);
|
|
@@ -746,7 +864,7 @@ describe('PluginManager', () => {
|
|
|
746
864
|
assert.strictEqual(eventsFiredUpdates.count, 1);
|
|
747
865
|
assert.strictEqual(pendingResetUpdates.count, 4);
|
|
748
866
|
|
|
749
|
-
manager.remove(Plugin1.meta.id);
|
|
867
|
+
yield* manager.remove(Plugin1.meta.id);
|
|
750
868
|
assert.strictEqual(pluginUpdates.count, 4);
|
|
751
869
|
assert.strictEqual(enabledUpdates.count, 4);
|
|
752
870
|
assert.strictEqual(modulesUpdates.count, 4);
|
|
@@ -793,6 +911,7 @@ describe('PluginManager', () => {
|
|
|
793
911
|
|
|
794
912
|
const manager = PluginManager.make({ pluginLoader });
|
|
795
913
|
yield* manager.add(SlowPlugin.meta.id);
|
|
914
|
+
yield* manager.enable(SlowPlugin.meta.id);
|
|
796
915
|
|
|
797
916
|
// Fork the activation so we can control time with TestClock.
|
|
798
917
|
const activationFiber = yield* Effect.fork(manager.activate(SlowEvent));
|
|
@@ -841,6 +960,7 @@ describe('PluginManager', () => {
|
|
|
841
960
|
|
|
842
961
|
const manager = PluginManager.make({ pluginLoader });
|
|
843
962
|
yield* manager.add(ConcurrentPlugin.meta.id);
|
|
963
|
+
yield* manager.enable(ConcurrentPlugin.meta.id);
|
|
844
964
|
|
|
845
965
|
// Fork two concurrent activations with DIFFERENT events.
|
|
846
966
|
// Both events trigger the same module, so both will try to call _loadModule.
|
|
@@ -889,7 +1009,9 @@ describe('PluginManager', () => {
|
|
|
889
1009
|
|
|
890
1010
|
const manager = PluginManager.make({ pluginLoader });
|
|
891
1011
|
yield* manager.add(Plugin1.meta.id);
|
|
1012
|
+
yield* manager.enable(Plugin1.meta.id);
|
|
892
1013
|
yield* manager.add(Plugin2.meta.id);
|
|
1014
|
+
yield* manager.enable(Plugin2.meta.id);
|
|
893
1015
|
yield* manager.activate(ActivationEvents.Startup);
|
|
894
1016
|
assert.strictEqual(manager.getActive().length, 2);
|
|
895
1017
|
assert.strictEqual(manager.capabilities.getAll(String).length, 1);
|
|
@@ -926,6 +1048,7 @@ describe('PluginManager', () => {
|
|
|
926
1048
|
|
|
927
1049
|
const manager = PluginManager.make({ pluginLoader });
|
|
928
1050
|
yield* manager.add(testMeta.id);
|
|
1051
|
+
yield* manager.enable(testMeta.id);
|
|
929
1052
|
yield* manager.activate(ActivationEvents.Startup);
|
|
930
1053
|
assert.isFalse(deactivated);
|
|
931
1054
|
|
|
@@ -971,7 +1094,9 @@ describe('PluginManager', () => {
|
|
|
971
1094
|
|
|
972
1095
|
const manager = PluginManager.make({ pluginLoader });
|
|
973
1096
|
yield* manager.add(Plugin1.meta.id);
|
|
1097
|
+
yield* manager.enable(Plugin1.meta.id);
|
|
974
1098
|
yield* manager.add(Plugin2.meta.id);
|
|
1099
|
+
yield* manager.enable(Plugin2.meta.id);
|
|
975
1100
|
yield* manager.activate(ActivationEvents.Startup);
|
|
976
1101
|
|
|
977
1102
|
yield* manager.shutdown();
|
|
@@ -994,6 +1119,7 @@ describe('PluginManager', () => {
|
|
|
994
1119
|
|
|
995
1120
|
const manager = PluginManager.make({ pluginLoader });
|
|
996
1121
|
yield* manager.add(testMeta.id);
|
|
1122
|
+
yield* manager.enable(testMeta.id);
|
|
997
1123
|
yield* manager.activate(ActivationEvents.Startup);
|
|
998
1124
|
assert.isTrue(manager.getEventsFired().length > 0);
|
|
999
1125
|
|
|
@@ -1026,6 +1152,7 @@ describe('PluginManager', () => {
|
|
|
1026
1152
|
|
|
1027
1153
|
const manager = PluginManager.make({ pluginLoader });
|
|
1028
1154
|
yield* manager.add(testMeta.id);
|
|
1155
|
+
yield* manager.enable(testMeta.id);
|
|
1029
1156
|
|
|
1030
1157
|
const activationFiber = yield* Effect.fork(manager.activate(ActivationEvents.Startup));
|
|
1031
1158
|
yield* activationStarted.await;
|
|
@@ -1062,6 +1189,7 @@ describe('PluginManager', () => {
|
|
|
1062
1189
|
|
|
1063
1190
|
const manager = PluginManager.make({ pluginLoader });
|
|
1064
1191
|
yield* manager.add(testMeta.id);
|
|
1192
|
+
yield* manager.enable(testMeta.id);
|
|
1065
1193
|
yield* manager.activate(ActivationEvents.Startup);
|
|
1066
1194
|
|
|
1067
1195
|
const pluginsBefore = manager.getPlugins();
|
|
@@ -1097,6 +1225,7 @@ describe('PluginManager', () => {
|
|
|
1097
1225
|
|
|
1098
1226
|
const manager = PluginManager.make({ pluginLoader });
|
|
1099
1227
|
yield* manager.add(testMeta.id);
|
|
1228
|
+
yield* manager.enable(testMeta.id);
|
|
1100
1229
|
yield* manager.activate(ActivationEvents.Startup);
|
|
1101
1230
|
assert.strictEqual(activateCount, 1);
|
|
1102
1231
|
assert.deepStrictEqual(manager.getActive(), [testPlugin.modules[0].id]);
|
|
@@ -1110,4 +1239,661 @@ describe('PluginManager', () => {
|
|
|
1110
1239
|
assert.strictEqual(manager.capabilities.getAll(String).length, 1);
|
|
1111
1240
|
}),
|
|
1112
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
|
+
const Real = (() => {
|
|
1404
|
+
const inner = Plugin.make(
|
|
1405
|
+
Plugin.define<void>(lazyMeta).pipe(
|
|
1406
|
+
Plugin.addModule({
|
|
1407
|
+
id: 'Hello',
|
|
1408
|
+
activatesOn: ActivationEvents.Startup,
|
|
1409
|
+
activate: () => Effect.succeed(Capability.contributes(String, { string: 'hello' })),
|
|
1410
|
+
}),
|
|
1411
|
+
),
|
|
1412
|
+
);
|
|
1413
|
+
const factory = (() => {
|
|
1414
|
+
factoryCalls++;
|
|
1415
|
+
return inner();
|
|
1416
|
+
}) as Plugin.PluginFactory;
|
|
1417
|
+
return Object.assign(factory, { meta: lazyMeta });
|
|
1418
|
+
})();
|
|
1419
|
+
const LazyTest = Plugin.lazy(lazyMeta, () => Promise.resolve({ default: Real }));
|
|
1420
|
+
const lazyStub = LazyTest();
|
|
1421
|
+
// `manager.enable(id)` is implicitly called twice — once from the
|
|
1422
|
+
// constructor's core/enabled chain, once from our explicit call. With
|
|
1423
|
+
// coalescing, the underlying factory should still run exactly once.
|
|
1424
|
+
plugins = [lazyStub];
|
|
1425
|
+
const manager = PluginManager.make({ pluginLoader, plugins, core: [lazyMeta.id] });
|
|
1426
|
+
yield* manager.enable(lazyMeta.id);
|
|
1427
|
+
assert.strictEqual(factoryCalls, 1);
|
|
1428
|
+
}),
|
|
1429
|
+
);
|
|
1430
|
+
|
|
1431
|
+
it.effect('fails with a tagged error when the factory output is not a Plugin', () =>
|
|
1432
|
+
Effect.gen(function* () {
|
|
1433
|
+
const BadFactory = Object.assign(() => ({ not: 'a plugin' }) as any, { meta: lazyMeta });
|
|
1434
|
+
const LazyTest = Plugin.lazy(lazyMeta, () => Promise.resolve({ default: BadFactory }));
|
|
1435
|
+
const lazyStub = LazyTest();
|
|
1436
|
+
plugins = [lazyStub];
|
|
1437
|
+
|
|
1438
|
+
const manager = PluginManager.make({ pluginLoader });
|
|
1439
|
+
yield* manager.add(lazyMeta.id);
|
|
1440
|
+
|
|
1441
|
+
const exit = yield* Effect.exit(manager.enable(lazyMeta.id));
|
|
1442
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1443
|
+
if (Exit.isFailure(exit)) {
|
|
1444
|
+
const failure = Cause.failureOption(exit.cause);
|
|
1445
|
+
assert.isTrue(failure._tag === 'Some');
|
|
1446
|
+
if (failure._tag === 'Some') {
|
|
1447
|
+
assert.isTrue(Plugin.LazyPluginError.is(failure.value));
|
|
1448
|
+
assert.strictEqual((failure.value as Plugin.LazyPluginError).context.reason, 'invalid-plugin');
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
}),
|
|
1452
|
+
);
|
|
1453
|
+
});
|
|
1454
|
+
|
|
1455
|
+
describe('timeouts and failure tracking', () => {
|
|
1456
|
+
// Atom subscriptions fire synchronously when the registry's `_set` runs,
|
|
1457
|
+
// even from a forked fiber on the default runtime. Wrapping in
|
|
1458
|
+
// `Effect.async` lets a TestClock-driven test wait for state produced by
|
|
1459
|
+
// a background `_runForkedFiber` (e.g. the auto-disable triggered when a
|
|
1460
|
+
// module activation times out) without relying on real-time `sleep`.
|
|
1461
|
+
const waitFor = <T>(registry: Registry.Registry, atom: Atom.Atom<T>, predicate: (value: T) => boolean) =>
|
|
1462
|
+
Effect.async<void>((resume) => {
|
|
1463
|
+
if (predicate(registry.get(atom))) {
|
|
1464
|
+
resume(Effect.void);
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
let resolved = false;
|
|
1468
|
+
const dispose = registry.subscribe(atom, () => {
|
|
1469
|
+
if (!resolved && predicate(registry.get(atom))) {
|
|
1470
|
+
resolved = true;
|
|
1471
|
+
dispose();
|
|
1472
|
+
resume(Effect.void);
|
|
1473
|
+
}
|
|
1474
|
+
});
|
|
1475
|
+
return Effect.sync(() => {
|
|
1476
|
+
if (!resolved) {
|
|
1477
|
+
dispose();
|
|
1478
|
+
}
|
|
1479
|
+
});
|
|
1480
|
+
});
|
|
1481
|
+
|
|
1482
|
+
it.effect('records and auto-disables a plugin whose module exceeds the activation timeout', () =>
|
|
1483
|
+
Effect.gen(function* () {
|
|
1484
|
+
const SlowEvent = ActivationEvent.make('org.dxos.test.activation-timeout');
|
|
1485
|
+
const SlowPlugin = Plugin.define({ id: 'org.dxos.test.slow-activation', name: 'Slow Activation' }).pipe(
|
|
1486
|
+
Plugin.addModule({
|
|
1487
|
+
id: 'Slow',
|
|
1488
|
+
activatesOn: SlowEvent,
|
|
1489
|
+
activate: Effect.fnUntraced(function* () {
|
|
1490
|
+
yield* Effect.sleep(Duration.seconds(60));
|
|
1491
|
+
return Capability.contributes(String, { string: 'never' });
|
|
1492
|
+
}),
|
|
1493
|
+
}),
|
|
1494
|
+
Plugin.make,
|
|
1495
|
+
);
|
|
1496
|
+
plugins = [SlowPlugin()];
|
|
1497
|
+
|
|
1498
|
+
const registry = Registry.make();
|
|
1499
|
+
const manager = PluginManager.make({
|
|
1500
|
+
pluginLoader,
|
|
1501
|
+
registry,
|
|
1502
|
+
activationTimeout: Duration.seconds(2),
|
|
1503
|
+
});
|
|
1504
|
+
yield* manager.add(SlowPlugin.meta.id);
|
|
1505
|
+
yield* manager.enable(SlowPlugin.meta.id);
|
|
1506
|
+
|
|
1507
|
+
const fiber = yield* Effect.fork(manager.activate(SlowEvent));
|
|
1508
|
+
// Push past the 2s activation timeout. The forked module fiber is on
|
|
1509
|
+
// TestClock too, so the timeout fires deterministically.
|
|
1510
|
+
yield* TestClock.adjust(Duration.seconds(3));
|
|
1511
|
+
const exit = yield* Fiber.await(fiber);
|
|
1512
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1513
|
+
|
|
1514
|
+
const failed = manager.getFailed();
|
|
1515
|
+
assert.strictEqual(failed.length, 1);
|
|
1516
|
+
assert.strictEqual(failed[0].id, SlowPlugin.meta.id);
|
|
1517
|
+
assert.strictEqual(failed[0].phase, 'activation');
|
|
1518
|
+
assert.strictEqual(failed[0].reason, 'timeout');
|
|
1519
|
+
|
|
1520
|
+
// Auto-disable runs in a forked fiber on the default runtime; wait for
|
|
1521
|
+
// the `enabled` atom to settle to the disabled state.
|
|
1522
|
+
yield* waitFor(registry, manager.enabled, (ids) => !ids.includes(SlowPlugin.meta.id));
|
|
1523
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
1524
|
+
}),
|
|
1525
|
+
);
|
|
1526
|
+
|
|
1527
|
+
it.effect('records and auto-disables a lazy plugin whose loader exceeds the load timeout', () =>
|
|
1528
|
+
Effect.gen(function* () {
|
|
1529
|
+
const lazyMeta = { id: 'org.dxos.test.slow-load', name: 'Slow Load' };
|
|
1530
|
+
// The dynamic import never resolves; the manager's load timeout should
|
|
1531
|
+
// surface this as a `LazyPluginError` whose `cause` is `PluginTimeoutError`.
|
|
1532
|
+
const LazyTest = Plugin.lazy(lazyMeta, () => new Promise<{ default: Plugin.PluginFactory }>(() => {}));
|
|
1533
|
+
plugins = [LazyTest()];
|
|
1534
|
+
|
|
1535
|
+
const registry = Registry.make();
|
|
1536
|
+
const manager = PluginManager.make({
|
|
1537
|
+
pluginLoader,
|
|
1538
|
+
registry,
|
|
1539
|
+
loadTimeout: Duration.seconds(1),
|
|
1540
|
+
});
|
|
1541
|
+
yield* manager.add(lazyMeta.id);
|
|
1542
|
+
|
|
1543
|
+
const enableFiber = yield* Effect.fork(manager.enable(lazyMeta.id));
|
|
1544
|
+
yield* TestClock.adjust(Duration.seconds(2));
|
|
1545
|
+
const exit = yield* Fiber.await(enableFiber);
|
|
1546
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1547
|
+
|
|
1548
|
+
// The wrapped `LazyPluginError` carries the timeout error as its cause.
|
|
1549
|
+
if (Exit.isFailure(exit)) {
|
|
1550
|
+
const failure = Cause.failureOption(exit.cause);
|
|
1551
|
+
if (failure._tag === 'Some') {
|
|
1552
|
+
assert.isTrue(Plugin.LazyPluginError.is(failure.value));
|
|
1553
|
+
const lazyError = failure.value as Plugin.LazyPluginError;
|
|
1554
|
+
assert.isTrue(PluginManager.PluginTimeoutError.is(lazyError.cause as Error));
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
const failed = manager.getFailed();
|
|
1559
|
+
assert.strictEqual(failed.length, 1);
|
|
1560
|
+
assert.strictEqual(failed[0].id, lazyMeta.id);
|
|
1561
|
+
assert.strictEqual(failed[0].phase, 'load');
|
|
1562
|
+
assert.strictEqual(failed[0].reason, 'timeout');
|
|
1563
|
+
|
|
1564
|
+
// The plugin was added to `enabled` before the lazy resolution failed,
|
|
1565
|
+
// so the auto-disable fork should clear it.
|
|
1566
|
+
yield* waitFor(registry, manager.enabled, (ids) => !ids.includes(lazyMeta.id));
|
|
1567
|
+
}),
|
|
1568
|
+
);
|
|
1569
|
+
|
|
1570
|
+
it.effect('records non-timeout activation errors as reason: error', () =>
|
|
1571
|
+
Effect.gen(function* () {
|
|
1572
|
+
const FailingEvent = ActivationEvent.make('org.dxos.test.activation-error');
|
|
1573
|
+
const FailingPlugin = Plugin.define({ id: 'org.dxos.test.failing', name: 'Failing' }).pipe(
|
|
1574
|
+
Plugin.addModule({
|
|
1575
|
+
id: 'Boom',
|
|
1576
|
+
activatesOn: FailingEvent,
|
|
1577
|
+
activate: () => Effect.fail(new Error('boom')),
|
|
1578
|
+
}),
|
|
1579
|
+
Plugin.make,
|
|
1580
|
+
);
|
|
1581
|
+
plugins = [FailingPlugin()];
|
|
1582
|
+
|
|
1583
|
+
const registry = Registry.make();
|
|
1584
|
+
const manager = PluginManager.make({ pluginLoader, registry });
|
|
1585
|
+
yield* manager.add(FailingPlugin.meta.id);
|
|
1586
|
+
yield* manager.enable(FailingPlugin.meta.id);
|
|
1587
|
+
|
|
1588
|
+
const exit = yield* Effect.exit(manager.activate(FailingEvent));
|
|
1589
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1590
|
+
|
|
1591
|
+
const failed = manager.getFailed();
|
|
1592
|
+
assert.strictEqual(failed.length, 1);
|
|
1593
|
+
assert.strictEqual(failed[0].reason, 'error');
|
|
1594
|
+
assert.strictEqual(failed[0].error.message, 'boom');
|
|
1595
|
+
|
|
1596
|
+
yield* waitFor(registry, manager.enabled, (ids) => !ids.includes(FailingPlugin.meta.id));
|
|
1597
|
+
}),
|
|
1598
|
+
);
|
|
1599
|
+
|
|
1600
|
+
it.effect('does not auto-disable a core plugin even though the failure is recorded', () =>
|
|
1601
|
+
Effect.gen(function* () {
|
|
1602
|
+
const FailingEvent = ActivationEvent.make('org.dxos.test.core-fail');
|
|
1603
|
+
const CorePlugin = Plugin.define({ id: 'org.dxos.test.core', name: 'Core' }).pipe(
|
|
1604
|
+
Plugin.addModule({
|
|
1605
|
+
id: 'Boom',
|
|
1606
|
+
activatesOn: FailingEvent,
|
|
1607
|
+
activate: () => Effect.fail(new Error('boom')),
|
|
1608
|
+
}),
|
|
1609
|
+
Plugin.make,
|
|
1610
|
+
);
|
|
1611
|
+
const corePlugin = CorePlugin();
|
|
1612
|
+
plugins = [corePlugin];
|
|
1613
|
+
|
|
1614
|
+
const manager = PluginManager.make({
|
|
1615
|
+
pluginLoader,
|
|
1616
|
+
plugins: [corePlugin],
|
|
1617
|
+
core: [corePlugin.meta.id],
|
|
1618
|
+
});
|
|
1619
|
+
// Core is auto-enabled via the constructor's enable chain.
|
|
1620
|
+
const exit = yield* Effect.exit(manager.activate(FailingEvent));
|
|
1621
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1622
|
+
|
|
1623
|
+
assert.strictEqual(manager.getFailed().length, 1);
|
|
1624
|
+
// Core stays enabled; host opted into it being non-removable.
|
|
1625
|
+
assert.deepStrictEqual(manager.getEnabled(), [corePlugin.meta.id]);
|
|
1626
|
+
}),
|
|
1627
|
+
);
|
|
1628
|
+
|
|
1629
|
+
it.effect('clearFailure removes the failure record and re-enable starts fresh', () =>
|
|
1630
|
+
Effect.gen(function* () {
|
|
1631
|
+
let shouldFail = true;
|
|
1632
|
+
const Event = ActivationEvent.make('org.dxos.test.flaky');
|
|
1633
|
+
const FlakyPlugin = Plugin.define({ id: 'org.dxos.test.flaky', name: 'Flaky' }).pipe(
|
|
1634
|
+
Plugin.addModule({
|
|
1635
|
+
id: 'Maybe',
|
|
1636
|
+
activatesOn: Event,
|
|
1637
|
+
activate: () =>
|
|
1638
|
+
shouldFail
|
|
1639
|
+
? Effect.fail(new Error('first try'))
|
|
1640
|
+
: Effect.succeed(Capability.contributes(String, { string: 'ok' })),
|
|
1641
|
+
}),
|
|
1642
|
+
Plugin.make,
|
|
1643
|
+
);
|
|
1644
|
+
const flakyPlugin = FlakyPlugin();
|
|
1645
|
+
plugins = [flakyPlugin];
|
|
1646
|
+
|
|
1647
|
+
const registry = Registry.make();
|
|
1648
|
+
const manager = PluginManager.make({ pluginLoader, registry });
|
|
1649
|
+
yield* manager.add(flakyPlugin.meta.id);
|
|
1650
|
+
yield* manager.enable(flakyPlugin.meta.id);
|
|
1651
|
+
|
|
1652
|
+
yield* Effect.exit(manager.activate(Event));
|
|
1653
|
+
assert.strictEqual(manager.getFailed().length, 1);
|
|
1654
|
+
yield* waitFor(registry, manager.enabled, (ids) => !ids.includes(flakyPlugin.meta.id));
|
|
1655
|
+
|
|
1656
|
+
// Calling `enable` again clears the prior failure record before
|
|
1657
|
+
// attempting resolution; verify the explicit API does too.
|
|
1658
|
+
assert.isTrue(manager.clearFailure(flakyPlugin.meta.id));
|
|
1659
|
+
assert.strictEqual(manager.getFailed().length, 0);
|
|
1660
|
+
assert.isFalse(manager.clearFailure(flakyPlugin.meta.id));
|
|
1661
|
+
|
|
1662
|
+
// Retry: enable + reset the activation event so the module re-runs.
|
|
1663
|
+
shouldFail = false;
|
|
1664
|
+
yield* manager.enable(flakyPlugin.meta.id);
|
|
1665
|
+
yield* manager.reset(Event);
|
|
1666
|
+
assert.strictEqual(manager.getFailed().length, 0);
|
|
1667
|
+
assert.strictEqual(manager.capabilities.getAll(String).length, 1);
|
|
1668
|
+
}),
|
|
1669
|
+
);
|
|
1670
|
+
});
|
|
1671
|
+
|
|
1672
|
+
describe('plugin dependencies (dependsOn)', () => {
|
|
1673
|
+
// Build a small plugin with a `dependsOn` chain. The helper keeps each test
|
|
1674
|
+
// focused on the dependency semantics rather than module wiring.
|
|
1675
|
+
const makePlugin = (id: string, dependsOn?: string[]) => Plugin.make(Plugin.define({ id, name: id, dependsOn }))();
|
|
1676
|
+
|
|
1677
|
+
it.effect('enable resolves the transitive closure in dependency-first order', () =>
|
|
1678
|
+
Effect.gen(function* () {
|
|
1679
|
+
const a = makePlugin('a');
|
|
1680
|
+
const b = makePlugin('b', ['a']);
|
|
1681
|
+
const c = makePlugin('c', ['b']);
|
|
1682
|
+
const manager = PluginManager.make({ plugins: [a, b, c], core: [], pluginLoader });
|
|
1683
|
+
|
|
1684
|
+
const ok = yield* manager.enable('c');
|
|
1685
|
+
assert.isTrue(ok);
|
|
1686
|
+
// `a` enables first, then `b`, then `c`.
|
|
1687
|
+
assert.deepStrictEqual(manager.getEnabled(), ['a', 'b', 'c']);
|
|
1688
|
+
}),
|
|
1689
|
+
);
|
|
1690
|
+
|
|
1691
|
+
it.effect('enable is idempotent when dependencies are already enabled', () =>
|
|
1692
|
+
Effect.gen(function* () {
|
|
1693
|
+
const a = makePlugin('a');
|
|
1694
|
+
const b = makePlugin('b', ['a']);
|
|
1695
|
+
const manager = PluginManager.make({ plugins: [a, b], core: [], pluginLoader });
|
|
1696
|
+
|
|
1697
|
+
yield* manager.enable('a');
|
|
1698
|
+
yield* manager.enable('b');
|
|
1699
|
+
assert.deepStrictEqual(manager.getEnabled(), ['a', 'b']);
|
|
1700
|
+
// Re-enabling shouldn't duplicate entries.
|
|
1701
|
+
yield* manager.enable('b');
|
|
1702
|
+
assert.deepStrictEqual(manager.getEnabled(), ['a', 'b']);
|
|
1703
|
+
}),
|
|
1704
|
+
);
|
|
1705
|
+
|
|
1706
|
+
it.effect('enable with a missing declared dependency records a PluginDependencyError', () =>
|
|
1707
|
+
Effect.gen(function* () {
|
|
1708
|
+
const dependent = makePlugin('dependent', ['org.dxos.missing']);
|
|
1709
|
+
const manager = PluginManager.make({ plugins: [dependent], core: [], pluginLoader });
|
|
1710
|
+
|
|
1711
|
+
const ok = yield* manager.enable('dependent');
|
|
1712
|
+
assert.isFalse(ok);
|
|
1713
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
1714
|
+
const failures = manager.getFailed();
|
|
1715
|
+
assert.strictEqual(failures.length, 1);
|
|
1716
|
+
assert.strictEqual(failures[0].id, 'dependent');
|
|
1717
|
+
assert.instanceOf(failures[0].error, Plugin.PluginDependencyError);
|
|
1718
|
+
}),
|
|
1719
|
+
);
|
|
1720
|
+
|
|
1721
|
+
it.effect('enable detects A↔B cycle and records a cycle failure', () =>
|
|
1722
|
+
Effect.gen(function* () {
|
|
1723
|
+
const a = makePlugin('a', ['b']);
|
|
1724
|
+
const b = makePlugin('b', ['a']);
|
|
1725
|
+
const manager = PluginManager.make({ plugins: [a, b], core: [], pluginLoader });
|
|
1726
|
+
|
|
1727
|
+
const ok = yield* manager.enable('a');
|
|
1728
|
+
assert.isFalse(ok);
|
|
1729
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
1730
|
+
const failures = manager.getFailed();
|
|
1731
|
+
assert.strictEqual(failures.length, 1);
|
|
1732
|
+
assert.instanceOf(failures[0].error, Plugin.PluginDependencyError);
|
|
1733
|
+
}),
|
|
1734
|
+
);
|
|
1735
|
+
|
|
1736
|
+
it.effect('enable with resolveDependencies: false skips closure walk and missing-dep check', () =>
|
|
1737
|
+
Effect.gen(function* () {
|
|
1738
|
+
// Dependent declares a dep that is intentionally unregistered — the
|
|
1739
|
+
// caller has accepted responsibility for satisfying it some other way.
|
|
1740
|
+
const dependent = makePlugin('dependent', ['org.dxos.alt-impl']);
|
|
1741
|
+
const manager = PluginManager.make({ plugins: [dependent], core: [], pluginLoader });
|
|
1742
|
+
|
|
1743
|
+
const ok = yield* manager.enable('dependent', { resolveDependencies: false });
|
|
1744
|
+
assert.isTrue(ok);
|
|
1745
|
+
assert.deepStrictEqual(manager.getEnabled(), ['dependent']);
|
|
1746
|
+
assert.strictEqual(manager.getFailed().length, 0);
|
|
1747
|
+
}),
|
|
1748
|
+
);
|
|
1749
|
+
|
|
1750
|
+
it.effect('disable cascades to transitive dependents by default', () =>
|
|
1751
|
+
Effect.gen(function* () {
|
|
1752
|
+
const a = makePlugin('a');
|
|
1753
|
+
const b = makePlugin('b', ['a']);
|
|
1754
|
+
const c = makePlugin('c', ['b']);
|
|
1755
|
+
const manager = PluginManager.make({ plugins: [a, b, c], core: [], pluginLoader });
|
|
1756
|
+
|
|
1757
|
+
yield* manager.enable('c');
|
|
1758
|
+
assert.deepStrictEqual(manager.getEnabled(), ['a', 'b', 'c']);
|
|
1759
|
+
|
|
1760
|
+
const ok = yield* manager.disable('a');
|
|
1761
|
+
assert.isTrue(ok);
|
|
1762
|
+
// Cascade tears down `c` (leaf) and `b` before `a`.
|
|
1763
|
+
assert.deepStrictEqual(manager.getEnabled(), []);
|
|
1764
|
+
}),
|
|
1765
|
+
);
|
|
1766
|
+
|
|
1767
|
+
it.effect('default disable refuses when a transitive dependent is core', () =>
|
|
1768
|
+
Effect.gen(function* () {
|
|
1769
|
+
const lib = makePlugin('lib');
|
|
1770
|
+
const coreClient = makePlugin('coreClient', ['lib']);
|
|
1771
|
+
const manager = PluginManager.make({
|
|
1772
|
+
plugins: [lib, coreClient],
|
|
1773
|
+
core: ['coreClient'],
|
|
1774
|
+
enabled: ['lib'],
|
|
1775
|
+
pluginLoader,
|
|
1776
|
+
});
|
|
1777
|
+
|
|
1778
|
+
const exit = yield* Effect.exit(manager.disable('lib'));
|
|
1779
|
+
assert.isTrue(Exit.isFailure(exit));
|
|
1780
|
+
// No state mutation when cascade is refused for a core dependent.
|
|
1781
|
+
assert.isTrue(manager.getEnabled().includes('lib'));
|
|
1782
|
+
assert.isTrue(manager.getEnabled().includes('coreClient'));
|
|
1783
|
+
}),
|
|
1784
|
+
);
|
|
1785
|
+
|
|
1786
|
+
it.effect('disable with cascade: false disables only the target', () =>
|
|
1787
|
+
Effect.gen(function* () {
|
|
1788
|
+
const a = makePlugin('a');
|
|
1789
|
+
const b = makePlugin('b', ['a']);
|
|
1790
|
+
const manager = PluginManager.make({ plugins: [a, b], core: [], pluginLoader });
|
|
1791
|
+
|
|
1792
|
+
yield* manager.enable('b');
|
|
1793
|
+
const ok = yield* manager.disable('a', { cascade: false });
|
|
1794
|
+
assert.isTrue(ok);
|
|
1795
|
+
// `b` is left enabled-but-broken (no `a` to satisfy its declared dep).
|
|
1796
|
+
assert.deepStrictEqual(manager.getEnabled(), ['b']);
|
|
1797
|
+
}),
|
|
1798
|
+
);
|
|
1799
|
+
|
|
1800
|
+
it.effect('getDependencies and getDependents reflect the declared graph', () =>
|
|
1801
|
+
Effect.gen(function* () {
|
|
1802
|
+
const a = makePlugin('a');
|
|
1803
|
+
const b = makePlugin('b', ['a']);
|
|
1804
|
+
const c = makePlugin('c', ['b']);
|
|
1805
|
+
const manager = PluginManager.make({ plugins: [a, b, c], core: [], pluginLoader });
|
|
1806
|
+
|
|
1807
|
+
assert.deepStrictEqual([...manager.getDependencies('c', { transitive: false })], ['b']);
|
|
1808
|
+
assert.deepStrictEqual([...manager.getDependencies('c', { transitive: true })], ['a', 'b']);
|
|
1809
|
+
|
|
1810
|
+
assert.deepStrictEqual([...manager.getDependents('a', { transitive: false })], ['b']);
|
|
1811
|
+
assert.deepStrictEqual([...manager.getDependents('a', { transitive: true })], ['c', 'b']);
|
|
1812
|
+
|
|
1813
|
+
yield* manager.enable('b');
|
|
1814
|
+
assert.deepStrictEqual([...manager.getDependents('a', { transitive: true, enabledOnly: true })], ['b']);
|
|
1815
|
+
}),
|
|
1816
|
+
);
|
|
1817
|
+
|
|
1818
|
+
it.effect('enable installs a catalog-only dependency via add() before enabling it', () =>
|
|
1819
|
+
Effect.gen(function* () {
|
|
1820
|
+
// The "remote" plugin is not pre-registered; the loader knows about
|
|
1821
|
+
// it, simulating a fetch from the registry.
|
|
1822
|
+
const remote = makePlugin('remote');
|
|
1823
|
+
const dependent = makePlugin('dependent', ['remote']);
|
|
1824
|
+
const remoteLoader = Effect.fn(function* (id: string) {
|
|
1825
|
+
if (id === 'remote') {
|
|
1826
|
+
return { plugin: remote };
|
|
1827
|
+
}
|
|
1828
|
+
throw new Error(`Unknown id: ${id}`);
|
|
1829
|
+
});
|
|
1830
|
+
|
|
1831
|
+
const registry = Registry.make();
|
|
1832
|
+
const manager = PluginManager.make({
|
|
1833
|
+
plugins: [dependent],
|
|
1834
|
+
core: [],
|
|
1835
|
+
pluginLoader: remoteLoader,
|
|
1836
|
+
registry,
|
|
1837
|
+
});
|
|
1838
|
+
// Seed the catalog with the remote entry so the dependency walk can
|
|
1839
|
+
// discover it.
|
|
1840
|
+
registry.set(manager.pluginRegistry.plugins, {
|
|
1841
|
+
entries: [
|
|
1842
|
+
{
|
|
1843
|
+
id: 'remote',
|
|
1844
|
+
name: 'Remote',
|
|
1845
|
+
moduleUrl: 'about:blank',
|
|
1846
|
+
repo: 'example/remote',
|
|
1847
|
+
version: 'v0.0.0',
|
|
1848
|
+
},
|
|
1849
|
+
],
|
|
1850
|
+
loading: false,
|
|
1851
|
+
error: null,
|
|
1852
|
+
});
|
|
1853
|
+
|
|
1854
|
+
const ok = yield* manager.enable('dependent');
|
|
1855
|
+
assert.isTrue(ok);
|
|
1856
|
+
assert.deepStrictEqual(manager.getEnabled(), ['remote', 'dependent']);
|
|
1857
|
+
assert.isTrue(manager.getPlugins().some((plugin) => plugin.meta.id === 'remote'));
|
|
1858
|
+
}),
|
|
1859
|
+
);
|
|
1860
|
+
|
|
1861
|
+
it.effect('enable records install-failed when a catalog-only dep fails to load', () =>
|
|
1862
|
+
Effect.gen(function* () {
|
|
1863
|
+
const dependent = makePlugin('dependent', ['remote-broken']);
|
|
1864
|
+
const failingLoader = Effect.fn(function* (_id: string) {
|
|
1865
|
+
return yield* Effect.fail(new Error('fetch failed'));
|
|
1866
|
+
});
|
|
1867
|
+
|
|
1868
|
+
const registry = Registry.make();
|
|
1869
|
+
const manager = PluginManager.make({
|
|
1870
|
+
plugins: [dependent],
|
|
1871
|
+
core: [],
|
|
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
|
+
});
|
|
1113
1899
|
});
|