gloomberb 0.16.1 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (574) hide show
  1. package/README.md +2 -1
  2. package/package.json +2 -1
  3. package/src/api-client/beneficial-owners.ts +92 -0
  4. package/src/api-client/data.ts +26 -8
  5. package/src/api-client/errors.ts +12 -0
  6. package/src/api-client/geo.ts +363 -0
  7. package/src/api-client/index.ts +2 -0
  8. package/src/api-client/market-discovery.ts +10 -0
  9. package/src/api-client/paths.ts +30 -1
  10. package/src/api-client/perps.ts +37 -0
  11. package/src/api-client/request.ts +5 -2
  12. package/src/api-client/types.ts +2 -0
  13. package/src/brokers/account-cache.ts +24 -0
  14. package/src/cli/commands/command-utils.ts +8 -0
  15. package/src/cli/commands/crypto-hints.ts +75 -0
  16. package/src/cli/commands/market.ts +414 -106
  17. package/src/cli/commands/overview.ts +77 -32
  18. package/src/cli/commands/ticker.ts +101 -43
  19. package/src/cli/desktop-pane-shot.ts +34 -4
  20. package/src/cli/freshness.ts +61 -0
  21. package/src/cli/help.ts +1 -0
  22. package/src/cli/helpers.ts +4 -8
  23. package/src/cli/index.ts +12 -2
  24. package/src/cli/listing-arg.ts +321 -0
  25. package/src/cli/pane-functions/access-gate.ts +42 -0
  26. package/src/cli/pane-functions/catalog.ts +28 -1
  27. package/src/cli/pane-functions/data.ts +3 -1
  28. package/src/cli/pane-functions/dom.ts +20 -2
  29. package/src/cli/pane-functions/freshness.ts +400 -0
  30. package/src/cli/pane-functions/function-help.ts +27 -20
  31. package/src/cli/pane-functions/headless.ts +39 -11
  32. package/src/cli/pane-functions/index.ts +15 -4
  33. package/src/cli/pane-functions/options.ts +3 -0
  34. package/src/cli/pane-functions/report.ts +4 -0
  35. package/src/cli/pane-functions/resolver.ts +35 -7
  36. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  37. package/src/cli/pane-functions/screenshot.ts +7 -3
  38. package/src/cli/result.ts +41 -27
  39. package/src/cli/ticker-resolution.ts +7 -5
  40. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  41. package/src/components/chart/composite/drawing-store.ts +59 -0
  42. package/src/components/chart/composite/legend.tsx +319 -0
  43. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  44. package/src/components/chart/composite/panel-gestures.ts +59 -0
  45. package/src/components/chart/composite/panel-labels.ts +107 -0
  46. package/src/components/chart/composite/panel-surface.tsx +876 -0
  47. package/src/components/chart/composite/tool-catalog.ts +98 -0
  48. package/src/components/chart/composite/toolbar.tsx +186 -0
  49. package/src/components/chart/composite/tools.ts +8 -0
  50. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  51. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  52. package/src/components/command-bar/list/model.ts +5 -0
  53. package/src/components/command-bar/list/view.tsx +16 -3
  54. package/src/components/command-bar/pane-templates/workflow.ts +1 -0
  55. package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
  56. package/src/components/command-bar/workflow/ops.ts +1 -1
  57. package/src/components/command-bar/workflow/tickers.ts +6 -0
  58. package/src/components/data-table/view.tsx +29 -10
  59. package/src/components/feedback-dialog.tsx +2 -1
  60. package/src/components/form-modal/field-row.tsx +2 -2
  61. package/src/components/layout/detached-pane-shell.tsx +6 -3
  62. package/src/components/layout/pane/content.tsx +23 -10
  63. package/src/components/layout/pane/error-boundary.tsx +103 -0
  64. package/src/components/layout/pane/footer/registration.tsx +68 -23
  65. package/src/components/layout/pane/header.tsx +11 -11
  66. package/src/components/layout/shell/menu.ts +2 -1
  67. package/src/components/layout/shell/pane/actions.ts +2 -1
  68. package/src/components/layout/shell/pane/layers.tsx +14 -3
  69. package/src/components/metric-treemap/heat-surface.tsx +43 -16
  70. package/src/components/metric-treemap/heat-tiles.ts +18 -0
  71. package/src/components/metric-treemap/layout.ts +2 -0
  72. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  73. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  74. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  75. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  76. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  77. package/src/components/ticker/list-table-view.tsx +13 -1
  78. package/src/components/ui/fields.tsx +8 -0
  79. package/src/components/ui/range-track.tsx +10 -3
  80. package/src/components/ui/status.tsx +8 -2
  81. package/src/components/ui/tabs.tsx +7 -4
  82. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  83. package/src/data/config/store/normalize.ts +17 -1
  84. package/src/i18n/es.ts +19 -1
  85. package/src/i18n/ja.ts +19 -1
  86. package/src/i18n/ko.ts +19 -1
  87. package/src/i18n/zh-cn.ts +19 -1
  88. package/src/i18n/zh-tw.ts +19 -1
  89. package/src/market-data/coordinator/chart.ts +1 -1
  90. package/src/market-data/coordinator/quotes.ts +23 -4
  91. package/src/market-data/fx-closes.ts +72 -0
  92. package/src/market-data/market/freshness.ts +78 -6
  93. package/src/market-data/market/session-close-note.ts +57 -0
  94. package/src/market-data/market/status.ts +151 -0
  95. package/src/market-data/published-apac-sessions.ts +66 -0
  96. package/src/market-data/quotes/contributions.ts +2 -0
  97. package/src/market-data/quotes/resolution.ts +2 -0
  98. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  99. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  100. package/src/plugins/builtin/alerts/cli.ts +10 -5
  101. package/src/plugins/builtin/alerts/index.tsx +1 -0
  102. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  103. package/src/plugins/builtin/analytics/risk-client.ts +191 -66
  104. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  105. package/src/plugins/builtin/analytics/risk-headless.ts +19 -13
  106. package/src/plugins/builtin/analytics/risk-model.ts +45 -17
  107. package/src/plugins/builtin/analytics/risk-pane.tsx +1 -0
  108. package/src/plugins/builtin/analytics/risk-test-data.ts +25 -1
  109. package/src/plugins/builtin/attention/headless.ts +6 -4
  110. package/src/plugins/builtin/attention/index.tsx +1 -1
  111. package/src/plugins/builtin/attention/pane.tsx +1 -1
  112. package/src/plugins/builtin/awards/headless.ts +1 -0
  113. package/src/plugins/builtin/awards/pane.tsx +1 -1
  114. package/src/plugins/builtin/backtest/headless.ts +1 -0
  115. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  116. package/src/plugins/builtin/buildout/index.tsx +1 -0
  117. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  118. package/src/plugins/builtin/cds/headless.ts +2 -0
  119. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  120. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  121. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  122. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  123. package/src/plugins/builtin/chat/channels.ts +19 -3
  124. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  125. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  126. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  127. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  128. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  129. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  130. package/src/plugins/builtin/chat/index.tsx +1 -0
  131. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  132. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  133. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  134. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  135. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  136. package/src/plugins/builtin/chat/message/types.ts +14 -2
  137. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  138. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  139. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  140. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  141. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  142. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  143. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  144. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  145. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  146. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  147. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  148. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  149. package/src/plugins/builtin/correlation/compute.ts +59 -16
  150. package/src/plugins/builtin/correlation/geo.ts +34 -0
  151. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  152. package/src/plugins/builtin/correlation/headless.ts +42 -8
  153. package/src/plugins/builtin/correlation/history.ts +2 -0
  154. package/src/plugins/builtin/correlation/index.tsx +68 -14
  155. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  156. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  157. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  158. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  159. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  160. package/src/plugins/builtin/correlation/settings.ts +1 -1
  161. package/src/plugins/builtin/cot/headless.ts +6 -3
  162. package/src/plugins/builtin/cot/index.tsx +3 -3
  163. package/src/plugins/builtin/cot/model.ts +36 -3
  164. package/src/plugins/builtin/cpi/headless.ts +4 -0
  165. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  166. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  167. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  168. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  169. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  170. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  171. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  172. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  173. package/src/plugins/builtin/doe/headless.ts +7 -0
  174. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  175. package/src/plugins/builtin/earnings/headless.ts +5 -0
  176. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  177. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  178. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  179. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  180. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  181. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  182. package/src/plugins/builtin/econ/index.tsx +1 -0
  183. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  184. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  185. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  186. package/src/plugins/builtin/executives/index.tsx +1 -0
  187. package/src/plugins/builtin/exposure/headless.ts +3 -1
  188. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  189. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  190. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  191. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  192. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  193. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  194. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  195. package/src/plugins/builtin/gpu/headless.ts +7 -3
  196. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  197. package/src/plugins/builtin/gpu/model.ts +27 -1
  198. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  199. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  200. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  201. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  202. package/src/plugins/builtin/holders/headless.ts +139 -5
  203. package/src/plugins/builtin/holders/index.tsx +10 -3
  204. package/src/plugins/builtin/holders/pane.tsx +20 -3
  205. package/src/plugins/builtin/holders/report-header.ts +95 -0
  206. package/src/plugins/builtin/holders/table-model.ts +20 -5
  207. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  208. package/src/plugins/builtin/holders/types.ts +2 -1
  209. package/src/plugins/builtin/insider/headless.ts +2 -0
  210. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  211. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  212. package/src/plugins/builtin/jobs/headless.ts +1 -0
  213. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  214. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  215. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  216. package/src/plugins/builtin/market-heatmap/data.ts +2 -0
  217. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  218. package/src/plugins/builtin/market-heatmap/index.tsx +39 -46
  219. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  220. package/src/plugins/builtin/market-heatmap/portfolio.ts +23 -4
  221. package/src/plugins/builtin/market-movers/headless.ts +2 -0
  222. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  223. package/src/plugins/builtin/members/client.ts +20 -3
  224. package/src/plugins/builtin/members/headless.ts +5 -3
  225. package/src/plugins/builtin/members/model.ts +10 -2
  226. package/src/plugins/builtin/members/pane.tsx +13 -6
  227. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  228. package/src/plugins/builtin/mna/headless.ts +1 -0
  229. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  230. package/src/plugins/builtin/news/headless.ts +2 -0
  231. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  232. package/src/plugins/builtin/notes/cli.ts +14 -6
  233. package/src/plugins/builtin/notes/index.tsx +1 -0
  234. package/src/plugins/builtin/openfda/index.tsx +1 -0
  235. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  236. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  237. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  238. package/src/plugins/builtin/pe-band/client.ts +48 -3
  239. package/src/plugins/builtin/pe-band/headless.ts +25 -7
  240. package/src/plugins/builtin/pe-band/model.ts +92 -16
  241. package/src/plugins/builtin/pe-band/pane.tsx +33 -16
  242. package/src/plugins/builtin/perps/client.ts +50 -3
  243. package/src/plugins/builtin/perps/headless.ts +144 -16
  244. package/src/plugins/builtin/perps/index.tsx +6 -6
  245. package/src/plugins/builtin/perps/model.ts +189 -12
  246. package/src/plugins/builtin/perps/pane.tsx +248 -47
  247. package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
  248. package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
  249. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  250. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  251. package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
  252. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  253. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  254. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  255. package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
  256. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  257. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  258. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  259. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  260. package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
  261. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  262. package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
  263. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  264. package/src/plugins/builtin/power/headless.ts +3 -1
  265. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  266. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  267. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  268. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  269. package/src/plugins/builtin/research/events-headless.ts +2 -0
  270. package/src/plugins/builtin/research/headless.ts +2 -0
  271. package/src/plugins/builtin/research/index.tsx +1 -0
  272. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  273. package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
  274. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  275. package/src/plugins/builtin/research-search/index.tsx +1 -0
  276. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  277. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  278. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  279. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  280. package/src/plugins/builtin/scanner/headless.ts +14 -0
  281. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  282. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  283. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  284. package/src/plugins/builtin/sec/forms.ts +12 -0
  285. package/src/plugins/builtin/sec/headless.ts +2 -0
  286. package/src/plugins/builtin/sectors/client.ts +1 -0
  287. package/src/plugins/builtin/sectors/headless.ts +9 -1
  288. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  289. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  290. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  291. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  292. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  293. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  294. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  295. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  296. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  297. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  298. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  299. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  300. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  301. package/src/plugins/builtin/themes/headless.ts +3 -0
  302. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  303. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  304. package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
  305. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  306. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
  307. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
  308. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  309. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  310. package/src/plugins/builtin/volatility/headless.ts +6 -1
  311. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  312. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
  313. package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
  314. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  315. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  316. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  317. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  318. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  319. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  320. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  321. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
  322. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  323. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  324. package/src/plugins/builtin/world-venue-map/index.ts +67 -4
  325. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
  326. package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
  327. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  328. package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
  329. package/src/plugins/builtin/world-venue-map/model.ts +7 -4
  330. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
  331. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  332. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  333. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  334. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  335. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  336. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  337. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  338. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  339. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  340. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  341. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  342. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  343. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  344. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  345. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  346. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  347. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  348. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  349. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  350. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  351. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  352. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  353. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  354. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  355. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  356. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  357. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  358. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  359. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  360. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  361. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  362. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  363. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  364. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  365. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  366. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  367. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  368. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  369. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  370. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  371. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  372. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  373. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  374. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  375. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  376. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  377. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  378. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  379. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  380. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  381. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  382. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  383. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  384. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  385. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  386. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  387. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  388. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  389. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  390. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  391. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  392. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  393. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  394. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  395. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  396. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  397. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  398. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  399. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  400. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  401. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  402. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  403. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  404. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  405. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  406. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  407. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  408. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  409. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  410. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  411. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  412. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  413. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  414. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  415. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  416. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  417. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  418. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
  524. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  525. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  526. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  527. package/src/plugins/loader.ts +13 -1
  528. package/src/plugins/registry/pane-settings.ts +1 -0
  529. package/src/renderers/dom/build-assets.ts +81 -3
  530. package/src/renderers/dom/data-table/row.tsx +2 -0
  531. package/src/renderers/dom/desktop/controls.tsx +7 -3
  532. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  533. package/src/renderers/dom/desktop/popover.tsx +73 -14
  534. package/src/renderers/dom/host/input.tsx +14 -3
  535. package/src/renderers/dom/styles.css +6 -7
  536. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  537. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -0
  538. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  539. package/src/renderers/opentui/host.tsx +5 -0
  540. package/src/sources/gloomberb-cloud/index.ts +25 -4
  541. package/src/sources/gloomberb-cloud/normalizers.ts +27 -3
  542. package/src/sources/provider-router/cached-routes.ts +4 -1
  543. package/src/sources/provider-router/financials.ts +8 -7
  544. package/src/sources/provider-router/history.ts +15 -10
  545. package/src/sources/sec-registrant.ts +75 -0
  546. package/src/state/app/context/index.tsx +24 -8
  547. package/src/state/hooks/quote-streaming.ts +41 -26
  548. package/src/sync/core-contributors.ts +4 -0
  549. package/src/telemetry/crash-reports.ts +4 -1
  550. package/src/test-support/cli-context.ts +10 -2
  551. package/src/theme/heat-colors.ts +266 -84
  552. package/src/time-series/resolve.ts +1 -1
  553. package/src/time-series/use-chart-resolution.ts +1 -1
  554. package/src/types/context-menu.ts +6 -0
  555. package/src/types/data-provider.ts +2 -0
  556. package/src/types/financials.ts +3 -0
  557. package/src/types/headless.ts +79 -2
  558. package/src/types/plugin.ts +20 -1
  559. package/src/types/ticker.ts +15 -0
  560. package/src/ui/host.tsx +14 -0
  561. package/src/updater/index.ts +9 -11
  562. package/src/utils/async-deadline.ts +21 -0
  563. package/src/utils/cli-output.ts +5 -1
  564. package/src/utils/crypto-pair.ts +41 -0
  565. package/src/utils/currency-units.ts +14 -0
  566. package/src/utils/depositary-receipt.ts +26 -0
  567. package/src/utils/exchanges.ts +72 -0
  568. package/src/utils/fire-and-forget.ts +24 -0
  569. package/src/utils/format.ts +13 -0
  570. package/src/utils/price-earnings.ts +70 -3
  571. package/src/utils/price-history.ts +58 -13
  572. package/src/utils/rpc-timeout-error.ts +27 -0
  573. package/src/utils/sec.ts +13 -1
  574. package/src/utils/utc-time.ts +79 -0
