gloomberb 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +169 -5
- package/src/account/auth-model.ts +7 -3
- package/src/api-client/auth.ts +9 -4
- package/src/api-client/catalysts.ts +2 -1
- package/src/api-client/cot.ts +6 -2
- package/src/api-client/credit-documents.ts +6 -0
- package/src/api-client/data.ts +31 -6
- package/src/api-client/equity-screener.ts +24 -0
- package/src/api-client/fund-facts.ts +45 -4
- package/src/api-client/index.ts +171 -11
- package/src/api-client/live-scan.ts +91 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/market-movers.ts +7 -0
- package/src/api-client/members.ts +13 -1
- package/src/api-client/perps.ts +43 -0
- package/src/api-client/request.ts +222 -41
- package/src/api-client/research-activity.ts +6 -12
- package/src/api-client/types.ts +74 -0
- package/src/app/keybindings/index.ts +3 -0
- package/src/app/keybindings/labels.ts +18 -1
- package/src/app/keybindings/resolve.ts +14 -0
- package/src/app/pane-runtime/plugin-bindings.ts +9 -5
- package/src/app/runtime/broker-import.ts +42 -27
- package/src/app/runtime/plugin-bindings.ts +73 -56
- package/src/architecture/core-builtin-allowlist.json +1 -1
- package/src/architecture/pane-tabs-allowlist.json +3 -0
- package/src/architecture/ttl-caches-allowlist.json +19 -0
- package/src/brokers/sync-broker-instance.ts +2 -8
- package/src/capabilities/chart-series.ts +1 -1
- package/src/cli/commands/crypto-hints.ts +40 -24
- package/src/cli/commands/fred-series.ts +5 -0
- package/src/cli/commands/keybindings.ts +23 -0
- package/src/cli/commands/market.ts +138 -46
- package/src/cli/commands/options-chain.ts +107 -10
- package/src/cli/commands/options-leaps.ts +9 -3
- package/src/cli/commands/overview.ts +176 -39
- package/src/cli/commands/search.ts +39 -3
- package/src/cli/commands/themes.ts +11 -2
- package/src/cli/commands/ticker.ts +57 -35
- package/src/cli/company-name-hint.ts +41 -0
- package/src/cli/earnings-calendar.ts +1 -1
- package/src/cli/errors.ts +10 -2
- package/src/cli/export-source.ts +29 -1
- package/src/cli/glossary.ts +73 -1
- package/src/cli/history-rows.ts +87 -16
- package/src/cli/index.ts +2 -0
- package/src/cli/known-gaps.ts +5 -2
- package/src/cli/listing-arg.ts +195 -56
- package/src/cli/output-file.ts +68 -0
- package/src/cli/pane-functions/capabilities.ts +3 -0
- package/src/cli/pane-functions/catalog.ts +80 -7
- package/src/cli/pane-functions/dom.ts +13 -3
- package/src/cli/pane-functions/freshness.ts +111 -16
- package/src/cli/pane-functions/function-help.ts +23 -13
- package/src/cli/pane-functions/headless.ts +56 -12
- package/src/cli/pane-functions/index.ts +58 -16
- package/src/cli/pane-functions/market-session.ts +81 -9
- package/src/cli/pane-functions/options.ts +19 -1
- package/src/cli/pane-functions/report.ts +5 -1
- package/src/cli/pane-functions/resolver.ts +35 -8
- package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
- package/src/cli/pane-functions/screenshot-types.ts +5 -0
- package/src/cli/quote-answer.ts +30 -13
- package/src/cli/report-tables.ts +18 -7
- package/src/cli/restore-plugins.ts +13 -1
- package/src/cli/result.ts +57 -5
- package/src/cli/ticker-resolution.ts +3 -2
- package/src/components/chart/composite/composite-chart.tsx +26 -4
- package/src/components/chart/composite/format.ts +27 -0
- package/src/components/chart/composite/interactions.ts +6 -0
- package/src/components/chart/composite/legend.tsx +45 -7
- package/src/components/chart/composite/levels.ts +2 -0
- package/src/components/chart/composite/panel-gestures.ts +33 -0
- package/src/components/chart/composite/panel-series.ts +1 -0
- package/src/components/chart/composite/panel-surface.tsx +61 -5
- package/src/components/chart/composite/range-statistics.ts +62 -0
- package/src/components/chart/composite/rasterizer.ts +24 -13
- package/src/components/chart/composite/scene.ts +46 -7
- package/src/components/chart/composite/series-axis-tags.tsx +16 -9
- package/src/components/chart/composite/series-cues.ts +14 -0
- package/src/components/chart/composite/text-renderer.ts +9 -2
- package/src/components/chart/composite/tool-catalog.ts +36 -0
- package/src/components/chart/composite/tools.ts +203 -44
- package/src/components/chart/composite/types.ts +4 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
- package/src/components/command-bar/assist/inventory.ts +2 -1
- package/src/components/command-bar/commands/direct/index.ts +28 -13
- package/src/components/command-bar/pane-templates/items.ts +3 -2
- package/src/components/command-bar/panel/prompt-binding.ts +0 -8
- package/src/components/command-bar/workflow/alert.ts +1 -1
- package/src/components/command-bar/workflow/collection-actions.ts +3 -3
- package/src/components/layout/header.tsx +26 -40
- package/src/components/layout/pane/footer/index.tsx +1 -0
- package/src/components/layout/pane/footer/model.ts +27 -0
- package/src/components/onboarding/onboarding-frame.tsx +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +4 -1
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -9
- package/src/components/onboarding/wizard-broker-sync.ts +0 -1
- package/src/components/onboarding/wizard-positions.ts +3 -3
- package/src/components/ticker/list-table-view.tsx +4 -1
- package/src/components/ui/choice-dialog.tsx +23 -18
- package/src/components/ui/choice-groups.ts +18 -0
- package/src/components/ui/data-table/opentui/index.tsx +9 -7
- package/src/components/ui/data-table/opentui/model.ts +26 -1
- package/src/components/ui/data-table/types.ts +2 -0
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/list-view.tsx +8 -4
- package/src/components/ui/query-bar-keys.tsx +2 -0
- package/src/components/ui/query-bar.tsx +1 -0
- package/src/components/ui/select-button.tsx +5 -1
- package/src/components/ui/select-field.tsx +1 -0
- package/src/components/ui/table-layout.ts +8 -5
- package/src/core/app-runtime.ts +2 -0
- package/src/core/app-services.ts +2 -2
- package/src/core/state/app/layout.ts +2 -0
- package/src/core/state/app/state.ts +9 -0
- package/src/core/state/app/types.ts +3 -0
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/json-ticker-repository.ts +17 -8
- package/src/data/saved-copies.ts +55 -16
- package/src/data/ticker-repository.ts +16 -9
- package/src/data/ticker-writes.ts +81 -0
- package/src/data/ttl-cache.ts +165 -0
- package/src/docs/snapshot.json +427 -216
- package/src/i18n/es.ts +19 -3
- package/src/i18n/ja.ts +19 -3
- package/src/i18n/ko.ts +19 -3
- package/src/i18n/zh-cn.ts +19 -3
- package/src/i18n/zh-tw.ts +19 -3
- package/src/market-data/coordinator/financials.ts +10 -2
- package/src/market-data/coordinator/index.ts +3 -1
- package/src/market-data/coordinator/quotes.ts +4 -2
- package/src/market-data/depositary-pair.ts +2 -2
- package/src/market-data/fund-facts.ts +50 -0
- package/src/market-data/market/change-basis.ts +48 -7
- package/src/market-data/market/dated-previous-close.ts +203 -0
- package/src/market-data/market/format.ts +25 -0
- package/src/market-data/market/freshness.ts +2 -1
- package/src/market-data/market/futures-week.ts +68 -0
- package/src/market-data/market/status.ts +16 -4
- package/src/market-data/options-alternatives.ts +141 -4
- package/src/market-data/quotes/contributions.ts +20 -2
- package/src/market-data/quotes/resolution.ts +3 -0
- package/src/market-data/selectors.ts +3 -0
- package/src/news/aggregator.ts +113 -9
- package/src/news/cloud-session.ts +21 -0
- package/src/news/hooks.ts +1 -0
- package/src/news/news-model.ts +1 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/notification-log.ts +6 -4
- package/src/plugins/builtin/alerts/alert-engine.ts +25 -2
- package/src/plugins/builtin/alerts/alert-log.ts +33 -0
- package/src/plugins/builtin/alerts/calendar-events.ts +57 -6
- package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
- package/src/plugins/builtin/alerts/cli.ts +380 -82
- package/src/plugins/builtin/alerts/command.ts +31 -0
- package/src/plugins/builtin/alerts/constants.ts +1 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +19 -4
- package/src/plugins/builtin/alerts/fired-log.ts +113 -8
- package/src/plugins/builtin/alerts/format.ts +80 -4
- package/src/plugins/builtin/alerts/headless.ts +30 -7
- package/src/plugins/builtin/alerts/history-rows.ts +7 -3
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +135 -22
- package/src/plugins/builtin/alerts/live.ts +3 -3
- package/src/plugins/builtin/alerts/metric-command.ts +134 -0
- package/src/plugins/builtin/alerts/metric-data.ts +111 -0
- package/src/plugins/builtin/alerts/metric-model.ts +324 -0
- package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
- package/src/plugins/builtin/alerts/pane.tsx +90 -39
- package/src/plugins/builtin/alerts/quotes.ts +6 -0
- package/src/plugins/builtin/alerts/storage.ts +37 -10
- package/src/plugins/builtin/alerts/types.ts +7 -0
- package/src/plugins/builtin/analytics/index.tsx +2 -1
- package/src/plugins/builtin/analytics/risk-client.ts +16 -5
- package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
- package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
- package/src/plugins/builtin/analytics/risk-model.ts +55 -9
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
- package/src/plugins/builtin/attention/index.tsx +2 -1
- package/src/plugins/builtin/attention/listing.ts +14 -0
- package/src/plugins/builtin/backtest/headless.ts +10 -5
- package/src/plugins/builtin/backtest/pane.tsx +9 -4
- package/src/plugins/builtin/backtest/presets.ts +29 -3
- package/src/plugins/builtin/broker-manager/index.tsx +10 -5
- package/src/plugins/builtin/broker-manager/model.ts +6 -1
- package/src/plugins/builtin/broker-trading/controller.ts +22 -12
- package/src/plugins/builtin/broker-trading/index.tsx +13 -1
- package/src/plugins/builtin/broker-trading/order-feed.ts +9 -4
- package/src/plugins/builtin/broker-trading/pane.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +12 -4
- package/src/plugins/builtin/buildout/format.ts +38 -0
- package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
- package/src/plugins/builtin/buildout/table-model.ts +23 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +7 -3
- package/src/plugins/builtin/catalysts/model.ts +2 -1
- package/src/plugins/builtin/changelog/index.tsx +9 -6
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +6 -1
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +1 -1
- package/src/plugins/builtin/chart-composer/cli-options.ts +9 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +12 -2
- package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -2
- package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +7 -5
- package/src/plugins/builtin/chart-composer/formula.ts +71 -18
- package/src/plugins/builtin/chart-composer/headless-schema.ts +21 -4
- package/src/plugins/builtin/chart-composer/headless.ts +19 -3
- package/src/plugins/builtin/chart-composer/index.tsx +1 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +53 -9
- package/src/plugins/builtin/chart-composer/presets.ts +50 -15
- package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
- package/src/plugins/builtin/chart-composer/session-history.ts +18 -9
- package/src/plugins/builtin/chart-composer/settings.ts +27 -0
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +40 -26
- package/src/plugins/builtin/chat/content/command-suggestions.ts +93 -0
- package/src/plugins/builtin/chat/content/composer.tsx +13 -6
- package/src/plugins/builtin/chat/content/footer.tsx +6 -3
- package/src/plugins/builtin/chat/content/index.tsx +50 -21
- package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
- package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
- package/src/plugins/builtin/chat/index.tsx +23 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
- package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
- package/src/plugins/builtin/chat/pane-links/commands.ts +271 -0
- package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
- package/src/plugins/builtin/chat/pane-links/open.ts +8 -1
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
- package/src/plugins/builtin/clinical-trials/model.ts +0 -9
- package/src/plugins/builtin/clinical-trials/pane.tsx +15 -22
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +8 -6
- package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -1
- package/src/plugins/builtin/company-attention/building.tsx +5 -1
- package/src/plugins/builtin/company-attention/client.ts +8 -9
- package/src/plugins/builtin/company-attention/evidence.ts +4 -1
- package/src/plugins/builtin/company-attention/moves.tsx +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +9 -2
- package/src/plugins/builtin/company-attention/signals.tsx +5 -1
- package/src/plugins/builtin/correlation/headless.ts +13 -5
- package/src/plugins/builtin/correlation/history.ts +22 -0
- package/src/plugins/builtin/cot/client.ts +22 -18
- package/src/plugins/builtin/cot/headless.ts +15 -10
- package/src/plugins/builtin/cot/model.ts +14 -1
- package/src/plugins/builtin/cot/pane.tsx +22 -14
- package/src/plugins/builtin/credit-boards/client.ts +6 -10
- package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
- package/src/plugins/builtin/credit-conditions/model.ts +4 -0
- package/src/plugins/builtin/credit-conditions/series.ts +3 -1
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
- package/src/plugins/builtin/credit-documents/export.ts +173 -0
- package/src/plugins/builtin/credit-documents/headless.ts +7 -7
- package/src/plugins/builtin/credit-documents/model.ts +104 -14
- package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
- package/src/plugins/builtin/custom-view/sources.ts +2 -0
- package/src/plugins/builtin/dividend-yield/client.ts +131 -23
- package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
- package/src/plugins/builtin/dividend-yield/model.ts +8 -5
- package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
- package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
- package/src/plugins/builtin/dividend-yield/types.ts +20 -2
- package/src/plugins/builtin/dividend-yield/view.ts +30 -2
- package/src/plugins/builtin/docs/targets.ts +5 -1
- package/src/plugins/builtin/earnings/board-model.ts +16 -15
- package/src/plugins/builtin/earnings/board.tsx +62 -71
- package/src/plugins/builtin/earnings/headless.ts +40 -4
- package/src/plugins/builtin/earnings/scope.ts +31 -43
- package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
- package/src/plugins/builtin/earnings-calls/format.ts +31 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +7 -2
- package/src/plugins/builtin/earnings-calls/model.ts +6 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +5 -4
- package/src/plugins/builtin/econ/calendar-model.ts +14 -9
- package/src/plugins/builtin/econ/figures.ts +72 -0
- package/src/plugins/builtin/econ/index.tsx +33 -3
- package/src/plugins/builtin/econ/types.ts +4 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +85 -35
- package/src/plugins/builtin/econ-statistics/stats.ts +37 -9
- package/src/plugins/builtin/econ-statistics/view.ts +3 -0
- package/src/plugins/builtin/equity-screener/categories.ts +179 -0
- package/src/plugins/builtin/equity-screener/client.ts +4 -2
- package/src/plugins/builtin/equity-screener/headless.ts +144 -13
- package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
- package/src/plugins/builtin/equity-screener/model.ts +99 -10
- package/src/plugins/builtin/equity-screener/pane.tsx +70 -15
- package/src/plugins/builtin/exposure/charts.tsx +2 -2
- package/src/plugins/builtin/exposure/model.ts +13 -1
- package/src/plugins/builtin/exposure/pane.tsx +4 -4
- package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
- package/src/plugins/builtin/futures/index.tsx +1 -0
- package/src/plugins/builtin/futures/model.ts +2 -1
- package/src/plugins/builtin/futures/table.tsx +2 -2
- package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
- package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
- package/src/plugins/builtin/fx-matrix/client.ts +11 -3
- package/src/plugins/builtin/fx-matrix/headless.ts +6 -3
- package/src/plugins/builtin/fx-matrix/index.tsx +16 -4
- package/src/plugins/builtin/fx-matrix/live-legs.ts +54 -3
- package/src/plugins/builtin/gpu/headless.ts +8 -2
- package/src/plugins/builtin/help/function-index.ts +4 -1
- package/src/plugins/builtin/help/index.tsx +1 -0
- package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
- package/src/plugins/builtin/help/shortcut-model.ts +1 -1
- package/src/plugins/builtin/holders/fund-holders.ts +51 -0
- package/src/plugins/builtin/holders/headless.ts +18 -1
- package/src/plugins/builtin/iv-history/client.ts +52 -11
- package/src/plugins/builtin/iv-history/format.ts +36 -23
- package/src/plugins/builtin/iv-history/headless.ts +36 -18
- package/src/plugins/builtin/iv-history/index.tsx +2 -2
- package/src/plugins/builtin/iv-history/model.ts +163 -27
- package/src/plugins/builtin/iv-history/pane.tsx +10 -6
- package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
- package/src/plugins/builtin/iv-history/universe.ts +5 -1
- package/src/plugins/builtin/jobs/client.ts +25 -29
- package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
- package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
- package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
- package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
- package/src/plugins/builtin/macro-day/pane.tsx +7 -5
- package/src/plugins/builtin/macro-day/release-table.ts +2 -2
- package/src/plugins/builtin/market-heatmap/data.ts +8 -33
- package/src/plugins/builtin/market-movers/client.ts +25 -7
- package/src/plugins/builtin/market-movers/footer.ts +2 -2
- package/src/plugins/builtin/market-movers/headless.ts +32 -12
- package/src/plugins/builtin/market-movers/index.tsx +26 -14
- package/src/plugins/builtin/market-movers/min-float.ts +74 -0
- package/src/plugins/builtin/market-movers/model.ts +4 -1
- package/src/plugins/builtin/market-movers/screener.ts +14 -0
- package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
- package/src/plugins/builtin/market-movers/session-table.ts +4 -3
- package/src/plugins/builtin/market-movers/table.ts +17 -5
- package/src/plugins/builtin/members/breadth-pane.tsx +82 -0
- package/src/plugins/builtin/members/client.ts +19 -4
- package/src/plugins/builtin/members/headless.ts +20 -7
- package/src/plugins/builtin/members/index.tsx +9 -9
- package/src/plugins/builtin/members/model.ts +23 -4
- package/src/plugins/builtin/members/pane.tsx +25 -15
- package/src/plugins/builtin/news/index.tsx +1 -0
- package/src/plugins/builtin/news/wire/categories.ts +19 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
- package/src/plugins/builtin/openfda/client.ts +14 -2
- package/src/plugins/builtin/openfda/index.tsx +3 -2
- package/src/plugins/builtin/openfda/model.ts +9 -0
- package/src/plugins/builtin/openfda/pane.tsx +42 -6
- package/src/plugins/builtin/options/analytics.ts +54 -6
- package/src/plugins/builtin/options/enrichment.ts +17 -5
- package/src/plugins/builtin/options/model-spot.ts +5 -2
- package/src/plugins/builtin/options/strike-window.ts +2 -1
- package/src/plugins/builtin/options/table.ts +6 -9
- package/src/plugins/builtin/options/types.ts +2 -0
- package/src/plugins/builtin/options/view.tsx +42 -12
- package/src/plugins/builtin/options-positioning/client.ts +30 -0
- package/src/plugins/builtin/options-positioning/headless.ts +74 -21
- package/src/plugins/builtin/options-positioning/index.tsx +4 -4
- package/src/plugins/builtin/options-positioning/model.ts +122 -14
- package/src/plugins/builtin/options-positioning/pane.tsx +87 -42
- package/src/plugins/builtin/options-scenario/client.ts +116 -47
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
- package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
- package/src/plugins/builtin/options-scenario/csp.ts +8 -2
- package/src/plugins/builtin/options-scenario/index.tsx +9 -7
- package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
- package/src/plugins/builtin/pe-band/model.ts +12 -49
- package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
- package/src/plugins/builtin/perps/cascade.ts +236 -0
- package/src/plugins/builtin/perps/client.ts +56 -2
- package/src/plugins/builtin/perps/freshness.ts +12 -10
- package/src/plugins/builtin/perps/headless.ts +65 -9
- package/src/plugins/builtin/perps/index.tsx +7 -5
- package/src/plugins/builtin/perps/live-rows.ts +10 -3
- package/src/plugins/builtin/perps/model.ts +18 -4
- package/src/plugins/builtin/perps/pane.tsx +32 -31
- package/src/plugins/builtin/perps/status-line.ts +25 -0
- package/src/plugins/builtin/plugin-module.ts +5 -1
- package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
- package/src/plugins/builtin/portfolio-list/cli/render.ts +12 -7
- package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +4 -1
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +3 -1
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
- package/src/plugins/builtin/portfolio-list/table.tsx +11 -3
- package/src/plugins/builtin/primary-dealers/client.ts +13 -38
- package/src/plugins/builtin/rate-path/pane.tsx +2 -2
- package/src/plugins/builtin/realized-vol/index.tsx +2 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/client.ts +18 -4
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
- package/src/plugins/builtin/relative-rotation/model.ts +16 -40
- package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
- package/src/plugins/builtin/research/event-model.ts +10 -8
- package/src/plugins/builtin/research/headless.ts +1 -1
- package/src/plugins/builtin/research/relative-valuation-headless.ts +5 -1
- package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +11 -9
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
- package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
- package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
- package/src/plugins/builtin/scanner/feed.ts +2 -2
- package/src/plugins/builtin/scanner/flow-model.ts +50 -4
- package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
- package/src/plugins/builtin/scanner/flow-session.ts +146 -0
- package/src/plugins/builtin/scanner/headless.ts +204 -35
- package/src/plugins/builtin/scanner/index.ts +40 -6
- package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
- package/src/plugins/builtin/scanner/live-feed.ts +168 -0
- package/src/plugins/builtin/scanner/live-headless.ts +138 -0
- package/src/plugins/builtin/scanner/live-model.ts +362 -0
- package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
- package/src/plugins/builtin/scanner/live-track.ts +186 -0
- package/src/plugins/builtin/scanner/lock-note.ts +3 -2
- package/src/plugins/builtin/seasonality/headless.ts +10 -1
- package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
- package/src/plugins/builtin/sec/fund-facts.ts +116 -34
- package/src/plugins/builtin/sec/headless.ts +2 -1
- package/src/plugins/builtin/series-inventory.ts +3 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +3 -2
- package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
- package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
- package/src/plugins/builtin/shared/earnings-report.ts +2 -2
- package/src/plugins/builtin/shared/job-posting.ts +1 -0
- package/src/plugins/builtin/shared/macro-releases.ts +65 -0
- package/src/plugins/builtin/shared/members-menu.tsx +3 -2
- package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
- package/src/plugins/builtin/shared/report-freshness.ts +3 -2
- package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
- package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
- package/src/plugins/builtin/shared/ticker-company.ts +77 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +10 -3
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
- package/src/plugins/builtin/shared/volatility/pricing.ts +26 -1
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
- package/src/plugins/builtin/themes/headless.ts +6 -4
- package/src/plugins/builtin/themes/model.ts +17 -8
- package/src/plugins/builtin/themes/pane.tsx +7 -7
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
- package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
- package/src/plugins/builtin/ticker-detail/overview/model.ts +1 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +6 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -19
- package/src/plugins/builtin/treasury-daily/client.ts +41 -5
- package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
- package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
- package/src/plugins/builtin/treasury-daily/model.ts +50 -3
- package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
- package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
- package/src/plugins/builtin/vol-surface/client.ts +9 -17
- package/src/plugins/builtin/vol-surface/headless.ts +63 -14
- package/src/plugins/builtin/vol-surface/index.tsx +2 -2
- package/src/plugins/builtin/vol-surface/model.ts +22 -7
- package/src/plugins/builtin/vol-surface/pane.tsx +48 -9
- package/src/plugins/builtin/vol-surface/tables.ts +31 -3
- package/src/plugins/builtin/volatility/dvol.ts +46 -0
- package/src/plugins/builtin/volatility/index.tsx +2 -2
- package/src/plugins/builtin/volatility/pane.tsx +4 -4
- package/src/plugins/builtin/volatility/series.ts +26 -0
- package/src/plugins/builtin/world-indices/footer.ts +1 -1
- package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
- package/src/plugins/catalog-browser.ts +13 -8
- package/src/plugins/catalog-manifest.ts +2 -1
- package/src/plugins/marketplace/model.ts +18 -5
- package/src/portfolio/column-values.ts +5 -5
- package/src/portfolio/futures-positions.ts +6 -3
- package/src/portfolio/position-quantity.ts +15 -9
- package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
- package/src/remote/resources.ts +2 -1
- package/src/renderers/browser/app-services.ts +1 -7
- package/src/renderers/browser/config-host.ts +2 -55
- package/src/renderers/browser/main.tsx +7 -57
- package/src/renderers/dom/data-table/row.tsx +26 -0
- package/src/renderers/dom/desktop/list-view.tsx +13 -10
- package/src/renderers/dom/desktop/query-bar.tsx +4 -2
- package/src/renderers/dom/desktop/select-field.tsx +4 -2
- package/src/renderers/dom/host/chart-surface.tsx +21 -0
- package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +29 -7
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
- package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +173 -5
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
- package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
- package/src/renderers/electrobun/bun/index.ts +25 -1
- package/src/renderers/electrobun/shared/app-name.ts +30 -0
- package/src/renderers/electrobun/shared/protocol.ts +10 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
- package/src/renderers/electrobun/view/main.tsx +24 -1
- package/src/renderers/electrobun/view/news-source.ts +3 -1
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
- package/src/renderers/electrobun/view/view-ids.ts +85 -0
- package/src/renderers/opentui/start.tsx +5 -0
- package/src/renderers/opentui/toast-host.tsx +71 -43
- package/src/series/registry.ts +1 -0
- package/src/series/types.ts +6 -0
- package/src/series/validate.ts +1 -0
- package/src/sources/gloomberb-cloud/index.ts +1 -0
- package/src/sources/gloomberb-cloud/news.ts +47 -7
- package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
- package/src/sources/provider-router/batches.ts +10 -2
- package/src/sources/provider-router/financial-routes.ts +3 -3
- package/src/sources/provider-router/financials.ts +15 -3
- package/src/sources/provider-router/history.ts +28 -7
- package/src/sources/provider-router/index.ts +149 -10
- package/src/sources/provider-router/search.ts +13 -2
- package/src/state/app/context/index.tsx +3 -0
- package/src/state/ticker-cleanup.ts +50 -0
- package/src/sync/auth-transition.ts +19 -9
- package/src/sync/baseline.ts +10 -4
- package/src/sync/controller.ts +70 -19
- package/src/sync/core-contributors.ts +90 -31
- package/src/sync/react.ts +4 -1
- package/src/sync/types.ts +3 -0
- package/src/telemetry/stall-reports-dom.ts +38 -0
- package/src/telemetry/stall-reports-node.ts +75 -0
- package/src/telemetry/stall-reports.ts +214 -0
- package/src/telemetry/usage-counts.ts +0 -18
- package/src/test-support/preload.ts +14 -0
- package/src/theme/colors.ts +8 -0
- package/src/theme/themes.ts +10 -0
- package/src/tickers/company-name.ts +103 -3
- package/src/tickers/listing-venues.ts +38 -3
- package/src/tickers/search/bare-symbol.ts +36 -0
- package/src/tickers/search/index.ts +36 -7
- package/src/tickers/search/ranking.ts +10 -1
- package/src/tickers/search/types.ts +5 -0
- package/src/tickers/terminal-codes.ts +19 -0
- package/src/time-series/alignment.ts +1 -1
- package/src/time-series/base-series.ts +13 -5
- package/src/time-series/daily-valuation.ts +62 -0
- package/src/time-series/economic.ts +18 -4
- package/src/time-series/field-catalog.ts +2 -4
- package/src/time-series/filed-trailing-eps.ts +197 -0
- package/src/time-series/forward-valuation.ts +32 -0
- package/src/time-series/fundamentals.ts +198 -7
- package/src/time-series/hooks.ts +1 -0
- package/src/time-series/ice-credit.ts +3 -0
- package/src/time-series/price-comparison.ts +30 -2
- package/src/time-series/price-units.ts +72 -2
- package/src/time-series/resolve-context.ts +7 -1
- package/src/time-series/resolve.ts +116 -15
- package/src/time-series/series-presentation.ts +40 -6
- package/src/time-series/session-bar.ts +11 -0
- package/src/time-series/spec.ts +5 -3
- package/src/time-series/studies.ts +278 -74
- package/src/time-series/total-return.ts +160 -0
- package/src/time-series/transforms.ts +3 -3
- package/src/time-series/types.ts +27 -1
- package/src/time-series/valuation-releases.ts +39 -0
- package/src/types/data-provider.ts +9 -1
- package/src/types/desktop-window.ts +2 -0
- package/src/types/financials.ts +73 -2
- package/src/types/headless.ts +61 -5
- package/src/types/instrument.ts +3 -0
- package/src/types/news-source.ts +1 -0
- package/src/types/plugin.ts +10 -1
- package/src/ui/host.tsx +3 -0
- package/src/updater/command-names.ts +12 -7
- package/src/updater/failure.ts +4 -1
- package/src/utils/cli-output.ts +42 -1
- package/src/utils/crypto-pair.ts +44 -0
- package/src/utils/financial-statements.ts +6 -1
- package/src/utils/forward-dividend.ts +2 -0
- package/src/utils/fundamentals.ts +24 -3
- package/src/utils/fx-market-hours.ts +26 -3
- package/src/utils/main-thread-stall.ts +35 -2
- package/src/utils/market-capitalization.ts +24 -1
- package/src/utils/network-failure.ts +9 -6
- package/src/utils/option-expiry.ts +48 -1
- package/src/utils/options.ts +10 -0
- package/src/utils/plugin-proxy-hosts.json +1 -0
- package/src/utils/price-history.ts +12 -1
- package/src/utils/shell-word.ts +8 -0
- package/src/utils/trailing-dividend.ts +53 -4
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
- package/src/renderers/browser/first-screen.ts +0 -193
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { logFailure } from "../utils/log-failure";
|
|
2
2
|
import { httpFetch, isHttpFetchStreaming } from "../utils/http-transport";
|
|
3
|
-
import {
|
|
3
|
+
import { OperationTimeoutError } from "../utils/async-deadline";
|
|
4
4
|
import {
|
|
5
5
|
ApiRequestError,
|
|
6
6
|
parseApiErrorCode,
|
|
@@ -16,17 +16,59 @@ import {
|
|
|
16
16
|
type ConnectionHealthRegistry,
|
|
17
17
|
} from "../core/connection-health";
|
|
18
18
|
import { SESSION_COOKIE_NAMES } from "./session-cookie";
|
|
19
|
-
import { asDataServiceFailure } from "../utils/network-failure";
|
|
19
|
+
import { asDataServiceFailure, DataServiceUnreachableError } from "../utils/network-failure";
|
|
20
20
|
|
|
21
21
|
/** The public Gloom Cloud API, which the web app's same-origin `/api` path forwards to. */
|
|
22
22
|
export const DEFAULT_API_URL = "https://api.gloom.sh";
|
|
23
|
+
/**
|
|
24
|
+
* How long a request waits for the service to answer at all. Nothing back by
|
|
25
|
+
* then, and nothing else answered meanwhile, is a hung connection: the request
|
|
26
|
+
* fails as the data service being unreachable, as a refused one does.
|
|
27
|
+
*/
|
|
23
28
|
const DEFAULT_MARKET_REQUEST_TIMEOUT_MS = 10_000;
|
|
29
|
+
/**
|
|
30
|
+
* A search, which a command and a keystroke wait on, gives up on a connection
|
|
31
|
+
* that sends nothing back sooner. A slow search on a service that answers
|
|
32
|
+
* (some take five seconds) still gets the full market deadline.
|
|
33
|
+
*/
|
|
34
|
+
const SEARCH_ANSWER_TIMEOUT_MS = 4_000;
|
|
35
|
+
/**
|
|
36
|
+
* Once a request went unanswered, later ones wait this long for an answer,
|
|
37
|
+
* until any answer comes back: a hung connection is not waited out in full by
|
|
38
|
+
* every request a command or a pane makes after it.
|
|
39
|
+
*/
|
|
40
|
+
const UNREACHABLE_REQUEST_TIMEOUT_MS = 3_000;
|
|
41
|
+
/**
|
|
42
|
+
* Right after a request hung with nothing back, the requests that follow it
|
|
43
|
+
* (a fallback, the next step of a command) fail at once rather than each
|
|
44
|
+
* waiting out a connection that just proved dead. Past this they try again.
|
|
45
|
+
*/
|
|
46
|
+
const HUNG_FAIL_FAST_MS = 5_000;
|
|
24
47
|
const DEFAULT_RESEARCH_REQUEST_TIMEOUT_MS = 45_000;
|
|
48
|
+
/** Requests outside market reads (saves, uploads, drafts) may take the server this long once it is known to answer. */
|
|
49
|
+
const DEFAULT_SERVICE_REQUEST_LIMIT_MS = 120_000;
|
|
50
|
+
const UPLOAD_REQUEST_LIMIT_MS = 300_000;
|
|
51
|
+
/**
|
|
52
|
+
* How long the check that the service answers at all waits. It runs this long
|
|
53
|
+
* before a request's answer deadline, unless something answered meanwhile, so
|
|
54
|
+
* one slow request on a service that answers is waited for and a dead
|
|
55
|
+
* connection is not.
|
|
56
|
+
*/
|
|
57
|
+
const SERVICE_PROBE_TIMEOUT_MS = 3_000;
|
|
58
|
+
const SERVICE_PROBE_PATH = "/health";
|
|
25
59
|
// Research may fill missing sections after a primary read; quote/history reads remain latency bounded.
|
|
26
60
|
const RESEARCH_MARKET_PATHS = new Set([
|
|
27
61
|
"/market/dividends", "/market/short-interest", "/market/movers", "/market/trending",
|
|
28
62
|
"/market/heatmap", "/market/earnings-calendar",
|
|
29
63
|
]);
|
|
64
|
+
|
|
65
|
+
/** When a request gives up: without any answer from the service, and in all. */
|
|
66
|
+
interface RequestDeadline {
|
|
67
|
+
answerMs: number;
|
|
68
|
+
limitMs: number;
|
|
69
|
+
/** When to check that the service answers at all, if nothing has by then; null when the deadline is too short for it. */
|
|
70
|
+
probeAtMs: number | null;
|
|
71
|
+
}
|
|
30
72
|
/** Local status for "this runtime cannot stream", never returned by the server. */
|
|
31
73
|
export const STREAMING_UNSUPPORTED_STATUS = 0;
|
|
32
74
|
|
|
@@ -74,6 +116,8 @@ type CloudApiUploadTransport = (request: CloudApiUploadRequest) => Promise<Cloud
|
|
|
74
116
|
let cloudApiFetchTransport: CloudApiFetchTransport = httpFetch;
|
|
75
117
|
let cloudApiUploadTransport: CloudApiUploadTransport | null = null;
|
|
76
118
|
let cloudApiTransportInstalled = false;
|
|
119
|
+
/** Counts installed transports, so what a client learned of one connection is not applied to the next. */
|
|
120
|
+
let cloudApiTransportGeneration = 0;
|
|
77
121
|
let cloudApiFetchStreaming = true;
|
|
78
122
|
let cloudApiStreamFetch: CloudApiStreamFetch | null = null;
|
|
79
123
|
|
|
@@ -83,6 +127,7 @@ export function setCloudApiFetchTransport(
|
|
|
83
127
|
): void {
|
|
84
128
|
cloudApiFetchTransport = transport ?? httpFetch;
|
|
85
129
|
cloudApiTransportInstalled = !!transport;
|
|
130
|
+
cloudApiTransportGeneration += 1;
|
|
86
131
|
cloudApiFetchStreaming = transport ? (options.streaming ?? false) : true;
|
|
87
132
|
cloudApiStreamFetch = transport ? options.streamFetch ?? null : null;
|
|
88
133
|
}
|
|
@@ -163,22 +208,6 @@ function throwIfRequestAborted(signal: AbortSignal | null | undefined): void {
|
|
|
163
208
|
);
|
|
164
209
|
}
|
|
165
210
|
|
|
166
|
-
/**
|
|
167
|
-
* Sends one request, saying the same thing whichever fetch failed to connect
|
|
168
|
-
* (Bun's "Unable to connect", a browser's "Failed to fetch", a refused proxy):
|
|
169
|
-
* every command, pane and status line then reads "Gloom couldn't reach its
|
|
170
|
-
* data service", and code that falls back to a saved copy can tell it apart.
|
|
171
|
-
* A caller's abort stays an abort.
|
|
172
|
-
*/
|
|
173
|
-
async function reachService<R>(fetch: () => Promise<R>, signal: AbortSignal | null | undefined): Promise<R> {
|
|
174
|
-
try {
|
|
175
|
-
return await fetch();
|
|
176
|
-
} catch (error) {
|
|
177
|
-
if (signal?.aborted) throw error;
|
|
178
|
-
throw asDataServiceFailure(error);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
211
|
export class CloudApiRequestTransport {
|
|
183
212
|
private sessionToken: string | null = null;
|
|
184
213
|
private sessionCookieName: SessionCookieName | null = null;
|
|
@@ -188,6 +217,17 @@ export class CloudApiRequestTransport {
|
|
|
188
217
|
private readonly marketRequestTimeoutMs: number;
|
|
189
218
|
private readonly researchRequestTimeoutMs: number;
|
|
190
219
|
private readonly connectionHealth: ConnectionHealthRegistry;
|
|
220
|
+
/** Answers received from the service, by any request: a request that sees this grow knows the connection works. */
|
|
221
|
+
private answers = 0;
|
|
222
|
+
/** The last request went unanswered (refused or hung) and nothing has answered since. */
|
|
223
|
+
private unreachable = false;
|
|
224
|
+
/** When a request last hung with nothing back, while nothing has answered since. */
|
|
225
|
+
private hungAt: number | null = null;
|
|
226
|
+
/** The installed transport the two above were learned on. */
|
|
227
|
+
private connectionGeneration = cloudApiTransportGeneration;
|
|
228
|
+
/** Requests waiting under a deadline: the check that the service answers runs only while one is. */
|
|
229
|
+
private pending = 0;
|
|
230
|
+
private probe: AbortController | null = null;
|
|
191
231
|
|
|
192
232
|
readonly baseUrl = getCloudApiBaseUrl();
|
|
193
233
|
|
|
@@ -280,7 +320,7 @@ export class CloudApiRequestTransport {
|
|
|
280
320
|
GLOOM_CLOUD_HTTP_CONNECTION_ID,
|
|
281
321
|
operation,
|
|
282
322
|
async () => {
|
|
283
|
-
const response = await reachService(() => streamFetch(`${this.baseUrl}${path}`, {
|
|
323
|
+
const response = await this.reachService(() => streamFetch(`${this.baseUrl}${path}`, {
|
|
284
324
|
...options,
|
|
285
325
|
headers,
|
|
286
326
|
credentials: "include",
|
|
@@ -301,37 +341,178 @@ export class CloudApiRequestTransport {
|
|
|
301
341
|
}
|
|
302
342
|
|
|
303
343
|
async request<T>(path: string, options?: RequestInit, canApplySession: () => boolean = () => true): Promise<T> {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
344
|
+
return this.withDeadline(path, this.deadlineFor(path), options?.signal, (signal) => this.performRequest<T>(path, {
|
|
345
|
+
...options,
|
|
346
|
+
signal,
|
|
347
|
+
}, canApplySession));
|
|
348
|
+
}
|
|
307
349
|
|
|
308
|
-
|
|
309
|
-
|
|
350
|
+
/**
|
|
351
|
+
* Every request's deadline. A market read or a search waits about ten
|
|
352
|
+
* seconds, research and requests outside market data longer. With nothing
|
|
353
|
+
* back from the service, a request gives up at ten seconds, a search at
|
|
354
|
+
* four, and any request at three after one went unanswered, until something
|
|
355
|
+
* answers again. Three seconds before that, a request still unanswered
|
|
356
|
+
* checks that the service answers at all, so one slow request on a working
|
|
357
|
+
* connection is waited for and a dead connection is not.
|
|
358
|
+
*/
|
|
359
|
+
private deadlineFor(path: string, limitMs?: number): RequestDeadline {
|
|
360
|
+
this.forgetOtherTransport();
|
|
361
|
+
const pathname = path.split("?")[0]!;
|
|
362
|
+
const market = pathname.startsWith("/market/");
|
|
363
|
+
const limit = limitMs ?? (!market ? DEFAULT_SERVICE_REQUEST_LIMIT_MS
|
|
364
|
+
: RESEARCH_MARKET_PATHS.has(pathname) ? this.researchRequestTimeoutMs : this.marketRequestTimeoutMs);
|
|
365
|
+
let answerMs = pathname === "/market/search"
|
|
366
|
+
? Math.min(this.marketRequestTimeoutMs, SEARCH_ANSWER_TIMEOUT_MS)
|
|
367
|
+
: this.marketRequestTimeoutMs;
|
|
368
|
+
if (this.unreachable) answerMs = Math.min(answerMs, UNREACHABLE_REQUEST_TIMEOUT_MS);
|
|
369
|
+
return {
|
|
370
|
+
answerMs,
|
|
371
|
+
limitMs: Math.max(limit, answerMs),
|
|
372
|
+
probeAtMs: answerMs >= SERVICE_PROBE_TIMEOUT_MS ? answerMs - SERVICE_PROBE_TIMEOUT_MS : null,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Runs one request under its deadline. Without an answer from the service by
|
|
378
|
+
* `answerMs` (from this request, any other, or the check that the service
|
|
379
|
+
* answers at all), the connection is taken as hung: the request is aborted
|
|
380
|
+
* and fails as the data service being unreachable, as a refused connection
|
|
381
|
+
* does. A service that answers but is slow gets until `limitMs`, then the
|
|
382
|
+
* request times out. A caller's abort stays an abort.
|
|
383
|
+
*/
|
|
384
|
+
private async withDeadline<T>(
|
|
385
|
+
path: string,
|
|
386
|
+
deadline: RequestDeadline,
|
|
387
|
+
callerSignal: AbortSignal | null | undefined,
|
|
388
|
+
run: (signal: AbortSignal) => Promise<T>,
|
|
389
|
+
): Promise<T> {
|
|
310
390
|
const controller = new AbortController();
|
|
311
|
-
const callerSignal = options?.signal;
|
|
312
391
|
const abortFromCaller = () => controller.abort(callerSignal?.reason);
|
|
313
392
|
if (callerSignal?.aborted) {
|
|
314
393
|
abortFromCaller();
|
|
315
394
|
} else {
|
|
316
395
|
callerSignal?.addEventListener("abort", abortFromCaller, { once: true });
|
|
317
396
|
}
|
|
318
|
-
|
|
397
|
+
const answersAtStart = this.answers;
|
|
398
|
+
const answered = () => this.answers > answersAtStart;
|
|
399
|
+
const generation = cloudApiTransportGeneration;
|
|
400
|
+
const what = path.startsWith("/market/") ? "Cloud market request" : "Cloud request";
|
|
401
|
+
const timedOut = (ms: number) => new OperationTimeoutError(`${what} timed out after ${ms}ms: ${path.split("?")[0]}`);
|
|
402
|
+
const timers: Array<ReturnType<typeof setTimeout>> = [];
|
|
403
|
+
if (this.hungAt != null && Date.now() - this.hungAt < HUNG_FAIL_FAST_MS && !controller.signal.aborted) {
|
|
404
|
+
callerSignal?.removeEventListener("abort", abortFromCaller);
|
|
405
|
+
throw new DataServiceUnreachableError(new OperationTimeoutError(`${what} not sent: the last one got no answer: ${path.split("?")[0]}`));
|
|
406
|
+
}
|
|
407
|
+
this.pending += 1;
|
|
319
408
|
try {
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
409
|
+
const work = run(controller.signal);
|
|
410
|
+
return await new Promise<T>((resolve, reject) => {
|
|
411
|
+
const fail = (error: Error) => {
|
|
412
|
+
reject(error);
|
|
413
|
+
controller.abort(error);
|
|
414
|
+
};
|
|
415
|
+
work.then(resolve, reject);
|
|
416
|
+
if (deadline.probeAtMs != null) {
|
|
417
|
+
timers.push(setTimeout(() => {
|
|
418
|
+
if (!answered()) this.checkServiceAnswers();
|
|
419
|
+
}, deadline.probeAtMs));
|
|
420
|
+
}
|
|
421
|
+
timers.push(setTimeout(() => {
|
|
422
|
+
// The caller gave up first: its abort settles the request, and says nothing of the connection.
|
|
423
|
+
if (callerSignal?.aborted) return;
|
|
424
|
+
if (!answered()) {
|
|
425
|
+
this.recordNoAnswer(generation, true);
|
|
426
|
+
fail(new DataServiceUnreachableError(timedOut(deadline.answerMs)));
|
|
427
|
+
} else if (deadline.limitMs > deadline.answerMs) {
|
|
428
|
+
timers.push(setTimeout(() => fail(timedOut(deadline.limitMs)), deadline.limitMs - deadline.answerMs));
|
|
429
|
+
} else {
|
|
430
|
+
fail(timedOut(deadline.answerMs));
|
|
431
|
+
}
|
|
432
|
+
}, deadline.answerMs));
|
|
433
|
+
});
|
|
330
434
|
} finally {
|
|
435
|
+
for (const timer of timers) clearTimeout(timer);
|
|
331
436
|
callerSignal?.removeEventListener("abort", abortFromCaller);
|
|
437
|
+
this.pending -= 1;
|
|
438
|
+
// Nothing waits on the check any more: it must not hold a command's process open.
|
|
439
|
+
if (this.pending === 0) this.probe?.abort();
|
|
332
440
|
}
|
|
333
441
|
}
|
|
334
442
|
|
|
443
|
+
/**
|
|
444
|
+
* Sends one request, saying the same thing whichever fetch failed to connect
|
|
445
|
+
* (Bun's "Unable to connect", a browser's "Failed to fetch", a refused proxy):
|
|
446
|
+
* every command, pane and status line then reads "Gloom couldn't reach its
|
|
447
|
+
* data service", and code that falls back to a saved copy can tell it apart.
|
|
448
|
+
* A caller's abort stays an abort. An answer of any status says the
|
|
449
|
+
* connection works, for the deadlines of the requests beside it.
|
|
450
|
+
*/
|
|
451
|
+
private async reachService<R>(fetch: () => Promise<R>, signal: AbortSignal | null | undefined): Promise<R> {
|
|
452
|
+
const generation = cloudApiTransportGeneration;
|
|
453
|
+
let response: R;
|
|
454
|
+
try {
|
|
455
|
+
response = await fetch();
|
|
456
|
+
} catch (error) {
|
|
457
|
+
if (signal?.aborted) throw error;
|
|
458
|
+
const failure = asDataServiceFailure(error);
|
|
459
|
+
if (failure instanceof DataServiceUnreachableError) this.recordNoAnswer(generation, false);
|
|
460
|
+
throw failure;
|
|
461
|
+
}
|
|
462
|
+
this.recordAnswer();
|
|
463
|
+
return response;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/** A new transport installed is a new connection: what failed on the last one says nothing about it. */
|
|
467
|
+
private forgetOtherTransport(): void {
|
|
468
|
+
if (this.fetchTransport || this.connectionGeneration === cloudApiTransportGeneration) return;
|
|
469
|
+
this.connectionGeneration = cloudApiTransportGeneration;
|
|
470
|
+
this.unreachable = false;
|
|
471
|
+
this.hungAt = null;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/** Something came back from the service: the connection works. */
|
|
475
|
+
private recordAnswer(): void {
|
|
476
|
+
this.answers += 1;
|
|
477
|
+
this.unreachable = false;
|
|
478
|
+
this.hungAt = null;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* A request sent on the transport installed as `generation` got no answer:
|
|
483
|
+
* refused, or `hung` with nothing back by its deadline. Once another
|
|
484
|
+
* transport is installed, what one sent on the last says nothing of it.
|
|
485
|
+
*/
|
|
486
|
+
private recordNoAnswer(generation: number, hung: boolean): void {
|
|
487
|
+
if (!this.fetchTransport && generation !== cloudApiTransportGeneration) return;
|
|
488
|
+
this.unreachable = true;
|
|
489
|
+
if (hung) this.hungAt = Date.now();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Asks the service for anything at all, once at a time, so a request that
|
|
494
|
+
* is slow can tell a slow server (which answers this) from a dead
|
|
495
|
+
* connection (which does not). Any status counts as an answer. It stops
|
|
496
|
+
* when nothing waits on it any more.
|
|
497
|
+
*/
|
|
498
|
+
private checkServiceAnswers(): void {
|
|
499
|
+
if (this.probe) return;
|
|
500
|
+
const controller = new AbortController();
|
|
501
|
+
const timer = setTimeout(() => controller.abort(), SERVICE_PROBE_TIMEOUT_MS);
|
|
502
|
+
const done = () => {
|
|
503
|
+
clearTimeout(timer);
|
|
504
|
+
if (this.probe === controller) this.probe = null;
|
|
505
|
+
};
|
|
506
|
+
// Done once given up on, even through a transport that ignores the abort.
|
|
507
|
+
controller.signal.addEventListener("abort", done, { once: true });
|
|
508
|
+
this.probe = controller;
|
|
509
|
+
(this.fetchTransport ?? cloudApiFetchTransport)(`${this.baseUrl}${SERVICE_PROBE_PATH}`, { signal: controller.signal })
|
|
510
|
+
.then(() => this.recordAnswer(), () => {
|
|
511
|
+
// Intentional ignore: an unanswered check only leaves the request it guards to its own deadline.
|
|
512
|
+
})
|
|
513
|
+
.finally(done);
|
|
514
|
+
}
|
|
515
|
+
|
|
335
516
|
/**
|
|
336
517
|
* POSTs raw bytes, such as an image, and parses the JSON answer like
|
|
337
518
|
* `request`. Progress is reported where the installed upload transport can
|
|
@@ -355,17 +536,17 @@ export class CloudApiRequestTransport {
|
|
|
355
536
|
url,
|
|
356
537
|
body,
|
|
357
538
|
headers: new Headers(init?.headers),
|
|
358
|
-
signal: options.signal,
|
|
539
|
+
signal: init?.signal ?? options.signal,
|
|
359
540
|
onProgress: options.onProgress,
|
|
360
541
|
})
|
|
361
542
|
: undefined;
|
|
362
|
-
return this.performRequest<T>(path, {
|
|
543
|
+
return this.withDeadline(path, this.deadlineFor(path, UPLOAD_REQUEST_LIMIT_MS), options.signal, (signal) => this.performRequest<T>(path, {
|
|
363
544
|
method: "POST",
|
|
364
545
|
headers,
|
|
365
546
|
// Typed arrays are valid fetch bodies; RequestInit's DOM typing lags behind.
|
|
366
547
|
body: body as BodyInit,
|
|
367
|
-
signal
|
|
368
|
-
}, () => true, send);
|
|
548
|
+
signal,
|
|
549
|
+
}, () => true, send));
|
|
369
550
|
}
|
|
370
551
|
|
|
371
552
|
private async performRequest<T>(
|
|
@@ -389,7 +570,7 @@ export class CloudApiRequestTransport {
|
|
|
389
570
|
|
|
390
571
|
const operation = `${options?.method ?? "GET"} ${path.split("?")[0]}`;
|
|
391
572
|
const request = async () => {
|
|
392
|
-
const res = await reachService(() => (send ?? this.fetchTransport ?? cloudApiFetchTransport)(
|
|
573
|
+
const res = await this.reachService(() => (send ?? this.fetchTransport ?? cloudApiFetchTransport)(
|
|
393
574
|
`${this.baseUrl}${path}`,
|
|
394
575
|
{
|
|
395
576
|
...options,
|
|
@@ -29,10 +29,7 @@ export type ResearchActivity =
|
|
|
29
29
|
| "onboarding_signed_in"
|
|
30
30
|
| "onboarding_pro_viewed"
|
|
31
31
|
| "onboarding_completed"
|
|
32
|
-
| "onboarding_skipped"
|
|
33
|
-
// The first action of a web visitor counted in the first-screen experiment,
|
|
34
|
-
// in that first session. Keep in sync with the server's list.
|
|
35
|
-
| "first_screen_engaged";
|
|
32
|
+
| "onboarding_skipped";
|
|
36
33
|
export type ResearchFeature =
|
|
37
34
|
| "overview"
|
|
38
35
|
| "chart"
|
|
@@ -49,8 +46,9 @@ const signinWallExperiment = createWallExperimentSession("wall_teaser_signin");
|
|
|
49
46
|
const upgradeExperiment = createUpgradeExperimentSession();
|
|
50
47
|
const WALL_VIEWS_SESSION_KEY = "gloomberb.wall-teaser.views";
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
const
|
|
49
|
+
// The desktop app also keeps a copy of these two on disk (electrobun/view/view-ids.ts).
|
|
50
|
+
export const ATTRIBUTION_STORAGE_KEY = "gloomberb.web.attribution";
|
|
51
|
+
export const ANONYMOUS_ID_STORAGE_KEY = "gloomberb.web.anonymous-id";
|
|
54
52
|
const HANDOFF_ID_KEY = "_gloom";
|
|
55
53
|
const ATTRIBUTION_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;
|
|
56
54
|
/** Another device's clock may run slightly ahead; a touch from a minute in the future is still fresh. */
|
|
@@ -461,10 +459,7 @@ function webExperimentAttribution(): { experiments?: string } {
|
|
|
461
459
|
* visitors on term.gloom.sh with an analytics id (no Do Not Track or Global
|
|
462
460
|
* Privacy Control) and not driven by automation are asked. See web-experiments.ts.
|
|
463
461
|
*/
|
|
464
|
-
export function exposeWebExperiment(
|
|
465
|
-
experiment: string,
|
|
466
|
-
{ placement, signal }: { placement?: string; signal?: AbortSignal } = {},
|
|
467
|
-
): Promise<string | null> {
|
|
462
|
+
export function exposeWebExperiment(experiment: string): Promise<string | null> {
|
|
468
463
|
if (!researchTelemetryAllowed()) return Promise.resolve(null);
|
|
469
464
|
if (getCurrentPluginTarget() !== "web") return Promise.resolve(null);
|
|
470
465
|
try {
|
|
@@ -481,8 +476,7 @@ export function exposeWebExperiment(
|
|
|
481
476
|
attribution: attributionPayload(),
|
|
482
477
|
experiment: key,
|
|
483
478
|
variant,
|
|
484
|
-
|
|
485
|
-
}, signal),
|
|
479
|
+
}),
|
|
486
480
|
});
|
|
487
481
|
} catch {
|
|
488
482
|
return Promise.resolve(null);
|
package/src/api-client/types.ts
CHANGED
|
@@ -516,6 +516,18 @@ export interface CloudEconEventPayload {
|
|
|
516
516
|
referencePeriod?: string | null;
|
|
517
517
|
/** Who publishes the release (Freddie Mac for the 30-year mortgage rate), and its page when one is named. */
|
|
518
518
|
source?: { name: string; url?: string };
|
|
519
|
+
/**
|
|
520
|
+
* The indicator this release is of, the same from one release to the next
|
|
521
|
+
* (`us-unemployment-rate` on every month's row), where `id` names the one
|
|
522
|
+
* row. Absent from a server that names none; exports leave the column empty.
|
|
523
|
+
*/
|
|
524
|
+
indicatorId?: string | null;
|
|
525
|
+
/**
|
|
526
|
+
* Where the forecast (the consensus) was read from, `week-feed` or
|
|
527
|
+
* `release-calendar`, and when that feed was read. Absent on a row with no
|
|
528
|
+
* forecast and on one kept before the read was recorded.
|
|
529
|
+
*/
|
|
530
|
+
consensus?: { source: string; readAt: string } | null;
|
|
519
531
|
}
|
|
520
532
|
|
|
521
533
|
/** One currency's short-term rate, as GET /cloud/econ/short-rates serves it. */
|
|
@@ -885,6 +897,13 @@ export interface CloudEarningsCallPayload {
|
|
|
885
897
|
* New York day). Absent from a server that predates it.
|
|
886
898
|
*/
|
|
887
899
|
callTimeKnown?: boolean;
|
|
900
|
+
/**
|
|
901
|
+
* "other" for an event that is not an earnings call (a deal call, a
|
|
902
|
+
* conference, an investor day), named by eventLabel and with no fiscal
|
|
903
|
+
* period; null when unclear. Older servers omit both.
|
|
904
|
+
*/
|
|
905
|
+
eventKind?: "earnings" | "other" | null;
|
|
906
|
+
eventLabel?: string | null;
|
|
888
907
|
}
|
|
889
908
|
|
|
890
909
|
interface CloudJobsSeriesPoint {
|
|
@@ -1249,6 +1268,13 @@ export interface CloudEarningsTranscriptPayload {
|
|
|
1249
1268
|
companyName: string | null;
|
|
1250
1269
|
fiscalYear: number | null;
|
|
1251
1270
|
fiscalQuarter: number | null;
|
|
1271
|
+
/**
|
|
1272
|
+
* "other" for an event that is not an earnings call (a deal call, a
|
|
1273
|
+
* conference, an investor day), named by eventLabel and with no fiscal
|
|
1274
|
+
* period; null when unclear. Older servers omit both.
|
|
1275
|
+
*/
|
|
1276
|
+
eventKind?: "earnings" | "other" | null;
|
|
1277
|
+
eventLabel?: string | null;
|
|
1252
1278
|
callAt: string | null;
|
|
1253
1279
|
timing: string | null;
|
|
1254
1280
|
webcastUrl: string | null;
|
|
@@ -1530,6 +1556,8 @@ export interface CloudNewsPayload {
|
|
|
1530
1556
|
export interface CloudNewsListResponse {
|
|
1531
1557
|
items: CloudNewsPayload[];
|
|
1532
1558
|
nextCursor: string | null;
|
|
1559
|
+
/** Which news the service answered with, when it says: the live wire, or the one held back for a free account. */
|
|
1560
|
+
access?: "realtime" | "delayed";
|
|
1533
1561
|
}
|
|
1534
1562
|
|
|
1535
1563
|
interface CloudTweetUserPayload {
|
|
@@ -1733,6 +1761,14 @@ export interface CloudMarketScreenerItem extends CloudMoverSessionFields {
|
|
|
1733
1761
|
exchange: string;
|
|
1734
1762
|
lastUpdated: number;
|
|
1735
1763
|
dataSource: "live";
|
|
1764
|
+
/** The listing's float as the equity screener serves it; absent where it serves none. */
|
|
1765
|
+
floatShares?: number;
|
|
1766
|
+
/** Set with a float the source states no measurement date for: `partial`. */
|
|
1767
|
+
floatSharesState?: "partial";
|
|
1768
|
+
/** Why the float is partial, as the server says it. */
|
|
1769
|
+
floatSharesReason?: string;
|
|
1770
|
+
/** When the statistics the float is read from were retrieved (ISO). */
|
|
1771
|
+
floatSharesRetrievedAt?: string;
|
|
1736
1772
|
}
|
|
1737
1773
|
|
|
1738
1774
|
export interface CloudMarketScreenerPayload {
|
|
@@ -1927,6 +1963,44 @@ export interface ScannerFlowHistoryPage {
|
|
|
1927
1963
|
hasMore: boolean;
|
|
1928
1964
|
}
|
|
1929
1965
|
|
|
1966
|
+
/**
|
|
1967
|
+
* Premium of a slice of the session's recorded prints by where it traded: at
|
|
1968
|
+
* or above the ask (bought) or at or below the bid (sold). Mid and unknown
|
|
1969
|
+
* prints count as neither.
|
|
1970
|
+
*/
|
|
1971
|
+
interface ScannerFlowSidePremium {
|
|
1972
|
+
callAsk: number;
|
|
1973
|
+
callBid: number;
|
|
1974
|
+
putAsk: number;
|
|
1975
|
+
putBid: number;
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
/** The session's prints in one time bucket, which starts at `at`. */
|
|
1979
|
+
export interface ScannerFlowSessionBucket extends ScannerFlowSidePremium {
|
|
1980
|
+
at: number;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
/** What one name printed at one expiry and strike during the session. */
|
|
1984
|
+
export interface ScannerFlowSessionStrike extends ScannerFlowSidePremium {
|
|
1985
|
+
expiry: string;
|
|
1986
|
+
strike: number;
|
|
1987
|
+
/** Every call print's premium, mid and unknown included. */
|
|
1988
|
+
callPremium: number;
|
|
1989
|
+
putPremium: number;
|
|
1990
|
+
prints: number;
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
/** The latest session's recorded prints under the FLOW pane's filters, summed. */
|
|
1994
|
+
export interface ScannerFlowSession {
|
|
1995
|
+
/** The New York date of the session; null before any print was recorded. */
|
|
1996
|
+
session: string | null;
|
|
1997
|
+
bucketMs: number;
|
|
1998
|
+
/** Buckets with a matching print, oldest first. */
|
|
1999
|
+
buckets: ScannerFlowSessionBucket[];
|
|
2000
|
+
/** Only when one name was asked for: most premium first. */
|
|
2001
|
+
strikes: ScannerFlowSessionStrike[] | null;
|
|
2002
|
+
}
|
|
2003
|
+
|
|
1930
2004
|
export type ScannerPayload = ScannerHiloPayload | ScannerFlowPayload;
|
|
1931
2005
|
|
|
1932
2006
|
/** What a scanner subscriber receives: data, or the entitlement refusal. */
|
|
@@ -14,6 +14,7 @@ export {
|
|
|
14
14
|
type KeyChordEventLike,
|
|
15
15
|
} from "./chord";
|
|
16
16
|
export {
|
|
17
|
+
coreActionOnChord,
|
|
17
18
|
describeKeybindingIssue,
|
|
18
19
|
isPaneKeybindingAction,
|
|
19
20
|
keyChordsOverlap,
|
|
@@ -32,6 +33,8 @@ export {
|
|
|
32
33
|
formatChordForHost,
|
|
33
34
|
menuAcceleratorFor,
|
|
34
35
|
primaryModifierFor,
|
|
36
|
+
shortActionLabel,
|
|
37
|
+
takenChordMessage,
|
|
35
38
|
} from "./labels";
|
|
36
39
|
export { KeybindingsProvider, getDefaultKeybindings, useKeybindings, useResolvedKeybindings } from "./react";
|
|
37
40
|
export {
|
|
@@ -3,8 +3,9 @@ import {
|
|
|
3
3
|
type ShortcutDisplayMode,
|
|
4
4
|
type ShortcutPlatform,
|
|
5
5
|
} from "../../utils/shortcut-labels";
|
|
6
|
+
import { t, tf } from "../../i18n";
|
|
6
7
|
import { formatKeyChord, serializeKeyChord, type KeyChord, type PrimaryModifier } from "./chord";
|
|
7
|
-
import type { ResolvedKeybindings } from "./resolve";
|
|
8
|
+
import type { ResolvedKeybindingAction, ResolvedKeybindings } from "./resolve";
|
|
8
9
|
|
|
9
10
|
/** What `CmdOrCtrl` is on this host: Control in a terminal, Command on a Mac desktop. */
|
|
10
11
|
export function primaryModifierFor(
|
|
@@ -85,3 +86,19 @@ export function menuAcceleratorFor(resolved: ResolvedKeybindings, actionId: stri
|
|
|
85
86
|
const chord = resolved.actionsById.get(actionId)?.chords.find((entry) => entry.primary || entry.cmd);
|
|
86
87
|
return chord ? serializeKeyChord(chord) : undefined;
|
|
87
88
|
}
|
|
89
|
+
|
|
90
|
+
/** The first clause of a description, for messages that name an action mid-sentence. */
|
|
91
|
+
export function shortActionLabel(description: string): string {
|
|
92
|
+
const clause = description.split(/[,.](?:\s|$)/)[0] ?? description;
|
|
93
|
+
return clause.trim() || description.trim();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Why a chord a built-in action uses (coreActionOnChord) is refused, the
|
|
98
|
+
* same in the shortcuts editor and `config set keybindings`: "Ctrl+P is
|
|
99
|
+
* taken: Open the command bar. Press another key."
|
|
100
|
+
*/
|
|
101
|
+
export function takenChordMessage(chord: string, action: ResolvedKeybindingAction): string {
|
|
102
|
+
const name = action.def ? t(action.def.description) : action.pluginShortcut?.description ?? action.id;
|
|
103
|
+
return tf("{chord} is taken: {target}. Press another key.", { chord, target: shortActionLabel(name) });
|
|
104
|
+
}
|
|
@@ -249,6 +249,20 @@ export function matchKeybinding(resolved: ResolvedKeybindings, event: KeyChordEv
|
|
|
249
249
|
return null;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
/**
|
|
253
|
+
* The built-in action already on a chord, on this host, other than `exceptId`:
|
|
254
|
+
* one whose chord fires on the same keypress, a digit under the layout
|
|
255
|
+
* switcher's 1-9 included. Capture refuses such a chord, so a new binding never
|
|
256
|
+
* leaves a core key (the command bar, close pane, quit) dead. Null when no
|
|
257
|
+
* built-in action has it; a plugin shortcut or a bound command does not count.
|
|
258
|
+
*/
|
|
259
|
+
export function coreActionOnChord(resolved: ResolvedKeybindings, chord: KeyChord, exceptId?: string): ResolvedKeybindingAction | null {
|
|
260
|
+
return resolved.actions.find((action) => action.def && action.id !== exceptId
|
|
261
|
+
&& action.chords.some((existing) => keyChordsOverlap(existing, chord)
|
|
262
|
+
|| (existing.key === "digit" && /^[1-9]$/.test(chord.key) && keyChordsOverlap({ ...existing, key: chord.key }, chord))))
|
|
263
|
+
?? null;
|
|
264
|
+
}
|
|
265
|
+
|
|
252
266
|
export function matchesKeybindingAction(resolved: ResolvedKeybindings, id: string, event: KeyChordEventLike): boolean {
|
|
253
267
|
const action = resolved.actionsById.get(id);
|
|
254
268
|
return !!action && action.chords.some((chord) => matchesKeyChord(chord, event));
|
|
@@ -513,13 +513,17 @@ export function bindAppPanePluginRegistry({
|
|
|
513
513
|
removeExternalPlugin(pluginId, directory);
|
|
514
514
|
},
|
|
515
515
|
contributions: (pluginId) => {
|
|
516
|
+
// An unlisted function (`listed: false`) and a pane only it opens are left out, as of every list.
|
|
517
|
+
const registered = pluginRegistry.getPluginPaneTemplateIds(pluginId)
|
|
518
|
+
.map((id) => ({ id, template: pluginRegistry.paneTemplates.get(id) }));
|
|
519
|
+
const listedPaneIds = new Set(registered.flatMap(({ template }) => template && template.listed !== false ? [template.paneId] : []));
|
|
520
|
+
const unlistedPaneIds = new Set(registered.flatMap(({ template }) => template?.listed === false && !listedPaneIds.has(template.paneId) ? [template.paneId] : []));
|
|
516
521
|
const panes = pluginRegistry.getPluginPaneIds(pluginId)
|
|
522
|
+
.filter((id) => !unlistedPaneIds.has(id))
|
|
517
523
|
.map((id) => ({ id, name: pluginRegistry.panes.get(id)?.name ?? id }));
|
|
518
|
-
const templates =
|
|
519
|
-
.
|
|
520
|
-
|
|
521
|
-
return { id, label: template?.label ?? id, ...(template?.shortcut?.prefix ? { prefix: template.shortcut.prefix } : {}) };
|
|
522
|
-
});
|
|
524
|
+
const templates = registered
|
|
525
|
+
.filter(({ template }) => template?.listed !== false)
|
|
526
|
+
.map(({ id, template }) => ({ id, label: template?.label ?? id, ...(template?.shortcut?.prefix ? { prefix: template.shortcut.prefix } : {}) }));
|
|
523
527
|
const commands = [...pluginRegistry.commands.entries()]
|
|
524
528
|
.filter(([id]) => pluginRegistry.getCommandPluginId(id) === pluginId && !id.endsWith(":setup"))
|
|
525
529
|
.map(([id, command]) => ({ id, label: command.label, ...(command.shortcut ? { shortcut: command.shortcut } : {}) }));
|