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
|
@@ -14,16 +14,6 @@ const contextMenuActionScope = new DesktopContextMenuActionScope(
|
|
|
14
14
|
CONTEXT_MENU_ACTION_TTL_MS,
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
-
export function startElectrobunWindowDrag(): void {
|
|
18
|
-
window.__electrobunInternalBridge?.postMessage(JSON.stringify([
|
|
19
|
-
JSON.stringify({
|
|
20
|
-
type: "message",
|
|
21
|
-
id: "startWindowMove",
|
|
22
|
-
payload: { id: window.__electrobunWindowId },
|
|
23
|
-
}),
|
|
24
|
-
]));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
17
|
export async function showDesktopContextMenu(items: ContextMenuItem[]): Promise<boolean> {
|
|
28
18
|
if (!NATIVE_CONTEXT_MENU_SUPPORTED) return false;
|
|
29
19
|
contextMenuActionScope.clear();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
function postWindowMove(id: "startWindowMove" | "stopWindowMove"): void {
|
|
2
|
+
window.__electrobunInternalBridge?.postMessage(JSON.stringify([
|
|
3
|
+
JSON.stringify({ type: "message", id, payload: { id: window.__electrobunWindowId } }),
|
|
4
|
+
]));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let endWindowMove: (() => void) | null = null;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Moves the window with the pointer until the button comes up. Electrobun
|
|
11
|
+
* stops the move when its native monitor sees the release, but only if the
|
|
12
|
+
* start reached it first: the start goes through the Bun process, and a quick
|
|
13
|
+
* click releases before it lands, leaving the window following the bare
|
|
14
|
+
* pointer until the next click. The release is sent from here too, as
|
|
15
|
+
* Electrobun's own drag regions do; it always arrives after the start.
|
|
16
|
+
*/
|
|
17
|
+
export function startElectrobunWindowDrag(): void {
|
|
18
|
+
// A press whose release never reached the page (it ended outside the window) is over.
|
|
19
|
+
endWindowMove?.();
|
|
20
|
+
postWindowMove("startWindowMove");
|
|
21
|
+
const end = () => {
|
|
22
|
+
window.removeEventListener("mouseup", end, true);
|
|
23
|
+
if (endWindowMove === end) endWindowMove = null;
|
|
24
|
+
postWindowMove("stopWindowMove");
|
|
25
|
+
};
|
|
26
|
+
endWindowMove = end;
|
|
27
|
+
window.addEventListener("mouseup", end, true);
|
|
28
|
+
}
|
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
SESSION_SAVE_DEBOUNCE_MS,
|
|
5
5
|
} from "../../../../state/persist-scheduler";
|
|
6
6
|
import { backendRequest, getElectrobunBackendInitSnapshot } from "../backend-rpc";
|
|
7
|
-
import {
|
|
7
|
+
import { WriteThroughResourceStore } from "../../../../data/memory-resource-store";
|
|
8
|
+
import { isBrokerAccountSnapshotKey } from "../../../../brokers/account-cache";
|
|
8
9
|
|
|
9
10
|
class RemoteSessionStore {
|
|
10
11
|
private snapshot = getElectrobunBackendInitSnapshot()?.sessionSnapshot ?? null;
|
|
@@ -123,9 +124,21 @@ class RemotePluginStateStore {
|
|
|
123
124
|
}
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Caches stay in the view's memory, except broker account snapshots: the Bun
|
|
129
|
+
* process saves those in the cache database, as the terminal does, so a
|
|
130
|
+
* broker portfolio opens with its last known equity and cash.
|
|
131
|
+
*/
|
|
132
|
+
function createViewResourceStore(): WriteThroughResourceStore {
|
|
133
|
+
return new WriteThroughResourceStore(getElectrobunBackendInitSnapshot()?.savedResources ?? [], {
|
|
134
|
+
set: (record) => void backendRequest("resources.set", { record }).catch(() => {}),
|
|
135
|
+
delete: (key) => void backendRequest("resources.delete", { key }).catch(() => {}),
|
|
136
|
+
}, isBrokerAccountSnapshotKey);
|
|
137
|
+
}
|
|
138
|
+
|
|
126
139
|
export class RemotePersistence {
|
|
127
140
|
readonly tickers = {};
|
|
128
|
-
readonly resources =
|
|
141
|
+
readonly resources = createViewResourceStore();
|
|
129
142
|
readonly pluginState = new RemotePluginStateStore(getElectrobunBackendInitSnapshot()?.pluginState ?? {});
|
|
130
143
|
readonly sessions = new RemoteSessionStore();
|
|
131
144
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { getCloudApiBaseUrl } from "../../../api-client/request";
|
|
2
|
+
import { RpcTimeoutError } from "../../../utils/rpc-timeout-error";
|
|
2
3
|
import type { DesktopBackendRequestMethod } from "../shared/protocol";
|
|
3
4
|
|
|
5
|
+
/** How long the view waits for the Bun process to answer one request. */
|
|
6
|
+
export const RPC_MAX_REQUEST_TIME_MS = 120_000;
|
|
7
|
+
|
|
4
8
|
/** What Electrobun's request timer rejects with: no method, request id or caller. */
|
|
5
9
|
const ELECTROBUN_REQUEST_TIMEOUT_MESSAGE = "RPC request timed out.";
|
|
6
10
|
|
|
@@ -16,7 +20,9 @@ const ELECTROBUN_REQUEST_TIMEOUT_MESSAGE = "RPC request timed out.";
|
|
|
16
20
|
* from the user's config (a broker gateway, a feed, a plugin endpoint) and is
|
|
17
21
|
* only called external. Never the payload, rest of the path, query or headers.
|
|
18
22
|
* Elapsed time is rounded to 10 s because crash reports are deduplicated per
|
|
19
|
-
* session on the message.
|
|
23
|
+
* session on the message. The error keeps its message and `Error` type, and
|
|
24
|
+
* carries the elapsed time so a timer that fired long after its limit (the
|
|
25
|
+
* machine slept) can be told from a request that really stalled.
|
|
20
26
|
*/
|
|
21
27
|
export async function nameRpcTimeout<T>(
|
|
22
28
|
method: DesktopBackendRequestMethod,
|
|
@@ -28,8 +34,13 @@ export async function nameRpcTimeout<T>(
|
|
|
28
34
|
return await request();
|
|
29
35
|
} catch (error) {
|
|
30
36
|
if (!(error instanceof Error) || error.message !== ELECTROBUN_REQUEST_TIMEOUT_MESSAGE) throw error;
|
|
31
|
-
const
|
|
32
|
-
|
|
37
|
+
const elapsedMs = performance.now() - startedAt;
|
|
38
|
+
const seconds = Math.round(elapsedMs / 10_000) * 10;
|
|
39
|
+
throw new RpcTimeoutError(`RPC request timed out: ${describeRequest(method, payload)} after ~${seconds}s`, {
|
|
40
|
+
elapsedMs,
|
|
41
|
+
limitMs: RPC_MAX_REQUEST_TIME_MS,
|
|
42
|
+
cause: error,
|
|
43
|
+
});
|
|
33
44
|
}
|
|
34
45
|
}
|
|
35
46
|
|
|
@@ -2,11 +2,8 @@
|
|
|
2
2
|
import type { RendererHost, UiHost } from "../../../ui/host";
|
|
3
3
|
import { flushUsageCounts } from "../../../telemetry/usage-counts";
|
|
4
4
|
import { backendRequest } from "./backend-rpc";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
showDesktopContextMenu,
|
|
8
|
-
startElectrobunWindowDrag,
|
|
9
|
-
} from "./host/native";
|
|
5
|
+
import { NATIVE_CONTEXT_MENU_SUPPORTED, showDesktopContextMenu } from "./host/native";
|
|
6
|
+
import { startElectrobunWindowDrag } from "./host/window-move";
|
|
10
7
|
import { createDomUiHost } from "../../dom/dom-ui-host";
|
|
11
8
|
|
|
12
9
|
export function createWebUiHost(desktopPlatform?: string): UiHost {
|
|
@@ -108,6 +108,11 @@ export async function createOpenTuiHost(): Promise<OpenTuiHost> {
|
|
|
108
108
|
enableMouseMovement: true,
|
|
109
109
|
});
|
|
110
110
|
const root = createRoot(renderer);
|
|
111
|
+
// Every mounted ScrollBox listens for `selection` and many components for
|
|
112
|
+
// `resize`, so the counts grow with the panes on screen (14 and 18 with one
|
|
113
|
+
// DES open at 80x24) and fall back when they close. Node's default warning
|
|
114
|
+
// at 11 is not a leak here, and it prints over the panes.
|
|
115
|
+
renderer.setMaxListeners(0);
|
|
111
116
|
installResolutionEventBridge(renderer);
|
|
112
117
|
// Streamed quotes apply and notify on one clock of up to 10 Hz: every
|
|
113
118
|
// visible row stays live while a burst of ticks costs one terminal redraw,
|
|
@@ -2,6 +2,7 @@ import { RGBA, StyledText as OpenTuiStyledText, SyntaxStyle, TextAttributes as O
|
|
|
2
2
|
import { createElement, forwardRef, useEffect, useRef, useState, type ReactNode } from "react";
|
|
3
3
|
import { TextAttributes, type UiHost, type TextProps } from "../../ui/host";
|
|
4
4
|
import { renderAsciiText } from "../../ui/ascii-font";
|
|
5
|
+
import { scrollBoxScrollsVertically } from "../../ui/scroll-box-axis";
|
|
5
6
|
import { OpenTuiImageSurface } from "./image/surface";
|
|
6
7
|
import { OpenTuiChartSurface } from "./chart-surface";
|
|
7
8
|
|
|
@@ -141,7 +142,12 @@ function mapTextContent(content: unknown): unknown {
|
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
const OpenTuiBox = createOpenTuiPrimitive("box");
|
|
144
|
-
const
|
|
145
|
+
const OpenTuiScrollBoxPrimitive = createOpenTuiPrimitive("scrollbox");
|
|
146
|
+
// The native box scrolls vertically unless scrollY is false; the shared rule
|
|
147
|
+
// also keeps the one-row horizontal strips from scrolling on that axis.
|
|
148
|
+
const OpenTuiScrollBox = forwardRef<unknown, OpenTuiPrimitiveProps>(function OpenTuiScrollBox(props, ref) {
|
|
149
|
+
return createElement(OpenTuiScrollBoxPrimitive, { ...props, scrollY: scrollBoxScrollsVertically(props), ref });
|
|
150
|
+
});
|
|
145
151
|
const OpenTuiInput = createOpenTuiPrimitive("input");
|
|
146
152
|
const OpenTuiTextarea = createOpenTuiPrimitive("textarea");
|
|
147
153
|
const OpenTuiMediaSurface = createOpenTuiPrimitive("box");
|
|
@@ -40,6 +40,8 @@ import { resolveCurrencyUnit } from "../../utils/currency-units";
|
|
|
40
40
|
import { canonicalExchange, canonicalTickerKey, parsePublicTickerKey } from "../../utils/exchanges";
|
|
41
41
|
import { normalizePriceHistory, priceHistoryIntervalMs, reachesLatestSettledSession } from "../../utils/price-history";
|
|
42
42
|
import { createProviderMiss } from "../provider-errors";
|
|
43
|
+
import { assertSecRegistrantMatches } from "../sec-registrant";
|
|
44
|
+
import { nonUsSecListingVenue } from "../../utils/sec";
|
|
43
45
|
import { publicListingTarget } from "../listing-target";
|
|
44
46
|
import { canonicalHistoryInterval, HistoryRetentionError, parseHistoryRecoveryCandidate, parseHistoryRetention, type HistoryRetention } from "../history-retention";
|
|
45
47
|
import { getRouterEntityKey } from "../provider-router/cache";
|
|
@@ -195,7 +197,7 @@ function mapCloudPriceHistory(
|
|
|
195
197
|
`Cloud chart data is unavailable for ${ticker}`,
|
|
196
198
|
).map((point) => mapPricePoint(point, divisor, exchange)),
|
|
197
199
|
);
|
|
198
|
-
if (stale && !reachesLatestSettledSession(points, Date.now(), { exchange, intervalMs: priceHistoryIntervalMs(interval) })) {
|
|
200
|
+
if (stale && !reachesLatestSettledSession(points, Date.now(), { symbol: ticker, exchange, intervalMs: priceHistoryIntervalMs(interval) })) {
|
|
199
201
|
throw createProviderMiss(`Cloud chart data is stale for ${ticker}`);
|
|
200
202
|
}
|
|
201
203
|
if (
|
|
@@ -486,11 +488,30 @@ export class GloomberbCloudProvider implements AssetDataProvider {
|
|
|
486
488
|
);
|
|
487
489
|
}
|
|
488
490
|
|
|
489
|
-
async getSecFilings(ticker: string, count = 15): Promise<SecFilingItem[]> {
|
|
490
|
-
|
|
491
|
-
|
|
491
|
+
async getSecFilings(ticker: string, count = 15, exchange?: string, context?: MarketDataRequestContext): Promise<SecFilingItem[]> {
|
|
492
|
+
const venue = nonUsSecListingVenue(ticker, exchange);
|
|
493
|
+
const name = venue ? context?.listingName?.trim() || await this.listingName(ticker, venue) || undefined : undefined;
|
|
494
|
+
const filings = await withCloudFallback(async () => {
|
|
495
|
+
const response = await apiClient.getCloudSecFilings({ ticker, exchange, name, limit: count, offset: 0 });
|
|
492
496
|
return response.filings.map(mapCloudSecFiling);
|
|
493
497
|
}, `Cloud SEC filings are unavailable for ${ticker}`);
|
|
498
|
+
if (!venue || filings.length === 0) return filings;
|
|
499
|
+
const symbol = parsePublicTickerKey(ticker).symbol;
|
|
500
|
+
// Without the listing's company the filings cannot be told apart from another company's.
|
|
501
|
+
if (!name) throw createProviderMiss(`SEC filings for ${symbol} could not be matched to its ${venue} listing`);
|
|
502
|
+
assertSecRegistrantMatches(filings, { symbol, exchange: venue, name });
|
|
503
|
+
return filings;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** The company a listing belongs to, from its own quote; null when the quote prices another venue. */
|
|
507
|
+
private async listingName(ticker: string, venue: string): Promise<string | null> {
|
|
508
|
+
try {
|
|
509
|
+
const quote = await this.getQuote(ticker, venue);
|
|
510
|
+
const quoteVenue = canonicalExchange(quote.listingExchangeName || quote.exchangeName);
|
|
511
|
+
return quoteVenue === venue ? quote.name?.trim() || null : null;
|
|
512
|
+
} catch {
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
494
515
|
}
|
|
495
516
|
|
|
496
517
|
async getSecFilingDocuments(filing: SecFilingItem): Promise<SecFilingDocument[]> {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { futuresGenericListing, futuresGenericPriceBasis } from "../../utils/futures-generic";
|
|
2
2
|
import type { TimeRange } from "../../time-series/range";
|
|
3
|
+
import { RANGE_HISTORY_RESOLUTION } from "../../time-series/resolution";
|
|
3
4
|
import type {
|
|
4
5
|
FinancialStatement,
|
|
5
6
|
Fundamentals,
|
|
@@ -36,6 +37,24 @@ function cloudInternalProviderId(providerMeta?: CloudProviderMeta): string | nul
|
|
|
36
37
|
return upstream ? `${GLOOMBERB_CLOUD_PROVIDER_ID}:${upstream}` : null;
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
* A previous close is a price from inside the trailing 52 weeks, so it cannot
|
|
42
|
+
* sit far below the 52-week low. The service has sent 0.000205 as the
|
|
43
|
+
* Shanghai Composite's close (52-week low 3,741), which drew a +1.86e9% move.
|
|
44
|
+
* Today's price plays no part, so a real gap of any size still shows; two
|
|
45
|
+
* orders of magnitude leave room for a 52-week low that lags a crash or a split.
|
|
46
|
+
*/
|
|
47
|
+
const IMPOSSIBLE_CLOSE_FACTOR = 100;
|
|
48
|
+
|
|
49
|
+
function isImpossiblePreviousClose(
|
|
50
|
+
previousClose: number | null | undefined,
|
|
51
|
+
low52w: number | null | undefined,
|
|
52
|
+
): boolean {
|
|
53
|
+
return typeof previousClose === "number" && Number.isFinite(previousClose) && previousClose > 0
|
|
54
|
+
&& typeof low52w === "number" && Number.isFinite(low52w) && low52w > 0
|
|
55
|
+
&& previousClose * IMPOSSIBLE_CLOSE_FACTOR < low52w;
|
|
56
|
+
}
|
|
57
|
+
|
|
39
58
|
export function mapQuote(
|
|
40
59
|
quote: CloudQuotePayload,
|
|
41
60
|
providerMeta?: CloudProviderMeta,
|
|
@@ -50,10 +69,11 @@ export function mapQuote(
|
|
|
50
69
|
quote.fullExchangeName ??
|
|
51
70
|
listingExchangeName;
|
|
52
71
|
const internalProviderId = cloudInternalProviderId(providerMeta);
|
|
53
|
-
const
|
|
72
|
+
const impossibleClose = isImpossiblePreviousClose(quote.previousClose, quote.low52w);
|
|
73
|
+
const change = !impossibleClose && typeof quote.change === "number" && Number.isFinite(quote.change)
|
|
54
74
|
? quote.change / divisor
|
|
55
75
|
: Number.NaN;
|
|
56
|
-
const changePercent = typeof quote.changePercent === "number" && Number.isFinite(quote.changePercent)
|
|
76
|
+
const changePercent = !impossibleClose && typeof quote.changePercent === "number" && Number.isFinite(quote.changePercent)
|
|
57
77
|
? quote.changePercent
|
|
58
78
|
: Number.NaN;
|
|
59
79
|
// A generic future (VX1, TY1) reads in points or 32nds, not dollars.
|
|
@@ -70,8 +90,13 @@ export function mapQuote(
|
|
|
70
90
|
price: normalizePriceValueByDivisor(quote.price, divisor) ?? quote.price,
|
|
71
91
|
change,
|
|
72
92
|
changePercent,
|
|
73
|
-
previousClose: normalizePriceValueByDivisor(quote.previousClose, divisor),
|
|
93
|
+
previousClose: impossibleClose ? undefined : normalizePriceValueByDivisor(quote.previousClose, divisor),
|
|
74
94
|
regularClose: normalizePriceValueByDivisor(quote.regularClose, divisor),
|
|
95
|
+
// JSON carries an unavailable move as null; the percent is unitless.
|
|
96
|
+
regularChange: normalizePriceValueByDivisor(quote.regularChange ?? undefined, divisor),
|
|
97
|
+
regularChangePercent: typeof quote.regularChangePercent === "number" && Number.isFinite(quote.regularChangePercent)
|
|
98
|
+
? quote.regularChangePercent
|
|
99
|
+
: undefined,
|
|
75
100
|
high52w: normalizePriceValueByDivisor(quote.high52w, divisor),
|
|
76
101
|
low52w: normalizePriceValueByDivisor(quote.low52w, divisor),
|
|
77
102
|
bid: normalizePriceValueByDivisor(quote.bid, divisor),
|
|
@@ -346,29 +371,24 @@ export function formatCloudDateTime(
|
|
|
346
371
|
return `${year}-${month}-${day}`;
|
|
347
372
|
}
|
|
348
373
|
|
|
374
|
+
const HISTORY_OUTPUT_SIZE: Record<TimeRange, number> = {
|
|
375
|
+
"1D": 24 * 12,
|
|
376
|
+
"1W": 7 * 24,
|
|
377
|
+
"1M": 31,
|
|
378
|
+
"3M": 93,
|
|
379
|
+
"6M": 186,
|
|
380
|
+
"1Y": 366,
|
|
381
|
+
"5Y": 261,
|
|
382
|
+
"ALL": 600,
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
/** The bar size comes from the shared range table, which `gloomberb help history` also lists. */
|
|
349
386
|
export function toHistoryRequest(range: TimeRange): {
|
|
350
387
|
interval: string;
|
|
351
388
|
outputsize: number;
|
|
352
389
|
rangeKey: TimeRange;
|
|
353
390
|
} {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
case "1W":
|
|
358
|
-
return { interval: "1h", outputsize: 7 * 24, rangeKey: range };
|
|
359
|
-
case "1M":
|
|
360
|
-
return { interval: "1day", outputsize: 31, rangeKey: range };
|
|
361
|
-
case "3M":
|
|
362
|
-
return { interval: "1day", outputsize: 93, rangeKey: range };
|
|
363
|
-
case "6M":
|
|
364
|
-
return { interval: "1day", outputsize: 186, rangeKey: range };
|
|
365
|
-
case "1Y":
|
|
366
|
-
return { interval: "1day", outputsize: 366, rangeKey: range };
|
|
367
|
-
case "5Y":
|
|
368
|
-
return { interval: "1week", outputsize: 261, rangeKey: range };
|
|
369
|
-
case "ALL":
|
|
370
|
-
return { interval: "1month", outputsize: 600, rangeKey: range };
|
|
371
|
-
default:
|
|
372
|
-
return { interval: "1day", outputsize: 366, rangeKey: range };
|
|
373
|
-
}
|
|
391
|
+
const resolution = RANGE_HISTORY_RESOLUTION[range];
|
|
392
|
+
if (!resolution) return { interval: "1day", outputsize: 366, rangeKey: range };
|
|
393
|
+
return { interval: toCloudInterval(resolution), outputsize: HISTORY_OUTPUT_SIZE[range], rangeKey: range };
|
|
374
394
|
}
|
|
@@ -66,7 +66,7 @@ export class ProviderRouterBatchRoutes {
|
|
|
66
66
|
const rawCached = selectCachedResource<Quote>(this.deps.resources, "quote", entityKey, variantKeys, sourceKeys, false);
|
|
67
67
|
const cached = rawCached && (brokerSourceKeys.includes(rawCached.sourceKey)
|
|
68
68
|
? !isQuoteStaleForCurrentSession(quoteWithFreshnessExchange(rawCached.value, target.exchange))
|
|
69
|
-
: isProviderQuoteUsableForCurrentSession(rawCached.value, target.exchange, target.symbol))
|
|
69
|
+
: isProviderQuoteUsableForCurrentSession(rawCached.value, target.exchange, target.symbol, { recentAnswer: !rawCached.stale }))
|
|
70
70
|
? rawCached
|
|
71
71
|
: null;
|
|
72
72
|
if (cached && !forceRefresh && !cached.stale) {
|
|
@@ -93,7 +93,7 @@ export class ProviderRouterBatchRoutes {
|
|
|
93
93
|
const uniqueTargets = [...providerIndexes.values()].map((bucket) => bucket[0]!.target);
|
|
94
94
|
const batchResults = await batchProvider.getQuotesBatch!(uniqueTargets, options).catch(() => []);
|
|
95
95
|
for (const item of batchResults) {
|
|
96
|
-
if (!isProviderQuoteUsableForCurrentSession(item.quote, item.target.exchange, item.target.symbol)) continue;
|
|
96
|
+
if (!isProviderQuoteUsableForCurrentSession(item.quote, item.target.exchange, item.target.symbol, { recentAnswer: true })) continue;
|
|
97
97
|
const key = this.quoteBatchKey(item.target);
|
|
98
98
|
const sourceKey = this.deps.providerSourceKey(batchProvider);
|
|
99
99
|
for (const entry of providerIndexes.get(key) ?? []) {
|
|
@@ -162,7 +162,7 @@ export class ProviderRouterBatchRoutes {
|
|
|
162
162
|
const key = this.cachedFinancialsBatchKey(item.target);
|
|
163
163
|
let value = resolveTickerFinancialsQuoteState(normalizeTickerFinancialsPriceHistory(item.financials));
|
|
164
164
|
if (value && !item.target.instrument && !providerFinancialsMatchTarget(value, item.target.symbol, item.target.exchange)) continue;
|
|
165
|
-
if (value) value = dropUnusableProviderQuote(value, item.target.exchange);
|
|
165
|
+
if (value) value = dropUnusableProviderQuote(value, item.target.exchange, { recentAnswer: true });
|
|
166
166
|
if (!value) continue;
|
|
167
167
|
const sourceKey = this.deps.providerSourceKey(batchProvider);
|
|
168
168
|
for (const entry of providerIndexes.get(key) ?? []) {
|
|
@@ -3,6 +3,7 @@ import { CachedQuery, type CachedValue } from "../../data/cached-query";
|
|
|
3
3
|
import type { CachedAssetArgs, CachedAssetMethod, CachedAssetValue, DataProvider, MarketDataRequestContext, SecFilingItem } from "../../types/data-provider";
|
|
4
4
|
import type { AnalystResearchData, CorporateActionsData, HolderData } from "../../types/financials";
|
|
5
5
|
import { canonicalExchange } from "../../utils/exchanges";
|
|
6
|
+
import { nonUsSecListingVenue } from "../../utils/sec";
|
|
6
7
|
import { shouldLogProviderError } from "../provider-errors";
|
|
7
8
|
import { hasBrokerContext, withBrokerTimeout } from "./brokers";
|
|
8
9
|
import { publicListingExchange } from "../listing-target";
|
|
@@ -220,9 +221,11 @@ export class ProviderRouterCachedRoutes {
|
|
|
220
221
|
};
|
|
221
222
|
case "getSecFilings": {
|
|
222
223
|
const [symbol, count = 15, listingExchange, requestContext] = args as CachedAssetArgs<"getSecFilings">;
|
|
224
|
+
const exact = buildVariantKey([["exchange", canonicalExchange(listingExchange)], ["count", count]]);
|
|
223
225
|
return {
|
|
224
226
|
kind: "sec-filings", policy: "secFilings", entityKey: this.deps.getEntityKey(symbol, requestContext?.instrument),
|
|
225
|
-
|
|
227
|
+
// A non-US listing never reads the bare symbol's filings: SAN in Paris is Sanofi, SAN at the SEC is Santander.
|
|
228
|
+
variants: nonUsSecListingVenue(symbol, listingExchange) ? [exact] : [...new Set([exact, buildVariantKey([["count", count]]), ""])],
|
|
226
229
|
request: (provider, force) => provider.getSecFilings?.(symbol, count, listingExchange, force ? { ...requestContext, cacheMode: "refresh" } : requestContext),
|
|
227
230
|
throwLastError: true, error: `No SEC filings provider available for ${symbol}`,
|
|
228
231
|
};
|
|
@@ -200,7 +200,7 @@ export class ProviderRouterFinancialRoutes {
|
|
|
200
200
|
const rawCached = selectCachedResource<Quote>(this.deps.resources, "quote", entityKey, variantKeys, sourceKeys, false);
|
|
201
201
|
const cachedIsStale = rawCached && (brokerSourceKeys.includes(rawCached.sourceKey)
|
|
202
202
|
? isQuoteContributionStaleForCurrentSession(quoteWithFreshnessExchange(rawCached.value, exchange))
|
|
203
|
-
: !isProviderQuoteUsableForCurrentSession(rawCached.value, exchange, ticker));
|
|
203
|
+
: !isProviderQuoteUsableForCurrentSession(rawCached.value, exchange, ticker, { recentAnswer: !rawCached.stale }));
|
|
204
204
|
const cached = rawCached && !cachedIsStale
|
|
205
205
|
? rawCached
|
|
206
206
|
: null;
|
|
@@ -259,7 +259,7 @@ export class ProviderRouterFinancialRoutes {
|
|
|
259
259
|
if (
|
|
260
260
|
record
|
|
261
261
|
&& (includeStale || !record.stale)
|
|
262
|
-
&& isProviderQuoteUsableForCurrentSession(record.value, exchange, ticker)
|
|
262
|
+
&& isProviderQuoteUsableForCurrentSession(record.value, exchange, ticker, { recentAnswer: !record.stale })
|
|
263
263
|
) {
|
|
264
264
|
return record.value;
|
|
265
265
|
}
|
|
@@ -7,7 +7,16 @@ import { redactUnavailableFundamentals, RETRACTABLE_VALUATION_FIELDS } from "../
|
|
|
7
7
|
import { isExtendedHoursExchange, isQuoteStaleForCurrentSession } from "../../market-data/quotes/freshness";
|
|
8
8
|
import { mergeQuoteMetadata, quoteMetadataFromQuote, quoteMetadataMatchesTarget } from "../../market-data/quotes/metadata";
|
|
9
9
|
import { parsePublicTickerKey } from "../../utils/exchanges";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
activeUsMarketSession,
|
|
12
|
+
delayedFeedLagMs,
|
|
13
|
+
isMiddayBreakPrint,
|
|
14
|
+
isRegularSessionTime,
|
|
15
|
+
isUsPostSessionPrint,
|
|
16
|
+
isUsPriorSessionPremarketQuote,
|
|
17
|
+
isUsRegularCloseQuoteInPostSession,
|
|
18
|
+
latestRegularSessionOpen,
|
|
19
|
+
} from "../../market-data/market/freshness";
|
|
11
20
|
import {
|
|
12
21
|
mergeQuoteContributionMaps,
|
|
13
22
|
isQuoteContributionStaleForCurrentSession,
|
|
@@ -122,21 +131,62 @@ function isQuoteInActiveSession(quote: Quote, now: number): boolean {
|
|
|
122
131
|
return false;
|
|
123
132
|
}
|
|
124
133
|
|
|
125
|
-
|
|
134
|
+
// An opening auction can print before the continuous open (Hong Kong's at 09:20).
|
|
135
|
+
const OPENING_AUCTION_MS = 15 * 60_000;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Whether Gloom Cloud vouches that a delayed quote is current, however long
|
|
139
|
+
* ago its last trade was. The service judges more than that trade's age: it
|
|
140
|
+
* knows when it asked for the quote and how often the listing trades, so a
|
|
141
|
+
* thinly traded listing's hour-old trade can be the current price while its
|
|
142
|
+
* venue trades. Its verdict stands in for the age bound when:
|
|
143
|
+
* - the service answered on this request, or a cache entry still inside its
|
|
144
|
+
* TTL holds that answer (`recentAnswer`); a copy past the TTL is not vouched for;
|
|
145
|
+
* - the answer says `stale: false`. One without the flag vouches for nothing,
|
|
146
|
+
* and one flagged stale never gets this far;
|
|
147
|
+
* - the quote is delayed. The service bounds a delayed quote's feed age itself
|
|
148
|
+
* but not a real-time one's, so real-time quotes keep the age bound;
|
|
149
|
+
* - it reports the regular session, the venue's session is in progress as
|
|
150
|
+
* the delayed feed shows it, and the trade belongs to that session; or it
|
|
151
|
+
* reports a US after-hours price, the after-hours session is in progress and
|
|
152
|
+
* the trade belongs to it.
|
|
153
|
+
* The answer says nothing about how often a listing trades, so a liquid
|
|
154
|
+
* listing the service wrongly vouches for is accepted too. The service's own
|
|
155
|
+
* bound for liquid listings, about twenty minutes, is tighter than this one.
|
|
156
|
+
*/
|
|
157
|
+
function isVouchedCurrentByService(quote: Quote, exchange: string | undefined, now: number): boolean {
|
|
158
|
+
if (quote.providerId !== "gloomberb-cloud" || quote.stale !== false || quote.dataSource !== "delayed") return false;
|
|
159
|
+
if (quote.marketState === "POST") {
|
|
160
|
+
return finitePositiveNumber(quote.postMarketPrice) && isUsPostSessionPrint(quote.lastUpdated, exchange, now);
|
|
161
|
+
}
|
|
162
|
+
if (quote.marketState !== "REGULAR") return false;
|
|
163
|
+
const feedTime = now - delayedFeedLagMs(exchange);
|
|
164
|
+
if (isRegularSessionTime(exchange, feedTime) !== true) return false;
|
|
165
|
+
const open = latestRegularSessionOpen(exchange, feedTime);
|
|
166
|
+
return open != null && quote.lastUpdated >= open - OPENING_AUCTION_MS;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function isActiveProviderQuoteTooOld(quote: Quote, now = Date.now(), recentAnswer = false): boolean {
|
|
126
170
|
// The shared freshness predicate already validates and dates a daily NAV.
|
|
127
171
|
if (quote.priceObservation === "nav") return false;
|
|
128
172
|
if (!isQuoteInActiveSession(quote, now)) return false;
|
|
129
173
|
// A prior-session close before any pre-market trade has no in-session print
|
|
130
174
|
// to age; the session-date rules bound it instead.
|
|
131
|
-
|
|
175
|
+
const exchange = quote.listingExchangeName || quote.exchangeName;
|
|
176
|
+
if (isUsPriorSessionPremarketQuote(quote.lastUpdated, exchange, quote.marketState, now)) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
// Likewise today's regular close before any after-hours trade.
|
|
180
|
+
if (quote.postMarketPrice == null && isUsRegularCloseQuoteInPostSession(quote.lastUpdated, exchange, quote.marketState, now)) {
|
|
132
181
|
return false;
|
|
133
182
|
}
|
|
134
183
|
if (!Number.isFinite(quote.lastUpdated)) return false;
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
184
|
+
const delayed = quote.dataSource === "delayed";
|
|
185
|
+
const maxAge = delayed ? ACTIVE_DELAYED_PROVIDER_QUOTE_MAX_AGE_MS : ACTIVE_PROVIDER_QUOTE_MAX_AGE_MS;
|
|
186
|
+
if (now - quote.lastUpdated <= maxAge) return false;
|
|
187
|
+
// While the venue pauses at midday, the morning's last print is the current price.
|
|
188
|
+
if (isMiddayBreakPrint(quote.lastUpdated, exchange, now, delayed ? delayedFeedLagMs(exchange) : 0)) return false;
|
|
189
|
+
return !(recentAnswer && isVouchedCurrentByService(quote, exchange, now));
|
|
140
190
|
}
|
|
141
191
|
|
|
142
192
|
export function providerQuoteMatchesTarget(quote: Quote | null | undefined, symbol?: string, exchange?: string): quote is Quote {
|
|
@@ -156,11 +206,21 @@ export function providerQuoteMatchesTarget(quote: Quote | null | undefined, symb
|
|
|
156
206
|
return true;
|
|
157
207
|
}
|
|
158
208
|
|
|
159
|
-
|
|
209
|
+
/**
|
|
210
|
+
* `recentAnswer`: the source answered with this quote on this request, or a
|
|
211
|
+
* cache entry still inside its TTL holds it. Only then can the source's own
|
|
212
|
+
* verdict on a delayed quote stand in for the age bound.
|
|
213
|
+
*/
|
|
214
|
+
export function isProviderQuoteUsableForCurrentSession(
|
|
215
|
+
quote: Quote | null | undefined,
|
|
216
|
+
exchange?: string,
|
|
217
|
+
symbol?: string,
|
|
218
|
+
options: { recentAnswer?: boolean } = {},
|
|
219
|
+
): quote is Quote {
|
|
160
220
|
if (!providerQuoteMatchesTarget(quote, symbol, exchange)) return false;
|
|
161
221
|
const normalized = quoteWithFreshnessExchange(quote, exchange);
|
|
162
222
|
if (isQuoteStaleForCurrentSession(normalized)) return false;
|
|
163
|
-
if (isActiveProviderQuoteTooOld(normalized)) return false;
|
|
223
|
+
if (isActiveProviderQuoteTooOld(normalized, Date.now(), options.recentAnswer === true)) return false;
|
|
164
224
|
// Futures may trade or settle at zero or negative prices. Require explicit
|
|
165
225
|
// source type metadata; an alias alone cannot establish the price domain.
|
|
166
226
|
const futures = ["FUT", "FUTURE", "FUTURES"].includes(normalized.instrumentType?.trim().toUpperCase() ?? "");
|
|
@@ -187,8 +247,12 @@ export function providerFinancialsMatchTarget(value: TickerFinancials, symbol: s
|
|
|
187
247
|
return quoteMetadataMatchesTarget(metadata, hasListing ? symbol : parsePublicTickerKey(symbol).symbol, hasListing ? exchange : undefined);
|
|
188
248
|
}
|
|
189
249
|
|
|
190
|
-
export function dropUnusableProviderQuote(
|
|
191
|
-
|
|
250
|
+
export function dropUnusableProviderQuote(
|
|
251
|
+
value: TickerFinancials,
|
|
252
|
+
exchange?: string,
|
|
253
|
+
options: { recentAnswer?: boolean } = {},
|
|
254
|
+
): TickerFinancials {
|
|
255
|
+
if (!value.quote || isProviderQuoteUsableForCurrentSession(value.quote, exchange, undefined, options)) {
|
|
192
256
|
return value;
|
|
193
257
|
}
|
|
194
258
|
|
|
@@ -19,6 +19,7 @@ import { subtractTimeRange } from "../../time-series/date-window";
|
|
|
19
19
|
import { clipPriceHistoryToRange } from "../../time-series/history-window";
|
|
20
20
|
import { repairIsolatedIntradayOhlcOutliers } from "../../time-series/history-quality";
|
|
21
21
|
import { canonicalExchange, parsePublicTickerKey, resolveExchangeTimeZone } from "../../utils/exchanges";
|
|
22
|
+
import { isRoundTheClockCoin } from "../../utils/crypto-pair";
|
|
22
23
|
import { zonedDateKey } from "../../utils/zoned-date-time";
|
|
23
24
|
import { resolvePriceHistoryCurrencyUnit } from "../../utils/currency-units";
|
|
24
25
|
import { calendarHistoryFetchState, calendarHistoryLastBarDate, dropLeadingPlaceholderBars, getPricePointTimestamp, hasUsablePriceHistory, preservePriceHistoryGaps, isPriceHistoryStaleForCurrentWindow, normalizePriceHistory, priceHistoryIntervalMs, type CalendarHistoryFetchState } from "../../utils/price-history";
|
|
@@ -245,9 +246,9 @@ function normalizeRequestResult(value: PriceHistoryResult, request: HistoryReque
|
|
|
245
246
|
};
|
|
246
247
|
}
|
|
247
248
|
|
|
248
|
-
function resultIsStale(value: PriceHistoryResult, exchange: string, intervalMs?: number | null): boolean {
|
|
249
|
+
function resultIsStale(value: PriceHistoryResult, symbol: string, exchange: string, intervalMs?: number | null): boolean {
|
|
249
250
|
return isPriceHistoryStaleForCurrentWindow(value.points, Date.now(), {
|
|
250
|
-
exchange, intervalMs: intervalMs ?? (value.resolution ? priceHistoryIntervalMs(value.resolution) : undefined), session: value.session,
|
|
251
|
+
symbol, exchange, intervalMs: intervalMs ?? (value.resolution ? priceHistoryIntervalMs(value.resolution) : undefined), session: value.session,
|
|
251
252
|
});
|
|
252
253
|
}
|
|
253
254
|
|
|
@@ -342,8 +343,8 @@ export class ProviderRouterHistoryRoutes {
|
|
|
342
343
|
context,
|
|
343
344
|
cachePolicyKey: intraday ? "priceHistoryIntraday" : "priceHistoryDaily",
|
|
344
345
|
missingProviderError: `No history provider available for ${ticker}`,
|
|
345
|
-
isCachedValueStale: (value) => intraday && resultIsStale(value, exchange),
|
|
346
|
-
isFetchedValueStale: (value) => intraday && resultIsStale(value, exchange),
|
|
346
|
+
isCachedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange),
|
|
347
|
+
isFetchedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange),
|
|
347
348
|
fetchBroker: async (candidate) => candidate.broker.getPriceHistory
|
|
348
349
|
? candidate.broker.getPriceHistory(
|
|
349
350
|
ticker,
|
|
@@ -399,8 +400,8 @@ export class ProviderRouterHistoryRoutes {
|
|
|
399
400
|
context,
|
|
400
401
|
cachePolicyKey: intraday ? "priceHistoryIntraday" : "priceHistoryDaily",
|
|
401
402
|
missingProviderError: `No resolution-aware history provider available for ${ticker}`,
|
|
402
|
-
isCachedValueStale: (value) => intraday && resultIsStale(value, exchange, intervalMs),
|
|
403
|
-
isFetchedValueStale: (value) => intraday && resultIsStale(value, exchange, intervalMs),
|
|
403
|
+
isCachedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange, intervalMs),
|
|
404
|
+
isFetchedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange, intervalMs),
|
|
404
405
|
fetchBroker: async (candidate) => candidate.broker.getPriceHistoryForResolution
|
|
405
406
|
? candidate.broker.getPriceHistoryForResolution(
|
|
406
407
|
ticker,
|
|
@@ -515,9 +516,9 @@ export class ProviderRouterHistoryRoutes {
|
|
|
515
516
|
context,
|
|
516
517
|
cachePolicyKey: intervalMs != null && intervalMs >= 24 * 60 * 60 * 1000 ? "priceHistoryDaily" : "priceHistoryIntraday",
|
|
517
518
|
isCachedValueStale: (value) => currentWindowAtLookup
|
|
518
|
-
&& resultIsStale(value, exchange, intervalMs),
|
|
519
|
+
&& resultIsStale(value, ticker, exchange, intervalMs),
|
|
519
520
|
isFetchedValueStale: (value) => isCurrentHistoryWindow(endDate)
|
|
520
|
-
&& resultIsStale(value, exchange, intervalMs),
|
|
521
|
+
&& resultIsStale(value, ticker, exchange, intervalMs),
|
|
521
522
|
fetchBroker: async (candidate) => candidate.broker.getDetailedPriceHistory
|
|
522
523
|
? candidate.broker.getDetailedPriceHistory(
|
|
523
524
|
ticker,
|
|
@@ -568,6 +569,7 @@ export class ProviderRouterHistoryRoutes {
|
|
|
568
569
|
const now = Date.now();
|
|
569
570
|
const fetchState = (record: { fetchedAt: number; value: PriceHistoryResult }, checkedAt?: number): CalendarHistoryFetchState => currentWindow
|
|
570
571
|
? calendarHistoryFetchState(record.value.points, record.fetchedAt, now, {
|
|
572
|
+
symbol: target.symbol,
|
|
571
573
|
exchange: target.exchange || request.target.exchange,
|
|
572
574
|
checkedAt,
|
|
573
575
|
// Bar size comes from the request: a cached weekly or monthly series
|
|
@@ -580,7 +582,7 @@ export class ProviderRouterHistoryRoutes {
|
|
|
580
582
|
const ranked = cachedRecords.filter((record) => hasUsablePriceHistory(record.value.points)).map((record) => {
|
|
581
583
|
const tier = fetchTier[fetchState(record)];
|
|
582
584
|
return { record, tier, exact: request.exactCacheVariantKeys.includes(record.variantKey),
|
|
583
|
-
lastBar: tier === 0 ? "" : calendarHistoryLastBarDate(record.value.points, target.exchange || request.target.exchange) ?? "" };
|
|
585
|
+
lastBar: tier === 0 ? "" : calendarHistoryLastBarDate(record.value.points, target.exchange || request.target.exchange, target.symbol) ?? "" };
|
|
584
586
|
});
|
|
585
587
|
// Current copies keep their listed order. Otherwise ties go to this key's
|
|
586
588
|
// own copy, then the latest fetch, rather than to row order.
|
|
@@ -657,7 +659,10 @@ export class ProviderRouterHistoryRoutes {
|
|
|
657
659
|
throw new HistoryRetentionError(candidates[0]?.retention ?? attempts.retention, { candidates, outcomes: [...attempts.outcomes.values()] });
|
|
658
660
|
}
|
|
659
661
|
if (!providerResult && request.missingProviderError && !reportedGaps.some((value) => value.points.length > 0)) {
|
|
660
|
-
|
|
662
|
+
// A source answered a coin's history but it stops short of the present: say so, not that nothing answered.
|
|
663
|
+
const behind = isRoundTheClockCoin(target.symbol, target.exchange || request.target.exchange)
|
|
664
|
+
&& [...attempts.outcomes.values()].some((outcome) => outcome.outcome === "stale");
|
|
665
|
+
throw new Error(behind ? `Latest history for ${target.symbol} is behind` : request.missingProviderError);
|
|
661
666
|
}
|
|
662
667
|
return withReportedGaps(providerResult?.value ?? { points: [], resolution: historyResolutionForInterval(request.interval) });
|
|
663
668
|
}
|
|
@@ -73,7 +73,7 @@ export class ProviderRouterPrimaryRoutes {
|
|
|
73
73
|
if (rawValue && !context?.instrument && !providerFinancialsMatchTarget(rawValue, ticker, exchange)) continue;
|
|
74
74
|
const resolvedValue = resolveTickerFinancialsQuoteState(normalizeTickerFinancialsPriceHistory(rawValue));
|
|
75
75
|
if (resolvedValue && !context?.instrument && !providerFinancialsMatchTarget(resolvedValue, ticker, exchange)) continue;
|
|
76
|
-
let value = resolvedValue ? dropUnusableProviderQuote(resolvedValue, exchange) : null;
|
|
76
|
+
let value = resolvedValue ? dropUnusableProviderQuote(resolvedValue, exchange, { recentAnswer: true }) : null;
|
|
77
77
|
if (!value) continue;
|
|
78
78
|
const sourceKey = this.options.providerSourceKey(provider);
|
|
79
79
|
if (context?.statementHistory === "extended" && !hasReusableExtendedHistory(value)) {
|
|
@@ -187,7 +187,7 @@ export class ProviderRouterPrimaryRoutes {
|
|
|
187
187
|
for (const provider of this.options.providersInPriorityOrder()) {
|
|
188
188
|
try {
|
|
189
189
|
const quote = await provider.getQuote(ticker, exchange, context);
|
|
190
|
-
if (!isProviderQuoteUsableForCurrentSession(quote, exchange, ticker)) continue;
|
|
190
|
+
if (!isProviderQuoteUsableForCurrentSession(quote, exchange, ticker, { recentAnswer: true })) continue;
|
|
191
191
|
const sourceKey = this.options.providerSourceKey(provider);
|
|
192
192
|
this.options.cacheResource(
|
|
193
193
|
"quote",
|