gloomberb 0.16.1 → 0.16.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.
Files changed (574) hide show
  1. package/README.md +2 -1
  2. package/package.json +2 -1
  3. package/src/api-client/beneficial-owners.ts +92 -0
  4. package/src/api-client/data.ts +26 -8
  5. package/src/api-client/errors.ts +12 -0
  6. package/src/api-client/geo.ts +363 -0
  7. package/src/api-client/index.ts +2 -0
  8. package/src/api-client/market-discovery.ts +10 -0
  9. package/src/api-client/paths.ts +30 -1
  10. package/src/api-client/perps.ts +37 -0
  11. package/src/api-client/request.ts +5 -2
  12. package/src/api-client/types.ts +2 -0
  13. package/src/brokers/account-cache.ts +24 -0
  14. package/src/cli/commands/command-utils.ts +8 -0
  15. package/src/cli/commands/crypto-hints.ts +75 -0
  16. package/src/cli/commands/market.ts +414 -106
  17. package/src/cli/commands/overview.ts +77 -32
  18. package/src/cli/commands/ticker.ts +101 -43
  19. package/src/cli/desktop-pane-shot.ts +34 -4
  20. package/src/cli/freshness.ts +61 -0
  21. package/src/cli/help.ts +1 -0
  22. package/src/cli/helpers.ts +4 -8
  23. package/src/cli/index.ts +12 -2
  24. package/src/cli/listing-arg.ts +321 -0
  25. package/src/cli/pane-functions/access-gate.ts +42 -0
  26. package/src/cli/pane-functions/catalog.ts +28 -1
  27. package/src/cli/pane-functions/data.ts +3 -1
  28. package/src/cli/pane-functions/dom.ts +20 -2
  29. package/src/cli/pane-functions/freshness.ts +400 -0
  30. package/src/cli/pane-functions/function-help.ts +27 -20
  31. package/src/cli/pane-functions/headless.ts +39 -11
  32. package/src/cli/pane-functions/index.ts +15 -4
  33. package/src/cli/pane-functions/options.ts +3 -0
  34. package/src/cli/pane-functions/report.ts +4 -0
  35. package/src/cli/pane-functions/resolver.ts +35 -7
  36. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  37. package/src/cli/pane-functions/screenshot.ts +7 -3
  38. package/src/cli/result.ts +41 -27
  39. package/src/cli/ticker-resolution.ts +7 -5
  40. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  41. package/src/components/chart/composite/drawing-store.ts +59 -0
  42. package/src/components/chart/composite/legend.tsx +319 -0
  43. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  44. package/src/components/chart/composite/panel-gestures.ts +59 -0
  45. package/src/components/chart/composite/panel-labels.ts +107 -0
  46. package/src/components/chart/composite/panel-surface.tsx +876 -0
  47. package/src/components/chart/composite/tool-catalog.ts +98 -0
  48. package/src/components/chart/composite/toolbar.tsx +186 -0
  49. package/src/components/chart/composite/tools.ts +8 -0
  50. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  51. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  52. package/src/components/command-bar/list/model.ts +5 -0
  53. package/src/components/command-bar/list/view.tsx +16 -3
  54. package/src/components/command-bar/pane-templates/workflow.ts +1 -0
  55. package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
  56. package/src/components/command-bar/workflow/ops.ts +1 -1
  57. package/src/components/command-bar/workflow/tickers.ts +6 -0
  58. package/src/components/data-table/view.tsx +29 -10
  59. package/src/components/feedback-dialog.tsx +2 -1
  60. package/src/components/form-modal/field-row.tsx +2 -2
  61. package/src/components/layout/detached-pane-shell.tsx +6 -3
  62. package/src/components/layout/pane/content.tsx +23 -10
  63. package/src/components/layout/pane/error-boundary.tsx +103 -0
  64. package/src/components/layout/pane/footer/registration.tsx +68 -23
  65. package/src/components/layout/pane/header.tsx +11 -11
  66. package/src/components/layout/shell/menu.ts +2 -1
  67. package/src/components/layout/shell/pane/actions.ts +2 -1
  68. package/src/components/layout/shell/pane/layers.tsx +14 -3
  69. package/src/components/metric-treemap/heat-surface.tsx +43 -16
  70. package/src/components/metric-treemap/heat-tiles.ts +18 -0
  71. package/src/components/metric-treemap/layout.ts +2 -0
  72. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  73. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  74. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  75. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  76. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  77. package/src/components/ticker/list-table-view.tsx +13 -1
  78. package/src/components/ui/fields.tsx +8 -0
  79. package/src/components/ui/range-track.tsx +10 -3
  80. package/src/components/ui/status.tsx +8 -2
  81. package/src/components/ui/tabs.tsx +7 -4
  82. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  83. package/src/data/config/store/normalize.ts +17 -1
  84. package/src/i18n/es.ts +19 -1
  85. package/src/i18n/ja.ts +19 -1
  86. package/src/i18n/ko.ts +19 -1
  87. package/src/i18n/zh-cn.ts +19 -1
  88. package/src/i18n/zh-tw.ts +19 -1
  89. package/src/market-data/coordinator/chart.ts +1 -1
  90. package/src/market-data/coordinator/quotes.ts +23 -4
  91. package/src/market-data/fx-closes.ts +72 -0
  92. package/src/market-data/market/freshness.ts +78 -6
  93. package/src/market-data/market/session-close-note.ts +57 -0
  94. package/src/market-data/market/status.ts +151 -0
  95. package/src/market-data/published-apac-sessions.ts +66 -0
  96. package/src/market-data/quotes/contributions.ts +2 -0
  97. package/src/market-data/quotes/resolution.ts +2 -0
  98. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  99. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  100. package/src/plugins/builtin/alerts/cli.ts +10 -5
  101. package/src/plugins/builtin/alerts/index.tsx +1 -0
  102. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  103. package/src/plugins/builtin/analytics/risk-client.ts +191 -66
  104. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  105. package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
  106. package/src/plugins/builtin/analytics/risk-model.ts +45 -17
  107. package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
  108. package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
  109. package/src/plugins/builtin/attention/headless.ts +6 -4
  110. package/src/plugins/builtin/attention/index.tsx +1 -1
  111. package/src/plugins/builtin/attention/pane.tsx +1 -1
  112. package/src/plugins/builtin/awards/headless.ts +1 -0
  113. package/src/plugins/builtin/awards/pane.tsx +1 -1
  114. package/src/plugins/builtin/backtest/headless.ts +1 -0
  115. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  116. package/src/plugins/builtin/buildout/index.tsx +1 -0
  117. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  118. package/src/plugins/builtin/cds/headless.ts +2 -0
  119. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  120. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  121. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  122. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  123. package/src/plugins/builtin/chat/channels.ts +19 -3
  124. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  125. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  126. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  127. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  128. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  129. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  130. package/src/plugins/builtin/chat/index.tsx +1 -0
  131. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  132. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  133. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  134. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  135. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  136. package/src/plugins/builtin/chat/message/types.ts +14 -2
  137. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  138. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  139. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  140. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  141. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  142. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  143. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  144. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  145. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  146. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  147. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  148. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  149. package/src/plugins/builtin/correlation/compute.ts +59 -16
  150. package/src/plugins/builtin/correlation/geo.ts +34 -0
  151. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  152. package/src/plugins/builtin/correlation/headless.ts +42 -8
  153. package/src/plugins/builtin/correlation/history.ts +2 -0
  154. package/src/plugins/builtin/correlation/index.tsx +68 -14
  155. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  156. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  157. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  158. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  159. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  160. package/src/plugins/builtin/correlation/settings.ts +1 -1
  161. package/src/plugins/builtin/cot/headless.ts +6 -3
  162. package/src/plugins/builtin/cot/index.tsx +3 -3
  163. package/src/plugins/builtin/cot/model.ts +36 -3
  164. package/src/plugins/builtin/cpi/headless.ts +4 -0
  165. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  166. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  167. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  168. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  169. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  170. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  171. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  172. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  173. package/src/plugins/builtin/doe/headless.ts +7 -0
  174. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  175. package/src/plugins/builtin/earnings/headless.ts +5 -0
  176. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  177. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  178. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  179. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  180. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  181. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  182. package/src/plugins/builtin/econ/index.tsx +1 -0
  183. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  184. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  185. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  186. package/src/plugins/builtin/executives/index.tsx +1 -0
  187. package/src/plugins/builtin/exposure/headless.ts +3 -1
  188. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  189. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  190. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  191. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  192. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  193. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  194. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  195. package/src/plugins/builtin/gpu/headless.ts +7 -3
  196. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  197. package/src/plugins/builtin/gpu/model.ts +27 -1
  198. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  199. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  200. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  201. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  202. package/src/plugins/builtin/holders/headless.ts +139 -5
  203. package/src/plugins/builtin/holders/index.tsx +10 -3
  204. package/src/plugins/builtin/holders/pane.tsx +20 -3
  205. package/src/plugins/builtin/holders/report-header.ts +95 -0
  206. package/src/plugins/builtin/holders/table-model.ts +20 -5
  207. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  208. package/src/plugins/builtin/holders/types.ts +2 -1
  209. package/src/plugins/builtin/insider/headless.ts +2 -0
  210. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  211. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  212. package/src/plugins/builtin/jobs/headless.ts +1 -0
  213. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  214. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  215. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  216. package/src/plugins/builtin/market-heatmap/data.ts +2 -0
  217. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  218. package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
  219. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  220. package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
  221. package/src/plugins/builtin/market-movers/headless.ts +2 -0
  222. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  223. package/src/plugins/builtin/members/client.ts +20 -3
  224. package/src/plugins/builtin/members/headless.ts +5 -3
  225. package/src/plugins/builtin/members/model.ts +10 -2
  226. package/src/plugins/builtin/members/pane.tsx +13 -6
  227. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  228. package/src/plugins/builtin/mna/headless.ts +1 -0
  229. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  230. package/src/plugins/builtin/news/headless.ts +2 -0
  231. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  232. package/src/plugins/builtin/notes/cli.ts +14 -6
  233. package/src/plugins/builtin/notes/index.tsx +1 -0
  234. package/src/plugins/builtin/openfda/index.tsx +1 -0
  235. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  236. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  237. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  238. package/src/plugins/builtin/pe-band/client.ts +48 -3
  239. package/src/plugins/builtin/pe-band/headless.ts +25 -7
  240. package/src/plugins/builtin/pe-band/model.ts +92 -16
  241. package/src/plugins/builtin/pe-band/pane.tsx +33 -16
  242. package/src/plugins/builtin/perps/client.ts +50 -3
  243. package/src/plugins/builtin/perps/headless.ts +144 -16
  244. package/src/plugins/builtin/perps/index.tsx +6 -6
  245. package/src/plugins/builtin/perps/model.ts +189 -12
  246. package/src/plugins/builtin/perps/pane.tsx +248 -47
  247. package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
  248. package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
  249. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  250. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  251. package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
  252. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  253. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  254. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  255. package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
  256. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  257. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  258. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  259. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  260. package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
  261. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  262. package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
  263. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  264. package/src/plugins/builtin/power/headless.ts +3 -1
  265. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  266. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  267. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  268. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  269. package/src/plugins/builtin/research/events-headless.ts +2 -0
  270. package/src/plugins/builtin/research/headless.ts +2 -0
  271. package/src/plugins/builtin/research/index.tsx +1 -0
  272. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  273. package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
  274. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  275. package/src/plugins/builtin/research-search/index.tsx +1 -0
  276. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  277. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  278. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  279. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  280. package/src/plugins/builtin/scanner/headless.ts +14 -0
  281. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  282. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  283. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  284. package/src/plugins/builtin/sec/forms.ts +12 -0
  285. package/src/plugins/builtin/sec/headless.ts +2 -0
  286. package/src/plugins/builtin/sectors/client.ts +1 -0
  287. package/src/plugins/builtin/sectors/headless.ts +9 -1
  288. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  289. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  290. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  291. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  292. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  293. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  294. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  295. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  296. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  297. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  298. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  299. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  300. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  301. package/src/plugins/builtin/themes/headless.ts +3 -0
  302. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  303. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  304. package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
  305. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  306. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
  307. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
  308. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  309. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  310. package/src/plugins/builtin/volatility/headless.ts +6 -1
  311. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  312. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
  313. package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
  314. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  315. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  316. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  317. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  318. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  319. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  320. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  321. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
  322. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  323. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  324. package/src/plugins/builtin/world-venue-map/index.ts +67 -4
  325. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
  326. package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
  327. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  328. package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
  329. package/src/plugins/builtin/world-venue-map/model.ts +7 -4
  330. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
  331. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  332. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  333. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  334. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  335. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  336. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  337. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  338. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  339. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  340. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  341. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  342. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  343. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  344. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  345. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  346. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  347. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  348. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  349. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  350. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  351. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  352. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  353. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  354. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  355. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  356. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  357. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  358. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  359. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  360. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  361. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  362. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  363. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  364. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  365. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  366. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  367. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  368. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  369. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  370. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  371. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  372. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  373. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  374. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  375. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  376. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  377. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  378. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  379. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  380. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  381. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  382. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  383. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  384. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  385. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  386. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  387. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  388. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  389. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  390. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  391. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  392. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  393. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  394. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  395. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  396. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  397. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  398. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  399. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  400. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  401. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  402. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  403. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  404. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  405. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  406. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  407. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  408. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  409. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  410. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  411. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  412. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  413. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  414. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  415. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  416. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  417. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  418. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
  524. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  525. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  526. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  527. package/src/plugins/loader.ts +13 -1
  528. package/src/plugins/registry/pane-settings.ts +1 -0
  529. package/src/renderers/dom/build-assets.ts +81 -3
  530. package/src/renderers/dom/data-table/row.tsx +2 -0
  531. package/src/renderers/dom/desktop/controls.tsx +7 -3
  532. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  533. package/src/renderers/dom/desktop/popover.tsx +73 -14
  534. package/src/renderers/dom/host/input.tsx +14 -3
  535. package/src/renderers/dom/styles.css +6 -7
  536. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  537. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
  538. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  539. package/src/renderers/opentui/host.tsx +5 -0
  540. package/src/sources/gloomberb-cloud/index.ts +25 -4
  541. package/src/sources/gloomberb-cloud/normalizers.ts +27 -3
  542. package/src/sources/provider-router/cached-routes.ts +4 -1
  543. package/src/sources/provider-router/financials.ts +8 -7
  544. package/src/sources/provider-router/history.ts +15 -10
  545. package/src/sources/sec-registrant.ts +75 -0
  546. package/src/state/app/context/index.tsx +24 -8
  547. package/src/state/hooks/quote-streaming.ts +41 -26
  548. package/src/sync/core-contributors.ts +4 -0
  549. package/src/telemetry/crash-reports.ts +4 -1
  550. package/src/test-support/cli-context.ts +10 -2
  551. package/src/theme/heat-colors.ts +266 -84
  552. package/src/time-series/resolve.ts +1 -1
  553. package/src/time-series/use-chart-resolution.ts +1 -1
  554. package/src/types/context-menu.ts +6 -0
  555. package/src/types/data-provider.ts +2 -0
  556. package/src/types/financials.ts +3 -0
  557. package/src/types/headless.ts +79 -2
  558. package/src/types/plugin.ts +20 -1
  559. package/src/types/ticker.ts +15 -0
  560. package/src/ui/host.tsx +14 -0
  561. package/src/updater/index.ts +9 -11
  562. package/src/utils/async-deadline.ts +21 -0
  563. package/src/utils/cli-output.ts +5 -1
  564. package/src/utils/crypto-pair.ts +41 -0
  565. package/src/utils/currency-units.ts +14 -0
  566. package/src/utils/depositary-receipt.ts +26 -0
  567. package/src/utils/exchanges.ts +72 -0
  568. package/src/utils/fire-and-forget.ts +24 -0
  569. package/src/utils/format.ts +13 -0
  570. package/src/utils/price-earnings.ts +70 -3
  571. package/src/utils/price-history.ts +58 -13
  572. package/src/utils/rpc-timeout-error.ts +27 -0
  573. package/src/utils/sec.ts +13 -1
  574. package/src/utils/utc-time.ts +79 -0
