gloomberb 0.19.1 → 0.19.3
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 +7 -1
- package/package.json +2 -1
- package/patches/electrobun@1.18.1.patch +108 -1
- package/src/account/upgrade-dialog.tsx +4 -23
- package/src/api-client/coalesce.ts +118 -0
- package/src/api-client/credit-boards.ts +13 -0
- package/src/api-client/crypto-etf-flows.ts +6 -0
- package/src/api-client/crypto-markets.ts +40 -0
- package/src/api-client/data.ts +201 -14
- package/src/api-client/equity-screener.ts +10 -0
- package/src/api-client/errors.ts +58 -0
- package/src/api-client/gpu.ts +29 -0
- package/src/api-client/index.ts +5 -2
- package/src/api-client/plan-access.ts +10 -1
- package/src/api-client/plan-rules.ts +35 -0
- package/src/api-client/research-activity.ts +1 -32
- package/src/api-client/types.ts +21 -1
- package/src/app/attention-notice.tsx +94 -0
- package/src/app/runtime/startup.ts +3 -1
- package/src/app.tsx +23 -1
- package/src/architecture/core-builtin-allowlist.json +2 -1
- package/src/capabilities/chart-series.ts +2 -1
- package/src/capabilities/factories.ts +1 -0
- package/src/cli/ascii-output.ts +42 -0
- package/src/cli/base-converter.ts +10 -2
- package/src/cli/command-options.ts +16 -1
- package/src/cli/commands/crypto-hints.ts +23 -4
- package/src/cli/commands/market.ts +101 -27
- package/src/cli/commands/news-search.ts +24 -5
- package/src/cli/commands/overview.ts +14 -10
- package/src/cli/commands/search.ts +84 -25
- package/src/cli/commands/system.ts +22 -30
- package/src/cli/commands/ticker.ts +49 -9
- package/src/cli/commands/version.ts +33 -0
- package/src/cli/context.ts +6 -9
- package/src/cli/data-dir.ts +7 -0
- package/src/cli/desktop-pane-shot-api-policy.ts +85 -0
- package/src/cli/desktop-pane-shot-browser.ts +320 -0
- package/src/cli/desktop-pane-shot-routes.ts +26 -1
- package/src/cli/desktop-pane-shot.ts +196 -256
- package/src/cli/early-command.ts +42 -0
- package/src/cli/earnings-calendar.ts +9 -0
- package/src/cli/entry.ts +19 -13
- package/src/cli/errors.ts +12 -2
- package/src/cli/glossary.ts +2 -1
- package/src/cli/help.ts +1 -1
- package/src/cli/history-export.ts +22 -2
- package/src/cli/history-rows.ts +189 -11
- package/src/cli/index.ts +18 -1
- package/src/cli/known-gaps.ts +51 -5
- package/src/cli/listing-arg.ts +63 -10
- package/src/cli/options.ts +1 -1
- package/src/cli/output-file.ts +60 -13
- package/src/cli/pane-functions/catalog.ts +14 -3
- package/src/cli/pane-functions/data.ts +1 -1
- package/src/cli/pane-functions/dom.ts +45 -0
- package/src/cli/pane-functions/freshness.ts +46 -9
- package/src/cli/pane-functions/function-help.ts +17 -9
- package/src/cli/pane-functions/headless.ts +22 -14
- package/src/cli/pane-functions/index.ts +6 -2
- package/src/cli/pane-functions/options.ts +6 -2
- package/src/cli/pane-functions/resolver.ts +27 -5
- package/src/cli/pane-functions/screenshot-assessment.ts +33 -0
- package/src/cli/pane-functions/screenshot-bridge.ts +94 -13
- package/src/cli/pane-functions/screenshot-http.ts +70 -0
- package/src/cli/pane-functions/screenshot-render.ts +19 -5
- package/src/cli/quote-answer.ts +49 -6
- package/src/cli/registry.ts +41 -13
- package/src/cli/result.ts +12 -6
- package/src/cli/ticker-resolution.ts +2 -1
- package/src/cli/types.ts +2 -0
- package/src/components/chart/composite/format.ts +3 -0
- package/src/components/chart-table/header.tsx +1 -1
- package/src/components/chart-table/layout.ts +28 -11
- package/src/components/command-bar/action-runtime.ts +4 -0
- package/src/components/command-bar/commands/direct/index.ts +18 -33
- package/src/components/command-bar/commands/direct/runtime.ts +5 -0
- package/src/components/command-bar/commands/registry.ts +10 -1
- package/src/components/command-bar/routes/root/command-items.ts +9 -4
- package/src/components/command-bar/routes/root/runtime.ts +51 -6
- package/src/components/command-bar/selection-runtime.ts +12 -29
- package/src/components/command-bar/surface/index.tsx +9 -3
- package/src/components/company-logo.tsx +2 -1
- package/src/components/layout/detached-pane-shell.tsx +2 -2
- package/src/components/layout/header.tsx +10 -5
- package/src/components/layout/market-summary.ts +25 -7
- package/src/components/layout/pane/footer/index.tsx +8 -2
- package/src/components/layout/pane/footer/model.ts +73 -6
- package/src/components/layout/pane/header.tsx +2 -2
- package/src/components/layout/pane/status-footer.ts +2 -1
- package/src/components/market-board/index.tsx +3 -2
- package/src/components/onboarding/desks-step.tsx +12 -4
- package/src/components/onboarding/first-run-workspace.ts +81 -4
- package/src/components/onboarding/onboarding-frame.tsx +4 -2
- package/src/components/onboarding/onboarding-keyboard.ts +8 -5
- package/src/components/onboarding/onboarding-wizard.tsx +60 -26
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +7 -2
- package/src/components/onboarding/run-setup-again.ts +24 -0
- package/src/components/onboarding/use-onboarding-progress.ts +33 -15
- package/src/components/onboarding/use-onboarding-upgrade.ts +2 -6
- package/src/components/onboarding/wizard-model.ts +57 -3
- package/src/components/onboarding/wizard-positions.ts +1 -1
- package/src/components/ui/delayed-mark.tsx +56 -0
- package/src/components/ui/display.tsx +16 -5
- package/src/components/ui/external-link.tsx +3 -6
- package/src/components/ui/icon.tsx +16 -3
- package/src/components/ui/logo-mark.tsx +8 -5
- package/src/components/ui/stat-grid.tsx +263 -19
- package/src/core/app-services.ts +11 -2
- package/src/data/app-persistence.ts +9 -7
- package/src/data/config/store/node.ts +11 -5
- package/src/data/config/store/normalize.ts +16 -3
- package/src/data/plugin-cache.ts +15 -0
- package/src/data/plugin-state-store.ts +81 -24
- package/src/data/profile-permissions.ts +47 -0
- package/src/data/resource-store.ts +165 -90
- package/src/data/session-store.ts +31 -8
- package/src/data/sqlite/access.ts +324 -0
- package/src/data/sqlite/checkpointer.ts +285 -0
- package/src/data/sqlite/database.ts +80 -4
- package/src/data/sqlite/retry.ts +50 -9
- package/src/data/ticker-store.ts +57 -23
- package/src/docs/snapshot.json +191 -78
- package/src/i18n/es.ts +18 -2
- package/src/i18n/ja.ts +18 -2
- package/src/i18n/ko.ts +18 -2
- package/src/i18n/zh-cn.ts +18 -2
- package/src/i18n/zh-tw.ts +18 -2
- package/src/layout/desk-keys.ts +4 -1
- package/src/layout/desks.ts +38 -5
- package/src/layout-marketplace/gallery-desktop.tsx +45 -16
- package/src/market-data/batched-reads.ts +16 -0
- package/src/market-data/coordinator/auxiliary.ts +4 -2
- package/src/market-data/coordinator/index.ts +11 -2
- package/src/market-data/futures-board.ts +1 -1
- package/src/market-data/futures-contract.ts +3 -1
- package/src/market-data/market/index-level.ts +6 -4
- package/src/market-data/published-apac-sessions.ts +6 -0
- package/src/market-data/realized-volatility.ts +4 -2
- package/src/news/aggregator.ts +7 -4
- package/src/news/news-model.ts +11 -0
- package/src/news/story-id.ts +22 -0
- package/src/news/ticker-symbols.ts +17 -1
- package/src/notifications/app-notifier.ts +35 -14
- package/src/plugins/auto-update-node.ts +10 -6
- package/src/plugins/builtin/account-management/form-components.tsx +1 -1
- package/src/plugins/builtin/account-management/index.tsx +2 -3
- package/src/plugins/builtin/account-management/model.ts +1 -1
- package/src/plugins/builtin/alerts/cli-forms.ts +15 -1
- package/src/plugins/builtin/alerts/events-pane.tsx +7 -5
- package/src/plugins/builtin/alerts/events.ts +10 -2
- package/src/plugins/builtin/alerts/index.tsx +5 -5
- package/src/plugins/builtin/alerts/research-builder.ts +5 -1
- package/src/plugins/builtin/alerts/research-rules.ts +18 -0
- package/src/plugins/builtin/alerts/targets.ts +4 -1
- package/src/plugins/builtin/attention/headless.ts +1 -1
- package/src/plugins/builtin/attention/index.tsx +2 -4
- package/src/plugins/builtin/attention/listing.ts +1 -1
- package/src/plugins/builtin/attention/series.ts +1 -1
- package/src/plugins/builtin/awards/index.tsx +1 -2
- package/src/plugins/builtin/backtest/client.ts +1 -0
- package/src/plugins/builtin/backtest/index.tsx +1 -2
- package/src/plugins/builtin/backtest/rules.ts +3 -1
- package/src/plugins/builtin/backtest/window.ts +8 -7
- package/src/plugins/builtin/broker-manager/detail.tsx +16 -3
- package/src/plugins/builtin/broker-manager/index.tsx +1 -1
- package/src/plugins/builtin/buildout/cells.tsx +5 -0
- package/src/plugins/builtin/buildout/company/flow.tsx +367 -0
- package/src/plugins/builtin/buildout/company/id.ts +2 -0
- package/src/plugins/builtin/buildout/company/model.ts +247 -0
- package/src/plugins/builtin/buildout/company/pane.tsx +317 -0
- package/src/plugins/builtin/buildout/data-runtime.ts +31 -10
- package/src/plugins/builtin/buildout/facilities.ts +309 -0
- package/src/plugins/builtin/buildout/format.ts +9 -0
- package/src/plugins/builtin/buildout/index.tsx +51 -5
- package/src/plugins/builtin/buildout/model/index.ts +62 -10
- package/src/plugins/builtin/buildout/model/normalizers.ts +5 -0
- package/src/plugins/builtin/buildout/model/types.ts +11 -2
- package/src/plugins/builtin/buildout/pane/index.tsx +91 -20
- package/src/plugins/builtin/buildout/pane/status.tsx +1 -1
- package/src/plugins/builtin/buildout/pane/themes.tsx +110 -0
- package/src/plugins/builtin/buildout/table-model.ts +26 -2
- package/src/plugins/builtin/builtin-plugin-meta.ts +16 -0
- package/src/plugins/builtin/cds/headless.ts +10 -2
- package/src/plugins/builtin/cds/model.ts +7 -3
- package/src/plugins/builtin/central-bank-rates/index.tsx +1 -2
- package/src/plugins/builtin/central-bank-rates/pane.tsx +2 -1
- package/src/plugins/builtin/central-bank-rates/series.ts +2 -3
- package/src/plugins/builtin/changelog/index.tsx +3 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +16 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -0
- package/src/plugins/builtin/chart-composer/headless.ts +88 -21
- package/src/plugins/builtin/chart-composer/index.tsx +2 -3
- package/src/plugins/builtin/chart-composer/pane.tsx +30 -2
- package/src/plugins/builtin/chart-composer/series-expression.ts +3 -2
- package/src/plugins/builtin/chart-composer/session-range.ts +5 -2
- package/src/plugins/builtin/chart-composer/studies.ts +1 -1
- package/src/plugins/builtin/chat/controller/index.ts +1 -1
- package/src/plugins/builtin/chat/controller/messages.ts +15 -4
- package/src/plugins/builtin/chat/ghost-user.ts +8 -0
- package/src/plugins/builtin/chat/index.tsx +5 -5
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -2
- package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
- package/src/plugins/builtin/cloud/index.tsx +1 -2
- package/src/plugins/builtin/cloud/plugin.tsx +6 -4
- package/src/plugins/builtin/cloud/team/module.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -1
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +24 -1
- package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +39 -15
- package/src/plugins/builtin/comment-letters/index.tsx +1 -2
- package/src/plugins/builtin/commodity-balances/client.ts +4 -1
- package/src/plugins/builtin/commodity-balances/index.tsx +3 -3
- package/src/plugins/builtin/commodity-balances/pane.tsx +2 -2
- package/src/plugins/builtin/congress-trades/aggregates.ts +13 -2
- package/src/plugins/builtin/congress-trades/detail.tsx +20 -4
- package/src/plugins/builtin/congress-trades/headless.ts +2 -0
- package/src/plugins/builtin/congress-trades/model.ts +92 -64
- package/src/plugins/builtin/congress-trades/table.tsx +14 -2
- package/src/plugins/builtin/connections/index.ts +2 -3
- package/src/plugins/builtin/cot/client.ts +28 -2
- package/src/plugins/builtin/cot/headless.ts +4 -1
- package/src/plugins/builtin/cot/index.tsx +5 -4
- package/src/plugins/builtin/cot/model.ts +58 -7
- package/src/plugins/builtin/cot/pane.tsx +6 -2
- package/src/plugins/builtin/cpi/client.ts +6 -5
- package/src/plugins/builtin/cpi/index.tsx +1 -2
- package/src/plugins/builtin/credit-boards/cdx-pane.tsx +2 -1
- package/src/plugins/builtin/credit-boards/client.ts +7 -2
- package/src/plugins/builtin/credit-boards/headless.ts +25 -12
- package/src/plugins/builtin/credit-boards/model.ts +29 -0
- package/src/plugins/builtin/credit-boards/series.ts +3 -4
- package/src/plugins/builtin/credit-boards/sovr-pane.tsx +9 -4
- package/src/plugins/builtin/credit-conditions/client.ts +22 -14
- package/src/plugins/builtin/crypto-board/bitcoin-network.ts +143 -0
- package/src/plugins/builtin/crypto-board/client.ts +5 -5
- package/src/plugins/builtin/crypto-board/headless.ts +4 -3
- package/src/plugins/builtin/crypto-board/index.tsx +4 -2
- package/src/plugins/builtin/crypto-board/series.ts +6 -4
- package/src/plugins/builtin/crypto-etf-flows/client.ts +9 -2
- package/src/plugins/builtin/crypto-etf-flows/headless.ts +61 -6
- package/src/plugins/builtin/crypto-etf-flows/index.tsx +1 -2
- package/src/plugins/builtin/crypto-etf-flows/model.ts +14 -1
- package/src/plugins/builtin/crypto-etf-flows/pane.tsx +8 -5
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -3
- package/src/plugins/builtin/debt-maturities/model.ts +17 -1
- package/src/plugins/builtin/debt-maturities/pane.tsx +18 -4
- package/src/plugins/builtin/debt-maturities/series.ts +3 -3
- package/src/plugins/builtin/debug/index.tsx +1 -1
- package/src/plugins/builtin/dividend-yield/client.ts +32 -2
- package/src/plugins/builtin/dividend-yield/headless.ts +58 -33
- package/src/plugins/builtin/dividend-yield/index.tsx +37 -2
- package/src/plugins/builtin/dividend-yield/pane.tsx +32 -13
- package/src/plugins/builtin/dividend-yield/ranking-reads.ts +73 -0
- package/src/plugins/builtin/dividend-yield/ranking-view.tsx +163 -0
- package/src/plugins/builtin/dividend-yield/ranking.ts +1 -1
- package/src/plugins/builtin/dividend-yield/view.ts +21 -0
- package/src/plugins/builtin/docs/index.tsx +2 -3
- package/src/plugins/builtin/doe/client.ts +6 -5
- package/src/plugins/builtin/doe/headless.ts +16 -3
- package/src/plugins/builtin/doe/index.tsx +5 -4
- package/src/plugins/builtin/doe/prices.ts +2 -3
- package/src/plugins/builtin/doe/series.ts +4 -4
- package/src/plugins/builtin/earnings/board.tsx +2 -1
- package/src/plugins/builtin/earnings/history.tsx +2 -1
- package/src/plugins/builtin/earnings-calls/calendar.tsx +10 -2
- package/src/plugins/builtin/earnings-calls/data.ts +19 -11
- package/src/plugins/builtin/earnings-calls/pane.tsx +27 -14
- package/src/plugins/builtin/earnings-ripple/client.ts +32 -7
- package/src/plugins/builtin/earnings-ripple/index.tsx +1 -2
- package/src/plugins/builtin/econ/calendar-model.ts +29 -6
- package/src/plugins/builtin/econ/detail-view.tsx +16 -2
- package/src/plugins/builtin/econ-statistics/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/headless.ts +1 -0
- package/src/plugins/builtin/equity-screener/ideas.ts +30 -1
- package/src/plugins/builtin/equity-screener/index.tsx +1 -2
- package/src/plugins/builtin/equity-screener/model.ts +28 -4
- package/src/plugins/builtin/equity-screener/pane.tsx +5 -0
- package/src/plugins/builtin/equity-screener/screen-check.ts +23 -1
- package/src/plugins/builtin/estimate-revisions/index.tsx +1 -2
- package/src/plugins/builtin/executives/data.ts +6 -1
- package/src/plugins/builtin/executives/pane.tsx +9 -21
- package/src/plugins/builtin/exposure/holdings.ts +35 -13
- package/src/plugins/builtin/exposure/index.tsx +1 -2
- package/src/plugins/builtin/fear-greed/cache.ts +4 -0
- package/src/plugins/builtin/fear-greed/cli.ts +44 -0
- package/src/plugins/builtin/fear-greed/index.tsx +5 -53
- package/src/plugins/builtin/fear-greed/pane.tsx +2 -1
- package/src/plugins/builtin/fear-greed/series.ts +6 -4
- package/src/plugins/builtin/fixed-income/index.tsx +1 -2
- package/src/plugins/builtin/futures/board-reads.ts +25 -0
- package/src/plugins/builtin/futures/coalesced-bump.ts +44 -0
- package/src/plugins/builtin/futures/index.tsx +15 -0
- package/src/plugins/builtin/futures/model.ts +14 -0
- package/src/plugins/builtin/futures/use-board-terms.ts +22 -15
- package/src/plugins/builtin/futures/use-front-returns.ts +20 -14
- package/src/plugins/builtin/futures-curve/headless.ts +6 -1
- package/src/plugins/builtin/futures-curve/index.tsx +1 -2
- package/src/plugins/builtin/fx-matrix/index.tsx +2 -2
- package/src/plugins/builtin/gpu/board.tsx +51 -12
- package/src/plugins/builtin/gpu/client.ts +19 -3
- package/src/plugins/builtin/gpu/equities.tsx +5 -2
- package/src/plugins/builtin/gpu/headless.ts +14 -2
- package/src/plugins/builtin/gpu/index.tsx +1 -2
- package/src/plugins/builtin/gpu/model.ts +20 -2
- package/src/plugins/builtin/gpu/pane.tsx +1 -1
- package/src/plugins/builtin/gpu/series.ts +2 -3
- package/src/plugins/builtin/help/index.tsx +1 -1
- package/src/plugins/builtin/holders/beneficial-view.tsx +1 -2
- package/src/plugins/builtin/holders/index-holders.ts +24 -12
- package/src/plugins/builtin/holders/index.tsx +2 -3
- package/src/plugins/builtin/ipo-calendar/index.tsx +1 -2
- package/src/plugins/builtin/iv-history/index.tsx +1 -2
- package/src/plugins/builtin/jodi/client.ts +4 -1
- package/src/plugins/builtin/jodi/index.tsx +1 -2
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -2
- package/src/plugins/builtin/layout-manager/index.tsx +9 -8
- package/src/plugins/builtin/macro-day/pane.tsx +4 -2
- package/src/plugins/builtin/market-halts/index.tsx +1 -2
- package/src/plugins/builtin/market-heatmap/index.tsx +11 -2
- package/src/plugins/builtin/market-movers/client.ts +1 -0
- package/src/plugins/builtin/market-movers/index.tsx +16 -5
- package/src/plugins/builtin/market-movers/screener.ts +23 -6
- package/src/plugins/builtin/market-movers/session-body.tsx +6 -2
- package/src/plugins/builtin/market-valuation/index.tsx +1 -2
- package/src/plugins/builtin/members/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/index.tsx +1 -2
- package/src/plugins/builtin/money-markets/pane.tsx +2 -1
- package/src/plugins/builtin/money-markets/series.ts +3 -5
- package/src/plugins/builtin/news/headless.ts +7 -0
- package/src/plugins/builtin/news/wire/index.tsx +1 -1
- package/src/plugins/builtin/news/wire/news/pop-out.tsx +9 -3
- package/src/plugins/builtin/notes/index.tsx +3 -6
- package/src/plugins/builtin/openfda/index.tsx +1 -2
- package/src/plugins/builtin/options/view.tsx +6 -5
- package/src/plugins/builtin/options-calculator/index.tsx +1 -2
- package/src/plugins/builtin/options-positioning/index.tsx +1 -2
- package/src/plugins/builtin/options-scenario/index.tsx +2 -4
- package/src/plugins/builtin/perps/index.tsx +1 -2
- package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -3
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -1
- package/src/plugins/builtin/plugin-module.ts +16 -2
- package/src/plugins/builtin/portfolio-list/cli/render.ts +53 -3
- package/src/plugins/builtin/portfolio-list/index.tsx +1 -2
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +11 -0
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +2 -2
- package/src/plugins/builtin/power/gas-client.ts +2 -1
- package/src/plugins/builtin/power/index.tsx +1 -2
- package/src/plugins/builtin/power/prices-client.ts +3 -2
- package/src/plugins/builtin/rate-path/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/index.tsx +1 -2
- package/src/plugins/builtin/realized-vol/model.ts +16 -2
- package/src/plugins/builtin/realized-vol/pane.tsx +3 -3
- package/src/plugins/builtin/relative-rotation/index.tsx +1 -2
- package/src/plugins/builtin/research/analyst-headless.ts +33 -6
- package/src/plugins/builtin/research/analyst-model.ts +37 -2
- package/src/plugins/builtin/research/analyst-pane.tsx +25 -5
- package/src/plugins/builtin/research/index.tsx +5 -8
- package/src/plugins/builtin/research-search/index.tsx +1 -2
- package/src/plugins/builtin/revenue-breakdown/headless.ts +22 -8
- package/src/plugins/builtin/revenue-breakdown/model.ts +23 -0
- package/src/plugins/builtin/reverse-dcf/pane.tsx +4 -2
- package/src/plugins/builtin/risk-factors/data.ts +8 -4
- package/src/plugins/builtin/risk-factors/index.tsx +3 -1
- package/src/plugins/builtin/risk-factors/pane.tsx +5 -8
- package/src/plugins/builtin/roadmap/index.tsx +2 -3
- package/src/plugins/builtin/roadmap/pane.tsx +49 -2
- package/src/plugins/builtin/scanner/hilo-model.ts +18 -1
- package/src/plugins/builtin/scanner/hilo-pane.tsx +12 -2
- package/src/plugins/builtin/scanner/live-pane.tsx +7 -4
- package/src/plugins/builtin/scanner/lock-note.ts +26 -3
- package/src/plugins/builtin/sec/filing-content.ts +38 -6
- package/src/plugins/builtin/sec/headless.ts +5 -1
- package/src/plugins/builtin/sec/index.tsx +4 -2
- package/src/plugins/builtin/sec/model.ts +2 -0
- package/src/plugins/builtin/sectors/index.tsx +11 -5
- package/src/plugins/builtin/series-inventory.ts +2 -0
- package/src/plugins/builtin/shared/cloud-resource.ts +73 -8
- package/src/plugins/builtin/shared/cloud-upgrade.ts +24 -1
- package/src/plugins/builtin/shared/forming-bars.ts +29 -0
- package/src/plugins/builtin/shared/fred-points.ts +6 -1
- package/src/plugins/builtin/shared/fx-rate-freshness.ts +17 -0
- package/src/plugins/builtin/shared/pro-lock-note.ts +23 -8
- package/src/plugins/builtin/shared/series-detail-chart.tsx +4 -2
- package/src/plugins/builtin/shared/series-warning.ts +13 -4
- package/src/plugins/builtin/shared/use-quote-board.ts +5 -0
- package/src/plugins/builtin/short-interest/publications-pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/pane.tsx +2 -1
- package/src/plugins/builtin/short-volume/series.ts +2 -3
- package/src/plugins/builtin/social-mentions/client.ts +15 -10
- package/src/plugins/builtin/social-mentions/index.tsx +1 -2
- package/src/plugins/builtin/social-mentions/pane.tsx +2 -1
- package/src/plugins/builtin/social-mentions/series.ts +2 -3
- package/src/plugins/builtin/supply-chain/client.ts +22 -1
- package/src/plugins/builtin/supply-chain/graph-client.ts +22 -1
- package/src/plugins/builtin/supply-chain/index.tsx +1 -2
- package/src/plugins/builtin/thirteenf/api.ts +127 -29
- package/src/plugins/builtin/thirteenf/data.ts +165 -35
- package/src/plugins/builtin/thirteenf/index.tsx +2 -4
- package/src/plugins/builtin/thirteenf/model.ts +2 -0
- package/src/plugins/builtin/thirteenf/overlap-pane.tsx +5 -1
- package/src/plugins/builtin/thirteenf/pane.tsx +41 -16
- package/src/plugins/builtin/thirteenf/types.ts +14 -0
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -6
- package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +81 -11
- package/src/plugins/builtin/ticker-detail/financials/model.ts +35 -2
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +53 -18
- package/src/plugins/builtin/ticker-detail/headless.ts +70 -11
- package/src/plugins/builtin/ticker-detail/index.tsx +5 -10
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +16 -6
- package/src/plugins/builtin/time-sales/index.tsx +1 -2
- package/src/plugins/builtin/time-sales/pane.tsx +3 -1
- package/src/plugins/builtin/trace-bonds/headless.ts +11 -2
- package/src/plugins/builtin/trace-bonds/model.ts +44 -10
- package/src/plugins/builtin/trace-bonds/pane.tsx +12 -7
- package/src/plugins/builtin/treasury-auctions/cache.ts +20 -8
- package/src/plugins/builtin/treasury-auctions/client.ts +3 -3
- package/src/plugins/builtin/treasury-auctions/headless.ts +3 -1
- package/src/plugins/builtin/treasury-auctions/pane.tsx +10 -4
- package/src/plugins/builtin/vol-surface/client.ts +18 -3
- package/src/plugins/builtin/vol-surface/index.tsx +1 -2
- package/src/plugins/builtin/volatility/client.ts +43 -16
- package/src/plugins/builtin/volatility/headless.ts +5 -2
- package/src/plugins/builtin/volatility/index.tsx +1 -2
- package/src/plugins/builtin/volatility/model.ts +17 -6
- package/src/plugins/builtin/volatility/pane.tsx +6 -2
- package/src/plugins/builtin/volatility/series.ts +2 -1
- package/src/plugins/builtin/world-indices/footer.ts +6 -1
- package/src/plugins/builtin/world-venue-map/client.ts +10 -1
- package/src/plugins/builtin/world-venue-map/index.ts +6 -2
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +48 -7
- package/src/plugins/builtin/world-venue-map/layers.ts +17 -0
- package/src/plugins/builtin/world-venue-map/local-layers.ts +141 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +18 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +4 -2
- package/src/plugins/builtin/world-venue-map/scope.ts +63 -0
- package/src/plugins/builtin/yield-curve/client.ts +4 -6
- package/src/plugins/builtin/yield-curve/curves.ts +16 -2
- package/src/plugins/builtin/yield-curve/headless.ts +3 -3
- package/src/plugins/bundle.ts +52 -2
- package/src/plugins/catalog-browser.ts +2 -2
- package/src/plugins/catalog-cli.ts +20 -0
- package/src/plugins/host-link.ts +13 -1
- package/src/plugins/installer.ts +64 -42
- package/src/plugins/loader.ts +43 -11
- package/src/plugins/peer-imports.ts +201 -0
- package/src/plugins/peer-retry.ts +26 -29
- package/src/plugins/plugin-process.ts +128 -0
- package/src/plugins/redirection-guard.ts +45 -0
- package/src/remote/endpoint.ts +16 -3
- package/src/renderers/browser/main.tsx +3 -2
- package/src/renderers/cloudflare/http-proxy.ts +7 -123
- package/src/renderers/dom/desktop/icons.tsx +5 -2
- package/src/renderers/dom/host/image-surface.tsx +46 -21
- package/src/renderers/dom/styles.css +7 -0
- package/src/renderers/dom/toast-host.tsx +2 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +7 -1
- package/src/renderers/electrobun/bun/desktop/detached-windows.ts +23 -1
- package/src/renderers/electrobun/bun/desktop/initialization.ts +12 -3
- package/src/renderers/electrobun/bun/desktop/rpc-timing.ts +88 -0
- package/src/renderers/electrobun/bun/desktop/update.ts +20 -4
- package/src/renderers/electrobun/bun/desktop/view-ids.ts +8 -4
- package/src/renderers/electrobun/bun/external-plugins.ts +4 -0
- package/src/renderers/electrobun/bun/window/attention.ts +54 -0
- package/src/renderers/electrobun/bun/window/create.ts +6 -2
- package/src/renderers/electrobun/bun/window/native-timing.ts +48 -0
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +82 -4
- package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +13 -5
- package/src/renderers/electrobun/view/desktop/window/snapshot.ts +3 -0
- package/src/renderers/electrobun/view/main.tsx +7 -2
- package/src/renderers/electrobun/view/remote/asset-data-client.ts +1 -0
- package/src/renderers/electrobun/view/ui-host.tsx +9 -2
- package/src/renderers/opentui/browser-open.ts +10 -4
- package/src/renderers/opentui/image/surface.tsx +1 -1
- package/src/renderers/opentui/start.tsx +12 -6
- package/src/renderers/opentui/toast-host.tsx +2 -1
- package/src/series/registry.ts +18 -0
- package/src/series/resolve.ts +2 -1
- package/src/series/standalone.ts +10 -1
- package/src/series/types.ts +12 -0
- package/src/series/validate.ts +11 -2
- package/src/sources/gloomberb-cloud/fred-series.ts +5 -3
- package/src/sources/gloomberb-cloud/index.ts +28 -5
- package/src/sources/gloomberb-cloud/news.ts +24 -3
- package/src/sources/gloomberb-cloud/normalizers.ts +17 -2
- package/src/sources/provider-errors.ts +26 -3
- package/src/sources/provider-router/history.ts +5 -0
- package/src/sources/provider-router/index.ts +13 -0
- package/src/sync/core-contributors.ts +32 -0
- package/src/telemetry/attention-counts.ts +64 -6
- package/src/telemetry/attention-setting.ts +33 -0
- package/src/telemetry/crash-reports-node.ts +3 -1
- package/src/telemetry/stall-clocks.ts +93 -0
- package/src/telemetry/stall-reports-node.ts +25 -9
- package/src/telemetry/stall-reports.ts +218 -13
- package/src/test-support/outage.ts +8 -0
- package/src/test-support/preload.ts +9 -0
- package/src/tickers/company-name-listing.ts +59 -29
- package/src/tickers/company-name.ts +84 -1
- package/src/tickers/listing-fate.ts +14 -3
- package/src/tickers/saved-instrument.ts +17 -0
- package/src/tickers/search/home-listing.ts +104 -8
- package/src/tickers/search/index.ts +5 -2
- package/src/tickers/search/types.ts +6 -1
- package/src/time-series/bar-aggregation.ts +7 -1
- package/src/time-series/base-series.ts +3 -3
- package/src/time-series/chart-bounds.ts +1 -1
- package/src/time-series/chart-data.ts +5 -2
- package/src/time-series/chart-seed.ts +1 -1
- package/src/time-series/coin-session-close.ts +211 -0
- package/src/time-series/live-bars.ts +13 -2
- package/src/time-series/live-quotes.ts +1 -1
- package/src/time-series/market.ts +5 -3
- package/src/time-series/official-close.ts +159 -0
- package/src/time-series/price-comparison.ts +75 -8
- package/src/time-series/resolve.ts +32 -4
- package/src/time-series/series-presentation.ts +1 -1
- package/src/time-series/studies/formula.ts +205 -0
- package/src/time-series/studies/indicators.ts +299 -0
- package/src/time-series/studies/leverage.ts +75 -0
- package/src/time-series/studies/pair.ts +138 -0
- package/src/time-series/studies/resolve.ts +333 -0
- package/src/time-series/studies/shared.ts +141 -0
- package/src/time-series/studies/units.ts +243 -0
- package/src/time-series/studies/vwap.ts +274 -0
- package/src/time-series/types.ts +7 -0
- package/src/types/config.ts +18 -2
- package/src/types/data-provider.ts +23 -0
- package/src/types/financials.ts +40 -3
- package/src/types/headless.ts +42 -3
- package/src/types/plugin.ts +32 -3
- package/src/ui/host.tsx +17 -1
- package/src/ui/toast.tsx +26 -1
- package/src/utils/ascii-text.ts +140 -0
- package/src/utils/cli-output.ts +91 -18
- package/src/utils/concurrency.ts +24 -0
- package/src/utils/exchanges.ts +6 -0
- package/src/utils/external-url.ts +20 -7
- package/src/utils/financial-statements.ts +73 -16
- package/src/utils/fundamentals.ts +17 -5
- package/src/utils/futures-generic.ts +4 -4
- package/src/utils/http-proxy-upstream.ts +124 -0
- package/src/utils/lease-liabilities.ts +54 -0
- package/src/utils/main-thread-stall.ts +122 -5
- package/src/utils/perf-marks.ts +58 -12
- package/src/utils/price-history-integrity.ts +47 -1
- package/src/utils/private-files.ts +141 -0
- package/src/utils/public-address.ts +99 -0
- package/src/account/upgrade-personalization.ts +0 -57
- package/src/account/upgrade-tickers.ts +0 -124
- package/src/api-client/upgrade-experiment.ts +0 -91
- package/src/plugins/builtin/cloud/browser.tsx +0 -3
- package/src/time-series/studies.ts +0 -1628
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { unavailableText } from "../../../components/ui/status";
|
|
2
2
|
import { apiClient } from "../../../api-client";
|
|
3
|
-
import {
|
|
3
|
+
import { isAccessDenied } from "../../../api-client/errors";
|
|
4
4
|
import type { SocialMentionDayPosts, SocialMentionPost, SocialMentionsPayload, SocialMentionsRange } from "../../../api-client/social-mentions";
|
|
5
|
-
import { createPluginCache } from "../../../data/plugin-cache";
|
|
5
|
+
import { createPluginCache, savedCopyForTransientFailure } from "../../../data/plugin-cache";
|
|
6
6
|
import { CLOUD_SESSION_REQUIRED } from "../shared/research-cloud-session";
|
|
7
|
+
import { unavailableOnServer } from "../shared/cloud-resource";
|
|
7
8
|
|
|
8
9
|
export const socialMentionsCache = createPluginCache<SocialMentionsPayload>({
|
|
9
10
|
kind: "social-mentions", source: "gloom-cloud", schemaVersion: 1,
|
|
@@ -56,12 +57,15 @@ export function validateSocialMentions(payload: SocialMentionsPayload, symbol: s
|
|
|
56
57
|
export async function fetchSocialMentions(symbol: string, range: SocialMentionsRange = "1y",
|
|
57
58
|
client: Pick<typeof apiClient, "getCloudSocialMentions"> = apiClient): Promise<SocialMentionsPayload> {
|
|
58
59
|
try { return validateSocialMentions(await client.getCloudSocialMentions(symbol, range), symbol, range); }
|
|
59
|
-
catch (error) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
catch (error) { throw unavailableOnServer(error, unavailableText("social mentions")); }
|
|
61
|
+
}
|
|
62
|
+
export interface SocialMentionsResource {
|
|
63
|
+
payload: SocialMentionsPayload;
|
|
64
|
+
stale: boolean;
|
|
65
|
+
refreshError: string | null;
|
|
66
|
+
/** When the copy shown was saved, when it is one because its refresh failed. */
|
|
67
|
+
savedAt?: number;
|
|
63
68
|
}
|
|
64
|
-
export interface SocialMentionsResource { payload: SocialMentionsPayload; stale: boolean; refreshError: string | null }
|
|
65
69
|
const cacheKey = (symbol: string, range: SocialMentionsRange) => `${range}:${symbol}`;
|
|
66
70
|
export function cachedSocialMentions(symbol: string, range: SocialMentionsRange): SocialMentionsResource | null {
|
|
67
71
|
const cached = socialMentionsCache.get(cacheKey(symbol, range), { allowExpired: true });
|
|
@@ -70,9 +74,10 @@ export function cachedSocialMentions(symbol: string, range: SocialMentionsRange)
|
|
|
70
74
|
catch { return null; }
|
|
71
75
|
}
|
|
72
76
|
export async function loadSocialMentions(symbol: string, range: SocialMentionsRange, force = false): Promise<SocialMentionsResource> {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return { payload: validateSocialMentions(result.data, symbol, range), stale: result.stale, refreshError: result.refreshError ?? null
|
|
77
|
+
// A refusal (a signed-out session, any other 4xx but 408 and 429) or a reply that fails validation shows as itself.
|
|
78
|
+
const result = savedCopyForTransientFailure(await socialMentionsCache.load(cacheKey(symbol, range), () => fetchSocialMentions(symbol, range), { force }));
|
|
79
|
+
return { payload: validateSocialMentions(result.data, symbol, range), stale: result.stale, refreshError: result.refreshError ?? null,
|
|
80
|
+
...(result.source === "stale-fallback" ? { savedAt: result.fetchedAt } : {}) };
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
/**
|
|
@@ -4,7 +4,6 @@ import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
|
|
|
4
4
|
import { socialMentionPostsCache, socialMentionsCache } from "./client";
|
|
5
5
|
import { socialMentionsHeadless } from "./headless";
|
|
6
6
|
import { socialMentionsLockNote } from "./lock-note";
|
|
7
|
-
import { SocialMentionsPane } from "./pane";
|
|
8
7
|
|
|
9
8
|
const socialMentionsSettings = [
|
|
10
9
|
{ key: "socialRange", label: "History", type: "select" as const,
|
|
@@ -12,7 +11,7 @@ const socialMentionsSettings = [
|
|
|
12
11
|
];
|
|
13
12
|
export const socialMentionsModule: PluginModule = {
|
|
14
13
|
series: SOCIAL_MENTION_SERIES,
|
|
15
|
-
panes: [{ id: "social-mentions", reportLockNote: socialMentionsLockNote, name: "Social Mentions", icon: "B", component: SocialMentionsPane,
|
|
14
|
+
panes: [{ id: "social-mentions", reportLockNote: socialMentionsLockNote, name: "Social Mentions", icon: "B", get component(): typeof import("./pane").SocialMentionsPane { const { SocialMentionsPane } = require("./pane"); return SocialMentionsPane; },
|
|
16
15
|
defaultPosition: "right", tickerFollower: true, defaultMode: "floating", defaultFloatingSize: { width: 96, height: 30 },
|
|
17
16
|
tableExport: true, headless: socialMentionsHeadless, settings: { title: "Social Mentions", fields: socialMentionsSettings } }],
|
|
18
17
|
paneTemplates: [{ ...createTickerSurfacePaneTemplate({ id: "social-mentions-pane", paneId: "social-mentions", label: "Social Mentions",
|
|
@@ -3,6 +3,7 @@ import { listingIdentity } from "../shared/ticker-request";
|
|
|
3
3
|
import { Box, ScrollBox, Text, useUiCapabilities } from "../../../ui";
|
|
4
4
|
import { useAsyncResource, useAutoRefresh, usePaneSettingValue, usePluginPaneState, useShortcut, useUpdatedAgo } from "../../../public/react";
|
|
5
5
|
import { CompositeChart, DataTableStackView, EmptyState, PaneStatusBody, usePaneNoticeFooter, usePaneStatusLinkFooter, type DataTableCell, StatGrid } from "../../../components";
|
|
6
|
+
import { ageFooterSegment } from "../../../components/layout/pane/footer";
|
|
6
7
|
import { colors } from "../../../theme/colors";
|
|
7
8
|
import type { SocialMentionPost, SocialMentionsRange } from "../../../api-client/social-mentions";
|
|
8
9
|
import { staticSeries } from "../../../components/chart/static/series";
|
|
@@ -117,7 +118,7 @@ export function SocialMentionsPane({ width, height, focused }: Pick<PaneProps, "
|
|
|
117
118
|
usePaneStatusLinkFooter({ registrationId: "social-mentions", focused, loading: resource.loading || pending, error: signInWall ? null : resource.error,
|
|
118
119
|
url: selected?.topPost?.url ?? (symbol ? `https://x.com/search?q=%24${symbol}` : null), showOpenHint: true,
|
|
119
120
|
info: data ? [
|
|
120
|
-
...(updatedAgo ? [
|
|
121
|
+
...(updatedAgo ? [ageFooterSegment(updatedAgo)] : []),
|
|
121
122
|
...(resource.data?.stale ? [{ id: "stale", parts: [{ text: "stale", tone: "warning" as const }] }] : []),
|
|
122
123
|
] : [],
|
|
123
124
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SeriesDefinition } from "../../../series/types";
|
|
2
|
-
import {
|
|
2
|
+
import { cachedSeriesNote } from "../shared/series-warning";
|
|
3
3
|
import { loadSocialMentions } from "./client";
|
|
4
4
|
|
|
5
5
|
/** How often a ticker is posted about each day, over the last year. */
|
|
@@ -14,10 +14,9 @@ export const SOCIAL_MENTION_SERIES: readonly SeriesDefinition[] = [{
|
|
|
14
14
|
style: "columns",
|
|
15
15
|
load: async ({ ticker }) => {
|
|
16
16
|
const resource = await loadSocialMentions(ticker!, "1y");
|
|
17
|
-
const warning = cachedSeriesWarning(resource);
|
|
18
17
|
return {
|
|
19
18
|
points: resource.payload.x.days.map((row) => ({ date: row.day, value: row.mentions })),
|
|
20
|
-
...(
|
|
19
|
+
...cachedSeriesNote(resource),
|
|
21
20
|
};
|
|
22
21
|
},
|
|
23
22
|
}];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { apiClient } from "../../../api-client";
|
|
2
2
|
import type { SupplyChainPayload, SupplyEntity, SupplyEvidenceItem, SupplyOptions, SupplyRow } from "../../../api-client/supply-chain";
|
|
3
3
|
import { createPluginCache } from "../../../data/plugin-cache";
|
|
4
|
-
import { cachedCloudResource, loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
|
|
4
|
+
import { batchReplyItems, cachedCloudResource, createCloudBatchAhead, loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
|
|
5
5
|
import { activeRelationship, canShowQuote, isUnconfirmed, publicEvidence, supplyOptions, TIER_OPTIONS, trustTier } from "./trust";
|
|
6
6
|
|
|
7
7
|
export const SUPPLY_UNAVAILABLE = "Supply chain disclosures are not available yet.";
|
|
@@ -111,3 +111,24 @@ export async function fetchSupplyChain(symbol: string, client: Pick<typeof apiCl
|
|
|
111
111
|
const cacheKey = (symbol: string, access: string, options: SupplyOptions) => `${symbol.toUpperCase()}:${access}:${JSON.stringify(supplyOptions(options.tiers))}:${!!options.includeLeads}`;
|
|
112
112
|
export const cachedSupplyChain = (symbol: string, access: string, options: SupplyOptions = {}) => cachedCloudResource(supplyChainCache, cacheKey(symbol, access, options), validateSupplyChain);
|
|
113
113
|
export const loadSupplyChain = (symbol: string, access: string, force = false, options: SupplyOptions = {}) => loadCloudResource(supplyChainCache, cacheKey(symbol, access, options), () => fetchSupplyChain(symbol, apiClient, options), { force, validate: validateSupplyChain });
|
|
114
|
+
/** Symbols per disclosures batch request: a ripple's sixty holdings are two, read sixteen at a time on the server. */
|
|
115
|
+
const SUPPLY_BATCH_MAX = 30;
|
|
116
|
+
const supplyChainsAheadByOptions = new Map<string, ReturnType<typeof createCloudBatchAhead<SupplyChainPayload>>>();
|
|
117
|
+
/**
|
|
118
|
+
* Reads many symbols' disclosures ahead in a request per 30 (EARN ripple's
|
|
119
|
+
* holdings), into the cache loadSupplyChain reads. Answers the symbols stored.
|
|
120
|
+
*/
|
|
121
|
+
export function loadSupplyChainsAhead(symbols: readonly string[], access: string, force = false, options: SupplyOptions = {}): Promise<Set<string>> {
|
|
122
|
+
const optionsKey = JSON.stringify([supplyOptions(options.tiers), !!options.includeLeads]);
|
|
123
|
+
let ahead = supplyChainsAheadByOptions.get(optionsKey);
|
|
124
|
+
if (!ahead) {
|
|
125
|
+
ahead = createCloudBatchAhead(supplyChainCache, {
|
|
126
|
+
max: SUPPLY_BATCH_MAX,
|
|
127
|
+
validate: validateSupplyChain,
|
|
128
|
+
read: async (ids) => batchReplyItems(await apiClient.getCloudSupplyChains(ids, options))
|
|
129
|
+
.flatMap((item) => item.chain ? [{ id: item.symbol.toUpperCase(), payload: item.chain }] : []),
|
|
130
|
+
});
|
|
131
|
+
supplyChainsAheadByOptions.set(optionsKey, ahead);
|
|
132
|
+
}
|
|
133
|
+
return ahead(symbols.map((symbol) => ({ id: symbol.toUpperCase(), key: cacheKey(symbol, access, options) })), force);
|
|
134
|
+
}
|
|
@@ -2,7 +2,7 @@ import { apiClient } from "../../../api-client";
|
|
|
2
2
|
import { DEFAULT_GRAPH_OPTIONS, supplyGraphQuery, type GraphOptions, type GraphPayload, type GraphPath } from "../../../api-client/supply-chain-graph";
|
|
3
3
|
import { createPluginCache } from "../../../data/plugin-cache";
|
|
4
4
|
import { dateOptionError, readCalendarDate } from "../../../utils/calendar-date";
|
|
5
|
-
import { cachedCloudResource, loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
|
|
5
|
+
import { batchReplyItems, cachedCloudResource, createCloudBatchAhead, loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
|
|
6
6
|
import { normalizeSupplyRow, validPeriodMonths, validSupplyEntity, validSupplyRow } from "./client";
|
|
7
7
|
import { graphEvidenceRow } from "./graph-evidence";
|
|
8
8
|
import { activeRelationship, isUnconfirmed } from "./trust";
|
|
@@ -84,3 +84,24 @@ export function graphOptions(input: Record<string, unknown>): GraphOptions {
|
|
|
84
84
|
|| options.tiers.some(value => !["structured", "primary", "secondary", "imported"].includes(value))) throw new Error("Invalid supply chain graph filters");
|
|
85
85
|
return options;
|
|
86
86
|
}
|
|
87
|
+
/** Symbols per graphs batch request: a ripple's sixty holdings are two, read sixteen at a time on the server. */
|
|
88
|
+
const GRAPH_BATCH_MAX = 30;
|
|
89
|
+
const graphsAheadByOptions = new Map<string, ReturnType<typeof createCloudBatchAhead<GraphPayload>>>();
|
|
90
|
+
/**
|
|
91
|
+
* Reads many symbols' graphs on one query ahead in a request per 30 (EARN
|
|
92
|
+
* ripple's two hops), into the cache loadGraph reads. Answers the symbols stored.
|
|
93
|
+
*/
|
|
94
|
+
export function loadGraphsAhead(symbols: readonly string[], options: GraphOptions, access: string, force = false): Promise<Set<string>> {
|
|
95
|
+
const query = supplyGraphQuery(options);
|
|
96
|
+
let ahead = graphsAheadByOptions.get(query);
|
|
97
|
+
if (!ahead) {
|
|
98
|
+
ahead = createCloudBatchAhead(graphCache, {
|
|
99
|
+
max: GRAPH_BATCH_MAX,
|
|
100
|
+
validate: validateGraph,
|
|
101
|
+
read: async (ids) => batchReplyItems(await apiClient.getCloudSupplyGraphs(ids, options))
|
|
102
|
+
.flatMap((item) => item.graph ? [{ id: item.symbol.toUpperCase(), payload: item.graph }] : []),
|
|
103
|
+
});
|
|
104
|
+
graphsAheadByOptions.set(query, ahead);
|
|
105
|
+
}
|
|
106
|
+
return ahead(symbols.map((symbol) => ({ id: symbol.toUpperCase(), key: key(symbol, "", options, access) })), force);
|
|
107
|
+
}
|
|
@@ -3,7 +3,6 @@ import { createTickerSurfacePaneTemplate } from "../shared/ticker-surface";
|
|
|
3
3
|
import { graphCache } from "./graph-client";
|
|
4
4
|
import { supplyChainCache } from "./client";
|
|
5
5
|
import { supplyChainHeadless } from "./headless";
|
|
6
|
-
import { SupplyChainPane } from "./pane";
|
|
7
6
|
|
|
8
7
|
/** What another pane can open SPLC on: a Graph or Path view, its target and its query, as `graphOptions` reads them. */
|
|
9
8
|
const OPENING_SETTINGS = ["tab", "to", "depth", "direction", "roles", "tiers"];
|
|
@@ -13,7 +12,7 @@ const openingSettings = (values: Record<string, string> = {}) =>
|
|
|
13
12
|
export const supplyChainModule: PluginModule = {
|
|
14
13
|
setup(ctx) { supplyChainCache.attach(ctx.persistence); graphCache.attach(ctx.persistence); },
|
|
15
14
|
dispose() { supplyChainCache.reset(); graphCache.reset(); },
|
|
16
|
-
panes: [{ id: "supply-chain", name: "Supply Chain", icon: "S", component: SupplyChainPane,
|
|
15
|
+
panes: [{ id: "supply-chain", name: "Supply Chain", icon: "S", get component(): typeof import("./pane").SupplyChainPane { const { SupplyChainPane } = require("./pane"); return SupplyChainPane; },
|
|
17
16
|
defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 130, height: 30 },
|
|
18
17
|
tickerFollower: true, instruments: ["equity"], tableExport: true, headless: supplyChainHeadless }],
|
|
19
18
|
paneTemplates: [{ ...createTickerSurfacePaneTemplate({ id: "supply-chain-pane", paneId: "supply-chain", label: "Supply Chain",
|
|
@@ -10,17 +10,25 @@ import type {
|
|
|
10
10
|
} from "./types";
|
|
11
11
|
import type { PluginPersistence } from "../../../types/plugin";
|
|
12
12
|
import { apiClient } from "../../../api-client";
|
|
13
|
-
import { ApiRequestError, isPermanentClientError } from "../../../api-client/errors";
|
|
13
|
+
import { ApiRequestError, isPermanentClientError, isTransientFailure } from "../../../api-client/errors";
|
|
14
14
|
import { httpFetch } from "../../../utils/http-transport";
|
|
15
|
+
import { isNetworkFailure } from "../../../utils/network-failure";
|
|
15
16
|
import { asRecord, finiteOrNull } from "../../../utils/guards";
|
|
16
17
|
import { logFailure } from "../../../utils/log-failure";
|
|
17
18
|
|
|
18
19
|
const FORMS_13F_BASE_URL = "https://forms13f.com/api/v1";
|
|
19
20
|
const FORM_PAGE_LIMIT = 100;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
21
|
+
/** The most rows the 13F source gives in one page. */
|
|
22
|
+
const FILING_PAGE_ROWS = 250;
|
|
23
|
+
/** Pages of one filing read at once where the service cannot send it whole. */
|
|
24
|
+
const FILING_PAGE_CONCURRENCY = 4;
|
|
25
|
+
// Large funds file tens of thousands of positions (BlackRock about 50,000), and
|
|
26
|
+
// a silently clipped list makes every weight, total, and buy/sell action wrong.
|
|
27
|
+
const MAX_FORM_ROWS = 100_000;
|
|
28
|
+
/** Rows asked first of a large filing the service is still reading. */
|
|
29
|
+
const FIRST_ROWS = 2_000;
|
|
30
|
+
/** How long a large filing is waited for whole before its first rows are asked. */
|
|
31
|
+
const FIRST_ROWS_AFTER_MS = 300;
|
|
24
32
|
const CACHE_KIND = "forms13f-api";
|
|
25
33
|
const CACHE_SOURCE = "forms13f";
|
|
26
34
|
const CACHE_SCHEMA_VERSION = 1;
|
|
@@ -30,11 +38,12 @@ const FORMS_13F_CACHE_POLICY = {
|
|
|
30
38
|
} as const;
|
|
31
39
|
|
|
32
40
|
export interface Forms13FReadOptions {
|
|
41
|
+
/** A part of the answer that could not be read, said beside what was. */
|
|
33
42
|
onWarning?: (warning: string) => void;
|
|
34
43
|
/**
|
|
35
44
|
* A read answered from the copy saved at `savedAt` (ms) because its refresh
|
|
36
|
-
* failed
|
|
37
|
-
*
|
|
45
|
+
* failed. Only a caller that says when its copy was saved (the footer's
|
|
46
|
+
* "saved copy from", a command's closing line) is answered from one.
|
|
38
47
|
*/
|
|
39
48
|
onSavedCopy?: (savedAt: number) => void;
|
|
40
49
|
forceRefresh?: boolean;
|
|
@@ -51,6 +60,8 @@ let forms13FPersistence: PluginPersistence | null = null;
|
|
|
51
60
|
const failedRefreshes = new Set<string>();
|
|
52
61
|
// The promise is the generation. A newer download replaces it, and the replaced one must not write.
|
|
53
62
|
const activeRequests = new Map<string, Promise<unknown>>();
|
|
63
|
+
/** The service answered a whole filing with 404: it is an older one, so filings are read a page at a time. */
|
|
64
|
+
let wholeFilingsMissing = false;
|
|
54
65
|
|
|
55
66
|
export function attachThirteenFApiPersistence(persistence: PluginPersistence) {
|
|
56
67
|
if (forms13FPersistence !== persistence) resetThirteenFApiPersistence();
|
|
@@ -61,6 +72,7 @@ export function resetThirteenFApiPersistence() {
|
|
|
61
72
|
forms13FPersistence = null;
|
|
62
73
|
failedRefreshes.clear();
|
|
63
74
|
activeRequests.clear();
|
|
75
|
+
wholeFilingsMissing = false;
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
function padCik(value: string): string {
|
|
@@ -121,7 +133,15 @@ async function fetchForms13F<T>(
|
|
|
121
133
|
|
|
122
134
|
if (!options.forceRefresh) {
|
|
123
135
|
const pending = activeRequests.get(key) as Promise<T> | undefined;
|
|
124
|
-
if (pending)
|
|
136
|
+
if (pending) {
|
|
137
|
+
if (cached != null) return cached.value;
|
|
138
|
+
// Another reader's request, which that reader may stop (a fund read ahead
|
|
139
|
+
// while the cursor rested on it): this reader then asks again on its own.
|
|
140
|
+
return pending.catch((error: unknown) => {
|
|
141
|
+
if (options.signal?.aborted || !(error instanceof Error && error.name === "AbortError")) throw error;
|
|
142
|
+
return fetchForms13F<T>(path, params, options);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
125
145
|
}
|
|
126
146
|
|
|
127
147
|
const slot: { promise?: Promise<T> } = {};
|
|
@@ -156,23 +176,17 @@ async function fetchForms13F<T>(
|
|
|
156
176
|
} catch (error) {
|
|
157
177
|
options.signal?.throwIfAborted();
|
|
158
178
|
if (current()) failedRefreshes.add(key);
|
|
159
|
-
|
|
160
|
-
|
|
179
|
+
// A saved copy answers only for a failure asking again may get past; a refusal or a reply that
|
|
180
|
+
// fails validation is the error, and a missing or denied resource also drops its copy.
|
|
181
|
+
if (!isTransientFailure(error)) {
|
|
182
|
+
if (isPermanentClientError(error) && current()) store?.deleteResource(CACHE_KIND, key, { sourceKey: CACHE_SOURCE });
|
|
161
183
|
throw error;
|
|
162
184
|
}
|
|
163
185
|
const retained = options.cache !== false
|
|
164
186
|
? store?.getResource<T>(CACHE_KIND, key, { ...cacheOptions, allowExpired: true }) : null;
|
|
165
|
-
// A caller may retain old research only when it can
|
|
166
|
-
if (!retained) throw error;
|
|
167
|
-
|
|
168
|
-
options.onSavedCopy(retained.fetchedAt);
|
|
169
|
-
return retained.value;
|
|
170
|
-
}
|
|
171
|
-
if (!options.onWarning) throw error;
|
|
172
|
-
const retrieved = new Date(retained.fetchedAt);
|
|
173
|
-
const age = Number.isFinite(retrieved.getTime()) ? `retrieved ${retrieved.toISOString()}` : "with unavailable retrieval time";
|
|
174
|
-
const reason = (error instanceof Error ? error.message : String(error)).trim() || "Request failed";
|
|
175
|
-
options.onWarning(`${key}: refresh failed: ${reason}. Retained data ${age}.`);
|
|
187
|
+
// A caller may retain old research only when it can say when it was saved.
|
|
188
|
+
if (!retained || !options.onSavedCopy || !Number.isFinite(retained.fetchedAt)) throw error;
|
|
189
|
+
options.onSavedCopy(retained.fetchedAt);
|
|
176
190
|
return retained.value;
|
|
177
191
|
} finally {
|
|
178
192
|
if (activeRequests.get(key) === slot.promise) activeRequests.delete(key);
|
|
@@ -348,24 +362,108 @@ export async function listThirteenFFormHoldingsPage(
|
|
|
348
362
|
return { rows, hasMore: rows.length >= limit && offset + rows.length < MAX_FORM_ROWS };
|
|
349
363
|
}
|
|
350
364
|
|
|
365
|
+
function mapHoldings(raw: unknown): ThirteenFHoldingRecord[] {
|
|
366
|
+
return arrayResponse(raw).map(mapHolding).filter((holding): holding is ThirteenFHoldingRecord => !!holding);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** A filing's whole information table as Gloom Cloud sends it in one answer. */
|
|
370
|
+
function filingRows(raw: unknown): ThirteenFHoldingRecord[] {
|
|
371
|
+
const rows = asRecord(raw).rows;
|
|
372
|
+
if (!Array.isArray(rows)) throw new Error("13F filing answer has no rows");
|
|
373
|
+
return mapHoldings(rows);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export interface FilingHoldingsOptions extends Forms13FReadOptions {
|
|
377
|
+
/** The rows the filing's summary counts, when known: a large filing's first rows come first. */
|
|
378
|
+
entries?: number | null;
|
|
379
|
+
/** The filing's first rows, while a large filing the service has not read yet is still loading. */
|
|
380
|
+
onFirstRows?: (rows: ThirteenFHoldingRecord[]) => void;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* A filing's whole information table: one request to Gloom Cloud, which
|
|
385
|
+
* reads the source's pages itself and keeps the filing. An older service
|
|
386
|
+
* without that answer (a 404, remembered for the session) or one that cannot
|
|
387
|
+
* be reached is read a page at a time, a few pages at once, as before; a page
|
|
388
|
+
* Gloom Cloud cannot send comes from the public source. A busy or failing
|
|
389
|
+
* service (429, 5xx) is the error: paging it would only ask it more.
|
|
390
|
+
*/
|
|
351
391
|
export async function listThirteenFFormHoldings(
|
|
352
392
|
cik: string,
|
|
353
393
|
accessionNumber: string,
|
|
354
394
|
signal?: AbortSignal,
|
|
355
|
-
options:
|
|
395
|
+
options: FilingHoldingsOptions = {},
|
|
356
396
|
): Promise<ThirteenFHoldingRecord[]> {
|
|
357
|
-
const
|
|
358
|
-
|
|
397
|
+
const { entries, onFirstRows, ...readOptions } = options;
|
|
398
|
+
if (wholeFilingsMissing) return listPagedHoldings(cik, accessionNumber, signal, readOptions);
|
|
399
|
+
// The count lets a filing the service has not stored yet be read in fewer requests.
|
|
400
|
+
const params = {
|
|
401
|
+
cik: normalizeCik(cik),
|
|
402
|
+
accession_number: accessionNumber,
|
|
403
|
+
...(entries != null && entries > 0 ? { entries } : {}),
|
|
404
|
+
};
|
|
405
|
+
const whole = fetchForms13F<unknown>("/holdings", params, { ...readOptions, signal, cloudOnly: true });
|
|
406
|
+
let answered = false;
|
|
407
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
408
|
+
if (onFirstRows && entries != null && entries > FIRST_ROWS) {
|
|
409
|
+
timer = setTimeout(() => {
|
|
410
|
+
if (answered) return;
|
|
411
|
+
void fetchForms13F<unknown>("/holdings", { ...params, limit: FIRST_ROWS }, { signal, cloudOnly: true, cache: false })
|
|
412
|
+
.then((raw) => { if (!answered) onFirstRows(filingRows(raw)); })
|
|
413
|
+
.catch(() => {
|
|
414
|
+
// Intentional ignore: the first rows only come ahead of the whole filing, which reports its own failure.
|
|
415
|
+
});
|
|
416
|
+
}, FIRST_ROWS_AFTER_MS);
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
return filingRows(await whole);
|
|
420
|
+
} catch (error) {
|
|
359
421
|
signal?.throwIfAborted();
|
|
422
|
+
const missing = error instanceof ApiRequestError && error.status === 404;
|
|
423
|
+
if (!missing && !isNetworkFailure(error)) throw error;
|
|
424
|
+
if (missing) wholeFilingsMissing = true;
|
|
425
|
+
return listPagedHoldings(cik, accessionNumber, signal, readOptions);
|
|
426
|
+
} finally {
|
|
427
|
+
answered = true;
|
|
428
|
+
clearTimeout(timer);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/** A filing read a page at a time, a few pages at once, until a page comes back short. */
|
|
433
|
+
async function listPagedHoldings(
|
|
434
|
+
cik: string,
|
|
435
|
+
accessionNumber: string,
|
|
436
|
+
signal: AbortSignal | undefined,
|
|
437
|
+
options: Forms13FReadOptions,
|
|
438
|
+
): Promise<ThirteenFHoldingRecord[]> {
|
|
439
|
+
const pages: ThirteenFHoldingRecord[][] = [];
|
|
440
|
+
const maxPages = Math.ceil(MAX_FORM_ROWS / FILING_PAGE_ROWS);
|
|
441
|
+
let next = 0;
|
|
442
|
+
let last: number | null = null;
|
|
443
|
+
let failed = false;
|
|
444
|
+
async function readPage() {
|
|
445
|
+
signal?.throwIfAborted();
|
|
446
|
+
const index = next++;
|
|
360
447
|
const page = await listThirteenFFormHoldingsPage(cik, accessionNumber, signal, {
|
|
361
448
|
...options,
|
|
362
|
-
offset,
|
|
363
|
-
limit:
|
|
449
|
+
offset: index * FILING_PAGE_ROWS,
|
|
450
|
+
limit: FILING_PAGE_ROWS,
|
|
364
451
|
});
|
|
365
|
-
|
|
366
|
-
if (
|
|
452
|
+
pages[index] = page.rows;
|
|
453
|
+
if (page.rows.length < FILING_PAGE_ROWS && (last === null || index < last)) last = index;
|
|
454
|
+
}
|
|
455
|
+
async function worker() {
|
|
456
|
+
try {
|
|
457
|
+
while (!failed && next < maxPages && (last === null || next <= last)) await readPage();
|
|
458
|
+
} catch (error) {
|
|
459
|
+
failed = true;
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
367
462
|
}
|
|
368
|
-
|
|
463
|
+
// The first page alone says whether there is more: most filings fit in it.
|
|
464
|
+
await readPage();
|
|
465
|
+
await Promise.all(Array.from({ length: FILING_PAGE_CONCURRENCY }, worker));
|
|
466
|
+
return pages.slice(0, (last ?? maxPages - 1) + 1).flat();
|
|
369
467
|
}
|
|
370
468
|
|
|
371
469
|
export async function lookupThirteenFTickers(
|