@dxos/app-framework 0.8.4-main.c85a9c8dae → 0.8.4-main.d05539e30a
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-7RLVE42K.mjs → capability-K5XIVCQU.mjs} +12 -11
- package/dist/lib/browser/capability-K5XIVCQU.mjs.map +7 -0
- package/dist/lib/browser/chunk-5AHASNDW.mjs +95 -0
- 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-PKQT6C53.mjs → chunk-66IXTIVK.mjs} +3 -2
- package/dist/lib/browser/chunk-66IXTIVK.mjs.map +7 -0
- package/dist/lib/browser/{chunk-ZRWBPIZG.mjs → chunk-BRK6GYNB.mjs} +14 -42
- package/dist/lib/browser/chunk-BRK6GYNB.mjs.map +7 -0
- package/dist/lib/browser/chunk-FJ4765WW.mjs +8 -0
- package/dist/lib/browser/{chunk-FHQTHCX7.mjs.map → chunk-FJ4765WW.mjs.map} +3 -3
- 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-5RJNZV7K.mjs → chunk-KFDF7KR3.mjs} +11 -13
- package/dist/lib/browser/{chunk-5RJNZV7K.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-FNKT2QQ2.mjs → chunk-SLX73WRZ.mjs} +90 -17
- 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 +17 -32
- 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 +16 -4
- 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 +199 -56
- 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-EVZK4REM.mjs → capability-RLKFFLTB.mjs} +12 -11
- package/dist/lib/node-esm/capability-RLKFFLTB.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-UEWJDI2L.mjs → chunk-37Z53PXZ.mjs} +2 -2
- package/dist/lib/node-esm/{chunk-UEWJDI2L.mjs.map → chunk-37Z53PXZ.mjs.map} +3 -3
- 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-CJCQS2YL.mjs → chunk-6S45OMUP.mjs} +90 -17
- package/dist/lib/node-esm/chunk-6S45OMUP.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-2A4PRBIX.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-VUIUFIGT.mjs → chunk-OUEMWPIW.mjs} +11 -13
- package/dist/lib/node-esm/{chunk-VUIUFIGT.mjs.map → chunk-OUEMWPIW.mjs.map} +3 -3
- package/dist/lib/node-esm/chunk-PW2VYGOS.mjs +96 -0
- 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-7OWSHPYK.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 +17 -32
- 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 +16 -4
- 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 +199 -56
- 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 +5 -5
- 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 +238 -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 +182 -7
- 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/useApp.test.d.ts +2 -0
- package/dist/types/src/ui/hooks/useApp.test.d.ts.map +1 -0
- 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 +4 -9
- package/src/common/activation-events.ts +12 -17
- package/src/common/annotations.ts +3 -0
- package/src/common/capabilities.ts +160 -29
- package/src/common/operations.ts +7 -10
- package/src/context.ts +1 -1
- package/src/core/activation-event.ts +5 -2
- 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 +1085 -31
- package/src/core/plugin-manager.ts +1170 -198
- package/src/core/plugin-manifest.test.ts +75 -0
- package/src/core/plugin-manifest.ts +134 -0
- package/src/core/plugin.ts +194 -12
- 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 +4 -4
- package/src/testing/withPluginManager.stories.tsx +1 -2
- package/src/testing/withPluginManager.tsx +45 -20
- package/src/ui/components/App/App.stories.tsx +7 -13
- 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 +8 -7
- 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 +159 -0
- package/src/ui/hooks/useApp.tsx +229 -24
- 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/vitest.config.ts +1 -1
- package/.swc/plugins/linux_x86_64_19.0.0/727453fb3a62f7f1d952a41e051ca8a6f88cadc45cee43c6a4d1aa45f9b75665.wasmer-v7 +0 -0
- package/dist/lib/browser/capability-2GL5JAGJ.mjs +0 -37
- package/dist/lib/browser/capability-2GL5JAGJ.mjs.map +0 -7
- package/dist/lib/browser/capability-7RLVE42K.mjs.map +0 -7
- package/dist/lib/browser/chunk-4CTRO67U.mjs +0 -703
- package/dist/lib/browser/chunk-4CTRO67U.mjs.map +0 -7
- package/dist/lib/browser/chunk-FHQTHCX7.mjs +0 -8
- package/dist/lib/browser/chunk-FNKT2QQ2.mjs.map +0 -7
- package/dist/lib/browser/chunk-HE27PNNQ.mjs +0 -824
- package/dist/lib/browser/chunk-HE27PNNQ.mjs.map +0 -7
- package/dist/lib/browser/chunk-NPUEVX42.mjs +0 -34
- package/dist/lib/browser/chunk-NPUEVX42.mjs.map +0 -7
- package/dist/lib/browser/chunk-PKQT6C53.mjs.map +0 -7
- package/dist/lib/browser/chunk-REORGDJT.mjs +0 -80
- package/dist/lib/browser/chunk-REORGDJT.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/chunk-ZRWBPIZG.mjs.map +0 -7
- package/dist/lib/browser/invoker-capability-BNLVNYHU.mjs +0 -36
- package/dist/lib/browser/invoker-capability-BNLVNYHU.mjs.map +0 -7
- package/dist/lib/node-esm/capability-CHIMU6LX.mjs +0 -38
- package/dist/lib/node-esm/capability-CHIMU6LX.mjs.map +0 -7
- package/dist/lib/node-esm/capability-EVZK4REM.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-2A4PRBIX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-7CPNAEGV.mjs +0 -704
- package/dist/lib/node-esm/chunk-7CPNAEGV.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-7OWSHPYK.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-CJCQS2YL.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-DTCHT2X2.mjs +0 -825
- package/dist/lib/node-esm/chunk-DTCHT2X2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-JAZVHID3.mjs +0 -35
- package/dist/lib/node-esm/chunk-JAZVHID3.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-SB5ODNPX.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-UFW652GS.mjs +0 -81
- package/dist/lib/node-esm/chunk-UFW652GS.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-Z4TJPSMP.mjs +0 -2
- package/dist/lib/node-esm/invoker-capability-VF6SP44V.mjs +0 -37
- package/dist/lib/node-esm/invoker-capability-VF6SP44V.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,9 +2,11 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
5
6
|
import React, {
|
|
6
7
|
Fragment,
|
|
7
8
|
type NamedExoticComponent,
|
|
9
|
+
Profiler,
|
|
8
10
|
type RefAttributes,
|
|
9
11
|
Suspense,
|
|
10
12
|
forwardRef,
|
|
@@ -21,22 +23,29 @@ import { byPosition } from '@dxos/util';
|
|
|
21
23
|
|
|
22
24
|
import { Capabilities } from '../../../common';
|
|
23
25
|
import { type CapabilityManager } from '../../../core';
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
+
import { usePluginManager } from '../PluginManager/PluginManagerProvider';
|
|
26
27
|
import { SurfaceContext } from './context';
|
|
27
28
|
import { SurfaceInfo } from './SurfaceInfo';
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
import { useSurfaceProfilerCallback } from './SurfaceProfilerContext';
|
|
30
|
+
import {
|
|
31
|
+
type Definition,
|
|
32
|
+
type Props,
|
|
33
|
+
type RoleToken,
|
|
34
|
+
type TokenData,
|
|
35
|
+
type TypedProps,
|
|
36
|
+
type WebComponentDefinition,
|
|
37
|
+
} from './types';
|
|
31
38
|
|
|
32
39
|
const DEBUG = import.meta.env.VITE_DEBUG;
|
|
33
40
|
|
|
41
|
+
const DEFAULT_PLACEHOLDER = <Fragment />;
|
|
42
|
+
|
|
34
43
|
/**
|
|
35
44
|
* Wrapper component for rendering Web Component surfaces.
|
|
36
45
|
* Handles creation, prop setting, and cleanup of Web Components.
|
|
37
46
|
*/
|
|
38
47
|
const WebComponentWrapper = memo(
|
|
39
|
-
forwardRef<HTMLElement, Props & { definition: WebComponentDefinition }>(
|
|
48
|
+
forwardRef<HTMLElement, Omit<Props, 'role'> & { role: string; definition: WebComponentDefinition }>(
|
|
40
49
|
({ id, role, data, limit, definition, ...rest }, forwardedRef) => {
|
|
41
50
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
42
51
|
const elementRef = useRef<HTMLElement | null>(null);
|
|
@@ -106,9 +115,11 @@ WebComponentWrapper.displayName = 'WebComponentWrapper';
|
|
|
106
115
|
*/
|
|
107
116
|
// TODO(burdon): Allow DebugPlugin to provide different fallback using react-ui ErrorFallback.
|
|
108
117
|
const SurfaceContextProvider = memo(
|
|
109
|
-
forwardRef<HTMLElement, Props & { definition: Definition }>(
|
|
118
|
+
forwardRef<HTMLElement, Omit<Props, 'role'> & { role: string; definition: Definition }>(
|
|
110
119
|
({ id, role, data, limit, fallback = ErrorFallback, definition, ...rest }, forwardedRef) => {
|
|
111
120
|
const contextValue = useMemo(() => ({ id, role, data }), [id, role, data]);
|
|
121
|
+
const onProfilerRender = useSurfaceProfilerCallback();
|
|
122
|
+
const profilerId = `surface/${id}/${role}`;
|
|
112
123
|
|
|
113
124
|
// Handle Web Component surfaces
|
|
114
125
|
if (definition.kind === 'web-component') {
|
|
@@ -137,10 +148,16 @@ const SurfaceContextProvider = memo(
|
|
|
137
148
|
if (debug) {
|
|
138
149
|
return (
|
|
139
150
|
<ErrorBoundary name='surface' resetKeys={[data]} FallbackComponent={fallback}>
|
|
140
|
-
<div
|
|
151
|
+
<div className='contents' data-id={id} data-role={role}>
|
|
141
152
|
<SurfaceContext.Provider value={contextValue}>
|
|
142
153
|
<SurfaceInfo ref={forwardedRef}>
|
|
143
|
-
|
|
154
|
+
{onProfilerRender && !profilerId.includes('org.dxos.plugin.debug') ? (
|
|
155
|
+
<Profiler id={profilerId} onRender={onProfilerRender}>
|
|
156
|
+
<Component id={id} role={role} data={data} limit={limit} {...rest} />
|
|
157
|
+
</Profiler>
|
|
158
|
+
) : (
|
|
159
|
+
<Component id={id} role={role} data={data} limit={limit} {...rest} />
|
|
160
|
+
)}
|
|
144
161
|
</SurfaceInfo>
|
|
145
162
|
</SurfaceContext.Provider>
|
|
146
163
|
</div>
|
|
@@ -150,7 +167,7 @@ const SurfaceContextProvider = memo(
|
|
|
150
167
|
|
|
151
168
|
return (
|
|
152
169
|
<ErrorBoundary name='surface' resetKeys={[data]} FallbackComponent={fallback}>
|
|
153
|
-
<div
|
|
170
|
+
<div className='contents' data-id={id} data-role={role}>
|
|
154
171
|
<SurfaceContext.Provider value={contextValue}>
|
|
155
172
|
<Component id={id} role={role} data={data} limit={limit} {...rest} ref={forwardedRef} />
|
|
156
173
|
</SurfaceContext.Provider>
|
|
@@ -167,43 +184,53 @@ SurfaceContextProvider.displayName = 'SurfaceContextProvider';
|
|
|
167
184
|
* A surface is a named region of the screen that can be populated by plugins.
|
|
168
185
|
*/
|
|
169
186
|
// TODO(burdon): Remove `ref` since relying on this would be error prone.
|
|
170
|
-
export const SurfaceComponent
|
|
171
|
-
forwardRef
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
export const SurfaceComponent = memo(
|
|
188
|
+
forwardRef<HTMLElement, Props & { type?: RoleToken<any> }>(
|
|
189
|
+
({ id: _id, role, type, data: dataProp, limit, placeholder = DEFAULT_PLACEHOLDER, ...rest }, forwardedRef) => {
|
|
190
|
+
const data = useDefaultValue(dataProp, () => ({}));
|
|
191
|
+
// TODO(wittjosiah): This will make all surfaces depend on a single signal.
|
|
192
|
+
// This isn't ideal because it means that any change to the data will cause all surfaces to re-render.
|
|
193
|
+
// This effectively means that plugin modules which contribute surfaces need to all be activated at startup.
|
|
194
|
+
// This should be fine for now because it's how it worked prior to capabilities api anyway.
|
|
195
|
+
// In the future, it would be nice to be able to bucket the surface contributions by role.
|
|
196
|
+
const surfaces = useSurfaces();
|
|
197
|
+
|
|
198
|
+
const effectiveRole = role ?? type?.role;
|
|
199
|
+
if (effectiveRole == null) {
|
|
200
|
+
if (DEBUG) {
|
|
201
|
+
log.warn('Surface has neither `role` nor `type` prop', { id: _id });
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
188
205
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
206
|
+
// NOTE: Memoizing the candidates makes the surface not re-render based on reactivity within data.
|
|
207
|
+
const definitions = findCandidates(surfaces, { role: effectiveRole, data });
|
|
208
|
+
const candidates = limit ? definitions.slice(0, limit) : definitions;
|
|
209
|
+
if (DEBUG && candidates.length === 0) {
|
|
210
|
+
log.warn('no candidates for surface', { role: effectiveRole, data });
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<Suspense fallback={placeholder}>
|
|
216
|
+
{candidates.map((definition) => (
|
|
217
|
+
<SurfaceContextProvider
|
|
218
|
+
key={definition.id}
|
|
219
|
+
id={definition.id}
|
|
220
|
+
role={effectiveRole}
|
|
221
|
+
data={data}
|
|
222
|
+
limit={limit}
|
|
223
|
+
definition={definition}
|
|
224
|
+
ref={forwardedRef}
|
|
225
|
+
{...rest}
|
|
226
|
+
/>
|
|
227
|
+
))}
|
|
228
|
+
</Suspense>
|
|
229
|
+
);
|
|
230
|
+
},
|
|
231
|
+
),
|
|
232
|
+
) as (<TToken extends RoleToken<any>>(props: TypedProps<TToken> & RefAttributes<HTMLElement>) => React.ReactNode) &
|
|
233
|
+
NamedExoticComponent<Props & RefAttributes<HTMLElement>>;
|
|
207
234
|
|
|
208
235
|
SurfaceComponent.displayName = 'Surface';
|
|
209
236
|
|
|
@@ -217,12 +244,12 @@ const ErrorFallback = ({ error }: Props) => {
|
|
|
217
244
|
);
|
|
218
245
|
};
|
|
219
246
|
|
|
220
|
-
const findCandidates = (surfaces: Definition[], { role, data }:
|
|
247
|
+
const findCandidates = (surfaces: Definition[], { role, data }: { role: string; data: Props['data'] }) => {
|
|
221
248
|
return Object.values(surfaces)
|
|
222
249
|
.filter((definition) =>
|
|
223
250
|
Array.isArray(definition.role) ? definition.role.includes(role) : definition.role === role,
|
|
224
251
|
)
|
|
225
|
-
.filter(({ filter }) => (filter ? filter(data ?? {}) : true))
|
|
252
|
+
.filter(({ filter }) => (filter ? filter(data ?? {}, role) : true))
|
|
226
253
|
.toSorted(byPosition);
|
|
227
254
|
};
|
|
228
255
|
|
|
@@ -230,18 +257,47 @@ const findCandidates = (surfaces: Definition[], { role, data }: Pick<Props, 'rol
|
|
|
230
257
|
* @internal
|
|
231
258
|
*/
|
|
232
259
|
export const useSurfaces = () => {
|
|
233
|
-
const
|
|
234
|
-
|
|
260
|
+
const manager = usePluginManager();
|
|
261
|
+
const surfacesByModule = useAtomValue(manager.capabilities.atomByModule(Capabilities.ReactSurface));
|
|
262
|
+
return useMemo(() => {
|
|
263
|
+
const result: Definition[] = [];
|
|
264
|
+
for (const [moduleId, surfaces] of Object.entries(surfacesByModule)) {
|
|
265
|
+
for (const def of surfaces.flat()) {
|
|
266
|
+
result.push({ ...def, id: `${moduleId}.${def.id}` });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return result;
|
|
270
|
+
}, [surfacesByModule]);
|
|
235
271
|
};
|
|
236
272
|
|
|
237
273
|
/**
|
|
238
274
|
* @returns `true` if there is a contributed surface which matches the specified role & data, `false` otherwise.
|
|
275
|
+
*
|
|
276
|
+
* Two overloads:
|
|
277
|
+
* - Typed: pass a `type` role token and `data` is constrained to the token's
|
|
278
|
+
* declared contract (e.g. `AppSurface.Section` requires `attendableId`).
|
|
279
|
+
* - Legacy: pass a string `role` and `data` is untyped.
|
|
239
280
|
*/
|
|
240
|
-
export
|
|
281
|
+
export function isSurfaceAvailable<TToken extends RoleToken<any>>(
|
|
282
|
+
capabilityManager: CapabilityManager.CapabilityManager,
|
|
283
|
+
args: { type: TToken; data?: TokenData<TToken>; role?: never },
|
|
284
|
+
): boolean;
|
|
285
|
+
export function isSurfaceAvailable(
|
|
241
286
|
capabilityManager: CapabilityManager.CapabilityManager,
|
|
242
|
-
|
|
243
|
-
)
|
|
287
|
+
args: Pick<Props, 'role' | 'data'> & { type?: undefined },
|
|
288
|
+
): boolean;
|
|
289
|
+
export function isSurfaceAvailable(
|
|
290
|
+
capabilityManager: CapabilityManager.CapabilityManager,
|
|
291
|
+
{ role, type, data }: { role?: string; type?: RoleToken<any>; data?: unknown },
|
|
292
|
+
): boolean {
|
|
293
|
+
const effectiveRole = role ?? type?.role;
|
|
294
|
+
if (effectiveRole == null) {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
244
297
|
const surfaces = capabilityManager.getAll(Capabilities.ReactSurface);
|
|
245
|
-
const candidates = findCandidates(surfaces.flat(), {
|
|
298
|
+
const candidates = findCandidates(surfaces.flat(), {
|
|
299
|
+
role: effectiveRole,
|
|
300
|
+
data: data as Props['data'],
|
|
301
|
+
});
|
|
246
302
|
return candidates.length > 0;
|
|
247
|
-
}
|
|
303
|
+
}
|
|
@@ -65,7 +65,6 @@ export const SurfaceInfo = forwardRef<HTMLElement, SurfaceInfoProps>(({ children
|
|
|
65
65
|
{rect &&
|
|
66
66
|
createPortal(
|
|
67
67
|
<div
|
|
68
|
-
role='none'
|
|
69
68
|
className='z-[100] fixed flex flex-col-reverse scrollbar-none overflow-auto pointer-events-none'
|
|
70
69
|
style={{
|
|
71
70
|
top: rect.top + padding,
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React, {
|
|
6
|
+
type Context,
|
|
7
|
+
type PropsWithChildren,
|
|
8
|
+
type ProfilerOnRenderCallback,
|
|
9
|
+
createContext,
|
|
10
|
+
useContext,
|
|
11
|
+
useMemo,
|
|
12
|
+
useRef,
|
|
13
|
+
useSyncExternalStore,
|
|
14
|
+
} from 'react';
|
|
15
|
+
|
|
16
|
+
const MAX_ENTRIES = 500;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Single profiler record captured from React Profiler onRender callback.
|
|
20
|
+
*/
|
|
21
|
+
export type SurfaceProfilerEntry = {
|
|
22
|
+
id: string;
|
|
23
|
+
phase: 'mount' | 'update' | 'nested-update';
|
|
24
|
+
actualDuration: number;
|
|
25
|
+
baseDuration: number;
|
|
26
|
+
startTime: number;
|
|
27
|
+
commitTime: number;
|
|
28
|
+
timestamp: number;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Aggregated stats for a single profiled surface.
|
|
33
|
+
*/
|
|
34
|
+
export type SurfaceProfilerStats = {
|
|
35
|
+
id: string;
|
|
36
|
+
mountCount: number;
|
|
37
|
+
updateCount: number;
|
|
38
|
+
totalRenders: number;
|
|
39
|
+
avgActualDuration: number;
|
|
40
|
+
maxActualDuration: number;
|
|
41
|
+
avgBaseDuration: number;
|
|
42
|
+
lastActualDuration: number;
|
|
43
|
+
lastCommitTime: number;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Store that collects profiler entries and notifies subscribers.
|
|
48
|
+
*/
|
|
49
|
+
class SurfaceProfilerStore {
|
|
50
|
+
private _entries: SurfaceProfilerEntry[] = [];
|
|
51
|
+
private _listeners = new Set<() => void>();
|
|
52
|
+
private _snapshot: readonly SurfaceProfilerEntry[] = [];
|
|
53
|
+
private _pendingNotify = false;
|
|
54
|
+
|
|
55
|
+
/** Records an entry and schedules a deferred notification to avoid re-render loops. */
|
|
56
|
+
record(entry: SurfaceProfilerEntry) {
|
|
57
|
+
this._entries.push(entry);
|
|
58
|
+
if (this._entries.length > MAX_ENTRIES) {
|
|
59
|
+
this._entries = this._entries.slice(-MAX_ENTRIES);
|
|
60
|
+
}
|
|
61
|
+
this._snapshot = [...this._entries];
|
|
62
|
+
this._scheduleNotify();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
clear() {
|
|
66
|
+
this._entries = [];
|
|
67
|
+
this._snapshot = [];
|
|
68
|
+
this._notifySync();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
subscribe = (listener: () => void) => {
|
|
72
|
+
this._listeners.add(listener);
|
|
73
|
+
return () => {
|
|
74
|
+
this._listeners.delete(listener);
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
getSnapshot = (): readonly SurfaceProfilerEntry[] => {
|
|
79
|
+
return this._snapshot;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Defers notification to the next animation frame to break the
|
|
84
|
+
* Profiler onRender → record → notify → re-render → onRender loop.
|
|
85
|
+
*/
|
|
86
|
+
private _scheduleNotify() {
|
|
87
|
+
if (!this._pendingNotify) {
|
|
88
|
+
this._pendingNotify = true;
|
|
89
|
+
requestAnimationFrame(() => {
|
|
90
|
+
this._pendingNotify = false;
|
|
91
|
+
this._notifySync();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private _notifySync() {
|
|
97
|
+
for (const listener of this._listeners) {
|
|
98
|
+
listener();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type SurfaceProfilerContextValue = {
|
|
104
|
+
store: SurfaceProfilerStore;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const SurfaceProfilerContext: Context<SurfaceProfilerContextValue | undefined> = createContext<
|
|
108
|
+
SurfaceProfilerContextValue | undefined
|
|
109
|
+
>(undefined);
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Provider that collects React Profiler data from Surface components.
|
|
113
|
+
*/
|
|
114
|
+
export const SurfaceProfilerProvider = ({ children }: PropsWithChildren) => {
|
|
115
|
+
const storeRef = useRef<SurfaceProfilerStore>(null);
|
|
116
|
+
if (!storeRef.current) {
|
|
117
|
+
storeRef.current = new SurfaceProfilerStore();
|
|
118
|
+
}
|
|
119
|
+
return (
|
|
120
|
+
<SurfaceProfilerContext.Provider value={{ store: storeRef.current }}>{children}</SurfaceProfilerContext.Provider>
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Returns a stable onRender callback for use with React Profiler.
|
|
126
|
+
*/
|
|
127
|
+
export const useSurfaceProfilerCallback = (): ProfilerOnRenderCallback | undefined => {
|
|
128
|
+
const store = useContext(SurfaceProfilerContext)?.store;
|
|
129
|
+
return useMemo<ProfilerOnRenderCallback | undefined>(() => {
|
|
130
|
+
if (!store) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
return (id, phase, actualDuration, baseDuration, startTime, commitTime) => {
|
|
134
|
+
store.record({
|
|
135
|
+
id,
|
|
136
|
+
phase,
|
|
137
|
+
actualDuration,
|
|
138
|
+
baseDuration,
|
|
139
|
+
startTime,
|
|
140
|
+
commitTime,
|
|
141
|
+
timestamp: Date.now(),
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
}, [store]);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Returns all profiler entries reactively.
|
|
149
|
+
*/
|
|
150
|
+
export const useSurfaceProfilerEntries = (): readonly SurfaceProfilerEntry[] => {
|
|
151
|
+
const context = useContext(SurfaceProfilerContext);
|
|
152
|
+
return useSyncExternalStore(context?.store.subscribe ?? noop, context?.store.getSnapshot ?? emptySnapshot);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Returns aggregated stats grouped by surface id.
|
|
157
|
+
*/
|
|
158
|
+
export const useSurfaceProfilerStats = (): SurfaceProfilerStats[] => {
|
|
159
|
+
const entries = useSurfaceProfilerEntries();
|
|
160
|
+
const statsMap = new Map<string, SurfaceProfilerStats>();
|
|
161
|
+
|
|
162
|
+
for (const entry of entries) {
|
|
163
|
+
let stats = statsMap.get(entry.id);
|
|
164
|
+
if (!stats) {
|
|
165
|
+
stats = {
|
|
166
|
+
id: entry.id,
|
|
167
|
+
mountCount: 0,
|
|
168
|
+
updateCount: 0,
|
|
169
|
+
totalRenders: 0,
|
|
170
|
+
avgActualDuration: 0,
|
|
171
|
+
maxActualDuration: 0,
|
|
172
|
+
avgBaseDuration: 0,
|
|
173
|
+
lastActualDuration: 0,
|
|
174
|
+
lastCommitTime: 0,
|
|
175
|
+
};
|
|
176
|
+
statsMap.set(entry.id, stats);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (entry.phase === 'mount') {
|
|
180
|
+
stats.mountCount++;
|
|
181
|
+
} else {
|
|
182
|
+
stats.updateCount++;
|
|
183
|
+
}
|
|
184
|
+
stats.totalRenders++;
|
|
185
|
+
stats.avgActualDuration =
|
|
186
|
+
(stats.avgActualDuration * (stats.totalRenders - 1) + entry.actualDuration) / stats.totalRenders;
|
|
187
|
+
stats.avgBaseDuration =
|
|
188
|
+
(stats.avgBaseDuration * (stats.totalRenders - 1) + entry.baseDuration) / stats.totalRenders;
|
|
189
|
+
stats.maxActualDuration = Math.max(stats.maxActualDuration, entry.actualDuration);
|
|
190
|
+
stats.lastActualDuration = entry.actualDuration;
|
|
191
|
+
stats.lastCommitTime = entry.commitTime;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return [...statsMap.values()].sort((a, b) => b.maxActualDuration - a.maxActualDuration);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Clears all collected profiler entries.
|
|
199
|
+
*/
|
|
200
|
+
export const useSurfaceProfilerClear = (): (() => void) | undefined => {
|
|
201
|
+
const store = useContext(SurfaceProfilerContext)?.store;
|
|
202
|
+
return useMemo(() => (store ? () => store.clear() : undefined), [store]);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const noop = () => () => {};
|
|
206
|
+
const EMPTY_SNAPSHOT: readonly SurfaceProfilerEntry[] = [];
|
|
207
|
+
const emptySnapshot = () => EMPTY_SNAPSHOT;
|
|
@@ -5,7 +5,25 @@
|
|
|
5
5
|
// TODO(wittjosiah): Cleanup to avoid re-naming.
|
|
6
6
|
import { SurfaceContext } from './context';
|
|
7
7
|
import { SurfaceComponent, isSurfaceAvailable } from './SurfaceComponent';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
SurfaceProfilerProvider,
|
|
10
|
+
useSurfaceProfilerCallback,
|
|
11
|
+
useSurfaceProfilerClear,
|
|
12
|
+
useSurfaceProfilerEntries,
|
|
13
|
+
useSurfaceProfilerStats,
|
|
14
|
+
} from './SurfaceProfilerContext';
|
|
15
|
+
import {
|
|
16
|
+
type Definition as SurfaceDefinition,
|
|
17
|
+
type RoleToken as SurfaceRoleToken,
|
|
18
|
+
type SurfaceBinding as SurfaceBindingType,
|
|
19
|
+
type SurfaceFilter as SurfaceFilterType,
|
|
20
|
+
type TokenData as SurfaceTokenData,
|
|
21
|
+
type TypedProps as SurfaceTypedProps,
|
|
22
|
+
create as createSurface,
|
|
23
|
+
createWeb as createWebSurface,
|
|
24
|
+
isSurfaceFilter as isSurfaceFilterFn,
|
|
25
|
+
makeType as makeTypeFn,
|
|
26
|
+
} from './types';
|
|
9
27
|
|
|
10
28
|
export namespace Surface {
|
|
11
29
|
export type Definition = SurfaceDefinition;
|
|
@@ -17,4 +35,20 @@ export namespace Surface {
|
|
|
17
35
|
|
|
18
36
|
export const Surface = SurfaceComponent;
|
|
19
37
|
export const isAvailable = isSurfaceAvailable;
|
|
38
|
+
|
|
39
|
+
export type RoleToken<TData> = SurfaceRoleToken<TData>;
|
|
40
|
+
export type Binding = SurfaceBindingType;
|
|
41
|
+
export type Filter<TData> = SurfaceFilterType<TData>;
|
|
42
|
+
export type TokenData<T> = SurfaceTokenData<T>;
|
|
43
|
+
export type TypedProps<TToken extends SurfaceRoleToken<any>> = SurfaceTypedProps<TToken>;
|
|
44
|
+
export const makeType = makeTypeFn;
|
|
45
|
+
export const isFilter = isSurfaceFilterFn;
|
|
46
|
+
|
|
47
|
+
export const ProfilerProvider = SurfaceProfilerProvider;
|
|
48
|
+
export const useProfilerCallback = useSurfaceProfilerCallback;
|
|
49
|
+
export const useProfilerEntries = useSurfaceProfilerEntries;
|
|
50
|
+
export const useProfilerStats = useSurfaceProfilerStats;
|
|
51
|
+
export const useProfilerClear = useSurfaceProfilerClear;
|
|
20
52
|
}
|
|
53
|
+
|
|
54
|
+
export type { SurfaceProfilerEntry, SurfaceProfilerStats } from './SurfaceProfilerContext';
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, test } from 'vitest';
|
|
6
|
+
|
|
7
|
+
import { type CapabilityManager } from '../../../core';
|
|
8
|
+
import { isSurfaceAvailable } from './SurfaceComponent';
|
|
9
|
+
import { type RoleToken, type SurfaceFilter, create, isSurfaceFilter, makeType } from './types';
|
|
10
|
+
|
|
11
|
+
describe('Surface.makeType', () => {
|
|
12
|
+
test('creates a role token carrying the role string', ({ expect }) => {
|
|
13
|
+
const token = makeType<{ subject: string }>('test-role');
|
|
14
|
+
expect(token.role).toBe('test-role');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('tokens with the same role are independent objects (identity-by-role)', ({ expect }) => {
|
|
18
|
+
const a = makeType<{ x: number }>('shared');
|
|
19
|
+
const b = makeType<{ x: number }>('shared');
|
|
20
|
+
expect(a).not.toBe(b);
|
|
21
|
+
expect(a.role).toBe(b.role);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('isSurfaceFilter', () => {
|
|
26
|
+
test('distinguishes filter objects from predicate functions', ({ expect }) => {
|
|
27
|
+
const filter: SurfaceFilter<Record<string, any>> = { bindings: [{ role: 'r', guard: () => true }] };
|
|
28
|
+
expect(isSurfaceFilter(filter)).toBe(true);
|
|
29
|
+
expect(isSurfaceFilter(() => true)).toBe(false);
|
|
30
|
+
expect(isSurfaceFilter({})).toBe(false);
|
|
31
|
+
expect(isSurfaceFilter(null)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('create', () => {
|
|
36
|
+
test('accepts the legacy { role, filter } shape', ({ expect }) => {
|
|
37
|
+
const def = create({
|
|
38
|
+
id: 'legacy',
|
|
39
|
+
role: 'article',
|
|
40
|
+
filter: (data): data is { x: number } => typeof (data as any).x === 'number',
|
|
41
|
+
component: () => null,
|
|
42
|
+
});
|
|
43
|
+
expect(def.kind).toBe('react');
|
|
44
|
+
expect(def.role).toBe('article');
|
|
45
|
+
expect(def.filter!({ x: 1 })).toBe(true);
|
|
46
|
+
expect(def.filter!({})).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('expands a single-binding SurfaceFilter into a role string', ({ expect }) => {
|
|
50
|
+
const filter: SurfaceFilter<Record<string, any>> = {
|
|
51
|
+
bindings: [{ role: 'article', guard: (d) => (d as any).subject === 'ok' }],
|
|
52
|
+
};
|
|
53
|
+
const def = create({ id: 'typed-single', filter, component: () => null });
|
|
54
|
+
expect(def.role).toBe('article');
|
|
55
|
+
expect(def.filter!({ subject: 'ok' }, 'article')).toBe(true);
|
|
56
|
+
expect(def.filter!({ subject: 'no' }, 'article')).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('expands a multi-binding SurfaceFilter into a role array with role-scoped guards', ({ expect }) => {
|
|
60
|
+
const filter: SurfaceFilter<Record<string, any>> = {
|
|
61
|
+
bindings: [
|
|
62
|
+
{ role: 'article', guard: (d) => (d as any).subject === 'a' },
|
|
63
|
+
{ role: 'section', guard: (d) => (d as any).subject === 's' },
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
const def = create({ id: 'typed-multi', filter, component: () => null });
|
|
67
|
+
expect(def.role).toEqual(['article', 'section']);
|
|
68
|
+
// Role-specific guard.
|
|
69
|
+
expect(def.filter!({ subject: 'a' }, 'article')).toBe(true);
|
|
70
|
+
expect(def.filter!({ subject: 'a' }, 'section')).toBe(false);
|
|
71
|
+
expect(def.filter!({ subject: 's' }, 'section')).toBe(true);
|
|
72
|
+
expect(def.filter!({ subject: 's' }, 'article')).toBe(false);
|
|
73
|
+
// Without role, any binding may match.
|
|
74
|
+
expect(def.filter!({ subject: 'a' })).toBe(true);
|
|
75
|
+
expect(def.filter!({ subject: 'unknown' })).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('passes position through untouched', ({ expect }) => {
|
|
79
|
+
const filter: SurfaceFilter<Record<string, any>> = { bindings: [{ role: 'r', guard: () => true }] };
|
|
80
|
+
const def = create({ id: 'pos', filter, component: () => null, position: 'last' });
|
|
81
|
+
expect(def.position).toBe('last');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('role token typing', () => {
|
|
86
|
+
test('makeType preserves TData through token use-sites', ({ expect }) => {
|
|
87
|
+
// Type-level smoke test: if TS compiles, we're fine. The `RoleToken<T>`
|
|
88
|
+
// phantom should not impose a runtime constraint.
|
|
89
|
+
const token: RoleToken<{ subject: number }> = makeType('numeric');
|
|
90
|
+
expect(token.role).toBe('numeric');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('isSurfaceAvailable typing', () => {
|
|
95
|
+
// These tests double as static assertions: the `@ts-expect-error` comments
|
|
96
|
+
// fail to compile if the surrounding expression typechecks, so they verify
|
|
97
|
+
// the typed overload narrows `data` to the token's declared contract.
|
|
98
|
+
const sectionToken = makeType<{ attendableId: string; subject: string }>('section');
|
|
99
|
+
const capabilityManager = { getAll: () => [] } as unknown as CapabilityManager.CapabilityManager;
|
|
100
|
+
|
|
101
|
+
test('typed overload accepts data matching the token contract', () => {
|
|
102
|
+
// No error — data has all required fields.
|
|
103
|
+
isSurfaceAvailable(capabilityManager, {
|
|
104
|
+
type: sectionToken,
|
|
105
|
+
data: { attendableId: 'id', subject: 'x' },
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('typed overload rejects data missing required fields', () => {
|
|
110
|
+
// @ts-expect-error — `data` is missing `attendableId` required by the token.
|
|
111
|
+
isSurfaceAvailable(capabilityManager, { type: sectionToken, data: { subject: 'x' } });
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('typed overload rejects data with wrong field type', () => {
|
|
115
|
+
// @ts-expect-error — `attendableId` must be a string, not a number.
|
|
116
|
+
isSurfaceAvailable(capabilityManager, { type: sectionToken, data: { attendableId: 123, subject: 'x' } });
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('legacy overload accepts loose data when `role` is a string', () => {
|
|
120
|
+
// No error — legacy overload's `data` is untyped (`Record<string, unknown>`).
|
|
121
|
+
isSurfaceAvailable(capabilityManager, {
|
|
122
|
+
role: 'article',
|
|
123
|
+
data: { anything: 'goes' },
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|