gloomberb 0.18.2 → 0.18.4
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 +8 -8
- package/README.zh-CN.md +11 -11
- package/bin/{gloomberb → gloom} +3 -1
- package/package.json +6 -2
- package/patches/electrobun@1.18.1.patch +106 -5
- package/src/account/checkout-handoff.tsx +225 -0
- package/src/account/device-signin-dialog.tsx +2 -2
- package/src/account/device-signin.ts +2 -2
- package/src/account/upgrade-dialog.tsx +1 -1
- package/src/api-client/askg.ts +2 -2
- package/src/api-client/auth.ts +2 -2
- package/src/api-client/central-bank-rates.ts +6 -0
- package/src/api-client/collections.ts +5 -1
- package/src/api-client/cot.ts +2 -0
- package/src/api-client/crypto-etf-flows.ts +37 -0
- package/src/api-client/crypto-markets.ts +60 -0
- package/src/api-client/data.ts +99 -5
- package/src/api-client/doe.ts +15 -0
- package/src/api-client/equity-screener.ts +28 -0
- package/src/api-client/exchange-announcements.ts +38 -0
- package/src/api-client/fund-facts.ts +39 -0
- package/src/api-client/futures-curve.ts +9 -1
- package/src/api-client/hiring.ts +301 -0
- package/src/api-client/index.ts +24 -5
- package/src/api-client/market-discovery.ts +14 -0
- package/src/api-client/members.ts +6 -0
- package/src/api-client/mna.ts +6 -0
- package/src/api-client/paths.ts +18 -1
- package/src/api-client/request.ts +26 -7
- package/src/api-client/short-side-publications.ts +37 -0
- package/src/api-client/socket.ts +64 -4
- package/src/api-client/swap-curve.ts +35 -0
- package/src/api-client/telemetry.ts +17 -0
- package/src/api-client/themes.ts +7 -1
- package/src/api-client/types.ts +90 -2
- package/src/app/global-shortcuts.ts +1 -16
- package/src/app/pane-runtime/plugin-bindings.ts +9 -2
- package/src/app/runtime/desktop-deeplink.ts +5 -5
- package/src/app/runtime/plugin-bindings.ts +2 -2
- package/src/app/runtime/startup.ts +13 -0
- package/src/app/runtime/update.ts +28 -8
- package/src/app/star-prompt/status-line.tsx +2 -2
- package/src/architecture/core-builtin-allowlist.json +5 -2
- package/src/architecture/pane-tabs-allowlist.json +65 -0
- package/src/architecture/ui-literals-allowlist.json +3 -3
- package/src/architecture/ui-tokens-allowlist.json +1 -1
- package/src/brokers/broker-portfolio-sync.ts +37 -0
- package/src/brokers/directory.ts +11 -0
- package/src/brokers/logos.ts +3 -1
- package/src/brokers/signed-in/adapter.ts +304 -26
- package/src/brokers/signed-in/client.ts +14 -2
- package/src/brokers/signed-in/connect.ts +10 -2
- package/src/brokers/sync-broker-instance.ts +9 -1
- package/src/capabilities/chart-series.ts +22 -6
- package/src/cli/bank-section.ts +1 -1
- package/src/cli/base-converter.ts +23 -14
- package/src/cli/central-bank-events.ts +1 -1
- package/src/cli/command-options.ts +59 -4
- package/src/cli/commands/api.ts +9 -6
- package/src/cli/commands/broker.ts +2 -2
- package/src/cli/commands/command-utils.ts +2 -2
- package/src/cli/commands/crypto-hints.ts +7 -20
- package/src/cli/commands/fred-series.ts +4 -2
- package/src/cli/commands/keybindings.ts +2 -2
- package/src/cli/commands/market.ts +1189 -296
- package/src/cli/commands/news-hints.ts +2 -2
- package/src/cli/commands/news-search.ts +59 -6
- package/src/cli/commands/options-leaps.ts +41 -26
- package/src/cli/commands/overview.ts +121 -48
- package/src/cli/commands/plugins.ts +9 -9
- package/src/cli/commands/remote.ts +13 -10
- package/src/cli/commands/search.ts +64 -44
- package/src/cli/commands/system.ts +27 -19
- package/src/cli/commands/themes.ts +1 -1
- package/src/cli/commands/ticker.ts +272 -70
- package/src/cli/context.ts +3 -2
- package/src/cli/desktop-pane-shot-view.ts +2 -2
- package/src/cli/desktop-pane-shot.ts +1 -1
- package/src/cli/earnings-calendar.ts +4 -4
- package/src/cli/entry.ts +18 -1
- package/src/cli/errors.ts +20 -2
- package/src/cli/exit-codes.ts +1 -1
- package/src/cli/export-source.ts +10 -4
- package/src/cli/freshness.ts +2 -8
- package/src/cli/fx-forward.ts +130 -0
- package/src/cli/fx-pair.ts +10 -9
- package/src/cli/glossary.ts +64 -20
- package/src/cli/help.ts +20 -14
- package/src/cli/history-export.ts +126 -0
- package/src/cli/history-rows.ts +196 -43
- package/src/cli/index-roots.ts +5 -45
- package/src/cli/index.ts +32 -18
- package/src/cli/issuer-membership.ts +103 -0
- package/src/cli/known-gaps.ts +118 -25
- package/src/cli/listing-arg.ts +315 -43
- package/src/cli/name-entries.ts +73 -22
- package/src/cli/native-smoke.ts +2 -0
- package/src/cli/not-a-ticker.ts +19 -9
- package/src/cli/opentui-libc.ts +5 -0
- package/src/cli/options.ts +12 -0
- package/src/cli/pane-functions/capabilities.ts +77 -20
- package/src/cli/pane-functions/catalog.ts +40 -23
- package/src/cli/pane-functions/discovery.ts +1 -1
- package/src/cli/pane-functions/dom.ts +12 -8
- package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
- package/src/cli/pane-functions/freshness.ts +174 -23
- package/src/cli/pane-functions/function-help.ts +66 -27
- package/src/cli/pane-functions/headless.ts +48 -16
- package/src/cli/pane-functions/index.ts +82 -21
- package/src/cli/pane-functions/options.ts +22 -2
- package/src/cli/pane-functions/report-notices.ts +12 -4
- package/src/cli/pane-functions/report.ts +5 -5
- package/src/cli/pane-functions/resolver.ts +65 -14
- package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
- package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
- package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
- package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
- package/src/cli/pane-functions/screenshot-payload.ts +453 -0
- package/src/cli/pane-functions/screenshot-render.ts +316 -0
- package/src/cli/pane-functions/screenshot-types.ts +162 -0
- package/src/cli/pane-functions/shot-options.ts +8 -3
- package/src/cli/peso-dollar-rates.ts +79 -0
- package/src/cli/quote-answer.ts +38 -3
- package/src/cli/report-tables.ts +190 -27
- package/src/cli/restore-plugins.ts +29 -14
- package/src/cli/result.ts +122 -25
- package/src/cli/series-search.ts +5 -5
- package/src/cli/statement-filings.ts +19 -0
- package/src/cli/suffixed-listing-rows.ts +49 -0
- package/src/cli/symbol-args.ts +50 -15
- package/src/cli/symbol-cells.ts +120 -0
- package/src/cli/symbol-list.ts +226 -60
- package/src/cli/symbol-rows.ts +131 -25
- package/src/cli/ticker-resolution.ts +108 -11
- package/src/cli/treasury-yields.ts +5 -5
- package/src/cli/types.ts +2 -0
- package/src/cli/uncovered-instrument.ts +3 -3
- package/src/cli/unknown-command.ts +6 -6
- package/src/components/chart/composite/chart-layout.ts +131 -0
- package/src/components/chart/composite/composite-chart.tsx +387 -21
- package/src/components/chart/composite/drawing-store.ts +26 -6
- package/src/components/chart/composite/interactions.ts +9 -3
- package/src/components/chart/composite/legend.tsx +75 -3
- package/src/components/chart/composite/levels.ts +5 -0
- package/src/components/chart/composite/panel-gestures.ts +41 -0
- package/src/components/chart/composite/panel-labels.ts +2 -1
- package/src/components/chart/composite/panel-surface.tsx +316 -11
- package/src/components/chart/composite/price-axis-labels.tsx +27 -3
- package/src/components/chart/composite/rasterizer.ts +44 -19
- package/src/components/chart/composite/scene.ts +16 -4
- package/src/components/chart/composite/text-renderer.ts +48 -21
- package/src/components/chart/composite/toolbar.tsx +52 -5
- package/src/components/chart/composite/types.ts +19 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
- package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
- package/src/components/chart/composite/use-composite-viewport.ts +12 -3
- package/src/components/chart/composite/value-scale.ts +149 -0
- package/src/components/chart/composite/volume-profile-paint.ts +6 -3
- package/src/components/chart/core/pointer.ts +2 -0
- package/src/components/chart-table/index.ts +2 -0
- package/src/components/chart-table/read.tsx +74 -0
- package/src/components/command-bar/commands/collection-list.ts +41 -19
- package/src/components/command-bar/commands/collection.ts +9 -3
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +3 -2
- package/src/components/command-bar/pane-templates/items.ts +59 -6
- package/src/components/command-bar/pane-templates/workflow.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +32 -6
- package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
- package/src/components/command-bar/routes/root/provider-search.ts +42 -11
- package/src/components/command-bar/routes/root/results.ts +18 -4
- package/src/components/command-bar/routes/root/runtime.ts +15 -3
- package/src/components/command-bar/routes/root/search-providers.ts +25 -2
- package/src/components/command-bar/routes/root/selection.ts +6 -1
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
- package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
- package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
- package/src/components/command-bar/selection-runtime.ts +50 -10
- package/src/components/command-bar/surface/index.tsx +24 -2
- package/src/components/command-bar/view-model.ts +7 -0
- package/src/components/command-bar/workflow/broker.ts +2 -2
- package/src/components/command-bar/workflow/collection-actions.ts +46 -7
- package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
- package/src/components/command-bar/workflow/fields.ts +8 -2
- package/src/components/command-bar/workflow/ops.ts +18 -4
- package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
- package/src/components/command-bar/workflow/submit.ts +3 -2
- package/src/components/command-bar/workflow/tickers.ts +5 -1
- package/src/components/company-logo.tsx +39 -0
- package/src/components/data-table/sections.ts +4 -2
- package/src/components/data-table/view.tsx +23 -3
- package/src/components/form-modal/confirm.tsx +2 -1
- package/src/components/form-modal/request.ts +5 -0
- package/src/components/form-modal/routes.ts +4 -1
- package/src/components/index.ts +13 -6
- package/src/components/layout/detached-pane-shell.tsx +1 -0
- package/src/components/layout/floating-pane.tsx +1 -0
- package/src/components/layout/header.tsx +234 -60
- package/src/components/layout/market-summary.ts +9 -6
- package/src/components/layout/pane/capture-status.ts +1 -1
- package/src/components/layout/pane/footer/model.ts +11 -5
- package/src/components/layout/pane/header.tsx +10 -3
- package/src/components/layout/pane/index.tsx +1 -0
- package/src/components/layout/pane/pane-tabs.tsx +9 -1
- package/src/components/layout/shell/chrome.ts +19 -6
- package/src/components/layout/shell/index.tsx +2 -1
- package/src/components/layout/shell/pane/layers.tsx +19 -1
- package/src/components/layout/status-bar.tsx +2 -2
- package/src/components/market-board/index.tsx +11 -3
- package/src/components/onboarding/onboarding-wizard.tsx +1 -0
- package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
- package/src/components/onboarding/wizard-broker-sync.ts +4 -1
- package/src/components/pane-settings-dialog/desktop.tsx +20 -7
- package/src/components/pane-settings-dialog/tui.tsx +17 -9
- package/src/components/pane-settings-dialog/value.ts +8 -1
- package/src/components/pane-settings-dialog.tsx +44 -13
- package/src/components/sign-in-code-panel.tsx +27 -19
- package/src/components/ui/column-grid.tsx +48 -4
- package/src/components/ui/country-flag-art.tsx +180 -0
- package/src/components/ui/country-flag.tsx +118 -12
- package/src/components/ui/data-table/opentui/index.tsx +61 -2
- package/src/components/ui/data-table/opentui/model.ts +109 -2
- package/src/components/ui/data-table/types.ts +1 -1
- package/src/components/ui/display.tsx +5 -1
- package/src/components/ui/index.ts +3 -1
- package/src/components/ui/logo-mark.tsx +11 -2
- package/src/components/ui/query-bar.tsx +1 -1
- package/src/components/ui/row-notes.ts +79 -0
- package/src/components/ui/stat-grid.tsx +28 -3
- package/src/components/ui/status.tsx +3 -1
- package/src/core/app-services.ts +4 -0
- package/src/core/state/app/layout.ts +4 -4
- package/src/data/cached-query.ts +8 -1
- package/src/data/config/chart-settings.ts +3 -3
- package/src/data/config/home.ts +10 -2
- package/src/data/config/layout.ts +4 -1
- package/src/data/config/store/node.ts +4 -0
- package/src/data/config/store/normalize.ts +13 -3
- package/src/data/config/store/portfolio-as-of-column.ts +2 -2
- package/src/data/json-storage.ts +2 -0
- package/src/data/saved-copies.ts +84 -0
- package/src/docs/snapshot.json +65 -32
- package/src/i18n/es.ts +51 -12
- package/src/i18n/ja.ts +51 -12
- package/src/i18n/ko.ts +51 -12
- package/src/i18n/zh-cn.ts +51 -12
- package/src/i18n/zh-tw.ts +51 -12
- package/src/layout/desks.ts +1 -1
- package/src/layout/launch-layout.ts +1 -1
- package/src/layout/pane-manager/floating-actions.ts +5 -3
- package/src/layout/pane-manager/floating.ts +43 -1
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/layout/selected-ticker.ts +74 -0
- package/src/market-data/depositary-pair.ts +251 -0
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +124 -40
- package/src/market-data/fx-closes.ts +17 -2
- package/src/market-data/hooks.tsx +19 -11
- package/src/market-data/market/change-basis.ts +49 -7
- package/src/market-data/market/freshness.ts +34 -5
- package/src/market-data/market/period-return.ts +163 -0
- package/src/market-data/market/trading-sessions.ts +13 -0
- package/src/market-data/market/year-to-date.ts +8 -13
- package/src/market-data/performance.ts +20 -14
- package/src/market-data/perpetual-premium.ts +32 -0
- package/src/market-data/published-apac-sessions.ts +2 -1
- package/src/market-data/published-futures-sessions.ts +69 -0
- package/src/market-data/quotes/contributions.ts +5 -1
- package/src/market-data/quotes/freshness.ts +42 -0
- package/src/market-data/quotes/intraday-bar.ts +37 -0
- package/src/market-data/quotes/regular-session-valuation.ts +13 -8
- package/src/market-data/quotes/resolution.ts +4 -2
- package/src/market-data/tax-equivalent.ts +1 -1
- package/src/market-data/ticker-price-returns.ts +3 -1
- package/src/news/aggregator.ts +5 -1
- package/src/news/news-model.ts +4 -0
- package/src/news/types.ts +11 -0
- package/src/notifications/app-notifier.ts +1 -1
- package/src/plugins/auto-update.ts +2 -2
- package/src/plugins/builtin/account-management/index.tsx +1 -0
- package/src/plugins/builtin/account-management/pane.tsx +9 -8
- package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
- package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
- package/src/plugins/builtin/alerts/cli.ts +485 -76
- package/src/plugins/builtin/alerts/command.ts +5 -10
- package/src/plugins/builtin/alerts/event-rows.ts +9 -5
- package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
- package/src/plugins/builtin/alerts/events.ts +108 -5
- package/src/plugins/builtin/alerts/fired-log.ts +78 -0
- package/src/plugins/builtin/alerts/format.ts +2 -1
- package/src/plugins/builtin/alerts/headless.ts +100 -39
- package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
- package/src/plugins/builtin/alerts/history-rows.ts +89 -0
- package/src/plugins/builtin/alerts/index.tsx +45 -18
- package/src/plugins/builtin/alerts/iv-level.ts +365 -0
- package/src/plugins/builtin/alerts/levels.ts +3 -3
- package/src/plugins/builtin/alerts/pane.tsx +97 -29
- package/src/plugins/builtin/alerts/price.ts +35 -0
- package/src/plugins/builtin/alerts/quotes.ts +24 -0
- package/src/plugins/builtin/alerts/research-builder.ts +84 -11
- package/src/plugins/builtin/alerts/research-rules.ts +77 -3
- package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
- package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
- package/src/plugins/builtin/alerts/scheduled.ts +188 -29
- package/src/plugins/builtin/alerts/storage.ts +13 -10
- package/src/plugins/builtin/alerts/targets.ts +12 -3
- package/src/plugins/builtin/analytics/index.tsx +8 -2
- package/src/plugins/builtin/analytics/metrics.ts +1 -1
- package/src/plugins/builtin/analytics/risk-book.ts +215 -0
- package/src/plugins/builtin/analytics/risk-client.ts +13 -6
- package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
- package/src/plugins/builtin/analytics/risk-math.ts +6 -3
- package/src/plugins/builtin/analytics/risk-model.ts +297 -104
- package/src/plugins/builtin/analytics/risk-options.ts +17 -2
- package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
- package/src/plugins/builtin/attention/pane.tsx +22 -16
- package/src/plugins/builtin/awards/headless.ts +7 -3
- package/src/plugins/builtin/awards/model.ts +18 -0
- package/src/plugins/builtin/awards/pane.tsx +12 -9
- package/src/plugins/builtin/backtest/export.ts +1 -1
- package/src/plugins/builtin/backtest/headless.ts +3 -3
- package/src/plugins/builtin/backtest/rules.ts +41 -5
- package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
- package/src/plugins/builtin/broker-manager/footer.ts +27 -11
- package/src/plugins/builtin/broker-manager/index.tsx +21 -12
- package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
- package/src/plugins/builtin/broker-manager/model.ts +12 -2
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
- package/src/plugins/builtin/broker-manager/table.ts +28 -12
- package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
- package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
- package/src/plugins/builtin/broker-trading/controller.ts +45 -13
- package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
- package/src/plugins/builtin/broker-trading/headless.ts +2 -1
- package/src/plugins/builtin/broker-trading/index.tsx +7 -1
- package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
- package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
- package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
- package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
- package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
- package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
- package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
- package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
- package/src/plugins/builtin/buildout/cells.tsx +4 -0
- package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
- package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
- package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
- package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
- package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
- package/src/plugins/builtin/catalysts/client.ts +2 -2
- package/src/plugins/builtin/catalysts/detail.tsx +3 -2
- package/src/plugins/builtin/catalysts/index.tsx +1 -1
- package/src/plugins/builtin/catalysts/model.ts +49 -4
- package/src/plugins/builtin/catalysts/pane.tsx +9 -11
- package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
- package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
- package/src/plugins/builtin/changelog/index.tsx +1 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
- package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
- package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
- package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
- package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
- package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
- package/src/plugins/builtin/chart-composer/headless.ts +253 -35
- package/src/plugins/builtin/chart-composer/index.tsx +12 -2
- package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
- package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
- package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
- package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
- package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
- package/src/plugins/builtin/chart-composer/settings.ts +31 -19
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
- package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
- package/src/plugins/builtin/chat/attachments/model.ts +3 -1
- package/src/plugins/builtin/chat/content/index.tsx +1 -1
- package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
- package/src/plugins/builtin/chat/people.ts +1 -1
- package/src/plugins/builtin/clinical-trials/client.ts +5 -2
- package/src/plugins/builtin/clinical-trials/model.ts +13 -4
- package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
- package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
- package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
- package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
- package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
- package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
- package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
- package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
- package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
- package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
- package/src/plugins/builtin/company-attention/building-model.ts +222 -0
- package/src/plugins/builtin/company-attention/building.tsx +172 -0
- package/src/plugins/builtin/company-attention/client.ts +117 -1
- package/src/plugins/builtin/company-attention/evidence.ts +16 -3
- package/src/plugins/builtin/company-attention/headless.ts +101 -5
- package/src/plugins/builtin/company-attention/index.tsx +6 -3
- package/src/plugins/builtin/company-attention/model.ts +33 -7
- package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
- package/src/plugins/builtin/company-attention/moves.tsx +159 -0
- package/src/plugins/builtin/company-attention/pane.tsx +89 -31
- package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
- package/src/plugins/builtin/company-attention/signals.tsx +160 -0
- package/src/plugins/builtin/company-kpis/headless.ts +3 -2
- package/src/plugins/builtin/company-kpis/model.ts +2 -2
- package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
- package/src/plugins/builtin/composite-plugins.ts +2 -1
- package/src/plugins/builtin/congress-trades/headless.ts +1 -1
- package/src/plugins/builtin/connections/index.ts +1 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
- package/src/plugins/builtin/correlation/headless.ts +7 -4
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
- package/src/plugins/builtin/correlation/settings.ts +1 -0
- package/src/plugins/builtin/cot/headless.ts +28 -6
- package/src/plugins/builtin/cot/model.ts +12 -0
- package/src/plugins/builtin/cot/pane.tsx +7 -5
- package/src/plugins/builtin/cpi/headless.ts +5 -1
- package/src/plugins/builtin/cpi/pane.tsx +11 -9
- package/src/plugins/builtin/credit-boards/model.ts +2 -0
- package/src/plugins/builtin/credit-documents/headless.ts +1 -1
- package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
- package/src/plugins/builtin/crypto-board/client.ts +86 -0
- package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
- package/src/plugins/builtin/crypto-board/defi.ts +239 -0
- package/src/plugins/builtin/crypto-board/headless.ts +117 -6
- package/src/plugins/builtin/crypto-board/index.tsx +8 -3
- package/src/plugins/builtin/crypto-board/model.ts +40 -8
- package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
- package/src/plugins/builtin/crypto-board/series.ts +19 -1
- package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
- package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
- package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
- package/src/plugins/builtin/debug/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
- package/src/plugins/builtin/docs/index.tsx +1 -1
- package/src/plugins/builtin/docs/pane.tsx +2 -2
- package/src/plugins/builtin/docs/targets.ts +1 -1
- package/src/plugins/builtin/doe/client.ts +5 -1
- package/src/plugins/builtin/doe/headless.ts +12 -6
- package/src/plugins/builtin/doe/model.ts +43 -6
- package/src/plugins/builtin/doe/pane.tsx +19 -12
- package/src/plugins/builtin/earnings/board-model.ts +13 -6
- package/src/plugins/builtin/earnings/board-table.ts +4 -1
- package/src/plugins/builtin/earnings/board.tsx +253 -50
- package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
- package/src/plugins/builtin/earnings/calendar.tsx +338 -0
- package/src/plugins/builtin/earnings/client.ts +4 -3
- package/src/plugins/builtin/earnings/headless.ts +53 -15
- package/src/plugins/builtin/earnings/history-model.ts +53 -36
- package/src/plugins/builtin/earnings/index.tsx +15 -22
- package/src/plugins/builtin/earnings/model.ts +17 -12
- package/src/plugins/builtin/earnings/scope.ts +89 -0
- package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
- package/src/plugins/builtin/earnings-calls/data.ts +146 -2
- package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
- package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
- package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
- package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
- package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
- package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +132 -20
- package/src/plugins/builtin/econ/detail-view.tsx +48 -10
- package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
- package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
- package/src/plugins/builtin/econ/index.tsx +112 -25
- package/src/plugins/builtin/econ/print-watch.ts +2 -1
- package/src/plugins/builtin/econ/types.ts +32 -1
- package/src/plugins/builtin/econ-statistics/client.ts +16 -3
- package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
- package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
- package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
- package/src/plugins/builtin/econ-statistics/view.ts +16 -1
- package/src/plugins/builtin/equity-screener/client.ts +21 -3
- package/src/plugins/builtin/equity-screener/headless.ts +77 -5
- package/src/plugins/builtin/equity-screener/live.ts +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +34 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
- package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
- package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
- package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
- package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
- package/src/plugins/builtin/exposure/headless.ts +51 -6
- package/src/plugins/builtin/exposure/index.tsx +28 -2
- package/src/plugins/builtin/exposure/model.ts +7 -0
- package/src/plugins/builtin/exposure/pane.tsx +16 -10
- package/src/plugins/builtin/fear-greed/index.tsx +1 -1
- package/src/plugins/builtin/filing-events/index.tsx +1 -1
- package/src/plugins/builtin/futures/model.ts +10 -9
- package/src/plugins/builtin/futures/returns.ts +8 -36
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +40 -9
- package/src/plugins/builtin/futures-curve/headless.ts +39 -17
- package/src/plugins/builtin/futures-curve/model.ts +258 -69
- package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
- package/src/plugins/builtin/fx-matrix/client.ts +15 -8
- package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
- package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
- package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
- package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
- package/src/plugins/builtin/gpu/board.tsx +4 -1
- package/src/plugins/builtin/gpu/changes.tsx +10 -10
- package/src/plugins/builtin/gpu/equities.tsx +4 -1
- package/src/plugins/builtin/gpu/headless.ts +9 -4
- package/src/plugins/builtin/gpu/history.tsx +4 -2
- package/src/plugins/builtin/gpu/pane.tsx +5 -3
- package/src/plugins/builtin/help/index.tsx +13 -3
- package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
- package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
- package/src/plugins/builtin/holders/client.ts +15 -2
- package/src/plugins/builtin/holders/format.ts +28 -17
- package/src/plugins/builtin/holders/headless.ts +48 -8
- package/src/plugins/builtin/holders/index-holders.ts +264 -0
- package/src/plugins/builtin/holders/pane.tsx +79 -15
- package/src/plugins/builtin/holders/report-rows.ts +35 -7
- package/src/plugins/builtin/holders/table-model.ts +2 -1
- package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
- package/src/plugins/builtin/holders/treemap.tsx +2 -2
- package/src/plugins/builtin/insider/base-values.ts +11 -7
- package/src/plugins/builtin/insider/client.ts +3 -0
- package/src/plugins/builtin/insider/headless.ts +20 -7
- package/src/plugins/builtin/insider/index.tsx +17 -8
- package/src/plugins/builtin/insider/issuer.ts +34 -4
- package/src/plugins/builtin/insider/signals-client.ts +3 -3
- package/src/plugins/builtin/insider/signals.tsx +1 -1
- package/src/plugins/builtin/insider/table-model.ts +35 -13
- package/src/plugins/builtin/insider/table.tsx +5 -2
- package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
- package/src/plugins/builtin/iv-history/client.ts +20 -0
- package/src/plugins/builtin/iv-history/events.ts +145 -0
- package/src/plugins/builtin/iv-history/format.ts +3 -0
- package/src/plugins/builtin/iv-history/headless.ts +91 -7
- package/src/plugins/builtin/iv-history/index.tsx +1 -1
- package/src/plugins/builtin/iv-history/model.ts +13 -4
- package/src/plugins/builtin/iv-history/series.ts +3 -1
- package/src/plugins/builtin/jobs/lock-note.ts +1 -1
- package/src/plugins/builtin/jobs/model.ts +4 -15
- package/src/plugins/builtin/jobs/pane.tsx +7 -5
- package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
- package/src/plugins/builtin/jodi/pane.tsx +14 -8
- package/src/plugins/builtin/layout-manager/index.tsx +1 -0
- package/src/plugins/builtin/macro-day/headless.ts +20 -7
- package/src/plugins/builtin/macro-day/index.tsx +3 -2
- package/src/plugins/builtin/macro-day/model.ts +29 -8
- package/src/plugins/builtin/macro-day/pane.tsx +46 -10
- package/src/plugins/builtin/macro-day/releases.ts +55 -13
- package/src/plugins/builtin/market-heatmap/data.ts +9 -2
- package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
- package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
- package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
- package/src/plugins/builtin/market-heatmap/model.ts +10 -7
- package/src/plugins/builtin/market-movers/client.ts +36 -21
- package/src/plugins/builtin/market-movers/headless.ts +8 -2
- package/src/plugins/builtin/market-movers/index.tsx +16 -10
- package/src/plugins/builtin/market-movers/screener.ts +33 -11
- package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
- package/src/plugins/builtin/market-movers/session-table.ts +4 -2
- package/src/plugins/builtin/market-movers/table.ts +4 -1
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/view.ts +5 -0
- package/src/plugins/builtin/members/headless.ts +6 -5
- package/src/plugins/builtin/members/pane.tsx +11 -4
- package/src/plugins/builtin/mna/client.ts +1 -0
- package/src/plugins/builtin/mna/detail.tsx +20 -32
- package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
- package/src/plugins/builtin/mna/distress/model.ts +3 -2
- package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
- package/src/plugins/builtin/mna/headless.ts +6 -13
- package/src/plugins/builtin/mna/model.ts +93 -15
- package/src/plugins/builtin/mna/pane.tsx +5 -4
- package/src/plugins/builtin/news/headless.ts +12 -6
- package/src/plugins/builtin/news/index.tsx +10 -1
- package/src/plugins/builtin/news/wire/index.tsx +3 -2
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
- package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
- package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
- package/src/plugins/builtin/notes/cli.ts +50 -15
- package/src/plugins/builtin/notes/export.ts +17 -6
- package/src/plugins/builtin/notes/files.ts +16 -5
- package/src/plugins/builtin/openfda/pane.tsx +1 -1
- package/src/plugins/builtin/options/carry.ts +2 -2
- package/src/plugins/builtin/options/enrichment-model.ts +10 -9
- package/src/plugins/builtin/options/index.tsx +1 -1
- package/src/plugins/builtin/options/model-spot.ts +70 -4
- package/src/plugins/builtin/options/view.tsx +51 -23
- package/src/plugins/builtin/options-calculator/headless.ts +46 -7
- package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
- package/src/plugins/builtin/options-positioning/headless.ts +11 -3
- package/src/plugins/builtin/options-positioning/model.ts +24 -0
- package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
- package/src/plugins/builtin/options-scenario/client.ts +142 -29
- package/src/plugins/builtin/options-scenario/collar.ts +8 -6
- package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
- package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
- package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
- package/src/plugins/builtin/options-scenario/csp.ts +101 -21
- package/src/plugins/builtin/options-scenario/headless.ts +49 -21
- package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
- package/src/plugins/builtin/options-scenario/index.tsx +28 -3
- package/src/plugins/builtin/options-scenario/model.ts +13 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
- package/src/plugins/builtin/perps/equity-row.tsx +11 -3
- package/src/plugins/builtin/perps/freshness.ts +8 -5
- package/src/plugins/builtin/perps/headless.ts +3 -1
- package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
- package/src/plugins/builtin/perps/live-rows.ts +161 -0
- package/src/plugins/builtin/perps/markets-section.tsx +154 -0
- package/src/plugins/builtin/perps/pane.tsx +36 -17
- package/src/plugins/builtin/perps/venue-markets.ts +96 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
- package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
- package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
- package/src/plugins/builtin/portfolio-list/income.ts +13 -2
- package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
- package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
- package/src/plugins/builtin/power/client.ts +6 -3
- package/src/plugins/builtin/power/evidence.ts +22 -7
- package/src/plugins/builtin/power/gas.tsx +5 -1
- package/src/plugins/builtin/power/pane.tsx +44 -32
- package/src/plugins/builtin/power/prices.tsx +10 -3
- package/src/plugins/builtin/research/analyst-headless.ts +25 -8
- package/src/plugins/builtin/research/analyst-model.ts +68 -3
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
- package/src/plugins/builtin/research/event-model.ts +3 -1
- package/src/plugins/builtin/research/event-sources.ts +12 -4
- package/src/plugins/builtin/research/index.tsx +2 -1
- package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
- package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
- package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
- package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
- package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
- package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
- package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
- package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
- package/src/plugins/builtin/risk-factors/index.tsx +2 -2
- package/src/plugins/builtin/scanner/lock-note.ts +1 -1
- package/src/plugins/builtin/seasonality/client.ts +2 -1
- package/src/plugins/builtin/sec/forms.ts +13 -0
- package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
- package/src/plugins/builtin/sec/fund-facts.ts +68 -8
- package/src/plugins/builtin/sec/headless.ts +85 -8
- package/src/plugins/builtin/sec/index.tsx +58 -12
- package/src/plugins/builtin/sectors/client.ts +6 -4
- package/src/plugins/builtin/sectors/sector-model.ts +11 -15
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
- package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
- package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
- package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
- package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
- package/src/plugins/builtin/shared/earnings-report.ts +3 -3
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
- package/src/plugins/builtin/shared/job-posting.ts +129 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
- package/src/plugins/builtin/shared/report-freshness.ts +3 -0
- package/src/plugins/builtin/shared/research-trading.tsx +23 -0
- package/src/plugins/builtin/shared/series-cache.ts +2 -0
- package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
- package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
- package/src/plugins/builtin/shared/volatility/options.ts +2 -1
- package/src/plugins/builtin/short-interest/client.ts +2 -0
- package/src/plugins/builtin/short-interest/headless.ts +41 -12
- package/src/plugins/builtin/short-interest/index.tsx +23 -1
- package/src/plugins/builtin/short-interest/model.ts +70 -19
- package/src/plugins/builtin/short-interest/pane.tsx +19 -2
- package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
- package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
- package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
- package/src/plugins/builtin/short-interest/schedule.ts +35 -2
- package/src/plugins/builtin/short-interest/surface.tsx +11 -4
- package/src/plugins/builtin/short-interest/types.ts +9 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
- package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
- package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
- package/src/plugins/builtin/social-mentions/client.ts +2 -1
- package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
- package/src/plugins/builtin/supply-chain/model.ts +51 -3
- package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
- package/src/plugins/builtin/themes/headless.ts +8 -5
- package/src/plugins/builtin/themes/model.ts +14 -4
- package/src/plugins/builtin/themes/pane.tsx +24 -5
- package/src/plugins/builtin/thirteenf/headless.ts +5 -5
- package/src/plugins/builtin/thirteenf/signals.ts +3 -1
- package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
- package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
- package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
- package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
- package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
- package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
- package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
- package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
- package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
- package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
- package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
- package/src/plugins/builtin/vol-surface/client.ts +28 -7
- package/src/plugins/builtin/vol-surface/headless.ts +43 -15
- package/src/plugins/builtin/vol-surface/model.ts +34 -12
- package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
- package/src/plugins/builtin/vol-surface/stored.ts +34 -3
- package/src/plugins/builtin/vol-surface/tables.ts +14 -0
- package/src/plugins/builtin/volatility/model.ts +5 -10
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
- package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
- package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
- package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
- package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -26
- package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
- package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
- package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
- package/src/plugins/builtin/yield-curve/client.ts +25 -0
- package/src/plugins/builtin/yield-curve/curves.ts +7 -4
- package/src/plugins/builtin/yield-curve/headless.ts +38 -4
- package/src/plugins/builtin/yield-curve/history.ts +4 -3
- package/src/plugins/builtin/yield-curve/index.tsx +12 -6
- package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
- package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
- package/src/plugins/bundle.ts +1 -1
- package/src/plugins/catalog-browser.ts +2 -1
- package/src/plugins/compat.ts +3 -3
- package/src/plugins/dependencies.ts +75 -14
- package/src/plugins/extracted-plugins.ts +132 -34
- package/src/plugins/host-link.ts +149 -34
- package/src/plugins/installer.ts +35 -10
- package/src/plugins/loader.ts +206 -38
- package/src/plugins/manager-node.ts +2 -2
- package/src/plugins/marketplace/deactivation.ts +22 -0
- package/src/plugins/marketplace/model.ts +2 -2
- package/src/plugins/marketplace/packs.ts +1 -1
- package/src/plugins/ownership.ts +1 -1
- package/src/plugins/peer-retry.ts +155 -0
- package/src/plugins/registry/contributions.ts +3 -1
- package/src/plugins/registry/index.ts +4 -3
- package/src/plugins/registry/plugin-state.ts +3 -0
- package/src/plugins/seed-notice.ts +20 -0
- package/src/plugins/shortcut-argument.ts +39 -0
- package/src/portfolio/allocation.ts +1 -1
- package/src/portfolio/collection-name.ts +31 -0
- package/src/portfolio/column-values.ts +10 -8
- package/src/portfolio/cost-fx.ts +296 -19
- package/src/portfolio/manual-lots.ts +75 -0
- package/src/portfolio/mutations.ts +60 -22
- package/src/portfolio/suffixed-listings.ts +209 -0
- package/src/portfolio/totals-currency.ts +24 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
- package/src/public/time-series.ts +11 -8
- package/src/remote/schema.ts +1 -1
- package/src/renderers/browser/config-host.ts +3 -0
- package/src/renderers/browser/main.tsx +23 -3
- package/src/renderers/dom/boot-frame-page.ts +187 -0
- package/src/renderers/dom/boot-frame.ts +237 -0
- package/src/renderers/dom/build-assets.ts +46 -8
- package/src/renderers/dom/desktop/controls.tsx +1 -1
- package/src/renderers/dom/desktop/query-bar.tsx +2 -0
- package/src/renderers/dom/dom-ui-host.tsx +4 -29
- package/src/renderers/dom/host/ascii-text.ts +16 -2
- package/src/renderers/dom/host/box.tsx +43 -2
- package/src/renderers/dom/host/chart-surface.tsx +2 -0
- package/src/renderers/dom/host/hls.chunk.ts +3 -0
- package/src/renderers/dom/host/image-surface.tsx +49 -0
- package/src/renderers/dom/host/media-surface.tsx +24 -18
- package/src/renderers/dom/host/mouse.ts +30 -0
- package/src/renderers/dom/host/size-observer.ts +1 -1
- package/src/renderers/dom/host/style.ts +1 -1
- package/src/renderers/dom/host/tabs.tsx +16 -5
- package/src/renderers/dom/host/top-surface.ts +127 -0
- package/src/renderers/dom/styles.css +115 -0
- package/src/renderers/dom/test-utils.tsx +2 -1
- package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
- package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
- package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
- package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
- package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
- package/src/renderers/electrobun/bun/index.ts +11 -1
- package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
- package/src/renderers/electrobun/bun/window/create.ts +4 -1
- package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
- package/src/renderers/electrobun/shared/protocol.ts +6 -1
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/config-host.ts +3 -0
- package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
- package/src/renderers/electrobun/view/main.tsx +30 -4
- package/src/renderers/electrobun/view/news-source.ts +9 -7
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
- package/src/renderers/electrobun/view/ui-host.tsx +1 -1
- package/src/renderers/opentui/browser-open.ts +88 -0
- package/src/renderers/opentui/host.tsx +5 -14
- package/src/renderers/opentui/image/loader.ts +3 -2
- package/src/renderers/opentui/native-smoke.ts +10 -1
- package/src/renderers/opentui/pane-image/index.ts +2 -1
- package/src/renderers/opentui/render-lib.ts +253 -0
- package/src/renderers/opentui/render-timing-smoke.ts +1 -1
- package/src/renderers/opentui/start.tsx +8 -1
- package/src/renderers/share/layout-view.tsx +2 -2
- package/src/renderers/share/main.tsx +4 -4
- package/src/renderers/share/view.tsx +1 -1
- package/src/series/resolve.ts +22 -6
- package/src/series/standalone.ts +30 -2
- package/src/series/types.ts +8 -1
- package/src/shares/api.ts +4 -1
- package/src/shares/pane.ts +1 -1
- package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
- package/src/sources/gloomberb-cloud/index.ts +39 -16
- package/src/sources/gloomberb-cloud/news.ts +39 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
- package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
- package/src/sources/listing-symbols.ts +37 -0
- package/src/sources/provider-errors.ts +16 -2
- package/src/sources/provider-router/financial-routes.ts +21 -3
- package/src/sources/provider-router/financials.ts +15 -2
- package/src/sources/provider-router/history.ts +30 -8
- package/src/sources/provider-router/index.ts +16 -0
- package/src/sources/provider-router/primary.ts +1 -1
- package/src/state/app/bootstrap.ts +23 -0
- package/src/state/hooks/inline-tickers.ts +30 -5
- package/src/sync/controller.ts +1 -1
- package/src/sync/core-contributors.ts +46 -14
- package/src/team/collections-sync.ts +2 -1
- package/src/team/collections.ts +178 -17
- package/src/telemetry/crash-reports.ts +21 -4
- package/src/telemetry/update-failures-node.ts +59 -0
- package/src/telemetry/update-failures.ts +307 -0
- package/src/test-support/builtin-panes.ts +1 -1
- package/src/theme/colors.ts +3 -30
- package/src/theme/ui-tokens.ts +37 -1
- package/src/tickers/company-name-listing.ts +215 -36
- package/src/tickers/company-name.ts +43 -0
- package/src/tickers/index-roots.ts +47 -0
- package/src/tickers/instrument-label.ts +5 -1
- package/src/tickers/listing-fate.ts +30 -0
- package/src/tickers/metadata.ts +10 -0
- package/src/tickers/perpetual-listing.ts +5 -2
- package/src/tickers/search/home-listing.ts +75 -0
- package/src/tickers/search/index.ts +76 -27
- package/src/tickers/search/ranking.ts +54 -4
- package/src/tickers/search/upsert.ts +29 -0
- package/src/tickers/terminal-codes.ts +416 -40
- package/src/time-series/bar-aggregation.ts +243 -0
- package/src/time-series/base-series.ts +307 -0
- package/src/time-series/chart-bounds.ts +349 -0
- package/src/time-series/chart-seed.ts +142 -0
- package/src/time-series/economic.ts +5 -0
- package/src/time-series/fundamentals.ts +18 -3
- package/src/time-series/history-acquisition.ts +499 -0
- package/src/time-series/leverage.ts +100 -0
- package/src/time-series/market-resolution.ts +4 -2
- package/src/time-series/market.ts +2 -1
- package/src/time-series/price-comparison.ts +175 -30
- package/src/time-series/range.ts +9 -1
- package/src/time-series/resolution.ts +174 -16
- package/src/time-series/resolve-context.ts +157 -0
- package/src/time-series/resolve.ts +126 -1577
- package/src/time-series/series-name.ts +38 -0
- package/src/time-series/series-presentation.ts +208 -0
- package/src/time-series/spec.ts +11 -6
- package/src/time-series/studies.ts +109 -12
- package/src/time-series/tail-reconcile.ts +121 -0
- package/src/time-series/types.ts +29 -2
- package/src/time-series/use-chart-resolution.ts +4 -5
- package/src/types/broker.ts +10 -0
- package/src/types/config.ts +14 -0
- package/src/types/data-provider.ts +20 -0
- package/src/types/exchange-rate.ts +6 -0
- package/src/types/financials.ts +104 -7
- package/src/types/headless.ts +83 -6
- package/src/types/instrument.ts +3 -0
- package/src/types/issuer-listings.ts +28 -0
- package/src/types/plugin.ts +65 -8
- package/src/types/price-history.ts +2 -0
- package/src/types/ticker.ts +13 -0
- package/src/types/trading.ts +59 -1
- package/src/ui/ascii-font.ts +13 -1
- package/src/ui/host.tsx +6 -1
- package/src/updater/command-names.ts +175 -0
- package/src/updater/failure.ts +163 -0
- package/src/updater/index.ts +97 -28
- package/src/utils/calendar-date.ts +32 -15
- package/src/utils/cash-runway.ts +241 -0
- package/src/utils/central-banks.ts +42 -0
- package/src/utils/cli-output.ts +259 -80
- package/src/utils/contract-month.ts +16 -0
- package/src/utils/crypto-pair.ts +61 -3
- package/src/utils/currency-pair.ts +26 -0
- package/src/utils/currency-units.ts +29 -0
- package/src/utils/datetime-format.ts +10 -0
- package/src/utils/debug-log.ts +1 -1
- package/src/utils/decimal-comma.ts +39 -6
- package/src/utils/exchange-announcements.ts +71 -0
- package/src/utils/exchange-rate-snapshot.ts +10 -0
- package/src/utils/financial-statements.ts +83 -4
- package/src/utils/format.ts +34 -16
- package/src/utils/fundamentals.ts +150 -34
- package/src/utils/fx-market-hours.ts +10 -1
- package/src/utils/latest-financial-period.ts +8 -0
- package/src/utils/linux-libc.ts +54 -0
- package/src/utils/market-capitalization.ts +111 -15
- package/src/utils/max-drawdown.ts +64 -0
- package/src/utils/network-failure.ts +83 -0
- package/src/utils/option-expiry.ts +139 -7
- package/src/utils/price-earnings.ts +11 -5
- package/src/utils/price-history.ts +18 -8
- package/src/utils/price-window.ts +131 -0
- package/src/utils/release-date.ts +47 -0
- package/src/utils/sec.ts +71 -0
- package/src/utils/throttled-fetch.ts +11 -4
- package/src/utils/trailing-eps.ts +67 -0
- package/src/utils/typed-text.ts +21 -0
- package/src/utils/utc-time.ts +24 -1
- package/src/version.ts +6 -0
- package/src/cli/pane-functions/screenshot.ts +0 -2122
|
@@ -12,8 +12,9 @@ import { getSharedRegistry } from "../../registry";
|
|
|
12
12
|
import { requestAccountManagementTab } from "../account-management/navigation";
|
|
13
13
|
import { resolvePlanAccess, usePlanAccess, type PlanAccess } from "../../../api-client/plan-access";
|
|
14
14
|
import { useViewport } from "../../../react/input";
|
|
15
|
-
import { useOptionalDialog } from "../../../ui/dialog";
|
|
15
|
+
import { type DialogApi, useOptionalDialog } from "../../../ui/dialog";
|
|
16
16
|
import { promptCloudUpgrade } from "../../../account/upgrade-dialog";
|
|
17
|
+
import { type CheckoutHandoffTarget, promptCheckoutHandoff } from "../../../account/checkout-handoff";
|
|
17
18
|
|
|
18
19
|
const CLOUD_UPGRADE_URL = "https://gloom.sh/cloud?upgrade=pro";
|
|
19
20
|
|
|
@@ -120,8 +121,12 @@ export function resetCloudUpgradeGuardForTests(): void {
|
|
|
120
121
|
cloudUpgradeBlockedUntil.clear();
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
function cloudUpgradeReturnTo(): string | undefined {
|
|
125
|
+
return getCurrentPluginTarget() === "web" ? window.location.href : undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
123
128
|
async function resolveCloudUpgradeUrl(page: CloudUpgradePage, options: CloudUpgradeOptions): Promise<string> {
|
|
124
|
-
const returnTo =
|
|
129
|
+
const returnTo = cloudUpgradeReturnTo();
|
|
125
130
|
if (page === "cloud") return researchUpgradeUrl(returnTo);
|
|
126
131
|
const { url } = page === "portal"
|
|
127
132
|
? await apiClient.createBillingPortal()
|
|
@@ -138,6 +143,28 @@ async function openCloudUpgrade(
|
|
|
138
143
|
await rendererHost.openExternal(await resolveCloudUpgradeUrl(page, options));
|
|
139
144
|
}
|
|
140
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Opens checkout with the hand-off over the app: it says checkout is in the
|
|
148
|
+
* browser, reopens that same checkout, shows the short link where no browser
|
|
149
|
+
* opened, and waits for Pro. Settles once the browser was asked to open it;
|
|
150
|
+
* the dialog stays until Pro arrives or it is closed. Only a checkout that
|
|
151
|
+
* cannot be created rejects: a browser that fails to open leaves the link.
|
|
152
|
+
*/
|
|
153
|
+
async function openCheckoutWithHandoff(
|
|
154
|
+
dialog: DialogApi,
|
|
155
|
+
rendererHost: Pick<RendererHost, "openExternal">,
|
|
156
|
+
options: CloudUpgradeOptions,
|
|
157
|
+
): Promise<void> {
|
|
158
|
+
const target = apiClient.createCloudCheckout(cloudUpgradeReturnTo(), options.interval ?? "month")
|
|
159
|
+
.then(({ url, link }): CheckoutHandoffTarget => ({
|
|
160
|
+
url,
|
|
161
|
+
link: link ?? null,
|
|
162
|
+
opened: rendererHost.openExternal(url).then((result) => result !== false, () => false),
|
|
163
|
+
}));
|
|
164
|
+
void promptCheckoutHandoff(dialog, target);
|
|
165
|
+
await (await target).opened;
|
|
166
|
+
}
|
|
167
|
+
|
|
141
168
|
/**
|
|
142
169
|
* Opens the checkout page when any cloud UI has published an opener, counted
|
|
143
170
|
* under `placement` rather than the UI that published it.
|
|
@@ -166,9 +193,9 @@ function isCloudUpgradeOptions(value: unknown): value is CloudUpgradeOptions {
|
|
|
166
193
|
* a held Enter would otherwise open a checkout per keypress.
|
|
167
194
|
*
|
|
168
195
|
* A signed-in account without Pro sees the upgrade sheet first (what Pro adds,
|
|
169
|
-
* what today costs), and checkout opens only once they choose to go on
|
|
170
|
-
*
|
|
171
|
-
* portal, as before.
|
|
196
|
+
* what today costs), and checkout opens only once they choose to go on, with
|
|
197
|
+
* the checkout hand-off over the app until Pro arrives. Signed-out users get
|
|
198
|
+
* the public Cloud page and Pro accounts the billing portal, as before.
|
|
172
199
|
*/
|
|
173
200
|
export function useCloudUpgradeAction(placement: string): (options?: unknown) => Promise<void> {
|
|
174
201
|
const rendererHost = useRendererHost();
|
|
@@ -184,7 +211,8 @@ export function useCloudUpgradeAction(placement: string): (options?: unknown) =>
|
|
|
184
211
|
const page = currentCloudUpgradePage();
|
|
185
212
|
await openCloudUpgradePage(page, async () => {
|
|
186
213
|
resolved.onOpening?.();
|
|
187
|
-
await
|
|
214
|
+
if (page === "checkout" && dialog) await openCheckoutWithHandoff(dialog, rendererHost, resolved);
|
|
215
|
+
else await openCloudUpgrade(rendererHost, page, resolved);
|
|
188
216
|
}).catch(() => (
|
|
189
217
|
// Keep the Cloud page reachable when checkout cannot be created; a native
|
|
190
218
|
// session still rides along on the server's one-time handoff URL. Under
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import type { DataProvider, EarningsEvent } from "../../../types/data-provider";
|
|
2
|
+
import type { CorporateActionsData, EarningsAction, EarningsDateStatus, EarningsEpsBasis } from "../../../types/financials";
|
|
3
|
+
import { logFailure } from "../../../utils/log-failure";
|
|
4
|
+
import { zonedDateKey } from "../../../utils/zoned-date-time";
|
|
5
|
+
import { dateStatusFromEstimateFlag, earningsDateStatus, earningsEpsBasis } from "./earnings-report";
|
|
6
|
+
import { coherentEarningsValue, EARNINGS_ESTIMATE_FIELDS } from "./earnings-estimate-basis";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The one reading of a company's report dates that `earnings`, `events`, EE,
|
|
10
|
+
* ERN, OSA and the LEAPS next-earnings column share: the per-ticker
|
|
11
|
+
* calendar's date resolved against the quarters the company has on record
|
|
12
|
+
* (corporate actions, ERN's history), so a symbol shows the same next date,
|
|
13
|
+
* timing and status everywhere.
|
|
14
|
+
*
|
|
15
|
+
* - A confirmed date beats an estimated one; otherwise the calendar's stands
|
|
16
|
+
* (JPM: the record's 2027-01-13 gives way to the calendar's confirmed
|
|
17
|
+
* 2027-01-14).
|
|
18
|
+
* - A date that has passed is reported, with the actual EPS once it is known
|
|
19
|
+
* (PEP's 2026-10-08). A report out today is reported as soon as its figure
|
|
20
|
+
* is, as same-day actuals are (META after the close).
|
|
21
|
+
* - A next date only the calendar knows is added (GS's 2027-01-19).
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/** Two dates this close are one report under two sources: quarterly reports are some ninety days apart. */
|
|
25
|
+
const SAME_QUARTER_DAYS = 45;
|
|
26
|
+
/** An actual this close to an upcoming date is that report, out already. */
|
|
27
|
+
const SAME_REPORT_DAYS = 3;
|
|
28
|
+
const DAY_MS = 86_400_000;
|
|
29
|
+
|
|
30
|
+
/** The trading calendar's day, which report dates are on. */
|
|
31
|
+
export function newYorkDay(now = Date.now()): string {
|
|
32
|
+
return zonedDateKey(now, "America/New_York");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The day the calendar puts a report on, YYYY-MM-DD. */
|
|
36
|
+
function calendarDay(event: Pick<EarningsEvent, "earningsDate">): string {
|
|
37
|
+
return event.earningsDate.toISOString().slice(0, 10);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A calendar event's status on `today`: reported once the report is out
|
|
42
|
+
* (Gloom Cloud says so, or has its figure) or its date has passed.
|
|
43
|
+
*/
|
|
44
|
+
export function calendarStatus(
|
|
45
|
+
event: Pick<EarningsEvent, "earningsDate" | "epsActual" | "isDateEstimate" | "dateStatus">,
|
|
46
|
+
today: string,
|
|
47
|
+
): EarningsDateStatus | null {
|
|
48
|
+
if (event.epsActual != null || earningsDateStatus(event.dateStatus) === "reported" || calendarDay(event) < today) return "reported";
|
|
49
|
+
return dateStatusFromEstimateFlag(event.isDateEstimate);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Whether the calendar's date for a report replaces another source's: a confirmed date beats an estimated one, else the calendar's stands. */
|
|
53
|
+
function calendarDateWins(calendar: EarningsDateStatus | null, other: EarningsDateStatus | null): boolean {
|
|
54
|
+
return calendar === "confirmed" || other !== "confirmed";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The calendar's report as a quarter on record takes it. */
|
|
58
|
+
interface CalendarReport {
|
|
59
|
+
date: string;
|
|
60
|
+
timing: "bmo" | "amc" | null;
|
|
61
|
+
dateStatus: EarningsDateStatus | null;
|
|
62
|
+
/** Whether the calendar's consensus is for this report; see `consensusIsReports`. */
|
|
63
|
+
ownConsensus: boolean;
|
|
64
|
+
/** Null when the calendar's consensus cannot be tied to the report. */
|
|
65
|
+
epsEstimate: number | null;
|
|
66
|
+
epsAnalysts: number | null;
|
|
67
|
+
epsActual: number | null;
|
|
68
|
+
epsBasis: EarningsEpsBasis | null;
|
|
69
|
+
revenueEstimate: number | null;
|
|
70
|
+
/** The quarter the estimate is for, YYYY-MM, when the calendar names it. */
|
|
71
|
+
fiscalPeriod: string | null;
|
|
72
|
+
currency: string | null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Whether the calendar's consensus is for its own report. A report out keeps
|
|
77
|
+
* its date while the consensus rolls to the next quarter (PEP's 2026-10-08
|
|
78
|
+
* beside December's 2.24), so once a report is out its consensus counts only
|
|
79
|
+
* when something ties it to that report: the calendar's actual beside it,
|
|
80
|
+
* Gloom Cloud's stored report (which says its status, and keeps the report's
|
|
81
|
+
* own consensus), or a forecast quarter ending before the report date.
|
|
82
|
+
*/
|
|
83
|
+
function consensusIsReports(event: EarningsEvent, dateStatus: EarningsDateStatus | null, date: string): boolean {
|
|
84
|
+
if (dateStatus !== "reported" || event.epsActual != null || event.dateStatus != null) return true;
|
|
85
|
+
const periodEnd = event.estimateBasis?.epsEstimate?.periodEndDate ?? null;
|
|
86
|
+
return periodEnd != null && periodEnd < date;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function calendarReport(event: EarningsEvent, today: string): CalendarReport {
|
|
90
|
+
const date = calendarDay(event);
|
|
91
|
+
const dateStatus = calendarStatus(event, today);
|
|
92
|
+
const ownConsensus = consensusIsReports(event, dateStatus, date);
|
|
93
|
+
const periodEnd = event.estimateBasis?.epsEstimate?.periodEndDate ?? null;
|
|
94
|
+
const epsEstimate = ownConsensus ? coherentEarningsValue(event, "epsEstimate") : null;
|
|
95
|
+
return {
|
|
96
|
+
date,
|
|
97
|
+
timing: event.timing === "BMO" ? "bmo" : event.timing === "AMC" ? "amc" : null,
|
|
98
|
+
dateStatus,
|
|
99
|
+
ownConsensus,
|
|
100
|
+
epsEstimate,
|
|
101
|
+
epsAnalysts: epsEstimate == null ? null : coherentEarningsValue(event, "epsAnalysts"),
|
|
102
|
+
epsActual: event.epsActual ?? null,
|
|
103
|
+
epsBasis: epsEstimate == null ? null : earningsEpsBasis(event.epsBasis),
|
|
104
|
+
revenueEstimate: ownConsensus ? coherentEarningsValue(event, "revenueEstimate") : null,
|
|
105
|
+
fiscalPeriod: ownConsensus && periodEnd ? periodEnd.slice(0, 7) : null,
|
|
106
|
+
currency: epsEstimate == null ? null : event.estimateBasis?.epsEstimate?.currency ?? null,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** What the resolver reads of a quarter on record. */
|
|
111
|
+
interface ReportSlot {
|
|
112
|
+
date: string;
|
|
113
|
+
dateStatus: EarningsDateStatus | null | undefined;
|
|
114
|
+
epsActual: number | null | undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** How one source's rows are read and rebuilt: corporate actions for events and EE, history for ERN. */
|
|
118
|
+
export interface ReportRowAdapter<T> {
|
|
119
|
+
slot(row: T): ReportSlot;
|
|
120
|
+
/** The row labelled reported, with `epsActual` when it has no figure of its own. */
|
|
121
|
+
reported(row: T, epsActual: number | null): T;
|
|
122
|
+
/** The calendar's report as a row: over `row` when it is the same report, else a new one. */
|
|
123
|
+
fromCalendar(report: CalendarReport, row: T | null): T;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const isOut = (slot: ReportSlot, today: string) => slot.epsActual != null || slot.dateStatus === "reported" || slot.date < today;
|
|
127
|
+
const dayGap = (left: string, right: string) => Math.abs(Date.parse(`${left}T00:00:00Z`) - Date.parse(`${right}T00:00:00Z`)) / DAY_MS;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The row the calendar's report is: for a report out, the nearest quarter on
|
|
131
|
+
* record that is out, else an upcoming one days away; for an upcoming one,
|
|
132
|
+
* the nearest upcoming quarter, else one out days away (out early).
|
|
133
|
+
*/
|
|
134
|
+
function calendarRowIndex(slots: readonly ReportSlot[], report: CalendarReport, today: string): number {
|
|
135
|
+
const nearest = (keep: (slot: ReportSlot) => boolean, days: number) => {
|
|
136
|
+
let best = -1;
|
|
137
|
+
for (const [index, slot] of slots.entries()) {
|
|
138
|
+
const gap = dayGap(slot.date, report.date);
|
|
139
|
+
if (gap <= days && keep(slot) && (best < 0 || gap < dayGap(slots[best]!.date, report.date))) best = index;
|
|
140
|
+
}
|
|
141
|
+
return best;
|
|
142
|
+
};
|
|
143
|
+
const out = (slot: ReportSlot) => isOut(slot, today);
|
|
144
|
+
const upcoming = (slot: ReportSlot) => !isOut(slot, today);
|
|
145
|
+
const [first, second] = report.dateStatus === "reported" ? [out, upcoming] : [upcoming, out];
|
|
146
|
+
const index = nearest(first, SAME_QUARTER_DAYS);
|
|
147
|
+
return index >= 0 ? index : nearest(second, SAME_REPORT_DAYS);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Quarters on record resolved against the calendar's event, with the row
|
|
152
|
+
* that is the calendar's report. Past quarters read reported; the calendar's
|
|
153
|
+
* report updates its row, or is added when the record has none.
|
|
154
|
+
*/
|
|
155
|
+
function resolveReportRowsWithCalendar<T>(
|
|
156
|
+
rows: readonly T[],
|
|
157
|
+
event: EarningsEvent | null | undefined,
|
|
158
|
+
today: string,
|
|
159
|
+
adapter: ReportRowAdapter<T>,
|
|
160
|
+
): { rows: T[]; calendarRow: T | null } {
|
|
161
|
+
const resolved = rows.map((row) => {
|
|
162
|
+
const slot = adapter.slot(row);
|
|
163
|
+
return isOut(slot, today) && slot.dateStatus !== "reported" ? adapter.reported(row, null) : row;
|
|
164
|
+
});
|
|
165
|
+
if (!event) return { rows: resolved, calendarRow: null };
|
|
166
|
+
const report = calendarReport(event, today);
|
|
167
|
+
const index = calendarRowIndex(resolved.map(adapter.slot), report, today);
|
|
168
|
+
if (index < 0) {
|
|
169
|
+
const added = adapter.fromCalendar(report, null);
|
|
170
|
+
return { rows: [...resolved, added], calendarRow: added };
|
|
171
|
+
}
|
|
172
|
+
const row = resolved[index]!;
|
|
173
|
+
const slot = adapter.slot(row);
|
|
174
|
+
if (isOut(slot, today)) {
|
|
175
|
+
if (slot.epsActual == null && report.epsActual != null) resolved[index] = adapter.reported(row, report.epsActual);
|
|
176
|
+
} else if (report.dateStatus === "reported" || calendarDateWins(report.dateStatus, earningsDateStatus(slot.dateStatus))) {
|
|
177
|
+
resolved[index] = adapter.fromCalendar(report, row);
|
|
178
|
+
}
|
|
179
|
+
return { rows: resolved, calendarRow: resolved[index]! };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function resolveReportRows<T>(rows: readonly T[], event: EarningsEvent | null | undefined, today: string, adapter: ReportRowAdapter<T>): T[] {
|
|
183
|
+
return resolveReportRowsWithCalendar(rows, event, today, adapter).rows;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const TIME_TEXT = { bmo: "Pre Market", amc: "After Hours" } as const;
|
|
187
|
+
|
|
188
|
+
/** A row's beat, measured as Gloom Cloud measures it, once the calendar gives it a figure or an estimate it lacked. */
|
|
189
|
+
function withSurprise(row: EarningsAction, before: EarningsAction | null): EarningsAction {
|
|
190
|
+
const { epsActual: actual, epsEstimate: estimate } = row;
|
|
191
|
+
if (actual == null || estimate == null || (actual === before?.epsActual && estimate === before.epsEstimate)) return row;
|
|
192
|
+
const cents = (value: number) => Math.round(value * 100) / 100;
|
|
193
|
+
const { difference: _difference, surprisePercent: _surprise, ...rest } = row;
|
|
194
|
+
return { ...rest, difference: cents(actual - estimate), ...(estimate !== 0 ? { surprisePercent: cents((actual - estimate) / Math.abs(estimate) * 100) } : {}) };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function definedFields<T extends object>(row: T): T {
|
|
198
|
+
return Object.fromEntries(Object.entries(row).filter(([, value]) => value !== undefined)) as T;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Corporate-actions earnings rows, as events, EE and the `earnings` resolution read them. */
|
|
202
|
+
const ACTION_ROWS: ReportRowAdapter<EarningsAction> = {
|
|
203
|
+
slot: (row) => ({ date: row.date, dateStatus: earningsDateStatus(row.dateStatus), epsActual: row.epsActual }),
|
|
204
|
+
reported: (row, epsActual) => withSurprise({ ...row, dateStatus: "reported", ...(row.epsActual == null && epsActual != null ? { epsActual } : {}) }, row),
|
|
205
|
+
fromCalendar(report, row) {
|
|
206
|
+
// The calendar's consensus goes with its date; without one, the record's stays.
|
|
207
|
+
const estimate = report.epsEstimate != null;
|
|
208
|
+
return withSurprise(definedFields<EarningsAction>({
|
|
209
|
+
...row,
|
|
210
|
+
date: report.date,
|
|
211
|
+
dateType: "announcement",
|
|
212
|
+
time: report.timing ? TIME_TEXT[report.timing] : row?.time,
|
|
213
|
+
currency: estimate ? report.currency ?? row?.currency : row?.currency,
|
|
214
|
+
epsEstimate: estimate ? report.epsEstimate! : row?.epsEstimate,
|
|
215
|
+
epsAnalysts: estimate ? report.epsAnalysts ?? undefined : row?.epsAnalysts,
|
|
216
|
+
epsActual: report.epsActual ?? row?.epsActual,
|
|
217
|
+
fiscalPeriod: row?.fiscalPeriod ?? report.fiscalPeriod ?? undefined,
|
|
218
|
+
epsBasis: estimate ? report.epsBasis : row?.epsBasis,
|
|
219
|
+
dateStatus: report.dateStatus ?? undefined,
|
|
220
|
+
}), row);
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/** A company's corporate-actions earnings rows, newest first, resolved against its calendar event. */
|
|
225
|
+
export function resolveEarningsActions(earnings: readonly EarningsAction[], event: EarningsEvent | null | undefined, today: string): EarningsAction[] {
|
|
226
|
+
return resolveReportRows(earnings, event, today, ACTION_ROWS).sort((left, right) => right.date.localeCompare(left.date));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** A company's corporate actions with their earnings rows resolved against its calendar event. */
|
|
230
|
+
export function withResolvedEarnings(actions: CorporateActionsData, event: EarningsEvent | null | undefined, today: string): CorporateActionsData {
|
|
231
|
+
// Without a calendar event the rows still resolve: a date gone by reads reported, as ERN reads it.
|
|
232
|
+
return { ...actions, earnings: resolveEarningsActions(actions.earnings, event, today) };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** The calendar's event for a symbol, as it was asked for (SAN:EPA comes back as SAN:EPA). */
|
|
236
|
+
export function calendarEventOf(events: readonly EarningsEvent[] | null | undefined, symbol: string): EarningsEvent | null {
|
|
237
|
+
const key = symbol.trim().toUpperCase();
|
|
238
|
+
return events?.find((event) => event.symbol.trim().toUpperCase() === key) ?? null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Whether the calendar event is read against its quarters on record: once
|
|
243
|
+
* its date has come or its report is out, for the actual and the next
|
|
244
|
+
* report, and while its date is not confirmed, which a confirmed date on
|
|
245
|
+
* record beats. A confirmed date to come stands alone.
|
|
246
|
+
*/
|
|
247
|
+
function needsRecordedQuarters(event: EarningsEvent, today: string): boolean {
|
|
248
|
+
return event.epsActual == null && (calendarDay(event) <= today || calendarStatus(event, today) !== "confirmed");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface ResolvedEarningsEvent extends EarningsEvent {
|
|
252
|
+
/** Out, announced or projected, after resolution; null when no source says. */
|
|
253
|
+
dateStatus: EarningsDateStatus | null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const TIMING_OF_TEXT: Record<string, EarningsEvent["timing"]> = { "Pre Market": "BMO", "After Hours": "AMC" };
|
|
257
|
+
|
|
258
|
+
/** The calendar's event without its consensus, which is another quarter's than the report's. */
|
|
259
|
+
function withoutConsensus(event: EarningsEvent): EarningsEvent {
|
|
260
|
+
const stripped: EarningsEvent = { ...event, epsEstimate: null, revenueEstimate: null, epsBasis: null };
|
|
261
|
+
delete stripped.estimateBasis;
|
|
262
|
+
for (const field of EARNINGS_ESTIMATE_FIELDS) if (stripped[field] != null) stripped[field] = null;
|
|
263
|
+
return stripped;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const statusFlag = (status: EarningsDateStatus | null) => status === "projected" ? true : status === "confirmed" ? false : null;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* The resolved event for a row. The calendar's own report keeps every figure
|
|
270
|
+
* the calendar carries (revenue, ranges, bases), but its consensus only when
|
|
271
|
+
* it is the report's, and takes the row's status and, when the record has the
|
|
272
|
+
* actual the calendar lacks, the record's EPS figures, measured against the
|
|
273
|
+
* record's estimate. Another report on record is that row alone.
|
|
274
|
+
*/
|
|
275
|
+
function eventOfRow(event: EarningsEvent, row: EarningsAction, report: CalendarReport | null): ResolvedEarningsEvent {
|
|
276
|
+
const ownDate = row.date === calendarDay(event);
|
|
277
|
+
const dateStatus = earningsDateStatus(row.dateStatus);
|
|
278
|
+
const earningsDate = ownDate ? event.earningsDate : new Date(`${row.date}T00:00:00.000Z`);
|
|
279
|
+
const rowTiming = TIMING_OF_TEXT[row.time ?? ""];
|
|
280
|
+
if (report) {
|
|
281
|
+
const base = report.ownConsensus ? event : withoutConsensus(event);
|
|
282
|
+
const recordFigures = row.epsActual != null && event.epsActual == null;
|
|
283
|
+
return {
|
|
284
|
+
...base,
|
|
285
|
+
earningsDate,
|
|
286
|
+
earningsCallDate: ownDate ? event.earningsCallDate ?? null : null,
|
|
287
|
+
isDateEstimate: statusFlag(dateStatus) ?? (dateStatus === "reported" ? base.isDateEstimate ?? null : null),
|
|
288
|
+
epsEstimate: recordFigures ? row.epsEstimate ?? null : base.epsEstimate ?? row.epsEstimate ?? null,
|
|
289
|
+
epsAnalysts: recordFigures ? row.epsAnalysts ?? null : base.epsAnalysts ?? row.epsAnalysts ?? null,
|
|
290
|
+
epsActual: event.epsActual ?? row.epsActual ?? null,
|
|
291
|
+
epsBasis: recordFigures ? row.epsBasis ?? null : base.epsBasis ?? row.epsBasis ?? null,
|
|
292
|
+
surprise: recordFigures ? row.surprisePercent ?? null : base.surprise ?? row.surprisePercent ?? null,
|
|
293
|
+
timing: (ownDate && event.timing) || rowTiming || event.timing,
|
|
294
|
+
dateStatus,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
symbol: event.symbol,
|
|
299
|
+
name: event.name,
|
|
300
|
+
earningsDate,
|
|
301
|
+
earningsCallDate: null,
|
|
302
|
+
isDateEstimate: statusFlag(dateStatus),
|
|
303
|
+
epsEstimate: row.epsEstimate ?? null,
|
|
304
|
+
epsAnalysts: row.epsAnalysts ?? null,
|
|
305
|
+
epsActual: row.epsActual ?? null,
|
|
306
|
+
epsBasis: row.epsBasis ?? null,
|
|
307
|
+
revenueEstimate: null,
|
|
308
|
+
revenueActual: null,
|
|
309
|
+
surprise: row.surprisePercent ?? null,
|
|
310
|
+
timing: rowTiming ?? "",
|
|
311
|
+
dateStatus,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* A company's next report: the calendar's, resolved against its quarters on
|
|
317
|
+
* record when they were read. Once the calendar's date has passed, the next
|
|
318
|
+
* upcoming quarter on record stands in, else the report that is out, with its
|
|
319
|
+
* actual and the estimate it was measured against. Without the record, a past
|
|
320
|
+
* date still reads reported.
|
|
321
|
+
*/
|
|
322
|
+
export function resolveCalendarEvent(event: EarningsEvent, earnings: readonly EarningsAction[] | null | undefined, today: string): ResolvedEarningsEvent {
|
|
323
|
+
const status = calendarStatus(event, today);
|
|
324
|
+
if (!earnings && status !== "reported") return { ...event, dateStatus: status };
|
|
325
|
+
const { rows, calendarRow } = resolveReportRowsWithCalendar(earnings ?? [], event, today, ACTION_ROWS);
|
|
326
|
+
const next = rows
|
|
327
|
+
.filter((row) => !isOut(ACTION_ROWS.slot(row), today))
|
|
328
|
+
.sort((left, right) => left.date.localeCompare(right.date))[0];
|
|
329
|
+
const chosen = next ?? calendarRow!;
|
|
330
|
+
return eventOfRow(event, chosen, chosen === calendarRow ? calendarReport(event, today) : null);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** The next report date, YYYY-MM-DD, of a resolved event; null once it is out. */
|
|
334
|
+
export function upcomingReportDate(event: ResolvedEarningsEvent | null | undefined): string | null {
|
|
335
|
+
return event && event.dateStatus !== "reported" ? calendarDay(event) : null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** A listing: the calendar's key for it (SAN:EPA) and the symbol and venue corporate actions are read by. */
|
|
339
|
+
export interface EarningsListing {
|
|
340
|
+
key: string;
|
|
341
|
+
symbol: string;
|
|
342
|
+
exchange: string;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Calendar events need their quarters on record read at most this many at a time. */
|
|
346
|
+
const RECORD_CONCURRENCY = 4;
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Each listing's calendar event, resolved: the corporate actions of those
|
|
350
|
+
* whose date has come are read for their actual and the next quarter on
|
|
351
|
+
* record. A listing the calendar has nothing for is absent; one whose
|
|
352
|
+
* record cannot be read resolves on the calendar alone.
|
|
353
|
+
*/
|
|
354
|
+
export async function resolveListingEvents(
|
|
355
|
+
provider: Pick<DataProvider, "getCorporateActions">,
|
|
356
|
+
listings: readonly EarningsListing[],
|
|
357
|
+
events: readonly EarningsEvent[],
|
|
358
|
+
today: string,
|
|
359
|
+
): Promise<Map<string, ResolvedEarningsEvent>> {
|
|
360
|
+
const resolved = new Map<string, ResolvedEarningsEvent>();
|
|
361
|
+
const pending = listings.flatMap((listing) => {
|
|
362
|
+
const event = calendarEventOf(events, listing.key);
|
|
363
|
+
return event ? [{ listing, event }] : [];
|
|
364
|
+
});
|
|
365
|
+
for (let index = 0; index < pending.length; index += RECORD_CONCURRENCY) {
|
|
366
|
+
await Promise.all(pending.slice(index, index + RECORD_CONCURRENCY).map(async ({ listing, event }) => {
|
|
367
|
+
const earnings = needsRecordedQuarters(event, today) && provider.getCorporateActions
|
|
368
|
+
? await provider.getCorporateActions(listing.symbol, listing.exchange)
|
|
369
|
+
.then((actions) => actions.earnings, logFailure("earnings-calendar", "Read corporate actions for a past report date failed", null))
|
|
370
|
+
: null;
|
|
371
|
+
resolved.set(listing.key.toUpperCase(), resolveCalendarEvent(event, earnings, today));
|
|
372
|
+
}));
|
|
373
|
+
}
|
|
374
|
+
return resolved;
|
|
375
|
+
}
|
package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EarningsEstimateBasis, EarningsEstimateField, EarningsEvent } from "../../../types/data-provider";
|
|
2
2
|
|
|
3
|
-
const EARNINGS_ESTIMATE_FIELDS: readonly EarningsEstimateField[] = [
|
|
3
|
+
export const EARNINGS_ESTIMATE_FIELDS: readonly EarningsEstimateField[] = [
|
|
4
4
|
"epsEstimate", "epsLow", "epsHigh", "epsYearAgo", "epsGrowth", "epsAnalysts",
|
|
5
5
|
"epsTrend7dAgo", "epsTrend30dAgo", "epsRevisionUp7d", "epsRevisionUp30d", "epsRevisionDown7d", "epsRevisionDown30d",
|
|
6
6
|
"revenueEstimate", "revenueLow", "revenueHigh", "revenueYearAgo", "revenueGrowth", "revenueAnalysts",
|
|
@@ -54,8 +54,8 @@ export function epsBasisShort(basis: EarningsEpsBasis | null): string {
|
|
|
54
54
|
return basis === "gaap" ? "GAAP" : basis === "adjusted" ? "adj" : "?";
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
/**
|
|
58
|
-
const BASIS_TEXT: Record<EpsBasisName, string> = { GAAP: "GAAP", adjusted: "adj", unknown: "
|
|
57
|
+
/** Known bases are named in row details; unknown stays in the structured data and drilldown. */
|
|
58
|
+
const BASIS_TEXT: Record<EpsBasisName, string> = { GAAP: "GAAP", adjusted: "adj", unknown: "" };
|
|
59
59
|
|
|
60
60
|
type EarningsRecord = CorporateActionsData["earnings"][number];
|
|
61
61
|
|
|
@@ -80,7 +80,7 @@ export function earningsDetailParts(earning: EarningsRecord): string[] {
|
|
|
80
80
|
export function earningsDetail(earning: EarningsRecord): string {
|
|
81
81
|
const detail = earningsDetailParts(earning).join(", ");
|
|
82
82
|
if (earning.epsActual == null) return detail || "Pending";
|
|
83
|
-
return earning.dateType === "fiscal-period-end" ?
|
|
83
|
+
return earning.dateType === "fiscal-period-end" ? ["Period end", detail].filter(Boolean).join("; ") : detail;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { intradayBarText } from "../../../market-data/quotes/intraday-bar";
|
|
2
|
+
import type { Quote, QuoteIntradayBar } from "../../../types/financials";
|
|
2
3
|
import { isFxMarketOpen } from "../../../utils/fx-market-hours";
|
|
3
4
|
import { quoteFreshnessFields } from "./report-freshness";
|
|
4
5
|
|
|
@@ -32,6 +33,27 @@ export interface FxRateTiming {
|
|
|
32
33
|
error?: unknown;
|
|
33
34
|
/** How far the snapshot runs behind the market, as the data service states it; 0 is real-time. */
|
|
34
35
|
delayMinutes?: number;
|
|
36
|
+
/** The pair's bar the rate is the close of, when the data service took one over a print that had stopped behind it. */
|
|
37
|
+
intradayBar?: QuoteIntradayBar;
|
|
38
|
+
/** Why a stale rate stands, as the data service states it. */
|
|
39
|
+
staleReason?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* What the loaded USD rates behind a pair say of themselves, one line per
|
|
44
|
+
* rate (`BRL/USD: ...`): the bar a rate is the close of, and, for a stale
|
|
45
|
+
* rate, why it stands (its bars had nothing newer, or did not load). A rate
|
|
46
|
+
* whose own refresh failed is stale for that reason, so it states none.
|
|
47
|
+
*/
|
|
48
|
+
export function fxRateNotes(legs: ReadonlyMap<string, FxRateTiming>, now = Date.now()): string[] {
|
|
49
|
+
return [...legs].flatMap(([currency, timing]) => {
|
|
50
|
+
if (currency === "USD") return [];
|
|
51
|
+
const stale = timing.staleAt != null && timing.staleAt <= now;
|
|
52
|
+
return [
|
|
53
|
+
...timing.intradayBar ? [`${currency}/USD: ${intradayBarText(timing.intradayBar)}`] : [],
|
|
54
|
+
...stale && timing.error == null && timing.staleReason ? [`${currency}/USD: ${timing.staleReason}`] : [],
|
|
55
|
+
];
|
|
56
|
+
});
|
|
35
57
|
}
|
|
36
58
|
|
|
37
59
|
function isoTime(time: number | undefined | null): string | undefined {
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { CloudJobsPostingDetail } from "../../../api-client/types";
|
|
2
|
+
import { formatShortDate } from "../../../utils/datetime-format";
|
|
3
|
+
import { formatCompact, formatNumber } from "../../../utils/format";
|
|
4
|
+
import { humanLabel } from "./research-cells";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* One job posting read by a person: its place, when it was posted, its pay
|
|
8
|
+
* and its hours, in words. Shared by JOBS and HIRE's posting detail. A value
|
|
9
|
+
* the careers system did not give is left out, never shown as a dash or
|
|
10
|
+
* "Unknown".
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** "$120k–150k", "$45–52/h", "£60k"; empty when the posting has no pay. */
|
|
14
|
+
export function formatSalaryRange(
|
|
15
|
+
min: number | null,
|
|
16
|
+
max: number | null,
|
|
17
|
+
currency: string | null,
|
|
18
|
+
period: string | null,
|
|
19
|
+
): string {
|
|
20
|
+
if (min == null && max == null) return "";
|
|
21
|
+
const symbol = currency === "USD" ? "$" : currency === "EUR" ? "€" : currency === "GBP" ? "£" : currency ? `${currency} ` : "";
|
|
22
|
+
const fmt = (value: number) => (period === "hour" ? formatNumber(value, 0) : formatCompact(value));
|
|
23
|
+
const range = min != null && max != null && min !== max
|
|
24
|
+
? `${symbol}${fmt(min)}–${fmt(max)}`
|
|
25
|
+
: `${symbol}${fmt((min ?? max)!)}`;
|
|
26
|
+
return period === "hour" ? `${range}/h` : period === "month" ? `${range}/mo` : range;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const countryNames = new Intl.DisplayNames(["en"], { type: "region" });
|
|
30
|
+
|
|
31
|
+
/** A country code as its name: "AU" as "Australia". */
|
|
32
|
+
export function countryName(code: string | null | undefined): string | null {
|
|
33
|
+
if (!code || !/^[A-Z]{2}$/.test(code)) return null;
|
|
34
|
+
try {
|
|
35
|
+
return countryNames.of(code) ?? null;
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Where the role is, in words: the posting's location with its country named
|
|
43
|
+
* ("Paris, FR" as "Paris, France"), the country when the location does not end
|
|
44
|
+
* with it, and "Remote" when the role is remote and the location does not say
|
|
45
|
+
* so. A list of places ("Austin, TX; Denver, CO") stays as written.
|
|
46
|
+
*/
|
|
47
|
+
export function postingPlace(posting: { location: string | null; country: string | null; remote: boolean | null }): string | null {
|
|
48
|
+
const location = posting.location?.trim() || null;
|
|
49
|
+
const name = countryName(posting.country);
|
|
50
|
+
let place = location;
|
|
51
|
+
if (location && !location.includes(";")) {
|
|
52
|
+
const parts = location.split(/\s*,\s*/);
|
|
53
|
+
const last = parts.at(-1) ?? "";
|
|
54
|
+
const lastName = /^[A-Z]{2}$/.test(last) && parts.length > 1 ? countryName(last) : null;
|
|
55
|
+
// A trailing code names the country only when it is the posting's own ("…, CA" may be California).
|
|
56
|
+
if (lastName && last === posting.country) place = [...parts.slice(0, -1), lastName].join(", ");
|
|
57
|
+
else if (name && last.toLowerCase() !== name.toLowerCase() && last !== posting.country) place = `${location}, ${name}`;
|
|
58
|
+
} else if (!location) place = name;
|
|
59
|
+
const remote = posting.remote && !/remote/i.test(place ?? "") ? "Remote" : null;
|
|
60
|
+
return [place, remote].filter(Boolean).join(" · ") || null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** "Oct 3, 2026"; "about Oct 3, 2026" or "Oct 3, 2026 or earlier" when the careers system's date is not exact. */
|
|
64
|
+
function postedText(postedAt: string | null | undefined, precision?: string | null): string | null {
|
|
65
|
+
if (!postedAt) return null;
|
|
66
|
+
const date = formatShortDate(postedAt.slice(0, 10), { utc: true, fallback: "" });
|
|
67
|
+
if (!date) return null;
|
|
68
|
+
return precision === "floor" ? `${date} or earlier` : precision === "approximate" ? `about ${date}` : date;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** schema.org's employment types, in words. */
|
|
72
|
+
const EMPLOYMENT: Record<string, string> = {
|
|
73
|
+
FULL_TIME: "Full time", PART_TIME: "Part time", CONTRACTOR: "Contract", TEMPORARY: "Temporary",
|
|
74
|
+
INTERN: "Internship", PER_DIEM: "Per diem", VOLUNTEER: "Volunteer",
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/** "Full time" for FULL_TIME or full_time; a careers system's own word ("CDI", "Vollzeit") as written. Nothing for "other" or "unavailable". */
|
|
78
|
+
export function employmentText(value: string | null | undefined): string | null {
|
|
79
|
+
const text = value?.trim();
|
|
80
|
+
if (!text || /^(?:other|unknown|unavailable|n\/?a|none)$/i.test(text)) return null;
|
|
81
|
+
const known = EMPLOYMENT[text.toUpperCase().replace(/[\s-]+/g, "_")];
|
|
82
|
+
if (known) return known;
|
|
83
|
+
return /^[A-Z_]+$/.test(text) && text.includes("_") ? humanLabel(text) : text;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A title the careers system never gave: `Job <id>`, an id alone, or the
|
|
88
|
+
* words of the posting's address. A reader is shown "Untitled role" instead.
|
|
89
|
+
*/
|
|
90
|
+
function isPlaceholderTitle(title: string | null | undefined, externalId?: string | null): boolean {
|
|
91
|
+
const text = title?.trim() ?? "";
|
|
92
|
+
if (!text) return true;
|
|
93
|
+
if (/^job\s+\S*\d\S*$/i.test(text) || /^[A-Z]{0,4}[-_]?\d{3,}$/i.test(text)) return true;
|
|
94
|
+
if (externalId && (text === externalId || text === `Job ${externalId}`)) return true;
|
|
95
|
+
// Bytes still percent-encoded: the address's words, not the role's title.
|
|
96
|
+
return /%[0-9A-F]{2}/i.test(text);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** The posting's title as the careers system wrote it, or "Untitled role" for one it never gave. */
|
|
100
|
+
export function postingTitle(title: string | null | undefined, externalId?: string | null): string {
|
|
101
|
+
return isPlaceholderTitle(title, externalId) ? "Untitled role" : title!;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* A posting's description as words: the markdown marks some careers systems
|
|
106
|
+
* write (Starbucks' "#### Basic Qualifications", "**Pay**") taken off, so a
|
|
107
|
+
* heading reads as a heading line and bold as its words.
|
|
108
|
+
*/
|
|
109
|
+
export function descriptionText(text: string | null | undefined): string | null {
|
|
110
|
+
if (!text) return null;
|
|
111
|
+
return text.replace(/^[ \t]*#{1,6}[ \t]+(?=\S)/gm, "").replace(/\*\*([^*\n]+)\*\*/g, "$1").replace(/__([^_\n]+)__/g, "$1");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface PostingFact {
|
|
115
|
+
label: string;
|
|
116
|
+
value: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** A posting's facts, in the order a reader wants them; only those the posting has. */
|
|
120
|
+
export function postingFacts(posting: CloudJobsPostingDetail): PostingFact[] {
|
|
121
|
+
const facts: Array<[string, string | null]> = [
|
|
122
|
+
["Place", postingPlace(posting)],
|
|
123
|
+
["Posted", postedText(posting.postedAt, posting.postedPrecision)],
|
|
124
|
+
["Pay", formatSalaryRange(posting.salaryMin, posting.salaryMax, posting.salaryCurrency, posting.salaryPeriod) || null],
|
|
125
|
+
["Hours", employmentText(posting.employmentType)],
|
|
126
|
+
["Closed", posting.closedAt ? postedText(posting.closedAt) : null],
|
|
127
|
+
];
|
|
128
|
+
return facts.filter((fact): fact is [string, string] => !!fact[1]).map(([label, value]) => ({ label, value }));
|
|
129
|
+
}
|
|
@@ -127,10 +127,10 @@ export async function proLockNote(
|
|
|
127
127
|
? "verify your email (Ctrl+P, Resend Verification Email)"
|
|
128
128
|
: `log in or sign up${pro ? "" : " free"} from the command bar (Ctrl+P, Log In or Sign Up)`;
|
|
129
129
|
const unlock = gate === "pro"
|
|
130
|
-
? `To read ${pane.shows} in ${token}, upgrade in the app (
|
|
131
|
-
: `To read ${pane.shows} in ${token}, open the app (
|
|
130
|
+
? `To read ${pane.shows} in ${token}, upgrade in the app (gloom, then Ctrl+P, UPGRADE)`
|
|
131
|
+
: `To read ${pane.shows} in ${token}, open the app (gloom), ${account}${pro ? ", then upgrade (Ctrl+P, UPGRADE)" : ""}`;
|
|
132
132
|
const bare = pane.argument === "none" || (pane.argument === "optional" && !symbol);
|
|
133
|
-
const command = bare ? `
|
|
133
|
+
const command = bare ? `gloom fn ${token}` : `gloom fn ${token} ${ticker}`;
|
|
134
134
|
const free = pane.free ? await answeringFreeRoute(lock, pane.free) : null;
|
|
135
135
|
return [
|
|
136
136
|
`${token} ${what}: ${pane.does}. ${without} it shows none of ${pane.shows}.`,
|