@@ -36,6 +36,24 @@ function cloudInternalProviderId(providerMeta?: CloudProviderMeta): string | nul
36
36
  return upstream ? `${GLOOMBERB_CLOUD_PROVIDER_ID}:${upstream}` : null;
37
37
  }
38
38
 
39
+ /**
40
+ * A previous close is a price from inside the trailing 52 weeks, so it cannot
41
+ * sit far below the 52-week low. The service has sent 0.000205 as the
42
+ * Shanghai Composite's close (52-week low 3,741), which drew a +1.86e9% move.
43
+ * Today's price plays no part, so a real gap of any size still shows; two
44
+ * orders of magnitude leave room for a 52-week low that lags a crash or a split.
45
+ */
46
+ const IMPOSSIBLE_CLOSE_FACTOR = 100;
47
+
48
+ function isImpossiblePreviousClose(
49
+ previousClose: number | null | undefined,
50
+ low52w: number | null | undefined,
51
+ ): boolean {
52
+ return typeof previousClose === "number" && Number.isFinite(previousClose) && previousClose > 0
53
+ && typeof low52w === "number" && Number.isFinite(low52w) && low52w > 0
54
+ && previousClose * IMPOSSIBLE_CLOSE_FACTOR < low52w;
55
+ }
56
+
39
57
  export function mapQuote(
40
58
  quote: CloudQuotePayload,
41
59
  providerMeta?: CloudProviderMeta,
@@ -50,10 +68,11 @@ export function mapQuote(
50
68
  quote.fullExchangeName ??
51
69
  listingExchangeName;
52
70
  const internalProviderId = cloudInternalProviderId(providerMeta);
53
- const change = typeof quote.change === "number" && Number.isFinite(quote.change)
71
+ const impossibleClose = isImpossiblePreviousClose(quote.previousClose, quote.low52w);
72
+ const change = !impossibleClose && typeof quote.change === "number" && Number.isFinite(quote.change)
54
73
  ? quote.change / divisor
55
74
  : Number.NaN;
56
- const changePercent = typeof quote.changePercent === "number" && Number.isFinite(quote.changePercent)
75
+ const changePercent = !impossibleClose && typeof quote.changePercent === "number" && Number.isFinite(quote.changePercent)
57
76
  ? quote.changePercent
58
77
  : Number.NaN;
59
78
  // A generic future (VX1, TY1) reads in points or 32nds, not dollars.
@@ -70,8 +89,13 @@ export function mapQuote(
70
89
  price: normalizePriceValueByDivisor(quote.price, divisor) ?? quote.price,
71
90
  change,
72
91
  changePercent,
73
- previousClose: normalizePriceValueByDivisor(quote.previousClose, divisor),
92
+ previousClose: impossibleClose ? undefined : normalizePriceValueByDivisor(quote.previousClose, divisor),
74
93
  regularClose: normalizePriceValueByDivisor(quote.regularClose, divisor),
94
+ // JSON carries an unavailable move as null; the percent is unitless.
95
+ regularChange: normalizePriceValueByDivisor(quote.regularChange ?? undefined, divisor),
96
+ regularChangePercent: typeof quote.regularChangePercent === "number" && Number.isFinite(quote.regularChangePercent)
97
+ ? quote.regularChangePercent
98
+ : undefined,
75
99
  high52w: normalizePriceValueByDivisor(quote.high52w, divisor),
76
100
  low52w: normalizePriceValueByDivisor(quote.low52w, divisor),
77
101
  bid: normalizePriceValueByDivisor(quote.bid, divisor),
@@ -3,6 +3,7 @@ import { CachedQuery, type CachedValue } from "../../data/cached-query";
3
3
  import type { CachedAssetArgs, CachedAssetMethod, CachedAssetValue, DataProvider, MarketDataRequestContext, SecFilingItem } from "../../types/data-provider";
4
4
  import type { AnalystResearchData, CorporateActionsData, HolderData } from "../../types/financials";
5
5
  import { canonicalExchange } from "../../utils/exchanges";
6
+ import { nonUsSecListingVenue } from "../../utils/sec";
6
7
  import { shouldLogProviderError } from "../provider-errors";
7
8
  import { hasBrokerContext, withBrokerTimeout } from "./brokers";
8
9
  import { publicListingExchange } from "../listing-target";
@@ -220,9 +221,11 @@ export class ProviderRouterCachedRoutes {
220
221
  };
221
222
  case "getSecFilings": {
222
223
  const [symbol, count = 15, listingExchange, requestContext] = args as CachedAssetArgs<"getSecFilings">;
224
+ const exact = buildVariantKey([["exchange", canonicalExchange(listingExchange)], ["count", count]]);
223
225
  return {
224
226
  kind: "sec-filings", policy: "secFilings", entityKey: this.deps.getEntityKey(symbol, requestContext?.instrument),
225
- variants: [...new Set([buildVariantKey([["exchange", canonicalExchange(listingExchange)], ["count", count]]), buildVariantKey([["count", count]]), ""])],
227
+ // A non-US listing never reads the bare symbol's filings: SAN in Paris is Sanofi, SAN at the SEC is Santander.
228
+ variants: nonUsSecListingVenue(symbol, listingExchange) ? [exact] : [...new Set([exact, buildVariantKey([["count", count]]), ""])],
226
229
  request: (provider, force) => provider.getSecFilings?.(symbol, count, listingExchange, force ? { ...requestContext, cacheMode: "refresh" } : requestContext),
227
230
  throwLastError: true, error: `No SEC filings provider available for ${symbol}`,
228
231
  };
@@ -7,7 +7,7 @@ import { redactUnavailableFundamentals, RETRACTABLE_VALUATION_FIELDS } from "../
7
7
  import { isExtendedHoursExchange, isQuoteStaleForCurrentSession } from "../../market-data/quotes/freshness";
8
8
  import { mergeQuoteMetadata, quoteMetadataFromQuote, quoteMetadataMatchesTarget } from "../../market-data/quotes/metadata";
9
9
  import { parsePublicTickerKey } from "../../utils/exchanges";
10
- import { activeUsMarketSession, isUsPriorSessionPremarketQuote } from "../../market-data/market/freshness";
10
+ import { activeUsMarketSession, delayedFeedLagMs, isMiddayBreakPrint, isUsPriorSessionPremarketQuote } from "../../market-data/market/freshness";
11
11
  import {
12
12
  mergeQuoteContributionMaps,
13
13
  isQuoteContributionStaleForCurrentSession,
@@ -128,15 +128,16 @@ function isActiveProviderQuoteTooOld(quote: Quote, now = Date.now()): boolean {
128
128
  if (!isQuoteInActiveSession(quote, now)) return false;
129
129
  // A prior-session close before any pre-market trade has no in-session print
130
130
  // to age; the session-date rules bound it instead.
131
- if (isUsPriorSessionPremarketQuote(quote.lastUpdated, quote.listingExchangeName || quote.exchangeName, quote.marketState, now)) {
131
+ const exchange = quote.listingExchangeName || quote.exchangeName;
132
+ if (isUsPriorSessionPremarketQuote(quote.lastUpdated, exchange, quote.marketState, now)) {
132
133
  return false;
133
134
  }
134
135
  if (!Number.isFinite(quote.lastUpdated)) return false;
135
- const maxAge =
136
- quote.dataSource === "delayed"
137
- ? ACTIVE_DELAYED_PROVIDER_QUOTE_MAX_AGE_MS
138
- : ACTIVE_PROVIDER_QUOTE_MAX_AGE_MS;
139
- return now - quote.lastUpdated > maxAge;
136
+ const delayed = quote.dataSource === "delayed";
137
+ const maxAge = delayed ? ACTIVE_DELAYED_PROVIDER_QUOTE_MAX_AGE_MS : ACTIVE_PROVIDER_QUOTE_MAX_AGE_MS;
138
+ if (now - quote.lastUpdated <= maxAge) return false;
139
+ // While the venue pauses at midday, the morning's last print is the current price.
140
+ return !isMiddayBreakPrint(quote.lastUpdated, exchange, now, delayed ? delayedFeedLagMs(exchange) : 0);
140
141
  }
141
142
 
142
143
  export function providerQuoteMatchesTarget(quote: Quote | null | undefined, symbol?: string, exchange?: string): quote is Quote {
@@ -19,6 +19,7 @@ import { subtractTimeRange } from "../../time-series/date-window";
19
19
  import { clipPriceHistoryToRange } from "../../time-series/history-window";
20
20
  import { repairIsolatedIntradayOhlcOutliers } from "../../time-series/history-quality";
21
21
  import { canonicalExchange, parsePublicTickerKey, resolveExchangeTimeZone } from "../../utils/exchanges";
22
+ import { isRoundTheClockCoin } from "../../utils/crypto-pair";
22
23
  import { zonedDateKey } from "../../utils/zoned-date-time";
23
24
  import { resolvePriceHistoryCurrencyUnit } from "../../utils/currency-units";
24
25
  import { calendarHistoryFetchState, calendarHistoryLastBarDate, dropLeadingPlaceholderBars, getPricePointTimestamp, hasUsablePriceHistory, preservePriceHistoryGaps, isPriceHistoryStaleForCurrentWindow, normalizePriceHistory, priceHistoryIntervalMs, type CalendarHistoryFetchState } from "../../utils/price-history";
@@ -245,9 +246,9 @@ function normalizeRequestResult(value: PriceHistoryResult, request: HistoryReque
245
246
  };
246
247
  }
247
248
 
248
- function resultIsStale(value: PriceHistoryResult, exchange: string, intervalMs?: number | null): boolean {
249
+ function resultIsStale(value: PriceHistoryResult, symbol: string, exchange: string, intervalMs?: number | null): boolean {
249
250
  return isPriceHistoryStaleForCurrentWindow(value.points, Date.now(), {
250
- exchange, intervalMs: intervalMs ?? (value.resolution ? priceHistoryIntervalMs(value.resolution) : undefined), session: value.session,
251
+ symbol, exchange, intervalMs: intervalMs ?? (value.resolution ? priceHistoryIntervalMs(value.resolution) : undefined), session: value.session,
251
252
  });
252
253
  }
253
254
 
@@ -342,8 +343,8 @@ export class ProviderRouterHistoryRoutes {
342
343
  context,
343
344
  cachePolicyKey: intraday ? "priceHistoryIntraday" : "priceHistoryDaily",
344
345
  missingProviderError: `No history provider available for ${ticker}`,
345
- isCachedValueStale: (value) => intraday && resultIsStale(value, exchange),
346
- isFetchedValueStale: (value) => intraday && resultIsStale(value, exchange),
346
+ isCachedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange),
347
+ isFetchedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange),
347
348
  fetchBroker: async (candidate) => candidate.broker.getPriceHistory
348
349
  ? candidate.broker.getPriceHistory(
349
350
  ticker,
@@ -399,8 +400,8 @@ export class ProviderRouterHistoryRoutes {
399
400
  context,
400
401
  cachePolicyKey: intraday ? "priceHistoryIntraday" : "priceHistoryDaily",
401
402
  missingProviderError: `No resolution-aware history provider available for ${ticker}`,
402
- isCachedValueStale: (value) => intraday && resultIsStale(value, exchange, intervalMs),
403
- isFetchedValueStale: (value) => intraday && resultIsStale(value, exchange, intervalMs),
403
+ isCachedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange, intervalMs),
404
+ isFetchedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange, intervalMs),
404
405
  fetchBroker: async (candidate) => candidate.broker.getPriceHistoryForResolution
405
406
  ? candidate.broker.getPriceHistoryForResolution(
406
407
  ticker,
@@ -515,9 +516,9 @@ export class ProviderRouterHistoryRoutes {
515
516
  context,
516
517
  cachePolicyKey: intervalMs != null && intervalMs >= 24 * 60 * 60 * 1000 ? "priceHistoryDaily" : "priceHistoryIntraday",
517
518
  isCachedValueStale: (value) => currentWindowAtLookup
518
- && resultIsStale(value, exchange, intervalMs),
519
+ && resultIsStale(value, ticker, exchange, intervalMs),
519
520
  isFetchedValueStale: (value) => isCurrentHistoryWindow(endDate)
520
- && resultIsStale(value, exchange, intervalMs),
521
+ && resultIsStale(value, ticker, exchange, intervalMs),
521
522
  fetchBroker: async (candidate) => candidate.broker.getDetailedPriceHistory
522
523
  ? candidate.broker.getDetailedPriceHistory(
523
524
  ticker,
@@ -568,6 +569,7 @@ export class ProviderRouterHistoryRoutes {
568
569
  const now = Date.now();
569
570
  const fetchState = (record: { fetchedAt: number; value: PriceHistoryResult }, checkedAt?: number): CalendarHistoryFetchState => currentWindow
570
571
  ? calendarHistoryFetchState(record.value.points, record.fetchedAt, now, {
572
+ symbol: target.symbol,
571
573
  exchange: target.exchange || request.target.exchange,
572
574
  checkedAt,
573
575
  // Bar size comes from the request: a cached weekly or monthly series
@@ -580,7 +582,7 @@ export class ProviderRouterHistoryRoutes {
580
582
  const ranked = cachedRecords.filter((record) => hasUsablePriceHistory(record.value.points)).map((record) => {
581
583
  const tier = fetchTier[fetchState(record)];
582
584
  return { record, tier, exact: request.exactCacheVariantKeys.includes(record.variantKey),
583
- lastBar: tier === 0 ? "" : calendarHistoryLastBarDate(record.value.points, target.exchange || request.target.exchange) ?? "" };
585
+ lastBar: tier === 0 ? "" : calendarHistoryLastBarDate(record.value.points, target.exchange || request.target.exchange, target.symbol) ?? "" };
584
586
  });
585
587
  // Current copies keep their listed order. Otherwise ties go to this key's
586
588
  // own copy, then the latest fetch, rather than to row order.
@@ -657,7 +659,10 @@ export class ProviderRouterHistoryRoutes {
657
659
  throw new HistoryRetentionError(candidates[0]?.retention ?? attempts.retention, { candidates, outcomes: [...attempts.outcomes.values()] });
658
660
  }
659
661
  if (!providerResult && request.missingProviderError && !reportedGaps.some((value) => value.points.length > 0)) {
660
- throw new Error(request.missingProviderError);
662
+ // A source answered a coin's history but it stops short of the present: say so, not that nothing answered.
663
+ const behind = isRoundTheClockCoin(target.symbol, target.exchange || request.target.exchange)
664
+ && [...attempts.outcomes.values()].some((outcome) => outcome.outcome === "stale");
665
+ throw new Error(behind ? `Latest history for ${target.symbol} is behind` : request.missingProviderError);
661
666
  }
662
667
  return withReportedGaps(providerResult?.value ?? { points: [], resolution: historyResolutionForInterval(request.interval) });
663
668
  }
@@ -0,0 +1,75 @@
1
+ import type { SecFilingItem } from "../types/data-provider";
2
+ import { ProviderMissError } from "./provider-errors";
3
+
4
+ /** Legal forms and grouping words, which say nothing about which company a name is. */
5
+ const COMPANY_NAME_FILLER = new Set([
6
+ "THE", "SA", "PLC", "LTD", "LIMITED", "CORP", "CORPORATION", "INC", "INCORPORATED", "NV", "AG", "SE",
7
+ "HOLDING", "HOLDINGS", "GROUP", "COMPANY", "CO",
8
+ ]);
9
+
10
+ /**
11
+ * The first word of a company name that tells it apart, in capitals without
12
+ * accents: "BANCO" for "Banco Santander, S.A.", "BP" for "BP p.l.c.". Null
13
+ * when the name is only legal forms.
14
+ */
15
+ function companyNameToken(name: string | null | undefined): string | null {
16
+ const words = (name ?? "")
17
+ .normalize("NFKD")
18
+ .replace(/[\u0300-\u036f]/g, "")
19
+ .toUpperCase()
20
+ // An initialism (S.A., N.V., p.l.c.) is one word; any other dot separates two (Amazon.com).
21
+ .replace(/\b(?:[A-Z]\.){2,}/g, (initialism) => initialism.replaceAll(".", ""))
22
+ .replace(/['\u2019]/g, "")
23
+ .split(/[^A-Z0-9]+/);
24
+ return words.find((word) => word && !COMPANY_NAME_FILLER.has(word)) ?? null;
25
+ }
26
+
27
+ /**
28
+ * Whether two names are clearly different companies. Names that cannot be
29
+ * compared count as the same, so only a plain conflict hides anything.
30
+ */
31
+ export function areDifferentCompanies(left: string | null | undefined, right: string | null | undefined): boolean {
32
+ const leftToken = companyNameToken(left);
33
+ const rightToken = companyNameToken(right);
34
+ return !!leftToken && !!rightToken && leftToken !== rightToken;
35
+ }
36
+
37
+ export interface SecListing {
38
+ /** The bare symbol, such as SAN. */
39
+ symbol: string;
40
+ /** The listing's canonical venue, such as EPA. */
41
+ exchange: string;
42
+ /** The listing's company, from its own quote. */
43
+ name: string;
44
+ }
45
+
46
+ /** "No SEC filings found for Sanofi (EPA). The SEC lists SAN as Banco Santander, S.A. (NYSE)." */
47
+ export function secRegistrantMismatchMessage(listing: SecListing, registrantName: string, registrantExchange?: string | null): string {
48
+ const registrant = registrantExchange ? `${registrantName} (${registrantExchange})` : registrantName;
49
+ return `No SEC filings found for ${listing.name} (${listing.exchange}). The SEC lists ${listing.symbol} as ${registrant}${registrant.endsWith(".") ? "" : "."}`;
50
+ }
51
+
52
+ /** The SEC knows the listing's symbol as another company: SAN on EPA is Sanofi, SAN at the SEC is Banco Santander. */
53
+ export class SecRegistrantMismatchError extends ProviderMissError {
54
+ constructor(readonly listing: SecListing, readonly registrantName: string) {
55
+ super(secRegistrantMismatchMessage(listing, registrantName));
56
+ this.name = "SecRegistrantMismatchError";
57
+ }
58
+ }
59
+
60
+ /** The company the filings were filed by. */
61
+ function registrantName(filings: readonly SecFilingItem[]): string | null {
62
+ return filings.map((filing) => filing.companyName?.trim()).find((name): name is string => !!name) ?? null;
63
+ }
64
+
65
+ /**
66
+ * A lookup for a listing outside the US can answer with the US registrant of
67
+ * the same symbol: a backend that predates venue-aware lookups ignores the
68
+ * venue. Those filings are another company's, so they are refused.
69
+ */
70
+ export function assertSecRegistrantMatches(filings: readonly SecFilingItem[], listing: SecListing): void {
71
+ const registrant = registrantName(filings);
72
+ if (registrant && areDifferentCompanies(listing.name, registrant)) {
73
+ throw new SecRegistrantMismatchError(listing, registrant);
74
+ }
75
+ }
@@ -44,6 +44,7 @@ import {
44
44
  import type { AppAction, AppState } from "../../../core/state/app/state";
45
45
  import { scheduleConfigSave } from "../../config-save-scheduler";
46
46
  import { LOW_PRIORITY_CONFIG_SAVE_DEBOUNCE_MS } from "../../persist-scheduler";
47
+ import { fireAndForget } from "../../../utils/fire-and-forget";
47
48
 
48
49
  export {
49
50
  appReducer,
@@ -565,10 +566,16 @@ export function AppProvider({
565
566
  if (signature === lastMainSyncRef.current) return;
566
567
  lastMainSyncRef.current = signature;
567
568
  latestMainStateRevisionRef.current += 1;
568
- void desktopBridge.syncMainState({
569
- ...snapshot,
570
- mainStateRevision: latestMainStateRevisionRef.current,
571
- });
569
+ // A snapshot that did not arrive must not count as sent. Forget it, unless
570
+ // a newer one has replaced it, so the next effect run sends it again. The
571
+ // two syncs below dedupe the same way.
572
+ fireAndForget(
573
+ desktopBridge.syncMainState({ ...snapshot, mainStateRevision: latestMainStateRevisionRef.current }),
574
+ "desktop.syncMainState",
575
+ () => {
576
+ if (lastMainSyncRef.current === signature) lastMainSyncRef.current = null;
577
+ },
578
+ );
572
579
  }, [
573
580
  buildDesktopSnapshot,
574
581
  desktopBridge,
@@ -581,9 +588,12 @@ export function AppProvider({
581
588
 
582
589
  useEffect(() => {
583
590
  if (desktopBridge?.kind !== "main" || !desktopBridge.syncThemePreview) return;
584
- if (lastThemePreviewSyncRef.current === state.themePreview) return;
585
- lastThemePreviewSyncRef.current = state.themePreview;
586
- void desktopBridge.syncThemePreview({ theme: state.themePreview });
591
+ const theme = state.themePreview;
592
+ if (lastThemePreviewSyncRef.current === theme) return;
593
+ lastThemePreviewSyncRef.current = theme;
594
+ fireAndForget(desktopBridge.syncThemePreview({ theme }), "desktop.setThemePreview", () => {
595
+ if (lastThemePreviewSyncRef.current === theme) lastThemePreviewSyncRef.current = undefined;
596
+ });
587
597
  }, [desktopBridge, state.themePreview]);
588
598
 
589
599
  useEffect(() => {
@@ -598,7 +608,13 @@ export function AppProvider({
598
608
  const paneSignature = serializePaneState(state.paneState[desktopBridge.paneId]);
599
609
  if (paneSignature === lastDetachedPaneSyncRef.current) return;
600
610
  lastDetachedPaneSyncRef.current = paneSignature;
601
- void desktopBridge.replaceDetachedPaneState(desktopBridge.paneId, state.paneState[desktopBridge.paneId] ?? {});
611
+ fireAndForget(
612
+ desktopBridge.replaceDetachedPaneState(desktopBridge.paneId, state.paneState[desktopBridge.paneId] ?? {}),
613
+ "desktop.replaceDetachedPaneState",
614
+ () => {
615
+ if (lastDetachedPaneSyncRef.current === paneSignature) lastDetachedPaneSyncRef.current = null;
616
+ },
617
+ );
602
618
  }, [desktopBridge, serializePaneState, state.paneState]);
603
619
 
604
620
  useLayoutEffect(() => {
@@ -106,21 +106,28 @@ export function useQuoteStreaming(
106
106
  const paneInView = usePaneInView();
107
107
  const coordinator = getSharedMarketDataCoordinator();
108
108
 
109
- const normalizedEntries = new Map<string, QuoteSubscriptionTarget>();
110
- for (const target of targets) {
111
- const resolved = normalizeQuoteStreamSubscriptionTarget(target);
112
- if (!resolved) continue;
113
- const normalized = paneInView ? resolved : downgradeOffscreenQuoteTarget(resolved);
114
- const key = buildQuoteStreamSubscriptionKey(normalized);
115
- normalizedEntries.set(key, normalized);
116
- }
117
- const sortedEntries = [...normalizedEntries.entries()].sort(([left], [right]) => left.localeCompare(right));
118
- const normalizedTargets = sortedEntries.map(([, target]) => target);
119
- const subscriptionKey = sortedEntries.map(([key]) => key).join("|");
120
- const identityKey = [...new Set(normalizedTargets.map(buildQuoteStreamSubscriptionIdentityKey))]
121
- .sort()
122
- .join("\u001f");
123
- const coordinatorTargets = toCoordinatorQuoteTargets(normalizedTargets);
109
+ // Keyed on the array, not its contents: callers memoize their targets, and a
110
+ // portfolio re-renders on every data frame, where re-keying and sorting a
111
+ // thousand targets cost a few milliseconds each time.
112
+ const { coordinatorTargets, identityKey, subscriptionKey } = useMemo(() => {
113
+ const normalizedEntries = new Map<string, QuoteSubscriptionTarget>();
114
+ for (const target of targets) {
115
+ const resolved = normalizeQuoteStreamSubscriptionTarget(target);
116
+ if (!resolved) continue;
117
+ const normalized = paneInView ? resolved : downgradeOffscreenQuoteTarget(resolved);
118
+ const key = buildQuoteStreamSubscriptionKey(normalized);
119
+ normalizedEntries.set(key, normalized);
120
+ }
121
+ const sortedEntries = [...normalizedEntries.entries()].sort(([left], [right]) => left.localeCompare(right));
122
+ const normalizedTargets = sortedEntries.map(([, target]) => target);
123
+ return {
124
+ coordinatorTargets: toCoordinatorQuoteTargets(normalizedTargets),
125
+ identityKey: [...new Set(normalizedTargets.map(buildQuoteStreamSubscriptionIdentityKey))]
126
+ .sort()
127
+ .join("\u001f"),
128
+ subscriptionKey: sortedEntries.map(([key]) => key).join("|"),
129
+ };
130
+ }, [paneInView, targets]);
124
131
  const latestSubscriptionRef = useRef({
125
132
  identityKey,
126
133
  subscriptionKey,
@@ -208,11 +215,16 @@ export function useQuoteUpdates(
208
215
  ): void {
209
216
  const appActive = useAppVisible();
210
217
  const coordinator = getSharedMarketDataCoordinator();
211
- const normalizedTargets = normalizeQuoteStreamSubscriptionTargets(targets);
212
- const instrumentKey = normalizedTargets
213
- .map((target) => buildQuoteKey(instrumentFromQuoteTarget(target)))
214
- .sort()
215
- .join("\u001f");
218
+ const { instrumentKey, normalizedTargets } = useMemo(() => {
219
+ const normalized = normalizeQuoteStreamSubscriptionTargets(targets);
220
+ return {
221
+ instrumentKey: normalized
222
+ .map((target) => buildQuoteKey(instrumentFromQuoteTarget(target)))
223
+ .sort()
224
+ .join("\u001f"),
225
+ normalizedTargets: normalized,
226
+ };
227
+ }, [targets]);
216
228
  const instruments = useMemo(() => uniqueQuoteInstruments(normalizedTargets), [instrumentKey]);
217
229
 
218
230
  useQuoteStreaming(targets, { enabled: liveStreaming });
@@ -270,12 +282,15 @@ export function useLiveQuoteEntries(
270
282
  subscriptionStartedAt: number;
271
283
  } {
272
284
  const appActive = useAppVisible();
273
- const normalizedTargets = normalizeQuoteStreamSubscriptionTargets(targets);
274
- const targetKey = [...new Set(
275
- normalizedTargets.map((target) => buildQuoteStreamSubscriptionIdentityKey(target)),
276
- )]
277
- .sort()
278
- .join("\u001f");
285
+ const { normalizedTargets, targetKey } = useMemo(() => {
286
+ const normalized = normalizeQuoteStreamSubscriptionTargets(targets);
287
+ return {
288
+ normalizedTargets: normalized,
289
+ targetKey: [...new Set(normalized.map((target) => buildQuoteStreamSubscriptionIdentityKey(target)))]
290
+ .sort()
291
+ .join("\u001f"),
292
+ };
293
+ }, [targets]);
279
294
  const liveStreaming = options.liveStreaming !== false;
280
295
  const freshnessKey = options.freshnessScopeKey ?? targetKey;
281
296
  const subscriptionKey = `${appActive ? "active" : "inactive"}\u001f${liveStreaming ? "live" : "poll"}\u001f${freshnessKey}`;
@@ -102,6 +102,10 @@ function sanitizePortfolio(portfolio: Portfolio): Portfolio {
102
102
  currency: portfolio.currency,
103
103
  brokerId: portfolio.brokerId,
104
104
  lastSyncedAt: portfolio.lastSyncedAt,
105
+ // Cash and targets are the user's own entries: a pulled portfolio without
106
+ // them would erase them on this device.
107
+ ...(portfolio.cash ? { cash: { ...portfolio.cash } } : {}),
108
+ ...(portfolio.targetWeights ? { targetWeights: { ...portfolio.targetWeights } } : {}),
105
109
  };
106
110
  }
107
111
 
@@ -6,6 +6,7 @@ import {
6
6
  type CrashReportsPayload,
7
7
  } from "../api-client";
8
8
  import type { TelemetryConfig } from "../types/config";
9
+ import { isSleepRpcTimeout } from "../utils/rpc-timeout-error";
9
10
  import { VERSION } from "../version";
10
11
 
11
12
  /**
@@ -172,10 +173,12 @@ function toReportError(error: unknown, context: CrashReportContext): PendingErro
172
173
  /**
173
174
  * Queues one error. Safe to call from any error handler: it never throws,
174
175
  * never awaits, and drops the error when reporting is off, already seen this
175
- * session, or over the session cap.
176
+ * session, or over the session cap. A desktop request timeout that fired
177
+ * after the machine slept is not an error at all and is dropped too.
176
178
  */
177
179
  export function reportCrash(error: unknown, context: CrashReportContext): void {
178
180
  try {
181
+ if (isSleepRpcTimeout(error)) return;
179
182
  if (host && !host.isEnabled()) return;
180
183
  if (accepted >= MAX_ERRORS_PER_SESSION) return;
181
184
  const entry = toReportError(error, context);
@@ -8,7 +8,8 @@ export interface PrintedCliResult {
8
8
  }
9
9
 
10
10
  /**
11
- * A command context whose `initMarketData` resolves to `market` (config, store, dataProvider, ...).
11
+ * A command context whose `initMarketData` and `initConfigData` resolve to `market` (config, store, dataProvider, ...),
12
+ * with an empty ticker store unless `market` brings one.
12
13
  * `fail` throws, every printResult call is kept in `printed`, and `closeCount` reports how many
13
14
  * times the command closed its persistence.
14
15
  */
@@ -18,9 +19,16 @@ export function createTestCliContext(
18
19
  ): { context: CliCommandContext; printed: PrintedCliResult[]; closeCount: () => number } {
19
20
  const printed: PrintedCliResult[] = [];
20
21
  let closed = 0;
22
+ const init = async () => ({
23
+ persistence: { close: () => { closed += 1; } },
24
+ // Commands look up the saved listing of every symbol they are given.
25
+ store: { loadTicker: async () => null, loadAllTickers: async () => [] },
26
+ ...market,
27
+ });
21
28
  const context = {
22
29
  cliOptions: { ...DEFAULT_CLI_OPTIONS, ...cliOptions },
23
- initMarketData: async () => ({ persistence: { close: () => { closed += 1; } }, ...market }),
30
+ initMarketData: init,
31
+ initConfigData: init,
24
32
  printResult: (result: CliResult<any>, options?: CliResultRenderOptions<any, any>) => { printed.push({ result, options }); },
25
33
  fail: (message: string): never => { throw new Error(message); },
26
34
  } as unknown as CliCommandContext;