gloomberb 0.16.1 → 0.16.2
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 +24 -0
- package/src/cli/commands/command-utils.ts +8 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +414 -106
- package/src/cli/commands/overview.ts +77 -32
- package/src/cli/commands/ticker.ts +101 -43
- package/src/cli/desktop-pane-shot.ts +34 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +1 -0
- package/src/cli/helpers.ts +4 -8
- package/src/cli/index.ts +12 -2
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/pane-functions/access-gate.ts +42 -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 +20 -2
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +27 -20
- package/src/cli/pane-functions/headless.ts +39 -11
- package/src/cli/pane-functions/index.ts +15 -4
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +4 -0
- package/src/cli/pane-functions/resolver.ts +35 -7
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +7 -3
- package/src/cli/result.ts +41 -27
- 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/view.tsx +29 -10
- 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/menu.ts +2 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +14 -3
- 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/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 +78 -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/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/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 +1 -1
- 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/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 +1 -1
- 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/headless.ts +139 -5
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +20 -3
- package/src/plugins/builtin/holders/report-header.ts +95 -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/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 +13 -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 +248 -47
- package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -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 +230 -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 +98 -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 +47 -13
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -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 +11 -3
- 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/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/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/social-mentions/headless.ts +1 -0
- 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/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -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 +157 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -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 +447 -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 +67 -4
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
- package/src/plugins/builtin/world-venue-map/model.ts +7 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -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 +28 -43
- 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/dom/build-assets.ts +81 -3
- 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/input.tsx +14 -3
- package/src/renderers/dom/styles.css +6 -7
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +27 -3
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financials.ts +8 -7
- package/src/sources/provider-router/history.ts +15 -10
- 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/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/theme/heat-colors.ts +266 -84
- 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 +3 -0
- 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 +14 -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 +14 -0
- package/src/utils/depositary-receipt.ts +26 -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/price-earnings.ts +70 -3
- 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
|
@@ -78,6 +78,14 @@ export interface TextFieldProps {
|
|
|
78
78
|
}) => void;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Desktop and web: the `style` of a Textarea that sits in its own framed box (a
|
|
83
|
+
* prompt, a form's long field, a bio), so its text keeps off the frame as a
|
|
84
|
+
* TextField's does. The terminal's box border already leaves that cell; pass
|
|
85
|
+
* it only where `nativePaneChrome` is true.
|
|
86
|
+
*/
|
|
87
|
+
export const FRAMED_TEXTAREA_DESKTOP_STYLE = { padding: "6px var(--cell-w)", lineHeight: "var(--cell-h)" } as const;
|
|
88
|
+
|
|
81
89
|
const PASSWORD_MASK_CHAR = "*";
|
|
82
90
|
|
|
83
91
|
function maskPassword(value: string): string {
|
|
@@ -7,6 +7,12 @@ export interface RangeTrackProps {
|
|
|
7
7
|
/** Cells the track spans. */
|
|
8
8
|
width: number;
|
|
9
9
|
markerColor: string;
|
|
10
|
+
/**
|
|
11
|
+
* Mark a value past either end with an arrow at that end (a square on the
|
|
12
|
+
* desktop) instead of pinning the dot there, so it does not read as the low
|
|
13
|
+
* or the high itself.
|
|
14
|
+
*/
|
|
15
|
+
outside?: boolean;
|
|
10
16
|
}
|
|
11
17
|
|
|
12
18
|
/**
|
|
@@ -14,9 +20,10 @@ export interface RangeTrackProps {
|
|
|
14
20
|
* a rule with a dot on it. The caller draws the endpoints. The terminal draws
|
|
15
21
|
* a box-drawing rule; the desktop draws a real line and dot, never glyphs.
|
|
16
22
|
*/
|
|
17
|
-
export function RangeTrack({ position, width, markerColor }: RangeTrackProps) {
|
|
23
|
+
export function RangeTrack({ position, width, markerColor, outside = false }: RangeTrackProps) {
|
|
18
24
|
const colors = useThemeColors();
|
|
19
25
|
const isDesktopWeb = useUiCapabilities().nativePaneChrome === true;
|
|
26
|
+
const past = !outside ? null : position < 0 ? "below" : position > 1 ? "above" : null;
|
|
20
27
|
const at = position > 0 ? Math.min(1, position) : 0;
|
|
21
28
|
if (width <= 0) return null;
|
|
22
29
|
if (isDesktopWeb) {
|
|
@@ -29,7 +36,7 @@ export function RangeTrack({ position, width, markerColor }: RangeTrackProps) {
|
|
|
29
36
|
width: "8px",
|
|
30
37
|
height: "8px",
|
|
31
38
|
marginLeft: "-4px",
|
|
32
|
-
borderRadius: "50%",
|
|
39
|
+
borderRadius: past ? "1px" : "50%",
|
|
33
40
|
backgroundColor: markerColor,
|
|
34
41
|
}} />
|
|
35
42
|
</Box>
|
|
@@ -39,7 +46,7 @@ export function RangeTrack({ position, width, markerColor }: RangeTrackProps) {
|
|
|
39
46
|
return (
|
|
40
47
|
<Box width={width} height={1} flexShrink={0} flexDirection="row">
|
|
41
48
|
<Text fg={colors.border}>{"─".repeat(marker)}</Text>
|
|
42
|
-
<Text fg={markerColor}
|
|
49
|
+
<Text fg={markerColor}>{past === "below" ? "◂" : past === "above" ? "▸" : "●"}</Text>
|
|
43
50
|
<Text fg={colors.border}>{"─".repeat(width - marker - 1)}</Text>
|
|
44
51
|
</Box>
|
|
45
52
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import { t, tf } from "../../i18n";
|
|
3
3
|
import { useThemeColors } from "../../theme/theme-context";
|
|
4
|
-
import { Box, Text } from "../../ui";
|
|
4
|
+
import { Box, Text, useUiCapabilities } from "../../ui";
|
|
5
5
|
import { Spinner } from "./loading";
|
|
6
6
|
import { ButtonActionScope } from "./action-scope";
|
|
7
7
|
|
|
@@ -15,13 +15,19 @@ export interface EmptyStateProps {
|
|
|
15
15
|
|
|
16
16
|
export function EmptyState({ title, message, hint, actions, status = "empty" }: EmptyStateProps) {
|
|
17
17
|
const colors = useThemeColors();
|
|
18
|
+
const { nativePaneChrome } = useUiCapabilities();
|
|
18
19
|
// Provider messages must wrap at narrow pane widths rather than lose their tail.
|
|
19
20
|
return (
|
|
20
21
|
<Box flexDirection="column" data-gloom-status={status} data-gloom-ui="empty-state">
|
|
21
22
|
<Box><Text fg={status === "error" ? colors.negative : colors.textDim} wrapText>{t(title)}</Text></Box>
|
|
22
23
|
{message && <Box><Text fg={colors.textMuted} wrapText>{t(message)}</Text></Box>}
|
|
23
24
|
{hint && <Box><Text fg={colors.textMuted} wrapText>{t(hint)}</Text></Box>}
|
|
24
|
-
{
|
|
25
|
+
{/* Wraps in a narrow pane rather than clipping the second action; a terminal wraps without a blank row. */}
|
|
26
|
+
{actions && (
|
|
27
|
+
<Box flexDirection="row" flexWrap="wrap" gap={1} rowGap={nativePaneChrome ? undefined : 0} marginTop={1}>
|
|
28
|
+
<ButtonActionScope>{actions}</ButtonActionScope>
|
|
29
|
+
</Box>
|
|
30
|
+
)}
|
|
25
31
|
</Box>
|
|
26
32
|
);
|
|
27
33
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { usePaneMenuItems, usePaneTabStripKeys } from "../layout/pane/footer/registration";
|
|
3
3
|
import type { ContextMenuItem } from "../../types/context-menu";
|
|
4
4
|
import { useShortcut } from "../../react/input";
|
|
5
5
|
import { Box, ScrollBox, Text, useNativeRenderer, useUiHost } from "../../ui";
|
|
@@ -70,12 +70,16 @@ export function Tabs({
|
|
|
70
70
|
onAdd,
|
|
71
71
|
onReorder,
|
|
72
72
|
onDrag,
|
|
73
|
-
focused = false,
|
|
73
|
+
focused: paneFocused = false,
|
|
74
74
|
keyboardNavigation = true,
|
|
75
75
|
paneMenu = true,
|
|
76
76
|
scrollable = true,
|
|
77
77
|
scrollId,
|
|
78
78
|
}: TabsProps) {
|
|
79
|
+
// While a chart the user moved into holds the keys, the strip draws as
|
|
80
|
+
// unfocused, so it shows where the arrows went.
|
|
81
|
+
const stripKeys = usePaneTabStripKeys(keyboardNavigation, paneFocused);
|
|
82
|
+
const focused = paneFocused && !stripKeys.held;
|
|
79
83
|
const language = useAppLanguage();
|
|
80
84
|
const colors = useThemeColors();
|
|
81
85
|
const tabs = useMemo(() => rawTabs.map((tab) => (
|
|
@@ -216,8 +220,7 @@ export function Tabs({
|
|
|
216
220
|
event.stopPropagation();
|
|
217
221
|
selectAdjacentTab(1);
|
|
218
222
|
}
|
|
219
|
-
}, { enabled:
|
|
220
|
-
usePaneArrowClaim(focused && keyboardNavigation);
|
|
223
|
+
}, { enabled: stripKeys.active });
|
|
221
224
|
|
|
222
225
|
if (NativeTabs) {
|
|
223
226
|
return (
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from "react";
|
|
2
|
-
import { Box, Text, Textarea, type InputRenderable, type TextareaRenderable } from "../../ui";
|
|
2
|
+
import { Box, Text, Textarea, useUiCapabilities, type InputRenderable, type TextareaRenderable } from "../../ui";
|
|
3
3
|
import { t } from "../../i18n";
|
|
4
4
|
import { useDialogKeyboard, type PromptContext } from "../../ui/dialog";
|
|
5
5
|
import { useThemeColors } from "../../theme/theme-context";
|
|
6
6
|
import { Button } from "./button";
|
|
7
|
-
import { TextField } from "./fields";
|
|
7
|
+
import { FRAMED_TEXTAREA_DESKTOP_STYLE, TextField } from "./fields";
|
|
8
8
|
import { DialogFrame } from "./frame";
|
|
9
9
|
|
|
10
10
|
export interface TextPromptDialogProps extends PromptContext<string> {
|
|
@@ -48,6 +48,7 @@ export function TextPromptDialog({
|
|
|
48
48
|
footer,
|
|
49
49
|
}: TextPromptDialogProps) {
|
|
50
50
|
const colors = useThemeColors();
|
|
51
|
+
const { nativePaneChrome } = useUiCapabilities();
|
|
51
52
|
const inputRef = useRef<InputRenderable | null>(null);
|
|
52
53
|
const textareaRef = useRef<TextareaRenderable | null>(null);
|
|
53
54
|
const [value, setValue] = useState(initialValue);
|
|
@@ -97,6 +98,7 @@ export function TextPromptDialog({
|
|
|
97
98
|
backgroundColor={colors.panel}
|
|
98
99
|
flexGrow={1}
|
|
99
100
|
wrapText
|
|
101
|
+
{...(nativePaneChrome ? { style: FRAMED_TEXTAREA_DESKTOP_STYLE } : {})}
|
|
100
102
|
keyBindings={[
|
|
101
103
|
{ name: "return", action: "submit" },
|
|
102
104
|
{ name: "linefeed", action: "submit" },
|
|
@@ -311,7 +311,23 @@ function sanitizePortfolios(value: unknown, fallback: Portfolio[]): Portfolio[]
|
|
|
311
311
|
&& typeof (entry as Portfolio).name === "string"
|
|
312
312
|
&& typeof (entry as Portfolio).currency === "string",
|
|
313
313
|
)
|
|
314
|
-
.map(
|
|
314
|
+
.map(sanitizePortfolioAllocation);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/** Cash and target weights the portfolio commands write; anything else is dropped. */
|
|
318
|
+
function sanitizePortfolioAllocation(entry: Portfolio): Portfolio {
|
|
319
|
+
const { cash, targetWeights, ...portfolio } = entry;
|
|
320
|
+
const next: Portfolio = { ...portfolio };
|
|
321
|
+
if (isRecord(cash) && typeof cash.amount === "number" && Number.isFinite(cash.amount)
|
|
322
|
+
&& typeof cash.currency === "string" && /^[A-Z]{3}$/.test(cash.currency)) {
|
|
323
|
+
next.cash = { amount: cash.amount, currency: cash.currency };
|
|
324
|
+
}
|
|
325
|
+
if (isRecord(targetWeights)) {
|
|
326
|
+
const weights = Object.entries(targetWeights).filter((weight): weight is [string, number] =>
|
|
327
|
+
!!weight[0].trim() && typeof weight[1] === "number" && Number.isFinite(weight[1]) && weight[1] >= 0 && weight[1] <= 100);
|
|
328
|
+
if (weights.length > 0) next.targetWeights = Object.fromEntries(weights);
|
|
329
|
+
}
|
|
330
|
+
return next;
|
|
315
331
|
}
|
|
316
332
|
|
|
317
333
|
function sanitizeWatchlists(value: unknown, fallback: Watchlist[]): Watchlist[] {
|
package/src/i18n/es.ts
CHANGED
|
@@ -823,7 +823,22 @@ export const es: Record<string, string> = {
|
|
|
823
823
|
"Recent users": "Usuarios recientes",
|
|
824
824
|
"No recent users": "Sin usuarios recientes",
|
|
825
825
|
"Enter at least one @username.": "Ingresa al menos un @username.",
|
|
826
|
-
"
|
|
826
|
+
"@{username} only takes DMs from people they have written to first.": "@{username} solo acepta DM de personas a las que escribió primero.",
|
|
827
|
+
"@{username} does not take DMs.": "@{username} no acepta DM.",
|
|
828
|
+
"@{username} was not found.": "No se encontró a @{username}.",
|
|
829
|
+
"{usernames} were not found.": "No se encontró a {usernames}.",
|
|
830
|
+
"One of those users was not found.": "No se encontró a uno de esos usuarios.",
|
|
831
|
+
"Someone in that group only takes DMs from people they have written to first.": "Alguien de ese grupo solo acepta DM de personas a las que escribió primero.",
|
|
832
|
+
"Could not start the conversation (error {status}).": "No se pudo iniciar la conversación (error {status}).",
|
|
833
|
+
"Could not start the conversation. Check your connection and try again.": "No se pudo iniciar la conversación. Revisa tu conexión e inténtalo de nuevo.",
|
|
834
|
+
"no DMs": "sin DM",
|
|
835
|
+
"Only takes DMs from people they have written to first.": "Solo acepta DM de personas a las que escribió primero.",
|
|
836
|
+
"Does not take DMs.": "No acepta DM.",
|
|
837
|
+
"Message @{username}": "Enviar mensaje a @{username}",
|
|
838
|
+
"Open DM with @{username}": "Abrir DM con @{username}",
|
|
839
|
+
"Message": "Mensaje",
|
|
840
|
+
"Open DM": "Abrir DM",
|
|
841
|
+
"Show Profile": "Ver perfil",
|
|
827
842
|
"Starting": "Iniciando",
|
|
828
843
|
"Start": "Iniciar",
|
|
829
844
|
|
|
@@ -960,6 +975,9 @@ export const es: Record<string, string> = {
|
|
|
960
975
|
"Minimize": "Minimizar",
|
|
961
976
|
"Maximize": "Maximizar",
|
|
962
977
|
"Pane unavailable.": "Panel no disponible.",
|
|
978
|
+
"{title} stopped working.": "{title} dejó de funcionar.",
|
|
979
|
+
"Reload pane": "Recargar panel",
|
|
980
|
+
"Close pane": "Cerrar panel",
|
|
963
981
|
"Cash & Margin": "Efectivo y margen",
|
|
964
982
|
"No non-zero cash balances.": "Sin saldos de efectivo distintos de cero.",
|
|
965
983
|
"adding...": "agregando...",
|
package/src/i18n/ja.ts
CHANGED
|
@@ -837,7 +837,22 @@ export const ja: Record<string, string> = {
|
|
|
837
837
|
"Recent users": "最近のユーザー",
|
|
838
838
|
"No recent users": "最近のユーザーはいません",
|
|
839
839
|
"Enter at least one @username.": "@username を 1 件以上入力してください。",
|
|
840
|
-
"
|
|
840
|
+
"@{username} only takes DMs from people they have written to first.": "@{username} は自分から先にメッセージを送った相手の DM だけを受け付けています。",
|
|
841
|
+
"@{username} does not take DMs.": "@{username} は DM を受け付けていません。",
|
|
842
|
+
"@{username} was not found.": "@{username} が見つかりません。",
|
|
843
|
+
"{usernames} were not found.": "{usernames} が見つかりません。",
|
|
844
|
+
"One of those users was not found.": "見つからないユーザーがいます。",
|
|
845
|
+
"Someone in that group only takes DMs from people they have written to first.": "このグループには、自分から先にメッセージを送った相手の DM だけを受け付けている人がいます。",
|
|
846
|
+
"Could not start the conversation (error {status}).": "会話を開始できませんでした (エラー {status})。",
|
|
847
|
+
"Could not start the conversation. Check your connection and try again.": "会話を開始できませんでした。接続を確認して、もう一度お試しください。",
|
|
848
|
+
"no DMs": "DM 不可",
|
|
849
|
+
"Only takes DMs from people they have written to first.": "自分から先にメッセージを送った相手の DM だけを受け付けています。",
|
|
850
|
+
"Does not take DMs.": "DM を受け付けていません。",
|
|
851
|
+
"Message @{username}": "@{username} にメッセージ",
|
|
852
|
+
"Open DM with @{username}": "@{username} との DM を開く",
|
|
853
|
+
"Message": "メッセージ",
|
|
854
|
+
"Open DM": "DM を開く",
|
|
855
|
+
"Show Profile": "プロフィールを表示",
|
|
841
856
|
"Starting": "開始中",
|
|
842
857
|
"Start": "開始",
|
|
843
858
|
|
|
@@ -974,6 +989,9 @@ export const ja: Record<string, string> = {
|
|
|
974
989
|
"Minimize": "最小化",
|
|
975
990
|
"Maximize": "最大化",
|
|
976
991
|
"Pane unavailable.": "ペインが使用できません。",
|
|
992
|
+
"{title} stopped working.": "{title} が動作を停止しました。",
|
|
993
|
+
"Reload pane": "ペインを再読み込み",
|
|
994
|
+
"Close pane": "ペインを閉じる",
|
|
977
995
|
"Cash & Margin": "現金・証拠金",
|
|
978
996
|
"No non-zero cash balances.": "現金残高はありません。",
|
|
979
997
|
"adding...": "追加中...",
|
package/src/i18n/ko.ts
CHANGED
|
@@ -835,7 +835,22 @@ export const ko: Record<string, string> = {
|
|
|
835
835
|
"Recent users": "최근 사용자",
|
|
836
836
|
"No recent users": "최근 사용자 없음",
|
|
837
837
|
"Enter at least one @username.": "@username을 하나 이상 입력하세요.",
|
|
838
|
-
"
|
|
838
|
+
"@{username} only takes DMs from people they have written to first.": "@{username}님은 먼저 메시지를 보낸 상대의 DM만 받습니다.",
|
|
839
|
+
"@{username} does not take DMs.": "@{username}님은 DM을 받지 않습니다.",
|
|
840
|
+
"@{username} was not found.": "@{username}님을 찾을 수 없습니다.",
|
|
841
|
+
"{usernames} were not found.": "{usernames}님을 찾을 수 없습니다.",
|
|
842
|
+
"One of those users was not found.": "찾을 수 없는 사용자가 있습니다.",
|
|
843
|
+
"Someone in that group only takes DMs from people they have written to first.": "이 그룹에 먼저 메시지를 보낸 상대의 DM만 받는 사람이 있습니다.",
|
|
844
|
+
"Could not start the conversation (error {status}).": "대화를 시작할 수 없습니다 (오류 {status}).",
|
|
845
|
+
"Could not start the conversation. Check your connection and try again.": "대화를 시작할 수 없습니다. 연결을 확인하고 다시 시도하세요.",
|
|
846
|
+
"no DMs": "DM 불가",
|
|
847
|
+
"Only takes DMs from people they have written to first.": "먼저 메시지를 보낸 상대의 DM만 받습니다.",
|
|
848
|
+
"Does not take DMs.": "DM을 받지 않습니다.",
|
|
849
|
+
"Message @{username}": "@{username}님에게 메시지",
|
|
850
|
+
"Open DM with @{username}": "@{username}님과의 DM 열기",
|
|
851
|
+
"Message": "메시지",
|
|
852
|
+
"Open DM": "DM 열기",
|
|
853
|
+
"Show Profile": "프로필 보기",
|
|
839
854
|
"Starting": "시작 중",
|
|
840
855
|
"Start": "시작",
|
|
841
856
|
|
|
@@ -972,6 +987,9 @@ export const ko: Record<string, string> = {
|
|
|
972
987
|
"Minimize": "최소화",
|
|
973
988
|
"Maximize": "최대화",
|
|
974
989
|
"Pane unavailable.": "패널을 사용할 수 없습니다.",
|
|
990
|
+
"{title} stopped working.": "{title}이(가) 작동을 멈췄습니다.",
|
|
991
|
+
"Reload pane": "패널 다시 불러오기",
|
|
992
|
+
"Close pane": "패널 닫기",
|
|
975
993
|
"Cash & Margin": "현금·증거금",
|
|
976
994
|
"No non-zero cash balances.": "표시할 현금 잔액이 없습니다.",
|
|
977
995
|
"adding...": "추가 중...",
|
package/src/i18n/zh-cn.ts
CHANGED
|
@@ -837,7 +837,22 @@ export const zhCN: Record<string, string> = {
|
|
|
837
837
|
"Recent users": "最近联系人",
|
|
838
838
|
"No recent users": "没有最近联系人",
|
|
839
839
|
"Enter at least one @username.": "至少输入一个 @用户名。",
|
|
840
|
-
"
|
|
840
|
+
"@{username} only takes DMs from people they have written to first.": "@{username} 只接收自己先联系过的人的私信。",
|
|
841
|
+
"@{username} does not take DMs.": "@{username} 不接收私信。",
|
|
842
|
+
"@{username} was not found.": "找不到 @{username}。",
|
|
843
|
+
"{usernames} were not found.": "找不到 {usernames}。",
|
|
844
|
+
"One of those users was not found.": "其中有用户不存在。",
|
|
845
|
+
"Someone in that group only takes DMs from people they have written to first.": "该群组中有人只接收自己先联系过的人的私信。",
|
|
846
|
+
"Could not start the conversation (error {status}).": "无法开始会话(错误 {status})。",
|
|
847
|
+
"Could not start the conversation. Check your connection and try again.": "无法开始会话。请检查网络连接后重试。",
|
|
848
|
+
"no DMs": "不收私信",
|
|
849
|
+
"Only takes DMs from people they have written to first.": "只接收自己先联系过的人的私信。",
|
|
850
|
+
"Does not take DMs.": "不接收私信。",
|
|
851
|
+
"Message @{username}": "私信 @{username}",
|
|
852
|
+
"Open DM with @{username}": "打开与 @{username} 的私信",
|
|
853
|
+
"Message": "发私信",
|
|
854
|
+
"Open DM": "打开私信",
|
|
855
|
+
"Show Profile": "查看资料",
|
|
841
856
|
"Starting": "正在开始",
|
|
842
857
|
"Start": "开始",
|
|
843
858
|
|
|
@@ -974,6 +989,9 @@ export const zhCN: Record<string, string> = {
|
|
|
974
989
|
"Minimize": "最小化",
|
|
975
990
|
"Maximize": "最大化",
|
|
976
991
|
"Pane unavailable.": "面板不可用。",
|
|
992
|
+
"{title} stopped working.": "{title} 已停止工作。",
|
|
993
|
+
"Reload pane": "重新加载面板",
|
|
994
|
+
"Close pane": "关闭面板",
|
|
977
995
|
"Cash & Margin": "现金与保证金",
|
|
978
996
|
"No non-zero cash balances.": "没有非零现金余额。",
|
|
979
997
|
"adding...": "添加中...",
|
package/src/i18n/zh-tw.ts
CHANGED
|
@@ -837,7 +837,22 @@ export const zhTW: Record<string, string> = {
|
|
|
837
837
|
"Recent users": "最近聯絡人",
|
|
838
838
|
"No recent users": "沒有最近聯絡人",
|
|
839
839
|
"Enter at least one @username.": "至少輸入一個 @username。",
|
|
840
|
-
"
|
|
840
|
+
"@{username} only takes DMs from people they have written to first.": "@{username} 只接收自己先聯絡過的人的私訊。",
|
|
841
|
+
"@{username} does not take DMs.": "@{username} 不接收私訊。",
|
|
842
|
+
"@{username} was not found.": "找不到 @{username}。",
|
|
843
|
+
"{usernames} were not found.": "找不到 {usernames}。",
|
|
844
|
+
"One of those users was not found.": "其中有使用者不存在。",
|
|
845
|
+
"Someone in that group only takes DMs from people they have written to first.": "該群組中有人只接收自己先聯絡過的人的私訊。",
|
|
846
|
+
"Could not start the conversation (error {status}).": "無法開始對話(錯誤 {status})。",
|
|
847
|
+
"Could not start the conversation. Check your connection and try again.": "無法開始對話。請檢查網路連線後再試一次。",
|
|
848
|
+
"no DMs": "不收私訊",
|
|
849
|
+
"Only takes DMs from people they have written to first.": "只接收自己先聯絡過的人的私訊。",
|
|
850
|
+
"Does not take DMs.": "不接收私訊。",
|
|
851
|
+
"Message @{username}": "私訊 @{username}",
|
|
852
|
+
"Open DM with @{username}": "開啟與 @{username} 的私訊",
|
|
853
|
+
"Message": "傳私訊",
|
|
854
|
+
"Open DM": "開啟私訊",
|
|
855
|
+
"Show Profile": "查看個人資料",
|
|
841
856
|
"Starting": "正在開始",
|
|
842
857
|
"Start": "開始",
|
|
843
858
|
|
|
@@ -974,6 +989,9 @@ export const zhTW: Record<string, string> = {
|
|
|
974
989
|
"Minimize": "最小化",
|
|
975
990
|
"Maximize": "最大化",
|
|
976
991
|
"Pane unavailable.": "面板不可用。",
|
|
992
|
+
"{title} stopped working.": "{title} 已停止運作。",
|
|
993
|
+
"Reload pane": "重新載入面板",
|
|
994
|
+
"Close pane": "關閉面板",
|
|
977
995
|
"Cash & Margin": "現金與保證金",
|
|
978
996
|
"No non-zero cash balances.": "沒有非零的現金餘額。",
|
|
979
997
|
"adding...": "新增中...",
|
|
@@ -57,7 +57,7 @@ export function normalizeFreshChartData(
|
|
|
57
57
|
interval: interval ?? undefined }) ?? undefined;
|
|
58
58
|
if (
|
|
59
59
|
isIntradayChartRequest(request, history)
|
|
60
|
-
&& isPriceHistoryStaleForCurrentWindow(normalized, Date.now(), { exchange: target.exchange,
|
|
60
|
+
&& isPriceHistoryStaleForCurrentWindow(normalized, Date.now(), { symbol: target.symbol, exchange: target.exchange,
|
|
61
61
|
intervalMs: interval ? priceHistoryIntervalMs(interval) : undefined, session })
|
|
62
62
|
) {
|
|
63
63
|
return [];
|
|
@@ -113,13 +113,24 @@ export async function loadQuoteEntry({
|
|
|
113
113
|
const attempts = [createAttempt(source, startedAt, "success")];
|
|
114
114
|
return quoteStore.update(key, (current) => readyQuoteEntry(current, resolvedQuote, source, attempts, { keepNewerHeldQuote: true }));
|
|
115
115
|
} catch (error) {
|
|
116
|
-
|
|
117
|
-
const attempt = createAttempt(dataProvider.id, startedAt, EXPECTED_EMPTY.test(classified.message) ? "empty" : "fatal_error", classified.reasonCode, classified.message);
|
|
118
|
-
return quoteStore.update(key, (current) => errorEntry(current, attempt));
|
|
116
|
+
return storeQuoteFailure(quoteStore, key, dataProvider.id, startedAt, error);
|
|
119
117
|
}
|
|
120
118
|
});
|
|
121
119
|
}
|
|
122
120
|
|
|
121
|
+
function storeQuoteFailure(
|
|
122
|
+
quoteStore: QueryStore<Quote>,
|
|
123
|
+
key: string,
|
|
124
|
+
providerId: string,
|
|
125
|
+
startedAt: number,
|
|
126
|
+
error: unknown,
|
|
127
|
+
): QueryEntry<Quote> {
|
|
128
|
+
const classified = classifyError(error);
|
|
129
|
+
const status = EXPECTED_EMPTY.test(classified.message) ? "empty" : "fatal_error";
|
|
130
|
+
const attempt = createAttempt(providerId, startedAt, status, classified.reasonCode, classified.message);
|
|
131
|
+
return quoteStore.update(key, (current) => errorEntry(current, attempt));
|
|
132
|
+
}
|
|
133
|
+
|
|
123
134
|
interface LoadQuoteBatchEntriesOptions {
|
|
124
135
|
dataProvider: DataProvider;
|
|
125
136
|
instruments: InstrumentRef[];
|
|
@@ -152,14 +163,22 @@ export async function loadQuoteBatchEntries({
|
|
|
152
163
|
}
|
|
153
164
|
|
|
154
165
|
if (misses.length > 0 && dataProvider.getQuotesBatch) {
|
|
166
|
+
const startedAt = Date.now();
|
|
155
167
|
const batchResults = await dataProvider.getQuotesBatch(
|
|
156
168
|
misses.map((instrument) => quoteTargetFromInstrument(instrument)),
|
|
157
169
|
{ forceRefresh: options.forceRefresh },
|
|
158
170
|
);
|
|
159
171
|
batchResults.forEach((item, index) => {
|
|
160
172
|
const instrument = misses[index];
|
|
161
|
-
if (!instrument
|
|
173
|
+
if (!instrument) return;
|
|
162
174
|
const key = buildQuoteKey(instrument);
|
|
175
|
+
if (!item.quote) {
|
|
176
|
+
// The batch already asked for this one, one by one where the batch
|
|
177
|
+
// answer fell short, and says why it failed. Asking again here would
|
|
178
|
+
// only send the same request a second time.
|
|
179
|
+
if (item.error != null) results.set(key, storeQuoteFailure(quoteStore, key, dataProvider.id, startedAt, item.error));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
163
182
|
const quote = resolveQuote?.(instrument, item.quote) ?? item.quote;
|
|
164
183
|
const source = quote.providerId ?? dataProvider.id;
|
|
165
184
|
const attempts = [createAttempt(source, Date.now(), "success")];
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { CloudMarketResponse, CloudPricePointPayload } from "../api-client/types";
|
|
2
|
+
import type { FxLeg } from "./coordinator/fx-legs";
|
|
3
|
+
|
|
4
|
+
/** USD per unit of one currency at each completed daily FX close, by date. */
|
|
5
|
+
export interface FxCloses {
|
|
6
|
+
currency: string;
|
|
7
|
+
closes: ReadonlyMap<string, number>;
|
|
8
|
+
first: string;
|
|
9
|
+
asOf: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Why a daily FX history cannot be used: no usable closes, or none in the last week. */
|
|
13
|
+
export class FxHistoryError extends Error {
|
|
14
|
+
constructor(readonly problem: "unavailable" | "stale") {
|
|
15
|
+
super(problem === "stale" ? "Daily FX history is stale" : "Daily FX history unavailable");
|
|
16
|
+
this.name = "FxHistoryError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const DAY_MS = 86_400_000;
|
|
21
|
+
/** A pair's latest completed close older than this is stale; a weekend and a holiday fit well inside it. */
|
|
22
|
+
const FX_MAX_AGE_DAYS = 7;
|
|
23
|
+
|
|
24
|
+
const isDay = (value: string) => /^\d{4}-\d{2}-\d{2}$/.test(value) && Number.isFinite(Date.parse(value))
|
|
25
|
+
&& new Date(value).toISOString().slice(0, 10) === value;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Completed daily closes of the pair as USD per unit, today's still-trading
|
|
29
|
+
* bar left out. A malformed row, two different closes on one date, or more
|
|
30
|
+
* rows than asked for rejects the whole history rather than a part of it.
|
|
31
|
+
*/
|
|
32
|
+
export function dailyFxCloses(
|
|
33
|
+
response: CloudMarketResponse<CloudPricePointPayload[]>,
|
|
34
|
+
leg: FxLeg,
|
|
35
|
+
now = new Date(),
|
|
36
|
+
maxRows = 1500,
|
|
37
|
+
): FxCloses {
|
|
38
|
+
if (response.status !== "success" || !Array.isArray(response.data) || response.data.length < 2) throw new FxHistoryError("unavailable");
|
|
39
|
+
if (response.stale || response.providerMeta?.stale) throw new FxHistoryError("stale");
|
|
40
|
+
if (response.data.length > maxRows) throw new FxHistoryError("unavailable");
|
|
41
|
+
const today = now.toISOString().slice(0, 10);
|
|
42
|
+
const closes = new Map<string, number>();
|
|
43
|
+
for (const row of response.data) {
|
|
44
|
+
if (!row || typeof row.date !== "string" || !Number.isFinite(Date.parse(row.date)) || !isDay(row.date.slice(0, 10))
|
|
45
|
+
|| !Number.isFinite(row.close) || row.close <= 0) throw new FxHistoryError("unavailable");
|
|
46
|
+
const date = new Date(row.date).toISOString().slice(0, 10);
|
|
47
|
+
if (date >= today) continue;
|
|
48
|
+
const rate = leg.invert ? 1 / row.close : row.close;
|
|
49
|
+
const previous = closes.get(date);
|
|
50
|
+
if (previous != null && previous !== rate) throw new FxHistoryError("unavailable");
|
|
51
|
+
closes.set(date, rate);
|
|
52
|
+
}
|
|
53
|
+
const dates = [...closes.keys()].sort();
|
|
54
|
+
const asOf = dates.at(-1);
|
|
55
|
+
if (!asOf || Date.parse(today) - Date.parse(asOf) > FX_MAX_AGE_DAYS * DAY_MS) throw new FxHistoryError("stale");
|
|
56
|
+
return { currency: leg.currency, closes, first: dates[0]!, asOf };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The last completed close on or before `date` (YYYY-MM-DD), looking back at
|
|
61
|
+
* most a week so a weekend or holiday finds the close before it but a gap in
|
|
62
|
+
* the history is not bridged.
|
|
63
|
+
*/
|
|
64
|
+
export function fxCloseOnOrBefore(fx: FxCloses, date: string): { date: string; rate: number } | null {
|
|
65
|
+
const end = Date.parse(`${(date < fx.asOf ? date : fx.asOf)}T00:00:00Z`);
|
|
66
|
+
for (let back = 0; back <= FX_MAX_AGE_DAYS; back++) {
|
|
67
|
+
const day = new Date(end - back * DAY_MS).toISOString().slice(0, 10);
|
|
68
|
+
const rate = fx.closes.get(day);
|
|
69
|
+
if (rate != null) return { date: day, rate };
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MarketState } from "../../types/financials";
|
|
2
2
|
import { canonicalExchange, EXCHANGE_TIME_ZONES, isUsListingExchange } from "../../utils/exchanges";
|
|
3
|
+
import { hasPublishedApacCalendar, isPublishedApacClosure } from "../published-apac-sessions";
|
|
3
4
|
import { hasPublishedCnCalendar, isPublishedCnClosure } from "../published-cn-sessions";
|
|
4
5
|
import { hasPublishedJpxCalendar, isPublishedJpxClosure } from "../published-jpx-sessions";
|
|
5
6
|
import { hasPublishedNseCalendar, isPublishedNseClosure } from "../published-nse-sessions";
|
|
@@ -11,6 +12,9 @@ const ALWAYS_OPEN_EXCHANGES = new Set(["CCC"]);
|
|
|
11
12
|
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
12
13
|
const OVERNIGHT_CLOSE_MAX_AGE_MS = 20 * 60 * 60 * 1000;
|
|
13
14
|
const ALWAYS_OPEN_MAX_AGE_MS = 2 * 60 * 60 * 1000;
|
|
15
|
+
// Spring Festival can put the previous session twelve calendar days back
|
|
16
|
+
// (TWSE, February 2026).
|
|
17
|
+
const SESSION_LOOKBACK_DAYS = 14;
|
|
14
18
|
const REGULAR_OPEN_MINUTES: Record<string, number> = {
|
|
15
19
|
NASDAQ: 9 * 60 + 30,
|
|
16
20
|
NYSE: 9 * 60 + 30,
|
|
@@ -72,6 +76,28 @@ const REGULAR_CLOSE_MINUTES: Record<string, number> = {
|
|
|
72
76
|
NZX: 17 * 60, SSE: 15 * 60 + 30, SZSE: 15 * 60 + 30,
|
|
73
77
|
BMV: 15 * 60 + 10, B3: 18 * 60 + 30, BYMA: 17 * 60 + 10, JSE: 17 * 60 + 15, TASE: 17 * 60 + 40,
|
|
74
78
|
};
|
|
79
|
+
// Venues that pause at midday, as local minutes [start, end), with a zone for
|
|
80
|
+
// those the session tables above do not cover. Jakarta pauses longer on Fridays.
|
|
81
|
+
const MIDDAY_BREAKS: Record<string, {
|
|
82
|
+
timeZone?: string;
|
|
83
|
+
weekdays: readonly [number, number];
|
|
84
|
+
friday?: readonly [number, number];
|
|
85
|
+
}> = {
|
|
86
|
+
HKEX: { weekdays: [12 * 60, 13 * 60] },
|
|
87
|
+
SGX: { weekdays: [12 * 60, 13 * 60] },
|
|
88
|
+
SSE: { weekdays: [11 * 60 + 30, 13 * 60] },
|
|
89
|
+
SZSE: { weekdays: [11 * 60 + 30, 13 * 60] },
|
|
90
|
+
JPX: { weekdays: [11 * 60 + 30, 12 * 60 + 30] },
|
|
91
|
+
BURSAMY: { timeZone: "Asia/Kuala_Lumpur", weekdays: [12 * 60 + 30, 14 * 60 + 30] },
|
|
92
|
+
JAKARTA: { timeZone: "Asia/Jakarta", weekdays: [12 * 60, 13 * 60 + 30], friday: [11 * 60 + 30, 14 * 60] },
|
|
93
|
+
};
|
|
94
|
+
// A morning print this close to the break is its last one, and afternoon
|
|
95
|
+
// prints are due this long after the feed's lag has passed the reopening.
|
|
96
|
+
const MIDDAY_BREAK_MARGIN_MS = 5 * 60_000;
|
|
97
|
+
// How far the delayed feed runs behind each venue's trades.
|
|
98
|
+
const DELAYED_FEED_LAG_MS = 15 * 60_000;
|
|
99
|
+
const SLOWER_DELAYED_FEED_LAG_MS = 20 * 60_000;
|
|
100
|
+
const SLOWER_DELAYED_FEEDS = new Set(["ASX", "KRX", "KOSDAQ", "TWSE", "TPEX", "SGX", "NZX"]);
|
|
75
101
|
const exchangeLocalTimeFormatters = new Map<string, Intl.DateTimeFormat>();
|
|
76
102
|
const usSessionFormatter = new Intl.DateTimeFormat("en-US", {
|
|
77
103
|
timeZone: "America/New_York",
|
|
@@ -159,6 +185,7 @@ function isPublishedClosure(exchange: string, date: string): boolean {
|
|
|
159
185
|
if (exchange === "JPX") return isPublishedJpxClosure(date);
|
|
160
186
|
if (exchange === "NSE" || exchange === "BSE") return isPublishedNseClosure(date);
|
|
161
187
|
if (exchange === "SSE" || exchange === "SZSE") return isPublishedCnClosure(date);
|
|
188
|
+
if (isPublishedApacClosure(exchange, date)) return true;
|
|
162
189
|
return getPublishedUsEquityCalendarDay(exchange, date) === "closed";
|
|
163
190
|
}
|
|
164
191
|
|
|
@@ -207,9 +234,7 @@ export function latestRegularSessionClose(
|
|
|
207
234
|
if (!timeZone || ALWAYS_OPEN_EXCHANGES.has(canonical) || !Number.isFinite(time)) return null;
|
|
208
235
|
const { year, month, day } = zonedDateTimeParts(time, timeZone);
|
|
209
236
|
const today = Date.UTC(year, month - 1, day) / MS_PER_DAY;
|
|
210
|
-
|
|
211
|
-
const lookback = (canonical === "SSE" || canonical === "SZSE") && hasPublishedCnCalendar(year) ? 14 : 10;
|
|
212
|
-
for (let offset = 0; offset <= lookback; offset++) {
|
|
237
|
+
for (let offset = 0; offset <= SESSION_LOOKBACK_DAYS; offset++) {
|
|
213
238
|
const date = new Date((today - offset) * MS_PER_DAY).toISOString().slice(0, 10);
|
|
214
239
|
const published = getPublishedUsEquitySession(canonical, date);
|
|
215
240
|
let close: number | null = null;
|
|
@@ -225,6 +250,20 @@ export function latestRegularSessionClose(
|
|
|
225
250
|
return null;
|
|
226
251
|
}
|
|
227
252
|
|
|
253
|
+
/**
|
|
254
|
+
* The UTC minute of the day the venue's regular session closed, for the latest
|
|
255
|
+
* session at or before `time` (20:00 UTC is 1200 while New York is on daylight
|
|
256
|
+
* time). Null for round-the-clock venues and for venues whose close hour is
|
|
257
|
+
* not listed, which `latestRegularSessionClose` would take to close at local
|
|
258
|
+
* midnight.
|
|
259
|
+
*/
|
|
260
|
+
export function regularSessionCloseUtcMinute(exchange: string | undefined, time: number): number | null {
|
|
261
|
+
const canonical = canonicalExchange(exchange);
|
|
262
|
+
if (REGULAR_CLOSE_MINUTES[canonical] === undefined) return null;
|
|
263
|
+
const close = latestRegularSessionClose(canonical, time);
|
|
264
|
+
return close ? Math.floor(close.close / 60_000) % 1440 : null;
|
|
265
|
+
}
|
|
266
|
+
|
|
228
267
|
/**
|
|
229
268
|
* The open of the regular session `time` falls in, or of the latest one
|
|
230
269
|
* before it: the published calendar for US venues, otherwise the venue's
|
|
@@ -238,8 +277,7 @@ export function latestRegularSessionOpen(exchange: string | undefined, time: num
|
|
|
238
277
|
const minutes = REGULAR_OPEN_MINUTES[canonical];
|
|
239
278
|
const { year, month, day } = zonedDateTimeParts(time, timeZone);
|
|
240
279
|
const today = Date.UTC(year, month - 1, day) / MS_PER_DAY;
|
|
241
|
-
|
|
242
|
-
for (let offset = 0; offset <= lookback; offset++) {
|
|
280
|
+
for (let offset = 0; offset <= SESSION_LOOKBACK_DAYS; offset++) {
|
|
243
281
|
const date = new Date((today - offset) * MS_PER_DAY).toISOString().slice(0, 10);
|
|
244
282
|
const published = getPublishedUsEquitySession(canonical, date);
|
|
245
283
|
let open: number | null = null;
|
|
@@ -270,7 +308,8 @@ export function isRegularSessionTime(exchange: string | undefined, time: number)
|
|
|
270
308
|
|
|
271
309
|
/**
|
|
272
310
|
* True when the venue's full-day closures for the year of `date` are
|
|
273
|
-
* published: US venues, JPX, NSE, BSE, SSE
|
|
311
|
+
* published: US venues, JPX, NSE, BSE, SSE, SZSE, KRX, KOSDAQ, TWSE, TPEX,
|
|
312
|
+
* HKEX, SGX and ASX. Elsewhere a local holiday reads as a weekday.
|
|
274
313
|
*/
|
|
275
314
|
export function hasPublishedSessionCalendar(exchange: string | undefined, date: string): boolean {
|
|
276
315
|
const canonical = canonicalExchange(exchange);
|
|
@@ -278,9 +317,42 @@ export function hasPublishedSessionCalendar(exchange: string | undefined, date:
|
|
|
278
317
|
if (canonical === "JPX") return hasPublishedJpxCalendar(year);
|
|
279
318
|
if (canonical === "NSE" || canonical === "BSE") return hasPublishedNseCalendar(year);
|
|
280
319
|
if (canonical === "SSE" || canonical === "SZSE") return hasPublishedCnCalendar(year);
|
|
320
|
+
if (hasPublishedApacCalendar(canonical, year)) return true;
|
|
281
321
|
return !!getPublishedUsEquityCalendarYears(canonical)?.includes(year);
|
|
282
322
|
}
|
|
283
323
|
|
|
324
|
+
/** How far the delayed feed runs behind the venue's trades. */
|
|
325
|
+
export function delayedFeedLagMs(exchange: string | undefined): number {
|
|
326
|
+
return SLOWER_DELAYED_FEEDS.has(canonicalExchange(exchange)) ? SLOWER_DELAYED_FEED_LAG_MS : DELAYED_FEED_LAG_MS;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Whether a print is still the current price because the venue is paused at
|
|
331
|
+
* midday: `now` falls in the break, or within the feed's lag plus five
|
|
332
|
+
* minutes after it, and the print is the morning's last, no earlier than five
|
|
333
|
+
* minutes before the break started. An earlier morning print means the feed
|
|
334
|
+
* stopped before the break.
|
|
335
|
+
*/
|
|
336
|
+
export function isMiddayBreakPrint(
|
|
337
|
+
timestampMs: number,
|
|
338
|
+
exchange: string | undefined,
|
|
339
|
+
now: number,
|
|
340
|
+
feedLagMs: number,
|
|
341
|
+
): boolean {
|
|
342
|
+
const canonical = canonicalExchange(exchange);
|
|
343
|
+
const pause = MIDDAY_BREAKS[canonical];
|
|
344
|
+
const timeZone = pause?.timeZone ?? EXCHANGE_TIME_ZONES[canonical];
|
|
345
|
+
if (!pause || !timeZone || !Number.isFinite(timestampMs) || !Number.isFinite(now) || timestampMs > now) return false;
|
|
346
|
+
const { year, month, day } = zonedDateTimeParts(now, timeZone);
|
|
347
|
+
const weekday = new Date(Date.UTC(year, month - 1, day)).getUTCDay();
|
|
348
|
+
if (weekday === 0 || weekday === 6) return false;
|
|
349
|
+
const [start, end] = weekday === 5 && pause.friday ? pause.friday : pause.weekdays;
|
|
350
|
+
const at = (minutes: number) => zonedWallClockToUtcMs(timeZone, year, month, day, Math.floor(minutes / 60), minutes % 60, 0);
|
|
351
|
+
const breakStart = at(start);
|
|
352
|
+
return now >= breakStart && now <= at(end) + feedLagMs + MIDDAY_BREAK_MARGIN_MS
|
|
353
|
+
&& timestampMs >= breakStart - MIDDAY_BREAK_MARGIN_MS;
|
|
354
|
+
}
|
|
355
|
+
|
|
284
356
|
function usSessionState(timestampMs: number): UsSessionState {
|
|
285
357
|
const minute = Math.floor(timestampMs / 60_000);
|
|
286
358
|
return perMinute(usSessionCache, minute, () => formatUsSessionState(minute * 60_000));
|