gloomberb 0.17.5 → 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 +8 -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/chat.ts +9 -0
- package/src/api-client/commodity-balances.ts +77 -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 +135 -6
- package/src/api-client/debt-maturities.ts +18 -0
- package/src/api-client/earnings.ts +10 -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 +30 -2
- package/src/api-client/insider-signals.ts +159 -0
- package/src/api-client/market-discovery.ts +1 -1
- package/src/api-client/normalizers.ts +2 -0
- package/src/api-client/paths.ts +28 -0
- package/src/api-client/request.ts +11 -3
- package/src/api-client/research-activity.ts +15 -8
- package/src/api-client/socket.ts +16 -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 +91 -3
- 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/broker-import.ts +23 -21
- package/src/app/runtime/desktop-deeplink.ts +3 -4
- package/src/app/runtime/plugin-bindings.ts +16 -9
- package/src/app/runtime/startup.ts +3 -4
- package/src/app/runtime/ticker-refresh.ts +13 -12
- package/src/app/runtime/update.ts +17 -3
- package/src/architecture/core-builtin-allowlist.json +2 -13
- 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/broker-portfolio-sync.ts +66 -0
- 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 +77 -42
- 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 +434 -96
- package/src/cli/commands/news-search.ts +35 -2
- package/src/cli/commands/options-chain.ts +25 -9
- package/src/cli/commands/options-leaps.ts +3 -3
- package/src/cli/commands/overview.ts +130 -40
- 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 +361 -64
- package/src/cli/context.ts +15 -1
- package/src/cli/desktop-pane-shot.ts +11 -3
- package/src/cli/earnings-calendar.ts +2 -1
- package/src/cli/errors.ts +25 -2
- package/src/cli/export-source.ts +18 -3
- package/src/cli/fx-pair.ts +77 -0
- package/src/cli/glossary.ts +196 -14
- package/src/cli/history-rows.ts +84 -19
- package/src/cli/index-roots.ts +26 -0
- package/src/cli/index.ts +57 -20
- package/src/cli/known-gaps.ts +156 -22
- package/src/cli/listing-arg.ts +217 -150
- package/src/cli/listing-suggestion.ts +7 -23
- 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 +144 -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 +93 -17
- package/src/cli/pane-functions/function-help.ts +20 -17
- package/src/cli/pane-functions/headless.ts +187 -40
- package/src/cli/pane-functions/index.ts +126 -12
- 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 +74 -18
- package/src/cli/pane-functions/screenshot.ts +126 -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 +21 -6
- package/src/cli/result.ts +2 -0
- package/src/cli/series-search.ts +6 -1
- 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 -35
- 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/cli/unknown-command.ts +18 -0
- package/src/components/chart/composite/axis-overlays.tsx +16 -9
- package/src/components/chart/composite/composite-chart.tsx +163 -23
- package/src/components/chart/composite/downsample.ts +19 -3
- package/src/components/chart/composite/format.ts +13 -0
- package/src/components/chart/composite/legend.tsx +161 -68
- package/src/components/chart/composite/panel-bitmap.ts +8 -2
- package/src/components/chart/composite/panel-labels.ts +38 -0
- package/src/components/chart/composite/panel-series.ts +1 -0
- package/src/components/chart/composite/panel-surface.tsx +28 -10
- package/src/components/chart/composite/price-axis-labels.tsx +16 -3
- package/src/components/chart/composite/scene.ts +60 -2
- package/src/components/chart/composite/series-axis-tags.tsx +67 -0
- package/src/components/chart/composite/toolbar.tsx +12 -7
- package/src/components/chart/composite/tools.ts +2 -2
- package/src/components/chart/composite/types.ts +34 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +28 -1
- package/src/components/chart/core/view-reset.ts +46 -0
- 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 +11 -4
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- 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 +12 -0
- package/src/components/command-bar/list/view.tsx +1 -1
- package/src/components/command-bar/pane-templates/workflow.ts +5 -0
- 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/command-items.ts +1 -1
- package/src/components/command-bar/routes/root/pick-prefetch.ts +38 -0
- package/src/components/command-bar/routes/root/provider-search.ts +9 -9
- package/src/components/command-bar/routes/root/results.ts +13 -0
- package/src/components/command-bar/routes/root/runtime.ts +3 -0
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +3 -1
- package/src/components/command-bar/routes/root/shortcut-items.ts +1 -1
- package/src/components/command-bar/routes/root/start-here.ts +90 -0
- package/src/components/command-bar/routes/ticker-search/actions.ts +34 -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/surface/index.tsx +5 -0
- 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 +23 -13
- package/src/components/command-bar/workflow/ops.ts +25 -3
- package/src/components/command-bar/workflow/pane-reuse.ts +3 -2
- 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 +7 -5
- 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/content.tsx +11 -8
- 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 +62 -0
- 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-model.ts +1 -1
- package/src/components/onboarding/wizard-positions.ts +56 -19
- 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/format.ts +64 -15
- package/src/components/ticker/badge/index.tsx +33 -11
- package/src/components/ticker/badge/list.tsx +4 -3
- package/src/components/ticker/badge/text.tsx +2 -2
- package/src/components/ticker/list-table-view.tsx +8 -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/opentui/index.tsx +61 -20
- package/src/components/ui/data-table/opentui/model.ts +104 -0
- 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/inline-quick-add.tsx +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 +32 -6
- package/src/components/ui/query-bar.tsx +35 -4
- 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/ui/windowed-list.tsx +27 -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/docs/snapshot.json +248 -5
- 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/cloud.ts +16 -5
- package/src/layout-marketplace/gallery-desktop.tsx +8 -4
- package/src/layout-marketplace/gallery.tsx +4 -4
- package/src/layout-marketplace/linked-sync.ts +9 -3
- package/src/layout-marketplace/linked.ts +24 -3
- package/src/layout-marketplace/model.ts +39 -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 +39 -5
- package/src/market-data/futures-contract.ts +155 -5
- package/src/market-data/hooks.tsx +77 -12
- package/src/market-data/market/bar-period.ts +107 -0
- package/src/market-data/market/format.ts +18 -14
- package/src/market-data/market/freshness.ts +29 -4
- package/src/market-data/market/index-level.ts +51 -0
- package/src/market-data/market/status.ts +152 -13
- package/src/market-data/model-dividend-yield.ts +117 -0
- package/src/market-data/quotes/freshness.ts +30 -1
- package/src/{plugins/builtin/portfolio-list → market-data/quotes}/live-valuation.ts +52 -6
- package/src/market-data/quotes/regular-session-valuation.ts +32 -1
- 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 +55 -13
- package/src/plugins/builtin/analytics/risk-headless.ts +26 -7
- package/src/plugins/builtin/analytics/risk-math.ts +83 -0
- package/src/plugins/builtin/analytics/risk-model.ts +171 -19
- package/src/plugins/builtin/analytics/risk-pane.tsx +17 -12
- 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/builtin-plugin-meta.ts +0 -1
- 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/controller.ts +14 -10
- package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +2 -2
- package/src/plugins/builtin/chart-composer/formula.ts +233 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -2
- package/src/plugins/builtin/chart-composer/headless.ts +117 -15
- package/src/plugins/builtin/chart-composer/index.tsx +73 -15
- package/src/plugins/builtin/chart-composer/pane.tsx +86 -23
- package/src/plugins/builtin/chart-composer/presets.ts +165 -8
- package/src/plugins/builtin/chart-composer/quick-add.tsx +9 -2
- package/src/plugins/builtin/chart-composer/series-catalog.ts +85 -16
- package/src/plugins/builtin/chart-composer/series-expression.ts +10 -8
- 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/chart-composer/settings.ts +16 -4
- package/src/plugins/builtin/chart-composer/studies.ts +1 -1
- package/src/plugins/builtin/chat/attachments/desktop.tsx +4 -1
- package/src/plugins/builtin/chat/content/channel-navigation.ts +17 -6
- 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 +47 -10
- package/src/plugins/builtin/chat/content/layout-metrics.ts +3 -0
- package/src/plugins/builtin/chat/content/mentions.ts +50 -21
- package/src/plugins/builtin/chat/content/scroll.ts +12 -5
- package/src/plugins/builtin/chat/content/shortcuts.ts +32 -13
- package/src/plugins/builtin/chat/content/snapshot.ts +40 -6
- package/src/plugins/builtin/chat/content/transcript.tsx +48 -37
- package/src/plugins/builtin/chat/content/whole-message-copy.ts +44 -2
- package/src/plugins/builtin/chat/controller/index.ts +68 -17
- package/src/plugins/builtin/chat/controller/mention-candidates.ts +104 -0
- package/src/plugins/builtin/chat/controller/realtime.ts +9 -0
- package/src/plugins/builtin/chat/controller/state.ts +10 -0
- package/src/plugins/builtin/chat/controller/view.ts +2 -0
- package/src/plugins/builtin/chat/conversation-recency.ts +73 -0
- package/src/plugins/builtin/chat/conversations.ts +12 -5
- package/src/plugins/builtin/chat/ghost-user.ts +11 -3
- package/src/plugins/builtin/chat/layout.ts +25 -5
- package/src/plugins/builtin/chat/message/desktop.tsx +15 -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/chat/sidebar-rows.ts +18 -5
- package/src/plugins/builtin/chat/sidebar.tsx +6 -1
- 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/manifest.ts +4 -3
- 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/manifest.ts +16 -5
- 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 +31 -9
- package/src/plugins/builtin/commodities-energy/view-state.ts +11 -0
- package/src/plugins/builtin/commodity-balances/client.ts +51 -193
- package/src/plugins/builtin/commodity-balances/headless.ts +10 -3
- package/src/plugins/builtin/commodity-balances/model.ts +5 -180
- package/src/plugins/builtin/commodity-balances/pane.tsx +3 -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/custom-view/index.tsx +1 -1
- package/src/plugins/builtin/custom-view/loader.ts +57 -7
- package/src/plugins/builtin/custom-view/sources.ts +146 -0
- package/src/plugins/builtin/custom-view/view-spec.ts +37 -1
- 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/board-model.ts +33 -3
- package/src/plugins/builtin/earnings/board-table.ts +59 -14
- package/src/plugins/builtin/earnings/board.tsx +36 -3
- package/src/plugins/builtin/earnings/headless.ts +27 -7
- package/src/plugins/builtin/earnings/history-model.ts +9 -1
- package/src/plugins/builtin/earnings/history-table.ts +16 -5
- package/src/plugins/builtin/earnings/history.tsx +40 -10
- package/src/plugins/builtin/earnings/index.tsx +3 -1
- package/src/plugins/builtin/earnings/no-earnings.ts +52 -0
- 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 +11 -1
- package/src/plugins/builtin/econ-statistics/headless.ts +31 -5
- package/src/plugins/builtin/econ-statistics/pane.tsx +5 -3
- package/src/plugins/builtin/econ-statistics/stats.ts +10 -0
- package/src/plugins/builtin/econ-statistics/view.ts +23 -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 +39 -25
- package/src/plugins/builtin/futures/series.ts +38 -1
- 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/client.ts +4 -4
- package/src/plugins/builtin/futures-curve/headless.ts +24 -4
- package/src/plugins/builtin/futures-curve/index.tsx +2 -2
- package/src/plugins/builtin/futures-curve/model.ts +50 -9
- package/src/plugins/builtin/futures-curve/pane.tsx +14 -10
- 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 +345 -5
- package/src/plugins/builtin/insider/index.tsx +304 -36
- 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 +193 -0
- package/src/plugins/builtin/insider/signals-model.ts +718 -0
- package/src/plugins/builtin/insider/signals.tsx +376 -0
- 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/client.ts +41 -2
- package/src/plugins/builtin/iv-history/headless.ts +26 -16
- package/src/plugins/builtin/iv-history/screen-pane.tsx +25 -7
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/jobs/index.tsx +1 -0
- package/src/plugins/builtin/jodi/client.ts +42 -205
- package/src/plugins/builtin/jodi/headless.ts +15 -4
- package/src/plugins/builtin/jodi/model.ts +18 -43
- package/src/plugins/builtin/jodi/pane.tsx +5 -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-movers/client.ts +32 -6
- package/src/plugins/builtin/market-movers/headless.ts +7 -2
- package/src/plugins/builtin/market-movers/model.ts +64 -3
- package/src/plugins/builtin/market-movers/screener.ts +20 -9
- package/src/plugins/builtin/market-valuation/detail.tsx +7 -2
- package/src/plugins/builtin/market-valuation/headless.ts +17 -4
- package/src/plugins/builtin/market-valuation/pane.tsx +8 -4
- package/src/plugins/builtin/market-valuation/view.ts +10 -0
- 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-positioning/client.ts +10 -0
- package/src/plugins/builtin/options-positioning/headless.ts +88 -13
- package/src/plugins/builtin/options-positioning/index.tsx +2 -2
- package/src/plugins/builtin/options-positioning/model.ts +33 -0
- package/src/plugins/builtin/options-positioning/pane.tsx +38 -16
- package/src/plugins/builtin/options-scenario/charts.tsx +13 -4
- package/src/plugins/builtin/options-scenario/client.ts +114 -17
- package/src/plugins/builtin/options-scenario/collar.ts +141 -0
- package/src/plugins/builtin/options-scenario/csp.ts +1 -1
- package/src/plugins/builtin/options-scenario/freshness.ts +27 -0
- package/src/plugins/builtin/options-scenario/headless.ts +30 -12
- package/src/plugins/builtin/options-scenario/index.tsx +1 -1
- package/src/plugins/builtin/options-scenario/model.ts +55 -5
- package/src/plugins/builtin/options-scenario/pane.tsx +24 -5
- 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 +144 -63
- package/src/plugins/builtin/portfolio-list/cli/render.ts +373 -48
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +23 -9
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +25 -35
- package/src/plugins/builtin/portfolio-list/grid.tsx +3 -1
- package/src/plugins/builtin/portfolio-list/headless.ts +161 -32
- 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 +63 -14
- package/src/plugins/builtin/portfolio-list/pane/remove-ticker.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +47 -28
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +38 -8
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +12 -4
- package/src/plugins/builtin/portfolio-list/settings.ts +22 -0
- package/src/plugins/builtin/portfolio-list/since-last-seen.ts +197 -0
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +26 -4
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +32 -4
- package/src/plugins/builtin/portfolio-list/table.tsx +39 -7
- 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 +16 -5
- package/src/plugins/builtin/research/event-model.ts +63 -51
- package/src/plugins/builtin/research/headless-schema.ts +1 -0
- package/src/plugins/builtin/research/headless.ts +4 -1
- 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 +28 -9
- package/src/plugins/builtin/reverse-dcf/index.tsx +5 -2
- package/src/plugins/builtin/reverse-dcf/model.ts +87 -6
- package/src/plugins/builtin/reverse-dcf/pane.tsx +30 -7
- 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/earnings-report.ts +48 -1
- package/src/plugins/builtin/shared/headless-options.ts +10 -0
- package/src/plugins/builtin/shared/history-span.ts +55 -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 +45 -20
- package/src/plugins/builtin/shared/scanner-capture.ts +95 -0
- package/src/plugins/builtin/shared/series-detail-chart.tsx +5 -2
- package/src/plugins/builtin/shared/series-list-detail.tsx +7 -3
- package/src/plugins/builtin/shared/ticker-surface.ts +16 -2
- package/src/plugins/builtin/shared/treasury-cutoffs.ts +15 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +13 -5
- 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/headless.ts +15 -2
- 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 +106 -24
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +108 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +26 -8
- 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-schema.ts +4 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +109 -23
- 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 +37 -4
- 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 +25 -8
- 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 +82 -15
- package/src/{plugins/builtin/portfolio-list → portfolio}/column-values.ts +143 -55
- 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/{plugins/builtin/portfolio-list → portfolio}/mutations.ts +59 -15
- package/src/portfolio/position-metrics.ts +44 -10
- package/src/portfolio/valuation-basis.ts +34 -24
- package/src/public/__snapshots__/public-api.test.ts.snap +6 -0
- package/src/public/time-series.ts +2 -1
- package/src/remote/confirm-change.tsx +2 -1
- package/src/remote/controller.ts +27 -7
- package/src/remote/schema.ts +25 -9
- package/src/remote/server.ts +1 -1
- package/src/remote/watchlist.ts +9 -1
- package/src/renderers/cloudflare/http-proxy.ts +21 -13
- 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 +7 -5
- 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 +5 -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/dom/windowed-list.tsx +201 -0
- package/src/renderers/dom/windowed-rows.ts +65 -0
- package/src/renderers/electrobun/bun/core-capabilities.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +2 -9
- package/src/renderers/electrobun/bun/desktop/backend.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/http-stream.ts +21 -6
- 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/update.ts +21 -6
- package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +5 -1
- package/src/renderers/electrobun/shared/protocol.ts +4 -2
- 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/renderers/electrobun/view/http-fetch.ts +12 -1
- 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/listing-symbols.ts +8 -4
- 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 -0
- package/src/state/app/tab-cursor.ts +222 -0
- 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 +264 -74
- 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/test-support/config-store.ts +31 -0
- package/src/test-support/moved-symbols.ts +64 -0
- package/src/theme/colors.ts +32 -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 +282 -0
- package/src/tickers/listing-venues.ts +24 -5
- package/src/tickers/open-target.ts +13 -5
- package/src/tickers/search/index.ts +156 -37
- package/src/tickers/search/ranking.ts +68 -3
- package/src/tickers/search/types.ts +3 -0
- package/src/tickers/search/upsert.ts +22 -7
- package/src/tickers/terminal-codes.ts +79 -0
- package/src/tickers/ticker-changes.ts +100 -12
- package/src/tickers/us-listing.ts +2 -1
- package/src/time-series/bar-spacing.ts +19 -0
- package/src/time-series/chart-data.ts +116 -21
- package/src/time-series/field-catalog.ts +5 -2
- package/src/time-series/forward-valuation.ts +10 -7
- package/src/time-series/fundamentals.ts +103 -17
- package/src/time-series/hooks.ts +2 -0
- package/src/time-series/ice-credit.ts +17 -2
- package/src/time-series/live-bars.ts +24 -9
- package/src/time-series/live-quotes.ts +2 -3
- package/src/time-series/parsed-history-cache.ts +2 -0
- package/src/time-series/price-comparison.ts +6 -1
- package/src/time-series/price-units.ts +69 -0
- package/src/time-series/resolve.ts +114 -14
- package/src/time-series/session-bar.ts +138 -0
- package/src/time-series/spec.ts +14 -4
- package/src/time-series/studies.ts +214 -15
- package/src/time-series/transforms.ts +2 -0
- package/src/time-series/types.ts +33 -1
- package/src/time-series/use-chart-resolution.ts +2 -1
- package/src/time-series/valuation-price.ts +13 -0
- package/src/types/config.ts +17 -1
- package/src/types/data-provider.ts +20 -0
- package/src/types/financials.ts +2 -0
- package/src/types/headless.ts +169 -1
- package/src/types/instrument.ts +6 -0
- package/src/types/plugin.ts +39 -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 +45 -4
- package/src/ui/measured-cells.ts +13 -7
- package/src/ui/qr.ts +7 -5
- package/src/updater/index.ts +8 -6
- package/src/utils/asset-category.ts +20 -0
- 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/decimal-comma.ts +83 -3
- 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/fundamentals.ts +7 -2
- package/src/utils/futures-generic.ts +34 -8
- package/src/utils/http-proxy-response.ts +67 -9
- 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/plugin-proxy-hosts.json +1 -5
- 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/typo-distance.ts +22 -0
- 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/plugins/builtin/shared/zip-text.ts +0 -46
- package/src/renderers/dom/host/top-surface.ts +0 -119
- package/src/shares/dialog.tsx +0 -221
- package/src/shares/live.ts +0 -19
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../utils/log-failure";
|
|
1
2
|
import type { PriceHistoryResult } from "../../types/price-history";
|
|
2
3
|
import type { ResourceStore } from "../../data/resource-store";
|
|
3
4
|
import type { ConnectionHealthRegistry } from "../../core/connection-health";
|
|
@@ -174,8 +175,8 @@ export class AssetDataRouter implements DataProvider {
|
|
|
174
175
|
if (!provider.canProvide || await provider.canProvide(ticker, exchange, context)) {
|
|
175
176
|
return true;
|
|
176
177
|
}
|
|
177
|
-
} catch {
|
|
178
|
-
|
|
178
|
+
} catch (error) {
|
|
179
|
+
logFailure("sources.provider-router.index", "Checking provider availability failed")(error);
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
return false;
|
|
@@ -252,7 +253,9 @@ export class AssetDataRouter implements DataProvider {
|
|
|
252
253
|
known = mergeQuoteMetadata(known, metadata);
|
|
253
254
|
if (known?.currency && known.instrumentType) return known;
|
|
254
255
|
}
|
|
255
|
-
} catch {
|
|
256
|
+
} catch (error) {
|
|
257
|
+
logFailure("sources.provider-router.index", "Loading listing metadata failed")(error);
|
|
258
|
+
}
|
|
256
259
|
}
|
|
257
260
|
return known ?? null;
|
|
258
261
|
}
|
|
@@ -289,6 +292,18 @@ export class AssetDataRouter implements DataProvider {
|
|
|
289
292
|
return (await this.getCachedQuery("getCorporateActions", [ticker, exchange, context]).load({ force: context?.cacheMode === "refresh", background: this.revalidateInBackground })).value;
|
|
290
293
|
}
|
|
291
294
|
|
|
295
|
+
searchBatch(queries: string[], options?: { limit?: number; signal?: AbortSignal }): Promise<Map<string, InstrumentSearchResult[]> | null> {
|
|
296
|
+
return this.searchRoutes.searchBatch(queries, options);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** The first source that answers a batch of symbol changes; null when none can or it fails. */
|
|
300
|
+
async getTickerChangesBatch(symbols: string[], options?: { signal?: AbortSignal }): Promise<Map<string, TickerChanges | null> | null> {
|
|
301
|
+
const provider = this.providersInPriorityOrder().find((candidate) => candidate.getTickerChangesBatch);
|
|
302
|
+
if (!provider) return null;
|
|
303
|
+
return await provider.getTickerChangesBatch!(symbols, options)
|
|
304
|
+
.catch(logFailure("sources.provider-router.index", "Batched ticker changes failed", null));
|
|
305
|
+
}
|
|
306
|
+
|
|
292
307
|
/** The first source that keeps symbol changes answers; one that fails is passed over. */
|
|
293
308
|
async getTickerChanges(symbol: string, options?: { signal?: AbortSignal }): Promise<TickerChanges | null> {
|
|
294
309
|
for (const provider of this.providersInPriorityOrder()) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../utils/log-failure";
|
|
1
2
|
import { selectCachedResource } from "./cache";
|
|
2
3
|
import { financialHistoryVariants, hasReusableExtendedHistory } from "./statement-history";
|
|
3
4
|
import type { MarketDataRequestContext } from "../../types/data-provider";
|
|
@@ -57,8 +58,8 @@ export class ProviderRouterPrimaryRoutes {
|
|
|
57
58
|
this.options.resolveBrokerPolicy("financials", candidate.broker),
|
|
58
59
|
);
|
|
59
60
|
return { sourceKey: this.options.brokerSourceKey(candidate), value: result };
|
|
60
|
-
} catch {
|
|
61
|
-
|
|
61
|
+
} catch (error) {
|
|
62
|
+
logFailure("sources.provider-router.primary", "Loading broker financials failed")(error);
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
return null;
|
|
@@ -179,8 +180,8 @@ export class ProviderRouterPrimaryRoutes {
|
|
|
179
180
|
this.options.resolveBrokerPolicy("brokerQuote", candidate.broker),
|
|
180
181
|
);
|
|
181
182
|
return { sourceKey: this.options.brokerSourceKey(candidate), value: result };
|
|
182
|
-
} catch {
|
|
183
|
-
|
|
183
|
+
} catch (error) {
|
|
184
|
+
logFailure("sources.provider-router.primary", "Loading a broker quote failed")(error);
|
|
184
185
|
}
|
|
185
186
|
}
|
|
186
187
|
return null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../utils/log-failure";
|
|
1
2
|
import type { QuoteSubscriptionTarget } from "../../types/data-provider";
|
|
2
3
|
import { canonicalExchange, US_LISTING_EXCHANGES } from "../../utils/exchanges";
|
|
3
4
|
import type { BrokerCandidate } from "./brokers";
|
|
@@ -54,7 +55,8 @@ export function resolveBrokerQuoteStreamState(
|
|
|
54
55
|
const status = broker.getStatus?.(instance);
|
|
55
56
|
if (status && status.state !== "connected") return "offline";
|
|
56
57
|
return status?.quoteData === "delayed" || observedDelayed ? "delayed" : "live";
|
|
57
|
-
} catch {
|
|
58
|
+
} catch (error) {
|
|
59
|
+
logFailure("sources.provider-router.quote-route", "Reading broker quote stream status failed")(error);
|
|
58
60
|
return "unsupported";
|
|
59
61
|
}
|
|
60
62
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../utils/log-failure";
|
|
1
2
|
import type { MarketDataRequestContext } from "../../types/data-provider";
|
|
2
3
|
import type { ProviderRouterCoreDeps } from "./route-types";
|
|
3
4
|
import { buildVariantKey } from "./cache";
|
|
@@ -35,7 +36,7 @@ export function scheduleRouterRevalidation(
|
|
|
35
36
|
): void {
|
|
36
37
|
if (inFlight.has(key)) return;
|
|
37
38
|
const promise = task()
|
|
38
|
-
.catch((
|
|
39
|
+
.catch(logFailure("sources.provider-router.routing", "Refreshing a cached provider result failed"))
|
|
39
40
|
.finally(() => {
|
|
40
41
|
inFlight.delete(key);
|
|
41
42
|
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { logFailure } from "../../utils/log-failure";
|
|
1
2
|
import type { DataProvider, SearchRequestContext } from "../../types/data-provider";
|
|
2
3
|
import type { InstrumentSearchResult } from "../../types/instrument";
|
|
3
4
|
import type { BrokerCandidate } from "./brokers";
|
|
4
|
-
import { shouldLogProviderError } from "../provider-errors";
|
|
5
|
+
import { isProviderBusy, ProviderBusyError, SEARCH_BUSY_MESSAGE, shouldLogProviderError } from "../provider-errors";
|
|
5
6
|
import { searchInstrumentKey } from "../../tickers/search/identity";
|
|
6
|
-
import { settleWithin } from "../../utils/async-deadline";
|
|
7
|
+
import { OperationTimeoutError, settleWithin, withDeadline } from "../../utils/async-deadline";
|
|
7
8
|
|
|
8
9
|
const SEARCH_CACHE_TTL_MS = 30_000;
|
|
9
10
|
const SEARCH_CACHE_MAX_ENTRIES = 100;
|
|
@@ -87,6 +88,25 @@ export class ProviderRouterSearchRoutes {
|
|
|
87
88
|
|
|
88
89
|
constructor(private readonly deps: ProviderRouterSearchDeps) {}
|
|
89
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Several searches answered by the preferred provider in a few requests,
|
|
93
|
+
* each merged as `search` merges that source's rows. Null while a broker can
|
|
94
|
+
* search: its rows join every search's answer, so those go one at a time.
|
|
95
|
+
*/
|
|
96
|
+
async searchBatch(queries: string[], options?: { limit?: number; signal?: AbortSignal }): Promise<Map<string, InstrumentSearchResult[]> | null> {
|
|
97
|
+
if (this.deps.getBrokerCandidates().some((candidate) => candidate.broker.searchInstruments)) return null;
|
|
98
|
+
const [preferred] = this.deps.providersInPriorityOrder();
|
|
99
|
+
if (!preferred?.searchBatch) return null;
|
|
100
|
+
const answers = await preferred.searchBatch(queries, options)
|
|
101
|
+
.catch(logFailure("sources.provider-router.search", "Batched search failed", null));
|
|
102
|
+
if (!answers) return null;
|
|
103
|
+
return new Map([...answers].map(([query, items]) => {
|
|
104
|
+
const results: InstrumentSearchResult[] = [];
|
|
105
|
+
mergeSearchResults(results, new Map(), items);
|
|
106
|
+
return [query, results] as const;
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
|
|
90
110
|
async search(query: string, context?: SearchRequestContext): Promise<InstrumentSearchResult[]> {
|
|
91
111
|
const cacheKey = buildSearchCacheKey(query, context);
|
|
92
112
|
const cached = this.searchCache.get(cacheKey);
|
|
@@ -118,6 +138,10 @@ export class ProviderRouterSearchRoutes {
|
|
|
118
138
|
* Ordering still matters, it just no longer costs latency: `mergeSearchResults`
|
|
119
139
|
* keeps the richest entry per symbol, so a broker arriving after the cloud
|
|
120
140
|
* still upgrades the row, and `onPartial` hands that upgrade to the caller.
|
|
141
|
+
*
|
|
142
|
+
* A search nothing answered because a provider was busy (rate limited,
|
|
143
|
+
* overloaded, out of time) rejects with a `ProviderBusyError` instead of
|
|
144
|
+
* reading as an empty one, and is not cached, so asking again asks again.
|
|
121
145
|
*/
|
|
122
146
|
private fetchSearchResults(
|
|
123
147
|
query: string,
|
|
@@ -141,10 +165,13 @@ export class ProviderRouterSearchRoutes {
|
|
|
141
165
|
};
|
|
142
166
|
|
|
143
167
|
let resolveFirst!: (value: InstrumentSearchResult[]) => void;
|
|
144
|
-
|
|
168
|
+
let rejectFirst!: (error: unknown) => void;
|
|
169
|
+
const first = new Promise<InstrumentSearchResult[]>((resolve, reject) => {
|
|
145
170
|
resolveFirst = resolve;
|
|
171
|
+
rejectFirst = reject;
|
|
146
172
|
});
|
|
147
173
|
let answered = false;
|
|
174
|
+
let busy = false;
|
|
148
175
|
|
|
149
176
|
const record = (items: InstrumentSearchResult[] | null) => {
|
|
150
177
|
if (!items?.length) return;
|
|
@@ -167,16 +194,20 @@ export class ProviderRouterSearchRoutes {
|
|
|
167
194
|
timeoutMs,
|
|
168
195
|
);
|
|
169
196
|
record(items && annotateBrokerSearchResults(items, candidate));
|
|
170
|
-
} catch {
|
|
171
|
-
|
|
197
|
+
} catch (error) {
|
|
198
|
+
logFailure("sources.provider-router.search", "Searching broker instruments failed")(error);
|
|
172
199
|
}
|
|
173
200
|
})();
|
|
174
201
|
|
|
175
202
|
const searchProvider = (provider: DataProvider) => (async () => {
|
|
176
203
|
try {
|
|
177
|
-
record(await
|
|
204
|
+
record(await withDeadline(provider.search(query, context), timeoutMs, `${provider.id} search timed out`));
|
|
178
205
|
} catch (error) {
|
|
179
|
-
|
|
206
|
+
const timedOut = error instanceof OperationTimeoutError;
|
|
207
|
+
// A keystroke gives up on a slow source by design and asks again on the next one; only a full wait is busy.
|
|
208
|
+
if (isProviderBusy(error) || (timedOut && !context?.interactive)) {
|
|
209
|
+
busy = true;
|
|
210
|
+
} else if (!timedOut && shouldLogProviderError(error)) {
|
|
180
211
|
this.deps.logProviderError(`${provider.id} failed: ${error}`);
|
|
181
212
|
}
|
|
182
213
|
}
|
|
@@ -198,13 +229,16 @@ export class ProviderRouterSearchRoutes {
|
|
|
198
229
|
await Promise.allSettled(fallbacks.map(searchProvider));
|
|
199
230
|
}
|
|
200
231
|
})().then(() => {
|
|
201
|
-
if (
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
resolveFirst([]);
|
|
232
|
+
if (answered) return;
|
|
233
|
+
answered = true;
|
|
234
|
+
if (busy) {
|
|
235
|
+
rejectFirst(new ProviderBusyError(SEARCH_BUSY_MESSAGE));
|
|
236
|
+
return;
|
|
207
237
|
}
|
|
238
|
+
// Nothing matched anywhere, so hold the empty answer briefly rather
|
|
239
|
+
// than asking every source again on the next keystroke.
|
|
240
|
+
cacheResults(Math.min(SEARCH_CACHE_TTL_MS, 5_000));
|
|
241
|
+
resolveFirst([]);
|
|
208
242
|
});
|
|
209
243
|
|
|
210
244
|
return { first, settled };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../utils/log-failure";
|
|
1
2
|
import type { DataProvider, MarketDataRequestContext, QuoteSubscriptionTarget } from "../../types/data-provider";
|
|
2
3
|
import type { Quote } from "../../types/financials";
|
|
3
4
|
import type { BrokerCandidate } from "./brokers";
|
|
@@ -51,7 +52,8 @@ function isBrokerConnected(candidate: BrokerCandidate): boolean {
|
|
|
51
52
|
try {
|
|
52
53
|
const status = candidate.broker.getStatus?.(candidate.instance);
|
|
53
54
|
return !status || status.state === "connected";
|
|
54
|
-
} catch {
|
|
55
|
+
} catch (error) {
|
|
56
|
+
logFailure("sources.provider-router.streaming", "Reading broker connection status failed")(error);
|
|
55
57
|
return false;
|
|
56
58
|
}
|
|
57
59
|
}
|
|
@@ -62,7 +64,8 @@ function canWakeBroker(candidate: BrokerCandidate): boolean {
|
|
|
62
64
|
try {
|
|
63
65
|
const state = candidate.broker.getStatus?.(candidate.instance)?.state;
|
|
64
66
|
return state === "disconnected" || state === "error";
|
|
65
|
-
} catch {
|
|
67
|
+
} catch (error) {
|
|
68
|
+
logFailure("sources.provider-router.streaming", "Reading broker connection status failed")(error);
|
|
66
69
|
return false;
|
|
67
70
|
}
|
|
68
71
|
}
|
|
@@ -195,8 +198,8 @@ export class ProviderRouterStreamingRoutes {
|
|
|
195
198
|
scheduleApply();
|
|
196
199
|
});
|
|
197
200
|
if (unsubscribe) watchers.push(unsubscribe);
|
|
198
|
-
} catch {
|
|
199
|
-
|
|
201
|
+
} catch (error) {
|
|
202
|
+
logFailure("sources.provider-router.streaming", "Subscribing to broker connection status failed")(error);
|
|
200
203
|
}
|
|
201
204
|
}
|
|
202
205
|
this.delayedSessionListeners.add(scheduleApply);
|
package/src/sources/sec-edgar.ts
CHANGED
|
@@ -171,9 +171,7 @@ function resolveSecArchiveUrl(href: string, filingUrl: string): string | null {
|
|
|
171
171
|
return new URL(ixviewerDocument, "https://www.sec.gov").toString();
|
|
172
172
|
}
|
|
173
173
|
return url.toString();
|
|
174
|
-
} catch {
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
174
|
+
} catch { /* Intentional ignore: Malformed document hrefs are not usable archive links. */ return null; }
|
|
177
175
|
}
|
|
178
176
|
|
|
179
177
|
function isHtmlResponse(body: string): boolean {
|
|
@@ -458,6 +458,7 @@ export function AppProvider({
|
|
|
458
458
|
const effectiveThemeId = getEffectiveThemeId(state);
|
|
459
459
|
const previousRecentTickers = useRef(state.recentTickers);
|
|
460
460
|
const previousRecentCommands = useRef(state.config.recentCommands);
|
|
461
|
+
const previousCommandBarOpens = useRef(state.config.commandBarOpens);
|
|
461
462
|
const stateRef = useRef(state);
|
|
462
463
|
const listenersRef = useRef(new Set<() => void>());
|
|
463
464
|
const storeRef = useRef<AppContextStoreValue | null>(null);
|
|
@@ -538,6 +539,14 @@ export function AppProvider({
|
|
|
538
539
|
scheduleConfigSave(() => ({ ...stateRef.current.config, recentTickers: stateRef.current.recentTickers }));
|
|
539
540
|
}, [state.config.recentCommands]);
|
|
540
541
|
|
|
542
|
+
// Opening the empty bar changes only config.commandBarOpens, until it stops
|
|
543
|
+
// counting; nothing else saves it.
|
|
544
|
+
useEffect(() => {
|
|
545
|
+
if (previousCommandBarOpens.current === state.config.commandBarOpens) return;
|
|
546
|
+
previousCommandBarOpens.current = state.config.commandBarOpens;
|
|
547
|
+
scheduleConfigSave(() => ({ ...stateRef.current.config, recentTickers: stateRef.current.recentTickers }));
|
|
548
|
+
}, [state.config.commandBarOpens]);
|
|
549
|
+
|
|
541
550
|
useEffect(() => {
|
|
542
551
|
if (!desktopBridge) return;
|
|
543
552
|
return desktopBridge.subscribeState((snapshot) => {
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { useCallback, useContext, useEffect, useMemo, useSyncExternalStore } from "react";
|
|
2
|
+
import type { AppState } from "../../core/state/app/state";
|
|
3
|
+
import { findPaneInstance, type SavedLayout } from "../../types/config";
|
|
4
|
+
import { AppContext, useOptionalAppSelector, useOptionalPaneInstanceId, type AppContextStoreValue } from "./context";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The time the pointer or keyboard cursor is at on one chart of a layout tab,
|
|
8
|
+
* which the tab's other charts show at the same moment: the last instant the
|
|
9
|
+
* cursor covers, so a chart reads its data as of then. It is held per tab, in
|
|
10
|
+
* memory only: a cursor moves on every pointer event, and the app store would
|
|
11
|
+
* re-run every pane's selectors on each one.
|
|
12
|
+
*/
|
|
13
|
+
interface TabCursor {
|
|
14
|
+
time: number;
|
|
15
|
+
/** The chart the cursor is on; it never follows its own time back. */
|
|
16
|
+
sourceId: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const cursors = new Map<string, TabCursor>();
|
|
20
|
+
/**
|
|
21
|
+
* A pinned cursor belongs to no chart: every chart in the tab follows it, the
|
|
22
|
+
* one it was pinned from too, and no pointer leaving a chart takes it away.
|
|
23
|
+
*/
|
|
24
|
+
const PINNED = "\u0000pinned";
|
|
25
|
+
/** How many charts in each tab are mounted to show its pin; see `useTabCursorLink`. */
|
|
26
|
+
const pinViewers = new Map<string, number>();
|
|
27
|
+
const listeners = new Set<() => void>();
|
|
28
|
+
|
|
29
|
+
/** A time a Date can hold. A pin is never NaN, infinite or past the Date range, whatever asks for it. */
|
|
30
|
+
function isMoment(time: number): boolean {
|
|
31
|
+
return Number.isFinite(time) && Math.abs(time) <= 8.64e15;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function setTabCursorTime(tabKey: string, sourceId: string | null, time: number | null): void {
|
|
35
|
+
const current = cursors.get(tabKey);
|
|
36
|
+
if (time === null) {
|
|
37
|
+
// Only the chart the cursor is on can take it away: a chart clearing a
|
|
38
|
+
// cursor it no longer holds must not clear another chart's. A null source
|
|
39
|
+
// clears whichever chart holds it.
|
|
40
|
+
if (!current || (sourceId !== null && current.sourceId !== sourceId)) return;
|
|
41
|
+
cursors.delete(tabKey);
|
|
42
|
+
} else {
|
|
43
|
+
if (sourceId === null || (current?.sourceId === sourceId && current.time === time)) return;
|
|
44
|
+
cursors.set(tabKey, { time, sourceId });
|
|
45
|
+
}
|
|
46
|
+
for (const listener of listeners) listener();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function subscribe(listener: () => void): () => void {
|
|
50
|
+
listeners.add(listener);
|
|
51
|
+
return () => listeners.delete(listener);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** A chart's handle on the cursor its layout tab shares. */
|
|
55
|
+
export interface TabCursorLink {
|
|
56
|
+
/** Calls `listener` whenever a tab's cursor moves. */
|
|
57
|
+
subscribe(listener: () => void): () => void;
|
|
58
|
+
/** Where another chart's cursor is in this tab: null when none is, or the cursor is this chart's own. */
|
|
59
|
+
time(): number | null;
|
|
60
|
+
/** Whether this chart's cursor is the tab's. */
|
|
61
|
+
held(): boolean;
|
|
62
|
+
/** Reports this chart's cursor, or null when it leaves. */
|
|
63
|
+
publish(time: number | null): void;
|
|
64
|
+
/** Clears the tab's cursor, whichever chart holds it, a pinned one too. */
|
|
65
|
+
clear(): void;
|
|
66
|
+
/** Whether the tab's cursor is pinned. */
|
|
67
|
+
pinned?(): boolean;
|
|
68
|
+
/** Pins the tab's cursor at `time`, which no chart's pointer moves, or unpins it with null. */
|
|
69
|
+
pin?(time: number | null): void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** A layout tab is named by its id; older saved tabs have none, and go by position. */
|
|
73
|
+
const tabKeyAt = (layouts: readonly SavedLayout[], index: number): string => layouts[index]?.id ?? `index:${index}`;
|
|
74
|
+
const selectTabKey = (state: AppState): string => tabKeyAt(state.config.layouts, state.config.activeLayoutIndex);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Moves the cursors of a store's tabs with their tabs when the tab list
|
|
78
|
+
* changes. A tab with an id keeps its key while it is open. One without is
|
|
79
|
+
* keyed by its place, so when tabs open, close or move its cursor follows its
|
|
80
|
+
* name to the new place if no other tab shares that name, and goes otherwise.
|
|
81
|
+
* So a closed tab's pin goes with it, and a tab that takes its place never
|
|
82
|
+
* inherits it. Edits that leave every tab where it was keep every key, one
|
|
83
|
+
* tab renamed included.
|
|
84
|
+
*/
|
|
85
|
+
function retargetTabCursors(before: readonly SavedLayout[], after: readonly SavedLayout[]): void {
|
|
86
|
+
const inPlace = before.length === after.length && before.every((tab, index) => tab.id === after[index]!.id);
|
|
87
|
+
if (inPlace && before.filter((tab, index) => tab.name !== after[index]!.name).length <= 1) return;
|
|
88
|
+
const afterKeys = new Set(after.map((_, index) => tabKeyAt(after, index)));
|
|
89
|
+
const named = (tabs: readonly SavedLayout[], name: string) => tabs.filter((tab) => tab.id === undefined && tab.name === name).length;
|
|
90
|
+
const moved = new Map<string, TabCursor>();
|
|
91
|
+
let changed = false;
|
|
92
|
+
before.forEach((tab, index) => {
|
|
93
|
+
const key = tabKeyAt(before, index);
|
|
94
|
+
const cursor = cursors.get(key);
|
|
95
|
+
if (!cursor) return;
|
|
96
|
+
cursors.delete(key);
|
|
97
|
+
let target: string | null = null;
|
|
98
|
+
if (tab.id !== undefined) target = afterKeys.has(key) ? key : null;
|
|
99
|
+
else if (named(before, tab.name) === 1 && named(after, tab.name) === 1) {
|
|
100
|
+
target = `index:${after.findIndex((next) => next.id === undefined && next.name === tab.name)}`;
|
|
101
|
+
}
|
|
102
|
+
if (target !== key) changed = true;
|
|
103
|
+
if (target !== null) moved.set(target, cursor);
|
|
104
|
+
});
|
|
105
|
+
for (const [key, cursor] of moved) cursors.set(key, cursor);
|
|
106
|
+
if (changed) for (const listener of listeners) listener();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const watchedStores = new WeakSet<AppContextStoreValue>();
|
|
110
|
+
/** Follows a store's tab list once, from the first chart that links to it. */
|
|
111
|
+
function watchTabs(store: AppContextStoreValue): void {
|
|
112
|
+
if (watchedStores.has(store)) return;
|
|
113
|
+
watchedStores.add(store);
|
|
114
|
+
let tabs = store.getState().config.layouts;
|
|
115
|
+
store.subscribe(() => {
|
|
116
|
+
const next = store.getState().config.layouts;
|
|
117
|
+
if (next === tabs) return;
|
|
118
|
+
const before = tabs;
|
|
119
|
+
tabs = next;
|
|
120
|
+
retargetTabCursors(before, next);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Shares a chart's cursor time with the other charts in its layout tab.
|
|
126
|
+
* `sourceId` names the chart, unique in the tab: two charts in one pane each
|
|
127
|
+
* have their own, so either follows the other. Reading the handle does not
|
|
128
|
+
* re-render anything when the cursor moves: what draws the cursor
|
|
129
|
+
* subscribes, so a pointer move on one chart re-renders the other charts and
|
|
130
|
+
* nothing around them. A null `sourceId`, or no app around it (a test, a
|
|
131
|
+
* screenshot), shares nothing. `viewer` says whether the chart shows the pin
|
|
132
|
+
* and can lift it now; only such charts keep a pin from going (see below).
|
|
133
|
+
*/
|
|
134
|
+
export function useTabCursorLink(sourceId: string | null, { viewer = true }: { viewer?: boolean } = {}): TabCursorLink | undefined {
|
|
135
|
+
const tabKey = useOptionalAppSelector<string | null>(selectTabKey, null);
|
|
136
|
+
const app = useContext(AppContext);
|
|
137
|
+
const paneId = useOptionalPaneInstanceId();
|
|
138
|
+
const link = useMemo<TabCursorLink | undefined>(() => tabKey === null || sourceId === null ? undefined : {
|
|
139
|
+
subscribe,
|
|
140
|
+
time: () => {
|
|
141
|
+
const cursor = cursors.get(tabKey);
|
|
142
|
+
return cursor && cursor.sourceId !== sourceId ? cursor.time : null;
|
|
143
|
+
},
|
|
144
|
+
held: () => cursors.get(tabKey)?.sourceId === sourceId,
|
|
145
|
+
publish: (time) => {
|
|
146
|
+
// A pinned cursor stays until it is unpinned: hovering a chart, or leaving it, does not move it.
|
|
147
|
+
if (cursors.get(tabKey)?.sourceId === PINNED) return;
|
|
148
|
+
setTabCursorTime(tabKey, sourceId, time !== null && Number.isFinite(time) ? time : null);
|
|
149
|
+
},
|
|
150
|
+
clear: () => setTabCursorTime(tabKey, null, null),
|
|
151
|
+
pinned: () => cursors.get(tabKey)?.sourceId === PINNED,
|
|
152
|
+
// Null unpins; a time no Date can hold changes nothing.
|
|
153
|
+
pin: (time) => {
|
|
154
|
+
if (time === null || isMoment(time)) setTabCursorTime(tabKey, PINNED, time);
|
|
155
|
+
},
|
|
156
|
+
}, [sourceId, tabKey]);
|
|
157
|
+
useEffect(() => {
|
|
158
|
+
if (app && "subscribe" in app) watchTabs(app);
|
|
159
|
+
}, [app]);
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
if (!link) return;
|
|
162
|
+
// A chart closed or switched away from under the cursor takes its cursor with it.
|
|
163
|
+
return () => link.publish(null);
|
|
164
|
+
}, [link]);
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
if (!link || tabKey === null || !viewer) return;
|
|
167
|
+
pinViewers.set(tabKey, (pinViewers.get(tabKey) ?? 0) + 1);
|
|
168
|
+
return () => {
|
|
169
|
+
const left = (pinViewers.get(tabKey) ?? 1) - 1;
|
|
170
|
+
if (left > 0) {
|
|
171
|
+
pinViewers.set(tabKey, left);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
pinViewers.delete(tabKey);
|
|
175
|
+
// The pin is the tab's, so it stays when the chart it was pinned on
|
|
176
|
+
// closes and others remain, and through a switch to another tab. When
|
|
177
|
+
// the last chart showing it closes, nothing in the tab could lift it,
|
|
178
|
+
// so it goes too: a chart that is not interactive (an overview's
|
|
179
|
+
// sparkline) shows no pin and does not count. Read once the commit
|
|
180
|
+
// settles, from the app's current state: a chart replaced in place, or
|
|
181
|
+
// one in a pane that is still open (reloading, under a dialog), keeps it.
|
|
182
|
+
// A closed tab's pin goes with the tab (`retargetTabCursors`).
|
|
183
|
+
queueMicrotask(() => {
|
|
184
|
+
if (pinViewers.has(tabKey) || !app) return;
|
|
185
|
+
const state = "getState" in app ? app.getState() : app.state;
|
|
186
|
+
if (selectTabKey(state) !== tabKey) return;
|
|
187
|
+
if (paneId !== null && findPaneInstance(state.config.layout, paneId)) return;
|
|
188
|
+
setTabCursorTime(tabKey, PINNED, null);
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
}, [app, link, paneId, tabKey, viewer]);
|
|
192
|
+
return link;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The moment the layout tab's crosshair is pinned at, for a pane that is not a
|
|
197
|
+
* chart (news, the tape): null while nothing is pinned. It follows the pin, not
|
|
198
|
+
* a pointer passing over a chart, so a list re-renders when the pin moves and
|
|
199
|
+
* never on a pointer move.
|
|
200
|
+
*/
|
|
201
|
+
export function usePinnedTabTime(): number | null {
|
|
202
|
+
const tabKey = useOptionalAppSelector<string | null>(selectTabKey, null);
|
|
203
|
+
const pinnedTime = useCallback(() => {
|
|
204
|
+
const cursor = tabKey === null ? undefined : cursors.get(tabKey);
|
|
205
|
+
return cursor?.sourceId === PINNED ? cursor.time : null;
|
|
206
|
+
}, [tabKey]);
|
|
207
|
+
return useSyncExternalStore(subscribe, pinnedTime);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** The moment the active layout tab has its crosshair pinned at, outside React: a shared link opens there. */
|
|
211
|
+
export function pinnedTabTime(state: AppState): number | null {
|
|
212
|
+
const cursor = cursors.get(selectTabKey(state));
|
|
213
|
+
return cursor?.sourceId === PINNED ? cursor.time : null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Lifts the layout tab's pin from a pane that is not a chart, as Esc does on a chart. */
|
|
217
|
+
export function useUnpinTab(): () => void {
|
|
218
|
+
const tabKey = useOptionalAppSelector<string | null>(selectTabKey, null);
|
|
219
|
+
return useCallback(() => {
|
|
220
|
+
if (tabKey !== null) setTabCursorTime(tabKey, PINNED, null);
|
|
221
|
+
}, [tabKey]);
|
|
222
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../utils/log-failure";
|
|
1
2
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
3
|
import { useAppVisible, usePaneInView } from "../app/activity";
|
|
3
4
|
import type { QuoteSubscriptionTarget } from "../../types/data-provider";
|
|
@@ -252,8 +253,8 @@ export function useQuoteUpdates(
|
|
|
252
253
|
lastPollRef.current = { key: instrumentKey, at: Date.now() };
|
|
253
254
|
try {
|
|
254
255
|
await coordinator.loadQuotesBatch(instruments, { forceRefresh: true });
|
|
255
|
-
} catch {
|
|
256
|
-
|
|
256
|
+
} catch (error) {
|
|
257
|
+
logFailure("state.hooks.quote-streaming", "Polling broker quotes failed")(error);
|
|
257
258
|
} finally {
|
|
258
259
|
inFlight = false;
|
|
259
260
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logFailure } from "../../utils/log-failure";
|
|
1
2
|
import { useEffect, useRef } from "react";
|
|
2
3
|
import type { AppSessionStorePort } from "../../core/app-service-ports";
|
|
3
4
|
import {
|
|
@@ -69,8 +70,8 @@ export function usePersistSessionSnapshot(
|
|
|
69
70
|
recentTickers: currentState.recentTickers,
|
|
70
71
|
tickers: currentState.tickers,
|
|
71
72
|
}) satisfies AppSessionSnapshot;
|
|
72
|
-
} catch {
|
|
73
|
-
|
|
73
|
+
} catch (error) {
|
|
74
|
+
logFailure("persist", "Building the saved session snapshot failed")(error);
|
|
74
75
|
return null;
|
|
75
76
|
}
|
|
76
77
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { logFailure } from "../utils/log-failure";
|
|
2
|
+
|
|
1
3
|
export const CONFIG_SAVE_DEBOUNCE_MS = 500;
|
|
2
4
|
/** For config fields that change on every cursor move (recent tickers, the live pane-state mirror). */
|
|
3
5
|
export const LOW_PRIORITY_CONFIG_SAVE_DEBOUNCE_MS = 5_000;
|
|
@@ -51,7 +53,10 @@ export function createPersistScheduler<T>({
|
|
|
51
53
|
try {
|
|
52
54
|
await save(value);
|
|
53
55
|
} catch (error) {
|
|
54
|
-
if (reportError)
|
|
56
|
+
if (reportError) {
|
|
57
|
+
if (onError) onError(error);
|
|
58
|
+
else logFailure("persist", "Scheduled persistence failed")(error);
|
|
59
|
+
}
|
|
55
60
|
throw error;
|
|
56
61
|
}
|
|
57
62
|
});
|
|
@@ -60,11 +65,14 @@ export function createPersistScheduler<T>({
|
|
|
60
65
|
inFlightSaves.add(saveTask);
|
|
61
66
|
void saveTask.then(
|
|
62
67
|
() => { inFlightSaves.delete(saveTask); },
|
|
63
|
-
() => {
|
|
68
|
+
() => {
|
|
69
|
+
// Intentional ignore: The returned saveTask or enqueueSave already reports this failure.
|
|
70
|
+
inFlightSaves.delete(saveTask);
|
|
71
|
+
},
|
|
64
72
|
);
|
|
65
73
|
// Keep the serialization chain usable after a failed immediate save while
|
|
66
74
|
// still returning that failure to its caller.
|
|
67
|
-
inFlight = saveTask.catch(() => {});
|
|
75
|
+
inFlight = saveTask.catch(() => { /* Intentional ignore: The returned saveTask reports to the caller; this rejection only keeps the queue usable. */ });
|
|
68
76
|
return saveTask;
|
|
69
77
|
};
|
|
70
78
|
|
|
@@ -76,7 +84,7 @@ export function createPersistScheduler<T>({
|
|
|
76
84
|
const value = pendingValue as T;
|
|
77
85
|
pendingValue = undefined;
|
|
78
86
|
hasPendingValue = false;
|
|
79
|
-
return enqueueSave(value, true).catch(() => {});
|
|
87
|
+
return enqueueSave(value, true).catch(() => { /* Intentional ignore: enqueueSave reports scheduled errors before this drain consumes them. */ });
|
|
80
88
|
};
|
|
81
89
|
|
|
82
90
|
return {
|
package/src/sync/controller.ts
CHANGED
|
@@ -87,6 +87,13 @@ export class CloudSyncController {
|
|
|
87
87
|
private syncQueued = false;
|
|
88
88
|
private clientId: string | null = null;
|
|
89
89
|
private lastSignature: string | null = null;
|
|
90
|
+
/**
|
|
91
|
+
* The content signature of the cloud's copy, with the revision and the
|
|
92
|
+
* write it belongs to. Each 15 s poll pulls the same copy again until a
|
|
93
|
+
* device writes; working its signature out every time was a third of an
|
|
94
|
+
* idle sync on a large workspace (GLO-925).
|
|
95
|
+
*/
|
|
96
|
+
private cloudSignature: { transportId: string; revision: number; clientId: string; createdAt: string; signature: string } | null = null;
|
|
90
97
|
private baseline: Record<string, unknown> | null = null;
|
|
91
98
|
private baselineLoaded = false;
|
|
92
99
|
private pulledContributors: SyncSnapshot["contributors"] = {};
|
|
@@ -302,7 +309,7 @@ export class CloudSyncController {
|
|
|
302
309
|
});
|
|
303
310
|
return {
|
|
304
311
|
revision: response.snapshot ? response.revision : 0,
|
|
305
|
-
signature: response.snapshot ?
|
|
312
|
+
signature: response.snapshot ? this.pulledSignature(transport, response.revision, response.snapshot) : null,
|
|
306
313
|
};
|
|
307
314
|
} catch (error) {
|
|
308
315
|
if (!this.isCurrent(runtime, transport)) return null;
|
|
@@ -435,6 +442,19 @@ export class CloudSyncController {
|
|
|
435
442
|
return this.runtime === runtime && runtime.getTransport()?.transport === transport;
|
|
436
443
|
}
|
|
437
444
|
|
|
445
|
+
private pulledSignature(transport: SyncTransport, revision: number | null, snapshot: SyncSnapshot): string {
|
|
446
|
+
const kept = this.cloudSignature;
|
|
447
|
+
if (revision != null && kept && kept.transportId === transport.id && kept.revision === revision
|
|
448
|
+
&& kept.clientId === snapshot.clientId && kept.createdAt === snapshot.createdAt) {
|
|
449
|
+
return kept.signature;
|
|
450
|
+
}
|
|
451
|
+
const signature = snapshotContentSignature(snapshot);
|
|
452
|
+
this.cloudSignature = revision == null
|
|
453
|
+
? null
|
|
454
|
+
: { transportId: transport.id, revision, clientId: snapshot.clientId, createdAt: snapshot.createdAt, signature };
|
|
455
|
+
return signature;
|
|
456
|
+
}
|
|
457
|
+
|
|
438
458
|
private shouldApplyPulledRevision(revision: number | null): boolean {
|
|
439
459
|
return revision == null || this.appliedRevision == null || revision > this.appliedRevision;
|
|
440
460
|
}
|
|
@@ -456,6 +476,7 @@ export class CloudSyncController {
|
|
|
456
476
|
this.inFlight = null;
|
|
457
477
|
this.syncQueued = false;
|
|
458
478
|
this.lastSignature = null;
|
|
479
|
+
this.cloudSignature = null;
|
|
459
480
|
this.appliedRevision = null;
|
|
460
481
|
this.baseline = null;
|
|
461
482
|
this.baselineLoaded = false;
|