gloomberb 0.16.4 → 0.16.6
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 +14 -91
- package/package.json +5 -1
- package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
- package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
- package/src/account/billing.ts +57 -0
- package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
- package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
- package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
- package/src/account/session.ts +16 -0
- package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +16 -15
- package/src/{plugins/builtin/cloud → account}/upgrade-personalization.ts +7 -7
- package/src/{plugins/builtin/cloud → account}/upgrade-tickers.ts +6 -6
- package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
- package/src/api-client/central-bank-rates.ts +6 -1
- package/src/api-client/chat.ts +26 -0
- package/src/api-client/credit-boards.ts +2 -0
- package/src/api-client/data.ts +73 -3
- package/src/api-client/earnings.ts +6 -0
- package/src/api-client/europe-energy.ts +106 -0
- package/src/api-client/futures-curve.ts +56 -0
- package/src/api-client/index.ts +13 -1
- package/src/api-client/market-discovery.ts +13 -1
- package/src/api-client/normalizers.ts +32 -0
- package/src/api-client/paths.ts +7 -0
- package/src/api-client/perps.ts +8 -0
- package/src/api-client/request.ts +9 -2
- package/src/api-client/research-activity.ts +15 -10
- package/src/api-client/socket.ts +29 -0
- package/src/api-client/themes.ts +22 -1
- package/src/api-client/types.ts +78 -2
- package/src/api-client/yield-curves.ts +8 -0
- package/src/app/global-shortcuts.ts +50 -2
- package/src/app/keybindings/actions.ts +12 -1
- package/src/app/pane-runtime/plugin-bindings.ts +2 -2
- package/src/app/pane-runtime/ticker-open-runtime.ts +16 -6
- package/src/app/runtime/desktop-deeplink.ts +10 -5
- package/src/app/runtime/startup.ts +1 -1
- package/src/app.tsx +6 -0
- package/src/architecture/core-builtin-allowlist.json +8 -26
- package/src/ask-gloom/pane-context.ts +114 -0
- package/src/ask-gloom/pane-request.ts +70 -0
- package/src/ask-gloom/pane-text.ts +201 -0
- package/src/brokers/signed-in/sign-in-dialog.tsx +11 -5
- package/src/capabilities/chart-series.ts +19 -2
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/central-bank-events.ts +23 -0
- package/src/cli/command-options.ts +17 -5
- package/src/cli/commands/crypto-hints.ts +35 -2
- package/src/cli/commands/fred-series.ts +146 -0
- package/src/cli/commands/market.ts +501 -115
- package/src/cli/commands/news-hints.ts +62 -0
- package/src/cli/commands/news-search.ts +53 -0
- package/src/cli/commands/options-leaps.ts +5 -2
- package/src/cli/commands/overview.ts +132 -26
- package/src/cli/commands/remote.ts +2 -1
- package/src/cli/commands/search.ts +317 -13
- package/src/cli/commands/system.ts +55 -8
- package/src/cli/commands/ticker.ts +155 -18
- package/src/cli/context.ts +45 -14
- package/src/cli/desktop-pane-shot.ts +76 -7
- package/src/cli/earnings-calendar.ts +71 -0
- package/src/cli/errors.ts +7 -5
- package/src/cli/exit-codes.ts +8 -0
- package/src/cli/export-source.ts +58 -0
- package/src/cli/freshness.ts +18 -7
- package/src/cli/glossary.ts +483 -0
- package/src/cli/help.ts +10 -0
- package/src/cli/helpers.ts +2 -5
- package/src/cli/history-rows.ts +118 -7
- package/src/cli/index-roots.ts +7 -0
- package/src/cli/index.ts +29 -9
- package/src/cli/known-gaps.ts +84 -0
- package/src/cli/listing-arg.ts +551 -97
- package/src/cli/not-a-ticker.ts +24 -9
- package/src/cli/pane-functions/access-gate.ts +13 -2
- package/src/cli/pane-functions/capabilities.ts +4 -3
- package/src/cli/pane-functions/catalog.ts +214 -40
- package/src/cli/pane-functions/data.ts +42 -8
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/dom.ts +37 -8
- package/src/cli/pane-functions/freshness.ts +393 -49
- package/src/cli/pane-functions/function-help.ts +31 -15
- package/src/cli/pane-functions/headless.ts +98 -30
- package/src/cli/pane-functions/index.ts +101 -19
- package/src/cli/pane-functions/market-session.ts +22 -8
- package/src/cli/pane-functions/options.ts +71 -22
- package/src/cli/pane-functions/report-notices.ts +25 -7
- package/src/cli/pane-functions/report.ts +15 -8
- package/src/cli/pane-functions/resolver.ts +74 -19
- package/src/cli/pane-functions/screenshot.ts +250 -27
- package/src/cli/perpetual-contract.ts +60 -0
- package/src/cli/registry.ts +3 -1
- package/src/cli/report-tables.ts +26 -7
- package/src/cli/result.ts +45 -11
- package/src/cli/series-search.ts +111 -0
- package/src/cli/staged-tickers.ts +52 -0
- package/src/cli/symbol-args.ts +27 -0
- package/src/cli/symbol-list.ts +154 -0
- package/src/cli/symbol-rows.ts +154 -0
- package/src/cli/ticker-resolution.ts +311 -27
- package/src/cli/types.ts +5 -0
- package/src/components/chart/composite/axis-overlays.tsx +14 -3
- package/src/components/chart/composite/composite-chart.tsx +71 -11
- package/src/components/chart/composite/crosshair-readout.tsx +150 -0
- package/src/components/chart/composite/downsample.ts +1 -1
- package/src/components/chart/composite/format.ts +29 -0
- package/src/components/chart/composite/interactions.ts +9 -2
- package/src/components/chart/composite/legend.tsx +100 -33
- package/src/components/chart/composite/panel-bitmap.ts +70 -35
- package/src/components/chart/composite/panel-labels.ts +18 -17
- package/src/components/chart/composite/panel-series.ts +1 -0
- package/src/components/chart/composite/panel-surface.tsx +46 -21
- package/src/components/chart/composite/price-axis-labels.tsx +3 -1
- package/src/components/chart/composite/rasterizer.ts +50 -8
- package/src/components/chart/composite/scene.ts +2 -1
- package/src/components/chart/composite/time-scale.ts +26 -9
- package/src/components/chart/composite/types.ts +18 -0
- package/src/components/chart/composite/use-composite-viewport.ts +30 -2
- package/src/components/chart/native/raster/crosshair.ts +8 -3
- package/src/components/chart/native/raster/primitives.ts +85 -21
- package/src/components/chart/native/surface/manager.ts +33 -8
- package/src/components/chart/surface3d/chart.tsx +1 -1
- package/src/components/command-bar/action-runtime.ts +1 -1
- package/src/components/command-bar/commands/collection-list.ts +210 -0
- package/src/components/command-bar/commands/collection.ts +40 -1
- package/src/components/command-bar/commands/direct/index.ts +4 -0
- package/src/components/command-bar/commands/registry.ts +8 -0
- package/src/components/command-bar/panel/index.tsx +11 -3
- package/src/components/command-bar/panel/runtime.ts +3 -0
- package/src/components/command-bar/panel/types.ts +2 -0
- package/src/components/command-bar/routes/root/plugin-install.ts +4 -4
- package/src/components/command-bar/routes/root/provider-search.ts +4 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
- package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
- package/src/components/command-bar/routing/actions.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +42 -17
- package/src/components/layout/detached-pane-shell.tsx +68 -39
- package/src/components/layout/floating-pane.tsx +10 -1
- package/src/components/layout/header.tsx +25 -5
- package/src/components/layout/missing-pane.tsx +3 -3
- package/src/components/layout/pane/capture-stamp.ts +41 -0
- package/src/components/layout/pane/capture-status.ts +12 -0
- package/src/components/layout/pane/content.tsx +7 -13
- package/src/components/layout/pane/footer/index.tsx +6 -2
- package/src/components/layout/pane/footer/keyboard.ts +3 -0
- package/src/components/layout/pane/footer/model.ts +41 -1
- package/src/components/layout/pane/header.tsx +50 -1
- package/src/components/layout/pane/index.tsx +21 -3
- package/src/components/layout/pane/sidebar.tsx +88 -21
- package/src/components/layout/shell/active-drag.ts +21 -5
- package/src/components/layout/shell/cursor-occlusion.ts +2 -1
- package/src/components/layout/shell/drag/index.ts +39 -9
- package/src/components/layout/shell/drag/live.ts +61 -51
- package/src/components/layout/shell/drag/runtime.ts +54 -12
- package/src/components/layout/shell/index.tsx +84 -65
- package/src/components/layout/shell/menu.ts +14 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
- package/src/components/layout/shell/pane/actions.ts +32 -10
- package/src/components/layout/shell/pane/ask.ts +131 -0
- package/src/components/layout/shell/pane/capture.ts +162 -0
- package/src/components/layout/shell/pane/layers.tsx +218 -50
- package/src/components/layout/shell/pane/management-shortcuts.ts +46 -1
- package/src/components/layout/shell/shortcuts.ts +21 -4
- package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
- package/src/components/markdown-text.tsx +62 -20
- package/src/components/metric-treemap/heat-surface.tsx +8 -1
- package/src/components/onboarding/account-step/form-panel.tsx +1 -1
- package/src/components/onboarding/account-step/index.tsx +1 -1
- package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
- package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
- package/src/components/onboarding/onboarding-keyboard.ts +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +2 -2
- package/src/components/onboarding/use-onboarding-upgrade.ts +3 -3
- package/src/components/onboarding/wizard-account.ts +2 -2
- package/src/components/pane-template-wizard.tsx +9 -1
- package/src/components/price-selector-dialog.tsx +11 -2
- package/src/components/reader/article-reader.tsx +642 -0
- package/src/components/reader/article-text.ts +527 -0
- package/src/components/sign-in-gate.tsx +3 -3
- package/src/components/ticker/list-table-view.tsx +43 -2
- package/src/components/ui/action-row.tsx +2 -1
- package/src/components/ui/button.tsx +7 -1
- package/src/components/ui/choice-dialog.tsx +6 -4
- package/src/components/ui/confirm-dialog.tsx +28 -18
- package/src/components/ui/data-table/index.tsx +18 -6
- package/src/components/ui/data-table/opentui/index.tsx +37 -6
- package/src/components/ui/data-table/types.ts +12 -0
- package/src/components/ui/dialog-actions.tsx +64 -0
- package/src/components/ui/display.tsx +17 -3
- package/src/components/ui/frame.tsx +35 -2
- package/src/components/ui/icon.tsx +6 -1
- package/src/components/ui/query-bar.tsx +10 -1
- package/src/components/ui/text-prompt-dialog.tsx +11 -9
- package/src/data/cached-query.ts +2 -0
- package/src/data/config/store/migrations.ts +7 -0
- package/src/data/config/store/normalize.ts +7 -2
- package/src/data/config/store/portfolio-as-of-column.ts +57 -0
- package/src/data/ticker-repository.ts +5 -0
- package/src/data/ticker-store.ts +15 -0
- package/src/docs/content.ts +215 -0
- package/src/docs/load.ts +139 -0
- package/src/docs/requests.ts +39 -0
- package/src/docs/snapshot.chunk.ts +8 -0
- package/src/docs/snapshot.json +7555 -0
- package/src/docs/topics.ts +216 -0
- package/src/i18n/es.ts +65 -5
- package/src/i18n/ja.ts +65 -5
- package/src/i18n/ko.ts +65 -5
- package/src/i18n/zh-cn.ts +65 -5
- package/src/i18n/zh-tw.ts +65 -5
- package/src/layout/desks.ts +1 -1
- package/src/layout/pane-manager/dock-tree.ts +18 -0
- package/src/layout/pane-manager/index.ts +1 -0
- package/src/layout-marketplace/gallery.tsx +1 -1
- package/src/market-data/coordinator/chart.ts +10 -4
- package/src/market-data/coordinator/index.ts +6 -3
- package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
- package/src/market-data/futures-contract.ts +151 -0
- package/src/market-data/hooks.tsx +10 -2
- package/src/market-data/market/format.ts +39 -21
- package/src/market-data/market/freshness.ts +84 -20
- package/src/market-data/market/session-close-note.ts +3 -2
- package/src/market-data/market/status.ts +19 -23
- package/src/market-data/published-apac-sessions.ts +23 -1
- package/src/market-data/quotes/contributions.ts +5 -0
- package/src/market-data/quotes/metadata.ts +19 -24
- package/src/market-data/quotes/resolution.ts +5 -0
- package/src/market-data/quotes/screener-live-quotes.ts +5 -4
- package/src/market-data/result-types.ts +2 -0
- package/src/notifications/app-notifier.ts +17 -1
- package/src/notifications/notification-log.ts +180 -0
- package/src/plugins/auto-update-node.ts +2 -2
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/model.ts +1 -56
- package/src/plugins/builtin/account-management/pane.tsx +6 -4
- package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
- package/src/plugins/builtin/alerts/catalysts.ts +1 -1
- package/src/plugins/builtin/alerts/cli.ts +313 -47
- package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
- package/src/plugins/builtin/alerts/events.ts +23 -2
- package/src/plugins/builtin/alerts/focus.ts +27 -0
- package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +47 -11
- package/src/plugins/builtin/alerts/pane.tsx +27 -1
- package/src/plugins/builtin/alerts/research-builder.ts +8 -3
- package/src/plugins/builtin/alerts/research-rules.ts +18 -2
- package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
- package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
- package/src/plugins/builtin/alerts/scheduled.ts +254 -0
- package/src/plugins/builtin/alerts/targets.ts +92 -0
- package/src/plugins/builtin/analytics/index.tsx +8 -3
- package/src/plugins/builtin/analytics/risk-headless.ts +60 -27
- package/src/plugins/builtin/analytics/risk-math.ts +91 -27
- package/src/plugins/builtin/analytics/risk-model.ts +35 -5
- package/src/plugins/builtin/analytics/risk-pane.tsx +15 -8
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/attention/index.tsx +2 -0
- package/src/plugins/builtin/attention/pane.tsx +3 -1
- package/src/plugins/builtin/attention/series.ts +26 -0
- package/src/plugins/builtin/awards/headless.ts +88 -18
- package/src/plugins/builtin/awards/index.tsx +2 -0
- package/src/plugins/builtin/awards/model.ts +41 -1
- package/src/plugins/builtin/awards/pane.tsx +22 -13
- package/src/plugins/builtin/awards/series.ts +29 -0
- package/src/plugins/builtin/backtest/headless.ts +2 -2
- package/src/plugins/builtin/bond-calculator/model.ts +2 -1
- package/src/plugins/builtin/broker-manager/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/headless.ts +1 -1
- package/src/plugins/builtin/catalysts/pane.tsx +3 -1
- package/src/plugins/builtin/cds/client.ts +49 -12
- package/src/plugins/builtin/cds/headless.ts +119 -19
- package/src/plugins/builtin/cds/index.tsx +3 -1
- package/src/plugins/builtin/cds/model.ts +214 -32
- package/src/plugins/builtin/cds/pane.tsx +58 -14
- package/src/plugins/builtin/cds/series.ts +19 -0
- package/src/plugins/builtin/central-bank-rates/client.ts +4 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +46 -16
- package/src/plugins/builtin/central-bank-rates/index.tsx +3 -1
- package/src/plugins/builtin/central-bank-rates/model.ts +99 -0
- package/src/plugins/builtin/central-bank-rates/pane.tsx +1 -1
- package/src/plugins/builtin/central-bank-rates/series.ts +36 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +193 -255
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
- package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
- package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +1 -1
- package/src/plugins/builtin/chart-composer/headless.ts +70 -5
- package/src/plugins/builtin/chart-composer/index.tsx +15 -3
- package/src/plugins/builtin/chart-composer/pane.tsx +81 -38
- package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
- package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
- package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
- package/src/plugins/builtin/chat/content/composer.tsx +5 -1
- package/src/plugins/builtin/chat/content/footer.tsx +12 -0
- package/src/plugins/builtin/chat/content/index.tsx +89 -5
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
- package/src/plugins/builtin/chat/content/new-messages.tsx +89 -0
- package/src/plugins/builtin/chat/content/row-activity.ts +132 -0
- package/src/plugins/builtin/chat/content/scroll.ts +127 -27
- package/src/plugins/builtin/chat/content/shortcuts.ts +2 -2
- package/src/plugins/builtin/chat/content/transcript.tsx +145 -78
- package/src/plugins/builtin/chat/content/types.ts +1 -0
- package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
- package/src/plugins/builtin/chat/controller/index.ts +123 -1
- package/src/plugins/builtin/chat/controller/message-loading.ts +3 -0
- package/src/plugins/builtin/chat/controller/messages.ts +7 -2
- package/src/plugins/builtin/chat/controller/realtime.ts +10 -1
- package/src/plugins/builtin/chat/controller/send.ts +61 -1
- package/src/plugins/builtin/chat/controller/state.ts +8 -0
- package/src/plugins/builtin/chat/ghost-user.ts +20 -0
- package/src/plugins/builtin/chat/index.tsx +23 -5
- package/src/plugins/builtin/chat/layout.ts +78 -5
- package/src/plugins/builtin/chat/message/ai-badge.tsx +18 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +55 -6
- package/src/plugins/builtin/chat/message/header.tsx +16 -4
- package/src/plugins/builtin/chat/message/profile-popover.tsx +5 -1
- package/src/plugins/builtin/chat/message/reactions.tsx +210 -0
- package/src/plugins/builtin/chat/message/render-state.ts +18 -2
- package/src/plugins/builtin/chat/message/terminal.tsx +43 -4
- package/src/plugins/builtin/chat/message/types.ts +12 -0
- package/src/plugins/builtin/chat/reactions.ts +197 -0
- package/src/plugins/builtin/chat/share/flow.tsx +87 -0
- package/src/plugins/builtin/chat/share/targets.ts +27 -0
- package/src/plugins/builtin/chat/status-widget.tsx +6 -3
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +148 -27
- package/src/plugins/builtin/chat/unread-inbox.ts +22 -0
- package/src/plugins/builtin/cloud/askg/attached-pane.tsx +69 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +111 -19
- package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
- package/src/plugins/builtin/cloud/askg/manifest.ts +32 -7
- package/src/plugins/builtin/cloud/askg/model.ts +27 -8
- package/src/plugins/builtin/cloud/askg/pane-attachment.ts +94 -0
- package/src/plugins/builtin/cloud/askg/pane.tsx +141 -12
- package/src/plugins/builtin/cloud/askg/pending-question.ts +11 -0
- package/src/plugins/builtin/cloud/askg/protocol.ts +10 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +3 -0
- package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
- package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
- package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +3 -0
- package/src/plugins/builtin/cloud/plugin.tsx +19 -2
- package/src/plugins/builtin/cloud/team/model.ts +5 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/team/store.ts +8 -3
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +77 -9
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +6 -1
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +9 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +35 -11
- package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
- package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
- package/src/plugins/builtin/company-attention/headless.ts +21 -7
- package/src/plugins/builtin/company-attention/index.tsx +2 -0
- package/src/plugins/builtin/company-attention/model.ts +26 -7
- package/src/plugins/builtin/company-attention/pane.tsx +12 -9
- package/src/plugins/builtin/company-attention/series.ts +52 -0
- package/src/plugins/builtin/company-kpis/headless.ts +97 -10
- package/src/plugins/builtin/company-kpis/model.ts +24 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +17 -16
- package/src/plugins/builtin/composite-plugins.ts +19 -13
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/cot/headless.ts +1 -1
- package/src/plugins/builtin/cot/index.tsx +3 -1
- package/src/plugins/builtin/cot/model.ts +40 -11
- package/src/plugins/builtin/cot/series.ts +27 -0
- package/src/plugins/builtin/cpi/headless.ts +3 -3
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +10 -1
- package/src/plugins/builtin/credit-boards/client.ts +6 -2
- package/src/plugins/builtin/credit-boards/headless.ts +108 -31
- package/src/plugins/builtin/credit-boards/index.tsx +2 -0
- package/src/plugins/builtin/credit-boards/model.ts +11 -1
- package/src/plugins/builtin/credit-boards/series.ts +66 -0
- package/src/plugins/builtin/credit-conditions/client.ts +12 -9
- package/src/plugins/builtin/credit-conditions/headless.ts +13 -2
- package/src/plugins/builtin/credit-conditions/index.tsx +18 -9
- package/src/plugins/builtin/credit-conditions/model.ts +19 -11
- package/src/plugins/builtin/credit-conditions/series.ts +16 -0
- package/src/plugins/builtin/credit-documents/headless.ts +33 -3
- package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
- package/src/plugins/builtin/crypto-board/headless.ts +2 -3
- package/src/plugins/builtin/crypto-board/index.tsx +2 -0
- package/src/plugins/builtin/crypto-board/model.ts +12 -0
- package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
- package/src/plugins/builtin/crypto-board/series.ts +48 -0
- package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
- package/src/plugins/builtin/debt-maturities/headless.ts +17 -11
- package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
- package/src/plugins/builtin/debt-maturities/series.ts +45 -0
- package/src/plugins/builtin/dividend-yield/client.ts +3 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +7 -4
- package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +3 -1
- package/src/plugins/builtin/dividend-yield/series.ts +20 -0
- package/src/plugins/builtin/dividend-yield/types.ts +2 -0
- package/src/plugins/builtin/docs/blocks.tsx +181 -0
- package/src/plugins/builtin/docs/index.tsx +68 -0
- package/src/plugins/builtin/docs/pane.tsx +426 -0
- package/src/plugins/builtin/docs/targets.ts +72 -0
- package/src/plugins/builtin/docs/use-docs.ts +60 -0
- package/src/plugins/builtin/doe/headless.ts +12 -8
- package/src/plugins/builtin/doe/index.tsx +2 -0
- package/src/plugins/builtin/doe/series.ts +62 -0
- package/src/plugins/builtin/earnings/client.ts +3 -2
- package/src/plugins/builtin/earnings/format.ts +1 -5
- package/src/plugins/builtin/earnings/headless.ts +58 -6
- package/src/plugins/builtin/earnings/history-model.ts +15 -1
- package/src/plugins/builtin/earnings/history-table.ts +13 -2
- package/src/plugins/builtin/earnings/history.tsx +7 -3
- package/src/plugins/builtin/earnings/index.tsx +9 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +28 -2
- package/src/plugins/builtin/earnings-calls/index.tsx +1 -1
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -0
- package/src/plugins/builtin/econ/fred-catalog.ts +198 -0
- package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
- package/src/plugins/builtin/econ/index.tsx +2 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +19 -4
- package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
- package/src/plugins/builtin/equity-screener/headless.ts +3 -3
- package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -3
- package/src/plugins/builtin/exposure/drivers.ts +13 -0
- package/src/plugins/builtin/exposure/headless.ts +205 -13
- package/src/plugins/builtin/exposure/holdings.ts +1 -1
- package/src/plugins/builtin/exposure/index.tsx +1 -0
- package/src/plugins/builtin/exposure/model.ts +23 -3
- package/src/plugins/builtin/exposure/pane.tsx +14 -12
- package/src/plugins/builtin/fear-greed/index.tsx +18 -10
- package/src/plugins/builtin/fear-greed/series.ts +52 -0
- package/src/plugins/builtin/futures/index.tsx +43 -3
- package/src/plugins/builtin/futures/model.ts +1 -1
- package/src/plugins/builtin/futures/returns.ts +1 -1
- package/src/plugins/builtin/futures/series.ts +13 -0
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +71 -10
- package/src/plugins/builtin/futures-curve/index.tsx +1 -1
- package/src/plugins/builtin/futures-curve/model.ts +66 -11
- package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
- package/src/plugins/builtin/fx-matrix/client.ts +63 -0
- package/src/plugins/builtin/fx-matrix/export.ts +2 -1
- package/src/plugins/builtin/fx-matrix/headless.ts +154 -0
- package/src/plugins/builtin/fx-matrix/index.tsx +4 -4
- package/src/plugins/builtin/gpu/board.tsx +13 -10
- package/src/plugins/builtin/gpu/changes.tsx +4 -4
- package/src/plugins/builtin/gpu/client.ts +19 -1
- package/src/plugins/builtin/gpu/equities.tsx +14 -10
- package/src/plugins/builtin/gpu/headless.ts +58 -27
- package/src/plugins/builtin/gpu/history.tsx +3 -3
- package/src/plugins/builtin/gpu/index.tsx +2 -0
- package/src/plugins/builtin/gpu/model.ts +101 -16
- package/src/plugins/builtin/gpu/pane.tsx +28 -12
- package/src/plugins/builtin/gpu/series.ts +38 -0
- package/src/plugins/builtin/help/function-card.tsx +25 -6
- package/src/plugins/builtin/help/function-index.ts +2 -0
- package/src/plugins/builtin/help/index.tsx +31 -9
- package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
- package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +55 -11
- package/src/plugins/builtin/holders/client.ts +22 -3
- package/src/plugins/builtin/holders/format.ts +18 -3
- package/src/plugins/builtin/holders/headless.ts +36 -133
- package/src/plugins/builtin/holders/pane.tsx +11 -4
- package/src/plugins/builtin/holders/report-header.ts +40 -5
- package/src/plugins/builtin/holders/report-rows.ts +240 -0
- package/src/plugins/builtin/insider/client.ts +35 -20
- package/src/plugins/builtin/insider/headless.ts +41 -11
- package/src/plugins/builtin/insider/index.tsx +26 -9
- package/src/plugins/builtin/insider/insider-data.ts +10 -0
- package/src/plugins/builtin/insider/issuer.ts +49 -0
- package/src/plugins/builtin/insider/model.ts +3 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -1
- package/src/plugins/builtin/iv-history/client.ts +20 -6
- package/src/plugins/builtin/iv-history/format.ts +9 -0
- package/src/plugins/builtin/iv-history/headless.ts +56 -21
- package/src/plugins/builtin/iv-history/index.tsx +2 -0
- package/src/plugins/builtin/iv-history/model.ts +143 -8
- package/src/plugins/builtin/iv-history/screen-pane.tsx +5 -9
- package/src/plugins/builtin/iv-history/series.ts +29 -0
- package/src/plugins/builtin/jobs/headless.ts +26 -3
- package/src/plugins/builtin/jobs/index.tsx +3 -1
- package/src/plugins/builtin/jobs/series.ts +19 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +2 -1
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
- package/src/plugins/builtin/macro-day/client.ts +44 -3
- package/src/plugins/builtin/macro-day/headless.ts +13 -10
- package/src/plugins/builtin/macro-day/model.ts +56 -10
- package/src/plugins/builtin/macro-day/pane.tsx +30 -20
- package/src/plugins/builtin/market-heatmap/headless.ts +20 -5
- package/src/plugins/builtin/market-heatmap/index.tsx +6 -0
- package/src/plugins/builtin/market-heatmap/model.ts +19 -11
- package/src/plugins/builtin/market-heatmap/portfolio.ts +2 -2
- package/src/plugins/builtin/market-movers/client.ts +7 -5
- package/src/plugins/builtin/market-movers/index.tsx +3 -2
- package/src/plugins/builtin/market-movers/model.ts +30 -0
- package/src/plugins/builtin/market-movers/screener.ts +31 -0
- package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
- package/src/plugins/builtin/market-valuation/index.tsx +3 -3
- package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
- package/src/plugins/builtin/members/headless.ts +8 -3
- package/src/plugins/builtin/members/model.ts +31 -3
- package/src/plugins/builtin/members/pane.tsx +6 -8
- package/src/plugins/builtin/mna/distress/headless.ts +4 -4
- package/src/plugins/builtin/mna/headless.ts +18 -6
- package/src/plugins/builtin/money-markets/headless.ts +5 -4
- package/src/plugins/builtin/money-markets/index.tsx +2 -0
- package/src/plugins/builtin/money-markets/series.ts +41 -0
- package/src/plugins/builtin/news/index.tsx +0 -2
- package/src/plugins/builtin/news/wire/news/detail-view.tsx +53 -104
- package/src/plugins/builtin/news/wire/news/footer.ts +2 -25
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +0 -2
- package/src/plugins/builtin/notes/cli.ts +12 -7
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/options/index.tsx +3 -0
- package/src/plugins/builtin/options/view.tsx +1 -1
- package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
- package/src/plugins/builtin/options-positioning/client.ts +7 -3
- package/src/plugins/builtin/options-positioning/headless.ts +4 -3
- package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +2 -1
- package/src/plugins/builtin/options-scenario/headless.ts +1 -0
- package/src/plugins/builtin/options-scenario/hedge.ts +2 -1
- package/src/plugins/builtin/perps/client.ts +90 -16
- package/src/plugins/builtin/perps/equity-row.tsx +52 -17
- package/src/plugins/builtin/perps/freshness.ts +66 -0
- package/src/plugins/builtin/perps/headless.ts +47 -32
- package/src/plugins/builtin/perps/index.tsx +23 -4
- package/src/plugins/builtin/perps/list-perpetuals.ts +118 -0
- package/src/plugins/builtin/perps/model.ts +20 -5
- package/src/plugins/builtin/perps/open-market.ts +15 -0
- package/src/plugins/builtin/perps/pane.tsx +76 -20
- package/src/plugins/builtin/perps/series.ts +76 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +1 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +73 -67
- package/src/plugins/builtin/plugin-module.ts +3 -0
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +5 -4
- package/src/plugins/builtin/portfolio-list/cell-version.ts +8 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +161 -0
- package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +384 -74
- package/src/plugins/builtin/portfolio-list/cli/render.ts +437 -71
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +21 -4
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +121 -47
- package/src/plugins/builtin/portfolio-list/column-values.ts +104 -26
- package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
- package/src/plugins/builtin/portfolio-list/headless.ts +84 -18
- package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
- package/src/plugins/builtin/portfolio-list/index.tsx +5 -1
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
- package/src/plugins/builtin/portfolio-list/mutations.ts +2 -9
- package/src/plugins/builtin/portfolio-list/pane/data.ts +5 -1
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +52 -9
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +33 -11
- package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +21 -1
- package/src/plugins/builtin/portfolio-list/settings.ts +17 -0
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +9 -4
- package/src/plugins/builtin/portfolio-list/table.tsx +37 -7
- package/src/plugins/builtin/power/client.ts +16 -0
- package/src/plugins/builtin/power/evidence.ts +63 -10
- package/src/plugins/builtin/power/headless.ts +77 -9
- package/src/plugins/builtin/power/index.tsx +28 -3
- package/src/plugins/builtin/power/model.ts +73 -2
- package/src/plugins/builtin/power/pane.tsx +37 -9
- package/src/plugins/builtin/power/prices-client.ts +139 -0
- package/src/plugins/builtin/power/prices-headless.ts +137 -0
- package/src/plugins/builtin/power/prices-model.ts +103 -0
- package/src/plugins/builtin/power/prices.tsx +179 -0
- package/src/plugins/builtin/rate-path/headless.ts +46 -18
- package/src/plugins/builtin/realized-vol/headless.ts +5 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -2
- package/src/plugins/builtin/research/event-model.ts +68 -24
- package/src/plugins/builtin/research/events-headless.ts +2 -1
- package/src/plugins/builtin/research/headless.ts +2 -1
- package/src/plugins/builtin/research/index.tsx +2 -0
- package/src/plugins/builtin/research-search/article.ts +65 -0
- package/src/plugins/builtin/research-search/document-view.tsx +33 -215
- package/src/plugins/builtin/research-search/model.ts +0 -9
- package/src/plugins/builtin/research-search/pane.tsx +41 -30
- package/src/plugins/builtin/research-search/snippet.ts +0 -29
- package/src/plugins/builtin/revenue-breakdown/headless.ts +18 -6
- package/src/plugins/builtin/seasonality/client.ts +15 -7
- package/src/plugins/builtin/seasonality/headless.ts +36 -12
- package/src/plugins/builtin/seasonality/index.tsx +2 -2
- package/src/plugins/builtin/seasonality/model.ts +119 -0
- package/src/plugins/builtin/seasonality/pane.tsx +108 -37
- package/src/plugins/builtin/sec/headless.ts +25 -3
- package/src/plugins/builtin/sec/index.tsx +2 -1
- package/src/plugins/builtin/series-inventory.ts +93 -0
- package/src/plugins/builtin/shared/cloud-denied.ts +15 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
- package/src/plugins/builtin/shared/command-tab.ts +30 -12
- package/src/plugins/builtin/shared/earnings-report.ts +55 -0
- package/src/plugins/builtin/shared/fred-points.ts +20 -0
- package/src/plugins/builtin/shared/free-preview.ts +47 -0
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
- package/src/plugins/builtin/shared/open-description.ts +29 -0
- package/src/plugins/builtin/shared/report-freshness.ts +12 -1
- package/src/plugins/builtin/shared/series-warning.ts +5 -0
- package/src/plugins/builtin/shared/volatility/options.ts +4 -1
- package/src/plugins/builtin/short-interest/headless.ts +1 -0
- package/src/plugins/builtin/short-interest/index.tsx +2 -0
- package/src/plugins/builtin/short-interest/series.ts +36 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +3 -2
- package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
- package/src/plugins/builtin/short-volume/headless.ts +2 -1
- package/src/plugins/builtin/short-volume/index.tsx +2 -0
- package/src/plugins/builtin/short-volume/series.ts +23 -0
- package/src/plugins/builtin/social-mentions/headless.ts +1 -1
- package/src/plugins/builtin/social-mentions/index.tsx +2 -0
- package/src/plugins/builtin/social-mentions/series.ts +23 -0
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
- package/src/plugins/builtin/supply-chain/headless.ts +43 -11
- package/src/plugins/builtin/supply-chain/model.ts +13 -0
- package/src/plugins/builtin/supply-chain/pane.tsx +8 -6
- package/src/plugins/builtin/themes/headless.ts +74 -10
- package/src/plugins/builtin/themes/model.ts +71 -4
- package/src/plugins/builtin/themes/pane.tsx +22 -5
- package/src/plugins/builtin/thirteenf/api.ts +1 -0
- package/src/plugins/builtin/thirteenf/data.ts +6 -4
- package/src/plugins/builtin/thirteenf/headless.ts +217 -36
- package/src/plugins/builtin/thirteenf/model.ts +39 -1
- package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
- package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
- package/src/plugins/builtin/thirteenf/types.ts +2 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +114 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +57 -2
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +19 -55
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +30 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +86 -0
- package/src/plugins/builtin/ticker-detail/index.tsx +26 -11
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +49 -5
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
- package/src/plugins/builtin/time-sales/headless.ts +2 -1
- package/src/plugins/builtin/time-sales/index.tsx +2 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +16 -2
- package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
- package/src/plugins/builtin/treasury-auctions/model.ts +8 -0
- package/src/plugins/builtin/vol-surface/evidence.ts +7 -1
- package/src/plugins/builtin/vol-surface/headless.ts +51 -17
- package/src/plugins/builtin/vol-surface/heat-grid.tsx +113 -0
- package/src/plugins/builtin/vol-surface/model.ts +39 -6
- package/src/plugins/builtin/vol-surface/pane.tsx +14 -13
- package/src/plugins/builtin/vol-surface/stored.ts +63 -3
- package/src/plugins/builtin/vol-surface/surface.tsx +30 -2
- package/src/plugins/builtin/volatility/index.tsx +2 -0
- package/src/plugins/builtin/volatility/series.ts +84 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +6 -5
- package/src/plugins/builtin/world-venue-map/basemap.ts +6 -3
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/geo-series.ts +26 -1
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +6 -6
- package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
- package/src/plugins/builtin/world-venue-map/index.ts +2 -1
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +24 -13
- package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +144 -13
- package/src/plugins/builtin/world-venue-map/model.ts +56 -19
- package/src/plugins/builtin/world-venue-map/pane.tsx +5 -2
- package/src/plugins/builtin/yield-curve/chart.ts +2 -2
- package/src/plugins/builtin/yield-curve/curves.ts +21 -8
- package/src/plugins/builtin/yield-curve/headless.ts +71 -18
- package/src/plugins/builtin/yield-curve/index.tsx +4 -2
- package/src/plugins/builtin/yield-curve/series.ts +86 -0
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/installer.ts +2 -2
- package/src/plugins/loader.ts +15 -0
- package/src/plugins/manager-node.ts +1 -1
- package/src/plugins/{builtin/plugin-marketplace → marketplace}/feed.ts +2 -2
- package/src/plugins/{builtin/plugin-marketplace → marketplace}/model.ts +6 -6
- package/src/plugins/{builtin/plugin-marketplace → marketplace}/store.ts +1 -1
- package/src/plugins/registry/host-actions.ts +11 -0
- package/src/plugins/registry/index.ts +89 -4
- package/src/portfolio/collection-name.ts +31 -0
- package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
- package/src/portfolio/position-value.ts +40 -0
- package/src/portfolio/valuation-basis.ts +79 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
- package/src/public/time-series.ts +17 -0
- package/src/react/auto-refresh.ts +13 -3
- package/src/react/input.ts +33 -1
- package/src/react/key-repeat.ts +86 -0
- package/src/remote/app-host.tsx +20 -4
- package/src/remote/confirm-change.tsx +85 -0
- package/src/remote/controller-utils.ts +8 -1
- package/src/remote/controller.ts +144 -7
- package/src/remote/pane-screenshot.ts +47 -0
- package/src/remote/schema.ts +65 -2
- package/src/remote/types.ts +30 -0
- package/src/remote/watchlist.ts +306 -0
- package/src/renderers/browser/main.tsx +4 -3
- package/src/renderers/browser/research-entry.ts +4 -2
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/dom/data-table/frozen-column.ts +3 -1
- package/src/renderers/dom/data-table/index.tsx +33 -6
- package/src/renderers/dom/data-table/row.tsx +30 -1
- package/src/renderers/dom/desktop/control-styles.ts +63 -1
- package/src/renderers/dom/desktop/controls.tsx +30 -23
- package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
- package/src/renderers/dom/desktop/icons.tsx +16 -0
- package/src/renderers/dom/dom-ui-host.tsx +3 -0
- package/src/renderers/dom/host/block-glyph-canvas.tsx +6 -3
- package/src/renderers/dom/host/box.tsx +8 -0
- package/src/renderers/dom/host/chart-surface.tsx +33 -2
- package/src/renderers/dom/host/live-frame.ts +6 -2
- package/src/renderers/dom/host/overflow-fade.ts +14 -1
- package/src/renderers/dom/host/scroll-box.tsx +32 -0
- package/src/renderers/dom/host/size-observer.ts +41 -0
- package/src/renderers/dom/host/sticky-scroll.ts +128 -0
- package/src/renderers/dom/host/style.ts +1 -1
- package/src/renderers/dom/host/surface-3d.tsx +19 -7
- package/src/renderers/dom/host/surface-fit.ts +406 -0
- package/src/renderers/dom/host/text.tsx +1 -1
- package/src/renderers/dom/input-host.tsx +1 -0
- package/src/renderers/dom/styles.css +102 -5
- package/src/renderers/electrobun/bun/application-menu/click.ts +18 -0
- package/src/renderers/electrobun/bun/index.ts +3 -2
- package/src/renderers/electrobun/shared/protocol.ts +1 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +29 -2
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +63 -20
- package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
- package/src/renderers/electrobun/view/main.tsx +5 -3
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +2 -0
- package/src/renderers/opentui/chart-surface.tsx +1 -0
- package/src/renderers/opentui/frame-capture.ts +33 -0
- package/src/renderers/opentui/host.tsx +10 -13
- package/src/renderers/opentui/pane-image/glyphs-license.txt +107 -0
- package/src/renderers/opentui/pane-image/glyphs.json +1 -0
- package/src/renderers/opentui/pane-image/index.ts +107 -0
- package/src/renderers/opentui/pane-image/raster.ts +428 -0
- package/src/renderers/opentui/start.tsx +3 -3
- package/src/renderers/opentui/test-utils.tsx +3 -0
- package/src/renderers/opentui/ui-host.tsx +29 -1
- package/src/series/capability.ts +75 -0
- package/src/series/csv.ts +160 -0
- package/src/series/files.ts +107 -0
- package/src/series/registry.ts +198 -0
- package/src/series/resolve.ts +108 -0
- package/src/series/standalone.ts +48 -0
- package/src/series/types.ts +153 -0
- package/src/series/validate.ts +171 -0
- package/src/shares/chat.ts +34 -0
- package/src/shares/dialog.tsx +295 -0
- package/src/shares/flow.tsx +56 -0
- package/src/shares/live.ts +14 -22
- package/src/shares/pane-image.ts +152 -0
- package/src/shares/personal-pane.ts +64 -0
- package/src/shares/portable-layout.ts +4 -2
- package/src/shares/prepare.ts +20 -0
- package/src/sources/gloomberb-cloud/index.ts +109 -10
- package/src/sources/gloomberb-cloud/normalizers.ts +3 -0
- package/src/sources/gloomberb-cloud/perpetuals.ts +249 -0
- package/src/sources/history-result.ts +1 -0
- package/src/sources/history-retention.ts +11 -0
- package/src/sources/listing-symbols.ts +4 -1
- package/src/sources/listing-target.ts +4 -0
- package/src/sources/provider-router/batches.ts +4 -1
- package/src/sources/provider-router/cache.ts +4 -2
- package/src/sources/provider-router/cached-routes.ts +1 -1
- package/src/sources/provider-router/financial-routes.ts +1 -0
- package/src/sources/provider-router/financials.ts +13 -0
- package/src/sources/provider-router/history.ts +43 -25
- package/src/sources/provider-router/index.ts +14 -0
- package/src/sources/provider-router/search.ts +1 -0
- package/src/state/hooks/inline-tickers.ts +49 -11
- package/src/sync/core-contributors.ts +1 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/theme-context.tsx +15 -1
- package/src/tickers/company-name.ts +75 -0
- package/src/tickers/instrument-kind.ts +34 -1
- package/src/tickers/listing-name.ts +34 -0
- package/src/tickers/listing-venues.ts +132 -0
- package/src/tickers/open-target.ts +13 -4
- package/src/tickers/perpetual-listing.ts +151 -0
- package/src/tickers/prediction-listing.ts +26 -0
- package/src/tickers/search/index.ts +72 -11
- package/src/tickers/search/ranking.ts +98 -20
- package/src/tickers/search/types.ts +7 -1
- package/src/tickers/ticker-changes.ts +213 -0
- package/src/tickers/us-listing.ts +34 -0
- package/src/time-series/economic.ts +2 -6
- package/src/time-series/hooks.ts +9 -0
- package/src/time-series/ice-credit.ts +39 -0
- package/src/time-series/resolve.ts +211 -29
- package/src/time-series/studies.ts +1 -0
- package/src/time-series/types.ts +12 -2
- package/src/time-series/use-chart-resolution.ts +32 -0
- package/src/types/config.ts +10 -2
- package/src/types/data-provider.ts +11 -0
- package/src/types/financials.ts +62 -1
- package/src/types/headless.ts +113 -0
- package/src/types/instrument.ts +4 -0
- package/src/types/plugin.ts +52 -2
- package/src/types/price-history.ts +7 -0
- package/src/types/ticker-changes.ts +26 -0
- package/src/types/ticker.ts +14 -0
- package/src/ui/context-menu.tsx +13 -1
- package/src/ui/host.tsx +57 -3
- package/src/ui/live-resize.ts +91 -0
- package/src/ui/live-stretch.ts +153 -0
- package/src/ui/measured-cells.ts +58 -0
- package/src/ui/sticky-scroll.ts +7 -0
- package/src/utils/basis-points.ts +17 -0
- package/src/utils/central-banks.ts +76 -0
- package/src/utils/cli-output.ts +131 -15
- package/src/utils/concurrency.ts +25 -0
- package/src/utils/crypto-pair.ts +20 -0
- package/src/utils/currency-pair.ts +19 -0
- package/src/utils/currency-units.ts +11 -0
- package/src/utils/datetime-format.ts +27 -6
- package/src/utils/decimal-comma.ts +19 -0
- package/src/utils/dom-screenshot-css.ts +265 -0
- package/src/utils/dom-screenshot-rasters.ts +276 -0
- package/src/utils/dom-screenshot.ts +439 -52
- package/src/utils/double-escape-close.ts +15 -1
- package/src/utils/exchange-rate-snapshot.ts +6 -2
- package/src/utils/exchanges.ts +143 -1
- package/src/utils/format.ts +35 -5
- package/src/utils/forward-dividend.ts +14 -0
- package/src/utils/fundamentals.ts +66 -0
- package/src/utils/futures-generic.ts +6 -12
- package/src/utils/fx-market-hours.ts +15 -5
- package/src/utils/fx-status.ts +6 -1
- package/src/utils/inline-content-tokenizer.ts +22 -3
- package/src/utils/market-capitalization.ts +8 -0
- package/src/utils/one-shot.ts +73 -0
- package/src/utils/options.ts +37 -8
- package/src/utils/price-history.ts +99 -42
- package/src/utils/sec-eps-basis.ts +24 -11
- package/src/utils/sec.ts +61 -7
- package/src/utils/utc-time.ts +63 -4
- package/src/plugins/builtin/fx-matrix/freshness.ts +0 -65
- /package/src/plugins/{builtin/plugin-marketplace → marketplace}/activation.ts +0 -0
- /package/src/plugins/{builtin/plugin-marketplace → marketplace}/ids.ts +0 -0
- /package/src/plugins/{builtin/plugin-marketplace → marketplace}/packs.ts +0 -0
- /package/src/{plugins/builtin/cloud → tickers}/starter-symbols.ts +0 -0
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
HeadlessSeriesResult,
|
|
9
9
|
HeadlessSnapshotResult,
|
|
10
10
|
} from "../../types/plugin";
|
|
11
|
-
import { parseReportTime, type ReportTime } from "../../utils/utc-time";
|
|
11
|
+
import { localTimeSuffix, parseReportTime, type ReportTime } from "../../utils/utc-time";
|
|
12
12
|
import { isRecord } from "../../utils/guards";
|
|
13
13
|
import { latestRegularSessionClose } from "../../market-data/market/freshness";
|
|
14
14
|
import { reportMarketSession, type ReportMarket, type SessionObservation } from "./market-session";
|
|
@@ -27,6 +27,8 @@ export interface ReportFreshness {
|
|
|
27
27
|
asOf: string | null;
|
|
28
28
|
/** Oldest observation, when it is more than a day older than `asOf`. */
|
|
29
29
|
oldest?: string;
|
|
30
|
+
/** With a declared `citeOldest`: the oldest observation whenever it is older than `asOf`. Exports cite it. */
|
|
31
|
+
oldestObservation?: string;
|
|
30
32
|
status: ReportFreshnessStatus;
|
|
31
33
|
/** How far the data is held back; the most of its rows when they differ... */
|
|
32
34
|
delayMinutes?: number;
|
|
@@ -40,14 +42,54 @@ export interface ReportFreshness {
|
|
|
40
42
|
/** ...and what the rest are. */
|
|
41
43
|
feed?: "live" | "delayed";
|
|
42
44
|
basis?: string;
|
|
45
|
+
/** Set when the dates are the start of a period: the status line then reads `Sep 2026 (monthly)`. */
|
|
46
|
+
periodicity?: "monthly" | "quarterly" | "annual";
|
|
43
47
|
/** The local date of the session close `asOf` is, when the newest observation is its venue's latest close. */
|
|
44
48
|
asOfClose?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Whose trading day the dated as-of (`asOfClose`, or a date-only `asOf`) is,
|
|
51
|
+
* when one market's calendar dates it: `US`, or a venue code such as `ASX`.
|
|
52
|
+
*/
|
|
53
|
+
tradingDayMarket?: string;
|
|
45
54
|
/** Where the venues of a quote report stand now, from their session calendars. */
|
|
46
55
|
market?: ReportMarket;
|
|
56
|
+
/**
|
|
57
|
+
* For a dataset (declared `dataset`, with no quote among its rows): whole UTC
|
|
58
|
+
* days from the last day its newest observation covers to when this report
|
|
59
|
+
* was built. A capture's status line then reads `observed Sun 4 Oct · lag 6d`.
|
|
60
|
+
*/
|
|
61
|
+
lagDays?: number;
|
|
62
|
+
/**
|
|
63
|
+
* What the newest observation is, for a dataset that names it (`last
|
|
64
|
+
* trade`): every line then reads `Source: DTCC · last trade 2026-10-09 · lag 2 days`.
|
|
65
|
+
*/
|
|
66
|
+
observation?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Each source's own newest observation, in the order declared, when the data
|
|
69
|
+
* comes from several sources polled apart: `asOf` is the newest of them.
|
|
70
|
+
*/
|
|
71
|
+
sources?: ReportSourceAsOf[];
|
|
72
|
+
/**
|
|
73
|
+
* Whole minutes from the oldest of `sources` (or, declared `oldestAge`, the
|
|
74
|
+
* oldest observation) to when this report was built: `oldest 9 min`.
|
|
75
|
+
*/
|
|
76
|
+
oldestAgeMinutes?: number;
|
|
77
|
+
/** What the figures are, said after the status: `funding = current estimate, pays 08:00 UTC`. */
|
|
78
|
+
note?: string;
|
|
79
|
+
/** Who published the figures, when the data names them. */
|
|
80
|
+
publisher?: string;
|
|
81
|
+
/** When the publisher released the data, an ISO instant in UTC or an ISO date, when the data states it. */
|
|
82
|
+
publishedAt?: string;
|
|
47
83
|
/** When this report was built. */
|
|
48
84
|
retrievedAt: string;
|
|
49
85
|
}
|
|
50
86
|
|
|
87
|
+
/** One source's newest observation: an ISO instant in UTC. */
|
|
88
|
+
interface ReportSourceAsOf {
|
|
89
|
+
source: string;
|
|
90
|
+
asOf: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
51
93
|
const DEFAULT_REPORT_SOURCE = "Gloom Cloud";
|
|
52
94
|
|
|
53
95
|
/** Top-level row and metadata keys that say when a value was observed. */
|
|
@@ -159,12 +201,12 @@ function collect(
|
|
|
159
201
|
definition: Pick<HeadlessPaneDefinition, "shape">,
|
|
160
202
|
result: HeadlessPaneResult,
|
|
161
203
|
now: number,
|
|
162
|
-
{ observedKey, ignoreStaleFlags }: Pick<HeadlessPaneFreshness, "observedKey" | "ignoreStaleFlags">,
|
|
204
|
+
{ observedKey, ignoreStaleFlags, observations: declaredObservations }: Pick<HeadlessPaneFreshness, "observedKey" | "ignoreStaleFlags" | "observations">,
|
|
163
205
|
): { signals: FeedSignals; observations: Observations } {
|
|
164
206
|
const signals = emptySignals();
|
|
165
207
|
const observations: Observations = { units: [], extra: [] };
|
|
166
208
|
const rowKeys = observedKey ? [observedKey] : OBSERVATION_KEYS;
|
|
167
|
-
for (const row of resultRecords(definition, result)) {
|
|
209
|
+
for (const row of declaredObservations ?? resultRecords(definition, result)) {
|
|
168
210
|
if (!isRecord(row)) continue;
|
|
169
211
|
readFeedSignals(row, signals);
|
|
170
212
|
const time = observedTime(row, now, rowKeys)
|
|
@@ -173,7 +215,7 @@ function collect(
|
|
|
173
215
|
readSession(row, time, signals);
|
|
174
216
|
if (time) observations.units.push(time);
|
|
175
217
|
}
|
|
176
|
-
if (definition.shape === "series") {
|
|
218
|
+
if (definition.shape === "series" && !declaredObservations) {
|
|
177
219
|
for (const series of (result as HeadlessSeriesResult).series) {
|
|
178
220
|
const record = series as unknown as Record<string, unknown>;
|
|
179
221
|
readFeedSignals(record, signals);
|
|
@@ -190,6 +232,8 @@ function collect(
|
|
|
190
232
|
const time = observedKey ? null : observedTime(result.metadata, now)
|
|
191
233
|
?? (observations.units.length ? null : observedTime(result.metadata, now, UPDATE_KEYS));
|
|
192
234
|
if (time) observations.extra.push(time);
|
|
235
|
+
// A board whose figures follow one venue's sessions (HM's) names it as a quote row does.
|
|
236
|
+
readSession(result.metadata, time, signals);
|
|
193
237
|
}
|
|
194
238
|
if (definition.shape === "snapshot" && !observedKey) {
|
|
195
239
|
const time = parseReportTime((result as HeadlessSnapshotResult).asOf);
|
|
@@ -230,13 +274,17 @@ function worstFeedStatus(statuses: Array<"live" | "delayed" | "stale">): "live"
|
|
|
230
274
|
), null);
|
|
231
275
|
}
|
|
232
276
|
|
|
233
|
-
/**
|
|
234
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Completed sessions after the day of `newest`, counted back from `now`, up to
|
|
279
|
+
* `limit`: the US's, or `exchange`'s when the app knows its sessions.
|
|
280
|
+
*/
|
|
281
|
+
function sessionsAfter(newest: ReportTime, now: number, limit: number, exchange?: string): number {
|
|
235
282
|
const newestDate = new Date(newest.time).toISOString().slice(0, 10);
|
|
283
|
+
const venue = exchange && latestRegularSessionClose(exchange, now) ? exchange : "NYSE";
|
|
236
284
|
let count = 0;
|
|
237
285
|
let cursor = now;
|
|
238
286
|
while (count < limit) {
|
|
239
|
-
const close = latestRegularSessionClose(
|
|
287
|
+
const close = latestRegularSessionClose(venue, cursor);
|
|
240
288
|
if (!close || close.date <= newestDate) break;
|
|
241
289
|
count += 1;
|
|
242
290
|
cursor = close.close - 1;
|
|
@@ -250,7 +298,26 @@ function overdue(declared: HeadlessPaneFreshness, asOf: ReportTime | null, now:
|
|
|
250
298
|
if (nextExpected != null && now > nextExpected.time + RELEASE_GRACE_MS) return true;
|
|
251
299
|
if (!asOf) return false;
|
|
252
300
|
if (declared.maxAgeMinutes != null && now - asOf.time > declared.maxAgeMinutes * 60_000) return true;
|
|
253
|
-
return declared.cadence === "daily" && sessionsAfter(asOf, now, 2) > 1;
|
|
301
|
+
return declared.cadence === "daily" && sessionsAfter(asOf, now, 2, declared.cadenceExchange) > 1;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Whole UTC days from the last day an observation covers to `now`: its own
|
|
306
|
+
* day, or the last day of the month, quarter or year a periodic date starts.
|
|
307
|
+
* September's figure read on 10 Oct lags 10 days, not 39.
|
|
308
|
+
*/
|
|
309
|
+
function datasetLagDays(observed: ReportTime, periodicity: ReportFreshness["periodicity"], now: number): number {
|
|
310
|
+
const day = new Date(observed.time);
|
|
311
|
+
const year = day.getUTCFullYear();
|
|
312
|
+
const month = day.getUTCMonth();
|
|
313
|
+
const through = !periodicity ? Date.UTC(year, month, day.getUTCDate())
|
|
314
|
+
// Day 0 of the month after the period is its last day.
|
|
315
|
+
: periodicity === "monthly" ? Date.UTC(year, month + 1, 0)
|
|
316
|
+
: periodicity === "quarterly" ? Date.UTC(year, month - (month % 3) + 3, 0)
|
|
317
|
+
: Date.UTC(year, 12, 0);
|
|
318
|
+
const today = new Date(now);
|
|
319
|
+
const todayStart = Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
|
|
320
|
+
return Math.max(0, Math.round((todayStart - through) / DAY_MS));
|
|
254
321
|
}
|
|
255
322
|
|
|
256
323
|
interface FreshnessInputs {
|
|
@@ -260,13 +327,29 @@ interface FreshnessInputs {
|
|
|
260
327
|
now: number;
|
|
261
328
|
}
|
|
262
329
|
|
|
330
|
+
/** The declared sources that name themselves and carry a time, in the order declared. */
|
|
331
|
+
function declaredSources(declared: HeadlessPaneFreshness, now: number): Array<{ source: string; time: ReportTime }> {
|
|
332
|
+
return (declared.sources ?? []).flatMap(({ source, asOf }) => {
|
|
333
|
+
const name = source.trim();
|
|
334
|
+
const time = observedTime({ asOf }, now, ["asOf"]);
|
|
335
|
+
return name && time && !time.dateOnly ? [{ source: name, time }] : [];
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
263
339
|
function resolveFreshness({ declared, signals, observations, now }: FreshnessInputs): ReportFreshness {
|
|
264
|
-
const
|
|
340
|
+
const sources = declaredSources(declared, now);
|
|
341
|
+
// Sources date the data by their own observations, as a declared as-of does.
|
|
342
|
+
const declaredAsOf = observedTime({ asOf: declared.asOf }, now, ["asOf"]) ?? newest(sources.map(({ time }) => time));
|
|
265
343
|
const asOf = declaredAsOf ?? newest([...observations.units, ...observations.extra]);
|
|
344
|
+
// The oldest source, not the newest, says how far behind the view can be.
|
|
345
|
+
const agedFrom = sources.length ? oldest(sources.map(({ time }) => time))
|
|
346
|
+
: declared.oldestAge ? oldest(observations.units) ?? asOf : null;
|
|
347
|
+
const oldestAgeMinutes = agedFrom && !agedFrom.dateOnly ? Math.max(0, Math.floor((now - agedFrom.time) / 60_000)) : null;
|
|
266
348
|
// A loader that dates its data itself also says how old the oldest part is, or nothing;
|
|
267
349
|
// `oldest: null` says the rows are a history, whose first entry is not stale data.
|
|
268
350
|
const oldestTime = declared.oldest != null ? parseReportTime(declared.oldest)
|
|
269
351
|
: declaredAsOf || declared.oldest === null ? null : oldest(observations.units);
|
|
352
|
+
const oldestUnit = declared.citeOldest ? oldest(observations.units) : null;
|
|
270
353
|
const late = overdue(declared, asOf, now);
|
|
271
354
|
|
|
272
355
|
let status: ReportFreshnessStatus;
|
|
@@ -320,22 +403,44 @@ function resolveFreshness({ declared, signals, observations, now }: FreshnessInp
|
|
|
320
403
|
}
|
|
321
404
|
}
|
|
322
405
|
}
|
|
323
|
-
const { market, closeDate } = reportMarketSession(signals.sessions, now);
|
|
406
|
+
const { market, closeDate, closeMarket } = reportMarketSession(signals.sessions, now);
|
|
324
407
|
// The close wording dates the newest observation, so only when that is what `asOf` is.
|
|
325
408
|
const asOfClose = closeDate && asOf && !declaredAsOf ? closeDate : null;
|
|
326
|
-
|
|
409
|
+
const tradingDayMarket = asOfClose ? closeMarket
|
|
410
|
+
: asOf?.dateOnly ? declared.tradingDayMarket?.trim() || null : null;
|
|
411
|
+
const periodicity = declared.periodicity && asOf?.dateOnly ? declared.periodicity : undefined;
|
|
412
|
+
// Rows that are quotes (a feed, a venue's session) keep the market line, even on a dataset's pane.
|
|
413
|
+
const quoted = signals.live || signals.delayed || signals.sessions.length > 0;
|
|
414
|
+
// A dataset disseminated with a delay (DTCC's swap tape) lags its newest observation all the same.
|
|
415
|
+
const lagDays = declared.dataset && asOf && !quoted && (status === "not-a-feed" || status === "stale" || status === "delayed")
|
|
416
|
+
? datasetLagDays(asOf, periodicity, now) : null;
|
|
417
|
+
const observation = lagDays != null ? declared.observation?.trim() : undefined;
|
|
418
|
+
|
|
419
|
+
const note = declared.note?.trim();
|
|
420
|
+
const publisher = declared.publisher?.trim();
|
|
421
|
+
const publishedAt = parseReportTime(declared.publishedAt);
|
|
327
422
|
return {
|
|
328
|
-
source: declared.source?.trim() || DEFAULT_REPORT_SOURCE,
|
|
423
|
+
source: declared.source?.trim() || (sources.length ? [...new Set(sources.map(({ source }) => source))].join(", ") : DEFAULT_REPORT_SOURCE),
|
|
329
424
|
asOf: asOf ? isoTime(asOf) : null,
|
|
330
425
|
...(asOf && oldestTime && asOf.time - oldestTime.time > OLDEST_GAP_MS ? { oldest: isoTime(oldestTime) } : {}),
|
|
426
|
+
...(asOf && oldestUnit && oldestUnit.time < asOf.time ? { oldestObservation: isoTime(oldestUnit) } : {}),
|
|
331
427
|
status,
|
|
332
428
|
...(delayMinutes != null && delayMinutes > 0 ? { delayMinutes } : {}),
|
|
333
429
|
...(minDelayMinutes != null && minDelayMinutes > 0 ? { minDelayMinutes } : {}),
|
|
334
430
|
...(status === "stale" && staleAt ? { ageMinutes: Math.max(0, Math.floor((now - staleAt.time) / 60_000)) } : {}),
|
|
335
431
|
...(partial ?? {}),
|
|
336
432
|
...(status === "not-a-feed" && declared.basis ? { basis: declared.basis } : {}),
|
|
433
|
+
...(periodicity ? { periodicity } : {}),
|
|
337
434
|
...(asOfClose ? { asOfClose } : {}),
|
|
435
|
+
...(tradingDayMarket ? { tradingDayMarket } : {}),
|
|
338
436
|
...(market ? { market } : {}),
|
|
437
|
+
...(lagDays != null ? { lagDays } : {}),
|
|
438
|
+
...(observation ? { observation } : {}),
|
|
439
|
+
...(sources.length ? { sources: sources.map(({ source, time }) => ({ source, asOf: isoTime(time) })) } : {}),
|
|
440
|
+
...(oldestAgeMinutes != null ? { oldestAgeMinutes } : {}),
|
|
441
|
+
...(note ? { note } : {}),
|
|
442
|
+
...(publisher ? { publisher } : {}),
|
|
443
|
+
...(publishedAt ? { publishedAt: isoTime(publishedAt) } : {}),
|
|
339
444
|
retrievedAt: new Date(now).toISOString(),
|
|
340
445
|
};
|
|
341
446
|
}
|
|
@@ -401,20 +506,52 @@ const DAY_MS = 24 * 60 * 60_000;
|
|
|
401
506
|
/** A reopen further ahead than this reads with its date, not just its weekday. */
|
|
402
507
|
const WEEKDAY_ONLY_MS = 6 * DAY_MS;
|
|
403
508
|
|
|
404
|
-
/**
|
|
405
|
-
|
|
509
|
+
/**
|
|
510
|
+
* `Fri 9 Oct 2026` for a `YYYY-MM-DD` date. Always with its year: a report
|
|
511
|
+
* read later, or pasted somewhere, still says which day it means.
|
|
512
|
+
*/
|
|
513
|
+
function dayText(date: string): string {
|
|
514
|
+
const day = new Date(`${date.slice(0, 10)}T00:00:00Z`);
|
|
515
|
+
if (!Number.isFinite(day.getTime())) return date;
|
|
516
|
+
return `${WEEKDAYS[day.getUTCDay()]} ${day.getUTCDate()} ${MONTHS[day.getUTCMonth()]} ${day.getUTCFullYear()}`;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* `US trading day Fri 9 Oct 2026`: a date names whose day it is when one
|
|
521
|
+
* market's calendar dates it, so a reader a day ahead of New York does not take
|
|
522
|
+
* the US Friday for their own. Never shifted to the reader's zone.
|
|
523
|
+
*/
|
|
524
|
+
function tradingDayText(date: string, market: string | undefined): string {
|
|
525
|
+
return market ? `${market} trading day ${dayText(date)}` : dayText(date);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/** `Sep 2026`, `Q2 2026` or `2026` for the period a date starts. */
|
|
529
|
+
function periodText(date: string, periodicity: NonNullable<ReportFreshness["periodicity"]>): string {
|
|
406
530
|
const day = new Date(`${date.slice(0, 10)}T00:00:00Z`);
|
|
407
531
|
if (!Number.isFinite(day.getTime())) return date;
|
|
408
|
-
const year = day.getUTCFullYear()
|
|
409
|
-
|
|
532
|
+
const year = day.getUTCFullYear();
|
|
533
|
+
const month = day.getUTCMonth();
|
|
534
|
+
return periodicity === "monthly" ? `${MONTHS[month]} ${year}`
|
|
535
|
+
: periodicity === "quarterly" ? `Q${Math.floor(month / 3) + 1} ${year}`
|
|
536
|
+
: `${year}`;
|
|
410
537
|
}
|
|
411
538
|
|
|
412
|
-
/**
|
|
413
|
-
function
|
|
539
|
+
/** The period a FRED series frequency ("Monthly", "Quarterly") publishes in; null for daily and weekly series, whose dates are days. */
|
|
540
|
+
export function periodicityOf(frequency: string | null | undefined): ReportFreshness["periodicity"] | null {
|
|
541
|
+
const word = frequency?.trim().toLowerCase() ?? "";
|
|
542
|
+
return word.startsWith("monthly") ? "monthly" : word.startsWith("quarterly") ? "quarterly" : word.startsWith("annual") ? "annual" : null;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* `Fri 9 Oct 2026 23:59 UTC`, or `Fri 9 Oct 2026` for a date. With `local`, the
|
|
547
|
+
* reader's own time follows when they set a zone: `(Sat 10 Oct 08:59 Asia/Tokyo)`.
|
|
548
|
+
*/
|
|
549
|
+
function timeText(value: string, local: boolean): string {
|
|
414
550
|
const time = parseReportTime(value);
|
|
415
551
|
if (!time) return value;
|
|
416
552
|
const iso = new Date(time.time).toISOString();
|
|
417
|
-
|
|
553
|
+
if (time.dateOnly) return dayText(iso);
|
|
554
|
+
return `${dayText(iso)} ${iso.slice(11, 16)} UTC${local ? localTimeSuffix(time.time) : ""}`;
|
|
418
555
|
}
|
|
419
556
|
|
|
420
557
|
/**
|
|
@@ -449,6 +586,16 @@ function ageText(minutes: number): string {
|
|
|
449
586
|
return `${Math.floor(hours / 24)} days`;
|
|
450
587
|
}
|
|
451
588
|
|
|
589
|
+
/**
|
|
590
|
+
* How many rows are stale when only some are: `2 of 16 stale`, or `2 stale`
|
|
591
|
+
* when `short`. Null when the report does not count them. One wording for a
|
|
592
|
+
* report's status line, a capture's and the status a capture prints.
|
|
593
|
+
*/
|
|
594
|
+
export function staleRowsText(freshness: Pick<ReportFreshness, "staleCount" | "observationCount">, short = false): string | null {
|
|
595
|
+
if (freshness.staleCount == null || freshness.observationCount == null) return null;
|
|
596
|
+
return `${short ? freshness.staleCount : `${freshness.staleCount} of ${freshness.observationCount}`} stale`;
|
|
597
|
+
}
|
|
598
|
+
|
|
452
599
|
/** `short` counts stale rows without their total (`2 stale`), for a narrow capture. */
|
|
453
600
|
function statusText(freshness: ReportFreshness, short = false): string {
|
|
454
601
|
switch (freshness.status) {
|
|
@@ -457,12 +604,13 @@ function statusText(freshness: ReportFreshness, short = false): string {
|
|
|
457
604
|
case "delayed":
|
|
458
605
|
return delayedText(freshness);
|
|
459
606
|
case "stale": {
|
|
460
|
-
|
|
607
|
+
const stale = staleRowsText(freshness, short);
|
|
608
|
+
if (stale) {
|
|
461
609
|
const rest = freshness.feed === "live" ? "live" : freshness.feed === "delayed" ? delayedText(freshness) : null;
|
|
462
|
-
|
|
463
|
-
return `${rest ? `${rest}, ` : ""}${count} stale`;
|
|
610
|
+
return `${rest ? `${rest}, ` : ""}${stale}`;
|
|
464
611
|
}
|
|
465
|
-
|
|
612
|
+
// A line that says how old its oldest observation is does not say it twice.
|
|
613
|
+
return freshness.ageMinutes != null && freshness.oldestAgeMinutes == null ? `stale (${ageText(freshness.ageMinutes)} old)` : "stale";
|
|
466
614
|
}
|
|
467
615
|
case "not-a-feed":
|
|
468
616
|
return freshness.basis ? `not a live feed (${freshness.basis})` : "not a live feed";
|
|
@@ -475,32 +623,66 @@ function statusText(freshness: ReportFreshness, short = false): string {
|
|
|
475
623
|
}
|
|
476
624
|
}
|
|
477
625
|
|
|
626
|
+
/** Whether an ISO instant falls on the UTC day the report was built. */
|
|
627
|
+
function onRetrievalDay(iso: string, retrievedAt: string): boolean {
|
|
628
|
+
return iso.slice(0, 10) === retrievedAt.slice(0, 10);
|
|
629
|
+
}
|
|
630
|
+
|
|
478
631
|
/**
|
|
479
632
|
* The dated as-of: a session close, a UTC time, a date, or when the report was
|
|
480
|
-
* retrieved; with the oldest observation unless `short
|
|
633
|
+
* retrieved; with the oldest observation unless `short`, or when the line says
|
|
634
|
+
* how old the oldest is instead. `undated` leaves the day off a time of the
|
|
635
|
+
* day the report was built, as a pane footer reads today.
|
|
636
|
+
*/
|
|
637
|
+
function asOfText(freshness: ReportFreshness, short: boolean, local: boolean, undated = false): string {
|
|
638
|
+
if (!freshness.asOf) return `retrieved ${timeText(freshness.retrievedAt, local)}`;
|
|
639
|
+
const market = freshness.tradingDayMarket;
|
|
640
|
+
const period = freshness.periodicity;
|
|
641
|
+
const time = parseReportTime(freshness.asOf);
|
|
642
|
+
const asOf = period ? `${periodText(freshness.asOf, period)} (${period})`
|
|
643
|
+
: freshness.asOfClose
|
|
644
|
+
? `${tradingDayText(freshness.asOfClose, market)} close`
|
|
645
|
+
: time?.dateOnly ? tradingDayText(freshness.asOf, market)
|
|
646
|
+
: undated && time && onRetrievalDay(new Date(time.time).toISOString(), freshness.retrievedAt)
|
|
647
|
+
? `${new Date(time.time).toISOString().slice(11, 16)} UTC` : timeText(freshness.asOf, local);
|
|
648
|
+
const oldest = freshness.oldest && (period ? periodText(freshness.oldest, period) : dayText(freshness.oldest));
|
|
649
|
+
return oldest && !short && freshness.oldestAgeMinutes == null ? `${asOf} (oldest ${oldest})` : asOf;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Each source's own as-of, the zone named once at the end:
|
|
654
|
+
* `Sun 11 Oct 2026 · Binance 02:15 · Bybit 02:24 UTC`. The day leads, the newest source's,
|
|
655
|
+
* and a source observed on another day carries its own (`Binance Sat 10 Oct
|
|
656
|
+
* 23:58`). `undated` leaves the leading day off when it is the day the report
|
|
657
|
+
* was built.
|
|
481
658
|
*/
|
|
482
|
-
function
|
|
483
|
-
|
|
484
|
-
const
|
|
485
|
-
|
|
659
|
+
function sourcesAsOfParts(freshness: ReportFreshness, sources: readonly ReportSourceAsOf[], undated: boolean): string[] {
|
|
660
|
+
const times = sources.map(({ source, asOf }) => ({ source, iso: new Date(Date.parse(asOf)).toISOString() }));
|
|
661
|
+
const day = times.reduce((latest, { iso }) => (iso > latest ? iso : latest), "").slice(0, 10);
|
|
662
|
+
const parts = times.map(({ source, iso }) => {
|
|
663
|
+
const date = iso.slice(0, 10) === day ? "" : `${dayText(iso).replace(/ \d{4}$/, "")} `;
|
|
664
|
+
return `${source} ${date}${iso.slice(11, 16)}`;
|
|
665
|
+
});
|
|
666
|
+
parts[parts.length - 1] += " UTC";
|
|
667
|
+
return undated && onRetrievalDay(day, freshness.retrievedAt) ? parts : [dayText(day), ...parts];
|
|
486
668
|
}
|
|
487
669
|
|
|
488
670
|
/**
|
|
489
671
|
* When the first venue opens again: its UTC time when that is later the same
|
|
490
672
|
* UTC day, else its weekday at the venue (`Mon`), with the date a week out.
|
|
491
673
|
*/
|
|
492
|
-
function reopenText(market: ReportMarket, now: number): string | null {
|
|
674
|
+
function reopenText(market: ReportMarket, now: number, local: boolean): string | null {
|
|
493
675
|
if (!market.reopensAt || !market.reopensOn) return null;
|
|
494
676
|
const at = Date.parse(market.reopensAt);
|
|
495
677
|
if (!Number.isFinite(at)) return null;
|
|
496
678
|
const iso = new Date(at).toISOString();
|
|
497
|
-
if (iso.slice(0, 10) === new Date(now).toISOString().slice(0, 10)) return `${iso.slice(11, 16)} UTC`;
|
|
498
|
-
return at - now > WEEKDAY_ONLY_MS ? dayText(market.reopensOn
|
|
679
|
+
if (iso.slice(0, 10) === new Date(now).toISOString().slice(0, 10)) return `${iso.slice(11, 16)} UTC${local ? localTimeSuffix(at) : ""}`;
|
|
680
|
+
return at - now > WEEKDAY_ONLY_MS ? dayText(market.reopensOn) : WEEKDAYS[new Date(`${market.reopensOn}T00:00:00Z`).getUTCDay()]!;
|
|
499
681
|
}
|
|
500
682
|
|
|
501
683
|
/** `markets closed until Mon`; `short` is the compact form a narrow capture falls back to (`reopens Mon`). */
|
|
502
|
-
function marketText(market: ReportMarket, now: number, short
|
|
503
|
-
const reopen = reopenText(market, now);
|
|
684
|
+
function marketText(market: ReportMarket, now: number, short: boolean, local: boolean): string {
|
|
685
|
+
const reopen = reopenText(market, now, local);
|
|
504
686
|
switch (market.state) {
|
|
505
687
|
case "open":
|
|
506
688
|
return short ? "open" : "markets open";
|
|
@@ -525,18 +707,31 @@ interface StatusLineDetail {
|
|
|
525
707
|
status?: "short";
|
|
526
708
|
/** `reopens Mon` for `markets closed until Mon`; `none` leaves the market out. */
|
|
527
709
|
market?: "short" | "none";
|
|
710
|
+
/** Leave out the reader's local time beside UTC times. */
|
|
711
|
+
local?: "none";
|
|
712
|
+
/** Leave the day off a time of the day the report was built. */
|
|
713
|
+
date?: "none";
|
|
714
|
+
/** Leave out what the figures are (`funding = current estimate`). */
|
|
715
|
+
note?: "none";
|
|
528
716
|
}
|
|
529
717
|
|
|
530
718
|
/**
|
|
531
|
-
* The parts of a report's status line: the dated as-of
|
|
532
|
-
*
|
|
719
|
+
* The parts of a report's status line: the dated as-of (each source's, when
|
|
720
|
+
* it names several), how old the oldest observation is when it says, how
|
|
721
|
+
* current the data is (`15 min delayed`, `live`), where its markets stand,
|
|
722
|
+
* and what the figures are, when known.
|
|
533
723
|
*/
|
|
534
724
|
function statusLineParts(freshness: ReportFreshness, detail: StatusLineDetail = {}): string[] {
|
|
535
725
|
const now = Date.parse(freshness.retrievedAt);
|
|
726
|
+
const local = detail.local !== "none";
|
|
727
|
+
const undated = detail.date === "none";
|
|
536
728
|
return [
|
|
537
|
-
|
|
729
|
+
...(freshness.sources?.length ? sourcesAsOfParts(freshness, freshness.sources, undated)
|
|
730
|
+
: [asOfText(freshness, detail.asOf === "short", local, undated)]),
|
|
731
|
+
...(freshness.oldestAgeMinutes != null ? [`oldest ${ageText(freshness.oldestAgeMinutes)}`] : []),
|
|
538
732
|
statusText(freshness, detail.status === "short"),
|
|
539
|
-
...(freshness.market && detail.market !== "none" ? [marketText(freshness.market, now, detail.market === "short")] : []),
|
|
733
|
+
...(freshness.market && detail.market !== "none" ? [marketText(freshness.market, now, detail.market === "short", local)] : []),
|
|
734
|
+
...(freshness.note && detail.note !== "none" ? [freshness.note] : []),
|
|
540
735
|
];
|
|
541
736
|
}
|
|
542
737
|
|
|
@@ -544,36 +739,185 @@ function capitalize(text: string): string {
|
|
|
544
739
|
return text ? `${text[0]!.toUpperCase()}${text.slice(1)}` : text;
|
|
545
740
|
}
|
|
546
741
|
|
|
742
|
+
/** `Sun 4 Oct`, with the year only when it is not the year of the capture, which the lag counts from. */
|
|
743
|
+
function observedDayText(date: string, retrievedAt: string): string {
|
|
744
|
+
const text = dayText(date);
|
|
745
|
+
return date.slice(0, 4) === retrievedAt.slice(0, 4) ? text.replace(/ \d{4}$/, "") : text;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
interface DatasetLineDetail {
|
|
749
|
+
/** Leave out the source. */
|
|
750
|
+
source?: "none";
|
|
751
|
+
/** Leave out the oldest observation. */
|
|
752
|
+
oldest?: "none";
|
|
753
|
+
/** Count stale rows without their total. */
|
|
754
|
+
status?: "short";
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/** `lag 2 days`, `lag 1 day`. */
|
|
758
|
+
function lagText(days: number): string {
|
|
759
|
+
return `lag ${days} ${days === 1 ? "day" : "days"}`;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* A dataset's status line: its source, the newest observation's date (the
|
|
764
|
+
* period, for monthly to annual data) and how many days it lags, then which
|
|
765
|
+
* rows are stale, if any. No market part: a dataset has no session. A
|
|
766
|
+
* dataset that names its observation reads as its rows do, by ISO date:
|
|
767
|
+
* `Source: DTCC · last trade 2026-10-09 · lag 2 days`.
|
|
768
|
+
*/
|
|
769
|
+
function datasetLineParts(freshness: ReportFreshness, asOf: string, lagDays: number, detail: DatasetLineDetail = {}): string[] {
|
|
770
|
+
if (freshness.observation) {
|
|
771
|
+
return [
|
|
772
|
+
...(detail.source === "none" ? [] : [`Source: ${freshness.source}`]),
|
|
773
|
+
`${freshness.observation} ${asOf.slice(0, 10)}`,
|
|
774
|
+
lagText(lagDays),
|
|
775
|
+
...(freshness.status === "stale" ? ["stale"] : []),
|
|
776
|
+
];
|
|
777
|
+
}
|
|
778
|
+
const period = freshness.periodicity;
|
|
779
|
+
const dated = (date: string) => (period ? periodText(date, period) : observedDayText(date, freshness.retrievedAt));
|
|
780
|
+
const oldest = freshness.oldest && detail.oldest !== "none" ? ` (oldest ${dated(freshness.oldest)})` : "";
|
|
781
|
+
const stale = freshness.status !== "stale" ? null : staleRowsText(freshness, detail.status === "short") ?? "stale";
|
|
782
|
+
return [
|
|
783
|
+
...(detail.source === "none" ? [] : [`Source: ${freshness.source}`]),
|
|
784
|
+
`observed ${dated(asOf)}${period ? ` (${period})` : ""}${oldest}`,
|
|
785
|
+
`lag ${lagDays}d`,
|
|
786
|
+
...(stale ? [stale] : []),
|
|
787
|
+
];
|
|
788
|
+
}
|
|
789
|
+
|
|
547
790
|
/**
|
|
548
|
-
* The plain status line of a
|
|
549
|
-
* `Fri 9 Oct close · 15 min delayed · markets closed until Mon
|
|
791
|
+
* The plain status line of a capture: the longest of `statusLineVariants`,
|
|
792
|
+
* `Fri 9 Oct close · 15 min delayed · markets closed until Mon` for quotes.
|
|
550
793
|
*/
|
|
551
794
|
export function formatStatusLine(freshness: ReportFreshness): string {
|
|
552
|
-
return
|
|
795
|
+
return statusLineVariants(freshness)[0]!;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/** Whether the status line dates the data by its newest observation and lag (a dataset's), not by a market session. */
|
|
799
|
+
function datesObservation(freshness: ReportFreshness): freshness is ReportFreshness & { asOf: string; lagDays: number } {
|
|
800
|
+
return freshness.lagDays != null && !!freshness.asOf;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* The status line a pane's footer shows, the one its report and capture end
|
|
805
|
+
* with: without the reader's local time, and without the day when the data is
|
|
806
|
+
* from the day it is read.
|
|
807
|
+
*/
|
|
808
|
+
export function paneStatusLine(freshness: ReportFreshness): string {
|
|
809
|
+
return paneStatusLineVariants(freshness)[0]!;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* `paneStatusLine` from longest to shortest, for a footer to show the first
|
|
814
|
+
* that fits beside its keys: the market part shortens, the stale total goes,
|
|
815
|
+
* then what the figures are.
|
|
816
|
+
*/
|
|
817
|
+
export function paneStatusLineVariants(freshness: ReportFreshness): string[] {
|
|
818
|
+
// A dataset's line has no market or local time to leave out: it reads as its report and capture do.
|
|
819
|
+
if (datesObservation(freshness)) return statusLineVariants(freshness);
|
|
820
|
+
const pane: StatusLineDetail = { local: "none", date: "none" };
|
|
821
|
+
const details: StatusLineDetail[] = [pane, { ...pane, market: "short" }, { ...pane, market: "short", status: "short" }, { ...pane, market: "short", status: "short", note: "none" }];
|
|
822
|
+
return [...new Set(details.map((detail) => capitalize(statusLineParts(freshness, detail).join(" · "))))];
|
|
553
823
|
}
|
|
554
824
|
|
|
555
825
|
/**
|
|
556
826
|
* The status line from longest to shortest, for a capture to take the first
|
|
557
|
-
* that fits its width.
|
|
558
|
-
*
|
|
559
|
-
* the
|
|
827
|
+
* that fits its width. Quotes and other reports leave out their source: the
|
|
828
|
+
* date and the delay stay to the last; the market part shortens, then the
|
|
829
|
+
* reader's local time, the oldest observation and the stale total go, then
|
|
830
|
+
* the market part. With `source`, the line starts as `fn` ends,
|
|
831
|
+
* `Source: CFTC · Tue 6 Oct 2026 · not a live feed (weekly report)`, shortens
|
|
832
|
+
* the same way and gives up its source last. A dataset reads
|
|
833
|
+
* `Source: Gloom Cloud · observed Sun 4 Oct · lag 6d` and gives up its oldest
|
|
834
|
+
* observation, the stale total, then its source.
|
|
560
835
|
*/
|
|
561
|
-
export function statusLineVariants(freshness: ReportFreshness): string[] {
|
|
836
|
+
export function statusLineVariants(freshness: ReportFreshness, { source = false }: { source?: boolean } = {}): string[] {
|
|
837
|
+
if (datesObservation(freshness)) {
|
|
838
|
+
const { asOf, lagDays } = freshness;
|
|
839
|
+
const datasetDetails: DatasetLineDetail[] = [
|
|
840
|
+
{},
|
|
841
|
+
{ oldest: "none" },
|
|
842
|
+
{ oldest: "none", status: "short" },
|
|
843
|
+
{ source: "none", oldest: "none", status: "short" },
|
|
844
|
+
];
|
|
845
|
+
return [...new Set(datasetDetails.map((detail) => capitalize(datasetLineParts(freshness, asOf, lagDays, detail).join(" · "))))];
|
|
846
|
+
}
|
|
562
847
|
const details: StatusLineDetail[] = [
|
|
563
848
|
{},
|
|
564
849
|
{ market: "short" },
|
|
565
|
-
{
|
|
566
|
-
{ asOf: "short",
|
|
567
|
-
{ asOf: "short", status: "short", market: "none" },
|
|
850
|
+
{ market: "short", local: "none" },
|
|
851
|
+
{ asOf: "short", market: "short", local: "none" },
|
|
852
|
+
{ asOf: "short", status: "short", market: "short", local: "none" },
|
|
853
|
+
{ asOf: "short", status: "short", market: "none", local: "none" },
|
|
568
854
|
];
|
|
569
|
-
|
|
855
|
+
// A line that dates each source keeps every source's time and their age to
|
|
856
|
+
// the last: its day goes first, then what the figures are.
|
|
857
|
+
const shortest = details.at(-1)!;
|
|
858
|
+
const variants: StatusLineDetail[] = freshness.sources?.length
|
|
859
|
+
? [{}, ...details.map((detail) => ({ ...detail, date: "none" as const })), { ...shortest, date: "none", note: "none" }]
|
|
860
|
+
: freshness.note ? [...details, { ...shortest, note: "none" }] : details;
|
|
861
|
+
const lines = [...new Set(variants.map((detail) => capitalize(statusLineParts(freshness, detail).join(" · "))))];
|
|
862
|
+
// A line that dates each source names them already.
|
|
863
|
+
if (!source || freshness.sources?.length) return lines;
|
|
864
|
+
const sourced = [...new Set(variants.map((detail) => [`Source: ${freshness.source}`, ...statusLineParts(freshness, detail)].join(" · ")))];
|
|
865
|
+
const floor = sourced.at(-1)!.length;
|
|
866
|
+
return [...sourced, ...lines.filter((line) => line.length < floor)];
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/** A capture's status line: the facts it states (its `freshness` in JSON) and its text, longest first. */
|
|
870
|
+
export interface CaptureStatusLine {
|
|
871
|
+
freshness: ReportFreshness;
|
|
872
|
+
variants: string[];
|
|
873
|
+
/**
|
|
874
|
+
* What the line dates: `data` when it comes from the pane's own report or
|
|
875
|
+
* the view the pane dates itself, so the pane's own `as of` text says it
|
|
876
|
+
* twice; `quotes` for the quotes on screen, which may not be what the pane's
|
|
877
|
+
* `as of` dates; null when it dates nothing it can name.
|
|
878
|
+
*/
|
|
879
|
+
dates: "data" | "quotes" | null;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* What a capture's status line says about its data, from the first that applies:
|
|
884
|
+
* - a dataset's report (CHOKE's transits, HIRE's postings): its source, newest observation and lag;
|
|
885
|
+
* - a pane that dates its own view (PERP's venues, FXC's rates, the news wire's delay): what it publishes;
|
|
886
|
+
* - quotes on screen, when the pane does not say what its data is: their session, delay and market;
|
|
887
|
+
* - the pane's report, when it says how current its data is: the line `fn` ends with, source first;
|
|
888
|
+
* - otherwise what the rendered view carries, which may be nothing.
|
|
889
|
+
*/
|
|
890
|
+
export function captureStatusLine({ report, selfDated, quoted, rendered }: {
|
|
891
|
+
/** The pane's own report, loaded for the capture: what `fn` would say. */
|
|
892
|
+
report?: ReportFreshness;
|
|
893
|
+
/** Whether the rendered pane published how current its view is. */
|
|
894
|
+
selfDated: boolean;
|
|
895
|
+
/** The quotes the capture shows, read when the pane does not say what its data is. */
|
|
896
|
+
quoted?: ReportFreshness;
|
|
897
|
+
rendered: () => ReportFreshness;
|
|
898
|
+
}): CaptureStatusLine {
|
|
899
|
+
const plain = (freshness: ReportFreshness, dates: CaptureStatusLine["dates"]): CaptureStatusLine => ({ freshness, variants: statusLineVariants(freshness), dates });
|
|
900
|
+
const dated = (freshness: ReportFreshness) => (freshness.asOf ? "data" as const : null);
|
|
901
|
+
if (report && datesObservation(report)) return plain(report, "data");
|
|
902
|
+
if (selfDated) {
|
|
903
|
+
const view = rendered();
|
|
904
|
+
return plain(view, dated(view));
|
|
905
|
+
}
|
|
906
|
+
if (quoted) return plain(quoted, "quotes");
|
|
907
|
+
if (report && report.status !== "unreported") return { freshness: report, variants: statusLineVariants(report, { source: true }), dates: dated(report) };
|
|
908
|
+
return plain(rendered(), null);
|
|
570
909
|
}
|
|
571
910
|
|
|
572
911
|
/**
|
|
573
912
|
* The one line every text report ends with, its source then its status line:
|
|
574
913
|
* `Source: Gloom Cloud · Fri 9 Oct close · 15 min delayed · markets closed until Mon`.
|
|
575
914
|
* Without a dated observation it says when the report was retrieved instead.
|
|
915
|
+
* A line that dates each of its sources names them there, so it is the status
|
|
916
|
+
* line alone: `Sun 11 Oct 2026 · Binance 02:15 · Bybit 02:24 UTC · oldest 9 min · delayed`.
|
|
576
917
|
*/
|
|
577
918
|
export function formatFreshnessLine(freshness: ReportFreshness): string {
|
|
578
|
-
|
|
919
|
+
// A dataset that names its observation ends `fn` as its pane and capture do.
|
|
920
|
+
if (freshness.observation && datesObservation(freshness)) return statusLineVariants(freshness)[0]!;
|
|
921
|
+
const parts = statusLineParts(freshness);
|
|
922
|
+
return (freshness.sources?.length ? parts : [`Source: ${freshness.source}`, ...parts]).join(" · ");
|
|
579
923
|
}
|