gloomberb 0.16.0 → 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 (691) 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 +44 -11
  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 +5 -0
  8. package/src/api-client/market-discovery.ts +10 -0
  9. package/src/api-client/members.ts +26 -0
  10. package/src/api-client/paths.ts +30 -1
  11. package/src/api-client/perps.ts +41 -0
  12. package/src/api-client/request.ts +5 -2
  13. package/src/api-client/types.ts +9 -1
  14. package/src/app/global-shortcuts.ts +14 -6
  15. package/src/app/keybindings/actions.ts +1 -1
  16. package/src/app/runtime/update.ts +38 -2
  17. package/src/app.tsx +10 -6
  18. package/src/brokers/account-cache.ts +24 -0
  19. package/src/cli/commands/command-utils.ts +8 -0
  20. package/src/cli/commands/crypto-hints.ts +75 -0
  21. package/src/cli/commands/market.ts +414 -106
  22. package/src/cli/commands/overview.ts +77 -32
  23. package/src/cli/commands/ticker.ts +101 -43
  24. package/src/cli/desktop-pane-shot.ts +34 -4
  25. package/src/cli/freshness.ts +61 -0
  26. package/src/cli/help.ts +1 -0
  27. package/src/cli/helpers.ts +4 -8
  28. package/src/cli/index.ts +12 -2
  29. package/src/cli/listing-arg.ts +321 -0
  30. package/src/cli/pane-functions/access-gate.ts +42 -0
  31. package/src/cli/pane-functions/catalog.ts +28 -1
  32. package/src/cli/pane-functions/data.ts +3 -1
  33. package/src/cli/pane-functions/dom.ts +20 -2
  34. package/src/cli/pane-functions/freshness.ts +400 -0
  35. package/src/cli/pane-functions/function-help.ts +36 -22
  36. package/src/cli/pane-functions/headless.ts +39 -11
  37. package/src/cli/pane-functions/index.ts +15 -4
  38. package/src/cli/pane-functions/options.ts +3 -0
  39. package/src/cli/pane-functions/report.ts +4 -0
  40. package/src/cli/pane-functions/resolver.ts +35 -7
  41. package/src/cli/pane-functions/screenshot-evidence.ts +2 -0
  42. package/src/cli/pane-functions/screenshot.ts +7 -3
  43. package/src/cli/result.ts +41 -27
  44. package/src/cli/ticker-resolution.ts +7 -5
  45. package/src/components/chart/composite/composite-chart.tsx +88 -2536
  46. package/src/components/chart/composite/drawing-store.ts +59 -0
  47. package/src/components/chart/composite/legend.tsx +319 -0
  48. package/src/components/chart/composite/panel-bitmap.ts +139 -0
  49. package/src/components/chart/composite/panel-gestures.ts +59 -0
  50. package/src/components/chart/composite/panel-labels.ts +107 -0
  51. package/src/components/chart/composite/panel-surface.tsx +876 -0
  52. package/src/components/chart/composite/tool-catalog.ts +98 -0
  53. package/src/components/chart/composite/toolbar.tsx +186 -0
  54. package/src/components/chart/composite/tools.ts +8 -0
  55. package/src/components/chart/composite/use-composite-chart-keyboard.ts +703 -0
  56. package/src/components/chart/composite/use-composite-viewport.ts +143 -0
  57. package/src/components/command-bar/commands/collection.ts +5 -1
  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/root/command-items.ts +9 -2
  62. package/src/components/command-bar/routes/root/plugin-install.ts +2 -2
  63. package/src/components/command-bar/routes/root/provider-search.ts +19 -5
  64. package/src/components/command-bar/routes/root/runtime.ts +14 -5
  65. package/src/components/command-bar/routes/ticker-search/actions.ts +5 -0
  66. package/src/components/command-bar/routes/ticker-search/results.ts +31 -5
  67. package/src/components/command-bar/routes/ticker-search/route.ts +2 -2
  68. package/src/components/command-bar/routing/actions.ts +2 -0
  69. package/src/components/command-bar/selection-runtime.ts +38 -0
  70. package/src/components/command-bar/surface/index.tsx +7 -2
  71. package/src/components/command-bar/workflow/ops.ts +1 -1
  72. package/src/components/command-bar/workflow/tickers.ts +6 -0
  73. package/src/components/data-table/view.tsx +29 -10
  74. package/src/components/feedback-dialog.tsx +2 -1
  75. package/src/components/form-modal/field-row.tsx +2 -2
  76. package/src/components/index.ts +2 -2
  77. package/src/components/layout/detached-pane-shell.tsx +6 -3
  78. package/src/components/layout/floating-pane.tsx +6 -0
  79. package/src/components/layout/header.tsx +24 -7
  80. package/src/components/layout/missing-pane.tsx +2 -2
  81. package/src/components/layout/pane/content.tsx +23 -10
  82. package/src/components/layout/pane/error-boundary.tsx +103 -0
  83. package/src/components/layout/pane/footer/registration.tsx +68 -23
  84. package/src/components/layout/pane/header.tsx +61 -28
  85. package/src/components/layout/pane/index.tsx +6 -0
  86. package/src/components/layout/pane/title.ts +31 -7
  87. package/src/components/layout/shell/drag/index.ts +6 -5
  88. package/src/components/layout/shell/drag/runtime.ts +3 -0
  89. package/src/components/layout/shell/index.tsx +6 -0
  90. package/src/components/layout/shell/menu.ts +2 -1
  91. package/src/components/layout/shell/pane/actions.ts +2 -1
  92. package/src/components/layout/shell/pane/layers.tsx +29 -10
  93. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -3
  94. package/src/components/layout/shell/ticker-link-menu.ts +23 -9
  95. package/src/components/metric-treemap/heat-surface.tsx +745 -0
  96. package/src/components/metric-treemap/heat-tiles.ts +228 -0
  97. package/src/components/metric-treemap/index.tsx +2 -0
  98. package/src/components/metric-treemap/layout.ts +8 -0
  99. package/src/components/metric-treemap/scene.ts +432 -0
  100. package/src/components/onboarding/onboarding-keyboard.ts +311 -0
  101. package/src/components/onboarding/onboarding-wizard.tsx +101 -788
  102. package/src/components/onboarding/use-onboarding-broker-form.ts +263 -0
  103. package/src/components/onboarding/use-onboarding-progress.ts +298 -0
  104. package/src/components/onboarding/use-onboarding-upgrade.ts +83 -0
  105. package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -0
  106. package/src/components/ticker/list-table-view.tsx +13 -1
  107. package/src/components/toggle-list.tsx +38 -12
  108. package/src/components/ui/country-flag-art.tsx +449 -0
  109. package/src/components/ui/country-flag.tsx +41 -0
  110. package/src/components/ui/data-table/types.ts +13 -0
  111. package/src/components/ui/fields.tsx +8 -0
  112. package/src/components/ui/icon.tsx +2 -0
  113. package/src/components/ui/index.ts +4 -0
  114. package/src/components/ui/multi-select/dialog.tsx +108 -22
  115. package/src/components/ui/range-track.tsx +53 -0
  116. package/src/components/ui/status.tsx +8 -2
  117. package/src/components/ui/tabs.tsx +11 -4
  118. package/src/components/ui/text-prompt-dialog.tsx +4 -2
  119. package/src/core/state/app/types.ts +10 -1
  120. package/src/data/config/store/normalize.ts +17 -1
  121. package/src/i18n/es.ts +24 -4
  122. package/src/i18n/ja.ts +24 -4
  123. package/src/i18n/ko.ts +24 -4
  124. package/src/i18n/zh-cn.ts +24 -4
  125. package/src/i18n/zh-tw.ts +24 -4
  126. package/src/layout/ticker-navigation.ts +28 -2
  127. package/src/market-data/coordinator/chart.ts +1 -1
  128. package/src/market-data/coordinator/quotes.ts +23 -4
  129. package/src/market-data/fx-closes.ts +72 -0
  130. package/src/market-data/market/freshness.ts +78 -6
  131. package/src/market-data/market/session-close-note.ts +57 -0
  132. package/src/market-data/market/status.ts +151 -0
  133. package/src/market-data/published-apac-sessions.ts +66 -0
  134. package/src/market-data/quotes/contributions.ts +8 -0
  135. package/src/market-data/quotes/freshness.ts +36 -0
  136. package/src/market-data/quotes/resolution.ts +24 -8
  137. package/src/market-data/quotes/screener-live-quotes.ts +49 -4
  138. package/src/market-data/quotes/time.ts +16 -0
  139. package/src/plugins/builtin/account-management/pane.tsx +4 -0
  140. package/src/plugins/builtin/alerts/cli.ts +10 -5
  141. package/src/plugins/builtin/alerts/index.tsx +1 -0
  142. package/src/plugins/builtin/analytics/metrics.ts +8 -3
  143. package/src/plugins/builtin/analytics/risk-client.ts +330 -79
  144. package/src/plugins/builtin/analytics/risk-fx.ts +102 -0
  145. package/src/plugins/builtin/analytics/risk-headless.ts +61 -49
  146. package/src/plugins/builtin/analytics/risk-math.ts +33 -13
  147. package/src/plugins/builtin/analytics/risk-model.ts +282 -64
  148. package/src/plugins/builtin/analytics/risk-pane.tsx +62 -30
  149. package/src/plugins/builtin/analytics/risk-test-data.ts +206 -0
  150. package/src/plugins/builtin/attention/headless.ts +6 -4
  151. package/src/plugins/builtin/attention/index.tsx +1 -1
  152. package/src/plugins/builtin/attention/pane.tsx +1 -1
  153. package/src/plugins/builtin/awards/headless.ts +1 -0
  154. package/src/plugins/builtin/awards/pane.tsx +1 -1
  155. package/src/plugins/builtin/backtest/headless.ts +1 -0
  156. package/src/plugins/builtin/bond-calculator/headless.ts +1 -0
  157. package/src/plugins/builtin/buildout/cells.tsx +15 -12
  158. package/src/plugins/builtin/buildout/detail/company.tsx +3 -3
  159. package/src/plugins/builtin/buildout/detail/index.tsx +0 -1
  160. package/src/plugins/builtin/buildout/detail/intel.tsx +6 -6
  161. package/src/plugins/builtin/buildout/detail/site.tsx +4 -7
  162. package/src/plugins/builtin/buildout/detail/ui.tsx +0 -19
  163. package/src/plugins/builtin/buildout/index.tsx +1 -0
  164. package/src/plugins/builtin/catalysts/headless.ts +3 -1
  165. package/src/plugins/builtin/catalysts/index.tsx +2 -2
  166. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  167. package/src/plugins/builtin/cds/headless.ts +2 -0
  168. package/src/plugins/builtin/cds/index.tsx +1 -0
  169. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -0
  170. package/src/plugins/builtin/chart-composer/headless.ts +38 -3
  171. package/src/plugins/builtin/chart-composer/index.tsx +3 -1
  172. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -2
  173. package/src/plugins/builtin/chat/channels.ts +19 -3
  174. package/src/plugins/builtin/chat/content/composer-runtime.ts +28 -13
  175. package/src/plugins/builtin/chat/content/footer.tsx +15 -6
  176. package/src/plugins/builtin/chat/content/index.tsx +120 -21
  177. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +261 -113
  178. package/src/plugins/builtin/chat/content/transcript.tsx +20 -2
  179. package/src/plugins/builtin/chat/direct-messages.ts +200 -0
  180. package/src/plugins/builtin/chat/index.tsx +1 -0
  181. package/src/plugins/builtin/chat/message/desktop.tsx +3 -0
  182. package/src/plugins/builtin/chat/message/header.tsx +16 -6
  183. package/src/plugins/builtin/chat/message/inline-tokens.tsx +72 -32
  184. package/src/plugins/builtin/chat/message/profile-popover.tsx +96 -12
  185. package/src/plugins/builtin/chat/message/terminal.tsx +3 -0
  186. package/src/plugins/builtin/chat/message/types.ts +14 -2
  187. package/src/plugins/builtin/chat/profile-popover.ts +18 -13
  188. package/src/plugins/builtin/clinical-trials/index.tsx +1 -0
  189. package/src/plugins/builtin/cloud/askg/executor.ts +2 -1
  190. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  191. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  192. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  193. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  194. package/src/plugins/builtin/comment-letters/index.tsx +1 -0
  195. package/src/plugins/builtin/company-attention/headless.ts +5 -1
  196. package/src/plugins/builtin/company-attention/pane.tsx +1 -1
  197. package/src/plugins/builtin/company-kpis/headless.ts +1 -0
  198. package/src/plugins/builtin/congress-trades/headless.ts +1 -0
  199. package/src/plugins/builtin/correlation/compute.ts +59 -16
  200. package/src/plugins/builtin/correlation/geo.ts +34 -0
  201. package/src/plugins/builtin/correlation/headless-schema.ts +4 -1
  202. package/src/plugins/builtin/correlation/headless.ts +42 -8
  203. package/src/plugins/builtin/correlation/history.ts +2 -0
  204. package/src/plugins/builtin/correlation/index.tsx +68 -14
  205. package/src/plugins/builtin/correlation/matrix/model.ts +17 -2
  206. package/src/plugins/builtin/correlation/matrix/selection.ts +5 -3
  207. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  208. package/src/plugins/builtin/correlation/relationship/pane.tsx +4 -2
  209. package/src/plugins/builtin/correlation/relationship/view-model.ts +16 -1
  210. package/src/plugins/builtin/correlation/settings.ts +1 -1
  211. package/src/plugins/builtin/cot/headless.ts +6 -3
  212. package/src/plugins/builtin/cot/index.tsx +3 -3
  213. package/src/plugins/builtin/cot/model.ts +36 -3
  214. package/src/plugins/builtin/cpi/headless.ts +4 -0
  215. package/src/plugins/builtin/credit-boards/headless.ts +2 -0
  216. package/src/plugins/builtin/credit-conditions/headless.ts +1 -0
  217. package/src/plugins/builtin/credit-documents/gauge.tsx +5 -8
  218. package/src/plugins/builtin/credit-documents/headless.ts +2 -0
  219. package/src/plugins/builtin/crypto-board/headless.ts +3 -0
  220. package/src/plugins/builtin/custom-view/loader.ts +1 -1
  221. package/src/plugins/builtin/debt-maturities/headless.ts +4 -0
  222. package/src/plugins/builtin/debt-maturities/wall-bar.tsx +14 -41
  223. package/src/plugins/builtin/dividend-yield/client.ts +4 -2
  224. package/src/plugins/builtin/dividend-yield/headless.ts +1 -0
  225. package/src/plugins/builtin/doe/headless.ts +7 -0
  226. package/src/plugins/builtin/doe/range-bar.tsx +7 -37
  227. package/src/plugins/builtin/earnings/client.ts +2 -2
  228. package/src/plugins/builtin/earnings/headless.ts +5 -0
  229. package/src/plugins/builtin/earnings-calls/headless.ts +1 -0
  230. package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
  231. package/src/plugins/builtin/earnings-ripple/client.ts +91 -18
  232. package/src/plugins/builtin/earnings-ripple/headless.ts +28 -8
  233. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -2
  234. package/src/plugins/builtin/earnings-ripple/model.ts +97 -7
  235. package/src/plugins/builtin/earnings-ripple/pane.tsx +148 -23
  236. package/src/plugins/builtin/econ/index.tsx +1 -0
  237. package/src/plugins/builtin/econ-statistics/headless.ts +2 -0
  238. package/src/plugins/builtin/equity-screener/headless.ts +2 -0
  239. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  240. package/src/plugins/builtin/executives/index.tsx +1 -0
  241. package/src/plugins/builtin/exposure/headless.ts +3 -1
  242. package/src/plugins/builtin/fear-greed/headless.ts +2 -0
  243. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  244. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  245. package/src/plugins/builtin/futures-curve/headless.ts +39 -10
  246. package/src/plugins/builtin/futures-curve/index.tsx +3 -3
  247. package/src/plugins/builtin/futures-curve/model.ts +188 -4
  248. package/src/plugins/builtin/futures-curve/pane.tsx +51 -9
  249. package/src/plugins/builtin/fx-matrix/direction.ts +81 -0
  250. package/src/plugins/builtin/fx-matrix/index.tsx +71 -33
  251. package/src/plugins/builtin/fx-matrix/live-legs.ts +17 -0
  252. package/src/plugins/builtin/fx-matrix/pairs.ts +68 -14
  253. package/src/plugins/builtin/fx-matrix/settings.ts +62 -0
  254. package/src/plugins/builtin/gpu/headless.ts +7 -3
  255. package/src/plugins/builtin/gpu/ladder.tsx +26 -30
  256. package/src/plugins/builtin/gpu/model.ts +27 -1
  257. package/src/plugins/builtin/holders/beneficial-client.ts +209 -0
  258. package/src/plugins/builtin/holders/beneficial-model.ts +279 -0
  259. package/src/plugins/builtin/holders/beneficial-report.ts +126 -0
  260. package/src/plugins/builtin/holders/beneficial-view.tsx +241 -0
  261. package/src/plugins/builtin/holders/headless.ts +139 -5
  262. package/src/plugins/builtin/holders/index.tsx +10 -3
  263. package/src/plugins/builtin/holders/pane.tsx +20 -3
  264. package/src/plugins/builtin/holders/report-header.ts +95 -0
  265. package/src/plugins/builtin/holders/table-model.ts +20 -5
  266. package/src/plugins/builtin/holders/thirteenf-match.ts +29 -1
  267. package/src/plugins/builtin/holders/types.ts +2 -1
  268. package/src/plugins/builtin/insider/headless.ts +2 -0
  269. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -0
  270. package/src/plugins/builtin/iv-history/headless.ts +4 -1
  271. package/src/plugins/builtin/jobs/headless.ts +1 -0
  272. package/src/plugins/builtin/jobs/index.tsx +1 -0
  273. package/src/plugins/builtin/jobs/share-bars.tsx +5 -28
  274. package/src/plugins/builtin/kelly-sizer/index.tsx +1 -0
  275. package/src/plugins/builtin/macro-day/headless.ts +2 -0
  276. package/src/plugins/builtin/market-halts/index.tsx +1 -0
  277. package/src/plugins/builtin/market-heatmap/data.ts +30 -2
  278. package/src/plugins/builtin/market-heatmap/headless.ts +135 -0
  279. package/src/plugins/builtin/market-heatmap/index.tsx +245 -81
  280. package/src/plugins/builtin/market-heatmap/live.ts +88 -0
  281. package/src/plugins/builtin/market-heatmap/model.ts +146 -0
  282. package/src/plugins/builtin/market-heatmap/portfolio.ts +50 -11
  283. package/src/plugins/builtin/market-movers/client.ts +3 -2
  284. package/src/plugins/builtin/market-movers/headless.ts +10 -1
  285. package/src/plugins/builtin/market-movers/screener.ts +18 -5
  286. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  287. package/src/plugins/builtin/members/client.ts +53 -0
  288. package/src/plugins/builtin/members/headless.ts +35 -0
  289. package/src/plugins/builtin/members/index.tsx +20 -0
  290. package/src/plugins/builtin/members/model.ts +68 -0
  291. package/src/plugins/builtin/members/pane.tsx +175 -0
  292. package/src/plugins/builtin/mna/distress/headless.ts +1 -0
  293. package/src/plugins/builtin/mna/headless.ts +1 -0
  294. package/src/plugins/builtin/mna/index.tsx +2 -1
  295. package/src/plugins/builtin/mna/pane.tsx +5 -2
  296. package/src/plugins/builtin/money-markets/headless.ts +1 -0
  297. package/src/plugins/builtin/news/headless.ts +2 -0
  298. package/src/plugins/builtin/news/wire/index.tsx +8 -1
  299. package/src/plugins/builtin/notes/cli.ts +14 -6
  300. package/src/plugins/builtin/notes/index.tsx +1 -0
  301. package/src/plugins/builtin/openfda/index.tsx +1 -0
  302. package/src/plugins/builtin/options/index.tsx +2 -1
  303. package/src/plugins/builtin/options-calculator/headless.ts +2 -0
  304. package/src/plugins/builtin/options-positioning/headless.ts +3 -0
  305. package/src/plugins/builtin/options-scenario/headless.ts +5 -0
  306. package/src/plugins/builtin/pe-band/client.ts +74 -2
  307. package/src/plugins/builtin/pe-band/headless.ts +26 -8
  308. package/src/plugins/builtin/pe-band/model.ts +102 -22
  309. package/src/plugins/builtin/pe-band/pane.tsx +34 -16
  310. package/src/plugins/builtin/pe-band/report-dates.ts +78 -0
  311. package/src/plugins/builtin/perps/client.ts +66 -5
  312. package/src/plugins/builtin/perps/equity-identity.ts +16 -0
  313. package/src/plugins/builtin/perps/equity-row.tsx +6 -4
  314. package/src/plugins/builtin/perps/headless.ts +144 -16
  315. package/src/plugins/builtin/perps/index.tsx +6 -6
  316. package/src/plugins/builtin/perps/model.ts +189 -12
  317. package/src/plugins/builtin/perps/pane.tsx +248 -47
  318. package/src/plugins/builtin/plugin-marketplace/activation.ts +19 -0
  319. package/src/plugins/builtin/plugin-marketplace/pane.tsx +2 -2
  320. package/src/plugins/builtin/plugin-marketplace/store.ts +2 -0
  321. package/src/plugins/builtin/portfolio-list/allocation.ts +245 -0
  322. package/src/plugins/builtin/portfolio-list/cached-account.ts +33 -0
  323. package/src/plugins/builtin/portfolio-list/cell-version.ts +19 -1
  324. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +328 -29
  325. package/src/plugins/builtin/portfolio-list/cli/render.ts +230 -39
  326. package/src/plugins/builtin/portfolio-list/cli/shared.ts +67 -2
  327. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +35 -31
  328. package/src/plugins/builtin/portfolio-list/column-values.ts +124 -47
  329. package/src/plugins/builtin/portfolio-list/headless.ts +98 -16
  330. package/src/plugins/builtin/portfolio-list/index.tsx +14 -3
  331. package/src/plugins/builtin/portfolio-list/live-valuation.ts +7 -5
  332. package/src/plugins/builtin/portfolio-list/mutations.ts +55 -1
  333. package/src/plugins/builtin/portfolio-list/pane/data.ts +6 -0
  334. package/src/plugins/builtin/portfolio-list/pane/index.tsx +47 -13
  335. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +43 -2
  336. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +48 -5
  337. package/src/plugins/builtin/portfolio-list/settings.ts +33 -2
  338. package/src/plugins/builtin/portfolio-list/summary/index.tsx +24 -1
  339. package/src/plugins/builtin/portfolio-list/summary/totals.ts +26 -7
  340. package/src/plugins/builtin/power/headless.ts +3 -1
  341. package/src/plugins/builtin/rate-path/headless.ts +2 -0
  342. package/src/plugins/builtin/realized-vol/headless.ts +2 -0
  343. package/src/plugins/builtin/relative-rotation/headless.ts +2 -0
  344. package/src/plugins/builtin/research/analyst-headless.ts +3 -0
  345. package/src/plugins/builtin/research/events-headless.ts +2 -0
  346. package/src/plugins/builtin/research/headless.ts +2 -0
  347. package/src/plugins/builtin/research/index.tsx +1 -0
  348. package/src/plugins/builtin/research/relative-valuation-headless.ts +10 -5
  349. package/src/plugins/builtin/research/relative-valuation-model.ts +11 -3
  350. package/src/plugins/builtin/research/relative-valuation-pane.tsx +3 -3
  351. package/src/plugins/builtin/research-search/index.tsx +1 -0
  352. package/src/plugins/builtin/revenue-breakdown/headless.ts +2 -0
  353. package/src/plugins/builtin/reverse-dcf/headless.ts +2 -0
  354. package/src/plugins/builtin/risk-factors/headless.ts +2 -0
  355. package/src/plugins/builtin/scanner/flow-history.ts +2 -13
  356. package/src/plugins/builtin/scanner/headless.ts +14 -0
  357. package/src/plugins/builtin/scanner/hilo-bars.tsx +12 -70
  358. package/src/plugins/builtin/scanner/hilo-model.ts +0 -18
  359. package/src/plugins/builtin/seasonality/headless.ts +2 -0
  360. package/src/plugins/builtin/sec/command-bar-search.ts +14 -4
  361. package/src/plugins/builtin/sec/filing-content.ts +42 -17
  362. package/src/plugins/builtin/sec/forms.ts +12 -0
  363. package/src/plugins/builtin/sec/headless.ts +2 -0
  364. package/src/plugins/builtin/sectors/client.ts +1 -0
  365. package/src/plugins/builtin/sectors/headless.ts +9 -1
  366. package/src/plugins/builtin/sectors/move-bar.tsx +10 -32
  367. package/src/plugins/builtin/sectors/sector-model.ts +2 -0
  368. package/src/plugins/builtin/shared/crypto-pair.ts +14 -0
  369. package/src/plugins/builtin/shared/locked-rows.tsx +1 -1
  370. package/src/plugins/builtin/shared/report-freshness.ts +57 -0
  371. package/src/plugins/builtin/shared/research-cells.tsx +4 -9
  372. package/src/plugins/builtin/short-interest/headless.ts +2 -0
  373. package/src/plugins/builtin/short-interest/watch-headless.ts +1 -0
  374. package/src/plugins/builtin/short-volume/headless.ts +1 -0
  375. package/src/plugins/builtin/social-mentions/headless.ts +1 -0
  376. package/src/plugins/builtin/social-mentions/index.tsx +1 -1
  377. package/src/plugins/builtin/supply-chain/headless.ts +7 -1
  378. package/src/plugins/builtin/supply-chain/index.tsx +10 -1
  379. package/src/plugins/builtin/supply-chain/model.ts +27 -2
  380. package/src/plugins/builtin/supply-chain/pane.tsx +71 -32
  381. package/src/plugins/builtin/themes/headless.ts +3 -0
  382. package/src/plugins/builtin/thirteenf/headless.ts +110 -25
  383. package/src/plugins/builtin/thirteenf/index.tsx +2 -1
  384. package/src/plugins/builtin/thirteenf/report-notes.ts +149 -0
  385. package/src/plugins/builtin/ticker-detail/headless.ts +7 -1
  386. package/src/plugins/builtin/ticker-detail/index.tsx +1 -0
  387. package/src/plugins/builtin/ticker-detail/overview/components.tsx +5 -60
  388. package/src/plugins/builtin/ticker-detail/overview/model.ts +9 -2
  389. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +1 -1
  390. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +26 -26
  391. package/src/plugins/builtin/ticker-detail/pane.tsx +1 -1
  392. package/src/plugins/builtin/ticker-detail/quote-footer.ts +7 -1
  393. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +20 -4
  394. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +2 -2
  395. package/src/plugins/builtin/time-sales/headless.ts +5 -1
  396. package/src/plugins/builtin/treasury-auctions/headless.ts +1 -0
  397. package/src/plugins/builtin/vol-surface/index.tsx +1 -1
  398. package/src/plugins/builtin/volatility/headless.ts +6 -1
  399. package/src/plugins/builtin/world-indices/headless.ts +2 -0
  400. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +157 -0
  401. package/src/plugins/builtin/world-venue-map/basemap.ts +214 -0
  402. package/src/plugins/builtin/world-venue-map/client.ts +45 -0
  403. package/src/plugins/builtin/world-venue-map/entity-detail.tsx +147 -0
  404. package/src/plugins/builtin/world-venue-map/entity-table.ts +59 -0
  405. package/src/plugins/builtin/world-venue-map/evidence.ts +77 -0
  406. package/src/plugins/builtin/world-venue-map/feed.ts +293 -0
  407. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +248 -0
  408. package/src/plugins/builtin/world-venue-map/geo-series.ts +142 -0
  409. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +447 -0
  410. package/src/plugins/builtin/world-venue-map/headless.ts +146 -0
  411. package/src/plugins/builtin/world-venue-map/ids.ts +1 -0
  412. package/src/plugins/builtin/world-venue-map/index.ts +67 -4
  413. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +552 -0
  414. package/src/plugins/builtin/world-venue-map/layers.ts +348 -0
  415. package/src/plugins/builtin/world-venue-map/map-symbols.ts +220 -0
  416. package/src/plugins/builtin/world-venue-map/map.tsx +381 -45
  417. package/src/plugins/builtin/world-venue-map/model.ts +7 -4
  418. package/src/plugins/builtin/world-venue-map/natural-earth/index.chunk.ts +199 -0
  419. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n00.chunk.ts +4 -0
  420. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n15.chunk.ts +4 -0
  421. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n30.chunk.ts +4 -0
  422. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n45.chunk.ts +4 -0
  423. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n60.chunk.ts +4 -0
  424. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000n75.chunk.ts +4 -0
  425. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s15.chunk.ts +4 -0
  426. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s30.chunk.ts +4 -0
  427. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e000s60.chunk.ts +4 -0
  428. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n00.chunk.ts +4 -0
  429. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n15.chunk.ts +4 -0
  430. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n30.chunk.ts +4 -0
  431. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n45.chunk.ts +4 -0
  432. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n60.chunk.ts +4 -0
  433. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015n75.chunk.ts +4 -0
  434. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s15.chunk.ts +4 -0
  435. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s30.chunk.ts +4 -0
  436. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e015s45.chunk.ts +4 -0
  437. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n00.chunk.ts +4 -0
  438. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n15.chunk.ts +4 -0
  439. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n30.chunk.ts +4 -0
  440. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n45.chunk.ts +4 -0
  441. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n60.chunk.ts +4 -0
  442. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030n75.chunk.ts +4 -0
  443. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s15.chunk.ts +4 -0
  444. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s30.chunk.ts +4 -0
  445. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s45.chunk.ts +4 -0
  446. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e030s60.chunk.ts +4 -0
  447. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n00.chunk.ts +4 -0
  448. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n15.chunk.ts +4 -0
  449. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n30.chunk.ts +4 -0
  450. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n45.chunk.ts +4 -0
  451. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n60.chunk.ts +4 -0
  452. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045n75.chunk.ts +4 -0
  453. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s15.chunk.ts +4 -0
  454. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s30.chunk.ts +4 -0
  455. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e045s60.chunk.ts +4 -0
  456. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n00.chunk.ts +4 -0
  457. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n15.chunk.ts +4 -0
  458. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n30.chunk.ts +4 -0
  459. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n45.chunk.ts +4 -0
  460. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n60.chunk.ts +4 -0
  461. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060n75.chunk.ts +4 -0
  462. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s15.chunk.ts +4 -0
  463. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s30.chunk.ts +4 -0
  464. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e060s60.chunk.ts +4 -0
  465. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n00.chunk.ts +4 -0
  466. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n15.chunk.ts +4 -0
  467. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n30.chunk.ts +4 -0
  468. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n45.chunk.ts +4 -0
  469. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n60.chunk.ts +4 -0
  470. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075n75.chunk.ts +4 -0
  471. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e075s45.chunk.ts +4 -0
  472. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n00.chunk.ts +4 -0
  473. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n15.chunk.ts +4 -0
  474. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n30.chunk.ts +4 -0
  475. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n45.chunk.ts +4 -0
  476. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n60.chunk.ts +4 -0
  477. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090n75.chunk.ts +4 -0
  478. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e090s15.chunk.ts +4 -0
  479. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n00.chunk.ts +4 -0
  480. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n15.chunk.ts +4 -0
  481. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n30.chunk.ts +4 -0
  482. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n45.chunk.ts +4 -0
  483. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n60.chunk.ts +4 -0
  484. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105n75.chunk.ts +4 -0
  485. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s15.chunk.ts +4 -0
  486. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s30.chunk.ts +4 -0
  487. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e105s45.chunk.ts +4 -0
  488. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n00.chunk.ts +4 -0
  489. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n15.chunk.ts +4 -0
  490. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n30.chunk.ts +4 -0
  491. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n45.chunk.ts +4 -0
  492. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120n60.chunk.ts +4 -0
  493. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s15.chunk.ts +4 -0
  494. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s30.chunk.ts +4 -0
  495. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e120s45.chunk.ts +4 -0
  496. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n00.chunk.ts +4 -0
  497. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n15.chunk.ts +4 -0
  498. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n30.chunk.ts +4 -0
  499. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n45.chunk.ts +4 -0
  500. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n60.chunk.ts +4 -0
  501. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135n75.chunk.ts +4 -0
  502. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s15.chunk.ts +4 -0
  503. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s30.chunk.ts +4 -0
  504. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e135s45.chunk.ts +4 -0
  505. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n00.chunk.ts +4 -0
  506. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n15.chunk.ts +4 -0
  507. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n45.chunk.ts +4 -0
  508. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n60.chunk.ts +4 -0
  509. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150n75.chunk.ts +4 -0
  510. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s15.chunk.ts +4 -0
  511. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s30.chunk.ts +4 -0
  512. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s45.chunk.ts +4 -0
  513. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e150s60.chunk.ts +4 -0
  514. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n00.chunk.ts +4 -0
  515. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n15.chunk.ts +4 -0
  516. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n45.chunk.ts +4 -0
  517. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165n60.chunk.ts +4 -0
  518. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s15.chunk.ts +4 -0
  519. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s30.chunk.ts +4 -0
  520. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s45.chunk.ts +4 -0
  521. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/e165s60.chunk.ts +4 -0
  522. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n00.chunk.ts +4 -0
  523. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n15.chunk.ts +4 -0
  524. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n30.chunk.ts +4 -0
  525. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n45.chunk.ts +4 -0
  526. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n60.chunk.ts +4 -0
  527. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015n75.chunk.ts +4 -0
  528. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s15.chunk.ts +4 -0
  529. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s30.chunk.ts +4 -0
  530. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w015s45.chunk.ts +4 -0
  531. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n00.chunk.ts +4 -0
  532. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n15.chunk.ts +4 -0
  533. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n30.chunk.ts +4 -0
  534. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n60.chunk.ts +4 -0
  535. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030n75.chunk.ts +4 -0
  536. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s30.chunk.ts +4 -0
  537. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w030s60.chunk.ts +4 -0
  538. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n30.chunk.ts +4 -0
  539. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n45.chunk.ts +4 -0
  540. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n60.chunk.ts +4 -0
  541. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045n75.chunk.ts +4 -0
  542. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s15.chunk.ts +4 -0
  543. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s30.chunk.ts +4 -0
  544. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w045s60.chunk.ts +4 -0
  545. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n00.chunk.ts +4 -0
  546. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n30.chunk.ts +4 -0
  547. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n45.chunk.ts +4 -0
  548. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n60.chunk.ts +4 -0
  549. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060n75.chunk.ts +4 -0
  550. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s15.chunk.ts +4 -0
  551. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s30.chunk.ts +4 -0
  552. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s45.chunk.ts +4 -0
  553. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w060s60.chunk.ts +4 -0
  554. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n00.chunk.ts +4 -0
  555. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n15.chunk.ts +4 -0
  556. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n30.chunk.ts +4 -0
  557. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n45.chunk.ts +4 -0
  558. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n60.chunk.ts +4 -0
  559. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075n75.chunk.ts +4 -0
  560. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s15.chunk.ts +4 -0
  561. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s30.chunk.ts +4 -0
  562. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s45.chunk.ts +4 -0
  563. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w075s60.chunk.ts +4 -0
  564. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n00.chunk.ts +4 -0
  565. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n15.chunk.ts +4 -0
  566. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n30.chunk.ts +4 -0
  567. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n45.chunk.ts +4 -0
  568. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n60.chunk.ts +4 -0
  569. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090n75.chunk.ts +4 -0
  570. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s15.chunk.ts +4 -0
  571. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s30.chunk.ts +4 -0
  572. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s45.chunk.ts +4 -0
  573. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w090s60.chunk.ts +4 -0
  574. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n00.chunk.ts +4 -0
  575. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n15.chunk.ts +4 -0
  576. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n30.chunk.ts +4 -0
  577. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n45.chunk.ts +4 -0
  578. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n60.chunk.ts +4 -0
  579. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105n75.chunk.ts +4 -0
  580. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w105s15.chunk.ts +4 -0
  581. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n00.chunk.ts +4 -0
  582. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n15.chunk.ts +4 -0
  583. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n30.chunk.ts +4 -0
  584. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n45.chunk.ts +4 -0
  585. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n60.chunk.ts +4 -0
  586. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120n75.chunk.ts +4 -0
  587. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w120s30.chunk.ts +4 -0
  588. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n30.chunk.ts +4 -0
  589. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n45.chunk.ts +4 -0
  590. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n60.chunk.ts +4 -0
  591. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135n75.chunk.ts +4 -0
  592. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w135s30.chunk.ts +4 -0
  593. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n45.chunk.ts +4 -0
  594. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150n60.chunk.ts +4 -0
  595. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s15.chunk.ts +4 -0
  596. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w150s30.chunk.ts +4 -0
  597. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n00.chunk.ts +4 -0
  598. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n15.chunk.ts +4 -0
  599. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n45.chunk.ts +4 -0
  600. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165n60.chunk.ts +4 -0
  601. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s15.chunk.ts +4 -0
  602. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w165s30.chunk.ts +4 -0
  603. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n00.chunk.ts +4 -0
  604. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n15.chunk.ts +4 -0
  605. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n45.chunk.ts +4 -0
  606. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180n60.chunk.ts +4 -0
  607. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s15.chunk.ts +4 -0
  608. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s30.chunk.ts +4 -0
  609. package/src/plugins/builtin/world-venue-map/natural-earth/tiles/w180s45.chunk.ts +4 -0
  610. package/src/plugins/builtin/world-venue-map/natural-earth/world-50m.chunk.ts +4 -0
  611. package/src/plugins/builtin/world-venue-map/pane.tsx +28 -43
  612. package/src/plugins/builtin/world-venue-map/use-geo.ts +55 -0
  613. package/src/plugins/builtin/world-venue-map/venue-header.tsx +32 -0
  614. package/src/plugins/builtin/yield-curve/headless.ts +16 -0
  615. package/src/plugins/catalog-browser.ts +2 -0
  616. package/src/plugins/catalog-manifest.ts +1 -0
  617. package/src/plugins/catalog-ui.ts +3 -1
  618. package/src/plugins/catalog.ts +1 -1
  619. package/src/plugins/host-link.ts +33 -1
  620. package/src/plugins/installer.ts +48 -12
  621. package/src/plugins/loader.ts +30 -3
  622. package/src/plugins/manager-node.ts +15 -5
  623. package/src/plugins/registry/index.ts +1 -1
  624. package/src/plugins/registry/pane-settings.ts +26 -7
  625. package/src/public/__snapshots__/public-api.test.ts.snap +2 -0
  626. package/src/renderers/dom/build-assets.ts +81 -3
  627. package/src/renderers/dom/data-table/row.tsx +52 -16
  628. package/src/renderers/dom/desktop/controls.tsx +7 -3
  629. package/src/renderers/dom/desktop/icons.tsx +1 -0
  630. package/src/renderers/dom/desktop/list-view.tsx +35 -10
  631. package/src/renderers/dom/desktop/popover.tsx +73 -14
  632. package/src/renderers/dom/host/box.tsx +69 -26
  633. package/src/renderers/dom/host/input.tsx +14 -3
  634. package/src/renderers/dom/host/tabs.tsx +37 -1
  635. package/src/renderers/dom/styles.css +41 -7
  636. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +11 -6
  637. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -0
  638. package/src/renderers/electrobun/bun/desktop/update.ts +181 -87
  639. package/src/renderers/electrobun/bun/index.ts +73 -6
  640. package/src/renderers/electrobun/bun/window/remembered-frame.ts +122 -0
  641. package/src/renderers/electrobun/shared/protocol.ts +3 -0
  642. package/src/renderers/electrobun/view/backend-rpc.ts +10 -4
  643. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +3 -1
  644. package/src/renderers/electrobun/view/main.tsx +7 -1
  645. package/src/renderers/electrobun/view/renderer-window-error.ts +18 -0
  646. package/src/renderers/electrobun/view/rpc-timeout.ts +14 -3
  647. package/src/renderers/electrobun/view/update-host.ts +45 -21
  648. package/src/renderers/opentui/host.tsx +5 -0
  649. package/src/sources/gloomberb-cloud/index.ts +25 -4
  650. package/src/sources/gloomberb-cloud/normalizers.ts +36 -5
  651. package/src/sources/provider-router/cached-routes.ts +4 -1
  652. package/src/sources/provider-router/financials.ts +11 -8
  653. package/src/sources/provider-router/history.ts +15 -10
  654. package/src/sources/sec-registrant.ts +75 -0
  655. package/src/state/app/context/index.tsx +24 -8
  656. package/src/state/hooks/quote-streaming.ts +41 -26
  657. package/src/sync/core-contributors.ts +4 -0
  658. package/src/telemetry/benign-window-error.ts +7 -0
  659. package/src/telemetry/crash-reports-dom.ts +2 -0
  660. package/src/telemetry/crash-reports.ts +4 -1
  661. package/src/test-support/cli-context.ts +10 -2
  662. package/src/test-support/daily-nav.ts +25 -0
  663. package/src/theme/heat-colors.ts +357 -2
  664. package/src/tickers/instrument-kind.ts +34 -7
  665. package/src/tickers/search/asset-classes.ts +24 -9
  666. package/src/tickers/search/index.ts +44 -11
  667. package/src/tickers/search/ranking.ts +23 -3
  668. package/src/time-series/resolve.ts +1 -1
  669. package/src/time-series/use-chart-resolution.ts +1 -1
  670. package/src/types/context-menu.ts +6 -0
  671. package/src/types/data-provider.ts +2 -0
  672. package/src/types/financials.ts +5 -0
  673. package/src/types/headless.ts +79 -2
  674. package/src/types/plugin.ts +38 -6
  675. package/src/types/ticker.ts +15 -0
  676. package/src/ui/context-menu.tsx +1 -0
  677. package/src/ui/host.tsx +16 -0
  678. package/src/updater/index.ts +38 -13
  679. package/src/utils/async-deadline.ts +21 -0
  680. package/src/utils/cli-output.ts +5 -1
  681. package/src/utils/crypto-pair.ts +41 -0
  682. package/src/utils/currency-units.ts +14 -0
  683. package/src/utils/depositary-receipt.ts +26 -0
  684. package/src/utils/exchanges.ts +72 -0
  685. package/src/utils/fire-and-forget.ts +24 -0
  686. package/src/utils/format.ts +13 -0
  687. package/src/utils/price-earnings.ts +70 -3
  688. package/src/utils/price-history.ts +58 -13
  689. package/src/utils/rpc-timeout-error.ts +27 -0
  690. package/src/utils/sec.ts +13 -1
  691. package/src/utils/utc-time.ts +79 -0
