gloomberb 0.17.6 → 0.18.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 +2 -0
- package/README.zh-CN.md +2 -0
- package/package.json +6 -1
- package/patches/electrobun@1.18.1.patch +74 -0
- package/src/account/auth-model.ts +3 -2
- package/src/account/device-signin-dialog.tsx +38 -13
- package/src/account/device-signin.ts +2 -1
- package/src/account/upgrade-dialog.tsx +6 -2
- package/src/api-client/askg.ts +5 -3
- package/src/api-client/bank-figures.ts +73 -0
- package/src/api-client/credit-boards.ts +21 -1
- package/src/api-client/crypto-markets.ts +88 -1
- package/src/api-client/data.ts +104 -4
- package/src/api-client/debt-maturities.ts +18 -0
- package/src/api-client/equity-screener.ts +3 -0
- package/src/api-client/errors.ts +13 -0
- package/src/api-client/fund-facts.ts +72 -0
- package/src/api-client/futures-curve.ts +26 -3
- package/src/api-client/geo.ts +11 -1
- package/src/api-client/index.ts +25 -2
- package/src/api-client/insider-signals.ts +95 -11
- package/src/api-client/normalizers.ts +1 -0
- package/src/api-client/paths.ts +20 -1
- package/src/api-client/request.ts +11 -3
- package/src/api-client/research-activity.ts +15 -8
- package/src/api-client/socket.ts +6 -3
- package/src/api-client/supply-chain-graph.ts +2 -2
- package/src/api-client/supply-chain.ts +8 -0
- package/src/api-client/tape.ts +12 -0
- package/src/api-client/types.ts +66 -2
- package/src/api-client/upgrade-experiment.ts +4 -3
- package/src/api-client/wall-experiments.ts +5 -3
- package/src/api-client/wall-summary.ts +3 -1
- package/src/api-client/web-experiments.ts +5 -2
- package/src/api-client/yield-curves.ts +17 -0
- package/src/app/command-bar-intro.ts +38 -0
- package/src/app/keybindings/actions.ts +1 -1
- package/src/app/pane-runtime/pane-template-runtime.ts +35 -7
- package/src/app/pane-runtime/plugin-bindings.ts +4 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +4 -14
- package/src/app/pane-runtime/ticker-open-target.ts +31 -0
- package/src/app/runtime/desktop-deeplink.ts +3 -4
- package/src/app/runtime/plugin-bindings.ts +3 -2
- package/src/app/runtime/startup.ts +3 -4
- package/src/app/runtime/ticker-refresh.ts +13 -12
- package/src/app/runtime/update.ts +3 -2
- package/src/architecture/core-builtin-allowlist.json +0 -3
- package/src/architecture/silent-catch-allowlist.json +3 -0
- package/src/architecture/ui-literals-allowlist.json +186 -0
- package/src/architecture/ui-tokens-allowlist.json +40 -0
- package/src/ask-gloom/pane-context.ts +3 -1
- package/src/brokers/signed-in/catalog.ts +2 -1
- package/src/brokers/signed-in/client.ts +7 -2
- package/src/brokers/signed-in/sign-in-dialog.tsx +120 -26
- package/src/brokers/signed-in/sign-in.ts +22 -20
- package/src/brokers/sync-broker-instance.ts +2 -1
- package/src/capabilities/chart-series.ts +2 -0
- package/src/capabilities/registry.ts +1 -3
- package/src/cli/bank-section.ts +147 -0
- package/src/cli/base-converter.ts +5 -2
- package/src/cli/board-coins.ts +70 -0
- package/src/cli/commands/fred-series.ts +90 -0
- package/src/cli/commands/market.ts +340 -69
- package/src/cli/commands/news-search.ts +35 -2
- package/src/cli/commands/options-chain.ts +7 -5
- package/src/cli/commands/options-leaps.ts +3 -3
- package/src/cli/commands/overview.ts +78 -29
- package/src/cli/commands/plugins.ts +1 -0
- package/src/cli/commands/search.ts +87 -24
- package/src/cli/commands/system.ts +5 -2
- package/src/cli/commands/ticker.ts +337 -60
- package/src/cli/context.ts +2 -1
- package/src/cli/desktop-pane-shot.ts +11 -3
- package/src/cli/earnings-calendar.ts +2 -1
- package/src/cli/errors.ts +10 -0
- package/src/cli/export-source.ts +18 -3
- package/src/cli/glossary.ts +196 -14
- package/src/cli/history-rows.ts +60 -9
- package/src/cli/index-roots.ts +26 -0
- package/src/cli/index.ts +34 -9
- package/src/cli/known-gaps.ts +156 -22
- package/src/cli/listing-arg.ts +156 -12
- package/src/cli/listing-suggestion.ts +4 -2
- package/src/cli/name-entries.ts +76 -0
- package/src/cli/not-a-ticker.ts +15 -6
- package/src/cli/pane-functions/access-gate.ts +22 -0
- package/src/cli/pane-functions/capabilities.ts +62 -4
- package/src/cli/pane-functions/catalog.ts +94 -39
- package/src/cli/pane-functions/data.ts +6 -5
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +3 -3
- package/src/cli/pane-functions/freshness.ts +49 -8
- package/src/cli/pane-functions/function-help.ts +13 -10
- package/src/cli/pane-functions/headless.ts +177 -42
- package/src/cli/pane-functions/index.ts +64 -8
- package/src/cli/pane-functions/options.ts +17 -3
- package/src/cli/pane-functions/report-notices.ts +17 -3
- package/src/cli/pane-functions/resolver.ts +48 -13
- package/src/cli/pane-functions/screenshot.ts +124 -23
- package/src/cli/pane-functions/shot-options.ts +68 -0
- package/src/cli/perpetual-contract.ts +3 -1
- package/src/cli/report-tables.ts +10 -2
- package/src/cli/staged-tickers.ts +5 -0
- package/src/cli/statement-filings.ts +261 -0
- package/src/cli/symbol-args.ts +47 -8
- package/src/cli/symbol-list.ts +9 -2
- package/src/cli/symbol-rows.ts +269 -29
- package/src/cli/ticker-resolution.ts +148 -34
- package/src/cli/treasury-yields.ts +86 -0
- package/src/cli/types.ts +3 -0
- package/src/cli/uncovered-instrument.ts +20 -0
- package/src/components/chart/composite/axis-overlays.tsx +16 -9
- package/src/components/chart/composite/composite-chart.tsx +85 -6
- package/src/components/chart/composite/downsample.ts +19 -3
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart/composite/legend.tsx +155 -76
- package/src/components/chart/composite/panel-bitmap.ts +8 -2
- package/src/components/chart/composite/panel-surface.tsx +3 -3
- package/src/components/chart/composite/toolbar.tsx +12 -7
- package/src/components/chart/composite/types.ts +6 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +28 -1
- package/src/components/chart/curve/curve-surface.tsx +1 -1
- package/src/components/chart/static/series.ts +39 -0
- package/src/components/chart/static/trail-chart-surface.tsx +2 -1
- package/src/components/command-bar/commands/collection-list.ts +45 -15
- package/src/components/command-bar/commands/collection.ts +10 -3
- package/src/components/command-bar/commands/registry.ts +2 -2
- package/src/components/command-bar/list/badge.ts +4 -3
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +1 -1
- package/src/components/command-bar/panel/index.tsx +19 -8
- package/src/components/command-bar/panel/native-surface.ts +6 -4
- package/src/components/command-bar/panel/prompt-example.ts +22 -0
- package/src/components/command-bar/routes/root/provider-search.ts +3 -9
- package/src/components/command-bar/routes/root/results.ts +13 -0
- package/src/components/command-bar/routes/root/start-here.ts +90 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +42 -3
- package/src/components/command-bar/routes/ticker-search/route.ts +3 -10
- package/src/components/command-bar/theme-picker.tsx +3 -1
- package/src/components/command-bar/workflow/builtin.ts +5 -1
- package/src/components/command-bar/workflow/collection-actions.ts +21 -12
- package/src/components/command-bar/workflow/ops.ts +21 -1
- package/src/{plugins/builtin/portfolio-list/command-bar.ts → components/command-bar/workflow/portfolio-position.ts} +42 -9
- package/src/components/command-bar/workflow/tickers.ts +6 -4
- package/src/components/feedback-dialog.tsx +1 -1
- package/src/components/form-modal/broker-step.tsx +7 -63
- package/src/components/form-modal/content.tsx +7 -2
- package/src/components/form-modal/field-row.tsx +6 -8
- package/src/components/form-modal/host.tsx +3 -3
- package/src/components/form-modal/model.ts +3 -0
- package/src/components/form-modal/routes.ts +17 -2
- package/src/components/index.ts +6 -6
- package/src/components/input-search-bar.tsx +43 -6
- package/src/components/layout/detached-pane-shell.tsx +0 -1
- package/src/components/layout/floating-pane.tsx +0 -1
- package/src/components/layout/header.tsx +8 -7
- package/src/components/layout/pane/footer/index.tsx +7 -4
- package/src/components/layout/pane/footer/model.ts +28 -2
- package/src/components/layout/pane/header.tsx +9 -19
- package/src/components/layout/pane/index.tsx +0 -1
- package/src/components/layout/pane/instrument-coverage-gate.tsx +57 -0
- package/src/components/layout/pane/pane-tabs.tsx +4 -3
- package/src/components/layout/pane/sizing.ts +9 -0
- package/src/components/layout/pane/ticker-fate-gate.tsx +8 -2
- package/src/components/layout/shell/pane/capture.ts +44 -20
- package/src/components/layout/status-bar.tsx +3 -6
- package/src/components/markdown-text.tsx +17 -2
- package/src/components/market-board/index.tsx +19 -8
- package/src/components/metric-treemap/heat-surface.tsx +2 -7
- package/src/components/onboarding/account-step/qr-panel.tsx +5 -2
- package/src/components/onboarding/onboarding-frame.tsx +24 -21
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +20 -10
- package/src/components/onboarding/wizard-positions.ts +40 -11
- package/src/components/pane-settings-dialog/desktop.tsx +12 -50
- package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -1
- package/src/components/price-performance.tsx +18 -2
- package/src/components/reader/article-reader.tsx +11 -10
- package/src/components/reader/detail-reader.tsx +9 -5
- package/src/components/reader/reader-text.tsx +51 -24
- package/src/components/sign-in-code-panel.tsx +129 -75
- package/src/components/ticker/badge/index.tsx +2 -1
- package/src/components/ui/action-row.tsx +5 -2
- package/src/components/ui/audio-player.tsx +70 -0
- package/src/components/ui/card.tsx +75 -0
- package/src/components/ui/data-table/index.tsx +4 -2
- package/src/components/ui/data-table/types.ts +11 -0
- package/src/components/ui/detail-scroll-body.tsx +1 -1
- package/src/components/ui/dialog-actions.tsx +1 -21
- package/src/components/ui/display.tsx +13 -5
- package/src/components/ui/external-link.tsx +4 -2
- package/src/components/ui/fields.tsx +12 -0
- package/src/components/ui/figure.tsx +5 -3
- package/src/components/ui/frame.tsx +40 -6
- package/src/components/ui/icon.tsx +4 -0
- package/src/components/ui/index.ts +4 -1
- package/src/components/ui/list-view.tsx +8 -0
- package/src/components/ui/prose.tsx +97 -25
- package/src/components/ui/query-bar-keys.tsx +3 -1
- package/src/components/ui/query-bar.tsx +6 -0
- package/src/components/ui/quote.ts +42 -0
- package/src/components/ui/range-track.tsx +15 -2
- package/src/components/ui/reveal-in-scroll-box.ts +21 -3
- package/src/components/ui/select-button.tsx +38 -3
- package/src/components/ui/status.tsx +73 -4
- package/src/components/ui/table-layout.ts +20 -0
- package/src/components/use-pinned-moment.ts +19 -0
- package/src/core/app-runtime.ts +2 -2
- package/src/core/state/app/instrument.ts +18 -1
- package/src/core/state/app/layout.ts +6 -0
- package/src/core/state/app/state.ts +14 -2
- package/src/data/cached-query.ts +1 -1
- package/src/data/config/chart-settings.ts +3 -1
- package/src/data/config/home.ts +4 -1
- package/src/data/config/store/node.ts +9 -4
- package/src/data/config/store/normalize.ts +9 -0
- package/src/data/json-storage.ts +6 -3
- package/src/data/json-ticker-repository.ts +3 -1
- package/src/data/plugin-cache.ts +5 -1
- package/src/data/sqlite/json.ts +3 -1
- package/src/data/ticker-repository.ts +5 -2
- package/src/feedback/diagnostics.ts +2 -6
- package/src/i18n/es.ts +86 -6
- package/src/i18n/index.ts +3 -9
- package/src/i18n/ja.ts +86 -6
- package/src/i18n/ko.ts +86 -6
- package/src/i18n/zh-cn.ts +86 -6
- package/src/i18n/zh-tw.ts +86 -6
- package/src/layout-marketplace/gallery-desktop.tsx +8 -4
- package/src/market-data/bars-per-year.ts +43 -0
- package/src/market-data/bond-funds.ts +85 -0
- package/src/market-data/coordinator/auxiliary.ts +5 -2
- package/src/market-data/coordinator/index.ts +6 -5
- package/src/market-data/futures-contract.ts +102 -5
- package/src/market-data/hooks.tsx +20 -11
- package/src/market-data/market/bar-period.ts +36 -0
- package/src/market-data/market/format.ts +5 -13
- package/src/market-data/market/freshness.ts +1 -3
- package/src/market-data/market/index-level.ts +51 -0
- package/src/market-data/model-dividend-yield.ts +57 -16
- package/src/market-data/quotes/live-valuation.ts +48 -2
- package/src/market-data/realized-volatility.ts +16 -7
- package/src/market-data/tax-equivalent.ts +344 -0
- package/src/news/aggregator.ts +4 -2
- package/src/notifications/notification-log.ts +5 -3
- package/src/plugins/auto-update-node.ts +1 -0
- package/src/plugins/builtin/account-management/footer.ts +1 -1
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +1 -0
- package/src/plugins/builtin/account-management/pane.tsx +71 -19
- package/src/plugins/builtin/account-management/trial-cancel.ts +40 -0
- package/src/plugins/builtin/alerts/cli.ts +7 -18
- package/src/plugins/builtin/alerts/constants.ts +8 -0
- package/src/plugins/builtin/alerts/event-rows.ts +16 -0
- package/src/plugins/builtin/alerts/events-pane.tsx +2 -14
- package/src/plugins/builtin/alerts/headless.ts +182 -0
- package/src/plugins/builtin/alerts/index.tsx +3 -0
- package/src/plugins/builtin/alerts/pane.tsx +1 -7
- package/src/plugins/builtin/alerts/storage.ts +17 -1
- package/src/plugins/builtin/analytics/index.tsx +6 -1
- package/src/plugins/builtin/analytics/metrics.ts +47 -9
- package/src/plugins/builtin/analytics/risk-headless.ts +14 -2
- package/src/plugins/builtin/analytics/risk-math.ts +83 -0
- package/src/plugins/builtin/analytics/risk-model.ts +97 -4
- package/src/plugins/builtin/analytics/risk-pane.tsx +11 -6
- package/src/plugins/builtin/analytics/sector-model.ts +14 -3
- package/src/plugins/builtin/awards/headless.ts +6 -5
- package/src/plugins/builtin/awards/index.tsx +1 -1
- package/src/plugins/builtin/backtest/client.ts +38 -8
- package/src/plugins/builtin/backtest/engine.ts +25 -13
- package/src/plugins/builtin/backtest/export.ts +27 -0
- package/src/plugins/builtin/backtest/format.ts +19 -3
- package/src/plugins/builtin/backtest/headless.ts +42 -28
- package/src/plugins/builtin/backtest/index.tsx +3 -0
- package/src/plugins/builtin/backtest/pane.tsx +39 -10
- package/src/plugins/builtin/backtest/report.ts +160 -0
- package/src/plugins/builtin/backtest/rules.ts +2 -0
- package/src/plugins/builtin/backtest/window.ts +112 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +3 -2
- package/src/plugins/builtin/broker-manager/add-flow.tsx +4 -4
- package/src/plugins/builtin/catalysts/headless.ts +24 -13
- package/src/plugins/builtin/catalysts/index.tsx +4 -2
- package/src/plugins/builtin/catalysts/model.ts +18 -1
- package/src/plugins/builtin/catalysts/pane.tsx +2 -2
- package/src/plugins/builtin/cds/client.ts +28 -5
- package/src/plugins/builtin/cds/headless.ts +183 -31
- package/src/plugins/builtin/cds/index.tsx +1 -1
- package/src/plugins/builtin/cds/model.ts +229 -53
- package/src/plugins/builtin/cds/pane.tsx +82 -26
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -1
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +39 -1
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +77 -0
- package/src/plugins/builtin/chart-composer/chart-spec.ts +15 -0
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +22 -2
- package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +2 -2
- package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -2
- package/src/plugins/builtin/chart-composer/headless.ts +99 -21
- package/src/plugins/builtin/chart-composer/index.tsx +70 -13
- package/src/plugins/builtin/chart-composer/pane.tsx +65 -15
- package/src/plugins/builtin/chart-composer/presets.ts +79 -11
- package/src/plugins/builtin/chart-composer/series-catalog.ts +50 -14
- package/src/plugins/builtin/chart-composer/series-expression.ts +9 -7
- package/src/plugins/builtin/chart-composer/series-listings.ts +178 -0
- package/src/plugins/builtin/chart-composer/session-range.ts +87 -0
- package/src/plugins/builtin/chat/attachments/desktop.tsx +4 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +49 -14
- package/src/plugins/builtin/chat/content/composer.tsx +22 -1
- package/src/plugins/builtin/chat/content/index.tsx +35 -5
- package/src/plugins/builtin/chat/content/layout-metrics.ts +3 -0
- package/src/plugins/builtin/chat/content/shortcuts.ts +32 -13
- package/src/plugins/builtin/chat/content/snapshot.ts +29 -6
- package/src/plugins/builtin/chat/ghost-user.ts +11 -3
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +13 -5
- package/src/plugins/builtin/chat/message/header.tsx +26 -4
- package/src/plugins/builtin/chat/message/pane-chip.tsx +131 -35
- package/src/plugins/builtin/chat/message/render-state.ts +28 -1
- package/src/plugins/builtin/chat/message/terminal.tsx +9 -3
- package/src/plugins/builtin/chat/pane-links/composer.ts +87 -0
- package/src/plugins/builtin/chat/pane-links/model.ts +1 -1
- package/src/plugins/builtin/chat/share/flow.tsx +9 -73
- package/src/plugins/builtin/cloud/askg/controller.ts +5 -3
- package/src/plugins/builtin/cloud/askg/executor.ts +3 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +16 -0
- package/src/plugins/builtin/cloud/askg/pane.tsx +6 -2
- package/src/plugins/builtin/cloud/auth-actions.tsx +4 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +21 -26
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +5 -3
- package/src/plugins/builtin/cloud/plugin.tsx +2 -0
- package/src/plugins/builtin/cloud/team/module.tsx +5 -1
- package/src/plugins/builtin/cloud/team/pane.tsx +11 -4
- package/src/plugins/builtin/cloud/team/views.ts +11 -4
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +9 -4
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +3 -2
- package/src/plugins/builtin/cloud/thesis/detail.tsx +2 -1
- package/src/plugins/builtin/cloud/thesis/exposure.ts +3 -0
- package/src/plugins/builtin/cloud/thesis/prompts.tsx +3 -2
- package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +2 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +2 -1
- package/src/plugins/builtin/cloud/verification-status-widget.tsx +2 -1
- package/src/plugins/builtin/commodities-energy/index.tsx +8 -5
- package/src/plugins/builtin/commodities-energy/view-state.ts +11 -0
- package/src/plugins/builtin/company-attention/headless.ts +15 -7
- package/src/plugins/builtin/company-attention/index.tsx +1 -1
- package/src/plugins/builtin/company-attention/model.ts +49 -4
- package/src/plugins/builtin/company-attention/pane.tsx +11 -9
- package/src/plugins/builtin/company-kpis/headless.ts +4 -3
- package/src/plugins/builtin/company-kpis/index.tsx +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +9 -3
- package/src/plugins/builtin/congress-trades/headless.ts +23 -2
- package/src/plugins/builtin/correlation/relationship/pane.tsx +18 -46
- package/src/plugins/builtin/cot/headless.ts +5 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +41 -13
- package/src/plugins/builtin/credit-boards/client.ts +9 -2
- package/src/plugins/builtin/credit-boards/headless.ts +93 -27
- package/src/plugins/builtin/credit-boards/index.tsx +15 -4
- package/src/plugins/builtin/credit-boards/model.ts +105 -6
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +14 -3
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -1
- package/src/plugins/builtin/credit-documents/index.tsx +3 -0
- package/src/plugins/builtin/credit-documents/model.ts +3 -10
- package/src/plugins/builtin/crypto-board/client.ts +152 -2
- package/src/plugins/builtin/crypto-board/headless.ts +138 -19
- package/src/plugins/builtin/crypto-board/index.tsx +5 -3
- package/src/plugins/builtin/crypto-board/model.ts +210 -12
- package/src/plugins/builtin/crypto-board/pane.tsx +148 -9
- package/src/plugins/builtin/crypto-board/series.ts +52 -1
- package/src/plugins/builtin/crypto-board/supply.ts +123 -0
- package/src/plugins/builtin/debt-maturities/client.ts +54 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +27 -3
- package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
- package/src/plugins/builtin/debt-maturities/model.ts +58 -13
- package/src/plugins/builtin/debt-maturities/pane.tsx +47 -7
- package/src/plugins/builtin/dividend-yield/client.ts +42 -36
- package/src/plugins/builtin/dividend-yield/headless.ts +113 -18
- package/src/plugins/builtin/dividend-yield/index.tsx +5 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +37 -13
- package/src/plugins/builtin/dividend-yield/provider-client.ts +7 -3
- package/src/plugins/builtin/dividend-yield/ranking.ts +187 -0
- package/src/plugins/builtin/dividend-yield/reference-price.ts +28 -5
- package/src/plugins/builtin/dividend-yield/types.ts +6 -1
- package/src/plugins/builtin/dividend-yield/view.ts +1 -1
- package/src/plugins/builtin/docs/blocks.tsx +54 -8
- package/src/plugins/builtin/docs/pane.tsx +8 -13
- package/src/plugins/builtin/earnings/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/data.ts +51 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +7 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
- package/src/plugins/builtin/earnings-calls/model.ts +97 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +107 -7
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +140 -22
- package/src/plugins/builtin/earnings-calls/use-call-playback.ts +194 -0
- package/src/plugins/builtin/econ/calendar-model.ts +22 -0
- package/src/plugins/builtin/econ/calendar-source.ts +35 -0
- package/src/plugins/builtin/econ/index.tsx +40 -8
- package/src/plugins/builtin/econ-statistics/defs.ts +7 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +8 -1
- package/src/plugins/builtin/econ-statistics/headless.ts +26 -5
- package/src/plugins/builtin/econ-statistics/pane.tsx +4 -2
- package/src/plugins/builtin/econ-statistics/stats.ts +10 -0
- package/src/plugins/builtin/econ-statistics/view.ts +19 -0
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +46 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +3 -0
- package/src/plugins/builtin/estimate-revisions/client.ts +32 -22
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -0
- package/src/plugins/builtin/estimate-revisions/pane.tsx +5 -3
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/editor.tsx +3 -3
- package/src/plugins/builtin/fear-greed/index.tsx +9 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures/index.tsx +2 -2
- package/src/plugins/builtin/futures/model.ts +34 -21
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures/use-board-terms.ts +2 -2
- package/src/plugins/builtin/futures-curve/headless.ts +4 -2
- package/src/plugins/builtin/futures-curve/model.ts +5 -7
- package/src/plugins/builtin/help/index.tsx +55 -8
- package/src/plugins/builtin/help/shortcut-table.tsx +15 -2
- package/src/plugins/builtin/holders/headless.ts +12 -0
- package/src/plugins/builtin/insider/headless.ts +311 -41
- package/src/plugins/builtin/insider/index.tsx +280 -106
- package/src/plugins/builtin/insider/insiders.tsx +224 -0
- package/src/plugins/builtin/insider/signals-cells.tsx +52 -0
- package/src/plugins/builtin/insider/signals-client.ts +135 -11
- package/src/plugins/builtin/insider/signals-model.ts +628 -56
- package/src/plugins/builtin/insider/signals.tsx +283 -83
- package/src/plugins/builtin/ipo-calendar/headless.ts +17 -7
- package/src/plugins/builtin/ipo-calendar/index.tsx +23 -3
- package/src/plugins/builtin/ipo-calendar/model.ts +84 -36
- package/src/plugins/builtin/ipo-calendar/pane.tsx +20 -8
- package/src/plugins/builtin/iv-history/headless.ts +2 -0
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/jobs/index.tsx +1 -0
- package/src/plugins/builtin/jodi/headless.ts +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +1 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +3 -1
- package/src/plugins/builtin/market-valuation/pane.tsx +1 -1
- package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +31 -57
- package/src/plugins/builtin/mna/distress/headless.ts +2 -1
- package/src/plugins/builtin/mna/headless.ts +14 -2
- package/src/plugins/builtin/mna/index.tsx +1 -0
- package/src/plugins/builtin/news/headless.ts +4 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +5 -3
- package/src/plugins/builtin/news/wire/news/table.tsx +57 -11
- package/src/plugins/builtin/notes/cli.ts +8 -4
- package/src/plugins/builtin/notes/files.ts +66 -20
- package/src/plugins/builtin/notes/migration.ts +18 -6
- package/src/plugins/builtin/notes/owner.tsx +3 -2
- package/src/plugins/builtin/notes/quick-notes-pane.tsx +3 -2
- package/src/plugins/builtin/options-scenario/client.ts +7 -4
- package/src/plugins/builtin/options-scenario/headless.ts +5 -3
- package/src/plugins/builtin/pe-band/index.tsx +1 -1
- package/src/plugins/builtin/pe-band/model.ts +1 -15
- package/src/plugins/builtin/perps/headless.ts +30 -13
- package/src/plugins/builtin/perps/model.ts +45 -3
- package/src/plugins/builtin/perps/pane.tsx +7 -7
- package/src/plugins/builtin/portfolio-list/cell-version.ts +10 -4
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +128 -14
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +108 -46
- package/src/plugins/builtin/portfolio-list/cli/render.ts +368 -45
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +8 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +24 -34
- package/src/plugins/builtin/portfolio-list/grid.tsx +3 -1
- package/src/plugins/builtin/portfolio-list/headless.ts +151 -29
- package/src/plugins/builtin/portfolio-list/income.ts +296 -0
- package/src/plugins/builtin/portfolio-list/metrics.ts +2 -2
- package/src/plugins/builtin/portfolio-list/pane/futures-terms.ts +58 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +27 -10
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +47 -28
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +10 -3
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +26 -4
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +31 -3
- package/src/plugins/builtin/portfolio-list/table.tsx +25 -5
- package/src/plugins/builtin/power/prices-headless.ts +2 -1
- package/src/plugins/builtin/realized-vol/chart-model.ts +29 -5
- package/src/plugins/builtin/realized-vol/charts.tsx +14 -8
- package/src/plugins/builtin/realized-vol/evidence.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +6 -4
- package/src/plugins/builtin/realized-vol/model.ts +5 -1
- package/src/plugins/builtin/realized-vol/pane.tsx +31 -11
- package/src/plugins/builtin/realized-vol/settings.ts +1 -1
- package/src/plugins/builtin/research/analyst-headless.ts +4 -0
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -0
- package/src/plugins/builtin/research/event-model.ts +22 -2
- package/src/plugins/builtin/research/headless-schema.ts +1 -0
- package/src/plugins/builtin/research/headless.ts +3 -0
- package/src/plugins/builtin/research/index.tsx +3 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +27 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +2 -0
- package/src/plugins/builtin/revenue-breakdown/index.tsx +1 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +9 -6
- package/src/plugins/builtin/reverse-dcf/index.tsx +2 -2
- package/src/plugins/builtin/reverse-dcf/model.ts +51 -4
- package/src/plugins/builtin/reverse-dcf/pane.tsx +23 -10
- package/src/plugins/builtin/risk-factors/headless.ts +7 -0
- package/src/plugins/builtin/risk-factors/index.tsx +1 -0
- package/src/plugins/builtin/scanner/feed.ts +5 -3
- package/src/plugins/builtin/scanner/headless.ts +9 -57
- package/src/plugins/builtin/scanner/index.ts +1 -2
- package/src/plugins/builtin/sec/forms.ts +2 -6
- package/src/plugins/builtin/sec/fund-facts-view.tsx +53 -0
- package/src/plugins/builtin/sec/fund-facts.ts +328 -0
- package/src/plugins/builtin/sec/headless.ts +140 -44
- package/src/plugins/builtin/sec/index.tsx +95 -30
- package/src/plugins/builtin/sec/model.ts +2 -44
- package/src/plugins/builtin/shared/headless-options.ts +10 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +3 -1
- package/src/plugins/builtin/shared/move-rank.ts +108 -0
- package/src/plugins/builtin/shared/report-freshness.ts +25 -9
- package/src/plugins/builtin/shared/scanner-capture.ts +95 -0
- package/src/plugins/builtin/shared/treasury-cutoffs.ts +15 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +1 -0
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -0
- package/src/plugins/builtin/shared/volatility-indices.ts +32 -0
- package/src/plugins/builtin/short-interest/headless.ts +3 -0
- package/src/plugins/builtin/short-interest/watch-model.ts +2 -2
- package/src/plugins/builtin/social-mentions/client.ts +8 -1
- package/src/plugins/builtin/social-mentions/pane.tsx +8 -6
- package/src/plugins/builtin/supply-chain/client.ts +12 -3
- package/src/plugins/builtin/supply-chain/disclosure-quote.tsx +9 -5
- package/src/plugins/builtin/supply-chain/evidence.ts +3 -1
- package/src/plugins/builtin/supply-chain/flow-layout.ts +2 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +23 -16
- package/src/plugins/builtin/supply-chain/graph-client.ts +8 -5
- package/src/plugins/builtin/supply-chain/graph-evidence.ts +1 -1
- package/src/plugins/builtin/supply-chain/graph-model.ts +10 -2
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +9 -7
- package/src/plugins/builtin/supply-chain/graph.tsx +8 -6
- package/src/plugins/builtin/supply-chain/headless.ts +69 -27
- package/src/plugins/builtin/supply-chain/index.tsx +1 -1
- package/src/plugins/builtin/supply-chain/model.ts +76 -15
- package/src/plugins/builtin/supply-chain/pane.tsx +29 -15
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +5 -4
- package/src/plugins/builtin/themes/model.ts +2 -5
- package/src/plugins/builtin/thirteenf/api.ts +50 -2
- package/src/plugins/builtin/thirteenf/data.ts +250 -11
- package/src/plugins/builtin/thirteenf/headless.ts +311 -28
- package/src/plugins/builtin/thirteenf/index.tsx +4 -1
- package/src/plugins/builtin/thirteenf/model.ts +244 -19
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +133 -33
- package/src/plugins/builtin/thirteenf/overlap.ts +1 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/report-notes.ts +78 -0
- package/src/plugins/builtin/thirteenf/types.ts +49 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -8
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +17 -1
- package/src/plugins/builtin/ticker-detail/financials/model.ts +2 -42
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +23 -10
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +27 -3
- package/src/plugins/builtin/ticker-detail/overview/dividend.ts +60 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +46 -9
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +3 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +36 -3
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +18 -19
- package/src/plugins/builtin/time-sales/client.ts +7 -4
- package/src/plugins/builtin/time-sales/headless.ts +71 -22
- package/src/plugins/builtin/time-sales/model.ts +12 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -7
- package/src/plugins/builtin/time-sales/window.ts +128 -0
- package/src/plugins/builtin/trace-bonds/client.ts +351 -33
- package/src/plugins/builtin/trace-bonds/headless.ts +60 -22
- package/src/plugins/builtin/trace-bonds/index.tsx +4 -2
- package/src/plugins/builtin/trace-bonds/model.ts +27 -25
- package/src/plugins/builtin/trace-bonds/pane.tsx +63 -45
- package/src/plugins/builtin/treasury-auctions/cache.ts +61 -15
- package/src/plugins/builtin/treasury-auctions/client.ts +45 -10
- package/src/plugins/builtin/treasury-auctions/headless.ts +35 -13
- package/src/plugins/builtin/treasury-auctions/index.tsx +5 -2
- package/src/plugins/builtin/treasury-auctions/model.ts +20 -16
- package/src/plugins/builtin/treasury-auctions/pane.tsx +29 -12
- package/src/plugins/builtin/vol-surface/charts.tsx +2 -1
- package/src/plugins/builtin/vol-surface/headless.ts +3 -2
- package/src/plugins/builtin/vol-surface/pane.tsx +2 -1
- package/src/plugins/builtin/vol-surface/stored.ts +4 -7
- package/src/plugins/builtin/volatility/chart-model.ts +16 -15
- package/src/plugins/builtin/volatility/charts.tsx +5 -5
- package/src/plugins/builtin/volatility/client.ts +73 -2
- package/src/plugins/builtin/volatility/evidence.ts +13 -14
- package/src/plugins/builtin/volatility/headless.ts +13 -7
- package/src/plugins/builtin/volatility/index.tsx +1 -1
- package/src/plugins/builtin/volatility/model.ts +104 -38
- package/src/plugins/builtin/volatility/pane.tsx +42 -24
- package/src/plugins/builtin/volatility/series.ts +22 -13
- package/src/plugins/builtin/world-venue-map/geo-series.ts +9 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +8 -5
- package/src/plugins/builtin/world-venue-map/index.ts +16 -2
- package/src/plugins/builtin/world-venue-map/map.tsx +13 -17
- package/src/plugins/builtin/yield-curve/curves.ts +29 -5
- package/src/plugins/builtin/yield-curve/headless.ts +41 -8
- package/src/plugins/builtin/yield-curve/history.ts +5 -5
- package/src/plugins/builtin/yield-curve/index.tsx +30 -13
- package/src/plugins/compat.ts +3 -1
- package/src/plugins/dependencies.ts +8 -2
- package/src/plugins/host-link.ts +12 -5
- package/src/plugins/installer.ts +16 -7
- package/src/plugins/loader.ts +9 -2
- package/src/plugins/marketplace/activation.ts +10 -4
- package/src/plugins/registry/host-actions.ts +3 -0
- package/src/plugins/registry/index.ts +3 -1
- package/src/{plugins/builtin/portfolio-list → portfolio}/allocation.ts +74 -12
- package/src/{plugins/builtin/portfolio-list → portfolio}/column-values.ts +140 -53
- package/src/portfolio/futures-positions.ts +213 -0
- package/src/portfolio/futures-terms.ts +75 -0
- package/src/portfolio/manual-lots.ts +78 -0
- package/src/portfolio/mutations.ts +54 -10
- package/src/portfolio/position-metrics.ts +44 -10
- package/src/portfolio/valuation-basis.ts +31 -4
- package/src/public/__snapshots__/public-api.test.ts.snap +4 -0
- package/src/public/time-series.ts +2 -1
- package/src/remote/confirm-change.tsx +2 -1
- package/src/remote/server.ts +1 -1
- package/src/remote/watchlist.ts +9 -1
- package/src/renderers/dom/data-table/row.tsx +1 -1
- package/src/renderers/dom/desktop/audio-player.tsx +312 -0
- package/src/renderers/dom/desktop/control-styles.ts +17 -82
- package/src/renderers/dom/desktop/controls.tsx +39 -63
- package/src/renderers/dom/desktop/dialog-actions.tsx +13 -53
- package/src/renderers/dom/desktop/icons.tsx +8 -0
- package/src/renderers/dom/desktop/list-view.tsx +6 -6
- package/src/renderers/dom/desktop/popover.tsx +0 -3
- package/src/renderers/dom/desktop/query-bar.tsx +6 -4
- package/src/renderers/dom/desktop/select-field.tsx +9 -8
- package/src/renderers/dom/desktop/stack-header.ts +3 -0
- package/src/renderers/dom/dom-ui-host.tsx +3 -2
- package/src/renderers/dom/host/chart-surface.tsx +3 -3
- package/src/renderers/dom/host/size-observer.ts +33 -4
- package/src/renderers/dom/host/surface-3d.tsx +3 -2
- package/src/renderers/dom/host/surface-fit.ts +4 -1
- package/src/renderers/dom/host/tabs.tsx +22 -132
- package/src/renderers/dom/styles.css +358 -160
- package/src/renderers/electrobun/bun/core-capabilities.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/backend.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +43 -1
- package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +5 -1
- package/src/renderers/electrobun/shared/rpc-codec.ts +7 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +21 -17
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
- package/src/renderers/electrobun/view/desktop/window/bridge.ts +6 -8
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +18 -0
- package/src/series/capability.ts +1 -0
- package/src/series/files.ts +9 -3
- package/src/series/registry.ts +40 -14
- package/src/series/resolve.ts +121 -18
- package/src/series/standalone.ts +3 -2
- package/src/series/types.ts +55 -1
- package/src/series/validate.ts +39 -0
- package/src/shares/api.ts +26 -7
- package/src/shares/bug-report-dialog.tsx +2 -2
- package/src/shares/bug-report-flow.tsx +4 -7
- package/src/shares/capture-flow.ts +5 -4
- package/src/shares/capture-preview.tsx +2 -2
- package/src/shares/chat.ts +7 -27
- package/src/shares/flow.tsx +86 -40
- package/src/shares/location.ts +1 -3
- package/src/shares/pane-image.ts +11 -9
- package/src/shares/pane.ts +5 -2
- package/src/shares/payload.ts +1 -1
- package/src/shares/personal-pane.ts +3 -3
- package/src/shares/portable-layout.ts +9 -2
- package/src/shares/ready.ts +42 -0
- package/src/shares/test-harness.ts +62 -0
- package/src/sources/gloomberb-cloud/batched-lookups.ts +73 -0
- package/src/sources/gloomberb-cloud/index.ts +64 -12
- package/src/sources/gloomberb-cloud/normalizers.ts +31 -2
- package/src/sources/gloomberb-cloud/perpetuals.ts +20 -1
- package/src/sources/history-omitted.ts +34 -0
- package/src/sources/history-result.ts +3 -0
- package/src/sources/history-retention.ts +1 -1
- package/src/sources/provider-errors.ts +43 -1
- package/src/sources/provider-router/batches.ts +3 -2
- package/src/sources/provider-router/cache.ts +2 -1
- package/src/sources/provider-router/cached-routes.ts +9 -3
- package/src/sources/provider-router/history.ts +9 -8
- package/src/sources/provider-router/index.ts +18 -3
- package/src/sources/provider-router/primary.ts +5 -4
- package/src/sources/provider-router/quote-route.ts +3 -1
- package/src/sources/provider-router/routing.ts +2 -1
- package/src/sources/provider-router/search.ts +47 -13
- package/src/sources/provider-router/streaming.ts +7 -4
- package/src/sources/sec-edgar.ts +1 -3
- package/src/state/app/context/index.tsx +9 -13
- package/src/state/app/tab-cursor.ts +149 -12
- package/src/state/hooks/quote-streaming.ts +3 -2
- package/src/state/hooks/session-snapshot.ts +3 -2
- package/src/state/persist-scheduler.ts +12 -4
- package/src/sync/controller.ts +22 -1
- package/src/sync/core-contributors.ts +58 -15
- package/src/team/collections-sync.ts +14 -4
- package/src/team/collections.ts +40 -11
- package/src/team/store.ts +5 -4
- package/src/telemetry/attention-counts.ts +8 -2
- package/src/telemetry/crash-reports-dom.ts +3 -0
- package/src/telemetry/crash-reports-node.ts +7 -4
- package/src/telemetry/crash-reports.ts +11 -11
- package/src/telemetry/usage-counts.ts +16 -12
- package/src/theme/colors.ts +2 -0
- package/src/theme/font-scale.ts +2 -0
- package/src/theme/ui-tokens.ts +71 -0
- package/src/tickers/batched-lookups.ts +186 -0
- package/src/tickers/company-name-listing.ts +97 -0
- package/src/tickers/company-name.ts +13 -0
- package/src/tickers/instrument-coverage.ts +112 -0
- package/src/tickers/listing-fate.ts +49 -9
- package/src/tickers/listing-venues.ts +24 -5
- package/src/tickers/open-target.ts +13 -5
- package/src/tickers/search/index.ts +112 -35
- package/src/tickers/search/ranking.ts +49 -1
- package/src/tickers/terminal-codes.ts +79 -0
- package/src/tickers/ticker-changes.ts +74 -3
- package/src/tickers/us-listing.ts +2 -1
- package/src/time-series/chart-data.ts +79 -8
- package/src/time-series/fundamentals.ts +55 -7
- package/src/time-series/ice-credit.ts +17 -2
- package/src/time-series/live-bars.ts +21 -8
- package/src/time-series/live-quotes.ts +2 -3
- package/src/time-series/price-comparison.ts +6 -1
- package/src/time-series/resolve.ts +65 -10
- package/src/time-series/spec.ts +2 -1
- package/src/time-series/studies.ts +3 -3
- package/src/time-series/types.ts +22 -0
- package/src/time-series/use-chart-resolution.ts +2 -1
- package/src/types/config.ts +7 -0
- package/src/types/data-provider.ts +20 -0
- package/src/types/headless.ts +142 -1
- package/src/types/instrument.ts +6 -0
- package/src/types/plugin.ts +32 -9
- package/src/types/price-history.ts +5 -0
- package/src/types/ticker-changes.ts +19 -0
- package/src/types/ticker.ts +10 -2
- package/src/ui/context-menu.tsx +2 -0
- package/src/ui/host.tsx +40 -4
- package/src/ui/measured-cells.ts +13 -7
- package/src/ui/qr.ts +7 -5
- package/src/updater/index.ts +5 -5
- package/src/utils/calendar-date.ts +86 -27
- package/src/utils/currency-units.ts +17 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/dividend-cash.ts +48 -0
- package/src/utils/dom-screenshot-rasters.ts +3 -1
- package/src/utils/dom-screenshot.ts +14 -10
- package/src/utils/exchange-rate-snapshot.ts +9 -4
- package/src/utils/external-url.ts +1 -0
- package/src/utils/fiscal-period.ts +47 -0
- package/src/utils/format.ts +5 -2
- package/src/utils/forward-dividend.ts +160 -11
- package/src/utils/futures-generic.ts +34 -8
- package/src/utils/http-proxy-response.ts +2 -1
- package/src/utils/local-utc-offset.ts +2 -0
- package/src/utils/log-failure.ts +31 -0
- package/src/utils/option-expiry.ts +12 -12
- package/src/utils/price-history-integrity.ts +56 -0
- package/src/utils/price-history.ts +13 -1
- package/src/utils/sec-filings.ts +245 -0
- package/src/utils/selection-clipboard.ts +5 -2
- package/src/utils/throttled-fetch.ts +1 -0
- package/src/{plugins/builtin/dividend-yield/trailing-cash.ts → utils/trailing-dividend.ts} +55 -8
- package/src/utils/url.ts +1 -0
- package/src/utils/utc-time.ts +11 -0
- package/src/plugins/builtin/chat/share/targets.ts +0 -27
- package/src/renderers/dom/host/top-surface.ts +0 -119
- package/src/shares/dialog.tsx +0 -221
- package/src/shares/live.ts +0 -19
|
@@ -209,7 +209,7 @@ function createNotesFilesCapability(): PluginCapability {
|
|
|
209
209
|
await io(input).delete(file(input));
|
|
210
210
|
return null;
|
|
211
211
|
}, "action"),
|
|
212
|
-
listKeys: op((input: any) => io(input).listKeys()),
|
|
212
|
+
listKeys: op((input: any) => io(input).listKeys({ strict: input.strict === true })),
|
|
213
213
|
},
|
|
214
214
|
};
|
|
215
215
|
}
|
|
@@ -470,7 +470,7 @@ export class DesktopBackend {
|
|
|
470
470
|
case "desktop.dockDetachedPane":
|
|
471
471
|
case "desktop.closeDetachedPane":
|
|
472
472
|
case "desktop.focusDetachedPane":
|
|
473
|
-
return handleDesktopWorkspaceRequest(this, request);
|
|
473
|
+
return handleDesktopWorkspaceRequest(this, rpc, request);
|
|
474
474
|
case "pluginState.setMany":
|
|
475
475
|
case "pluginState.delete":
|
|
476
476
|
return handleDesktopPluginStateRequest(this.requireServices().persistence.pluginState, request);
|
|
@@ -108,6 +108,7 @@ export async function initializeDesktopBackend(
|
|
|
108
108
|
): Promise<ElectrobunBackendInit> {
|
|
109
109
|
const windowTarget = normalizeInitWindowTarget(backend.rpcs.getRpcWindowKey(rpc), payload);
|
|
110
110
|
backend.rpcs.markWindowRpcReady(rpc);
|
|
111
|
+
backend.stateBroadcaster.forgetWindowState(rpc);
|
|
111
112
|
|
|
112
113
|
const currentConfig = backend.config;
|
|
113
114
|
const currentServices = backend.services;
|
|
@@ -17,9 +17,25 @@ interface DesktopStateBroadcasterOptions<Rpc extends DesktopStateRpc> {
|
|
|
17
17
|
forEachReadyWindowRpc: (callback: (rpc: Rpc) => void) => void;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* The parts of a snapshot a window applies, as the text the windows compare;
|
|
22
|
+
* the revision and layout flag only qualify them. Being text, it keeps no
|
|
23
|
+
* reference to objects this process may change later.
|
|
24
|
+
*/
|
|
25
|
+
function desktopStateKey(snapshot: DesktopSharedStateSnapshot): string {
|
|
26
|
+
return JSON.stringify({
|
|
27
|
+
config: snapshot.config,
|
|
28
|
+
paneState: snapshot.paneState,
|
|
29
|
+
focusedPaneId: snapshot.focusedPaneId,
|
|
30
|
+
statusBarVisible: snapshot.statusBarVisible,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
20
34
|
export class DesktopStateBroadcaster<Rpc extends DesktopStateRpc> {
|
|
21
35
|
private dockPreview: DesktopDockPreviewState = { paneId: null, edge: null };
|
|
22
36
|
private themePreview: DesktopThemePreviewState = { theme: null };
|
|
37
|
+
/** The state held by each window that sends its whole state: what it last sent here or was sent. */
|
|
38
|
+
private readonly heldStateKeys = new WeakMap<Rpc, string>();
|
|
23
39
|
|
|
24
40
|
constructor(private readonly options: DesktopStateBroadcasterOptions<Rpc>) {}
|
|
25
41
|
|
|
@@ -35,10 +51,36 @@ export class DesktopStateBroadcaster<Rpc extends DesktopStateRpc> {
|
|
|
35
51
|
this.dockPreview = { paneId: null, edge: null };
|
|
36
52
|
}
|
|
37
53
|
|
|
54
|
+
/** A window that sent its whole state holds it, and is not sent it back. */
|
|
55
|
+
noteWindowState(rpc: Rpc, snapshot: DesktopSharedStateSnapshot): void {
|
|
56
|
+
this.heldStateKeys.set(rpc, desktopStateKey(snapshot));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** A window that starts over (a load or reload) gets every state until it sends its own. */
|
|
60
|
+
forgetWindowState(rpc: Rpc): void {
|
|
61
|
+
this.heldStateKeys.delete(rpc);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Sends the state to every ready window in the order the changes happen,
|
|
66
|
+
* except a window that sent its whole state and already holds this one: it
|
|
67
|
+
* would decode and compare the state only to drop it. A popped-out window
|
|
68
|
+
* gets every state. It applies one only when the part for its own pane
|
|
69
|
+
* changed, and then whole, so the state its own change produces is what
|
|
70
|
+
* brings its copy of the tabs and settings up to date.
|
|
71
|
+
*/
|
|
38
72
|
sendDesktopState(snapshot: DesktopSharedStateSnapshot | null): void {
|
|
39
73
|
if (!snapshot) return;
|
|
40
|
-
|
|
74
|
+
let encodedSnapshot: DesktopSharedStateSnapshot | null = null;
|
|
75
|
+
let snapshotKey: string | null = null;
|
|
41
76
|
this.options.forEachReadyWindowRpc((rpc) => {
|
|
77
|
+
const heldKey = this.heldStateKeys.get(rpc);
|
|
78
|
+
if (heldKey !== undefined) {
|
|
79
|
+
snapshotKey ??= desktopStateKey(snapshot);
|
|
80
|
+
if (heldKey === snapshotKey) return;
|
|
81
|
+
this.heldStateKeys.set(rpc, snapshotKey);
|
|
82
|
+
}
|
|
83
|
+
encodedSnapshot ??= encodeRpcValue(snapshot) as DesktopSharedStateSnapshot;
|
|
42
84
|
rpc.send["desktop.state"]({
|
|
43
85
|
snapshot: encodedSnapshot,
|
|
44
86
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DesktopWorkspaceRequest } from "../../../shared/protocol";
|
|
2
|
-
import type { DesktopBackend } from "../backend";
|
|
2
|
+
import type { DesktopBackend, DesktopRpc } from "../backend";
|
|
3
3
|
|
|
4
4
|
type DockEdge = "left" | "right" | "top" | "bottom";
|
|
5
5
|
|
|
@@ -18,6 +18,7 @@ function normalizeDockEdge(edge: unknown): DockEdge | undefined {
|
|
|
18
18
|
|
|
19
19
|
export async function handleDesktopWorkspaceRequest(
|
|
20
20
|
backend: DesktopBackend,
|
|
21
|
+
rpc: DesktopRpc,
|
|
21
22
|
request: DesktopWorkspaceRequest,
|
|
22
23
|
): Promise<null> {
|
|
23
24
|
const workspace = backend.requireWorkspace();
|
|
@@ -27,6 +28,9 @@ export async function handleDesktopWorkspaceRequest(
|
|
|
27
28
|
const snapshot = workspace.syncMainState(request.payload.snapshot);
|
|
28
29
|
backend.setConfig(snapshot.config);
|
|
29
30
|
detachedWindows.reconcile();
|
|
31
|
+
// The main window holds what it sent. It gets the state back only when
|
|
32
|
+
// this process changed it: a popped-out window's frame, a stale revision.
|
|
33
|
+
stateBroadcaster.noteWindowState(rpc, request.payload.snapshot);
|
|
30
34
|
stateBroadcaster.sendDesktopState(snapshot);
|
|
31
35
|
return null;
|
|
32
36
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ApiRequestError } from "../../../api-client/errors";
|
|
2
2
|
import { isHistoryRetentionError, parseHistoryRetentionError } from "../../../sources/history-retention";
|
|
3
|
+
import { isProviderBusy, ProviderBusyError } from "../../../sources/provider-errors";
|
|
3
4
|
|
|
4
5
|
const DATE_MARKER = "__gloomDate";
|
|
5
6
|
const MAP_MARKER = "__gloomMap";
|
|
@@ -15,6 +16,8 @@ export async function encodeRpcResponse(load: () => unknown | Promise<unknown>):
|
|
|
15
16
|
ok: false,
|
|
16
17
|
error: { kind: "history-retention", retention: error.retention, candidates: error.candidates, outcomes: error.outcomes },
|
|
17
18
|
};
|
|
19
|
+
// A search the view runs must tell a busy source from one that found nothing.
|
|
20
|
+
if (isProviderBusy(error)) return { [RESPONSE_MARKER]: 1, ok: false, error: { kind: "provider-busy", message: error.message } };
|
|
18
21
|
if (!(error instanceof ApiRequestError)) throw error;
|
|
19
22
|
return {
|
|
20
23
|
[RESPONSE_MARKER]: 1,
|
|
@@ -36,6 +39,10 @@ export function decodeRpcResponse<T = unknown>(value: unknown): T {
|
|
|
36
39
|
if (!retention) throw new Error("Invalid desktop response");
|
|
37
40
|
throw retention;
|
|
38
41
|
}
|
|
42
|
+
if (response.ok === false && error && typeof error === "object" && error.kind === "provider-busy") {
|
|
43
|
+
if (typeof error.message !== "string") throw new Error("Invalid desktop response");
|
|
44
|
+
throw new ProviderBusyError(error.message);
|
|
45
|
+
}
|
|
39
46
|
if (response.ok !== false || !error || typeof error !== "object"
|
|
40
47
|
|| (error.kind !== undefined && error.kind !== "api")
|
|
41
48
|
|| typeof error.message !== "string"
|
|
@@ -3,6 +3,7 @@ import { createRoot } from "react-dom/client";
|
|
|
3
3
|
import { useEffect, useState, type ReactNode } from "react";
|
|
4
4
|
import { TapeClientContext } from "../../../plugins/builtin/time-sales/use-tape";
|
|
5
5
|
import { createSnapshotTapeClient } from "../../../plugins/builtin/time-sales/snapshot-client";
|
|
6
|
+
import { createSnapshotScannerClient, ScannerClientContext } from "../../../plugins/builtin/shared/scanner-capture";
|
|
6
7
|
import type { TapeSnapshot } from "../../../api-client/tape";
|
|
7
8
|
import { AppProvider, useAppDispatch } from "../../../state/app/context";
|
|
8
9
|
import { createCliPaneShotConnectionHealth } from "./cli-pane-shot-health";
|
|
@@ -513,25 +514,28 @@ async function render() {
|
|
|
513
514
|
|
|
514
515
|
const tapeClient = createSnapshotTapeClient(payload.tapeSnapshots ?? [],
|
|
515
516
|
(symbol, exchange) => requestShotMarketData<TapeSnapshot>("getCloudTape", [symbol, exchange]));
|
|
517
|
+
const scannerClient = createSnapshotScannerClient(payload.scannerSnapshots ?? []);
|
|
516
518
|
createRoot(rootElement).render(
|
|
517
519
|
<TapeClientContext.Provider value={tapeClient}>
|
|
518
|
-
<
|
|
519
|
-
<
|
|
520
|
-
|
|
521
|
-
<
|
|
522
|
-
config
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
<
|
|
529
|
-
<
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
520
|
+
<ScannerClientContext.Provider value={scannerClient}>
|
|
521
|
+
<RemoteUiRegistryProvider>
|
|
522
|
+
<CaptureShotSemanticUi />
|
|
523
|
+
<DomHostProviders ui={webUiHost} renderer={rendererHost}>
|
|
524
|
+
<AppProvider config={payload.config} desktopSnapshot={{
|
|
525
|
+
config: payload.config,
|
|
526
|
+
paneState: payload.paneState,
|
|
527
|
+
focusedPaneId: payload.paneId,
|
|
528
|
+
statusBarVisible: false,
|
|
529
|
+
}}>
|
|
530
|
+
<HydratePayload payload={payload}>
|
|
531
|
+
<ChartSnapshotContext.Provider value={payload.chartModel ?? null}>
|
|
532
|
+
<ShotPane payload={payload} registry={services.pluginRegistry} />
|
|
533
|
+
</ChartSnapshotContext.Provider>
|
|
534
|
+
</HydratePayload>
|
|
535
|
+
</AppProvider>
|
|
536
|
+
</DomHostProviders>
|
|
537
|
+
</RemoteUiRegistryProvider>
|
|
538
|
+
</ScannerClientContext.Provider>
|
|
535
539
|
</TapeClientContext.Provider>,
|
|
536
540
|
);
|
|
537
541
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useCallback, useEffect, useRef, useState, type ReactNode } from "react";
|
|
3
3
|
import { FloatingPaneWrapper } from "../../../components/layout/floating-pane";
|
|
4
4
|
import { CaptureDatesDataContext } from "../../../components/layout/pane/capture-status";
|
|
5
|
-
import { PaneFooterProvider, hasPaneFooterContent, type PaneFooterSegment } from "../../../components/layout/pane/footer";
|
|
5
|
+
import { PaneFooterProvider, datesPaneData, hasPaneFooterContent, type PaneFooterSegment } from "../../../components/layout/pane/footer";
|
|
6
6
|
import { resolvePaneBodyFrame } from "../../../components/layout/pane/sizing";
|
|
7
7
|
|
|
8
8
|
/** What a capture's status line dates (`CaptureStatusLine`): the pane's own data, the quotes on screen, or neither. */
|
|
@@ -150,9 +150,9 @@ export function PaneShotFrame({ paneId, title, width, height, preserveStatus = f
|
|
|
150
150
|
return <PaneFooterProvider>{(registeredFooter) => {
|
|
151
151
|
const status: PaneFooterSegment[] = statusLine ? [{ id: "shot-status", parts: [{ text: statusText, tone: "label" }] }] : [];
|
|
152
152
|
const info = registeredFooter.info.filter((segment) => (preserveStatus || segment.icon === "warning")
|
|
153
|
-
&& !(segment
|
|
153
|
+
&& !(datesPaneData(segment) && (datesData || crowded))
|
|
154
154
|
&& !(segment.quoteStatus && statusLine && dates !== null));
|
|
155
|
-
shownAsOf.current = info.some(
|
|
155
|
+
shownAsOf.current = info.some(datesPaneData);
|
|
156
156
|
const footer = { info: [...info, ...status], hints: [], menu: [], keys: [] };
|
|
157
157
|
const bodyFrame = resolvePaneBodyFrame({
|
|
158
158
|
width,
|
|
@@ -6,12 +6,12 @@ import type {
|
|
|
6
6
|
DesktopWindowBridge,
|
|
7
7
|
} from "../../../../../types/desktop-window";
|
|
8
8
|
import { backendRequest, getElectrobunBackendInitSnapshot, onBackendMessage } from "../../backend-rpc";
|
|
9
|
-
import {
|
|
9
|
+
import { createDetachedSnapshotFilter } from "./snapshot";
|
|
10
10
|
|
|
11
11
|
export function createDesktopWindowBridge(kind: "main" | "detached", paneId?: string): DesktopWindowBridge {
|
|
12
12
|
const initialDesktopSnapshot = getElectrobunBackendInitSnapshot()?.desktopSnapshot ?? null;
|
|
13
|
-
|
|
14
|
-
?
|
|
13
|
+
const takeDetachedSnapshot = kind === "detached" && paneId
|
|
14
|
+
? createDetachedSnapshotFilter(paneId, initialDesktopSnapshot)
|
|
15
15
|
: null;
|
|
16
16
|
|
|
17
17
|
return {
|
|
@@ -46,11 +46,9 @@ export function createDesktopWindowBridge(kind: "main" | "detached", paneId?: st
|
|
|
46
46
|
},
|
|
47
47
|
subscribeState(listener: (snapshot: DesktopSharedStateSnapshot) => void) {
|
|
48
48
|
return onBackendMessage("desktop.state", (message) => {
|
|
49
|
-
if (
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
52
|
-
lastDetachedSnapshotKey = nextKey;
|
|
53
|
-
listener(prepareDetachedSnapshot(message.snapshot, paneId));
|
|
49
|
+
if (takeDetachedSnapshot) {
|
|
50
|
+
const snapshot = takeDetachedSnapshot(message.snapshot);
|
|
51
|
+
if (snapshot) listener(snapshot);
|
|
54
52
|
return;
|
|
55
53
|
}
|
|
56
54
|
listener(message.snapshot);
|
|
@@ -39,3 +39,21 @@ export function detachedSnapshotKey(snapshot: DesktopSharedStateSnapshot, paneId
|
|
|
39
39
|
paneState: Object.fromEntries(paneStateIds.map((id) => [id, snapshot.paneState[id] ?? {}])),
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* What a popped-out window takes of each state it is sent: nothing unless the
|
|
45
|
+
* part for its pane and the panes it follows changed, and then all of it,
|
|
46
|
+
* config included.
|
|
47
|
+
*/
|
|
48
|
+
export function createDetachedSnapshotFilter(
|
|
49
|
+
paneId: string,
|
|
50
|
+
initialSnapshot: DesktopSharedStateSnapshot | null,
|
|
51
|
+
): (snapshot: DesktopSharedStateSnapshot) => DesktopSharedStateSnapshot | null {
|
|
52
|
+
let lastKey = initialSnapshot ? detachedSnapshotKey(initialSnapshot, paneId) : null;
|
|
53
|
+
return (snapshot) => {
|
|
54
|
+
const nextKey = detachedSnapshotKey(snapshot, paneId);
|
|
55
|
+
if (nextKey === lastKey) return null;
|
|
56
|
+
lastKey = nextKey;
|
|
57
|
+
return prepareDetachedSnapshot(snapshot, paneId);
|
|
58
|
+
};
|
|
59
|
+
}
|
package/src/series/capability.ts
CHANGED
|
@@ -21,6 +21,7 @@ export async function resolveRegisteredSeries(
|
|
|
21
21
|
const resolved = await resolveLoadedSeries(found.series.definition as LoadedSeriesDefinition, {
|
|
22
22
|
viewport,
|
|
23
23
|
...(found.ticker ? { ticker: found.ticker } : {}),
|
|
24
|
+
...(found.line ? { line: found.line } : {}),
|
|
24
25
|
...(signal ? { signal } : {}),
|
|
25
26
|
});
|
|
26
27
|
// The same checks a series from another process passes.
|
package/src/series/files.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../utils/log-failure";
|
|
1
2
|
import { inferSeriesFrequency, parseSeriesCsv } from "./csv";
|
|
2
3
|
import type { SeriesDefinition, SeriesFrequency } from "./types";
|
|
3
4
|
import { SERIES_FREQUENCIES, isValidSeriesUnit } from "./validate";
|
|
@@ -78,7 +79,9 @@ export async function listSeriesFiles(dataDir: string): Promise<SeriesFolderFile
|
|
|
78
79
|
let names: string[];
|
|
79
80
|
try {
|
|
80
81
|
names = (await readdir(folder)).filter((name) => name.toLowerCase().endsWith(".csv"));
|
|
81
|
-
} catch {
|
|
82
|
+
} catch (error) {
|
|
83
|
+
// An absent optional file or directory is expected.
|
|
84
|
+
if ((error as { code?: unknown } | null)?.code !== "ENOENT") logFailure("series.files", "Listing series files failed")(error);
|
|
82
85
|
return [];
|
|
83
86
|
}
|
|
84
87
|
const files = await Promise.all(names.map(async (name): Promise<SeriesFolderFile | null> => {
|
|
@@ -86,7 +89,9 @@ export async function listSeriesFiles(dataDir: string): Promise<SeriesFolderFile
|
|
|
86
89
|
try {
|
|
87
90
|
const { mtimeMs } = await stat(path);
|
|
88
91
|
return { name, mtimeMs, readText: () => readFile(path, "utf-8") };
|
|
89
|
-
} catch {
|
|
92
|
+
} catch (error) {
|
|
93
|
+
// An absent optional file or directory is expected.
|
|
94
|
+
if ((error as { code?: unknown } | null)?.code !== "ENOENT") logFailure("series.files", "Reading series file metadata failed")(error);
|
|
90
95
|
return null;
|
|
91
96
|
}
|
|
92
97
|
}));
|
|
@@ -99,7 +104,8 @@ export async function readSeriesFolder(dataDir: string): Promise<SeriesDefinitio
|
|
|
99
104
|
const definitions = await Promise.all(files.map(async (file) => {
|
|
100
105
|
try {
|
|
101
106
|
return seriesFromFile(file.name, await file.readText(), file.readText);
|
|
102
|
-
} catch {
|
|
107
|
+
} catch (error) {
|
|
108
|
+
logFailure("series.files", "Reading series definitions failed")(error);
|
|
103
109
|
return [];
|
|
104
110
|
}
|
|
105
111
|
}));
|
package/src/series/registry.ts
CHANGED
|
@@ -8,11 +8,15 @@ import type {
|
|
|
8
8
|
RegisteredSeries,
|
|
9
9
|
SeriesCatalogEntry,
|
|
10
10
|
SeriesDefinition,
|
|
11
|
+
SeriesLine,
|
|
11
12
|
} from "./types";
|
|
12
13
|
|
|
14
|
+
/** Between a series' name and one of its lines in a capability series id: `bands~upper/AAPL`. */
|
|
15
|
+
const LINE_SEPARATOR = "~";
|
|
16
|
+
|
|
13
17
|
/** The expression a loaded series charts as: the namespace is its chart-series capability. */
|
|
14
|
-
function loadedSeriesExpression(definition: Pick<SeriesDefinition, "id" | "input"
|
|
15
|
-
return `CAP:${definition.id}${definition.input ? `/${TICKER_PLACEHOLDER}` : ""}`;
|
|
18
|
+
function loadedSeriesExpression(definition: Pick<SeriesDefinition, "id" | "input">, lineId?: string): string {
|
|
19
|
+
return `CAP:${definition.id}${lineId ? `${LINE_SEPARATOR}${lineId}` : ""}${definition.input ? `/${TICKER_PLACEHOLDER}` : ""}`;
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
export function seriesExpression(definition: SeriesDefinition): string {
|
|
@@ -20,25 +24,31 @@ export function seriesExpression(definition: SeriesDefinition): string {
|
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
/**
|
|
23
|
-
* The capability series id a loaded series charts under: its name,
|
|
24
|
-
* series with an input, the symbol after a
|
|
27
|
+
* The capability series id a loaded series charts under: its name, one of its
|
|
28
|
+
* lines after a tilde, and for a series with an input, the symbol after a
|
|
29
|
+
* slash (`days-to-cover/AAPL`, `bands~upper/AAPL`).
|
|
25
30
|
*/
|
|
26
|
-
export function capabilitySeriesId(definition: Pick<SeriesDefinition, "id">, ticker?: string): string {
|
|
27
|
-
const name = splitSeriesId(definition.id)?.name ?? definition.id
|
|
31
|
+
export function capabilitySeriesId(definition: Pick<SeriesDefinition, "id">, ticker?: string, lineId?: string): string {
|
|
32
|
+
const name = `${splitSeriesId(definition.id)?.name ?? definition.id}${lineId ? `${LINE_SEPARATOR}${lineId}` : ""}`;
|
|
28
33
|
return ticker ? `${name}/${encodeURIComponent(ticker.trim().toUpperCase())}` : name;
|
|
29
34
|
}
|
|
30
35
|
|
|
31
|
-
/** The registered id and the typed symbol a capability series id names. */
|
|
32
|
-
function parseCapabilitySeriesId(namespace: string, seriesId: string): { id: string; ticker?: string } {
|
|
36
|
+
/** The registered id, the line and the typed symbol a capability series id names. */
|
|
37
|
+
function parseCapabilitySeriesId(namespace: string, seriesId: string): { id: string; ticker?: string; line?: string } {
|
|
33
38
|
const slash = seriesId.indexOf("/");
|
|
34
|
-
|
|
39
|
+
const named = slash < 0 ? seriesId : seriesId.slice(0, slash);
|
|
40
|
+
const tilde = named.indexOf(LINE_SEPARATOR);
|
|
41
|
+
const name = tilde < 0 ? named : named.slice(0, tilde);
|
|
42
|
+
const line = tilde < 0 ? undefined : named.slice(tilde + 1);
|
|
43
|
+
const base = { id: `${namespace}:${name}`, ...(line ? { line } : {}) };
|
|
44
|
+
if (slash < 0) return base;
|
|
35
45
|
let ticker: string;
|
|
36
46
|
try {
|
|
37
47
|
ticker = decodeURIComponent(seriesId.slice(slash + 1));
|
|
38
48
|
} catch {
|
|
39
49
|
ticker = seriesId.slice(slash + 1);
|
|
40
50
|
}
|
|
41
|
-
return {
|
|
51
|
+
return { ...base, ticker };
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
export function seriesCatalogEntry(series: RegisteredSeries): SeriesCatalogEntry {
|
|
@@ -54,6 +64,16 @@ export function seriesCatalogEntry(series: RegisteredSeries): SeriesCatalogEntry
|
|
|
54
64
|
...(definition.publisher ? { publisher: definition.publisher } : {}),
|
|
55
65
|
...(definition.url ? { url: definition.url } : {}),
|
|
56
66
|
...(definition.input ? { input: definition.input } : {}),
|
|
67
|
+
...(definition.placement ? { placement: definition.placement } : {}),
|
|
68
|
+
...(definition.lines?.length ? {
|
|
69
|
+
lines: definition.lines.map((line) => ({
|
|
70
|
+
id: line.id,
|
|
71
|
+
name: line.name,
|
|
72
|
+
// A line shading the area to another is drawn as a band: its line inside the shade.
|
|
73
|
+
...(line.fill ? { style: "band" as const } : line.style ? { style: line.style } : {}),
|
|
74
|
+
expression: loadedSeriesExpression(definition, line.id),
|
|
75
|
+
})),
|
|
76
|
+
} : {}),
|
|
57
77
|
expression: seriesExpression(definition),
|
|
58
78
|
pluginId,
|
|
59
79
|
};
|
|
@@ -131,14 +151,20 @@ export class SeriesRegistry {
|
|
|
131
151
|
return this.namespaces.get(namespace)?.pluginId;
|
|
132
152
|
}
|
|
133
153
|
|
|
134
|
-
/**
|
|
135
|
-
|
|
154
|
+
/**
|
|
155
|
+
* The loaded series a chart-series capability source names, with the typed
|
|
156
|
+
* symbol and the line. A series with lines named without one is its first line.
|
|
157
|
+
*/
|
|
158
|
+
findLoaded(capabilityId: string, seriesId: string): { series: RegisteredSeries; ticker?: string; line?: SeriesLine } | null {
|
|
136
159
|
if (!this.namespaces.has(capabilityId)) return null;
|
|
137
|
-
const { id, ticker } = parseCapabilitySeriesId(capabilityId, seriesId);
|
|
160
|
+
const { id, ticker, line: lineId } = parseCapabilitySeriesId(capabilityId, seriesId);
|
|
138
161
|
const series = this.entries.get(id);
|
|
139
162
|
if (!series?.definition.load) return null;
|
|
140
163
|
if (!!series.definition.input !== !!ticker) return null;
|
|
141
|
-
|
|
164
|
+
const lines = series.definition.lines;
|
|
165
|
+
const line = lines?.length ? lineId ? lines.find((entry) => entry.id === lineId) : lines[0] : undefined;
|
|
166
|
+
if (lineId && !line) return null;
|
|
167
|
+
return { series, ...(ticker ? { ticker } : {}), ...(line ? { line } : {}) };
|
|
142
168
|
}
|
|
143
169
|
|
|
144
170
|
/** The series that charts as this exact expression (`FRED:UNRATE`), if one without an input does. */
|
package/src/series/resolve.ts
CHANGED
|
@@ -6,12 +6,16 @@ import type {
|
|
|
6
6
|
SeriesPeriod,
|
|
7
7
|
TimeSeriesPoint,
|
|
8
8
|
} from "../time-series/types";
|
|
9
|
+
import { getPresetResolution, type ManualChartResolution } from "../time-series/resolution";
|
|
9
10
|
import { SERIES_COLORS } from "../theme/series-colors";
|
|
10
11
|
import type {
|
|
11
12
|
LoadedSeriesDefinition,
|
|
12
13
|
SeriesFrequency,
|
|
14
|
+
SeriesLine,
|
|
15
|
+
SeriesLinesLoadResult,
|
|
13
16
|
SeriesLoadOutput,
|
|
14
17
|
SeriesLoadRequest,
|
|
18
|
+
SeriesLoadResult,
|
|
15
19
|
SeriesPoint,
|
|
16
20
|
} from "./types";
|
|
17
21
|
|
|
@@ -25,8 +29,7 @@ function seriesPointDate(value: SeriesPoint["date"]): Date | null {
|
|
|
25
29
|
return Number.isFinite(date.getTime()) ? date : null;
|
|
26
30
|
}
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
export function normalizeSeriesPoints(points: readonly SeriesPoint[]): TimeSeriesPoint[] {
|
|
32
|
+
function valuesByTime(points: readonly SeriesPoint[]): Map<number, number | null> {
|
|
30
33
|
const byTime = new Map<number, number | null>();
|
|
31
34
|
for (const point of points) {
|
|
32
35
|
const date = point ? seriesPointDate(point.date) : null;
|
|
@@ -34,10 +37,24 @@ export function normalizeSeriesPoints(points: readonly SeriesPoint[]): TimeSerie
|
|
|
34
37
|
const value = typeof point.value === "number" && Number.isFinite(point.value) ? point.value : null;
|
|
35
38
|
byTime.set(date.getTime(), value);
|
|
36
39
|
}
|
|
40
|
+
return byTime;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Oldest first, one point per instant (the last one given wins), at most the
|
|
45
|
+
* chart's point limit. With `edge`, another line's points, each point spans
|
|
46
|
+
* from its value to that line's value at the same instant: a band's range.
|
|
47
|
+
*/
|
|
48
|
+
export function normalizeSeriesPoints(points: readonly SeriesPoint[], edge?: readonly SeriesPoint[]): TimeSeriesPoint[] {
|
|
49
|
+
const byTime = valuesByTime(points);
|
|
50
|
+
const edges = edge ? valuesByTime(edge) : null;
|
|
37
51
|
const sorted = [...byTime].sort(([left], [right]) => left - right);
|
|
38
52
|
return sorted.slice(-MAX_CHART_SERIES_POINTS).map(([time, value]) => {
|
|
39
53
|
const date = new Date(time);
|
|
40
|
-
|
|
54
|
+
const other = edges?.get(time);
|
|
55
|
+
return value !== null && other != null
|
|
56
|
+
? { date, observedAt: date, value, low: Math.min(value, other), high: Math.max(value, other) }
|
|
57
|
+
: { date, observedAt: date, value };
|
|
41
58
|
});
|
|
42
59
|
}
|
|
43
60
|
|
|
@@ -50,11 +67,16 @@ function seriesUnitGroup(unit: string): string {
|
|
|
50
67
|
return unit === "%" ? "percent" : `series:${unit.toLowerCase()}`;
|
|
51
68
|
}
|
|
52
69
|
|
|
53
|
-
/** One colour per id, so two loaded series on a chart are told apart. */
|
|
54
|
-
function seriesColor(id: string): string {
|
|
70
|
+
/** One colour per id, so two loaded series on a chart are told apart; a series' lines take the colours after it. */
|
|
71
|
+
function seriesColor(id: string, lineIndex = 0): string {
|
|
55
72
|
let hash = 0;
|
|
56
73
|
for (const char of id) hash = (hash * 31 + char.charCodeAt(0)) >>> 0;
|
|
57
|
-
return SERIES_COLORS[hash % SERIES_COLORS.length]!;
|
|
74
|
+
return SERIES_COLORS[(hash + lineIndex) % SERIES_COLORS.length]!;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The bar size a chart draws prices in: the one it was set to, else its range's default. */
|
|
78
|
+
function viewportResolution(viewport: ChartViewportSpec): ManualChartResolution {
|
|
79
|
+
return viewport.resolution === "auto" ? getPresetResolution(viewport.range) : viewport.resolution;
|
|
58
80
|
}
|
|
59
81
|
|
|
60
82
|
/** The dates a chart viewport covers, as a series load request takes them. */
|
|
@@ -68,32 +90,113 @@ export function seriesLoadWindow(viewport: ChartViewportSpec, now = new Date()):
|
|
|
68
90
|
return { start: subtractTimeRange(now, viewport.range) };
|
|
69
91
|
}
|
|
70
92
|
|
|
71
|
-
function loadResult(output: SeriesLoadOutput):
|
|
72
|
-
if (Array.isArray(output))
|
|
73
|
-
|
|
93
|
+
function loadResult(output: SeriesLoadOutput, line: SeriesLine | undefined): SeriesLoadResult & { edge?: readonly SeriesPoint[] } {
|
|
94
|
+
if (Array.isArray(output)) {
|
|
95
|
+
if (line) throw new Error("Series loader returned points where its lines were expected.");
|
|
96
|
+
return { points: output };
|
|
97
|
+
}
|
|
98
|
+
const result = output as Partial<SeriesLoadResult & SeriesLinesLoadResult> | null;
|
|
99
|
+
if (line) {
|
|
100
|
+
if (!result || !result.lines || typeof result.lines !== "object") throw new Error("Series loader returned no lines.");
|
|
101
|
+
const { lines, ...rest } = result;
|
|
102
|
+
const points = lines[line.id];
|
|
103
|
+
const edge = line.fill ? lines[line.fill] : undefined;
|
|
104
|
+
// A line the loaded data no longer has (the series changed under a saved chart) draws nothing.
|
|
105
|
+
return { ...rest, points: Array.isArray(points) ? points : [], ...(Array.isArray(edge) ? { edge } : {}) };
|
|
106
|
+
}
|
|
74
107
|
if (!result || !Array.isArray(result.points)) throw new Error("Series loader returned no points.");
|
|
75
|
-
return result;
|
|
108
|
+
return result as SeriesLoadResult;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** How long one load is shared by the lines of a series that ask for it together. */
|
|
112
|
+
const SHARED_LOAD_MS = 2_000;
|
|
113
|
+
|
|
114
|
+
interface SharedLoad {
|
|
115
|
+
output: Promise<SeriesLoadOutput>;
|
|
116
|
+
controller: AbortController;
|
|
117
|
+
/** Requests still waiting that can be called off. */
|
|
118
|
+
waiting: number;
|
|
119
|
+
/** A request that cannot be called off shares the load, so it runs to the end. */
|
|
120
|
+
kept: boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const sharedLoads = new WeakMap<LoadedSeriesDefinition, Map<string, SharedLoad>>();
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Loads a series once for all of its lines: a chart asks for each line on its
|
|
127
|
+
* own, at the same time and for the same dates, and the loader runs once. The
|
|
128
|
+
* loader's signal aborts when every request sharing the load has.
|
|
129
|
+
*/
|
|
130
|
+
function loadSeries(definition: LoadedSeriesDefinition, request: SeriesLoadRequest): Promise<SeriesLoadOutput> {
|
|
131
|
+
if (!definition.lines?.length) return Promise.resolve(definition.load(request));
|
|
132
|
+
const { signal, ...shared } = request;
|
|
133
|
+
if (signal?.aborted) return Promise.reject(signal.reason);
|
|
134
|
+
// A window measured back from now moves by milliseconds between the lines' requests.
|
|
135
|
+
const minute = (date: Date | undefined) => date ? Math.floor(date.getTime() / 60_000) : null;
|
|
136
|
+
const key = JSON.stringify([shared.ticker ?? null, minute(shared.start), minute(shared.end), shared.resolution ?? null]);
|
|
137
|
+
let byKey = sharedLoads.get(definition);
|
|
138
|
+
if (!byKey) sharedLoads.set(definition, byKey = new Map());
|
|
139
|
+
let load = byKey.get(key);
|
|
140
|
+
if (!load) {
|
|
141
|
+
const controller = new AbortController();
|
|
142
|
+
const output = Promise.resolve().then(() => {
|
|
143
|
+
controller.signal.throwIfAborted();
|
|
144
|
+
return definition.load({ ...shared, signal: controller.signal });
|
|
145
|
+
});
|
|
146
|
+
const entry: SharedLoad = { output, controller, waiting: 0, kept: false };
|
|
147
|
+
load = entry;
|
|
148
|
+
byKey.set(key, entry);
|
|
149
|
+
const forget = () => {
|
|
150
|
+
const timer = setTimeout(() => { if (byKey.get(key) === entry) byKey.delete(key); }, SHARED_LOAD_MS);
|
|
151
|
+
(timer as { unref?: () => void }).unref?.();
|
|
152
|
+
};
|
|
153
|
+
output.then(forget, forget);
|
|
154
|
+
}
|
|
155
|
+
const entry = load;
|
|
156
|
+
if (!signal) {
|
|
157
|
+
entry.kept = true;
|
|
158
|
+
return entry.output;
|
|
159
|
+
}
|
|
160
|
+
entry.waiting += 1;
|
|
161
|
+
return new Promise<SeriesLoadOutput>((resolve, reject) => {
|
|
162
|
+
const onAbort = () => {
|
|
163
|
+
entry.waiting -= 1;
|
|
164
|
+
if (entry.waiting === 0 && !entry.kept) {
|
|
165
|
+
if (byKey.get(key) === entry) byKey.delete(key);
|
|
166
|
+
entry.controller.abort(signal.reason);
|
|
167
|
+
}
|
|
168
|
+
reject(signal.reason);
|
|
169
|
+
};
|
|
170
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
171
|
+
entry.output.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
|
|
172
|
+
});
|
|
76
173
|
}
|
|
77
174
|
|
|
78
175
|
export async function resolveLoadedSeries(
|
|
79
176
|
definition: LoadedSeriesDefinition,
|
|
80
|
-
request: { viewport: ChartViewportSpec; ticker?: string; signal?: AbortSignal },
|
|
177
|
+
request: { viewport: ChartViewportSpec; ticker?: string; line?: SeriesLine; signal?: AbortSignal },
|
|
81
178
|
now = new Date(),
|
|
82
179
|
): Promise<ResolvedSeries> {
|
|
83
180
|
const ticker = request.ticker?.trim().toUpperCase() || undefined;
|
|
84
|
-
const
|
|
181
|
+
const line = definition.lines?.length ? request.line ?? definition.lines[0] : undefined;
|
|
182
|
+
const { points, edge, warning, attribution } = loadResult(await loadSeries(definition, {
|
|
85
183
|
...seriesLoadWindow(request.viewport, now),
|
|
86
184
|
...(ticker ? { ticker } : {}),
|
|
185
|
+
resolution: viewportResolution(request.viewport),
|
|
87
186
|
...(request.signal ? { signal: request.signal } : {}),
|
|
88
|
-
}));
|
|
89
|
-
const
|
|
90
|
-
const
|
|
187
|
+
}), line);
|
|
188
|
+
const seriesId = ticker ? `${definition.id}/${ticker}` : definition.id;
|
|
189
|
+
const id = line ? `${definition.id}~${line.id}${ticker ? `/${ticker}` : ""}` : seriesId;
|
|
190
|
+
const name = line ? `${definition.name} · ${line.name}` : definition.name;
|
|
191
|
+
const style = line?.style ?? definition.style ?? "line";
|
|
91
192
|
return {
|
|
92
193
|
id,
|
|
93
|
-
label: ticker ? `${ticker} · ${
|
|
94
|
-
color: seriesColor(
|
|
194
|
+
label: ticker ? `${ticker} · ${name}` : name,
|
|
195
|
+
color: line?.color ?? definition.color ?? seriesColor(seriesId, line ? definition.lines!.indexOf(line) : 0),
|
|
95
196
|
unit: definition.unit,
|
|
96
197
|
unitGroup: seriesUnitGroup(definition.unit),
|
|
198
|
+
// Drawn in the ticker's price: the chart puts it on that price's axis.
|
|
199
|
+
...(definition.placement === "price" && ticker ? { priceOf: ticker } : {}),
|
|
97
200
|
nativeFrequency: nativeFrequency(definition.frequency),
|
|
98
201
|
dataShape: "scalar",
|
|
99
202
|
style,
|
|
@@ -103,6 +206,6 @@ export async function resolveLoadedSeries(
|
|
|
103
206
|
interpolation: style === "step" ? "step-after" : "none",
|
|
104
207
|
...(warning ? { warning } : {}),
|
|
105
208
|
...(attribution ? { attribution: { ...attribution } } : {}),
|
|
106
|
-
points: normalizeSeriesPoints(points),
|
|
209
|
+
points: normalizeSeriesPoints(points, edge),
|
|
107
210
|
};
|
|
108
211
|
}
|
package/src/series/standalone.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../utils/log-failure";
|
|
1
2
|
import { chartSeriesResolveRequestSchema } from "../capabilities/chart-series";
|
|
2
3
|
import type { CapabilityInvoker } from "../capabilities/types";
|
|
3
4
|
import type { GloomPlugin } from "../types/plugin";
|
|
@@ -23,8 +24,8 @@ export function standaloneSeriesInvoker(
|
|
|
23
24
|
for (const definition of definitions) {
|
|
24
25
|
try {
|
|
25
26
|
built.register(pluginId, definition);
|
|
26
|
-
} catch {
|
|
27
|
-
|
|
27
|
+
} catch (error) {
|
|
28
|
+
logFailure("series.standalone", "Registering a standalone series failed")(error);
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
};
|