gloomberb 0.18.2 → 0.18.4

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 (954) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -0,0 +1,187 @@
1
+ /**
2
+ * The launch frame's format and the inline script that draws it, for the
3
+ * page builds and the desktop Bun process; the DOM side that records it is
4
+ * boot-frame.ts.
5
+ */
6
+
7
+ export interface BootFrame {
8
+ /** The build that drew it; markup only matches the stylesheet it was drawn with. */
9
+ build: string;
10
+ width: number;
11
+ height: number;
12
+ /** The root element's inline style: the theme's colours. */
13
+ rootStyle: string;
14
+ /** The body's inline style: cell metrics and text size. */
15
+ bodyStyle: string;
16
+ html: string;
17
+ }
18
+
19
+ /** The element the page draws the frame in, over the app's root. */
20
+ export const BOOT_FRAME_ELEMENT_ID = "gloom-boot-frame";
21
+ /** Marks a copied box that was scrolled, as `top,left`, for the page to scroll it the same. */
22
+ export const BOOT_FRAME_SCROLL_ATTRIBUTE = "data-gloom-boot-scroll";
23
+ /** The page's build, which the inline script sets for the recorder to stamp frames with. */
24
+ export const BOOT_FRAME_BUILD_GLOBAL = "__gloomBootFrameBuild";
25
+ /** A frame's markup larger than this is not kept or drawn; a layout's chrome is a few dozen kilobytes. */
26
+ export const MAX_BOOT_FRAME_CHARS = 600_000;
27
+ /** The root and body styles: the theme's colours and the text metrics, a few kilobytes. */
28
+ const MAX_BOOT_FRAME_STYLE_CHARS = 20_000;
29
+ const MAX_BOOT_FRAME_BUILD_CHARS = 200;
30
+
31
+ function isPositiveSize(value: unknown): boolean {
32
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
33
+ }
34
+
35
+ /** A stored frame of the right shape and within the size limits. Anything else is not saved or drawn. */
36
+ export function isBootFrame(value: unknown): value is BootFrame {
37
+ if (!value || typeof value !== "object") return false;
38
+ const frame = value as Record<string, unknown>;
39
+ return typeof frame.build === "string" && frame.build.length <= MAX_BOOT_FRAME_BUILD_CHARS
40
+ && isPositiveSize(frame.width)
41
+ && isPositiveSize(frame.height)
42
+ && typeof frame.rootStyle === "string" && frame.rootStyle.length <= MAX_BOOT_FRAME_STYLE_CHARS
43
+ && typeof frame.bodyStyle === "string" && frame.bodyStyle.length <= MAX_BOOT_FRAME_STYLE_CHARS
44
+ && typeof frame.html === "string" && frame.html.length <= MAX_BOOT_FRAME_CHARS;
45
+ }
46
+
47
+ /**
48
+ * Strips a frame's markup, in `container` and the container itself, of
49
+ * everything that could load, run, navigate, take focus or be found as the
50
+ * app's own: elements that load or run, event handlers, links and sources,
51
+ * form targets, styles that fetch, ids and names. The recorder runs it on the
52
+ * copy it stores, and the page again on the copy it reads back, which is only
53
+ * as trustworthy as the file or storage it was kept in.
54
+ *
55
+ * The page's inline script carries this function's source, so it is plain
56
+ * JavaScript that reads nothing outside itself.
57
+ */
58
+ export function scrubBootFrame(container: ParentNode): void {
59
+ const droppedElements = [
60
+ "script", "noscript", "style", "link", "meta", "base", "title", "template", "slot",
61
+ "iframe", "frame", "frameset", "object", "embed", "applet", "param", "portal", "fencedframe",
62
+ "img", "image", "picture", "source", "track", "video", "audio", "canvas", "math",
63
+ "foreignobject", "use", "feimage", "animate", "animatemotion", "animatetransform", "animatecolor",
64
+ "set", "discard", "mpath", "handler", "listener",
65
+ ];
66
+ const droppedAttributes = [
67
+ "src", "srcset", "srcdoc", "action", "formaction", "poster", "background", "ping", "lowsrc",
68
+ "dynsrc", "data", "codebase", "classid", "archive", "longdesc", "usemap", "manifest", "is",
69
+ "id", "name", "tabindex", "autofocus", "contenteditable", "value",
70
+ "data-gloom-pane-id", "data-gloom-remote-node-id",
71
+ ];
72
+ // A style that could fetch: url(), image() and image-set() take addresses,
73
+ // and an escape could spell either past this check.
74
+ const fetchingStyle = /url\s*\(|image(-set)?\s*\(|\\|@import|expression\s*\(/i;
75
+ const scriptAddress = /^\s*(javascript|vbscript|data)\s*:/i;
76
+ const scrubElement = (element: Element) => {
77
+ for (const attribute of Array.from(element.attributes)) {
78
+ const name = attribute.name.toLowerCase();
79
+ const value = attribute.value;
80
+ if (
81
+ name.startsWith("on")
82
+ || name.endsWith("href")
83
+ || droppedAttributes.includes(name)
84
+ || /url\s*\(/i.test(value)
85
+ || scriptAddress.test(value)
86
+ || (name === "style" && fetchingStyle.test(value))
87
+ ) {
88
+ element.removeAttribute(attribute.name);
89
+ }
90
+ }
91
+ };
92
+ const self = container as unknown as Element;
93
+ if (self.nodeType === 1) scrubElement(self);
94
+ for (const element of Array.from(container.querySelectorAll("*"))) {
95
+ if (droppedElements.includes(element.localName.toLowerCase())) element.remove();
96
+ else scrubElement(element);
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Names the build a page comes from, from its script and stylesheet: a frame
102
+ * drawn by another build may not match the stylesheet it would be drawn with.
103
+ */
104
+ export function bootFrameBuildId(script: string | Uint8Array, stylesheet: string): string {
105
+ return `${Bun.hash(script).toString(36)}-${Bun.hash(stylesheet).toString(36)}`;
106
+ }
107
+
108
+ /** A JSON value safe inside an inline script. */
109
+ function scriptJson(value: unknown): string {
110
+ return JSON.stringify(value)
111
+ .replace(/</g, "\\u003c")
112
+ .replace(/\u2028/g, "\\u2028")
113
+ .replace(/\u2029/g, "\\u2029");
114
+ }
115
+
116
+ interface BootFrameScriptOptions {
117
+ build: string;
118
+ /** A JavaScript expression for the stored frame, evaluated inside a try. */
119
+ source: string;
120
+ /** A JavaScript expression that is true on a page that draws no frame, such as a window holding one popped-out pane. */
121
+ skip?: string;
122
+ /** The default theme's root style, for the bare shell drawn when there is no frame to redraw. */
123
+ shellStyle?: string;
124
+ }
125
+
126
+ /**
127
+ * The inline script that draws the frame, placed right after the app's root.
128
+ * A stored frame from this build for this window size is drawn as it was,
129
+ * after the page scrubs it again. Otherwise the page draws the bare shell:
130
+ * the header and status bar, empty, in the stored frame's theme and text
131
+ * size when there is one, else the default theme's.
132
+ */
133
+ export function bootFrameScript({ build, source, skip = "false", shellStyle = "" }: BootFrameScriptOptions): string {
134
+ return `(function () {
135
+ window.${BOOT_FRAME_BUILD_GLOBAL} = ${scriptJson(build)};
136
+ var root = document.getElementById("root");
137
+ var skip = false;
138
+ try { skip = !!(${skip}); } catch (error) { skip = false; }
139
+ if (!root || skip) return;
140
+ var frame = null;
141
+ try { frame = ${source}; } catch (error) { frame = null; }
142
+ var maxStyle = ${MAX_BOOT_FRAME_STYLE_CHARS};
143
+ if (!frame || typeof frame !== "object" || typeof frame.html !== "string" || frame.html.length > ${MAX_BOOT_FRAME_CHARS}
144
+ || typeof frame.rootStyle !== "string" || frame.rootStyle.length > maxStyle
145
+ || typeof frame.bodyStyle !== "string" || frame.bodyStyle.length > maxStyle) frame = null;
146
+ var scrub = ${scrubBootFrame.toString()};
147
+ // Parsed in a template, whose content is inert: nothing in it loads or runs before the scrub.
148
+ var template = document.createElement("template");
149
+ var safeStyle = function (style) {
150
+ var holder = template.content.ownerDocument.createElement("div");
151
+ holder.setAttribute("style", style);
152
+ scrub(holder);
153
+ return holder.getAttribute("style") || "";
154
+ };
155
+ var overlay = document.createElement("div");
156
+ overlay.id = ${scriptJson(BOOT_FRAME_ELEMENT_ID)};
157
+ // A picture of the app: nothing in it takes focus, a click or a screen reader.
158
+ overlay.setAttribute("inert", "");
159
+ overlay.setAttribute("aria-hidden", "true");
160
+ var rootStyle = frame ? safeStyle(frame.rootStyle) : "";
161
+ var bodyStyle = frame ? safeStyle(frame.bodyStyle) : "";
162
+ if (frame && frame.build === ${scriptJson(build)}
163
+ && Math.abs(frame.width - window.innerWidth) <= 1 && Math.abs(frame.height - window.innerHeight) <= 1) {
164
+ if (rootStyle) document.documentElement.setAttribute("style", rootStyle);
165
+ if (bodyStyle) document.body.setAttribute("style", bodyStyle);
166
+ overlay.setAttribute("data-gloom-boot-frame", "layout");
167
+ template.innerHTML = frame.html;
168
+ scrub(template.content);
169
+ overlay.appendChild(template.content);
170
+ } else {
171
+ // The default theme first, so a stored theme that names fewer colours still leaves every one set.
172
+ var shellStyle = ${scriptJson(shellStyle)};
173
+ var themeStyle = [shellStyle, rootStyle].join(" ").trim();
174
+ if (themeStyle && !document.documentElement.getAttribute("style")) document.documentElement.setAttribute("style", themeStyle);
175
+ if (bodyStyle) document.body.setAttribute("style", bodyStyle);
176
+ overlay.setAttribute("data-gloom-boot-frame", "shell");
177
+ overlay.innerHTML = '<div class="gloom-boot-header"></div><div class="gloom-boot-status"></div>';
178
+ }
179
+ root.parentNode.insertBefore(overlay, root.nextSibling);
180
+ var scrolled = overlay.querySelectorAll("[${BOOT_FRAME_SCROLL_ATTRIBUTE}]");
181
+ for (var index = 0; index < scrolled.length; index += 1) {
182
+ var offset = scrolled[index].getAttribute("${BOOT_FRAME_SCROLL_ATTRIBUTE}").split(",");
183
+ scrolled[index].scrollTop = Number(offset[0]) || 0;
184
+ scrolled[index].scrollLeft = Number(offset[1]) || 0;
185
+ }
186
+ })();`;
187
+ }
@@ -0,0 +1,237 @@
1
+ /**
2
+ * The layout a launch draws before the app is up.
3
+ *
4
+ * Loading the app's script and starting it takes a second or more, and the
5
+ * page used to say "Loading Gloomberb..." for that time. Instead the app keeps
6
+ * a copy of its own frame: the header, every pane's chrome with its title and
7
+ * tabs, the dividers and the status bar, with each pane's body and footer
8
+ * left empty. The page draws that copy before its script loads, over the
9
+ * root the app renders into, and the app takes it down the first frame it
10
+ * has drawn its own layout. The copy is redrawn only from the same build, in
11
+ * a window of the same size: anything else could put panes where the app
12
+ * will not. The page's side, the stored format and the script that draws
13
+ * it, is boot-frame-page.ts.
14
+ *
15
+ * Each host keeps the copy where its page can read it before any script has
16
+ * loaded: the web app in localStorage, the desktop app beside the remembered
17
+ * window frame, handed to the window as it opens.
18
+ */
19
+
20
+ import {
21
+ BOOT_FRAME_BUILD_GLOBAL,
22
+ BOOT_FRAME_ELEMENT_ID,
23
+ BOOT_FRAME_SCROLL_ATTRIBUTE,
24
+ MAX_BOOT_FRAME_CHARS,
25
+ scrubBootFrame,
26
+ type BootFrame,
27
+ } from "./boot-frame-page";
28
+
29
+ /** What a frame keeps: these elements, and the elements on the way to them. */
30
+ const FRAME_ROLES = ["app-header", "pane-window", "dock-divider", "status-bar"];
31
+ const FRAME_SELECTOR = FRAME_ROLES.map((role) => `[data-gloom-role="${role}"]`).join(", ");
32
+ /**
33
+ * Kept empty: pane bodies and footers are most of the page and are the data
34
+ * the app fills from its cache as it starts. The market state and SPY quote in
35
+ * the header, an update status said last session ("Restart to update") and
36
+ * the status bar's widgets (an unread count, the account) are not true at the
37
+ * next launch.
38
+ */
39
+ const EMPTIED_SELECTOR = [
40
+ "pane-body",
41
+ "pane-footer",
42
+ "header-market",
43
+ "header-update-status",
44
+ "status-widgets",
45
+ ].map((role) => `[data-gloom-role="${role}"]`).join(", ");
46
+
47
+ /** The build this page says it is, or null where no frame script ran (tests, other pages). */
48
+ function currentBootFrameBuild(win: Window = window): string | null {
49
+ const build = (win as unknown as Record<string, unknown>)[BOOT_FRAME_BUILD_GLOBAL];
50
+ return typeof build === "string" && build ? build : null;
51
+ }
52
+
53
+ const ELEMENT_NODE = 1;
54
+ const TEXT_NODE = 3;
55
+
56
+ /**
57
+ * Copies what the frame keeps of `node`: frame elements whole but for their
58
+ * data, and the elements on the way to them bare. Walks the live tree rather
59
+ * than cloning it all, so pane bodies (most of the page) are never copied.
60
+ */
61
+ function copyFrame(node: Node, insideFrame: boolean): Node | null {
62
+ if (node.nodeType === TEXT_NODE) return insideFrame ? node.cloneNode(false) : null;
63
+ if (node.nodeType !== ELEMENT_NODE) return null;
64
+ const element = node as Element;
65
+ const isFrame = insideFrame || element.matches(FRAME_SELECTOR);
66
+ if (!isFrame && element.querySelector(FRAME_SELECTOR) === null) return null;
67
+ const copy = element.cloneNode(false) as Element;
68
+ if (isFrame && element.matches(EMPTIED_SELECTOR)) return copy;
69
+ // A box scrolled by a pixel of overflow (the shell is) is drawn scrolled too.
70
+ if (element.scrollTop || element.scrollLeft) {
71
+ copy.setAttribute(BOOT_FRAME_SCROLL_ATTRIBUTE, `${Math.round(element.scrollTop)},${Math.round(element.scrollLeft)}`);
72
+ }
73
+ for (const child of element.childNodes) {
74
+ const childCopy = copyFrame(child, isFrame);
75
+ if (childCopy) copy.appendChild(childCopy);
76
+ }
77
+ return copy;
78
+ }
79
+
80
+ /**
81
+ * The app's frame as it is drawn now, or null when there is none to keep: no
82
+ * layout drawn yet, or a frame too large to store. A layout with every pane
83
+ * closed is kept as it is, so the next launch does not draw panes the user
84
+ * closed.
85
+ */
86
+ export function captureBootFrame(doc: Document, root: Element, build: string): BootFrame | null {
87
+ const view = doc.defaultView;
88
+ if (!view || !root.querySelector('[data-gloom-role="pane-window"], [data-gloom-role="status-bar"]')) return null;
89
+ const copy = copyFrame(root, false) as Element | null;
90
+ if (copy) scrubBootFrame(copy);
91
+ const html = copy?.innerHTML ?? "";
92
+ if (!html || html.length > MAX_BOOT_FRAME_CHARS) return null;
93
+ return {
94
+ build,
95
+ width: view.innerWidth,
96
+ height: view.innerHeight,
97
+ rootStyle: doc.documentElement.getAttribute("style") ?? "",
98
+ bodyStyle: doc.body.getAttribute("style") ?? "",
99
+ html,
100
+ };
101
+ }
102
+
103
+ /** The status bar's text but its widgets', which the frame leaves empty: a new unread count is not a new layout. */
104
+ function statusBarLabels(statusBar: Element): string {
105
+ return Array.from(statusBar.children)
106
+ .filter((child) => child.getAttribute("data-gloom-role") !== "status-widgets")
107
+ .map((child) => child.textContent ?? "")
108
+ .join("");
109
+ }
110
+
111
+ /**
112
+ * What would make a new frame differ from the last: the window, the theme
113
+ * and where each pane is and what it is called. Cheap enough to read every
114
+ * few seconds; the frame itself is only copied when this changes.
115
+ */
116
+ export function bootFrameSignature(doc: Document, root: Element): string {
117
+ const view = doc.defaultView;
118
+ const parts: string[] = [
119
+ `${view?.innerWidth ?? 0}x${view?.innerHeight ?? 0}`,
120
+ doc.documentElement.getAttribute("style") ?? "",
121
+ doc.body.getAttribute("style") ?? "",
122
+ ];
123
+ for (const element of root.querySelectorAll(
124
+ '[data-gloom-role="pane-window"], [data-gloom-role="dock-divider"], [data-gloom-role="status-bar"]',
125
+ )) {
126
+ const rect = element.getBoundingClientRect();
127
+ const role = element.getAttribute("data-gloom-role");
128
+ parts.push([
129
+ role,
130
+ Math.round(rect.x), Math.round(rect.y), Math.round(rect.width), Math.round(rect.height),
131
+ element.getAttribute("data-focused") ?? "",
132
+ role === "status-bar" ? statusBarLabels(element) : element.querySelector('[data-gloom-role="pane-header"]')?.textContent ?? "",
133
+ ].join(":"));
134
+ }
135
+ return parts.join("|");
136
+ }
137
+
138
+ const runningRecorders = new Set<() => void>();
139
+
140
+ /**
141
+ * Stops every recorder on the page for good, before the data is reset: a
142
+ * frame saved after the reset, as the page closes, would draw the old layout
143
+ * at the next launch.
144
+ */
145
+ export function stopBootFrameRecorders(): void {
146
+ for (const stop of [...runningRecorders]) stop();
147
+ }
148
+
149
+ interface BootFrameRecorderOptions {
150
+ doc: Document;
151
+ root: Element;
152
+ save(frame: BootFrame): void;
153
+ /** How often the layout is checked for a change. */
154
+ intervalMs?: number;
155
+ }
156
+
157
+ /**
158
+ * Keeps the stored frame current: shortly after the app is up, whenever the
159
+ * layout settles into something new, and as the page is hidden or closed.
160
+ * Does nothing on a page that drew no frame script, which is how a desktop
161
+ * pop-out window, a test or a share page stays out of it.
162
+ */
163
+ export function startBootFrameRecorder({
164
+ doc,
165
+ root,
166
+ save,
167
+ intervalMs = 10_000,
168
+ }: BootFrameRecorderOptions): () => void {
169
+ const view = doc.defaultView;
170
+ const build = view ? currentBootFrameBuild(view) : null;
171
+ if (!view || !build) return () => {};
172
+ let lastSignature = "";
173
+ let stopped = false;
174
+ const record = () => {
175
+ if (stopped) return;
176
+ const signature = bootFrameSignature(doc, root);
177
+ if (signature === lastSignature) return;
178
+ const frame = captureBootFrame(doc, root, build);
179
+ if (!frame) return;
180
+ lastSignature = signature;
181
+ save(frame);
182
+ };
183
+ const recordWhenIdle = () => {
184
+ if (doc.visibilityState === "hidden") return;
185
+ const idle = (view as Window & { requestIdleCallback?: (callback: () => void, options?: { timeout: number }) => number }).requestIdleCallback;
186
+ if (idle) idle.call(view, record, { timeout: 2_000 });
187
+ else record();
188
+ };
189
+ const onHidden = () => {
190
+ if (doc.visibilityState === "hidden") record();
191
+ };
192
+ const first = view.setTimeout(recordWhenIdle, 3_000);
193
+ const interval = view.setInterval(recordWhenIdle, intervalMs);
194
+ doc.addEventListener("visibilitychange", onHidden);
195
+ view.addEventListener("pagehide", record);
196
+ const stop = () => {
197
+ stopped = true;
198
+ runningRecorders.delete(stop);
199
+ view.clearTimeout(first);
200
+ view.clearInterval(interval);
201
+ doc.removeEventListener("visibilitychange", onHidden);
202
+ view.removeEventListener("pagehide", record);
203
+ };
204
+ runningRecorders.add(stop);
205
+ return stop;
206
+ }
207
+
208
+ /**
209
+ * Takes the launch frame down as the app draws its own layout, or a failure
210
+ * screen, in `root`. Until then the frame covers the app, so the user never
211
+ * sees it half built. Mutation observers run before the page paints, so the
212
+ * frame goes in the paint that shows the layout, not a frame after it.
213
+ * Returns a function that takes the frame down now, for a page that gives
214
+ * up on starting.
215
+ */
216
+ export function releaseBootFrameWhenDrawn(doc: Document, root: Element): () => void {
217
+ const view = doc.defaultView;
218
+ const frame = doc.getElementById(BOOT_FRAME_ELEMENT_ID);
219
+ if (!view || !frame) return () => {};
220
+ let released = false;
221
+ const release = () => {
222
+ if (released) return;
223
+ released = true;
224
+ observer.disconnect();
225
+ frame.remove();
226
+ };
227
+ const drawn = () => root.querySelector(
228
+ '[data-gloom-role="pane-window"], [data-gloom-role="status-bar"], .gloom-fatal',
229
+ ) !== null;
230
+ const observer = new view.MutationObserver(() => {
231
+ if (drawn()) release();
232
+ });
233
+ observer.observe(root, { childList: true, subtree: true });
234
+ if (drawn()) release();
235
+ return release;
236
+ }
237
+
@@ -2,6 +2,10 @@ import { readFile, writeFile } from "fs/promises";
2
2
  import { dirname, join, relative, resolve } from "path";
3
3
  import type { BunPlugin } from "bun";
4
4
  import { TITLEBAR_OVERLAY_HEIGHT_PX } from "../../components/layout/titlebar-overlay";
5
+ import { getThemeColors } from "../../theme/colors";
6
+ import { themeCssVariables } from "../../theme/ui-tokens";
7
+ import { DEFAULT_THEME } from "../../theme/themes";
8
+ import { bootFrameBuildId, bootFrameScript } from "./boot-frame-page";
5
9
 
6
10
  /** Imports whose path ends with the first entry resolve to the second, relative to the view directory. */
7
11
  type AliasRule = readonly [string, string];
@@ -12,10 +16,19 @@ type PageOptions = {
12
16
  failureMessage: string;
13
17
  missingEntryMessage: string;
14
18
  title: string;
15
- loadingText: string;
19
+ /** Text the page shows until its script draws, for a page with no launch frame. */
20
+ loadingText?: string;
16
21
  bootstrapScript: string;
22
+ /** Draw the launch frame (boot-frame.ts) from where this host keeps it. */
23
+ bootFrame?: PageBootFrame;
17
24
  };
18
25
 
26
+ /** Where a page reads its launch frame from: JavaScript expressions run before its script loads. */
27
+ export interface PageBootFrame {
28
+ source: string;
29
+ skip?: string;
30
+ }
31
+
19
32
  interface ViewBundleOptions {
20
33
  entrypoint: string;
21
34
  outdir: string;
@@ -40,7 +53,7 @@ function minifyOption(keepNames: boolean | undefined) {
40
53
  }
41
54
 
42
55
  // From this file rather than the working directory, so a build started from
43
- // any folder (`gloomberb shot` run from a checkout or a package install) finds
56
+ // any folder (`gloom shot` run from a checkout or a package install) finds
44
57
  // the sources.
45
58
  const ELECTROBUN_VIEW_DIR = join(import.meta.dir, "..", "electrobun", "view");
46
59
 
@@ -109,7 +122,7 @@ export async function buildViewBundle({
109
122
  }
110
123
 
111
124
  export async function writeElectrobunViewPage(options: PageOptions): Promise<string> {
112
- const { script } = await buildViewBundle({
125
+ const { script, stylesheet: bundledStylesheet } = await buildViewBundle({
113
126
  entrypoint: options.entrypoint,
114
127
  outdir: options.outdir,
115
128
  aliasRules: options.aliasRules,
@@ -125,23 +138,48 @@ export async function writeElectrobunViewPage(options: PageOptions): Promise<str
125
138
  const stylesheet = await readViewStylesheet();
126
139
  const entrySrc = `./${relative(options.outdir, script).replaceAll("\\", "/")}`;
127
140
  const htmlPath = join(options.outdir, "index.html");
128
- await writeFile(htmlPath, renderElectrobunViewHtml({ ...options, stylesheet, entrySrc }));
141
+ const bootFrame = options.bootFrame
142
+ ? { ...options.bootFrame, build: await pageBuildId(script, bundledStylesheet ?? null, stylesheet) }
143
+ : undefined;
144
+ await writeFile(htmlPath, renderElectrobunViewHtml({ ...options, stylesheet, entrySrc, bootFrame }));
129
145
  return htmlPath;
130
146
  }
131
147
 
148
+ /** Names a page's build for its launch frame, from the files that draw it. */
149
+ export async function pageBuildId(script: string, stylesheetPath: string | null, inlineStylesheet = ""): Promise<string> {
150
+ const css = (stylesheetPath ? await readFile(stylesheetPath, "utf8") : "") + inlineStylesheet;
151
+ return bootFrameBuildId(await readFile(script), css);
152
+ }
153
+
154
+ /** The launch frame's inline script, with the default theme's colours for the bare shell. */
155
+ export function pageBootFrameScript(bootFrame: PageBootFrame & { build: string }): string {
156
+ const shellStyle = themeCssVariables(getThemeColors(DEFAULT_THEME)).map(([name, value]) => `${name}: ${value};`).join(" ");
157
+ return bootFrameScript({ ...bootFrame, shellStyle });
158
+ }
159
+
132
160
  /** The DOM renderer's stylesheet, sized for the titlebar, which a view page inlines. */
133
161
  export async function readViewStylesheet(): Promise<string> {
134
162
  return withTitlebarOverlayHeight(await readFile(join(DOM_RENDERER_DIR, "styles.css"), "utf8"));
135
163
  }
136
164
 
137
- /** A view page: the stylesheet inline, the bootstrap script, then the bundle at `entrySrc`. */
165
+ /**
166
+ * A view page: the stylesheet inline, the bootstrap script, the launch frame
167
+ * when the page has one, then the bundle at `entrySrc`.
168
+ */
138
169
  export function renderElectrobunViewHtml({
139
170
  title,
140
171
  loadingText,
141
172
  stylesheet,
142
173
  bootstrapScript,
174
+ bootFrame,
143
175
  entrySrc,
144
- }: Pick<PageOptions, "title" | "loadingText" | "bootstrapScript"> & { stylesheet: string; entrySrc: string }): string {
176
+ }: Pick<PageOptions, "title" | "loadingText" | "bootstrapScript"> & {
177
+ stylesheet: string;
178
+ entrySrc: string;
179
+ bootFrame?: PageBootFrame & { build: string };
180
+ }): string {
181
+ const loading = loadingText ? `<div class="gloom-loading">${loadingText}</div>` : "";
182
+ const frameScript = bootFrame ? `\n <script>\n${pageBootFrameScript(bootFrame)}\n </script>` : "";
145
183
  return `<!doctype html>
146
184
  <html lang="en">
147
185
  <head>
@@ -151,10 +189,10 @@ export function renderElectrobunViewHtml({
151
189
  <style>${stylesheet}</style>
152
190
  </head>
153
191
  <body style="margin:0;background:#000;">
154
- <div id="root"><div class="gloom-loading">${loadingText}</div></div>
192
+ <div id="root">${loading}</div>
155
193
  <script>
156
194
  ${bootstrapScript}
157
- </script>
195
+ </script>${frameScript}
158
196
  <script type="module" src="${entrySrc}"></script>
159
197
  </body>
160
198
  </html>
@@ -670,7 +670,7 @@ export function WebPageStackView({
670
670
  return (
671
671
  <Box flexDirection="column" flexGrow={1} flexShrink={1} flexBasis={0} minWidth={0} minHeight={0} overflow="hidden">
672
672
  {!headerAttached && (
673
- <div className="gloom-stack-bar" data-gloom-role="page-stack-header">
673
+ <div className="gloom-stack-bar" data-gloom-role="page-stack-header" data-gloom-top-surface="">
674
674
  <button
675
675
  type="button"
676
676
  className="gloom-stack-back"
@@ -290,6 +290,8 @@ export function WebQueryBar({ search, items, view, onClearAll, meta, leading, op
290
290
  ref={rootRef}
291
291
  className="gloom-qb"
292
292
  data-gloom-role="query-bar"
293
+ // The active title-bar tab above takes this band's colour (top-surface.ts).
294
+ data-gloom-top-surface=""
293
295
  // A search with nothing beside it may take the room the filters would.
294
296
  data-search-only={search && items.length === 0 && !view ? "true" : undefined}
295
297
  >
@@ -1,5 +1,5 @@
1
1
  /** @jsxImportSource react */
2
- import { useEffect, useState, type CSSProperties, type ReactNode } from "react";
2
+ import type { CSSProperties } from "react";
3
3
  import type { UiHost } from "../../ui/host";
4
4
  import { WEB_CELL_HEIGHT, WEB_CELL_WIDTH } from "../../theme/font-scale";
5
5
  import { detectPlatform } from "../../utils/platform";
@@ -26,9 +26,10 @@ import { WebBox } from "./host/box";
26
26
  import { WebChartSurface } from "./host/chart-surface";
27
27
  import { WebSurface3D } from "./host/surface-3d";
28
28
  import { WebInput, WebTextarea } from "./host/input";
29
+ import { WebImageSurface } from "./host/image-surface";
29
30
  import { WebMediaSurface } from "./host/media-surface";
30
31
  import { WebScrollBox } from "./host/scroll-box";
31
- import { cleanDomProps, commonStyle } from "./host/style";
32
+ import { cleanDomProps } from "./host/style";
32
33
  import { WebAsciiText, WebSpan, WebStrong, WebText, WebUnderline } from "./host/text";
33
34
  import { WebTabs } from "./host/tabs";
34
35
 
@@ -97,33 +98,7 @@ export function createDomUiHost(
97
98
  Tabs: WebTabs,
98
99
  ChartSurface: WebChartSurface,
99
100
  Surface3D: WebSurface3D,
100
- ImageSurface: ({ children, src, alt = "", objectFit = "contain", ...props }) => {
101
- const imageSrc = typeof src === "string" ? src.trim() : "";
102
- const [failed, setFailed] = useState(false);
103
- useEffect(() => setFailed(false), [imageSrc]);
104
- const baseStyle = commonStyle(props);
105
- return (
106
- <div
107
- {...cleanDomProps(props)}
108
- style={{
109
- ...baseStyle,
110
- overflow: baseStyle.overflow ?? "hidden",
111
- ...(props.style as CSSProperties | undefined),
112
- }}
113
- >
114
- {imageSrc && !failed ? (
115
- <img
116
- key={imageSrc}
117
- src={imageSrc}
118
- alt={alt}
119
- draggable={false}
120
- onError={() => setFailed(true)}
121
- style={{ width: "100%", height: "100%", display: "block", objectFit }}
122
- />
123
- ) : children as ReactNode}
124
- </div>
125
- );
126
- },
101
+ ImageSurface: WebImageSurface,
127
102
  MediaSurface: WebMediaSurface,
128
103
  AudioPlayer: WebAudioPlayer,
129
104
  SpinnerMark: ({ color, ...props }) => (
@@ -9,6 +9,20 @@ const WEB_GLOOMBERB_WORDMARK = [
9
9
  " \\____|_|\\___/ \\___/|_| |_| |_|_.__/ \\___|_| |_.__/ ",
10
10
  ];
11
11
 
12
+ const WEB_GLOOM_WORDMARK = [
13
+ " ____ _ ",
14
+ " / ___| | ___ ___ _ __ ___ ",
15
+ "| | _| |/ _ \\ / _ \\| '_ ` _ \\ ",
16
+ "| |_| | | (_) | (_) | | | | | |",
17
+ " \\____|_|\\___/ \\___/|_| |_| |_|",
18
+ ];
19
+
20
+ /** The web wordmarks, by the text they spell. */
21
+ const WEB_WORDMARKS = new Map<string, string[]>([
22
+ ["gloom", WEB_GLOOM_WORDMARK],
23
+ ["gloomberb", WEB_GLOOMBERB_WORDMARK],
24
+ ]);
25
+
12
26
  type WebWordmarkVariant = "legacy" | "compat" | null;
13
27
 
14
28
  /**
@@ -22,7 +36,7 @@ export function webAsciiTextWordmarkVariant(
22
36
  font: AsciiFontName = "tiny",
23
37
  desktopPlatform?: string,
24
38
  ): WebWordmarkVariant {
25
- if (font !== "wordmark" || text.trim().toLowerCase() !== "gloomberb") return null;
39
+ if (font !== "wordmark" || !WEB_WORDMARKS.has(text.trim().toLowerCase())) return null;
26
40
  return detectPlatform(desktopPlatform) === "darwin" ? "legacy" : "compat";
27
41
  }
28
42
 
@@ -32,6 +46,6 @@ export function webAsciiTextLines(
32
46
  desktopPlatform?: string,
33
47
  ): string[] {
34
48
  return webAsciiTextWordmarkVariant(text, font, desktopPlatform) === "compat"
35
- ? WEB_GLOOMBERB_WORDMARK
49
+ ? WEB_WORDMARKS.get(text.trim().toLowerCase())!
36
50
  : renderAsciiText(text, font);
37
51
  }