@@ -0,0 +1,146 @@
1
+ import type { MarketHeatmapAsset } from "../../../api-client/market-discovery";
2
+
3
+ /**
4
+ * The board's grouping and move arithmetic, shared by the pane and the `fn HM`
5
+ * report so a sector reads the same in both. Isomorphic: no React or renderer.
6
+ */
7
+
8
+ type HeatmapMoveAsset = Pick<MarketHeatmapAsset, "symbol" | "hasChange" | "changePercent" | "size" | "sector" | "industry"> & {
9
+ /** Treemap area, when it is not `size` itself. */
10
+ weight?: number;
11
+ };
12
+
13
+ /**
14
+ * The move, or null when there is none: no change data is not a flat session.
15
+ * A name without the last session's close still has the move of the open
16
+ * pre-market or after-hours session it streams (`extendedSession`).
17
+ */
18
+ export function heatmapMove(asset: Pick<MarketHeatmapAsset, "hasChange" | "changePercent"> & { extendedSession?: string }): number | null {
19
+ return (asset.hasChange || asset.extendedSession != null) && typeof asset.changePercent === "number" && Number.isFinite(asset.changePercent)
20
+ ? asset.changePercent
21
+ : null;
22
+ }
23
+
24
+ export type HeatmapGrouping = "sector-industry" | "sector" | "flat";
25
+
26
+ /**
27
+ * Sector and industry blocks when the board knows its sectors. A board where
28
+ * most of the value has none (ETFs, or a snapshot whose classification
29
+ * failed) lays out flat rather than as one big unlabeled block.
30
+ */
31
+ export function resolveHeatmapGrouping(assets: readonly HeatmapMoveAsset[], industries: boolean): HeatmapGrouping {
32
+ let total = 0;
33
+ let classified = 0;
34
+ const sectors = new Set<string>();
35
+ for (const asset of assets) {
36
+ const weight = asset.weight ?? asset.size ?? 0;
37
+ total += weight;
38
+ if (asset.sector) {
39
+ classified += weight;
40
+ sectors.add(asset.sector);
41
+ }
42
+ }
43
+ if (sectors.size < 2 || classified < total / 2) return "flat";
44
+ return industries ? "sector-industry" : "sector";
45
+ }
46
+
47
+ /**
48
+ * The move of a set of names weighted by their size (market cap, an ETF's net
49
+ * assets, a position's value), over the names that have both. Null when none do.
50
+ */
51
+ export function sizeWeightedMove(assets: readonly HeatmapMoveAsset[]): number | null {
52
+ let weight = 0;
53
+ let weightedMove = 0;
54
+ for (const asset of assets) {
55
+ const change = heatmapMove(asset);
56
+ const size = asset.size ?? 0;
57
+ if (change == null || !(size > 0)) continue;
58
+ weight += size;
59
+ weightedMove += change * size;
60
+ }
61
+ return weight > 0 ? weightedMove / weight : null;
62
+ }
63
+
64
+ export type HeatmapGroupBy = "sector" | "industry";
65
+
66
+ export interface HeatmapGroupSummary {
67
+ /** The sector or industry; null for names the snapshot does not classify, or every name on a flat board. */
68
+ group: string | null;
69
+ /** The industry's sector, when grouping by industry. */
70
+ sector: string | null;
71
+ names: number;
72
+ /** Total size: market cap, or net assets on the ETF board. */
73
+ size: number;
74
+ /** This group's share of the board's total size. */
75
+ share: number;
76
+ move: number | null;
77
+ /** Names with a move, and the size they carry; the rest have no change data yet. */
78
+ moved: number;
79
+ up: number;
80
+ down: number;
81
+ unchanged: number;
82
+ best: { symbol: string; move: number } | null;
83
+ worst: { symbol: string; move: number } | null;
84
+ }
85
+
86
+ function summarize(group: string | null, sector: string | null, assets: readonly HeatmapMoveAsset[], boardSize: number): HeatmapGroupSummary {
87
+ let up = 0;
88
+ let down = 0;
89
+ let unchanged = 0;
90
+ let size = 0;
91
+ let best: HeatmapGroupSummary["best"] = null;
92
+ let worst: HeatmapGroupSummary["worst"] = null;
93
+ for (const asset of assets) {
94
+ size += asset.size ?? 0;
95
+ const move = heatmapMove(asset);
96
+ if (move == null) continue;
97
+ if (move > 0) up += 1;
98
+ else if (move < 0) down += 1;
99
+ else unchanged += 1;
100
+ if (!best || move > best.move) best = { symbol: asset.symbol, move };
101
+ if (!worst || move < worst.move) worst = { symbol: asset.symbol, move };
102
+ }
103
+ return {
104
+ group,
105
+ sector,
106
+ names: assets.length,
107
+ size,
108
+ share: boardSize > 0 ? size / boardSize : 0,
109
+ move: sizeWeightedMove(assets),
110
+ moved: up + down + unchanged,
111
+ up,
112
+ down,
113
+ unchanged,
114
+ best,
115
+ worst,
116
+ };
117
+ }
118
+
119
+ /**
120
+ * One summary per sector or industry, largest first as the board lays them
121
+ * out. A flat board (ETFs) is one group of every name. Unclassified names form
122
+ * their own group last.
123
+ */
124
+ export function summarizeHeatmapGroups(
125
+ assets: readonly HeatmapMoveAsset[],
126
+ groupBy: HeatmapGroupBy,
127
+ ): { grouping: HeatmapGrouping; groups: HeatmapGroupSummary[]; board: HeatmapGroupSummary } {
128
+ const grouping = resolveHeatmapGrouping(assets, groupBy === "industry");
129
+ const boardSize = assets.reduce((sum, asset) => sum + (asset.size ?? 0), 0);
130
+ const board = summarize(null, null, assets, boardSize);
131
+ if (grouping === "flat") return { grouping, groups: [board], board };
132
+ const buckets = new Map<string, { group: string | null; sector: string | null; assets: HeatmapMoveAsset[] }>();
133
+ for (const asset of assets) {
134
+ const sector = asset.sector ?? null;
135
+ const group = sector == null ? null : grouping === "sector-industry" ? asset.industry ?? null : sector;
136
+ const key = `${sector ?? ""}\u0000${group ?? ""}`;
137
+ const bucket = buckets.get(key) ?? { group, sector, assets: [] };
138
+ bucket.assets.push(asset);
139
+ buckets.set(key, bucket);
140
+ }
141
+ const groups = [...buckets.values()]
142
+ .map((bucket) => summarize(bucket.group, grouping === "sector-industry" ? bucket.sector : null, bucket.assets, boardSize))
143
+ .sort((left, right) => Number(left.sector == null && left.group == null) - Number(right.sector == null && right.group == null)
144
+ || right.size - left.size);
145
+ return { grouping, groups, board };
146
+ }
@@ -3,6 +3,7 @@ import type { MarketHeatmapAsset, MarketHeatmapUniverseId } from "../../../api-c
3
3
  import { useAppSelector, usePaneStateValue } from "../../../state/app/context";
