gloomberb 0.16.1 → 0.16.3

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 (643) 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 +69 -0
  14. package/src/cli/command-options.ts +74 -0
  15. package/src/cli/commands/command-utils.ts +37 -0
  16. package/src/cli/commands/crypto-hints.ts +75 -0
  17. package/src/cli/commands/market.ts +560 -136
  18. package/src/cli/commands/overview.ts +136 -48
  19. package/src/cli/commands/ticker.ts +220 -67
  20. package/src/cli/desktop-pane-shot.ts +37 -4
  21. package/src/cli/freshness.ts +61 -0
  22. package/src/cli/help.ts +27 -6
  23. package/src/cli/helpers.ts +4 -8
  24. package/src/cli/history-rows.ts +187 -15
  25. package/src/cli/index.ts +23 -8
  26. package/src/cli/listing-arg.ts +321 -0
  27. package/src/cli/options.ts +5 -1
  28. package/src/cli/pane-functions/access-gate.ts +42 -0
  29. package/src/cli/pane-functions/capabilities.ts +5 -0
  30. package/src/cli/pane-functions/catalog.ts +28 -1
  31. package/src/cli/pane-functions/data.ts +3 -1
  32. package/src/cli/pane-functions/dom.ts +87 -16
  33. package/src/cli/pane-functions/freshness.ts +400 -0
  34. package/src/cli/pane-functions/function-help.ts +31 -22
  35. package/src/cli/pane-functions/headless.ts +201 -41
  36. package/src/cli/pane-functions/index.ts +24 -6
  37. package/src/cli/pane-functions/options.ts +3 -0
  38. package/src/cli/pane-functions/report.ts +12 -1
  39. package/src/cli/pane-functions/resolver.ts +63 -9
  40. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  41. package/src/cli/pane-functions/screenshot.ts +11 -3
  42. package/src/cli/registry.ts +6 -3
  43. package/src/cli/report-tables.ts +460 -0
  44. package/src/cli/result.ts +53 -29
  45. package/src/cli/ticker-resolution.ts +7 -5
  46. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  47. package/src/components/chart/composite/drawing-store.ts +59 -0
  48. package/src/components/chart/composite/legend.tsx +319 -0
  49. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  50. package/src/components/chart/composite/panel-gestures.ts +59 -0
  51. package/src/components/chart/composite/panel-labels.ts +107 -0
  52. package/src/components/chart/composite/panel-surface.tsx +876 -0
  53. package/src/components/chart/composite/tool-catalog.ts +98 -0
  54. package/src/components/chart/composite/toolbar.tsx +186 -0
  55. package/src/components/chart/composite/tools.ts +8 -0
  56. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  57. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  58. package/src/components/command-bar/list/model.ts +5 -0
  59. package/src/components/command-bar/list/view.tsx +16 -3
  60. package/src/components/command-bar/pane-templates/workflow.ts +1 -0
  61. package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
  62. package/src/components/command-bar/workflow/ops.ts +1 -1
  63. package/src/components/command-bar/workflow/tickers.ts +6 -0
  64. package/src/components/data-table/export.ts +6 -51
  65. package/src/components/data-table/view.tsx +32 -11
  66. package/src/components/feedback-dialog.tsx +2 -1
  67. package/src/components/form-modal/field-row.tsx +2 -2
  68. package/src/components/layout/detached-pane-shell.tsx +6 -3
  69. package/src/components/layout/pane/content.tsx +23 -10
  70. package/src/components/layout/pane/error-boundary.tsx +103 -0
  71. package/src/components/layout/pane/footer/registration.tsx +68 -23
  72. package/src/components/layout/pane/header.tsx +11 -11
  73. package/src/components/layout/shell/active-drag.ts +67 -35
  74. package/src/components/layout/shell/cursor-occlusion.ts +6 -5
  75. package/src/components/layout/shell/drag/index.ts +12 -7
  76. package/src/components/layout/shell/drag/live.ts +122 -0
  77. package/src/components/layout/shell/drag/overlays.tsx +179 -35
  78. package/src/components/layout/shell/drag/runtime.ts +62 -50
  79. package/src/components/layout/shell/drag/slide.ts +10 -0
  80. package/src/components/layout/shell/index.tsx +37 -51
  81. package/src/components/layout/shell/menu.ts +2 -1
  82. package/src/components/layout/shell/native/pointer-runtime.ts +13 -13
  83. package/src/components/layout/shell/native/surfaces.ts +30 -14
  84. package/src/components/layout/shell/pane/actions.ts +2 -1
  85. package/src/components/layout/shell/pane/layers.tsx +419 -168
  86. package/src/components/layout/shell/terminal-pointer-runtime.ts +18 -18
  87. package/src/components/layout/shell/window-mode/overlays.tsx +12 -4
  88. package/src/components/metric-treemap/heat-surface.tsx +43 -16
  89. package/src/components/metric-treemap/heat-tiles.ts +18 -0
  90. package/src/components/metric-treemap/layout.ts +2 -0
  91. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  92. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  93. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  94. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  95. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  96. package/src/components/ticker/list-table-view.tsx +13 -1
  97. package/src/components/ui/fields.tsx +8 -0
  98. package/src/components/ui/range-track.tsx +10 -3
  99. package/src/components/ui/status.tsx +8 -2
  100. package/src/components/ui/tabs.tsx +7 -4
  101. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  102. package/src/data/config/store/normalize.ts +17 -1
  103. package/src/data/json-persistence.ts +17 -3
  104. package/src/data/json-storage.ts +2 -0
  105. package/src/data/memory-resource-store.ts +46 -0
  106. package/src/i18n/es.ts +19 -1
  107. package/src/i18n/ja.ts +19 -1
  108. package/src/i18n/ko.ts +19 -1
  109. package/src/i18n/zh-cn.ts +19 -1
  110. package/src/i18n/zh-tw.ts +19 -1
  111. package/src/market-data/coordinator/chart.ts +1 -1
  112. package/src/market-data/coordinator/quotes.ts +23 -4
  113. package/src/market-data/fx-closes.ts +72 -0
  114. package/src/market-data/market/freshness.ts +123 -6
  115. package/src/market-data/market/session-close-note.ts +57 -0
  116. package/src/market-data/market/status.ts +151 -0
  117. package/src/market-data/published-apac-sessions.ts +66 -0
  118. package/src/market-data/quotes/contributions.ts +2 -0
  119. package/src/market-data/quotes/freshness.ts +5 -0
  120. package/src/market-data/quotes/resolution.ts +2 -0
  121. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  122. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  123. package/src/plugins/builtin/alerts/cli.ts +10 -5
  124. package/src/plugins/builtin/alerts/index.tsx +1 -0
  125. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  126. package/src/plugins/builtin/analytics/pane-model.ts +10 -6
  127. package/src/plugins/builtin/analytics/risk-client.ts +191 -66
  128. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  129. package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
  130. package/src/plugins/builtin/analytics/risk-model.ts +45 -17
  131. package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
  132. package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
  133. package/src/plugins/builtin/attention/headless.ts +6 -4
  134. package/src/plugins/builtin/attention/index.tsx +1 -1
  135. package/src/plugins/builtin/attention/pane.tsx +2 -2
  136. package/src/plugins/builtin/awards/headless.ts +1 -0
  137. package/src/plugins/builtin/awards/pane.tsx +1 -1
  138. package/src/plugins/builtin/backtest/headless.ts +1 -0
  139. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  140. package/src/plugins/builtin/buildout/index.tsx +1 -0
  141. package/src/plugins/builtin/catalysts/detail.tsx +1 -1
  142. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  143. package/src/plugins/builtin/cds/headless.ts +2 -0
  144. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  145. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  146. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  147. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  148. package/src/plugins/builtin/chat/channels.ts +19 -3
  149. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  150. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  151. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  152. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  153. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  154. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  155. package/src/plugins/builtin/chat/index.tsx +1 -0
  156. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  157. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  158. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  159. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  160. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  161. package/src/plugins/builtin/chat/message/types.ts +14 -2
  162. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  163. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  164. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  165. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  166. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  167. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  168. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  169. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  170. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  171. package/src/plugins/builtin/company-attention/pane.tsx +2 -2
  172. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  173. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  174. package/src/plugins/builtin/correlation/compute.ts +59 -16
  175. package/src/plugins/builtin/correlation/geo.ts +34 -0
  176. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  177. package/src/plugins/builtin/correlation/headless.ts +42 -8
  178. package/src/plugins/builtin/correlation/history.ts +2 -0
  179. package/src/plugins/builtin/correlation/index.tsx +68 -14
  180. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  181. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  182. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  183. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  184. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  185. package/src/plugins/builtin/correlation/settings.ts +1 -1
  186. package/src/plugins/builtin/cot/headless.ts +6 -3
  187. package/src/plugins/builtin/cot/index.tsx +3 -3
  188. package/src/plugins/builtin/cot/model.ts +36 -3
  189. package/src/plugins/builtin/cpi/headless.ts +4 -0
  190. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  191. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  192. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  193. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  194. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  195. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  196. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  197. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  198. package/src/plugins/builtin/doe/headless.ts +7 -0
  199. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  200. package/src/plugins/builtin/earnings/headless.ts +5 -0
  201. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  202. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  203. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  204. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  205. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  206. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  207. package/src/plugins/builtin/econ/index.tsx +1 -0
  208. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  209. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  210. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  211. package/src/plugins/builtin/executives/index.tsx +1 -0
  212. package/src/plugins/builtin/exposure/headless.ts +3 -1
  213. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  214. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  215. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  216. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  217. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  218. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  219. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  220. package/src/plugins/builtin/gpu/headless.ts +7 -3
  221. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  222. package/src/plugins/builtin/gpu/model.ts +27 -1
  223. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  224. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  225. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  226. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  227. package/src/plugins/builtin/holders/client.ts +3 -6
  228. package/src/plugins/builtin/holders/format.ts +31 -1
  229. package/src/plugins/builtin/holders/headless.ts +161 -6
  230. package/src/plugins/builtin/holders/index.tsx +10 -3
  231. package/src/plugins/builtin/holders/pane.tsx +42 -16
  232. package/src/plugins/builtin/holders/report-header.ts +136 -0
  233. package/src/plugins/builtin/holders/table-model.ts +20 -5
  234. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  235. package/src/plugins/builtin/holders/types.ts +2 -1
  236. package/src/plugins/builtin/insider/headless.ts +2 -0
  237. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  238. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  239. package/src/plugins/builtin/jobs/headless.ts +1 -0
  240. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  241. package/src/plugins/builtin/kelly-sizer/pane.tsx +12 -6
  242. package/src/plugins/builtin/kelly-sizer/portfolio.ts +25 -0
  243. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  244. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  245. package/src/plugins/builtin/market-heatmap/data.ts +2 -0
  246. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  247. package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
  248. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  249. package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
  250. package/src/plugins/builtin/market-movers/headless.ts +2 -0
  251. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  252. package/src/plugins/builtin/members/client.ts +20 -3
  253. package/src/plugins/builtin/members/headless.ts +5 -3
  254. package/src/plugins/builtin/members/model.ts +10 -2
  255. package/src/plugins/builtin/members/pane.tsx +23 -6
  256. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  257. package/src/plugins/builtin/mna/headless.ts +1 -0
  258. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  259. package/src/plugins/builtin/news/headless.ts +2 -0
  260. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  261. package/src/plugins/builtin/notes/cli.ts +14 -6
  262. package/src/plugins/builtin/notes/index.tsx +1 -0
  263. package/src/plugins/builtin/openfda/index.tsx +1 -0
  264. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  265. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  266. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  267. package/src/plugins/builtin/pe-band/client.ts +48 -3
  268. package/src/plugins/builtin/pe-band/headless.ts +25 -7
  269. package/src/plugins/builtin/pe-band/model.ts +92 -16
  270. package/src/plugins/builtin/pe-band/pane.tsx +33 -16
  271. package/src/plugins/builtin/perps/client.ts +50 -3
  272. package/src/plugins/builtin/perps/headless.ts +144 -16
  273. package/src/plugins/builtin/perps/index.tsx +6 -6
  274. package/src/plugins/builtin/perps/model.ts +189 -12
  275. package/src/plugins/builtin/perps/pane.tsx +249 -48
  276. package/src/plugins/builtin/portfolio-list/account-metrics.ts +16 -1
  277. package/src/plugins/builtin/portfolio-list/allocation.ts +248 -0
  278. package/src/plugins/builtin/portfolio-list/cached-account.ts +42 -0
  279. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  280. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  281. package/src/plugins/builtin/portfolio-list/cli/render.ts +232 -39
  282. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  283. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  284. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  285. package/src/plugins/builtin/portfolio-list/headless.ts +100 -16
  286. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  287. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  288. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  289. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  290. package/src/plugins/builtin/portfolio-list/pane/index.tsx +53 -16
  291. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  292. package/src/plugins/builtin/portfolio-list/summary/index.tsx +46 -5
  293. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +11 -1
  294. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  295. package/src/plugins/builtin/power/headless.ts +3 -1
  296. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  297. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  298. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  299. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  300. package/src/plugins/builtin/research/events-headless.ts +2 -0
  301. package/src/plugins/builtin/research/headless.ts +2 -0
  302. package/src/plugins/builtin/research/index.tsx +1 -0
  303. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  304. package/src/plugins/builtin/research/relative-valuation-model.ts +18 -6
  305. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  306. package/src/plugins/builtin/research-search/index.tsx +1 -0
  307. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  308. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  309. package/src/plugins/builtin/reverse-dcf/model.ts +2 -1
  310. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  311. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  312. package/src/plugins/builtin/scanner/headless.ts +14 -0
  313. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  314. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  315. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  316. package/src/plugins/builtin/sec/forms.ts +12 -0
  317. package/src/plugins/builtin/sec/headless.ts +2 -0
  318. package/src/plugins/builtin/sectors/client.ts +1 -0
  319. package/src/plugins/builtin/sectors/headless.ts +9 -1
  320. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  321. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  322. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  323. package/src/plugins/builtin/shared/members-menu.tsx +260 -0
  324. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  325. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  326. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  327. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  328. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  329. package/src/plugins/builtin/short-volume/pane.tsx +1 -1
  330. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  331. package/src/plugins/builtin/social-mentions/pane.tsx +1 -1
  332. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  333. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  334. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  335. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  336. package/src/plugins/builtin/themes/headless.ts +3 -0
  337. package/src/plugins/builtin/themes/pane.tsx +3 -0
  338. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  339. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  340. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +4 -0
  341. package/src/plugins/builtin/ticker-detail/financials/model.ts +25 -2
  342. package/src/plugins/builtin/ticker-detail/headless.ts +27 -5
  343. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  344. package/src/plugins/builtin/ticker-detail/overview/model.ts +17 -5
  345. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +27 -26
  346. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  347. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  348. package/src/plugins/builtin/volatility/headless.ts +6 -1
  349. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  350. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +159 -0
  351. package/src/plugins/builtin/world-venue-map/basemap.ts +232 -0
  352. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  353. package/src/plugins/builtin/world-venue-map/country-labels.ts +78 -0
  354. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  355. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  356. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  357. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  358. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  359. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  360. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +448 -0
  361. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  362. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  363. package/src/plugins/builtin/world-venue-map/index.ts +69 -6
  364. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +565 -0
  365. package/src/plugins/builtin/world-venue-map/layers.ts +406 -0
  366. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  367. package/src/plugins/builtin/world-venue-map/map.tsx +557 -85
  368. package/src/plugins/builtin/world-venue-map/model.ts +23 -4
  369. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +202 -0
  370. package/src/plugins/builtin/world-venue-map/natural-earth/labels.chunk.ts +244 -0
  371. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  372. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  373. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  374. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  375. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  376. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  377. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  378. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  379. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  380. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  381. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  382. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  383. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  384. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  385. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  386. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  387. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  388. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  389. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  390. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  391. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  392. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  393. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  394. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  395. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  396. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  397. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  398. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  399. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  400. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  401. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  402. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  403. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  404. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  405. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  406. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  407. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  408. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  409. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  410. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  411. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  412. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  413. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  414. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  415. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  416. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  417. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  418. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  524. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  525. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  526. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  527. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  528. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  529. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  530. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  531. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  532. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  533. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  534. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  535. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  536. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  537. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  538. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  539. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  540. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  541. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  542. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  543. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  544. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  545. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  546. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  547. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  548. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  549. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  550. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  551. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  552. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  553. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  554. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  555. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  556. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  557. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  558. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  559. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  560. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  561. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  562. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  563. package/src/plugins/builtin/world-venue-map/pane.tsx +35 -44
  564. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  565. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  566. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  567. package/src/plugins/loader.ts +13 -1
  568. package/src/plugins/registry/pane-settings.ts +1 -0
  569. package/src/renderers/browser/app-services.ts +3 -1
  570. package/src/renderers/dom/build-assets.ts +81 -3
  571. package/src/renderers/dom/data-table/dom.ts +31 -0
  572. package/src/renderers/dom/data-table/index.tsx +5 -0
  573. package/src/renderers/dom/data-table/row.tsx +2 -0
  574. package/src/renderers/dom/desktop/controls.tsx +7 -3
  575. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  576. package/src/renderers/dom/desktop/popover.tsx +73 -14
  577. package/src/renderers/dom/host/box.tsx +113 -17
  578. package/src/renderers/dom/host/drag-shield.ts +24 -0
  579. package/src/renderers/dom/host/input.tsx +14 -3
  580. package/src/renderers/dom/host/live-frame.ts +54 -0
  581. package/src/renderers/dom/host/mouse.ts +8 -1
  582. package/src/renderers/dom/host/scroll-box.tsx +6 -5
  583. package/src/renderers/dom/host/tabs.tsx +3 -2
  584. package/src/renderers/dom/styles.css +16 -9
  585. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +7 -0
  586. package/src/renderers/electrobun/bun/desktop/backend.ts +2 -0
  587. package/src/renderers/electrobun/bun/desktop/initialization.ts +13 -0
  588. package/src/renderers/electrobun/shared/protocol.ts +10 -1
  589. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  590. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +4 -0
  591. package/src/renderers/electrobun/view/host/native.ts +0 -10
  592. package/src/renderers/electrobun/view/host/window-move.ts +28 -0
  593. package/src/renderers/electrobun/view/remote/persistence.ts +15 -2
  594. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  595. package/src/renderers/electrobun/view/ui-host.tsx +2 -5
  596. package/src/renderers/opentui/host.tsx +5 -0
  597. package/src/renderers/opentui/ui-host.tsx +7 -1
  598. package/src/sources/gloomberb-cloud/index.ts +25 -4
  599. package/src/sources/gloomberb-cloud/normalizers.ts +43 -23
  600. package/src/sources/provider-router/batches.ts +3 -3
  601. package/src/sources/provider-router/cached-routes.ts +4 -1
  602. package/src/sources/provider-router/financial-routes.ts +2 -2
  603. package/src/sources/provider-router/financials.ts +76 -12
  604. package/src/sources/provider-router/history.ts +15 -10
  605. package/src/sources/provider-router/primary.ts +2 -2
  606. package/src/sources/sec-registrant.ts +75 -0
  607. package/src/state/app/context/index.tsx +24 -8
  608. package/src/state/hooks/quote-streaming.ts +41 -26
  609. package/src/state/pane-scroll-registry.tsx +67 -35
  610. package/src/sync/core-contributors.ts +4 -0
  611. package/src/telemetry/crash-reports.ts +4 -1
  612. package/src/test-support/cli-context.ts +10 -2
  613. package/src/test-support/margin-account.ts +108 -0
  614. package/src/theme/heat-colors.ts +266 -84
  615. package/src/time-series/resolution.ts +15 -0
  616. package/src/time-series/resolve.ts +1 -1
  617. package/src/time-series/use-chart-resolution.ts +1 -1
  618. package/src/types/context-menu.ts +6 -0
  619. package/src/types/data-provider.ts +2 -0
  620. package/src/types/financials.ts +35 -3
  621. package/src/types/headless.ts +79 -2
  622. package/src/types/plugin.ts +20 -1
  623. package/src/types/ticker.ts +15 -0
  624. package/src/ui/host.tsx +26 -0
  625. package/src/ui/index.tsx +8 -3
  626. package/src/ui/scroll-box-axis.ts +26 -0
  627. package/src/updater/index.ts +9 -11
  628. package/src/utils/async-deadline.ts +21 -0
  629. package/src/utils/cli-output.ts +5 -1
  630. package/src/utils/crypto-pair.ts +41 -0
  631. package/src/utils/currency-units.ts +19 -0
  632. package/src/utils/depositary-receipt.ts +70 -0
  633. package/src/utils/display-number.ts +63 -0
  634. package/src/utils/exchanges.ts +72 -0
  635. package/src/utils/fire-and-forget.ts +24 -0
  636. package/src/utils/format.ts +13 -0
  637. package/src/utils/fundamentals.ts +17 -1
  638. package/src/utils/price-earnings.ts +70 -3
  639. package/src/utils/price-history-integrity.ts +19 -6
  640. package/src/utils/price-history.ts +58 -13
  641. package/src/utils/rpc-timeout-error.ts +27 -0
  642. package/src/utils/sec.ts +13 -1
  643. package/src/utils/utc-time.ts +79 -0
