gloomberb 0.11.0 → 0.11.2
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 +38 -15
- package/README.zh-CN.md +12 -12
- package/package.json +10 -3
- package/src/api-client/auth.ts +14 -10
- package/src/api-client/data.ts +54 -0
- package/src/api-client/index.test.ts +124 -0
- package/src/api-client/index.ts +139 -4
- package/src/api-client/paths.ts +89 -0
- package/src/api-client/request.ts +15 -2
- package/src/api-client/socket-health.test.ts +1 -0
- package/src/api-client/socket.ts +2 -1
- package/src/api-client/types.ts +163 -0
- package/src/app/pane-runtime/index.tsx +4 -1
- package/src/app/pane-runtime/plugin-bindings.test.ts +117 -0
- package/src/app/pane-runtime/plugin-bindings.ts +25 -4
- package/src/app/pane-runtime/ticker-inspector-runtime.ts +25 -14
- package/src/app/runtime/desktop-deeplink.test.ts +16 -0
- package/src/app/runtime/desktop-deeplink.ts +66 -2
- package/src/app/runtime/desktop-menu.ts +3 -0
- package/src/app/runtime/plugin-bindings.ts +30 -28
- package/src/app/runtime/update.ts +8 -6
- package/src/app.tsx +21 -7
- package/src/architecture/import-boundaries.test.ts +5 -1
- package/src/capabilities/factories.ts +4 -0
- package/src/cli/commands/automation.test.ts +9 -0
- package/src/cli/commands/automation.ts +22 -73
- package/src/cli/index.ts +10 -6
- package/src/cli/registry.ts +1 -1
- package/src/components/chart/composite/composite-chart.test.tsx +45 -2
- package/src/components/chart/composite/composite-chart.tsx +16 -12
- package/src/components/chart/composite/format.test.ts +34 -0
- package/src/components/chart/composite/format.ts +33 -10
- package/src/components/chart/composite/scene.ts +0 -21
- package/src/components/chart/composite/tools.ts +49 -0
- package/src/components/chart/core/axis-format.ts +13 -3
- package/src/components/chart/core/index.test.ts +7 -0
- package/src/components/chart/core/renderer.ts +3 -4
- package/src/components/command-bar/commands/direct/index.ts +4 -0
- package/src/components/command-bar/commands/registry.ts +8 -1
- package/src/components/command-bar/layout-items/current-layout.ts +1 -1
- package/src/components/command-bar/pane-templates/workflow.ts +4 -0
- package/src/components/command-bar/routes/root/shortcut-feedback.ts +3 -0
- package/src/components/command-bar/routes/root/shortcuts.test.ts +19 -0
- package/src/components/command-bar/routes/root/shortcuts.ts +3 -1
- package/src/components/command-bar/surface/index.test.tsx +6 -6
- package/src/components/command-bar/surface/index.tsx +4 -1
- package/src/components/command-bar/surface/pane.test.tsx +66 -2
- package/src/components/command-bar/view-model.test.ts +2 -1
- package/src/components/command-bar/workflow/ops.test.ts +54 -0
- package/src/components/command-bar/workflow/ops.ts +1 -1
- package/src/components/company-logo.test.ts +19 -0
- package/src/components/company-logo.tsx +60 -0
- package/src/components/feed-data-table/stack-view.tsx +7 -1
- package/src/components/index.ts +1 -0
- package/src/components/layout/detached-pane-shell.tsx +85 -15
- package/src/components/layout/header.tsx +5 -5
- package/src/components/layout/pane/title.ts +31 -3
- package/src/components/layout/shell/active-drag.ts +4 -11
- package/src/components/layout/shell/drag/index.ts +4 -20
- package/src/components/layout/shell/drag/runtime.ts +3 -4
- package/src/components/layout/shell/index.test.tsx +17 -3
- package/src/components/layout/shell/index.tsx +89 -31
- package/src/components/layout/shell/menu.test.ts +37 -1
- package/src/components/layout/shell/menu.ts +14 -0
- package/src/components/layout/shell/native/pointer-runtime.ts +22 -8
- package/src/components/layout/shell/pane/actions.ts +0 -5
- package/src/components/layout/shell/pane/management-shortcuts.ts +9 -4
- package/src/components/layout/shell/shortcuts.ts +6 -3
- package/src/components/layout/shell/ticker-link-menu.test.ts +82 -0
- package/src/components/layout/shell/ticker-link-menu.ts +78 -0
- package/src/components/layout/status-bar.test.tsx +62 -61
- package/src/components/layout/status-bar.tsx +53 -75
- package/src/components/onboarding/account-step/form-panel.tsx +4 -2
- package/src/components/onboarding/account-step/index.tsx +1 -1
- package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
- package/src/components/onboarding/onboarding-wizard.test.tsx +44 -1
- package/src/components/onboarding/onboarding-wizard.tsx +13 -5
- package/src/components/onboarding/wizard-account.ts +4 -23
- package/src/components/table-view-shared.test.ts +11 -0
- package/src/components/table-view-shared.tsx +26 -0
- package/src/components/ui/data-table/index.tsx +19 -1
- package/src/components/ui/fields.tsx +5 -1
- package/src/core/state/app/layout-reducer.ts +36 -0
- package/src/core/state/app/layout.ts +10 -5
- package/src/core/state/app/state.ts +0 -13
- package/src/core/state/app/types.ts +6 -4
- package/src/data/config/chart-settings.ts +1 -1
- package/src/data/config/layout.ts +2 -0
- package/src/data/config/store/index.test.ts +27 -6
- package/src/data/config/store/normalize.ts +3 -5
- package/src/data/plugin-state-store.ts +11 -0
- package/src/data/sqlite/cache.test.ts +10 -0
- package/src/i18n/es.ts +13 -5
- package/src/i18n/ja.ts +13 -5
- package/src/i18n/ko.ts +13 -5
- package/src/i18n/zh-cn.ts +13 -5
- package/src/i18n/zh-tw.ts +13 -5
- package/src/layout-marketplace/api.test.ts +54 -0
- package/src/layout-marketplace/api.ts +65 -0
- package/src/layout-marketplace/gallery-desktop.test.tsx +262 -0
- package/src/layout-marketplace/gallery-desktop.tsx +375 -0
- package/src/layout-marketplace/gallery-terminal.tsx +376 -0
- package/src/layout-marketplace/gallery.test.tsx +84 -0
- package/src/layout-marketplace/gallery.tsx +323 -0
- package/src/layout-marketplace/geometry.test.ts +47 -0
- package/src/layout-marketplace/geometry.ts +80 -0
- package/src/layout-marketplace/mini-workspace.test.tsx +122 -0
- package/src/layout-marketplace/mini-workspace.tsx +428 -0
- package/src/layout-marketplace/model.test.ts +118 -0
- package/src/layout-marketplace/model.ts +171 -0
- package/src/layout-marketplace/name-dialog.tsx +60 -0
- package/src/layout-marketplace/pane-imagery.ts +85 -0
- package/src/layout-marketplace/pane.tsx +20 -0
- package/src/layout-marketplace/payload.test.ts +246 -0
- package/src/layout-marketplace/payload.ts +624 -0
- package/src/layout-marketplace/use-marketplace.ts +63 -0
- package/src/market-data/coordinator/index.test.ts +2 -2
- package/src/market-data/coordinator/index.ts +1 -1
- package/src/market-data/hooks.tsx +0 -41
- package/src/market-data/market/format.test.ts +7 -0
- package/src/market-data/market/freshness.ts +5 -2
- package/src/market-data/quotes/freshness.test.ts +16 -0
- package/src/news/aggregator.test.ts +92 -3
- package/src/news/aggregator.ts +98 -18
- package/src/news/hooks.test.tsx +2 -0
- package/src/news/hooks.ts +27 -1
- package/src/news/news-model.ts +5 -2
- package/src/news/types.ts +7 -0
- package/src/plugins/broker-sync/broker-sync.test.ts +58 -0
- package/src/plugins/broker-sync/normalize.ts +42 -5
- package/src/plugins/builtin/account-management/pane.tsx +5 -5
- package/src/plugins/builtin/ai/index.tsx +18 -2
- package/src/plugins/builtin/ai/screener/pane.test.tsx +47 -4
- package/src/plugins/builtin/ai/screener/pane.tsx +35 -12
- package/src/plugins/builtin/alerts/alert-engine.test.ts +53 -1
- package/src/plugins/builtin/alerts/alert-engine.ts +34 -1
- package/src/plugins/builtin/alerts/index.test.tsx +49 -6
- package/src/plugins/builtin/alerts/index.tsx +11 -6
- package/src/plugins/builtin/alerts/pane.tsx +51 -9
- package/src/plugins/builtin/alerts/quotes.ts +11 -3
- package/src/plugins/builtin/alerts/types.ts +1 -0
- package/src/plugins/builtin/analytics/index.tsx +11 -1
- package/src/plugins/builtin/analytics/pane-model.ts +6 -4
- package/src/plugins/builtin/broker-manager/index.tsx +3 -0
- package/src/plugins/builtin/buildout/model/index.ts +1 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +17 -18
- package/src/plugins/builtin/cds/client.test.ts +83 -0
- package/src/plugins/builtin/cds/client.ts +67 -0
- package/src/plugins/builtin/cds/index.tsx +41 -0
- package/src/plugins/builtin/cds/model.test.ts +232 -0
- package/src/plugins/builtin/cds/model.ts +401 -0
- package/src/plugins/builtin/cds/pane.test.tsx +132 -0
- package/src/plugins/builtin/cds/pane.tsx +358 -0
- package/src/plugins/builtin/chart-composer/chart-spec.ts +31 -0
- package/src/plugins/builtin/chart-composer/index.tsx +88 -2
- package/src/plugins/builtin/chart-composer/pane-share.test.ts +71 -0
- package/src/plugins/builtin/chart-composer/pane.tsx +103 -15
- package/src/plugins/builtin/chat/content/index.tsx +4 -1
- package/src/plugins/builtin/chat/controller/channels.ts +7 -1
- package/src/plugins/builtin/chat/controller/index.ts +14 -9
- package/src/plugins/builtin/chat/controller/notifications.ts +13 -3
- package/src/plugins/builtin/chat/controller/persistence.ts +0 -3
- package/src/plugins/builtin/chat/controller/realtime.ts +3 -3
- package/src/plugins/builtin/chat/controller/send.ts +1 -3
- package/src/plugins/builtin/chat/controller/session-runtime.ts +18 -11
- package/src/plugins/builtin/chat/controller/state.ts +1 -3
- package/src/plugins/builtin/chat/controller/storage.ts +0 -2
- package/src/plugins/builtin/chat/controller/utils.ts +4 -6
- package/src/plugins/builtin/chat/controller/view.ts +2 -2
- package/src/plugins/builtin/chat/controller.test.ts +142 -14
- package/src/plugins/builtin/chat/message/desktop.test.tsx +88 -0
- package/src/plugins/builtin/chat/message/desktop.tsx +3 -1
- package/src/plugins/builtin/chat/message/profile-popover.test.tsx +1 -29
- package/src/plugins/builtin/chat/profile-popover.ts +53 -22
- package/src/plugins/builtin/chat/sidebar.test.tsx +81 -0
- package/src/plugins/builtin/chat/sidebar.tsx +63 -0
- package/src/plugins/builtin/chat/test-harness.tsx +29 -1
- package/src/plugins/builtin/cloud/auth-actions.tsx +14 -7
- package/src/plugins/builtin/cloud/auth-commands.ts +21 -51
- package/src/plugins/builtin/cloud/auth-dialog.tsx +296 -0
- package/src/{components/onboarding/account-step/model.test.ts → plugins/builtin/cloud/auth-model.test.ts} +1 -1
- package/src/{components/onboarding/account-step/model.ts → plugins/builtin/cloud/auth-model.ts} +37 -3
- package/src/plugins/builtin/cloud/browser.tsx +9 -0
- package/src/plugins/builtin/cloud/buildout-module.tsx +23 -0
- package/src/plugins/builtin/cloud/device-signin.ts +2 -8
- package/src/plugins/builtin/cloud/index.tsx +2 -0
- package/src/plugins/builtin/cloud/plugin.tsx +14 -24
- package/src/plugins/builtin/cloud/upgrade-command.ts +13 -6
- package/src/plugins/builtin/cloud-tweets/pane-share.test.ts +56 -0
- package/src/plugins/builtin/cloud-tweets/pane.tsx +20 -5
- package/src/plugins/builtin/cloud-tweets/registration.ts +50 -6
- package/src/plugins/builtin/composite-plugins.ts +3 -1
- package/src/plugins/builtin/congress-trades/detail.tsx +43 -1
- package/src/plugins/builtin/congress-trades/model.test.ts +85 -0
- package/src/plugins/builtin/congress-trades/model.ts +69 -1
- package/src/plugins/builtin/congress-trades/pane.tsx +51 -2
- package/src/plugins/builtin/connections/index.ts +3 -0
- package/src/plugins/builtin/dividend-yield/client.ts +18 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +7 -6
- package/src/plugins/builtin/earnings/index.tsx +5 -3
- package/src/plugins/builtin/earnings/model.test.ts +19 -1
- package/src/plugins/builtin/earnings/model.ts +17 -15
- package/src/plugins/builtin/econ/calendar-model.ts +0 -5
- package/src/plugins/builtin/econ/index.test.tsx +6 -1
- package/src/plugins/builtin/fear-greed/charts.tsx +12 -8
- package/src/plugins/builtin/help/index.tsx +2 -2
- package/src/plugins/builtin/holders/thirteenf-match.ts +1 -2
- package/src/plugins/builtin/insider/index.tsx +27 -11
- package/src/plugins/builtin/kelly-sizer/index.tsx +4 -1
- package/src/plugins/builtin/layout-manager/index.tsx +17 -4
- package/src/plugins/builtin/news/index.tsx +11 -6
- package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +2 -0
- package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +2 -0
- package/src/plugins/builtin/news/wire/breaking/pane.tsx +4 -1
- package/src/plugins/builtin/news/wire/feed-config.test.ts +15 -1
- package/src/plugins/builtin/news/wire/feed-config.ts +25 -5
- package/src/plugins/builtin/news/wire/index.tsx +3 -3
- package/src/plugins/builtin/news/wire/industry-pane.tsx +7 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +34 -1
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +4 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +8 -2
- package/src/plugins/builtin/news/wire/rss/source.test.ts +12 -0
- package/src/plugins/builtin/news/wire/rss/source.ts +1 -1
- package/src/plugins/builtin/notes/files.ts +80 -0
- package/src/plugins/builtin/notes/index.tsx +3 -0
- package/src/plugins/builtin/notes/sync.test.ts +49 -0
- package/src/plugins/builtin/notes/sync.ts +98 -0
- package/src/plugins/builtin/options/index.tsx +1 -0
- package/src/plugins/builtin/options/view.test.tsx +25 -3
- package/src/plugins/builtin/options/view.tsx +1 -0
- package/src/plugins/builtin/portfolio-list/account-metrics.test.ts +22 -0
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +12 -7
- package/src/plugins/builtin/portfolio-list/cli/render.ts +5 -3
- package/src/plugins/builtin/portfolio-list/column-values.ts +15 -4
- package/src/plugins/builtin/portfolio-list/header.tsx +13 -3
- package/src/plugins/builtin/portfolio-list/index.tsx +8 -0
- package/src/plugins/builtin/portfolio-list/metrics.test.ts +31 -1
- package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +1 -0
- package/src/plugins/builtin/portfolio-list/pane/index.tsx +10 -7
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +6 -1
- package/src/plugins/builtin/portfolio-list/position-metrics.ts +25 -6
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +35 -21
- package/src/plugins/builtin/portfolio-list/summary/totals.ts +20 -6
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -12
- package/src/plugins/builtin/research/equity-diagnostic-pane.test.tsx +329 -0
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +582 -0
- package/src/plugins/builtin/research/index.test.ts +14 -0
- package/src/plugins/builtin/research/index.tsx +29 -0
- package/src/plugins/builtin/sec/index.tsx +24 -9
- package/src/plugins/builtin/sectors/index.tsx +14 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +18 -11
- package/src/plugins/builtin/shared/public-pane.test.ts +12 -0
- package/src/plugins/builtin/shared/public-pane.ts +9 -0
- package/src/plugins/builtin/shared/public-share.ts +23 -0
- package/src/plugins/builtin/shared/ticker-source.ts +32 -0
- package/src/plugins/builtin/shared/ticker-surface.test.ts +27 -0
- package/src/plugins/builtin/shared/ticker-surface.ts +17 -0
- package/src/plugins/builtin/substack/api/cache.ts +7 -3
- package/src/plugins/builtin/substack/api/loaders.ts +36 -12
- package/src/plugins/builtin/substack/api/types.ts +2 -0
- package/src/plugins/builtin/substack/pane-state.ts +1 -1
- package/src/plugins/builtin/substack/pane.tsx +55 -12
- package/src/plugins/builtin/thirteenf/api.test.ts +1 -1
- package/src/plugins/builtin/thirteenf/api.ts +40 -18
- package/src/plugins/builtin/thirteenf/data.ts +15 -7
- package/src/plugins/builtin/thirteenf/pane.tsx +45 -10
- package/src/plugins/builtin/ticker-detail/index.tsx +10 -0
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +12 -4
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +8 -2
- package/src/plugins/builtin/ticker-detail/settings.ts +12 -0
- package/src/plugins/builtin/treasury-auctions/index.tsx +2 -0
- package/src/plugins/builtin/world-indices/index.tsx +2 -0
- package/src/plugins/catalog-browser.test.ts +78 -0
- package/src/plugins/catalog-browser.ts +136 -0
- package/src/plugins/gridlock-notification.ts +2 -1
- package/src/plugins/ibkr/flex/index.test.ts +19 -0
- package/src/plugins/ibkr/flex/index.ts +1 -1
- package/src/plugins/pane-manager/gridlock.ts +87 -3
- package/src/plugins/pane-manager.test.ts +30 -0
- package/src/plugins/pane-manager.ts +6 -1
- package/src/plugins/prediction-markets/chart.tsx +2 -2
- package/src/plugins/prediction-markets/controller/catalog.ts +77 -2
- package/src/plugins/prediction-markets/controller/data.ts +7 -1
- package/src/plugins/prediction-markets/controller/index.ts +9 -2
- package/src/plugins/prediction-markets/controller/keyboard.ts +10 -14
- package/src/plugins/prediction-markets/detail/overview.tsx +21 -0
- package/src/plugins/prediction-markets/detail/pane.tsx +43 -34
- package/src/plugins/prediction-markets/detail/trades.tsx +34 -9
- package/src/plugins/prediction-markets/detail.test.tsx +29 -2
- package/src/plugins/prediction-markets/index.tsx +8 -4
- package/src/plugins/prediction-markets/navigation.ts +0 -1
- package/src/plugins/prediction-markets/pane.test.tsx +77 -0
- package/src/plugins/prediction-markets/pane.tsx +12 -0
- package/src/plugins/prediction-markets/plugin.test.tsx +36 -0
- package/src/plugins/prediction-markets/services/kalshi/adapter.ts +49 -9
- package/src/plugins/prediction-markets/services/polymarket/adapter.ts +31 -0
- package/src/plugins/prediction-markets/test-helpers.tsx +9 -0
- package/src/plugins/registry/index.ts +2 -0
- package/src/plugins/ticker-navigation.test.ts +24 -0
- package/src/plugins/ticker-navigation.ts +40 -0
- package/src/remote/schema.ts +1 -1
- package/src/renderers/browser/app-services.ts +61 -0
- package/src/renderers/browser/cloud-transport.test.ts +68 -0
- package/src/renderers/browser/cloud-transport.ts +48 -0
- package/src/renderers/browser/config-host.ts +58 -0
- package/src/renderers/browser/deeplink-bridge.test.ts +41 -0
- package/src/renderers/browser/deeplink-bridge.ts +22 -0
- package/src/renderers/browser/error-boundary.tsx +23 -0
- package/src/renderers/browser/main.tsx +64 -0
- package/src/renderers/browser/persistence.ts +74 -0
- package/src/renderers/browser/storage.test.ts +66 -0
- package/src/renderers/browser/storage.ts +50 -0
- package/src/renderers/browser/ticker-repository.ts +59 -0
- package/src/renderers/browser/ui-host.tsx +40 -0
- package/src/renderers/cloudflare/worker.test.ts +136 -0
- package/src/renderers/cloudflare/worker.ts +116 -0
- package/src/renderers/electrobun/bun/application-menu/index.ts +3 -2
- package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
- package/src/renderers/electrobun/bun/desktop/plugin-state.ts +7 -1
- package/src/renderers/electrobun/view/app-services.ts +14 -3
- package/src/renderers/electrobun/view/build-assets.ts +12 -10
- package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
- package/src/renderers/electrobun/view/data-table/index.tsx +10 -1
- package/src/renderers/electrobun/view/desktop/controls.tsx +2 -0
- package/src/renderers/electrobun/view/dom-ui-host.tsx +143 -0
- package/src/renderers/electrobun/view/host/box.test.tsx +33 -0
- package/src/renderers/electrobun/view/host/box.tsx +11 -6
- package/src/renderers/electrobun/view/host/chart-surface.tsx +7 -1
- package/src/renderers/electrobun/view/host/input.tsx +11 -7
- package/src/renderers/electrobun/view/host/native.ts +0 -5
- package/src/renderers/electrobun/view/main.tsx +2 -0
- package/src/renderers/electrobun/view/remote/persistence.ts +5 -0
- package/src/renderers/electrobun/view/styles.css +107 -7
- package/src/renderers/electrobun/view/toast-host.test.tsx +78 -0
- package/src/renderers/electrobun/view/toast-host.tsx +69 -43
- package/src/renderers/electrobun/view/ui-host.tsx +6 -137
- package/src/renderers/opentui/start.tsx +2 -0
- package/src/renderers/share/layout-view.test.tsx +58 -0
- package/src/renderers/share/layout-view.tsx +133 -0
- package/src/renderers/share/main.tsx +102 -0
- package/src/renderers/share/styles.css +54 -0
- package/src/renderers/share/view.test.tsx +100 -0
- package/src/renderers/share/view.tsx +150 -0
- package/src/shares/api.test.ts +105 -0
- package/src/shares/api.ts +127 -0
- package/src/shares/chart-snapshot.test.ts +34 -0
- package/src/shares/chart-snapshot.ts +28 -0
- package/src/shares/location.test.ts +19 -0
- package/src/shares/location.ts +11 -0
- package/src/shares/pane.test.ts +110 -0
- package/src/shares/pane.ts +54 -0
- package/src/shares/payload.ts +177 -0
- package/src/sources/gloomberb-cloud/index.test.ts +61 -1
- package/src/sources/gloomberb-cloud/index.ts +86 -14
- package/src/sources/gloomberb-cloud/normalizers.test.ts +34 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +5 -5
- package/src/sources/provider-router/history.test.ts +2 -2
- package/src/sources/provider-router/news.test.ts +34 -0
- package/src/sources/provider-router/news.ts +15 -1
- package/src/sources/sec-edgar.test.ts +59 -0
- package/src/sources/sec-edgar.ts +63 -23
- package/src/sources/yahoo-finance/mappers.ts +3 -0
- package/src/sources/yahoo-finance/snapshots.ts +10 -2
- package/src/sources/yahoo-finance/symbols.test.ts +10 -0
- package/src/sources/yahoo-finance/symbols.ts +13 -8
- package/src/sources/yahoo-finance.test.ts +1 -1
- package/src/sources/yahoo-finance.ts +6 -2
- package/src/state/app/bootstrap.ts +6 -7
- package/src/state/app/context/index.test.ts +41 -1
- package/src/state/app/context/index.test.tsx +34 -16
- package/src/state/selectors-ui.ts +0 -8
- package/src/sync/baseline.ts +32 -0
- package/src/sync/controller.test.ts +124 -1
- package/src/sync/controller.ts +54 -12
- package/src/sync/core-contributors.test.ts +44 -0
- package/src/sync/core-contributors.ts +59 -10
- package/src/sync/react.ts +22 -2
- package/src/sync/types.ts +12 -0
- package/src/theme/font-scale.ts +0 -11
- package/src/tickers/search/index.test.ts +27 -0
- package/src/tickers/search/upsert.ts +10 -0
- package/src/types/capability-route-source.ts +2 -1
- package/src/types/config.ts +35 -5
- package/src/types/desktop-menu.ts +1 -0
- package/src/types/plugin.ts +36 -0
- package/src/ui/context-menu.tsx +1 -1
- package/src/ui/host.tsx +4 -0
- package/src/ui/toast.tsx +2 -0
- package/src/utils/back-navigation.ts +0 -4
- package/src/utils/price-history.ts +11 -10
- package/src/utils/sec.test.ts +6 -0
- package/src/utils/sec.ts +1 -1
package/src/api-client/index.ts
CHANGED
|
@@ -3,11 +3,15 @@ import type { InstrumentSearchResult } from "../types/instrument";
|
|
|
3
3
|
import { CloudAuthApi } from "./auth";
|
|
4
4
|
import { CloudChatApi } from "./chat";
|
|
5
5
|
import { CloudDataApi } from "./data";
|
|
6
|
+
import { ApiRequestError } from "./errors";
|
|
6
7
|
import { CloudApiRequestTransport } from "./request";
|
|
7
8
|
import { CloudApiSocket } from "./socket";
|
|
8
9
|
import type {
|
|
10
|
+
CloudCdsParams,
|
|
9
11
|
CloudCongressHouseParams,
|
|
10
12
|
CloudFredSeriesParams,
|
|
13
|
+
CloudSecFilingParams,
|
|
14
|
+
CloudSecFilingsParams,
|
|
11
15
|
CloudHistoryParams,
|
|
12
16
|
CloudNewsParams,
|
|
13
17
|
CloudTickerTweetsParams,
|
|
@@ -40,10 +44,16 @@ import type {
|
|
|
40
44
|
CloudCorporateActionsPayload,
|
|
41
45
|
CloudPricePointPayload,
|
|
42
46
|
CloudEconEventPayload,
|
|
47
|
+
CloudEquityDiagnosticMode,
|
|
48
|
+
CloudEquityDiagnosticResult,
|
|
49
|
+
CloudCdsResponse,
|
|
43
50
|
CloudFredSeriesPayload,
|
|
44
51
|
CloudYieldPointPayload,
|
|
45
52
|
CloudCongressHousePayload,
|
|
46
53
|
CloudNewsPayload,
|
|
54
|
+
CloudSecContentResponse,
|
|
55
|
+
CloudSecDocumentsResponse,
|
|
56
|
+
CloudSecFilingsResponse,
|
|
47
57
|
CloudNewsListResponse,
|
|
48
58
|
CloudTweetSearchResponse,
|
|
49
59
|
CloudMarketResponse,
|
|
@@ -62,6 +72,13 @@ import type {
|
|
|
62
72
|
ScannerKind,
|
|
63
73
|
} from "./types";
|
|
64
74
|
import type { SyncSettings, SyncSnapshot } from "../sync/types";
|
|
75
|
+
import {
|
|
76
|
+
isMarketplaceLayoutId,
|
|
77
|
+
parseMarketplaceLayoutEntry,
|
|
78
|
+
parseMarketplaceLayoutList,
|
|
79
|
+
type LayoutMarketplaceEntry,
|
|
80
|
+
type LayoutMarketplacePayload,
|
|
81
|
+
} from "../layout-marketplace/payload";
|
|
65
82
|
|
|
66
83
|
export type * from "./types";
|
|
67
84
|
export { setCloudApiFetchTransport } from "./request";
|
|
@@ -73,6 +90,8 @@ const ASSIST_REQUEST_TIMEOUT_MS = 6_000;
|
|
|
73
90
|
|
|
74
91
|
class GloomApiClient {
|
|
75
92
|
private currentUser: AuthUser | null = null;
|
|
93
|
+
private sessionChecked = false;
|
|
94
|
+
private sessionRequest: Promise<AuthUser | null> | null = null;
|
|
76
95
|
private readonly currentUserListeners = new Set<() => void>();
|
|
77
96
|
private readonly transport = new CloudApiRequestTransport();
|
|
78
97
|
private readonly auth: CloudAuthApi;
|
|
@@ -84,6 +103,7 @@ class GloomApiClient {
|
|
|
84
103
|
this.auth = new CloudAuthApi({
|
|
85
104
|
getCurrentUser: () => this.currentUser,
|
|
86
105
|
getSessionToken: () => this.transport.getSessionToken(),
|
|
106
|
+
hasSessionCredential: () => this.transport.hasSessionCredential(),
|
|
87
107
|
request: (path, options) => this.request(path, options),
|
|
88
108
|
requireCapturedSession: (message) => this.requireCapturedSession(message),
|
|
89
109
|
setCurrentUser: (user) => this.setCurrentUser(user),
|
|
@@ -93,6 +113,7 @@ class GloomApiClient {
|
|
|
93
113
|
this.socket = new CloudApiSocket({
|
|
94
114
|
getBaseUrl: () => this.transport.baseUrl,
|
|
95
115
|
getSocketAuthToken: () => this.getSocketAuthToken(),
|
|
116
|
+
hasSessionCredential: () => this.transport.hasSessionCredential(),
|
|
96
117
|
hasVerifiedUser: () => this.currentUser?.emailVerified === true,
|
|
97
118
|
isUsingWebSocketToken: () => !!this.transport.getWebSocketToken(),
|
|
98
119
|
clearWebSocketTokenForFallback: () => this.transport.clearWebSocketTokenForFallback(),
|
|
@@ -123,8 +144,14 @@ class GloomApiClient {
|
|
|
123
144
|
return this.transport.getWebSocketToken();
|
|
124
145
|
}
|
|
125
146
|
|
|
147
|
+
setCookieSessionMode(enabled: boolean): void {
|
|
148
|
+
this.sessionChecked = false;
|
|
149
|
+
this.transport.setCookieSessionMode(enabled);
|
|
150
|
+
}
|
|
151
|
+
|
|
126
152
|
setSessionToken(token: string | null): void {
|
|
127
153
|
const changed = this.transport.getSessionToken() !== token;
|
|
154
|
+
this.sessionChecked = false;
|
|
128
155
|
this.transport.setSessionToken(token);
|
|
129
156
|
if (!token) {
|
|
130
157
|
this.currentUser = null;
|
|
@@ -143,6 +170,15 @@ class GloomApiClient {
|
|
|
143
170
|
return this.currentUser;
|
|
144
171
|
}
|
|
145
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Whether a signed-in session exists on this surface. Browser builds keep the
|
|
175
|
+
* session in an HttpOnly cookie, so the raw token is deliberately null there
|
|
176
|
+
* and the restored user is the only signal.
|
|
177
|
+
*/
|
|
178
|
+
isSignedIn(): boolean {
|
|
179
|
+
return !!this.transport.getSessionToken() || !!this.currentUser;
|
|
180
|
+
}
|
|
181
|
+
|
|
146
182
|
/** Notifies when the signed-in user changes, including plan and trial entitlement. */
|
|
147
183
|
subscribeCurrentUser(listener: () => void): () => void {
|
|
148
184
|
this.currentUserListeners.add(listener);
|
|
@@ -156,7 +192,7 @@ class GloomApiClient {
|
|
|
156
192
|
}
|
|
157
193
|
|
|
158
194
|
isVerified(): boolean {
|
|
159
|
-
return
|
|
195
|
+
return this.transport.hasSessionCredential() && !!this.currentUser?.emailVerified;
|
|
160
196
|
}
|
|
161
197
|
|
|
162
198
|
private setCurrentUser(user: AuthUser | null): void {
|
|
@@ -187,7 +223,7 @@ class GloomApiClient {
|
|
|
187
223
|
}
|
|
188
224
|
|
|
189
225
|
private requireCapturedSession(message: string): void {
|
|
190
|
-
if (this.transport.
|
|
226
|
+
if (this.transport.hasSessionCredential()) return;
|
|
191
227
|
this.transport.setWebSocketToken(null);
|
|
192
228
|
this.setCurrentUser(null);
|
|
193
229
|
throw new Error(message);
|
|
@@ -202,7 +238,9 @@ class GloomApiClient {
|
|
|
202
238
|
}
|
|
203
239
|
|
|
204
240
|
async ensureVerifiedSession(): Promise<AuthUser | null> {
|
|
205
|
-
|
|
241
|
+
if (!this.transport.hasSessionCredential()) return null;
|
|
242
|
+
if (!this.currentUser && !this.sessionChecked) await this.getSession();
|
|
243
|
+
return this.currentUser?.emailVerified ? this.currentUser : null;
|
|
206
244
|
}
|
|
207
245
|
|
|
208
246
|
async signUp(email: string, username: string, name: string, password: string): Promise<AuthUser> {
|
|
@@ -226,17 +264,47 @@ class GloomApiClient {
|
|
|
226
264
|
}
|
|
227
265
|
|
|
228
266
|
async getSession(): Promise<AuthUser | null> {
|
|
229
|
-
return this.
|
|
267
|
+
if (this.sessionRequest) return this.sessionRequest;
|
|
268
|
+
this.sessionRequest = this.auth.getSession();
|
|
269
|
+
try {
|
|
270
|
+
const user = await this.sessionRequest;
|
|
271
|
+
this.sessionChecked = true;
|
|
272
|
+
return user;
|
|
273
|
+
} finally {
|
|
274
|
+
this.sessionRequest = null;
|
|
275
|
+
}
|
|
230
276
|
}
|
|
231
277
|
|
|
232
278
|
async sendVerification(): Promise<CloudVerificationResponse> {
|
|
233
279
|
return this.auth.sendVerification();
|
|
234
280
|
}
|
|
235
281
|
|
|
282
|
+
async requestPasswordReset(email: string): Promise<void> {
|
|
283
|
+
return this.auth.requestPasswordReset(email);
|
|
284
|
+
}
|
|
285
|
+
|
|
236
286
|
async createBrowserHandoff(): Promise<CloudBrowserHandoffResponse> {
|
|
237
287
|
return this.auth.createBrowserHandoff();
|
|
238
288
|
}
|
|
239
289
|
|
|
290
|
+
/** Creates a Stripe checkout session for Cloud Pro; the URL opens in a browser. */
|
|
291
|
+
async createCloudCheckout(): Promise<{ url: string }> {
|
|
292
|
+
return this.request<{ url: string }>("/stripe/checkout", { method: "POST", body: JSON.stringify({}) });
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Stores a verified user's public terminal snapshot or pane handoff. */
|
|
296
|
+
async createTerminalShare(payload: unknown): Promise<{ id: string; expiresAt: string }> {
|
|
297
|
+
return this.request<{ id: string; expiresAt: string }>("/shares", {
|
|
298
|
+
method: "POST",
|
|
299
|
+
body: JSON.stringify(payload),
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Stripe billing portal for an account that already has a subscription. */
|
|
304
|
+
async createBillingPortal(): Promise<{ url: string }> {
|
|
305
|
+
return this.request<{ url: string }>("/stripe/portal", { method: "POST", body: JSON.stringify({}) });
|
|
306
|
+
}
|
|
307
|
+
|
|
240
308
|
async getAccountProfile(): Promise<AccountProfile> {
|
|
241
309
|
return this.auth.getAccountProfile();
|
|
242
310
|
}
|
|
@@ -271,6 +339,45 @@ class GloomApiClient {
|
|
|
271
339
|
});
|
|
272
340
|
}
|
|
273
341
|
|
|
342
|
+
async getMarketplaceLayout(
|
|
343
|
+
id: string,
|
|
344
|
+
options?: { signal?: AbortSignal },
|
|
345
|
+
): Promise<LayoutMarketplaceEntry | null> {
|
|
346
|
+
if (!isMarketplaceLayoutId(id)) return null;
|
|
347
|
+
try {
|
|
348
|
+
return parseMarketplaceLayoutEntry(await this.request<unknown>(`/layouts/${encodeURIComponent(id)}`, {
|
|
349
|
+
method: "GET",
|
|
350
|
+
signal: options?.signal,
|
|
351
|
+
}));
|
|
352
|
+
} catch (error) {
|
|
353
|
+
if (error instanceof ApiRequestError && error.status === 404) return null;
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
async listMarketplaceLayouts(options?: { signal?: AbortSignal }): Promise<LayoutMarketplaceEntry[]> {
|
|
359
|
+
const items = parseMarketplaceLayoutList(await this.request<unknown>("/layouts", {
|
|
360
|
+
method: "GET",
|
|
361
|
+
signal: options?.signal,
|
|
362
|
+
}));
|
|
363
|
+
if (!items) throw new Error("The layout marketplace returned invalid data.");
|
|
364
|
+
return items;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async publishMarketplaceLayout(
|
|
368
|
+
name: string,
|
|
369
|
+
payload: LayoutMarketplacePayload,
|
|
370
|
+
options?: { signal?: AbortSignal },
|
|
371
|
+
): Promise<LayoutMarketplaceEntry> {
|
|
372
|
+
const item = parseMarketplaceLayoutEntry(await this.request<unknown>("/layouts", {
|
|
373
|
+
method: "POST",
|
|
374
|
+
body: JSON.stringify({ name: name.trim(), ...payload }),
|
|
375
|
+
signal: options?.signal,
|
|
376
|
+
}));
|
|
377
|
+
if (!item) throw new Error("The layout marketplace returned invalid data.");
|
|
378
|
+
return item;
|
|
379
|
+
}
|
|
380
|
+
|
|
274
381
|
async updateSyncSettings(update: Partial<SyncSettings>): Promise<SyncSettings> {
|
|
275
382
|
const result = await this.request<{ settings: SyncSettings }>("/sync/settings", {
|
|
276
383
|
method: "PATCH",
|
|
@@ -513,6 +620,14 @@ class GloomApiClient {
|
|
|
513
620
|
return this.data.getCloudEconomicCalendar();
|
|
514
621
|
}
|
|
515
622
|
|
|
623
|
+
async getCloudEquityDiagnostic(
|
|
624
|
+
symbol: string,
|
|
625
|
+
exchange?: string,
|
|
626
|
+
mode: CloudEquityDiagnosticMode = "cache-first",
|
|
627
|
+
): Promise<CloudEquityDiagnosticResult> {
|
|
628
|
+
return this.data.getCloudEquityDiagnostic(symbol, exchange, mode);
|
|
629
|
+
}
|
|
630
|
+
|
|
516
631
|
async getCloudFredSeries(
|
|
517
632
|
seriesId: string,
|
|
518
633
|
params: CloudFredSeriesParams = {},
|
|
@@ -524,10 +639,30 @@ class GloomApiClient {
|
|
|
524
639
|
return this.data.getCloudYieldCurve();
|
|
525
640
|
}
|
|
526
641
|
|
|
642
|
+
async getCloudCds(params: CloudCdsParams = {}): Promise<CloudCdsResponse> {
|
|
643
|
+
return this.data.getCloudCds(params);
|
|
644
|
+
}
|
|
645
|
+
|
|
527
646
|
async getCloudCongressHouse(params: CloudCongressHouseParams = {}): Promise<CloudCongressHousePayload> {
|
|
528
647
|
return this.data.getCloudCongressHouse(params);
|
|
529
648
|
}
|
|
530
649
|
|
|
650
|
+
async getCloudSecFilings(params: CloudSecFilingsParams): Promise<CloudSecFilingsResponse> {
|
|
651
|
+
return this.data.getCloudSecFilings(params);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
async getCloudSecFilingDocuments(params: CloudSecFilingParams): Promise<CloudSecDocumentsResponse> {
|
|
655
|
+
return this.data.getCloudSecFilingDocuments(params);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
async getCloudSecFilingContent(params: CloudSecFilingParams): Promise<CloudSecContentResponse> {
|
|
659
|
+
return this.data.getCloudSecFilingContent(params);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
async getCloudSec13F(path: string, params: Record<string, string | number | undefined> = {}): Promise<unknown> {
|
|
663
|
+
return this.data.getCloudSec13F(path, params);
|
|
664
|
+
}
|
|
665
|
+
|
|
531
666
|
async getCloudNews(params: CloudNewsParams = {}): Promise<CloudNewsListResponse> {
|
|
532
667
|
return this.data.getCloudNews(params);
|
|
533
668
|
}
|
package/src/api-client/paths.ts
CHANGED
|
@@ -16,10 +16,19 @@ export type CloudFredSeriesParams = {
|
|
|
16
16
|
sortOrder?: "asc" | "desc";
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
export type CloudCdsParams = {
|
|
20
|
+
/** Reference entity name, matched by the backend against DTCC issuer names. */
|
|
21
|
+
issuer?: string;
|
|
22
|
+
days?: number;
|
|
23
|
+
limit?: number;
|
|
24
|
+
};
|
|
25
|
+
|
|
19
26
|
export type CloudCongressHouseParams = {
|
|
20
27
|
year?: number;
|
|
21
28
|
limit?: number;
|
|
29
|
+
offset?: number;
|
|
22
30
|
filingLimit?: number;
|
|
31
|
+
filingOffset?: number;
|
|
23
32
|
member?: string;
|
|
24
33
|
ticker?: string;
|
|
25
34
|
refresh?: boolean;
|
|
@@ -60,6 +69,23 @@ export type CloudTweetSearchParams = {
|
|
|
60
69
|
hours?: number;
|
|
61
70
|
};
|
|
62
71
|
|
|
72
|
+
const LOGO_SYMBOL_RE = /^[A-Z0-9][A-Z0-9._^:-]{0,23}$/;
|
|
73
|
+
const CRYPTO_QUOTE = /[-/](USD|USDT|USDC|EUR|GBP|BTC)$/;
|
|
74
|
+
|
|
75
|
+
export type CloudLogoKind = "ticker" | "crypto";
|
|
76
|
+
|
|
77
|
+
export function normalizeCloudLogoSymbol(kind: CloudLogoKind, symbol: string): string | null {
|
|
78
|
+
let normalized = symbol.trim().toUpperCase();
|
|
79
|
+
if (kind === "crypto") normalized = normalized.replace(CRYPTO_QUOTE, "");
|
|
80
|
+
return LOGO_SYMBOL_RE.test(normalized) ? normalized : null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function cloudLogoPath(kind: CloudLogoKind, symbol: string): string | null {
|
|
84
|
+
const normalized = normalizeCloudLogoSymbol(kind, symbol);
|
|
85
|
+
if (!normalized) return null;
|
|
86
|
+
return `/cloud/logos/${kind}/${encodeURIComponent(normalized)}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
63
89
|
function appendQuery(path: string, search: URLSearchParams): string {
|
|
64
90
|
const query = search.toString();
|
|
65
91
|
return `${path}${query ? `?${query}` : ""}`;
|
|
@@ -118,17 +144,80 @@ export function cloudFredSeriesPath(seriesId: string, params: CloudFredSeriesPar
|
|
|
118
144
|
return appendQuery(`/cloud/econ/series/${encodeURIComponent(seriesId)}`, search);
|
|
119
145
|
}
|
|
120
146
|
|
|
147
|
+
export function cloudCdsPath(params: CloudCdsParams = {}): string {
|
|
148
|
+
const search = new URLSearchParams();
|
|
149
|
+
const issuer = params.issuer?.trim();
|
|
150
|
+
if (issuer) search.set("issuer", issuer);
|
|
151
|
+
if (params.days != null) search.set("days", String(params.days));
|
|
152
|
+
if (params.limit != null) search.set("limit", String(params.limit));
|
|
153
|
+
return appendQuery("/cloud/credit/cds", search);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export type CloudSecFilingsParams = {
|
|
157
|
+
ticker: string;
|
|
158
|
+
limit?: number;
|
|
159
|
+
offset?: number;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export type CloudSecFilingParams = {
|
|
163
|
+
cik?: string;
|
|
164
|
+
accession?: string;
|
|
165
|
+
form?: string;
|
|
166
|
+
primaryDocument?: string;
|
|
167
|
+
primaryDocumentUrl?: string;
|
|
168
|
+
filingUrl?: string;
|
|
169
|
+
};
|
|
170
|
+
|
|
121
171
|
export function cloudCongressHousePath(params: CloudCongressHouseParams = {}): string {
|
|
122
172
|
const search = new URLSearchParams();
|
|
123
173
|
if (params.year != null) search.set("year", String(params.year));
|
|
124
174
|
if (params.limit != null) search.set("limit", String(params.limit));
|
|
175
|
+
if (params.offset != null) search.set("offset", String(params.offset));
|
|
125
176
|
if (params.filingLimit != null) search.set("filingLimit", String(params.filingLimit));
|
|
177
|
+
if (params.filingOffset != null) search.set("filingOffset", String(params.filingOffset));
|
|
126
178
|
if (params.member) search.set("member", params.member);
|
|
127
179
|
if (params.ticker) search.set("ticker", params.ticker);
|
|
128
180
|
if (params.refresh != null) search.set("refresh", String(params.refresh));
|
|
129
181
|
return appendQuery("/cloud/congress/house", search);
|
|
130
182
|
}
|
|
131
183
|
|
|
184
|
+
export function cloudSecFilingsPath(params: CloudSecFilingsParams): string {
|
|
185
|
+
const search = new URLSearchParams({ ticker: params.ticker });
|
|
186
|
+
if (params.limit != null) search.set("limit", String(params.limit));
|
|
187
|
+
if (params.offset != null) search.set("offset", String(params.offset));
|
|
188
|
+
return appendQuery("/cloud/sec/filings", search);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function cloudSecFilingDocumentsPath(params: CloudSecFilingParams): string {
|
|
192
|
+
const search = new URLSearchParams();
|
|
193
|
+
if (params.cik) search.set("cik", params.cik);
|
|
194
|
+
if (params.accession) search.set("accession", params.accession);
|
|
195
|
+
if (params.form) search.set("form", params.form);
|
|
196
|
+
if (params.primaryDocument) search.set("primaryDocument", params.primaryDocument);
|
|
197
|
+
if (params.filingUrl) search.set("filingUrl", params.filingUrl);
|
|
198
|
+
return appendQuery("/cloud/sec/filing/documents", search);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function cloudSecFilingContentPath(params: CloudSecFilingParams): string {
|
|
202
|
+
const search = new URLSearchParams();
|
|
203
|
+
if (params.cik) search.set("cik", params.cik);
|
|
204
|
+
if (params.accession) search.set("accession", params.accession);
|
|
205
|
+
if (params.form) search.set("form", params.form);
|
|
206
|
+
if (params.primaryDocument) search.set("primaryDocument", params.primaryDocument);
|
|
207
|
+
if (params.primaryDocumentUrl) search.set("primaryDocumentUrl", params.primaryDocumentUrl);
|
|
208
|
+
if (params.filingUrl) search.set("filingUrl", params.filingUrl);
|
|
209
|
+
return appendQuery("/cloud/sec/filing/content", search);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function cloudSec13FPath(path: string, params: Record<string, string | number | undefined> = {}): string {
|
|
213
|
+
const search = new URLSearchParams();
|
|
214
|
+
for (const [key, value] of Object.entries(params)) {
|
|
215
|
+
if (value !== undefined) search.set(key, String(value));
|
|
216
|
+
}
|
|
217
|
+
const normalized = path.startsWith("/") ? path.slice(1) : path;
|
|
218
|
+
return appendQuery(`/cloud/sec/13f/${normalized}`, search);
|
|
219
|
+
}
|
|
220
|
+
|
|
132
221
|
export function cloudNewsPath(params: CloudNewsParams = {}): string {
|
|
133
222
|
const search = new URLSearchParams();
|
|
134
223
|
if (params.feed) search.set("feed", params.feed);
|
|
@@ -24,10 +24,14 @@ export function setCloudApiFetchTransport(transport: CloudApiFetchTransport | nu
|
|
|
24
24
|
|
|
25
25
|
declare const __GLOOMBERB_API_URL__: string | undefined;
|
|
26
26
|
|
|
27
|
-
function getCloudApiBaseUrl(): string {
|
|
27
|
+
export function getCloudApiBaseUrl(): string {
|
|
28
28
|
// Browser bundles have no `process`; the build replaces this with a literal.
|
|
29
29
|
const bundled = typeof __GLOOMBERB_API_URL__ === "string" ? __GLOOMBERB_API_URL__ : "";
|
|
30
|
-
if (bundled)
|
|
30
|
+
if (bundled) {
|
|
31
|
+
return typeof location !== "undefined" && bundled === location.origin
|
|
32
|
+
? `${bundled}/api`
|
|
33
|
+
: bundled;
|
|
34
|
+
}
|
|
31
35
|
if (typeof process === "undefined") {
|
|
32
36
|
return DEFAULT_API_URL;
|
|
33
37
|
}
|
|
@@ -43,6 +47,7 @@ export class CloudApiRequestTransport {
|
|
|
43
47
|
private sessionToken: string | null = null;
|
|
44
48
|
private sessionCookieName: SessionCookieName | null = null;
|
|
45
49
|
private websocketToken: string | null = null;
|
|
50
|
+
private cookieSessionMode = false;
|
|
46
51
|
private readonly fetchTransport: CloudApiFetchTransport | null;
|
|
47
52
|
private readonly marketRequestTimeoutMs: number;
|
|
48
53
|
private readonly connectionHealth: ConnectionHealthRegistry;
|
|
@@ -67,6 +72,14 @@ export class CloudApiRequestTransport {
|
|
|
67
72
|
return this.websocketToken;
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
hasSessionCredential(): boolean {
|
|
76
|
+
return this.cookieSessionMode || !!this.sessionToken;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
setCookieSessionMode(enabled: boolean): void {
|
|
80
|
+
this.cookieSessionMode = enabled;
|
|
81
|
+
}
|
|
82
|
+
|
|
70
83
|
setSessionToken(token: string | null): void {
|
|
71
84
|
if (this.sessionToken !== token) {
|
|
72
85
|
this.sessionCookieName = null;
|
|
@@ -50,6 +50,7 @@ describe("CloudApiSocket connection health", () => {
|
|
|
50
50
|
const socket = new CloudApiSocket({
|
|
51
51
|
getBaseUrl: () => `http://127.0.0.1:${server.port}`,
|
|
52
52
|
getSocketAuthToken: () => null,
|
|
53
|
+
hasSessionCredential: () => false,
|
|
53
54
|
hasVerifiedUser: () => false,
|
|
54
55
|
isUsingWebSocketToken: () => false,
|
|
55
56
|
clearWebSocketTokenForFallback: () => false,
|
package/src/api-client/socket.ts
CHANGED
|
@@ -49,6 +49,7 @@ function mergeQuoteStreamSubscriptions(
|
|
|
49
49
|
type CloudApiSocketDelegate = {
|
|
50
50
|
getBaseUrl: () => string;
|
|
51
51
|
getSocketAuthToken: () => string | null;
|
|
52
|
+
hasSessionCredential: () => boolean;
|
|
52
53
|
hasVerifiedUser: () => boolean;
|
|
53
54
|
isUsingWebSocketToken: () => boolean;
|
|
54
55
|
clearWebSocketTokenForFallback: () => boolean;
|
|
@@ -427,7 +428,7 @@ export class CloudApiSocket {
|
|
|
427
428
|
|
|
428
429
|
private shouldKeepSocketOpen(): boolean {
|
|
429
430
|
if (this.quoteTargets.size > 0 || this.scannerListeners.size > 0) return true;
|
|
430
|
-
return
|
|
431
|
+
return this.delegate.hasSessionCredential()
|
|
431
432
|
&& this.delegate.hasVerifiedUser()
|
|
432
433
|
&& this.channelListeners.size > 0;
|
|
433
434
|
}
|
package/src/api-client/types.ts
CHANGED
|
@@ -322,6 +322,40 @@ export interface CloudFredSeriesPayload {
|
|
|
322
322
|
info: CloudFredSeriesInfoPayload | null;
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
+
/** One publicly disseminated single-name CDS transaction report. */
|
|
326
|
+
export interface CloudCdsTradePayload {
|
|
327
|
+
disseminationId: string;
|
|
328
|
+
originalDisseminationId: string | null;
|
|
329
|
+
actionType: string;
|
|
330
|
+
eventTimestamp: string;
|
|
331
|
+
executionTimestamp: string | null;
|
|
332
|
+
effectiveDate: string | null;
|
|
333
|
+
expirationDate: string | null;
|
|
334
|
+
maturityDate: string | null;
|
|
335
|
+
issuerName: string | null;
|
|
336
|
+
underlierId: string | null;
|
|
337
|
+
underlierIdSource: string | null;
|
|
338
|
+
upi: string | null;
|
|
339
|
+
upiFisn: string | null;
|
|
340
|
+
upiUnderlierName: string | null;
|
|
341
|
+
notionalAmount: number | null;
|
|
342
|
+
/** Reported notional is a regulatory cap, so the real trade was at least this size. */
|
|
343
|
+
notionalCapped: boolean;
|
|
344
|
+
notionalCurrency: string | null;
|
|
345
|
+
fixedRate: number | null;
|
|
346
|
+
reportedSpread: number | null;
|
|
347
|
+
/** Unit of `reportedSpread`, e.g. basis points or percent. */
|
|
348
|
+
spreadNotation: string | null;
|
|
349
|
+
upfrontAmount: number | null;
|
|
350
|
+
upfrontCurrency: string | null;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export interface CloudCdsResponse {
|
|
354
|
+
source: string;
|
|
355
|
+
asOf: string | null;
|
|
356
|
+
trades: CloudCdsTradePayload[];
|
|
357
|
+
}
|
|
358
|
+
|
|
325
359
|
export interface CloudShortInterestPointPayload {
|
|
326
360
|
settlementDate: string;
|
|
327
361
|
sharesShort: number;
|
|
@@ -399,10 +433,66 @@ export interface CloudCongressHousePayload {
|
|
|
399
433
|
indexUpdatedAt: string | null;
|
|
400
434
|
filingsScanned: number;
|
|
401
435
|
filingCount: number;
|
|
436
|
+
filingOffset?: number;
|
|
437
|
+
hasMore?: boolean;
|
|
438
|
+
hasMoreFilings?: boolean;
|
|
439
|
+
nextOffset?: number;
|
|
440
|
+
nextFilingOffset?: number;
|
|
402
441
|
trades: CloudCongressTradePayload[];
|
|
403
442
|
members: CloudCongressMemberPayload[];
|
|
404
443
|
}
|
|
405
444
|
|
|
445
|
+
export interface CloudSecFilingPayload {
|
|
446
|
+
accessionNumber: string;
|
|
447
|
+
form: string;
|
|
448
|
+
filingDate: string;
|
|
449
|
+
acceptedAt?: string;
|
|
450
|
+
primaryDocument?: string;
|
|
451
|
+
primaryDocDescription?: string;
|
|
452
|
+
items?: string;
|
|
453
|
+
cik: string;
|
|
454
|
+
companyName?: string;
|
|
455
|
+
filingUrl: string;
|
|
456
|
+
primaryDocumentUrl?: string;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export interface CloudSecDocumentPayload {
|
|
460
|
+
sequence?: string;
|
|
461
|
+
type: string;
|
|
462
|
+
description?: string;
|
|
463
|
+
document: string;
|
|
464
|
+
url: string;
|
|
465
|
+
size?: string;
|
|
466
|
+
isPrimary: boolean;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export interface CloudSecFilingsResponse {
|
|
470
|
+
filings: CloudSecFilingPayload[];
|
|
471
|
+
hasMore: boolean;
|
|
472
|
+
nextOffset: number;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export interface CloudSecDocumentsResponse {
|
|
476
|
+
documents: CloudSecDocumentPayload[];
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export interface CloudSecForm4Payload {
|
|
480
|
+
filingDate: string;
|
|
481
|
+
reportedName: string;
|
|
482
|
+
title: string;
|
|
483
|
+
transactionType: "P" | "S" | "A" | "D" | "";
|
|
484
|
+
shares: number;
|
|
485
|
+
pricePerShare: number | null;
|
|
486
|
+
totalValue: number | null;
|
|
487
|
+
sharesOwned: number | null;
|
|
488
|
+
form: string;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export interface CloudSecContentResponse {
|
|
492
|
+
content: string | null;
|
|
493
|
+
form4: CloudSecForm4Payload | null;
|
|
494
|
+
}
|
|
495
|
+
|
|
406
496
|
interface CloudNewsEntityPayload {
|
|
407
497
|
id: string;
|
|
408
498
|
entityType: string;
|
|
@@ -617,6 +707,79 @@ export interface CloudMarketScreenerPayload {
|
|
|
617
707
|
items: CloudMarketScreenerItem[];
|
|
618
708
|
}
|
|
619
709
|
|
|
710
|
+
/** Cache reuse policy for one Equity Diagnostic request. */
|
|
711
|
+
export type CloudEquityDiagnosticMode = "cache-first" | "refresh";
|
|
712
|
+
|
|
713
|
+
export type CloudEquityDiagnosticFindingKind = "red_flag" | "green_flag" | "anomaly";
|
|
714
|
+
|
|
715
|
+
/** 3 is the most severe. */
|
|
716
|
+
export type CloudEquityDiagnosticSeverity = 1 | 2 | 3;
|
|
717
|
+
|
|
718
|
+
export interface CloudEquityDiagnosticFinding {
|
|
719
|
+
id: string;
|
|
720
|
+
kind: CloudEquityDiagnosticFindingKind;
|
|
721
|
+
severity: CloudEquityDiagnosticSeverity;
|
|
722
|
+
confidence: number;
|
|
723
|
+
title: string;
|
|
724
|
+
/** What the data says, with no reading attached. */
|
|
725
|
+
observation: string;
|
|
726
|
+
/** What the observation may mean; kept apart from the observation on purpose. */
|
|
727
|
+
interpretation: string;
|
|
728
|
+
/** Ids into `evidence`; unresolved ids are dropped by the client. */
|
|
729
|
+
evidenceIds: string[];
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
export interface CloudEquityDiagnosticCoverage {
|
|
733
|
+
dataset: string;
|
|
734
|
+
status: "available" | "no_data" | "unsupported" | "failed";
|
|
735
|
+
asOf?: string;
|
|
736
|
+
provider?: string;
|
|
737
|
+
note?: string;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/** The server owns citation URLs; the client never builds them. */
|
|
741
|
+
export interface CloudEquityDiagnosticEvidence {
|
|
742
|
+
id: string;
|
|
743
|
+
dataset: string;
|
|
744
|
+
label: string;
|
|
745
|
+
asOf?: string;
|
|
746
|
+
provider?: string;
|
|
747
|
+
url?: string;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
export interface CloudEquityDiagnosticPending {
|
|
751
|
+
status: "generating";
|
|
752
|
+
retryAfterMs: number;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
export interface CloudEquityDiagnosticResponse {
|
|
756
|
+
schemaVersion: 1;
|
|
757
|
+
access: "preview" | "full";
|
|
758
|
+
symbol: string;
|
|
759
|
+
exchange: string;
|
|
760
|
+
companyName?: string;
|
|
761
|
+
status: "complete" | "partial" | "insufficient_data";
|
|
762
|
+
verdict: "risk_skewed" | "balanced" | "opportunity_skewed" | "unclear";
|
|
763
|
+
summary: string;
|
|
764
|
+
confidence: number;
|
|
765
|
+
findings: CloudEquityDiagnosticFinding[];
|
|
766
|
+
watchItems: string[];
|
|
767
|
+
coverage: CloudEquityDiagnosticCoverage[];
|
|
768
|
+
evidence: CloudEquityDiagnosticEvidence[];
|
|
769
|
+
generatedAt: string;
|
|
770
|
+
expiresAt: string;
|
|
771
|
+
/** Before this instant a `refresh` request may still answer from cache. */
|
|
772
|
+
refreshAllowedAt: string;
|
|
773
|
+
cached: boolean;
|
|
774
|
+
stale: boolean;
|
|
775
|
+
promptVersion: 1;
|
|
776
|
+
model: "gpt-5.6-luna";
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
export type CloudEquityDiagnosticResult =
|
|
780
|
+
| CloudEquityDiagnosticPending
|
|
781
|
+
| CloudEquityDiagnosticResponse;
|
|
782
|
+
|
|
620
783
|
export interface CloudVerificationResponse {
|
|
621
784
|
sent: boolean;
|
|
622
785
|
email?: string;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import type { PluginRegistry } from "../../plugins/registry";
|
|
12
12
|
import {
|
|
13
13
|
getFocusedCollectionId,
|
|
14
|
+
resolveTickerForPane,
|
|
14
15
|
syncConfigActiveLayoutState,
|
|
15
16
|
type AppAction,
|
|
16
17
|
type AppState,
|
|
@@ -75,7 +76,9 @@ export function useAppPaneRuntime({
|
|
|
75
76
|
|
|
76
77
|
const persistLayout = useCallback((layout: LayoutConfig, options?: { pushHistory?: boolean; focusedPaneId?: string | null }) => {
|
|
77
78
|
const currentState = stateRef.current;
|
|
78
|
-
const normalizedLayout = normalizePaneLayout(layout
|
|
79
|
+
const normalizedLayout = normalizePaneLayout(layout, {
|
|
80
|
+
resolveOrphanSymbol: (instanceId) => resolveTickerForPane(currentState, instanceId),
|
|
81
|
+
});
|
|
79
82
|
if (options?.pushHistory !== false) {
|
|
80
83
|
dispatch({ type: "PUSH_LAYOUT_HISTORY" });
|
|
81
84
|
}
|