gloomberb 0.16.3 → 0.16.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -91
- package/package.json +7 -1
- package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
- package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
- package/src/account/billing.ts +57 -0
- package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
- package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
- package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
- package/src/account/session.ts +16 -0
- package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +42 -17
- package/src/account/upgrade-personalization.ts +57 -0
- package/src/account/upgrade-tickers.ts +124 -0
- package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
- package/src/api-client/askg.ts +43 -0
- package/src/api-client/auth.ts +15 -0
- package/src/api-client/beneficial-owners.ts +4 -0
- package/src/api-client/chat.ts +19 -0
- package/src/api-client/company-kpis.ts +14 -2
- package/src/api-client/data.ts +58 -18
- package/src/api-client/earnings.ts +6 -0
- package/src/api-client/futures-curve.ts +56 -0
- package/src/api-client/index.ts +16 -1
- package/src/api-client/market-discovery.ts +10 -1
- package/src/api-client/normalizers.ts +27 -0
- package/src/api-client/paths.ts +95 -23
- package/src/api-client/request.ts +2 -1
- package/src/api-client/research-activity.ts +46 -10
- package/src/api-client/socket.ts +39 -8
- package/src/api-client/types.ts +74 -2
- package/src/api-client/upgrade-experiment.ts +90 -0
- package/src/api-client/yield-curves.ts +8 -0
- package/src/app/global-shortcuts.ts +26 -2
- package/src/app/keybindings/actions.ts +10 -0
- package/src/app/pane-runtime/index.tsx +8 -0
- package/src/app/pane-runtime/pane-template-runtime.ts +5 -0
- package/src/app/pane-runtime/plugin-bindings.ts +65 -25
- package/src/app/pane-runtime/ticker-inspector-runtime.ts +12 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +25 -4
- package/src/app/runtime/desktop-deeplink.ts +5 -0
- package/src/app/star-prompt/model.ts +98 -0
- package/src/app/star-prompt/runtime.ts +41 -0
- package/src/app/star-prompt/status-line.tsx +190 -0
- package/src/app.tsx +13 -7
- package/src/architecture/core-builtin-allowlist.json +61 -0
- package/src/brokers/signed-in/adapter.ts +33 -2
- package/src/brokers/signed-in/client.ts +10 -0
- package/src/brokers/signed-in/sign-in-dialog.tsx +34 -14
- package/src/brokers/signed-in/sign-in.ts +62 -5
- package/src/capabilities/chart-series.ts +11 -1
- package/src/capabilities/registry.ts +8 -1
- package/src/capabilities/types.ts +2 -0
- package/src/cli/commands/crypto-hints.ts +19 -4
- package/src/cli/commands/fred-series.ts +61 -0
- package/src/cli/commands/market.ts +744 -181
- package/src/cli/commands/news-hints.ts +62 -0
- package/src/cli/commands/news-search.ts +53 -0
- package/src/cli/commands/options-chain.ts +172 -0
- package/src/cli/commands/options-leaps.ts +425 -0
- package/src/cli/commands/overview.ts +251 -40
- package/src/cli/commands/remote.ts +2 -1
- package/src/cli/commands/search.ts +109 -15
- package/src/cli/commands/system.ts +151 -24
- package/src/cli/commands/themes.ts +64 -0
- package/src/cli/commands/ticker.ts +149 -40
- package/src/cli/context.ts +45 -14
- package/src/cli/desktop-pane-shot.ts +150 -17
- package/src/cli/earnings-calendar.ts +71 -0
- package/src/cli/errors.ts +25 -2
- package/src/cli/freshness.ts +22 -8
- package/src/cli/fx-pair.ts +57 -0
- package/src/cli/glossary.ts +429 -0
- package/src/cli/help.ts +14 -1
- package/src/cli/history-rows.ts +48 -7
- package/src/cli/index-roots.ts +58 -0
- package/src/cli/index.ts +29 -12
- package/src/cli/known-gaps.ts +27 -0
- package/src/cli/listing-arg.ts +595 -26
- package/src/cli/not-a-ticker.ts +44 -0
- package/src/cli/options.ts +50 -6
- package/src/cli/pane-functions/access-gate.ts +5 -0
- package/src/cli/pane-functions/capabilities.ts +11 -4
- package/src/cli/pane-functions/catalog.ts +48 -7
- package/src/cli/pane-functions/data.ts +48 -13
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/dom.ts +41 -19
- package/src/cli/pane-functions/freshness.ts +531 -32
- package/src/cli/pane-functions/function-help.ts +77 -25
- package/src/cli/pane-functions/headless.ts +50 -21
- package/src/cli/pane-functions/index.ts +66 -10
- package/src/cli/pane-functions/market-session.ts +147 -0
- package/src/cli/pane-functions/options.ts +77 -25
- package/src/cli/pane-functions/report-notices.ts +81 -0
- package/src/cli/pane-functions/report.ts +19 -8
- package/src/cli/pane-functions/resolver.ts +53 -18
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +199 -30
- package/src/cli/registry.ts +2 -1
- package/src/cli/report-tables.ts +3 -0
- package/src/cli/result.ts +53 -13
- package/src/cli/row-window.ts +76 -0
- package/src/cli/scroll-truncation.ts +34 -0
- package/src/cli/staged-tickers.ts +52 -0
- package/src/cli/symbol-args.ts +9 -0
- package/src/cli/symbol-list.ts +172 -0
- package/src/cli/ticker-resolution.ts +223 -30
- package/src/cli/types.ts +5 -0
- package/src/components/chart/composite/axis-overlays.tsx +6 -2
- package/src/components/chart/composite/composite-chart.tsx +83 -10
- package/src/components/chart/composite/legend.tsx +88 -8
- package/src/components/chart/composite/panel-surface.tsx +44 -17
- package/src/components/chart/composite/price-axis-labels.tsx +3 -1
- package/src/components/chart/composite/rasterizer.ts +64 -4
- package/src/components/chart/composite/series-cues.ts +71 -0
- package/src/components/chart/composite/text-renderer.ts +16 -8
- package/src/components/chart/composite/types.ts +3 -0
- package/src/components/command-bar/commands/direct/index.ts +9 -1
- package/src/components/command-bar/commands/plugin/items.ts +3 -1
- package/src/components/command-bar/commands/registry.ts +7 -0
- package/src/components/command-bar/layout-items/focused-pane.ts +38 -0
- package/src/components/command-bar/pane-templates/workflow.ts +5 -0
- package/src/components/command-bar/panel/index.tsx +11 -3
- package/src/components/command-bar/panel/runtime.ts +3 -0
- package/src/components/command-bar/panel/types.ts +2 -0
- package/src/components/command-bar/routes/root/command-items.ts +2 -0
- package/src/components/command-bar/routes/root/plugin-turn-on.ts +92 -0
- package/src/components/command-bar/routes/root/provider-search.ts +4 -3
- package/src/components/command-bar/routes/root/results.ts +40 -10
- package/src/components/command-bar/routes/root/runtime.ts +8 -0
- package/src/components/command-bar/routes/root/search-providers.ts +97 -14
- package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
- package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
- package/src/components/command-bar/surface/index.tsx +18 -4
- package/src/components/command-bar/theme-picker.tsx +48 -13
- package/src/components/command-bar/workflow/ops.ts +5 -3
- package/src/components/command-bar/workflow/tickers.ts +23 -4
- package/src/components/data-table/view.tsx +28 -9
- package/src/components/layout/detached-pane-shell.tsx +9 -0
- package/src/components/layout/floating-pane.tsx +9 -2
- package/src/components/layout/header.tsx +20 -5
- package/src/components/layout/market-summary.ts +23 -9
- package/src/components/layout/pane/content.tsx +40 -29
- package/src/components/layout/pane/cycle-order.ts +2 -11
- package/src/components/layout/pane/footer/index.tsx +6 -2
- package/src/components/layout/pane/footer/model.ts +35 -1
- package/src/components/layout/pane/header.tsx +26 -2
- package/src/components/layout/pane/index.tsx +12 -2
- package/src/components/layout/pane/sidebar.tsx +78 -10
- package/src/components/layout/pane/title.ts +1 -1
- package/src/components/layout/presentation.ts +22 -0
- package/src/components/layout/shell/active-drag.ts +21 -5
- package/src/components/layout/shell/drag/index.ts +43 -9
- package/src/components/layout/shell/drag/live.ts +87 -6
- package/src/components/layout/shell/drag/runtime.ts +62 -20
- package/src/components/layout/shell/index.tsx +71 -12
- package/src/components/layout/shell/layout-state.ts +5 -11
- package/src/components/layout/shell/menu.ts +33 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +216 -28
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/pane/new-layout.ts +116 -0
- package/src/components/layout/shell/shortcuts.ts +5 -2
- package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
- package/src/components/layout/shell/visible-layout.ts +44 -1
- package/src/components/layout/status-bar.tsx +4 -1
- package/src/components/markdown-text.tsx +69 -23
- package/src/components/metric-treemap/heat-surface.tsx +37 -9
- package/src/components/metric-treemap/heat-tiles.ts +48 -17
- package/src/components/onboarding/account-step/form-panel.tsx +1 -1
- package/src/components/onboarding/account-step/index.tsx +1 -1
- package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
- package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
- package/src/components/onboarding/onboarding-frame.tsx +33 -10
- package/src/components/onboarding/onboarding-keyboard.ts +1 -1
- package/src/components/onboarding/onboarding-wizard.tsx +50 -41
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +5 -2
- package/src/components/onboarding/pro-step-layout.ts +86 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +8 -4
- package/src/components/onboarding/wizard-account.ts +2 -2
- package/src/components/pane-template-wizard.tsx +9 -1
- package/src/components/price-selector-dialog.tsx +11 -2
- package/src/components/sign-in-gate.tsx +3 -3
- package/src/components/ticker/list-table-view.tsx +24 -1
- package/src/components/ui/action-row.tsx +2 -1
- package/src/components/ui/button.tsx +17 -1
- package/src/components/ui/choice-dialog.tsx +6 -4
- package/src/components/ui/confirm-dialog.tsx +28 -18
- package/src/components/ui/data-table/index.tsx +49 -0
- package/src/components/ui/data-table/opentui/index.tsx +37 -6
- package/src/components/ui/data-table/types.ts +20 -1
- package/src/components/ui/data-table/visible-range.ts +2 -0
- package/src/components/ui/dialog-actions.tsx +64 -0
- package/src/components/ui/display.tsx +17 -3
- package/src/components/ui/frame.tsx +35 -2
- package/src/components/ui/icon.tsx +13 -2
- package/src/components/ui/index.ts +1 -1
- package/src/components/ui/text-prompt-dialog.tsx +11 -9
- package/src/core/connection-health.ts +1 -1
- package/src/core/state/app/layout-reducer.ts +89 -3
- package/src/core/state/app/state.ts +8 -5
- package/src/core/state/app/types.ts +13 -2
- package/src/data/cached-query.ts +2 -0
- package/src/data/config/layout.ts +55 -21
- package/src/data/config/store/fold-panes.ts +149 -0
- package/src/data/config/store/migrations.ts +7 -0
- package/src/data/config/store/node.ts +27 -6
- package/src/data/config/store/normalize.ts +44 -5
- package/src/data/ticker-repository.ts +5 -0
- package/src/data/ticker-store.ts +15 -0
- package/src/docs/content.ts +215 -0
- package/src/docs/load.ts +139 -0
- package/src/docs/requests.ts +39 -0
- package/src/docs/snapshot.chunk.ts +8 -0
- package/src/docs/snapshot.json +7416 -0
- package/src/docs/topics.ts +216 -0
- package/src/i18n/es.ts +75 -5
- package/src/i18n/ja.ts +75 -5
- package/src/i18n/ko.ts +75 -5
- package/src/i18n/zh-cn.ts +75 -5
- package/src/i18n/zh-tw.ts +75 -5
- package/src/layout/desks.ts +2 -3
- package/src/layout/pane-layout-move.ts +264 -0
- package/src/layout/pane-manager/dock-tree.ts +18 -0
- package/src/layout/pane-manager/hidden-panes.ts +160 -0
- package/src/layout/pane-manager/index.ts +2 -0
- package/src/market-data/coordinator/chart.ts +10 -4
- package/src/market-data/coordinator/entries.ts +7 -1
- package/src/market-data/coordinator/index.ts +6 -3
- package/src/market-data/coordinator/quotes.ts +2 -2
- package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
- package/src/market-data/futures-contract.ts +151 -0
- package/src/market-data/hooks.tsx +10 -2
- package/src/market-data/market/format.ts +39 -21
- package/src/market-data/market/freshness.ts +193 -30
- package/src/market-data/market/status.ts +59 -23
- package/src/market-data/options-alternatives.ts +69 -0
- package/src/market-data/published-apac-sessions.ts +23 -1
- package/src/market-data/quotes/contributions.ts +22 -2
- package/src/market-data/quotes/metadata.ts +8 -9
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +61 -9
- package/src/market-data/result-types.ts +2 -0
- package/src/plugins/builtin/account-management/keyboard.ts +3 -0
- package/src/plugins/builtin/account-management/model.ts +2 -56
- package/src/plugins/builtin/account-management/navigation.ts +1 -1
- package/src/plugins/builtin/account-management/pane.tsx +37 -8
- package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
- package/src/plugins/builtin/alerts/cli.ts +313 -47
- package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
- package/src/plugins/builtin/alerts/events.ts +23 -2
- package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
- package/src/plugins/builtin/alerts/history.ts +2 -0
- package/src/plugins/builtin/alerts/index.tsx +41 -9
- package/src/plugins/builtin/alerts/pane.tsx +8 -0
- package/src/plugins/builtin/alerts/quotes.ts +3 -0
- package/src/plugins/builtin/alerts/research-builder.ts +8 -3
- package/src/plugins/builtin/alerts/research-rules.ts +18 -2
- package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
- package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
- package/src/plugins/builtin/alerts/scheduled.ts +254 -0
- package/src/plugins/builtin/alerts/targets.ts +92 -0
- package/src/plugins/builtin/analytics/index.tsx +4 -2
- package/src/plugins/builtin/analytics/risk-headless.ts +33 -13
- package/src/plugins/builtin/analytics/risk-math.ts +91 -27
- package/src/plugins/builtin/analytics/risk-model.ts +71 -12
- package/src/plugins/builtin/analytics/risk-pane.tsx +23 -12
- package/src/plugins/builtin/attention/index.tsx +2 -0
- package/src/plugins/builtin/attention/pane.tsx +3 -1
- package/src/plugins/builtin/attention/series.ts +26 -0
- package/src/plugins/builtin/awards/index.tsx +2 -0
- package/src/plugins/builtin/awards/pane.tsx +3 -1
- package/src/plugins/builtin/awards/series.ts +29 -0
- package/src/plugins/builtin/backtest/pane.tsx +1 -1
- package/src/plugins/builtin/bond-calculator/model.ts +2 -1
- package/src/plugins/builtin/broker-manager/detail.tsx +4 -0
- package/src/plugins/builtin/broker-manager/index.tsx +7 -3
- package/src/plugins/builtin/broker-manager/model.ts +8 -0
- package/src/plugins/builtin/broker-manager/pane-actions.tsx +8 -2
- package/src/plugins/builtin/broker-manager/sign-in-end.ts +82 -0
- package/src/plugins/builtin/broker-manager/table.ts +5 -0
- package/src/plugins/builtin/builtin-plugin-meta.ts +121 -11
- package/src/plugins/builtin/catalysts/pane.tsx +3 -1
- package/src/plugins/builtin/cds/client.ts +70 -13
- package/src/plugins/builtin/cds/headless.ts +116 -19
- package/src/plugins/builtin/cds/index.tsx +3 -1
- package/src/plugins/builtin/cds/model.ts +193 -31
- package/src/plugins/builtin/cds/pane.tsx +56 -14
- package/src/plugins/builtin/cds/series.ts +19 -0
- package/src/plugins/builtin/central-bank-rates/index.tsx +2 -0
- package/src/plugins/builtin/central-bank-rates/series.ts +42 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +192 -255
- package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
- package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
- package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
- package/src/plugins/builtin/chart-composer/headless.ts +8 -3
- package/src/plugins/builtin/chart-composer/index.tsx +9 -2
- package/src/plugins/builtin/chart-composer/pane.tsx +1 -1
- package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
- package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
- package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
- package/src/plugins/builtin/chat/channels.ts +34 -36
- package/src/plugins/builtin/chat/command-bar.ts +138 -0
- package/src/plugins/builtin/chat/composer-commands.ts +21 -1
- package/src/plugins/builtin/chat/content/composer-runtime.ts +11 -1
- package/src/plugins/builtin/chat/content/footer.tsx +5 -3
- package/src/plugins/builtin/chat/content/index.tsx +21 -1
- package/src/plugins/builtin/chat/content/mentions.ts +2 -1
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
- package/src/plugins/builtin/chat/content/user-map.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +50 -0
- package/src/plugins/builtin/chat/conversations.ts +256 -0
- package/src/plugins/builtin/chat/discord-command.ts +91 -0
- package/src/plugins/builtin/chat/edit-window.ts +12 -6
- package/src/plugins/builtin/chat/ghost-user.ts +14 -0
- package/src/plugins/builtin/chat/index.tsx +40 -2
- package/src/plugins/builtin/chat/layout.ts +2 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +2 -1
- package/src/plugins/builtin/chat/message/header.tsx +24 -15
- package/src/plugins/builtin/chat/message/profile-popover.tsx +2 -1
- package/src/plugins/builtin/chat/message/render-state.ts +3 -0
- package/src/plugins/builtin/chat/pane-requests.ts +60 -0
- package/src/plugins/builtin/chat/pane-state.ts +32 -2
- package/src/plugins/builtin/chat/pane.tsx +8 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +223 -23
- package/src/plugins/builtin/cloud/askg/conversation-store.ts +21 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
- package/src/plugins/builtin/cloud/askg/manifest.ts +33 -7
- package/src/plugins/builtin/cloud/askg/model.ts +156 -78
- package/src/plugins/builtin/cloud/askg/pane.tsx +772 -377
- package/src/plugins/builtin/cloud/askg/protocol.ts +50 -3
- package/src/plugins/builtin/cloud/askg/tool-display.ts +440 -0
- package/src/plugins/builtin/cloud/askg/tool-timeline.tsx +403 -0
- package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
- package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
- package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
- package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -9
- package/src/plugins/builtin/cloud/mcp-connect/command.ts +24 -0
- package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +363 -0
- package/src/plugins/builtin/cloud/mcp-connect/model.ts +135 -0
- package/src/plugins/builtin/cloud/mcp-connect/sections.ts +62 -0
- package/src/plugins/builtin/cloud/plugin.tsx +36 -1
- package/src/plugins/builtin/cloud/terminal-relay/acm-tab.tsx +89 -0
- package/src/plugins/builtin/cloud/terminal-relay/client.ts +97 -0
- package/src/plugins/builtin/cloud/terminal-relay/connect-section.tsx +57 -0
- package/src/plugins/builtin/cloud/terminal-relay/engine.ts +734 -0
- package/src/plugins/builtin/cloud/terminal-relay/grants.ts +137 -0
- package/src/plugins/builtin/cloud/terminal-relay/host.tsx +81 -0
- package/src/plugins/builtin/cloud/terminal-relay/indicator.tsx +82 -0
- package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +239 -0
- package/src/plugins/builtin/cloud/terminal-relay/policy.ts +162 -0
- package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +192 -0
- package/src/plugins/builtin/cloud/terminal-relay/redact.ts +73 -0
- package/src/plugins/builtin/cloud/terminal-relay/summary.ts +62 -0
- package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
- package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
- package/src/plugins/builtin/comment-letters/client.ts +1 -3
- package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
- package/src/plugins/builtin/company-attention/headless.ts +19 -5
- package/src/plugins/builtin/company-attention/index.tsx +2 -0
- package/src/plugins/builtin/company-attention/model.ts +26 -7
- package/src/plugins/builtin/company-attention/pane.tsx +12 -9
- package/src/plugins/builtin/company-attention/series.ts +52 -0
- package/src/plugins/builtin/company-kpis/client.ts +23 -8
- package/src/plugins/builtin/company-kpis/headless.ts +3 -1
- package/src/plugins/builtin/company-kpis/pane.tsx +19 -9
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +10 -3
- package/src/plugins/builtin/composite-plugins.ts +116 -67
- package/src/plugins/builtin/cot/index.tsx +3 -1
- package/src/plugins/builtin/cot/model.ts +40 -11
- package/src/plugins/builtin/cot/series.ts +27 -0
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +4 -4
- package/src/plugins/builtin/credit-boards/index.tsx +23 -21
- package/src/plugins/builtin/credit-boards/model.ts +0 -1
- package/src/plugins/builtin/credit-boards/pane.tsx +30 -0
- package/src/plugins/builtin/credit-boards/series.ts +66 -0
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +4 -4
- package/src/plugins/builtin/credit-conditions/index.tsx +2 -0
- package/src/plugins/builtin/credit-conditions/series.ts +26 -0
- package/src/plugins/builtin/credit-documents/headless.ts +31 -1
- package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
- package/src/plugins/builtin/crypto-board/headless.ts +2 -3
- package/src/plugins/builtin/crypto-board/index.tsx +2 -0
- package/src/plugins/builtin/crypto-board/model.ts +12 -0
- package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
- package/src/plugins/builtin/crypto-board/series.ts +48 -0
- package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
- package/src/plugins/builtin/debt-maturities/client.ts +37 -9
- package/src/plugins/builtin/debt-maturities/headless.ts +3 -1
- package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
- package/src/plugins/builtin/debt-maturities/pane.tsx +5 -4
- package/src/plugins/builtin/debt-maturities/series.ts +45 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +2 -2
- package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/series.ts +20 -0
- package/src/plugins/builtin/docs/blocks.tsx +181 -0
- package/src/plugins/builtin/docs/index.tsx +68 -0
- package/src/plugins/builtin/docs/pane.tsx +426 -0
- package/src/plugins/builtin/docs/targets.ts +72 -0
- package/src/plugins/builtin/docs/use-docs.ts +60 -0
- package/src/plugins/builtin/doe/index.tsx +2 -0
- package/src/plugins/builtin/doe/series.ts +62 -0
- package/src/plugins/builtin/earnings/client.ts +3 -2
- package/src/plugins/builtin/earnings/format.ts +1 -5
- package/src/plugins/builtin/earnings/headless.ts +58 -6
- package/src/plugins/builtin/earnings/history-model.ts +15 -1
- package/src/plugins/builtin/earnings/history-table.ts +13 -2
- package/src/plugins/builtin/earnings/history.tsx +7 -3
- package/src/plugins/builtin/earnings-calls/data.ts +28 -7
- package/src/plugins/builtin/earnings-calls/headless.ts +3 -2
- package/src/plugins/builtin/earnings-calls/pane.tsx +10 -5
- package/src/plugins/builtin/econ/calendar-model.ts +42 -17
- package/src/plugins/builtin/econ/detail-view.tsx +2 -2
- package/src/plugins/builtin/econ/fred-catalog.ts +189 -0
- package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
- package/src/plugins/builtin/econ/index.tsx +70 -22
- package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +30 -5
- package/src/plugins/builtin/econ-statistics/pane.tsx +1 -1
- package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
- package/src/plugins/builtin/econ-statistics/view.ts +17 -0
- package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
- package/src/plugins/builtin/executives/data.ts +17 -6
- package/src/plugins/builtin/executives/pane.tsx +16 -7
- package/src/plugins/builtin/exposure/holdings.ts +1 -1
- package/src/plugins/builtin/exposure/pane.tsx +3 -1
- package/src/plugins/builtin/fear-greed/index.tsx +4 -0
- package/src/plugins/builtin/fear-greed/series.ts +52 -0
- package/src/plugins/builtin/filing-events/pane.tsx +22 -5
- package/src/plugins/builtin/futures/index.tsx +43 -3
- package/src/plugins/builtin/futures/model.ts +1 -1
- package/src/plugins/builtin/futures/returns.ts +1 -1
- package/src/plugins/builtin/futures/series.ts +13 -0
- package/src/plugins/builtin/futures/table.tsx +1 -1
- package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +70 -9
- package/src/plugins/builtin/futures-curve/index.tsx +1 -1
- package/src/plugins/builtin/futures-curve/model.ts +66 -11
- package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
- package/src/plugins/builtin/fx-matrix/index.tsx +22 -1
- package/src/plugins/builtin/fx-matrix/pairs.ts +1 -1
- package/src/plugins/builtin/fx-matrix/settings.ts +42 -2
- package/src/plugins/builtin/gpu/board.tsx +13 -10
- package/src/plugins/builtin/gpu/changes.tsx +4 -4
- package/src/plugins/builtin/gpu/client.ts +19 -1
- package/src/plugins/builtin/gpu/equities.tsx +14 -10
- package/src/plugins/builtin/gpu/headless.ts +64 -27
- package/src/plugins/builtin/gpu/history.tsx +3 -3
- package/src/plugins/builtin/gpu/index.tsx +2 -0
- package/src/plugins/builtin/gpu/model.ts +114 -20
- package/src/plugins/builtin/gpu/pane.tsx +28 -12
- package/src/plugins/builtin/gpu/series.ts +38 -0
- package/src/plugins/builtin/help/function-card.tsx +25 -6
- package/src/plugins/builtin/help/index.tsx +18 -8
- package/src/plugins/builtin/holders/beneficial-client.ts +29 -7
- package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
- package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
- package/src/plugins/builtin/holders/beneficial-view.tsx +62 -14
- package/src/plugins/builtin/holders/client.ts +22 -3
- package/src/plugins/builtin/holders/format.ts +18 -3
- package/src/plugins/builtin/holders/headless.ts +42 -134
- package/src/plugins/builtin/holders/pane.tsx +14 -4
- package/src/plugins/builtin/holders/report-header.ts +40 -5
- package/src/plugins/builtin/holders/report-rows.ts +240 -0
- package/src/plugins/builtin/insider/client.ts +35 -20
- package/src/plugins/builtin/insider/headless.ts +41 -11
- package/src/plugins/builtin/insider/index.tsx +27 -10
- package/src/plugins/builtin/insider/insider-data.ts +10 -0
- package/src/plugins/builtin/insider/issuer.ts +49 -0
- package/src/plugins/builtin/insider/model.ts +3 -0
- package/src/plugins/builtin/iv-history/charts.tsx +21 -7
- package/src/plugins/builtin/iv-history/client.ts +26 -6
- package/src/plugins/builtin/iv-history/format.ts +33 -2
- package/src/plugins/builtin/iv-history/headless.ts +27 -12
- package/src/plugins/builtin/iv-history/index.tsx +5 -3
- package/src/plugins/builtin/iv-history/model.ts +172 -20
- package/src/plugins/builtin/iv-history/pane.tsx +11 -3
- package/src/plugins/builtin/iv-history/screen-pane.tsx +45 -25
- package/src/plugins/builtin/iv-history/series.ts +29 -0
- package/src/plugins/builtin/jobs/headless.ts +28 -3
- package/src/plugins/builtin/jobs/index.tsx +3 -1
- package/src/plugins/builtin/jobs/pane.tsx +1 -1
- package/src/plugins/builtin/jobs/series.ts +19 -0
- package/src/plugins/builtin/kelly-sizer/headless.ts +149 -0
- package/src/plugins/builtin/kelly-sizer/history.ts +80 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +111 -40
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
- package/src/plugins/builtin/kelly-sizer/sections.tsx +14 -0
- package/src/plugins/builtin/kelly-sizer/types.ts +9 -1
- package/src/plugins/builtin/layout-manager/index.tsx +9 -1
- package/src/plugins/builtin/macro-day/client.ts +68 -3
- package/src/plugins/builtin/macro-day/headless.ts +18 -12
- package/src/plugins/builtin/macro-day/index.tsx +3 -0
- package/src/plugins/builtin/macro-day/model.ts +66 -15
- package/src/plugins/builtin/macro-day/pane.tsx +34 -20
- package/src/plugins/builtin/macro-day/release-table.ts +40 -0
- package/src/plugins/builtin/macro-day/releases.ts +62 -44
- package/src/plugins/builtin/market-heatmap/data.ts +25 -5
- package/src/plugins/builtin/market-heatmap/evidence.ts +90 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +144 -63
- package/src/plugins/builtin/market-heatmap/model.ts +102 -3
- package/src/plugins/builtin/market-heatmap/portfolio.ts +12 -2
- package/src/plugins/builtin/market-movers/client.ts +7 -5
- package/src/plugins/builtin/market-movers/headless.ts +31 -4
- package/src/plugins/builtin/market-movers/index.tsx +11 -3
- package/src/plugins/builtin/market-movers/model.ts +101 -17
- package/src/plugins/builtin/market-movers/screener.ts +31 -0
- package/src/plugins/builtin/market-movers/table.ts +50 -23
- package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
- package/src/plugins/builtin/market-valuation/index.tsx +3 -3
- package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
- package/src/plugins/builtin/members/headless.ts +7 -2
- package/src/plugins/builtin/members/model.ts +31 -3
- package/src/plugins/builtin/members/pane.tsx +3 -6
- package/src/plugins/builtin/mna/headless.ts +15 -3
- package/src/plugins/builtin/money-markets/index.tsx +2 -0
- package/src/plugins/builtin/money-markets/series.ts +41 -0
- package/src/plugins/builtin/news/headless.ts +9 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +10 -0
- package/src/plugins/builtin/notes/cli.ts +12 -7
- package/src/plugins/builtin/openfda/client.ts +1 -1
- package/src/plugins/builtin/options/carry.ts +95 -0
- package/src/plugins/builtin/options/index.tsx +58 -5
- package/src/plugins/builtin/options/strike-window.ts +183 -0
- package/src/plugins/builtin/options/table.ts +55 -3
- package/src/plugins/builtin/options/types.ts +8 -1
- package/src/plugins/builtin/options/view.tsx +162 -13
- package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
- package/src/plugins/builtin/options-positioning/client.ts +7 -3
- package/src/plugins/builtin/options-positioning/headless.ts +5 -2
- package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
- package/src/plugins/builtin/options-scenario/charts.tsx +2 -2
- package/src/plugins/builtin/options-scenario/client.ts +75 -18
- package/src/plugins/builtin/options-scenario/headless.ts +72 -24
- package/src/plugins/builtin/options-scenario/hedge.ts +285 -0
- package/src/plugins/builtin/options-scenario/index.tsx +9 -2
- package/src/plugins/builtin/options-scenario/model.ts +33 -0
- package/src/plugins/builtin/options-scenario/pane.tsx +40 -16
- package/src/plugins/builtin/pe-band/model.ts +2 -2
- package/src/plugins/builtin/pe-band/report-dates.ts +11 -7
- package/src/plugins/builtin/perps/client.ts +40 -6
- package/src/plugins/builtin/perps/equity-row.tsx +33 -8
- package/src/plugins/builtin/perps/freshness.ts +66 -0
- package/src/plugins/builtin/perps/headless.ts +45 -30
- package/src/plugins/builtin/perps/index.tsx +18 -1
- package/src/plugins/builtin/perps/model.ts +32 -6
- package/src/plugins/builtin/perps/pane.tsx +76 -20
- package/src/plugins/builtin/perps/series.ts +76 -0
- package/src/plugins/builtin/plugin-marketplace/model.ts +64 -21
- package/src/plugins/builtin/plugin-marketplace/packs.ts +118 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +357 -39
- package/src/plugins/builtin/plugin-marketplace/store.ts +7 -1
- package/src/plugins/builtin/plugin-module.ts +90 -4
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
- package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +273 -0
- package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +400 -99
- package/src/plugins/builtin/portfolio-list/cli/render.ts +281 -43
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +26 -16
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +120 -47
- package/src/plugins/builtin/portfolio-list/column-values.ts +1 -1
- package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
- package/src/plugins/builtin/portfolio-list/headless.ts +70 -9
- package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +6 -1
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +17 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +1 -1
- package/src/plugins/builtin/portfolio-list/table.tsx +7 -1
- package/src/plugins/builtin/power/client.ts +16 -0
- package/src/plugins/builtin/power/evidence.ts +6 -2
- package/src/plugins/builtin/power/headless.ts +71 -7
- package/src/plugins/builtin/power/index.tsx +4 -1
- package/src/plugins/builtin/power/model.ts +72 -1
- package/src/plugins/builtin/power/pane.tsx +32 -9
- package/src/plugins/builtin/rate-path/headless.ts +11 -3
- package/src/plugins/builtin/realized-vol/headless.ts +8 -0
- package/src/plugins/builtin/realized-vol/pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +7 -4
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +1 -1
- package/src/plugins/builtin/research/event-model.ts +68 -24
- package/src/plugins/builtin/research/events-headless.ts +2 -1
- package/src/plugins/builtin/research/headless.ts +2 -1
- package/src/plugins/builtin/revenue-breakdown/client.ts +13 -6
- package/src/plugins/builtin/revenue-breakdown/headless.ts +4 -1
- package/src/plugins/builtin/revenue-breakdown/pane.tsx +7 -4
- package/src/plugins/builtin/reverse-dcf/headless.ts +5 -1
- package/src/plugins/builtin/reverse-dcf/pane.tsx +1 -1
- package/src/plugins/builtin/risk-factors/data.ts +23 -9
- package/src/plugins/builtin/risk-factors/headless.ts +5 -2
- package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
- package/src/plugins/builtin/seasonality/client.ts +15 -7
- package/src/plugins/builtin/seasonality/headless.ts +36 -12
- package/src/plugins/builtin/seasonality/index.tsx +2 -2
- package/src/plugins/builtin/seasonality/model.ts +119 -0
- package/src/plugins/builtin/seasonality/pane.tsx +108 -37
- package/src/plugins/builtin/sec/index.tsx +5 -5
- package/src/plugins/builtin/sectors/client.ts +10 -2
- package/src/plugins/builtin/sectors/headless.ts +35 -6
- package/src/plugins/builtin/sectors/index.tsx +18 -1
- package/src/plugins/builtin/sectors/sector-model.ts +150 -41
- package/src/plugins/builtin/series-inventory.ts +91 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
- package/src/plugins/builtin/shared/command-tab.ts +69 -0
- package/src/plugins/builtin/shared/earnings-report.ts +55 -0
- package/src/plugins/builtin/shared/fred-points.ts +20 -0
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
- package/src/plugins/builtin/shared/headless-market-data.ts +33 -1
- package/src/plugins/builtin/shared/members-menu.tsx +4 -4
- package/src/plugins/builtin/shared/open-description.ts +29 -0
- package/src/plugins/builtin/shared/report-freshness.ts +59 -2
- package/src/plugins/builtin/shared/series-warning.ts +5 -0
- package/src/plugins/builtin/shared/ticker-request.ts +25 -1
- package/src/plugins/builtin/shared/use-quote-board.ts +25 -5
- package/src/plugins/builtin/shared/volatility/options.ts +1 -46
- package/src/plugins/builtin/short-interest/headless.ts +1 -0
- package/src/plugins/builtin/short-interest/index.tsx +21 -4
- package/src/plugins/builtin/short-interest/series.ts +36 -0
- package/src/plugins/builtin/short-interest/surface.tsx +4 -4
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/short-volume/index.tsx +3 -10
- package/src/plugins/builtin/short-volume/series.ts +23 -0
- package/src/plugins/builtin/social-mentions/index.tsx +2 -0
- package/src/plugins/builtin/social-mentions/series.ts +23 -0
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
- package/src/plugins/builtin/supply-chain/model.ts +1 -1
- package/src/plugins/builtin/supply-chain/pane.tsx +3 -1
- package/src/plugins/builtin/thirteenf/api.ts +1 -0
- package/src/plugins/builtin/thirteenf/data.ts +6 -4
- package/src/plugins/builtin/thirteenf/headless.ts +217 -36
- package/src/plugins/builtin/thirteenf/model.ts +39 -1
- package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
- package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
- package/src/plugins/builtin/thirteenf/types.ts +2 -0
- package/src/plugins/builtin/ticker-detail/headless.ts +43 -21
- package/src/plugins/builtin/ticker-detail/index.tsx +3 -0
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +48 -4
- package/src/plugins/builtin/ticker-detail/pane.tsx +4 -5
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +94 -6
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
- package/src/plugins/builtin/time-sales/headless.ts +1 -0
- package/src/plugins/builtin/treasury-auctions/cache.ts +5 -2
- package/src/plugins/builtin/treasury-auctions/client.ts +22 -8
- package/src/plugins/builtin/treasury-auctions/headless.ts +56 -6
- package/src/plugins/builtin/treasury-auctions/index.tsx +12 -9
- package/src/plugins/builtin/treasury-auctions/model.ts +205 -30
- package/src/plugins/builtin/treasury-auctions/pane.tsx +35 -11
- package/src/plugins/builtin/treasury-auctions/types.ts +11 -1
- package/src/plugins/builtin/vol-surface/charts.tsx +1 -3
- package/src/plugins/builtin/vol-surface/client.ts +6 -2
- package/src/plugins/builtin/vol-surface/evidence.ts +11 -6
- package/src/plugins/builtin/vol-surface/headless.ts +125 -20
- package/src/plugins/builtin/vol-surface/model.ts +23 -11
- package/src/plugins/builtin/vol-surface/pane.tsx +38 -27
- package/src/plugins/builtin/vol-surface/tables.ts +124 -0
- package/src/plugins/builtin/volatility/index.tsx +2 -0
- package/src/plugins/builtin/volatility/series.ts +84 -0
- package/src/plugins/builtin/world-indices/client.ts +22 -4
- package/src/plugins/builtin/world-indices/headless.ts +54 -27
- package/src/plugins/builtin/world-indices/model.ts +4 -2
- package/src/plugins/builtin/world-indices/table.tsx +13 -2
- package/src/plugins/builtin/world-venue-map/geo-series.ts +27 -2
- package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
- package/src/plugins/builtin/world-venue-map/index.ts +3 -2
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +8 -4
- package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
- package/src/plugins/builtin/yield-curve/chart.ts +2 -2
- package/src/plugins/builtin/yield-curve/curves.ts +21 -8
- package/src/plugins/builtin/yield-curve/headless.ts +71 -18
- package/src/plugins/builtin/yield-curve/index.tsx +4 -2
- package/src/plugins/builtin/yield-curve/series.ts +86 -0
- package/src/plugins/builtin-editorial.ts +126 -0
- package/src/plugins/catalog-backend.ts +16 -9
- package/src/plugins/catalog-browser.ts +129 -64
- package/src/plugins/catalog-manifest.ts +73 -40
- package/src/plugins/catalog-ui.ts +26 -6
- package/src/plugins/extracted-plugins.ts +7 -1
- package/src/plugins/ownership.ts +150 -7
- package/src/plugins/plugin-functions.ts +54 -0
- package/src/plugins/plugin-off.ts +36 -0
- package/src/plugins/registry/host-actions.ts +16 -0
- package/src/plugins/registry/index.ts +173 -28
- package/src/plugins/registry/plugin-state.ts +25 -1
- package/src/plugins/runtime/context.tsx +29 -0
- package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
- package/src/portfolio/position-value.ts +40 -0
- package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
- package/src/public/time-series.ts +17 -0
- package/src/react/auto-refresh.ts +13 -3
- package/src/react/input.ts +48 -1
- package/src/remote/app-host.tsx +25 -4
- package/src/remote/confirm-change.tsx +85 -0
- package/src/remote/controller-utils.ts +8 -1
- package/src/remote/controller.ts +126 -59
- package/src/remote/matching.ts +69 -0
- package/src/remote/pane-screenshot.ts +47 -0
- package/src/remote/schema.ts +63 -1
- package/src/remote/semantic-tree.tsx +14 -0
- package/src/remote/types.ts +32 -0
- package/src/remote/watchlist.ts +306 -0
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/dom/data-table/frozen-column.ts +3 -1
- package/src/renderers/dom/data-table/index.tsx +33 -6
- package/src/renderers/dom/data-table/row.tsx +27 -1
- package/src/renderers/dom/desktop/control-styles.ts +63 -1
- package/src/renderers/dom/desktop/controls.tsx +30 -23
- package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
- package/src/renderers/dom/desktop/icons.tsx +21 -0
- package/src/renderers/dom/desktop/query-bar.tsx +59 -32
- package/src/renderers/dom/dom-ui-host.tsx +3 -0
- package/src/renderers/dom/host/box.tsx +4 -1
- package/src/renderers/dom/host/chart-surface.tsx +6 -2
- package/src/renderers/dom/host/drag-shield.ts +17 -6
- package/src/renderers/dom/host/live-frame.ts +14 -2
- package/src/renderers/dom/host/overflow-fade.ts +14 -1
- package/src/renderers/dom/host/size-observer.ts +26 -0
- package/src/renderers/dom/host/surface-3d.tsx +7 -2
- package/src/renderers/dom/host/text.tsx +1 -1
- package/src/renderers/dom/input-host.tsx +6 -1
- package/src/renderers/dom/styles.css +74 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +5 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +12 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +2 -1
- package/src/renderers/electrobun/shared/protocol.ts +2 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +18 -3
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +109 -5
- package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
- package/src/renderers/electrobun/view/main.tsx +6 -1
- package/src/renderers/opentui/input-host.tsx +6 -1
- package/src/renderers/opentui/start.tsx +9 -0
- package/src/series/capability.ts +75 -0
- package/src/series/csv.ts +160 -0
- package/src/series/files.ts +107 -0
- package/src/series/registry.ts +198 -0
- package/src/series/resolve.ts +107 -0
- package/src/series/standalone.ts +48 -0
- package/src/series/types.ts +145 -0
- package/src/series/validate.ts +171 -0
- package/src/shares/portable-layout.ts +16 -6
- package/src/sources/gloomberb-cloud/index.ts +26 -17
- package/src/sources/gloomberb-cloud/normalizers.ts +5 -1
- package/src/sources/history-result.ts +1 -0
- package/src/sources/listing-symbols.ts +14 -5
- package/src/sources/provider-errors.ts +88 -3
- package/src/sources/provider-router/batches.ts +4 -1
- package/src/sources/provider-router/cache.ts +4 -2
- package/src/sources/provider-router/cached-routes.ts +9 -5
- package/src/sources/provider-router/financial-routes.ts +12 -5
- package/src/sources/provider-router/financials.ts +55 -15
- package/src/sources/provider-router/history.ts +68 -34
- package/src/sources/provider-router/index.ts +1 -1
- package/src/sources/provider-router/primary.ts +23 -5
- package/src/sources/provider-router/search.ts +1 -0
- package/src/sources/sec-edgar.ts +68 -8
- package/src/sync/core-contributors.ts +5 -3
- package/src/test-support/cli-context.ts +2 -1
- package/src/test-support/data-provider.ts +34 -0
- package/src/test-support/shell-pane-keys.tsx +1 -0
- package/src/theme/series-colors.ts +46 -0
- package/src/theme/themes.ts +149 -0
- package/src/tickers/company-name.ts +75 -0
- package/src/tickers/instrument-kind.ts +25 -0
- package/src/tickers/open-target.ts +3 -2
- package/src/tickers/search/index.ts +67 -9
- package/src/tickers/search/ranking.ts +78 -18
- package/src/tickers/search/types.ts +10 -2
- package/src/tickers/starter-symbols.ts +8 -0
- package/src/tickers/us-listing.ts +34 -0
- package/src/time-series/hooks.ts +9 -0
- package/src/time-series/resolve.ts +96 -30
- package/src/time-series/types.ts +4 -2
- package/src/time-series/use-chart-resolution.ts +32 -0
- package/src/types/config.ts +67 -1
- package/src/types/data-provider.ts +5 -0
- package/src/types/financials.ts +52 -1
- package/src/types/headless.ts +72 -0
- package/src/types/instrument.ts +8 -0
- package/src/types/plugin.ts +68 -3
- package/src/types/price-history.ts +7 -0
- package/src/types/ticker.ts +14 -0
- package/src/ui/host.tsx +26 -4
- package/src/ui/index.tsx +2 -0
- package/src/ui/live-resize.ts +81 -0
- package/src/ui/live-stretch.ts +121 -0
- package/src/ui/measured-cells.ts +58 -0
- package/src/ui/pane-fill.ts +11 -0
- package/src/utils/basis-points.ts +17 -0
- package/src/utils/cli-output.ts +21 -2
- package/src/utils/concurrency.ts +25 -0
- package/src/utils/crypto-pair.ts +20 -0
- package/src/utils/currency-pair.ts +19 -0
- package/src/utils/decimal-comma.ts +19 -0
- package/src/utils/dom-screenshot-css.ts +265 -0
- package/src/utils/dom-screenshot-rasters.ts +276 -0
- package/src/utils/dom-screenshot.ts +437 -52
- package/src/utils/exchange-rate-snapshot.ts +6 -2
- package/src/utils/exchanges.ts +120 -1
- package/src/utils/format.ts +17 -3
- package/src/utils/fundamentals.ts +66 -0
- package/src/utils/futures-generic.ts +6 -12
- package/src/utils/fx-market-hours.ts +44 -0
- package/src/utils/option-expiry.ts +126 -0
- package/src/utils/price-history.ts +130 -40
- package/src/utils/rpc-timeout-error.ts +6 -2
- package/src/utils/sec-eps-basis.ts +178 -36
- package/src/utils/sec.ts +98 -40
- package/src/utils/throttled-fetch.ts +51 -22
- package/src/utils/utc-time.ts +51 -4
package/src/cli/result.ts
CHANGED
|
@@ -7,13 +7,16 @@ import {
|
|
|
7
7
|
statValueWidth,
|
|
8
8
|
visibleLength,
|
|
9
9
|
wrapText,
|
|
10
|
+
wrapToTerminal,
|
|
10
11
|
type CliStatEntry,
|
|
11
12
|
type CliTableColumn,
|
|
12
13
|
} from "../utils/cli-output";
|
|
13
14
|
import { serializeCsv } from "../utils/csv";
|
|
14
15
|
import { formatUtcTime, isEpochMilliseconds, isZonedIsoDateTime } from "../utils/utc-time";
|
|
15
16
|
import { formatFreshnessLine, type ReportFreshness } from "./pane-functions/freshness";
|
|
17
|
+
import { withSearchHints } from "./not-a-ticker";
|
|
16
18
|
import { renderReportCsv, renderReportNdjson, type CliReportTables } from "./report-tables";
|
|
19
|
+
import { windowRows, type RowWindow, type RowWindowOptions } from "./row-window";
|
|
17
20
|
|
|
18
21
|
export interface CliResult<T = unknown> {
|
|
19
22
|
data: T;
|
|
@@ -59,6 +62,19 @@ export interface CliResultRenderOptions<T = unknown, Row = Record<string, unknow
|
|
|
59
62
|
summary?: (data: T) => string;
|
|
60
63
|
/** Text-mode line printed first, naming what the result is about, such as the listing a symbol resolved to. */
|
|
61
64
|
heading?: string;
|
|
65
|
+
/** Text-mode line printed under the rows, such as where a listing stops. Not printed with no rows: say it in `empty`. */
|
|
66
|
+
footnote?: string;
|
|
67
|
+
/** Text-mode block printed under the rows and footnote, for figures about a row that are not columns. */
|
|
68
|
+
details?: (data: T) => string;
|
|
69
|
+
/**
|
|
70
|
+
* The row key holding each row's date, which makes the rows a dated series:
|
|
71
|
+
* `--tail` keeps the newest rows whichever way the series runs, and a
|
|
72
|
+
* `--limit` that keeps the oldest says so, under the text table and as
|
|
73
|
+
* `metadata.rows` in JSON.
|
|
74
|
+
*/
|
|
75
|
+
dateKey?: string;
|
|
76
|
+
/** How many rows to show when neither `--limit` nor `--tail` is given; every row when absent. */
|
|
77
|
+
defaultLimit?: number;
|
|
62
78
|
/**
|
|
63
79
|
* What CSV and NDJSON write instead of the rows: a report's tables as the
|
|
64
80
|
* text view shows them, CSV with its `# section:` and closing `#` lines.
|
|
@@ -89,14 +105,28 @@ const KEY_ACRONYMS: Record<string, string> = {
|
|
|
89
105
|
usd: "USD",
|
|
90
106
|
};
|
|
91
107
|
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
108
|
+
function rowWindowOptions(options: CliGlobalOptions, renderOptions: Pick<CliResultRenderOptions, "defaultLimit">): RowWindowOptions {
|
|
109
|
+
return options.tail != null ? { tail: options.tail } : { limit: options.limit ?? renderOptions.defaultLimit };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function windowed<Row>(
|
|
113
|
+
rows: readonly Row[],
|
|
114
|
+
options: CliGlobalOptions,
|
|
115
|
+
renderOptions: Pick<CliResultRenderOptions, "dateKey" | "defaultLimit">,
|
|
116
|
+
): RowWindow<Row> {
|
|
117
|
+
const { dateKey } = renderOptions;
|
|
118
|
+
const dateOf = dateKey ? (row: Row) => (isPlainObject(row) ? row[dateKey] : undefined) : undefined;
|
|
119
|
+
return windowRows(rows, rowWindowOptions(options, renderOptions), dateOf);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function asRows<T, Row>(data: T, rows?: (data: T) => Row[]): Row[] {
|
|
123
|
+
return rows ? rows(data) : (Array.isArray(data) ? data : [data]) as Row[];
|
|
95
124
|
}
|
|
96
125
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
126
|
+
/** What JSON says about rows the window cut, under `metadata.rows`. */
|
|
127
|
+
function cutMetadata(window: RowWindow<unknown>) {
|
|
128
|
+
if (window.rows.length >= window.total) return null;
|
|
129
|
+
return { shown: window.rows.length, total: window.total, kept: window.kept, ...(window.note ? { note: window.note } : {}) };
|
|
100
130
|
}
|
|
101
131
|
|
|
102
132
|
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
@@ -277,6 +307,7 @@ function renderTextTable<Row extends Record<string, unknown>>(
|
|
|
277
307
|
width: column.width,
|
|
278
308
|
maxWidth: column.maxWidth,
|
|
279
309
|
optional: column.optional,
|
|
310
|
+
dropPriority: column.dropPriority,
|
|
280
311
|
shrink: column.shrink,
|
|
281
312
|
})),
|
|
282
313
|
cells.map((row) => shown.map(({ index }) => row[index]!)),
|
|
@@ -310,7 +341,7 @@ function overflowsTerminal<Row extends Record<string, unknown>>(rows: Row[]): bo
|
|
|
310
341
|
|
|
311
342
|
/** The closing source, as-of and status line of a text result, for output printed without `printResult`. */
|
|
312
343
|
export function cliFreshnessFooter(freshness: ReportFreshness): string {
|
|
313
|
-
return cliStyles.muted(formatFreshnessLine(freshness));
|
|
344
|
+
return cliStyles.muted(wrapToTerminal(formatFreshnessLine(freshness)));
|
|
314
345
|
}
|
|
315
346
|
|
|
316
347
|
export function serializeCliResult<T, Row extends Record<string, unknown> = Record<string, unknown>>(
|
|
@@ -321,11 +352,13 @@ export function serializeCliResult<T, Row extends Record<string, unknown> = Reco
|
|
|
321
352
|
const { freshness, ...rest } = result;
|
|
322
353
|
if (options.format === "json") {
|
|
323
354
|
const columns = serializeColumns(renderOptions.columns);
|
|
355
|
+
const window = Array.isArray(result.data) ? windowed(result.data as unknown[], options, renderOptions) : null;
|
|
356
|
+
const cut = window ? cutMetadata(window) : null;
|
|
324
357
|
const envelope: CliResultJsonEnvelope<T> = {
|
|
325
358
|
ok: true,
|
|
326
359
|
...rest,
|
|
327
|
-
...(freshness ? { metadata: { ...rest.metadata, freshness } } : {}),
|
|
328
|
-
data:
|
|
360
|
+
...(freshness || cut ? { metadata: { ...rest.metadata, ...(freshness ? { freshness } : {}), ...(cut ? { rows: cut } : {}) } } : {}),
|
|
361
|
+
data: window ? window.rows as T : result.data,
|
|
329
362
|
...(columns?.length ? { columns } : {}),
|
|
330
363
|
};
|
|
331
364
|
return JSON.stringify(envelope, null, 2);
|
|
@@ -342,7 +375,8 @@ function serializeCliRows<T, Row extends Record<string, unknown>>(
|
|
|
342
375
|
): string {
|
|
343
376
|
if (renderOptions.tables && options.format === "csv") return renderReportCsv(renderOptions.tables);
|
|
344
377
|
if (renderOptions.tables && options.format === "ndjson") return renderReportNdjson(renderOptions.tables);
|
|
345
|
-
const
|
|
378
|
+
const window = windowed(asRows(result.data, renderOptions.rows), options, renderOptions);
|
|
379
|
+
const rows = window.rows;
|
|
346
380
|
if (options.format === "ndjson") {
|
|
347
381
|
return rows.map((row) => JSON.stringify(row)).join("\n");
|
|
348
382
|
}
|
|
@@ -357,7 +391,10 @@ function serializeCliRows<T, Row extends Record<string, unknown>>(
|
|
|
357
391
|
if (rows.length === 0) {
|
|
358
392
|
return withHeading(summary || cliStyles.muted(renderOptions.empty ?? "No results."));
|
|
359
393
|
}
|
|
360
|
-
const
|
|
394
|
+
const table = renderTextRows(rows as Row[], result.data, renderOptions);
|
|
395
|
+
const notes = [window.note, renderOptions.footnote].filter((note): note is string => !!note);
|
|
396
|
+
const details = renderOptions.details?.(result.data) ?? "";
|
|
397
|
+
const body = [table, ...notes.map((note) => cliStyles.muted(note)), ...details ? ["", details] : []].join("\n");
|
|
361
398
|
return withHeading(summary ? `${summary}\n\n${body}` : body);
|
|
362
399
|
}
|
|
363
400
|
|
|
@@ -382,9 +419,12 @@ export function printCliResult<T, Row extends Record<string, unknown> = Record<s
|
|
|
382
419
|
result: CliResult<T>,
|
|
383
420
|
options: CliGlobalOptions,
|
|
384
421
|
renderOptions: CliResultRenderOptions<T, Row> = {},
|
|
422
|
+
args: readonly string[] = [],
|
|
385
423
|
): void {
|
|
386
424
|
if (options.quiet && options.format === "text") return;
|
|
387
|
-
|
|
425
|
+
// JSON keeps the router's own words; everything else is for a person, so a "Not a ticker" gets its hint.
|
|
426
|
+
const hinted = (text: string) => options.format === "json" ? text : withSearchHints(text, args);
|
|
427
|
+
const output = hinted(serializeCliResult(result, options, renderOptions));
|
|
388
428
|
// Bun's console writer can truncate a large pipe write after stdout has been
|
|
389
429
|
// initialized. The stream queues the remaining bytes until the reader drains.
|
|
390
430
|
if (output) process.stdout.write(`${output}\n`);
|
|
@@ -392,7 +432,7 @@ export function printCliResult<T, Row extends Record<string, unknown> = Record<s
|
|
|
392
432
|
// rows, so a warning goes to stderr, out of a file the rows are piped into.
|
|
393
433
|
if (options.format !== "json" && !options.quiet) {
|
|
394
434
|
for (const warning of result.warnings ?? []) {
|
|
395
|
-
console.error(`${cliStyles.warning("warning:")} ${warning}`);
|
|
435
|
+
console.error(`${cliStyles.warning("warning:")} ${hinted(warning)}`);
|
|
396
436
|
}
|
|
397
437
|
}
|
|
398
438
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which rows `--limit` and `--tail` keep, for every command that prints a
|
|
3
|
+
* list. `--limit n` keeps the first n rows as printed. `--tail n` keeps the
|
|
4
|
+
* newest n rows of a dated series, whichever way it runs (the first n of a
|
|
5
|
+
* newest-first series, the last n of an oldest-first one), and the last n of
|
|
6
|
+
* any other list. The kept rows stay in their printed order.
|
|
7
|
+
*/
|
|
8
|
+
export interface RowWindowOptions {
|
|
9
|
+
limit?: number;
|
|
10
|
+
tail?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface RowWindow<Row> {
|
|
14
|
+
rows: Row[];
|
|
15
|
+
/** How many rows there were before the cut. */
|
|
16
|
+
total: number;
|
|
17
|
+
/** The end of a dated series the cut kept; null when nothing was cut or the rows are not a dated series. */
|
|
18
|
+
kept: "oldest" | "newest" | null;
|
|
19
|
+
/**
|
|
20
|
+
* Said when `--limit` cut an oldest-first series, which reads as the latest
|
|
21
|
+
* rows but is the earliest: "showing the oldest 2 of 252 rows; --tail 2 for
|
|
22
|
+
* the latest". Null otherwise.
|
|
23
|
+
*/
|
|
24
|
+
note: string | null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function timeOf(value: unknown): number | null {
|
|
28
|
+
if (value instanceof Date) return Number.isFinite(value.getTime()) ? value.getTime() : null;
|
|
29
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
30
|
+
if (typeof value !== "string" || !value.trim()) return null;
|
|
31
|
+
const time = Date.parse(value);
|
|
32
|
+
return Number.isFinite(time) ? time : null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function firstTime<Row>(rows: readonly Row[], dateOf: (row: Row) => unknown, fromEnd: boolean): number | null {
|
|
36
|
+
for (let step = 0; step < rows.length; step += 1) {
|
|
37
|
+
const time = timeOf(dateOf(rows[fromEnd ? rows.length - 1 - step : step]!));
|
|
38
|
+
if (time != null) return time;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Which way a dated series runs, from its first and last dated rows; null when it is undated or spans one instant. */
|
|
44
|
+
function seriesOrder<Row>(rows: readonly Row[], dateOf: (row: Row) => unknown): "ascending" | "descending" | null {
|
|
45
|
+
const first = firstTime(rows, dateOf, false);
|
|
46
|
+
const last = firstTime(rows, dateOf, true);
|
|
47
|
+
if (first == null || last == null || first === last) return null;
|
|
48
|
+
return first < last ? "ascending" : "descending";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The rows `options` keep. `dateOf` reads a row's date, which makes the rows a dated series. */
|
|
52
|
+
export function windowRows<Row>(
|
|
53
|
+
rows: readonly Row[],
|
|
54
|
+
options: RowWindowOptions,
|
|
55
|
+
dateOf?: (row: Row) => unknown,
|
|
56
|
+
): RowWindow<Row> {
|
|
57
|
+
const total = rows.length;
|
|
58
|
+
const count = options.tail ?? options.limit;
|
|
59
|
+
if (count == null || count >= total) return { rows: [...rows], total, kept: null, note: null };
|
|
60
|
+
const order = dateOf ? seriesOrder(rows, dateOf) : null;
|
|
61
|
+
if (options.tail != null) {
|
|
62
|
+
return {
|
|
63
|
+
rows: order === "descending" ? rows.slice(0, count) : rows.slice(total - count),
|
|
64
|
+
total,
|
|
65
|
+
kept: order ? "newest" : null,
|
|
66
|
+
note: null,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const kept = order === "ascending" ? "oldest" : order === "descending" ? "newest" : null;
|
|
70
|
+
return {
|
|
71
|
+
rows: rows.slice(0, count),
|
|
72
|
+
total,
|
|
73
|
+
kept,
|
|
74
|
+
note: kept === "oldest" ? `showing the oldest ${count} of ${total} rows; --tail ${count} for the latest` : null,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** A scrolling box as the page measures it. */
|
|
2
|
+
export interface ScrollBoxMetrics {
|
|
3
|
+
scrollTop: number;
|
|
4
|
+
scrollHeight: number;
|
|
5
|
+
clientHeight: number;
|
|
6
|
+
scrollLeft: number;
|
|
7
|
+
scrollWidth: number;
|
|
8
|
+
clientWidth: number;
|
|
9
|
+
/** The box draws a scrollbar on that axis, which says it overflows even when the measures cannot. */
|
|
10
|
+
scrollbarY: boolean;
|
|
11
|
+
scrollbarX: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* What a capture leaves out of a scrolling box, naming the side: a chain
|
|
16
|
+
* centred on the money is cut above and below, a list at its top only below.
|
|
17
|
+
* Self-contained so the screenshot runner can evaluate it in the browser.
|
|
18
|
+
*/
|
|
19
|
+
export function scrollTruncationReasons(box: ScrollBoxMetrics): string[] {
|
|
20
|
+
const reasons: string[] = [];
|
|
21
|
+
const cut = (offset: number, content: number, viewport: number, flagged: boolean, noun: string, sides: readonly [string, string, string, string]) => {
|
|
22
|
+
if (!flagged && !(content > viewport + 1)) return;
|
|
23
|
+
// One pixel either way is subpixel layout, not a hidden row.
|
|
24
|
+
const before = offset > 1;
|
|
25
|
+
const after = offset + viewport < content - 1;
|
|
26
|
+
// A drawn scrollbar over content that measures as fitting (a list that loads more) cannot say which side.
|
|
27
|
+
reasons.push(before || after
|
|
28
|
+
? `${noun} ${before && after ? sides[2] : before ? sides[0] : sides[1]} the rendered viewport are cut`
|
|
29
|
+
: `${noun} ${sides[3]} the rendered viewport may be cut`);
|
|
30
|
+
};
|
|
31
|
+
cut(box.scrollTop, box.scrollHeight, box.clientHeight, box.scrollbarY, "rows", ["above", "below", "above and below", "above or below"]);
|
|
32
|
+
cut(box.scrollLeft, box.scrollWidth, box.clientWidth, box.scrollbarX, "columns", ["left of", "right of", "left and right of", "left or right of"]);
|
|
33
|
+
return reasons;
|
|
34
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { TickerRepository } from "../data/ticker-repository";
|
|
2
|
+
import type { TickerMetadata, TickerRecord } from "../types/ticker";
|
|
3
|
+
|
|
4
|
+
type TickerSource = Pick<TickerRepository, "loadTicker" | "loadAllTickers" | "saveTicker"> & Partial<Pick<TickerRepository, "saveTickers">>;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A ticker store that keeps a command's changes in memory until `commit`,
|
|
8
|
+
* which saves them in one write. A command that adds hundreds of symbols reads
|
|
9
|
+
* its own changes back while it works and writes once at the end, so the app
|
|
10
|
+
* sharing the database is never held up by a write per symbol.
|
|
11
|
+
*/
|
|
12
|
+
export class StagedTickerRepository {
|
|
13
|
+
private readonly staged = new Map<string, TickerRecord>();
|
|
14
|
+
private saved: Promise<TickerRecord[]> | null = null;
|
|
15
|
+
|
|
16
|
+
constructor(private readonly base: TickerSource) {}
|
|
17
|
+
|
|
18
|
+
async loadTicker(symbol: string): Promise<TickerRecord | null> {
|
|
19
|
+
return this.staged.get(symbol) ?? await this.base.loadTicker(symbol);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async loadAllTickers(): Promise<TickerRecord[]> {
|
|
23
|
+
this.saved ??= this.base.loadAllTickers();
|
|
24
|
+
const merged = new Map((await this.saved).map((ticker) => [ticker.metadata.ticker, ticker] as const));
|
|
25
|
+
for (const [symbol, ticker] of this.staged) merged.set(symbol, ticker);
|
|
26
|
+
return [...merged.values()];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async saveTicker(ticker: TickerRecord): Promise<void> {
|
|
30
|
+
this.staged.set(ticker.metadata.ticker, ticker);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async createTicker(metadata: TickerMetadata): Promise<TickerRecord> {
|
|
34
|
+
const ticker: TickerRecord = { metadata };
|
|
35
|
+
await this.saveTicker(ticker);
|
|
36
|
+
return ticker;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async deleteTicker(): Promise<void> {
|
|
40
|
+
throw new Error("A staged ticker store does not delete tickers.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Writes every staged ticker at once. */
|
|
44
|
+
async commit(): Promise<void> {
|
|
45
|
+
const tickers = [...this.staged.values()];
|
|
46
|
+
if (tickers.length === 0) return;
|
|
47
|
+
if (this.base.saveTickers) await this.base.saveTickers(tickers);
|
|
48
|
+
else for (const ticker of tickers) await this.base.saveTicker(ticker);
|
|
49
|
+
this.staged.clear();
|
|
50
|
+
this.saved = null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Symbols given as command arguments, each of which may hold several split by
|
|
3
|
+
* commas, semicolons, spaces, tabs or newlines (a pasted list), with the blanks
|
|
4
|
+
* dropped and the typed case kept. Every command that takes a symbol list splits
|
|
5
|
+
* its arguments here, and `not-a-ticker` reads the typed spelling back from them.
|
|
6
|
+
*/
|
|
7
|
+
export function splitSymbolArgs(args: readonly string[]): string[] {
|
|
8
|
+
return args.flatMap((arg) => arg.replace(/^\uFEFF/, "").split(/[\s,;]+/)).filter(Boolean);
|
|
9
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import { fstatSync } from "fs";
|
|
3
|
+
import { splitSymbolArgs } from "./symbol-args";
|
|
4
|
+
|
|
5
|
+
/** Header cells that name a spreadsheet's symbol column, compared without case, spaces or punctuation. */
|
|
6
|
+
const SYMBOL_HEADERS = new Set(["symbol", "symbols", "ticker", "tickers", "code", "stockcode", "securitycode", "instrument"]);
|
|
7
|
+
|
|
8
|
+
/** One symbol as it can be typed: AAPL, $nvda, TTF.AS, SAN:EPA, BRK-B, 7203.T, ^GSPC, ES=F. */
|
|
9
|
+
const SYMBOL_TOKEN = /^\$?[\p{L}\p{N}^][\p{L}\p{N}.:\-^=/&]{0,23}$/u;
|
|
10
|
+
/** A plain number: a price, a weight or a share count in a spreadsheet's other columns. */
|
|
11
|
+
const NUMBER_CELL = /^[+-]?(?:\d{1,3}(?:,\d{3})+|\d*)(?:\.\d+)?%?$/;
|
|
12
|
+
|
|
13
|
+
function headerKey(cell: string): string {
|
|
14
|
+
return cell.toLowerCase().replace(/[^\p{L}\p{N}]/gu, "");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isComment(cell: string): boolean {
|
|
18
|
+
return cell.startsWith("#") || cell.startsWith("//");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The delimiter of the first data line: tab, comma or semicolon, or null for a list split by spaces. */
|
|
22
|
+
function detectDelimiter(lines: readonly string[]): string | null {
|
|
23
|
+
const first = lines.find((line) => line.trim() && !isComment(line.trim()));
|
|
24
|
+
if (!first) return null;
|
|
25
|
+
const unquoted = first.replace(/"[^"]*"/g, "");
|
|
26
|
+
for (const delimiter of ["\t", ",", ";"]) {
|
|
27
|
+
if (unquoted.includes(delimiter)) return delimiter;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** RFC 4180 records: a quoted cell may hold the delimiter, a newline and doubled quotes. */
|
|
33
|
+
function parseDelimited(text: string, delimiter: string): string[][] {
|
|
34
|
+
const records: string[][] = [];
|
|
35
|
+
let record: string[] = [];
|
|
36
|
+
let cell = "";
|
|
37
|
+
let quoted = false;
|
|
38
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
39
|
+
const char = text[index]!;
|
|
40
|
+
if (quoted) {
|
|
41
|
+
if (char === "\"" && text[index + 1] === "\"") {
|
|
42
|
+
cell += "\"";
|
|
43
|
+
index += 1;
|
|
44
|
+
} else if (char === "\"") {
|
|
45
|
+
quoted = false;
|
|
46
|
+
} else {
|
|
47
|
+
cell += char;
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (char === "\"" && !cell.trim()) {
|
|
52
|
+
quoted = true;
|
|
53
|
+
cell = "";
|
|
54
|
+
} else if (char === delimiter) {
|
|
55
|
+
record.push(cell);
|
|
56
|
+
cell = "";
|
|
57
|
+
} else if (char === "\n") {
|
|
58
|
+
record.push(cell);
|
|
59
|
+
records.push(record);
|
|
60
|
+
record = [];
|
|
61
|
+
cell = "";
|
|
62
|
+
} else {
|
|
63
|
+
cell += char;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (cell || record.length > 0) {
|
|
67
|
+
record.push(cell);
|
|
68
|
+
records.push(record);
|
|
69
|
+
}
|
|
70
|
+
return records.map((cells) => cells.map((value) => value.trim()));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function looksLikeSymbol(cell: string): boolean {
|
|
74
|
+
return SYMBOL_TOKEN.test(cell) && !(NUMBER_CELL.test(cell) && /[.,%]/.test(cell));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The symbols in a file or piped text, in order. A spreadsheet export reads
|
|
79
|
+
* from the column its header names (Symbol, Ticker, Code), or else its first
|
|
80
|
+
* column; a list split by commas, spaces or newlines gives every entry. A byte
|
|
81
|
+
* order mark, Windows line ends, blank lines and lines starting with # or //
|
|
82
|
+
* are ignored.
|
|
83
|
+
*/
|
|
84
|
+
export function parseSymbolText(text: string): string[] {
|
|
85
|
+
const normalized = text.replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n");
|
|
86
|
+
const lines = normalized.split("\n");
|
|
87
|
+
const delimiter = detectDelimiter(lines);
|
|
88
|
+
const records = (delimiter ? parseDelimited(normalized, delimiter) : lines.map((line) => line.trim().split(/\s+/)))
|
|
89
|
+
.filter((cells) => cells.some(Boolean) && !isComment(cells[0] ?? ""));
|
|
90
|
+
if (records.length === 0) return [];
|
|
91
|
+
const header = records[0]!.map(headerKey);
|
|
92
|
+
const exact = header.findIndex((cell) => SYMBOL_HEADERS.has(cell));
|
|
93
|
+
const column = exact >= 0 ? exact : header.findIndex((cell) => cell.includes("symbol") || cell.includes("ticker"));
|
|
94
|
+
if (column >= 0) return records.slice(1).map((cells) => cells[column] ?? "").filter(Boolean);
|
|
95
|
+
// Without a header, symbols laid out across columns are all symbols; a
|
|
96
|
+
// table with names, prices or weights beside them is read by its first column.
|
|
97
|
+
const grid = records.every((cells) => cells.every((cell, index) => !cell || (looksLikeSymbol(cell) && (index === 0 || !NUMBER_CELL.test(cell)))));
|
|
98
|
+
return grid ? records.flat().filter(Boolean) : records.map((cells) => cells[0] ?? "").filter(Boolean);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** How a symbol is compared for repeats: AAPL, aapl and $AAPL are one. */
|
|
102
|
+
export function symbolInputKey(symbol: string): string {
|
|
103
|
+
return symbol.trim().replace(/^\$/, "").toUpperCase();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** The symbols without repeats, first spelling kept, and how many repeats were dropped. */
|
|
107
|
+
function uniqueSymbols(symbols: readonly string[]): { symbols: string[]; repeated: number } {
|
|
108
|
+
const seen = new Set<string>();
|
|
109
|
+
const unique: string[] = [];
|
|
110
|
+
for (const symbol of symbols) {
|
|
111
|
+
const key = symbolInputKey(symbol);
|
|
112
|
+
if (!key || seen.has(key)) continue;
|
|
113
|
+
seen.add(key);
|
|
114
|
+
unique.push(symbol.trim());
|
|
115
|
+
}
|
|
116
|
+
return { symbols: unique, repeated: symbols.filter((symbol) => symbolInputKey(symbol)).length - unique.length };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Whether standard input is a pipe or a file rather than a terminal, so a command may read its list from it. */
|
|
120
|
+
function stdinIsPiped(): boolean {
|
|
121
|
+
try {
|
|
122
|
+
const stats = fstatSync(0);
|
|
123
|
+
return stats.isFIFO() || stats.isFile();
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface SymbolListSource {
|
|
130
|
+
/** The arguments after the list name, symbols and `-` for standard input. */
|
|
131
|
+
args: readonly string[];
|
|
132
|
+
/** `--file <path>`. */
|
|
133
|
+
file?: string;
|
|
134
|
+
/** Reads standard input; injected so tests never block on it. */
|
|
135
|
+
readStdin?: () => Promise<string>;
|
|
136
|
+
/** Whether standard input was piped in, so a command given no symbols reads it. */
|
|
137
|
+
stdinPiped?: boolean;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export class SymbolListError extends Error {
|
|
141
|
+
constructor(message: string) {
|
|
142
|
+
super(message);
|
|
143
|
+
this.name = "SymbolListError";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The symbols a command was given: as arguments, from `--file`, and from
|
|
149
|
+
* standard input when an argument is `-` or nothing else was given and input
|
|
150
|
+
* is piped in. Repeats are dropped.
|
|
151
|
+
*/
|
|
152
|
+
export async function readSymbolList(source: SymbolListSource): Promise<{ symbols: string[]; repeated: number }> {
|
|
153
|
+
const readStdin = source.readStdin ?? (() => Bun.stdin.text());
|
|
154
|
+
const wantsStdin = source.args.includes("-") || source.file === "-";
|
|
155
|
+
const typed = splitSymbolArgs(source.args.filter((arg) => arg !== "-"));
|
|
156
|
+
const collected = [...typed];
|
|
157
|
+
if (source.file != null && source.file !== "-") {
|
|
158
|
+
if (!source.file.trim() || source.file.startsWith("--")) throw new SymbolListError("--file needs a path, such as --file symbols.csv.");
|
|
159
|
+
let text: string;
|
|
160
|
+
try {
|
|
161
|
+
text = await readFile(source.file, "utf-8");
|
|
162
|
+
} catch (error) {
|
|
163
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
164
|
+
throw new SymbolListError(code === "ENOENT" ? `No file at ${source.file}.` : `Could not read ${source.file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
165
|
+
}
|
|
166
|
+
collected.push(...parseSymbolText(text));
|
|
167
|
+
}
|
|
168
|
+
if (wantsStdin || (typed.length === 0 && source.file == null && (source.stdinPiped ?? stdinIsPiped()))) {
|
|
169
|
+
collected.push(...parseSymbolText(await readStdin()));
|
|
170
|
+
}
|
|
171
|
+
return uniqueSymbols(collected);
|
|
172
|
+
}
|