@@ -1,5 +1,7 @@
1
1
  import type { MarketState, Quote } from "../../types/financials";
2
2
  import { blendHex, colors, priceColor, type ThemeColors } from "../../theme/colors";
3
+ import { isFiniteNumber } from "../../utils/guards";
4
+ import { quoteTradingDay } from "../quotes/day-range";
3
5
 
4
6
  const CLOSED_CHANGE_MUTING_RATIO = 0.55;
5
7
  const US_SESSION_TIME = new Intl.DateTimeFormat("en-US", {
@@ -20,6 +22,12 @@ export interface ActiveQuoteDisplay {
20
22
  changePercent?: number;
21
23
  }
22
24
 
25
+ export type ExtendedSession = "PRE" | "POST";
26
+
27
+ export interface ExtendedSessionDisplay extends ActiveQuoteDisplay {
28
+ session: ExtendedSession;
29
+ }
30
+
23
31
  export function marketStateLabel(state: MarketState): string {
24
32
  switch (state) {
25
33
  case "PRE": return "PRE-MKT";
@@ -124,6 +132,11 @@ export function exchangeShortName(exchangeName?: string, fullExchangeName?: stri
124
132
  return map[name] || name;
125
133
  }
126
134
 
135
+ /**
136
+ * The live print against the daily reference, extended hours included: what
137
+ * a position is worth now and its day P&L. A headline that shows an
138
+ * extended-hours line beside it uses getRegularSessionDisplay instead.
139
+ */
127
140
  export function getActiveQuoteDisplay(quote: Quote | null | undefined): ActiveQuoteDisplay | null {
128
141
  if (!quote) return null;
129
142
  if ((quote.marketState === "PRE" || quote.marketState === "PREPRE") && quote.preMarketPrice != null) {
@@ -141,3 +154,141 @@ export function getActiveQuoteDisplay(quote: Quote | null | undefined): ActiveQu
141
154
  }
142
155
  return { price: quote.price, change: quote.change, changePercent: quote.changePercent };
143
156
  }
157
+
158
+ function isPositive(value: number | undefined): value is number {
159
+ return isFiniteNumber(value) && value > 0;
160
+ }
161
+
162
+ interface CompletedRegularSession {
163
+ close: number;
164
+ /** The close's move from the session before it, when the quote reports it with the close. */
165
+ reported: { change: number; changePercent: number } | null;
166
+ }
167
+
168
+ function reportedRegularMove(quote: Quote, close: number): CompletedRegularSession["reported"] {
169
+ const change = quote.regularChange;
170
+ if (!isFiniteNumber(change)) return null;
171
+ const reference = close - change;
172
+ const changePercent = isFiniteNumber(quote.regularChangePercent)
173
+ ? quote.regularChangePercent
174
+ : isPositive(reference) ? (change / reference) * 100 : null;
175
+ return changePercent == null ? null : { change, changePercent };
176
+ }
177
+
178
+ /**
179
+ * The regular session the quote's day follows, once it is over: after hours,
180
+ * overnight, and through a weekend or holiday until the next pre-market, and
181
+ * in the pre-market when the quote reports the last session's close and move,
182
+ * which its own previous close can no longer give once the day has rolled.
183
+ * Only a US listing with extended trading reports one. Without a reported
184
+ * close, an after-hours print less its move from the close gives it. Null in
185
+ * the regular session.
186
+ */
187
+ function completedRegularSession(quote: Quote): CompletedRegularSession | null {
188
+ const state = quote.marketState;
189
+ if (state == null || state === "REGULAR") return null;
190
+ const close = quote.regularClose;
191
+ if (isPositive(close)) {
192
+ const closeDate = quote.regularCloseSessionDate;
193
+ const reported = reportedRegularMove(quote, close);
194
+ if (state === "PRE") {
195
+ // The quote's own day is today; the close must be an earlier one, with its move.
196
+ const today = quoteTradingDay(quote);
197
+ return reported && closeDate && today && closeDate < today ? { close, reported } : null;
198
+ }
199
+ if (closeDate ? closeDate === quoteTradingDay(quote) : state === "POST") return { close, reported };
200
+ }
201
+ if (state === "POST" && isFiniteNumber(quote.postMarketPrice) && isFiniteNumber(quote.postMarketChange)) {
202
+ const derived = quote.postMarketPrice - quote.postMarketChange;
203
+ if (derived > 0) return { close: derived, reported: null };
204
+ }
205
+ return null;
206
+ }
207
+
208
+ function completedRegularClose(quote: Quote): number | null {
209
+ return completedRegularSession(quote)?.close ?? null;
210
+ }
211
+
212
+ /**
213
+ * The day's headline: the regular session, which stops at its close. Once it
214
+ * is over, and in the pre-market while the quote carries the last session's
215
+ * close and move, the price is that close and the move is its own, so
216
+ * extended trading never moves it; the extended print is
217
+ * getExtendedSessionDisplay. A close without its reported move is measured
218
+ * against the previous close. In the pre-market without that close and move
219
+ * the headline is the live price against the previous close, as the
220
+ * pre-market line is.
221
+ */
222
+ export function getRegularSessionDisplay(quote: Quote | null | undefined): ActiveQuoteDisplay | null {
223
+ if (!quote) return null;
224
+ const session = completedRegularSession(quote);
225
+ if (session == null) return { price: quote.price, change: quote.change, changePercent: quote.changePercent };
226
+ const { close, reported } = session;
227
+ if (reported) return { price: close, ...reported };
228
+ const reference = isPositive(quote.previousClose)
229
+ ? quote.previousClose
230
+ : isFiniteNumber(quote.change) && isPositive(quote.price - quote.change) ? quote.price - quote.change : null;
231
+ if (reference == null) return { price: close };
232
+ const change = close - reference;
233
+ return { price: close, change, changePercent: (change / reference) * 100 };
234
+ }
235
+
236
+ /**
237
+ * getRegularSessionDisplay once the regular session is over (and in the
238
+ * pre-market, while the quote carries the last session's close and move), null
239
+ * while it is open. A table row headlines this when it has a column for the
240
+ * extended move: the close and its move stay put, and the extended column is
241
+ * the only figure that follows the extended print.
242
+ */
243
+ export function getCompletedRegularSessionDisplay(quote: Quote | null | undefined): ActiveQuoteDisplay | null {
244
+ return quote && completedRegularClose(quote) != null ? getRegularSessionDisplay(quote) : null;
245
+ }
246
+
247
+ /**
248
+ * The pre-market or after-hours print, measured from the regular close before
249
+ * it, while the quote has one: the pre-market until the open, the after-hours
250
+ * session from the close, and its last print until the next pre-market. Null
251
+ * when there is no extended print to show.
252
+ */
253
+ export function getExtendedSessionDisplay(quote: Quote | null | undefined): ExtendedSessionDisplay | null {
254
+ if (!quote) return null;
255
+ const state = quote.marketState;
256
+ if (state === "PRE" || state === "PREPRE") {
257
+ if (isFiniteNumber(quote.preMarketPrice)) {
258
+ // Against the close the headline shows, so the two cannot disagree about it.
259
+ const close = state === "PRE" && quote.preMarketPrice > 0 ? completedRegularClose(quote) : null;
260
+ if (close != null) {
261
+ const change = quote.preMarketPrice - close;
262
+ return { session: "PRE", price: quote.preMarketPrice, change, changePercent: (change / close) * 100 };
263
+ }
264
+ return { session: "PRE", price: quote.preMarketPrice, change: quote.preMarketChange, changePercent: quote.preMarketChangePercent };
265
+ }
266
+ if (state === "PRE") return null;
267
+ }
268
+ const close = completedRegularClose(quote);
269
+ if (close == null) {
270
+ return state === "POST" && isFiniteNumber(quote.postMarketPrice)
271
+ ? { session: "POST", price: quote.postMarketPrice, change: quote.postMarketChange, changePercent: quote.postMarketChangePercent }
272
+ : null;
273
+ }
274
+ const price = state === "POST" ? quote.postMarketPrice ?? quote.price : quote.price;
275
+ // Once the session is over, a last print at the close means nothing traded after it.
276
+ if (!isPositive(price) || (state !== "POST" && price === close)) return null;
277
+ const change = price - close;
278
+ return { session: "POST", price, change, changePercent: (change / close) * 100 };
279
+ }
280
+
281
+ /** The extended display only while its session is open: the pre-market or the after-hours session. */
282
+ function getOpenExtendedSessionDisplay(quote: Quote | null | undefined): ExtendedSessionDisplay | null {
283
+ return quote?.marketState === "PRE" || quote?.marketState === "POST" ? getExtendedSessionDisplay(quote) : null;
284
+ }
285
+
286
+ /**
287
+ * The move a board of tiles colors by: the open pre-market or after-hours
288
+ * session's, from the regular close, otherwise the day's regular session.
289
+ */
290
+ export function getSessionMoveDisplay(
291
+ quote: Quote | null | undefined,
292
+ ): (ActiveQuoteDisplay & { session?: ExtendedSession }) | null {
293
+ return getOpenExtendedSessionDisplay(quote) ?? getRegularSessionDisplay(quote);
294
+ }
@@ -0,0 +1,66 @@
1
+ // Published full-day closures (weekend dates omitted) for Asia-Pacific venues,
2
+ // not a holiday-rule engine. A year a venue has not published is unknown, not
3
+ // open: every weekday of it reads as a session. Half-day sessions (HKEX and
4
+ // SGX eves, ASX's 14:10 closes) are not modelled. Checked 2026-10-09:
5
+ // KRX, also KOSDAQ: http://open.krx.co.kr/contents/MKD/01/0110/01100305/MKD01100305.jsp
6
+ // TWSE, whose closures TPEx shares: https://www.twse.com.tw/en/trading/holiday.html
7
+ // (2027 not yet published; 12 and 13 Feb 2026 are clearing-only days without trading)
8
+ // HKEX: https://www.hkex.com.hk/-/media/HKEX-Market/Services/Circulars-and-Notices/Participant-and-Members-Circulars/SEHK/2025/ce_SEHK_CT_075_2025.pdf
9
+ // and https://www.hkex.com.hk/-/media/HKEX-Market/Services/Circulars-and-Notices/Participant-and-Members-Circulars/SEHK/2026/ce_SEHK_CT_077_2026.pdf
10
+ // SGX closes on Singapore's gazetted public holidays, one on a Sunday moving to the Monday:
11
+ // https://www.sgx.com/stock-exchange/trading and https://www.mom.gov.sg/employment-practices/public-holidays
12
+ // ASX: https://www.asx.com.au/markets/market-resources/trading-hours-calendar/cash-market-trading-hours/trading-calendar
13
+ const KRX_CLOSURES: Record<number, readonly string[]> = {
14
+ 2026: [
15
+ "01-01", "02-16", "02-17", "02-18", "03-02", "05-01", "05-05", "05-25", "06-03",
16
+ "07-17", "08-17", "09-24", "09-25", "10-05", "10-09", "12-25", "12-31",
17
+ ],
18
+ 2027: [
19
+ "01-01", "02-08", "02-09", "03-01", "05-03", "05-05", "05-13", "07-19", "08-16",
20
+ "09-14", "09-15", "09-16", "10-04", "10-11", "12-27", "12-31",
21
+ ],
22
+ };
23
+
24
+ const TWSE_CLOSURES: Record<number, readonly string[]> = {
25
+ 2026: [
26
+ "01-01", "02-12", "02-13", "02-16", "02-17", "02-18", "02-19", "02-20", "02-27",
27
+ "04-03", "04-06", "05-01", "06-19", "09-25", "09-28", "10-09", "10-26", "12-25",
28
+ ],
29
+ };
30
+
31
+ /** Closures by canonical venue code. */
32
+ export const PUBLISHED_APAC_CLOSURES: Readonly<Record<string, Record<number, readonly string[]>>> = {
33
+ KRX: KRX_CLOSURES,
34
+ KOSDAQ: KRX_CLOSURES,
35
+ TWSE: TWSE_CLOSURES,
36
+ TPEX: TWSE_CLOSURES,
37
+ HKEX: {
38
+ 2026: [
39
+ "01-01", "02-17", "02-18", "02-19", "04-03", "04-06", "04-07", "05-01", "05-25",
40
+ "06-19", "07-01", "10-01", "10-19", "12-25",
41
+ ],
42
+ 2027: [
43
+ "01-01", "02-08", "02-09", "03-26", "03-29", "04-05", "05-13", "06-09", "07-01",
44
+ "09-16", "10-01", "10-08", "12-27",
45
+ ],
46
+ },
47
+ SGX: {
48
+ 2026: ["01-01", "02-17", "02-18", "04-03", "05-01", "05-27", "06-01", "08-10", "11-09", "12-25"],
49
+ 2027: ["01-01", "02-08", "03-10", "03-26", "05-17", "05-20", "08-09", "10-28"],
50
+ },
51
+ ASX: {
52
+ 2026: ["01-01", "01-26", "04-03", "04-06", "06-08", "12-25", "12-28"],
53
+ 2027: ["01-01", "01-26", "03-26", "03-29", "06-14", "12-27", "12-28"],
54
+ },
55
+ };
56
+
57
+ /** True only for a published full-day closure; unpublished years are unknown, not open. */
58
+ export function isPublishedApacClosure(exchange: string, date: string): boolean {
59
+ if (!Object.hasOwn(PUBLISHED_APAC_CLOSURES, exchange)) return false;
60
+ return PUBLISHED_APAC_CLOSURES[exchange]![Number(date.slice(0, 4))]?.includes(date.slice(5)) ?? false;
61
+ }
62
+
63
+ /** True when the venue's closures of that year are published. */
64
+ export function hasPublishedApacCalendar(exchange: string, year: number): boolean {
65
+ return Object.hasOwn(PUBLISHED_APAC_CLOSURES, exchange) && PUBLISHED_APAC_CLOSURES[exchange]![year] !== undefined;
66
+ }
@@ -152,6 +152,12 @@ export function mergeQuoteContribution(
152
152
  }
153
153
  if (!current) return next;
154
154
 
155
+ // NAV responses are complete dated observations. Never carry an earlier
156
+ // date or intraday session fields into one, or its marker into a later tick.
157
+ if (current.priceObservation != null || next.priceObservation != null) {
158
+ return { ...next, name: next.name ?? current.name };
159
+ }
160
+
155
161
  const priorBasis = resolvePriceBasis(current.priceBasis, current.instrumentType);
156
162
  const samePriceBasis = priorBasis !== null && priorBasis === resolvePriceBasis(next.priceBasis, next.instrumentType || current.instrumentType);
157
163
  const merged: QuoteContribution = {
@@ -171,6 +177,8 @@ export function mergeQuoteContribution(
171
177
  priceBasis: next.priceBasis,
172
178
  regularClose: next.regularClose,
173
179
  regularCloseSessionDate: next.regularClose != null ? next.regularCloseSessionDate : undefined,
180
+ regularChange: next.regularClose != null ? next.regularChange : undefined,
181
+ regularChangePercent: next.regularClose != null ? next.regularChangePercent : undefined,
174
182
  };
175
183
 
176
184
  if (isOtherTradingDay(current, next)) {
@@ -1,5 +1,7 @@
1
1
  import type { Quote } from "../../types/financials";
2
2
  import { isUsListingExchange } from "../../utils/exchanges";
3
+ import { zonedDateKey } from "../../utils/zoned-date-time";
4
+ import { getPublishedUsEquitySession } from "../published-us-sessions";
3
5
  import { quoteFutureToleranceMs } from "./clock";
4
6
  import {
5
7
  activeUsExtendedHoursSession,
@@ -7,6 +9,9 @@ import {
7
9
  isUsPriorSessionPremarketQuote,
8
10
  } from "../market/freshness";
9
11
 
12
+ // Give the next regular session's NAV time to publish after its actual close.
13
+ const NAV_PUBLICATION_ALLOWANCE_MS = 12 * 60 * 60_000;
14
+
10
15
  /**
11
16
  * Receipt time cannot establish when the source observed a quoted price. A
12
17
  * stamp slightly ahead of local time is clock skew, not a bad observation.
@@ -18,6 +23,36 @@ export function hasValidQuoteObservationTime(quote: Pick<Quote, "lastUpdated">,
18
23
  && Number.isFinite(new Date(timestamp).getTime()) && Number.isFinite(new Date(now).getTime());
19
24
  }
20
25
 
26
+ /** The source date of a validated daily fund observation, including an old NAV. */
27
+ export function dailyNavDate(quote: Quote, now = Date.now()): string | null {
28
+ if (quote.priceObservation !== "nav" || quote.instrumentType !== "MUTUALFUND"
29
+ || (quote.priceBasis !== undefined && quote.priceBasis !== "per-unit")
30
+ || !Number.isFinite(quote.price) || quote.price <= 0
31
+ || !hasValidQuoteObservationTime(quote, now) || quote.lastUpdated > now) return null;
32
+ const exchange = quote.listingExchangeName || quote.exchangeName;
33
+ const date = quote.changeSessionDate;
34
+ if (typeof exchange !== "string" || typeof date !== "string"
35
+ || getPublishedUsEquitySession(exchange, date)?.kind !== "session"
36
+ || zonedDateKey(quote.lastUpdated, "America/New_York") !== date) return null;
37
+ return date;
38
+ }
39
+
40
+ function isDailyNavStale(quote: Quote, now: number): boolean {
41
+ const date = dailyNavDate(quote, now);
42
+ if (!date) return true;
43
+ const exchange = quote.listingExchangeName || quote.exchangeName;
44
+ const today = zonedDateKey(now, "America/New_York");
45
+ if (!today || !getPublishedUsEquitySession(exchange!, today) || date > today) return true;
46
+ const sourceDay = Date.parse(`${date}T00:00:00Z`);
47
+ for (let ahead = 1; ahead <= 10; ahead++) {
48
+ const nextDate = new Date(sourceDay + ahead * 24 * 60 * 60_000).toISOString().slice(0, 10);
49
+ const next = getPublishedUsEquitySession(exchange!, nextDate);
50
+ if (!next) return true;
51
+ if (next.kind === "session") return now >= next.close + NAV_PUBLICATION_ALLOWANCE_MS;
52
+ }
53
+ return true;
54
+ }
55
+
21
56
  export function isExtendedHoursExchange(quote: Quote): boolean {
22
57
  return isUsListingExchange(quote.listingExchangeName || quote.exchangeName);
23
58
  }
@@ -38,6 +73,7 @@ export function isQuoteStaleForCurrentSession(quote: Quote | null | undefined, n
38
73
  if (!quote) return false;
39
74
  if (quote.stale === true) return true;
40
75
  if (!hasValidQuoteObservationTime(quote, now)) return true;
76
+ if (quote.priceObservation != null) return isDailyNavStale(quote, now);
41
77
  if (isQuoteMissingActiveSessionPrice(quote, now)) return true;
42
78
 
43
79
  // A tolerated future stamp belongs to the session in progress, not the next one.
@@ -12,7 +12,7 @@ import { mergeQuoteMetadata, quoteMetadataFromQuote } from "./metadata";
12
12
  import { resolvePriceBasis } from "../market/price-basis";
13
13
  import { hasLikelyQuoteUnitMismatch } from "../../utils/currency-units";
14
14
  import { debugLog } from "../../utils/debug-log";
15
- import { hasValidQuoteObservationTime, isExtendedHoursExchange, isQuoteStaleForCurrentSession } from "./freshness";
15
+ import { dailyNavDate, hasValidQuoteObservationTime, isExtendedHoursExchange, isQuoteStaleForCurrentSession } from "./freshness";
16
16
  import { activeUsExtendedHoursSession, isTimestampStaleForExchangeSession } from "../market/freshness";
17
17
  import {
18
18
  finalizeSessionFields,
@@ -243,7 +243,10 @@ function buildAcceptedPriceCandidates(contributions: QuoteContribution[], now: n
243
243
  } {
244
244
  const ranks = new Map(contributions.map((quote) => [quote, priceRank(quote, now)] as const));
245
245
  const sorted = [...contributions]
246
- .filter((quote) => Number.isFinite(quote.price))
246
+ // Even a stale research snapshot must have its own NAV evidence. Canonical
247
+ // fallbacks cannot supply a missing observation time or security type.
248
+ .filter((quote) => Number.isFinite(quote.price)
249
+ && (quote.priceObservation == null || dailyNavDate(quote, now) !== null))
247
250
  .sort((left, right) => {
248
251
  const rankDelta = ranks.get(left)! - ranks.get(right)!;
249
252
  if (rankDelta !== 0) return rankDelta;
@@ -281,7 +284,7 @@ function buildAcceptedPriceCandidates(contributions: QuoteContribution[], now: n
281
284
  }
282
285
 
283
286
  export function isQuoteContributionStaleForCurrentSession(contribution: Quote, now = Date.now()): boolean {
284
- if (contribution.marketState != null) return isQuoteStaleForCurrentSession(contribution, now);
287
+ if (contribution.priceObservation != null || contribution.marketState != null) return isQuoteStaleForCurrentSession(contribution, now);
285
288
  // A price-only source can be combined with independent session metadata.
286
289
  // Its observation must still belong to the current active session.
287
290
  if (contribution.stale === true || !hasValidQuoteObservationTime(contribution, now)) return true;
@@ -387,8 +390,8 @@ export function resolveCanonicalQuote(
387
390
  const { accepted: acceptedPriceCandidates, rejectedProviders } = buildAcceptedPriceCandidates(effectiveQuoteCandidates, now);
388
391
  if (acceptedPriceCandidates.length === 0) return {};
389
392
 
390
- const sessionCandidates = buildSessionCandidates(effectiveQuoteCandidates);
391
- const listingCandidates = buildListingCandidates(contributions);
393
+ let sessionCandidates = buildSessionCandidates(effectiveQuoteCandidates);
394
+ let listingCandidates = buildListingCandidates(contributions);
392
395
  const routingCandidates = buildRoutingCandidates(contributions);
393
396
  const descriptiveCandidates = buildDescriptiveCandidates(contributions);
394
397
 
@@ -401,9 +404,18 @@ export function resolveCanonicalQuote(
401
404
  // The selected response owns the price convention; metadata enrichment must
402
405
  // not declare units for another provider's price or supply incompatible anchors.
403
406
  assignField(resolved, provenance, "priceBasis", priceProvider);
407
+ assignField(resolved, provenance, "priceObservation", priceProvider);
408
+ const isNav = priceProvider?.priceObservation === "nav";
409
+ if (isNav) {
410
+ sessionCandidates = priceProvider ? [priceProvider] : [];
411
+ listingCandidates = sessionCandidates;
412
+ } else {
413
+ sessionCandidates = sessionCandidates.filter((quote) => quote.priceObservation == null);
414
+ }
404
415
  const selectedBasis = resolvePriceBasis(priceProvider?.priceBasis, priceProvider?.instrumentType);
405
416
  const compatiblePrice = (candidate: QuoteContribution) => candidate === priceProvider
406
- || selectedBasis !== null && resolvePriceBasis(candidate.priceBasis, candidate.instrumentType) === selectedBasis;
417
+ || !isNav && candidate.priceObservation == null
418
+ && selectedBasis !== null && resolvePriceBasis(candidate.priceBasis, candidate.instrumentType) === selectedBasis;
407
419
  const compatiblePriceCandidates = acceptedPriceCandidates.filter(compatiblePrice);
408
420
  for (const field of PRICE_FIELD_KEYS) {
409
421
  if (field === "price") continue;
@@ -459,13 +471,14 @@ export function resolveCanonicalQuote(
459
471
 
460
472
  let descriptiveProvider: QuoteContribution | undefined;
461
473
  for (const field of DESCRIPTIVE_FIELD_KEYS) {
462
- const provider = pickField(resolved, provenance, field, field === "high52w" || field === "low52w" ? descriptiveCandidates.filter(compatiblePrice) : descriptiveCandidates);
474
+ const ownsPriceField = field === "high52w" || field === "low52w" || isNav && (field === "volume" || field === "marketCap");
475
+ const provider = pickField(resolved, provenance, field, ownsPriceField ? descriptiveCandidates.filter(compatiblePrice) : descriptiveCandidates);
463
476
  descriptiveProvider ??= provider;
464
477
  }
465
478
  provenance.descriptive = toProvenance(descriptiveProvider);
466
479
  // Descriptive enrichment cannot turn an unknown-unit bond observation into
467
480
  // an ordinary share price by replacing its source-reported security type.
468
- if (priceProvider?.instrumentType?.trim().toUpperCase() === "BOND") {
481
+ if (isNav || priceProvider?.instrumentType?.trim().toUpperCase() === "BOND") {
469
482
  assignField(resolved, provenance, "instrumentType", priceProvider);
470
483
  }
471
484
 
@@ -474,6 +487,7 @@ export function resolveCanonicalQuote(
474
487
  providerId: priceProvider?.providerId ?? contributions[0]!.providerId,
475
488
  price: Number(resolved.price ?? priceProvider?.price ?? 0),
476
489
  priceBasis: priceProvider?.priceBasis,
490
+ priceObservation: priceProvider?.priceObservation,
477
491
  // The price's own source unit, like its basis; another provider's divisor does not apply.
478
492
  ...(typeof priceProvider?.providerPriceDivisor === "number" ? { providerPriceDivisor: priceProvider.providerPriceDivisor } : {}),
479
493
  currency: String(resolved.currency ?? priceProvider?.currency ?? contributions[0]!.currency ?? ""),
@@ -482,6 +496,8 @@ export function resolveCanonicalQuote(
482
496
  previousClose: resolved.previousClose as Quote["previousClose"],
483
497
  regularClose: priceProvider?.regularClose,
484
498
  regularCloseSessionDate: priceProvider?.regularClose != null ? priceProvider.regularCloseSessionDate : undefined,
499
+ regularChange: priceProvider?.regularClose != null ? priceProvider.regularChange : undefined,
500
+ regularChangePercent: priceProvider?.regularClose != null ? priceProvider.regularChangePercent : undefined,
485
501
  changeSessionDate: resolved.changeSessionDate as Quote["changeSessionDate"],
486
502
  high52w: resolved.high52w as Quote["high52w"],
487
503
  low52w: resolved.low52w as Quote["low52w"],
@@ -5,6 +5,7 @@ import { buildQuoteKey, resolveEntryData } from "../selectors";
5
5
  import type { QueryEntry } from "../result-types";
6
6
  import { resolveCurrencyUnit } from "../../utils/currency-units";
7
7
  import { isFiniteNumber } from "../../utils/guards";
8
+ import { getCompletedRegularSessionDisplay, getSessionMoveDisplay, type ExtendedSession } from "../market/status";
8
9
 
9
10
  const STREAM_FRESHNESS_MS = 2 * 60_000;
10
11
  const STREAM_CONNECTING_GRACE_MS = 15_000;
@@ -20,6 +21,24 @@ export interface ScreenerQuoteRow {
20
21
  exchange: string;
21
22
  lastUpdated?: number;
22
23
  previousClose?: number;
24
+ /** Set when the price and move are an open pre-market or after-hours session's (see `extendedSessions`). */
25
+ extendedSession?: ExtendedSession;
26
+ /** Set when the price and move are the last completed regular session's close and its move; the move, in percent. */
27
+ regularChangePercent?: number | null;
28
+ }
29
+
30
+ export interface ScreenerQuoteOverlayOptions {
31
+ /**
32
+ * While a pre-market or after-hours session is open, show its price and its
33
+ * move from the regular close, marked with `extendedSession`; otherwise the
34
+ * regular session's, which stops at the close. Without it a row shows the
35
+ * live price against the previous close. A row that is a completed regular
36
+ * session's close and move (`regularChangePercent`) keeps them outside the
37
+ * regular session when its quote has neither an open extended print nor
38
+ * that session's close of its own, so its price and move never come from
39
+ * two different days.
40
+ */
41
+ extendedSessions?: boolean;
23
42
  }
24
43
 
25
44
  export interface ScreenerQuoteFreshness {
@@ -64,12 +83,14 @@ function overlayCurrency(row: ScreenerQuoteRow, quote: Quote): string {
64
83
  * entries map, but most rows' quotes did not move; returning the same row
65
84
  * object for those lets memoized table rows skip the render.
66
85
  */
67
- const overlayCache = new WeakMap<object, { quote: Quote; row: ScreenerQuoteRow }>();
86
+ const overlayCache = new WeakMap<object, { quote: Quote; extended: boolean; row: ScreenerQuoteRow }>();
68
87
 
69
88
  export function overlayScreenerQuoteEntries<T extends ScreenerQuoteRow>(
70
89
  rows: readonly T[],
71
90
  entries: ReadonlyMap<string, QueryEntry<Quote>>,
91
+ options: ScreenerQuoteOverlayOptions = {},
72
92
  ): T[] {
93
+ const extended = options.extendedSessions === true;
73
94
  return rows.map((row) => {
74
95
  const quote = resolveEntryData(entries.get(quoteKey(row)));
75
96
  if (!quote || !isFiniteNumber(quote.price)) return row;
@@ -81,9 +102,9 @@ export function overlayScreenerQuoteEntries<T extends ScreenerQuoteRow>(
81
102
  return row;
82
103
  }
83
104
  const cached = overlayCache.get(row);
84
- if (cached?.quote === quote) return cached.row as T;
85
- const overlaid = overlayQuote(row, quote);
86
- overlayCache.set(row, { quote, row: overlaid });
105
+ if (cached?.quote === quote && cached.extended === extended) return cached.row as T;
106
+ const overlaid = extended ? overlaySessionQuote(row, quote) : overlayQuote(row, quote);
107
+ overlayCache.set(row, { quote, extended, row: overlaid });
87
108
  return overlaid;
88
109
  });
89
110
  }
@@ -101,6 +122,30 @@ function overlayQuote<T extends ScreenerQuoteRow>(row: T, quote: Quote): T {
101
122
  currency: overlayCurrency(row, quote),
102
123
  previousClose: isFiniteNumber(quote.previousClose) ? quote.previousClose : undefined,
103
124
  lastUpdated: quote.lastUpdated,
125
+ // The streamed price and move are no longer the snapshot's completed session.
126
+ ...(row.regularChangePercent !== undefined ? { regularChangePercent: null } : {}),
127
+ };
128
+ }
129
+
130
+ function overlaySessionQuote<T extends ScreenerQuoteRow>(row: T, quote: Quote): T {
131
+ const overlaid = overlayQuote(row, quote);
132
+ const display = getSessionMoveDisplay(quote);
133
+ if (!display || !isFiniteNumber(display.price)) return overlaid;
134
+ if (
135
+ !display.session
136
+ && row.regularChangePercent != null
137
+ && quote.marketState != null
138
+ && quote.marketState !== "REGULAR"
139
+ && !getCompletedRegularSessionDisplay(quote)
140
+ ) {
141
+ return { ...overlaid, price: row.price, change: row.change, changePercent: row.changePercent, regularChangePercent: row.regularChangePercent };
142
+ }
143
+ return {
144
+ ...overlaid,
145
+ price: display.price,
146
+ change: isFiniteNumber(display.change) ? display.change : null,
147
+ changePercent: isFiniteNumber(display.changePercent) ? display.changePercent : null,
148
+ extendedSession: display.session,
104
149
  };
105
150
  }
106
151
 
@@ -1,4 +1,20 @@
1
1
  import type { Quote } from "../../types/financials";
2
+ import { getLanguage, tf } from "../../i18n";
3
+ import { dailyNavDate } from "./freshness";
4
+
5
+ /** The published NAV session date, independent of local time and receipt time. */
6
+ export function formatQuoteNavAsOf(quote: Quote | null | undefined, now = Date.now()): string | null {
7
+ const date = quote && dailyNavDate(quote, now);
8
+ if (!date) return null;
9
+ const sourceDate = new Date(`${date}T00:00:00Z`);
10
+ const dateText = new Intl.DateTimeFormat(getLanguage(), {
11
+ timeZone: "UTC",
12
+ month: "short",
13
+ day: "numeric",
14
+ ...(sourceDate.getUTCFullYear() !== new Date(now).getUTCFullYear() ? { year: "numeric" as const } : {}),
15
+ }).format(sourceDate);
16
+ return tf("NAV · as of {date}", { date: dateText });
17
+ }
2
18
 
3
19
  function clampQuoteTimestamp(lastUpdated: number | undefined, now = Date.now()): number | null {
4
20
  if (typeof lastUpdated !== "number" || !Number.isFinite(lastUpdated) || lastUpdated <= 0) {
@@ -22,11 +22,13 @@ import {
22
22
  ScrollBox,
23
23
  Textarea,
24
24
  TextAttributes,
25
+ useUiCapabilities,
25
26
  type ScrollBoxRenderable,
26
27
  type TextareaRenderable,
27
28
  } from "../../../ui";
28
29
  import { useDialog, type AlertContext } from "../../../ui/dialog";
29
30
  import type { SelectControl } from "../../../components/ui/select-button";
31
+ import { FRAMED_TEXTAREA_DESKTOP_STYLE } from "../../../components/ui/fields";
30
32
  import { apiClient, type AccountProfile, type CloudPricing } from "../../../api-client";
31
33
  import { chatController } from "../chat/controller";
32
34
  import { SignInWall } from "../cloud/auth-actions";
@@ -220,6 +222,7 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
220
222
  setActiveField(ACCOUNT_TAB_FIELD_ORDER[tab][0] ?? "username");
221
223
  }), []);
222
224
  const syncStatus = useCloudSyncStatus();
225
+ const { nativePaneChrome } = useUiCapabilities();
223
226
  const bioRef = useRef<TextareaRenderable | null>(null);
224
227
  const portfolioSelectRef = useRef<SelectControl | null>(null);
225
228
  const refreshedSyncRevisionRef = useRef<number | null>(null);
@@ -821,6 +824,7 @@ export function AccountManagementPane({ focused, width, height }: PaneProps) {
821
824
  backgroundColor={colors.panel}
822
825
  flexGrow={1}
823
826
  wrapText
827
+ {...(nativePaneChrome ? { style: FRAMED_TEXTAREA_DESKTOP_STYLE } : {})}
824
828
  onInput={(value: string) => setDraftValue("bio", value)}
825
829
  />
826
830
  </Box>
@@ -1,7 +1,8 @@
1
1
  import { withConfigData } from "../../../cli/scoped-context";
2
2
  import { CLI_COMMAND_GROUPS } from "../../../cli/help";
3
3
  import { dryRunNote } from "../../../cli/helpers";
4
- import { requireArg } from "../../../cli/commands/command-utils";
4
+ import { requireArg, takeOption } from "../../../cli/commands/command-utils";
5
+ import { EXCHANGE_OPTION, requireListingArg } from "../../../cli/listing-arg";
5
6
  import { saveConfig } from "../../../data/config/store";
6
7
  import type { CliCommandDef } from "../../../types/plugin";
7
8
  import { cliStyles } from "../../../utils/cli-output";
@@ -18,10 +19,14 @@ export const alertsCliCommand: CliCommandDef = {
18
19
  help: {
19
20
  group: CLI_COMMAND_GROUPS.portfolios,
20
21
  usage: ["alerts list", "alerts add <symbol> <above|below|crosses> <price>", "alerts delete <id>", "alerts rearm <id>"],
21
- examples: ["alerts", "alerts add AAPL above 250", "alerts add BTC-USD below 60000"],
22
+ options: [EXCHANGE_OPTION],
23
+ examples: ["alerts", "alerts add AAPL above 250", "alerts add SAN:EPA below 70", "alerts add BTC-USD below 60000"],
22
24
  },
23
- execute: async (args, ctx) => {
25
+ execute: async (rawArgs, ctx) => {
26
+ const args = [...rawArgs];
27
+ const exchange = takeOption(args, "--exchange");
24
28
  const action = args[0] ?? "list";
29
+ const listing = action === "add" && args[1] ? await requireListingArg(args[1], exchange, ctx) : null;
25
30
  await withConfigData(ctx, async (config) => {
26
31
  const raw = config.config.pluginConfig[ALERTS_PLUGIN_ID]?.[ALERTS_KEY];
27
32
  const alerts = deserializeAlerts(typeof raw === "string" ? raw : "[]");
@@ -56,12 +61,12 @@ export const alertsCliCommand: CliCommandDef = {
56
61
  return;
57
62
  }
58
63
  if (action === "add") {
59
- const symbol = requireArg(args[1]?.toUpperCase(), "Usage: gloomberb alerts add <symbol> <above|below|crosses> <price>", ctx);
64
+ const symbol = requireArg(listing?.key, "Usage: gloomberb alerts add <symbol> <above|below|crosses> <price>", ctx);
60
65
  const condition = requireArg(args[2], "Usage: gloomberb alerts add <symbol> <above|below|crosses> <price>", ctx) as AlertCondition;
61
66
  if (!["above", "below", "crosses"].includes(condition)) ctx.fail("Condition must be above, below, or crosses.");
62
67
  const price = Number(requireArg(args[3], "Usage: gloomberb alerts add <symbol> <above|below|crosses> <price>", ctx));
63
68
  if (!Number.isFinite(price)) ctx.fail("Alert price must be a finite number.");
64
- const alert = createAlert(symbol, condition, price);
69
+ const alert = createAlert(symbol, condition, price, listing?.exchange);
65
70
  await saveAlerts([...alerts, alert]);
66
71
  ctx.printResult({ data: { changed: !ctx.cliOptions.dryRun, dryRun: ctx.cliOptions.dryRun, alert } }, {
67
72
  text: (data) => `Added alert ${data.alert.id}: ${symbol} ${condition} ${price}.${dryRunNote(data.dryRun)}`,
@@ -282,6 +282,7 @@ export const alertsPlugin: GloomPlugin = {
282
282
 
283
283
  ctx.registerPane({
284
284
  id: "alerts",
285
+ reportFreshness: { source: "Your alerts", status: "not-a-feed", basis: "your alert rules" },
285
286
  name: "Alerts",
286
287
  icon: "A",
287
288
  component: AlertsPane,
@@ -33,13 +33,18 @@ export function syntheticPositionUnsupportedReason(ticker: TickerRecord, quoteCu
33
33
  if (positions.some((position) => position.side === "short" || position.shares < 0)) {
34
34
  return "Short positions: signed exposure history required";
35
35
  }
36
+ const category = (ticker.metadata.assetCategory ?? "").toUpperCase();
37
+ // Crypto trades every day at another close, so its daily returns do not pair with the equity factor proxies.
38
+ if (category.startsWith("CRYPTO") || /-[A-Z]{3,4}$/.test(ticker.metadata.ticker)) {
39
+ return "Crypto is not covered by the equity basket";
40
+ }
36
41
  // "Common Stock" is the category provider search hands a ticker added from
37
42
  // the command bar, so a plain equity must not read as unsupported.
38
43
  const equityCategories = new Set(["", "STK", "STOCK", "COMMON STOCK", "EQUITY", "ETF", "ETN", "FUND", "ADR", "REIT"]);
39
- if (!equityCategories.has((ticker.metadata.assetCategory ?? "").toUpperCase())
44
+ if (!equityCategories.has(category)
40
45
  || positions.some((position) => position.multiplier != null && position.multiplier !== 1)
41
- || /=[A-Z]+$|-[A-Z]{3,4}$|\d{6}[CP]\d{8}$/.test(ticker.metadata.ticker)) {
42
- return "Unsupported asset: equity basket estimate only";
46
+ || /=[A-Z]+$|\d{6}[CP]\d{8}$/.test(ticker.metadata.ticker)) {
47
+ return "Asset type is not covered by the equity basket";
43
48
  }
44
49
  if (quoteCurrency !== "USD") return "Foreign holdings: historical FX returns required";
45
50
  return null;