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
@@ -0,0 +1,143 @@
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
+ import type { ResolvedSeries } from "../../../time-series/types";
3
+ import {
4
+ buildCompositeNavigationFrame,
5
+ compositeNavigationDataViewport,
6
+ compositeViewportPositions,
7
+ fitCompositeViewport,
8
+ panCompositeViewport,
9
+ sameCompositeViewport,
10
+ shouldResetCompositeViewport,
11
+ zoomCompositeViewport,
12
+ type CompositeNavigationFrame,
13
+ type CompositeViewportRange,
14
+ } from "./interactions";
15
+ import type { CompositeChartProps } from "./types";
16
+
17
+ /** How far past the first loaded observation a backfilling chart may pan, as a fraction of the view. */
18
+ const HISTORICAL_PADDING_RATIO = 0.5;
19
+
20
+ export function useCompositeViewport({
21
+ viewport,
22
+ viewportResetKey,
23
+ visibleSeries,
24
+ marketTimelineSeries,
25
+ allowHistoricalBackfill,
26
+ onViewportChange,
27
+ }: {
28
+ viewport: CompositeChartProps["viewport"];
29
+ viewportResetKey: CompositeChartProps["viewportResetKey"];
30
+ visibleSeries: ResolvedSeries[];
31
+ marketTimelineSeries: ResolvedSeries[];
32
+ allowHistoricalBackfill: boolean;
33
+ onViewportChange: CompositeChartProps["onViewportChange"];
34
+ }) {
35
+ const previousAuthoredViewportRef = useRef<CompositeViewportRange | null>(viewport ?? null);
36
+ const previousViewportResetKeyRef = useRef(viewportResetKey);
37
+ // The user owns this once they navigate. Data refreshes never rewrite it;
38
+ // only the authored viewport changing or an explicit reset clears it.
39
+ const [userViewport, setUserViewport] = useState<CompositeViewportRange | null>(null);
40
+ const hasViewportResetKey = viewportResetKey !== undefined
41
+ || previousViewportResetKeyRef.current !== undefined;
42
+ const authoredViewportChanged = hasViewportResetKey
43
+ ? previousViewportResetKeyRef.current !== viewportResetKey
44
+ : shouldResetCompositeViewport(
45
+ previousAuthoredViewportRef.current,
46
+ viewport ?? null,
47
+ );
48
+ const navigationFrame = useMemo(
49
+ () => buildCompositeNavigationFrame(visibleSeries, marketTimelineSeries, {
50
+ historicalPaddingRatio: allowHistoricalBackfill ? HISTORICAL_PADDING_RATIO : 0,
51
+ }),
52
+ [allowHistoricalBackfill, marketTimelineSeries, visibleSeries],
53
+ );
54
+ const authoredViewport = useMemo(() => {
55
+ // The requested dates own the axis, including gaps in a cached or partial
56
+ // response. Fitting them to available observations silently changes the
57
+ // research period. User pan/zoom gestures retain their navigation limits.
58
+ if (viewport && Number.isFinite(viewport.start.getTime())
59
+ && Number.isFinite(viewport.end.getTime()) && viewport.start <= viewport.end) return viewport;
60
+ return navigationFrame ? compositeNavigationDataViewport(navigationFrame) : null;
61
+ }, [navigationFrame, viewport]);
62
+ const activeUserViewport = authoredViewportChanged ? null : userViewport;
63
+ const effectiveViewport = activeUserViewport ?? authoredViewport;
64
+ const userViewportStart = activeUserViewport?.start.getTime() ?? null;
65
+ const userViewportEnd = activeUserViewport?.end.getTime() ?? null;
66
+ const lastReportedViewportRef = useRef<string | null>(null);
67
+ const viewportInteractionRef = useRef<"pan" | "reset" | "zoom">("reset");
68
+ useEffect(() => {
69
+ if (!onViewportChange) return;
70
+ const key = userViewportStart === null || userViewportEnd === null
71
+ ? "none"
72
+ : `${userViewportStart}:${userViewportEnd}`;
73
+ // The callback drives adaptive data loading. Seed it from the authored
74
+ // viewport without echoing that controlled value back into the loader.
75
+ if (lastReportedViewportRef.current === null) {
76
+ lastReportedViewportRef.current = key;
77
+ return;
78
+ }
79
+ if (lastReportedViewportRef.current === key) return;
80
+ lastReportedViewportRef.current = key;
81
+ onViewportChange(
82
+ userViewportStart === null || userViewportEnd === null
83
+ ? null
84
+ : { start: new Date(userViewportStart), end: new Date(userViewportEnd) },
85
+ viewportInteractionRef.current,
86
+ );
87
+ }, [onViewportChange, userViewportEnd, userViewportStart]);
88
+
89
+ useEffect(() => {
90
+ previousAuthoredViewportRef.current = viewport ?? null;
91
+ previousViewportResetKeyRef.current = viewportResetKey;
92
+ if (authoredViewportChanged && userViewport) {
93
+ viewportInteractionRef.current = "reset";
94
+ setUserViewport(null);
95
+ }
96
+ }, [authoredViewportChanged, userViewport, viewport, viewportResetKey]);
97
+
98
+ const navigate = useCallback((
99
+ kind: "pan" | "zoom",
100
+ compute: (base: CompositeViewportRange, frame: CompositeNavigationFrame) => CompositeViewportRange,
101
+ gesture?: { frame: CompositeNavigationFrame; from: CompositeViewportRange },
102
+ ) => {
103
+ const frame = gesture?.frame ?? navigationFrame;
104
+ if (!frame) return;
105
+ viewportInteractionRef.current = kind;
106
+ setUserViewport((current) => {
107
+ const base = gesture?.from ?? current ?? authoredViewport;
108
+ if (!base) return current;
109
+ const next = compute(base, frame);
110
+ // Once navigated, the window is the user's until they reset it, even if
111
+ // a gesture happens to land back on the authored range: the owner may
112
+ // echo a navigated range back as the authored one, and dropping to null
113
+ // there would reload the original range under the pointer.
114
+ return sameCompositeViewport(next, current ?? base) ? current : next;
115
+ });
116
+ }, [authoredViewport, navigationFrame]);
117
+ const panViewport = useCallback((
118
+ deltaPositions: number,
119
+ gesture?: { frame: CompositeNavigationFrame; from: CompositeViewportRange },
120
+ ) => {
121
+ navigate("pan", (base, frame) => panCompositeViewport(frame, base, deltaPositions), gesture);
122
+ }, [navigate]);
123
+ const panViewportByRatio = useCallback((shiftRatio: number) => {
124
+ if (!navigationFrame || !effectiveViewport) return;
125
+ const positions = compositeViewportPositions(navigationFrame, effectiveViewport);
126
+ if (!positions) return;
127
+ panViewport(shiftRatio * Math.max(positions.end - positions.start, Number.EPSILON));
128
+ }, [effectiveViewport, navigationFrame, panViewport]);
129
+ const zoomViewport = useCallback((zoomFactor: number, anchorRatio = 1) => {
130
+ navigate("zoom", (base, frame) => zoomCompositeViewport(frame, base, zoomFactor, anchorRatio));
131
+ }, [navigate]);
132
+ const setViewportRange = useCallback((range: CompositeViewportRange) => {
133
+ navigate("zoom", (_base, frame) => fitCompositeViewport(frame, range));
134
+ }, [navigate]);
135
+ const resetViewport = useCallback(() => {
136
+ viewportInteractionRef.current = "reset";
137
+ setUserViewport(null);
138
+ }, []);
139
+ return {
140
+ navigationFrame, activeUserViewport, effectiveViewport,
141
+ panViewport, panViewportByRatio, zoomViewport, setViewportRange, resetViewport,
142
+ };
143
+ }
@@ -24,6 +24,11 @@ export interface ResultItem {
24
24
  lines?: CommandBarResultLine[];
25
25
  /** Short tag drawn left of the label: a shortcut, an asset class, a document type. */
26
26
  badge?: string;
27
+ /**
28
+ * An instrument's name, drawn muted after the symbol. Listings that share a
29
+ * symbol (SAP on NYSE and XETRA, Saputo as SAP on TSX) differ only here.
30
+ */
31
+ name?: string;
27
32
  right?: string;
28
33
  /** Provider type retained for symbol/alias identity checks. */
29
34
  instrumentType?: string;
@@ -11,7 +11,7 @@ import {
11
11
  TextAttributes,
12
12
  type ScrollBoxRenderable,
13
13
  } from "../../../ui";
14
- import { truncateTextSegments, truncateToDisplayWidth } from "../../../utils/format";
14
+ import { displayWidth, truncateTextSegments, truncateToDisplayWidth } from "../../../utils/format";
15
15
  import { Spinner } from "../../ui";
16
16
  import { useCommandBarPalette } from "../panel/palette";
17
17
  import { getRowPresentation } from "../view-model";
@@ -37,6 +37,9 @@ export type CommandBarListScrollEvent = {
37
37
 
38
38
  /** Columns every row gives up to the badge column, badge or not. */
39
39
  const BADGE_INDENT = BADGE_COLUMN_WIDTH + BADGE_GAP;
40
+ const NAME_GAP = 2;
41
+ /** Below this a name is a few letters and an ellipsis, which tells nobody apart. */
42
+ const MIN_NAME_WIDTH = 6;
40
43
 
41
44
  interface CommandBarListItemRowProps {
42
45
  item: ResultItem;
@@ -79,7 +82,12 @@ const CommandBarListItemRow = memo(function CommandBarListItemRow({
79
82
  const labelColumnWidth = Math.max(1, labelWidth - BADGE_INDENT);
80
83
  // A long title stops one cell short of the right column, so its ellipsis
81
84
  // never runs into the date or shortcut sitting there.
82
- const label = truncateToDisplayWidth(presentation.label, Math.max(1, labelColumnWidth - (trailingWidth > 0 ? 1 : 0)));
85
+ const labelSpace = Math.max(1, labelColumnWidth - (trailingWidth > 0 ? 1 : 0));
86
+ const label = truncateToDisplayWidth(presentation.label, labelSpace);
87
+ // The name gives way before the symbol: it shrinks to its ellipsis and drops
88
+ // out once fewer than a few characters of it would show.
89
+ const nameSpace = labelSpace - displayWidth(label) - NAME_GAP;
90
+ const name = item.name && nameSpace >= MIN_NAME_WIDTH ? truncateToDisplayWidth(item.name, nameSpace) : "";
83
91
  // "current" outranks the shortcut on the right; otherwise a badge lifted from
84
92
  // `right` must not be repeated there.
85
93
  const trailing = badgeConsumesRight(item) && !item.current
@@ -152,10 +160,15 @@ const CommandBarListItemRow = memo(function CommandBarListItemRow({
152
160
  <Box width={BADGE_INDENT} flexDirection="row">
153
161
  {badge && <CommandBarRowBadge text={badge.text} tone={badge.tone} width={BADGE_COLUMN_WIDTH} />}
154
162
  </Box>
155
- <Box width={labelColumnWidth}>
163
+ <Box width={labelColumnWidth} flexDirection="row">
156
164
  <Text fg={isSelected ? palette.selectedText : presentation.primaryMuted ? palette.subtle : palette.text}>
157
165
  {label}
158
166
  </Text>
167
+ {name && (
168
+ <Text fg={isSelected ? palette.selectedText : palette.subtle}>
169
+ {" ".repeat(NAME_GAP) + name}
170
+ </Text>
171
+ )}
159
172
  </Box>
160
173
  <Box width={trailingWidth}>
161
174
  <Text
@@ -165,6 +165,7 @@ export function useCommandBarPaneTemplateActions({
165
165
  trimmedList,
166
166
  activeCollectionId,
167
167
  buildWorkflowDeps(),
168
+ template.shortcut?.keepArgToken,
168
169
  );
169
170
  const createOptions = {
170
171
  arg: trimmedList,
@@ -64,6 +64,9 @@ export function useCommandBarTickerSearchActions({
64
64
  // text goes quiet rather than repeating it.
65
65
  const badge = formatInstrumentBadge(candidate);
66
66
  const right = candidate.exchangeLabel || candidate.primaryExchangeLabel || candidate.right || undefined;
67
+ // The candidate's detail leads with the name; the rest repeats the badge or venue.
68
+ const leadingName = candidate.detail.split(" | ")[0]?.trim();
69
+ const name = leadingName && leadingName.toUpperCase() !== candidate.label.toUpperCase() ? leadingName : undefined;
67
70
 
68
71
  if (candidate.kind === "ticker" && candidate.ticker) {
69
72
  return {
@@ -74,6 +77,7 @@ export function useCommandBarTickerSearchActions({
74
77
  instrumentType: candidate.instrumentType,
75
78
  detail,
76
79
  badge,
80
+ name,
77
81
  right,
78
82
  category: candidate.category,
79
83
  kind: "ticker",
@@ -97,6 +101,7 @@ export function useCommandBarTickerSearchActions({
97
101
  instrumentType: candidate.instrumentType,
98
102
  detail,
99
103
  badge,
104
+ name,
100
105
  right,
101
106
  category: candidate.category,
102
107
  kind: "search",
@@ -252,7 +252,7 @@ async function resolvePaneTemplateOptions(
252
252
  const rawInput = resolvedOptions?.arg ?? resolvedOptions?.values?.tickers ?? "";
253
253
  const symbols = !String(rawInput).trim() && template.shortcut?.openWithoutArg
254
254
  ? []
255
- : await resolveTickerListInput(rawInput, baseContext.activeCollectionId, deps);
255
+ : await resolveTickerListInput(rawInput, baseContext.activeCollectionId, deps, template.shortcut?.keepArgToken);
256
256
  resolvedOptions = {
257
257
  ...resolvedOptions,
258
258
  arg: rawInput,
@@ -233,12 +233,18 @@ export async function resolveTickerListInput(
233
233
  rawInput: string,
234
234
  collectionId: string | null,
235
235
  deps: SharedWorkflowDeps,
236
+ keepToken?: (token: string) => boolean,
236
237
  ): Promise<string[]> {
237
238
  const tokens = parseTickerListInput(rawInput);
238
239
  const symbols: string[] = [];
239
240
  const seen = new Set<string>();
240
241
 
241
242
  for (const token of tokens) {
243
+ if (keepToken?.(token)) {
244
+ if (!seen.has(token)) symbols.push(token);
245
+ seen.add(token);
246
+ continue;
247
+ }
242
248
  const resolvedTicker = await resolveTickerInputOrThrow(token, null, collectionId, deps, { preserveListingKey: true });
243
249
  const symbol = resolvedTicker.symbol;
244
250
 
@@ -593,26 +593,45 @@ export function DataTableView<
593
593
  && (!isNavigable || isNavigable(item, index))
594
594
  ), [effectiveSelectedIndex, isNavigable]);
595
595
 
596
+ // The row handlers reach the latest cursor logic through a ref, so their
597
+ // identity survives a parent render. Most callers build `selection` inline,
598
+ // which used to give every handler a new identity on each render and made
599
+ // every visible row re-render its cells, even when nothing in it changed.
600
+ const rowHandlerStateRef = useRef({
601
+ activateIndex,
602
+ onRowContextMenu: tableProps.onRowContextMenu,
603
+ onRowMouseDown: tableProps.onRowMouseDown,
604
+ updateCursorIndex,
605
+ });
606
+ rowHandlerStateRef.current = {
607
+ activateIndex,
608
+ onRowContextMenu: tableProps.onRowContextMenu,
609
+ onRowMouseDown: tableProps.onRowMouseDown,
610
+ updateCursorIndex,
611
+ };
612
+
596
613
  const handleTableSelect = useCallback((_item: T, index: number) => {
597
- updateCursorIndex(index, { commit: "immediate" });
598
- }, [updateCursorIndex]);
614
+ rowHandlerStateRef.current.updateCursorIndex(index, { commit: "immediate" });
615
+ }, []);
599
616
 
600
617
  const handleTableActivate = useCallback((_item: T, index: number) => {
601
- activateIndex(index);
602
- }, [activateIndex]);
618
+ rowHandlerStateRef.current.activateIndex(index);
619
+ }, []);
603
620
 
604
621
  const handleRowMouseDown = useCallback((item: T, index: number, event: any) => {
605
- const handled = tableProps.onRowMouseDown?.(item, index, event);
622
+ const latest = rowHandlerStateRef.current;
623
+ const handled = latest.onRowMouseDown?.(item, index, event);
606
624
  if (handled === true) {
607
- updateCursorIndex(index, { commit: "immediate" });
625
+ latest.updateCursorIndex(index, { commit: "immediate" });
608
626
  }
609
627
  return handled;
610
- }, [tableProps.onRowMouseDown, updateCursorIndex]);
628
+ }, []);
611
629
 
612
630
  const handleRowContextMenu = useCallback((item: T, index: number, event: any) => {
613
- updateCursorIndex(index, { commit: "immediate" });
614
- tableProps.onRowContextMenu?.(item, index, event);
615
- }, [tableProps.onRowContextMenu, updateCursorIndex]);
631
+ const latest = rowHandlerStateRef.current;
632
+ latest.updateCursorIndex(index, { commit: "immediate" });
633
+ latest.onRowContextMenu?.(item, index, event);
634
+ }, []);
616
635
 
617
636
  // Wide tables scroll their columns on Shift+Left/Right, the way a chart pans,
618
637
  // and on Ctrl+Left/Right where the OS leaves those alone (macOS takes them to
@@ -37,6 +37,7 @@ import { useToastHost } from "../ui/toast";
37
37
  import { VERSION } from "../version";
38
38
  import { Button } from "./ui/button";
39
39
  import { Checkbox } from "./ui/checkbox";
40
+ import { FRAMED_TEXTAREA_DESKTOP_STYLE } from "./ui/fields";
40
41
  import { DialogFrame } from "./ui/frame";
41
42
  import { TERMINAL_MESSAGE_KEYS } from "./textarea-keys";
42
43
 
@@ -217,7 +218,7 @@ function FeedbackDialog({
217
218
  flexGrow={1}
218
219
  wrapText
219
220
  {...(nativePaneChrome
220
- ? { style: { padding: "6px 8px", lineHeight: "18px" }, onKeyDown: sendOnModifiedEnter }
221
+ ? { style: FRAMED_TEXTAREA_DESKTOP_STYLE, onKeyDown: sendOnModifiedEnter }
221
222
  : { keyBindings: TERMINAL_MESSAGE_KEYS, onSubmit: () => { void send(); } })}
222
223
  onInput={(value: string) => {
223
224
  messageValueRef.current = value;
@@ -19,7 +19,7 @@ import {
19
19
  import type { CommandBarFieldValue, CommandBarWorkflowField } from "../command-bar/workflow/types";
20
20
  import { TERMINAL_MESSAGE_KEYS } from "../textarea-keys";
21
21
  import { Checkbox } from "../ui/checkbox";
22
- import { FieldLabel, NumberField, TextField } from "../ui/fields";
22
+ import { FieldLabel, FRAMED_TEXTAREA_DESKTOP_STYLE, NumberField, TextField } from "../ui/fields";
23
23
  import { SelectField, type SelectFieldHandle } from "../ui/select-field";
24
24
  import { FORM_TEXTAREA_ROWS } from "./model";
25
25
 
@@ -132,7 +132,7 @@ function FormTextarea({
132
132
  flexGrow={1}
133
133
  wrapText
134
134
  {...(desktop
135
- ? { style: { padding: "6px 8px", lineHeight: "18px" }, onKeyDown: submitOnModifiedEnter }
135
+ ? { style: FRAMED_TEXTAREA_DESKTOP_STYLE, onKeyDown: submitOnModifiedEnter }
136
136
  : { keyBindings: TERMINAL_MESSAGE_KEYS, onSubmit: onSubmitField })}
137
137
  onInput={(nextValue: string) => onChange(nextValue)}
138
138
  />
@@ -32,6 +32,7 @@ import { contextMenuDivider, type ContextMenuItem } from "../../types/context-me
32
32
  import { useKeybindings } from "../../app/keybindings";
33
33
  import { useDialogState } from "../../ui/dialog";
34
34
  import { getShortcutDisplayMode } from "../../utils/shortcut-labels";
35
+ import { fireAndForget } from "../../utils/fire-and-forget";
35
36
  import {
36
37
  inputCaptureAllowsPaneManagementShortcut,
37
38
  modalSurfaceOwnsKey,
@@ -142,7 +143,7 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
142
143
  if (takeDoubleEscapeClose(doubleEscapeState, desktopWindowBridge.paneId, Date.now())) {
143
144
  event.preventDefault();
144
145
  event.stopPropagation();
145
- if (!locked) void desktopWindowBridge.closeDetachedPane?.(desktopWindowBridge.paneId);
146
+ if (!locked) fireAndForget(desktopWindowBridge.closeDetachedPane?.(desktopWindowBridge.paneId), "desktop.closeDetachedPane");
146
147
  }
147
148
  return;
148
149
  }
@@ -170,7 +171,7 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
170
171
  pluginRegistry.notify({ body: "Pane is locked. Unlock it in pane settings.", type: "info" });
171
172
  return;
172
173
  }
173
- void desktopWindowBridge.closeDetachedPane?.(desktopWindowBridge.paneId);
174
+ fireAndForget(desktopWindowBridge.closeDetachedPane?.(desktopWindowBridge.paneId), "desktop.closeDetachedPane");
174
175
  }, [desktopWindowBridge, locked, pluginRegistry]);
175
176
 
176
177
  const startWindowDrag = useCallback(() => {
@@ -212,7 +213,7 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
212
213
  }, [desktopWindowBridge.paneId, focusPane, pluginRegistry]);
213
214
 
214
215
  const dockPane = desktopWindowBridge.dockDetachedPane
215
- ? () => { void desktopWindowBridge.dockDetachedPane?.(desktopWindowBridge.paneId); }
216
+ ? () => { fireAndForget(desktopWindowBridge.dockDetachedPane?.(desktopWindowBridge.paneId), "desktop.dockDetachedPane"); }
216
217
  : null;
217
218
 
218
219
  /** The same menu as a pane in the main window, minus what a window cannot do. */
@@ -428,9 +429,11 @@ export function DetachedPaneShell({ pluginRegistry, desktopWindowBridge }: Detac
428
429
  component={paneDef.component}
429
430
  paneId={instance.instanceId}
430
431
  paneType={instance.paneId}
432
+ title={title}
431
433
  focused={focused}
432
434
  width={bodyWidth}
433
435
  height={bodyHeight}
436
+ closePane={closePane}
434
437
  />
435
438
  </PaneHeaderTabsProvider>
436
439
  </PaneBodyFrame>
@@ -7,6 +7,7 @@ import { useThemeColors } from "../../../theme/theme-context";
7
7
  import { PaneKeyboardScrollController } from "../../../state/pane-scroll-registry";
8
8
  import type { PaneDef } from "../../../types/plugin";
9
9
  import { Box } from "../../../ui";
10
+ import { PaneErrorBoundary } from "./error-boundary";
10
11
 
11
12
  // Under GLOOMBERB_PERF_TRACE every pane commit is reported by pane, which is
12
13
  // how a store update that fans out to the whole layout gets attributed. The
@@ -29,29 +30,39 @@ interface PaneContentProps {
29
30
  component: PaneDef["component"];
30
31
  paneId: string;
31
32
  paneType: string;
33
+ /** The header's title, named by the failure card when the pane throws. */
34
+ title: string;
32
35
  focused: boolean;
33
36
  width: number;
34
37
  height: number;
35
38
  /** False while the pane is covered on screen; its streams drop to the off-screen cadence. */
36
39
  inView?: boolean;
40
+ /** Passed to the pane as `close` (floating panes). */
37
41
  onClose?: (paneId: string) => void;
42
+ /** Takes the pane out of its layout; the failure card offers it. Keep it stable: the content is memoized. */
43
+ closePane?: (paneId: string) => void;
38
44
  }
39
45
 
40
46
  export const PaneContent = memo(function PaneContent({
41
47
  component: Component,
42
48
  paneId,
43
49
  paneType,
50
+ title,
44
51
  focused,
45
52
  width,
46
53
  height,
47
54
  inView = true,
48
55
  onClose,
56
+ closePane,
49
57
  }: PaneContentProps) {
50
58
  useAppLanguage();
51
59
  useThemeColors();
52
60
  const close = useCallback(() => {
53
61
  onClose?.(paneId);
54
62
  }, [onClose, paneId]);
63
+ const closeFailedPane = useCallback(() => {
64
+ closePane?.(paneId);
65
+ }, [closePane, paneId]);
55
66
 
56
67
  return (
57
68
  <PaneInstanceProvider paneId={paneId}>
@@ -67,16 +78,18 @@ export const PaneContent = memo(function PaneContent({
67
78
  overflow="hidden"
68
79
  data-gloom-role="pane-content"
69
80
  >
70
- <PaneRenderTrace paneId={paneId} paneType={paneType}>
71
- <Component
72
- paneId={paneId}
73
- paneType={paneType}
74
- focused={focused}
75
- width={width}
76
- height={height}
77
- close={onClose ? close : undefined}
78
- />
79
- </PaneRenderTrace>
81
+ <PaneErrorBoundary paneType={paneType} title={title} onClose={closePane ? closeFailedPane : undefined}>
82
+ <PaneRenderTrace paneId={paneId} paneType={paneType}>
83
+ <Component
84
+ paneId={paneId}
85
+ paneType={paneType}
86
+ focused={focused}
87
+ width={width}
88
+ height={height}
89
+ close={onClose ? close : undefined}
90
+ />
91
+ </PaneRenderTrace>
92
+ </PaneErrorBoundary>
80
93
  </Box>
81
94
  </PaneInViewProvider>
82
95
  </PaneInstanceProvider>
@@ -0,0 +1,103 @@
1
+ import { Component, type ErrorInfo, type ReactNode } from "react";
2
+ import { tf } from "../../../i18n";
3
+ import { getSharedRegistry } from "../../../plugins/registry/shared";
4
+ import { reportCrash } from "../../../telemetry/crash-reports";
5
+ import { debugLog } from "../../../utils/debug-log";
6
+ import { Button } from "../../ui/button";
7
+ import { PaneStatusBody } from "../../ui/status";
8
+
9
+ const MAX_MESSAGE_LENGTH = 200;
10
+
11
+ /** The first line of what was thrown, clipped: the card has one line for it. */
12
+ function failureMessage(error: unknown): string {
13
+ const raw = error instanceof Error
14
+ ? error.message || error.name
15
+ : typeof error === "string" ? error : String(error);
16
+ const line = raw.split("\n").find((part) => part.trim())?.trim() || "Unknown error";
17
+ return line.length > MAX_MESSAGE_LENGTH ? `${line.slice(0, MAX_MESSAGE_LENGTH - 3)}...` : line;
18
+ }
19
+
20
+ function failureKey(error: unknown): string {
21
+ return error instanceof Error ? `${error.name}\n${error.message}` : String(error);
22
+ }
23
+
24
+ interface PaneErrorBoundaryProps {
25
+ paneType: string;
26
+ title: string;
27
+ /** Takes the pane out of the layout; without it the card offers Reload only. */
28
+ onClose?: () => void;
29
+ children: ReactNode;
30
+ }
31
+
32
+ interface PaneErrorBoundaryState {
33
+ error: { value: unknown } | null;
34
+ }
35
+
36
+ /**
37
+ * Keeps a pane that throws while rendering inside its own frame: the pane body
38
+ * becomes a failure card with Reload and Close, and every other pane, the
39
+ * command bar and the layout keep working. The pane's header stays outside, so
40
+ * it can still be moved or closed from its menu.
41
+ *
42
+ * Only render errors reach it. Event handlers, effects and async work fail the
43
+ * way they always have.
44
+ */
45
+ export class PaneErrorBoundary extends Component<PaneErrorBoundaryProps, PaneErrorBoundaryState> {
46
+ override state: PaneErrorBoundaryState = { error: null };
47
+ private reportedKey: string | null = null;
48
+
49
+ static getDerivedStateFromError(error: unknown): PaneErrorBoundaryState {
50
+ return { error: { value: error } };
51
+ }
52
+
53
+ override componentDidCatch(error: unknown, errorInfo: ErrorInfo): void {
54
+ // A pane that fails again after Reload, or re-renders its card, is still
55
+ // the same failure: reported once.
56
+ const key = failureKey(error);
57
+ if (key === this.reportedKey) return;
58
+ this.reportedKey = key;
59
+ const { paneType } = this.props;
60
+ const plugin = getSharedRegistry()?.getPanePluginId(paneType);
61
+ reportCrash(error, { kind: "render", pane: paneType, plugin, componentStack: errorInfo.componentStack });
62
+ // Logged under the owning plugin, so the Plugins pane counts it as one of its errors.
63
+ debugLog.createLogger(plugin ?? "pane").error(`Pane ${paneType} stopped rendering: ${failureMessage(error)}`, {
64
+ componentStack: errorInfo.componentStack,
65
+ });
66
+ }
67
+
68
+ private readonly reload = () => {
69
+ this.setState({ error: null });
70
+ };
71
+
72
+ override render(): ReactNode {
73
+ const { error } = this.state;
74
+ if (!error) return this.props.children;
75
+ return (
76
+ <FallbackGuard>
77
+ <PaneStatusBody
78
+ error={failureMessage(error.value)}
79
+ errorTitle={tf("{title} stopped working.", { title: this.props.title })}
80
+ actions={(
81
+ <>
82
+ <Button label="Reload pane" variant="primary" compact onPress={this.reload} />
83
+ {this.props.onClose && <Button label="Close pane" variant="secondary" compact onPress={this.props.onClose} />}
84
+ </>
85
+ )}
86
+ />
87
+ </FallbackGuard>
88
+ );
89
+ }
90
+ }
91
+
92
+ /** A card that cannot render leaves the body empty rather than taking the app down with it. */
93
+ class FallbackGuard extends Component<{ children: ReactNode }, { failed: boolean }> {
94
+ override state = { failed: false };
95
+
96
+ static getDerivedStateFromError(): { failed: boolean } {
97
+ return { failed: true };
98
+ }
99
+
100
+ override render(): ReactNode {
101
+ return this.state.failed ? null : this.props.children;
102
+ }
103
+ }