gloomberb 0.16.1 → 0.16.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 +2 -1
- package/package.json +2 -1
- package/src/api-client/beneficial-owners.ts +92 -0
- package/src/api-client/data.ts +26 -8
- package/src/api-client/errors.ts +12 -0
- package/src/api-client/geo.ts +363 -0
- package/src/api-client/index.ts +2 -0
- package/src/api-client/market-discovery.ts +10 -0
- package/src/api-client/paths.ts +30 -1
- package/src/api-client/perps.ts +37 -0
- package/src/api-client/request.ts +5 -2
- package/src/api-client/types.ts +2 -0
- package/src/brokers/account-cache.ts +69 -0
- package/src/cli/command-options.ts +74 -0
- package/src/cli/commands/command-utils.ts +37 -0
- package/src/cli/commands/crypto-hints.ts +75 -0
- package/src/cli/commands/market.ts +560 -136
- package/src/cli/commands/overview.ts +136 -48
- package/src/cli/commands/ticker.ts +220 -67
- package/src/cli/desktop-pane-shot.ts +37 -4
- package/src/cli/freshness.ts +61 -0
- package/src/cli/help.ts +27 -6
- package/src/cli/helpers.ts +4 -8
- package/src/cli/history-rows.ts +187 -15
- package/src/cli/index.ts +23 -8
- package/src/cli/listing-arg.ts +321 -0
- package/src/cli/options.ts +5 -1
- package/src/cli/pane-functions/access-gate.ts +42 -0
- package/src/cli/pane-functions/capabilities.ts +5 -0
- package/src/cli/pane-functions/catalog.ts +28 -1
- package/src/cli/pane-functions/data.ts +3 -1
- package/src/cli/pane-functions/dom.ts +87 -16
- package/src/cli/pane-functions/freshness.ts +400 -0
- package/src/cli/pane-functions/function-help.ts +31 -22
- package/src/cli/pane-functions/headless.ts +201 -41
- package/src/cli/pane-functions/index.ts +24 -6
- package/src/cli/pane-functions/options.ts +3 -0
- package/src/cli/pane-functions/report.ts +12 -1
- package/src/cli/pane-functions/resolver.ts +63 -9
- package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
- package/src/cli/pane-functions/screenshot.ts +11 -3
- package/src/cli/registry.ts +6 -3
- package/src/cli/report-tables.ts +460 -0
- package/src/cli/result.ts +53 -29
- package/src/cli/ticker-resolution.ts +7 -5
- package/src/components/chart/composite/composite-chart.tsx +88 -2536
- package/src/components/chart/composite/drawing-store.ts +59 -0
- package/src/components/chart/composite/legend.tsx +319 -0
- package/src/components/chart/composite/panel-bitmap.ts +139 -0
- package/src/components/chart/composite/panel-gestures.ts +59 -0
- package/src/components/chart/composite/panel-labels.ts +107 -0
- package/src/components/chart/composite/panel-surface.tsx +876 -0
- package/src/components/chart/composite/tool-catalog.ts +98 -0
- package/src/components/chart/composite/toolbar.tsx +186 -0
- package/src/components/chart/composite/tools.ts +8 -0
- package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
- package/src/components/chart/composite/use-composite-viewport.ts +143 -0
- package/src/components/command-bar/list/model.ts +5 -0
- package/src/components/command-bar/list/view.tsx +16 -3
- package/src/components/command-bar/pane-templates/workflow.ts +1 -0
- package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/command-bar/workflow/tickers.ts +6 -0
- package/src/components/data-table/export.ts +6 -51
- package/src/components/data-table/view.tsx +32 -11
- package/src/components/feedback-dialog.tsx +2 -1
- package/src/components/form-modal/field-row.tsx +2 -2
- package/src/components/layout/detached-pane-shell.tsx +6 -3
- package/src/components/layout/pane/content.tsx +23 -10
- package/src/components/layout/pane/error-boundary.tsx +103 -0
- package/src/components/layout/pane/footer/registration.tsx +68 -23
- package/src/components/layout/pane/header.tsx +11 -11
- package/src/components/layout/shell/active-drag.ts +67 -35
- package/src/components/layout/shell/cursor-occlusion.ts +6 -5
- package/src/components/layout/shell/drag/index.ts +12 -7
- package/src/components/layout/shell/drag/live.ts +122 -0
- package/src/components/layout/shell/drag/overlays.tsx +179 -35
- package/src/components/layout/shell/drag/runtime.ts +62 -50
- package/src/components/layout/shell/drag/slide.ts +10 -0
- package/src/components/layout/shell/index.tsx +37 -51
- package/src/components/layout/shell/menu.ts +2 -1
- package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
- package/src/components/layout/shell/native/surfaces.ts +30 -14
- package/src/components/layout/shell/pane/actions.ts +2 -1
- package/src/components/layout/shell/pane/layers.tsx +419 -168
- package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
- package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
- package/src/components/metric-treemap/heat-surface.tsx +43 -16
- package/src/components/metric-treemap/heat-tiles.ts +18 -0
- package/src/components/metric-treemap/layout.ts +2 -0
- package/src/components/onboarding/onboarding-keyboard.ts +311 -0
- package/src/components/onboarding/onboarding-wizard.tsx +101 -788
- package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
- package/src/components/onboarding/use-onboarding-progress.ts +298 -0
- package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
- package/src/components/ticker/list-table-view.tsx +13 -1
- package/src/components/ui/fields.tsx +8 -0
- package/src/components/ui/range-track.tsx +10 -3
- package/src/components/ui/status.tsx +8 -2
- package/src/components/ui/tabs.tsx +7 -4
- package/src/components/ui/text-prompt-dialog.tsx +4 -2
- package/src/data/config/store/normalize.ts +17 -1
- package/src/data/json-persistence.ts +17 -3
- package/src/data/json-storage.ts +2 -0
- package/src/data/memory-resource-store.ts +46 -0
- package/src/i18n/es.ts +19 -1
- package/src/i18n/ja.ts +19 -1
- package/src/i18n/ko.ts +19 -1
- package/src/i18n/zh-cn.ts +19 -1
- package/src/i18n/zh-tw.ts +19 -1
- package/src/market-data/coordinator/chart.ts +1 -1
- package/src/market-data/coordinator/quotes.ts +23 -4
- package/src/market-data/fx-closes.ts +72 -0
- package/src/market-data/market/freshness.ts +123 -6
- package/src/market-data/market/session-close-note.ts +57 -0
- package/src/market-data/market/status.ts +151 -0
- package/src/market-data/published-apac-sessions.ts +66 -0
- package/src/market-data/quotes/contributions.ts +2 -0
- package/src/market-data/quotes/freshness.ts +5 -0
- package/src/market-data/quotes/resolution.ts +2 -0
- package/src/market-data/quotes/screener-live-quotes.ts +49 -4
- package/src/plugins/builtin/account-management/pane.tsx +4 -0
- package/src/plugins/builtin/alerts/cli.ts +10 -5
- package/src/plugins/builtin/alerts/index.tsx +1 -0
- package/src/plugins/builtin/analytics/metrics.ts +8 -3
- package/src/plugins/builtin/analytics/pane-model.ts +10 -6
- package/src/plugins/builtin/analytics/risk-client.ts +191 -66
- package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
- package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
- package/src/plugins/builtin/analytics/risk-model.ts +45 -17
- package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
- package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
- package/src/plugins/builtin/attention/headless.ts +6 -4
- package/src/plugins/builtin/attention/index.tsx +1 -1
- package/src/plugins/builtin/attention/pane.tsx +2 -2
- package/src/plugins/builtin/awards/headless.ts +1 -0
- package/src/plugins/builtin/awards/pane.tsx +1 -1
- package/src/plugins/builtin/backtest/headless.ts +1 -0
- package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
- package/src/plugins/builtin/buildout/index.tsx +1 -0
- package/src/plugins/builtin/catalysts/detail.tsx +1 -1
- package/src/plugins/builtin/catalysts/headless.ts +3 -1
- package/src/plugins/builtin/cds/headless.ts +2 -0
- package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
- package/src/plugins/builtin/chart-composer/headless.ts +38 -3
- package/src/plugins/builtin/chart-composer/index.tsx +3 -1
- package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
- package/src/plugins/builtin/chat/channels.ts +19 -3
- package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
- package/src/plugins/builtin/chat/content/footer.tsx +15 -6
- package/src/plugins/builtin/chat/content/index.tsx +120 -21
- package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
- package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
- package/src/plugins/builtin/chat/direct-messages.ts +200 -0
- package/src/plugins/builtin/chat/index.tsx +1 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
- package/src/plugins/builtin/chat/message/header.tsx +16 -6
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
- package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
- package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
- package/src/plugins/builtin/chat/message/types.ts +14 -2
- package/src/plugins/builtin/chat/profile-popover.ts +18 -13
- package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
- package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/team/module.tsx +1 -0
- package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
- package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
- package/src/plugins/builtin/comment-letters/index.tsx +1 -0
- package/src/plugins/builtin/company-attention/headless.ts +5 -1
- package/src/plugins/builtin/company-attention/pane.tsx +2 -2
- package/src/plugins/builtin/company-kpis/headless.ts +1 -0
- package/src/plugins/builtin/congress-trades/headless.ts +1 -0
- package/src/plugins/builtin/correlation/compute.ts +59 -16
- package/src/plugins/builtin/correlation/geo.ts +34 -0
- package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
- package/src/plugins/builtin/correlation/headless.ts +42 -8
- package/src/plugins/builtin/correlation/history.ts +2 -0
- package/src/plugins/builtin/correlation/index.tsx +68 -14
- package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
- package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
- package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
- package/src/plugins/builtin/correlation/settings.ts +1 -1
- package/src/plugins/builtin/cot/headless.ts +6 -3
- package/src/plugins/builtin/cot/index.tsx +3 -3
- package/src/plugins/builtin/cot/model.ts +36 -3
- package/src/plugins/builtin/cpi/headless.ts +4 -0
- package/src/plugins/builtin/credit-boards/headless.ts +2 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
- package/src/plugins/builtin/credit-documents/headless.ts +2 -0
- package/src/plugins/builtin/crypto-board/headless.ts +3 -0
- package/src/plugins/builtin/custom-view/loader.ts +1 -1
- package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
- package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
- package/src/plugins/builtin/doe/headless.ts +7 -0
- package/src/plugins/builtin/doe/range-bar.tsx +7 -37
- package/src/plugins/builtin/earnings/headless.ts +5 -0
- package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
- package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
- package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
- package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
- package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
- package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
- package/src/plugins/builtin/econ/index.tsx +1 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
- package/src/plugins/builtin/equity-screener/headless.ts +2 -0
- package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
- package/src/plugins/builtin/executives/index.tsx +1 -0
- package/src/plugins/builtin/exposure/headless.ts +3 -1
- package/src/plugins/builtin/fear-greed/headless.ts +2 -0
- package/src/plugins/builtin/filing-events/index.tsx +1 -0
- package/src/plugins/builtin/futures-curve/client.ts +12 -3
- package/src/plugins/builtin/futures-curve/headless.ts +39 -10
- package/src/plugins/builtin/futures-curve/index.tsx +3 -3
- package/src/plugins/builtin/futures-curve/model.ts +188 -4
- package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
- package/src/plugins/builtin/gpu/headless.ts +7 -3
- package/src/plugins/builtin/gpu/ladder.tsx +26 -30
- package/src/plugins/builtin/gpu/model.ts +27 -1
- package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
- package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
- package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
- package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
- package/src/plugins/builtin/holders/client.ts +3 -6
- package/src/plugins/builtin/holders/format.ts +31 -1
- package/src/plugins/builtin/holders/headless.ts +161 -6
- package/src/plugins/builtin/holders/index.tsx +10 -3
- package/src/plugins/builtin/holders/pane.tsx +42 -16
- package/src/plugins/builtin/holders/report-header.ts +136 -0
- package/src/plugins/builtin/holders/table-model.ts +20 -5
- package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
- package/src/plugins/builtin/holders/types.ts +2 -1
- package/src/plugins/builtin/insider/headless.ts +2 -0
- package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
- package/src/plugins/builtin/iv-history/headless.ts +4 -1
- package/src/plugins/builtin/jobs/headless.ts +1 -0
- package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +12 -6
- package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
- package/src/plugins/builtin/macro-day/headless.ts +2 -0
- package/src/plugins/builtin/market-halts/index.tsx +1 -0
- package/src/plugins/builtin/market-heatmap/data.ts +2 -0
- package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
- package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
- package/src/plugins/builtin/market-heatmap/model.ts +146 -0
- package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
- package/src/plugins/builtin/market-movers/headless.ts +2 -0
- package/src/plugins/builtin/market-valuation/headless.ts +2 -0
- package/src/plugins/builtin/members/client.ts +20 -3
- package/src/plugins/builtin/members/headless.ts +5 -3
- package/src/plugins/builtin/members/model.ts +10 -2
- package/src/plugins/builtin/members/pane.tsx +23 -6
- package/src/plugins/builtin/mna/distress/headless.ts +1 -0
- package/src/plugins/builtin/mna/headless.ts +1 -0
- package/src/plugins/builtin/money-markets/headless.ts +1 -0
- package/src/plugins/builtin/news/headless.ts +2 -0
- package/src/plugins/builtin/news/wire/index.tsx +8 -1
- package/src/plugins/builtin/notes/cli.ts +14 -6
- package/src/plugins/builtin/notes/index.tsx +1 -0
- package/src/plugins/builtin/openfda/index.tsx +1 -0
- package/src/plugins/builtin/options-calculator/headless.ts +2 -0
- package/src/plugins/builtin/options-positioning/headless.ts +3 -0
- package/src/plugins/builtin/options-scenario/headless.ts +5 -0
- package/src/plugins/builtin/pe-band/client.ts +48 -3
- package/src/plugins/builtin/pe-band/headless.ts +25 -7
- package/src/plugins/builtin/pe-band/model.ts +92 -16
- package/src/plugins/builtin/pe-band/pane.tsx +33 -16
- package/src/plugins/builtin/perps/client.ts +50 -3
- package/src/plugins/builtin/perps/headless.ts +144 -16
- package/src/plugins/builtin/perps/index.tsx +6 -6
- package/src/plugins/builtin/perps/model.ts +189 -12
- package/src/plugins/builtin/perps/pane.tsx +249 -48
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
- package/src/plugins/builtin/portfolio-list/allocation.ts +248 -0
- package/src/plugins/builtin/portfolio-list/cached-account.ts +42 -0
- package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
- package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
- package/src/plugins/builtin/portfolio-list/cli/render.ts +232 -39
- package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
- package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
- package/src/plugins/builtin/portfolio-list/headless.ts +100 -16
- package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
- package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
- package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +53 -16
- package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +46 -5
- package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
- package/src/plugins/builtin/power/headless.ts +3 -1
- package/src/plugins/builtin/rate-path/headless.ts +2 -0
- package/src/plugins/builtin/realized-vol/headless.ts +2 -0
- package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
- package/src/plugins/builtin/research/analyst-headless.ts +3 -0
- package/src/plugins/builtin/research/events-headless.ts +2 -0
- package/src/plugins/builtin/research/headless.ts +2 -0
- package/src/plugins/builtin/research/index.tsx +1 -0
- package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
- package/src/plugins/builtin/research/relative-valuation-model.ts +18 -6
- package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
- package/src/plugins/builtin/research-search/index.tsx +1 -0
- package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
- package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
- package/src/plugins/builtin/risk-factors/headless.ts +2 -0
- package/src/plugins/builtin/scanner/flow-history.ts +2 -13
- package/src/plugins/builtin/scanner/headless.ts +14 -0
- package/src/plugins/builtin/seasonality/headless.ts +2 -0
- package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
- package/src/plugins/builtin/sec/filing-content.ts +42 -17
- package/src/plugins/builtin/sec/forms.ts +12 -0
- package/src/plugins/builtin/sec/headless.ts +2 -0
- package/src/plugins/builtin/sectors/client.ts +1 -0
- package/src/plugins/builtin/sectors/headless.ts +9 -1
- package/src/plugins/builtin/sectors/sector-model.ts +2 -0
- package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
- package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
- package/src/plugins/builtin/shared/members-menu.tsx +260 -0
- package/src/plugins/builtin/shared/report-freshness.ts +57 -0
- package/src/plugins/builtin/shared/research-cells.tsx +4 -9
- package/src/plugins/builtin/short-interest/headless.ts +2 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
- package/src/plugins/builtin/short-volume/headless.ts +1 -0
- package/src/plugins/builtin/short-volume/pane.tsx +1 -1
- package/src/plugins/builtin/social-mentions/headless.ts +1 -0
- package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
- package/src/plugins/builtin/supply-chain/headless.ts +7 -1
- package/src/plugins/builtin/supply-chain/index.tsx +10 -1
- package/src/plugins/builtin/supply-chain/model.ts +27 -2
- package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
- package/src/plugins/builtin/themes/headless.ts +3 -0
- package/src/plugins/builtin/themes/pane.tsx +3 -0
- package/src/plugins/builtin/thirteenf/headless.ts +110 -25
- package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
- package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
- package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
- package/src/plugins/builtin/ticker-detail/headless.ts +27 -5
- package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/overview/model.ts +17 -5
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +27 -26
- package/src/plugins/builtin/time-sales/headless.ts +5 -1
- package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
- package/src/plugins/builtin/volatility/headless.ts +6 -1
- package/src/plugins/builtin/world-indices/headless.ts +2 -0
- package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +159 -0
- package/src/plugins/builtin/world-venue-map/basemap.ts +232 -0
- package/src/plugins/builtin/world-venue-map/client.ts +45 -0
- package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
- package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
- package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
- package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
- package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
- package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
- package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
- package/src/plugins/builtin/world-venue-map/geo-svg.tsx +448 -0
- package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
- package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
- package/src/plugins/builtin/world-venue-map/index.ts +69 -6
- package/src/plugins/builtin/world-venue-map/layered-pane.tsx +565 -0
- package/src/plugins/builtin/world-venue-map/layers.ts +406 -0
- package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +557 -85
- package/src/plugins/builtin/world-venue-map/model.ts +23 -4
- package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +202 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
- package/src/plugins/builtin/world-venue-map/pane.tsx +35 -44
- package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
- package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
- package/src/plugins/builtin/yield-curve/headless.ts +16 -0
- package/src/plugins/loader.ts +13 -1
- package/src/plugins/registry/pane-settings.ts +1 -0
- package/src/renderers/browser/app-services.ts +3 -1
- package/src/renderers/dom/build-assets.ts +81 -3
- package/src/renderers/dom/data-table/dom.ts +31 -0
- package/src/renderers/dom/data-table/index.tsx +5 -0
- package/src/renderers/dom/data-table/row.tsx +2 -0
- package/src/renderers/dom/desktop/controls.tsx +7 -3
- package/src/renderers/dom/desktop/list-view.tsx +35 -10
- package/src/renderers/dom/desktop/popover.tsx +73 -14
- package/src/renderers/dom/host/box.tsx +113 -17
- package/src/renderers/dom/host/drag-shield.ts +24 -0
- package/src/renderers/dom/host/input.tsx +14 -3
- package/src/renderers/dom/host/live-frame.ts +54 -0
- package/src/renderers/dom/host/mouse.ts +8 -1
- package/src/renderers/dom/host/scroll-box.tsx +6 -5
- package/src/renderers/dom/host/tabs.tsx +3 -2
- package/src/renderers/dom/styles.css +16 -9
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
- package/src/renderers/electrobun/bun/desktop/backend.ts +2 -0
- package/src/renderers/electrobun/bun/desktop/initialization.ts +13 -0
- package/src/renderers/electrobun/shared/protocol.ts +10 -1
- package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -0
- package/src/renderers/electrobun/view/host/native.ts +0 -10
- package/src/renderers/electrobun/view/host/window-move.ts +28 -0
- package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
- package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
- package/src/renderers/electrobun/view/ui-host.tsx +2 -5
- package/src/renderers/opentui/host.tsx +5 -0
- package/src/renderers/opentui/ui-host.tsx +7 -1
- package/src/sources/gloomberb-cloud/index.ts +25 -4
- package/src/sources/gloomberb-cloud/normalizers.ts +43 -23
- package/src/sources/provider-router/batches.ts +3 -3
- package/src/sources/provider-router/cached-routes.ts +4 -1
- package/src/sources/provider-router/financial-routes.ts +2 -2
- package/src/sources/provider-router/financials.ts +76 -12
- package/src/sources/provider-router/history.ts +15 -10
- package/src/sources/provider-router/primary.ts +2 -2
- package/src/sources/sec-registrant.ts +75 -0
- package/src/state/app/context/index.tsx +24 -8
- package/src/state/hooks/quote-streaming.ts +41 -26
- package/src/state/pane-scroll-registry.tsx +67 -35
- package/src/sync/core-contributors.ts +4 -0
- package/src/telemetry/crash-reports.ts +4 -1
- package/src/test-support/cli-context.ts +10 -2
- package/src/test-support/margin-account.ts +108 -0
- package/src/theme/heat-colors.ts +266 -84
- package/src/time-series/resolution.ts +15 -0
- package/src/time-series/resolve.ts +1 -1
- package/src/time-series/use-chart-resolution.ts +1 -1
- package/src/types/context-menu.ts +6 -0
- package/src/types/data-provider.ts +2 -0
- package/src/types/financials.ts +35 -3
- package/src/types/headless.ts +79 -2
- package/src/types/plugin.ts +20 -1
- package/src/types/ticker.ts +15 -0
- package/src/ui/host.tsx +26 -0
- package/src/ui/index.tsx +8 -3
- package/src/ui/scroll-box-axis.ts +26 -0
- package/src/updater/index.ts +9 -11
- package/src/utils/async-deadline.ts +21 -0
- package/src/utils/cli-output.ts +5 -1
- package/src/utils/crypto-pair.ts +41 -0
- package/src/utils/currency-units.ts +19 -0
- package/src/utils/depositary-receipt.ts +70 -0
- package/src/utils/display-number.ts +63 -0
- package/src/utils/exchanges.ts +72 -0
- package/src/utils/fire-and-forget.ts +24 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/fundamentals.ts +17 -1
- package/src/utils/price-earnings.ts +70 -3
- package/src/utils/price-history-integrity.ts +19 -6
- package/src/utils/price-history.ts +58 -13
- package/src/utils/rpc-timeout-error.ts +27 -0
- package/src/utils/sec.ts +13 -1
- package/src/utils/utc-time.ts +79 -0
|
@@ -27,27 +27,46 @@ import { SupplyFlow } from "./flow";
|
|
|
27
27
|
import { SupplyGraphPane } from "./graph-pane";
|
|
28
28
|
import {
|
|
29
29
|
cellText, counterpartyKind, counterpartyKindLabel, counterpartyLabel, counterpartyName, disclosedValue, nativeValue, percentage, ROLE_COLORS, roleLabel,
|
|
30
|
-
shareParts, sortRows, type SupplySort,
|
|
30
|
+
shareParts, sortRows, supplyRoleCounts, type SupplySort,
|
|
31
31
|
} from "./model";
|
|
32
32
|
import { RowEvidence } from "./row-evidence";
|
|
33
33
|
import { evidenceDate, evidenceLabel, isUnconfirmed, matchesSupplyOptions, supplyOptions, TIER_OPTIONS } from "./trust";
|
|
34
34
|
|
|
35
35
|
type Item = { kind: "edge"; row: SupplyRow } | { kind: "locked"; id: string };
|
|
36
36
|
const itemId = (item: Item) => item.kind === "edge" ? item.row.id : item.id;
|
|
37
|
-
const ROLE_ORDER: SupplyRole[] = ["customer", "supplier", "partner", "competitor", "investee"];
|
|
38
37
|
const ROLE_PLURALS: Record<SupplyRole, string> = { customer: "Customers", supplier: "Suppliers", partner: "Partners", competitor: "Competitors", investee: "Investees" };
|
|
39
|
-
|
|
38
|
+
/** A share figure is at most five cells (`99.9%`, `100%`), right-aligned so the bars line up. */
|
|
39
|
+
const SHARE_FIGURE_CELLS = 5;
|
|
40
|
+
/** Bar, gap and figure: below this a share cell shows the figure alone. */
|
|
41
|
+
const SHARE_BAR_MIN_CELLS = 3 + 1 + SHARE_FIGURE_CELLS;
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* row
|
|
44
|
+
* Cells of a share column's bar: as long as the column allows after the figure
|
|
45
|
+
* and the longest basis that fits, between 3 and 8 cells, and the same on every
|
|
46
|
+
* row so the bars and figures line up. Zero leaves the figure alone.
|
|
45
47
|
*/
|
|
46
|
-
function
|
|
48
|
+
function shareBarCells(width: number, bases: readonly number[]): number {
|
|
49
|
+
if (width < SHARE_BAR_MIN_CELLS) return 0;
|
|
50
|
+
// Room for the longest basis that can show at all; a longer one gives way, not every bar.
|
|
51
|
+
const basis = longestBasis(bases, width);
|
|
52
|
+
return Math.min(width >= 36 ? 8 : 5, Math.max(3, width - SHARE_FIGURE_CELLS - 2 - basis));
|
|
53
|
+
}
|
|
54
|
+
const longestBasis = (bases: readonly number[], width: number) => Math.max(0, ...bases.filter((cells) => SHARE_BAR_MIN_CELLS + 1 + cells <= width));
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Columns that fit the pane, giving up the least first: the share bar shortens
|
|
58
|
+
* to keep the whole basis, the name shortens to 18 cells, the ticker folds into
|
|
59
|
+
* the name and the period is left to the evidence view; then the share drops
|
|
60
|
+
* its basis and its bar, and the name shortens further. Only a pane narrower
|
|
61
|
+
* than that scrolls sideways, so the pane edge never cuts a share in half.
|
|
62
|
+
* Value shows only when some row discloses a value, retaining its original
|
|
63
|
+
* currency and units.
|
|
64
|
+
*/
|
|
65
|
+
function tableColumns(width: number, desktop: boolean, locked: boolean, valueWidth: number | null, bases: readonly number[]): DataTableColumn[] {
|
|
47
66
|
const wide = width >= 150, medium = width >= 110;
|
|
48
67
|
const name: DataTableColumn = { id: "name", label: "Counterparty", width: Math.max(locked && !desktop ? 34 : 0, wide ? 30 : medium ? 26 : 20), flexGrow: 1, align: "left" };
|
|
49
68
|
const share: DataTableColumn = { id: "pct", label: "Share", width: wide ? 34 : medium ? 30 : 26, align: "left" };
|
|
50
|
-
|
|
69
|
+
let columns: DataTableColumn[] = [
|
|
51
70
|
name,
|
|
52
71
|
{ id: "evidence", label: "Evidence", width: 12, align: "left" },
|
|
53
72
|
...(medium ? [{ id: "ticker", label: "Ticker", width: 8, align: "left" as const }] : []),
|
|
@@ -61,40 +80,57 @@ function tableColumns(width: number, desktop: boolean, locked: boolean, valueWid
|
|
|
61
80
|
{ id: "corroboration", label: "Origins", width: 8, align: "right" as const },
|
|
62
81
|
] : []),
|
|
63
82
|
];
|
|
64
|
-
|
|
83
|
+
const preferred = { share: share.width, name: name.width };
|
|
65
84
|
// The table ignores its last trailing gutter when deciding whether it fits.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
85
|
+
const overflow = () => getTableWidth(columns) - width - 1;
|
|
86
|
+
// Native units keep their column before the share keeps its bar or basis.
|
|
87
|
+
const shareFloor = valueWidth !== null ? SHARE_BAR_MIN_CELLS + 1 : SHARE_BAR_MIN_CELLS + 1 + longestBasis(bases, preferred.share);
|
|
88
|
+
const fit = (shareMin: number, nameMin = 18) => {
|
|
89
|
+
share.width = preferred.share; name.width = preferred.name;
|
|
90
|
+
share.width = Math.max(shareMin, share.width - Math.max(0, overflow()));
|
|
91
|
+
name.width = Math.max(nameMin, name.width - Math.max(0, overflow()));
|
|
92
|
+
};
|
|
93
|
+
fit(shareFloor);
|
|
94
|
+
for (const id of ["ticker", "fy"]) {
|
|
95
|
+
if (overflow() <= 0) break;
|
|
96
|
+
if (!columns.some((column) => column.id === id)) continue;
|
|
97
|
+
columns = columns.filter((column) => column.id !== id);
|
|
98
|
+
fit(shareFloor);
|
|
69
99
|
}
|
|
100
|
+
// The narrowest panes keep the figure alone, then a shorter name, before anything scrolls.
|
|
101
|
+
if (overflow() > 0) fit(SHARE_BAR_MIN_CELLS);
|
|
102
|
+
if (overflow() > 0) fit(SHARE_FIGURE_CELLS + 2, 12);
|
|
70
103
|
return columns;
|
|
71
104
|
}
|
|
72
105
|
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Company, then the counterparties per role on this tab, with how many
|
|
108
|
+
* disclosures a free preview locks: the strip that heads the table and the flow.
|
|
109
|
+
*/
|
|
110
|
+
function supplyFigures(data: SupplyChainPayload, views: readonly ("says" | "names")[], options: Required<SupplyOptions>): StatItem[] {
|
|
76
111
|
return [
|
|
77
112
|
...(data.entity ? [{ id: "company", label: "Company", value: data.entity.name }] : []),
|
|
78
|
-
...
|
|
79
|
-
|
|
80
|
-
const count = data.truncated && !flow && !options.includeLeads ? views.reduce((total, view) => total + data.counts[view][role], 0) : visible;
|
|
81
|
-
return count ? [{ id: role, label: ROLE_PLURALS[role], value: String(count), color: ROLE_COLORS[role],
|
|
82
|
-
detail: visible < count ? `${visible} shown` : undefined }] : [];
|
|
83
|
-
}),
|
|
113
|
+
...supplyRoleCounts(data, views, options).map(({ role, counterparties, locked }) => ({ id: role, label: ROLE_PLURALS[role], value: String(counterparties),
|
|
114
|
+
color: ROLE_COLORS[role], detail: locked ? `+${locked} locked` : undefined })),
|
|
84
115
|
];
|
|
85
116
|
}
|
|
86
117
|
|
|
87
|
-
/**
|
|
88
|
-
|
|
118
|
+
/**
|
|
119
|
+
* The share as a bar on a 0 to 100% scale, the figure, and what it is a share
|
|
120
|
+
* of. The basis shows whole or not at all: a column too narrow for it keeps
|
|
121
|
+
* the bar and figure, and the evidence view says the rest.
|
|
122
|
+
*/
|
|
123
|
+
function ShareCell({ row, focusId, width, bases, selected }: { row: SupplyRow; focusId?: string; width: number; bases: readonly number[]; selected: boolean }) {
|
|
89
124
|
const colors = useThemeColors();
|
|
90
125
|
const share = shareParts(row, focusId);
|
|
91
126
|
if (!share) return <Text fg={colors.textMuted}>{""}</Text>;
|
|
92
|
-
|
|
93
|
-
|
|
127
|
+
const bar = shareBarCells(width, bases);
|
|
128
|
+
if (!bar) return <Text fg={selected ? colors.selectedText : colors.textBright} attributes={TextAttributes.BOLD}>{share.value}</Text>;
|
|
129
|
+
const basis = bar + SHARE_FIGURE_CELLS + 2 + displayWidth(share.basis) <= width;
|
|
94
130
|
return <Box flexDirection="row" width={width} height={1} gap={1} overflow="hidden">
|
|
95
|
-
<RatioBar ratio={row.pctOfRevenue! / 100} width={
|
|
96
|
-
<Text fg={selected ? colors.selectedText : colors.textBright} attributes={TextAttributes.BOLD}>{share.value.padStart(
|
|
97
|
-
<Text fg={selected ? colors.selectedText : colors.textDim}>{
|
|
131
|
+
<RatioBar ratio={row.pctOfRevenue! / 100} width={bar} color={ROLE_COLORS[row.role]} track />
|
|
132
|
+
<Text fg={selected ? colors.selectedText : colors.textBright} attributes={TextAttributes.BOLD}>{share.value.padStart(SHARE_FIGURE_CELLS)}</Text>
|
|
133
|
+
{basis ? <Text fg={selected ? colors.selectedText : colors.textDim}>{share.basis}</Text> : null}
|
|
98
134
|
</Box>;
|
|
99
135
|
}
|
|
100
136
|
|
|
@@ -180,7 +216,8 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
180
216
|
const focusId = data?.entity?.id;
|
|
181
217
|
const values = rows.filter((row) => nativeValue(row) !== null || row.usd !== null);
|
|
182
218
|
const valueWidth = values.length ? Math.min(28, Math.max(...values.map((row) => displayWidth(disclosedValue(row).replace(/ (disclosed|derived)$/, ""))))) : null;
|
|
183
|
-
const
|
|
219
|
+
const bases = rows.flatMap((row) => { const share = shareParts(row, focusId); return share ? [displayWidth(share.basis)] : []; });
|
|
220
|
+
const columns = tableColumns(width, desktop, locked > 0, valueWidth, bases);
|
|
184
221
|
const renderCell = (entry: SectionedRow<Item>, column: DataTableColumn, _index: number, state: { selected: boolean }): DataTableCell => {
|
|
185
222
|
if (!isSectionedItemRow(entry)) return { text: "" };
|
|
186
223
|
const item = entry.item;
|
|
@@ -222,7 +259,7 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
222
259
|
<Text fg={ink ?? ROLE_COLORS[row.role]}>{` ${roleLabel(row.role)}`}</Text>
|
|
223
260
|
</Box> };
|
|
224
261
|
case "pct": return { text: percentage(row) === "--" ? "" : `${shareParts(row, focusId)?.value ?? ""} ${shareParts(row, focusId)?.basis ?? ""}`.trim(), value: row.pctOfRevenue,
|
|
225
|
-
content: <ShareCell row={row} focusId={focusId} width={column.width} selected={state.selected} /> };
|
|
262
|
+
content: <ShareCell row={row} focusId={focusId} width={column.width} bases={bases} selected={state.selected} /> };
|
|
226
263
|
case "usd": return nativeValue(row) === null && row.usd === null ? { text: "", value: null }
|
|
227
264
|
: { text: disclosedValue(row).replace(/ (disclosed|derived)$/, ""), value: row.nativeAmount != null ? row.nativeAmount * (row.nativeScale ?? 1) : row.usd, color: colors.text };
|
|
228
265
|
case "fy": return { text: row.period, color: colors.textDim };
|
|
@@ -233,7 +270,7 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
233
270
|
if (graphTab) return <Box width={width} height={height} flexDirection="column">{strip}<SupplyGraphPane symbol={symbol} tab={savedTab as "graph" | "path"} width={width} height={Math.max(3, height - tabRows)} focused={focused} /></Box>;
|
|
234
271
|
if (!data && isCloudSessionRequired(resource.error)) return <SignInWall placement="supply-chain-signin" action="view supply chain disclosures" needsVerification={session.needsVerification} />;
|
|
235
272
|
const bodyHeight = Math.max(3, height - tabRows);
|
|
236
|
-
const figures = data ? supplyFigures(data, tab === "flow" ? ["says", "names"] : [view], options
|
|
273
|
+
const figures = data ? supplyFigures(data, tab === "flow" ? ["says", "names"] : [view], options) : [];
|
|
237
274
|
const tierFilter = { id: "tiers", label: "Evidence", kind: "multi" as const, emptyLabel: "Primary", values: options.tiers, options: TIER_OPTIONS, onChange: (value: string[]) => { setTiers(supplyOptions(value).tiers); setSelected(null); setOpen(null); } };
|
|
238
275
|
const header = <Box flexDirection="column" flexShrink={0}>
|
|
239
276
|
<QueryBar width={width} filters={[{ id: "direction", label: "Direction", inline: true, value: view,
|
|
@@ -263,7 +300,9 @@ function SupplyView({ symbol, width, height, focused }: Pick<PaneProps, "width"
|
|
|
263
300
|
</Box> : <DataTableView<SectionedRow<Item>> columns={columns}
|
|
264
301
|
items={items} focused={focused && !openRow} rootWidth={width} rootHeight={bodyHeight} rootBefore={header}
|
|
265
302
|
selection={{ kind: "id", selectedId: selected?.id ?? null, getId: (entry) => entry.key, onChange: (id) => setSelected(id) }} getItemKey={(entry) => entry.key}
|
|
266
|
-
isNavigable={isSectionedItemRow}
|
|
303
|
+
isNavigable={isSectionedItemRow}
|
|
304
|
+
// The placeholders stand for every locked disclosure; the header counts those, as the figures do.
|
|
305
|
+
renderSectionHeader={(entry) => entry.kind === "section" && entry.label === "Pro" ? { text: `Pro (${locked})` } : renderSectionedRowHeader(entry)}
|
|
267
306
|
onActivate={(entry) => { if (isSectionedItemRow(entry)) entry.item.kind === "edge" ? navigate(entry.item.row) : openUpgrade(); }}
|
|
268
307
|
renderCell={renderCell} sortColumnId={sort.column} sortDirection={sort.direction}
|
|
269
308
|
onHeaderClick={(column) => setSort((old) => ({ column, direction: old.column === column && old.direction === "desc" ? "asc" : "desc" }))}
|
|
@@ -6,6 +6,9 @@ import { aggregateText, DEFAULT_SORT, matchTheme, memberPrice, percent, PERIOD_L
|
|
|
6
6
|
const periods: HeadlessPaneColumn[] = THEME_PERIODS.map((key) => ({ key, header: PERIOD_LABELS[key], align: "right", format: (value) => percent(value as number | null) }));
|
|
7
7
|
export const themesHeadless: HeadlessPaneDefinition<"rows"> = {
|
|
8
8
|
shape: "rows",
|
|
9
|
+
// The pane's stored snapshot: 15-minute delayed prices, refreshed every 15 minutes. As in the pane,
|
|
10
|
+
// the payload's stale flags are historical; a snapshot over 30 minutes old is what reads stale.
|
|
11
|
+
freshness: { status: "delayed", delayMinutes: 15, maxAgeMinutes: 30, ignoreStaleFlags: true },
|
|
9
12
|
argument: { kind: "free-text", optional: true, placeholder: "theme", description: "Theme name or keyword, such as nuclear; omit for all themes." },
|
|
10
13
|
options: [],
|
|
11
14
|
discovery: { aliases: ["THEM"], dataRequirements: ["Gloom Cloud stored equity snapshot"],
|
|
@@ -8,6 +8,7 @@ import { priceColor } from "../../../theme/colors";
|
|
|
8
8
|
import { useThemeColors } from "../../../theme/theme-context";
|
|
9
9
|
import { Box, Text } from "../../../ui";
|
|
10
10
|
import { nextHeaderSort } from "../../../utils/sort-values";
|
|
11
|
+
import { useMembersMenu } from "../shared/members-menu";
|
|
11
12
|
import { cachedMembers, cachedThemes, loadMembers, loadThemes } from "./client";
|
|
12
13
|
import { aggregateText, coverageWidth, DEFAULT_SORT, matchTheme, memberColumns, memberPrice, percent, sortMembers, sortThemes, themeColumns, type ThemeSort } from "./model";
|
|
13
14
|
|
|
@@ -37,6 +38,8 @@ function Members({ id, width, height, focused }: { id: string; width: number; he
|
|
|
37
38
|
useAutoRefresh(resource.updatedAt, resource.load);
|
|
38
39
|
usePaneRefreshKey(() => void resource.reload(), { focused });
|
|
39
40
|
useSnapshotFooter("themes:members", resource, focused);
|
|
41
|
+
const memberList = useMemo(() => data ? { title: data.theme.name, watchlistName: data.theme.name, members: rows } : null, [data, rows]);
|
|
42
|
+
useMembersMenu("themes:members-menu", memberList);
|
|
40
43
|
const renderCell = useCallback((row: ThemeMember, column: DataTableColumn): DataTableCell => {
|
|
41
44
|
if (column.id === "symbol") return { text: row.symbol, color: colors.textBright };
|
|
42
45
|
if (column.id === "name") return { text: row.name ?? "--", color: colors.text };
|
|
@@ -7,7 +7,16 @@ import type {
|
|
|
7
7
|
import { formatShortDate } from "../../../utils/datetime-format";
|
|
8
8
|
import { normalizeCik } from "./api";
|
|
9
9
|
import { buildFundOverlap, overlapPeriod } from "./overlap";
|
|
10
|
-
import { appendTickerHoldings, loadCrowding, loadTickerHoldings, type TickerHoldings } from "./signals";
|
|
10
|
+
import { appendTickerHoldings, loadCrowding, loadTickerHoldings, type CrowdingRow, type TickerHoldings } from "./signals";
|
|
11
|
+
import {
|
|
12
|
+
AS_FILED_VALUE,
|
|
13
|
+
compareCrowding,
|
|
14
|
+
crowdingForTicker,
|
|
15
|
+
cutText,
|
|
16
|
+
periodText,
|
|
17
|
+
summarizeTickerHoldings,
|
|
18
|
+
THIRTEENF_MAX_LIMIT,
|
|
19
|
+
} from "./report-notes";
|
|
11
20
|
import {
|
|
12
21
|
loadBrowserRows,
|
|
13
22
|
loadFundDetail,
|
|
@@ -44,6 +53,7 @@ import type {
|
|
|
44
53
|
ThirteenFBrowserTab,
|
|
45
54
|
} from "./types";
|
|
46
55
|
import { finiteOrNull } from "../../../utils/guards";
|
|
56
|
+
import { SEC_FILINGS } from "../shared/report-freshness";
|
|
47
57
|
|
|
48
58
|
const money = (value: unknown) => formatMoneyCompact(finiteOrNull(value));
|
|
49
59
|
const weight = (value: unknown) => formatWeightMaybe(finiteOrNull(value));
|
|
@@ -65,7 +75,7 @@ const BROWSER_COLUMNS: HeadlessPaneColumn[] = [
|
|
|
65
75
|
},
|
|
66
76
|
{
|
|
67
77
|
key: "tableValueTotal",
|
|
68
|
-
header: "Value",
|
|
78
|
+
header: "Value (USD)",
|
|
69
79
|
align: "right",
|
|
70
80
|
format: (value) => formatMoneyCompact(value == null ? null : Number(value)),
|
|
71
81
|
},
|
|
@@ -83,13 +93,13 @@ const HOLDING_COLUMNS: HeadlessPaneColumn[] = [
|
|
|
83
93
|
{ key: "issuer", header: "Issuer" },
|
|
84
94
|
{
|
|
85
95
|
key: "value",
|
|
86
|
-
header: "Value",
|
|
96
|
+
header: "Value (USD)",
|
|
87
97
|
align: "right",
|
|
88
98
|
format: (value) => formatMoneyCompact(value == null ? null : Number(value)),
|
|
89
99
|
},
|
|
90
100
|
{
|
|
91
101
|
key: "estimatedPnl",
|
|
92
|
-
header: "Est P&L",
|
|
102
|
+
header: "Est P&L (USD)",
|
|
93
103
|
align: "right",
|
|
94
104
|
format: (value) => formatMoneyCompact(value == null ? null : Number(value)),
|
|
95
105
|
},
|
|
@@ -124,7 +134,7 @@ const FILING_COLUMNS: HeadlessPaneColumn[] = [
|
|
|
124
134
|
},
|
|
125
135
|
{
|
|
126
136
|
key: "tableValueTotal",
|
|
127
|
-
header: "Value",
|
|
137
|
+
header: "Value (USD)",
|
|
128
138
|
align: "right",
|
|
129
139
|
format: (value) => formatMoneyCompact(value == null ? null : Number(value)),
|
|
130
140
|
},
|
|
@@ -177,6 +187,30 @@ const defaultDependencies: ThirteenFHeadlessDependencies = {
|
|
|
177
187
|
loadDetail: (cik, name, _args, ctx) => loadFundDetail(cik, name, ctx.signal),
|
|
178
188
|
};
|
|
179
189
|
|
|
190
|
+
const VIEW_TITLES: Record<string, string> = {
|
|
191
|
+
overlap: "13F Overlap",
|
|
192
|
+
crowding: "13F Crowding",
|
|
193
|
+
"ticker-holdings": "13F Holders",
|
|
194
|
+
byTicker: "13F Holders",
|
|
195
|
+
"by-ticker": "13F Holders",
|
|
196
|
+
holdings: "13F Holdings",
|
|
197
|
+
filings: "13F Filings",
|
|
198
|
+
performance: "13F Performance",
|
|
199
|
+
funds: "13F Funds",
|
|
200
|
+
latest: "13F Latest Filings",
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/** The view a query resolved to and what it is about, never the bare `auto` it was asked as. */
|
|
204
|
+
function thirteenFTitle(args: HeadlessPaneLoadArgs, metadata: Record<string, unknown> | undefined): string {
|
|
205
|
+
const query = typeof args.argument === "string" ? args.argument.trim() : "";
|
|
206
|
+
const view = String(metadata?.view ?? args.options.view);
|
|
207
|
+
const text = (value: unknown) => (typeof value === "string" && value ? value : "");
|
|
208
|
+
const subject = view === "overlap" && metadata?.firstFund && metadata.secondFund
|
|
209
|
+
? `${text(metadata.firstFund)} vs ${text(metadata.secondFund)}`
|
|
210
|
+
: text(metadata?.ticker) || text(metadata?.fund) || (view === "latest" || view === "performance" ? "" : query);
|
|
211
|
+
return [VIEW_TITLES[view] ?? "13F Funds", subject].filter(Boolean).join(" | ");
|
|
212
|
+
}
|
|
213
|
+
|
|
180
214
|
function browserTab(view: HeadlessThirteenFView, query: string): ThirteenFBrowserTab {
|
|
181
215
|
if (view === "performance" || view === "funds" || view === "latest") return view;
|
|
182
216
|
if (view === "by-ticker") return "byTicker";
|
|
@@ -210,6 +244,7 @@ export function createThirteenFHeadless(
|
|
|
210
244
|
): HeadlessPaneDefinition<"rows"> {
|
|
211
245
|
return {
|
|
212
246
|
shape: "rows",
|
|
247
|
+
freshness: { ...SEC_FILINGS, basis: "13F filings", observedKey: "filedAsOfDate" },
|
|
213
248
|
argument: {
|
|
214
249
|
kind: "free-text",
|
|
215
250
|
placeholder: "fund, ticker, or CIK",
|
|
@@ -245,10 +280,10 @@ export function createThirteenFHeadless(
|
|
|
245
280
|
type: "integer",
|
|
246
281
|
defaultValue: 50,
|
|
247
282
|
minimum: 1,
|
|
248
|
-
maximum:
|
|
283
|
+
maximum: THIRTEENF_MAX_LIMIT,
|
|
249
284
|
},
|
|
250
285
|
],
|
|
251
|
-
describe: (args) =>
|
|
286
|
+
describe: (args, result) => thirteenFTitle(args, result?.metadata),
|
|
252
287
|
async load(args, ctx) {
|
|
253
288
|
const query = typeof args.argument === "string" ? args.argument.trim() : "";
|
|
254
289
|
const requestedView = String(args.options.view) as HeadlessThirteenFView;
|
|
@@ -264,21 +299,23 @@ export function createThirteenFHeadless(
|
|
|
264
299
|
const [first, second] = await Promise.all([dependencies.loadDetail(fund.cik, fund.name, args, ctx), dependencies.loadDetail(other.cik, other.name, args, ctx)]);
|
|
265
300
|
const comparedPeriod = overlapPeriod(first, second);
|
|
266
301
|
const rows = buildFundOverlap(first, second);
|
|
267
|
-
|
|
302
|
+
const cut = cutText(rows.length, limit, "positions");
|
|
303
|
+
return { columns: [{ key: "ticker", header: "Ticker" }, { key: "type", header: "Type" }, { key: "issuer", header: "Issuer" }, { key: "weight", header: "First weight", align: "right", format: weight }, { key: "comparedWeight", header: "Second weight", align: "right", format: weight }], rows: rows.slice(0, limit).map(row => ({ ...row })), errors: [...(first.warnings ?? []), ...(second.warnings ?? []), ...(!comparedPeriod ? ["No reporting quarter is loaded for both funds."] : [])], metadata: { view, firstFund: first.name, secondFund: second.name, firstPeriod: first.latestForm?.periodOfReport ?? null, secondPeriod: second.latestForm?.periodOfReport ?? null, comparedPeriod, shown: Math.min(rows.length, limit), total: rows.length, truncated: rows.length > limit, notices: [[comparedPeriod ? `Quarter compared: ${comparedPeriod}` : "", cut].filter(Boolean).join(" | ")].filter(Boolean) } };
|
|
268
304
|
}
|
|
269
305
|
if (view === "crowding") {
|
|
270
306
|
const { rows: sourceRows, ...metadata } = await loadCrowding(ctx.signal);
|
|
271
307
|
const rank = String(args.options.rank ?? "new");
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
metadata: { ...metadata, view, rank,
|
|
308
|
+
const ranked = [...sourceRows].sort((left, right) => compareCrowding(rank, left, right));
|
|
309
|
+
// The pane states the fund sample beside the table; the text report needs it too.
|
|
310
|
+
const sample = `${metadata.period}: ${metadata.loadedFunds}/${metadata.sourceFunds} ranked funds`;
|
|
311
|
+
const ticker = query ? query.replace(/^\$/, "").toUpperCase() : null;
|
|
312
|
+
const focus = ticker ? crowdingForTicker(ranked, ticker, rank) : null;
|
|
313
|
+
const rows: Array<CrowdingRow & { rank?: number }> = focus ? focus.rows : ranked;
|
|
314
|
+
const columns: HeadlessPaneColumn[] = [{ key: "ticker", header: "Ticker" }, { key: "issuer", header: "Issuer" }, { key: "type", header: "Type" }, { key: "holderCount", header: "Funds", align: "right" }, { key: "newCount", header: "New", align: "right" }, { key: "exitCount", header: "Exits", align: "right" }, { key: "weightChange", header: "Weight change", align: "right", format: weightPoints }, { key: "comparedFunds", header: "Compared", align: "right" }, { key: "totalValue", header: "Value (USD)", align: "right", format: money }];
|
|
315
|
+
const cut = cutText(rows.length, limit, "securities");
|
|
316
|
+
return { columns: focus ? [{ key: "rank", header: "Rank", align: "right" }, ...columns] : columns, rows: rows.slice(0, limit).map(row => ({ ...row })),
|
|
317
|
+
metadata: { ...metadata, view, rank, ...(ticker ? { ticker, found: rows.length > 0, rankedSecurities: ranked.length } : {}), shown: Math.min(rows.length, limit), total: rows.length, truncated: rows.length > limit, notices: [[sample, cut].filter(Boolean).join(" | "), ...(focus ? [focus.notice] : [])] },
|
|
318
|
+
freshness: { asOf: metadata.period }, errors: metadata.warnings };
|
|
282
319
|
}
|
|
283
320
|
let holdings: TickerHoldings | null = null;
|
|
284
321
|
if (view === "ticker-holdings") {
|
|
@@ -297,16 +334,42 @@ export function createThirteenFHeadless(
|
|
|
297
334
|
}
|
|
298
335
|
if (holdings) {
|
|
299
336
|
const { rows, ...metadata } = holdings;
|
|
300
|
-
|
|
337
|
+
const offset = Number(args.options.offset ?? 0);
|
|
338
|
+
const summary = summarizeTickerHoldings({ ...metadata, offset, limit, loaded: rows });
|
|
339
|
+
return {
|
|
340
|
+
columns: [{ key: "fund", header: "Fund" }, { key: "cik", header: "CIK" }, { key: "type", header: "Type" }, { key: "value", header: "Value (USD)", align: "right", format: money }, { key: "shares", header: "Shares", align: "right", format: shares }, { key: "weight", header: "13F weight", align: "right", format: weight }, { key: "action", header: "Action" }],
|
|
341
|
+
rows: rows.slice(0, limit).map(row => ({ ...row })),
|
|
342
|
+
metadata: {
|
|
343
|
+
...metadata,
|
|
344
|
+
view,
|
|
345
|
+
offset,
|
|
346
|
+
shown: Math.min(rows.length, limit),
|
|
347
|
+
shownFunds: summary.shownFunds,
|
|
348
|
+
total: summary.total,
|
|
349
|
+
truncated: summary.truncated,
|
|
350
|
+
hasMore: summary.truncated,
|
|
351
|
+
nextOffset: summary.nextOffset,
|
|
352
|
+
// The value of the rows shown, not of every fund a page loaded.
|
|
353
|
+
totalValue: summary.shownValue,
|
|
354
|
+
valueScope: "shown funds",
|
|
355
|
+
valueBasis: "as reported at period end",
|
|
356
|
+
notices: summary.notices,
|
|
357
|
+
},
|
|
358
|
+
freshness: { asOf: metadata.period },
|
|
359
|
+
errors: metadata.warnings,
|
|
360
|
+
};
|
|
301
361
|
}
|
|
302
362
|
|
|
303
363
|
if (view === "holdings" || view === "filings") {
|
|
304
364
|
const fund = await resolveFund(query, args, ctx, dependencies);
|
|
305
365
|
const detail = await dependencies.loadDetail(fund.cik, fund.name, args, ctx);
|
|
366
|
+
const latestPeriod = detail.latestForm?.periodOfReport ?? null;
|
|
306
367
|
if (view === "filings") {
|
|
307
|
-
const
|
|
368
|
+
const all = sortTimelineRows(buildTimelineRows(detail.forms), DEFAULT_TIMELINE_SORT);
|
|
369
|
+
const rows = all
|
|
308
370
|
.slice(0, limit)
|
|
309
371
|
.map((row) => ({ ...row }));
|
|
372
|
+
const cut = cutText(all.length, limit, "filings");
|
|
310
373
|
return {
|
|
311
374
|
columns: FILING_COLUMNS,
|
|
312
375
|
rows,
|
|
@@ -315,14 +378,21 @@ export function createThirteenFHeadless(
|
|
|
315
378
|
view,
|
|
316
379
|
cik: detail.cik,
|
|
317
380
|
fund: detail.name,
|
|
318
|
-
latestPeriod
|
|
381
|
+
latestPeriod,
|
|
382
|
+
shown: rows.length,
|
|
383
|
+
total: all.length,
|
|
384
|
+
truncated: all.length > limit,
|
|
385
|
+
notices: [[`CIK ${detail.cik}`, cut].filter(Boolean).join(" | ")],
|
|
319
386
|
},
|
|
320
387
|
};
|
|
321
388
|
}
|
|
322
|
-
const
|
|
389
|
+
const all = sortHoldingRows(
|
|
323
390
|
buildFundHoldingRows(detail),
|
|
324
391
|
DEFAULT_HOLDING_SORT,
|
|
325
|
-
)
|
|
392
|
+
);
|
|
393
|
+
const previousPeriod = detail.previousForm?.periodOfReport ?? null;
|
|
394
|
+
const cut = cutText(all.length, limit, "positions, exits included");
|
|
395
|
+
const rows = all
|
|
326
396
|
.slice(0, limit)
|
|
327
397
|
.map((row) => ({
|
|
328
398
|
...row,
|
|
@@ -333,12 +403,21 @@ export function createThirteenFHeadless(
|
|
|
333
403
|
columns: HOLDING_COLUMNS,
|
|
334
404
|
rows,
|
|
335
405
|
...(detail.warnings?.length ? { errors: detail.warnings } : {}),
|
|
406
|
+
// Positions as of the quarter they report; the rows carry no filing date.
|
|
407
|
+
...(latestPeriod ? { freshness: { asOf: latestPeriod } } : {}),
|
|
336
408
|
metadata: {
|
|
337
409
|
view,
|
|
338
410
|
cik: detail.cik,
|
|
339
411
|
fund: detail.name,
|
|
340
|
-
latestPeriod
|
|
341
|
-
previousPeriod
|
|
412
|
+
latestPeriod,
|
|
413
|
+
previousPeriod,
|
|
414
|
+
shown: rows.length,
|
|
415
|
+
total: all.length,
|
|
416
|
+
truncated: all.length > limit,
|
|
417
|
+
notices: [
|
|
418
|
+
[`CIK ${detail.cik}`, periodText(latestPeriod, hasComparable13FQuarter(detail) ? previousPeriod : null), AS_FILED_VALUE].filter(Boolean).join(" | "),
|
|
419
|
+
...(cut ? [`${cut[0]!.toUpperCase()}${cut.slice(1)}`] : []),
|
|
420
|
+
],
|
|
342
421
|
comparisonAvailable: hasComparable13FQuarter(detail),
|
|
343
422
|
currentFilings: detail.latestReport?.filings.map((form) => form.accessionNumber) ?? [],
|
|
344
423
|
previousFilings: detail.previousReport?.filings.map((form) => form.accessionNumber) ?? [],
|
|
@@ -352,6 +431,7 @@ export function createThirteenFHeadless(
|
|
|
352
431
|
|
|
353
432
|
const tab = browserTab(view === "ticker-holdings" ? requestedView : view, query);
|
|
354
433
|
const result = await dependencies.loadBrowser(tab, query, limit, args, ctx);
|
|
434
|
+
const more = result.hasMore || result.rows.length > limit;
|
|
355
435
|
return {
|
|
356
436
|
columns: result.rows[0]?.priorReturns?.length ? [...BROWSER_COLUMNS.filter(column => !["filedAsOfDate", "tableEntryTotal"].includes(column.key)), ...result.rows[0].priorReturns.map((point, index) => ({ key: `return${index + 1}`, header: point.quarter, align: "right" as const, format: (value: unknown) => formatRawPercentMaybe(typeof value === "number" ? value : null) }))]
|
|
357
437
|
: tab === "performance" ? BROWSER_COLUMNS : BROWSER_COLUMNS.filter(column => column.key !== "estQuarterReturn"),
|
|
@@ -365,6 +445,11 @@ export function createThirteenFHeadless(
|
|
|
365
445
|
period: result.period ?? null,
|
|
366
446
|
quarter: result.quarter ?? null,
|
|
367
447
|
hasMore: result.hasMore ?? false,
|
|
448
|
+
shown: Math.min(result.rows.length, limit),
|
|
449
|
+
truncated: more,
|
|
450
|
+
notices: more
|
|
451
|
+
? [[`Showing the first ${Math.min(result.rows.length, limit)}`, limit < THIRTEENF_MAX_LIMIT ? `more: --limit ${THIRTEENF_MAX_LIMIT}` : ""].filter(Boolean).join(" | ")]
|
|
452
|
+
: [],
|
|
368
453
|
},
|
|
369
454
|
};
|
|
370
455
|
},
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { CrowdingRow, TickerHolderRow } from "./signals";
|
|
2
|
+
import { formatMoneyCompact } from "./format";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Summary lines for the 13F text reports. Each says which quarters the rows
|
|
6
|
+
* compare, that values are as filed, and, whenever rows are cut, how many
|
|
7
|
+
* are shown and the option that shows the rest.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** The largest `--limit` the 13F report accepts. */
|
|
11
|
+
export const THIRTEENF_MAX_LIMIT = 200;
|
|
12
|
+
|
|
13
|
+
export const AS_FILED_VALUE = "Value (USD) as reported at period end, not today's price";
|
|
14
|
+
|
|
15
|
+
const count = (value: number) => value.toLocaleString("en-US");
|
|
16
|
+
|
|
17
|
+
export function periodText(period: string | null | undefined, previousPeriod?: string | null): string {
|
|
18
|
+
if (!period) return "";
|
|
19
|
+
return previousPeriod ? `Period ${period} vs ${previousPeriod}` : `Period ${period}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** "showing 50 of 374" from the start of the list, "showing 51-100 of 374" past it. */
|
|
23
|
+
function shownRangeText(offset: number, end: number, total: number): string {
|
|
24
|
+
return offset > 0
|
|
25
|
+
? `showing ${count(offset + 1)}-${count(end)} of ${count(total)}`
|
|
26
|
+
: `showing ${count(end)} of ${count(total)}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** "showing 50 of 104 positions | more: --limit 104"; empty when nothing is cut. */
|
|
30
|
+
export function cutText(total: number, limit: number, noun: string): string {
|
|
31
|
+
if (total <= limit) return "";
|
|
32
|
+
return [
|
|
33
|
+
`showing ${count(limit)} of ${count(total)} ${noun}`,
|
|
34
|
+
limit < THIRTEENF_MAX_LIMIT ? `more: --limit ${Math.min(THIRTEENF_MAX_LIMIT, total)}` : "",
|
|
35
|
+
].filter(Boolean).join(" | ");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface TickerHoldingsSummary {
|
|
39
|
+
notices: string[];
|
|
40
|
+
/** Funds in the list: holders, then the funds that exited. */
|
|
41
|
+
total: number;
|
|
42
|
+
/** The fund offset where the next page starts. */
|
|
43
|
+
nextOffset: number;
|
|
44
|
+
/** Funds with rows shown. */
|
|
45
|
+
shownFunds: number;
|
|
46
|
+
/** Rows follow the ones shown. */
|
|
47
|
+
truncated: boolean;
|
|
48
|
+
/** Reported value of the positions shown, exits excluded. */
|
|
49
|
+
shownValue: number | null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The ticker-holdings list ranks a quarter's holders by size, then the funds
|
|
54
|
+
* that exited. A fund can have several rows (shares, calls, puts), so pages
|
|
55
|
+
* are counted in funds.
|
|
56
|
+
*/
|
|
57
|
+
export function summarizeTickerHoldings(input: {
|
|
58
|
+
period: string;
|
|
59
|
+
previousPeriod?: string | null;
|
|
60
|
+
holderCount: number;
|
|
61
|
+
newCount?: number | null;
|
|
62
|
+
exitCount?: number | null;
|
|
63
|
+
offset: number;
|
|
64
|
+
limit: number;
|
|
65
|
+
/** Rows of the pages loaded from `offset`, in list order. */
|
|
66
|
+
loaded: readonly Pick<TickerHolderRow, "cik" | "value" | "action">[];
|
|
67
|
+
/** The source has pages after the loaded ones, from `nextOffset`. */
|
|
68
|
+
hasMore: boolean;
|
|
69
|
+
nextOffset: number;
|
|
70
|
+
}): TickerHoldingsSummary {
|
|
71
|
+
const shownRows = input.loaded.slice(0, input.limit);
|
|
72
|
+
const funds = [...new Set(shownRows.map((row) => row.cik))];
|
|
73
|
+
const cut = input.loaded.length > shownRows.length;
|
|
74
|
+
const lastCut = cut && input.loaded[shownRows.length]?.cik === shownRows.at(-1)?.cik;
|
|
75
|
+
// A fund whose holdings could not be read keeps its place in the source's
|
|
76
|
+
// list without rows, so a cut page restarts after the funds shown whole:
|
|
77
|
+
// that can repeat a few, never skip one.
|
|
78
|
+
const nextOffset = cut ? input.offset + Math.max(1, funds.length - (lastCut ? 1 : 0)) : input.nextOffset;
|
|
79
|
+
const truncated = cut || input.hasMore;
|
|
80
|
+
const partial = truncated || input.offset > 0;
|
|
81
|
+
const compared = !!input.previousPeriod;
|
|
82
|
+
const exits = compared ? input.exitCount ?? 0 : 0;
|
|
83
|
+
const listed = input.holderCount + exits;
|
|
84
|
+
// The source's next offset steps a whole page, past the end of the list on the last one.
|
|
85
|
+
const total = truncated ? Math.max(listed, nextOffset + 1) : Math.max(listed, input.offset + funds.length);
|
|
86
|
+
const end = !truncated ? total : cut ? input.offset + funds.length : nextOffset;
|
|
87
|
+
const shownValue = shownRows
|
|
88
|
+
.filter((row) => row.action !== "exit")
|
|
89
|
+
.reduce<number | null>((sum, row) => (sum != null && row.value != null ? sum + row.value : null), 0);
|
|
90
|
+
const holders = [
|
|
91
|
+
`${count(input.holderCount)} holders`,
|
|
92
|
+
compared && input.newCount != null ? ` (${count(input.newCount)} new)` : "",
|
|
93
|
+
compared && input.exitCount != null ? `, ${count(input.exitCount)} exited` : "",
|
|
94
|
+
!partial && shownValue ? `, total ${formatMoneyCompact(shownValue)}` : "",
|
|
95
|
+
].join("");
|
|
96
|
+
const notices = [[periodText(input.period, input.previousPeriod), holders, AS_FILED_VALUE].filter(Boolean).join(" | ")];
|
|
97
|
+
if (partial) {
|
|
98
|
+
const shown = [
|
|
99
|
+
`${shownRangeText(input.offset, end, total)} funds`,
|
|
100
|
+
exits > 0 ? ", exits last" : "",
|
|
101
|
+
shownValue ? `; the ${count(funds.length)} shown hold ${formatMoneyCompact(shownValue)}` : "",
|
|
102
|
+
].join("");
|
|
103
|
+
// The limit counts rows and a fund can have several, so the larger page is the safe suggestion.
|
|
104
|
+
const more = truncated
|
|
105
|
+
? `more: --offset ${nextOffset}${input.limit < THIRTEENF_MAX_LIMIT ? ` or --limit ${THIRTEENF_MAX_LIMIT}` : ""}`
|
|
106
|
+
: null;
|
|
107
|
+
notices.push([`${shown[0]!.toUpperCase()}${shown.slice(1)}`, more].filter(Boolean).join(" | "));
|
|
108
|
+
}
|
|
109
|
+
return { notices, total, nextOffset, shownFunds: funds.length, truncated, shownValue };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
type CrowdingRank = "new" | "exits" | "increases" | "decreases";
|
|
113
|
+
|
|
114
|
+
const RANK_LABELS: Record<CrowdingRank, string> = {
|
|
115
|
+
new: "new holders",
|
|
116
|
+
exits: "exits",
|
|
117
|
+
increases: "weight increase",
|
|
118
|
+
decreases: "weight decrease",
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export function compareCrowding(rank: string, left: CrowdingRow, right: CrowdingRow): number {
|
|
122
|
+
if (rank === "new") return right.newCount - left.newCount;
|
|
123
|
+
if (rank === "exits") return right.exitCount - left.exitCount;
|
|
124
|
+
if (left.weightChange == null) return right.weightChange == null ? 0 : 1;
|
|
125
|
+
if (right.weightChange == null) return -1;
|
|
126
|
+
return (left.weightChange - right.weightChange) * (rank === "decreases" ? 1 : -1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* One ticker's place in the crowding ranking. Ties share a rank, so the
|
|
131
|
+
* number is how many securities rank strictly ahead, plus one.
|
|
132
|
+
*/
|
|
133
|
+
export function crowdingForTicker(
|
|
134
|
+
ranked: readonly CrowdingRow[],
|
|
135
|
+
ticker: string,
|
|
136
|
+
rank: string,
|
|
137
|
+
): { rows: Array<CrowdingRow & { rank: number }>; notice: string } {
|
|
138
|
+
const label = RANK_LABELS[rank as CrowdingRank] ?? rank;
|
|
139
|
+
const rows = ranked
|
|
140
|
+
.filter((row) => row.ticker.toUpperCase() === ticker)
|
|
141
|
+
.map((row) => ({ ...row, rank: 1 + ranked.filter((other) => compareCrowding(rank, other, row) < 0).length }));
|
|
142
|
+
const of = `of ${count(ranked.length)} securities by ${label}`;
|
|
143
|
+
const notice = rows.length === 0
|
|
144
|
+
? `${ticker} is not in this ranking | full ranking: fn 13F --view crowding | its 13F holders: fn 13F ${ticker}`
|
|
145
|
+
: rows.length === 1
|
|
146
|
+
? `${ticker} ranks ${count(rows[0]!.rank)} ${of} | full ranking: fn 13F --view crowding`
|
|
147
|
+
: `${ticker} ranks ${rows.map((row) => `${count(row.rank)} (${row.type})`).join(", ")} ${of} | full ranking: fn 13F --view crowding`;
|
|
148
|
+
return { rows, notice };
|
|
149
|
+
}
|
|
@@ -166,10 +166,14 @@ function aggregateQuarterlyStatements(
|
|
|
166
166
|
}
|
|
167
167
|
const currencies = new Set(statements.map((statement) => statement.currency));
|
|
168
168
|
if (currencies.size > 1) return null;
|
|
169
|
+
// Its counts and EPS are on the quarters' share basis when all four state the same one.
|
|
170
|
+
const shareBases = new Set(statements.map((statement) => statement.shareBasis));
|
|
171
|
+
const shareBasis = shareBases.size === 1 ? [...shareBases][0] : undefined;
|
|
169
172
|
|
|
170
173
|
const aggregate: FinancialTableStatement = {
|
|
171
174
|
date,
|
|
172
175
|
currency: [...currencies][0],
|
|
176
|
+
...(shareBasis ? { shareBasis } : {}),
|
|
173
177
|
aggregation: {
|
|
174
178
|
kind: "trailing-four-quarters",
|
|
175
179
|
periodEnd: statements.at(-1)!.date,
|