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
@@ -95,6 +95,8 @@ export interface PluginDirectoryInfo {
95
95
  path: string;
96
96
  commit: string | null;
97
97
  plugin: Pick<GloomPlugin, "id" | "name" | "version"> | null;
98
+ /** Sibling plugins installed along with it, by folder, each before the plugin that imports it. */
99
+ peers?: string[];
98
100
  }
99
101
 
100
102
  class GitError extends Error {
@@ -258,6 +260,10 @@ async function installDependencies(targetDir: string, quiet: boolean): Promise<v
258
260
  }
259
261
 
260
262
  async function readPluginExport(targetDir: string): Promise<Pick<GloomPlugin, "id" | "name" | "version"> | null> {
263
+ // Not before the sibling plugins it imports are installed: the import
264
+ // would fail, and Bun keeps that failure for the life of the process, so
265
+ // loading the plugin once the sibling is there would fail the same way.
266
+ if (missingPeerPlugins(targetDir).length > 0) return null;
261
267
  const entryFile = await resolvePluginEntry(targetDir);
262
268
  if (!entryFile) return null;
263
269
  // Fresh so an update is validated against the new code, not the module Bun
@@ -322,6 +328,19 @@ export async function installPlugin(ref: string, options: PluginInstallOptions =
322
328
 
323
329
  await installDependencies(targetDir, quiet);
324
330
 
331
+ const missing = missingPeerPlugins(targetDir);
332
+ if (missing.length > 0) {
333
+ say(cliStyles.muted(`Needs the ${missing.join(", ")} plugin.`));
334
+ return describe(targetDir, name, null);
335
+ }
336
+ return validateInstall(targetDir, name, quiet);
337
+ }
338
+
339
+ /** Reads the export of a checkout that was just installed, and says what it is. */
340
+ async function validateInstall(targetDir: string, name: string, quiet: boolean): Promise<PluginDirectoryInfo> {
341
+ const say = (message: string) => {
342
+ if (!quiet) console.log(message);
343
+ };
325
344
  try {
326
345
  const plugin = await readPluginExport(targetDir);
327
346
  if (plugin) {
@@ -518,28 +537,45 @@ export async function loadRegistryListings(): Promise<Map<string, RegistryListin
518
537
 
519
538
  /**
520
539
  * Installs a plugin the way the marketplace does: a listed one at the commit
521
- * the registry reviewed, and not at all on a Gloomberb too old to run it.
522
- * An unlisted repository follows its default branch. A caller installing
523
- * several passes `listings` so the registry is read once.
540
+ * the registry reviewed (or at `options.pin`, the one the user was shown), and
541
+ * not at all on a Gloomberb too old to run it. An unlisted repository follows
542
+ * its default branch. A caller installing several passes `listings` so the
543
+ * registry is read once.
524
544
  */
525
545
  export async function installListedPlugin(
526
546
  ref: string,
527
- options: Omit<PluginInstallOptions, "pin"> = {},
547
+ options: PluginInstallOptions = {},
528
548
  listings?: ReadonlyMap<string, RegistryListing>,
529
549
  ): Promise<PluginDirectoryInfo> {
550
+ const { pin, ...shared } = options;
530
551
  const repo = parseGitHubRef(ref).repo.toLowerCase();
531
- const listing = (listings ?? await loadRegistryListings()).get(repo);
552
+ const known = listings ?? await loadRegistryListings();
553
+ const listing = known.get(repo);
532
554
  const required = requiredGloomberb(listing?.minGloomberb);
533
555
  if (required) fail(`${ref} needs Gloomberb ${required}, this is ${VERSION}.`, "Update Gloomberb first.");
534
- const installed = await installPlugin(ref, { ...options, ...(listing?.pin ? { pin: listing.pin } : {}) });
556
+ const reviewed = pin ?? listing?.pin;
557
+ const installed = await installPlugin(ref, { ...shared, ...(reviewed ? { pin: reviewed } : {}) });
558
+ const missing = missingPeerPlugins(installed.path);
559
+ if (missing.length === 0) return installed;
560
+
535
561
  // A plugin that imports a sibling plugin (IBKR Gateway imports Interactive
536
- // Brokers) brings it along, from the same registry.
537
- const known = listings ?? await loadRegistryListings();
538
- for (const peer of missingPeerPlugins(installed.path)) {
539
- const repo = [...known.keys()].find((candidate) => pluginDirectoryNames(peer).includes(candidate.split("/")[1] ?? ""));
540
- if (repo) await installListedPlugin(repo, options, known);
562
+ // Brokers) brings it along, from the same registry. One that cannot be
563
+ // installed leaves the plugin waiting for it, never imported.
564
+ const peers: string[] = [];
565
+ for (const peer of missing) {
566
+ const peerRepo = [...known.keys()].find((candidate) => pluginDirectoryNames(peer).includes(candidate.split("/")[1] ?? ""));
567
+ if (!peerRepo) continue;
568
+ try {
569
+ const added = await installListedPlugin(peerRepo, shared, known);
570
+ peers.push(...(added.peers ?? []), added.directory);
571
+ } catch (error) {
572
+ if (!shared.quiet) console.error(cliStyles.warning(`Could not install ${peer}: ${error instanceof Error ? error.message : String(error)}`));
573
+ }
541
574
  }
542
- return installed;
575
+ const withPeers = peers.length > 0 ? { peers } : {};
576
+ if (missingPeerPlugins(installed.path).length > 0) return { ...installed, ...withPeers };
577
+ linkHostPackages(installed.path);
578
+ return { ...await validateInstall(installed.path, installed.directory, shared.quiet === true), ...withPeers };
543
579
  }
544
580
 
545
581
  /** Folder names of every installed plugin, clones and links alike. */
@@ -8,7 +8,7 @@ import { reportCrash } from "../telemetry/crash-reports";
8
8
  import { findAbsorbedPlugin, type AbsorbedPlugin } from "./absorbed";
9
9
  import { checkPluginCompatibility, explainPluginLoadError, findMissingHostExport, pluginSourceFiles, readPluginManifest } from "./compat";
10
10
  import { installPluginDependencies, missingPluginDependencies } from "./dependencies";
11
- import { linkHostPackages } from "./host-link";
11
+ import { isLinkedPeerModule, linkHostPackages } from "./host-link";
12
12
  import { pluginFromModule, pluginSupportsTarget } from "./plugin-export";
13
13
 
14
14
  const loaderLog = debugLog.createLogger("plugin-loader");
@@ -40,7 +40,11 @@ export interface LoadedExternalPlugin {
40
40
  needsGloomberb?: string;
41
41
  /** Set when the plugin loaded but does not support the running renderer. */
42
42
  unsupportedTarget?: PluginTarget;
43
- /** Loaded after startup in a way this session could not fully apply. */
43
+ /**
44
+ * Loaded in a way this session cannot fully apply: new files under modules
45
+ * it already imported, or an import Bun failed before a sibling plugin was
46
+ * linked. Never registered; the next launch loads it.
47
+ */
44
48
  needsRestart?: boolean;
45
49
  }
46
50
 
@@ -197,6 +201,21 @@ export function pluginsMissingHostExports(): string[] {
197
201
  return [...missingHostExportFailures].sort();
198
202
  }
199
203
 
204
+ /** Bun's wording when an import does not resolve, from a native import. */
205
+ const UNRESOLVED_MODULE = /Cannot find (?:module|package) '([^']+)'/;
206
+
207
+ /**
208
+ * The specifier an import failed to resolve. Bun puts it on the error as
209
+ * `specifier`; the message is only a fallback, because from Bun 1.4 it names
210
+ * the package alone ("Cannot find package 'peer' imported from …" for
211
+ * `peer/bridge`), and the subpath decides whether the peer has the file.
212
+ */
213
+ export function unresolvedSpecifier(err: unknown, message: string): string | undefined {
214
+ const specifier = (err as { specifier?: unknown } | null)?.specifier;
215
+ if (typeof specifier === "string" && specifier) return specifier;
216
+ return UNRESOLVED_MODULE.exec(message)?.[1];
217
+ }
218
+
200
219
  /** Imported at another commit earlier in this process, with files besides the entry that Bun keeps. */
201
220
  function hasStaleModules(pluginDir: string, commit: string | null): boolean {
202
221
  if (!importedCommits.has(pluginDir) || importedCommits.get(pluginDir) === commit) return false;
@@ -289,9 +308,17 @@ export async function loadExternalPlugin(
289
308
  loaderLog.info(`Loaded external plugin: ${plugin.id} v${plugin.version ?? "0.0.0"}`);
290
309
  return { ...base, ...restart, plugin };
291
310
  } catch (err) {
311
+ const message = err instanceof Error ? err.message : String(err);
312
+ // A sibling plugin it imports that is linked now but was not when this
313
+ // process first resolved it. Bun keeps that failure until a restart, which
314
+ // is all the plugin needs: not a crash.
315
+ const unresolved = unresolvedSpecifier(err, message);
316
+ if (unresolved && isLinkedPeerModule(pluginDir, unresolved)) {
317
+ loaderLog.info(`${directory} loads after a restart: ${message}`);
318
+ return { ...base, plugin: placeholder, needsRestart: true };
319
+ }
292
320
  loaderLog.error(`Failed to load plugin from ${pluginDir}: ${err}`);
293
321
  reportCrash(err, { kind: "plugin", plugin: directory });
294
- const message = err instanceof Error ? err.message : String(err);
295
322
  if (findMissingHostExport(message)) missingHostExportFailures.add(directory);
296
323
  return {
297
324
  ...base,
@@ -22,18 +22,28 @@ export interface NodePluginManagerHooks {
22
22
  const installer = () => import("./installer");
23
23
 
24
24
  export function createNodePluginManager(target: PluginTarget, hooks: NodePluginManagerHooks = {}): NodePluginManager {
25
- async function attempt(run: () => Promise<{ directory: string; kept?: string; changed?: boolean }>): Promise<PluginOperationResult> {
25
+ async function attempt(
26
+ run: () => Promise<{ directory: string; kept?: string; changed?: boolean; peers?: string[] }>,
27
+ ): Promise<PluginOperationResult> {
26
28
  try {
27
- const { directory, kept, changed } = await run();
28
- hooks.onChanged?.(join(getPluginsDir(), directory));
29
- return { ok: true, directory, ...(kept ? { kept } : {}), ...(changed !== undefined ? { changed } : {}) };
29
+ const { directory, kept, changed, peers } = await run();
30
+ for (const changedDirectory of [...(peers ?? []), directory]) hooks.onChanged?.(join(getPluginsDir(), changedDirectory));
31
+ return {
32
+ ok: true,
33
+ directory,
34
+ ...(kept ? { kept } : {}),
35
+ ...(changed !== undefined ? { changed } : {}),
36
+ ...(peers?.length ? { peers } : {}),
37
+ };
30
38
  } catch (error) {
31
39
  return { ok: false, error: error instanceof Error ? error.message : String(error) };
32
40
  }
33
41
  }
34
42
 
35
43
  return {
36
- install: (repo, pin) => attempt(async () => (await installer()).installPlugin(repo, { quiet: true, pin })),
44
+ // Through the registry, like `gloomberb install`: a plugin that builds on
45
+ // another brings it along instead of failing to load without it.
46
+ install: (repo, pin) => attempt(async () => (await installer()).installListedPlugin(repo, { quiet: true, ...(pin ? { pin } : {}) })),
37
47
  update: (directory, pin) => attempt(async () => (await installer()).updatePlugin(directory, { quiet: true, pin })),
38
48
  remove: (directory) => attempt(async () => {
39
49
  await (await installer()).removePlugin(directory, { quiet: true });
@@ -388,7 +388,7 @@ export class PluginRegistry implements PluginRuntimeAccess {
388
388
  async togglePaneQuickSetting(paneId: string, key: string): Promise<void> {
389
389
  const quickSetting = this.resolvePaneQuickSettings(paneId).find((setting) => setting.key === key);
390
390
  if (!quickSetting) return;
391
- await this.applyPaneSettingValue(paneId, quickSetting.field, !quickSetting.value);
391
+ await this.applyPaneSettingValue(paneId, quickSetting.field, quickSetting.nextValue);
392
392
  }
393
393
 
394
394
  getCommandPluginId(commandId: string): string | undefined {
@@ -31,7 +31,9 @@ export interface ResolvedRegistryPaneQuickSetting extends PaneQuickSettingDef {
31
31
  label: string;
32
32
  description?: string;
33
33
  value: boolean;
34
- field: PaneSettingField & { type: "toggle" };
34
+ field: PaneSettingField;
35
+ /** What pressing the control writes to the field. */
36
+ nextValue: boolean | string;
35
37
  }
36
38
 
37
39
  export function resolveRegistryPaneQuickSettings(
@@ -39,17 +41,34 @@ export function resolveRegistryPaneQuickSettings(
39
41
  ): ResolvedRegistryPaneQuickSetting[] {
40
42
  if (!resolved?.paneDef.quickSettings?.length) return [];
41
43
 
42
- return resolved.paneDef.quickSettings.flatMap((quickSetting) => {
43
- const field = resolved.settingsDef.fields.find((candidate) => (
44
- candidate.key === quickSetting.key && candidate.type === "toggle"
45
- ));
46
- if (!field || field.type !== "toggle") return [];
44
+ return resolved.paneDef.quickSettings.flatMap((quickSetting): ResolvedRegistryPaneQuickSetting[] => {
45
+ const field = resolved.settingsDef.fields.find((candidate) => candidate.key === quickSetting.key);
46
+ if (!field) return [];
47
+ if (quickSetting.visible && !quickSetting.visible(resolved.context)) return [];
48
+ if (quickSetting.onValue != null) {
49
+ if (field.type !== "select") return [];
50
+ const onValue = quickSetting.onValue;
51
+ const offValue = field.options.find((option) => option.value !== onValue)?.value;
52
+ if (offValue == null || !field.options.some((option) => option.value === onValue)) return [];
53
+ const value = resolved.context.settings[quickSetting.key] === onValue;
54
+ return [{
55
+ ...quickSetting,
56
+ label: quickSetting.label ?? field.label,
57
+ description: field.description,
58
+ value,
59
+ field,
60
+ nextValue: value ? offValue : onValue,
61
+ }];
62
+ }
63
+ if (field.type !== "toggle") return [];
64
+ const value = resolved.context.settings[quickSetting.key] === true;
47
65
  return [{
48
66
  ...quickSetting,
49
67
  label: quickSetting.label ?? field.label,
50
68
  description: field.description,
51
- value: resolved.context.settings[quickSetting.key] === true,
69
+ value,
52
70
  field,
71
+ nextValue: !value,
53
72
  }];
54
73
  });
55
74
  }
@@ -99,6 +99,8 @@ exports[`the runtime exports of every public subpath are the reviewed ones 1`] =
99
99
  "Prose",
100
100
  "QueryBar",
101
101
  "READING_WIDTH",
102
+ "RangeTrack",
103
+ "RatioBar",
102
104
  "RemoteImage",
103
105
  "Section",
104
106
  "SectionHeading",
@@ -1,5 +1,6 @@
1
1
  import { readFile, writeFile } from "fs/promises";
2
- import { join, relative } from "path";
2
+ import { dirname, join, relative, resolve } from "path";
3
+ import type { BunPlugin } from "bun";
3
4
  import { TITLEBAR_OVERLAY_HEIGHT_PX } from "../../components/layout/titlebar-overlay";
4
5
 
5
6
  /** Imports whose path ends with the first entry resolve to the second, relative to the view directory. */
@@ -27,6 +28,13 @@ interface ViewBundleOptions {
27
28
  }
28
29
 
29
30
  const ELECTROBUN_VIEW_DIR = join(process.cwd(), "src", "renderers", "electrobun", "view");
31
+
32
+ /**
33
+ * Where the world map finds its land data, relative to the map's
34
+ * `basemap.ts`. Only view bundles define it, so the terminal binary, which
35
+ * never draws that map, leaves the data out.
36
+ */
37
+ export const WORLD_MAP_DATA_SPECIFIER = "./natural-earth/index.chunk.js";
30
38
  const DOM_RENDERER_DIR = join(process.cwd(), "src", "renderers", "dom");
31
39
 
32
40
  export function electrobunViewPath(...parts: string[]): string {
@@ -50,6 +58,7 @@ export async function buildViewBundle({
50
58
  failureMessage,
51
59
  missingEntryMessage,
52
60
  }: ViewBundleOptions): Promise<{ script: string; stylesheet: string | null }> {
61
+ const chunks = new Map<string, string>();
53
62
  const result = await Bun.build({
54
63
  entrypoints: [entrypoint],
55
64
  outdir,
@@ -58,8 +67,15 @@ export async function buildViewBundle({
58
67
  splitting: false,
59
68
  sourcemap,
60
69
  minify: true,
61
- define: { "process.env.NODE_ENV": "\"production\"", ...define },
62
- plugins: aliasRules.length > 0 ? [electrobunViewAliasPlugin(aliasRules)] : [],
70
+ define: {
71
+ "process.env.NODE_ENV": "\"production\"",
72
+ __GLOOM_WORLD_MAP_DATA__: JSON.stringify(WORLD_MAP_DATA_SPECIFIER),
73
+ ...define,
74
+ },
75
+ plugins: [
76
+ lazyChunkPlugin(outdir, outdir, chunks),
77
+ ...(aliasRules.length > 0 ? [electrobunViewAliasPlugin(aliasRules)] : []),
78
+ ],
63
79
  });
64
80
 
65
81
  if (!result.success) {
@@ -69,6 +85,7 @@ export async function buildViewBundle({
69
85
 
70
86
  const script = result.outputs.find((output) => output.kind === "entry-point" && output.path.endsWith(".js"));
71
87
  if (!script) throw new Error(missingEntryMessage);
88
+ await buildLazyChunks(outdir, chunks, failureMessage);
72
89
 
73
90
  const stylesheet = result.outputs.find((output) => output.path.endsWith(".css"))?.path ?? null;
74
91
  if (stylesheet) await writeFile(stylesheet, withTitlebarOverlayHeight(await readFile(stylesheet, "utf8")));
@@ -122,6 +139,67 @@ ${bootstrapScript}
122
139
  `;
123
140
  }
124
141
 
142
+ /**
143
+ * The view bundle is one file (no splitting), so a module reached through
144
+ * `import()` would land in it. A module named `*.chunk.ts` and imported as
145
+ * `import("./path/name.chunk.js")` instead ships as its own file at that path
146
+ * next to the importing bundle, fetched the first time it is asked for: large
147
+ * data only some panes draw, such as the world map's coastlines. The terminal
148
+ * and the tests run the source, where the same `import()` loads the module.
149
+ */
150
+ function lazyChunkPlugin(rootOutdir: string, emitDir: string, chunks: Map<string, string>): BunPlugin {
151
+ return {
152
+ name: "lazy-chunks",
153
+ setup(build) {
154
+ build.onResolve({ filter: /\.chunk(\.js|\.ts)?$/ }, (args) => {
155
+ if (args.kind.startsWith("entry-point") || /[\\/]node_modules[\\/]/.test(args.importer)) return undefined;
156
+ if (args.kind !== "dynamic-import") {
157
+ throw new Error(`${args.path} is a lazy chunk; load it with import() (from ${args.importer})`);
158
+ }
159
+ if (!args.path.startsWith("./") || !args.path.endsWith(".chunk.js")) {
160
+ throw new Error(`Lazy chunk ${args.path} must be imported as "./<path>.chunk.js" (from ${args.importer})`);
161
+ }
162
+ const source = resolve(dirname(args.importer), args.path.replace(/\.js$/, ".ts"));
163
+ const output = resolve(emitDir, args.path);
164
+ if (relative(rootOutdir, output).startsWith("..")) throw new Error(`Lazy chunk ${args.path} would land outside ${rootOutdir}`);
165
+ const existing = chunks.get(output);
166
+ if (existing && existing !== source) throw new Error(`Two lazy chunks emit ${output}: ${existing} and ${source}`);
167
+ chunks.set(output, source);
168
+ return { path: args.path, external: true };
169
+ });
170
+ },
171
+ };
172
+ }
173
+
174
+ /** Builds each lazy chunk on its own, and the chunks those load in turn. */
175
+ async function buildLazyChunks(rootOutdir: string, chunks: Map<string, string>, failureMessage: string): Promise<void> {
176
+ const built = new Set<string>();
177
+ let pending = [...chunks.entries()];
178
+ while (pending.length) {
179
+ const nested = new Map<string, string>();
180
+ for (const [output, source] of pending) {
181
+ if (built.has(output)) continue;
182
+ built.add(output);
183
+ const result = await Bun.build({
184
+ entrypoints: [source],
185
+ outdir: dirname(output),
186
+ naming: relative(dirname(output), output),
187
+ target: "browser",
188
+ format: "esm",
189
+ splitting: false,
190
+ sourcemap: "none",
191
+ minify: true,
192
+ plugins: [lazyChunkPlugin(rootOutdir, dirname(output), nested)],
193
+ });
194
+ if (!result.success) {
195
+ const details = result.logs.map((log) => log.message).filter(Boolean).join("\n");
196
+ throw new Error(`${failureMessage}: lazy chunk ${source}\n${details}`);
197
+ }
198
+ }
199
+ pending = [...nested.entries()];
200
+ }
201
+ }
202
+
125
203
  function electrobunViewAliasPlugin(aliasRules: AliasRule[]) {
126
204
  return {
127
205
  name: "electrobun-view-aliases",
@@ -1,5 +1,5 @@
1
1
  /** @jsxImportSource react */
2
- import { memo, type CSSProperties } from "react";
2
+ import { memo, type CSSProperties, type ReactNode } from "react";
3
3
  import { TextAttributes } from "../../../ui/host";
4
4
  import { DisclosureMarker } from "../../../components/ui/disclosure-marker";
5
5
  import type {
@@ -27,10 +27,26 @@ import {
27
27
  eventWithCellCoordinates,
28
28
  } from "./dom";
29
29
 
30
- /** Space between a header label and its sort marker. */
31
- const SORT_MARKER_GAP_PX = 4;
30
+ /** Space between a label and its sort marker or the artwork drawn before it. */
31
+ const LABEL_GAP_PX = 4;
32
32
  const SORT_MARKER_SIZE_PX = 9;
33
33
 
34
+ /**
35
+ * Artwork a column or cell draws before its text. It is decoration, so
36
+ * assistive technology skips it and the text stays the only name.
37
+ */
38
+ function Leading({ children }: { children: ReactNode }) {
39
+ return (
40
+ <span
41
+ aria-hidden="true"
42
+ data-gloom-role="data-table-leading"
43
+ style={{ display: "flex", flex: "none", alignItems: "center" }}
44
+ >
45
+ {children}
46
+ </span>
47
+ );
48
+ }
49
+
34
50
  function contentJustifyForAlign(align: string | undefined): CSSProperties["justifyContent"] {
35
51
  if (align === "right") return "flex-end";
36
52
  if (align === "center") return "center";
@@ -130,7 +146,7 @@ export function WebDataTableHeader<C extends DataTableColumn>({
130
146
  display: "flex",
131
147
  alignItems: "center",
132
148
  justifyContent: contentJustifyForAlign(column.align),
133
- gap: column.label ? SORT_MARKER_GAP_PX : 0,
149
+ gap: column.label ? LABEL_GAP_PX : 0,
134
150
  backgroundColor: column.headerBackgroundColor ?? CSS_PANEL,
135
151
  boxShadow: freezeFirstColumn && columnIndex === 0 ? `-${inlinePaddingPx(horizontalPadding)}px 0 0 ${column.headerBackgroundColor ?? CSS_PANEL}, ${columnGap * WEB_CELL_WIDTH}px 0 0 ${column.headerBackgroundColor ?? CSS_PANEL}` : undefined,
136
152
  }}
@@ -141,6 +157,7 @@ export function WebDataTableHeader<C extends DataTableColumn>({
141
157
  onHeaderClick(column.id);
142
158
  } : undefined}
143
159
  >
160
+ {column.headerLeading !== undefined ? <Leading>{column.headerLeading}</Leading> : null}
144
161
  <span
145
162
  title={column.label || undefined}
146
163
  style={{
@@ -336,6 +353,8 @@ function WebDataTableRowInner<
336
353
  <div
337
354
  key={column.id}
338
355
  data-gloom-role="data-table-cell"
356
+ // The instant behind a shortened time ("Wed 11:27"), so a rendered-view report can print it whole.
357
+ data-gloom-cell-instant={cell.value instanceof Date && Number.isFinite(cell.value.getTime()) ? cell.value.toISOString() : undefined}
339
358
  style={{
340
359
  minWidth: 0,
341
360
  position: freezeFirstColumn && columnIndex === 0 ? "sticky" : undefined,
@@ -392,18 +411,13 @@ function WebDataTableRowInner<
392
411
  {cell.content}
393
412
  </div>
394
413
  ) : (
395
- <span
396
- title={cell.text}
397
- style={clippedCellTextStyle(
398
- column,
399
- selected && (cell.color === undefined || (selectedTextOverridesCellColor && !cell.keepColorWhenSelected))
400
- ? CSS_SELECTED_TEXT
401
- : cell.color ?? CSS_TEXT,
402
- cell.attributes ?? TextAttributes.NONE,
403
- )}
404
- >
405
- {cell.text}
406
- </span>
414
+ <CellText
415
+ cell={cell}
416
+ column={column}
417
+ color={selected && (cell.color === undefined || (selectedTextOverridesCellColor && !cell.keepColorWhenSelected))
418
+ ? CSS_SELECTED_TEXT
419
+ : cell.color ?? CSS_TEXT}
420
+ />
407
421
  )}
408
422
  </div>
409
423
  );
@@ -412,4 +426,26 @@ function WebDataTableRowInner<
412
426
  );
413
427
  }
414
428
 
429
+ function CellText({ cell, column, color }: { cell: DataTableCell; column: DataTableColumn; color: string }) {
430
+ const style = clippedCellTextStyle(column, color, cell.attributes ?? TextAttributes.NONE);
431
+ if (cell.leading === undefined) return <span title={cell.text} style={style}>{cell.text}</span>;
432
+ return (
433
+ <div
434
+ style={{
435
+ display: "flex",
436
+ alignItems: "center",
437
+ justifyContent: contentJustifyForAlign(column.align),
438
+ gap: LABEL_GAP_PX,
439
+ width: "100%",
440
+ height: "100%",
441
+ minWidth: 0,
442
+ overflow: "hidden",
443
+ }}
444
+ >
445
+ <Leading>{cell.leading}</Leading>
446
+ <span title={cell.text} style={{ ...style, width: "auto", flex: "0 1 auto" }}>{cell.text}</span>
447
+ </div>
448
+ );
449
+ }
450
+
415
451
  export const WebDataTableRow = memo(WebDataTableRowInner) as typeof WebDataTableRowInner;
@@ -345,8 +345,10 @@ export function WebTextField({
345
345
  focusedBackgroundColor={plain ? "transparent" : resolvedBackgroundColor}
346
346
  cursorColor={colors.textBright}
347
347
  style={{
348
- paddingLeft: plain ? 0 : comfortable ? 8 : 10,
349
- paddingRight: plain ? 0 : comfortable ? 8 : 10,
348
+ // A framed field keeps its text one cell off the frame; a plain one
349
+ // sits flush in the row or band that holds it.
350
+ paddingLeft: plain ? 0 : "var(--cell-w)",
351
+ paddingRight: plain ? 0 : "var(--cell-w)",
350
352
  borderRadius: plain ? 0 : CONTROL_RADIUS,
351
353
  // The field is taller than a cell, so the input takes the inner
352
354
  // height and centers its text on the box's own line.
@@ -581,8 +583,10 @@ export function WebDialogFrame({
581
583
  </Box>
582
584
  {children}
583
585
  {footer && (
586
+ // Sized by its line, not one cell: a cell-high box with this padding
587
+ // left the key line hanging out of its bottom.
584
588
  <Box
585
- height={1}
589
+ flexShrink={0}
586
590
  style={{
587
591
  borderTop: `1px solid ${panelBorder(colors)}`,
588
592
  paddingTop: 8,
@@ -14,6 +14,7 @@ const ICONS: Record<IconName, ReactNode> = {
14
14
  ),
15
15
  close: <path d="M3 3L9 9M9 3L3 9" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />,
16
16
  zap: <path d="M7.1 1.2 2.7 6.5h3.1l-.7 4.3 4.4-5.5H6.4l.7-4.1Z" fill="currentColor" />,
17
+ sqrt: <path d="M1.5 6.6h1.6l1.8 3.6L7.6 2h3" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" />,
17
18
  lock: (
18
19
  <>
19
20
  <rect x="2.5" y="5.5" width="7" height="5" rx="1.2" fill="currentColor" />
@@ -5,6 +5,7 @@ import { TextAttributes } from "../../../ui";
5
5
  import type { ListRowState, ListViewItem, ListViewProps } from "../../../components/ui/list-view";
6
6
  import { blendHex, hoverBg, type ThemeColors } from "../../../theme/colors";
7
7
  import { useThemeColors } from "../../../theme/theme-context";
8
+ import { WEB_CELL_HEIGHT } from "../../../theme/font-scale";
8
9
  import { isInsideDialogSurface } from "../host/focus-scope";
9
10
  import { isEditableKeyboardTarget } from "../key-event";
10
11
  import {
@@ -58,6 +59,10 @@ function DefaultDesktopRow({
58
59
  );
59
60
  }
60
61
 
62
+ const FRAMED_LIST_PADDING_PX = 4;
63
+ /** What a framed list adds above and below its rows: padding and a 1px border on each side. */
64
+ const FRAMED_LIST_CHROME_PX = 2 * (FRAMED_LIST_PADDING_PX + 1);
65
+
61
66
  function listRowStyle(selected: boolean, disabled: boolean, colors: ThemeColors): CSSProperties {
62
67
  return {
63
68
  borderRadius: CONTROL_RADIUS,
@@ -109,6 +114,16 @@ export function WebListView({
109
114
  const tabStopIndex = selectedIndex >= 0 && items[selectedIndex] && !items[selectedIndex].disabled
110
115
  ? selectedIndex : items.findIndex((item) => !item.disabled);
111
116
  const effectiveSurface = surface ?? (scrollable ? "framed" : "plain");
117
+ // `height` counts terminal rows. A list that is not meant to scroll takes
118
+ // only the rows it has, up to that many; one with more rows than that
119
+ // scrolls inside the height instead of drawing over whatever follows it.
120
+ const rowsHeight = items.length === 0 ? 1 : items.length * rowHeight + (items.length - 1) * rowGap;
121
+ const overflowsHeight = !scrollable && height != null && rowsHeight > height;
122
+ const scrolls = scrollable || overflowsHeight;
123
+ // The frame's padding and border sit outside the rows it was asked to hold.
124
+ const scrollHeight = overflowsHeight
125
+ ? `${height * WEB_CELL_HEIGHT + (effectiveSurface === "plain" ? 0 : FRAMED_LIST_CHROME_PX)}px`
126
+ : height;
112
127
  const frameStyle = effectiveSurface === "plain"
113
128
  ? {
114
129
  border: "none",
@@ -119,12 +134,12 @@ export function WebListView({
119
134
  : {
120
135
  border: `1px solid ${panelBorder(colors)}`,
121
136
  borderRadius: CONTROL_RADIUS,
122
- padding: 4,
137
+ padding: FRAMED_LIST_PADDING_PX,
123
138
  backgroundColor: subtlePanelFill(colors),
124
139
  };
125
140
 
126
141
  useEffect(() => {
127
- if (!scrollable || !autoScrollToIndex || activeScrollIndex < 0) return;
142
+ if (!scrolls || !autoScrollToIndex || activeScrollIndex < 0) return;
128
143
  const scrollBox = scrollRef.current;
129
144
  if (!scrollBox) return;
130
145
  const safeIndex = Math.min(activeScrollIndex, items.length - 1);
@@ -136,16 +151,16 @@ export function WebListView({
136
151
  } else if (rowBottom > scrollBox.scrollTop + viewportHeight) {
137
152
  scrollBox.scrollTo(rowBottom - viewportHeight);
138
153
  }
139
- }, [activeScrollIndex, autoScrollToIndex, items.length, rowHeight, rowStride, scrollable]);
154
+ }, [activeScrollIndex, autoScrollToIndex, items.length, rowHeight, rowStride, scrolls]);
140
155
 
141
156
  useEffect(() => {
142
- if (!scrollable) return;
157
+ if (!scrolls) return;
143
158
  const scrollBox = scrollRef.current;
144
159
  if (!scrollBox) return;
145
160
  if (scrollBox.verticalScrollBar) {
146
161
  scrollBox.verticalScrollBar.visible = items.length * rowStride - rowGap > (scrollBox.viewport?.height ?? 0);
147
162
  }
148
- }, [items.length, height, flexGrow, rowGap, rowStride, scrollable]);
163
+ }, [items.length, height, flexGrow, rowGap, rowStride, scrolls]);
149
164
 
150
165
  // The dialog or pane around the list moves its cursor (j/k, Home/End). A row
151
166
  // Tab or a press left focused follows it, or Space and Enter would act on the
@@ -156,8 +171,8 @@ export function WebListView({
156
171
  const active = document.activeElement;
157
172
  if (!list || !active || !list.contains(active) || isEditableKeyboardTarget(active)) return;
158
173
  const row = list.querySelectorAll<HTMLElement>('[role="option"]')[selectedIndex];
159
- if (row && !row.contains(active)) row.focus({ preventScroll: scrollable });
160
- }, [listDomId, scrollable, selectedIndex]);
174
+ if (row && !row.contains(active)) row.focus({ preventScroll: scrolls });
175
+ }, [listDomId, scrolls, selectedIndex]);
161
176
 
162
177
  const rows = items.length === 0
163
178
  ? (
@@ -233,11 +248,21 @@ export function WebListView({
233
248
  });
234
249
 
235
250
  return (
236
- <Box id={listDomId} flexDirection="column" height={height} flexGrow={flexGrow} gap={1} role="listbox" aria-label={remoteLabel}>
237
- {scrollable ? (
251
+ <Box
252
+ id={listDomId}
253
+ flexDirection="column"
254
+ height={scrollable ? height : undefined}
255
+ // A list sized by its container gives up height to it, and scrolls.
256
+ minHeight={scrollable && height == null ? 0 : undefined}
257
+ flexGrow={flexGrow}
258
+ gap={1}
259
+ role="listbox"
260
+ aria-label={remoteLabel}
261
+ >
262
+ {scrolls ? (
238
263
  <ScrollBox
239
264
  ref={scrollRef}
240
- height={height}
265
+ height={scrollHeight}
241
266
  flexGrow={flexGrow}
242
267
  scrollY
243
268
  focusable={false}