4
4
  import type { ColumnConfig } from "../../../types/config";
5
5
  import type { TickerFinancials } from "../../../types/financials";
6
+ import { getSessionMoveDisplay, type ExtendedSession } from "../../../market-data/market/status";
6
7
  import type { TickerRecord } from "../../../types/ticker";
7
8
  import { getSortValue, type ColumnContext } from "../portfolio-list/metrics";
8
9
 
@@ -36,6 +37,8 @@ export interface HeatmapBoardAsset extends MarketHeatmapAsset {
36
37
  sizeCurrency?: string;
37
38
  /** Treemap area, when it is not `size` itself. */
38
39
  weight?: number;
40
+ /** The price and move are this open pre-market or after-hours session's, from the regular close. */
41
+ extendedSession?: ExtendedSession;
39
42
  }
40
43
 
41
44
  export interface HeatmapPortfolioPane {
@@ -48,6 +51,19 @@ export function heatmapTabId(value: string | null | undefined): HeatmapTabId {
48
51
  return "us-equity";
49
52
  }
50
53
 
54
+ /** Pane state where the pane says which kind of list its portfolio tab shows, for the header to read. */
55
+ export const HEATMAP_COLLECTION_KIND_STATE_KEY = "collectionKind";
56
+
57
+ /**
58
+ * Whether Size by changes the board: the market boards and a watchlist, never
59
+ * a portfolio, whose holdings are always sized by position value. Until the
60
+ * pane has said which list its tab shows, the control stays away.
61
+ */
62
+ export function heatmapSizeByApplies(universe: unknown, collectionKind: unknown): boolean {
63
+ return heatmapTabId(typeof universe === "string" ? universe : null) !== PORTFOLIO_HEATMAP_TAB
64
+ || collectionKind === "watchlist";
65
+ }
66
+
51
67
  export function isRemoteHeatmapUniverse(value: HeatmapTabId): value is MarketHeatmapUniverseId {
52
68
  return value !== PORTFOLIO_HEATMAP_TAB;
53
69
  }
@@ -200,16 +216,19 @@ export function buildPortfolioHeatmapAssets({
200
216
  const symbol = ticker.metadata.ticker;
201
217
  const snapshot = financials.get(symbol);
202
218
  const quote = snapshot?.quote;
203
- const price = quote != null && Number.isFinite(quote.price) ? quote.price : null;
219
+ // Colored like the market boards: an open extended session's move, else the regular session's.
220
+ const display = getSessionMoveDisplay(quote);
221
+ const price = display != null && Number.isFinite(display.price) ? display.price : null;
204
222
  const size = positiveNumber(getSortValue(sizeColumn, ticker, snapshot, context));
205
- const hasChange = quote != null && Number.isFinite(quote.changePercent);
223
+ const hasChange = display?.changePercent != null && Number.isFinite(display.changePercent);
206
224
  return {
207
225
  symbol,
208
226
  name: quote?.name?.trim() || ticker.metadata.name || symbol,
209
227
  price: price ?? 0,
210
- change: quote != null && Number.isFinite(quote.change) ? quote.change : 0,
211
- changePercent: hasChange ? quote.changePercent : 0,
228
+ change: display?.change != null && Number.isFinite(display.change) ? display.change : 0,
229
+ changePercent: hasChange ? display.changePercent! : 0,
212
230
  hasChange,
231
+ ...(display?.session ? { extendedSession: display.session } : {}),
213
232
  size,
214
233
  weight: size == null ? undefined : kind === "portfolio" ? size : heatmapSizeWeight(size, sizeBy),
215
234
  sizeKind: "market-cap",
@@ -81,6 +81,8 @@ export function createMarketMoversHeadless(
81
81
  ): HeadlessPaneDefinition<"rows"> {
82
82
  return {
83
83
  shape: "rows",
84
+ // A screener snapshot, not a real-time feed; rows keep the time of their own last price.
85
+ freshness: { status: "delayed" },
84
86
  argument: { kind: "none" },
85
87
  options: [{
86
88
  key: "list",
@@ -120,6 +120,8 @@ function projectValuationHeadlessBundle(
120
120
 
121
121
  export const marketValuationHeadless: HeadlessPaneDefinition<"bundle"> = {
122
122
  shape: "bundle",
123
+ // Each indicator row checks its own release schedule and says when it is stale.
124
+ freshness: { status: "not-a-feed", basis: "published statistics" },
123
125
  argument: {
124
126
  kind: "free-text",
125
127
  placeholder: "indicator",
@@ -1,7 +1,9 @@
1
1
  import { apiClient } from "../../../api-client";
2
+ import { ApiRequestError } from "../../../api-client/errors";
2
3
  import type { FundMembersPayload, FundChangesPayload, MemberFundsPayload } from "../../../api-client/members";
3
4
  import { createPluginCache } from "../../../data/plugin-cache";
4
5
  import { cachedCloudResource, loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
6
+ import { coveredFund, notCoveredMessage } from "./model";
5
7
  const policy = { staleMs: 60_000, expireMs: 2 * 60 * 60_000 };
6
8
  export const fundListCache = createPluginCache<MemberFundsPayload>({ kind: "member-funds", source: "gloom-cloud", schemaVersion: 1, policy });
7
9
  export const fundMembersCache = createPluginCache<FundMembersPayload>({ kind: "fund-members", source: "gloom-cloud", schemaVersion: 1, policy });
@@ -22,12 +24,27 @@ function validateFunds(data: MemberFundsPayload) {
22
24
  if (!data || !Array.isArray(data.funds) || !data.funds.every((fund) => typeof fund.ticker === "string" && typeof fund.name === "string")) throw new Error("Unreadable covered funds response");
23
25
  return data;
24
26
  }
27
+ const UNAVAILABLE = "Fund members are not available on this server yet.";
25
28
  async function fetchPayload<T>(fetcher: () => Promise<T>, validate: (data: T) => T) {
26
- try { return validate(await fetcher()); } catch (error) { throw unavailableOnServer(error, "Fund members are not available on this server yet."); }
29
+ try { return validate(await fetcher()); } catch (error) { throw unavailableOnServer(error, UNAVAILABLE); }
30
+ }
31
+ /**
32
+ * A 404 for one fund means either an uncovered fund or a server without the route, and the two read the
33
+ * same. The covered list tells them apart: a fund missing from a readable list is not covered; a list
34
+ * that cannot be read, or that holds the fund, leaves the server-side message.
35
+ */
36
+ async function fetchFundPayload<T>(fund: string, fetcher: () => Promise<T>, validate: (data: T) => T, client: Client) {
37
+ try { return validate(await fetcher()); } catch (error) {
38
+ if (error instanceof ApiRequestError && error.status === 404) {
39
+ const funds = await fetchFunds(client).then((payload) => payload.funds, () => []);
40
+ if (funds.length && !coveredFund(funds, fund)) throw new Error(notCoveredMessage(fund, funds));
41
+ }
42
+ throw unavailableOnServer(error, UNAVAILABLE);
43
+ }
27
44
  }
28
45
  export const fetchFunds = (client: Client = apiClient) => fetchPayload(() => client.getMemberFunds(), validateFunds);
29
- export const fetchMembers = (fund: string, client: Client = apiClient) => fetchPayload(() => client.getFundMembers(fund), validateMembers);
30
- export const fetchChanges = (fund: string, client: Client = apiClient) => fetchPayload(() => client.getFundChanges(fund), validateChanges);
46
+ export const fetchMembers = (fund: string, client: Client = apiClient) => fetchFundPayload(fund, () => client.getFundMembers(fund), validateMembers, client);
47
+ export const fetchChanges = (fund: string, client: Client = apiClient) => fetchFundPayload(fund, () => client.getFundChanges(fund), validateChanges, client);
31
48
  export const cachedFunds = () => cachedCloudResource(fundListCache, "list", validateFunds);
32
49
  export const loadFunds = (force = false) => loadCloudResource(fundListCache, "list", () => fetchFunds(), { force, validate: validateFunds });
33
50
  export const cachedMembers = (fund: string) => cachedCloudResource(fundMembersCache, fund, validateMembers);
@@ -15,17 +15,19 @@ export const membersHeadless: HeadlessPaneDefinition<"rows"> = {
15
15
  describe: (args) => args.rawArgument ? `MEMB ${args.rawArgument}` : "Index and ETF members",
16
16
  async load(args, context) {
17
17
  const input = args.symbols[0] ?? args.rawArgument ?? "";
18
- if (!input) return { rows: (await fetchFunds(context.apiClient)).funds.map((fund) => ({ ...fund })), columns: [{ key: "ticker", header: "Fund" }, { key: "name", header: "Index" }, { key: "asOf", header: "Holdings as of" }] };
18
+ if (!input) return { freshness: { status: "not-a-feed", basis: "fund holdings files" }, rows: (await fetchFunds(context.apiClient)).funds.map((fund) => ({ ...fund })), columns: [{ key: "ticker", header: "Fund" }, { key: "name", header: "Index" }, { key: "asOf", header: "Holdings as of" }] };
19
19
  const fund = canonicalFund(input);
20
20
  if (args.options.tab === "changes") {
21
21
  const data = await fetchChanges(fund, context.apiClient);
22
- return { rows: data.changes.map((row) => ({ ...row, reason: changeReason(row) })), columns: [{ key: "effectiveDate", header: "Effective" }, { key: "added", header: "Added" }, { key: "removed", header: "Removed" }, { key: "daysToGo", header: "In days", align: "right" }, { key: "reason", header: "Reason" }],
22
+ return { freshness: { status: "not-a-feed", basis: "index changes" }, rows: data.changes.map((row) => ({ ...row, reason: changeReason(row) })), columns: [{ key: "effectiveDate", header: "Effective" }, { key: "added", header: "Added" }, { key: "removed", header: "Removed" }, { key: "daysToGo", header: "In days", align: "right" }, { key: "reason", header: "Reason" }],
23
23
  complete: data.available && !data.stale, metadata: { ...data, changes: undefined } };
24
24
  }
25
25
  const data = await fetchMembers(fund, context.apiClient);
26
26
  const movers = args.options.tab === "movers";
27
27
  const rows = memberRows(data.members, movers ? "movers" : "members", "", DEFAULT_SORT).flatMap((row) => row.kind === "item" ? [{ ...row.item }] : []);
28
- return { rows, columns: movers ? [...columns.slice(0, 3), { key: "contribution", header: "Contrib. pp", align: "right", format: (value) => percent(value as number | null, "", 3) }] : columns,
28
+ // Member prices are the pane's 15-minute delayed quotes. As in the pane, the fund's snapshot says
29
+ // whether it is stale; the members' own flags are not what the pane reads.
30
+ return { freshness: { status: data.stale ? "stale" : "delayed", delayMinutes: 15, ignoreStaleFlags: true }, rows, columns: movers ? [...columns.slice(0, 3), { key: "contribution", header: "Contrib. pp", align: "right", format: (value) => percent(value as number | null, "", 3) }] : columns,
29
31
  complete: !data.stale && data.aggregate.fresh1D === data.aggregate.total,
30
32
  unavailableSymbols: data.members.flatMap((row) => row.symbol && row.changePercent === null ? [row.symbol] : []),
31
33
  metadata: { fund: data.fund, asOf: data.asOf, snapshotAsOf: data.snapshotAsOf, aggregate: data.aggregate, stale: data.stale } };
@@ -1,4 +1,4 @@
1
- import type { FundChange, FundMember } from "../../../api-client/members";
1
+ import type { FundChange, FundMember, MemberFundsPayload } from "../../../api-client/members";
2
2
  import type { DataTableColumn } from "../../../components";
3
3
  import { buildSectionedRows, type SectionedRow } from "../../../components/data-table/sections";
4
4
  import { getTableWidth } from "../../../components/ui/table-layout";
@@ -6,8 +6,16 @@ import { compareSortValues, type SortPreference } from "../../../utils/sort-valu
6
6
  export type MembersTab = "members" | "movers" | "changes";
7
7
  export const TABS = [{ value: "members", label: "Members" }, { value: "movers", label: "Movers" }, { value: "changes", label: "Changes" }];
8
8
  export const isTab = (value: unknown): value is MembersTab => TABS.some((tab) => tab.value === value);
9
- export const COVERED = [{ ticker: "IVV", name: "S&P 500" }, { ticker: "IJH", name: "S&P 400" }, { ticker: "IJR", name: "S&P 600" }, { ticker: "IWM", name: "Russell 2000" }, { ticker: "IWB", name: "Russell 1000" }];
9
+ const COVERED = [{ ticker: "IVV", name: "S&P 500" }, { ticker: "IJH", name: "S&P 400" }, { ticker: "IJR", name: "S&P 600" }, { ticker: "IWM", name: "Russell 2000" }, { ticker: "IWB", name: "Russell 1000" }];
10
10
  export function canonicalFund(input: string) { const symbol = input.split(":")[0]!.trim().toUpperCase(); return ["SPX", "SPY", "^GSPC"].includes(symbol) ? "IVV" : symbol; }
11
+ /** The covered fund the user asked for, by ticker or by an alias such as SPX, or undefined when it is not covered. */
12
+ export function coveredFund(funds: MemberFundsPayload["funds"], input: string) {
13
+ const symbol = canonicalFund(input);
14
+ return funds.find((fund) => fund.ticker === symbol || fund.aliases.some((alias) => alias.toUpperCase() === symbol));
15
+ }
16
+ export function notCoveredMessage(input: string, funds: MemberFundsPayload["funds"]) {
17
+ return `${input.split(":")[0]!.trim().toUpperCase()} is not a covered fund. Covered: ${funds.map((fund) => fund.ticker).join(", ")}.`;
18
+ }
11
19
  export function membersTitle(input: string) {
12
20
  const requested = input.split(":")[0]!.trim().toUpperCase();
13
21
  const fund = canonicalFund(requested);
@@ -12,7 +12,7 @@ import { Box, type ScrollBoxRenderable } from "../../../ui";
12
12
  import { nextHeaderSort, type SortPreference } from "../../../utils/sort-values";
13
13
  import { isPlainArrowUp, stopSearchFocusNavigation } from "../../../utils/search-focus-navigation";
14
14
  import { cachedChanges, cachedFunds, cachedMembers, loadChanges, loadFunds, loadMembers } from "./client";
15
- import { canonicalFund, changeColumns, changeLabel, changeReason, COVERED, decimal, DEFAULT_SORT, isTab, memberColumns, memberRows, membersTitle, percent, TABS, type MembersTab } from "./model";
15
+ import { canonicalFund, changeColumns, changeLabel, changeReason, coveredFund, decimal, DEFAULT_SORT, isTab, memberColumns, memberRows, membersTitle, notCoveredMessage, percent, TABS, type MembersTab } from "./model";
16
16
 
17
17
  type ViewProps = Pick<PaneProps, "width" | "height" | "focused"> & { fund: string; active: boolean };
18
18
  const rowKey = (row: SectionedRow<FundMember>) => row.key;
@@ -156,13 +156,20 @@ function FundPicker({ width, height, focused, choose }: Pick<PaneProps, "width"
156
156
  onActivate={(row) => choose(row.ticker)} sortColumnId={null} sortDirection="asc" renderCell={(row, col) => ({ text: String(row[col.id as "ticker"] ?? "--") })} />}
157
157
  </PaneStatusBody>;
158
158
  }
159
+ type FundPaneProps = Pick<PaneProps, "width" | "height" | "focused"> & { fund: string; requested: string };
160
+ /** The covered list is the server's, so a fund it adds opens without an app update. A list that cannot be read leaves the fund's own load to report the failure. */
161
+ function CoveredFund({ fund, requested, ...props }: FundPaneProps) {
162
+ const resource = useAsyncResource(loadFunds, { initialData: cachedFunds });
163
+ const funds = resource.data?.payload.funds;
164
+ if (funds?.length && !coveredFund(funds, fund)) return <PaneStatusBody empty emptyTitle={notCoveredMessage(requested, funds)} />;
165
+ return <FundView key={fund} fund={fund} {...props} />;
166
+ }
159
167
  export function MembersPane(props: PaneProps) {
160
168
  const { symbol } = usePaneTickerIdentity();
161
169
  const [chosen, choose] = usePluginPaneState("fund", "");
162
- const fund = canonicalFund(symbol ?? chosen);
163
- const definition = COVERED.find((item) => item.ticker === fund);
164
- usePaneTitle(membersTitle(symbol ?? chosen));
170
+ const requested = symbol ?? chosen;
171
+ const fund = canonicalFund(requested);
172
+ usePaneTitle(membersTitle(requested));
165
173
  if (!fund) return <FundPicker {...props} choose={choose} />;
166
- if (!definition) return <EmptyState title="This index or fund is not covered." hint="IVV, IJH, IJR, IWM and IWB are covered. Nasdaq-100 (NDX/QQQ) is not covered." />;
167
- return <FundView key={fund} fund={fund} {...props} />;
174
+ return <CoveredFund fund={fund} requested={requested} {...props} />;
168
175
  }
@@ -140,6 +140,7 @@ const text = (value: unknown) => (typeof value === "string" ? value : "");
140
140
 
141
141
  export const distressHeadless: HeadlessPaneDefinition<"rows"> = {
142
142
  shape: "rows",
143
+ freshness: { source: "Public filings and insolvency notices", status: "not-a-feed", basis: "filed records" },
143
144
  description: "Dated public records about companies in difficulty: US 8-K bankruptcy, obligation and listing filings, SEC going-concern disclosures, Taiwan exchange listing designations, and French and UK company insolvency notices. No scores or predictions.",
144
145
  argument: { kind: "none" },
145
146
  discovery: {
@@ -19,6 +19,7 @@ const COLUMNS: HeadlessPaneColumn[] = [
19
19
 
20
20
  export const mnaHeadless: HeadlessPaneDefinition<"rows"> = {
21
21
  shape: "rows",
22
+ freshness: { status: "not-a-feed", basis: "reported deals" },
22
23
  argument: {
23
24
  kind: "ticker",
24
25
  optional: true,
@@ -6,6 +6,7 @@ export const moneyMarketsHeadless: HeadlessPaneDefinition<"bundle"> = {
6
6
  discovery: { aliases: ["BTMM"], dataRequirements: ["Gloom Cloud money-markets endpoint"],
7
7
  limitations: ["Published daily and weekly observations", "Treasury bill discount yields", "Net liquidity is a same-date proxy"] },
8
8
  shape: "bundle", argument: { kind: "none" },
9
+ freshness: { source: "FRED", status: "not-a-feed", basis: "published daily and weekly data" },
9
10
  options: [{ key: "tab", type: "enum", description: "Money-market view.", values: [{ value: "rates" }, { value: "bills" }, { value: "liquidity" }], defaultValue: "rates" }],
10
11
  describe: "US money markets",
11
12
  async load(args, ctx) {
@@ -81,6 +81,8 @@ function projectNewsHeadless(
81
81
  return {
82
82
  asOf: now.toISOString(),
83
83
  items,
84
+ // Published stories, dated by the newest; the list is a history, so its last story is not stale data.
85
+ freshness: { status: "not-a-feed", basis: "published stories", observedKey: "publishedAt", oldest: null },
84
86
  metadata: {
85
87
  nextCursor: response.nextCursor,
86
88
  sentiment,
@@ -25,6 +25,7 @@ import { NEWS_INDUSTRY_CODES, NEWS_QUERY_PRESETS, parseNewsIndustryCode } from "
25
25
  import { createRssNewsCapability } from "./rss/source";
26
26
  import { rssCliCommand } from "./rss/cli";
27
27
  import { newsFeedHeadless } from "../headless";
28
+ import type { PaneDef } from "../../../../types/plugin";
28
29
 
29
30
  const TopPane = createNewsPresetPane({
30
31
  paneKey: "top:curated",
@@ -61,8 +62,11 @@ export const BreakingPane = createNewsPresetPane({
61
62
 
62
63
  let disposeBreakingNewsNotifications: (() => void) | null = null;
63
64
 
65
+ // A rendered news pane is a list of published stories, dated by its newest.
66
+ const NEWS_REPORT_FRESHNESS: PaneDef["reportFreshness"] = { status: "not-a-feed", basis: "published stories" };
67
+
64
68
  const newsWirePanes: PluginModule["panes"] = [
65
- { id: "news-top", name: "Top News", icon: "T", component: TopPane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 90, height: 30 } },
69
+ { id: "news-top", reportFreshness: NEWS_REPORT_FRESHNESS, name: "Top News", icon: "T", component: TopPane, defaultPosition: "right", defaultMode: "floating", defaultFloatingSize: { width: 90, height: 30 } },
66
70
  {
67
71
  id: "news-feed",
68
72
  name: "News Feed",
@@ -75,6 +79,7 @@ const newsWirePanes: PluginModule["panes"] = [
75
79
  },
76
80
  {
77
81
  id: "news-industry",
82
+ reportFreshness: NEWS_REPORT_FRESHNESS,
78
83
  name: TOPIC_NEWS_TITLE,
79
84
  icon: "S",
80
85
  component: IndustryPane,
@@ -85,6 +90,7 @@ const newsWirePanes: PluginModule["panes"] = [
85
90
  },
86
91
  {
87
92
  id: NEWS_STORY_PANE_ID,
93
+ reportFreshness: NEWS_REPORT_FRESHNESS,
88
94
  name: "Story",
89
95
  icon: "A",
90
96
  component: NewsStoryPane,
@@ -94,6 +100,7 @@ const newsWirePanes: PluginModule["panes"] = [
94
100
  },
95
101
  {
96
102
  id: "news-breaking",
103
+ reportFreshness: NEWS_REPORT_FRESHNESS,
97
104
  name: "Breaking News",
98
105
  icon: "!",
99
106
  component: BreakingPane,
@@ -2,7 +2,8 @@ import { apiClient } from "../../../api-client";
2
2
  import { withCliServices, withConfigData } from "../../../cli/scoped-context";
3
3
  import { CLI_COMMAND_GROUPS } from "../../../cli/help";
4
4
  import { dryRunNote } from "../../../cli/helpers";
5
- import { requireArg } from "../../../cli/commands/command-utils";
5
+ import { requireArg, takeOption } from "../../../cli/commands/command-utils";
6
+ import { EXCHANGE_OPTION, requireListingArg } from "../../../cli/listing-arg";
6
7
  import { createPluginPersistence } from "../../plugin-persistence";
7
8
  import type { CliCommandDef } from "../../../types/plugin";
8
9
  import { cliStyles } from "../../../utils/cli-output";
@@ -17,9 +18,16 @@ export const notesCliCommand: CliCommandDef = {
17
18
  help: {
18
19
  group: CLI_COMMAND_GROUPS.portfolios,
19
20
  usage: ["notes show <symbol>", "notes set <symbol> <text...>", "notes delete <symbol>", "notes quick list", "notes export [dir]"],
20
- examples: ["notes show AAPL", "notes set AAPL \"Services margin above 70%\"", "notes export ~/notes"],
21
+ options: [EXCHANGE_OPTION],
22
+ examples: ["notes show AAPL", "notes set AAPL \"Services margin above 70%\"", "notes show SAN:EPA", "notes export ~/notes"],
21
23
  },
22
- execute: async (args, ctx) => {
24
+ execute: async (rawArgs, ctx) => {
25
+ const args = [...rawArgs];
26
+ const exchange = takeOption(args, "--exchange");
27
+ // A note belongs to one listing: SAN:EPA, or SAN with --exchange EPA.
28
+ const noteSymbol = async (usage: string) => (
29
+ await requireListingArg(requireArg(args[1], usage, ctx), exchange, ctx)
30
+ ).key;
23
31
  await withConfigData(ctx, async (config) => {
24
32
  const notes = new NotesFiles(config.dataDir);
25
33
  const action = args[0] ?? "list";
@@ -62,14 +70,14 @@ export const notesCliCommand: CliCommandDef = {
62
70
  return;
63
71
  }
64
72
  if (action === "show") {
65
- const symbol = requireArg(args[1]?.toUpperCase(), "Usage: gloomberb notes show <symbol>", ctx);
73
+ const symbol = await noteSymbol("Usage: gloomberb notes show <symbol>");
66
74
  ctx.printResult({ data: { symbol, text: await notes.load(symbol) } }, {
67
75
  text: (data) => data.text?.trim() ? data.text.trimEnd() : cliStyles.muted(`No note for ${symbol}.`),
68
76
  });
69
77
  return;
70
78
  }
71
79
  if (action === "set") {
72
- const symbol = requireArg(args[1]?.toUpperCase(), "Usage: gloomberb notes set <symbol> <text...>", ctx);
80
+ const symbol = await noteSymbol("Usage: gloomberb notes set <symbol> <text...>");
73
81
  const text = args.slice(2).join(" ");
74
82
  if (!ctx.cliOptions.dryRun) await notes.save(symbol, text);
75
83
  ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, symbol, bytes: text.length } }, {
@@ -78,7 +86,7 @@ export const notesCliCommand: CliCommandDef = {
78
86
  return;
79
87
  }
80
88
  if (action === "delete" || action === "rm") {
81
- const symbol = requireArg(args[1]?.toUpperCase(), "Usage: gloomberb notes delete <symbol>", ctx);
89
+ const symbol = await noteSymbol("Usage: gloomberb notes delete <symbol>");
82
90
  // Only picks the message; an unreadable note is still deleted.
83
91
  const existed = await notes.load(symbol).then((text) => !!text?.trim(), () => true);
84
92
  if (!ctx.cliOptions.dryRun) await notes.delete(symbol);
@@ -79,6 +79,7 @@ export const notesPlugin: GloomPlugin = {
79
79
 
80
80
  ctx.registerPane({
81
81
  id: "quick-notes",
82
+ reportFreshness: { source: "Your notes", status: "not-a-feed", basis: "your notes" },
82
83
  name: "Notes",
83
84
  icon: "N",
84
85
  component: QuickNotesPane,
@@ -31,6 +31,7 @@ export const openFdaPlugin: GloomPlugin = {
31
31
  panes: [
32
32
  {
33
33
  id: OPENFDA_PANE_ID,
34
+ reportFreshness: { source: "US FDA", status: "not-a-feed", basis: "published reports" },
34
35
  name: "FDA Reports",
35
36
  icon: "F",
36
37
  component: OpenFdaPane,
@@ -39,6 +39,7 @@ function report(draft: OptionCalcDraft, valuation: OptionValuation | null,
39
39
  ],
40
40
  complete: valuation !== null && errors.length === 0,
41
41
  errors, unavailableSymbols: surface?.error && draft.symbol ? [draft.symbol] : [],
42
+ ...(surface ? { freshness: { source: "Your inputs and Gloom Cloud volatility" } } : {}),
42
43
  metadata: { model, inputs: draft, valuation, impliedVolatility: implied, surface, effectiveTreeSteps,
43
44
  warnings: surface?.warnings ?? [], method: model === "american" ? "CRR American tree with discrete cash dividends" : "European Black-Scholes",
44
45
  greekUnits: { delta: "underlying units per option unit", gamma: "delta per underlying price unit", theta: "currency per calendar day",
@@ -49,6 +50,7 @@ function report(draft: OptionCalcDraft, valuation: OptionValuation | null,
49
50
 
50
51
  export const optionsCalculatorHeadless: HeadlessPaneDefinition<"bundle"> = {
51
52
  shape: "bundle", argument: { kind: "none" }, describe: "OVME option valuation",
53
+ freshness: { source: "Your inputs", status: "not-a-feed", basis: "calculator" },
52
54
  discovery: { limitations: ["Discrete dividends use days from valuation and cash per underlying unit; model values exclude fees and assignment costs."] },
53
55
  options: [
54
56
  { key: "model", type: "enum", values: [{ value: "european" }, { value: "american" }], defaultValue: "european", description: "European closed form or American CRR tree" },
@@ -23,6 +23,7 @@ const gamma = (value: unknown) => formatGamma(typeof value === "number" ? value
23
23
  /** OPX opens on Strikes, GEX on its own tab; the report carries every section either way. */
24
24
  export const optionsPositioningHeadless = (initialTab: PositioningTab): HeadlessPaneDefinition<"bundle"> => ({
25
25
  shape: "bundle",
26
+ freshness: { status: "not-a-feed", basis: "daily open interest", cadence: "daily" },
26
27
  argument: { kind: "ticker", optional: true, description: "US option underlying, or SPX; SPY when omitted" },
27
28
  describe: (args) => `${initialTab === "gex" ? "GEX" : "OPX"} ${args.symbols[0] ?? "SPY"}`,
28
29
  discovery: {
@@ -59,6 +60,8 @@ export const optionsPositioningHeadless = (initialTab: PositioningTab): Headless
59
60
  ];
60
61
  const changes = openInterest.previousOiDate != null;
61
62
  return {
63
+ // Open interest is published once a day for the prior session; the spot beside it is context.
64
+ freshness: { asOf: openInterest.oiDate },
62
65
  sections: [
63
66
  { title: `Expiries · OI as of ${openInterest.oiDate ?? "--"}`, columns: [
64
67
  { key: "date", header: "Expiry" }, { key: "days", header: "Days" },
@@ -57,7 +57,12 @@ export const optionsScenarioHeadless: HeadlessPaneDefinition<"bundle"> = {
57
57
  // A seeded strategy starts at the spot its quote mids imply; the last print is reported beside it.
58
58
  const lastPrint = midVolatility && !supplied(settings.spot) && market.spot != null && money(market.spot) !== money(position!.spot)
59
59
  ? market.spot : null;
60
+ const chain = market.chain;
60
61
  return {
62
+ freshness: suppliedInputs
63
+ ? { source: "Your inputs", status: "not-a-feed", basis: "scenario" }
64
+ : { asOf: market.asOf, ...(chain?.dataSource === "live" || chain?.dataSource === "delayed" ? { status: chain.dataSource } : {}),
65
+ ...(chain?.delayMinutes ? { delayMinutes: chain.delayMinutes } : {}) },
61
66
  sections: scenario ? [
62
67
  { title: "Position", columns: [
63
68
  { key: "side", header: "Side" }, { key: "strike", header: "Strike" }, { key: "expiry", header: "Expiry" },