gloomberb 0.5.1 → 0.6.1
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/README.md +91 -11
- package/package.json +13 -5
- package/src/app.tsx +414 -191
- package/src/architecture/import-boundaries.test.ts +118 -0
- package/src/assets/gloomberb-logo.png +0 -0
- package/src/assets/gloomberb-logo.svg +73 -0
- package/src/brokers/account-cache.ts +157 -0
- package/src/brokers/profile-form.test.ts +73 -0
- package/src/brokers/profile-form.ts +109 -0
- package/src/brokers/remote-broker-adapter.ts +91 -0
- package/src/brokers/sync-broker-instance.test.ts +124 -1
- package/src/brokers/sync-broker-instance.ts +113 -17
- package/src/capabilities/factories.ts +100 -0
- package/src/capabilities/index.ts +4 -0
- package/src/capabilities/registry.test.ts +137 -0
- package/src/capabilities/registry.ts +131 -0
- package/src/capabilities/service-capabilities.ts +27 -0
- package/src/capabilities/types.ts +84 -0
- package/src/cli/commands/ticker.ts +11 -3
- package/src/cli/context.ts +19 -13
- package/src/cli/helpers.ts +1 -0
- package/src/cli/types.ts +2 -2
- package/src/components/chart/chart-controller.ts +4 -24
- package/src/components/chart/chart-data.ts +3 -14
- package/src/components/chart/chart-indicator-selector.tsx +28 -6
- package/src/components/chart/chart-pane-settings.ts +15 -28
- package/src/components/chart/chart-renderer.ts +74 -99
- package/src/components/chart/chart-resolution.ts +10 -10
- package/src/components/chart/chart-scroll.test.ts +6 -5
- package/src/components/chart/chart-scroll.ts +2 -2
- package/src/components/chart/chart-types.ts +0 -1
- package/src/components/chart/chart-viewport.ts +2 -1
- package/src/components/chart/chart.test.ts +37 -0
- package/src/components/chart/comparison-chart-data.ts +3 -17
- package/src/components/chart/comparison-chart-renderer.test.ts +27 -4
- package/src/components/chart/comparison-chart-renderer.ts +1 -1
- package/src/components/chart/comparison-stock-chart.tsx +318 -158
- package/src/components/chart/cursor-motion.ts +3 -2
- package/src/components/chart/indicators/bands.test.ts +0 -14
- package/src/components/chart/indicators/moving-averages.test.ts +0 -15
- package/src/components/chart/indicators/options.ts +3 -3
- package/src/components/chart/indicators/oscillators.test.ts +0 -21
- package/src/components/chart/indicators/types.ts +1 -2
- package/src/components/chart/native/chart-rasterizer.ts +37 -44
- package/src/components/chart/native/kitty-adapter.ts +2 -5
- package/src/components/chart/native/kitty-manager.ts +1 -1
- package/src/components/chart/native/kitty-protocol.ts +0 -1
- package/src/components/chart/native/kitty-support.ts +1 -1
- package/src/components/chart/native/kitty.test.ts +53 -13
- package/src/components/chart/native/renderer-selection.ts +1 -1
- package/src/components/chart/native/surface-manager.ts +1 -1
- package/src/components/chart/native/surface-visibility.ts +48 -0
- package/src/components/chart/static-chart-surface.test.tsx +51 -0
- package/src/components/chart/static-chart-surface.tsx +191 -0
- package/src/components/chart/stock-chart-renderer-switch.test.tsx +242 -35
- package/src/components/chart/stock-chart.tsx +452 -191
- package/src/components/command-bar/__snapshots__/command-bar.test.tsx.snap +4 -4
- package/src/components/command-bar/command-bar.test.tsx +269 -20
- package/src/components/command-bar/command-bar.tsx +830 -353
- package/src/components/command-bar/command-registry.ts +10 -20
- package/src/components/command-bar/helpers.test.ts +1 -1
- package/src/components/command-bar/helpers.ts +9 -11
- package/src/components/command-bar/pane-template-display.ts +4 -8
- package/src/components/command-bar/root-shortcuts.ts +12 -11
- package/src/components/command-bar/view-model.test.ts +8 -42
- package/src/components/command-bar/view-model.ts +8 -36
- package/src/components/command-bar/workflow-ops.test.ts +76 -2
- package/src/components/command-bar/workflow-ops.ts +40 -9
- package/src/components/command-bar/workflow-types.ts +2 -1
- package/src/components/data-table-stack-view.test.tsx +206 -0
- package/src/components/data-table-stack-view.tsx +152 -0
- package/src/components/data-table-view.test.tsx +188 -0
- package/src/components/data-table-view.tsx +279 -0
- package/src/components/feed-data-table-stack-view.test.tsx +225 -0
- package/src/components/feed-data-table-stack-view.tsx +365 -0
- package/src/components/index.ts +26 -31
- package/src/components/layout/detached-pane-shell.tsx +185 -0
- package/src/components/layout/floating-pane.tsx +87 -14
- package/src/components/layout/header.tsx +139 -49
- package/src/components/layout/pane-content.tsx +42 -0
- package/src/components/layout/pane-footer.test.tsx +195 -0
- package/src/components/layout/pane-footer.tsx +425 -0
- package/src/components/layout/pane-header.test.tsx +39 -0
- package/src/components/layout/pane-header.tsx +192 -14
- package/src/components/layout/pane-keyboard-scroll.test.tsx +226 -0
- package/src/components/layout/pane-sizing.ts +9 -10
- package/src/components/layout/pane-title.ts +35 -0
- package/src/components/layout/pane.tsx +52 -11
- package/src/components/layout/shell.test.tsx +315 -107
- package/src/components/layout/shell.tsx +1010 -368
- package/src/components/layout/status-bar.test.tsx +17 -10
- package/src/components/layout/status-bar.tsx +367 -100
- package/src/components/layout/titlebar-overlay.ts +2 -0
- package/src/components/markdown-editor.tsx +29 -14
- package/src/components/markdown-text.tsx +25 -24
- package/src/components/onboarding/onboarding-wizard.test.tsx +8 -3
- package/src/components/onboarding/onboarding-wizard.tsx +347 -473
- package/src/components/pane-settings-dialog.tsx +521 -89
- package/src/components/pane-template-wizard.test.tsx +1 -1
- package/src/components/pane-template-wizard.tsx +38 -37
- package/src/components/price-selector-dialog.tsx +22 -21
- package/src/components/ticker-badge-list.tsx +53 -0
- package/src/components/ticker-badge-text.test.tsx +44 -1
- package/src/components/ticker-badge-text.tsx +78 -38
- package/src/components/ticker-badge.tsx +28 -7
- package/src/components/ticker-list-table-view.tsx +248 -0
- package/src/components/ticker-list-table.test.tsx +47 -1
- package/src/components/ticker-list-table.tsx +212 -41
- package/src/components/toggle-list.tsx +114 -8
- package/src/components/ui/button.tsx +24 -16
- package/src/components/ui/choice-dialog.tsx +89 -0
- package/src/components/ui/data-table.tsx +313 -114
- package/src/components/ui/external-link.tsx +52 -13
- package/src/components/ui/fields.tsx +44 -30
- package/src/components/ui/frame.tsx +24 -57
- package/src/components/ui/index.ts +15 -50
- package/src/components/ui/list-view.tsx +65 -25
- package/src/components/ui/loading.tsx +5 -60
- package/src/components/ui/message-composer.test.tsx +81 -0
- package/src/components/ui/message-composer.tsx +139 -0
- package/src/components/ui/multi-select-dialog.tsx +100 -32
- package/src/components/ui/multi-select.ts +112 -0
- package/src/components/ui/native-select.tsx +120 -0
- package/src/components/ui/page-stack-view.tsx +49 -19
- package/src/components/ui/remote-image.tsx +50 -0
- package/src/components/ui/row-value-cache.test.ts +17 -0
- package/src/components/ui/row-value-cache.ts +41 -0
- package/src/components/ui/shortcut-hint.tsx +55 -0
- package/src/components/ui/status.tsx +12 -67
- package/src/components/ui/table-layout.ts +59 -0
- package/src/components/ui/tabs.tsx +249 -27
- package/src/components/ui/toggle.tsx +19 -127
- package/src/components/ui/ui.test.tsx +266 -53
- package/src/components/use-double-click-activation.ts +7 -2
- package/src/components/use-external-link-footer.ts +79 -0
- package/src/core/app-services.ts +95 -0
- package/src/core/state/app-state.ts +886 -0
- package/src/{state → core/state}/session-persistence.ts +7 -6
- package/src/data/config-layout.ts +225 -0
- package/src/data/config-store-node.ts +390 -0
- package/src/data/config-store.test.ts +72 -0
- package/src/data/config-store.ts +35 -478
- package/src/data/sqlite-json.ts +2 -5
- package/src/data/sqlite-retry.ts +1 -0
- package/src/index.tsx +2 -68
- package/src/market-data/coordinator-subscriptions.test.ts +125 -0
- package/src/market-data/coordinator.test.ts +73 -4
- package/src/market-data/coordinator.ts +190 -24
- package/src/market-data/hooks.test.tsx +1 -1
- package/src/market-data/hooks.tsx +109 -87
- package/src/market-data/query-store.ts +3 -3
- package/src/market-data/request-types.test.ts +0 -14
- package/src/market-data/result-types.ts +1 -0
- package/src/news/aggregator.test.ts +267 -0
- package/src/news/aggregator.ts +452 -0
- package/src/news/hooks.ts +39 -0
- package/src/news/ticker-symbols.ts +21 -0
- package/src/news/types.ts +77 -0
- package/src/notifications/app-notifier.ts +21 -10
- package/src/pane-settings.test.ts +0 -2
- package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +124 -134
- package/src/plugins/builtin/ai/gloomberb-cli.ts +14 -13
- package/src/plugins/builtin/ai/providers.ts +1 -9
- package/src/plugins/builtin/ai/runner.ts +41 -5
- package/src/plugins/builtin/ai/screener-pane.test.tsx +37 -55
- package/src/plugins/builtin/ai/screener-pane.tsx +231 -276
- package/src/plugins/builtin/ai/settings.ts +0 -1
- package/src/plugins/builtin/ai/utils.ts +1 -71
- package/src/plugins/builtin/alerts/alert-engine.test.ts +1 -38
- package/src/plugins/builtin/alerts/index.test.tsx +61 -82
- package/src/plugins/builtin/alerts/index.tsx +263 -155
- package/src/plugins/builtin/alerts/types.ts +7 -0
- package/src/plugins/builtin/analytics/index.test.tsx +13 -8
- package/src/plugins/builtin/analytics/index.tsx +78 -120
- package/src/plugins/builtin/analytics/metrics.test.ts +0 -4
- package/src/plugins/builtin/ask-ai.test.tsx +55 -54
- package/src/plugins/builtin/broker-manager/index.test.tsx +168 -0
- package/src/plugins/builtin/broker-manager/index.tsx +759 -0
- package/src/plugins/builtin/broker-manager/model.test.ts +107 -0
- package/src/plugins/builtin/broker-manager/model.ts +142 -0
- package/src/plugins/builtin/chat-controller.test.ts +129 -0
- package/src/plugins/builtin/chat-controller.ts +85 -14
- package/src/plugins/builtin/chat.test.tsx +283 -36
- package/src/plugins/builtin/chat.tsx +363 -170
- package/src/plugins/builtin/cloud-auth-actions.tsx +72 -0
- package/src/plugins/builtin/cloud-tweets.tsx +896 -0
- package/src/plugins/builtin/comparison-chart.test.tsx +46 -57
- package/src/plugins/builtin/comparison-chart.tsx +11 -11
- package/src/plugins/builtin/correlation/compute.test.ts +0 -17
- package/src/plugins/builtin/correlation/index.tsx +51 -46
- package/src/plugins/builtin/correlation/settings.ts +1 -2
- package/src/plugins/builtin/debug.tsx +99 -70
- package/src/plugins/builtin/earnings/earnings-cache.test.ts +2 -2
- package/src/plugins/builtin/earnings/earnings-cache.ts +12 -3
- package/src/plugins/builtin/earnings/earnings-data.test.ts +42 -11
- package/src/plugins/builtin/earnings/earnings-data.ts +70 -5
- package/src/plugins/builtin/earnings/index.tsx +187 -94
- package/src/plugins/builtin/econ/calendar-source.ts +9 -116
- package/src/plugins/builtin/econ/fred-client.test.ts +1 -14
- package/src/plugins/builtin/econ/fred-series-map.ts +1 -0
- package/src/plugins/builtin/econ/index.tsx +236 -421
- package/src/plugins/builtin/econ/types.ts +1 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +43 -45
- package/src/plugins/builtin/fx-matrix/pairs.ts +1 -0
- package/src/plugins/builtin/help.test.tsx +120 -60
- package/src/plugins/builtin/help.tsx +266 -82
- package/src/plugins/builtin/holders/index.test.ts +45 -0
- package/src/plugins/builtin/holders/index.tsx +949 -0
- package/src/plugins/builtin/insider/index.tsx +207 -253
- package/src/plugins/builtin/insider/insider-data.test.ts +1 -11
- package/src/plugins/builtin/insider/insider-data.ts +1 -0
- package/src/plugins/builtin/layout-manager.tsx +12 -40
- package/src/plugins/builtin/market-movers/index.tsx +70 -144
- package/src/plugins/builtin/market-movers/screener.test.ts +0 -18
- package/src/plugins/builtin/news-wire/breaking-notifications.test.ts +98 -0
- package/src/plugins/builtin/news-wire/breaking-notifications.ts +110 -0
- package/src/plugins/builtin/news-wire/breaking-pane.tsx +157 -0
- package/src/plugins/builtin/news-wire/categories.ts +114 -0
- package/src/plugins/builtin/news-wire/default-feeds.ts +3 -0
- package/src/plugins/builtin/news-wire/digest-store.ts +44 -0
- package/src/plugins/builtin/news-wire/feed-config.test.ts +90 -0
- package/src/plugins/builtin/news-wire/feed-config.ts +216 -0
- package/src/plugins/builtin/news-wire/feed-pane.tsx +21 -0
- package/src/plugins/builtin/news-wire/hash.ts +9 -0
- package/src/plugins/builtin/news-wire/index.tsx +92 -0
- package/src/plugins/builtin/news-wire/industry-pane.tsx +140 -0
- package/src/plugins/builtin/news-wire/news-detail-view.tsx +256 -0
- package/src/plugins/builtin/news-wire/news-footer.ts +28 -0
- package/src/plugins/builtin/news-wire/news-preset-pane.tsx +94 -0
- package/src/plugins/builtin/news-wire/news-query-presets.ts +40 -0
- package/src/plugins/builtin/news-wire/news-table.test.tsx +206 -0
- package/src/plugins/builtin/news-wire/news-table.tsx +296 -0
- package/src/plugins/builtin/news-wire/persisted-articles.ts +92 -0
- package/src/plugins/builtin/news-wire/read-state.test.ts +30 -0
- package/src/plugins/builtin/news-wire/read-state.ts +76 -0
- package/src/plugins/builtin/news-wire/rss-parser.test.ts +184 -0
- package/src/plugins/builtin/news-wire/rss-parser.ts +213 -0
- package/src/plugins/builtin/news-wire/rss-source.test.ts +159 -0
- package/src/plugins/builtin/news-wire/rss-source.ts +181 -0
- package/src/plugins/builtin/news-wire/top-pane.tsx +21 -0
- package/src/plugins/builtin/news.tsx +98 -25
- package/src/plugins/builtin/notes-files.ts +51 -10
- package/src/plugins/builtin/notes.tsx +332 -131
- package/src/plugins/builtin/options.test.tsx +185 -0
- package/src/plugins/builtin/options.tsx +346 -206
- package/src/plugins/builtin/plugin-groups.ts +92 -0
- package/src/plugins/builtin/portfolio-list/header.tsx +72 -37
- package/src/plugins/builtin/portfolio-list/index.tsx +25 -42
- package/src/plugins/builtin/portfolio-list/metrics.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane.tsx +246 -164
- package/src/plugins/builtin/portfolio-list/settings.ts +19 -51
- package/src/plugins/builtin/portfolio-list/summary.tsx +21 -16
- package/src/plugins/builtin/portfolio-list/table.tsx +66 -25
- package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.test.tsx +1 -1
- package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.ts +1 -1
- package/src/plugins/builtin/portfolio-list.test.ts +60 -1
- package/src/plugins/builtin/portfolio-list.test.tsx +122 -55
- package/src/plugins/builtin/quote-monitor.test.tsx +2 -27
- package/src/plugins/builtin/research/index.tsx +724 -0
- package/src/plugins/builtin/sec.tsx +67 -19
- package/src/plugins/builtin/sectors/index.tsx +42 -80
- package/src/plugins/builtin/sectors/sector-data.ts +1 -0
- package/src/plugins/builtin/ticker-detail/chart-tab.tsx +25 -39
- package/src/plugins/builtin/ticker-detail/financials-tab.tsx +108 -58
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +383 -271
- package/src/plugins/builtin/ticker-detail/pane.tsx +143 -49
- package/src/plugins/builtin/ticker-detail/quote-monitor.tsx +43 -27
- package/src/plugins/builtin/ticker-detail/settings.ts +3 -6
- package/src/plugins/builtin/ticker-detail-chart-tab-switch.test.tsx +82 -10
- package/src/plugins/builtin/ticker-detail.test.tsx +258 -33
- package/src/plugins/builtin/ticker-surface.ts +68 -0
- package/src/plugins/builtin/world-indices/index.tsx +44 -82
- package/src/plugins/builtin/world-indices/indices.ts +1 -0
- package/src/plugins/builtin/yahoo.ts +55 -1
- package/src/plugins/builtin/yield-curve/index.tsx +87 -145
- package/src/plugins/builtin/yield-curve/treasury-data.ts +6 -77
- package/src/plugins/catalog-ui.test.ts +24 -0
- package/src/plugins/catalog-ui.ts +44 -0
- package/src/plugins/catalog.ts +2 -50
- package/src/plugins/ibkr/__snapshots__/trade-tab.test.tsx.snap +5 -5
- package/src/plugins/ibkr/account-cache.test.ts +15 -14
- package/src/plugins/ibkr/account-cache.ts +15 -120
- package/src/plugins/ibkr/broker-adapter.ts +67 -0
- package/src/plugins/ibkr/config.test.ts +0 -18
- package/src/plugins/ibkr/dialogs.tsx +14 -56
- package/src/plugins/ibkr/flex.test.ts +57 -2
- package/src/plugins/ibkr/flex.ts +116 -12
- package/src/plugins/ibkr/gateway-helpers.ts +8 -3
- package/src/plugins/ibkr/gateway-service-native.ts +2381 -0
- package/src/plugins/ibkr/gateway-service.test.ts +47 -9
- package/src/plugins/ibkr/gateway-service.ts +264 -2235
- package/src/plugins/ibkr/gateway-types.ts +27 -0
- package/src/plugins/ibkr/index.test.tsx +3 -11
- package/src/plugins/ibkr/index.tsx +1 -0
- package/src/plugins/ibkr/price-normalization.test.ts +1 -6
- package/src/plugins/ibkr/price-normalization.ts +1 -0
- package/src/plugins/ibkr/trade-badge.tsx +6 -5
- package/src/plugins/ibkr/trade-tab.test.tsx +55 -3
- package/src/plugins/ibkr/trade-tab.tsx +166 -117
- package/src/plugins/ibkr/trading-pane.tsx +117 -83
- package/src/plugins/pane-manager.test.ts +3 -1
- package/src/plugins/pane-manager.ts +93 -19
- package/src/plugins/plugin-runtime.test.tsx +176 -74
- package/src/plugins/plugin-runtime.tsx +228 -10
- package/src/plugins/prediction-markets/cache.ts +49 -0
- package/src/plugins/prediction-markets/categories.ts +0 -10
- package/src/plugins/prediction-markets/chart.test.tsx +1 -1
- package/src/plugins/prediction-markets/chart.tsx +21 -20
- package/src/plugins/prediction-markets/cli.ts +1 -0
- package/src/plugins/prediction-markets/controller-data.ts +135 -89
- package/src/plugins/prediction-markets/controller.ts +37 -108
- package/src/plugins/prediction-markets/detail/book.tsx +23 -22
- package/src/plugins/prediction-markets/detail/outcomes.tsx +33 -32
- package/src/plugins/prediction-markets/detail/overview.tsx +17 -12
- package/src/plugins/prediction-markets/detail/pane.tsx +59 -45
- package/src/plugins/prediction-markets/detail/rules.tsx +22 -7
- package/src/plugins/prediction-markets/detail/shared.tsx +3 -2
- package/src/plugins/prediction-markets/detail/trades.tsx +12 -11
- package/src/plugins/prediction-markets/detail.test.tsx +1 -1
- package/src/plugins/prediction-markets/keyboard.ts +1 -0
- package/src/plugins/prediction-markets/launch.test.ts +1 -1
- package/src/plugins/prediction-markets/launch.ts +1 -1
- package/src/plugins/prediction-markets/metrics.ts +25 -12
- package/src/plugins/prediction-markets/pane.test.tsx +16 -7
- package/src/plugins/prediction-markets/pane.tsx +180 -82
- package/src/plugins/prediction-markets/plugin.test.tsx +37 -45
- package/src/plugins/prediction-markets/services/fetch.ts +27 -10
- package/src/plugins/prediction-markets/services/kalshi-adapter.ts +20 -3
- package/src/plugins/prediction-markets/services/polymarket-adapter.ts +29 -11
- package/src/plugins/prediction-markets/settings.ts +0 -5
- package/src/plugins/prediction-markets/test-helpers.tsx +19 -44
- package/src/plugins/registry.test.ts +307 -0
- package/src/plugins/registry.ts +293 -82
- package/src/react/input.ts +61 -0
- package/src/react/plugins/plugin-slot.tsx +21 -0
- package/src/react/use-raf-callback.ts +44 -0
- package/src/renderers/electrobun/bun/application-menu-click.test.ts +41 -0
- package/src/renderers/electrobun/bun/application-menu-click.ts +55 -0
- package/src/renderers/electrobun/bun/application-menu.ts +118 -0
- package/src/renderers/electrobun/bun/context-menu-click.test.ts +67 -0
- package/src/renderers/electrobun/bun/context-menu-click.ts +61 -0
- package/src/renderers/electrobun/bun/context-menu-normalize.test.ts +52 -0
- package/src/renderers/electrobun/bun/context-menu-normalize.ts +67 -0
- package/src/renderers/electrobun/bun/core-capabilities.ts +328 -0
- package/src/renderers/electrobun/bun/desktop-workspace.test.ts +63 -0
- package/src/renderers/electrobun/bun/desktop-workspace.ts +162 -0
- package/src/renderers/electrobun/bun/index.ts +1149 -0
- package/src/renderers/electrobun/bun/window-frame.test.ts +40 -0
- package/src/renderers/electrobun/bun/window-frame.ts +46 -0
- package/src/renderers/electrobun/shared/protocol.ts +72 -0
- package/src/renderers/electrobun/view/ai-host.ts +93 -0
- package/src/renderers/electrobun/view/app-services.ts +348 -0
- package/src/renderers/electrobun/view/application-menu-bridge.ts +12 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +173 -0
- package/src/renderers/electrobun/view/broker-remote-client.ts +154 -0
- package/src/renderers/electrobun/view/config-host.ts +35 -0
- package/src/renderers/electrobun/view/context-menu.test.ts +140 -0
- package/src/renderers/electrobun/view/context-menu.ts +164 -0
- package/src/renderers/electrobun/view/data-table.tsx +773 -0
- package/src/renderers/electrobun/view/desktop-controls.tsx +651 -0
- package/src/renderers/electrobun/view/desktop-window-bridge.ts +59 -0
- package/src/renderers/electrobun/view/desktop-window-snapshot.test.ts +57 -0
- package/src/renderers/electrobun/view/desktop-window-snapshot.ts +41 -0
- package/src/renderers/electrobun/view/dialog-host.tsx +62 -0
- package/src/renderers/electrobun/view/http-fetch.ts +113 -0
- package/src/renderers/electrobun/view/input-host.tsx +112 -0
- package/src/renderers/electrobun/view/key-event.test.ts +34 -0
- package/src/renderers/electrobun/view/key-event.ts +134 -0
- package/src/renderers/electrobun/view/main.tsx +104 -0
- package/src/renderers/electrobun/view/native-renderer.ts +110 -0
- package/src/renderers/electrobun/view/native-stubs/chart-kitty-support.ts +9 -0
- package/src/renderers/electrobun/view/native-stubs/chart-surface-manager.ts +25 -0
- package/src/renderers/electrobun/view/native-stubs/chart-surface-sync.ts +1 -0
- package/src/renderers/electrobun/view/notes-files.ts +56 -0
- package/src/renderers/electrobun/view/resource-store.test.ts +44 -0
- package/src/renderers/electrobun/view/resource-store.ts +106 -0
- package/src/renderers/electrobun/view/rpc-codec.ts +42 -0
- package/src/renderers/electrobun/view/scrollbar-activity.ts +23 -0
- package/src/renderers/electrobun/view/toast-host.tsx +65 -0
- package/src/renderers/electrobun/view/ui-host.tsx +1509 -0
- package/src/renderers/electrobun/view/update-host.ts +38 -0
- package/src/renderers/opentui/dialog-host.test.tsx +44 -0
- package/src/renderers/opentui/dialog-host.tsx +56 -0
- package/src/renderers/opentui/host.tsx +140 -0
- package/src/renderers/opentui/image-loader.test.ts +25 -0
- package/src/renderers/opentui/image-loader.ts +105 -0
- package/src/renderers/opentui/image-surface.tsx +266 -0
- package/src/renderers/opentui/input-host.tsx +63 -0
- package/src/renderers/opentui/start.tsx +71 -0
- package/src/renderers/opentui/test-utils.tsx +76 -0
- package/src/renderers/opentui/toast-host.tsx +10 -0
- package/src/renderers/opentui/ui-host.tsx +98 -0
- package/src/sources/gloomberb-cloud.test.ts +288 -17
- package/src/sources/gloomberb-cloud.ts +176 -9
- package/src/sources/provider-errors.ts +1 -0
- package/src/sources/provider-router.test.ts +220 -81
- package/src/sources/provider-router.ts +294 -111
- package/src/sources/sec-edgar.ts +19 -6
- package/src/sources/yahoo-finance.test.ts +0 -5
- package/src/sources/yahoo-finance.ts +420 -11
- package/src/state/app-activity.ts +7 -7
- package/src/state/app-bootstrap.ts +114 -40
- package/src/state/app-context-selector.test.tsx +70 -1
- package/src/state/app-context.test.ts +71 -3
- package/src/state/app-context.test.tsx +14 -7
- package/src/state/app-context.tsx +209 -869
- package/src/state/config-save-scheduler.ts +35 -0
- package/src/state/pane-scroll-registry.tsx +254 -0
- package/src/state/persist-scheduler.test.ts +67 -0
- package/src/state/persist-scheduler.ts +69 -0
- package/src/state/selectors-ui.ts +55 -0
- package/src/state/selectors.ts +15 -71
- package/src/state/session-persistence.test.ts +1 -1
- package/src/state/ticker-refresh-queue.ts +52 -3
- package/src/state/use-inline-tickers.ts +18 -16
- package/src/state/use-quote-streaming.test.ts +0 -6
- package/src/state/use-quote-streaming.test.tsx +1 -1
- package/src/state/use-quote-streaming.ts +3 -2
- package/src/state/use-session-snapshot.ts +32 -17
- package/src/test-support/plugin-runtime.ts +149 -0
- package/src/theme/color-utils.ts +1 -0
- package/src/theme/colors.ts +16 -0
- package/src/types/broker.ts +16 -1
- package/src/types/capability-route-source.ts +23 -0
- package/src/types/config.test.ts +23 -0
- package/src/types/config.ts +145 -10
- package/src/types/context-menu.ts +95 -0
- package/src/types/data-provider.ts +34 -3
- package/src/types/desktop-menu.ts +13 -0
- package/src/types/desktop-window.ts +29 -0
- package/src/types/financials.ts +123 -2
- package/src/types/instrument.ts +1 -0
- package/src/types/news-source.ts +9 -0
- package/src/types/persistence.ts +1 -0
- package/src/types/plugin.ts +32 -8
- package/src/ui/ascii-font.ts +85 -0
- package/src/ui/context-menu.test.ts +94 -0
- package/src/ui/context-menu.tsx +433 -0
- package/src/ui/dialog.tsx +55 -0
- package/src/ui/host.tsx +364 -0
- package/src/ui/index.tsx +134 -0
- package/src/ui/toast.tsx +40 -0
- package/src/updater.test.ts +69 -0
- package/src/updater.ts +61 -18
- package/src/utils/api-client.test.ts +99 -9
- package/src/utils/api-client.ts +378 -18
- package/src/utils/back-navigation.ts +6 -0
- package/src/utils/cli-output.ts +1 -0
- package/src/utils/currency-units.test.ts +1 -6
- package/src/utils/currency-units.ts +1 -0
- package/src/utils/debug-log.ts +68 -0
- package/src/utils/dom-screenshot.ts +326 -0
- package/src/utils/exchange-rate-map.ts +1 -0
- package/src/utils/exchanges.ts +214 -0
- package/src/utils/format.test.ts +7 -0
- package/src/utils/format.ts +1 -0
- package/src/utils/fuzzy-search.ts +1 -0
- package/src/utils/html-entities.test.ts +8 -0
- package/src/utils/html-entities.ts +32 -0
- package/src/utils/http-transport.ts +11 -0
- package/src/utils/main-thread-monitor.ts +127 -0
- package/src/utils/perf-marks.ts +54 -0
- package/src/utils/quote-freshness.ts +27 -50
- package/src/utils/quote-resolution.test.ts +5 -5
- package/src/utils/quote-resolution.ts +0 -1
- package/src/utils/quote-time.ts +1 -5
- package/src/utils/sec.test.ts +0 -12
- package/src/utils/selection-clipboard.ts +14 -6
- package/src/utils/shortcut-labels.test.ts +20 -0
- package/src/utils/shortcut-labels.ts +67 -0
- package/src/utils/slugify.ts +1 -0
- package/src/utils/terminal-input-reset.ts +1 -0
- package/src/utils/text-wrap.ts +82 -0
- package/src/utils/throttled-fetch.test.ts +19 -0
- package/src/utils/throttled-fetch.ts +11 -9
- package/src/utils/ticker-list.test.ts +1 -7
- package/src/utils/ticker-list.ts +1 -0
- package/src/utils/timestamp.ts +29 -0
- package/src/utils/tweet-text.test.ts +13 -0
- package/src/utils/tweet-text.ts +18 -0
- package/src/utils/url.ts +11 -0
- package/src/version.ts +1 -1
- package/src/components/chart/chart-control-hint.tsx +0 -39
- package/src/components/detail-feed-view.test.tsx +0 -180
- package/src/components/detail-feed-view.tsx +0 -531
- package/src/components/layout/pixel-mouse-mode.test.ts +0 -122
- package/src/components/layout/pixel-mouse.test.ts +0 -40
- package/src/components/spinner.tsx +0 -2
- package/src/components/tab-bar.tsx +0 -17
- package/src/components/ui/multi-select-chips.tsx +0 -69
- package/src/plugins/builtin/ai/index.test.tsx +0 -139
- package/src/plugins/builtin/ask-ai.tsx +0 -9
- package/src/plugins/builtin/correlation/plugin.test.ts +0 -44
- package/src/plugins/builtin/correlation/settings.test.ts +0 -34
- package/src/plugins/builtin/econ/calendar-source.test.ts +0 -219
- package/src/plugins/builtin/econ/fred-client.ts +0 -79
- package/src/plugins/builtin/fred-settings.ts +0 -10
- package/src/plugins/builtin/options-availability.test.tsx +0 -179
- package/src/plugins/builtin/options-availability.ts +0 -158
- package/src/plugins/builtin/portfolio-list/metrics.test.ts +0 -61
- package/src/plugins/builtin/yield-curve/treasury-data.test.ts +0 -212
- package/src/plugins/prediction-markets/status.ts +0 -24
- package/src/plugins/prediction-markets/table.tsx +0 -87
- package/src/utils/quote-time.test.ts +0 -22
- package/src/utils/selection-clipboard.test.ts +0 -43
- package/src/utils/terminal-input-reset.test.ts +0 -50
package/src/plugins/registry.ts
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { createReactSlotRegistry, createSlot } from "@opentui/react";
|
|
3
|
-
import { createElement } from "react";
|
|
1
|
+
import { Fragment, createElement, type ReactNode } from "react";
|
|
4
2
|
import type { AppPersistence } from "../data/app-persistence";
|
|
5
3
|
import type { TickerRepository } from "../data/ticker-repository";
|
|
6
4
|
import type { BrokerAdapter } from "../types/broker";
|
|
5
|
+
import {
|
|
6
|
+
CapabilityRegistry,
|
|
7
|
+
type NewsCapability,
|
|
8
|
+
type PluginCapability,
|
|
9
|
+
} from "../capabilities";
|
|
7
10
|
import type { BrokerInstanceConfig, LayoutConfig, PaneInstanceConfig } from "../types/config";
|
|
8
11
|
import type { DataProvider } from "../types/data-provider";
|
|
9
12
|
import type { TickerFinancials } from "../types/financials";
|
|
10
13
|
import type {
|
|
11
14
|
AppNotificationRequest,
|
|
15
|
+
BrokerInstanceUpdateOptions,
|
|
12
16
|
CommandDef,
|
|
17
|
+
ContextMenuProviderDef,
|
|
13
18
|
CustomColumnDef,
|
|
14
19
|
DetailTabDef,
|
|
15
20
|
GloomPlugin,
|
|
@@ -25,6 +30,7 @@ import type {
|
|
|
25
30
|
PluginResumeState,
|
|
26
31
|
TickerAction,
|
|
27
32
|
} from "../types/plugin";
|
|
33
|
+
import type { ContextMenuContext, ContextMenuItem } from "../types/context-menu";
|
|
28
34
|
import type { TickerRecord } from "../types/ticker";
|
|
29
35
|
import { addPaneFloating, removePane } from "./pane-manager";
|
|
30
36
|
import { EventBus, type PluginEvents } from "./event-bus";
|
|
@@ -36,17 +42,31 @@ import {
|
|
|
36
42
|
resolveCollectionForPane,
|
|
37
43
|
resolveTickerForPane,
|
|
38
44
|
type PaneRuntimeState,
|
|
39
|
-
} from "../state/app-
|
|
45
|
+
} from "../core/state/app-state";
|
|
40
46
|
import { deletePaneSetting, getPaneSettings, setPaneSetting } from "../pane-settings";
|
|
41
47
|
|
|
42
|
-
let
|
|
48
|
+
let sharedMarketData: DataProvider | undefined;
|
|
43
49
|
let sharedRegistry: PluginRegistry | undefined;
|
|
44
|
-
|
|
50
|
+
type SlotEntry = {
|
|
51
|
+
pluginId: string;
|
|
52
|
+
order: number;
|
|
53
|
+
render: (props: unknown) => ReactNode;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
interface ContextMenuProviderEntry {
|
|
57
|
+
pluginId: string;
|
|
58
|
+
provider: ContextMenuProviderDef;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface PluginRegistryOptions {
|
|
62
|
+
enableCapabilityHandlers?: boolean;
|
|
63
|
+
wrapBrokerAdapter?: (broker: BrokerAdapter, pluginId: string) => BrokerAdapter;
|
|
64
|
+
}
|
|
45
65
|
|
|
46
|
-
export function
|
|
66
|
+
export function getSharedMarketData(): DataProvider | undefined { return sharedMarketData; }
|
|
47
67
|
export function getSharedRegistry(): PluginRegistry | undefined { return sharedRegistry; }
|
|
48
|
-
export function
|
|
49
|
-
|
|
68
|
+
export function setSharedMarketDataForTests(provider: DataProvider | undefined): void {
|
|
69
|
+
sharedMarketData = provider;
|
|
50
70
|
}
|
|
51
71
|
export function setSharedRegistryForTests(registry: PluginRegistry | undefined): void {
|
|
52
72
|
sharedRegistry = registry;
|
|
@@ -58,22 +78,27 @@ interface PluginItems {
|
|
|
58
78
|
commands: string[];
|
|
59
79
|
columns: string[];
|
|
60
80
|
brokers: string[];
|
|
61
|
-
|
|
81
|
+
capabilities: string[];
|
|
62
82
|
detailTabs: string[];
|
|
63
83
|
shortcuts: string[];
|
|
64
84
|
tickerActions: string[];
|
|
85
|
+
contextMenuProviders: string[];
|
|
65
86
|
eventDisposers: Array<() => void>;
|
|
87
|
+
capabilityDisposers: Array<() => void>;
|
|
88
|
+
newsQueryWatchDisposers: Array<() => void>;
|
|
66
89
|
}
|
|
67
90
|
|
|
68
91
|
export class PluginRegistry implements PluginRuntimeAccess {
|
|
69
|
-
private
|
|
92
|
+
private slotEntries = new Map<string, SlotEntry[]>();
|
|
70
93
|
private plugins = new Map<string, GloomPlugin>();
|
|
71
94
|
private unregisterFns = new Map<string, () => void>();
|
|
72
95
|
private pluginItems = new Map<string, PluginItems>();
|
|
73
96
|
private commandOwners = new Map<string, string>();
|
|
97
|
+
private paneOwners = new Map<string, string>();
|
|
74
98
|
private paneTemplateOwners = new Map<string, string>();
|
|
75
99
|
private shortcutOwners = new Map<string, string>();
|
|
76
|
-
private
|
|
100
|
+
private capabilityOwners = new Map<string, string>();
|
|
101
|
+
private detailTabOwners = new Map<string, string>();
|
|
77
102
|
private pluginResumeListeners = new Map<string, Set<() => void>>();
|
|
78
103
|
|
|
79
104
|
private panesMap = new Map<string, PaneDef>();
|
|
@@ -81,15 +106,18 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
81
106
|
private commandsMap = new Map<string, CommandDef>();
|
|
82
107
|
private columnsMap = new Map<string, CustomColumnDef>();
|
|
83
108
|
private brokersMap = new Map<string, BrokerAdapter>();
|
|
84
|
-
private dataProvidersMap = new Map<string, DataProvider>();
|
|
85
109
|
private detailTabsMap = new Map<string, DetailTabDef>();
|
|
86
110
|
private shortcutsMap = new Map<string, KeyboardShortcut>();
|
|
87
111
|
private tickerActionsMap = new Map<string, TickerAction>();
|
|
112
|
+
private contextMenuProvidersMap = new Map<string, ContextMenuProviderEntry>();
|
|
88
113
|
|
|
89
114
|
readonly events: EventBus;
|
|
90
|
-
readonly
|
|
115
|
+
readonly capabilities: CapabilityRegistry;
|
|
116
|
+
readonly marketData: DataProvider;
|
|
91
117
|
readonly tickerRepository: TickerRepository;
|
|
92
118
|
readonly persistence: AppPersistence;
|
|
119
|
+
private readonly enableCapabilityHandlers: boolean;
|
|
120
|
+
private readonly wrapBrokerAdapter?: (broker: BrokerAdapter, pluginId: string) => BrokerAdapter;
|
|
93
121
|
|
|
94
122
|
getTickerFn: ((symbol: string) => TickerRecord | null) = () => null;
|
|
95
123
|
getDataFn: ((symbol: string) => TickerFinancials | null) = () => null;
|
|
@@ -97,7 +125,8 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
97
125
|
createBrokerInstanceFn: ((brokerType: string, label: string, values: Record<string, unknown>) => Promise<BrokerInstanceConfig>) = async () => {
|
|
98
126
|
throw new Error("createBrokerInstanceFn not set");
|
|
99
127
|
};
|
|
100
|
-
|
|
128
|
+
connectBrokerInstanceFn: ((instanceId: string) => Promise<void>) = async () => {};
|
|
129
|
+
updateBrokerInstanceFn: ((instanceId: string, values: Record<string, unknown>, options?: BrokerInstanceUpdateOptions) => Promise<void>) = async () => {};
|
|
101
130
|
syncBrokerInstanceFn: ((instanceId: string) => Promise<void>) = async () => {};
|
|
102
131
|
removeBrokerInstanceFn: ((instanceId: string) => Promise<void>) = async () => {};
|
|
103
132
|
|
|
@@ -114,42 +143,86 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
114
143
|
focusPaneFn: ((paneId: string) => void) = () => {};
|
|
115
144
|
pinTickerFn: ((symbol: string, options?: { floating?: boolean; paneType?: string }) => void) = () => {};
|
|
116
145
|
navigateTickerFn: ((symbol: string) => void) = () => {};
|
|
146
|
+
getMarketData = () => this.marketData;
|
|
147
|
+
getCapability = (capabilityId: string) => this.capabilities.get(capabilityId)?.capability ?? null;
|
|
148
|
+
getBrokerAdapter = (brokerType: string) => this.brokersMap.get(brokerType) ?? null;
|
|
149
|
+
connectBrokerInstance = (instanceId: string) => this.connectBrokerInstanceFn(instanceId);
|
|
150
|
+
updateBrokerInstance = (instanceId: string, values: Record<string, unknown>, options?: BrokerInstanceUpdateOptions) => (
|
|
151
|
+
this.updateBrokerInstanceFn(instanceId, values, options)
|
|
152
|
+
);
|
|
153
|
+
syncBrokerInstance = (instanceId: string) => this.syncBrokerInstanceFn(instanceId);
|
|
154
|
+
removeBrokerInstance = (instanceId: string) => this.removeBrokerInstanceFn(instanceId);
|
|
117
155
|
pinTicker = (symbol: string, options?: { floating?: boolean; paneType?: string }) => {
|
|
118
156
|
this.pinTickerFn(symbol, options);
|
|
119
157
|
};
|
|
120
158
|
navigateTicker = (symbol: string) => {
|
|
121
159
|
this.navigateTickerFn(symbol);
|
|
122
160
|
};
|
|
161
|
+
selectTicker = (symbol: string, paneId?: string) => {
|
|
162
|
+
this.selectTickerFn(symbol, paneId);
|
|
163
|
+
};
|
|
164
|
+
switchPanel = (panel: "left" | "right") => {
|
|
165
|
+
this.switchPanelFn(panel);
|
|
166
|
+
};
|
|
167
|
+
switchTab = (tabId: string, paneId?: string) => {
|
|
168
|
+
this.switchTabFn(tabId, paneId);
|
|
169
|
+
};
|
|
170
|
+
openCommandBar = (query?: string) => {
|
|
171
|
+
this.openCommandBarFn(query);
|
|
172
|
+
};
|
|
123
173
|
openPluginCommandWorkflow = (commandId: string) => {
|
|
124
174
|
this.openPluginCommandWorkflowFn(commandId);
|
|
125
175
|
};
|
|
126
176
|
|
|
127
|
-
getLayoutFn: (() => LayoutConfig) = () => ({ dockRoot: null, instances: [], floating: [] });
|
|
177
|
+
getLayoutFn: (() => LayoutConfig) = () => ({ dockRoot: null, instances: [], floating: [], detached: [] });
|
|
128
178
|
updateLayoutFn: ((layout: LayoutConfig) => void) = () => {};
|
|
129
179
|
getTermSizeFn: (() => { width: number; height: number }) = () => ({ width: 120, height: 40 });
|
|
130
180
|
|
|
181
|
+
registerNewsCapabilityFn: ((capability: NewsCapability) => () => void) = () => () => {};
|
|
182
|
+
watchNewsQueryFn: ((
|
|
183
|
+
query: import("../types/news-source").NewsQuery,
|
|
184
|
+
listener: (state: import("../types/news-source").NewsQueryState) => void,
|
|
185
|
+
) => () => void) = () => () => {};
|
|
186
|
+
|
|
131
187
|
notifyFn: ((notification: AppNotificationRequest) => void) = () => {};
|
|
132
188
|
getPaneRuntimeStateFn: ((paneId: string) => PaneRuntimeState | null) = () => null;
|
|
133
189
|
updatePaneRuntimeStateFn: ((paneId: string, patch: Partial<PaneRuntimeState>) => void) = () => {};
|
|
134
190
|
applyPaneSettingValueFn: ((paneId: string, field: import("../types/plugin").PaneSettingField, value: unknown) => Promise<void>) = async () => {};
|
|
135
|
-
getPluginConfigValueFn: (<T = unknown>(pluginId: string, key: string) => T | null) = () =>
|
|
191
|
+
getPluginConfigValueFn: (<T = unknown>(pluginId: string, key: string) => T | null) = (pluginId, key) => (
|
|
192
|
+
(this.getConfigFn().pluginConfig[pluginId]?.[key] as T | undefined) ?? null
|
|
193
|
+
);
|
|
136
194
|
setPluginConfigValueFn: ((pluginId: string, key: string, value: unknown) => Promise<void>) = async () => {};
|
|
195
|
+
setPluginConfigValuesFn: ((pluginId: string, values: Record<string, unknown>) => Promise<void>) = async () => {};
|
|
137
196
|
deletePluginConfigValueFn: ((pluginId: string, key: string) => Promise<void>) = async () => {};
|
|
138
197
|
|
|
139
198
|
readonly Slot;
|
|
140
199
|
|
|
141
|
-
constructor(
|
|
142
|
-
|
|
200
|
+
constructor(
|
|
201
|
+
marketData: DataProvider,
|
|
202
|
+
tickerRepository: TickerRepository,
|
|
203
|
+
persistence: AppPersistence,
|
|
204
|
+
options: PluginRegistryOptions = {},
|
|
205
|
+
) {
|
|
206
|
+
this.marketData = marketData;
|
|
143
207
|
this.tickerRepository = tickerRepository;
|
|
144
208
|
this.persistence = persistence;
|
|
209
|
+
this.enableCapabilityHandlers = options.enableCapabilityHandlers ?? true;
|
|
210
|
+
this.wrapBrokerAdapter = options.wrapBrokerAdapter;
|
|
145
211
|
this.events = new EventBus();
|
|
146
212
|
|
|
147
|
-
|
|
213
|
+
sharedMarketData = marketData;
|
|
148
214
|
sharedRegistry = this;
|
|
149
215
|
(globalThis as any).__gloomRegistry = this;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
216
|
+
this.capabilities = new CapabilityRegistry({
|
|
217
|
+
isPluginEnabled: (pluginId) => !this.getConfigFn().disabledPlugins.includes(pluginId),
|
|
218
|
+
isCapabilityEnabled: (capability, pluginId) => {
|
|
219
|
+
const disabledSources = this.getConfigFn().disabledSources ?? [];
|
|
220
|
+
return !disabledSources.includes(capability.sourceId ?? capability.id) && !this.getConfigFn().disabledPlugins.includes(pluginId);
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
this.Slot = ({ name, ...props }: { name: keyof GloomSlots } & Record<string, unknown>) => (
|
|
224
|
+
this.renderSlot(name, props as any)
|
|
225
|
+
);
|
|
153
226
|
}
|
|
154
227
|
|
|
155
228
|
get panes(): ReadonlyMap<string, PaneDef> { return this.panesMap; }
|
|
@@ -157,28 +230,45 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
157
230
|
get commands(): ReadonlyMap<string, CommandDef> { return this.commandsMap; }
|
|
158
231
|
get columns(): ReadonlyMap<string, CustomColumnDef> { return this.columnsMap; }
|
|
159
232
|
get brokers(): ReadonlyMap<string, BrokerAdapter> { return this.brokersMap; }
|
|
160
|
-
get dataProviders(): ReadonlyMap<string, DataProvider> { return this.dataProvidersMap; }
|
|
161
233
|
get detailTabs(): ReadonlyMap<string, DetailTabDef> { return this.detailTabsMap; }
|
|
162
234
|
get shortcuts(): ReadonlyMap<string, KeyboardShortcut> { return this.shortcutsMap; }
|
|
163
235
|
get tickerActions(): ReadonlyMap<string, TickerAction> { return this.tickerActionsMap; }
|
|
164
236
|
get allPlugins(): ReadonlyMap<string, GloomPlugin> { return this.plugins; }
|
|
165
237
|
|
|
166
|
-
|
|
167
|
-
|
|
238
|
+
getContextMenuItems(context: ContextMenuContext): ContextMenuItem[] {
|
|
239
|
+
const disabledPlugins = new Set(this.getConfigFn().disabledPlugins ?? []);
|
|
240
|
+
const entries = [...this.contextMenuProvidersMap.entries()]
|
|
241
|
+
.filter(([, entry]) => !disabledPlugins.has(entry.pluginId))
|
|
242
|
+
.filter(([, entry]) => !entry.provider.contexts || entry.provider.contexts.includes(context.kind))
|
|
243
|
+
.sort((left, right) => (
|
|
244
|
+
(left[1].provider.order ?? 0) - (right[1].provider.order ?? 0)
|
|
245
|
+
|| left[1].pluginId.localeCompare(right[1].pluginId)
|
|
246
|
+
|| left[1].provider.id.localeCompare(right[1].provider.id)
|
|
247
|
+
));
|
|
248
|
+
|
|
249
|
+
const items: ContextMenuItem[] = [];
|
|
250
|
+
for (const [, entry] of entries) {
|
|
251
|
+
try {
|
|
252
|
+
const provided = entry.provider.getItems(context);
|
|
253
|
+
if (provided?.length) items.push(...provided);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
this.registryLog.error("Context menu provider failed", {
|
|
256
|
+
pluginId: entry.pluginId,
|
|
257
|
+
providerId: entry.provider.id,
|
|
258
|
+
context: context.kind,
|
|
259
|
+
error: error instanceof Error ? error.message : String(error),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return items;
|
|
168
264
|
}
|
|
169
265
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return [...this.dataProvidersMap.values()].filter((provider) => {
|
|
173
|
-
const ownerId = this.dataProviderOwners.get(provider.id);
|
|
174
|
-
return !ownerId || !disabledPlugins.has(ownerId);
|
|
175
|
-
});
|
|
266
|
+
getCapabilityPluginId(capabilityId: string): string | undefined {
|
|
267
|
+
return this.capabilityOwners.get(capabilityId);
|
|
176
268
|
}
|
|
177
269
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
for (const provider of this.dataProvidersMap.values()) active = provider;
|
|
181
|
-
return active;
|
|
270
|
+
getEnabledCapabilities(kind?: string): PluginCapability[] {
|
|
271
|
+
return this.capabilities.list(kind).map((entry) => entry.capability);
|
|
182
272
|
}
|
|
183
273
|
|
|
184
274
|
getPluginPaneIds(pluginId: string): string[] {
|
|
@@ -193,6 +283,20 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
193
283
|
this.notifyFn(notification);
|
|
194
284
|
}
|
|
195
285
|
|
|
286
|
+
renderSlot<K extends keyof GloomSlots>(name: K, props: GloomSlots[K]): ReactNode {
|
|
287
|
+
const entries = this.slotEntries.get(name as string) ?? [];
|
|
288
|
+
if (entries.length === 0) return null;
|
|
289
|
+
return createElement(
|
|
290
|
+
Fragment,
|
|
291
|
+
null,
|
|
292
|
+
...entries.map((entry) => createElement(
|
|
293
|
+
Fragment,
|
|
294
|
+
{ key: entry.pluginId },
|
|
295
|
+
entry.render(props),
|
|
296
|
+
)),
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
196
300
|
private getOrCreatePluginItems(pluginId: string): PluginItems {
|
|
197
301
|
const existing = this.pluginItems.get(pluginId);
|
|
198
302
|
if (existing) return existing;
|
|
@@ -203,23 +307,50 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
203
307
|
commands: [],
|
|
204
308
|
columns: [],
|
|
205
309
|
brokers: [],
|
|
206
|
-
|
|
310
|
+
capabilities: [],
|
|
207
311
|
detailTabs: [],
|
|
208
312
|
shortcuts: [],
|
|
209
313
|
tickerActions: [],
|
|
314
|
+
contextMenuProviders: [],
|
|
210
315
|
eventDisposers: [],
|
|
316
|
+
capabilityDisposers: [],
|
|
317
|
+
newsQueryWatchDisposers: [],
|
|
211
318
|
};
|
|
212
319
|
this.pluginItems.set(pluginId, items);
|
|
213
320
|
return items;
|
|
214
321
|
}
|
|
215
322
|
|
|
323
|
+
private registerCapabilityForPlugin(pluginId: string, capability: PluginCapability, items: PluginItems): void {
|
|
324
|
+
const ownedCapability: PluginCapability = {
|
|
325
|
+
...capability,
|
|
326
|
+
isEnabled: () => {
|
|
327
|
+
const config = this.getConfigFn();
|
|
328
|
+
const disabledPlugin = config.disabledPlugins.includes(pluginId);
|
|
329
|
+
const disabledSource = config.disabledSources?.includes(capability.sourceId ?? capability.id) ?? false;
|
|
330
|
+
return !disabledPlugin && !disabledSource && (capability.isEnabled?.() ?? true);
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
const disposeCapability = this.capabilities.register(pluginId, ownedCapability);
|
|
334
|
+
this.capabilityOwners.set(capability.id, pluginId);
|
|
335
|
+
items.capabilities.push(capability.id);
|
|
336
|
+
items.capabilityDisposers.push(disposeCapability);
|
|
337
|
+
|
|
338
|
+
if (ownedCapability.kind === "news") {
|
|
339
|
+
const dispose = this.registerNewsCapabilityFn(ownedCapability as NewsCapability);
|
|
340
|
+
items.capabilityDisposers.push(dispose);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
216
344
|
private wrapPaneDef(pluginId: string, pane: PaneDef): PaneDef {
|
|
217
345
|
return {
|
|
218
346
|
...pane,
|
|
219
347
|
component: (props) => createElement(
|
|
220
348
|
PluginRenderProvider,
|
|
221
|
-
{
|
|
222
|
-
|
|
349
|
+
{
|
|
350
|
+
pluginId,
|
|
351
|
+
runtime: this,
|
|
352
|
+
children: createElement(pane.component as any, props),
|
|
353
|
+
},
|
|
223
354
|
),
|
|
224
355
|
};
|
|
225
356
|
}
|
|
@@ -229,8 +360,11 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
229
360
|
...tab,
|
|
230
361
|
component: (props) => createElement(
|
|
231
362
|
PluginRenderProvider,
|
|
232
|
-
{
|
|
233
|
-
|
|
363
|
+
{
|
|
364
|
+
pluginId,
|
|
365
|
+
runtime: this,
|
|
366
|
+
children: createElement(tab.component as any, props),
|
|
367
|
+
},
|
|
234
368
|
),
|
|
235
369
|
};
|
|
236
370
|
}
|
|
@@ -280,6 +414,10 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
280
414
|
return this.setPluginConfigValueFn(pluginId, key, value);
|
|
281
415
|
}
|
|
282
416
|
|
|
417
|
+
setConfigStates(pluginId: string, values: Record<string, unknown>): Promise<void> {
|
|
418
|
+
return this.setPluginConfigValuesFn(pluginId, values);
|
|
419
|
+
}
|
|
420
|
+
|
|
283
421
|
deleteConfigState(pluginId: string, key: string): Promise<void> {
|
|
284
422
|
return this.deletePluginConfigValueFn(pluginId, key);
|
|
285
423
|
}
|
|
@@ -294,6 +432,7 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
294
432
|
|
|
295
433
|
resolvePaneSettings(paneId: string): {
|
|
296
434
|
paneId: string;
|
|
435
|
+
pluginId?: string;
|
|
297
436
|
pane: PaneInstanceConfig;
|
|
298
437
|
paneDef: PaneDef;
|
|
299
438
|
settingsDef: PaneSettingsDef;
|
|
@@ -310,6 +449,8 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
310
449
|
if (!paneDef?.settings) return null;
|
|
311
450
|
|
|
312
451
|
const config = this.getConfigFn();
|
|
452
|
+
const pluginId = this.paneOwners.get(pane.paneId);
|
|
453
|
+
const paneSettings = getPaneSettings(pane);
|
|
313
454
|
const paneStateMap = Object.fromEntries(
|
|
314
455
|
layout.instances.map((instance) => [instance.instanceId, this.getPaneRuntimeStateFn(instance.instanceId) ?? {}]),
|
|
315
456
|
);
|
|
@@ -324,7 +465,7 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
324
465
|
paneId: targetPaneId,
|
|
325
466
|
paneType: pane.paneId,
|
|
326
467
|
pane,
|
|
327
|
-
settings:
|
|
468
|
+
settings: paneSettings,
|
|
328
469
|
paneState,
|
|
329
470
|
activeTicker: resolveTickerForPane(stateView, targetPaneId),
|
|
330
471
|
activeCollectionId: resolveCollectionForPane(stateView, targetPaneId),
|
|
@@ -334,8 +475,23 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
334
475
|
: paneDef.settings;
|
|
335
476
|
if (!settingsDef) return null;
|
|
336
477
|
|
|
478
|
+
if (pluginId) {
|
|
479
|
+
const resolvedSettings = { ...paneSettings };
|
|
480
|
+
for (const field of settingsDef.fields) {
|
|
481
|
+
if (field.storage !== "plugin") continue;
|
|
482
|
+
const configValue = this.getConfigState(pluginId, field.key);
|
|
483
|
+
if (configValue === null) {
|
|
484
|
+
delete resolvedSettings[field.key];
|
|
485
|
+
} else {
|
|
486
|
+
resolvedSettings[field.key] = configValue;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
context.settings = resolvedSettings;
|
|
490
|
+
}
|
|
491
|
+
|
|
337
492
|
return {
|
|
338
493
|
paneId: targetPaneId,
|
|
494
|
+
pluginId,
|
|
339
495
|
pane,
|
|
340
496
|
paneDef,
|
|
341
497
|
settingsDef,
|
|
@@ -359,6 +515,10 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
359
515
|
return this.shortcutOwners.get(shortcutId);
|
|
360
516
|
}
|
|
361
517
|
|
|
518
|
+
getDetailTabPluginId(tabId: string): string | undefined {
|
|
519
|
+
return this.detailTabOwners.get(tabId);
|
|
520
|
+
}
|
|
521
|
+
|
|
362
522
|
isPaneFloating(paneId: string): boolean {
|
|
363
523
|
try {
|
|
364
524
|
const target = this.resolvePaneTarget(paneId);
|
|
@@ -414,9 +574,10 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
414
574
|
getState: (key, options) => this.getResumeState(pluginId, key, options?.schemaVersion),
|
|
415
575
|
setState: (key, value, options) => this.setResumeState(pluginId, key, value, options?.schemaVersion),
|
|
416
576
|
deleteState: (key) => this.deleteResumeState(pluginId, key),
|
|
417
|
-
getPaneState: (paneId, key) =>
|
|
418
|
-
this.getPaneRuntimeStateFn(paneId)?.pluginState?.[pluginId]?.[key]
|
|
419
|
-
|
|
577
|
+
getPaneState: <T = unknown>(paneId: string, key: string): T | null => {
|
|
578
|
+
const value = this.getPaneRuntimeStateFn(paneId)?.pluginState?.[pluginId]?.[key];
|
|
579
|
+
return value === undefined ? null : value as T;
|
|
580
|
+
},
|
|
420
581
|
setPaneState: (paneId, key, value) => {
|
|
421
582
|
const currentPaneState = this.getPaneRuntimeStateFn(paneId) ?? {};
|
|
422
583
|
const pluginState = {
|
|
@@ -466,7 +627,11 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
466
627
|
};
|
|
467
628
|
|
|
468
629
|
return {
|
|
469
|
-
registerPane: (pane) => {
|
|
630
|
+
registerPane: (pane) => {
|
|
631
|
+
this.panesMap.set(pane.id, this.wrapPaneDef(pluginId, pane));
|
|
632
|
+
this.paneOwners.set(pane.id, pluginId);
|
|
633
|
+
items.panes.push(pane.id);
|
|
634
|
+
},
|
|
470
635
|
registerPaneTemplate: (template) => {
|
|
471
636
|
this.paneTemplatesMap.set(template.id, template);
|
|
472
637
|
this.paneTemplateOwners.set(template.id, pluginId);
|
|
@@ -478,25 +643,43 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
478
643
|
items.commands.push(command.id);
|
|
479
644
|
},
|
|
480
645
|
registerColumn: (column) => { this.columnsMap.set(column.id, column); items.columns.push(column.id); },
|
|
481
|
-
registerBroker: (broker) => {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
646
|
+
registerBroker: (broker) => {
|
|
647
|
+
this.brokersMap.set(broker.id, this.wrapBrokerAdapter?.(broker, pluginId) ?? broker);
|
|
648
|
+
items.brokers.push(broker.id);
|
|
649
|
+
},
|
|
650
|
+
registerCapability: (capability) => {
|
|
651
|
+
if (this.enableCapabilityHandlers) {
|
|
652
|
+
this.registerCapabilityForPlugin(pluginId, capability, items);
|
|
653
|
+
}
|
|
654
|
+
},
|
|
655
|
+
registerDetailTab: (tab) => {
|
|
656
|
+
this.detailTabsMap.set(tab.id, this.wrapDetailTabDef(pluginId, tab));
|
|
657
|
+
this.detailTabOwners.set(tab.id, pluginId);
|
|
658
|
+
items.detailTabs.push(tab.id);
|
|
486
659
|
},
|
|
487
|
-
registerDetailTab: (tab) => { this.detailTabsMap.set(tab.id, this.wrapDetailTabDef(pluginId, tab)); items.detailTabs.push(tab.id); },
|
|
488
660
|
registerShortcut: (shortcut) => {
|
|
489
661
|
this.shortcutsMap.set(shortcut.id, shortcut);
|
|
490
662
|
this.shortcutOwners.set(shortcut.id, pluginId);
|
|
491
663
|
items.shortcuts.push(shortcut.id);
|
|
492
664
|
},
|
|
493
665
|
registerTickerAction: (action) => { this.tickerActionsMap.set(action.id, action); items.tickerActions.push(action.id); },
|
|
666
|
+
registerContextMenuProvider: (provider) => {
|
|
667
|
+
const providerKey = `${pluginId}:${provider.id}`;
|
|
668
|
+
this.contextMenuProvidersMap.set(providerKey, { pluginId, provider });
|
|
669
|
+
items.contextMenuProviders.push(providerKey);
|
|
670
|
+
},
|
|
671
|
+
watchNewsQuery: (query, listener) => {
|
|
672
|
+
const dispose = this.watchNewsQueryFn(query, listener);
|
|
673
|
+
items.newsQueryWatchDisposers.push(dispose);
|
|
674
|
+
return dispose;
|
|
675
|
+
},
|
|
494
676
|
|
|
495
677
|
getData: (ticker) => this.getDataFn(ticker),
|
|
496
678
|
getTicker: (ticker) => this.getTickerFn(ticker),
|
|
497
679
|
getConfig: () => this.getConfigFn(),
|
|
680
|
+
getPaneDef: (paneId) => this.panesMap.get(paneId),
|
|
498
681
|
|
|
499
|
-
|
|
682
|
+
marketData: this.marketData,
|
|
500
683
|
tickerRepository: this.tickerRepository,
|
|
501
684
|
persistence,
|
|
502
685
|
log,
|
|
@@ -510,14 +693,14 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
510
693
|
},
|
|
511
694
|
|
|
512
695
|
createBrokerInstance: (brokerType, label, values) => this.createBrokerInstanceFn(brokerType, label, values),
|
|
513
|
-
updateBrokerInstance: (instanceId, values) => this.updateBrokerInstanceFn(instanceId, values),
|
|
696
|
+
updateBrokerInstance: (instanceId, values, options) => this.updateBrokerInstanceFn(instanceId, values, options),
|
|
514
697
|
syncBrokerInstance: (instanceId) => this.syncBrokerInstanceFn(instanceId),
|
|
515
698
|
removeBrokerInstance: (instanceId) => this.removeBrokerInstanceFn(instanceId),
|
|
516
699
|
|
|
517
|
-
selectTicker:
|
|
518
|
-
switchPanel:
|
|
519
|
-
switchTab:
|
|
520
|
-
openCommandBar:
|
|
700
|
+
selectTicker: this.selectTicker,
|
|
701
|
+
switchPanel: this.switchPanel,
|
|
702
|
+
switchTab: this.switchTab,
|
|
703
|
+
openCommandBar: this.openCommandBar,
|
|
521
704
|
showPane: (paneId) => this.showPaneFn(paneId),
|
|
522
705
|
createPaneFromTemplate: (templateId, options) => this.createPaneFromTemplateFn(templateId, options),
|
|
523
706
|
hidePane: (paneId) => this.hidePaneFn(paneId),
|
|
@@ -547,6 +730,7 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
547
730
|
if (plugin.panes) {
|
|
548
731
|
for (const pane of plugin.panes) {
|
|
549
732
|
this.panesMap.set(pane.id, this.wrapPaneDef(plugin.id, pane));
|
|
733
|
+
this.paneOwners.set(pane.id, plugin.id);
|
|
550
734
|
items.panes.push(pane.id);
|
|
551
735
|
}
|
|
552
736
|
}
|
|
@@ -560,34 +744,51 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
560
744
|
}
|
|
561
745
|
|
|
562
746
|
if (plugin.broker) {
|
|
563
|
-
this.brokersMap.set(plugin.broker.id, plugin.broker);
|
|
747
|
+
this.brokersMap.set(plugin.broker.id, this.wrapBrokerAdapter?.(plugin.broker, plugin.id) ?? plugin.broker);
|
|
564
748
|
items.brokers.push(plugin.broker.id);
|
|
565
749
|
}
|
|
566
750
|
|
|
567
|
-
if (plugin.
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
751
|
+
if (this.enableCapabilityHandlers && plugin.capabilities) {
|
|
752
|
+
for (const capability of plugin.capabilities) {
|
|
753
|
+
this.registerCapabilityForPlugin(plugin.id, capability, items);
|
|
754
|
+
}
|
|
571
755
|
}
|
|
572
756
|
|
|
573
757
|
if (plugin.slots) {
|
|
574
|
-
const
|
|
575
|
-
id: plugin.id,
|
|
576
|
-
order: plugin.order,
|
|
577
|
-
slots: {} as Record<string, unknown>,
|
|
578
|
-
};
|
|
579
|
-
|
|
758
|
+
const registeredSlotNames: string[] = [];
|
|
580
759
|
for (const [slotName, renderer] of Object.entries(plugin.slots)) {
|
|
581
760
|
if (renderer) {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
761
|
+
const entries = this.slotEntries.get(slotName) ?? [];
|
|
762
|
+
entries.push({
|
|
763
|
+
pluginId: plugin.id,
|
|
764
|
+
order: plugin.order ?? 0,
|
|
765
|
+
render: (props: unknown) => createElement(
|
|
766
|
+
PluginRenderProvider,
|
|
767
|
+
{
|
|
768
|
+
pluginId: plugin.id,
|
|
769
|
+
runtime: this,
|
|
770
|
+
children: (renderer as any)(props),
|
|
771
|
+
},
|
|
772
|
+
),
|
|
773
|
+
});
|
|
774
|
+
entries.sort((left, right) => left.order - right.order || left.pluginId.localeCompare(right.pluginId));
|
|
775
|
+
this.slotEntries.set(slotName, entries);
|
|
776
|
+
registeredSlotNames.push(slotName);
|
|
587
777
|
}
|
|
588
778
|
}
|
|
589
779
|
|
|
590
|
-
const unregister =
|
|
780
|
+
const unregister = () => {
|
|
781
|
+
for (const slotName of registeredSlotNames) {
|
|
782
|
+
const entries = this.slotEntries.get(slotName);
|
|
783
|
+
if (!entries) continue;
|
|
784
|
+
const nextEntries = entries.filter((entry) => entry.pluginId !== plugin.id);
|
|
785
|
+
if (nextEntries.length === 0) {
|
|
786
|
+
this.slotEntries.delete(slotName);
|
|
787
|
+
} else {
|
|
788
|
+
this.slotEntries.set(slotName, nextEntries);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
};
|
|
591
792
|
this.unregisterFns.set(plugin.id, unregister);
|
|
592
793
|
}
|
|
593
794
|
|
|
@@ -611,7 +812,10 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
611
812
|
|
|
612
813
|
const items = this.pluginItems.get(pluginId);
|
|
613
814
|
if (items) {
|
|
614
|
-
for (const paneId of items.panes)
|
|
815
|
+
for (const paneId of items.panes) {
|
|
816
|
+
this.panesMap.delete(paneId);
|
|
817
|
+
this.paneOwners.delete(paneId);
|
|
818
|
+
}
|
|
615
819
|
for (const templateId of items.paneTemplates) {
|
|
616
820
|
this.paneTemplatesMap.delete(templateId);
|
|
617
821
|
this.paneTemplateOwners.delete(templateId);
|
|
@@ -622,17 +826,22 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
622
826
|
}
|
|
623
827
|
for (const columnId of items.columns) this.columnsMap.delete(columnId);
|
|
624
828
|
for (const brokerId of items.brokers) this.brokersMap.delete(brokerId);
|
|
625
|
-
for (const
|
|
626
|
-
this.
|
|
627
|
-
|
|
829
|
+
for (const capabilityId of items.capabilities) {
|
|
830
|
+
this.capabilityOwners.delete(capabilityId);
|
|
831
|
+
}
|
|
832
|
+
for (const tabId of items.detailTabs) {
|
|
833
|
+
this.detailTabsMap.delete(tabId);
|
|
834
|
+
this.detailTabOwners.delete(tabId);
|
|
628
835
|
}
|
|
629
|
-
for (const tabId of items.detailTabs) this.detailTabsMap.delete(tabId);
|
|
630
836
|
for (const shortcutId of items.shortcuts) {
|
|
631
837
|
this.shortcutsMap.delete(shortcutId);
|
|
632
838
|
this.shortcutOwners.delete(shortcutId);
|
|
633
839
|
}
|
|
634
840
|
for (const actionId of items.tickerActions) this.tickerActionsMap.delete(actionId);
|
|
841
|
+
for (const providerKey of items.contextMenuProviders) this.contextMenuProvidersMap.delete(providerKey);
|
|
635
842
|
for (const dispose of items.eventDisposers) dispose();
|
|
843
|
+
for (const dispose of items.capabilityDisposers) dispose();
|
|
844
|
+
for (const dispose of items.newsQueryWatchDisposers) dispose();
|
|
636
845
|
this.pluginItems.delete(pluginId);
|
|
637
846
|
}
|
|
638
847
|
|
|
@@ -651,12 +860,14 @@ export class PluginRegistry implements PluginRuntimeAccess {
|
|
|
651
860
|
});
|
|
652
861
|
}
|
|
653
862
|
}
|
|
863
|
+
this.capabilities.destroy();
|
|
864
|
+
this.capabilityOwners.clear();
|
|
654
865
|
this.pluginResumeListeners.clear();
|
|
655
866
|
if (sharedRegistry === this) {
|
|
656
867
|
sharedRegistry = undefined;
|
|
657
868
|
}
|
|
658
|
-
if (
|
|
659
|
-
|
|
869
|
+
if (sharedMarketData === this.marketData) {
|
|
870
|
+
sharedMarketData = undefined;
|
|
660
871
|
}
|
|
661
872
|
if ((globalThis as any).__gloomRegistry === this) {
|
|
662
873
|
delete (globalThis as any).__gloomRegistry;
|