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
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { apiClient } from "../api-client";
|
|
2
|
+
import type { FundBondFacts } from "../api-client/fund-facts";
|
|
3
|
+
import type { HeadlessPaneOptionDef } from "../types/headless";
|
|
4
|
+
import { formatFundYield, NOT_SEC_YIELD } from "./bond-funds";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Tax-equivalent yield and the muni/Treasury ratio, for `fundamentals` and
|
|
8
|
+
* `fn DVD` with `--tax-rate`.
|
|
9
|
+
*
|
|
10
|
+
* tax-equivalent yield = yield / (1 - (federal rate + state rate))
|
|
11
|
+
* muni/Treasury ratio = yield / Treasury par yield at the tenor nearest the fund's duration
|
|
12
|
+
*
|
|
13
|
+
* The yield is the fund's 30-day SEC yield where its sponsor publishes one,
|
|
14
|
+
* else its distribution yield, and the output says which. The federal rate is
|
|
15
|
+
* `--tax-rate` (40.8 is the 37% top bracket plus the 3.8% net investment
|
|
16
|
+
* income tax). The state rate counts only for a single-state municipal fund
|
|
17
|
+
* of `--state`, whose income is exempt from that state's tax too; a national
|
|
18
|
+
* fund's income is taxed by the state like a taxable bond's, so the state
|
|
19
|
+
* rate cancels out. The two rates add up without netting a federal deduction
|
|
20
|
+
* for state tax, which the SALT cap mostly removes: this is how iShares
|
|
21
|
+
* computes the tax-equivalent yields it publishes (MUB 4.04% at 40.8%: 6.83%;
|
|
22
|
+
* CMF 3.87% at 40.8% + 13.3% California: 8.43%). The ratio compares pre-tax
|
|
23
|
+
* yields, the convention for muni/Treasury ratios.
|
|
24
|
+
*/
|
|
25
|
+
const TAX_EQUIVALENT_FORMULA = "tax-equivalent yield = yield / (1 - (federal rate + state rate)); the state rate counts only for a single-state muni fund of --state";
|
|
26
|
+
const MUNI_TREASURY_RATIO_FORMULA = "muni/Treasury ratio = yield / Treasury par yield at the GC tenor nearest the fund's duration";
|
|
27
|
+
|
|
28
|
+
export interface TaxRates {
|
|
29
|
+
/** Percent: federal income tax plus the net investment income tax (40.8). */
|
|
30
|
+
federal: number;
|
|
31
|
+
/** A state's rate in percent and its two-letter code, applied to that state's single-state muni funds only. */
|
|
32
|
+
state: { rate: number; code: string } | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The raw option values as typed: `--tax-rate 40.8 --state-rate 9.3 --state CA`. */
|
|
36
|
+
export interface TaxRateInput {
|
|
37
|
+
taxRate?: unknown;
|
|
38
|
+
stateRate?: unknown;
|
|
39
|
+
state?: unknown;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function percentOption(value: unknown, flag: string): number {
|
|
43
|
+
const text = String(value).trim().replace(/%$/, "");
|
|
44
|
+
const rate = /^\d+(\.\d+)?$/.test(text) ? Number(text) : Number.NaN;
|
|
45
|
+
if (!Number.isFinite(rate) || rate < 0 || rate >= 100) {
|
|
46
|
+
throw new Error(`${flag} takes a rate in percent from 0 to under 100, such as 40.8 (37% federal + 3.8% NIIT).`);
|
|
47
|
+
}
|
|
48
|
+
return rate;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** A tax rate option as typed: `40.8` or `40.8%`, kept as the number. */
|
|
52
|
+
function normalizeTaxRate(value: string): number {
|
|
53
|
+
return percentOption(value, "--tax-rate");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** A state code as typed: `ca`, `CA`. */
|
|
57
|
+
function normalizeStateCode(value: string): string {
|
|
58
|
+
const code = value.trim().toUpperCase();
|
|
59
|
+
if (!/^[A-Z]{2}$/.test(code)) throw new Error("--state takes a two-letter US state code, such as CA or NY.");
|
|
60
|
+
return code;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The rates `--tax-rate`, `--state-rate` and `--state` ask for; null without
|
|
65
|
+
* `--tax-rate`. A state rate needs its state and the other way round, and the
|
|
66
|
+
* two rates together stay under 100%.
|
|
67
|
+
*/
|
|
68
|
+
export function parseTaxRates(input: TaxRateInput): TaxRates | null {
|
|
69
|
+
const has = (value: unknown) => value !== undefined && value !== null && String(value).trim() !== "";
|
|
70
|
+
if (!has(input.taxRate)) {
|
|
71
|
+
if (has(input.stateRate) || has(input.state)) throw new Error("--state-rate and --state go with --tax-rate, such as --tax-rate 40.8 --state-rate 9.3 --state CA.");
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const federal = percentOption(input.taxRate, "--tax-rate");
|
|
75
|
+
if (has(input.stateRate) !== has(input.state)) {
|
|
76
|
+
throw new Error("--state-rate and --state go together: the state rate counts only for a single-state muni fund of that state, such as --state-rate 9.3 --state CA.");
|
|
77
|
+
}
|
|
78
|
+
if (!has(input.stateRate)) return { federal, state: null };
|
|
79
|
+
const rate = percentOption(input.stateRate, "--state-rate");
|
|
80
|
+
if (federal + rate >= 100) throw new Error("--tax-rate and --state-rate together must stay under 100%.");
|
|
81
|
+
return { federal, state: { rate, code: normalizeStateCode(String(input.state)) } };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** One fund with the options, as the catalog shows them: the options refuse a ranking of several. */
|
|
85
|
+
export const TAX_RATE_EXAMPLES = ["MUB --tax-rate 40.8", "CMF --tax-rate 40.8 --state-rate 13.3 --state CA"] as const;
|
|
86
|
+
|
|
87
|
+
/** The options `fn DVD` takes for it; the pane does not draw them, the report adds its lines. */
|
|
88
|
+
export const TAX_RATE_OPTIONS: HeadlessPaneOptionDef[] = [
|
|
89
|
+
{
|
|
90
|
+
key: "tax-rate",
|
|
91
|
+
type: "string",
|
|
92
|
+
placeholder: "pct",
|
|
93
|
+
description: `Federal tax rate in percent (40.8 = 37% + 3.8% NIIT): adds a muni fund's tax-equivalent yield and muni/Treasury ratio. ${TAX_EQUIVALENT_FORMULA}; ${MUNI_TREASURY_RATIO_FORMULA}.`,
|
|
94
|
+
normalize: normalizeTaxRate,
|
|
95
|
+
shot: { reportOnly: "adds the tax-equivalent yield and muni/Treasury ratio to the text report" },
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
key: "state-rate",
|
|
99
|
+
type: "string",
|
|
100
|
+
placeholder: "pct",
|
|
101
|
+
description: "State tax rate in percent, with --state: added to --tax-rate only for a single-state muni fund of that state (CMF, VTEC for CA; NYF, MUNY for NY).",
|
|
102
|
+
normalize: (value) => percentOption(value, "--state-rate"),
|
|
103
|
+
shot: { reportOnly: "adds the tax-equivalent yield and muni/Treasury ratio to the text report" },
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
key: "state",
|
|
107
|
+
type: "string",
|
|
108
|
+
placeholder: "code",
|
|
109
|
+
description: "Two-letter state of --state-rate, such as CA or NY.",
|
|
110
|
+
normalize: normalizeStateCode,
|
|
111
|
+
shot: { reportOnly: "adds the tax-equivalent yield and muni/Treasury ratio to the text report" },
|
|
112
|
+
},
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
/** The same options in `gloomberb help fundamentals`. */
|
|
116
|
+
export const TAX_RATE_HELP_OPTIONS = [
|
|
117
|
+
{
|
|
118
|
+
flags: "--tax-rate <pct>",
|
|
119
|
+
description: `For a muni bond fund: its tax-equivalent yield and muni/Treasury ratio at this federal rate (40.8 = 37% + 3.8% NIIT). ${TAX_EQUIVALENT_FORMULA}; ${MUNI_TREASURY_RATIO_FORMULA}`,
|
|
120
|
+
},
|
|
121
|
+
{ flags: "--state-rate <pct>", description: "With --state: a state rate added to --tax-rate for a single-state muni fund of that state only" },
|
|
122
|
+
{ flags: "--state <code>", description: "The two-letter state of --state-rate, such as CA or NY" },
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
/** The yield a tax-equivalent yield is taken on: the SEC yield, or the distribution yield when the sponsor publishes none. */
|
|
126
|
+
export interface YieldBasis {
|
|
127
|
+
kind: "sec" | "distribution";
|
|
128
|
+
/** Percent. */
|
|
129
|
+
value: number;
|
|
130
|
+
asOf: string | null;
|
|
131
|
+
/** `30-day SEC yield`, `distribution yield (forward, not SEC yield)`. */
|
|
132
|
+
label: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** A Treasury curve point: its tenor (`7Y`), years, par yield in percent and date. */
|
|
136
|
+
export interface TreasuryTenor {
|
|
137
|
+
tenor: string;
|
|
138
|
+
years: number;
|
|
139
|
+
yield: number;
|
|
140
|
+
asOf: string | null;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* The curve tenor nearest a duration in years, the shorter one on a tie:
|
|
145
|
+
* MUB's 7.13 years is the 7-year. Null without a duration or a point.
|
|
146
|
+
*/
|
|
147
|
+
export function nearestTenor(points: readonly TreasuryTenor[], durationYears: number | null | undefined): TreasuryTenor | null {
|
|
148
|
+
if (durationYears == null || !Number.isFinite(durationYears)) return null;
|
|
149
|
+
let best: TreasuryTenor | null = null;
|
|
150
|
+
for (const point of [...points].sort((a, b) => a.years - b.years)) {
|
|
151
|
+
if (!Number.isFinite(point.yield)) continue;
|
|
152
|
+
if (!best || Math.abs(point.years - durationYears) < Math.abs(best.years - durationYears)) best = point;
|
|
153
|
+
}
|
|
154
|
+
return best;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function taxEquivalentYield(yieldPercent: number, combinedRatePercent: number): number {
|
|
158
|
+
return yieldPercent / (1 - combinedRatePercent / 100);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface TaxEquivalentAnalysis {
|
|
162
|
+
symbol: string;
|
|
163
|
+
rates: TaxRates;
|
|
164
|
+
/** Why there is no tax-equivalent yield: the fund is not a muni fund, or nothing classes it. */
|
|
165
|
+
notApplicable?: string;
|
|
166
|
+
/** The rate the yield is grossed up by: federal, plus the state's for one of its own funds. */
|
|
167
|
+
combinedRate?: number;
|
|
168
|
+
stateApplied?: boolean;
|
|
169
|
+
/** Why a state rate given was not added. */
|
|
170
|
+
stateNote?: string;
|
|
171
|
+
basis?: YieldBasis;
|
|
172
|
+
/** Percent. */
|
|
173
|
+
taxEquivalentYield?: number;
|
|
174
|
+
ratio?: { value: number; treasury: TreasuryTenor; durationYears: number } | null;
|
|
175
|
+
/** Why there is no ratio. */
|
|
176
|
+
ratioNote?: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** `40.8%`, `40.80%` read as `40.8%`. */
|
|
180
|
+
function formatRate(value: number): string {
|
|
181
|
+
return `${Number(value.toFixed(2))}%`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* A fund's tax-equivalent yield and muni/Treasury ratio from its bond facts,
|
|
186
|
+
* the distribution yield it falls back to, and the Treasury curve. Only a
|
|
187
|
+
* fund its sponsor classes as municipal has one; any other says why not.
|
|
188
|
+
*/
|
|
189
|
+
export function analyzeTaxEquivalent({
|
|
190
|
+
symbol, bond, rates, distribution, treasury,
|
|
191
|
+
}: {
|
|
192
|
+
symbol: string;
|
|
193
|
+
bond: FundBondFacts | null | undefined;
|
|
194
|
+
rates: TaxRates;
|
|
195
|
+
/** The distribution yield in percent and its label, for a fund without a SEC yield. */
|
|
196
|
+
distribution?: YieldBasis | null;
|
|
197
|
+
/** The Treasury curve's points, or null when it could not be read. */
|
|
198
|
+
treasury?: readonly TreasuryTenor[] | null;
|
|
199
|
+
}): TaxEquivalentAnalysis {
|
|
200
|
+
if (!bond) {
|
|
201
|
+
return { symbol, rates, notApplicable: `no tax-equivalent yield: ${symbol} is not a bond fund with sponsor figures (iShares, Vanguard and SPDR bond ETFs have them)` };
|
|
202
|
+
}
|
|
203
|
+
if (bond.kind !== "municipal") {
|
|
204
|
+
return { symbol, rates, notApplicable: `no tax-equivalent yield: ${symbol} is a taxable bond fund, its income is taxed` };
|
|
205
|
+
}
|
|
206
|
+
const state = rates.state;
|
|
207
|
+
const stateApplied = !!state && bond.state === state.code;
|
|
208
|
+
const stateNote = !state ? undefined
|
|
209
|
+
: stateApplied ? undefined
|
|
210
|
+
: bond.state ? `--state-rate not added: ${symbol} is a ${bond.state} fund, not ${state.code}`
|
|
211
|
+
: `--state-rate not added: ${symbol} is a national fund, its income is taxed by ${state.code}`;
|
|
212
|
+
const combinedRate = rates.federal + (stateApplied ? state!.rate : 0);
|
|
213
|
+
const basis: YieldBasis | null = bond.secYield
|
|
214
|
+
? { kind: "sec", value: bond.secYield.value, asOf: bond.secYield.asOf, label: "30-day SEC yield" }
|
|
215
|
+
: distribution ?? null;
|
|
216
|
+
if (!basis) {
|
|
217
|
+
return { symbol, rates, combinedRate, stateApplied, ...(stateNote ? { stateNote } : {}),
|
|
218
|
+
notApplicable: `no tax-equivalent yield: ${symbol} has neither a SEC yield nor a distribution yield` };
|
|
219
|
+
}
|
|
220
|
+
const durationYears = bond.duration?.value;
|
|
221
|
+
const treasuryPoint = treasury ? nearestTenor(treasury, durationYears) : null;
|
|
222
|
+
const ratioNote = durationYears == null ? `no ratio: ${symbol}'s sponsor publishes no duration to match a Treasury tenor`
|
|
223
|
+
: !treasuryPoint ? "no ratio: the Treasury curve could not be read" : undefined;
|
|
224
|
+
return {
|
|
225
|
+
symbol,
|
|
226
|
+
rates,
|
|
227
|
+
combinedRate,
|
|
228
|
+
stateApplied,
|
|
229
|
+
...(stateNote ? { stateNote } : {}),
|
|
230
|
+
basis,
|
|
231
|
+
taxEquivalentYield: taxEquivalentYield(basis.value, combinedRate),
|
|
232
|
+
ratio: treasuryPoint && durationYears != null
|
|
233
|
+
? { value: basis.value / treasuryPoint.yield, treasury: treasuryPoint, durationYears } : null,
|
|
234
|
+
...(ratioNote ? { ratioNote } : {}),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** A short form of the basis for the ratio line: `SEC yield 4.04%`, `distribution yield 3.27%`. */
|
|
239
|
+
function basisShort(basis: YieldBasis): string {
|
|
240
|
+
return `${basis.kind === "sec" ? "SEC yield" : "distribution yield"} ${formatFundYield(basis.value)}`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** One report line: its label, its text, and the raw value JSON keeps. */
|
|
244
|
+
export interface TaxEquivalentLine {
|
|
245
|
+
key: "taxRate" | "taxEquivalentYield" | "muniTreasuryRatio";
|
|
246
|
+
label: string;
|
|
247
|
+
text: string;
|
|
248
|
+
value: number | null;
|
|
249
|
+
unit?: string;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* The analysis as report lines, each saying what it was computed from:
|
|
254
|
+
*
|
|
255
|
+
* Tax rate 40.8% (federal; MUB is a national fund, no state rate)
|
|
256
|
+
* Tax-equivalent yield 6.83% (30-day SEC yield 4.04% as of 2026-10-15 / (1 - 40.8%))
|
|
257
|
+
* Muni/Treasury ratio 81.0% (SEC yield 4.04% / 7Y Treasury 4.99% on 2026-10-16, the tenor nearest its 7.13-year duration)
|
|
258
|
+
*/
|
|
259
|
+
export function taxEquivalentLines(analysis: TaxEquivalentAnalysis): TaxEquivalentLine[] {
|
|
260
|
+
const { rates } = analysis;
|
|
261
|
+
const stateText = !rates.state ? (analysis.notApplicable ? "federal" : "federal; no state rate given")
|
|
262
|
+
: analysis.stateApplied ? `federal ${formatRate(rates.federal)} + ${rates.state.code} ${formatRate(rates.state.rate)}`
|
|
263
|
+
: `federal; ${analysis.stateNote}`;
|
|
264
|
+
const combined = analysis.combinedRate ?? rates.federal;
|
|
265
|
+
const lines: TaxEquivalentLine[] = [
|
|
266
|
+
{ key: "taxRate", label: "Tax rate", text: `${formatRate(combined)} (${stateText})`, value: combined, unit: "%" },
|
|
267
|
+
];
|
|
268
|
+
if (analysis.notApplicable || !analysis.basis || analysis.taxEquivalentYield == null) {
|
|
269
|
+
lines.push({ key: "taxEquivalentYield", label: "Tax-equivalent yield", text: analysis.notApplicable ?? "—", value: null });
|
|
270
|
+
return lines;
|
|
271
|
+
}
|
|
272
|
+
const basis = analysis.basis;
|
|
273
|
+
lines.push({
|
|
274
|
+
key: "taxEquivalentYield",
|
|
275
|
+
label: "Tax-equivalent yield",
|
|
276
|
+
text: `${formatFundYield(analysis.taxEquivalentYield)} (${basis.label} ${formatFundYield(basis.value)}${basis.asOf ? ` as of ${basis.asOf}` : ""} / (1 - ${formatRate(combined)}))`,
|
|
277
|
+
value: Math.round(analysis.taxEquivalentYield * 10_000) / 10_000,
|
|
278
|
+
unit: "%",
|
|
279
|
+
});
|
|
280
|
+
const ratio = analysis.ratio;
|
|
281
|
+
lines.push(ratio
|
|
282
|
+
? {
|
|
283
|
+
key: "muniTreasuryRatio",
|
|
284
|
+
label: "Muni/Treasury ratio",
|
|
285
|
+
text: `${(ratio.value * 100).toFixed(1)}% (${basisShort(basis)} / ${ratio.treasury.tenor} Treasury ${formatFundYield(ratio.treasury.yield)}`
|
|
286
|
+
+ `${ratio.treasury.asOf ? ` on ${ratio.treasury.asOf}` : ""}, the tenor nearest its ${ratio.durationYears.toFixed(2)}-year duration)`,
|
|
287
|
+
value: Math.round(ratio.value * 10_000) / 10_000,
|
|
288
|
+
}
|
|
289
|
+
: { key: "muniTreasuryRatio", label: "Muni/Treasury ratio", text: analysis.ratioNote ?? "—", value: null });
|
|
290
|
+
return lines;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** The analysis as JSON keeps it: the rates, the yield it was taken on, the results and the formulas, without the text. */
|
|
294
|
+
export function taxEquivalentJson(tax: TaxEquivalentAnalysis) {
|
|
295
|
+
return {
|
|
296
|
+
federalRate: tax.rates.federal,
|
|
297
|
+
stateRate: tax.rates.state ? { ...tax.rates.state, applied: tax.stateApplied === true } : null,
|
|
298
|
+
combinedRate: tax.combinedRate ?? tax.rates.federal,
|
|
299
|
+
basis: tax.basis ?? null,
|
|
300
|
+
taxEquivalentYield: tax.taxEquivalentYield ?? null,
|
|
301
|
+
muniTreasuryRatio: tax.ratio ? {
|
|
302
|
+
value: tax.ratio.value, tenor: tax.ratio.treasury.tenor, treasuryYield: tax.ratio.treasury.yield,
|
|
303
|
+
treasuryAsOf: tax.ratio.treasury.asOf, durationYears: tax.ratio.durationYears,
|
|
304
|
+
} : null,
|
|
305
|
+
notes: [tax.notApplicable, tax.stateNote, tax.ratioNote].filter((note): note is string => !!note),
|
|
306
|
+
formula: TAX_EQUIVALENT_FORMULA,
|
|
307
|
+
ratioFormula: MUNI_TREASURY_RATIO_FORMULA,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** The distribution yield a report falls back to, labelled as not the SEC yield. */
|
|
312
|
+
export function distributionBasis(fraction: number | null | undefined, which: "forward" | "trailing", asOf: string | null = null): YieldBasis | null {
|
|
313
|
+
return fraction != null && Number.isFinite(fraction)
|
|
314
|
+
? { kind: "distribution", value: fraction * 100, asOf, label: `${which} distribution yield (${NOT_SEC_YIELD})` }
|
|
315
|
+
: null;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* The US Treasury par curve GC shows, as tenors: its latest stored session,
|
|
320
|
+
* or, when that cannot be read, FRED's constant-maturity curve, as GC falls
|
|
321
|
+
* back to. Null when neither can be read, which leaves the ratio out with a
|
|
322
|
+
* note.
|
|
323
|
+
*/
|
|
324
|
+
export async function loadTreasuryTenors(
|
|
325
|
+
client: Pick<typeof apiClient, "getCloudCurve" | "getCloudYieldCurve"> = apiClient,
|
|
326
|
+
): Promise<TreasuryTenor[] | null> {
|
|
327
|
+
const finite = (points: TreasuryTenor[]) => {
|
|
328
|
+
const kept = points.filter((point) => Number.isFinite(point.yield) && Number.isFinite(point.years));
|
|
329
|
+
return kept.length > 0 ? kept : null;
|
|
330
|
+
};
|
|
331
|
+
try {
|
|
332
|
+
const view = await client.getCloudCurve("us", null);
|
|
333
|
+
return finite(view.points.flatMap((point) => point.yield == null ? []
|
|
334
|
+
: [{ tenor: point.tenor, years: point.years, yield: point.yield, asOf: view.asOf ?? null }]));
|
|
335
|
+
} catch {
|
|
336
|
+
try {
|
|
337
|
+
return finite((await client.getCloudYieldCurve()).flatMap((point) => point.yield == null ? []
|
|
338
|
+
: [{ tenor: point.maturity, years: point.maturityYears, yield: point.yield, asOf: point.asOf ?? null }]));
|
|
339
|
+
} catch {
|
|
340
|
+
// Intentional ignore: the ratio line then says the Treasury curve could not be read.
|
|
341
|
+
return null;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
package/src/news/aggregator.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../utils/log-failure";
|
|
1
2
|
import type { NewsCapability } from "../capabilities";
|
|
2
3
|
import type { ConnectionHealthRegistry } from "../core/connection-health";
|
|
3
4
|
import type { NewsArticle, NewsQuery, NewsQueryState } from "./types";
|
|
@@ -153,7 +154,7 @@ export class NewsService {
|
|
|
153
154
|
this.pollTimer = null;
|
|
154
155
|
this.pollInFlight = true;
|
|
155
156
|
this.lastPollAt = this.now();
|
|
156
|
-
void this.pollActiveQueries().catch((
|
|
157
|
+
void this.pollActiveQueries().catch(logFailure("news.aggregator", "Polling active news queries failed")).then(() => {
|
|
157
158
|
this.pollInFlight = false;
|
|
158
159
|
this.scheduleNextPoll();
|
|
159
160
|
});
|
|
@@ -285,7 +286,8 @@ export class NewsService {
|
|
|
285
286
|
continue;
|
|
286
287
|
}
|
|
287
288
|
return commitDetail(article);
|
|
288
|
-
} catch {
|
|
289
|
+
} catch (error) {
|
|
290
|
+
logFailure("news.aggregator", "Loading story detail failed")(error);
|
|
289
291
|
failed = true;
|
|
290
292
|
// Continue to lower-priority sources.
|
|
291
293
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../utils/log-failure";
|
|
1
2
|
import type { AppPluginStateStorePort } from "../core/app-service-ports";
|
|
2
3
|
import type { AppNotificationRequest } from "../types/plugin";
|
|
3
4
|
|
|
@@ -73,8 +74,8 @@ function commit(next: NotificationLogEntry[]): void {
|
|
|
73
74
|
entries = next;
|
|
74
75
|
try {
|
|
75
76
|
store?.set(entries);
|
|
76
|
-
} catch {
|
|
77
|
-
|
|
77
|
+
} catch (error) {
|
|
78
|
+
logFailure("notifications.notification-log", "Saving notification history failed")(error);
|
|
78
79
|
}
|
|
79
80
|
for (const listener of listeners) listener();
|
|
80
81
|
}
|
|
@@ -88,7 +89,8 @@ function configureNotificationLog(nextStore: NotificationLogStore | null): void
|
|
|
88
89
|
let saved: readonly unknown[] = [];
|
|
89
90
|
try {
|
|
90
91
|
saved = nextStore?.get() ?? [];
|
|
91
|
-
} catch {
|
|
92
|
+
} catch (error) {
|
|
93
|
+
logFailure("notifications.notification-log", "Loading notification history failed")(error);
|
|
92
94
|
saved = [];
|
|
93
95
|
}
|
|
94
96
|
const loaded = saved.map(normalizeEntry).filter((entry): entry is NotificationLogEntry => !!entry);
|
|
@@ -31,6 +31,7 @@ function readJson(path: string): Record<string, unknown> | null {
|
|
|
31
31
|
const value = JSON.parse(readFileSync(path, "utf-8"));
|
|
32
32
|
return value && typeof value === "object" ? value as Record<string, unknown> : null;
|
|
33
33
|
} catch {
|
|
34
|
+
// Intentional ignore: Missing or invalid optional metadata starts with no cached update state.
|
|
34
35
|
return null;
|
|
35
36
|
}
|
|
36
37
|
}
|
|
@@ -15,7 +15,7 @@ export function useAccountManagementFooter({
|
|
|
15
15
|
message,
|
|
16
16
|
saveProfile,
|
|
17
17
|
}: {
|
|
18
|
-
busy: "profile" | "password" | "alerts" | "billing" | "delete" | null;
|
|
18
|
+
busy: "profile" | "password" | "alerts" | "billing" | "trial" | "delete" | null;
|
|
19
19
|
/** Off while a tab that owns its footer is showing. */
|
|
20
20
|
enabled: boolean;
|
|
21
21
|
hasSession: boolean;
|
|
@@ -34,6 +34,7 @@ export function useAccountManagementKeyboard({
|
|
|
34
34
|
setActiveField,
|
|
35
35
|
setDraftValue,
|
|
36
36
|
deleteAccount,
|
|
37
|
+
endTrial,
|
|
37
38
|
turnOffEmailAlerts,
|
|
38
39
|
}: {
|
|
39
40
|
activeField: AccountFieldKey;
|
|
@@ -52,6 +53,7 @@ export function useAccountManagementKeyboard({
|
|
|
52
53
|
setActiveField: (field: AccountFieldKey) => void;
|
|
53
54
|
setDraftValue: <K extends keyof AccountDraft>(key: K, value: AccountDraft[K]) => void;
|
|
54
55
|
deleteAccount: () => Promise<void>;
|
|
56
|
+
endTrial: () => Promise<void>;
|
|
55
57
|
turnOffEmailAlerts: () => Promise<void>;
|
|
56
58
|
}): FieldRing<AccountFieldKey> {
|
|
57
59
|
const actions: Partial<Record<AccountFieldKey, () => void>> = {
|
|
@@ -59,6 +61,7 @@ export function useAccountManagementKeyboard({
|
|
|
59
61
|
desks: openDeskPicker,
|
|
60
62
|
passwordAction: openPasswordDialog,
|
|
61
63
|
upgradeAction: openUpgrade,
|
|
64
|
+
cancelTrialAction: () => { void endTrial(); },
|
|
62
65
|
assistantsAction: openAssistants,
|
|
63
66
|
deleteAccountAction: () => { void deleteAccount(); },
|
|
64
67
|
emailAlertsOffAction: () => { void turnOffEmailAlerts(); },
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
} from "../../../ui";
|
|
32
32
|
import { useDialog, type AlertContext } from "../../../ui/dialog";
|
|
33
33
|
import type { SelectControl } from "../../../components/ui/select-button";
|
|
34
|
-
import { FRAMED_TEXTAREA_DESKTOP_STYLE } from "../../../components/ui/fields";
|
|
34
|
+
import { FRAMED_TEXTAREA_DESKTOP_STYLE, fieldFrameStyle } from "../../../components/ui/fields";
|
|
35
35
|
import { apiClient, type AccountProfile, type CloudPricing } from "../../../api-client";
|
|
36
36
|
import { chatController } from "../chat/controller";
|
|
37
37
|
import { SignInWall } from "../cloud/auth-actions";
|
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
formatTrialOffer,
|
|
68
68
|
} from "../../../account/billing";
|
|
69
69
|
import { PasswordChangeDialog } from "./password-dialog";
|
|
70
|
+
import { endTrialAfterWarning } from "./trial-cancel";
|
|
70
71
|
import { CalendarAccountTab } from "./calendar-tab";
|
|
71
72
|
import { useAccountManagementFooter } from "./footer";
|
|
72
73
|
import { useAccountManagementKeyboard } from "./keyboard";
|
|
@@ -89,7 +90,7 @@ import { useCloudUpgradeAction } from "../shared/cloud-upgrade";
|
|
|
89
90
|
import { resolvePlanAccess } from "../../../api-client/plan-access";
|
|
90
91
|
import { usePluginPaneState } from "../../runtime";
|
|
91
92
|
|
|
92
|
-
type AccountBusy = "profile" | "password" | "alerts" | "billing" | "delete" | null;
|
|
93
|
+
type AccountBusy = "profile" | "password" | "alerts" | "billing" | "trial" | "delete" | null;
|
|
93
94
|
const ACCOUNT_TAB_DEFS: Array<{ label: string; value: AccountManagementTab }> = [
|
|
94
95
|
{ label: "Profile", value: "profile" },
|
|
95
96
|
{ label: "Emails", value: "emails" },
|
|
@@ -124,7 +125,8 @@ const ACCOUNT_TAB_FIELD_ORDER: Record<AccountManagementTab, AccountFieldKey[]> =
|
|
|
124
125
|
],
|
|
125
126
|
// Its actions are footer hints; the tab owns its footer.
|
|
126
127
|
calendar: [],
|
|
127
|
-
|
|
128
|
+
// Cancel Trial shows only while a trial runs.
|
|
129
|
+
pro: ["upgradeAction", "cancelTrialAction"],
|
|
128
130
|
// The Teams tab owns its own keyboard handling (a list, not form fields).
|
|
129
131
|
teams: [],
|
|
130
132
|
// Remote assistants allowed to drive this terminal; a list with its own footer.
|
|
@@ -258,14 +260,15 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
|
|
|
258
260
|
const bodyHeight = Math.max(5, height);
|
|
259
261
|
// Chat's card settings show once the server keeps them; the desks only while showing them is on.
|
|
260
262
|
const chatCardSupported = profile?.showLocalTime !== undefined;
|
|
263
|
+
const planAccess = useMemo(() => resolvePlanAccess(profile), [profile]);
|
|
261
264
|
const fieldOrder = useMemo(() => ACCOUNT_TAB_FIELD_ORDER[activeTab].filter((field) => {
|
|
262
265
|
if (field === "showLocalTime" || field === "showDesks") return chatCardSupported;
|
|
263
266
|
if (field === "desks") return chatCardSupported && draft.showDesks;
|
|
267
|
+
if (field === "cancelTrialAction") return planAccess.isTrialActive;
|
|
264
268
|
return true;
|
|
265
|
-
}), [activeTab, chatCardSupported, draft.showDesks]);
|
|
269
|
+
}), [activeTab, chatCardSupported, draft.showDesks, planAccess.isTrialActive]);
|
|
266
270
|
const accountTabs = ACCOUNT_TAB_DEFS.map((tab) => ({ ...tab, label: t(tab.label) }));
|
|
267
271
|
|
|
268
|
-
const planAccess = useMemo(() => resolvePlanAccess(profile), [profile]);
|
|
269
272
|
const planPrice = useMemo(() => formatCloudMonthlyPrice(pricing), [language, pricing]);
|
|
270
273
|
const trialOffer = useMemo(() => formatTrialOffer(pricing), [language, pricing]);
|
|
271
274
|
const planStatusLabel = useMemo(() => {
|
|
@@ -741,6 +744,42 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
|
|
|
741
744
|
}
|
|
742
745
|
}, [busy, dialog]);
|
|
743
746
|
|
|
747
|
+
// Only after the warning that it ends the trial and Pro now (trial-cancel.ts).
|
|
748
|
+
const endTrial = useCallback(async () => {
|
|
749
|
+
setActiveField("cancelTrialAction");
|
|
750
|
+
if (busy) return;
|
|
751
|
+
try {
|
|
752
|
+
// Asks nothing unless a trial is running.
|
|
753
|
+
const result = await endTrialAfterWarning(
|
|
754
|
+
dialog,
|
|
755
|
+
planAccess,
|
|
756
|
+
() => apiClient.endCloudTrial(),
|
|
757
|
+
() => {
|
|
758
|
+
setBusy("trial");
|
|
759
|
+
setMessage({ tone: "info", text: t("Ending trial...") });
|
|
760
|
+
},
|
|
761
|
+
);
|
|
762
|
+
if (!result) return;
|
|
763
|
+
// The plan changed on the server: the session, the status bar and the tab follow it.
|
|
764
|
+
await chatController.refreshSession().catch(() => {});
|
|
765
|
+
const nextProfile = await apiClient.getAccountProfile().catch(() => null);
|
|
766
|
+
if (nextProfile) setProfile(nextProfile);
|
|
767
|
+
setMessage({
|
|
768
|
+
tone: "success",
|
|
769
|
+
text: result.endedNow
|
|
770
|
+
? t("Trial ended. Pro is off and you won't be charged.")
|
|
771
|
+
: t("Cancelled. Pro stays on until the end of the billing period."),
|
|
772
|
+
});
|
|
773
|
+
} catch (error) {
|
|
774
|
+
setMessage({
|
|
775
|
+
tone: "error",
|
|
776
|
+
text: error instanceof Error ? error.message : t("Failed to cancel the trial."),
|
|
777
|
+
});
|
|
778
|
+
} finally {
|
|
779
|
+
setBusy(null);
|
|
780
|
+
}
|
|
781
|
+
}, [busy, dialog, planAccess]);
|
|
782
|
+
|
|
744
783
|
useAccountManagementFooter({
|
|
745
784
|
busy,
|
|
746
785
|
// The Calendar and Agents tabs save nothing and show their own status.
|
|
@@ -755,6 +794,7 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
|
|
|
755
794
|
cyclePortfolio,
|
|
756
795
|
deleteAccount,
|
|
757
796
|
draftRef,
|
|
797
|
+
endTrial,
|
|
758
798
|
fieldOrder,
|
|
759
799
|
// Behind the sign-in wall the fields are not there, and Enter is the wall's.
|
|
760
800
|
focused: focused && activeTab !== "teams" && activeTab !== "calendar" && activeTab !== "agents" && (hasSession || apiClient.isSignedIn()),
|
|
@@ -881,13 +921,12 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
|
|
|
881
921
|
<Box
|
|
882
922
|
height={3}
|
|
883
923
|
width={Math.max(18, formWidth - formLabelWidth - 1)}
|
|
884
|
-
border
|
|
924
|
+
border={!nativePaneChrome}
|
|
885
925
|
borderColor={activeField === "bio" ? colors.borderFocused : colors.border}
|
|
886
926
|
backgroundColor={colors.panel}
|
|
887
|
-
style
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
}}
|
|
927
|
+
// The field look, as every other field of the form has it. OpenTUI applies `style`
|
|
928
|
+
// too: the terminal keeps the clip it always had.
|
|
929
|
+
style={nativePaneChrome ? { ...fieldFrameStyle(activeField === "bio"), overflow: "hidden" } : { overflow: "hidden" }}
|
|
891
930
|
>
|
|
892
931
|
<Textarea
|
|
893
932
|
key={`bio:${profile?.updatedAt ?? "empty"}`}
|
|
@@ -897,7 +936,7 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
|
|
|
897
936
|
focused={focused && activeField === "bio"}
|
|
898
937
|
textColor={colors.text}
|
|
899
938
|
placeholderColor={colors.textDim}
|
|
900
|
-
backgroundColor={colors.panel}
|
|
939
|
+
backgroundColor={nativePaneChrome ? "transparent" : colors.panel}
|
|
901
940
|
flexGrow={1}
|
|
902
941
|
wrapText
|
|
903
942
|
{...(nativePaneChrome ? { style: FRAMED_TEXTAREA_DESKTOP_STYLE } : {})}
|
|
@@ -988,14 +1027,27 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
|
|
|
988
1027
|
width={contentWidth}
|
|
989
1028
|
activePlan={planAccess.hasProAccess ? "pro" : "free"}
|
|
990
1029
|
/>
|
|
991
|
-
<Box
|
|
992
|
-
<
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1030
|
+
<Box flexDirection="row" gap={1}>
|
|
1031
|
+
<Box ref={fieldNodeRef("upgradeAction")} flexDirection="row">
|
|
1032
|
+
<Button
|
|
1033
|
+
label={planAccess.isPayingPro ? t("Manage Pro") : busy === "billing" ? t("Opening...") : t("Upgrade to Pro")}
|
|
1034
|
+
variant={planAccess.isPayingPro ? "secondary" : "primary"}
|
|
1035
|
+
active={activeField === "upgradeAction"}
|
|
1036
|
+
onPress={openUpgrade}
|
|
1037
|
+
disabled={!!busy}
|
|
1038
|
+
/>
|
|
1039
|
+
</Box>
|
|
1040
|
+
{planAccess.isTrialActive ? (
|
|
1041
|
+
<Box ref={fieldNodeRef("cancelTrialAction")} flexDirection="row">
|
|
1042
|
+
<Button
|
|
1043
|
+
label={busy === "trial" ? t("Ending...") : t("Cancel Trial")}
|
|
1044
|
+
variant="danger"
|
|
1045
|
+
active={activeField === "cancelTrialAction"}
|
|
1046
|
+
onPress={() => { void endTrial(); }}
|
|
1047
|
+
disabled={!!busy}
|
|
1048
|
+
/>
|
|
1049
|
+
</Box>
|
|
1050
|
+
) : null}
|
|
999
1051
|
</Box>
|
|
1000
1052
|
</>
|
|
1001
1053
|
) : null}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { confirmDialog } from "../../../components";
|
|
2
|
+
import { formatTrialEnd } from "../../../account/billing";
|
|
3
|
+
import { t, tf } from "../../../i18n";
|
|
4
|
+
import type { PlanAccess } from "../../../api-client/plan-rules";
|
|
5
|
+
import type { DialogApi } from "../../../ui/dialog";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Ends a Pro trial the way the account page on gloom.sh does: first a warning
|
|
9
|
+
* that it ends the trial and Pro now, and only a confirmed answer reaches the
|
|
10
|
+
* server. Ending Pro cannot be undone, so a stray Enter keeps the trial; `y`
|
|
11
|
+
* or End Trial Now ends it. Null when the person kept the trial, or when no
|
|
12
|
+
* trial is running (a stale key or click after it ended), which asks nothing.
|
|
13
|
+
*/
|
|
14
|
+
export async function endTrialAfterWarning(
|
|
15
|
+
dialog: DialogApi,
|
|
16
|
+
trial: Pick<PlanAccess, "isTrialActive" | "trialEndsAt">,
|
|
17
|
+
end: () => Promise<{ endedNow?: boolean }>,
|
|
18
|
+
onConfirmed?: () => void,
|
|
19
|
+
): Promise<{ endedNow: boolean } | null> {
|
|
20
|
+
if (!trial.isTrialActive) return null;
|
|
21
|
+
const date = formatTrialEnd(trial.trialEndsAt);
|
|
22
|
+
const confirmed = await confirmDialog(dialog, {
|
|
23
|
+
closeOnClickOutside: false,
|
|
24
|
+
title: t("Cancel Trial?"),
|
|
25
|
+
body: [
|
|
26
|
+
t("Cancelling ends your trial and Pro now."),
|
|
27
|
+
date
|
|
28
|
+
? tf("If you keep your trial, you can still cancel before {date} without being charged.", { date })
|
|
29
|
+
: t("If you keep your trial, you can still cancel before it ends without being charged."),
|
|
30
|
+
],
|
|
31
|
+
confirmLabel: t("End Trial Now"),
|
|
32
|
+
cancelLabel: t("Keep Trial"),
|
|
33
|
+
confirmVariant: "danger",
|
|
34
|
+
defaultAction: "cancel",
|
|
35
|
+
});
|
|
36
|
+
if (!confirmed) return null;
|
|
37
|
+
onConfirmed?.();
|
|
38
|
+
const result = await end();
|
|
39
|
+
return { endedNow: result.endedNow === true };
|
|
40
|
+
}
|