gloomberb 0.11.3 → 0.12.0
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 +6 -4
- package/README.zh-CN.md +4 -2
- package/package.json +28 -1
- package/src/api-client/auth.ts +10 -0
- package/src/api-client/data.ts +103 -1
- package/src/api-client/index.test.ts +127 -0
- package/src/api-client/index.ts +129 -1
- package/src/api-client/normalizers.ts +39 -0
- package/src/api-client/paths.ts +85 -1
- package/src/api-client/types.ts +196 -0
- package/src/app/pane-runtime/index.tsx +15 -12
- package/src/app/pane-runtime/layout-placement.test.ts +27 -0
- package/src/app/pane-runtime/layout-placement.ts +13 -0
- package/src/app/pane-runtime/plugin-bindings.ts +62 -0
- package/src/app.tsx +60 -18
- package/src/architecture/browser-entry-graph.test.ts +96 -0
- package/src/brokers/profile-form.test.ts +25 -27
- package/src/brokers/test-broker.ts +68 -0
- package/src/cli/commands/plugins.ts +39 -11
- package/src/cli/desktop-pane-shot.ts +285 -16
- package/src/cli/index.ts +1 -1
- package/src/cli/pane-functions/capabilities.ts +58 -28
- package/src/cli/pane-functions/catalog.ts +16 -4
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/headless.test.ts +247 -0
- package/src/cli/pane-functions/headless.ts +423 -0
- package/src/cli/pane-functions/index.test.ts +9 -0
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +27 -2
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +26 -8
- package/src/cli/pane-functions/screenshot.test.ts +76 -0
- package/src/cli/pane-functions/screenshot.ts +236 -20
- package/src/cli/restore-plugins.ts +34 -0
- package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
- package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
- package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
- package/src/components/chart/composite/composite-chart.test.tsx +68 -20
- package/src/components/chart/composite/composite-chart.tsx +301 -204
- package/src/components/chart/composite/format.ts +8 -2
- package/src/components/chart/composite/interactions.test.ts +68 -102
- package/src/components/chart/composite/interactions.ts +214 -264
- package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
- package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
- package/src/components/chart/composite/scene.ts +57 -3
- package/src/components/chart/composite/text-renderer.ts +3 -2
- package/src/components/chart/composite/time-scale.ts +138 -57
- package/src/components/chart/composite/types.ts +25 -1
- package/src/components/chart/core/data.ts +9 -13
- package/src/components/chart/core/date-window.ts +7 -1
- package/src/components/chart/core/pointer.ts +3 -0
- package/src/components/chart/core/types.ts +0 -45
- package/src/components/chart/native/chart-rasterizer.ts +0 -1
- package/src/components/chart/native/kitty/index.test.ts +0 -188
- package/src/components/chart/native/raster/crosshair.ts +6 -5
- package/src/components/chart/native/raster/primitives.ts +0 -23
- package/src/components/chart/native/renderer-selection.ts +81 -31
- package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
- package/src/components/chart/static/chart-surface.tsx +150 -0
- package/src/components/chart/static/index.ts +8 -0
- package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
- package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
- package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
- package/src/components/chart/static/series.ts +49 -0
- package/src/components/command-bar/action-runtime.ts +1 -3
- package/src/components/command-bar/assist/model.test.ts +17 -2
- package/src/components/command-bar/assist/model.ts +40 -9
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +1 -1
- package/src/components/command-bar/commands/registry.ts +0 -11
- package/src/components/command-bar/helpers.test.ts +2 -2
- package/src/components/command-bar/helpers.ts +2 -6
- package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
- package/src/components/command-bar/list/badge.test.ts +54 -0
- package/src/components/command-bar/list/badge.ts +62 -0
- package/src/components/command-bar/list/model.test.ts +103 -0
- package/src/components/command-bar/list/model.ts +61 -4
- package/src/components/command-bar/list/view.test.tsx +113 -0
- package/src/components/command-bar/list/view.tsx +147 -131
- package/src/components/command-bar/pane-templates/workflow.ts +1 -1
- package/src/components/command-bar/panel/body.tsx +51 -65
- package/src/components/command-bar/panel/index.tsx +48 -13
- package/src/components/command-bar/panel/layout.test.ts +139 -0
- package/src/components/command-bar/panel/layout.ts +65 -28
- package/src/components/command-bar/panel/native-surface.ts +24 -0
- package/src/components/command-bar/panel/prompt-binding.ts +54 -0
- package/src/components/command-bar/panel/runtime.ts +6 -3
- package/src/components/command-bar/panel/state.ts +41 -7
- package/src/components/command-bar/panel/types.ts +7 -1
- package/src/components/command-bar/routes/root/provider-search.ts +34 -15
- package/src/components/command-bar/routes/root/results.test.ts +161 -0
- package/src/components/command-bar/routes/root/results.ts +30 -28
- package/src/components/command-bar/routes/root/runtime.ts +37 -20
- package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
- package/src/components/command-bar/routes/root/search-providers.ts +205 -0
- package/src/components/command-bar/routes/root/selection.ts +1 -12
- package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
- package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
- package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
- package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
- package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
- package/src/components/command-bar/routing/actions.ts +1 -81
- package/src/components/command-bar/routing/launch-request.ts +1 -1
- package/src/components/command-bar/routing/list-state.ts +6 -21
- package/src/components/command-bar/selection-runtime.ts +1 -1
- package/src/components/command-bar/surface/assist.test.tsx +14 -10
- package/src/components/command-bar/surface/environment.ts +8 -1
- package/src/components/command-bar/surface/index.test.tsx +84 -68
- package/src/components/command-bar/surface/index.tsx +33 -36
- package/src/components/command-bar/surface/test-harness.tsx +15 -3
- package/src/components/command-bar/theme-picker.tsx +43 -15
- package/src/components/command-bar/view-model.test.ts +53 -8
- package/src/components/command-bar/view-model.ts +43 -14
- package/src/components/command-bar/workflow/tickers.ts +1 -0
- package/src/components/command-bar/workflow/types.ts +1 -1
- package/src/components/data-table/view.test.tsx +45 -6
- package/src/components/data-table/view.tsx +55 -9
- package/src/components/index.ts +10 -2
- package/src/components/input-search-bar.test.tsx +36 -2
- package/src/components/input-search-bar.tsx +18 -1
- package/src/components/layout/header.test.tsx +57 -10
- package/src/components/layout/header.tsx +292 -149
- package/src/components/layout/market-summary.test.ts +81 -0
- package/src/components/layout/market-summary.ts +109 -0
- package/src/components/layout/shell/chrome.ts +96 -1
- package/src/components/layout/shell/index.tsx +11 -3
- package/src/components/layout/shell/menu.ts +9 -0
- package/src/components/layout/shell/pane/actions.ts +29 -0
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/shortcuts.ts +3 -0
- package/src/components/layout/status-bar.test.tsx +9 -8
- package/src/components/layout/status-bar.tsx +85 -54
- package/src/components/onboarding/onboarding-frame.tsx +2 -26
- package/src/components/price-sparkline/index.ts +61 -34
- package/src/components/price-sparkline/view.tsx +1 -1
- package/src/components/sign-in-gate.test.tsx +128 -0
- package/src/components/sign-in-gate.tsx +149 -0
- package/src/components/speedometer-gauge/desktop.tsx +2 -12
- package/src/components/ticker/badge/list.tsx +17 -3
- package/src/components/ticker/list-table-view.tsx +6 -3
- package/src/components/ui/data-table/index.tsx +3 -2
- package/src/components/ui/data-table/opentui/index.tsx +165 -120
- package/src/components/ui/frame.tsx +28 -0
- package/src/components/ui/index.ts +3 -0
- package/src/components/ui/native-select.tsx +20 -10
- package/src/components/ui/select-button.tsx +138 -0
- package/src/components/ui/status.tsx +2 -2
- package/src/components/ui/table-layout.ts +1 -1
- package/src/components/use-double-click-activation.ts +7 -3
- package/src/core/app-services.ts +3 -3
- package/src/data/config/layout.ts +12 -6
- package/src/data/config/store/index.test.ts +97 -0
- package/src/data/config/store/migrations.ts +41 -0
- package/src/data/config/store/normalize.ts +5 -3
- package/src/i18n/es.ts +6 -2
- package/src/i18n/ja.ts +6 -2
- package/src/i18n/ko.ts +6 -2
- package/src/i18n/zh-cn.ts +6 -2
- package/src/i18n/zh-tw.ts +6 -2
- package/src/layout-marketplace/pane-imagery.ts +1 -0
- package/src/layout-marketplace/payload.test.ts +17 -0
- package/src/layout-marketplace/payload.ts +40 -5
- package/src/market-data/coordinator/index.ts +3 -2
- package/src/market-data/coordinator/quotes.ts +173 -66
- package/src/market-data/coordinator/subscriptions.test.ts +215 -37
- package/src/pane-settings.ts +1 -1
- package/src/plugins/builtin/analytics/pane-model.ts +1 -1
- package/src/plugins/builtin/analytics/view.tsx +1 -1
- package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
- package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
- package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
- package/src/plugins/builtin/chat/content/composer.tsx +8 -4
- package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
- package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/composite-plugins.ts +14 -1
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
- package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
- package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings-calls/data.ts +223 -0
- package/src/plugins/builtin/earnings-calls/format.ts +49 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
- package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
- package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
- package/src/plugins/builtin/econ/detail-view.tsx +1 -2
- package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
- package/src/plugins/builtin/econ/index.tsx +2 -1
- package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
- package/src/plugins/builtin/econ-statistics/client.ts +92 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
- package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
- package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
- package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
- package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
- package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
- package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
- package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
- package/src/plugins/builtin/econ-statistics/view.ts +90 -0
- package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
- package/src/plugins/builtin/fear-greed/data.ts +6 -1
- package/src/plugins/builtin/help/index.tsx +4 -0
- package/src/plugins/builtin/holders/index.tsx +1 -0
- package/src/plugins/builtin/insider/index.tsx +1 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
- package/src/plugins/builtin/market-valuation/align.ts +122 -0
- package/src/plugins/builtin/market-valuation/cache.ts +32 -0
- package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
- package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
- package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
- package/src/plugins/builtin/market-valuation/client.ts +116 -0
- package/src/plugins/builtin/market-valuation/defs.ts +251 -0
- package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
- package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
- package/src/plugins/builtin/market-valuation/headless.ts +170 -0
- package/src/plugins/builtin/market-valuation/index.tsx +64 -0
- package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
- package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
- package/src/plugins/builtin/market-valuation/model.ts +8 -0
- package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
- package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
- package/src/plugins/builtin/market-valuation/series.ts +12 -0
- package/src/plugins/builtin/market-valuation/settings.ts +38 -0
- package/src/plugins/builtin/market-valuation/sources.ts +130 -0
- package/src/plugins/builtin/market-valuation/trend.ts +89 -0
- package/src/plugins/builtin/market-valuation/view.ts +137 -0
- package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
- package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
- package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
- package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
- package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
- package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
- package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
- package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
- package/src/plugins/builtin/news/wire/index.tsx +31 -44
- package/src/plugins/builtin/options/index.tsx +1 -0
- package/src/plugins/builtin/options/view.test.tsx +29 -1
- package/src/plugins/builtin/options/view.tsx +1 -22
- package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
- package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
- package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
- package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
- package/src/plugins/builtin/plugin-module.ts +9 -1
- package/src/plugins/builtin/research/index.tsx +4 -0
- package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
- package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
- package/src/plugins/builtin/research-search/data.ts +109 -0
- package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
- package/src/plugins/builtin/research-search/document-view.tsx +254 -0
- package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
- package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
- package/src/plugins/builtin/research-search/index.tsx +85 -0
- package/src/plugins/builtin/research-search/model.test.ts +40 -0
- package/src/plugins/builtin/research-search/model.ts +291 -0
- package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
- package/src/plugins/builtin/research-search/pane.tsx +678 -0
- package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
- package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
- package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
- package/src/plugins/builtin/research-search/snippet.ts +134 -0
- package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
- package/src/plugins/builtin/scanner/flow-model.ts +29 -1
- package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
- package/src/plugins/builtin/sec/index.tsx +1 -0
- package/src/plugins/builtin/shared/series-cache.ts +93 -0
- package/src/plugins/builtin/short-interest/index.tsx +1 -0
- package/src/plugins/builtin/short-interest/pane.tsx +1 -1
- package/src/plugins/builtin/thirteenf/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/index.tsx +0 -14
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
- package/src/plugins/builtin/volatility/index.tsx +1 -1
- package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +213 -69
- package/src/plugins/builtin/world-venue-map/model.test.ts +32 -0
- package/src/plugins/builtin/world-venue-map/model.ts +134 -13
- package/src/plugins/builtin/yield-curve/index.tsx +1 -1
- package/src/plugins/bundle.test.ts +109 -0
- package/src/plugins/bundle.ts +139 -0
- package/src/plugins/catalog-browser.test.ts +1 -0
- package/src/plugins/catalog-browser.ts +10 -0
- package/src/plugins/catalog-manifest.test.ts +43 -0
- package/src/plugins/catalog-manifest.ts +92 -0
- package/src/plugins/catalog-ui.ts +20 -4
- package/src/plugins/catalog.ts +9 -2
- package/src/plugins/current-target.ts +28 -0
- package/src/plugins/host-contract.ts +37 -0
- package/src/plugins/host-link.ts +158 -0
- package/src/plugins/host-modules.ts +61 -0
- package/src/plugins/loader.ts +41 -22
- package/src/plugins/ownership.ts +1 -0
- package/src/plugins/prediction-markets/index.tsx +1 -0
- package/src/plugins/registry/context.ts +3 -0
- package/src/plugins/registry/contributions.ts +27 -0
- package/src/plugins/registry/index.test.ts +25 -0
- package/src/plugins/registry/index.ts +8 -0
- package/src/plugins/registry/pane-settings.ts +6 -13
- package/src/plugins/seed.test.ts +83 -0
- package/src/plugins/seed.ts +80 -0
- package/src/public/broker.ts +31 -0
- package/src/public/market-data.ts +9 -0
- package/src/public/pane-hooks.ts +57 -0
- package/src/public/public-api.test.ts +285 -0
- package/src/public/react.ts +62 -0
- package/src/public/test-support.ts +23 -0
- package/src/public/time-series.ts +8 -0
- package/src/public/utils.ts +77 -0
- package/src/remote/layout-helpers.ts +6 -8
- package/src/remote/resources.ts +2 -0
- package/src/remote/schema.ts +1 -0
- package/src/remote/semantic-tree.test.tsx +105 -0
- package/src/remote/semantic-tree.tsx +53 -35
- package/src/renderers/browser/main.tsx +6 -0
- package/src/renderers/cloudflare/worker.test.ts +19 -0
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
- package/src/renderers/electrobun/bun/index.ts +5 -2
- package/src/renderers/electrobun/shared/protocol.ts +21 -0
- package/src/renderers/electrobun/view/build-assets.ts +0 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
- package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
- package/src/renderers/electrobun/view/external-plugins.ts +63 -0
- package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
- package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
- package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
- package/src/renderers/electrobun/view/host/mouse.ts +16 -2
- package/src/renderers/electrobun/view/main.tsx +27 -2
- package/src/renderers/electrobun/view/styles.css +5 -0
- package/src/renderers/electrobun/view/toast-host.tsx +18 -0
- package/src/renderers/opentui/chart-surface.tsx +5 -1
- package/src/renderers/opentui/host.tsx +16 -2
- package/src/renderers/opentui/interaction-performance.test.ts +79 -0
- package/src/renderers/opentui/interaction-performance.ts +188 -0
- package/src/renderers/opentui/start.tsx +26 -1
- package/src/renderers/opentui/test-utils.tsx +13 -0
- package/src/renderers/opentui/toast-host.tsx +26 -2
- package/src/renderers/opentui/ui-host.tsx +1 -0
- package/src/sources/provider-router/search.test.ts +191 -0
- package/src/sources/provider-router/search.ts +92 -39
- package/src/state/app/context/index.tsx +2 -0
- package/src/state/app/context/selector.test.tsx +33 -1
- package/src/state/hooks/quote-streaming.test.tsx +93 -0
- package/src/state/hooks/quote-streaming.ts +106 -30
- package/src/state/pane-table-export-registry.ts +19 -0
- package/src/theme/color-utils.ts +1 -1
- package/src/theme/colors.ts +50 -0
- package/src/theme/themes.test.ts +15 -2
- package/src/theme/themes.ts +19 -1
- package/src/tickers/search/index.test.ts +26 -0
- package/src/tickers/search/index.ts +42 -17
- package/src/tickers/search/ranking.ts +14 -0
- package/src/time-series/chart-data.test.ts +216 -0
- package/src/time-series/resolution.test.ts +25 -26
- package/src/time-series/resolution.ts +41 -10
- package/src/time-series/resolve.ts +7 -0
- package/src/time-series/types.ts +3 -1
- package/src/time-series/use-chart-resolution.ts +5 -0
- package/src/types/config.ts +123 -3
- package/src/types/data-provider.ts +11 -0
- package/src/types/headless.ts +161 -0
- package/src/types/plugin.ts +102 -0
- package/src/ui/host.tsx +12 -1
- package/src/ui/index.tsx +1 -0
- package/src/ui/toast.tsx +8 -4
- package/src/utils/format.ts +35 -0
- package/src/utils/fuzzy-search.test.ts +94 -0
- package/src/utils/fuzzy-search.ts +81 -22
- package/src/utils/shortcut-labels.ts +14 -0
- package/src/components/chart/core/axis-format.ts +0 -157
- package/src/components/chart/core/index.test.ts +0 -1075
- package/src/components/chart/core/projection.ts +0 -357
- package/src/components/chart/core/render-utils.ts +0 -4
- package/src/components/chart/core/renderer.ts +0 -244
- package/src/components/chart/core/scene.ts +0 -180
- package/src/components/chart/core/time-axis.ts +0 -330
- package/src/components/chart/cursor-motion.ts +0 -47
- package/src/components/chart/indicators/types.ts +0 -26
- package/src/components/chart/market-session.ts +0 -176
- package/src/components/chart/multi-line/renderer.test.ts +0 -83
- package/src/components/chart/multi-line/renderer.ts +0 -161
- package/src/components/chart/multi-line/scene.ts +0 -188
- package/src/components/chart/native/raster/layout.ts +0 -129
- package/src/components/chart/native/raster/price-chart.ts +0 -244
- package/src/components/chart/rendering/chart-draw.ts +0 -270
- package/src/components/chart/rendering/geometry.ts +0 -95
- package/src/components/chart/rendering/pixel-buffer.ts +0 -267
- package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
- package/src/components/chart/scatter-chart-renderer.ts +0 -223
- package/src/components/chart/static/chart/surface.tsx +0 -358
- package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
- package/src/components/command-bar/routes/root/article-results.ts +0 -55
- package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
- package/src/plugins/builtin/news/wire/article-search.ts +0 -140
- package/src/plugins/builtin/substack/api/auth.ts +0 -185
- package/src/plugins/builtin/substack/api/cache.ts +0 -82
- package/src/plugins/builtin/substack/api/loaders.ts +0 -170
- package/src/plugins/builtin/substack/api/store.ts +0 -186
- package/src/plugins/builtin/substack/api/types.ts +0 -42
- package/src/plugins/builtin/substack/api.test.ts +0 -298
- package/src/plugins/builtin/substack/article-detail.tsx +0 -397
- package/src/plugins/builtin/substack/article-stack.tsx +0 -133
- package/src/plugins/builtin/substack/content.ts +0 -478
- package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
- package/src/plugins/builtin/substack/index.tsx +0 -49
- package/src/plugins/builtin/substack/login-view.tsx +0 -126
- package/src/plugins/builtin/substack/model.test.ts +0 -155
- package/src/plugins/builtin/substack/normalize.ts +0 -343
- package/src/plugins/builtin/substack/pane-footer.ts +0 -52
- package/src/plugins/builtin/substack/pane-state.ts +0 -170
- package/src/plugins/builtin/substack/pane.tsx +0 -547
- package/src/plugins/builtin/substack/read-state.ts +0 -30
- package/src/plugins/builtin/substack/table.ts +0 -111
- package/src/plugins/builtin/substack/types.ts +0 -71
- package/src/plugins/builtin/substack/utils.ts +0 -131
- package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
- package/src/plugins/ibkr/account-cache.test.ts +0 -102
- package/src/plugins/ibkr/account-cache.ts +0 -24
- package/src/plugins/ibkr/broker-adapter.ts +0 -286
- package/src/plugins/ibkr/config.test.ts +0 -79
- package/src/plugins/ibkr/config.ts +0 -250
- package/src/plugins/ibkr/dialogs.tsx +0 -40
- package/src/plugins/ibkr/flex/index.test.ts +0 -264
- package/src/plugins/ibkr/flex/index.ts +0 -367
- package/src/plugins/ibkr/flex/statement-client.ts +0 -235
- package/src/plugins/ibkr/fundamental-parser.ts +0 -149
- package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
- package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
- package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
- package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
- package/src/plugins/ibkr/gateway/connection.ts +0 -152
- package/src/plugins/ibkr/gateway/contracts.ts +0 -132
- package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
- package/src/plugins/ibkr/gateway/helpers.ts +0 -33
- package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
- package/src/plugins/ibkr/gateway/history.ts +0 -120
- package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
- package/src/plugins/ibkr/gateway/market-data.ts +0 -345
- package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
- package/src/plugins/ibkr/gateway/orders.ts +0 -63
- package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
- package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
- package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
- package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
- package/src/plugins/ibkr/gateway/selection.ts +0 -51
- package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
- package/src/plugins/ibkr/gateway/service/index.ts +0 -429
- package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
- package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
- package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
- package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
- package/src/plugins/ibkr/gateway/service/native.ts +0 -543
- package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
- package/src/plugins/ibkr/gateway/types.ts +0 -27
- package/src/plugins/ibkr/index.test.tsx +0 -162
- package/src/plugins/ibkr/index.tsx +0 -159
- package/src/plugins/ibkr/instance-selection.test.ts +0 -120
- package/src/plugins/ibkr/instance-selection.ts +0 -36
- package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
- package/src/plugins/ibkr/portfolio-performance.ts +0 -129
- package/src/plugins/ibkr/trade/badge.tsx +0 -28
- package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
- package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
- package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
- package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
- package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
- package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
- package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
- package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
- package/src/plugins/ibkr/trade/tab/model.ts +0 -159
- package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
- package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
- package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
- package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
- package/src/plugins/ibkr/trade/utils.test.ts +0 -175
- package/src/plugins/ibkr/trade/utils.ts +0 -144
- package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
- package/src/plugins/ibkr/trading/pane.tsx +0 -332
- package/src/plugins/ibkr/trading/state.test.ts +0 -109
- package/src/plugins/ibkr/trading/state.ts +0 -335
package/src/i18n/zh-cn.ts
CHANGED
|
@@ -573,6 +573,7 @@ export const zhCN: Record<string, string> = {
|
|
|
573
573
|
"Open the help window": "打开帮助窗口",
|
|
574
574
|
"Set up a portfolio": "设置投资组合",
|
|
575
575
|
"How would you like to get started?": "你想如何开始?",
|
|
576
|
+
"{shortcut} to get started.": "按 {shortcut} 开始。",
|
|
576
577
|
"Edits later from the command bar.": "之后可在命令栏中修改。",
|
|
577
578
|
"Create Manual Portfolio": "创建手动组合",
|
|
578
579
|
"Add tickers and positions by hand": "手动添加股票与持仓",
|
|
@@ -775,7 +776,7 @@ export const zhCN: Record<string, string> = {
|
|
|
775
776
|
"Verify your email to send messages.": "验证邮箱后才能发送消息。",
|
|
776
777
|
"Verify your email to use Cloud tweets.": "验证邮箱后才能使用 Cloud tweets。",
|
|
777
778
|
"Resend Verification Email": "重新发送验证邮件",
|
|
778
|
-
"
|
|
779
|
+
"{shortcut}, then Resend Verification Email": "按 {shortcut},然后选择“重新发送验证邮件”",
|
|
779
780
|
"editing": "编辑中",
|
|
780
781
|
"replying to": "回复",
|
|
781
782
|
"Reply": "回复",
|
|
@@ -1013,7 +1014,7 @@ export const zhCN: Record<string, string> = {
|
|
|
1013
1014
|
"No watchlist tickers": "自选列表暂无股票",
|
|
1014
1015
|
"No tickers in {name}.": "{name} 中暂无股票。",
|
|
1015
1016
|
"this collection": "此集合",
|
|
1016
|
-
"Press
|
|
1017
|
+
"Press {shortcut} to add one.": "按 {shortcut} 添加。",
|
|
1017
1018
|
"PRE-MKT": "盘前",
|
|
1018
1019
|
"OPEN": "盘中",
|
|
1019
1020
|
"AFTER-HRS": "盘后",
|
|
@@ -1079,6 +1080,9 @@ export const zhCN: Record<string, string> = {
|
|
|
1079
1080
|
"Approve from your phone, no typing": "在手机上确认,无需输入",
|
|
1080
1081
|
"Scan with the Gloom app": "用 Gloom 应用扫码",
|
|
1081
1082
|
"Open the Gloom app on your phone and approve this workspace.": "在手机上打开 Gloom 应用并确认此工作区。",
|
|
1083
|
+
"Approve the code from a phone that is already signed in.": "在已登录的手机上确认此代码。",
|
|
1084
|
+
"Layouts, watchlists and portfolios sync to your account.": "布局、自选列表和投资组合会同步到你的账户。",
|
|
1085
|
+
"Use email instead": "改用邮箱",
|
|
1082
1086
|
"Scan with the Gloom app to sign in": "用 Gloom 应用扫码登录",
|
|
1083
1087
|
"Waiting for approval...": "等待确认...",
|
|
1084
1088
|
"Approved as {email}": "已以 {email} 登录",
|
package/src/i18n/zh-tw.ts
CHANGED
|
@@ -573,6 +573,7 @@ export const zhTW: Record<string, string> = {
|
|
|
573
573
|
"Open the help window": "開啟說明視窗",
|
|
574
574
|
"Set up a portfolio": "設定投資組合",
|
|
575
575
|
"How would you like to get started?": "你想如何開始?",
|
|
576
|
+
"{shortcut} to get started.": "按 {shortcut} 開始。",
|
|
576
577
|
"Edits later from the command bar.": "之後可在命令列中修改。",
|
|
577
578
|
"Create Manual Portfolio": "建立手動投資組合",
|
|
578
579
|
"Add tickers and positions by hand": "手動新增股票與持倉",
|
|
@@ -775,7 +776,7 @@ export const zhTW: Record<string, string> = {
|
|
|
775
776
|
"Verify your email to send messages.": "驗證電子郵件後才能傳送訊息。",
|
|
776
777
|
"Verify your email to use Cloud tweets.": "驗證電子郵件後才能使用 Cloud tweets。",
|
|
777
778
|
"Resend Verification Email": "重新發送驗證郵件",
|
|
778
|
-
"
|
|
779
|
+
"{shortcut}, then Resend Verification Email": "按 {shortcut},然後選擇「重新發送驗證郵件」",
|
|
779
780
|
"editing": "編輯中",
|
|
780
781
|
"replying to": "回覆",
|
|
781
782
|
"Reply": "回覆",
|
|
@@ -1013,7 +1014,7 @@ export const zhTW: Record<string, string> = {
|
|
|
1013
1014
|
"No watchlist tickers": "自選清單暫無股票",
|
|
1014
1015
|
"No tickers in {name}.": "{name} 中暫無股票。",
|
|
1015
1016
|
"this collection": "此清單",
|
|
1016
|
-
"Press
|
|
1017
|
+
"Press {shortcut} to add one.": "按 {shortcut} 新增。",
|
|
1017
1018
|
"PRE-MKT": "盤前",
|
|
1018
1019
|
"OPEN": "盤中",
|
|
1019
1020
|
"AFTER-HRS": "盤後",
|
|
@@ -1079,6 +1080,9 @@ export const zhTW: Record<string, string> = {
|
|
|
1079
1080
|
"Approve from your phone, no typing": "在手機上確認,無需輸入",
|
|
1080
1081
|
"Scan with the Gloom app": "用 Gloom 應用程式掃碼",
|
|
1081
1082
|
"Open the Gloom app on your phone and approve this workspace.": "在手機上開啟 Gloom 應用程式並確認此工作區。",
|
|
1083
|
+
"Approve the code from a phone that is already signed in.": "在已登入的手機上確認這組代碼。",
|
|
1084
|
+
"Layouts, watchlists and portfolios sync to your account.": "版面、自選清單與投資組合會同步到你的帳號。",
|
|
1085
|
+
"Use email instead": "改用電子郵件",
|
|
1082
1086
|
"Scan with the Gloom app to sign in": "用 Gloom 應用程式掃碼登入",
|
|
1083
1087
|
"Waiting for approval...": "等待確認...",
|
|
1084
1088
|
"Approved as {email}": "已以 {email} 登入",
|
|
@@ -157,6 +157,23 @@ describe("layout marketplace payloads", () => {
|
|
|
157
157
|
expect(JSON.stringify(pane)).not.toContain("secret");
|
|
158
158
|
});
|
|
159
159
|
|
|
160
|
+
test("drops cache-sized pane state instead of failing the share", () => {
|
|
161
|
+
const pane = publishableMarketplacePane({
|
|
162
|
+
instanceId: "news-top:main",
|
|
163
|
+
paneId: "prediction-markets",
|
|
164
|
+
binding: { kind: "none" },
|
|
165
|
+
}, {
|
|
166
|
+
sort: { columnId: "time", direction: "desc" },
|
|
167
|
+
"news-top:articles": Array.from({ length: 400 }, (_, index) => ({
|
|
168
|
+
id: `article-${index}`,
|
|
169
|
+
title: "x".repeat(200),
|
|
170
|
+
publishedAt: "2026-08-26T00:00:00.000Z",
|
|
171
|
+
})),
|
|
172
|
+
}, panes);
|
|
173
|
+
|
|
174
|
+
expect(pane.paneState.p1).toEqual({ sort: { columnId: "time", direction: "desc" } });
|
|
175
|
+
});
|
|
176
|
+
|
|
160
177
|
test("shares portable pane setup and state while redacting private data", () => {
|
|
161
178
|
const fixture = portableFixture();
|
|
162
179
|
const payload = publishableMarketplaceLayout(fixture.layout, fixture.paneState, panes);
|
|
@@ -12,6 +12,10 @@ import type {
|
|
|
12
12
|
} from "../types/plugin";
|
|
13
13
|
|
|
14
14
|
const MAX_LAYOUT_BYTES = 128 * 1024;
|
|
15
|
+
// Pane runtime state doubles as a cache (news panes keep six figures of bytes of
|
|
16
|
+
// article backlog), so bulky fields drop out of the share rather than failing
|
|
17
|
+
// the whole publish.
|
|
18
|
+
const MAX_PANE_STATE_FIELD_BYTES = 16 * 1024;
|
|
15
19
|
const MAX_INSTANCES = 40;
|
|
16
20
|
const MAX_DOCK_DEPTH = 20;
|
|
17
21
|
const MAX_ID_LENGTH = 160;
|
|
@@ -493,14 +497,45 @@ function publishableLayout(
|
|
|
493
497
|
height,
|
|
494
498
|
})),
|
|
495
499
|
};
|
|
496
|
-
|
|
500
|
+
let publishableState = Object.fromEntries(
|
|
501
|
+
Object.entries(projectedState).flatMap(([id, state]) => {
|
|
502
|
+
const trimmed = withoutCacheFields(state);
|
|
503
|
+
return Object.keys(trimmed).length > 0 ? [[id, trimmed] as const] : [];
|
|
504
|
+
}),
|
|
505
|
+
);
|
|
506
|
+
let parsed = parsePublishablePayload(projected, publishableState);
|
|
507
|
+
while (!parsed && Object.keys(publishableState).length > 0) {
|
|
508
|
+
publishableState = withoutLargestState(publishableState);
|
|
509
|
+
parsed = parsePublishablePayload(projected, publishableState);
|
|
510
|
+
}
|
|
511
|
+
if (!parsed) throw new Error("This layout cannot be published safely.");
|
|
512
|
+
return parsed;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function parsePublishablePayload(
|
|
516
|
+
layout: LayoutConfig,
|
|
517
|
+
paneState: Record<string, PaneRuntimeState>,
|
|
518
|
+
): LayoutMarketplacePayload | null {
|
|
519
|
+
return parseMarketplaceLayoutPayload({
|
|
497
520
|
schemaVersion: 2,
|
|
498
521
|
sourceConfigVersion: CURRENT_CONFIG_VERSION,
|
|
499
|
-
layout
|
|
500
|
-
paneState
|
|
522
|
+
layout,
|
|
523
|
+
paneState,
|
|
501
524
|
});
|
|
502
|
-
|
|
503
|
-
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function withoutCacheFields(state: PaneRuntimeState): PaneRuntimeState {
|
|
528
|
+
return Object.fromEntries(
|
|
529
|
+
Object.entries(state).filter(([, value]) => encodedSize(value) <= MAX_PANE_STATE_FIELD_BYTES),
|
|
530
|
+
) as PaneRuntimeState;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function withoutLargestState(
|
|
534
|
+
paneState: Record<string, PaneRuntimeState>,
|
|
535
|
+
): Record<string, PaneRuntimeState> {
|
|
536
|
+
const largest = Object.entries(paneState)
|
|
537
|
+
.reduce((worst, entry) => (encodedSize(entry[1]) > encodedSize(worst[1]) ? entry : worst));
|
|
538
|
+
return Object.fromEntries(Object.entries(paneState).filter(([id]) => id !== largest[0]));
|
|
504
539
|
}
|
|
505
540
|
|
|
506
541
|
export function publishableMarketplaceLayout(
|
|
@@ -55,7 +55,8 @@ import {
|
|
|
55
55
|
loadQuoteBatchEntries,
|
|
56
56
|
loadQuoteEntry,
|
|
57
57
|
QuoteSubscriptionManager,
|
|
58
|
-
type
|
|
58
|
+
type QuoteSubscriptionHandle,
|
|
59
|
+
type QuoteSubscriptionRequest,
|
|
59
60
|
} from "./quotes";
|
|
60
61
|
|
|
61
62
|
export class MarketDataCoordinator {
|
|
@@ -361,7 +362,7 @@ export class MarketDataCoordinator {
|
|
|
361
362
|
});
|
|
362
363
|
}
|
|
363
364
|
|
|
364
|
-
subscribeQuotes(targets:
|
|
365
|
+
subscribeQuotes(targets: QuoteSubscriptionRequest[]): QuoteSubscriptionHandle {
|
|
365
366
|
return this.quoteSubscriptionManager.subscribe(targets);
|
|
366
367
|
}
|
|
367
368
|
|
|
@@ -19,6 +19,21 @@ import {
|
|
|
19
19
|
|
|
20
20
|
export type QuoteSubscriptionPriority = Pick<QuoteSubscriptionTarget, "route" | "surface" | "visible" | "selected" | "weight">;
|
|
21
21
|
|
|
22
|
+
export interface QuoteSubscriptionRequest {
|
|
23
|
+
instrument: InstrumentRef;
|
|
24
|
+
priority?: QuoteSubscriptionPriority;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Remains callable for compatibility with the original disposer API. Updating
|
|
29
|
+
* the handle lets long-lived consumers change priorities without unregistering
|
|
30
|
+
* their whole target set first.
|
|
31
|
+
*/
|
|
32
|
+
export interface QuoteSubscriptionHandle {
|
|
33
|
+
(): void;
|
|
34
|
+
update(targets: QuoteSubscriptionRequest[]): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
22
37
|
export interface QuoteSubscriptionEntry {
|
|
23
38
|
target: QuoteSubscriptionTarget;
|
|
24
39
|
targets: Map<number, QuoteSubscriptionTarget>;
|
|
@@ -30,7 +45,8 @@ interface PendingStreamQuote {
|
|
|
30
45
|
quote: Quote;
|
|
31
46
|
}
|
|
32
47
|
|
|
33
|
-
const QUOTE_SUBSCRIPTION_REMOVE_GRACE_MS = 250;
|
|
48
|
+
export const QUOTE_SUBSCRIPTION_REMOVE_GRACE_MS = 250;
|
|
49
|
+
export const QUOTE_SUBSCRIPTION_PRIORITY_UPDATE_DELAY_MS = 100;
|
|
34
50
|
|
|
35
51
|
const STREAM_QUOTE_FIELDS: Array<keyof Quote> = [
|
|
36
52
|
"symbol",
|
|
@@ -198,101 +214,192 @@ export class QuoteSubscriptionManager {
|
|
|
198
214
|
private readonly pendingStreamQuotes = new Map<string, PendingStreamQuote>();
|
|
199
215
|
private lastStreamQuoteBatchAppliedAt: number | null = null;
|
|
200
216
|
private pendingStreamQuoteTimer: ReturnType<typeof setTimeout> | null = null;
|
|
217
|
+
private pendingPriorityUpdateTimer: ReturnType<typeof setTimeout> | null = null;
|
|
201
218
|
private nextQuoteSubscriptionId = 1;
|
|
202
219
|
private quoteSubscriptionDispose: (() => void) | null = null;
|
|
203
220
|
private quoteSubscriptionSignature = "";
|
|
221
|
+
private quoteSubscriptionRoutingSignature = "";
|
|
204
222
|
|
|
205
223
|
constructor(
|
|
206
224
|
private readonly dataProvider: DataProvider,
|
|
207
225
|
private readonly applyQuote: (instrument: InstrumentRef, quote: Quote) => void,
|
|
208
226
|
) {}
|
|
209
227
|
|
|
210
|
-
subscribe(targets:
|
|
211
|
-
if (!this.dataProvider.subscribeQuotes
|
|
212
|
-
return ()
|
|
228
|
+
subscribe(targets: QuoteSubscriptionRequest[]): QuoteSubscriptionHandle {
|
|
229
|
+
if (!this.dataProvider.subscribeQuotes) {
|
|
230
|
+
return this.createNoopSubscription();
|
|
213
231
|
}
|
|
214
232
|
|
|
215
233
|
const subscriptionId = this.nextQuoteSubscriptionId++;
|
|
216
|
-
|
|
234
|
+
let subscribedKeys = new Set<string>();
|
|
235
|
+
let disposed = false;
|
|
236
|
+
const update = (nextTargets: QuoteSubscriptionRequest[]) => {
|
|
237
|
+
if (disposed) return;
|
|
238
|
+
subscribedKeys = this.updateSubscriptionTargets(subscriptionId, subscribedKeys, nextTargets);
|
|
239
|
+
};
|
|
240
|
+
const dispose = (() => {
|
|
241
|
+
if (disposed) return;
|
|
242
|
+
disposed = true;
|
|
243
|
+
subscribedKeys = this.updateSubscriptionTargets(subscriptionId, subscribedKeys, []);
|
|
244
|
+
}) as QuoteSubscriptionHandle;
|
|
245
|
+
dispose.update = update;
|
|
246
|
+
update(targets);
|
|
247
|
+
return dispose;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private createNoopSubscription(): QuoteSubscriptionHandle {
|
|
251
|
+
const dispose = (() => {}) as QuoteSubscriptionHandle;
|
|
252
|
+
dispose.update = () => {};
|
|
253
|
+
return dispose;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
private updateSubscriptionTargets(
|
|
257
|
+
subscriptionId: number,
|
|
258
|
+
subscribedKeys: Set<string>,
|
|
259
|
+
targets: QuoteSubscriptionRequest[],
|
|
260
|
+
): Set<string> {
|
|
261
|
+
const nextTargets = new Map<string, QuoteSubscriptionTarget>();
|
|
217
262
|
for (const { instrument, priority } of targets) {
|
|
218
263
|
const key = buildQuoteKey(instrument);
|
|
219
|
-
subscribedKeys.add(key);
|
|
220
264
|
const target = quoteTargetFromInstrument(instrument, priority);
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
265
|
+
const duplicate = nextTargets.get(key);
|
|
266
|
+
nextTargets.set(
|
|
267
|
+
key,
|
|
268
|
+
duplicate
|
|
269
|
+
? mergeQuoteSubscriptionTargets([duplicate, target]) ?? target
|
|
270
|
+
: target,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const nextKeys = new Set(nextTargets.keys());
|
|
275
|
+
const affectedKeys = new Set([...subscribedKeys, ...nextKeys]);
|
|
276
|
+
let shouldFlush = false;
|
|
277
|
+
for (const key of affectedKeys) {
|
|
278
|
+
const nextTarget = nextTargets.get(key);
|
|
279
|
+
let entry = this.quoteSubscriptions.get(key);
|
|
280
|
+
if (nextTarget) {
|
|
281
|
+
if (!entry) {
|
|
282
|
+
entry = {
|
|
283
|
+
target: nextTarget,
|
|
284
|
+
targets: new Map(),
|
|
285
|
+
removeTimer: null,
|
|
286
|
+
};
|
|
287
|
+
this.quoteSubscriptions.set(key, entry);
|
|
228
288
|
}
|
|
289
|
+
entry.targets.set(subscriptionId, nextTarget);
|
|
290
|
+
if (entry.removeTimer) {
|
|
291
|
+
clearTimeout(entry.removeTimer);
|
|
292
|
+
entry.removeTimer = null;
|
|
293
|
+
}
|
|
294
|
+
} else if (entry) {
|
|
295
|
+
entry.targets.delete(subscriptionId);
|
|
296
|
+
}
|
|
297
|
+
if (!entry) continue;
|
|
298
|
+
|
|
299
|
+
const mergedTarget = mergeQuoteSubscriptionTargets(entry.targets.values());
|
|
300
|
+
if (mergedTarget) {
|
|
301
|
+
entry.target = mergedTarget;
|
|
302
|
+
shouldFlush = true;
|
|
229
303
|
continue;
|
|
230
304
|
}
|
|
231
|
-
this.
|
|
232
|
-
target,
|
|
233
|
-
targets: new Map([[subscriptionId, target]]),
|
|
234
|
-
removeTimer: null,
|
|
235
|
-
});
|
|
305
|
+
this.scheduleSubscriptionRemoval(key, entry);
|
|
236
306
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
this.quoteSubscriptions.delete(key);
|
|
256
|
-
this.clearPendingStreamQuote(key);
|
|
257
|
-
this.flush();
|
|
258
|
-
}, QUOTE_SUBSCRIPTION_REMOVE_GRACE_MS);
|
|
259
|
-
}
|
|
260
|
-
};
|
|
307
|
+
if (shouldFlush) {
|
|
308
|
+
this.flush();
|
|
309
|
+
} else if (![...this.quoteSubscriptions.values()].some((entry) => entry.targets.size > 0)) {
|
|
310
|
+
this.cancelPendingPriorityUpdate();
|
|
311
|
+
}
|
|
312
|
+
return nextKeys;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private scheduleSubscriptionRemoval(key: string, entry: QuoteSubscriptionEntry): void {
|
|
316
|
+
if (entry.removeTimer) return;
|
|
317
|
+
this.clearPendingStreamQuote(key);
|
|
318
|
+
entry.removeTimer = setTimeout(() => {
|
|
319
|
+
const current = this.quoteSubscriptions.get(key);
|
|
320
|
+
if (!current || current.targets.size > 0) return;
|
|
321
|
+
this.quoteSubscriptions.delete(key);
|
|
322
|
+
this.clearPendingStreamQuote(key);
|
|
323
|
+
this.flush();
|
|
324
|
+
}, QUOTE_SUBSCRIPTION_REMOVE_GRACE_MS);
|
|
261
325
|
}
|
|
262
326
|
|
|
263
|
-
private flush(
|
|
327
|
+
private flush({
|
|
328
|
+
coalescePriorityChanges = true,
|
|
329
|
+
requireStableRouting = false,
|
|
330
|
+
}: {
|
|
331
|
+
coalescePriorityChanges?: boolean;
|
|
332
|
+
requireStableRouting?: boolean;
|
|
333
|
+
} = {}): void {
|
|
264
334
|
if (!this.dataProvider.subscribeQuotes) return;
|
|
265
335
|
|
|
266
336
|
const activeEntries = [...this.quoteSubscriptions.entries()]
|
|
267
337
|
.filter(([, entry]) => entry.targets.size > 0)
|
|
268
338
|
.sort(([left], [right]) => left.localeCompare(right));
|
|
269
|
-
const
|
|
339
|
+
const nextRoutingSignature = JSON.stringify(activeEntries.map(([key, entry]) => [
|
|
270
340
|
key,
|
|
271
|
-
entry.target.route ?? "",
|
|
341
|
+
entry.target.route ?? "auto",
|
|
342
|
+
]));
|
|
343
|
+
const nextSignature = JSON.stringify(activeEntries.map(([key, entry]) => [
|
|
344
|
+
key,
|
|
345
|
+
entry.target.route ?? "auto",
|
|
272
346
|
entry.target.surface ?? "",
|
|
273
|
-
entry.target.visible
|
|
274
|
-
entry.target.selected
|
|
275
|
-
Number.isFinite(entry.target.weight) ? entry.target.weight :
|
|
276
|
-
]
|
|
277
|
-
if (nextSignature === this.quoteSubscriptionSignature)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
this.
|
|
347
|
+
entry.target.visible === true,
|
|
348
|
+
entry.target.selected === true,
|
|
349
|
+
Number.isFinite(entry.target.weight) ? entry.target.weight : null,
|
|
350
|
+
]));
|
|
351
|
+
if (nextSignature === this.quoteSubscriptionSignature) {
|
|
352
|
+
this.cancelPendingPriorityUpdate();
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (requireStableRouting && nextRoutingSignature !== this.quoteSubscriptionRoutingSignature) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const priorityOnlyChange = this.quoteSubscriptionSignature.length > 0
|
|
360
|
+
&& nextRoutingSignature === this.quoteSubscriptionRoutingSignature;
|
|
361
|
+
if (coalescePriorityChanges && priorityOnlyChange) {
|
|
362
|
+
this.schedulePriorityUpdate();
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
this.cancelPendingPriorityUpdate();
|
|
282
366
|
|
|
283
367
|
const targets = activeEntries.map(([, entry]) => entry.target);
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
368
|
+
const nextDispose = targets.length > 0
|
|
369
|
+
? this.dataProvider.subscribeQuotes(targets, (target, quote) => {
|
|
370
|
+
const instrument: InstrumentRef = {
|
|
371
|
+
symbol: target.symbol,
|
|
372
|
+
exchange: target.exchange ?? "",
|
|
373
|
+
brokerId: target.context?.brokerId,
|
|
374
|
+
brokerInstanceId: target.context?.brokerInstanceId,
|
|
375
|
+
instrument: target.context?.instrument ?? null,
|
|
376
|
+
};
|
|
377
|
+
this.enqueueStreamQuote(instrument, quote);
|
|
378
|
+
})
|
|
379
|
+
: null;
|
|
380
|
+
// Register first so the cloud socket and desktop registries can merge the
|
|
381
|
+
// overlapping listeners without observing a zero-listener disconnect.
|
|
382
|
+
const previousDispose = this.quoteSubscriptionDispose;
|
|
383
|
+
this.quoteSubscriptionDispose = nextDispose;
|
|
384
|
+
this.quoteSubscriptionSignature = nextSignature;
|
|
385
|
+
this.quoteSubscriptionRoutingSignature = nextRoutingSignature;
|
|
386
|
+
previousDispose?.();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private schedulePriorityUpdate(): void {
|
|
390
|
+
// Do not reset this timer. Continuous navigation must still publish the
|
|
391
|
+
// latest priorities instead of postponing them indefinitely.
|
|
392
|
+
if (this.pendingPriorityUpdateTimer !== null) return;
|
|
393
|
+
this.pendingPriorityUpdateTimer = setTimeout(() => {
|
|
394
|
+
this.pendingPriorityUpdateTimer = null;
|
|
395
|
+
this.flush({ coalescePriorityChanges: false, requireStableRouting: true });
|
|
396
|
+
}, QUOTE_SUBSCRIPTION_PRIORITY_UPDATE_DELAY_MS);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
private cancelPendingPriorityUpdate(): void {
|
|
400
|
+
if (this.pendingPriorityUpdateTimer === null) return;
|
|
401
|
+
clearTimeout(this.pendingPriorityUpdateTimer);
|
|
402
|
+
this.pendingPriorityUpdateTimer = null;
|
|
296
403
|
}
|
|
297
404
|
|
|
298
405
|
private enqueueStreamQuote(instrument: InstrumentRef, quote: Quote): void {
|