gloomberb 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +1 -1
- package/patches/electrobun@1.18.1.patch +169 -5
- package/src/account/auth-model.ts +7 -3
- package/src/api-client/auth.ts +9 -4
- package/src/api-client/catalysts.ts +2 -1
- package/src/api-client/cot.ts +6 -2
- package/src/api-client/credit-documents.ts +6 -0
- package/src/api-client/data.ts +31 -6
- package/src/api-client/equity-screener.ts +24 -0
- package/src/api-client/fund-facts.ts +45 -4
- package/src/api-client/index.ts +171 -11
- package/src/api-client/live-scan.ts +91 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/market-movers.ts +7 -0
- package/src/api-client/members.ts +13 -1
- package/src/api-client/perps.ts +43 -0
- package/src/api-client/request.ts +222 -41
- package/src/api-client/research-activity.ts +6 -12
- package/src/api-client/types.ts +74 -0
- package/src/app/keybindings/index.ts +3 -0
- package/src/app/keybindings/labels.ts +18 -1
- package/src/app/keybindings/resolve.ts +14 -0
- package/src/app/pane-runtime/plugin-bindings.ts +9 -5
- package/src/app/runtime/broker-import.ts +42 -27
- package/src/app/runtime/plugin-bindings.ts +73 -56
- package/src/architecture/core-builtin-allowlist.json +1 -1
- package/src/architecture/pane-tabs-allowlist.json +3 -0
- package/src/architecture/ttl-caches-allowlist.json +19 -0
- package/src/brokers/sync-broker-instance.ts +2 -8
- package/src/capabilities/chart-series.ts +1 -1
- package/src/cli/commands/crypto-hints.ts +40 -24
- package/src/cli/commands/fred-series.ts +5 -0
- package/src/cli/commands/keybindings.ts +23 -0
- package/src/cli/commands/market.ts +138 -46
- package/src/cli/commands/options-chain.ts +107 -10
- package/src/cli/commands/options-leaps.ts +9 -3
- package/src/cli/commands/overview.ts +176 -39
- package/src/cli/commands/search.ts +39 -3
- package/src/cli/commands/themes.ts +11 -2
- package/src/cli/commands/ticker.ts +57 -35
- package/src/cli/company-name-hint.ts +41 -0
- package/src/cli/earnings-calendar.ts +1 -1
- package/src/cli/errors.ts +10 -2
- package/src/cli/export-source.ts +29 -1
- package/src/cli/glossary.ts +73 -1
- package/src/cli/history-rows.ts +87 -16
- package/src/cli/index.ts +2 -0
- package/src/cli/known-gaps.ts +5 -2
- package/src/cli/listing-arg.ts +195 -56
- package/src/cli/output-file.ts +68 -0
- package/src/cli/pane-functions/capabilities.ts +3 -0
- package/src/cli/pane-functions/catalog.ts +80 -7
- package/src/cli/pane-functions/dom.ts +13 -3
- package/src/cli/pane-functions/freshness.ts +111 -16
- package/src/cli/pane-functions/function-help.ts +23 -13
- package/src/cli/pane-functions/headless.ts +56 -12
- package/src/cli/pane-functions/index.ts +58 -16
- package/src/cli/pane-functions/market-session.ts +81 -9
- package/src/cli/pane-functions/options.ts +19 -1
- package/src/cli/pane-functions/report.ts +5 -1
- package/src/cli/pane-functions/resolver.ts +35 -8
- package/src/cli/pane-functions/screenshot-assessment.ts +6 -4
- package/src/cli/pane-functions/screenshot-types.ts +5 -0
- package/src/cli/quote-answer.ts +30 -13
- package/src/cli/report-tables.ts +18 -7
- package/src/cli/restore-plugins.ts +13 -1
- package/src/cli/result.ts +57 -5
- package/src/cli/ticker-resolution.ts +3 -2
- package/src/components/chart/composite/composite-chart.tsx +26 -4
- package/src/components/chart/composite/format.ts +27 -0
- package/src/components/chart/composite/interactions.ts +6 -0
- package/src/components/chart/composite/legend.tsx +45 -7
- package/src/components/chart/composite/levels.ts +2 -0
- package/src/components/chart/composite/panel-gestures.ts +33 -0
- package/src/components/chart/composite/panel-series.ts +1 -0
- package/src/components/chart/composite/panel-surface.tsx +61 -5
- package/src/components/chart/composite/range-statistics.ts +62 -0
- package/src/components/chart/composite/rasterizer.ts +24 -13
- package/src/components/chart/composite/scene.ts +46 -7
- package/src/components/chart/composite/series-axis-tags.tsx +16 -9
- package/src/components/chart/composite/series-cues.ts +14 -0
- package/src/components/chart/composite/text-renderer.ts +9 -2
- package/src/components/chart/composite/tool-catalog.ts +36 -0
- package/src/components/chart/composite/tools.ts +203 -44
- package/src/components/chart/composite/types.ts +4 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +11 -4
- package/src/components/command-bar/assist/inventory.ts +2 -1
- package/src/components/command-bar/commands/direct/index.ts +28 -13
- package/src/components/command-bar/pane-templates/items.ts +3 -2
- package/src/components/command-bar/panel/prompt-binding.ts +0 -8
- package/src/components/command-bar/workflow/alert.ts +1 -1
- package/src/components/command-bar/workflow/collection-actions.ts +3 -3
- package/src/components/layout/header.tsx +26 -40
- package/src/components/layout/pane/footer/index.tsx +1 -0
- package/src/components/layout/pane/footer/model.ts +27 -0
- package/src/components/onboarding/onboarding-frame.tsx +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +4 -1
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -9
- package/src/components/onboarding/wizard-broker-sync.ts +0 -1
- package/src/components/onboarding/wizard-positions.ts +3 -3
- package/src/components/ticker/list-table-view.tsx +4 -1
- package/src/components/ui/choice-dialog.tsx +23 -18
- package/src/components/ui/choice-groups.ts +18 -0
- package/src/components/ui/data-table/opentui/index.tsx +9 -7
- package/src/components/ui/data-table/opentui/model.ts +26 -1
- package/src/components/ui/data-table/types.ts +2 -0
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/list-view.tsx +8 -4
- package/src/components/ui/query-bar-keys.tsx +2 -0
- package/src/components/ui/query-bar.tsx +1 -0
- package/src/components/ui/select-button.tsx +5 -1
- package/src/components/ui/select-field.tsx +1 -0
- package/src/components/ui/table-layout.ts +8 -5
- package/src/core/app-runtime.ts +2 -0
- package/src/core/app-services.ts +2 -2
- package/src/core/state/app/layout.ts +2 -0
- package/src/core/state/app/state.ts +9 -0
- package/src/core/state/app/types.ts +3 -0
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/json-ticker-repository.ts +17 -8
- package/src/data/saved-copies.ts +55 -16
- package/src/data/ticker-repository.ts +16 -9
- package/src/data/ticker-writes.ts +81 -0
- package/src/data/ttl-cache.ts +165 -0
- package/src/docs/snapshot.json +427 -216
- package/src/i18n/es.ts +19 -3
- package/src/i18n/ja.ts +19 -3
- package/src/i18n/ko.ts +19 -3
- package/src/i18n/zh-cn.ts +19 -3
- package/src/i18n/zh-tw.ts +19 -3
- package/src/market-data/coordinator/financials.ts +10 -2
- package/src/market-data/coordinator/index.ts +3 -1
- package/src/market-data/coordinator/quotes.ts +4 -2
- package/src/market-data/depositary-pair.ts +2 -2
- package/src/market-data/fund-facts.ts +50 -0
- package/src/market-data/market/change-basis.ts +48 -7
- package/src/market-data/market/dated-previous-close.ts +203 -0
- package/src/market-data/market/format.ts +25 -0
- package/src/market-data/market/freshness.ts +2 -1
- package/src/market-data/market/futures-week.ts +68 -0
- package/src/market-data/market/status.ts +16 -4
- package/src/market-data/options-alternatives.ts +141 -4
- package/src/market-data/quotes/contributions.ts +20 -2
- package/src/market-data/quotes/resolution.ts +3 -0
- package/src/market-data/selectors.ts +3 -0
- package/src/news/aggregator.ts +113 -9
- package/src/news/cloud-session.ts +21 -0
- package/src/news/hooks.ts +1 -0
- package/src/news/news-model.ts +1 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/notification-log.ts +6 -4
- package/src/plugins/builtin/alerts/alert-engine.ts +25 -2
- package/src/plugins/builtin/alerts/alert-log.ts +33 -0
- package/src/plugins/builtin/alerts/calendar-events.ts +57 -6
- package/src/plugins/builtin/alerts/cli-forms.ts +216 -0
- package/src/plugins/builtin/alerts/cli.ts +380 -82
- package/src/plugins/builtin/alerts/command.ts +31 -0
- package/src/plugins/builtin/alerts/constants.ts +1 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +19 -4
- package/src/plugins/builtin/alerts/fired-log.ts +113 -8
- package/src/plugins/builtin/alerts/format.ts +80 -4
- package/src/plugins/builtin/alerts/headless.ts +30 -7
- package/src/plugins/builtin/alerts/history-rows.ts +7 -3
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +135 -22
- package/src/plugins/builtin/alerts/live.ts +3 -3
- package/src/plugins/builtin/alerts/metric-command.ts +134 -0
- package/src/plugins/builtin/alerts/metric-data.ts +111 -0
- package/src/plugins/builtin/alerts/metric-model.ts +324 -0
- package/src/plugins/builtin/alerts/metric-parity-fixture.json +725 -0
- package/src/plugins/builtin/alerts/pane.tsx +90 -39
- package/src/plugins/builtin/alerts/quotes.ts +6 -0
- package/src/plugins/builtin/alerts/storage.ts +37 -10
- package/src/plugins/builtin/alerts/types.ts +7 -0
- package/src/plugins/builtin/analytics/index.tsx +2 -1
- package/src/plugins/builtin/analytics/risk-client.ts +16 -5
- package/src/plugins/builtin/analytics/risk-fx.ts +70 -15
- package/src/plugins/builtin/analytics/risk-headless.ts +27 -0
- package/src/plugins/builtin/analytics/risk-model.ts +55 -9
- package/src/plugins/builtin/analytics/risk-pane.tsx +8 -2
- package/src/plugins/builtin/attention/index.tsx +2 -1
- package/src/plugins/builtin/attention/listing.ts +14 -0
- package/src/plugins/builtin/backtest/headless.ts +10 -5
- package/src/plugins/builtin/backtest/pane.tsx +9 -4
- package/src/plugins/builtin/backtest/presets.ts +29 -3
- package/src/plugins/builtin/broker-manager/index.tsx +10 -5
- package/src/plugins/builtin/broker-manager/model.ts +6 -1
- package/src/plugins/builtin/broker-trading/controller.ts +22 -12
- package/src/plugins/builtin/broker-trading/index.tsx +13 -1
- package/src/plugins/builtin/broker-trading/order-feed.ts +9 -4
- package/src/plugins/builtin/broker-trading/pane.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +12 -4
- package/src/plugins/builtin/buildout/format.ts +38 -0
- package/src/plugins/builtin/buildout/model/normalizers.ts +36 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +4 -1
- package/src/plugins/builtin/buildout/table-model.ts +23 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +7 -3
- package/src/plugins/builtin/catalysts/model.ts +2 -1
- package/src/plugins/builtin/changelog/index.tsx +9 -6
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +6 -1
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +1 -1
- package/src/plugins/builtin/chart-composer/cli-options.ts +9 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +12 -2
- package/src/plugins/builtin/chart-composer/editor/controller.ts +4 -2
- package/src/plugins/builtin/chart-composer/editor/model.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +7 -5
- package/src/plugins/builtin/chart-composer/formula.ts +71 -18
- package/src/plugins/builtin/chart-composer/headless-schema.ts +21 -4
- package/src/plugins/builtin/chart-composer/headless.ts +19 -3
- package/src/plugins/builtin/chart-composer/index.tsx +1 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +53 -9
- package/src/plugins/builtin/chart-composer/presets.ts +50 -15
- package/src/plugins/builtin/chart-composer/quick-add.tsx +40 -25
- package/src/plugins/builtin/chart-composer/session-history.ts +18 -9
- package/src/plugins/builtin/chart-composer/settings.ts +27 -0
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +40 -26
- package/src/plugins/builtin/chat/content/command-suggestions.ts +93 -0
- package/src/plugins/builtin/chat/content/composer.tsx +13 -6
- package/src/plugins/builtin/chat/content/footer.tsx +6 -3
- package/src/plugins/builtin/chat/content/index.tsx +50 -21
- package/src/plugins/builtin/chat/content/open-targets.ts +14 -3
- package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -2
- package/src/plugins/builtin/chat/index.tsx +23 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +1 -0
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +23 -0
- package/src/plugins/builtin/chat/message/pane-chip.tsx +50 -20
- package/src/plugins/builtin/chat/pane-links/commands.ts +271 -0
- package/src/plugins/builtin/chat/pane-links/model.ts +12 -3
- package/src/plugins/builtin/chat/pane-links/open.ts +8 -1
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +10 -1
- package/src/plugins/builtin/clinical-trials/model.ts +0 -9
- package/src/plugins/builtin/clinical-trials/pane.tsx +15 -22
- package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +8 -6
- package/src/plugins/builtin/cloud/askg/manifest.ts +2 -0
- package/src/plugins/builtin/cloud/plugin.tsx +1 -1
- package/src/plugins/builtin/company-attention/building.tsx +5 -1
- package/src/plugins/builtin/company-attention/client.ts +8 -9
- package/src/plugins/builtin/company-attention/evidence.ts +4 -1
- package/src/plugins/builtin/company-attention/moves.tsx +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +9 -2
- package/src/plugins/builtin/company-attention/signals.tsx +5 -1
- package/src/plugins/builtin/correlation/headless.ts +13 -5
- package/src/plugins/builtin/correlation/history.ts +22 -0
- package/src/plugins/builtin/cot/client.ts +22 -18
- package/src/plugins/builtin/cot/headless.ts +15 -10
- package/src/plugins/builtin/cot/model.ts +14 -1
- package/src/plugins/builtin/cot/pane.tsx +22 -14
- package/src/plugins/builtin/credit-boards/client.ts +6 -10
- package/src/plugins/builtin/credit-conditions/headless.ts +8 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +5 -1
- package/src/plugins/builtin/credit-conditions/model.ts +4 -0
- package/src/plugins/builtin/credit-conditions/series.ts +3 -1
- package/src/plugins/builtin/credit-documents/detail.tsx +2 -2
- package/src/plugins/builtin/credit-documents/export.ts +173 -0
- package/src/plugins/builtin/credit-documents/headless.ts +7 -7
- package/src/plugins/builtin/credit-documents/model.ts +104 -14
- package/src/plugins/builtin/credit-documents/pane.tsx +12 -5
- package/src/plugins/builtin/custom-view/sources.ts +2 -0
- package/src/plugins/builtin/dividend-yield/client.ts +131 -23
- package/src/plugins/builtin/dividend-yield/headless.ts +44 -16
- package/src/plugins/builtin/dividend-yield/model.ts +8 -5
- package/src/plugins/builtin/dividend-yield/pane.tsx +38 -13
- package/src/plugins/builtin/dividend-yield/ranking.ts +37 -14
- package/src/plugins/builtin/dividend-yield/types.ts +20 -2
- package/src/plugins/builtin/dividend-yield/view.ts +30 -2
- package/src/plugins/builtin/docs/targets.ts +5 -1
- package/src/plugins/builtin/earnings/board-model.ts +16 -15
- package/src/plugins/builtin/earnings/board.tsx +62 -71
- package/src/plugins/builtin/earnings/headless.ts +40 -4
- package/src/plugins/builtin/earnings/scope.ts +31 -43
- package/src/plugins/builtin/earnings-calls/calendar.tsx +2 -2
- package/src/plugins/builtin/earnings-calls/format.ts +31 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +7 -2
- package/src/plugins/builtin/earnings-calls/model.ts +6 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +5 -4
- package/src/plugins/builtin/econ/calendar-model.ts +14 -9
- package/src/plugins/builtin/econ/figures.ts +72 -0
- package/src/plugins/builtin/econ/index.tsx +33 -3
- package/src/plugins/builtin/econ/types.ts +4 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +6 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +85 -35
- package/src/plugins/builtin/econ-statistics/stats.ts +37 -9
- package/src/plugins/builtin/econ-statistics/view.ts +3 -0
- package/src/plugins/builtin/equity-screener/categories.ts +179 -0
- package/src/plugins/builtin/equity-screener/client.ts +4 -2
- package/src/plugins/builtin/equity-screener/headless.ts +144 -13
- package/src/plugins/builtin/equity-screener/ideas.ts +49 -0
- package/src/plugins/builtin/equity-screener/model.ts +99 -10
- package/src/plugins/builtin/equity-screener/pane.tsx +70 -15
- package/src/plugins/builtin/exposure/charts.tsx +2 -2
- package/src/plugins/builtin/exposure/model.ts +13 -1
- package/src/plugins/builtin/exposure/pane.tsx +4 -4
- package/src/plugins/builtin/fixed-income/pane.tsx +2 -1
- package/src/plugins/builtin/futures/index.tsx +1 -0
- package/src/plugins/builtin/futures/model.ts +2 -1
- package/src/plugins/builtin/futures/table.tsx +2 -2
- package/src/plugins/builtin/futures/use-board-terms.ts +42 -28
- package/src/plugins/builtin/futures/use-front-returns.ts +45 -28
- package/src/plugins/builtin/fx-matrix/client.ts +11 -3
- package/src/plugins/builtin/fx-matrix/headless.ts +6 -3
- package/src/plugins/builtin/fx-matrix/index.tsx +16 -4
- package/src/plugins/builtin/fx-matrix/live-legs.ts +54 -3
- package/src/plugins/builtin/gpu/headless.ts +8 -2
- package/src/plugins/builtin/help/function-index.ts +4 -1
- package/src/plugins/builtin/help/index.tsx +1 -0
- package/src/plugins/builtin/help/keybindings-editor.tsx +18 -14
- package/src/plugins/builtin/help/shortcut-model.ts +1 -1
- package/src/plugins/builtin/holders/fund-holders.ts +51 -0
- package/src/plugins/builtin/holders/headless.ts +18 -1
- package/src/plugins/builtin/iv-history/client.ts +52 -11
- package/src/plugins/builtin/iv-history/format.ts +36 -23
- package/src/plugins/builtin/iv-history/headless.ts +36 -18
- package/src/plugins/builtin/iv-history/index.tsx +2 -2
- package/src/plugins/builtin/iv-history/model.ts +163 -27
- package/src/plugins/builtin/iv-history/pane.tsx +10 -6
- package/src/plugins/builtin/iv-history/screen-pane.tsx +22 -15
- package/src/plugins/builtin/iv-history/universe.ts +5 -1
- package/src/plugins/builtin/jobs/client.ts +25 -29
- package/src/plugins/builtin/kelly-sizer/model.ts +12 -8
- package/src/plugins/builtin/kelly-sizer/pane.tsx +9 -9
- package/src/plugins/builtin/kelly-sizer/sections.tsx +19 -10
- package/src/plugins/builtin/kelly-sizer/types.ts +10 -4
- package/src/plugins/builtin/macro-day/pane.tsx +7 -5
- package/src/plugins/builtin/macro-day/release-table.ts +2 -2
- package/src/plugins/builtin/market-heatmap/data.ts +8 -33
- package/src/plugins/builtin/market-movers/client.ts +25 -7
- package/src/plugins/builtin/market-movers/footer.ts +2 -2
- package/src/plugins/builtin/market-movers/headless.ts +32 -12
- package/src/plugins/builtin/market-movers/index.tsx +26 -14
- package/src/plugins/builtin/market-movers/min-float.ts +74 -0
- package/src/plugins/builtin/market-movers/model.ts +4 -1
- package/src/plugins/builtin/market-movers/screener.ts +14 -0
- package/src/plugins/builtin/market-movers/session-body.tsx +13 -8
- package/src/plugins/builtin/market-movers/session-table.ts +4 -3
- package/src/plugins/builtin/market-movers/table.ts +17 -5
- package/src/plugins/builtin/members/breadth-pane.tsx +82 -0
- package/src/plugins/builtin/members/client.ts +19 -4
- package/src/plugins/builtin/members/headless.ts +20 -7
- package/src/plugins/builtin/members/index.tsx +9 -9
- package/src/plugins/builtin/members/model.ts +23 -4
- package/src/plugins/builtin/members/pane.tsx +25 -15
- package/src/plugins/builtin/news/index.tsx +1 -0
- package/src/plugins/builtin/news/wire/categories.ts +19 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +1 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +31 -5
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +6 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +2 -2
- package/src/plugins/builtin/openfda/client.ts +14 -2
- package/src/plugins/builtin/openfda/index.tsx +3 -2
- package/src/plugins/builtin/openfda/model.ts +9 -0
- package/src/plugins/builtin/openfda/pane.tsx +42 -6
- package/src/plugins/builtin/options/analytics.ts +54 -6
- package/src/plugins/builtin/options/enrichment.ts +17 -5
- package/src/plugins/builtin/options/model-spot.ts +5 -2
- package/src/plugins/builtin/options/strike-window.ts +2 -1
- package/src/plugins/builtin/options/table.ts +6 -9
- package/src/plugins/builtin/options/types.ts +2 -0
- package/src/plugins/builtin/options/view.tsx +42 -12
- package/src/plugins/builtin/options-positioning/client.ts +30 -0
- package/src/plugins/builtin/options-positioning/headless.ts +74 -21
- package/src/plugins/builtin/options-positioning/index.tsx +4 -4
- package/src/plugins/builtin/options-positioning/model.ts +122 -14
- package/src/plugins/builtin/options-positioning/pane.tsx +87 -42
- package/src/plugins/builtin/options-scenario/client.ts +116 -47
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +142 -10
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +206 -55
- package/src/plugins/builtin/options-scenario/csp-screen.ts +63 -23
- package/src/plugins/builtin/options-scenario/csp.ts +8 -2
- package/src/plugins/builtin/options-scenario/index.tsx +9 -7
- package/src/plugins/builtin/options-scenario/strategy-screen.ts +532 -0
- package/src/plugins/builtin/pe-band/model.ts +12 -49
- package/src/plugins/builtin/perps/cascade-tabs.tsx +161 -0
- package/src/plugins/builtin/perps/cascade.ts +236 -0
- package/src/plugins/builtin/perps/client.ts +56 -2
- package/src/plugins/builtin/perps/freshness.ts +12 -10
- package/src/plugins/builtin/perps/headless.ts +65 -9
- package/src/plugins/builtin/perps/index.tsx +7 -5
- package/src/plugins/builtin/perps/live-rows.ts +10 -3
- package/src/plugins/builtin/perps/model.ts +18 -4
- package/src/plugins/builtin/perps/pane.tsx +32 -31
- package/src/plugins/builtin/perps/status-line.ts +25 -0
- package/src/plugins/builtin/plugin-module.ts +5 -1
- package/src/plugins/builtin/portfolio-list/cached-account.ts +3 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +2 -8
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +4 -4
- package/src/plugins/builtin/portfolio-list/cli/render.ts +12 -7
- package/src/plugins/builtin/portfolio-list/headless.ts +1 -1
- package/src/plugins/builtin/portfolio-list/pane/futures-front.ts +40 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +4 -1
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +5 -2
- package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +3 -2
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +3 -1
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +11 -8
- package/src/plugins/builtin/portfolio-list/table.tsx +11 -3
- package/src/plugins/builtin/primary-dealers/client.ts +13 -38
- package/src/plugins/builtin/rate-path/pane.tsx +2 -2
- package/src/plugins/builtin/realized-vol/index.tsx +2 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/client.ts +18 -4
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +2 -1
- package/src/plugins/builtin/relative-rotation/model.ts +16 -40
- package/src/plugins/builtin/relative-rotation/pane.tsx +3 -2
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -2
- package/src/plugins/builtin/research/event-model.ts +10 -8
- package/src/plugins/builtin/research/headless.ts +1 -1
- package/src/plugins/builtin/research/relative-valuation-headless.ts +5 -1
- package/src/plugins/builtin/research/relative-valuation-model.ts +31 -3
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +11 -9
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -3
- package/src/plugins/builtin/reverse-dcf/model.ts +61 -6
- package/src/plugins/builtin/reverse-dcf/pane.tsx +7 -4
- package/src/plugins/builtin/scanner/feed.ts +2 -2
- package/src/plugins/builtin/scanner/flow-model.ts +50 -4
- package/src/plugins/builtin/scanner/flow-pane.tsx +367 -65
- package/src/plugins/builtin/scanner/flow-session.ts +146 -0
- package/src/plugins/builtin/scanner/headless.ts +204 -35
- package/src/plugins/builtin/scanner/index.ts +40 -6
- package/src/plugins/builtin/scanner/live-condition-editor.tsx +222 -0
- package/src/plugins/builtin/scanner/live-feed.ts +168 -0
- package/src/plugins/builtin/scanner/live-headless.ts +138 -0
- package/src/plugins/builtin/scanner/live-model.ts +362 -0
- package/src/plugins/builtin/scanner/live-pane.tsx +677 -0
- package/src/plugins/builtin/scanner/live-track.ts +186 -0
- package/src/plugins/builtin/scanner/lock-note.ts +3 -2
- package/src/plugins/builtin/seasonality/headless.ts +10 -1
- package/src/plugins/builtin/sec/fund-facts-view.tsx +5 -2
- package/src/plugins/builtin/sec/fund-facts.ts +116 -34
- package/src/plugins/builtin/sec/headless.ts +2 -1
- package/src/plugins/builtin/series-inventory.ts +3 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +3 -2
- package/src/plugins/builtin/shared/cloud-upgrade.ts +4 -3
- package/src/plugins/builtin/shared/earnings-calendar.ts +6 -2
- package/src/plugins/builtin/shared/earnings-report.ts +2 -2
- package/src/plugins/builtin/shared/job-posting.ts +1 -0
- package/src/plugins/builtin/shared/macro-releases.ts +65 -0
- package/src/plugins/builtin/shared/members-menu.tsx +3 -2
- package/src/plugins/builtin/shared/pro-lock-note.ts +12 -12
- package/src/plugins/builtin/shared/report-freshness.ts +3 -2
- package/src/plugins/builtin/shared/scanner-capture.ts +3 -0
- package/src/plugins/builtin/shared/ticker-choice.tsx +2 -1
- package/src/plugins/builtin/shared/ticker-company.ts +77 -0
- package/src/plugins/builtin/shared/use-quote-board.ts +10 -3
- package/src/plugins/builtin/shared/volatility/live-session.ts +34 -8
- package/src/plugins/builtin/shared/volatility/pricing.ts +26 -1
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +3 -1
- package/src/plugins/builtin/themes/headless.ts +6 -4
- package/src/plugins/builtin/themes/model.ts +17 -8
- package/src/plugins/builtin/themes/pane.tsx +7 -7
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +43 -18
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +3 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +62 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +83 -46
- package/src/plugins/builtin/ticker-detail/headless.ts +31 -16
- package/src/plugins/builtin/ticker-detail/overview/model.ts +1 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +3 -2
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +6 -1
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/settings.ts +1 -0
- package/src/plugins/builtin/time-sales/pane.tsx +31 -19
- package/src/plugins/builtin/treasury-daily/client.ts +41 -5
- package/src/plugins/builtin/treasury-daily/headless.ts +2 -2
- package/src/plugins/builtin/treasury-daily/index.tsx +1 -1
- package/src/plugins/builtin/treasury-daily/model.ts +50 -3
- package/src/plugins/builtin/treasury-daily/pane.tsx +81 -2
- package/src/plugins/builtin/vol-surface/charts.tsx +9 -4
- package/src/plugins/builtin/vol-surface/client.ts +9 -17
- package/src/plugins/builtin/vol-surface/headless.ts +63 -14
- package/src/plugins/builtin/vol-surface/index.tsx +2 -2
- package/src/plugins/builtin/vol-surface/model.ts +22 -7
- package/src/plugins/builtin/vol-surface/pane.tsx +48 -9
- package/src/plugins/builtin/vol-surface/tables.ts +31 -3
- package/src/plugins/builtin/volatility/dvol.ts +46 -0
- package/src/plugins/builtin/volatility/index.tsx +2 -2
- package/src/plugins/builtin/volatility/pane.tsx +4 -4
- package/src/plugins/builtin/volatility/series.ts +26 -0
- package/src/plugins/builtin/world-indices/footer.ts +1 -1
- package/src/plugins/builtin/world-venue-map/headless.ts +3 -3
- package/src/plugins/catalog-browser.ts +13 -8
- package/src/plugins/catalog-manifest.ts +2 -1
- package/src/plugins/marketplace/model.ts +18 -5
- package/src/portfolio/column-values.ts +5 -5
- package/src/portfolio/futures-positions.ts +6 -3
- package/src/portfolio/position-quantity.ts +15 -9
- package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
- package/src/remote/resources.ts +2 -1
- package/src/renderers/browser/app-services.ts +1 -7
- package/src/renderers/browser/config-host.ts +2 -55
- package/src/renderers/browser/main.tsx +7 -57
- package/src/renderers/dom/data-table/row.tsx +26 -0
- package/src/renderers/dom/desktop/list-view.tsx +13 -10
- package/src/renderers/dom/desktop/query-bar.tsx +4 -2
- package/src/renderers/dom/desktop/select-field.tsx +4 -2
- package/src/renderers/dom/host/chart-surface.tsx +21 -0
- package/src/renderers/electrobun/bun/desktop/app-name.ts +222 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +29 -7
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/relaunch.ts +74 -25
- package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +173 -5
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +52 -0
- package/src/renderers/electrobun/bun/desktop/workspace/index.ts +2 -0
- package/src/renderers/electrobun/bun/index.ts +25 -1
- package/src/renderers/electrobun/shared/app-name.ts +30 -0
- package/src/renderers/electrobun/shared/protocol.ts +10 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +6 -0
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +1 -0
- package/src/renderers/electrobun/view/main.tsx +24 -1
- package/src/renderers/electrobun/view/news-source.ts +3 -1
- package/src/renderers/electrobun/view/remote/ticker-repository.ts +14 -7
- package/src/renderers/electrobun/view/view-ids.ts +85 -0
- package/src/renderers/opentui/start.tsx +5 -0
- package/src/renderers/opentui/toast-host.tsx +71 -43
- package/src/series/registry.ts +1 -0
- package/src/series/types.ts +6 -0
- package/src/series/validate.ts +1 -0
- package/src/sources/gloomberb-cloud/index.ts +1 -0
- package/src/sources/gloomberb-cloud/news.ts +47 -7
- package/src/sources/gloomberb-cloud/normalizers.ts +2 -0
- package/src/sources/provider-router/batches.ts +10 -2
- package/src/sources/provider-router/financial-routes.ts +3 -3
- package/src/sources/provider-router/financials.ts +15 -3
- package/src/sources/provider-router/history.ts +28 -7
- package/src/sources/provider-router/index.ts +149 -10
- package/src/sources/provider-router/search.ts +13 -2
- package/src/state/app/context/index.tsx +3 -0
- package/src/state/ticker-cleanup.ts +50 -0
- package/src/sync/auth-transition.ts +19 -9
- package/src/sync/baseline.ts +10 -4
- package/src/sync/controller.ts +70 -19
- package/src/sync/core-contributors.ts +90 -31
- package/src/sync/react.ts +4 -1
- package/src/sync/types.ts +3 -0
- package/src/telemetry/stall-reports-dom.ts +38 -0
- package/src/telemetry/stall-reports-node.ts +75 -0
- package/src/telemetry/stall-reports.ts +214 -0
- package/src/telemetry/usage-counts.ts +0 -18
- package/src/test-support/preload.ts +14 -0
- package/src/theme/colors.ts +8 -0
- package/src/theme/themes.ts +10 -0
- package/src/tickers/company-name.ts +103 -3
- package/src/tickers/listing-venues.ts +38 -3
- package/src/tickers/search/bare-symbol.ts +36 -0
- package/src/tickers/search/index.ts +36 -7
- package/src/tickers/search/ranking.ts +10 -1
- package/src/tickers/search/types.ts +5 -0
- package/src/tickers/terminal-codes.ts +19 -0
- package/src/time-series/alignment.ts +1 -1
- package/src/time-series/base-series.ts +13 -5
- package/src/time-series/daily-valuation.ts +62 -0
- package/src/time-series/economic.ts +18 -4
- package/src/time-series/field-catalog.ts +2 -4
- package/src/time-series/filed-trailing-eps.ts +197 -0
- package/src/time-series/forward-valuation.ts +32 -0
- package/src/time-series/fundamentals.ts +198 -7
- package/src/time-series/hooks.ts +1 -0
- package/src/time-series/ice-credit.ts +3 -0
- package/src/time-series/price-comparison.ts +30 -2
- package/src/time-series/price-units.ts +72 -2
- package/src/time-series/resolve-context.ts +7 -1
- package/src/time-series/resolve.ts +116 -15
- package/src/time-series/series-presentation.ts +40 -6
- package/src/time-series/session-bar.ts +11 -0
- package/src/time-series/spec.ts +5 -3
- package/src/time-series/studies.ts +278 -74
- package/src/time-series/total-return.ts +160 -0
- package/src/time-series/transforms.ts +3 -3
- package/src/time-series/types.ts +27 -1
- package/src/time-series/valuation-releases.ts +39 -0
- package/src/types/data-provider.ts +9 -1
- package/src/types/desktop-window.ts +2 -0
- package/src/types/financials.ts +73 -2
- package/src/types/headless.ts +61 -5
- package/src/types/instrument.ts +3 -0
- package/src/types/news-source.ts +1 -0
- package/src/types/plugin.ts +10 -1
- package/src/ui/host.tsx +3 -0
- package/src/updater/command-names.ts +12 -7
- package/src/updater/failure.ts +4 -1
- package/src/utils/cli-output.ts +42 -1
- package/src/utils/crypto-pair.ts +44 -0
- package/src/utils/financial-statements.ts +6 -1
- package/src/utils/forward-dividend.ts +2 -0
- package/src/utils/fundamentals.ts +24 -3
- package/src/utils/fx-market-hours.ts +26 -3
- package/src/utils/main-thread-stall.ts +35 -2
- package/src/utils/market-capitalization.ts +24 -1
- package/src/utils/network-failure.ts +9 -6
- package/src/utils/option-expiry.ts +48 -1
- package/src/utils/options.ts +10 -0
- package/src/utils/plugin-proxy-hosts.json +1 -0
- package/src/utils/price-history.ts +12 -1
- package/src/utils/shell-word.ts +8 -0
- package/src/utils/trailing-dividend.ts +53 -4
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +0 -17
- package/src/renderers/browser/first-screen.ts +0 -193
package/src/api-client/index.ts
CHANGED
|
@@ -67,6 +67,8 @@ export const ASSIST_ARG_OPTION_LIMIT = 128;
|
|
|
67
67
|
const ASSIST_ARG_OPTION_VALUE_MAX_LENGTH = 40;
|
|
68
68
|
const ASSIST_ARG_OPTION_LABEL_MAX_LENGTH = 60;
|
|
69
69
|
const ASSIST_REQUEST_TIMEOUT_MS = 6_000;
|
|
70
|
+
const SESSION_REVALIDATION_INITIAL_MS = 1_000;
|
|
71
|
+
const SESSION_REVALIDATION_MAX_MS = 30_000;
|
|
70
72
|
|
|
71
73
|
/**
|
|
72
74
|
* Fits a command's argument values inside the server caps. The value is what
|
|
@@ -94,8 +96,15 @@ interface PendingSessionRequest {
|
|
|
94
96
|
|
|
95
97
|
class GloomApiClient {
|
|
96
98
|
private currentUser: AuthUser | null = null;
|
|
97
|
-
/** Local
|
|
99
|
+
/** Local user/credential binding, masked until verified and never serialized. */
|
|
98
100
|
private verifiedSessionIdentity: object | null = null;
|
|
101
|
+
private verifiedSessionCredential: string | null = null;
|
|
102
|
+
private sessionTransitions = 0;
|
|
103
|
+
private sessionTransition: Promise<void> | null = null;
|
|
104
|
+
/** Device adoption and external session installs supersede pending email auth. */
|
|
105
|
+
private sessionInstallationGeneration = 0;
|
|
106
|
+
private sessionRevalidationGeneration = 0;
|
|
107
|
+
private sessionRevalidationTimer: ReturnType<typeof setTimeout> | null = null;
|
|
99
108
|
private sessionChecked = false;
|
|
100
109
|
/** Last few session transitions, content-free, for app://auth. */
|
|
101
110
|
private authTrace: Array<{ at: number; event: string; token: boolean; user: string }> = [];
|
|
@@ -110,7 +119,7 @@ class GloomApiClient {
|
|
|
110
119
|
request: (path, options, canApplySession) => this.request(path, options, canApplySession),
|
|
111
120
|
requireCapturedSession: (message) => this.requireCapturedSession(message),
|
|
112
121
|
setCurrentUser: (user) => this.setCurrentUser(user),
|
|
113
|
-
setSessionToken: (token) => this.
|
|
122
|
+
setSessionToken: (token) => this.installSessionToken(token),
|
|
114
123
|
updateCurrentUser: (updater) => this.updateCurrentUser(updater),
|
|
115
124
|
});
|
|
116
125
|
private readonly socket: CloudApiSocket = new CloudApiSocket({
|
|
@@ -123,7 +132,6 @@ class GloomApiClient {
|
|
|
123
132
|
markCurrentUserUnverified: () => {
|
|
124
133
|
if (this.currentUser) {
|
|
125
134
|
this.currentUser = { ...this.currentUser, emailVerified: false };
|
|
126
|
-
this.verifiedSessionIdentity = null;
|
|
127
135
|
this.emitCurrentUserChange();
|
|
128
136
|
}
|
|
129
137
|
},
|
|
@@ -165,6 +173,8 @@ class GloomApiClient {
|
|
|
165
173
|
}
|
|
166
174
|
|
|
167
175
|
setCookieSessionMode(enabled: boolean): void {
|
|
176
|
+
this.cancelSessionRevalidation();
|
|
177
|
+
this.sessionInstallationGeneration += 1;
|
|
168
178
|
this.sessionChecked = false;
|
|
169
179
|
this.verifiedSessionIdentity = null;
|
|
170
180
|
this.transport.setCookieSessionMode(enabled);
|
|
@@ -172,12 +182,21 @@ class GloomApiClient {
|
|
|
172
182
|
}
|
|
173
183
|
|
|
174
184
|
setSessionToken(token: string | null): void {
|
|
185
|
+
if (this.transport.getSessionToken() !== token || !token) {
|
|
186
|
+
this.cancelSessionRevalidation();
|
|
187
|
+
this.sessionInstallationGeneration += 1;
|
|
188
|
+
}
|
|
189
|
+
this.installSessionToken(token);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private installSessionToken(token: string | null): void {
|
|
175
193
|
const changed = this.transport.getSessionToken() !== token;
|
|
176
194
|
this.sessionChecked = false;
|
|
177
195
|
this.transport.setSessionToken(token);
|
|
178
196
|
if (changed) this.verifiedSessionIdentity = null;
|
|
179
197
|
this.traceAuth(changed ? "setSessionToken:changed" : "setSessionToken:same");
|
|
180
198
|
if (!token) {
|
|
199
|
+
this.cancelSessionRevalidation();
|
|
181
200
|
this.currentUser = null;
|
|
182
201
|
this.verifiedSessionIdentity = null;
|
|
183
202
|
}
|
|
@@ -206,6 +225,14 @@ class GloomApiClient {
|
|
|
206
225
|
return !!this.transport.getSessionToken() || !!this.currentUser;
|
|
207
226
|
}
|
|
208
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Whether a request sent now carries a session: the token this client
|
|
230
|
+
* holds, or, in the browser, the cookie it cannot see and assumes is there.
|
|
231
|
+
*/
|
|
232
|
+
hasSessionCredential(): boolean {
|
|
233
|
+
return this.transport.hasSessionCredential();
|
|
234
|
+
}
|
|
235
|
+
|
|
209
236
|
/** Notifies when the user or credential changes, including plan and trial entitlement. */
|
|
210
237
|
subscribeCurrentUser(listener: () => void): () => void {
|
|
211
238
|
this.currentUserListeners.add(listener);
|
|
@@ -224,7 +251,9 @@ class GloomApiClient {
|
|
|
224
251
|
|
|
225
252
|
/** Null while a replacement credential still awaits its matching user. */
|
|
226
253
|
getVerifiedSessionIdentity(): object | null {
|
|
227
|
-
return this.
|
|
254
|
+
return this.sessionTransitions === 0 && this.isVerified()
|
|
255
|
+
&& this.verifiedSessionCredential === this.transport.getSessionToken()
|
|
256
|
+
? this.verifiedSessionIdentity : null;
|
|
228
257
|
}
|
|
229
258
|
|
|
230
259
|
/**
|
|
@@ -276,11 +305,18 @@ class GloomApiClient {
|
|
|
276
305
|
if (this.authTrace.length > 24) this.authTrace.shift();
|
|
277
306
|
}
|
|
278
307
|
|
|
279
|
-
private setCurrentUser(user: AuthUser | null): void {
|
|
308
|
+
private setCurrentUser(user: AuthUser | null, confirmSession = true): void {
|
|
309
|
+
const sameAccount = this.currentUser?.id === user?.id;
|
|
280
310
|
const changed = this.socketEntitlementKey(this.currentUser) !== this.socketEntitlementKey(user);
|
|
281
311
|
this.traceAuth("setCurrentUser", user);
|
|
282
312
|
this.currentUser = user;
|
|
283
|
-
|
|
313
|
+
if (confirmSession) {
|
|
314
|
+
this.clearSessionRevalidationTimer();
|
|
315
|
+
this.verifiedSessionIdentity = user ? {} : null;
|
|
316
|
+
this.verifiedSessionCredential = this.transport.getSessionToken();
|
|
317
|
+
} else if (!sameAccount || !user) {
|
|
318
|
+
this.verifiedSessionIdentity = null;
|
|
319
|
+
}
|
|
284
320
|
this.socket.syncAuthState({ reconnect: changed });
|
|
285
321
|
this.emitCurrentUserChange();
|
|
286
322
|
}
|
|
@@ -291,7 +327,9 @@ class GloomApiClient {
|
|
|
291
327
|
|
|
292
328
|
private updateCurrentUser(updater: (user: AuthUser) => AuthUser): void {
|
|
293
329
|
if (!this.currentUser) return;
|
|
294
|
-
|
|
330
|
+
// A socket/profile update is metadata, not proof that a replacement
|
|
331
|
+
// credential belongs to this user. Keep its existing binding, even null.
|
|
332
|
+
this.setCurrentUser(updater(this.currentUser), false);
|
|
295
333
|
}
|
|
296
334
|
|
|
297
335
|
private socketEntitlementKey(user: AuthUser | null): string {
|
|
@@ -326,11 +364,123 @@ class GloomApiClient {
|
|
|
326
364
|
return this.currentUser?.emailVerified ? this.currentUser : null;
|
|
327
365
|
}
|
|
328
366
|
|
|
329
|
-
signUp =
|
|
330
|
-
|
|
367
|
+
signUp = (email: string, username: string, name: string, password: string) =>
|
|
368
|
+
this.withSessionTransition((isCurrent) => this.auth.signUp(email, username, name, password, isCurrent));
|
|
369
|
+
signIn = (email: string, password: string) =>
|
|
370
|
+
this.withSessionTransition((isCurrent) => this.auth.signIn(email, password, isCurrent));
|
|
331
371
|
startDeviceSignIn = this.auth.startDeviceSignIn.bind(this.auth);
|
|
332
372
|
pollDeviceSignIn = this.auth.pollDeviceSignIn.bind(this.auth);
|
|
333
|
-
signOut = this.auth.signOut
|
|
373
|
+
signOut = () => this.withSessionTransition((isCurrent) => this.auth.signOut(isCurrent), false);
|
|
374
|
+
|
|
375
|
+
/** Cookies can change before an auth response's body arrives, including ones the browser hides. */
|
|
376
|
+
private withSessionTransition<T>(run: (isCurrent: () => boolean) => Promise<T>, reconcileFailure = true): Promise<T> {
|
|
377
|
+
const previous = this.sessionTransition;
|
|
378
|
+
this.cancelSessionRevalidation();
|
|
379
|
+
let revalidationGeneration = this.sessionRevalidationGeneration;
|
|
380
|
+
const generation = this.sessionInstallationGeneration;
|
|
381
|
+
const isCurrent = () => generation === this.sessionInstallationGeneration;
|
|
382
|
+
this.sessionTransitions += 1;
|
|
383
|
+
this.sessionChecked = false;
|
|
384
|
+
this.verifiedSessionIdentity = null;
|
|
385
|
+
this.sessionRequestGeneration += 1;
|
|
386
|
+
this.emitCurrentUserChange();
|
|
387
|
+
let needsRevalidation = false;
|
|
388
|
+
const operation = (async () => {
|
|
389
|
+
// Serialize credential-changing requests so a late response cannot pair
|
|
390
|
+
// one account's user with another request's installed cookie.
|
|
391
|
+
if (previous) await previous;
|
|
392
|
+
try {
|
|
393
|
+
if (!isCurrent()) throw new Error("Another sign-in replaced this request.");
|
|
394
|
+
// An earlier queued sign-out may have retired retries while clearing its token.
|
|
395
|
+
revalidationGeneration = this.sessionRevalidationGeneration;
|
|
396
|
+
this.sessionRequestGeneration += 1;
|
|
397
|
+
const result = await run(isCurrent);
|
|
398
|
+
if (!isCurrent()) throw new Error("Another sign-in replaced this request.");
|
|
399
|
+
return result;
|
|
400
|
+
} catch (error) {
|
|
401
|
+
if (isCurrent()) {
|
|
402
|
+
this.verifiedSessionIdentity = null;
|
|
403
|
+
this.sessionChecked = false;
|
|
404
|
+
}
|
|
405
|
+
if (isCurrent() && reconcileFailure && this.transport.hasSessionCredential()) {
|
|
406
|
+
// A failed body may already have changed the cookie. A fresh session
|
|
407
|
+
// check is the only way to resume; retry if it cannot validate yet.
|
|
408
|
+
needsRevalidation = true;
|
|
409
|
+
this.sessionRequestGeneration += 1;
|
|
410
|
+
await this.revalidateSession(() => isCurrent()
|
|
411
|
+
&& revalidationGeneration === this.sessionRevalidationGeneration).catch((failure) => {
|
|
412
|
+
if (!isCurrent()) return;
|
|
413
|
+
this.verifiedSessionIdentity = null;
|
|
414
|
+
logFailure("cloud.auth", "Restore session after failed sign-in failed")(failure);
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
throw error;
|
|
418
|
+
} finally {
|
|
419
|
+
if (isCurrent()) this.sessionRequestGeneration += 1;
|
|
420
|
+
this.sessionTransitions -= 1;
|
|
421
|
+
if (isCurrent() && needsRevalidation) this.scheduleSessionRevalidation(revalidationGeneration);
|
|
422
|
+
this.emitCurrentUserChange();
|
|
423
|
+
}
|
|
424
|
+
})();
|
|
425
|
+
const settled = operation.then(() => {}, () => {
|
|
426
|
+
// Intentional ignore: the caller receives the error while the auth queue continues.
|
|
427
|
+
});
|
|
428
|
+
this.sessionTransition = settled;
|
|
429
|
+
void settled.then(() => { if (this.sessionTransition === settled) this.sessionTransition = null; });
|
|
430
|
+
return operation;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
private clearSessionRevalidationTimer(): void {
|
|
434
|
+
if (this.sessionRevalidationTimer !== null) clearTimeout(this.sessionRevalidationTimer);
|
|
435
|
+
this.sessionRevalidationTimer = null;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
private cancelSessionRevalidation(): void {
|
|
439
|
+
this.sessionRevalidationGeneration += 1;
|
|
440
|
+
this.clearSessionRevalidationTimer();
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/** A failed auth response can replace a cookie even when its recovery read is offline. */
|
|
444
|
+
private scheduleSessionRevalidation(generation: number, delay = SESSION_REVALIDATION_INITIAL_MS): void {
|
|
445
|
+
const isCurrent = () => generation === this.sessionRevalidationGeneration;
|
|
446
|
+
const needsRevalidation = () => isCurrent() && this.sessionTransitions === 0
|
|
447
|
+
&& !this.sessionChecked && this.verifiedSessionIdentity === null && this.transport.hasSessionCredential();
|
|
448
|
+
if (!needsRevalidation() || this.sessionRevalidationTimer !== null) return;
|
|
449
|
+
this.sessionRevalidationTimer = setTimeout(() => {
|
|
450
|
+
this.sessionRevalidationTimer = null;
|
|
451
|
+
if (!needsRevalidation()) return;
|
|
452
|
+
void this.revalidateSession(isCurrent).catch((error) => {
|
|
453
|
+
if (isCurrent()) logFailure("cloud.auth", "Retry session validation failed")(error);
|
|
454
|
+
}).finally(() => {
|
|
455
|
+
this.scheduleSessionRevalidation(generation, Math.min(delay * 2, SESSION_REVALIDATION_MAX_MS));
|
|
456
|
+
});
|
|
457
|
+
}, delay);
|
|
458
|
+
this.sessionRevalidationTimer.unref?.();
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
private async revalidateSession(isCurrent: () => boolean): Promise<void> {
|
|
462
|
+
const user = await this.getSession(isCurrent);
|
|
463
|
+
const credential = this.getSessionToken();
|
|
464
|
+
if (user || !credential || !isCurrent()) return;
|
|
465
|
+
// A native null-session response can retain a usable token. Validate it
|
|
466
|
+
// through the account endpoint, without pairing it with a cached user.
|
|
467
|
+
this.sessionChecked = false;
|
|
468
|
+
const previousUser = this.currentUser;
|
|
469
|
+
const canApply = () => isCurrent() && this.getSessionToken() === credential && this.currentUser === previousUser;
|
|
470
|
+
try {
|
|
471
|
+
const profile = await this.auth.getAccountProfile(canApply);
|
|
472
|
+
if (!canApply()) return;
|
|
473
|
+
this.sessionChecked = true;
|
|
474
|
+
this.auth.restoreCachedUser({ ...profile, updatedAt: profile.updatedAt ?? undefined });
|
|
475
|
+
} catch (error) {
|
|
476
|
+
if (!canApply()) return;
|
|
477
|
+
if (error instanceof ApiRequestError && error.status === 401) {
|
|
478
|
+
this.installSessionToken(null);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
throw error;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
334
484
|
|
|
335
485
|
async getSession(isCurrent: () => boolean = () => true): Promise<AuthUser | null> {
|
|
336
486
|
if (!isCurrent()) return this.currentUser;
|
|
@@ -353,7 +503,10 @@ class GloomApiClient {
|
|
|
353
503
|
credential: this.getSessionToken(),
|
|
354
504
|
promise: this.auth.getSession(canApply)
|
|
355
505
|
.then(({ user, validated }) => {
|
|
356
|
-
if (validated && canApply())
|
|
506
|
+
if (validated && canApply()) {
|
|
507
|
+
this.sessionChecked = true;
|
|
508
|
+
this.clearSessionRevalidationTimer();
|
|
509
|
+
}
|
|
357
510
|
this.traceAuth(validated ? "getSession:done" : "getSession:retained", user);
|
|
358
511
|
return user;
|
|
359
512
|
})
|
|
@@ -753,6 +906,8 @@ class GloomApiClient {
|
|
|
753
906
|
subscribeScanner = this.socket.subscribeScanner.bind(this.socket);
|
|
754
907
|
|
|
755
908
|
dispose(): void {
|
|
909
|
+
this.cancelSessionRevalidation();
|
|
910
|
+
this.sessionInstallationGeneration += 1;
|
|
756
911
|
this.sessionRequestGeneration += 1;
|
|
757
912
|
this.sessionRequest = null;
|
|
758
913
|
this.socket.dispose();
|
|
@@ -799,11 +954,14 @@ class GloomApiClient {
|
|
|
799
954
|
getCloudCentralBankRates = this.data.getCloudCentralBankRates.bind(this.data);
|
|
800
955
|
getMobileAlertHistory = this.data.getMobileAlertHistory.bind(this.data);
|
|
801
956
|
getScannerFlowHistory = this.data.getScannerFlowHistory.bind(this.data);
|
|
957
|
+
getScannerFlowSession = this.data.getScannerFlowSession.bind(this.data);
|
|
958
|
+
getLiveScan = this.data.getLiveScan.bind(this.data);
|
|
802
959
|
getCloudEstimateRevisions = this.data.getCloudEstimateRevisions.bind(this.data);
|
|
803
960
|
getCloudMoneyMarkets = this.data.getCloudMoneyMarkets.bind(this.data);
|
|
804
961
|
equityScreener = this.data.equityScreener.bind(this.data);
|
|
805
962
|
getMemberFunds = this.data.getMemberFunds.bind(this.data);
|
|
806
963
|
getFundMembers = this.data.getFundMembers.bind(this.data);
|
|
964
|
+
getFundBreadth = this.data.getFundBreadth.bind(this.data);
|
|
807
965
|
getFundChanges = this.data.getFundChanges.bind(this.data);
|
|
808
966
|
getFundFacts = this.data.getFundFacts.bind(this.data);
|
|
809
967
|
getCloudExchangeAnnouncements = this.data.getCloudExchangeAnnouncements.bind(this.data);
|
|
@@ -855,6 +1013,8 @@ class GloomApiClient {
|
|
|
855
1013
|
getCloudPerpsHistory = this.data.getCloudPerpsHistory.bind(this.data);
|
|
856
1014
|
getCloudPerpsRankings = this.data.getCloudPerpsRankings.bind(this.data);
|
|
857
1015
|
getCloudPerpsCompare = this.data.getCloudPerpsCompare.bind(this.data);
|
|
1016
|
+
getCloudPerpsLiquidations = this.data.getCloudPerpsLiquidations.bind(this.data);
|
|
1017
|
+
getCloudPerpsDepth = this.data.getCloudPerpsDepth.bind(this.data);
|
|
858
1018
|
getCloudPerpsEquity = this.data.getCloudPerpsEquity.bind(this.data);
|
|
859
1019
|
getCloudPerpsEquities = this.data.getCloudPerpsEquities.bind(this.data);
|
|
860
1020
|
getCloudPerpsMarket = this.data.getCloudPerpsMarket.bind(this.data);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The live scanner's wire format: a user's own intraday conditions over a
|
|
3
|
+
* universe of US stocks, evaluated by Gloom Cloud against a market-wide
|
|
4
|
+
* snapshot it refreshes every few seconds (real-time for Pro, 15 minutes
|
|
5
|
+
* delayed otherwise). `GET /market/scanner/live?scan=<definition JSON>`.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Minutes a move, a volume window or an event can look back over. */
|
|
9
|
+
export const LIVE_SCAN_WINDOWS = [1, 5, 15, 30, 60] as const;
|
|
10
|
+
export type LiveScanWindow = (typeof LIVE_SCAN_WINDOWS)[number];
|
|
11
|
+
|
|
12
|
+
export const LIVE_SCAN_INDEXES = ["sp500", "sp400", "sp600", "russell1000", "russell2000"] as const;
|
|
13
|
+
export type LiveScanIndex = (typeof LIVE_SCAN_INDEXES)[number];
|
|
14
|
+
|
|
15
|
+
/** The universe as Gloom Cloud reads it; a watchlist goes as its symbols. */
|
|
16
|
+
type LiveScanWireUniverse =
|
|
17
|
+
| { kind: "all" }
|
|
18
|
+
| { kind: "index"; index: LiveScanIndex }
|
|
19
|
+
| { kind: "sector"; sector: string }
|
|
20
|
+
| { kind: "symbols"; symbols: string[] };
|
|
21
|
+
|
|
22
|
+
export type LiveScanDirection = "up" | "down" | "either";
|
|
23
|
+
|
|
24
|
+
export type LiveScanCondition =
|
|
25
|
+
/** Volume over the window (or the session so far) against the 20-session average's pace. */
|
|
26
|
+
| { kind: "volume_spike"; window: LiveScanWindow | "day"; ratio: number }
|
|
27
|
+
/** Percent move over the last `window` minutes. */
|
|
28
|
+
| { kind: "move"; window: LiveScanWindow; direction: LiveScanDirection; percent: number }
|
|
29
|
+
/** A new session high (low) printed in the last `within` minutes. */
|
|
30
|
+
| { kind: "new_high" | "new_low"; within: LiveScanWindow }
|
|
31
|
+
/** Crossed the session VWAP in the last `within` minutes, and still on that side. */
|
|
32
|
+
| { kind: "vwap_cross"; direction: "above" | "below" | "either"; within: LiveScanWindow }
|
|
33
|
+
/** The session's open against the previous close. */
|
|
34
|
+
| { kind: "gap"; direction: LiveScanDirection; percent: number };
|
|
35
|
+
|
|
36
|
+
export interface LiveScanWireDefinition {
|
|
37
|
+
version: 1;
|
|
38
|
+
universe: LiveScanWireUniverse;
|
|
39
|
+
conditions: LiveScanCondition[];
|
|
40
|
+
minPrice?: number;
|
|
41
|
+
minMarketCap?: number;
|
|
42
|
+
minVolume?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type LiveScanStatus = "live" | "starting" | "closed" | "degraded";
|
|
46
|
+
|
|
47
|
+
export interface LiveScanMatch {
|
|
48
|
+
symbol: string;
|
|
49
|
+
name: string | null;
|
|
50
|
+
/** Its US venue (NASDAQ, NYSE, ...), null when the screener does not list it. */
|
|
51
|
+
exchange?: string | null;
|
|
52
|
+
price: number;
|
|
53
|
+
changePercent: number | null;
|
|
54
|
+
volume: number | null;
|
|
55
|
+
/** The session's volume against the 20-session average's pace so far. */
|
|
56
|
+
relativeVolume: number | null;
|
|
57
|
+
/** Price against the session VWAP, in percent. */
|
|
58
|
+
vwapPercent: number | null;
|
|
59
|
+
gapPercent: number | null;
|
|
60
|
+
/**
|
|
61
|
+
* The figure each condition matched on, in the definition's order: a
|
|
62
|
+
* percent for a move or a gap, a multiple for a volume spike, the time of
|
|
63
|
+
* the event (epoch ms) for a new high or low or a VWAP cross.
|
|
64
|
+
*/
|
|
65
|
+
values: Array<number | null>;
|
|
66
|
+
/** The latest event a condition matched on. */
|
|
67
|
+
signalAt: number | null;
|
|
68
|
+
/** When the price printed. */
|
|
69
|
+
at: number | null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface LiveScanPayload {
|
|
73
|
+
status: LiveScanStatus;
|
|
74
|
+
access: "realtime" | "delayed";
|
|
75
|
+
delayMinutes: number;
|
|
76
|
+
/** The market time the snapshot shows. */
|
|
77
|
+
asOf: number | null;
|
|
78
|
+
/** When the snapshot was refreshed. */
|
|
79
|
+
takenAt: number | null;
|
|
80
|
+
/** How often the snapshot refreshes. */
|
|
81
|
+
refreshMs: number;
|
|
82
|
+
scanned: number;
|
|
83
|
+
matched: number;
|
|
84
|
+
matches: LiveScanMatch[];
|
|
85
|
+
/** Windows the scanner cannot measure yet after it started; a condition over one matches nothing until then. */
|
|
86
|
+
warmingWindows: LiveScanWindow[];
|
|
87
|
+
warnings: string[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** The scan travels in a POST body: a watchlist of 1,000 symbols would not fit a request line. */
|
|
91
|
+
export const LIVE_SCAN_PATH = "/market/scanner/live";
|
|
@@ -21,6 +21,12 @@ export interface ScreenerQuote {
|
|
|
21
21
|
previousClose?: number;
|
|
22
22
|
/** The quote's sessions beside the live print the server ranked the row by, when the server sends them. */
|
|
23
23
|
sessions?: CloudMoverSessionFields;
|
|
24
|
+
/** The listing's float as the equity screener serves it; absent where the server serves none or predates it. */
|
|
25
|
+
floatShares?: number;
|
|
26
|
+
/** Set with a float the source states no measurement date for: `partial`. */
|
|
27
|
+
floatSharesState?: "partial";
|
|
28
|
+
/** Why the float is partial, as the server says it. */
|
|
29
|
+
floatSharesReason?: string;
|
|
24
30
|
}
|
|
25
31
|
|
|
26
32
|
|
|
@@ -105,6 +111,8 @@ export interface DividendSummary {
|
|
|
105
111
|
/** The ex-date of the distribution that rate annualizes, YYYY-MM-DD. */
|
|
106
112
|
forwardRateAsOf?: string | null;
|
|
107
113
|
payoutRatio: number | null;
|
|
114
|
+
/** The trailing EPS fundamentals serve for the listing; only its sign is read, since a payout over a loss is not meaningful. Absent from older servers. */
|
|
115
|
+
trailingEps?: number | null;
|
|
108
116
|
exDividendDate: number | null;
|
|
109
117
|
dividendDate: number | null;
|
|
110
118
|
currency: string | null;
|
|
@@ -117,4 +125,6 @@ export interface MarketDividendsPayload {
|
|
|
117
125
|
summary: DividendSummary | null;
|
|
118
126
|
historyError?: string;
|
|
119
127
|
summaryError?: string;
|
|
128
|
+
/** When Gloom Cloud last asked for the history and the summary, ISO. Absent from older servers. */
|
|
129
|
+
triedAt?: string;
|
|
120
130
|
}
|
|
@@ -37,7 +37,14 @@ export interface CloudSessionMoverItem {
|
|
|
37
37
|
/** Regular-session VWAP. */
|
|
38
38
|
vwap: number | null;
|
|
39
39
|
vwapPercent: number | null;
|
|
40
|
+
/** The equity screener's float, null where it serves none. */
|
|
40
41
|
floatShares: number | null;
|
|
42
|
+
/** Set with a float the source states no measurement date for: `partial`. */
|
|
43
|
+
floatSharesState?: "partial";
|
|
44
|
+
/** Why the float is partial, as the server says it. */
|
|
45
|
+
floatSharesReason?: string;
|
|
46
|
+
/** When the statistics the float is read from were retrieved (ISO). */
|
|
47
|
+
floatSharesRetrievedAt?: string;
|
|
41
48
|
catalysts: CloudSessionCatalyst[];
|
|
42
49
|
lastUpdated: number;
|
|
43
50
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
interface MemberFund { ticker: string; name: string; aliases: string[]; changes: "sp500" | "announcements" | "none" }
|
|
2
2
|
export interface FundMember {
|
|
3
3
|
id: string; symbol: string | null; name: string; sector: string | null;
|
|
4
|
-
weight: number | null; shares: number; holdingPrice: number; marketValue: number;
|
|
4
|
+
weight: number | null; shares: number; holdingPrice: number | null; marketValue: number | null;
|
|
5
5
|
price: number | null; priceAsOf: string | null; changePercent: number | null; dailyAsOf: string | null;
|
|
6
6
|
return1WPercent: number | null; return1MPercent: number | null; returnYtdPercent: number | null;
|
|
7
7
|
contribution: number | null; stale: boolean;
|
|
@@ -30,3 +30,15 @@ export interface FundChangesPayload {
|
|
|
30
30
|
estimateLabel: string; attribution: { text: string; url: string } | null;
|
|
31
31
|
}
|
|
32
32
|
export interface MemberFundsPayload { funds: (MemberFund & { asOf: string | null })[] }
|
|
33
|
+
|
|
34
|
+
interface BreadthCount { above: number; eligible: number; percent: number | null }
|
|
35
|
+
export interface BreadthDay {
|
|
36
|
+
date: string; asOf: string; membershipAsOf: string; memberCount: number; observed: number;
|
|
37
|
+
advances: number; declines: number; unchanged: number; advanceDeclineEligible: number;
|
|
38
|
+
ma20: BreadthCount; ma50: BreadthCount; ma200: BreadthCount;
|
|
39
|
+
newHighs: number; newLows: number; highLowEligible: number; adLine: number | null;
|
|
40
|
+
}
|
|
41
|
+
export interface FundBreadthPayload {
|
|
42
|
+
fund: MemberFund; basis: "daily-close" | "intraday"; access?: "realtime" | "delayed"; membershipBasis: "current-members";
|
|
43
|
+
latest: BreadthDay | null; history: BreadthDay[]; stale: boolean;
|
|
44
|
+
}
|
package/src/api-client/perps.ts
CHANGED
|
@@ -174,3 +174,46 @@ export interface PerpMarketPayload extends PerpBoardPayload {
|
|
|
174
174
|
evidence: { kind: string; period_at: string; received_at: string; superseded_at: string | null; fingerprint: string; payload: PerpMarket | PerpFunding | PerpCandle }[];
|
|
175
175
|
methodologyUrl: string;
|
|
176
176
|
}
|
|
177
|
+
|
|
178
|
+
/** One contract's liquidations: long is longs liquidated (forced sells), short is shorts; quote notional. */
|
|
179
|
+
export interface PerpLiquidationMarket {
|
|
180
|
+
marketId: string; venue: string; symbol: string; dex: string; quoteCurrency: string;
|
|
181
|
+
long24h: number; short24h: number; long7d: number; short7d: number; count24h: number; count7d: number; lastEventAt: string | null;
|
|
182
|
+
}
|
|
183
|
+
export interface PerpLiquidationPrint {
|
|
184
|
+
marketId: string; venue: string; symbol: string; dex: string;
|
|
185
|
+
side: "long" | "short"; priceKind: "fill" | "bankruptcy"; price: number; quantity: number; notionalUsd: number;
|
|
186
|
+
/** The venue's time for the liquidation. */
|
|
187
|
+
eventAt: string;
|
|
188
|
+
/** When Gloom Cloud received it. */
|
|
189
|
+
receivedAt: string;
|
|
190
|
+
}
|
|
191
|
+
/** One base asset's liquidations across the venues' public streams. */
|
|
192
|
+
export interface PerpLiquidationsPayload {
|
|
193
|
+
status: string; baseAsset: string; asOf: string; from: string; collectingSince: string | null;
|
|
194
|
+
markets: PerpLiquidationMarket[];
|
|
195
|
+
totals: Pick<PerpLiquidationMarket, "long24h" | "short24h" | "long7d" | "short7d" | "count24h" | "count7d">;
|
|
196
|
+
/** Pro: UTC hours with liquidations over the last 7 days; empty for a preview. */
|
|
197
|
+
hourly: { time: string; long: number; short: number; count: number }[];
|
|
198
|
+
largest: PerpLiquidationPrint[];
|
|
199
|
+
streams: { venue: string; state: "live" | "down"; lastOkAt: string | null; error: string | null }[];
|
|
200
|
+
notes: string[];
|
|
201
|
+
locked: boolean; access: "pro" | "preview";
|
|
202
|
+
}
|
|
203
|
+
/** Quote notional resting within 0.5%, 1% and 2% of mid; reach is how far the returned book went, as a fraction of mid. */
|
|
204
|
+
export interface PerpDepthSnapshot {
|
|
205
|
+
marketId: string; bucket: string; observedAt: string; sourceAsOf: string | null; mid: number;
|
|
206
|
+
bid05: number; ask05: number; bid1: number; ask1: number; bid2: number; ask2: number;
|
|
207
|
+
bidReach: number; askReach: number; levels: number; grouping: number | null;
|
|
208
|
+
}
|
|
209
|
+
export interface PerpDepthRow extends PerpDepthSnapshot { venue: string; symbol: string; dex: string; quoteCurrency: string; stale: boolean }
|
|
210
|
+
/** One base asset's hourly order book depth across the venues. */
|
|
211
|
+
export interface PerpDepthPayload {
|
|
212
|
+
status: string; baseAsset: string; asOf: string;
|
|
213
|
+
rows: PerpDepthRow[];
|
|
214
|
+
/** Pro: every market's hourly snapshots over the last 7 days; empty for a preview. */
|
|
215
|
+
history: PerpDepthSnapshot[];
|
|
216
|
+
sources: { venue: string; lastOkAt: string | null; error: string | null }[];
|
|
217
|
+
notes: string[];
|
|
218
|
+
locked: boolean; access: "pro" | "preview";
|
|
219
|
+
}
|