gloomberb 0.16.1 → 0.16.3
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 +2 -1
- package/package.json +2 -1
- package/src/api-client/beneficial-owners.ts +92 -0
- package/src/api-client/data.ts +26 -8
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +2 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +37 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +2 -0
- package/src/brokers/account-cache.ts +69 -0
- package/src/cli/command-options.ts +74 -0
- package/src/cli/commands/command-utils.ts +37 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +560 -136
- package/src/cli/commands/overview.ts +136 -48
- package/src/cli/commands/ticker.ts +220 -67
- package/src/cli/desktop-pane-shot.ts +37 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +27 -6
- package/src/cli/helpers.ts +4 -8
- package/src/cli/history-rows.ts +187 -15
- package/src/cli/index.ts +23 -8
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/options.ts +5 -1
- package/src/cli/pane-functions/access-gate.ts +42 -0
- package/src/cli/pane-functions/capabilities.ts +5 -0
- package/src/cli/pane-functions/catalog.ts +28 -1
- package/src/cli/pane-functions/data.ts +3 -1
- package/src/cli/pane-functions/dom.ts +87 -16
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +31 -22
- package/src/cli/pane-functions/headless.ts +201 -41
- package/src/cli/pane-functions/index.ts +24 -6
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +12 -1
- package/src/cli/pane-functions/resolver.ts +63 -9
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +11 -3
- package/src/cli/registry.ts +6 -3
- package/src/cli/report-tables.ts +460 -0
- package/src/cli/result.ts +53 -29
- package/src/cli/ticker-resolution.ts +7 -5
- package/src/components/chart/composite/composite-chart.tsx +88 -2536
- package/src/components/chart/composite/drawing-store.ts +59 -0
- package/src/components/chart/composite/legend.tsx +319 -0
- package/src/components/chart/composite/panel-bitmap.ts +139 -0
- package/src/components/chart/composite/panel-gestures.ts +59 -0
- package/src/components/chart/composite/panel-labels.ts +107 -0
- package/src/components/chart/composite/panel-surface.tsx +876 -0
- package/src/components/chart/composite/tool-catalog.ts +98 -0
- package/src/components/chart/composite/toolbar.tsx +186 -0
- package/src/components/chart/composite/tools.ts +8 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
- package/src/components/chart/composite/use-composite-viewport.ts +143 -0
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +16 -3
- package/src/components/command-bar/pane-templates/workflow.ts +1 -0
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +6 -0
- package/src/components/data-table/export.ts +6 -51
- package/src/components/data-table/view.tsx +32 -11
- package/src/components/feedback-dialog.tsx +2 -1
- package/src/components/form-modal/field-row.tsx +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/pane/content.tsx +23 -10
- package/src/components/layout/pane/error-boundary.tsx +103 -0
- package/src/components/layout/pane/footer/registration.tsx +68 -23
- package/src/components/layout/pane/header.tsx +11 -11
- package/src/components/layout/shell/active-drag.ts +67 -35
- package/src/components/layout/shell/cursor-occlusion.ts +6 -5
- package/src/components/layout/shell/drag/index.ts +12 -7
- package/src/components/layout/shell/drag/live.ts +122 -0
- package/src/components/layout/shell/drag/overlays.tsx +179 -35
- package/src/components/layout/shell/drag/runtime.ts +62 -50
- package/src/components/layout/shell/drag/slide.ts +10 -0
- package/src/components/layout/shell/index.tsx +37 -51
- package/src/components/layout/shell/menu.ts +2 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
- package/src/components/layout/shell/native/surfaces.ts +30 -14
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +419 -168
- package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
- package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
- package/src/components/metric-treemap/heat-surface.tsx +43 -16
- package/src/components/metric-treemap/heat-tiles.ts +18 -0
- package/src/components/metric-treemap/layout.ts +2 -0
- package/src/components/onboarding/onboarding-keyboard.ts +311 -0
- package/src/components/onboarding/onboarding-wizard.tsx +101 -788
- package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
- package/src/components/onboarding/use-onboarding-progress.ts +298 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/range-track.tsx +10 -3
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +7 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/data/config/store/normalize.ts +17 -1
- package/src/data/json-persistence.ts +17 -3
- package/src/data/json-storage.ts +2 -0
- package/src/data/memory-resource-store.ts +46 -0
- package/src/i18n/es.ts +19 -1
- package/src/i18n/ja.ts +19 -1
- package/src/i18n/ko.ts +19 -1
- package/src/i18n/zh-cn.ts +19 -1
- package/src/i18n/zh-tw.ts +19 -1
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/quotes.ts +23 -4
- package/src/market-data/fx-closes.ts +72 -0
- package/src/market-data/market/freshness.ts +123 -6
- package/src/market-data/market/session-close-note.ts +57 -0
- package/src/market-data/market/status.ts +151 -0
- package/src/market-data/published-apac-sessions.ts +66 -0
- package/src/market-data/quotes/contributions.ts +2 -0
- package/src/market-data/quotes/freshness.ts +5 -0
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/plugins/builtin/account-management/pane.tsx +4 -0
- package/src/plugins/builtin/alerts/cli.ts +10 -5
- package/src/plugins/builtin/alerts/index.tsx +1 -0
- package/src/plugins/builtin/analytics/metrics.ts +8 -3
- package/src/plugins/builtin/analytics/pane-model.ts +10 -6
- package/src/plugins/builtin/analytics/risk-client.ts +191 -66
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
- package/src/plugins/builtin/analytics/risk-model.ts +45 -17
- package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
- package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
- package/src/plugins/builtin/attention/headless.ts +6 -4
- package/src/plugins/builtin/attention/index.tsx +1 -1
- package/src/plugins/builtin/attention/pane.tsx +2 -2
- package/src/plugins/builtin/awards/headless.ts +1 -0
- package/src/plugins/builtin/awards/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/headless.ts +1 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/detail.tsx +1 -1
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless.ts +38 -3
- package/src/plugins/builtin/chart-composer/index.tsx +3 -1
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
- package/src/plugins/builtin/chat/channels.ts +19 -3
- package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
- package/src/plugins/builtin/chat/content/footer.tsx +15 -6
- package/src/plugins/builtin/chat/content/index.tsx +120 -21
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
- package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
- package/src/plugins/builtin/chat/direct-messages.ts +200 -0
- package/src/plugins/builtin/chat/index.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
- package/src/plugins/builtin/chat/message/header.tsx +16 -6
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
- package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
- package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
- package/src/plugins/builtin/chat/message/types.ts +14 -2
- package/src/plugins/builtin/chat/profile-popover.ts +18 -13
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/comment-letters/index.tsx +1 -0
- package/src/plugins/builtin/company-attention/headless.ts +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +2 -2
- package/src/plugins/builtin/company-kpis/headless.ts +1 -0
- package/src/plugins/builtin/congress-trades/headless.ts +1 -0
- package/src/plugins/builtin/correlation/compute.ts +59 -16
- package/src/plugins/builtin/correlation/geo.ts +34 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
- package/src/plugins/builtin/correlation/headless.ts +42 -8
- package/src/plugins/builtin/correlation/history.ts +2 -0
- package/src/plugins/builtin/correlation/index.tsx +68 -14
- package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
- package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
- package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/cot/headless.ts +6 -3
- package/src/plugins/builtin/cot/index.tsx +3 -3
- package/src/plugins/builtin/cot/model.ts +36 -3
- package/src/plugins/builtin/cpi/headless.ts +4 -0
- package/src/plugins/builtin/credit-boards/headless.ts +2 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
- package/src/plugins/builtin/credit-documents/headless.ts +2 -0
- package/src/plugins/builtin/crypto-board/headless.ts +3 -0
- package/src/plugins/builtin/custom-view/loader.ts +1 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
- package/src/plugins/builtin/doe/headless.ts +7 -0
- package/src/plugins/builtin/doe/range-bar.tsx +7 -37
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
- package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
- package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
- package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
- package/src/plugins/builtin/econ/index.tsx +1 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
- package/src/plugins/builtin/equity-screener/headless.ts +2 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/headless.ts +3 -1
- package/src/plugins/builtin/fear-greed/headless.ts +2 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +39 -10
- package/src/plugins/builtin/futures-curve/index.tsx +3 -3
- package/src/plugins/builtin/futures-curve/model.ts +188 -4
- package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
- package/src/plugins/builtin/gpu/headless.ts +7 -3
- package/src/plugins/builtin/gpu/ladder.tsx +26 -30
- package/src/plugins/builtin/gpu/model.ts +27 -1
- package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
- package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
- package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
- package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
- package/src/plugins/builtin/holders/client.ts +3 -6
- package/src/plugins/builtin/holders/format.ts +31 -1
- package/src/plugins/builtin/holders/headless.ts +161 -6
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +42 -16
- package/src/plugins/builtin/holders/report-header.ts +136 -0
- package/src/plugins/builtin/holders/table-model.ts +20 -5
- package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
- package/src/plugins/builtin/holders/types.ts +2 -1
- package/src/plugins/builtin/insider/headless.ts +2 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -1
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +12 -6
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
- package/src/plugins/builtin/macro-day/headless.ts +2 -0
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +2 -0
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
- package/src/plugins/builtin/market-movers/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +20 -3
- package/src/plugins/builtin/members/headless.ts +5 -3
- package/src/plugins/builtin/members/model.ts +10 -2
- package/src/plugins/builtin/members/pane.tsx +23 -6
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/money-markets/headless.ts +1 -0
- package/src/plugins/builtin/news/headless.ts +2 -0
- package/src/plugins/builtin/news/wire/index.tsx +8 -1
- package/src/plugins/builtin/notes/cli.ts +14 -6
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/index.tsx +1 -0
- package/src/plugins/builtin/options-calculator/headless.ts +2 -0
- package/src/plugins/builtin/options-positioning/headless.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +5 -0
- package/src/plugins/builtin/pe-band/client.ts +48 -3
- package/src/plugins/builtin/pe-band/headless.ts +25 -7
- package/src/plugins/builtin/pe-band/model.ts +92 -16
- package/src/plugins/builtin/pe-band/pane.tsx +33 -16
- package/src/plugins/builtin/perps/client.ts +50 -3
- package/src/plugins/builtin/perps/headless.ts +144 -16
- package/src/plugins/builtin/perps/index.tsx +6 -6
- package/src/plugins/builtin/perps/model.ts +189 -12
- package/src/plugins/builtin/perps/pane.tsx +249 -48
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +248 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +42 -0
- package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
- package/src/plugins/builtin/portfolio-list/cli/render.ts +232 -39
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
- package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
- package/src/plugins/builtin/portfolio-list/headless.ts +100 -16
- package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
- package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +53 -16
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +46 -5
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
- package/src/plugins/builtin/power/headless.ts +3 -1
- package/src/plugins/builtin/rate-path/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
- package/src/plugins/builtin/research/analyst-headless.ts +3 -0
- package/src/plugins/builtin/research/events-headless.ts +2 -0
- package/src/plugins/builtin/research/headless.ts +2 -0
- package/src/plugins/builtin/research/index.tsx +1 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
- package/src/plugins/builtin/research/relative-valuation-model.ts +18 -6
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
- package/src/plugins/builtin/research-search/index.tsx +1 -0
- package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
- package/src/plugins/builtin/risk-factors/headless.ts +2 -0
- package/src/plugins/builtin/scanner/flow-history.ts +2 -13
- package/src/plugins/builtin/scanner/headless.ts +14 -0
- package/src/plugins/builtin/seasonality/headless.ts +2 -0
- package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
- package/src/plugins/builtin/sec/filing-content.ts +42 -17
- package/src/plugins/builtin/sec/forms.ts +12 -0
- package/src/plugins/builtin/sec/headless.ts +2 -0
- package/src/plugins/builtin/sectors/client.ts +1 -0
- package/src/plugins/builtin/sectors/headless.ts +9 -1
- package/src/plugins/builtin/sectors/sector-model.ts +2 -0
- package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/members-menu.tsx +260 -0
- package/src/plugins/builtin/shared/report-freshness.ts +57 -0
- package/src/plugins/builtin/shared/research-cells.tsx +4 -9
- package/src/plugins/builtin/short-interest/headless.ts +2 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/short-volume/pane.tsx +1 -1
- package/src/plugins/builtin/social-mentions/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
- package/src/plugins/builtin/supply-chain/headless.ts +7 -1
- package/src/plugins/builtin/supply-chain/index.tsx +10 -1
- package/src/plugins/builtin/supply-chain/model.ts +27 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
- package/src/plugins/builtin/themes/headless.ts +3 -0
- package/src/plugins/builtin/themes/pane.tsx +3 -0
- package/src/plugins/builtin/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
- package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +27 -5
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +17 -5
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +27 -26
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/volatility/headless.ts +6 -1
- package/src/plugins/builtin/world-indices/headless.ts +2 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +159 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +232 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -0
- package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
- package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
- package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +448 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
- package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +69 -6
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +565 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +406 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +557 -85
- package/src/plugins/builtin/world-venue-map/model.ts +23 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +202 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +35 -44
- package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
- package/src/plugins/builtin/yield-curve/headless.ts +16 -0
- package/src/plugins/loader.ts +13 -1
- package/src/plugins/registry/pane-settings.ts +1 -0
- package/src/renderers/browser/app-services.ts +3 -1
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/dom.ts +31 -0
- package/src/renderers/dom/data-table/index.tsx +5 -0
- package/src/renderers/dom/data-table/row.tsx +2 -0
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/box.tsx +113 -17
- package/src/renderers/dom/host/drag-shield.ts +24 -0
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/host/live-frame.ts +54 -0
- package/src/renderers/dom/host/mouse.ts +8 -1
- package/src/renderers/dom/host/scroll-box.tsx +6 -5
- package/src/renderers/dom/host/tabs.tsx +3 -2
- package/src/renderers/dom/styles.css +16 -9
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +13 -0
- package/src/renderers/electrobun/shared/protocol.ts +10 -1
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -0
- package/src/renderers/electrobun/view/host/native.ts +0 -10
- package/src/renderers/electrobun/view/host/window-move.ts +28 -0
- package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/electrobun/view/ui-host.tsx +2 -5
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/renderers/opentui/ui-host.tsx +7 -1
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +43 -23
- package/src/sources/provider-router/batches.ts +3 -3
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financial-routes.ts +2 -2
- package/src/sources/provider-router/financials.ts +76 -12
- package/src/sources/provider-router/history.ts +15 -10
- package/src/sources/provider-router/primary.ts +2 -2
- package/src/sources/sec-registrant.ts +75 -0
- package/src/state/app/context/index.tsx +24 -8
- package/src/state/hooks/quote-streaming.ts +41 -26
- package/src/state/pane-scroll-registry.tsx +67 -35
- package/src/sync/core-contributors.ts +4 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/test-support/margin-account.ts +108 -0
- package/src/theme/heat-colors.ts +266 -84
- package/src/time-series/resolution.ts +15 -0
- package/src/time-series/resolve.ts +1 -1
- package/src/time-series/use-chart-resolution.ts +1 -1
- package/src/types/context-menu.ts +6 -0
- package/src/types/data-provider.ts +2 -0
- package/src/types/financials.ts +35 -3
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +20 -1
- package/src/types/ticker.ts +15 -0
- package/src/ui/host.tsx +26 -0
- package/src/ui/index.tsx +8 -3
- package/src/ui/scroll-box-axis.ts +26 -0
- package/src/updater/index.ts +9 -11
- package/src/utils/async-deadline.ts +21 -0
- package/src/utils/cli-output.ts +5 -1
- package/src/utils/crypto-pair.ts +41 -0
- package/src/utils/currency-units.ts +19 -0
- package/src/utils/depositary-receipt.ts +70 -0
- package/src/utils/display-number.ts +63 -0
- package/src/utils/exchanges.ts +72 -0
- package/src/utils/fire-and-forget.ts +24 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/fundamentals.ts +17 -1
- package/src/utils/price-earnings.ts +70 -3
- package/src/utils/price-history-integrity.ts +19 -6
- package/src/utils/price-history.ts +58 -13
- package/src/utils/rpc-timeout-error.ts +27 -0
- package/src/utils/sec.ts +13 -1
- package/src/utils/utc-time.ts +79 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { HeadlessPaneColumn, HeadlessPaneDefinition } from "../../../types/plugin";
|
|
2
|
+
import { formatCompact, formatPercentRaw } from "../../../utils/format";
|
|
3
|
+
import { MARKET_HEATMAP_REQUEST_COUNT, MARKET_HEATMAP_UNIVERSES, fetchMarketHeatmap, type MarketHeatmapUniverseId } from "./data";
|
|
4
|
+
import { heatmapMove, summarizeHeatmapGroups, type HeatmapGroupBy, type HeatmapGroupSummary } from "./model";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A few names always lack a move (foreign listings and new tickers the snapshot
|
|
8
|
+
* has no change for). They are listed in a notice and in `metadata.noMove`; the
|
|
9
|
+
* report is incomplete only when so many lack one that the groups mislead.
|
|
10
|
+
*/
|
|
11
|
+
const MIN_MOVE_COVERAGE = 0.9;
|
|
12
|
+
|
|
13
|
+
const percent = (value: unknown) => typeof value === "number" ? formatPercentRaw(value) : "—";
|
|
14
|
+
const share = (value: unknown) => typeof value === "number" ? `${value.toFixed(1)}%` : "—";
|
|
15
|
+
const dollars = (value: unknown) => typeof value === "number" && value > 0 ? `$${formatCompact(value)}` : "—";
|
|
16
|
+
const member = (symbol: unknown, move: unknown) => typeof symbol === "string" && typeof move === "number"
|
|
17
|
+
? `${symbol} ${formatPercentRaw(move)}`
|
|
18
|
+
: "—";
|
|
19
|
+
|
|
20
|
+
function columns(universe: MarketHeatmapUniverseId, groupBy: HeatmapGroupBy, flat: boolean): HeadlessPaneColumn[] {
|
|
21
|
+
return [
|
|
22
|
+
...(flat ? [] : groupBy === "industry"
|
|
23
|
+
? [{ key: "group", header: "Industry" }, { key: "sector", header: "Sector" }]
|
|
24
|
+
: [{ key: "group", header: "Sector" }]),
|
|
25
|
+
{ key: "names", header: "Names", align: "right" },
|
|
26
|
+
{ key: "size", header: universe === "us-etf" ? "Net assets" : "Mkt cap", align: "right", format: dollars },
|
|
27
|
+
...(flat ? [] : [{ key: "sharePercent", header: "Share", align: "right" as const, format: share }]),
|
|
28
|
+
{ key: "move", header: universe === "us-etf" ? "Move (asset-wtd)" : "Move (cap-wtd)", align: "right", format: percent },
|
|
29
|
+
{ key: "up", header: "Up", align: "right" },
|
|
30
|
+
{ key: "down", header: "Down", align: "right" },
|
|
31
|
+
{ key: "bestSymbol", header: "Best", format: (value, row) => member(value, row.bestMove) },
|
|
32
|
+
{ key: "worstSymbol", header: "Worst", format: (value, row) => member(value, row.worstMove) },
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function noMoveNotice(symbols: readonly string[], names: number): string {
|
|
37
|
+
const shown = symbols.slice(0, 8).join(", ");
|
|
38
|
+
const rest = symbols.length > 8 ? ` and ${symbols.length - 8} more` : "";
|
|
39
|
+
return `${symbols.length} of ${names} names have no move yet and count toward size only: ${shown}${rest}.`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function projectRow(summary: HeatmapGroupSummary, groupBy: HeatmapGroupBy, whole = false) {
|
|
43
|
+
return {
|
|
44
|
+
group: whole ? "All" : summary.group ?? (summary.sector ? "No industry" : groupBy === "industry" ? "Unclassified" : "No sector"),
|
|
45
|
+
...(groupBy === "industry" ? { sector: summary.sector ?? "—" } : {}),
|
|
46
|
+
names: summary.names,
|
|
47
|
+
size: summary.size,
|
|
48
|
+
sharePercent: summary.share * 100,
|
|
49
|
+
move: summary.move,
|
|
50
|
+
moved: summary.moved,
|
|
51
|
+
up: summary.up,
|
|
52
|
+
down: summary.down,
|
|
53
|
+
unchanged: summary.unchanged,
|
|
54
|
+
bestSymbol: summary.best?.symbol ?? null,
|
|
55
|
+
bestMove: summary.best?.move ?? null,
|
|
56
|
+
worstSymbol: summary.worst?.symbol ?? null,
|
|
57
|
+
worstMove: summary.worst?.move ?? null,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const marketHeatmapHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
62
|
+
shape: "rows",
|
|
63
|
+
description: "The heat map's sectors or industries: each group's size-weighted day move, how many names rose and fell, and its best and worst name, for the 500 largest US stocks or large US ETFs.",
|
|
64
|
+
argument: { kind: "none" },
|
|
65
|
+
options: [
|
|
66
|
+
{
|
|
67
|
+
key: "universe",
|
|
68
|
+
description: "Board: the 500 largest US stocks, or large US ETFs (one group, as the ETF map has no sectors).",
|
|
69
|
+
type: "enum",
|
|
70
|
+
values: [
|
|
71
|
+
{ value: "us-equity", aliases: ["stocks", "equity", "us"] },
|
|
72
|
+
{ value: "us-etf", aliases: ["etf", "etfs"] },
|
|
73
|
+
],
|
|
74
|
+
defaultValue: "us-equity",
|
|
75
|
+
settingKey: "universe",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: "group",
|
|
79
|
+
description: "Group the stocks by sector, or by industry within each sector.",
|
|
80
|
+
type: "enum",
|
|
81
|
+
values: [{ value: "sector", aliases: ["sectors"] }, { value: "industry", aliases: ["industries"] }],
|
|
82
|
+
defaultValue: "sector",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
discovery: {
|
|
86
|
+
aliases: ["HM", "heatmap"],
|
|
87
|
+
dataRequirements: ["Gloom Cloud market heatmap snapshot"],
|
|
88
|
+
limitations: [
|
|
89
|
+
"The snapshot the pane starts from, refreshed about once a minute; the pane's live-streamed colors are not in the report",
|
|
90
|
+
"Moves are weighted by market cap (net assets for ETFs), not by the pane's square-root tile area",
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
// A board snapshot refreshed on a schedule, not a feed; the pane streams on top of it, the report does not.
|
|
94
|
+
freshness: { status: "delayed" },
|
|
95
|
+
describe: (args) => {
|
|
96
|
+
const universe = MARKET_HEATMAP_UNIVERSES.find((entry) => entry.id === args.options.universe)?.label ?? "US Stocks";
|
|
97
|
+
return args.options.universe === "us-etf" ? `Market Heatmap | ${universe}` : `Market Heatmap | ${universe} by ${String(args.options.group)}`;
|
|
98
|
+
},
|
|
99
|
+
async load(args, ctx) {
|
|
100
|
+
const universe: MarketHeatmapUniverseId = args.options.universe === "us-etf" ? "us-etf" : "us-equity";
|
|
101
|
+
const groupBy: HeatmapGroupBy = args.options.group === "industry" ? "industry" : "sector";
|
|
102
|
+
const result = await fetchMarketHeatmap(
|
|
103
|
+
universe,
|
|
104
|
+
{ count: MARKET_HEATMAP_REQUEST_COUNT[universe], forceRefresh: ctx.refresh },
|
|
105
|
+
{ client: ctx.apiClient },
|
|
106
|
+
);
|
|
107
|
+
ctx.signal.throwIfAborted();
|
|
108
|
+
const { grouping, groups, board } = summarizeHeatmapGroups(result.assets, groupBy);
|
|
109
|
+
const flat = grouping === "flat";
|
|
110
|
+
const noMove = result.assets.filter((asset) => heatmapMove(asset) == null).map((asset) => asset.symbol);
|
|
111
|
+
const covered = result.assets.length > 0 && board.moved / board.names >= MIN_MOVE_COVERAGE;
|
|
112
|
+
return {
|
|
113
|
+
columns: columns(universe, groupBy, flat),
|
|
114
|
+
rows: groups.map((summary) => projectRow(summary, groupBy, flat)),
|
|
115
|
+
complete: !result.stale && covered,
|
|
116
|
+
unavailableSymbols: covered ? [] : noMove,
|
|
117
|
+
metadata: {
|
|
118
|
+
universe,
|
|
119
|
+
groupBy: flat ? null : groupBy,
|
|
120
|
+
asOf: new Date(result.fetchedAt).toISOString(),
|
|
121
|
+
stale: result.stale === true,
|
|
122
|
+
session: result.session ?? null,
|
|
123
|
+
regularSessionDate: result.regularSessionDate ?? null,
|
|
124
|
+
names: result.assets.length,
|
|
125
|
+
noMove,
|
|
126
|
+
...(noMove.length > 0 ? { notices: [noMoveNotice(noMove, result.assets.length)] } : {}),
|
|
127
|
+
board: projectRow(board, groupBy, true),
|
|
128
|
+
unit: "move and sharePercent in percent; size in USD",
|
|
129
|
+
weighting: universe === "us-etf"
|
|
130
|
+
? "Each group's move is its names' day moves weighted by net assets, over the names with a move."
|
|
131
|
+
: "Each group's move is its names' day moves weighted by market cap, over the names with a move.",
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
};
|
|
@@ -29,7 +29,7 @@ import { t, tf } from "../../../i18n";
|
|
|
29
29
|
import { priceColor } from "../../../theme/colors";
|
|
30
30
|
import { clipToDisplayWidth, formatCompact, formatCurrency, formatPercentRaw } from "../../../utils/format";
|
|
31
31
|
import { isPlainKey } from "../../../utils/keyboard";
|
|
32
|
-
import { useAppSelector, usePaneAppConfig, usePaneSettingValue } from "../../../state/app/context";
|
|
32
|
+
import { useAppSelector, usePaneAppConfig, usePaneSettingValue, usePaneStateValue } from "../../../state/app/context";
|
|
33
33
|
import { usePluginTickerActions } from "../../runtime";
|
|
34
34
|
import { useLiveQuoteEntries } from "../../../state/hooks/quote-streaming";
|
|
35
35
|
import { useFxRatesMap, useTickerFinancialsMap } from "../../../market-data/hooks";
|
|
@@ -44,18 +44,21 @@ import { resolvePortfolioTotalsCurrency } from "../portfolio-list/metrics";
|
|
|
44
44
|
import { useThrottledMemo } from "../portfolio-list/use-throttled-memo";
|
|
45
45
|
import { PORTFOLIO_REORDER_THROTTLE_MS } from "../portfolio-list/use-throttled-ticker-order";
|
|
46
46
|
import {
|
|
47
|
+
MARKET_HEATMAP_REQUEST_COUNT,
|
|
47
48
|
MARKET_HEATMAP_UNIVERSES,
|
|
48
49
|
fetchMarketHeatmap,
|
|
49
50
|
resetMarketHeatmapCache,
|
|
50
51
|
type MarketHeatmapUniverseId,
|
|
51
52
|
} from "./data";
|
|
52
53
|
import {
|
|
54
|
+
HEATMAP_COLLECTION_KIND_STATE_KEY,
|
|
53
55
|
PORTFOLIO_HEATMAP_TAB,
|
|
54
56
|
buildPortfolioHeatmapAssets,
|
|
55
57
|
fallbackHeatmapCollectionId,
|
|
56
58
|
heatmapCollectionLabel,
|
|
57
59
|
heatmapFollowsCollection,
|
|
58
60
|
heatmapSizeBy,
|
|
61
|
+
heatmapSizeByApplies,
|
|
59
62
|
heatmapSizeWeight,
|
|
60
63
|
heatmapTabId,
|
|
61
64
|
isRemoteHeatmapUniverse,
|
|
@@ -76,6 +79,8 @@ import {
|
|
|
76
79
|
rankHeatmapQuoteWeights,
|
|
77
80
|
useSettledValue,
|
|
78
81
|
} from "./live";
|
|
82
|
+
import { marketHeatmapHeadless } from "./headless";
|
|
83
|
+
import { heatmapMove, resolveHeatmapGrouping, sizeWeightedMove, type HeatmapGrouping } from "./model";
|
|
79
84
|
import {
|
|
80
85
|
overlayScreenerQuoteEntries,
|
|
81
86
|
resolveScreenerQuoteFeedStatus,
|
|
@@ -83,8 +88,6 @@ import {
|
|
|
83
88
|
|
|
84
89
|
const NO_ASSETS: HeatmapBoardAsset[] = [];
|
|
85
90
|
const NO_TARGETS: QuoteSubscriptionTarget[] = [];
|
|
86
|
-
/** The 500 largest US stocks (an older server answers with its own maximum); ETFs stay flat and need fewer. */
|
|
87
|
-
const MARKET_HEATMAP_REQUEST_COUNT: Record<MarketHeatmapUniverseId, number> = { "us-equity": 500, "us-etf": 160 };
|
|
88
91
|
const SNAPSHOT_REFRESH_MS = 60_000;
|
|
89
92
|
const LAYOUT_THROTTLE_MS = 5_000;
|
|
90
93
|
/** A size change below this share of a tile's area is not worth moving it. */
|
|
@@ -128,34 +131,16 @@ function sizeLabel(asset: HeatmapBoardAsset): string | null {
|
|
|
128
131
|
return `${label} ${formatMoneyCompact(asset.size, asset.sizeCurrency ?? asset.currency)}`;
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
/**
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
/** Marks a pre-market or after-hours move, which is measured from the regular close. */
|
|
135
|
+
function sessionMark(asset: HeatmapBoardAsset): string | null {
|
|
136
|
+
if (asset.extendedSession === "PRE") return "PM";
|
|
137
|
+
if (asset.extendedSession === "POST") return "AH";
|
|
138
|
+
return null;
|
|
136
139
|
}
|
|
137
140
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
* Sector and industry blocks when the board knows its sectors. A board where
|
|
142
|
-
* most of the value has none (ETFs, or a snapshot whose classification
|
|
143
|
-
* failed) lays out flat rather than as one big unlabeled block.
|
|
144
|
-
*/
|
|
145
|
-
function resolveGrouping(assets: readonly HeatmapBoardAsset[], industries: boolean): HeatmapGrouping {
|
|
146
|
-
let total = 0;
|
|
147
|
-
let classified = 0;
|
|
148
|
-
const sectors = new Set<string>();
|
|
149
|
-
for (const asset of assets) {
|
|
150
|
-
const weight = asset.weight ?? asset.size ?? 0;
|
|
151
|
-
total += weight;
|
|
152
|
-
if (asset.sector) {
|
|
153
|
-
classified += weight;
|
|
154
|
-
sectors.add(asset.sector);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (sectors.size < 2 || classified < total / 2) return "flat";
|
|
158
|
-
return industries ? "sector-industry" : "sector";
|
|
141
|
+
function formatMove(asset: HeatmapBoardAsset, change: number | null): string {
|
|
142
|
+
const mark = sessionMark(asset);
|
|
143
|
+
return change == null ? "—" : mark ? `${formatPercentRaw(change)} ${mark}` : formatPercentRaw(change);
|
|
159
144
|
}
|
|
160
145
|
|
|
161
146
|
/**
|
|
@@ -191,7 +176,7 @@ const paintItemCache = new WeakMap<HeatmapBoardAsset, MetricTreemapItem<HeatmapB
|
|
|
191
176
|
function paintItem(asset: HeatmapBoardAsset): MetricTreemapItem<HeatmapBoardAsset> {
|
|
192
177
|
const cached = paintItemCache.get(asset);
|
|
193
178
|
if (cached) return cached;
|
|
194
|
-
const change =
|
|
179
|
+
const change = heatmapMove(asset);
|
|
195
180
|
const details = [
|
|
196
181
|
asset.price > 0 ? formatCurrency(asset.price, asset.currency) : null,
|
|
197
182
|
sizeLabel(asset),
|
|
@@ -205,8 +190,9 @@ function paintItem(asset: HeatmapBoardAsset): MetricTreemapItem<HeatmapBoardAsse
|
|
|
205
190
|
weight: asset.weight ?? asset.size ?? 0,
|
|
206
191
|
colorValue: change,
|
|
207
192
|
primaryText: formatHeatTileMove(change),
|
|
193
|
+
primaryTextSuffix: sessionMark(asset),
|
|
208
194
|
tooltip: [
|
|
209
|
-
[asset.symbol, name,
|
|
195
|
+
[asset.symbol, name, formatMove(asset, change)].filter(Boolean).join(" · "),
|
|
210
196
|
...(details.length > 0 ? [details.join(" · ")] : []),
|
|
211
197
|
],
|
|
212
198
|
data: asset,
|
|
@@ -224,18 +210,10 @@ function otherSummary(items: readonly MetricTreemapItem<HeatmapBoardAsset>[]): s
|
|
|
224
210
|
}
|
|
225
211
|
|
|
226
212
|
function otherTooltip(items: readonly MetricTreemapItem<HeatmapBoardAsset>[]): string[] {
|
|
227
|
-
|
|
228
|
-
let weightedMove = 0;
|
|
229
|
-
for (const item of items) {
|
|
230
|
-
const change = changeOf(item.data);
|
|
231
|
-
const size = item.data.size ?? 0;
|
|
232
|
-
if (change == null || !(size > 0)) continue;
|
|
233
|
-
weight += size;
|
|
234
|
-
weightedMove += change * size;
|
|
235
|
-
}
|
|
213
|
+
const move = sizeWeightedMove(items.map((item) => item.data));
|
|
236
214
|
return [
|
|
237
215
|
tf("Other · {count} smaller names", { count: items.length }),
|
|
238
|
-
...(
|
|
216
|
+
...(move != null ? [`${formatPercentRaw(move)} ${t("cap-weighted")}`] : []),
|
|
239
217
|
];
|
|
240
218
|
}
|
|
241
219
|
|
|
@@ -262,6 +240,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
262
240
|
const linkedPortfolio = useLinkedHeatmapCollection();
|
|
263
241
|
const collectionId = linkedPortfolio.collectionId ?? fallbackHeatmapCollectionId(config);
|
|
264
242
|
const collectionKind = getCollectionTypeFromConfig(config, collectionId);
|
|
243
|
+
const [, publishCollectionKind] = usePaneStateValue<string>(HEATMAP_COLLECTION_KIND_STATE_KEY, "");
|
|
265
244
|
const portfolioLabel = heatmapCollectionLabel(config, collectionId);
|
|
266
245
|
const universeTabs = useMemo(() => [
|
|
267
246
|
...MARKET_HEATMAP_UNIVERSES.map((universe) => ({ label: universe.label, value: universe.id })),
|
|
@@ -367,7 +346,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
367
346
|
liveStreaming,
|
|
368
347
|
});
|
|
369
348
|
const resolvedAssets = useMemo(
|
|
370
|
-
() => overlayScreenerQuoteEntries(boardAssets, liveQuoteEntries),
|
|
349
|
+
() => overlayScreenerQuoteEntries(boardAssets, liveQuoteEntries, { extendedSessions: true }),
|
|
371
350
|
[boardAssets, liveQuoteEntries],
|
|
372
351
|
);
|
|
373
352
|
const feedStatus = useMemo(
|
|
@@ -381,7 +360,7 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
381
360
|
// Sizes follow live prices at most every LAYOUT_THROTTLE_MS and only past
|
|
382
361
|
// LAYOUT_TOLERANCE; a new snapshot relays out at once. Ticks only recolour.
|
|
383
362
|
const grouping = useMemo(
|
|
384
|
-
() =>
|
|
363
|
+
() => resolveHeatmapGrouping(boardAssets, activeUniverse === "us-equity"),
|
|
385
364
|
[activeUniverse, boardAssets],
|
|
386
365
|
);
|
|
387
366
|
const layoutAssets = useThrottledMemo(
|
|
@@ -456,6 +435,11 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
456
435
|
setSelectedSymbol(null);
|
|
457
436
|
}, [collectionId, linkPortfolio, setActiveUniverse]);
|
|
458
437
|
|
|
438
|
+
// The header shows the square-root control only where it changes the board.
|
|
439
|
+
useEffect(() => {
|
|
440
|
+
publishCollectionKind(collectionKind ?? "");
|
|
441
|
+
}, [collectionKind, publishCollectionKind]);
|
|
442
|
+
|
|
459
443
|
// The financials map only reads the cache; this fills it for the list on screen.
|
|
460
444
|
useEffect(() => {
|
|
461
445
|
if (!portfolioTab) return;
|
|
@@ -610,11 +594,12 @@ function MarketHeatmapPane({ focused, width, height }: PaneProps) {
|
|
|
610
594
|
parts: [
|
|
611
595
|
{ text: selectedAsset.symbol, tone: "label" as const },
|
|
612
596
|
{
|
|
613
|
-
text:
|
|
597
|
+
text: heatmapMove(selectedAsset) == null ? "—" : formatPercentRaw(heatmapMove(selectedAsset)!),
|
|
614
598
|
tone: "value" as const,
|
|
615
|
-
color:
|
|
599
|
+
color: heatmapMove(selectedAsset) == null ? undefined : priceColor(heatmapMove(selectedAsset)!),
|
|
616
600
|
bold: true,
|
|
617
601
|
},
|
|
602
|
+
...(sessionMark(selectedAsset) ? [{ text: sessionMark(selectedAsset)!, tone: "muted" as const }] : []),
|
|
618
603
|
...(selectedAsset.price > 0
|
|
619
604
|
? [{ text: formatCurrency(selectedAsset.price, selectedAsset.currency), tone: "value" as const }]
|
|
620
605
|
: []),
|
|
@@ -696,12 +681,20 @@ export const marketHeatmapPlugin: GloomPlugin = {
|
|
|
696
681
|
name: "Market Heatmap",
|
|
697
682
|
icon: "H",
|
|
698
683
|
component: MarketHeatmapPane,
|
|
684
|
+
headless: marketHeatmapHeadless,
|
|
699
685
|
defaultPosition: "right",
|
|
700
686
|
defaultMode: "floating",
|
|
701
687
|
defaultFloatingSize: { width: 110, height: 36 },
|
|
702
688
|
quickSettings: [
|
|
703
689
|
LIVE_STREAMING_QUICK_SETTING,
|
|
704
|
-
{
|
|
690
|
+
{
|
|
691
|
+
type: "toggle",
|
|
692
|
+
key: SIZE_BY_SETTING_KEY,
|
|
693
|
+
icon: "sqrt",
|
|
694
|
+
onValue: SQRT_SIZE_VALUE,
|
|
695
|
+
label: "Size by square root of market cap",
|
|
696
|
+
visible: (context) => heatmapSizeByApplies(context.settings.universe, context.paneState[HEATMAP_COLLECTION_KIND_STATE_KEY]),
|
|
697
|
+
},
|
|
705
698
|
],
|
|
706
699
|
settings: (context) => withLiveStreamingSetting({
|
|
707
700
|
title: "Market Heatmap Settings",
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { MarketHeatmapAsset } from "../../../api-client/market-discovery";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The board's grouping and move arithmetic, shared by the pane and the `fn HM`
|
|
5
|
+
* report so a sector reads the same in both. Isomorphic: no React or renderer.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
type HeatmapMoveAsset = Pick<MarketHeatmapAsset, "symbol" | "hasChange" | "changePercent" | "size" | "sector" | "industry"> & {
|
|
9
|
+
/** Treemap area, when it is not `size` itself. */
|
|
10
|
+
weight?: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The move, or null when there is none: no change data is not a flat session.
|
|
15
|
+
* A name without the last session's close still has the move of the open
|
|
16
|
+
* pre-market or after-hours session it streams (`extendedSession`).
|
|
17
|
+
*/
|
|
18
|
+
export function heatmapMove(asset: Pick<MarketHeatmapAsset, "hasChange" | "changePercent"> & { extendedSession?: string }): number | null {
|
|
19
|
+
return (asset.hasChange || asset.extendedSession != null) && typeof asset.changePercent === "number" && Number.isFinite(asset.changePercent)
|
|
20
|
+
? asset.changePercent
|
|
21
|
+
: null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type HeatmapGrouping = "sector-industry" | "sector" | "flat";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Sector and industry blocks when the board knows its sectors. A board where
|
|
28
|
+
* most of the value has none (ETFs, or a snapshot whose classification
|
|
29
|
+
* failed) lays out flat rather than as one big unlabeled block.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveHeatmapGrouping(assets: readonly HeatmapMoveAsset[], industries: boolean): HeatmapGrouping {
|
|
32
|
+
let total = 0;
|
|
33
|
+
let classified = 0;
|
|
34
|
+
const sectors = new Set<string>();
|
|
35
|
+
for (const asset of assets) {
|
|
36
|
+
const weight = asset.weight ?? asset.size ?? 0;
|
|
37
|
+
total += weight;
|
|
38
|
+
if (asset.sector) {
|
|
39
|
+
classified += weight;
|
|
40
|
+
sectors.add(asset.sector);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (sectors.size < 2 || classified < total / 2) return "flat";
|
|
44
|
+
return industries ? "sector-industry" : "sector";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The move of a set of names weighted by their size (market cap, an ETF's net
|
|
49
|
+
* assets, a position's value), over the names that have both. Null when none do.
|
|
50
|
+
*/
|
|
51
|
+
export function sizeWeightedMove(assets: readonly HeatmapMoveAsset[]): number | null {
|
|
52
|
+
let weight = 0;
|
|
53
|
+
let weightedMove = 0;
|
|
54
|
+
for (const asset of assets) {
|
|
55
|
+
const change = heatmapMove(asset);
|
|
56
|
+
const size = asset.size ?? 0;
|
|
57
|
+
if (change == null || !(size > 0)) continue;
|
|
58
|
+
weight += size;
|
|
59
|
+
weightedMove += change * size;
|
|
60
|
+
}
|
|
61
|
+
return weight > 0 ? weightedMove / weight : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type HeatmapGroupBy = "sector" | "industry";
|
|
65
|
+
|
|
66
|
+
export interface HeatmapGroupSummary {
|
|
67
|
+
/** The sector or industry; null for names the snapshot does not classify, or every name on a flat board. */
|
|
68
|
+
group: string | null;
|
|
69
|
+
/** The industry's sector, when grouping by industry. */
|
|
70
|
+
sector: string | null;
|
|
71
|
+
names: number;
|
|
72
|
+
/** Total size: market cap, or net assets on the ETF board. */
|
|
73
|
+
size: number;
|
|
74
|
+
/** This group's share of the board's total size. */
|
|
75
|
+
share: number;
|
|
76
|
+
move: number | null;
|
|
77
|
+
/** Names with a move, and the size they carry; the rest have no change data yet. */
|
|
78
|
+
moved: number;
|
|
79
|
+
up: number;
|
|
80
|
+
down: number;
|
|
81
|
+
unchanged: number;
|
|
82
|
+
best: { symbol: string; move: number } | null;
|
|
83
|
+
worst: { symbol: string; move: number } | null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function summarize(group: string | null, sector: string | null, assets: readonly HeatmapMoveAsset[], boardSize: number): HeatmapGroupSummary {
|
|
87
|
+
let up = 0;
|
|
88
|
+
let down = 0;
|
|
89
|
+
let unchanged = 0;
|
|
90
|
+
let size = 0;
|
|
91
|
+
let best: HeatmapGroupSummary["best"] = null;
|
|
92
|
+
let worst: HeatmapGroupSummary["worst"] = null;
|
|
93
|
+
for (const asset of assets) {
|
|
94
|
+
size += asset.size ?? 0;
|
|
95
|
+
const move = heatmapMove(asset);
|
|
96
|
+
if (move == null) continue;
|
|
97
|
+
if (move > 0) up += 1;
|
|
98
|
+
else if (move < 0) down += 1;
|
|
99
|
+
else unchanged += 1;
|
|
100
|
+
if (!best || move > best.move) best = { symbol: asset.symbol, move };
|
|
101
|
+
if (!worst || move < worst.move) worst = { symbol: asset.symbol, move };
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
group,
|
|
105
|
+
sector,
|
|
106
|
+
names: assets.length,
|
|
107
|
+
size,
|
|
108
|
+
share: boardSize > 0 ? size / boardSize : 0,
|
|
109
|
+
move: sizeWeightedMove(assets),
|
|
110
|
+
moved: up + down + unchanged,
|
|
111
|
+
up,
|
|
112
|
+
down,
|
|
113
|
+
unchanged,
|
|
114
|
+
best,
|
|
115
|
+
worst,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* One summary per sector or industry, largest first as the board lays them
|
|
121
|
+
* out. A flat board (ETFs) is one group of every name. Unclassified names form
|
|
122
|
+
* their own group last.
|
|
123
|
+
*/
|
|
124
|
+
export function summarizeHeatmapGroups(
|
|
125
|
+
assets: readonly HeatmapMoveAsset[],
|
|
126
|
+
groupBy: HeatmapGroupBy,
|
|
127
|
+
): { grouping: HeatmapGrouping; groups: HeatmapGroupSummary[]; board: HeatmapGroupSummary } {
|
|
128
|
+
const grouping = resolveHeatmapGrouping(assets, groupBy === "industry");
|
|
129
|
+
const boardSize = assets.reduce((sum, asset) => sum + (asset.size ?? 0), 0);
|
|
130
|
+
const board = summarize(null, null, assets, boardSize);
|
|
131
|
+
if (grouping === "flat") return { grouping, groups: [board], board };
|
|
132
|
+
const buckets = new Map<string, { group: string | null; sector: string | null; assets: HeatmapMoveAsset[] }>();
|
|
133
|
+
for (const asset of assets) {
|
|
134
|
+
const sector = asset.sector ?? null;
|
|
135
|
+
const group = sector == null ? null : grouping === "sector-industry" ? asset.industry ?? null : sector;
|
|
136
|
+
const key = `${sector ?? ""}\u0000${group ?? ""}`;
|
|
137
|
+
const bucket = buckets.get(key) ?? { group, sector, assets: [] };
|
|
138
|
+
bucket.assets.push(asset);
|
|
139
|
+
buckets.set(key, bucket);
|
|
140
|
+
}
|
|
141
|
+
const groups = [...buckets.values()]
|
|
142
|
+
.map((bucket) => summarize(bucket.group, grouping === "sector-industry" ? bucket.sector : null, bucket.assets, boardSize))
|
|
143
|
+
.sort((left, right) => Number(left.sector == null && left.group == null) - Number(right.sector == null && right.group == null)
|
|
144
|
+
|| right.size - left.size);
|
|
145
|
+
return { grouping, groups, board };
|
|
146
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { MarketHeatmapAsset, MarketHeatmapUniverseId } from "../../../api-c
|
|
|
3
3
|
import { useAppSelector, usePaneStateValue } from "../../../state/app/context";
|
|
4
4
|
import type { ColumnConfig } from "../../../types/config";
|
|
5
5
|
import type { TickerFinancials } from "../../../types/financials";
|
|
6
|
+
import { getSessionMoveDisplay, type ExtendedSession } from "../../../market-data/market/status";
|
|
6
7
|
import type { TickerRecord } from "../../../types/ticker";
|
|
7
8
|
import { getSortValue, type ColumnContext } from "../portfolio-list/metrics";
|
|
8
9
|
|
|
@@ -36,6 +37,8 @@ export interface HeatmapBoardAsset extends MarketHeatmapAsset {
|
|
|
36
37
|
sizeCurrency?: string;
|
|
37
38
|
/** Treemap area, when it is not `size` itself. */
|
|
38
39
|
weight?: number;
|
|
40
|
+
/** The price and move are this open pre-market or after-hours session's, from the regular close. */
|
|
41
|
+
extendedSession?: ExtendedSession;
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
export interface HeatmapPortfolioPane {
|
|
@@ -48,6 +51,19 @@ export function heatmapTabId(value: string | null | undefined): HeatmapTabId {
|
|
|
48
51
|
return "us-equity";
|
|
49
52
|
}
|
|
50
53
|
|
|
54
|
+
/** Pane state where the pane says which kind of list its portfolio tab shows, for the header to read. */
|
|
55
|
+
export const HEATMAP_COLLECTION_KIND_STATE_KEY = "collectionKind";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Whether Size by changes the board: the market boards and a watchlist, never
|
|
59
|
+
* a portfolio, whose holdings are always sized by position value. Until the
|
|
60
|
+
* pane has said which list its tab shows, the control stays away.
|
|
61
|
+
*/
|
|
62
|
+
export function heatmapSizeByApplies(universe: unknown, collectionKind: unknown): boolean {
|
|
63
|
+
return heatmapTabId(typeof universe === "string" ? universe : null) !== PORTFOLIO_HEATMAP_TAB
|
|
64
|
+
|| collectionKind === "watchlist";
|
|
65
|
+
}
|
|
66
|
+
|
|
51
67
|
export function isRemoteHeatmapUniverse(value: HeatmapTabId): value is MarketHeatmapUniverseId {
|
|
52
68
|
return value !== PORTFOLIO_HEATMAP_TAB;
|
|
53
69
|
}
|
|
@@ -200,16 +216,19 @@ export function buildPortfolioHeatmapAssets({
|
|
|
200
216
|
const symbol = ticker.metadata.ticker;
|
|
201
217
|
const snapshot = financials.get(symbol);
|
|
202
218
|
const quote = snapshot?.quote;
|
|
203
|
-
|
|
219
|
+
// Colored like the market boards: an open extended session's move, else the regular session's.
|
|
220
|
+
const display = getSessionMoveDisplay(quote);
|
|
221
|
+
const price = display != null && Number.isFinite(display.price) ? display.price : null;
|
|
204
222
|
const size = positiveNumber(getSortValue(sizeColumn, ticker, snapshot, context));
|
|
205
|
-
const hasChange =
|
|
223
|
+
const hasChange = display?.changePercent != null && Number.isFinite(display.changePercent);
|
|
206
224
|
return {
|
|
207
225
|
symbol,
|
|
208
226
|
name: quote?.name?.trim() || ticker.metadata.name || symbol,
|
|
209
227
|
price: price ?? 0,
|
|
210
|
-
change:
|
|
211
|
-
changePercent: hasChange ?
|
|
228
|
+
change: display?.change != null && Number.isFinite(display.change) ? display.change : 0,
|
|
229
|
+
changePercent: hasChange ? display.changePercent! : 0,
|
|
212
230
|
hasChange,
|
|
231
|
+
...(display?.session ? { extendedSession: display.session } : {}),
|
|
213
232
|
size,
|
|
214
233
|
weight: size == null ? undefined : kind === "portfolio" ? size : heatmapSizeWeight(size, sizeBy),
|
|
215
234
|
sizeKind: "market-cap",
|
|
@@ -81,6 +81,8 @@ export function createMarketMoversHeadless(
|
|
|
81
81
|
): HeadlessPaneDefinition<"rows"> {
|
|
82
82
|
return {
|
|
83
83
|
shape: "rows",
|
|
84
|
+
// A screener snapshot, not a real-time feed; rows keep the time of their own last price.
|
|
85
|
+
freshness: { status: "delayed" },
|
|
84
86
|
argument: { kind: "none" },
|
|
85
87
|
options: [{
|
|
86
88
|
key: "list",
|
|
@@ -120,6 +120,8 @@ function projectValuationHeadlessBundle(
|
|
|
120
120
|
|
|
121
121
|
export const marketValuationHeadless: HeadlessPaneDefinition<"bundle"> = {
|
|
122
122
|
shape: "bundle",
|
|
123
|
+
// Each indicator row checks its own release schedule and says when it is stale.
|
|
124
|
+
freshness: { status: "not-a-feed", basis: "published statistics" },
|
|
123
125
|
argument: {
|
|
124
126
|
kind: "free-text",
|
|
125
127
|
placeholder: "indicator",
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { apiClient } from "../../../api-client";
|
|
2
|
+
import { ApiRequestError } from "../../../api-client/errors";
|
|
2
3
|
import type { FundMembersPayload, FundChangesPayload, MemberFundsPayload } from "../../../api-client/members";
|
|
3
4
|
import { createPluginCache } from "../../../data/plugin-cache";
|
|
4
5
|
import { cachedCloudResource, loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
|
|
6
|
+
import { coveredFund, notCoveredMessage } from "./model";
|
|
5
7
|
const policy = { staleMs: 60_000, expireMs: 2 * 60 * 60_000 };
|
|
6
8
|
export const fundListCache = createPluginCache<MemberFundsPayload>({ kind: "member-funds", source: "gloom-cloud", schemaVersion: 1, policy });
|
|
7
9
|
export const fundMembersCache = createPluginCache<FundMembersPayload>({ kind: "fund-members", source: "gloom-cloud", schemaVersion: 1, policy });
|
|
@@ -22,12 +24,27 @@ function validateFunds(data: MemberFundsPayload) {
|
|
|
22
24
|
if (!data || !Array.isArray(data.funds) || !data.funds.every((fund) => typeof fund.ticker === "string" && typeof fund.name === "string")) throw new Error("Unreadable covered funds response");
|
|
23
25
|
return data;
|
|
24
26
|
}
|
|
27
|
+
const UNAVAILABLE = "Fund members are not available on this server yet.";
|
|
25
28
|
async function fetchPayload<T>(fetcher: () => Promise<T>, validate: (data: T) => T) {
|
|
26
|
-
try { return validate(await fetcher()); } catch (error) { throw unavailableOnServer(error,
|
|
29
|
+
try { return validate(await fetcher()); } catch (error) { throw unavailableOnServer(error, UNAVAILABLE); }
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A 404 for one fund means either an uncovered fund or a server without the route, and the two read the
|
|
33
|
+
* same. The covered list tells them apart: a fund missing from a readable list is not covered; a list
|
|
34
|
+
* that cannot be read, or that holds the fund, leaves the server-side message.
|
|
35
|
+
*/
|
|
36
|
+
async function fetchFundPayload<T>(fund: string, fetcher: () => Promise<T>, validate: (data: T) => T, client: Client) {
|
|
37
|
+
try { return validate(await fetcher()); } catch (error) {
|
|
38
|
+
if (error instanceof ApiRequestError && error.status === 404) {
|
|
39
|
+
const funds = await fetchFunds(client).then((payload) => payload.funds, () => []);
|
|
40
|
+
if (funds.length && !coveredFund(funds, fund)) throw new Error(notCoveredMessage(fund, funds));
|
|
41
|
+
}
|
|
42
|
+
throw unavailableOnServer(error, UNAVAILABLE);
|
|
43
|
+
}
|
|
27
44
|
}
|
|
28
45
|
export const fetchFunds = (client: Client = apiClient) => fetchPayload(() => client.getMemberFunds(), validateFunds);
|
|
29
|
-
export const fetchMembers = (fund: string, client: Client = apiClient) =>
|
|
30
|
-
export const fetchChanges = (fund: string, client: Client = apiClient) =>
|
|
46
|
+
export const fetchMembers = (fund: string, client: Client = apiClient) => fetchFundPayload(fund, () => client.getFundMembers(fund), validateMembers, client);
|
|
47
|
+
export const fetchChanges = (fund: string, client: Client = apiClient) => fetchFundPayload(fund, () => client.getFundChanges(fund), validateChanges, client);
|
|
31
48
|
export const cachedFunds = () => cachedCloudResource(fundListCache, "list", validateFunds);
|
|
32
49
|
export const loadFunds = (force = false) => loadCloudResource(fundListCache, "list", () => fetchFunds(), { force, validate: validateFunds });
|
|
33
50
|
export const cachedMembers = (fund: string) => cachedCloudResource(fundMembersCache, fund, validateMembers);
|
|
@@ -15,17 +15,19 @@ export const membersHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
|
15
15
|
describe: (args) => args.rawArgument ? `MEMB ${args.rawArgument}` : "Index and ETF members",
|
|
16
16
|
async load(args, context) {
|
|
17
17
|
const input = args.symbols[0] ?? args.rawArgument ?? "";
|
|
18
|
-
if (!input) return { rows: (await fetchFunds(context.apiClient)).funds.map((fund) => ({ ...fund })), columns: [{ key: "ticker", header: "Fund" }, { key: "name", header: "Index" }, { key: "asOf", header: "Holdings as of" }] };
|
|
18
|
+
if (!input) return { freshness: { status: "not-a-feed", basis: "fund holdings files" }, rows: (await fetchFunds(context.apiClient)).funds.map((fund) => ({ ...fund })), columns: [{ key: "ticker", header: "Fund" }, { key: "name", header: "Index" }, { key: "asOf", header: "Holdings as of" }] };
|
|
19
19
|
const fund = canonicalFund(input);
|
|
20
20
|
if (args.options.tab === "changes") {
|
|
21
21
|
const data = await fetchChanges(fund, context.apiClient);
|
|
22
|
-
return { rows: data.changes.map((row) => ({ ...row, reason: changeReason(row) })), columns: [{ key: "effectiveDate", header: "Effective" }, { key: "added", header: "Added" }, { key: "removed", header: "Removed" }, { key: "daysToGo", header: "In days", align: "right" }, { key: "reason", header: "Reason" }],
|
|
22
|
+
return { freshness: { status: "not-a-feed", basis: "index changes" }, rows: data.changes.map((row) => ({ ...row, reason: changeReason(row) })), columns: [{ key: "effectiveDate", header: "Effective" }, { key: "added", header: "Added" }, { key: "removed", header: "Removed" }, { key: "daysToGo", header: "In days", align: "right" }, { key: "reason", header: "Reason" }],
|
|
23
23
|
complete: data.available && !data.stale, metadata: { ...data, changes: undefined } };
|
|
24
24
|
}
|
|
25
25
|
const data = await fetchMembers(fund, context.apiClient);
|
|
26
26
|
const movers = args.options.tab === "movers";
|
|
27
27
|
const rows = memberRows(data.members, movers ? "movers" : "members", "", DEFAULT_SORT).flatMap((row) => row.kind === "item" ? [{ ...row.item }] : []);
|
|
28
|
-
|
|
28
|
+
// Member prices are the pane's 15-minute delayed quotes. As in the pane, the fund's snapshot says
|
|
29
|
+
// whether it is stale; the members' own flags are not what the pane reads.
|
|
30
|
+
return { freshness: { status: data.stale ? "stale" : "delayed", delayMinutes: 15, ignoreStaleFlags: true }, rows, columns: movers ? [...columns.slice(0, 3), { key: "contribution", header: "Contrib. pp", align: "right", format: (value) => percent(value as number | null, "", 3) }] : columns,
|
|
29
31
|
complete: !data.stale && data.aggregate.fresh1D === data.aggregate.total,
|
|
30
32
|
unavailableSymbols: data.members.flatMap((row) => row.symbol && row.changePercent === null ? [row.symbol] : []),
|
|
31
33
|
metadata: { fund: data.fund, asOf: data.asOf, snapshotAsOf: data.snapshotAsOf, aggregate: data.aggregate, stale: data.stale } };
|