gloomberb 0.11.3 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/README.zh-CN.md +4 -2
- package/package.json +28 -2
- package/src/api-client/auth.ts +12 -1
- package/src/api-client/data.ts +103 -1
- package/src/api-client/index.test.ts +127 -0
- package/src/api-client/index.ts +139 -3
- package/src/api-client/normalizers.ts +39 -0
- package/src/api-client/paths.ts +85 -1
- package/src/api-client/research-activity.ts +61 -0
- package/src/api-client/types.ts +197 -0
- package/src/app/pane-runtime/index.tsx +15 -12
- package/src/app/pane-runtime/layout-placement.test.ts +27 -0
- package/src/app/pane-runtime/layout-placement.ts +13 -0
- package/src/app/pane-runtime/plugin-bindings.ts +62 -0
- package/src/app.tsx +60 -18
- package/src/architecture/browser-entry-graph.test.ts +96 -0
- package/src/brokers/profile-form.test.ts +25 -27
- package/src/brokers/test-broker.ts +68 -0
- package/src/cli/commands/plugins.ts +43 -14
- package/src/cli/desktop-pane-shot.ts +362 -24
- package/src/cli/index.ts +1 -1
- package/src/cli/pane-functions/capabilities.ts +126 -43
- package/src/cli/pane-functions/catalog.ts +16 -4
- package/src/cli/pane-functions/discovery.ts +1 -0
- package/src/cli/pane-functions/dom.test.ts +41 -0
- package/src/cli/pane-functions/dom.ts +199 -0
- package/src/cli/pane-functions/headless.test.ts +247 -0
- package/src/cli/pane-functions/headless.ts +423 -0
- package/src/cli/pane-functions/index.test.ts +20 -0
- package/src/cli/pane-functions/index.ts +10 -6
- package/src/cli/pane-functions/intraday-shot.test.ts +307 -0
- package/src/cli/pane-functions/intraday-shot.ts +334 -0
- package/src/cli/pane-functions/options.ts +27 -2
- package/src/cli/pane-functions/report.test.ts +29 -1
- package/src/cli/pane-functions/report.ts +69 -4
- package/src/cli/pane-functions/resolver.ts +26 -8
- package/src/cli/pane-functions/screenshot.test.ts +76 -0
- package/src/cli/pane-functions/screenshot.ts +428 -42
- package/src/cli/restore-plugins.ts +41 -0
- package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
- package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
- package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
- package/src/components/chart/composite/composite-chart.test.tsx +136 -21
- package/src/components/chart/composite/composite-chart.tsx +378 -215
- package/src/components/chart/composite/format.ts +8 -2
- package/src/components/chart/composite/interactions.test.ts +68 -102
- package/src/components/chart/composite/interactions.ts +214 -264
- package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
- package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
- package/src/components/chart/composite/rasterizer.ts +33 -0
- package/src/components/chart/composite/renderers.test.ts +51 -4
- package/src/components/chart/composite/scene.test.ts +128 -2
- package/src/components/chart/composite/scene.ts +149 -19
- package/src/components/chart/composite/text-renderer.ts +16 -2
- package/src/components/chart/composite/time-scale.ts +163 -62
- package/src/components/chart/composite/types.ts +51 -1
- package/src/components/chart/core/data.ts +9 -13
- package/src/components/chart/core/date-window.ts +7 -1
- package/src/components/chart/core/pointer.ts +3 -0
- package/src/components/chart/core/types.ts +0 -45
- package/src/components/chart/native/chart-rasterizer.ts +0 -1
- package/src/components/chart/native/kitty/index.test.ts +0 -188
- package/src/components/chart/native/raster/crosshair.ts +6 -5
- package/src/components/chart/native/raster/primitives.ts +0 -23
- package/src/components/chart/native/renderer-selection.ts +81 -31
- package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
- package/src/components/chart/static/chart-surface.tsx +150 -0
- package/src/components/chart/static/index.ts +8 -0
- package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
- package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
- package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
- package/src/components/chart/static/series.ts +49 -0
- package/src/components/command-bar/action-runtime.ts +1 -3
- package/src/components/command-bar/assist/model.test.ts +17 -2
- package/src/components/command-bar/assist/model.ts +40 -9
- package/src/components/command-bar/commands/direct/index.ts +1 -1
- package/src/components/command-bar/commands/direct/runtime.ts +1 -1
- package/src/components/command-bar/commands/registry.ts +0 -11
- package/src/components/command-bar/helpers.test.ts +2 -2
- package/src/components/command-bar/helpers.ts +2 -6
- package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
- package/src/components/command-bar/list/badge.test.ts +54 -0
- package/src/components/command-bar/list/badge.ts +62 -0
- package/src/components/command-bar/list/model.test.ts +103 -0
- package/src/components/command-bar/list/model.ts +61 -4
- package/src/components/command-bar/list/view.test.tsx +113 -0
- package/src/components/command-bar/list/view.tsx +147 -131
- package/src/components/command-bar/pane-templates/workflow.ts +1 -1
- package/src/components/command-bar/panel/body.tsx +51 -65
- package/src/components/command-bar/panel/index.tsx +48 -13
- package/src/components/command-bar/panel/layout.test.ts +139 -0
- package/src/components/command-bar/panel/layout.ts +65 -28
- package/src/components/command-bar/panel/native-surface.ts +24 -0
- package/src/components/command-bar/panel/prompt-binding.ts +54 -0
- package/src/components/command-bar/panel/runtime.ts +6 -3
- package/src/components/command-bar/panel/state.ts +41 -7
- package/src/components/command-bar/panel/types.ts +7 -1
- package/src/components/command-bar/routes/root/provider-search.ts +34 -15
- package/src/components/command-bar/routes/root/results.test.ts +161 -0
- package/src/components/command-bar/routes/root/results.ts +30 -28
- package/src/components/command-bar/routes/root/runtime.ts +37 -20
- package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
- package/src/components/command-bar/routes/root/search-providers.ts +205 -0
- package/src/components/command-bar/routes/root/selection.ts +1 -12
- package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
- package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
- package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
- package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
- package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
- package/src/components/command-bar/routing/actions.ts +1 -81
- package/src/components/command-bar/routing/launch-request.ts +1 -1
- package/src/components/command-bar/routing/list-state.ts +6 -21
- package/src/components/command-bar/selection-runtime.ts +1 -1
- package/src/components/command-bar/surface/assist.test.tsx +34 -19
- package/src/components/command-bar/surface/environment.ts +8 -1
- package/src/components/command-bar/surface/index.test.tsx +84 -68
- package/src/components/command-bar/surface/index.tsx +33 -36
- package/src/components/command-bar/surface/test-harness.tsx +38 -7
- package/src/components/command-bar/theme-picker.tsx +43 -15
- package/src/components/command-bar/view-model.test.ts +53 -8
- package/src/components/command-bar/view-model.ts +43 -14
- package/src/components/command-bar/workflow/tickers.ts +1 -0
- package/src/components/command-bar/workflow/types.ts +1 -1
- package/src/components/data-table/view.test.tsx +45 -6
- package/src/components/data-table/view.tsx +55 -9
- package/src/components/index.ts +10 -2
- package/src/components/input-search-bar.test.tsx +36 -2
- package/src/components/input-search-bar.tsx +18 -1
- package/src/components/layout/header.test.tsx +57 -10
- package/src/components/layout/header.tsx +292 -149
- package/src/components/layout/market-summary.test.ts +81 -0
- package/src/components/layout/market-summary.ts +109 -0
- package/src/components/layout/shell/chrome.ts +96 -1
- package/src/components/layout/shell/index.tsx +11 -3
- package/src/components/layout/shell/menu.ts +9 -0
- package/src/components/layout/shell/pane/actions.ts +29 -0
- package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
- package/src/components/layout/shell/shortcuts.ts +3 -0
- package/src/components/layout/status-bar.test.tsx +9 -8
- package/src/components/layout/status-bar.tsx +85 -54
- package/src/components/onboarding/account-step/chooser-panel.tsx +2 -2
- package/src/components/onboarding/account-step/qr-panel.tsx +2 -10
- package/src/components/onboarding/onboarding-frame.tsx +2 -26
- package/src/components/onboarding/onboarding-wizard.test.tsx +38 -12
- package/src/components/onboarding/onboarding-wizard.tsx +49 -14
- package/src/components/price-sparkline/index.ts +61 -34
- package/src/components/price-sparkline/view.tsx +1 -1
- package/src/components/sign-in-gate.test.tsx +128 -0
- package/src/components/sign-in-gate.tsx +149 -0
- package/src/components/speedometer-gauge/desktop.tsx +2 -12
- package/src/components/ticker/badge/list.tsx +17 -3
- package/src/components/ticker/list-table-view.tsx +6 -3
- package/src/components/ui/data-table/index.tsx +3 -2
- package/src/components/ui/data-table/opentui/index.tsx +165 -120
- package/src/components/ui/frame.tsx +28 -0
- package/src/components/ui/index.ts +3 -0
- package/src/components/ui/native-select.tsx +20 -10
- package/src/components/ui/select-button.tsx +138 -0
- package/src/components/ui/status.tsx +2 -2
- package/src/components/ui/table-layout.ts +1 -1
- package/src/components/use-double-click-activation.ts +7 -3
- package/src/core/app-services.ts +3 -3
- package/src/data/config/layout.ts +12 -6
- package/src/data/config/store/index.test.ts +120 -0
- package/src/data/config/store/migrations.ts +41 -0
- package/src/data/config/store/node.ts +7 -1
- package/src/data/config/store/normalize.ts +9 -3
- package/src/i18n/es.ts +6 -2
- package/src/i18n/ja.ts +6 -2
- package/src/i18n/ko.ts +6 -2
- package/src/i18n/zh-cn.ts +6 -2
- package/src/i18n/zh-tw.ts +6 -2
- package/src/layout-marketplace/pane-imagery.ts +1 -0
- package/src/layout-marketplace/payload.test.ts +17 -0
- package/src/layout-marketplace/payload.ts +40 -5
- package/src/market-data/coordinator/index.ts +3 -2
- package/src/market-data/coordinator/quotes.ts +173 -66
- package/src/market-data/coordinator/subscriptions.test.ts +215 -37
- package/src/pane-settings.ts +1 -1
- package/src/plugins/builtin/analytics/pane-model.ts +1 -1
- package/src/plugins/builtin/analytics/view.tsx +1 -1
- package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
- package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
- package/src/plugins/builtin/cds/client.test.ts +20 -0
- package/src/plugins/builtin/cds/client.ts +13 -3
- package/src/plugins/builtin/cds/headless.test.ts +30 -0
- package/src/plugins/builtin/cds/headless.ts +113 -0
- package/src/plugins/builtin/cds/index.tsx +4 -0
- package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
- package/src/plugins/builtin/chart-composer/cli-options.ts +4 -1
- package/src/plugins/builtin/chart-composer/index.tsx +1 -1
- package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
- package/src/plugins/builtin/chat/content/composer.tsx +8 -4
- package/src/plugins/builtin/cloud/askg/protocol.test.ts +189 -0
- package/src/plugins/builtin/cloud/askg/protocol.ts +274 -0
- package/src/plugins/builtin/cloud/auth-dialog.tsx +19 -227
- package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
- package/src/plugins/builtin/cloud/device-signin-dialog.tsx +21 -8
- package/src/plugins/builtin/cloud/plugin.tsx +1 -0
- package/src/plugins/builtin/cloud/verification-panel.tsx +56 -0
- package/src/plugins/builtin/composite-plugins.ts +14 -1
- package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
- package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
- package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
- package/src/plugins/builtin/credit-conditions/client.ts +1 -1
- package/src/plugins/builtin/credit-conditions/headless.test.ts +31 -0
- package/src/plugins/builtin/credit-conditions/headless.ts +55 -0
- package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
- package/src/plugins/builtin/credit-conditions/index.tsx +6 -21
- package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
- package/src/plugins/builtin/earnings-calls/data.ts +223 -0
- package/src/plugins/builtin/earnings-calls/format.ts +49 -0
- package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
- package/src/plugins/builtin/earnings-calls/pane.tsx +760 -0
- package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
- package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
- package/src/plugins/builtin/earnings-calls/transcript-view.tsx +337 -0
- package/src/plugins/builtin/econ/detail-view.tsx +1 -2
- package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
- package/src/plugins/builtin/econ/index.tsx +2 -1
- package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
- package/src/plugins/builtin/econ-statistics/client.ts +92 -0
- package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
- package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
- package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
- package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
- package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
- package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
- package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
- package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
- package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
- package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
- package/src/plugins/builtin/econ-statistics/view.ts +90 -0
- package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
- package/src/plugins/builtin/fear-greed/data.ts +6 -1
- package/src/plugins/builtin/fear-greed/headless.test.ts +53 -0
- package/src/plugins/builtin/fear-greed/headless.ts +84 -0
- package/src/plugins/builtin/fear-greed/index.tsx +4 -0
- package/src/plugins/builtin/help/index.tsx +4 -0
- package/src/plugins/builtin/holders/index.tsx +1 -0
- package/src/plugins/builtin/insider/index.tsx +1 -0
- package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
- package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
- package/src/plugins/builtin/market-movers/client.ts +76 -0
- package/src/plugins/builtin/market-movers/headless.test.ts +34 -0
- package/src/plugins/builtin/market-movers/headless.ts +73 -0
- package/src/plugins/builtin/market-movers/index.tsx +11 -51
- package/src/plugins/builtin/market-valuation/align.ts +122 -0
- package/src/plugins/builtin/market-valuation/cache.ts +32 -0
- package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
- package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
- package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
- package/src/plugins/builtin/market-valuation/client.ts +116 -0
- package/src/plugins/builtin/market-valuation/defs.ts +251 -0
- package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
- package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
- package/src/plugins/builtin/market-valuation/headless.ts +170 -0
- package/src/plugins/builtin/market-valuation/index.tsx +64 -0
- package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
- package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
- package/src/plugins/builtin/market-valuation/model.ts +8 -0
- package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
- package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
- package/src/plugins/builtin/market-valuation/series.ts +12 -0
- package/src/plugins/builtin/market-valuation/settings.ts +38 -0
- package/src/plugins/builtin/market-valuation/sources.ts +130 -0
- package/src/plugins/builtin/market-valuation/trend.ts +89 -0
- package/src/plugins/builtin/market-valuation/view.ts +137 -0
- package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
- package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
- package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
- package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
- package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
- package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
- package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
- package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
- package/src/plugins/builtin/news/wire/index.tsx +31 -44
- package/src/plugins/builtin/options/index.tsx +1 -0
- package/src/plugins/builtin/options/view.test.tsx +29 -1
- package/src/plugins/builtin/options/view.tsx +1 -22
- package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
- package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
- package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
- package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
- package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
- package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
- package/src/plugins/builtin/plugin-module.ts +9 -1
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -237
- package/src/plugins/builtin/research/event-model.ts +245 -0
- package/src/plugins/builtin/research/events-headless.test.ts +32 -0
- package/src/plugins/builtin/research/events-headless.ts +87 -0
- package/src/plugins/builtin/research/index.tsx +8 -0
- package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
- package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
- package/src/plugins/builtin/research-search/data.ts +109 -0
- package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
- package/src/plugins/builtin/research-search/document-view.tsx +254 -0
- package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
- package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
- package/src/plugins/builtin/research-search/index.tsx +85 -0
- package/src/plugins/builtin/research-search/model.test.ts +40 -0
- package/src/plugins/builtin/research-search/model.ts +291 -0
- package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
- package/src/plugins/builtin/research-search/pane.tsx +682 -0
- package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
- package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
- package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
- package/src/plugins/builtin/research-search/snippet.ts +134 -0
- package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
- package/src/plugins/builtin/scanner/flow-model.ts +29 -1
- package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
- package/src/plugins/builtin/scanner/headless.test.ts +59 -0
- package/src/plugins/builtin/scanner/headless.ts +125 -0
- package/src/plugins/builtin/scanner/index.ts +4 -0
- package/src/plugins/builtin/sec/index.tsx +1 -0
- package/src/plugins/builtin/sectors/client.ts +54 -0
- package/src/plugins/builtin/sectors/headless.test.ts +28 -0
- package/src/plugins/builtin/sectors/headless.ts +80 -0
- package/src/plugins/builtin/sectors/index.tsx +6 -51
- package/src/plugins/builtin/shared/cloud-upgrade.ts +8 -4
- package/src/plugins/builtin/shared/series-cache.ts +93 -0
- package/src/plugins/builtin/short-interest/index.tsx +1 -0
- package/src/plugins/builtin/short-interest/pane.tsx +1 -1
- package/src/plugins/builtin/thirteenf/index.tsx +1 -0
- package/src/plugins/builtin/ticker-detail/index.tsx +0 -14
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
- package/src/plugins/builtin/ticker-detail/pane.tsx +14 -0
- package/src/plugins/builtin/treasury-auctions/headless.test.ts +34 -0
- package/src/plugins/builtin/treasury-auctions/headless.ts +95 -0
- package/src/plugins/builtin/treasury-auctions/index.tsx +4 -0
- package/src/plugins/builtin/volatility/client.ts +16 -3
- package/src/plugins/builtin/volatility/headless.test.ts +35 -0
- package/src/plugins/builtin/volatility/headless.ts +75 -0
- package/src/plugins/builtin/volatility/index.tsx +5 -1
- package/src/plugins/builtin/world-indices/client.ts +43 -0
- package/src/plugins/builtin/world-indices/headless.test.ts +32 -0
- package/src/plugins/builtin/world-indices/headless.ts +109 -0
- package/src/plugins/builtin/world-indices/index.tsx +4 -0
- package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
- package/src/plugins/builtin/world-venue-map/map.tsx +213 -69
- package/src/plugins/builtin/world-venue-map/model.test.ts +32 -0
- package/src/plugins/builtin/world-venue-map/model.ts +134 -13
- package/src/plugins/builtin/yield-curve/headless.test.ts +24 -0
- package/src/plugins/builtin/yield-curve/headless.ts +67 -0
- package/src/plugins/builtin/yield-curve/index.tsx +7 -9
- package/src/plugins/builtin/yield-curve/treasury-data.ts +16 -6
- package/src/plugins/bundle.test.ts +166 -0
- package/src/plugins/bundle.ts +141 -0
- package/src/plugins/catalog-backend.test.ts +26 -0
- package/src/plugins/catalog-backend.ts +9 -2
- package/src/plugins/catalog-browser.test.ts +1 -13
- package/src/plugins/catalog-browser.ts +14 -0
- package/src/plugins/catalog-manifest.test.ts +58 -0
- package/src/plugins/catalog-manifest.ts +99 -0
- package/src/plugins/catalog-ui.ts +20 -10
- package/src/plugins/catalog.ts +9 -2
- package/src/plugins/current-target.ts +28 -0
- package/src/plugins/host-contract.ts +46 -0
- package/src/plugins/host-link.ts +158 -0
- package/src/plugins/host-modules.ts +73 -0
- package/src/plugins/loader.ts +90 -23
- package/src/plugins/ownership.ts +1 -0
- package/src/plugins/prediction-markets/index.tsx +1 -0
- package/src/plugins/registry/context.ts +3 -0
- package/src/plugins/registry/contributions.ts +27 -0
- package/src/plugins/registry/index.test.ts +25 -0
- package/src/plugins/registry/index.ts +8 -0
- package/src/plugins/registry/pane-settings.ts +6 -13
- package/src/plugins/seed.test.ts +83 -0
- package/src/plugins/seed.ts +83 -0
- package/src/public/broker.ts +37 -0
- package/src/public/market-data.ts +9 -0
- package/src/public/pane-hooks.ts +57 -0
- package/src/public/public-api.test.ts +285 -0
- package/src/public/react.ts +62 -0
- package/src/public/test-support.ts +23 -0
- package/src/public/time-series.ts +8 -0
- package/src/public/utils.ts +77 -0
- package/src/remote/layout-helpers.ts +6 -8
- package/src/remote/resources.ts +2 -0
- package/src/remote/schema.test.ts +65 -0
- package/src/remote/schema.ts +323 -39
- package/src/remote/semantic-tree.test.tsx +105 -0
- package/src/remote/semantic-tree.tsx +53 -35
- package/src/remote/types.ts +49 -2
- package/src/renderers/browser/app-services.ts +3 -0
- package/src/renderers/browser/config-host.ts +24 -8
- package/src/renderers/browser/deeplink-bridge.test.ts +11 -0
- package/src/renderers/browser/deeplink-bridge.ts +15 -3
- package/src/renderers/browser/main.tsx +8 -0
- package/src/renderers/browser/research-entry.test.ts +8 -0
- package/src/renderers/browser/research-entry.ts +7 -0
- package/src/renderers/cloudflare/worker.test.ts +19 -0
- package/src/renderers/cloudflare/worker.ts +1 -1
- package/src/renderers/electrobun/bun/desktop/backend-requests.ts +2 -2
- package/src/renderers/electrobun/bun/desktop/initialization.ts +10 -3
- package/src/renderers/electrobun/bun/external-plugins.ts +156 -0
- package/src/renderers/electrobun/bun/index.ts +5 -2
- package/src/renderers/electrobun/shared/protocol.ts +21 -0
- package/src/renderers/electrobun/view/build-assets.ts +0 -3
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +114 -11
- package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
- package/src/renderers/electrobun/view/external-plugins.ts +63 -0
- package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
- package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
- package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
- package/src/renderers/electrobun/view/host/mouse.ts +16 -2
- package/src/renderers/electrobun/view/main.tsx +27 -2
- package/src/renderers/electrobun/view/styles.css +5 -0
- package/src/renderers/electrobun/view/toast-host.tsx +18 -0
- package/src/renderers/opentui/chart-surface.tsx +5 -1
- package/src/renderers/opentui/host.tsx +16 -2
- package/src/renderers/opentui/interaction-performance.test.ts +79 -0
- package/src/renderers/opentui/interaction-performance.ts +188 -0
- package/src/renderers/opentui/start.tsx +26 -1
- package/src/renderers/opentui/test-utils.tsx +13 -0
- package/src/renderers/opentui/toast-host.tsx +26 -2
- package/src/renderers/opentui/ui-host.tsx +1 -0
- package/src/sources/provider-router/search.test.ts +191 -0
- package/src/sources/provider-router/search.ts +92 -39
- package/src/state/app/context/index.tsx +2 -0
- package/src/state/app/context/selector.test.tsx +33 -1
- package/src/state/hooks/quote-streaming.test.tsx +93 -0
- package/src/state/hooks/quote-streaming.ts +106 -30
- package/src/state/pane-table-export-registry.ts +19 -0
- package/src/sync/core-contributors.test.ts +111 -0
- package/src/sync/core-contributors.ts +155 -1
- package/src/theme/color-utils.ts +1 -1
- package/src/theme/colors.ts +50 -0
- package/src/theme/themes.test.ts +15 -2
- package/src/theme/themes.ts +19 -1
- package/src/tickers/search/index.test.ts +26 -0
- package/src/tickers/search/index.ts +42 -17
- package/src/tickers/search/ranking.ts +14 -0
- package/src/time-series/chart-data.test.ts +216 -0
- package/src/time-series/resolution.test.ts +25 -26
- package/src/time-series/resolution.ts +41 -10
- package/src/time-series/resolve.test.ts +118 -1
- package/src/time-series/resolve.ts +21 -16
- package/src/time-series/types.ts +3 -1
- package/src/time-series/use-chart-resolution.ts +5 -0
- package/src/types/config.ts +125 -3
- package/src/types/data-provider.ts +11 -0
- package/src/types/headless.ts +161 -0
- package/src/types/plugin.ts +102 -0
- package/src/ui/host.tsx +12 -1
- package/src/ui/index.tsx +1 -0
- package/src/ui/toast.tsx +8 -4
- package/src/utils/format.ts +35 -0
- package/src/utils/fuzzy-search.test.ts +94 -0
- package/src/utils/fuzzy-search.ts +81 -22
- package/src/utils/shortcut-labels.ts +14 -0
- package/src/components/chart/core/axis-format.ts +0 -157
- package/src/components/chart/core/index.test.ts +0 -1075
- package/src/components/chart/core/projection.ts +0 -357
- package/src/components/chart/core/render-utils.ts +0 -4
- package/src/components/chart/core/renderer.ts +0 -244
- package/src/components/chart/core/scene.ts +0 -180
- package/src/components/chart/core/time-axis.ts +0 -330
- package/src/components/chart/cursor-motion.ts +0 -47
- package/src/components/chart/indicators/types.ts +0 -26
- package/src/components/chart/market-session.ts +0 -176
- package/src/components/chart/multi-line/renderer.test.ts +0 -83
- package/src/components/chart/multi-line/renderer.ts +0 -161
- package/src/components/chart/multi-line/scene.ts +0 -188
- package/src/components/chart/native/raster/layout.ts +0 -129
- package/src/components/chart/native/raster/price-chart.ts +0 -244
- package/src/components/chart/rendering/chart-draw.ts +0 -270
- package/src/components/chart/rendering/geometry.ts +0 -95
- package/src/components/chart/rendering/pixel-buffer.ts +0 -267
- package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
- package/src/components/chart/scatter-chart-renderer.ts +0 -223
- package/src/components/chart/static/chart/surface.tsx +0 -358
- package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
- package/src/components/command-bar/routes/root/article-results.ts +0 -55
- package/src/plugins/broker-sync/broker-sync.test.ts +0 -188
- package/src/plugins/broker-sync/native-loader.ts +0 -10
- package/src/plugins/broker-sync/normalize.ts +0 -308
- package/src/plugins/broker-sync/public.ts +0 -122
- package/src/plugins/broker-sync/robinhood-native.ts +0 -367
- package/src/plugins/broker-sync/robinhood.ts +0 -114
- package/src/plugins/broker-sync/simplefin-native.ts +0 -201
- package/src/plugins/broker-sync/simplefin.ts +0 -70
- package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
- package/src/plugins/builtin/news/wire/article-search.ts +0 -140
- package/src/plugins/builtin/substack/api/auth.ts +0 -185
- package/src/plugins/builtin/substack/api/cache.ts +0 -82
- package/src/plugins/builtin/substack/api/loaders.ts +0 -170
- package/src/plugins/builtin/substack/api/store.ts +0 -186
- package/src/plugins/builtin/substack/api/types.ts +0 -42
- package/src/plugins/builtin/substack/api.test.ts +0 -298
- package/src/plugins/builtin/substack/article-detail.tsx +0 -397
- package/src/plugins/builtin/substack/article-stack.tsx +0 -133
- package/src/plugins/builtin/substack/content.ts +0 -478
- package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
- package/src/plugins/builtin/substack/index.tsx +0 -49
- package/src/plugins/builtin/substack/login-view.tsx +0 -126
- package/src/plugins/builtin/substack/model.test.ts +0 -155
- package/src/plugins/builtin/substack/normalize.ts +0 -343
- package/src/plugins/builtin/substack/pane-footer.ts +0 -52
- package/src/plugins/builtin/substack/pane-state.ts +0 -170
- package/src/plugins/builtin/substack/pane.tsx +0 -547
- package/src/plugins/builtin/substack/read-state.ts +0 -30
- package/src/plugins/builtin/substack/table.ts +0 -111
- package/src/plugins/builtin/substack/types.ts +0 -71
- package/src/plugins/builtin/substack/utils.ts +0 -131
- package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
- package/src/plugins/ibkr/account-cache.test.ts +0 -102
- package/src/plugins/ibkr/account-cache.ts +0 -24
- package/src/plugins/ibkr/broker-adapter.ts +0 -286
- package/src/plugins/ibkr/config.test.ts +0 -79
- package/src/plugins/ibkr/config.ts +0 -250
- package/src/plugins/ibkr/dialogs.tsx +0 -40
- package/src/plugins/ibkr/flex/index.test.ts +0 -264
- package/src/plugins/ibkr/flex/index.ts +0 -367
- package/src/plugins/ibkr/flex/statement-client.ts +0 -235
- package/src/plugins/ibkr/fundamental-parser.ts +0 -149
- package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
- package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
- package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
- package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
- package/src/plugins/ibkr/gateway/connection.ts +0 -152
- package/src/plugins/ibkr/gateway/contracts.ts +0 -132
- package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
- package/src/plugins/ibkr/gateway/helpers.ts +0 -33
- package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
- package/src/plugins/ibkr/gateway/history.ts +0 -120
- package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
- package/src/plugins/ibkr/gateway/market-data.ts +0 -345
- package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
- package/src/plugins/ibkr/gateway/orders.ts +0 -63
- package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
- package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
- package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
- package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
- package/src/plugins/ibkr/gateway/selection.ts +0 -51
- package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
- package/src/plugins/ibkr/gateway/service/index.ts +0 -429
- package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
- package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
- package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
- package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
- package/src/plugins/ibkr/gateway/service/native.ts +0 -543
- package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
- package/src/plugins/ibkr/gateway/types.ts +0 -27
- package/src/plugins/ibkr/index.test.tsx +0 -162
- package/src/plugins/ibkr/index.tsx +0 -159
- package/src/plugins/ibkr/instance-selection.test.ts +0 -120
- package/src/plugins/ibkr/instance-selection.ts +0 -36
- package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
- package/src/plugins/ibkr/portfolio-performance.ts +0 -129
- package/src/plugins/ibkr/trade/badge.tsx +0 -28
- package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
- package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
- package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
- package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
- package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
- package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
- package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
- package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
- package/src/plugins/ibkr/trade/tab/model.ts +0 -159
- package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
- package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
- package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
- package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
- package/src/plugins/ibkr/trade/utils.test.ts +0 -175
- package/src/plugins/ibkr/trade/utils.ts +0 -144
- package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
- package/src/plugins/ibkr/trading/pane.tsx +0 -332
- package/src/plugins/ibkr/trading/state.test.ts +0 -109
- package/src/plugins/ibkr/trading/state.ts +0 -335
- package/src/renderers/electrobun/view/native-stubs/broker-sync-native-loader.ts +0 -7
|
@@ -1,19 +1,33 @@
|
|
|
1
1
|
import { mkdir, mkdtemp, rm, writeFile } from "fs/promises";
|
|
2
2
|
import { tmpdir } from "os";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { pathToFileURL } from "url";
|
|
3
|
+
import { join, resolve, sep } from "path";
|
|
5
4
|
import type { AppConfig } from "../types/config";
|
|
6
5
|
import type { ResolvedSeries } from "../time-series/types";
|
|
7
|
-
import type { OptionsChain, TickerFinancials } from "../types/financials";
|
|
6
|
+
import type { OptionsChain, PricePoint, TickerFinancials } from "../types/financials";
|
|
7
|
+
import type { ManualChartResolution } from "../time-series/resolution";
|
|
8
8
|
import type { TickerRecord } from "../types/ticker";
|
|
9
9
|
import type { PaneRuntimeState } from "../core/state/app/state";
|
|
10
10
|
import type { RemoteUiNodeSnapshot } from "../remote/types";
|
|
11
11
|
import type { FredSeriesCacheEntry } from "../data/fred-series";
|
|
12
|
+
import type { DatedObservation } from "../plugins/builtin/market-valuation/series";
|
|
12
13
|
import {
|
|
13
14
|
electrobunViewPath,
|
|
14
15
|
writeElectrobunViewPage,
|
|
15
16
|
} from "../renderers/electrobun/view/build-assets";
|
|
16
17
|
|
|
18
|
+
export interface DesktopPaneShotIntradayHistory {
|
|
19
|
+
symbol: string;
|
|
20
|
+
exchange: string;
|
|
21
|
+
rangePreset: "1D" | "1W";
|
|
22
|
+
resolution: ManualChartResolution;
|
|
23
|
+
requestedSession: string | null;
|
|
24
|
+
sessionDates: string[];
|
|
25
|
+
points: PricePoint[];
|
|
26
|
+
start: string | null;
|
|
27
|
+
end: string | null;
|
|
28
|
+
unavailableReason: string | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
17
31
|
export interface DesktopPaneShotPayload {
|
|
18
32
|
config: AppConfig;
|
|
19
33
|
paneId: string;
|
|
@@ -21,16 +35,49 @@ export interface DesktopPaneShotPayload {
|
|
|
21
35
|
heightCells: number;
|
|
22
36
|
widthPx: number;
|
|
23
37
|
heightPx: number;
|
|
38
|
+
/** Chrome device scale factor; 2 keeps text crisp, higher values zoom the layout. */
|
|
39
|
+
deviceScaleFactor?: number;
|
|
40
|
+
/** Label drawn at the right edge of the pane title bar; null draws nothing. */
|
|
41
|
+
watermark?: string | null;
|
|
24
42
|
tickers: TickerRecord[];
|
|
25
43
|
financials: Array<[string, TickerFinancials]>;
|
|
44
|
+
intradayHistories: DesktopPaneShotIntradayHistory[];
|
|
26
45
|
optionsChains: Array<[string, OptionsChain]>;
|
|
27
46
|
fredSeries: Array<[string, FredSeriesCacheEntry]>;
|
|
47
|
+
valuationSeries: Array<[string, DatedObservation[]]>;
|
|
48
|
+
statSeries: Array<[string, DatedObservation[]]>;
|
|
28
49
|
capabilitySeries: Array<[string, ResolvedSeries]>;
|
|
29
50
|
paneState: Record<string, PaneRuntimeState>;
|
|
30
51
|
}
|
|
31
52
|
|
|
53
|
+
/** Kept in Bun memory and never serialized into the browser page or CLI result. */
|
|
54
|
+
export interface DesktopPaneShotApiProxy {
|
|
55
|
+
baseUrl: string;
|
|
56
|
+
sessionToken: string | null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface DesktopPaneShotRenderedCell {
|
|
60
|
+
columnId?: string;
|
|
61
|
+
columnLabel: string;
|
|
62
|
+
text: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface DesktopPaneShotRenderedRow {
|
|
66
|
+
tableIndex: number;
|
|
67
|
+
rowIndex: number;
|
|
68
|
+
key?: string;
|
|
69
|
+
selected: boolean;
|
|
70
|
+
cells: DesktopPaneShotRenderedCell[];
|
|
71
|
+
}
|
|
72
|
+
|
|
32
73
|
export interface DesktopPaneShotRenderResult {
|
|
33
74
|
visibleText: string;
|
|
75
|
+
rows: DesktopPaneShotRenderedRow[];
|
|
76
|
+
truncated: boolean;
|
|
77
|
+
truncationReasons: string[];
|
|
78
|
+
loadingStateDetected: boolean;
|
|
79
|
+
errorStateDetected: boolean;
|
|
80
|
+
errorStateMarkers: string[];
|
|
34
81
|
emptyStateDetected: boolean;
|
|
35
82
|
emptyStateMarkers: string[];
|
|
36
83
|
semanticUi: RemoteUiNodeSnapshot[];
|
|
@@ -47,30 +94,49 @@ type PendingCdpCall = {
|
|
|
47
94
|
reject: (error: Error) => void;
|
|
48
95
|
};
|
|
49
96
|
|
|
97
|
+
const SHOT_MODE_CSS = [
|
|
98
|
+
"[data-gloom-role='composite-chart-toolbar']",
|
|
99
|
+
"[data-gloom-role='chart-series-quick-add']",
|
|
100
|
+
"[data-gloom-role='pane-close']",
|
|
101
|
+
].join(", ") + " { display: none !important; }\n"
|
|
102
|
+
// Sits where the hidden close button was: one cell high, right-aligned in the title bar.
|
|
103
|
+
+ "[data-gloom-role='shot-watermark'] { position: fixed; top: 1px; right: 10px; height: var(--cell-h);"
|
|
104
|
+
+ " line-height: var(--cell-h); font-size: 12px; letter-spacing: 0.02em; color: var(--gloom-text-dim, #888);"
|
|
105
|
+
+ " pointer-events: none; z-index: 1000; }";
|
|
106
|
+
|
|
50
107
|
const CHROME_POLL_ATTEMPTS = 80;
|
|
51
|
-
const SHOT_READY_TIMEOUT_MS =
|
|
108
|
+
const SHOT_READY_TIMEOUT_MS = 45_000;
|
|
52
109
|
const CDP_CALL_TIMEOUT_MS = 10_000;
|
|
53
|
-
const
|
|
110
|
+
const DEFAULT_DEVICE_SCALE_FACTOR = 2;
|
|
111
|
+
const SHOT_API_PROXY_PREFIX = "/__gloom_cli_api__";
|
|
112
|
+
const SESSION_COOKIE_NAMES = ["__Secure-gloomberb.session_token", "gloomberb.session_token"] as const;
|
|
54
113
|
|
|
55
114
|
export async function renderDesktopPaneScreenshot(
|
|
56
115
|
payload: DesktopPaneShotPayload,
|
|
57
116
|
outputPath: string,
|
|
117
|
+
apiProxy: DesktopPaneShotApiProxy,
|
|
118
|
+
options: { captureImage?: boolean } = {},
|
|
58
119
|
): Promise<DesktopPaneShotRenderResult> {
|
|
59
120
|
const tempDir = await mkdtemp(join(tmpdir(), "gloom-pane-shot-"));
|
|
121
|
+
let server: ReturnType<typeof Bun.serve> | null = null;
|
|
60
122
|
try {
|
|
61
123
|
const outdir = join(tempDir, "assets");
|
|
62
124
|
await mkdir(outdir, { recursive: true });
|
|
63
|
-
|
|
125
|
+
await buildShotPage(outdir, payload);
|
|
126
|
+
server = serveShotPage(outdir, apiProxy);
|
|
64
127
|
const chrome = await findChromeExecutable();
|
|
65
128
|
return await capturePageScreenshot({
|
|
66
129
|
chrome,
|
|
67
|
-
url:
|
|
130
|
+
url: new URL("/", server.url).href,
|
|
68
131
|
outputPath,
|
|
69
132
|
widthPx: payload.widthPx,
|
|
70
133
|
heightPx: payload.heightPx,
|
|
134
|
+
deviceScaleFactor: payload.deviceScaleFactor ?? DEFAULT_DEVICE_SCALE_FACTOR,
|
|
71
135
|
userDataDir: join(tempDir, "chrome-profile"),
|
|
136
|
+
captureImage: options.captureImage !== false,
|
|
72
137
|
});
|
|
73
138
|
} finally {
|
|
139
|
+
server?.stop(true);
|
|
74
140
|
await rm(tempDir, { recursive: true, force: true });
|
|
75
141
|
}
|
|
76
142
|
}
|
|
@@ -90,6 +156,20 @@ async function buildShotPage(outdir: string, payload: DesktopPaneShotPayload): P
|
|
|
90
156
|
loadingText: "Rendering pane...",
|
|
91
157
|
bootstrapScript: `
|
|
92
158
|
window.__GLOOM_CLI_SHOT_PAYLOAD__ = ${payloadJson};
|
|
159
|
+
(() => {
|
|
160
|
+
// A screenshot cannot be interacted with, so drawing tools, the
|
|
161
|
+
// quick-add input and the close button only add noise to the image.
|
|
162
|
+
const style = document.createElement("style");
|
|
163
|
+
style.textContent = ${JSON.stringify(SHOT_MODE_CSS)};
|
|
164
|
+
document.head.appendChild(style);
|
|
165
|
+
const watermark = ${JSON.stringify(payload.watermark ?? null)};
|
|
166
|
+
if (watermark) {
|
|
167
|
+
const mark = document.createElement("div");
|
|
168
|
+
mark.setAttribute("data-gloom-role", "shot-watermark");
|
|
169
|
+
mark.textContent = watermark;
|
|
170
|
+
document.addEventListener("DOMContentLoaded", () => document.body.appendChild(mark));
|
|
171
|
+
}
|
|
172
|
+
})();
|
|
93
173
|
window.addEventListener("error", (event) => {
|
|
94
174
|
window.__GLOOM_CLI_SHOT_ERROR__ = event.error && event.error.stack ? event.error.stack : String(event.error || event.message);
|
|
95
175
|
});
|
|
@@ -100,6 +180,116 @@ async function buildShotPage(outdir: string, payload: DesktopPaneShotPayload): P
|
|
|
100
180
|
});
|
|
101
181
|
}
|
|
102
182
|
|
|
183
|
+
function serveShotPage(
|
|
184
|
+
outdir: string,
|
|
185
|
+
apiProxy: DesktopPaneShotApiProxy,
|
|
186
|
+
): ReturnType<typeof Bun.serve> {
|
|
187
|
+
const staticRoot = resolve(outdir);
|
|
188
|
+
return Bun.serve({
|
|
189
|
+
hostname: "127.0.0.1",
|
|
190
|
+
port: 0,
|
|
191
|
+
idleTimeout: 60,
|
|
192
|
+
fetch(request) {
|
|
193
|
+
const url = new URL(request.url);
|
|
194
|
+
if (url.pathname.startsWith(`${SHOT_API_PROXY_PREFIX}/`)) {
|
|
195
|
+
return proxyShotApiRequest(request, url, apiProxy);
|
|
196
|
+
}
|
|
197
|
+
return serveShotAsset(url, staticRoot);
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function serveShotAsset(url: URL, staticRoot: string): Promise<Response> {
|
|
203
|
+
let pathname: string;
|
|
204
|
+
try {
|
|
205
|
+
pathname = decodeURIComponent(url.pathname);
|
|
206
|
+
} catch {
|
|
207
|
+
return new Response("Bad request", { status: 400 });
|
|
208
|
+
}
|
|
209
|
+
const relativePath = pathname === "/" ? "index.html" : pathname.replace(/^\/+/, "");
|
|
210
|
+
const filePath = resolve(staticRoot, relativePath);
|
|
211
|
+
if (filePath !== staticRoot && !filePath.startsWith(`${staticRoot}${sep}`)) {
|
|
212
|
+
return new Response("Not found", { status: 404 });
|
|
213
|
+
}
|
|
214
|
+
const file = Bun.file(filePath);
|
|
215
|
+
if (!(await file.exists())) return new Response("Not found", { status: 404 });
|
|
216
|
+
return new Response(file);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async function proxyShotApiRequest(
|
|
220
|
+
request: Request,
|
|
221
|
+
requestUrl: URL,
|
|
222
|
+
apiProxy: DesktopPaneShotApiProxy,
|
|
223
|
+
): Promise<Response> {
|
|
224
|
+
const baseUrl = new URL(apiProxy.baseUrl);
|
|
225
|
+
const proxiedPath = requestUrl.pathname.slice(SHOT_API_PROXY_PREFIX.length) || "/";
|
|
226
|
+
const target = new URL(baseUrl);
|
|
227
|
+
const basePath = baseUrl.pathname.replace(/\/+$/, "");
|
|
228
|
+
target.pathname = `${basePath}${proxiedPath.startsWith("/") ? proxiedPath : `/${proxiedPath}`}`;
|
|
229
|
+
target.search = requestUrl.search;
|
|
230
|
+
target.hash = "";
|
|
231
|
+
const headers = new Headers(request.headers);
|
|
232
|
+
for (const name of [
|
|
233
|
+
"authorization",
|
|
234
|
+
"connection",
|
|
235
|
+
"content-length",
|
|
236
|
+
"cookie",
|
|
237
|
+
"host",
|
|
238
|
+
"origin",
|
|
239
|
+
"proxy-authorization",
|
|
240
|
+
"referer",
|
|
241
|
+
"te",
|
|
242
|
+
"trailer",
|
|
243
|
+
"transfer-encoding",
|
|
244
|
+
"upgrade",
|
|
245
|
+
"x-forwarded-for",
|
|
246
|
+
"x-forwarded-host",
|
|
247
|
+
"x-forwarded-proto",
|
|
248
|
+
]) {
|
|
249
|
+
headers.delete(name);
|
|
250
|
+
}
|
|
251
|
+
const browserOwnedHeaders: string[] = [];
|
|
252
|
+
headers.forEach((_value, name) => {
|
|
253
|
+
if (name.startsWith("sec-") || name === "accept-encoding") browserOwnedHeaders.push(name);
|
|
254
|
+
});
|
|
255
|
+
for (const name of browserOwnedHeaders) headers.delete(name);
|
|
256
|
+
headers.set("Origin", baseUrl.origin);
|
|
257
|
+
if (apiProxy.sessionToken) {
|
|
258
|
+
headers.set(
|
|
259
|
+
"Cookie",
|
|
260
|
+
SESSION_COOKIE_NAMES.map((name) => `${name}=${apiProxy.sessionToken}`).join("; "),
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const response = await fetch(target, {
|
|
266
|
+
method: request.method,
|
|
267
|
+
headers,
|
|
268
|
+
body: request.method === "GET" || request.method === "HEAD" ? undefined : request.body,
|
|
269
|
+
redirect: "follow",
|
|
270
|
+
});
|
|
271
|
+
const responseHeaders = new Headers(response.headers);
|
|
272
|
+
for (const name of [
|
|
273
|
+
"access-control-allow-credentials",
|
|
274
|
+
"access-control-allow-origin",
|
|
275
|
+
"content-encoding",
|
|
276
|
+
"content-length",
|
|
277
|
+
"set-cookie",
|
|
278
|
+
"transfer-encoding",
|
|
279
|
+
]) {
|
|
280
|
+
responseHeaders.delete(name);
|
|
281
|
+
}
|
|
282
|
+
responseHeaders.set("Cache-Control", "no-store");
|
|
283
|
+
return new Response(response.body, {
|
|
284
|
+
status: response.status,
|
|
285
|
+
statusText: response.statusText,
|
|
286
|
+
headers: responseHeaders,
|
|
287
|
+
});
|
|
288
|
+
} catch {
|
|
289
|
+
return Response.json({ error: "Cloud API request failed." }, { status: 502 });
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
103
293
|
async function findChromeExecutable(): Promise<string> {
|
|
104
294
|
const candidates = [
|
|
105
295
|
process.env.CHROME_PATH,
|
|
@@ -123,14 +313,18 @@ async function capturePageScreenshot({
|
|
|
123
313
|
outputPath,
|
|
124
314
|
widthPx,
|
|
125
315
|
heightPx,
|
|
316
|
+
deviceScaleFactor,
|
|
126
317
|
userDataDir,
|
|
318
|
+
captureImage,
|
|
127
319
|
}: {
|
|
128
320
|
chrome: string;
|
|
129
321
|
url: string;
|
|
130
322
|
outputPath: string;
|
|
131
323
|
widthPx: number;
|
|
132
324
|
heightPx: number;
|
|
325
|
+
deviceScaleFactor: number;
|
|
133
326
|
userDataDir: string;
|
|
327
|
+
captureImage: boolean;
|
|
134
328
|
}): Promise<DesktopPaneShotRenderResult> {
|
|
135
329
|
await mkdir(userDataDir, { recursive: true });
|
|
136
330
|
const port = 43000 + Math.floor(Math.random() * 10000);
|
|
@@ -166,18 +360,20 @@ async function capturePageScreenshot({
|
|
|
166
360
|
await session.send("Emulation.setDeviceMetricsOverride", {
|
|
167
361
|
width: widthPx,
|
|
168
362
|
height: heightPx,
|
|
169
|
-
deviceScaleFactor
|
|
363
|
+
deviceScaleFactor,
|
|
170
364
|
mobile: false,
|
|
171
365
|
});
|
|
172
366
|
await waitForShotReady(session);
|
|
173
367
|
const rendered = await readRenderedPaneState(session);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
368
|
+
if (captureImage) {
|
|
369
|
+
const screenshot = await session.send("Page.captureScreenshot", {
|
|
370
|
+
format: "png",
|
|
371
|
+
fromSurface: true,
|
|
372
|
+
captureBeyondViewport: false,
|
|
373
|
+
}) as { data?: string };
|
|
374
|
+
if (!screenshot.data) throw new Error("Chrome did not return screenshot data.");
|
|
375
|
+
await writeFile(outputPath, Uint8Array.from(Buffer.from(screenshot.data, "base64")));
|
|
376
|
+
}
|
|
181
377
|
return rendered;
|
|
182
378
|
} catch (error) {
|
|
183
379
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -189,6 +385,22 @@ async function capturePageScreenshot({
|
|
|
189
385
|
}
|
|
190
386
|
}
|
|
191
387
|
|
|
388
|
+
const LOADING_STATE_PATTERNS = [
|
|
389
|
+
/\bLoading(?: [^.]{0,80})?\.{3}/gi,
|
|
390
|
+
/\bRendering pane\.{3}/gi,
|
|
391
|
+
];
|
|
392
|
+
|
|
393
|
+
const ERROR_STATE_PATTERNS = [
|
|
394
|
+
/\b[^.]{1,100} unavailable\./gi,
|
|
395
|
+
/\bFailed to fetch\b/gi,
|
|
396
|
+
/\bCould not load\b/gi,
|
|
397
|
+
/\bSign in to\b/gi,
|
|
398
|
+
/\bVerify your email\b/gi,
|
|
399
|
+
/\brequires signup and email verification\b/gi,
|
|
400
|
+
/\bpart of Gloom Cloud Pro\b/gi,
|
|
401
|
+
/\bCloud API request failed\b/gi,
|
|
402
|
+
];
|
|
403
|
+
|
|
192
404
|
const EMPTY_STATE_PATTERNS = [
|
|
193
405
|
/\bNo chart data\b/gi,
|
|
194
406
|
/\bNo graph data\b/gi,
|
|
@@ -197,21 +409,127 @@ const EMPTY_STATE_PATTERNS = [
|
|
|
197
409
|
/\bNo comparison tickers configured\b/gi,
|
|
198
410
|
/\bNo relationship tickers configured\b/gi,
|
|
199
411
|
/\bNo overlapping price history\b/gi,
|
|
200
|
-
/\
|
|
201
|
-
/\bRendering pane\.{0,3}\b/gi,
|
|
202
|
-
/\bNo tickers selected\b/gi,
|
|
203
|
-
/\bMarket data unavailable\b/gi,
|
|
412
|
+
/\bNo tickers? selected\b/gi,
|
|
204
413
|
/\bNo data(?: available)?\b/gi,
|
|
414
|
+
/\bNothing to show yet\b/gi,
|
|
415
|
+
/\bNo transcribed calls(?: for [^.]+)? yet\b/gi,
|
|
416
|
+
/\bNo short interest (?:data|found)\b/gi,
|
|
417
|
+
/\bNo (?:House PTR |insider )?(?:trades|members|transactions|filings)\b/gi,
|
|
205
418
|
];
|
|
206
419
|
|
|
420
|
+
function stateMarkers(text: string, patterns: RegExp[]): string[] {
|
|
421
|
+
return [...new Set(patterns.flatMap((pattern) => (
|
|
422
|
+
[...text.matchAll(pattern)].map((match) => match[0])
|
|
423
|
+
)))];
|
|
424
|
+
}
|
|
425
|
+
|
|
207
426
|
async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneShotRenderResult> {
|
|
208
427
|
const result = await session.send("Runtime.evaluate", {
|
|
209
428
|
expression: `(() => {
|
|
210
429
|
const root = document.getElementById("root") || document.body;
|
|
430
|
+
const semanticUi = window.__GLOOM_CLI_SHOT_SEMANTIC_UI__ || [];
|
|
431
|
+
const normalize = (value) => String(value || "").replace(/\\s+/g, " ").trim();
|
|
432
|
+
const isVisible = (element) => {
|
|
433
|
+
if (!(element instanceof HTMLElement)) return false;
|
|
434
|
+
const style = getComputedStyle(element);
|
|
435
|
+
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") return false;
|
|
436
|
+
const rect = element.getBoundingClientRect();
|
|
437
|
+
return rect.width > 0 && rect.height > 0
|
|
438
|
+
&& rect.right > 0 && rect.bottom > 0
|
|
439
|
+
&& rect.left < window.innerWidth && rect.top < window.innerHeight;
|
|
440
|
+
};
|
|
441
|
+
const semanticTables = semanticUi.filter((node) => node && node.role === "table");
|
|
442
|
+
const rows = [];
|
|
443
|
+
const truncationReasons = new Set();
|
|
444
|
+
const markScrollTruncation = (element) => {
|
|
445
|
+
if (!(element instanceof HTMLElement) || !isVisible(element)) return;
|
|
446
|
+
if (
|
|
447
|
+
element.getAttribute("data-gloom-scrollbar-y") === "visible"
|
|
448
|
+
|| element.scrollHeight > element.clientHeight + 1
|
|
449
|
+
) {
|
|
450
|
+
truncationReasons.add("rows extend below the rendered viewport");
|
|
451
|
+
}
|
|
452
|
+
if (
|
|
453
|
+
element.getAttribute("data-gloom-scrollbar-x") === "visible"
|
|
454
|
+
|| element.scrollWidth > element.clientWidth + 1
|
|
455
|
+
) {
|
|
456
|
+
truncationReasons.add("columns extend beyond the rendered viewport");
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
[...root.querySelectorAll(
|
|
460
|
+
'[data-gloom-scrollbar-x="visible"], [data-gloom-scrollbar-y="visible"], [data-gloom-role="data-table-body-scroll"]',
|
|
461
|
+
)].forEach(markScrollTruncation);
|
|
462
|
+
[...root.querySelectorAll('[data-gloom-role="data-table"]')]
|
|
463
|
+
.filter(isVisible)
|
|
464
|
+
.forEach((table, tableIndex) => {
|
|
465
|
+
const tableMetadata = semanticTables[tableIndex] && semanticTables[tableIndex].metadata || {};
|
|
466
|
+
const semanticColumns = Array.isArray(tableMetadata.columns) ? tableMetadata.columns : [];
|
|
467
|
+
const semanticRows = Array.isArray(tableMetadata.rows) ? tableMetadata.rows : [];
|
|
468
|
+
const headers = [...table.querySelectorAll('[data-gloom-role="data-table-header-cell"]')]
|
|
469
|
+
.map((cell) => normalize(cell.innerText || cell.textContent));
|
|
470
|
+
const rowElements = [...table.querySelectorAll(
|
|
471
|
+
'[data-gloom-role="data-table-row"], [data-gloom-role="data-table-section-header"]',
|
|
472
|
+
)].filter(isVisible);
|
|
473
|
+
rowElements.forEach((row, rowIndex) => {
|
|
474
|
+
const cellElements = [...row.querySelectorAll('[data-gloom-role="data-table-cell"]')];
|
|
475
|
+
const values = cellElements.length > 0 ? cellElements : [row];
|
|
476
|
+
const semanticRow = semanticRows[rowIndex] || {};
|
|
477
|
+
const cells = values.map((cell, cellIndex) => {
|
|
478
|
+
const semanticColumn = semanticColumns[cellIndex] || {};
|
|
479
|
+
const text = normalize(cell.innerText || cell.textContent);
|
|
480
|
+
const textNodes = [cell, ...cell.querySelectorAll('*')];
|
|
481
|
+
if (
|
|
482
|
+
/\\u2026|\\.\\.\\./.test(text)
|
|
483
|
+
|| textNodes.some((node) => (
|
|
484
|
+
node instanceof HTMLElement
|
|
485
|
+
&& isVisible(node)
|
|
486
|
+
&& node.scrollWidth > node.clientWidth + 1
|
|
487
|
+
))
|
|
488
|
+
) {
|
|
489
|
+
truncationReasons.add("one or more cells are visibly clipped");
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
...(typeof semanticColumn.id === "string" ? { columnId: semanticColumn.id } : {}),
|
|
493
|
+
columnLabel: typeof semanticColumn.label === "string"
|
|
494
|
+
? semanticColumn.label
|
|
495
|
+
: headers[cellIndex] || (values.length === 1 ? "Row" : String(cellIndex + 1)),
|
|
496
|
+
text,
|
|
497
|
+
};
|
|
498
|
+
}).filter((cell) => cell.text.length > 0);
|
|
499
|
+
if (cells.length === 0) return;
|
|
500
|
+
rows.push({
|
|
501
|
+
tableIndex,
|
|
502
|
+
rowIndex,
|
|
503
|
+
...(typeof semanticRow.key === "string" ? { key: semanticRow.key } : {}),
|
|
504
|
+
selected: row.getAttribute("data-selected") === "true" || semanticRow.selected === true,
|
|
505
|
+
cells,
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
if (rows.length === 0) {
|
|
510
|
+
[...root.querySelectorAll('[data-gloom-role="desktop-list-row"]')]
|
|
511
|
+
.filter(isVisible)
|
|
512
|
+
.forEach((row, rowIndex) => {
|
|
513
|
+
const text = normalize(row.innerText || row.textContent);
|
|
514
|
+
if (!text) return;
|
|
515
|
+
rows.push({
|
|
516
|
+
tableIndex: 0,
|
|
517
|
+
rowIndex,
|
|
518
|
+
selected: row.getAttribute("data-selected") === "true",
|
|
519
|
+
cells: [{ columnLabel: "Row", text }],
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
}
|
|
211
523
|
return {
|
|
212
524
|
visibleText: root.innerText || root.textContent || "",
|
|
213
525
|
error: window.__GLOOM_CLI_SHOT_ERROR__ || "",
|
|
214
|
-
|
|
526
|
+
loadingStateDetected: root.querySelector('[data-gloom-status="loading"]') !== null,
|
|
527
|
+
errorStateDetected: root.querySelector('[data-gloom-status="error"]') !== null,
|
|
528
|
+
emptyStateDetected: root.querySelector('[data-gloom-status="empty"]') !== null,
|
|
529
|
+
rows,
|
|
530
|
+
truncated: truncationReasons.size > 0,
|
|
531
|
+
truncationReasons: [...truncationReasons],
|
|
532
|
+
semanticUi,
|
|
215
533
|
};
|
|
216
534
|
})()`,
|
|
217
535
|
returnByValue: true,
|
|
@@ -220,6 +538,12 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
220
538
|
value?: {
|
|
221
539
|
visibleText?: string;
|
|
222
540
|
error?: string;
|
|
541
|
+
loadingStateDetected?: boolean;
|
|
542
|
+
errorStateDetected?: boolean;
|
|
543
|
+
emptyStateDetected?: boolean;
|
|
544
|
+
rows?: DesktopPaneShotRenderedRow[];
|
|
545
|
+
truncated?: boolean;
|
|
546
|
+
truncationReasons?: string[];
|
|
223
547
|
semanticUi?: RemoteUiNodeSnapshot[];
|
|
224
548
|
};
|
|
225
549
|
};
|
|
@@ -227,12 +551,26 @@ async function readRenderedPaneState(session: CdpSession): Promise<DesktopPaneSh
|
|
|
227
551
|
const value = result.result?.value;
|
|
228
552
|
if (value?.error) throw new Error(value.error);
|
|
229
553
|
const visibleText = (value?.visibleText ?? "").replace(/\s+/g, " ").trim();
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
)
|
|
554
|
+
const loadingStateMarkers = stateMarkers(visibleText, LOADING_STATE_PATTERNS);
|
|
555
|
+
const errorStateMarkers = stateMarkers(visibleText, ERROR_STATE_PATTERNS);
|
|
556
|
+
const emptyStateMarkers = stateMarkers(visibleText, EMPTY_STATE_PATTERNS);
|
|
557
|
+
const rows = Array.isArray(value?.rows) ? value.rows : [];
|
|
558
|
+
const textShowsEllipsis = rows.some((row) => row.cells.some((cell) => /\u2026|\.\.\./.test(cell.text)));
|
|
559
|
+
const truncationReasons = Array.isArray(value?.truncationReasons)
|
|
560
|
+
? value.truncationReasons.filter((reason): reason is string => typeof reason === "string")
|
|
561
|
+
: [];
|
|
562
|
+
if (textShowsEllipsis && !truncationReasons.includes("one or more cells are visibly clipped")) {
|
|
563
|
+
truncationReasons.push("one or more cells are visibly clipped");
|
|
564
|
+
}
|
|
233
565
|
return {
|
|
234
566
|
visibleText,
|
|
235
|
-
|
|
567
|
+
rows,
|
|
568
|
+
truncated: value?.truncated === true || textShowsEllipsis,
|
|
569
|
+
truncationReasons,
|
|
570
|
+
loadingStateDetected: value?.loadingStateDetected === true || loadingStateMarkers.length > 0,
|
|
571
|
+
errorStateDetected: value?.errorStateDetected === true || errorStateMarkers.length > 0,
|
|
572
|
+
errorStateMarkers,
|
|
573
|
+
emptyStateDetected: value?.emptyStateDetected === true || emptyStateMarkers.length > 0,
|
|
236
574
|
emptyStateMarkers,
|
|
237
575
|
semanticUi: Array.isArray(value?.semanticUi) ? value.semanticUi : [],
|
|
238
576
|
};
|
package/src/cli/index.ts
CHANGED
|
@@ -121,7 +121,7 @@ function createCoreCliCommands(
|
|
|
121
121
|
aliases: ["screenshot"],
|
|
122
122
|
description: "Render a desktop-style screenshot for a pane-backed market function",
|
|
123
123
|
help: {
|
|
124
|
-
usage: ["shot <function-or-pane> [argument] [--output path] [--width px] [--height px] [--key value]"],
|
|
124
|
+
usage: ["shot <function-or-pane> [argument] [--output path] [--width px] [--height px] [--theme id] [--scale n] [--watermark text] [--key value]"],
|
|
125
125
|
},
|
|
126
126
|
execute: async (args, ctx) => {
|
|
127
127
|
await runPaneScreenshot(args, ctx);
|