gloomberb 0.15.7 → 0.16.0
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 +11 -2
- package/package.json +1 -1
- package/src/api-client/app-attention.ts +147 -0
- package/src/api-client/attention.ts +26 -0
- package/src/api-client/awards.ts +215 -0
- package/src/api-client/catalysts.ts +160 -0
- package/src/api-client/chat.ts +137 -14
- package/src/api-client/company-kpis.ts +153 -0
- package/src/api-client/cpi.ts +52 -0
- package/src/api-client/credit-documents.ts +107 -0
- package/src/api-client/data.ts +192 -3
- package/src/api-client/distress.ts +164 -0
- package/src/api-client/doe.ts +75 -0
- package/src/api-client/equity-screener.ts +11 -0
- package/src/api-client/exposure.ts +202 -0
- package/src/api-client/gpu.ts +93 -0
- package/src/api-client/hiring.ts +110 -0
- package/src/api-client/index.ts +78 -3
- package/src/api-client/normalizers.ts +31 -1
- package/src/api-client/paths.ts +3 -0
- package/src/api-client/perps.ts +127 -0
- package/src/api-client/power.ts +148 -0
- package/src/api-client/request.ts +58 -1
- package/src/api-client/research-activity.ts +172 -13
- package/src/api-client/socket.ts +75 -27
- package/src/api-client/supply-chain-graph.ts +40 -0
- package/src/api-client/supply-chain.ts +98 -0
- package/src/api-client/telemetry.ts +29 -0
- package/src/api-client/themes.ts +28 -0
- package/src/api-client/types.ts +33 -1
- package/src/api-client/wall-experiments.ts +100 -0
- package/src/api-client/wall-summary.ts +49 -0
- package/src/api-client/web-experiments.ts +136 -0
- package/src/app/pane-runtime/plugin-bindings.ts +5 -0
- package/src/app/pane-runtime/ticker-open-runtime.ts +8 -2
- package/src/app/runtime/update.ts +13 -1
- package/src/cli/commands/system.ts +2 -0
- package/src/cli/desktop-pane-shot.ts +3 -4
- package/src/cli/pane-functions/data.ts +78 -0
- package/src/cli/pane-functions/financial-ratio-shot.ts +160 -0
- package/src/cli/pane-functions/function-help.ts +220 -8
- package/src/cli/pane-functions/headless.ts +4 -0
- package/src/cli/pane-functions/screenshot-evidence.ts +21 -0
- package/src/cli/pane-functions/screenshot.ts +49 -5
- package/src/components/chart/composite/composite-chart.tsx +15 -2
- package/src/components/chart/composite/format.ts +24 -11
- package/src/components/chart/composite/rasterizer.ts +67 -16
- package/src/components/chart/composite/scene.ts +53 -2
- package/src/components/chart/composite/session-shading.ts +3 -2
- package/src/components/chart/composite/text-renderer.ts +52 -1
- package/src/components/chart/composite/time-axis.ts +100 -30
- package/src/components/chart/composite/tools.ts +2 -1
- package/src/components/chart/composite/types.ts +4 -0
- package/src/components/chart-table/index.ts +1 -0
- package/src/components/chart-table/layout.ts +15 -0
- package/src/components/command-bar/action-runtime.ts +1 -0
- package/src/components/command-bar/commands/direct/index.ts +32 -0
- package/src/components/command-bar/commands/registry.ts +7 -0
- package/src/components/command-bar/pane-templates/items.ts +11 -0
- package/src/components/command-bar/pane-templates/workflow.ts +19 -4
- package/src/components/command-bar/routes/root/command-items.ts +6 -0
- package/src/components/command-bar/routes/root/provider-search.ts +2 -0
- package/src/components/command-bar/routes/root/results.ts +64 -0
- package/src/components/command-bar/routes/root/runtime.ts +8 -0
- package/src/components/command-bar/routes/ticker-search/results.ts +89 -24
- package/src/components/command-bar/routes/ticker-search/route.ts +2 -0
- package/src/components/command-bar/surface/index.tsx +15 -0
- package/src/components/command-bar/view-model.ts +3 -0
- package/src/components/command-bar/workflow/collection-actions.ts +9 -7
- package/src/components/command-bar/workflow/ops.ts +19 -0
- package/src/components/command-bar/workflow/tickers.ts +5 -0
- package/src/components/company-logo.tsx +15 -2
- package/src/components/data-table/table-pane.ts +2 -1
- package/src/components/index.ts +1 -0
- package/src/components/layout/detached-pane-shell.tsx +12 -1
- package/src/components/layout/missing-pane.tsx +87 -23
- package/src/components/layout/pane/footer/index.tsx +64 -18
- package/src/components/layout/pane/footer/model.ts +85 -0
- package/src/components/layout/pane/sidebar.tsx +19 -1
- package/src/components/layout/shell/index.tsx +38 -28
- package/src/components/layout/shell/pane/management-shortcuts.ts +13 -1
- package/src/components/layout/status-bar.tsx +93 -28
- package/src/components/layout/status-widget-space.ts +72 -0
- package/src/components/onboarding/first-run-workspace.ts +8 -2
- package/src/components/onboarding/onboarding-wizard.tsx +35 -16
- package/src/components/onboarding/portfolio-step/positions-panel.tsx +14 -5
- package/src/components/onboarding/wizard-model.ts +13 -5
- package/src/components/onboarding/wizard-positions.ts +56 -7
- package/src/components/price-performance.tsx +31 -34
- package/src/components/ui/data-table/index.tsx +11 -8
- package/src/components/ui/display.tsx +15 -6
- package/src/components/ui/fields.tsx +5 -0
- package/src/components/ui/figure.tsx +94 -0
- package/src/components/ui/header-case.ts +25 -3
- package/src/components/ui/icon.tsx +3 -1
- package/src/components/ui/message-composer.tsx +8 -1
- package/src/components/ui/query-bar.tsx +8 -1
- package/src/components/ui/ratio-bar.tsx +84 -0
- package/src/components/ui/toggle.tsx +3 -1
- package/src/components/use-scrollbox-layout.ts +17 -0
- package/src/core/state/app/layout.ts +35 -1
- package/src/core/state/app/state.ts +15 -0
- package/src/core/state/app/types.ts +1 -0
- package/src/data/config/store/normalize.ts +24 -0
- package/src/i18n/es.ts +2 -0
- package/src/i18n/ja.ts +2 -0
- package/src/i18n/ko.ts +2 -0
- package/src/i18n/zh-cn.ts +2 -0
- package/src/i18n/zh-tw.ts +2 -0
- package/src/layout-marketplace/pane-imagery.ts +1 -0
- package/src/market-data/coordinator/entries.ts +13 -0
- package/src/market-data/coordinator/financials.ts +33 -8
- package/src/market-data/market/freshness.ts +16 -5
- package/src/market-data/market/trading-sessions.ts +65 -1
- package/src/market-data/published-cn-sessions.ts +25 -0
- package/src/market-data/published-nse-sessions.ts +20 -0
- package/src/news/aggregator.ts +4 -0
- package/src/plugins/builtin/account-management/model.ts +6 -1
- package/src/plugins/builtin/account-management/pane.tsx +36 -25
- package/src/plugins/builtin/alerts/catalysts.ts +77 -0
- package/src/plugins/builtin/alerts/events-pane.tsx +3 -0
- package/src/plugins/builtin/alerts/events.ts +10 -4
- package/src/plugins/builtin/alerts/history-pane.tsx +1 -1
- package/src/plugins/builtin/alerts/history.ts +1 -0
- package/src/plugins/builtin/alerts/index.tsx +6 -0
- package/src/plugins/builtin/alerts/research-builder.ts +10 -3
- package/src/plugins/builtin/alerts/research-rules.ts +15 -1
- package/src/plugins/builtin/analytics/risk-client.ts +15 -3
- package/src/plugins/builtin/analytics/risk-headless.ts +123 -18
- package/src/plugins/builtin/attention/client.ts +80 -0
- package/src/plugins/builtin/attention/evidence.ts +30 -0
- package/src/plugins/builtin/attention/headless.ts +33 -0
- package/src/plugins/builtin/attention/index.tsx +18 -0
- package/src/plugins/builtin/attention/model.ts +59 -0
- package/src/plugins/builtin/attention/pane.tsx +211 -0
- package/src/plugins/builtin/attention/trending.tsx +59 -0
- package/src/plugins/builtin/awards/alerts.ts +32 -0
- package/src/plugins/builtin/awards/client.ts +82 -0
- package/src/plugins/builtin/awards/detail.tsx +107 -0
- package/src/plugins/builtin/awards/evidence.ts +36 -0
- package/src/plugins/builtin/awards/headless.ts +55 -0
- package/src/plugins/builtin/awards/index.tsx +20 -0
- package/src/plugins/builtin/awards/model.ts +42 -0
- package/src/plugins/builtin/awards/pane.tsx +263 -0
- package/src/plugins/builtin/catalysts/client.ts +28 -0
- package/src/plugins/builtin/catalysts/detail.tsx +88 -0
- package/src/plugins/builtin/catalysts/evidence.ts +47 -0
- package/src/plugins/builtin/catalysts/headless.ts +42 -0
- package/src/plugins/builtin/catalysts/history.ts +26 -0
- package/src/plugins/builtin/catalysts/index.tsx +29 -0
- package/src/plugins/builtin/catalysts/model.ts +135 -0
- package/src/plugins/builtin/catalysts/pane.tsx +159 -0
- package/src/plugins/builtin/chart-composer/cli-options.ts +4 -0
- package/src/plugins/builtin/chart-composer/headless-schema.ts +6 -0
- package/src/plugins/builtin/chart-composer/index.tsx +8 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +28 -1
- package/src/plugins/builtin/chat/attachments/desktop.tsx +610 -0
- package/src/plugins/builtin/chat/attachments/files.ts +45 -0
- package/src/plugins/builtin/chat/attachments/model.ts +164 -0
- package/src/plugins/builtin/chat/attachments/terminal.tsx +72 -0
- package/src/plugins/builtin/chat/attachments/transfer.ts +165 -0
- package/src/plugins/builtin/chat/content/channel-navigation.ts +13 -12
- package/src/plugins/builtin/chat/content/composer-runtime.ts +25 -4
- package/src/plugins/builtin/chat/content/composer.tsx +46 -4
- package/src/plugins/builtin/chat/content/footer.tsx +46 -8
- package/src/plugins/builtin/chat/content/index.tsx +263 -62
- package/src/plugins/builtin/chat/content/layout-metrics.ts +10 -2
- package/src/plugins/builtin/chat/content/open-targets.ts +17 -3
- package/src/plugins/builtin/chat/content/scroll.ts +7 -1
- package/src/plugins/builtin/chat/content/shortcuts.ts +36 -11
- package/src/plugins/builtin/chat/content/snapshot.ts +3 -0
- package/src/plugins/builtin/chat/content/transcript.tsx +17 -1
- package/src/plugins/builtin/chat/content/types.ts +7 -0
- package/src/plugins/builtin/chat/controller/attachments.ts +213 -0
- package/src/plugins/builtin/chat/controller/connections.ts +3 -1
- package/src/plugins/builtin/chat/controller/index.ts +114 -2
- package/src/plugins/builtin/chat/controller/lifecycle.ts +9 -0
- package/src/plugins/builtin/chat/controller/messages.ts +35 -2
- package/src/plugins/builtin/chat/controller/send.ts +128 -25
- package/src/plugins/builtin/chat/controller/state.ts +12 -1
- package/src/plugins/builtin/chat/controller/utils.ts +7 -5
- package/src/plugins/builtin/chat/controller/view.ts +2 -0
- package/src/plugins/builtin/chat/index.tsx +21 -0
- package/src/plugins/builtin/chat/layout.ts +9 -4
- package/src/plugins/builtin/chat/message/desktop.tsx +55 -20
- package/src/plugins/builtin/chat/message/header.tsx +30 -5
- package/src/plugins/builtin/chat/message/inline-tokens.tsx +9 -0
- package/src/plugins/builtin/chat/message/pending-send.ts +35 -0
- package/src/plugins/builtin/chat/message/profile-popover.tsx +5 -1
- package/src/plugins/builtin/chat/message/render-state.ts +12 -2
- package/src/plugins/builtin/chat/message/terminal.tsx +51 -4
- package/src/plugins/builtin/chat/message/types.ts +6 -1
- package/src/plugins/builtin/chat/pane-state.ts +59 -1
- package/src/plugins/builtin/chat/profile-popover.ts +50 -1
- package/src/plugins/builtin/chat/sidebar.tsx +8 -3
- package/src/plugins/builtin/chat/status-widget.tsx +29 -12
- package/src/plugins/builtin/chat/unread-inbox-pane.tsx +143 -0
- package/src/plugins/builtin/chat/unread-inbox.ts +91 -0
- package/src/plugins/builtin/clinical-trials/client.ts +237 -0
- package/src/plugins/builtin/clinical-trials/index.tsx +74 -0
- package/src/plugins/builtin/clinical-trials/pane.tsx +225 -0
- package/src/plugins/builtin/clinical-trials/types.ts +2 -0
- package/src/plugins/builtin/cloud/askg/controller.ts +37 -6
- package/src/plugins/builtin/cloud/askg/executor.ts +59 -44
- package/src/plugins/builtin/cloud/askg/host.ts +8 -1
- package/src/plugins/builtin/cloud/askg/manifest.ts +29 -2
- package/src/plugins/builtin/cloud/askg/model.ts +47 -13
- package/src/plugins/builtin/cloud/askg/notes.ts +100 -0
- package/src/plugins/builtin/cloud/askg/pane.tsx +50 -14
- package/src/plugins/builtin/cloud/askg/protocol.ts +39 -1
- package/src/plugins/builtin/cloud/askg/result-budget.ts +156 -0
- package/src/plugins/builtin/cloud/askg/user-data.ts +89 -0
- package/src/plugins/builtin/cloud/auth-actions.tsx +55 -31
- package/src/plugins/builtin/cloud/plugin.tsx +4 -1
- package/src/plugins/builtin/cloud/team/pane-sections.tsx +10 -1
- package/src/plugins/builtin/cloud/team/pane.tsx +3 -2
- package/src/plugins/builtin/cloud/thesis/board-pane.tsx +2 -2
- package/src/plugins/builtin/cloud/thesis/detail.tsx +1 -1
- package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +2 -2
- package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +202 -0
- package/src/plugins/builtin/cloud/upgrade-command.ts +1 -1
- package/src/plugins/builtin/cloud/upgrade-dialog.tsx +29 -3
- package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +1 -1
- package/src/plugins/builtin/cloud-tweets/table.tsx +1 -1
- package/src/plugins/builtin/comment-letters/client.ts +342 -0
- package/src/plugins/builtin/comment-letters/index.tsx +74 -0
- package/src/plugins/builtin/comment-letters/pane.tsx +295 -0
- package/src/plugins/builtin/comment-letters/types.ts +43 -0
- package/src/plugins/builtin/company-attention/app-rank.tsx +79 -0
- package/src/plugins/builtin/company-attention/client.ts +69 -0
- package/src/plugins/builtin/company-attention/evidence.ts +45 -0
- package/src/plugins/builtin/company-attention/headless.ts +47 -0
- package/src/plugins/builtin/company-attention/index.tsx +30 -0
- package/src/plugins/builtin/company-attention/model.ts +129 -0
- package/src/plugins/builtin/company-attention/pane.tsx +183 -0
- package/src/plugins/builtin/company-kpis/client.ts +92 -0
- package/src/plugins/builtin/company-kpis/headless.ts +32 -0
- package/src/plugins/builtin/company-kpis/index.tsx +26 -0
- package/src/plugins/builtin/company-kpis/model.ts +124 -0
- package/src/plugins/builtin/company-kpis/pane.tsx +226 -0
- package/src/plugins/builtin/company-kpis/related.ts +11 -0
- package/src/plugins/builtin/company-kpis/screenshot-evidence.ts +44 -0
- package/src/plugins/builtin/composite-plugins.ts +34 -0
- package/src/plugins/builtin/correlation/history.ts +4 -1
- package/src/plugins/builtin/correlation/index.tsx +139 -80
- package/src/plugins/builtin/correlation/matrix/pair-chart.tsx +48 -0
- package/src/plugins/builtin/correlation/matrix/selection.ts +77 -0
- package/src/plugins/builtin/correlation/relationship/model.ts +2 -2
- package/src/plugins/builtin/cpi/client.ts +66 -0
- package/src/plugins/builtin/cpi/headless.ts +78 -0
- package/src/plugins/builtin/cpi/index.tsx +31 -0
- package/src/plugins/builtin/cpi/model.ts +198 -0
- package/src/plugins/builtin/cpi/pane.tsx +157 -0
- package/src/plugins/builtin/credit-documents/client.ts +99 -0
- package/src/plugins/builtin/credit-documents/detail.tsx +109 -0
- package/src/plugins/builtin/credit-documents/evidence.ts +64 -0
- package/src/plugins/builtin/credit-documents/gauge.tsx +55 -0
- package/src/plugins/builtin/credit-documents/headless.ts +40 -0
- package/src/plugins/builtin/credit-documents/index.tsx +19 -0
- package/src/plugins/builtin/credit-documents/model.ts +336 -0
- package/src/plugins/builtin/credit-documents/pane.tsx +185 -0
- package/src/plugins/builtin/custom-view/view-spec.ts +14 -2
- package/src/plugins/builtin/debt-maturities/pane.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/doe/client.ts +73 -0
- package/src/plugins/builtin/doe/headless.ts +93 -0
- package/src/plugins/builtin/doe/index.tsx +41 -0
- package/src/plugins/builtin/doe/model.ts +215 -0
- package/src/plugins/builtin/doe/pane.tsx +148 -0
- package/src/plugins/builtin/doe/range-bar.tsx +45 -0
- package/src/plugins/builtin/earnings/board.tsx +3 -0
- package/src/plugins/builtin/earnings/index.tsx +2 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +7 -1
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +7 -7
- package/src/plugins/builtin/earnings-ripple/client.ts +60 -0
- package/src/plugins/builtin/earnings-ripple/headless.ts +35 -0
- package/src/plugins/builtin/earnings-ripple/index.tsx +35 -0
- package/src/plugins/builtin/earnings-ripple/model.ts +98 -0
- package/src/plugins/builtin/earnings-ripple/pane.tsx +103 -0
- package/src/plugins/builtin/equity-screener/client.ts +1 -1
- package/src/plugins/builtin/equity-screener/criterion-editor.tsx +1 -1
- package/src/plugins/builtin/equity-screener/model.ts +74 -9
- package/src/plugins/builtin/equity-screener/pane.tsx +2 -0
- package/src/plugins/builtin/estimate-revisions/pane.tsx +3 -0
- package/src/plugins/builtin/executives/pane.tsx +7 -5
- package/src/plugins/builtin/exposure/charts.tsx +66 -0
- package/src/plugins/builtin/exposure/client.ts +53 -0
- package/src/plugins/builtin/exposure/drivers.ts +29 -0
- package/src/plugins/builtin/exposure/editor.tsx +61 -0
- package/src/plugins/builtin/exposure/evidence.ts +39 -0
- package/src/plugins/builtin/exposure/headless.ts +51 -0
- package/src/plugins/builtin/exposure/holdings.ts +56 -0
- package/src/plugins/builtin/exposure/index.tsx +13 -0
- package/src/plugins/builtin/exposure/model.ts +104 -0
- package/src/plugins/builtin/exposure/pane.tsx +247 -0
- package/src/plugins/builtin/fear-greed/charts.tsx +1 -1
- package/src/plugins/builtin/fear-greed/pane.tsx +2 -9
- package/src/plugins/builtin/filing-events/pane.tsx +2 -1
- package/src/plugins/builtin/gpu/board.tsx +163 -0
- package/src/plugins/builtin/gpu/changes.tsx +94 -0
- package/src/plugins/builtin/gpu/client.ts +130 -0
- package/src/plugins/builtin/gpu/equities.tsx +112 -0
- package/src/plugins/builtin/gpu/headless.ts +67 -0
- package/src/plugins/builtin/gpu/history.tsx +140 -0
- package/src/plugins/builtin/gpu/index.tsx +18 -0
- package/src/plugins/builtin/gpu/ladder.tsx +127 -0
- package/src/plugins/builtin/gpu/model.ts +317 -0
- package/src/plugins/builtin/gpu/pane.tsx +63 -0
- package/src/plugins/builtin/help/index.tsx +19 -2
- package/src/plugins/builtin/holders/pane.tsx +5 -9
- package/src/plugins/builtin/insider/detail.tsx +119 -0
- package/src/plugins/builtin/insider/display.ts +221 -0
- package/src/plugins/builtin/insider/headless.ts +24 -3
- package/src/plugins/builtin/insider/index.tsx +206 -108
- package/src/plugins/builtin/insider/insider-data.ts +31 -3
- package/src/plugins/builtin/insider/model.ts +53 -4
- package/src/plugins/builtin/insider/table-model.ts +226 -0
- package/src/plugins/builtin/insider/table.tsx +79 -0
- package/src/plugins/builtin/iv-history/screen-pane.tsx +1 -1
- package/src/plugins/builtin/jobs/pane.tsx +14 -7
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/macro-day/client.ts +50 -0
- package/src/plugins/builtin/macro-day/headless.ts +51 -0
- package/src/plugins/builtin/macro-day/index.tsx +21 -0
- package/src/plugins/builtin/macro-day/model.ts +137 -0
- package/src/plugins/builtin/macro-day/pane.tsx +118 -0
- package/src/plugins/builtin/macro-day/releases.ts +58 -0
- package/src/plugins/builtin/market-halts/model.ts +30 -17
- package/src/plugins/builtin/market-halts/pane.tsx +15 -21
- package/src/plugins/builtin/market-heatmap/data.ts +1 -1
- package/src/plugins/builtin/market-heatmap/index.tsx +198 -50
- package/src/plugins/builtin/market-heatmap/portfolio.ts +220 -0
- package/src/plugins/builtin/market-movers/index.tsx +1 -0
- package/src/plugins/builtin/market-movers/session-body.tsx +5 -2
- package/src/plugins/builtin/mna/distress/client.ts +326 -0
- package/src/plugins/builtin/mna/distress/detail.tsx +247 -0
- package/src/plugins/builtin/mna/distress/headless.ts +257 -0
- package/src/plugins/builtin/mna/distress/model.ts +427 -0
- package/src/plugins/builtin/mna/distress/pane.tsx +606 -0
- package/src/plugins/builtin/mna/index.tsx +15 -0
- package/src/plugins/builtin/mna/pane.tsx +42 -1
- package/src/plugins/builtin/news/index.tsx +62 -16
- package/src/plugins/builtin/news/wire/filter-articles.ts +54 -0
- package/src/plugins/builtin/news/wire/index.tsx +37 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +29 -13
- package/src/plugins/builtin/news/wire/mutes.ts +253 -0
- package/src/plugins/builtin/news/wire/news/command-bar-search.ts +117 -0
- package/src/plugins/builtin/news/wire/news/footer.ts +4 -0
- package/src/plugins/builtin/news/wire/news/list-search.ts +34 -0
- package/src/plugins/builtin/news/wire/news/pop-out.tsx +158 -0
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +64 -19
- package/src/plugins/builtin/openfda/client.ts +300 -0
- package/src/plugins/builtin/openfda/index.tsx +71 -0
- package/src/plugins/builtin/openfda/pane.tsx +382 -0
- package/src/plugins/builtin/openfda/types.ts +76 -0
- package/src/plugins/builtin/options/footer.ts +1 -0
- package/src/plugins/builtin/options/view.tsx +1 -1
- package/src/plugins/builtin/options-calculator/pane.tsx +0 -1
- package/src/plugins/builtin/options-positioning/index.tsx +4 -2
- package/src/plugins/builtin/options-positioning/pane.tsx +1 -1
- package/src/plugins/builtin/pe-band/client.ts +61 -0
- package/src/plugins/builtin/pe-band/headless.ts +51 -0
- package/src/plugins/builtin/pe-band/index.tsx +20 -0
- package/src/plugins/builtin/pe-band/model.ts +267 -0
- package/src/plugins/builtin/pe-band/pane.tsx +159 -0
- package/src/plugins/builtin/perps/client.ts +66 -0
- package/src/plugins/builtin/perps/equity-row.tsx +28 -0
- package/src/plugins/builtin/perps/headless.ts +34 -0
- package/src/plugins/builtin/perps/index.tsx +14 -0
- package/src/plugins/builtin/perps/model.ts +58 -0
- package/src/plugins/builtin/perps/pane.tsx +185 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +0 -1
- package/src/plugins/builtin/portfolio-list/cli/render.ts +177 -87
- package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +6 -20
- package/src/plugins/builtin/portfolio-list/command-bar.ts +6 -2
- package/src/plugins/builtin/portfolio-list/headless.ts +237 -0
- package/src/plugins/builtin/portfolio-list/index.tsx +2 -0
- package/src/plugins/builtin/portfolio-list/mutations.ts +70 -1
- package/src/plugins/builtin/portfolio-list/pane/data.ts +17 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +88 -5
- package/src/plugins/builtin/portfolio-list/pane/remove-ticker.ts +85 -0
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +18 -12
- package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +6 -0
- package/src/plugins/builtin/power/client.ts +100 -0
- package/src/plugins/builtin/power/detail.tsx +82 -0
- package/src/plugins/builtin/power/evidence.ts +56 -0
- package/src/plugins/builtin/power/generation.tsx +37 -0
- package/src/plugins/builtin/power/headless.ts +43 -0
- package/src/plugins/builtin/power/index.tsx +16 -0
- package/src/plugins/builtin/power/model.ts +89 -0
- package/src/plugins/builtin/power/pane.tsx +209 -0
- package/src/plugins/builtin/power/query.ts +25 -0
- package/src/plugins/builtin/relative-rotation/pane.tsx +3 -3
- package/src/plugins/builtin/research/analyst-pane.tsx +1 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +13 -4
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +11 -9
- package/src/plugins/builtin/research-search/pane.tsx +21 -7
- package/src/plugins/builtin/revenue-breakdown/pane.tsx +1 -1
- package/src/plugins/builtin/reverse-dcf/client.ts +35 -0
- package/src/plugins/builtin/reverse-dcf/headless.ts +44 -0
- package/src/plugins/builtin/reverse-dcf/index.tsx +20 -0
- package/src/plugins/builtin/reverse-dcf/model.ts +87 -0
- package/src/plugins/builtin/reverse-dcf/pane.tsx +107 -0
- package/src/plugins/builtin/risk-factors/pane.tsx +6 -5
- package/src/plugins/builtin/scanner/denied.tsx +4 -2
- package/src/plugins/builtin/scanner/feed.ts +1 -0
- package/src/plugins/builtin/scanner/flow-pane.tsx +3 -2
- package/src/plugins/builtin/scanner/hilo-pane.tsx +1 -1
- package/src/plugins/builtin/seasonality/client.ts +4 -1
- package/src/plugins/builtin/sec/command-bar-search.ts +217 -0
- package/src/plugins/builtin/sec/forms.ts +54 -0
- package/src/plugins/builtin/sec/headless.ts +31 -5
- package/src/plugins/builtin/sec/index.tsx +67 -11
- package/src/plugins/builtin/sec/model.ts +35 -5
- package/src/plugins/builtin/sectors/headless.ts +1 -0
- package/src/plugins/builtin/sectors/index.tsx +72 -26
- package/src/plugins/builtin/shared/cloud-upgrade.ts +143 -39
- package/src/plugins/builtin/shared/pro-feature-wall.tsx +8 -4
- package/src/plugins/builtin/shared/research-cells.tsx +107 -0
- package/src/plugins/builtin/shared/series-list-detail.tsx +5 -1
- package/src/plugins/builtin/shared/ticker-request.ts +1 -1
- package/src/plugins/builtin/shared/wall-teaser-catalog.ts +80 -0
- package/src/plugins/builtin/shared/wall-teaser.tsx +192 -0
- package/src/plugins/builtin/shared/wall-view-lifecycle.ts +43 -0
- package/src/plugins/builtin/short-interest/index.tsx +31 -0
- package/src/plugins/builtin/short-interest/watch-client.ts +70 -0
- package/src/plugins/builtin/short-interest/watch-headless.ts +49 -0
- package/src/plugins/builtin/short-interest/watch-model.ts +185 -0
- package/src/plugins/builtin/short-interest/watch-pane.tsx +169 -0
- package/src/plugins/builtin/short-volume/pane.tsx +1 -1
- package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
- package/src/plugins/builtin/supply-chain/client.ts +104 -0
- package/src/plugins/builtin/supply-chain/disclosure-quote.tsx +17 -0
- package/src/plugins/builtin/supply-chain/evidence.ts +88 -0
- package/src/plugins/builtin/supply-chain/flow-layout.ts +133 -0
- package/src/plugins/builtin/supply-chain/flow.tsx +323 -0
- package/src/plugins/builtin/supply-chain/graph-client.ts +83 -0
- package/src/plugins/builtin/supply-chain/graph-evidence.ts +25 -0
- package/src/plugins/builtin/supply-chain/graph-model.ts +45 -0
- package/src/plugins/builtin/supply-chain/graph-pane.tsx +218 -0
- package/src/plugins/builtin/supply-chain/graph.tsx +163 -0
- package/src/plugins/builtin/supply-chain/headless.ts +105 -0
- package/src/plugins/builtin/supply-chain/index.tsx +17 -0
- package/src/plugins/builtin/supply-chain/model.ts +145 -0
- package/src/plugins/builtin/supply-chain/pane.tsx +276 -0
- package/src/plugins/builtin/supply-chain/row-evidence.tsx +96 -0
- package/src/plugins/builtin/supply-chain/trust.ts +34 -0
- package/src/plugins/builtin/themes/client.ts +39 -0
- package/src/plugins/builtin/themes/headless.ts +38 -0
- package/src/plugins/builtin/themes/model.ts +92 -0
- package/src/plugins/builtin/themes/pane.tsx +125 -0
- package/src/plugins/builtin/thirteenf/pane.tsx +6 -15
- package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +5 -6
- package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +201 -0
- package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +327 -0
- package/src/plugins/builtin/ticker-detail/financials/period-end-history.ts +5 -2
- package/src/plugins/builtin/ticker-detail/financials/ratios.ts +60 -12
- package/src/plugins/builtin/ticker-detail/financials/tab.tsx +2 -1
- package/src/plugins/builtin/ticker-detail/headless.ts +7 -2
- package/src/plugins/builtin/ticker-detail/index.tsx +22 -0
- package/src/plugins/builtin/ticker-detail/overview/components.tsx +53 -30
- package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +112 -47
- package/src/plugins/builtin/ticker-detail/pane.tsx +50 -6
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +21 -42
- package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +3 -0
- package/src/plugins/builtin/time-sales/pane.tsx +1 -1
- package/src/plugins/builtin/world-indices/indices.ts +1 -0
- package/src/plugins/catalog-browser.ts +40 -0
- package/src/plugins/catalog-manifest.ts +3 -0
- package/src/plugins/catalog-ui.ts +6 -0
- package/src/plugins/current-target.ts +0 -9
- package/src/public/__snapshots__/public-api.test.ts.snap +1 -0
- package/src/renderers/browser/cloud-transport.ts +66 -1
- package/src/renderers/browser/main.tsx +2 -0
- package/src/renderers/dom/data-table/row.tsx +2 -0
- package/src/renderers/dom/desktop/controls.tsx +38 -25
- package/src/renderers/dom/desktop/icons.tsx +8 -0
- package/src/renderers/dom/host/chart-surface.tsx +36 -2
- package/src/renderers/dom/host/focus-scope.ts +11 -1
- package/src/renderers/dom/styles.css +28 -0
- package/src/renderers/electrobun/view/backend-rpc.ts +3 -2
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/http-fetch.ts +2 -0
- package/src/renderers/electrobun/view/main.tsx +3 -1
- package/src/renderers/electrobun/view/rpc-timeout.ts +59 -0
- package/src/renderers/opentui/start.tsx +3 -0
- package/src/shares/api.ts +3 -1
- package/src/sources/gloomberb-cloud/index.ts +47 -13
- package/src/sources/history-result.ts +1 -0
- package/src/sources/history-retention.ts +16 -0
- package/src/sources/provider-router/history.ts +4 -2
- package/src/sources/sec-edgar/identity.ts +36 -0
- package/src/sources/sec-edgar.ts +1 -34
- package/src/state/app/context/index.tsx +8 -0
- package/src/sync/core-contributors.ts +20 -2
- package/src/telemetry/attention-counts.ts +164 -0
- package/src/telemetry/live-config.ts +7 -0
- package/src/test-support/rpc-loopback.ts +7 -3
- package/src/test-support/shell-pane-keys.tsx +34 -0
- package/src/tickers/instrument-kind.ts +12 -6
- package/src/tickers/open-target.ts +1 -1
- package/src/tickers/search/asset-classes.ts +91 -0
- package/src/tickers/search/index.ts +62 -15
- package/src/tickers/search/ranking.ts +22 -3
- package/src/tickers/search/upsert.ts +4 -1
- package/src/time-series/live-bars.ts +8 -3
- package/src/time-series/resolve.ts +224 -17
- package/src/time-series/spec.ts +1 -0
- package/src/time-series/types.ts +9 -1
- package/src/types/config.ts +23 -1
- package/src/types/data-provider.ts +2 -0
- package/src/types/headless.ts +17 -0
- package/src/types/price-history.ts +2 -0
- package/src/ui/host.tsx +6 -0
- package/src/utils/double-escape-close.ts +20 -0
- package/src/utils/exchanges.ts +1 -0
- package/src/utils/html-entities.ts +15 -0
- package/src/utils/http-proxy-response.ts +44 -7
- package/src/utils/plugin-proxy-hosts.json +3 -0
- package/src/utils/price-history.ts +35 -1
- package/src/utils/sec.ts +21 -2
- package/src/utils/text-wrap.ts +13 -8
- package/src/utils/zoned-date-time.ts +67 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const ASSET_CLASSES = ["stocks", "indices", "energy", "metals", "fx", "crypto", "other"] as const
|
|
2
|
+
type AssetClass = (typeof ASSET_CLASSES)[number]
|
|
3
|
+
type PerpVenue = "hyperliquid" | "binance" | "bybit" | "okx" | "deribit" | "coinbase" | "kraken" | "dydx"
|
|
4
|
+
|
|
5
|
+
/** Rates and premiums are fractions, timestamps UTC; null always means unavailable. */
|
|
6
|
+
interface PerpMarket {
|
|
7
|
+
marketId: string
|
|
8
|
+
venue: PerpVenue
|
|
9
|
+
dex: string
|
|
10
|
+
symbol: string
|
|
11
|
+
baseAsset: string
|
|
12
|
+
displayName: string
|
|
13
|
+
assetClass: AssetClass
|
|
14
|
+
underlyingSymbol: string | null
|
|
15
|
+
underlyingCurrency: string | null
|
|
16
|
+
quoteCurrency: string
|
|
17
|
+
marginCurrency: string
|
|
18
|
+
contractType: "linear" | "inverse" | "quanto"
|
|
19
|
+
priceMultiplier: number
|
|
20
|
+
markPrice: number | null
|
|
21
|
+
oraclePrice: number | null
|
|
22
|
+
lastPrice: number | null
|
|
23
|
+
previousDayPrice: number | null
|
|
24
|
+
priceChange24h: number | null
|
|
25
|
+
premium: number | null
|
|
26
|
+
venuePremium: number | null
|
|
27
|
+
fundingRate: number | null
|
|
28
|
+
fundingIntervalHours: number | null
|
|
29
|
+
fundingKind: "current" | "last-paid" | "continuous"
|
|
30
|
+
fundingRate8h: number | null
|
|
31
|
+
fundingApr: number | null
|
|
32
|
+
predictedFundingRate: number | null
|
|
33
|
+
predictedFundingIntervalHours: number | null
|
|
34
|
+
nextFundingAt: string | null
|
|
35
|
+
openInterestBase: number | null
|
|
36
|
+
openInterestUsd: number | null
|
|
37
|
+
volume24hUsd: number | null
|
|
38
|
+
maxLeverage: number | null
|
|
39
|
+
isolatedOnly: boolean | null
|
|
40
|
+
delisted: boolean
|
|
41
|
+
observedAt: string
|
|
42
|
+
sourceAsOf: string | null
|
|
43
|
+
sourceUrl: string
|
|
44
|
+
confidence: "high" | "medium" | "low"
|
|
45
|
+
qualityFlags: string[]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface PerpFunding {
|
|
49
|
+
marketId: string
|
|
50
|
+
time: string
|
|
51
|
+
rate: number
|
|
52
|
+
intervalHours: number
|
|
53
|
+
premium: number | null
|
|
54
|
+
observedAt: string
|
|
55
|
+
sourceUrl: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface PerpCandle {
|
|
59
|
+
marketId: string
|
|
60
|
+
time: string
|
|
61
|
+
interval: "1h"
|
|
62
|
+
open: number
|
|
63
|
+
high: number
|
|
64
|
+
low: number
|
|
65
|
+
close: number
|
|
66
|
+
volumeBase: number | null
|
|
67
|
+
trades: number | null
|
|
68
|
+
observedAt: string
|
|
69
|
+
sourceUrl: string
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface UnderlyingReference {
|
|
73
|
+
symbol: string
|
|
74
|
+
price: number
|
|
75
|
+
currency: string
|
|
76
|
+
asOf: string
|
|
77
|
+
marketState: string | null
|
|
78
|
+
sourceUrl: string
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface PerpBoardRow extends PerpMarket {
|
|
82
|
+
stale: boolean
|
|
83
|
+
oiChange1h: number | null
|
|
84
|
+
oiChange24h: number | null
|
|
85
|
+
oiUsdChange1h: number | null
|
|
86
|
+
oiUsdChange24h: number | null
|
|
87
|
+
underlying: UnderlyingReference | null
|
|
88
|
+
underlyingPremium: number | null
|
|
89
|
+
closedMarketPremium: number | null
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
type PerpHistoryPoint = {
|
|
93
|
+
time: string
|
|
94
|
+
resolution: "minute" | "hour" | "day"
|
|
95
|
+
markPrice: number | null
|
|
96
|
+
oraclePrice: number | null
|
|
97
|
+
premium: number | null
|
|
98
|
+
fundingRate: number | null
|
|
99
|
+
fundingIntervalHours: number | null
|
|
100
|
+
openInterestBase: number | null
|
|
101
|
+
openInterestUsd: number | null
|
|
102
|
+
sampleCount: number
|
|
103
|
+
firstObservedAt: string
|
|
104
|
+
lastObservedAt: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface PerpBoardPayload {
|
|
108
|
+
status: string; asOf: string | null; rows: PerpBoardRow[]; total: number; locked: number;
|
|
109
|
+
access: "pro" | "preview"; sources?: unknown[];
|
|
110
|
+
}
|
|
111
|
+
export interface PerpHistoryPayload {
|
|
112
|
+
status: string; marketId: string; rows: PerpHistoryPoint[]; funding: PerpFunding[]; candles: PerpCandle[];
|
|
113
|
+
locked: boolean; access: "pro" | "preview"; asOf: string | null;
|
|
114
|
+
from?: string; to?: string; resolution?: "minute" | "hour" | "day"; truncated?: boolean;
|
|
115
|
+
}
|
|
116
|
+
export interface PerpRankingsPayload {
|
|
117
|
+
status: string; asOf: string | null; access: "pro" | "preview"; locked: boolean;
|
|
118
|
+
fundingPositive: PerpBoardRow[]; fundingNegative: PerpBoardRow[]; oiSurges: PerpBoardRow[];
|
|
119
|
+
premiumDislocations: PerpBoardRow[]; closedMarketDislocations: PerpBoardRow[];
|
|
120
|
+
}
|
|
121
|
+
export type PerpBoardQuery = { assetClass?: string; search?: string; sort?: string; includeDelisted?: boolean };
|
|
122
|
+
export type PerpHistoryQuery = { marketId: string; from?: string; to?: string; resolution?: "auto" | "minute" | "hour" | "day"; limit?: number };
|
|
123
|
+
|
|
124
|
+
export interface PerpMarketPayload extends PerpBoardPayload {
|
|
125
|
+
evidence: { kind: string; period_at: string; received_at: string; superseded_at: string | null; fingerprint: string; payload: PerpMarket | PerpFunding | PerpCandle }[];
|
|
126
|
+
methodologyUrl: string;
|
|
127
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/** Power quantities are MW unless explicitly qualified in metrics; dates retain source precision. */
|
|
2
|
+
type PowerKind = "queue" | "load" | "capacity" | "utility"
|
|
3
|
+
type PowerStatus = "active" | "completed" | "withdrawn" | "approved" | "operating" | "unknown"
|
|
4
|
+
type PowerFuel = "solar" | "wind" | "storage" | "gas" | "nuclear" | "hydro" | "coal" | "hybrid" | "other" | "load" | "unknown"
|
|
5
|
+
interface PowerRecord {
|
|
6
|
+
id: string
|
|
7
|
+
sourceId: string
|
|
8
|
+
sourceProjectId: string
|
|
9
|
+
kind: PowerKind
|
|
10
|
+
name: string
|
|
11
|
+
country: string
|
|
12
|
+
region: string
|
|
13
|
+
state: string | null
|
|
14
|
+
county: string | null
|
|
15
|
+
zone: string | null
|
|
16
|
+
developer: string | null
|
|
17
|
+
utility: string | null
|
|
18
|
+
fuel: PowerFuel
|
|
19
|
+
technology: string | null
|
|
20
|
+
status: PowerStatus
|
|
21
|
+
statusRaw: string | null
|
|
22
|
+
capacityMw: number | null
|
|
23
|
+
requestedDate: string | null
|
|
24
|
+
proposedDate: string | null
|
|
25
|
+
completedDate: string | null
|
|
26
|
+
withdrawnDate: string | null
|
|
27
|
+
period: string | null
|
|
28
|
+
asOf: string | null
|
|
29
|
+
observedAt: string
|
|
30
|
+
sourceUrl: string
|
|
31
|
+
sourceLocator: string
|
|
32
|
+
confidence: number
|
|
33
|
+
/** Raw source cells or exact source excerpt. Never manufactured prose presented as a quote. */
|
|
34
|
+
evidence: Record<string, unknown>
|
|
35
|
+
/** Optional native facts e.g. generationMwh, customers, salesMwh, loadClass. */
|
|
36
|
+
metrics: Record<string, string | number | boolean | null>
|
|
37
|
+
/** Historical benchmarks never add to current direct-source queue totals. */
|
|
38
|
+
historical: boolean
|
|
39
|
+
}
|
|
40
|
+
interface PowerEntityLink {
|
|
41
|
+
name: string
|
|
42
|
+
entityId: string
|
|
43
|
+
tickers: { ticker: string; exchange?: string }[]
|
|
44
|
+
confidence: number
|
|
45
|
+
role: "developer" | "utility"
|
|
46
|
+
}
|
|
47
|
+
export interface PowerProject extends PowerRecord {
|
|
48
|
+
snapshotId: string
|
|
49
|
+
revision: number
|
|
50
|
+
entities: PowerEntityLink[]
|
|
51
|
+
}
|
|
52
|
+
export interface PowerFilter {
|
|
53
|
+
sort?: "capacityMw" | "name" | "region" | "status" | "proposedDate" | "generationMwh" | "salesMwh" | "revenueUsd" | "summerPeakDemandMw" | "winterPeakDemandMw"
|
|
54
|
+
direction?: "asc" | "desc"
|
|
55
|
+
country?: string
|
|
56
|
+
region?: string
|
|
57
|
+
fuel?: string
|
|
58
|
+
status?: string
|
|
59
|
+
kind?: string
|
|
60
|
+
symbol?: string
|
|
61
|
+
search?: string
|
|
62
|
+
loadClass?: string
|
|
63
|
+
sourceId?: string
|
|
64
|
+
historical?: boolean
|
|
65
|
+
offset?: number
|
|
66
|
+
limit?: number
|
|
67
|
+
from?: string
|
|
68
|
+
to?: string
|
|
69
|
+
}
|
|
70
|
+
export interface PowerAggregate {
|
|
71
|
+
sourceId: string
|
|
72
|
+
country: string
|
|
73
|
+
region: string
|
|
74
|
+
fuel: string
|
|
75
|
+
status: string
|
|
76
|
+
kind: string
|
|
77
|
+
projects: number
|
|
78
|
+
capacityMw: number
|
|
79
|
+
unknownCapacity: number
|
|
80
|
+
}
|
|
81
|
+
export interface PowerHistoryPoint extends PowerAggregate {
|
|
82
|
+
basis: "observed" | "published"
|
|
83
|
+
sourceUrls: string[]
|
|
84
|
+
sourceId: string
|
|
85
|
+
observedAt: string
|
|
86
|
+
asOf: string | null
|
|
87
|
+
period: string | null
|
|
88
|
+
historical: boolean
|
|
89
|
+
}
|
|
90
|
+
export interface PowerCoverage {
|
|
91
|
+
id: string
|
|
92
|
+
country: string
|
|
93
|
+
region: string
|
|
94
|
+
kind: PowerKind
|
|
95
|
+
role: "direct" | "benchmark" | "context"
|
|
96
|
+
status: "current" | "stale" | "pending" | "failed" | "disabled"
|
|
97
|
+
reason: string | null
|
|
98
|
+
sourceUrl: string
|
|
99
|
+
asOf: string | null
|
|
100
|
+
observedAt: string | null
|
|
101
|
+
records: number
|
|
102
|
+
nextPollAt: string | null
|
|
103
|
+
}
|
|
104
|
+
export interface PowerRates {
|
|
105
|
+
sourceId: string
|
|
106
|
+
region: string
|
|
107
|
+
country: string
|
|
108
|
+
cohort: string
|
|
109
|
+
projects: number
|
|
110
|
+
completed: number
|
|
111
|
+
withdrawn: number
|
|
112
|
+
active: number
|
|
113
|
+
unknown: number
|
|
114
|
+
completionRate: number | null
|
|
115
|
+
withdrawalRate: number | null
|
|
116
|
+
}
|
|
117
|
+
export interface PowerExposure {
|
|
118
|
+
sourceId: string
|
|
119
|
+
sourceUrls: string[]
|
|
120
|
+
asOf: string | null
|
|
121
|
+
observedAt: string
|
|
122
|
+
utility: string
|
|
123
|
+
country: string
|
|
124
|
+
region: string
|
|
125
|
+
requestedMw: number
|
|
126
|
+
approvedMw: number
|
|
127
|
+
operatingMw: number
|
|
128
|
+
requests: number
|
|
129
|
+
unknownCapacity: number
|
|
130
|
+
entities: PowerEntityLink[]
|
|
131
|
+
}
|
|
132
|
+
export interface PowerBoard {
|
|
133
|
+
generatedAt: string
|
|
134
|
+
access: "full" | "preview"
|
|
135
|
+
projects: PowerProject[]
|
|
136
|
+
total: number
|
|
137
|
+
hasMore: boolean
|
|
138
|
+
nextOffset: number | null
|
|
139
|
+
aggregates: PowerAggregate[]
|
|
140
|
+
rates: PowerRates[]
|
|
141
|
+
exposure: PowerExposure[]
|
|
142
|
+
coverage: PowerCoverage[]
|
|
143
|
+
filters: { countries: string[]; regions: string[]; fuels: string[]; statuses: string[] }
|
|
144
|
+
locked: { projects: number; aggregates: number; rates: number; exposure: number }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface PowerHistory { generatedAt: string; access: "full" | "preview"; points: PowerHistoryPoint[]; locked: number; hasMore: boolean; nextOffset: number | null }
|
|
148
|
+
export interface PowerDetail { generatedAt: string; access: "full" | "preview"; project: PowerProject | null; revisions: PowerProject[]; totalRevisions: number; hasMore: boolean; nextOffset: number | null; locked: number }
|
|
@@ -53,7 +53,22 @@ export interface CloudApiFetchTransportOptions {
|
|
|
53
53
|
streamFetch?: CloudApiStreamFetch;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* One upload with its bytes and the headers the client built. A transport that
|
|
58
|
+
* can watch the body go out (a browser XMLHttpRequest) reports `onProgress`
|
|
59
|
+
* with the fraction sent; others never call it.
|
|
60
|
+
*/
|
|
61
|
+
export interface CloudApiUploadRequest {
|
|
62
|
+
url: string;
|
|
63
|
+
body: Blob | Uint8Array;
|
|
64
|
+
headers: Headers;
|
|
65
|
+
signal?: AbortSignal;
|
|
66
|
+
onProgress?: (fraction: number) => void;
|
|
67
|
+
}
|
|
68
|
+
type CloudApiUploadTransport = (request: CloudApiUploadRequest) => Promise<CloudApiResponse>;
|
|
69
|
+
|
|
56
70
|
let cloudApiFetchTransport: CloudApiFetchTransport = httpFetch;
|
|
71
|
+
let cloudApiUploadTransport: CloudApiUploadTransport | null = null;
|
|
57
72
|
let cloudApiTransportInstalled = false;
|
|
58
73
|
let cloudApiFetchStreaming = true;
|
|
59
74
|
let cloudApiStreamFetch: CloudApiStreamFetch | null = null;
|
|
@@ -68,6 +83,11 @@ export function setCloudApiFetchTransport(
|
|
|
68
83
|
cloudApiStreamFetch = transport ? options.streamFetch ?? null : null;
|
|
69
84
|
}
|
|
70
85
|
|
|
86
|
+
/** Installs the transport uploads go through; without one they use the fetch transport. */
|
|
87
|
+
export function setCloudApiUploadTransport(transport: CloudApiUploadTransport | null): void {
|
|
88
|
+
cloudApiUploadTransport = transport;
|
|
89
|
+
}
|
|
90
|
+
|
|
71
91
|
/**
|
|
72
92
|
* The fetch to use for a response that must be read while it arrives, or null
|
|
73
93
|
* when the installed transport buffers whole responses.
|
|
@@ -292,10 +312,47 @@ export class CloudApiRequestTransport {
|
|
|
292
312
|
}
|
|
293
313
|
}
|
|
294
314
|
|
|
315
|
+
/**
|
|
316
|
+
* POSTs raw bytes, such as an image, and parses the JSON answer like
|
|
317
|
+
* `request`. Progress is reported where the installed upload transport can
|
|
318
|
+
* see the body go out.
|
|
319
|
+
*/
|
|
320
|
+
async upload<T>(
|
|
321
|
+
path: string,
|
|
322
|
+
body: Blob | Uint8Array,
|
|
323
|
+
options: {
|
|
324
|
+
contentType: string;
|
|
325
|
+
headers?: HeadersInit;
|
|
326
|
+
signal?: AbortSignal;
|
|
327
|
+
onProgress?: (fraction: number) => void;
|
|
328
|
+
},
|
|
329
|
+
): Promise<T> {
|
|
330
|
+
const headers = new Headers(options.headers);
|
|
331
|
+
headers.set("Content-Type", options.contentType);
|
|
332
|
+
const uploadTransport = this.fetchTransport ? null : cloudApiUploadTransport;
|
|
333
|
+
const send: CloudApiFetchTransport | undefined = uploadTransport
|
|
334
|
+
? (url, init) => uploadTransport({
|
|
335
|
+
url,
|
|
336
|
+
body,
|
|
337
|
+
headers: new Headers(init?.headers),
|
|
338
|
+
signal: options.signal,
|
|
339
|
+
onProgress: options.onProgress,
|
|
340
|
+
})
|
|
341
|
+
: undefined;
|
|
342
|
+
return this.performRequest<T>(path, {
|
|
343
|
+
method: "POST",
|
|
344
|
+
headers,
|
|
345
|
+
// Typed arrays are valid fetch bodies; RequestInit's DOM typing lags behind.
|
|
346
|
+
body: body as BodyInit,
|
|
347
|
+
signal: options.signal,
|
|
348
|
+
}, () => true, send);
|
|
349
|
+
}
|
|
350
|
+
|
|
295
351
|
private async performRequest<T>(
|
|
296
352
|
path: string,
|
|
297
353
|
options: RequestInit | undefined,
|
|
298
354
|
canApplySession: () => boolean,
|
|
355
|
+
send?: CloudApiFetchTransport,
|
|
299
356
|
): Promise<T> {
|
|
300
357
|
throwIfRequestAborted(options?.signal);
|
|
301
358
|
const headers = new Headers(options?.headers);
|
|
@@ -312,7 +369,7 @@ export class CloudApiRequestTransport {
|
|
|
312
369
|
|
|
313
370
|
const operation = `${options?.method ?? "GET"} ${path.split("?")[0]}`;
|
|
314
371
|
const request = async () => {
|
|
315
|
-
const res = await (this.fetchTransport ?? cloudApiFetchTransport)(
|
|
372
|
+
const res = await (send ?? this.fetchTransport ?? cloudApiFetchTransport)(
|
|
316
373
|
`${this.baseUrl}${path}`,
|
|
317
374
|
{
|
|
318
375
|
...options,
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { apiClient } from "./index";
|
|
2
2
|
import { getCurrentPluginTarget } from "../plugins/current-target";
|
|
3
3
|
import type { DesktopDeepLinkBridge } from "../types/desktop-deeplink";
|
|
4
|
+
import { exposeExperiment, storedExperimentAssignments } from "./web-experiments";
|
|
5
|
+
import { createWallExperimentSession, type WallExperiment, type WallExperimentContext, type WallTeaserVariant } from "./wall-experiments";
|
|
6
|
+
import { hasProAccess } from "./plan-rules";
|
|
7
|
+
import { withDeadline } from "../utils/async-deadline";
|
|
4
8
|
|
|
5
9
|
export type ResearchActivity =
|
|
6
10
|
| "workspace_opened"
|
|
@@ -10,6 +14,8 @@ export type ResearchActivity =
|
|
|
10
14
|
| "ticker_saved"
|
|
11
15
|
| "pro_feature_used"
|
|
12
16
|
| "upgrade_intent"
|
|
17
|
+
| "wall_viewed"
|
|
18
|
+
| "wall_cta_clicked"
|
|
13
19
|
// First-run funnel, one per step reached. Keep in sync with the server's list.
|
|
14
20
|
| "onboarding_started"
|
|
15
21
|
| "onboarding_position_added"
|
|
@@ -30,6 +36,9 @@ export type ResearchFeature =
|
|
|
30
36
|
const sent = new Set<string>();
|
|
31
37
|
let anonymousId: string | undefined;
|
|
32
38
|
let attribution: Record<string, string> = {};
|
|
39
|
+
const wallExperiment = createWallExperimentSession();
|
|
40
|
+
const signinWallExperiment = createWallExperimentSession("wall_teaser_signin");
|
|
41
|
+
const WALL_VIEWS_SESSION_KEY = "gloomberb.wall-teaser.views";
|
|
33
42
|
|
|
34
43
|
const ATTRIBUTION_STORAGE_KEY = "gloomberb.web.attribution";
|
|
35
44
|
const ANONYMOUS_ID_STORAGE_KEY = "gloomberb.web.anonymous-id";
|
|
@@ -38,8 +47,8 @@ const ATTRIBUTION_WINDOW_MS = 30 * 24 * 60 * 60 * 1000;
|
|
|
38
47
|
/** Another device's clock may run slightly ahead; a touch from a minute in the future is still fresh. */
|
|
39
48
|
const CLOCK_SKEW_MS = 5 * 60 * 1000;
|
|
40
49
|
const ANONYMOUS_ID = /^[a-f0-9-]{36}$/;
|
|
41
|
-
/** The server accepts a tab id only in this shape. */
|
|
42
|
-
const
|
|
50
|
+
/** The server accepts a tab id or an upgrade placement only in this shape. */
|
|
51
|
+
const ACTIVITY_ID = /^[a-z0-9][a-z0-9-]{0,39}$/;
|
|
43
52
|
const CAMPAIGN_KEYS = [
|
|
44
53
|
"utm_source",
|
|
45
54
|
"utm_medium",
|
|
@@ -310,29 +319,67 @@ export function observeDesktopDeepLinks(
|
|
|
310
319
|
/** What the server stores against the account: stored touches plus the product marker. */
|
|
311
320
|
function attributionPayload(): Record<string, string> | undefined {
|
|
312
321
|
const target = getCurrentPluginTarget();
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
322
|
+
const context = wallExperimentContext();
|
|
323
|
+
const wallVariant = wallExperiment.variant(context);
|
|
324
|
+
// Keep an already-exposed visitor attributable after signup without enrolling
|
|
325
|
+
// the account or accepting a stored arm from an earlier session.
|
|
326
|
+
const signinVariant = signinWallExperiment.variant({ ...context, accountId: undefined, pro: false });
|
|
327
|
+
const base = target === "web"
|
|
328
|
+
? { product: "gloomberb", ...attribution, ...webExperimentAttribution() }
|
|
329
|
+
: target === "desktop" && Object.keys(attribution).length > 0
|
|
330
|
+
? { product: "gloomberb", ...attribution }
|
|
331
|
+
: undefined;
|
|
332
|
+
// A remembered browser arm is sent with the exposure request, but joins
|
|
333
|
+
// milestones only after this session has an accepted answer. Other live
|
|
334
|
+
// experiments keep their existing attribution unchanged.
|
|
335
|
+
const experiments = (base?.experiments ?? "").split(",").filter((part) => part && !part.startsWith("wall_teaser:") && !part.startsWith("wall_teaser_signin:"));
|
|
336
|
+
if (wallVariant) experiments.push(`wall_teaser:${wallVariant}`);
|
|
337
|
+
if (signinVariant) experiments.push(`wall_teaser_signin:${signinVariant}`);
|
|
338
|
+
if (!base && experiments.length === 0) return undefined;
|
|
339
|
+
const next: Record<string, string> = { ...base };
|
|
340
|
+
delete next.experiments;
|
|
341
|
+
if (experiments.length > 0) next.experiments = experiments.join(",");
|
|
342
|
+
return next;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export interface ResearchActivityDetails {
|
|
346
|
+
/** The desks picked at "What do you trade?", on the milestone that ends the first run. */
|
|
347
|
+
desks?: readonly string[];
|
|
348
|
+
/**
|
|
349
|
+
* Which prompt raised an `upgrade_intent` (a pane footer, a wall, the
|
|
350
|
+
* command bar), as a short id like a tab id. Never the prompt's text.
|
|
351
|
+
*/
|
|
352
|
+
placement?: string;
|
|
353
|
+
/** Only ids describing what a teaser-arm wall rendered, never its content. */
|
|
354
|
+
teaser_kind?: "summary" | "sample" | "none";
|
|
355
|
+
/** The sign-in wall action, never the button copy. */
|
|
356
|
+
cta?: "login" | "signup";
|
|
316
357
|
}
|
|
317
358
|
|
|
318
359
|
/**
|
|
319
|
-
* Counts milestones once per feature/session
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
* end of the first-run funnel: the desks picked at "What do you trade?".
|
|
360
|
+
* Counts milestones once per feature/tab/placement, session and account, never
|
|
361
|
+
* their content. Wall views require an account or an identified web visitor;
|
|
362
|
+
* other native milestones can retain an identifier handed over by the website.
|
|
323
363
|
*/
|
|
324
364
|
export function recordResearchActivity(
|
|
325
365
|
event: ResearchActivity,
|
|
326
366
|
feature?: ResearchFeature,
|
|
327
367
|
tab?: string,
|
|
328
|
-
desks
|
|
368
|
+
{ desks, placement: rawPlacement, teaser_kind, cta }: ResearchActivityDetails = {},
|
|
329
369
|
): void {
|
|
330
370
|
const target = getCurrentPluginTarget();
|
|
331
371
|
const user = apiClient.getCurrentUser();
|
|
372
|
+
const wallEvent = event === "wall_viewed" || event === "wall_cta_clicked";
|
|
373
|
+
if (wallEvent && (wallPrivacyBlocked() || (!user && target !== "web"))) return;
|
|
332
374
|
if (!user && !anonymousId) return;
|
|
333
375
|
if (!user && target !== "web" && target !== "desktop") return;
|
|
334
|
-
|
|
335
|
-
|
|
376
|
+
// The server refuses the whole event over a malformed id, so one is dropped instead.
|
|
377
|
+
const placement = rawPlacement && ACTIVITY_ID.test(rawPlacement) ? rawPlacement : undefined;
|
|
378
|
+
if (wallEvent && !placement) return;
|
|
379
|
+
if (event === "wall_cta_clicked" && cta !== "login" && cta !== "signup") return;
|
|
380
|
+
const identity = user?.id ?? (wallEvent ? anonymousId : "guest");
|
|
381
|
+
const key = `${identity}:${event}:${feature ?? ""}:${tab ?? ""}:${placement ?? ""}${event === "wall_cta_clicked" ? `:${cta}` : ""}`;
|
|
382
|
+
if (sent.has(key) || (wallEvent && wallSessionViews().has(key))) return;
|
|
336
383
|
sent.add(key);
|
|
337
384
|
if (event !== "workspace_opened") recordResearchActivity("workspace_opened");
|
|
338
385
|
void apiClient
|
|
@@ -345,6 +392,15 @@ export function recordResearchActivity(
|
|
|
345
392
|
feature,
|
|
346
393
|
tab,
|
|
347
394
|
desks,
|
|
395
|
+
placement,
|
|
396
|
+
...(event === "wall_viewed" && teaser_kind ? { teaser_kind } : {}),
|
|
397
|
+
...(event === "wall_cta_clicked" ? { cta } : {}),
|
|
398
|
+
})
|
|
399
|
+
.then(() => {
|
|
400
|
+
if (!wallEvent) return;
|
|
401
|
+
const views = wallSessionViews();
|
|
402
|
+
views.add(key);
|
|
403
|
+
try { sessionStorage.setItem(WALL_VIEWS_SESSION_KEY, JSON.stringify([...views])); } catch { /* Native sessions use the in-memory set. */ }
|
|
348
404
|
})
|
|
349
405
|
.catch(() => {
|
|
350
406
|
sent.delete(key);
|
|
@@ -357,7 +413,7 @@ export function recordResearchActivity(
|
|
|
357
413
|
* someone installed stay private; so is any id the server would refuse.
|
|
358
414
|
*/
|
|
359
415
|
export function recordResearchTabView(tabId: string, fromExternalPlugin: boolean): void {
|
|
360
|
-
const tab = !fromExternalPlugin &&
|
|
416
|
+
const tab = !fromExternalPlugin && ACTIVITY_ID.test(tabId) ? tabId : "plugin";
|
|
361
417
|
recordResearchActivity("research_tab_viewed", undefined, tab);
|
|
362
418
|
}
|
|
363
419
|
|
|
@@ -375,6 +431,109 @@ export function identifyResearchUser(): void {
|
|
|
375
431
|
}
|
|
376
432
|
}
|
|
377
433
|
|
|
434
|
+
/** The arms this browser was given, so each milestone carries them as `exp_<key>`. */
|
|
435
|
+
function webExperimentAttribution(): { experiments?: string } {
|
|
436
|
+
if (!anonymousId) return {};
|
|
437
|
+
try {
|
|
438
|
+
const experiments = storedExperimentAssignments(localStorage);
|
|
439
|
+
return experiments ? { experiments } : {};
|
|
440
|
+
} catch {
|
|
441
|
+
return {};
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* The arm of a web terminal experiment to show, asked for at the moment it
|
|
447
|
+
* would show and counted then, in every arm; null shows nothing. Only signed-out
|
|
448
|
+
* visitors on term.gloom.sh with an analytics id (no Do Not Track or Global
|
|
449
|
+
* Privacy Control) and not driven by automation are asked. See web-experiments.ts.
|
|
450
|
+
*/
|
|
451
|
+
export function exposeWebExperiment(experiment: string): Promise<string | null> {
|
|
452
|
+
if (getCurrentPluginTarget() !== "web") return Promise.resolve(null);
|
|
453
|
+
try {
|
|
454
|
+
return exposeExperiment(experiment, {
|
|
455
|
+
anonymousId,
|
|
456
|
+
signedIn: !!apiClient.getCurrentUser(),
|
|
457
|
+
automated: navigator.webdriver === true,
|
|
458
|
+
local: localStorage,
|
|
459
|
+
session: sessionStorage,
|
|
460
|
+
ask: ({ experiment: key, variant }) => apiClient.recordExperimentExposure({
|
|
461
|
+
eventId: crypto.randomUUID(),
|
|
462
|
+
surface: "web",
|
|
463
|
+
anonymousId,
|
|
464
|
+
attribution: attributionPayload(),
|
|
465
|
+
experiment: key,
|
|
466
|
+
variant,
|
|
467
|
+
}),
|
|
468
|
+
});
|
|
469
|
+
} catch {
|
|
470
|
+
return Promise.resolve(null);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function wallPrivacyBlocked(): boolean {
|
|
475
|
+
if (typeof navigator === "undefined") return false;
|
|
476
|
+
return navigator.doNotTrack === "1"
|
|
477
|
+
|| (navigator as Navigator & { globalPrivacyControl?: boolean }).globalPrivacyControl === true
|
|
478
|
+
|| navigator.webdriver === true;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function wallExperimentContext(): WallExperimentContext {
|
|
482
|
+
const user = apiClient.getCurrentUser();
|
|
483
|
+
const surface = getCurrentPluginTarget();
|
|
484
|
+
let local: StorageLike | undefined;
|
|
485
|
+
let session: StorageLike | undefined;
|
|
486
|
+
try {
|
|
487
|
+
if (surface === "web") local = localStorage;
|
|
488
|
+
if (surface === "web" || surface === "desktop") session = sessionStorage;
|
|
489
|
+
} catch { /* Native and private sessions keep their answer in memory. */ }
|
|
490
|
+
return {
|
|
491
|
+
surface,
|
|
492
|
+
accountId: user?.id,
|
|
493
|
+
pro: hasProAccess(user),
|
|
494
|
+
anonymousId,
|
|
495
|
+
optedOut: wallPrivacyBlocked(),
|
|
496
|
+
automated: typeof navigator !== "undefined" && navigator.webdriver === true,
|
|
497
|
+
local,
|
|
498
|
+
session,
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function wallSessionViews(): Set<string> {
|
|
503
|
+
try {
|
|
504
|
+
const saved: unknown = JSON.parse(sessionStorage.getItem(WALL_VIEWS_SESSION_KEY) ?? "[]");
|
|
505
|
+
if (Array.isArray(saved)) return new Set(saved.filter((value): value is string => typeof value === "string"));
|
|
506
|
+
} catch { /* Native sessions use the in-memory set. */ }
|
|
507
|
+
return new Set();
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/** A wall's first render asks once per eligible account or web visitor per session. */
|
|
511
|
+
export function exposeWallTeaser(experiment: WallExperiment = "wall_teaser"): Promise<WallTeaserVariant | null> {
|
|
512
|
+
const context = wallExperimentContext();
|
|
513
|
+
const session = experiment === "wall_teaser_signin" ? signinWallExperiment : wallExperiment;
|
|
514
|
+
return session.expose(context, (variant) => {
|
|
515
|
+
const controller = new AbortController();
|
|
516
|
+
return withDeadline(apiClient.recordExperimentExposure({
|
|
517
|
+
eventId: crypto.randomUUID(),
|
|
518
|
+
surface: context.surface,
|
|
519
|
+
anonymousId: context.surface === "web" ? anonymousId : undefined,
|
|
520
|
+
attribution: attributionPayload(),
|
|
521
|
+
experiment,
|
|
522
|
+
variant,
|
|
523
|
+
}, controller.signal), 3_000, "Wall experiment request timed out", (error) => controller.abort(error));
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/** Records the visible wall once per placement, including visitors outside the experiment. */
|
|
528
|
+
export function recordWallViewed(placement: string, teaserKind?: "summary" | "sample" | "none"): void {
|
|
529
|
+
recordResearchActivity("wall_viewed", undefined, undefined, { placement, teaser_kind: teaserKind });
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/** Counts each sign-in action once per eligible placement and session. */
|
|
533
|
+
export function recordWallCtaClicked(placement: string, cta: "login" | "signup"): void {
|
|
534
|
+
recordResearchActivity("wall_cta_clicked", undefined, undefined, { placement, cta });
|
|
535
|
+
}
|
|
536
|
+
|
|
378
537
|
export function researchUpgradeUrl(returnTo?: string): string {
|
|
379
538
|
const url = new URL("https://gloom.sh/cloud?upgrade=pro");
|
|
380
539
|
if (returnTo) url.searchParams.set("returnTo", returnTo);
|