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
@@ -14,16 +14,6 @@ const contextMenuActionScope = new DesktopContextMenuActionScope(
14
14
  CONTEXT_MENU_ACTION_TTL_MS,
15
15
  );
16
16
 
17
- export function startElectrobunWindowDrag(): void {
18
- window.__electrobunInternalBridge?.postMessage(JSON.stringify([
19
- JSON.stringify({
20
- type: "message",
21
- id: "startWindowMove",
22
- payload: { id: window.__electrobunWindowId },
23
- }),
24
- ]));
25
- }
26
-
27
17
  export async function showDesktopContextMenu(items: ContextMenuItem[]): Promise<boolean> {
28
18
  if (!NATIVE_CONTEXT_MENU_SUPPORTED) return false;
29
19
  contextMenuActionScope.clear();
@@ -0,0 +1,28 @@
1
+ function postWindowMove(id: "startWindowMove" | "stopWindowMove"): void {
2
+ window.__electrobunInternalBridge?.postMessage(JSON.stringify([
3
+ JSON.stringify({ type: "message", id, payload: { id: window.__electrobunWindowId } }),
4
+ ]));
5
+ }
6
+
7
+ let endWindowMove: (() => void) | null = null;
8
+
9
+ /**
10
+ * Moves the window with the pointer until the button comes up. Electrobun
11
+ * stops the move when its native monitor sees the release, but only if the
12
+ * start reached it first: the start goes through the Bun process, and a quick
13
+ * click releases before it lands, leaving the window following the bare
14
+ * pointer until the next click. The release is sent from here too, as
15
+ * Electrobun's own drag regions do; it always arrives after the start.
16
+ */
17
+ export function startElectrobunWindowDrag(): void {
18
+ // A press whose release never reached the page (it ended outside the window) is over.
19
+ endWindowMove?.();
20
+ postWindowMove("startWindowMove");
21
+ const end = () => {
22
+ window.removeEventListener("mouseup", end, true);
23
+ if (endWindowMove === end) endWindowMove = null;
24
+ postWindowMove("stopWindowMove");
25
+ };
26
+ endWindowMove = end;
27
+ window.addEventListener("mouseup", end, true);
28
+ }
@@ -4,7 +4,8 @@ import {
4
4
  SESSION_SAVE_DEBOUNCE_MS,
5
5
  } from "../../../../state/persist-scheduler";
6
6
  import { backendRequest, getElectrobunBackendInitSnapshot } from "../backend-rpc";
7
- import { MemoryResourceStore } from "../../../../data/memory-resource-store";
7
+ import { WriteThroughResourceStore } from "../../../../data/memory-resource-store";
8
+ import { isBrokerAccountSnapshotKey } from "../../../../brokers/account-cache";
8
9
 
9
10
  class RemoteSessionStore {
10
11
  private snapshot = getElectrobunBackendInitSnapshot()?.sessionSnapshot ?? null;
@@ -123,9 +124,21 @@ class RemotePluginStateStore {
123
124
  }
124
125
  }
125
126
 
127
+ /**
128
+ * Caches stay in the view's memory, except broker account snapshots: the Bun
129
+ * process saves those in the cache database, as the terminal does, so a
130
+ * broker portfolio opens with its last known equity and cash.
131
+ */
132
+ function createViewResourceStore(): WriteThroughResourceStore {
133
+ return new WriteThroughResourceStore(getElectrobunBackendInitSnapshot()?.savedResources ?? [], {
134
+ set: (record) => void backendRequest("resources.set", { record }).catch(() => {}),
135
+ delete: (key) => void backendRequest("resources.delete", { key }).catch(() => {}),
136
+ }, isBrokerAccountSnapshotKey);
137
+ }
138
+
126
139
  export class RemotePersistence {
127
140
  readonly tickers = {};
128
- readonly resources = new MemoryResourceStore();
141
+ readonly resources = createViewResourceStore();
129
142
  readonly pluginState = new RemotePluginStateStore(getElectrobunBackendInitSnapshot()?.pluginState ?? {});
130
143
  readonly sessions = new RemoteSessionStore();
131
144
 
@@ -1,6 +1,10 @@
1
1
  import { getCloudApiBaseUrl } from "../../../api-client/request";
2
+ import { RpcTimeoutError } from "../../../utils/rpc-timeout-error";
2
3
  import type { DesktopBackendRequestMethod } from "../shared/protocol";
3
4
 
5
+ /** How long the view waits for the Bun process to answer one request. */
6
+ export const RPC_MAX_REQUEST_TIME_MS = 120_000;
7
+
4
8
  /** What Electrobun's request timer rejects with: no method, request id or caller. */
5
9
  const ELECTROBUN_REQUEST_TIMEOUT_MESSAGE = "RPC request timed out.";
6
10
 
@@ -16,7 +20,9 @@ const ELECTROBUN_REQUEST_TIMEOUT_MESSAGE = "RPC request timed out.";
16
20
  * from the user's config (a broker gateway, a feed, a plugin endpoint) and is
17
21
  * only called external. Never the payload, rest of the path, query or headers.
18
22
  * Elapsed time is rounded to 10 s because crash reports are deduplicated per
19
- * session on the message.
23
+ * session on the message. The error keeps its message and `Error` type, and
24
+ * carries the elapsed time so a timer that fired long after its limit (the
25
+ * machine slept) can be told from a request that really stalled.
20
26
  */
21
27
  export async function nameRpcTimeout<T>(
22
28
  method: DesktopBackendRequestMethod,
@@ -28,8 +34,13 @@ export async function nameRpcTimeout<T>(
28
34
  return await request();
29
35
  } catch (error) {
30
36
  if (!(error instanceof Error) || error.message !== ELECTROBUN_REQUEST_TIMEOUT_MESSAGE) throw error;
31
- const seconds = Math.round((performance.now() - startedAt) / 10_000) * 10;
32
- throw new Error(`RPC request timed out: ${describeRequest(method, payload)} after ~${seconds}s`, { cause: error });
37
+ const elapsedMs = performance.now() - startedAt;
38
+ const seconds = Math.round(elapsedMs / 10_000) * 10;
39
+ throw new RpcTimeoutError(`RPC request timed out: ${describeRequest(method, payload)} after ~${seconds}s`, {
40
+ elapsedMs,
41
+ limitMs: RPC_MAX_REQUEST_TIME_MS,
42
+ cause: error,
43
+ });
33
44
  }
34
45
  }
35
46
 
@@ -2,11 +2,8 @@
2
2
  import type { RendererHost, UiHost } from "../../../ui/host";
3
3
  import { flushUsageCounts } from "../../../telemetry/usage-counts";
4
4
  import { backendRequest } from "./backend-rpc";
5
- import {
6
- NATIVE_CONTEXT_MENU_SUPPORTED,
7
- showDesktopContextMenu,
8
- startElectrobunWindowDrag,
9
- } from "./host/native";
5
+ import { NATIVE_CONTEXT_MENU_SUPPORTED, showDesktopContextMenu } from "./host/native";
6
+ import { startElectrobunWindowDrag } from "./host/window-move";
10
7
  import { createDomUiHost } from "../../dom/dom-ui-host";
11
8
 
12
9
  export function createWebUiHost(desktopPlatform?: string): UiHost {
@@ -108,6 +108,11 @@ export async function createOpenTuiHost(): Promise<OpenTuiHost> {
108
108
  enableMouseMovement: true,
109
109
  });
110
110
  const root = createRoot(renderer);
111
+ // Every mounted ScrollBox listens for `selection` and many components for
112
+ // `resize`, so the counts grow with the panes on screen (14 and 18 with one
113
+ // DES open at 80x24) and fall back when they close. Node's default warning
114
+ // at 11 is not a leak here, and it prints over the panes.
115
+ renderer.setMaxListeners(0);
111
116
  installResolutionEventBridge(renderer);
112
117
  // Streamed quotes apply and notify on one clock of up to 10 Hz: every
113
118
  // visible row stays live while a burst of ticks costs one terminal redraw,
@@ -2,6 +2,7 @@ import { RGBA, StyledText as OpenTuiStyledText, SyntaxStyle, TextAttributes as O
2
2
  import { createElement, forwardRef, useEffect, useRef, useState, type ReactNode } from "react";
3
3
  import { TextAttributes, type UiHost, type TextProps } from "../../ui/host";
4
4
  import { renderAsciiText } from "../../ui/ascii-font";
5
+ import { scrollBoxScrollsVertically } from "../../ui/scroll-box-axis";
5
6
  import { OpenTuiImageSurface } from "./image/surface";
6
7
  import { OpenTuiChartSurface } from "./chart-surface";
7
8
 
@@ -141,7 +142,12 @@ function mapTextContent(content: unknown): unknown {
141
142
  }
142
143
 
143
144
  const OpenTuiBox = createOpenTuiPrimitive("box");
144
- const OpenTuiScrollBox = createOpenTuiPrimitive("scrollbox");
145
+ const OpenTuiScrollBoxPrimitive = createOpenTuiPrimitive("scrollbox");
146
+ // The native box scrolls vertically unless scrollY is false; the shared rule
147
+ // also keeps the one-row horizontal strips from scrolling on that axis.
148
+ const OpenTuiScrollBox = forwardRef<unknown, OpenTuiPrimitiveProps>(function OpenTuiScrollBox(props, ref) {
149
+ return createElement(OpenTuiScrollBoxPrimitive, { ...props, scrollY: scrollBoxScrollsVertically(props), ref });
150
+ });
145
151
  const OpenTuiInput = createOpenTuiPrimitive("input");
146
152
  const OpenTuiTextarea = createOpenTuiPrimitive("textarea");
147
153
  const OpenTuiMediaSurface = createOpenTuiPrimitive("box");
@@ -40,6 +40,8 @@ import { resolveCurrencyUnit } from "../../utils/currency-units";
40
40
  import { canonicalExchange, canonicalTickerKey, parsePublicTickerKey } from "../../utils/exchanges";
41
41
  import { normalizePriceHistory, priceHistoryIntervalMs, reachesLatestSettledSession } from "../../utils/price-history";
42
42
  import { createProviderMiss } from "../provider-errors";
43
+ import { assertSecRegistrantMatches } from "../sec-registrant";
44
+ import { nonUsSecListingVenue } from "../../utils/sec";
43
45
  import { publicListingTarget } from "../listing-target";
44
46
  import { canonicalHistoryInterval, HistoryRetentionError, parseHistoryRecoveryCandidate, parseHistoryRetention, type HistoryRetention } from "../history-retention";
45
47
  import { getRouterEntityKey } from "../provider-router/cache";
@@ -195,7 +197,7 @@ function mapCloudPriceHistory(
195
197
  `Cloud chart data is unavailable for ${ticker}`,
196
198
  ).map((point) => mapPricePoint(point, divisor, exchange)),
197
199
  );
198
- if (stale && !reachesLatestSettledSession(points, Date.now(), { exchange, intervalMs: priceHistoryIntervalMs(interval) })) {
200
+ if (stale && !reachesLatestSettledSession(points, Date.now(), { symbol: ticker, exchange, intervalMs: priceHistoryIntervalMs(interval) })) {
199
201
  throw createProviderMiss(`Cloud chart data is stale for ${ticker}`);
200
202
  }
201
203
  if (
@@ -486,11 +488,30 @@ export class GloomberbCloudProvider implements AssetDataProvider {
486
488
  );
487
489
  }
488
490
 
489
- async getSecFilings(ticker: string, count = 15): Promise<SecFilingItem[]> {
490
- return withCloudFallback(async () => {
491
- const response = await apiClient.getCloudSecFilings({ ticker, limit: count, offset: 0 });
491
+ async getSecFilings(ticker: string, count = 15, exchange?: string, context?: MarketDataRequestContext): Promise<SecFilingItem[]> {
492
+ const venue = nonUsSecListingVenue(ticker, exchange);
493
+ const name = venue ? context?.listingName?.trim() || await this.listingName(ticker, venue) || undefined : undefined;
494
+ const filings = await withCloudFallback(async () => {
495
+ const response = await apiClient.getCloudSecFilings({ ticker, exchange, name, limit: count, offset: 0 });
492
496
  return response.filings.map(mapCloudSecFiling);
493
497
  }, `Cloud SEC filings are unavailable for ${ticker}`);
498
+ if (!venue || filings.length === 0) return filings;
499
+ const symbol = parsePublicTickerKey(ticker).symbol;
500
+ // Without the listing's company the filings cannot be told apart from another company's.
501
+ if (!name) throw createProviderMiss(`SEC filings for ${symbol} could not be matched to its ${venue} listing`);
502
+ assertSecRegistrantMatches(filings, { symbol, exchange: venue, name });
503
+ return filings;
504
+ }
505
+
506
+ /** The company a listing belongs to, from its own quote; null when the quote prices another venue. */
507
+ private async listingName(ticker: string, venue: string): Promise<string | null> {
508
+ try {
509
+ const quote = await this.getQuote(ticker, venue);
510
+ const quoteVenue = canonicalExchange(quote.listingExchangeName || quote.exchangeName);
511
+ return quoteVenue === venue ? quote.name?.trim() || null : null;
512
+ } catch {
513
+ return null;
514
+ }
494
515
  }
495
516
 
496
517
  async getSecFilingDocuments(filing: SecFilingItem): Promise<SecFilingDocument[]> {
@@ -1,5 +1,6 @@
1
1
  import { futuresGenericListing, futuresGenericPriceBasis } from "../../utils/futures-generic";
2
2
  import type { TimeRange } from "../../time-series/range";
3
+ import { RANGE_HISTORY_RESOLUTION } from "../../time-series/resolution";
3
4
  import type {
4
5
  FinancialStatement,
5
6
  Fundamentals,
@@ -36,6 +37,24 @@ function cloudInternalProviderId(providerMeta?: CloudProviderMeta): string | nul
36
37
  return upstream ? `${GLOOMBERB_CLOUD_PROVIDER_ID}:${upstream}` : null;
37
38
  }
38
39
 
40
+ /**
41
+ * A previous close is a price from inside the trailing 52 weeks, so it cannot
42
+ * sit far below the 52-week low. The service has sent 0.000205 as the
43
+ * Shanghai Composite's close (52-week low 3,741), which drew a +1.86e9% move.
44
+ * Today's price plays no part, so a real gap of any size still shows; two
45
+ * orders of magnitude leave room for a 52-week low that lags a crash or a split.
46
+ */
47
+ const IMPOSSIBLE_CLOSE_FACTOR = 100;
48
+
49
+ function isImpossiblePreviousClose(
50
+ previousClose: number | null | undefined,
51
+ low52w: number | null | undefined,
52
+ ): boolean {
53
+ return typeof previousClose === "number" && Number.isFinite(previousClose) && previousClose > 0
54
+ && typeof low52w === "number" && Number.isFinite(low52w) && low52w > 0
55
+ && previousClose * IMPOSSIBLE_CLOSE_FACTOR < low52w;
56
+ }
57
+
39
58
  export function mapQuote(
40
59
  quote: CloudQuotePayload,
41
60
  providerMeta?: CloudProviderMeta,
@@ -50,10 +69,11 @@ export function mapQuote(
50
69
  quote.fullExchangeName ??
51
70
  listingExchangeName;
52
71
  const internalProviderId = cloudInternalProviderId(providerMeta);
53
- const change = typeof quote.change === "number" && Number.isFinite(quote.change)
72
+ const impossibleClose = isImpossiblePreviousClose(quote.previousClose, quote.low52w);
73
+ const change = !impossibleClose && typeof quote.change === "number" && Number.isFinite(quote.change)
54
74
  ? quote.change / divisor
55
75
  : Number.NaN;
56
- const changePercent = typeof quote.changePercent === "number" && Number.isFinite(quote.changePercent)
76
+ const changePercent = !impossibleClose && typeof quote.changePercent === "number" && Number.isFinite(quote.changePercent)
57
77
  ? quote.changePercent
58
78
  : Number.NaN;
59
79
  // A generic future (VX1, TY1) reads in points or 32nds, not dollars.
@@ -70,8 +90,13 @@ export function mapQuote(
70
90
  price: normalizePriceValueByDivisor(quote.price, divisor) ?? quote.price,
71
91
  change,
72
92
  changePercent,
73
- previousClose: normalizePriceValueByDivisor(quote.previousClose, divisor),
93
+ previousClose: impossibleClose ? undefined : normalizePriceValueByDivisor(quote.previousClose, divisor),
74
94
  regularClose: normalizePriceValueByDivisor(quote.regularClose, divisor),
95
+ // JSON carries an unavailable move as null; the percent is unitless.
96
+ regularChange: normalizePriceValueByDivisor(quote.regularChange ?? undefined, divisor),
97
+ regularChangePercent: typeof quote.regularChangePercent === "number" && Number.isFinite(quote.regularChangePercent)
98
+ ? quote.regularChangePercent
99
+ : undefined,
75
100
  high52w: normalizePriceValueByDivisor(quote.high52w, divisor),
76
101
  low52w: normalizePriceValueByDivisor(quote.low52w, divisor),
77
102
  bid: normalizePriceValueByDivisor(quote.bid, divisor),
@@ -346,29 +371,24 @@ export function formatCloudDateTime(
346
371
  return `${year}-${month}-${day}`;
347
372
  }
348
373
 
374
+ const HISTORY_OUTPUT_SIZE: Record<TimeRange, number> = {
375
+ "1D": 24 * 12,
376
+ "1W": 7 * 24,
377
+ "1M": 31,
378
+ "3M": 93,
379
+ "6M": 186,
380
+ "1Y": 366,
381
+ "5Y": 261,
382
+ "ALL": 600,
383
+ };
384
+
385
+ /** The bar size comes from the shared range table, which `gloomberb help history` also lists. */
349
386
  export function toHistoryRequest(range: TimeRange): {
350
387
  interval: string;
351
388
  outputsize: number;
352
389
  rangeKey: TimeRange;
353
390
  } {
354
- switch (range) {
355
- case "1D":
356
- return { interval: "5min", outputsize: 24 * 12, rangeKey: range };
357
- case "1W":
358
- return { interval: "1h", outputsize: 7 * 24, rangeKey: range };
359
- case "1M":
360
- return { interval: "1day", outputsize: 31, rangeKey: range };
361
- case "3M":
362
- return { interval: "1day", outputsize: 93, rangeKey: range };
363
- case "6M":
364
- return { interval: "1day", outputsize: 186, rangeKey: range };
365
- case "1Y":
366
- return { interval: "1day", outputsize: 366, rangeKey: range };
367
- case "5Y":
368
- return { interval: "1week", outputsize: 261, rangeKey: range };
369
- case "ALL":
370
- return { interval: "1month", outputsize: 600, rangeKey: range };
371
- default:
372
- return { interval: "1day", outputsize: 366, rangeKey: range };
373
- }
391
+ const resolution = RANGE_HISTORY_RESOLUTION[range];
392
+ if (!resolution) return { interval: "1day", outputsize: 366, rangeKey: range };
393
+ return { interval: toCloudInterval(resolution), outputsize: HISTORY_OUTPUT_SIZE[range], rangeKey: range };
374
394
  }
@@ -66,7 +66,7 @@ export class ProviderRouterBatchRoutes {
66
66
  const rawCached = selectCachedResource<Quote>(this.deps.resources, "quote", entityKey, variantKeys, sourceKeys, false);
67
67
  const cached = rawCached && (brokerSourceKeys.includes(rawCached.sourceKey)
68
68
  ? !isQuoteStaleForCurrentSession(quoteWithFreshnessExchange(rawCached.value, target.exchange))
69
- : isProviderQuoteUsableForCurrentSession(rawCached.value, target.exchange, target.symbol))
69
+ : isProviderQuoteUsableForCurrentSession(rawCached.value, target.exchange, target.symbol, { recentAnswer: !rawCached.stale }))
70
70
  ? rawCached
71
71
  : null;
72
72
  if (cached && !forceRefresh && !cached.stale) {
@@ -93,7 +93,7 @@ export class ProviderRouterBatchRoutes {
93
93
  const uniqueTargets = [...providerIndexes.values()].map((bucket) => bucket[0]!.target);
94
94
  const batchResults = await batchProvider.getQuotesBatch!(uniqueTargets, options).catch(() => []);
95
95
  for (const item of batchResults) {
96
- if (!isProviderQuoteUsableForCurrentSession(item.quote, item.target.exchange, item.target.symbol)) continue;
96
+ if (!isProviderQuoteUsableForCurrentSession(item.quote, item.target.exchange, item.target.symbol, { recentAnswer: true })) continue;
97
97
  const key = this.quoteBatchKey(item.target);
98
98
  const sourceKey = this.deps.providerSourceKey(batchProvider);
99
99
  for (const entry of providerIndexes.get(key) ?? []) {
@@ -162,7 +162,7 @@ export class ProviderRouterBatchRoutes {
162
162
  const key = this.cachedFinancialsBatchKey(item.target);
163
163
  let value = resolveTickerFinancialsQuoteState(normalizeTickerFinancialsPriceHistory(item.financials));
164
164
  if (value && !item.target.instrument && !providerFinancialsMatchTarget(value, item.target.symbol, item.target.exchange)) continue;
165
- if (value) value = dropUnusableProviderQuote(value, item.target.exchange);
165
+ if (value) value = dropUnusableProviderQuote(value, item.target.exchange, { recentAnswer: true });
166
166
  if (!value) continue;
167
167
  const sourceKey = this.deps.providerSourceKey(batchProvider);
168
168
  for (const entry of providerIndexes.get(key) ?? []) {
@@ -3,6 +3,7 @@ import { CachedQuery, type CachedValue } from "../../data/cached-query";
3
3
  import type { CachedAssetArgs, CachedAssetMethod, CachedAssetValue, DataProvider, MarketDataRequestContext, SecFilingItem } from "../../types/data-provider";
4
4
  import type { AnalystResearchData, CorporateActionsData, HolderData } from "../../types/financials";
5
5
  import { canonicalExchange } from "../../utils/exchanges";
6
+ import { nonUsSecListingVenue } from "../../utils/sec";
6
7
  import { shouldLogProviderError } from "../provider-errors";
7
8
  import { hasBrokerContext, withBrokerTimeout } from "./brokers";
8
9
  import { publicListingExchange } from "../listing-target";
@@ -220,9 +221,11 @@ export class ProviderRouterCachedRoutes {
220
221
  };
221
222
  case "getSecFilings": {
222
223
  const [symbol, count = 15, listingExchange, requestContext] = args as CachedAssetArgs<"getSecFilings">;
224
+ const exact = buildVariantKey([["exchange", canonicalExchange(listingExchange)], ["count", count]]);
223
225
  return {
224
226
  kind: "sec-filings", policy: "secFilings", entityKey: this.deps.getEntityKey(symbol, requestContext?.instrument),
225
- variants: [...new Set([buildVariantKey([["exchange", canonicalExchange(listingExchange)], ["count", count]]), buildVariantKey([["count", count]]), ""])],
227
+ // A non-US listing never reads the bare symbol's filings: SAN in Paris is Sanofi, SAN at the SEC is Santander.
228
+ variants: nonUsSecListingVenue(symbol, listingExchange) ? [exact] : [...new Set([exact, buildVariantKey([["count", count]]), ""])],
226
229
  request: (provider, force) => provider.getSecFilings?.(symbol, count, listingExchange, force ? { ...requestContext, cacheMode: "refresh" } : requestContext),
227
230
  throwLastError: true, error: `No SEC filings provider available for ${symbol}`,
228
231
  };
@@ -200,7 +200,7 @@ export class ProviderRouterFinancialRoutes {
200
200
  const rawCached = selectCachedResource<Quote>(this.deps.resources, "quote", entityKey, variantKeys, sourceKeys, false);
201
201
  const cachedIsStale = rawCached && (brokerSourceKeys.includes(rawCached.sourceKey)
202
202
  ? isQuoteContributionStaleForCurrentSession(quoteWithFreshnessExchange(rawCached.value, exchange))
203
- : !isProviderQuoteUsableForCurrentSession(rawCached.value, exchange, ticker));
203
+ : !isProviderQuoteUsableForCurrentSession(rawCached.value, exchange, ticker, { recentAnswer: !rawCached.stale }));
204
204
  const cached = rawCached && !cachedIsStale
205
205
  ? rawCached
206
206
  : null;
@@ -259,7 +259,7 @@ export class ProviderRouterFinancialRoutes {
259
259
  if (
260
260
  record
261
261
  && (includeStale || !record.stale)
262
- && isProviderQuoteUsableForCurrentSession(record.value, exchange, ticker)
262
+ && isProviderQuoteUsableForCurrentSession(record.value, exchange, ticker, { recentAnswer: !record.stale })
263
263
  ) {
264
264
  return record.value;
265
265
  }
@@ -7,7 +7,16 @@ import { redactUnavailableFundamentals, RETRACTABLE_VALUATION_FIELDS } from "../
7
7
  import { isExtendedHoursExchange, isQuoteStaleForCurrentSession } from "../../market-data/quotes/freshness";
8
8
  import { mergeQuoteMetadata, quoteMetadataFromQuote, quoteMetadataMatchesTarget } from "../../market-data/quotes/metadata";
9
9
  import { parsePublicTickerKey } from "../../utils/exchanges";
10
- import { activeUsMarketSession, isUsPriorSessionPremarketQuote } from "../../market-data/market/freshness";
10
+ import {
11
+ activeUsMarketSession,
12
+ delayedFeedLagMs,
13
+ isMiddayBreakPrint,
14
+ isRegularSessionTime,
15
+ isUsPostSessionPrint,
16
+ isUsPriorSessionPremarketQuote,
17
+ isUsRegularCloseQuoteInPostSession,
18
+ latestRegularSessionOpen,
19
+ } from "../../market-data/market/freshness";
11
20
  import {
12
21
  mergeQuoteContributionMaps,
13
22
  isQuoteContributionStaleForCurrentSession,
@@ -122,21 +131,62 @@ function isQuoteInActiveSession(quote: Quote, now: number): boolean {
122
131
  return false;
123
132
  }
124
133
 
125
- function isActiveProviderQuoteTooOld(quote: Quote, now = Date.now()): boolean {
134
+ // An opening auction can print before the continuous open (Hong Kong's at 09:20).
135
+ const OPENING_AUCTION_MS = 15 * 60_000;
136
+
137
+ /**
138
+ * Whether Gloom Cloud vouches that a delayed quote is current, however long
139
+ * ago its last trade was. The service judges more than that trade's age: it
140
+ * knows when it asked for the quote and how often the listing trades, so a
141
+ * thinly traded listing's hour-old trade can be the current price while its
142
+ * venue trades. Its verdict stands in for the age bound when:
143
+ * - the service answered on this request, or a cache entry still inside its
144
+ * TTL holds that answer (`recentAnswer`); a copy past the TTL is not vouched for;
145
+ * - the answer says `stale: false`. One without the flag vouches for nothing,
146
+ * and one flagged stale never gets this far;
147
+ * - the quote is delayed. The service bounds a delayed quote's feed age itself
148
+ * but not a real-time one's, so real-time quotes keep the age bound;
149
+ * - it reports the regular session, the venue's session is in progress as
150
+ * the delayed feed shows it, and the trade belongs to that session; or it
151
+ * reports a US after-hours price, the after-hours session is in progress and
152
+ * the trade belongs to it.
153
+ * The answer says nothing about how often a listing trades, so a liquid
154
+ * listing the service wrongly vouches for is accepted too. The service's own
155
+ * bound for liquid listings, about twenty minutes, is tighter than this one.
156
+ */
157
+ function isVouchedCurrentByService(quote: Quote, exchange: string | undefined, now: number): boolean {
158
+ if (quote.providerId !== "gloomberb-cloud" || quote.stale !== false || quote.dataSource !== "delayed") return false;
159
+ if (quote.marketState === "POST") {
160
+ return finitePositiveNumber(quote.postMarketPrice) && isUsPostSessionPrint(quote.lastUpdated, exchange, now);
161
+ }
162
+ if (quote.marketState !== "REGULAR") return false;
163
+ const feedTime = now - delayedFeedLagMs(exchange);
164
+ if (isRegularSessionTime(exchange, feedTime) !== true) return false;
165
+ const open = latestRegularSessionOpen(exchange, feedTime);
166
+ return open != null && quote.lastUpdated >= open - OPENING_AUCTION_MS;
167
+ }
168
+
169
+ function isActiveProviderQuoteTooOld(quote: Quote, now = Date.now(), recentAnswer = false): boolean {
126
170
  // The shared freshness predicate already validates and dates a daily NAV.
127
171
  if (quote.priceObservation === "nav") return false;
128
172
  if (!isQuoteInActiveSession(quote, now)) return false;
129
173
  // A prior-session close before any pre-market trade has no in-session print
130
174
  // to age; the session-date rules bound it instead.
131
- if (isUsPriorSessionPremarketQuote(quote.lastUpdated, quote.listingExchangeName || quote.exchangeName, quote.marketState, now)) {
175
+ const exchange = quote.listingExchangeName || quote.exchangeName;
176
+ if (isUsPriorSessionPremarketQuote(quote.lastUpdated, exchange, quote.marketState, now)) {
177
+ return false;
178
+ }
179
+ // Likewise today's regular close before any after-hours trade.
180
+ if (quote.postMarketPrice == null && isUsRegularCloseQuoteInPostSession(quote.lastUpdated, exchange, quote.marketState, now)) {
132
181
  return false;
133
182
  }
134
183
  if (!Number.isFinite(quote.lastUpdated)) return false;
135
- const maxAge =
136
- quote.dataSource === "delayed"
137
- ? ACTIVE_DELAYED_PROVIDER_QUOTE_MAX_AGE_MS
138
- : ACTIVE_PROVIDER_QUOTE_MAX_AGE_MS;
139
- return now - quote.lastUpdated > maxAge;
184
+ const delayed = quote.dataSource === "delayed";
185
+ const maxAge = delayed ? ACTIVE_DELAYED_PROVIDER_QUOTE_MAX_AGE_MS : ACTIVE_PROVIDER_QUOTE_MAX_AGE_MS;
186
+ if (now - quote.lastUpdated <= maxAge) return false;
187
+ // While the venue pauses at midday, the morning's last print is the current price.
188
+ if (isMiddayBreakPrint(quote.lastUpdated, exchange, now, delayed ? delayedFeedLagMs(exchange) : 0)) return false;
189
+ return !(recentAnswer && isVouchedCurrentByService(quote, exchange, now));
140
190
  }
141
191
 
142
192
  export function providerQuoteMatchesTarget(quote: Quote | null | undefined, symbol?: string, exchange?: string): quote is Quote {
@@ -156,11 +206,21 @@ export function providerQuoteMatchesTarget(quote: Quote | null | undefined, symb
156
206
  return true;
157
207
  }
158
208
 
159
- export function isProviderQuoteUsableForCurrentSession(quote: Quote | null | undefined, exchange?: string, symbol?: string): quote is Quote {
209
+ /**
210
+ * `recentAnswer`: the source answered with this quote on this request, or a
211
+ * cache entry still inside its TTL holds it. Only then can the source's own
212
+ * verdict on a delayed quote stand in for the age bound.
213
+ */
214
+ export function isProviderQuoteUsableForCurrentSession(
215
+ quote: Quote | null | undefined,
216
+ exchange?: string,
217
+ symbol?: string,
218
+ options: { recentAnswer?: boolean } = {},
219
+ ): quote is Quote {
160
220
  if (!providerQuoteMatchesTarget(quote, symbol, exchange)) return false;
161
221
  const normalized = quoteWithFreshnessExchange(quote, exchange);
162
222
  if (isQuoteStaleForCurrentSession(normalized)) return false;
163
- if (isActiveProviderQuoteTooOld(normalized)) return false;
223
+ if (isActiveProviderQuoteTooOld(normalized, Date.now(), options.recentAnswer === true)) return false;
164
224
  // Futures may trade or settle at zero or negative prices. Require explicit
165
225
  // source type metadata; an alias alone cannot establish the price domain.
166
226
  const futures = ["FUT", "FUTURE", "FUTURES"].includes(normalized.instrumentType?.trim().toUpperCase() ?? "");
@@ -187,8 +247,12 @@ export function providerFinancialsMatchTarget(value: TickerFinancials, symbol: s
187
247
  return quoteMetadataMatchesTarget(metadata, hasListing ? symbol : parsePublicTickerKey(symbol).symbol, hasListing ? exchange : undefined);
188
248
  }
189
249
 
190
- export function dropUnusableProviderQuote(value: TickerFinancials, exchange?: string): TickerFinancials {
191
- if (!value.quote || isProviderQuoteUsableForCurrentSession(value.quote, exchange)) {
250
+ export function dropUnusableProviderQuote(
251
+ value: TickerFinancials,
252
+ exchange?: string,
253
+ options: { recentAnswer?: boolean } = {},
254
+ ): TickerFinancials {
255
+ if (!value.quote || isProviderQuoteUsableForCurrentSession(value.quote, exchange, undefined, options)) {
192
256
  return value;
193
257
  }
194
258
 
@@ -19,6 +19,7 @@ import { subtractTimeRange } from "../../time-series/date-window";
19
19
  import { clipPriceHistoryToRange } from "../../time-series/history-window";
20
20
  import { repairIsolatedIntradayOhlcOutliers } from "../../time-series/history-quality";
21
21
  import { canonicalExchange, parsePublicTickerKey, resolveExchangeTimeZone } from "../../utils/exchanges";
22
+ import { isRoundTheClockCoin } from "../../utils/crypto-pair";
22
23
  import { zonedDateKey } from "../../utils/zoned-date-time";
23
24
  import { resolvePriceHistoryCurrencyUnit } from "../../utils/currency-units";
24
25
  import { calendarHistoryFetchState, calendarHistoryLastBarDate, dropLeadingPlaceholderBars, getPricePointTimestamp, hasUsablePriceHistory, preservePriceHistoryGaps, isPriceHistoryStaleForCurrentWindow, normalizePriceHistory, priceHistoryIntervalMs, type CalendarHistoryFetchState } from "../../utils/price-history";
@@ -245,9 +246,9 @@ function normalizeRequestResult(value: PriceHistoryResult, request: HistoryReque
245
246
  };
246
247
  }
247
248
 
248
- function resultIsStale(value: PriceHistoryResult, exchange: string, intervalMs?: number | null): boolean {
249
+ function resultIsStale(value: PriceHistoryResult, symbol: string, exchange: string, intervalMs?: number | null): boolean {
249
250
  return isPriceHistoryStaleForCurrentWindow(value.points, Date.now(), {
250
- exchange, intervalMs: intervalMs ?? (value.resolution ? priceHistoryIntervalMs(value.resolution) : undefined), session: value.session,
251
+ symbol, exchange, intervalMs: intervalMs ?? (value.resolution ? priceHistoryIntervalMs(value.resolution) : undefined), session: value.session,
251
252
  });
252
253
  }
253
254
 
@@ -342,8 +343,8 @@ export class ProviderRouterHistoryRoutes {
342
343
  context,
343
344
  cachePolicyKey: intraday ? "priceHistoryIntraday" : "priceHistoryDaily",
344
345
  missingProviderError: `No history provider available for ${ticker}`,
345
- isCachedValueStale: (value) => intraday && resultIsStale(value, exchange),
346
- isFetchedValueStale: (value) => intraday && resultIsStale(value, exchange),
346
+ isCachedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange),
347
+ isFetchedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange),
347
348
  fetchBroker: async (candidate) => candidate.broker.getPriceHistory
348
349
  ? candidate.broker.getPriceHistory(
349
350
  ticker,
@@ -399,8 +400,8 @@ export class ProviderRouterHistoryRoutes {
399
400
  context,
400
401
  cachePolicyKey: intraday ? "priceHistoryIntraday" : "priceHistoryDaily",
401
402
  missingProviderError: `No resolution-aware history provider available for ${ticker}`,
402
- isCachedValueStale: (value) => intraday && resultIsStale(value, exchange, intervalMs),
403
- isFetchedValueStale: (value) => intraday && resultIsStale(value, exchange, intervalMs),
403
+ isCachedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange, intervalMs),
404
+ isFetchedValueStale: (value) => intraday && resultIsStale(value, ticker, exchange, intervalMs),
404
405
  fetchBroker: async (candidate) => candidate.broker.getPriceHistoryForResolution
405
406
  ? candidate.broker.getPriceHistoryForResolution(
406
407
  ticker,
@@ -515,9 +516,9 @@ export class ProviderRouterHistoryRoutes {
515
516
  context,
516
517
  cachePolicyKey: intervalMs != null && intervalMs >= 24 * 60 * 60 * 1000 ? "priceHistoryDaily" : "priceHistoryIntraday",
517
518
  isCachedValueStale: (value) => currentWindowAtLookup
518
- && resultIsStale(value, exchange, intervalMs),
519
+ && resultIsStale(value, ticker, exchange, intervalMs),
519
520
  isFetchedValueStale: (value) => isCurrentHistoryWindow(endDate)
520
- && resultIsStale(value, exchange, intervalMs),
521
+ && resultIsStale(value, ticker, exchange, intervalMs),
521
522
  fetchBroker: async (candidate) => candidate.broker.getDetailedPriceHistory
522
523
  ? candidate.broker.getDetailedPriceHistory(
523
524
  ticker,
@@ -568,6 +569,7 @@ export class ProviderRouterHistoryRoutes {
568
569
  const now = Date.now();
569
570
  const fetchState = (record: { fetchedAt: number; value: PriceHistoryResult }, checkedAt?: number): CalendarHistoryFetchState => currentWindow
570
571
  ? calendarHistoryFetchState(record.value.points, record.fetchedAt, now, {
572
+ symbol: target.symbol,
571
573
  exchange: target.exchange || request.target.exchange,
572
574
  checkedAt,
573
575
  // Bar size comes from the request: a cached weekly or monthly series
@@ -580,7 +582,7 @@ export class ProviderRouterHistoryRoutes {
580
582
  const ranked = cachedRecords.filter((record) => hasUsablePriceHistory(record.value.points)).map((record) => {
581
583
  const tier = fetchTier[fetchState(record)];
582
584
  return { record, tier, exact: request.exactCacheVariantKeys.includes(record.variantKey),
583
- lastBar: tier === 0 ? "" : calendarHistoryLastBarDate(record.value.points, target.exchange || request.target.exchange) ?? "" };
585
+ lastBar: tier === 0 ? "" : calendarHistoryLastBarDate(record.value.points, target.exchange || request.target.exchange, target.symbol) ?? "" };
584
586
  });
585
587
  // Current copies keep their listed order. Otherwise ties go to this key's
586
588
  // own copy, then the latest fetch, rather than to row order.
@@ -657,7 +659,10 @@ export class ProviderRouterHistoryRoutes {
657
659
  throw new HistoryRetentionError(candidates[0]?.retention ?? attempts.retention, { candidates, outcomes: [...attempts.outcomes.values()] });
658
660
  }
659
661
  if (!providerResult && request.missingProviderError && !reportedGaps.some((value) => value.points.length > 0)) {
660
- throw new Error(request.missingProviderError);
662
+ // A source answered a coin's history but it stops short of the present: say so, not that nothing answered.
663
+ const behind = isRoundTheClockCoin(target.symbol, target.exchange || request.target.exchange)
664
+ && [...attempts.outcomes.values()].some((outcome) => outcome.outcome === "stale");
665
+ throw new Error(behind ? `Latest history for ${target.symbol} is behind` : request.missingProviderError);
661
666
  }
662
667
  return withReportedGaps(providerResult?.value ?? { points: [], resolution: historyResolutionForInterval(request.interval) });
663
668
  }
@@ -73,7 +73,7 @@ export class ProviderRouterPrimaryRoutes {
73
73
  if (rawValue && !context?.instrument && !providerFinancialsMatchTarget(rawValue, ticker, exchange)) continue;
74
74
  const resolvedValue = resolveTickerFinancialsQuoteState(normalizeTickerFinancialsPriceHistory(rawValue));
75
75
  if (resolvedValue && !context?.instrument && !providerFinancialsMatchTarget(resolvedValue, ticker, exchange)) continue;
76
- let value = resolvedValue ? dropUnusableProviderQuote(resolvedValue, exchange) : null;
76
+ let value = resolvedValue ? dropUnusableProviderQuote(resolvedValue, exchange, { recentAnswer: true }) : null;
77
77
  if (!value) continue;
78
78
  const sourceKey = this.options.providerSourceKey(provider);
79
79
  if (context?.statementHistory === "extended" && !hasReusableExtendedHistory(value)) {
@@ -187,7 +187,7 @@ export class ProviderRouterPrimaryRoutes {
187
187
  for (const provider of this.options.providersInPriorityOrder()) {
188
188
  try {
189
189
  const quote = await provider.getQuote(ticker, exchange, context);
190
- if (!isProviderQuoteUsableForCurrentSession(quote, exchange, ticker)) continue;
190
+ if (!isProviderQuoteUsableForCurrentSession(quote, exchange, ticker, { recentAnswer: true })) continue;
191
191
  const sourceKey = this.options.providerSourceKey(provider);
192
192
  this.options.cacheResource(
193
193
  "quote",