@@ -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}`;
@@ -5,9 +5,12 @@ import { useAppSelector, useOptionalPaneInstanceId } from "./app/context";
5
5
 
6
6
  type ScrollDirection = "up" | "down";
7
7
 
8
+ /** A scroll position: rows (or cells), or device pixels where the host measures in them. */
9
+ type ScrollTarget = { cells: number } | { pixels: number };
10
+
8
11
  interface PaneScrollAction {
9
12
  direction: ScrollDirection;
10
- resolveTarget(scrollBox: ScrollBoxRenderable): number | null;
13
+ resolveTarget(scrollBox: ScrollBoxRenderable): ScrollTarget | null;
11
14
  }
12
15
 
13
16
  interface PaneScrollEntry {
@@ -57,17 +60,58 @@ function isVisibleScrollBox(scrollBox: ScrollBoxRenderable): boolean {
57
60
  return !hasHiddenAncestor(scrollBox) && !hasCollapsedBounds(scrollBox);
58
61
  }
59
62
 
60
- function clampScrollTop(scrollBox: ScrollBoxRenderable, target: number): number | null {
63
+ function maxScrollTop(scrollBox: ScrollBoxRenderable): number {
61
64
  const viewportHeight = Math.max(0, scrollBox.viewport?.height ?? 0);
62
- if (viewportHeight <= 0) return null;
63
- const maxScrollTop = Math.max(0, scrollBox.scrollHeight - viewportHeight);
64
- if (maxScrollTop <= 0) return null;
65
- return Math.max(0, Math.min(maxScrollTop, target));
65
+ if (viewportHeight <= 0) return 0;
66
+ return Math.max(0, scrollBox.scrollHeight - viewportHeight);
67
+ }
68
+
69
+ /**
70
+ * The desktop host rounds its viewport and content to whole rows, which can
71
+ * leave up to half a row of content past the last scrollable row. Where it
72
+ * also reports pixels, the ends are measured in them.
73
+ */
74
+ function pixelRange(scrollBox: ScrollBoxRenderable): { top: number; max: number } | null {
75
+ const { scrollTopPx, scrollHeightPx, viewportPx } = scrollBox;
76
+ if (!scrollBox.scrollToPixels || typeof scrollTopPx !== "number" || typeof scrollHeightPx !== "number" || !viewportPx) {
77
+ return null;
78
+ }
79
+ return { top: scrollTopPx, max: Math.max(0, scrollHeightPx - viewportPx.height) };
66
80
  }
67
81
 
68
- function scrollTargetByDelta(scrollBox: ScrollBoxRenderable, delta: number): number | null {
69
- const target = clampScrollTop(scrollBox, scrollBox.scrollTop + delta);
70
- return target == null || target === scrollBox.scrollTop ? null : target;
82
+ function topTarget(scrollBox: ScrollBoxRenderable): ScrollTarget | null {
83
+ if ((scrollBox.viewport?.height ?? 0) <= 0) return null;
84
+ const pixels = pixelRange(scrollBox);
85
+ if (pixels) return pixels.top >= 1 ? { pixels: 0 } : null;
86
+ return scrollBox.scrollTop > 0 ? { cells: 0 } : null;
87
+ }
88
+
89
+ function bottomTarget(scrollBox: ScrollBoxRenderable): ScrollTarget | null {
90
+ const max = maxScrollTop(scrollBox);
91
+ // A body that overflows by less than a row is not worth capturing the keys for.
92
+ if (max <= 0) return null;
93
+ const pixels = pixelRange(scrollBox);
94
+ if (pixels) return pixels.max - pixels.top >= 1 ? { pixels: pixels.max } : null;
95
+ return max !== scrollBox.scrollTop ? { cells: max } : null;
96
+ }
97
+
98
+ function scrollTargetByDelta(scrollBox: ScrollBoxRenderable, delta: number): ScrollTarget | null {
99
+ if ((scrollBox.viewport?.height ?? 0) <= 0) return null;
100
+ const wanted = scrollBox.scrollTop + delta;
101
+ if (delta < 0 && wanted <= 0) return topTarget(scrollBox);
102
+ if (delta > 0 && wanted >= maxScrollTop(scrollBox)) return bottomTarget(scrollBox);
103
+ return delta === 0 ? null : { cells: wanted };
104
+ }
105
+
106
+ function applyScrollTarget(scrollBox: ScrollBoxRenderable, target: ScrollTarget): void {
107
+ if ("pixels" in target) {
108
+ scrollBox.scrollToPixels?.(target.pixels);
109
+ return;
110
+ }
111
+ scrollBox.scrollTo(target.cells);
112
+ if (scrollBox.scrollTop !== target.cells) {
113
+ scrollBox.scrollTop = target.cells;
114
+ }
71
115
  }
72
116
 
73
117
  /**
@@ -76,7 +120,7 @@ function scrollTargetByDelta(scrollBox: ScrollBoxRenderable, delta: number): num
76
120
  */
77
121
  export function scrollByLines(scrollBox: ScrollBoxRenderable, delta: number): void {
78
122
  const target = scrollTargetByDelta(scrollBox, delta);
79
- if (target != null) scrollBox.scrollTop = target;
123
+ if (target) applyScrollTarget(scrollBox, target);
80
124
  }
81
125
 
82
126
  function arrowScrollLines(scrollBox: ScrollBoxRenderable): number {
@@ -117,20 +161,9 @@ function resolveKeyScrollAction(event: PaneScrollKeyEvent): PaneScrollAction | n
117
161
  ),
118
162
  };
119
163
  case "home":
120
- return {
121
- direction: "up",
122
- resolveTarget: (scrollBox) => (
123
- scrollBox.scrollTop > 0 ? 0 : null
124
- ),
125
- };
164
+ return { direction: "up", resolveTarget: topTarget };
126
165
  case "end":
127
- return {
128
- direction: "down",
129
- resolveTarget: (scrollBox) => {
130
- const target = clampScrollTop(scrollBox, Number.MAX_SAFE_INTEGER);
131
- return target == null || target === scrollBox.scrollTop ? null : target;
132
- },
133
- };
166
+ return { direction: "down", resolveTarget: bottomTarget };
134
167
  default:
135
168
  return null;
136
169
  }
@@ -145,12 +178,12 @@ function getEntryScore(entry: PaneScrollEntry, scrollBox: ScrollBoxRenderable):
145
178
  function findScrollableEntry(paneId: string, action: PaneScrollAction): {
146
179
  entry: PaneScrollEntry;
147
180
  scrollBox: ScrollBoxRenderable;
148
- target: number;
181
+ target: ScrollTarget;
149
182
  } | null {
150
183
  const entries = paneScrollBoxes.get(paneId);
151
184
  if (!entries) return null;
152
185
 
153
- let best: { entry: PaneScrollEntry; scrollBox: ScrollBoxRenderable; target: number; score: number } | null = null;
186
+ let best: { entry: PaneScrollEntry; scrollBox: ScrollBoxRenderable; target: ScrollTarget; score: number } | null = null;
154
187
  for (const entry of entries.values()) {
155
188
  const scrollBox = entry.ref.current;
156
189
  if (!scrollBox) continue;
@@ -176,17 +209,16 @@ function scrollPaneByKey(paneId: string, event: PaneScrollKeyEvent): boolean {
176
209
  const match = findScrollableEntry(paneId, action);
177
210
  if (!match) return false;
178
211
 
179
- const previousTop = match.scrollBox.scrollTop;
180
- match.scrollBox.scrollTo(match.target);
181
- if (match.scrollBox.scrollTop !== match.target) {
182
- match.scrollBox.scrollTop = match.target;
183
- }
212
+ const { scrollBox } = match;
213
+ const position = () => scrollBox.scrollTopPx ?? scrollBox.scrollTop;
214
+ const previousTop = scrollBox.scrollTop;
215
+ const previousPosition = position();
216
+ applyScrollTarget(scrollBox, match.target);
184
217
 
185
- const delta = Math.abs(match.scrollBox.scrollTop - previousTop);
186
- if (delta > 0) {
187
- match.entry.onScrollActivity?.({ scroll: { direction: action.direction, delta } });
188
- }
189
- return delta > 0;
218
+ if (position() === previousPosition) return false;
219
+ const delta = Math.max(1, Math.abs(scrollBox.scrollTop - previousTop));
220
+ match.entry.onScrollActivity?.({ scroll: { direction: action.direction, delta } });
221
+ return true;
190
222
  }
191
223
 
192
224
  export function useForwardedScrollBoxRef<T>(
@@ -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;
@@ -0,0 +1,108 @@
1
+ import type { Quote, TickerFinancials } from "../types/financials";
2
+ import type { Portfolio, TickerRecord } from "../types/ticker";
3
+ import type { BrokerAccount } from "../types/trading";
4
+ import { createTestTicker } from "./ticker";
5
+
6
+ /**
7
+ * An invented margin account: 1.0M of equity carrying 1.6M of positions, the
8
+ * difference borrowed in three currencies. It holds a US stock, a listing
9
+ * quoted in euros and an option, which no quote prices, so it stays at its
10
+ * broker mark. Every figure is made up.
11
+ */
12
+ export const MARGIN_PORTFOLIO: Portfolio = {
13
+ id: "broker:margin-test:M1",
14
+ name: "Margin test",
15
+ currency: "USD",
16
+ brokerId: "test",
17
+ brokerInstanceId: "margin-test",
18
+ brokerAccountId: "M1",
19
+ };
20
+
21
+ /** Dollars per unit of each currency. */
22
+ export const MARGIN_EXCHANGE_RATES = new Map([["USD", 1], ["EUR", 1.2], ["JPY", 0.008]]);
23
+
24
+ const OPTION = "CCC 280121C00050000";
25
+
26
+ function holding(symbol: string, details: {
27
+ exchange: string;
28
+ currency: string;
29
+ shares: number;
30
+ mark: number;
31
+ multiplier?: number;
32
+ assetCategory?: string;
33
+ }): TickerRecord {
34
+ return createTestTicker(symbol, symbol, {
35
+ exchange: details.exchange,
36
+ currency: details.currency,
37
+ assetCategory: details.assetCategory,
38
+ portfolios: [MARGIN_PORTFOLIO.id],
39
+ positions: [{
40
+ portfolio: MARGIN_PORTFOLIO.id,
41
+ shares: details.shares,
42
+ avgCost: details.mark,
43
+ markPrice: details.mark,
44
+ marketValue: details.shares * details.mark * (details.multiplier ?? 1),
45
+ unrealizedPnl: 0,
46
+ multiplier: details.multiplier,
47
+ currency: details.currency,
48
+ side: "long",
49
+ broker: "test",
50
+ brokerInstanceId: "margin-test",
51
+ brokerAccountId: "M1",
52
+ }],
53
+ });
54
+ }
55
+
56
+ export const MARGIN_TICKERS: TickerRecord[] = [
57
+ holding("AAA", { exchange: "NASDAQ", currency: "USD", shares: 4_000, mark: 200 }),
58
+ holding("BBB", { exchange: "XETRA", currency: "EUR", shares: 5_000, mark: 100 }),
59
+ holding(OPTION, { exchange: "", currency: "USD", shares: 20, mark: 100, multiplier: 100, assetCategory: "OPT" }),
60
+ ];
61
+
62
+ export function createMarginAccount(overrides: Partial<BrokerAccount> = {}): BrokerAccount {
63
+ return {
64
+ accountId: "M1",
65
+ name: "Margin test",
66
+ currency: "USD",
67
+ source: "cloud",
68
+ updatedAt: Date.now() - 60_000,
69
+ netLiquidation: 1_000_000,
70
+ grossPositionValue: 1_600_000,
71
+ totalCashValue: -600_000,
72
+ cashBalances: [
73
+ { currency: "EUR", quantity: -250_000, baseValue: -300_000, baseCurrency: "USD" },
74
+ { currency: "JPY", quantity: -25_000_000, baseValue: -200_000, baseCurrency: "USD" },
75
+ { currency: "USD", quantity: -100_000, baseValue: -100_000, baseCurrency: "USD" },
76
+ ],
77
+ ...overrides,
78
+ };
79
+ }
80
+
81
+ function liveQuote(symbol: string, price: number, previousClose: number, currency: string, exchange: string): TickerFinancials {
82
+ const quote: Quote = {
83
+ symbol,
84
+ price,
85
+ change: price - previousClose,
86
+ changePercent: (price / previousClose - 1) * 100,
87
+ previousClose,
88
+ currency,
89
+ lastUpdated: Date.now() - 1_000,
90
+ listingExchangeName: exchange,
91
+ marketState: "REGULAR",
92
+ dataSource: "live",
93
+ };
94
+ return { annualStatements: [], quarterlyStatements: [], priceHistory: [], quote };
95
+ }
96
+
97
+ /**
98
+ * Real-time quotes for the stock and the euro listing, the stock `move`
99
+ * dollars above its mark. With `option`, the option is quoted at its mark too,
100
+ * so every position has a live price.
101
+ */
102
+ export function marginQuotes({ move = 0, option = false }: { move?: number; option?: boolean } = {}): Map<string, TickerFinancials> {
103
+ return new Map([
104
+ ["AAA", liveQuote("AAA", 200 + move, 200, "USD", "NASDAQ")],
105
+ ["BBB", liveQuote("BBB", 100, 100, "EUR", "XETRA")],
106
+ ...(option ? [[OPTION, liveQuote(OPTION, 100, 100, "USD", "CBOE")] as const] : []),
107
+ ]);
108
+ }