gloomberb 0.16.4 → 0.16.6

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 (852) hide show
  1. package/README.md +14 -91
  2. package/package.json +5 -1
  3. package/src/{plugins/builtin/cloud → account}/auth-form.tsx +9 -9
  4. package/src/{plugins/builtin/cloud → account}/auth-model.ts +4 -4
  5. package/src/account/billing.ts +57 -0
  6. package/src/{plugins/builtin/cloud → account}/device-signin-dialog.tsx +18 -12
  7. package/src/{plugins/builtin/cloud → account}/device-signin.ts +2 -2
  8. package/src/{plugins/builtin/cloud → account}/email-auth-attempt.ts +2 -2
  9. package/src/account/session.ts +16 -0
  10. package/src/{plugins/builtin/cloud → account}/upgrade-dialog.tsx +16 -15
  11. package/src/{plugins/builtin/cloud → account}/upgrade-personalization.ts +7 -7
  12. package/src/{plugins/builtin/cloud → account}/upgrade-tickers.ts +6 -6
  13. package/src/{plugins/builtin/cloud → account}/verification-panel.tsx +6 -6
  14. package/src/api-client/central-bank-rates.ts +6 -1
  15. package/src/api-client/chat.ts +26 -0
  16. package/src/api-client/credit-boards.ts +2 -0
  17. package/src/api-client/data.ts +73 -3
  18. package/src/api-client/earnings.ts +6 -0
  19. package/src/api-client/europe-energy.ts +106 -0
  20. package/src/api-client/futures-curve.ts +56 -0
  21. package/src/api-client/index.ts +13 -1
  22. package/src/api-client/market-discovery.ts +13 -1
  23. package/src/api-client/normalizers.ts +32 -0
  24. package/src/api-client/paths.ts +7 -0
  25. package/src/api-client/perps.ts +8 -0
  26. package/src/api-client/request.ts +9 -2
  27. package/src/api-client/research-activity.ts +15 -10
  28. package/src/api-client/socket.ts +29 -0
  29. package/src/api-client/themes.ts +22 -1
  30. package/src/api-client/types.ts +78 -2
  31. package/src/api-client/yield-curves.ts +8 -0
  32. package/src/app/global-shortcuts.ts +50 -2
  33. package/src/app/keybindings/actions.ts +12 -1
  34. package/src/app/pane-runtime/plugin-bindings.ts +2 -2
  35. package/src/app/pane-runtime/ticker-open-runtime.ts +16 -6
  36. package/src/app/runtime/desktop-deeplink.ts +10 -5
  37. package/src/app/runtime/startup.ts +1 -1
  38. package/src/app.tsx +6 -0
  39. package/src/architecture/core-builtin-allowlist.json +8 -26
  40. package/src/ask-gloom/pane-context.ts +114 -0
  41. package/src/ask-gloom/pane-request.ts +70 -0
  42. package/src/ask-gloom/pane-text.ts +201 -0
  43. package/src/brokers/signed-in/sign-in-dialog.tsx +11 -5
  44. package/src/capabilities/chart-series.ts +19 -2
  45. package/src/capabilities/factories.ts +1 -0
  46. package/src/cli/central-bank-events.ts +23 -0
  47. package/src/cli/command-options.ts +17 -5
  48. package/src/cli/commands/crypto-hints.ts +35 -2
  49. package/src/cli/commands/fred-series.ts +146 -0
  50. package/src/cli/commands/market.ts +501 -115
  51. package/src/cli/commands/news-hints.ts +62 -0
  52. package/src/cli/commands/news-search.ts +53 -0
  53. package/src/cli/commands/options-leaps.ts +5 -2
  54. package/src/cli/commands/overview.ts +132 -26
  55. package/src/cli/commands/remote.ts +2 -1
  56. package/src/cli/commands/search.ts +317 -13
  57. package/src/cli/commands/system.ts +55 -8
  58. package/src/cli/commands/ticker.ts +155 -18
  59. package/src/cli/context.ts +45 -14
  60. package/src/cli/desktop-pane-shot.ts +76 -7
  61. package/src/cli/earnings-calendar.ts +71 -0
  62. package/src/cli/errors.ts +7 -5
  63. package/src/cli/exit-codes.ts +8 -0
  64. package/src/cli/export-source.ts +58 -0
  65. package/src/cli/freshness.ts +18 -7
  66. package/src/cli/glossary.ts +483 -0
  67. package/src/cli/help.ts +10 -0
  68. package/src/cli/helpers.ts +2 -5
  69. package/src/cli/history-rows.ts +118 -7
  70. package/src/cli/index-roots.ts +7 -0
  71. package/src/cli/index.ts +29 -9
  72. package/src/cli/known-gaps.ts +84 -0
  73. package/src/cli/listing-arg.ts +551 -97
  74. package/src/cli/not-a-ticker.ts +24 -9
  75. package/src/cli/pane-functions/access-gate.ts +13 -2
  76. package/src/cli/pane-functions/capabilities.ts +4 -3
  77. package/src/cli/pane-functions/catalog.ts +214 -40
  78. package/src/cli/pane-functions/data.ts +42 -8
  79. package/src/cli/pane-functions/discovery.ts +1 -0
  80. package/src/cli/pane-functions/dom.ts +37 -8
  81. package/src/cli/pane-functions/freshness.ts +393 -49
  82. package/src/cli/pane-functions/function-help.ts +31 -15
  83. package/src/cli/pane-functions/headless.ts +98 -30
  84. package/src/cli/pane-functions/index.ts +101 -19
  85. package/src/cli/pane-functions/market-session.ts +22 -8
  86. package/src/cli/pane-functions/options.ts +71 -22
  87. package/src/cli/pane-functions/report-notices.ts +25 -7
  88. package/src/cli/pane-functions/report.ts +15 -8
  89. package/src/cli/pane-functions/resolver.ts +74 -19
  90. package/src/cli/pane-functions/screenshot.ts +250 -27
  91. package/src/cli/perpetual-contract.ts +60 -0
  92. package/src/cli/registry.ts +3 -1
  93. package/src/cli/report-tables.ts +26 -7
  94. package/src/cli/result.ts +45 -11
  95. package/src/cli/series-search.ts +111 -0
  96. package/src/cli/staged-tickers.ts +52 -0
  97. package/src/cli/symbol-args.ts +27 -0
  98. package/src/cli/symbol-list.ts +154 -0
  99. package/src/cli/symbol-rows.ts +154 -0
  100. package/src/cli/ticker-resolution.ts +311 -27
  101. package/src/cli/types.ts +5 -0
  102. package/src/components/chart/composite/axis-overlays.tsx +14 -3
  103. package/src/components/chart/composite/composite-chart.tsx +71 -11
  104. package/src/components/chart/composite/crosshair-readout.tsx +150 -0
  105. package/src/components/chart/composite/downsample.ts +1 -1
  106. package/src/components/chart/composite/format.ts +29 -0
  107. package/src/components/chart/composite/interactions.ts +9 -2
  108. package/src/components/chart/composite/legend.tsx +100 -33
  109. package/src/components/chart/composite/panel-bitmap.ts +70 -35
  110. package/src/components/chart/composite/panel-labels.ts +18 -17
  111. package/src/components/chart/composite/panel-series.ts +1 -0
  112. package/src/components/chart/composite/panel-surface.tsx +46 -21
  113. package/src/components/chart/composite/price-axis-labels.tsx +3 -1
  114. package/src/components/chart/composite/rasterizer.ts +50 -8
  115. package/src/components/chart/composite/scene.ts +2 -1
  116. package/src/components/chart/composite/time-scale.ts +26 -9
  117. package/src/components/chart/composite/types.ts +18 -0
  118. package/src/components/chart/composite/use-composite-viewport.ts +30 -2
  119. package/src/components/chart/native/raster/crosshair.ts +8 -3
  120. package/src/components/chart/native/raster/primitives.ts +85 -21
  121. package/src/components/chart/native/surface/manager.ts +33 -8
  122. package/src/components/chart/surface3d/chart.tsx +1 -1
  123. package/src/components/command-bar/action-runtime.ts +1 -1
  124. package/src/components/command-bar/commands/collection-list.ts +210 -0
  125. package/src/components/command-bar/commands/collection.ts +40 -1
  126. package/src/components/command-bar/commands/direct/index.ts +4 -0
  127. package/src/components/command-bar/commands/registry.ts +8 -0
  128. package/src/components/command-bar/panel/index.tsx +11 -3
  129. package/src/components/command-bar/panel/runtime.ts +3 -0
  130. package/src/components/command-bar/panel/types.ts +2 -0
  131. package/src/components/command-bar/routes/root/plugin-install.ts +4 -4
  132. package/src/components/command-bar/routes/root/provider-search.ts +4 -3
  133. package/src/components/command-bar/routes/ticker-search/results.ts +12 -11
  134. package/src/components/command-bar/routes/ticker-search/route.ts +4 -3
  135. package/src/components/command-bar/routing/actions.ts +1 -1
  136. package/src/components/command-bar/workflow/tickers.ts +42 -17
  137. package/src/components/layout/detached-pane-shell.tsx +68 -39
  138. package/src/components/layout/floating-pane.tsx +10 -1
  139. package/src/components/layout/header.tsx +25 -5
  140. package/src/components/layout/missing-pane.tsx +3 -3
  141. package/src/components/layout/pane/capture-stamp.ts +41 -0
  142. package/src/components/layout/pane/capture-status.ts +12 -0
  143. package/src/components/layout/pane/content.tsx +7 -13
  144. package/src/components/layout/pane/footer/index.tsx +6 -2
  145. package/src/components/layout/pane/footer/keyboard.ts +3 -0
  146. package/src/components/layout/pane/footer/model.ts +41 -1
  147. package/src/components/layout/pane/header.tsx +50 -1
  148. package/src/components/layout/pane/index.tsx +21 -3
  149. package/src/components/layout/pane/sidebar.tsx +88 -21
  150. package/src/components/layout/shell/active-drag.ts +21 -5
  151. package/src/components/layout/shell/cursor-occlusion.ts +2 -1
  152. package/src/components/layout/shell/drag/index.ts +39 -9
  153. package/src/components/layout/shell/drag/live.ts +61 -51
  154. package/src/components/layout/shell/drag/runtime.ts +54 -12
  155. package/src/components/layout/shell/index.tsx +84 -65
  156. package/src/components/layout/shell/menu.ts +14 -1
  157. package/src/components/layout/shell/native/pointer-runtime.ts +3 -1
  158. package/src/components/layout/shell/pane/actions.ts +32 -10
  159. package/src/components/layout/shell/pane/ask.ts +131 -0
  160. package/src/components/layout/shell/pane/capture.ts +162 -0
  161. package/src/components/layout/shell/pane/layers.tsx +218 -50
  162. package/src/components/layout/shell/pane/management-shortcuts.ts +46 -1
  163. package/src/components/layout/shell/shortcuts.ts +21 -4
  164. package/src/components/layout/shell/terminal-pointer-runtime.ts +24 -0
  165. package/src/components/markdown-text.tsx +62 -20
  166. package/src/components/metric-treemap/heat-surface.tsx +8 -1
  167. package/src/components/onboarding/account-step/form-panel.tsx +1 -1
  168. package/src/components/onboarding/account-step/index.tsx +1 -1
  169. package/src/components/onboarding/account-step/qr-panel.tsx +1 -1
  170. package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
  171. package/src/components/onboarding/onboarding-keyboard.ts +1 -1
  172. package/src/components/onboarding/onboarding-wizard.tsx +2 -2
  173. package/src/components/onboarding/use-onboarding-upgrade.ts +3 -3
  174. package/src/components/onboarding/wizard-account.ts +2 -2
  175. package/src/components/pane-template-wizard.tsx +9 -1
  176. package/src/components/price-selector-dialog.tsx +11 -2
  177. package/src/components/reader/article-reader.tsx +642 -0
  178. package/src/components/reader/article-text.ts +527 -0
  179. package/src/components/sign-in-gate.tsx +3 -3
  180. package/src/components/ticker/list-table-view.tsx +43 -2
  181. package/src/components/ui/action-row.tsx +2 -1
  182. package/src/components/ui/button.tsx +7 -1
  183. package/src/components/ui/choice-dialog.tsx +6 -4
  184. package/src/components/ui/confirm-dialog.tsx +28 -18
  185. package/src/components/ui/data-table/index.tsx +18 -6
  186. package/src/components/ui/data-table/opentui/index.tsx +37 -6
  187. package/src/components/ui/data-table/types.ts +12 -0
  188. package/src/components/ui/dialog-actions.tsx +64 -0
  189. package/src/components/ui/display.tsx +17 -3
  190. package/src/components/ui/frame.tsx +35 -2
  191. package/src/components/ui/icon.tsx +6 -1
  192. package/src/components/ui/query-bar.tsx +10 -1
  193. package/src/components/ui/text-prompt-dialog.tsx +11 -9
  194. package/src/data/cached-query.ts +2 -0
  195. package/src/data/config/store/migrations.ts +7 -0
  196. package/src/data/config/store/normalize.ts +7 -2
  197. package/src/data/config/store/portfolio-as-of-column.ts +57 -0
  198. package/src/data/ticker-repository.ts +5 -0
  199. package/src/data/ticker-store.ts +15 -0
  200. package/src/docs/content.ts +215 -0
  201. package/src/docs/load.ts +139 -0
  202. package/src/docs/requests.ts +39 -0
  203. package/src/docs/snapshot.chunk.ts +8 -0
  204. package/src/docs/snapshot.json +7555 -0
  205. package/src/docs/topics.ts +216 -0
  206. package/src/i18n/es.ts +65 -5
  207. package/src/i18n/ja.ts +65 -5
  208. package/src/i18n/ko.ts +65 -5
  209. package/src/i18n/zh-cn.ts +65 -5
  210. package/src/i18n/zh-tw.ts +65 -5
  211. package/src/layout/desks.ts +1 -1
  212. package/src/layout/pane-manager/dock-tree.ts +18 -0
  213. package/src/layout/pane-manager/index.ts +1 -0
  214. package/src/layout-marketplace/gallery.tsx +1 -1
  215. package/src/market-data/coordinator/chart.ts +10 -4
  216. package/src/market-data/coordinator/index.ts +6 -3
  217. package/src/{plugins/builtin/futures/contracts.ts → market-data/futures-board.ts} +81 -28
  218. package/src/market-data/futures-contract.ts +151 -0
  219. package/src/market-data/hooks.tsx +10 -2
  220. package/src/market-data/market/format.ts +39 -21
  221. package/src/market-data/market/freshness.ts +84 -20
  222. package/src/market-data/market/session-close-note.ts +3 -2
  223. package/src/market-data/market/status.ts +19 -23
  224. package/src/market-data/published-apac-sessions.ts +23 -1
  225. package/src/market-data/quotes/contributions.ts +5 -0
  226. package/src/market-data/quotes/metadata.ts +19 -24
  227. package/src/market-data/quotes/resolution.ts +5 -0
  228. package/src/market-data/quotes/screener-live-quotes.ts +5 -4
  229. package/src/market-data/result-types.ts +2 -0
  230. package/src/notifications/app-notifier.ts +17 -1
  231. package/src/notifications/notification-log.ts +180 -0
  232. package/src/plugins/auto-update-node.ts +2 -2
  233. package/src/plugins/auto-update.ts +2 -2
  234. package/src/plugins/builtin/account-management/index.tsx +1 -0
  235. package/src/plugins/builtin/account-management/model.ts +1 -56
  236. package/src/plugins/builtin/account-management/pane.tsx +6 -4
  237. package/src/plugins/builtin/account-management/password-dialog.tsx +1 -1
  238. package/src/plugins/builtin/alerts/catalysts.ts +1 -1
  239. package/src/plugins/builtin/alerts/cli.ts +313 -47
  240. package/src/plugins/builtin/alerts/events-pane.tsx +45 -7
  241. package/src/plugins/builtin/alerts/events.ts +23 -2
  242. package/src/plugins/builtin/alerts/focus.ts +27 -0
  243. package/src/plugins/builtin/alerts/history-pane.tsx +7 -2
  244. package/src/plugins/builtin/alerts/history.ts +2 -0
  245. package/src/plugins/builtin/alerts/index.tsx +47 -11
  246. package/src/plugins/builtin/alerts/pane.tsx +27 -1
  247. package/src/plugins/builtin/alerts/research-builder.ts +8 -3
  248. package/src/plugins/builtin/alerts/research-rules.ts +18 -2
  249. package/src/plugins/builtin/alerts/scheduled-check.ts +122 -0
  250. package/src/plugins/builtin/alerts/scheduled-sources.ts +25 -0
  251. package/src/plugins/builtin/alerts/scheduled.ts +254 -0
  252. package/src/plugins/builtin/alerts/targets.ts +92 -0
  253. package/src/plugins/builtin/analytics/index.tsx +8 -3
  254. package/src/plugins/builtin/analytics/risk-headless.ts +60 -27
  255. package/src/plugins/builtin/analytics/risk-math.ts +91 -27
  256. package/src/plugins/builtin/analytics/risk-model.ts +35 -5
  257. package/src/plugins/builtin/analytics/risk-pane.tsx +15 -8
  258. package/src/plugins/builtin/attention/headless.ts +1 -1
  259. package/src/plugins/builtin/attention/index.tsx +2 -0
  260. package/src/plugins/builtin/attention/pane.tsx +3 -1
  261. package/src/plugins/builtin/attention/series.ts +26 -0
  262. package/src/plugins/builtin/awards/headless.ts +88 -18
  263. package/src/plugins/builtin/awards/index.tsx +2 -0
  264. package/src/plugins/builtin/awards/model.ts +41 -1
  265. package/src/plugins/builtin/awards/pane.tsx +22 -13
  266. package/src/plugins/builtin/awards/series.ts +29 -0
  267. package/src/plugins/builtin/backtest/headless.ts +2 -2
  268. package/src/plugins/builtin/bond-calculator/model.ts +2 -1
  269. package/src/plugins/builtin/broker-manager/index.tsx +1 -0
  270. package/src/plugins/builtin/catalysts/headless.ts +1 -1
  271. package/src/plugins/builtin/catalysts/pane.tsx +3 -1
  272. package/src/plugins/builtin/cds/client.ts +49 -12
  273. package/src/plugins/builtin/cds/headless.ts +119 -19
  274. package/src/plugins/builtin/cds/index.tsx +3 -1
  275. package/src/plugins/builtin/cds/model.ts +214 -32
  276. package/src/plugins/builtin/cds/pane.tsx +58 -14
  277. package/src/plugins/builtin/cds/series.ts +19 -0
  278. package/src/plugins/builtin/central-bank-rates/client.ts +4 -0
  279. package/src/plugins/builtin/central-bank-rates/headless.ts +46 -16
  280. package/src/plugins/builtin/central-bank-rates/index.tsx +3 -1
  281. package/src/plugins/builtin/central-bank-rates/model.ts +99 -0
  282. package/src/plugins/builtin/central-bank-rates/pane.tsx +1 -1
  283. package/src/plugins/builtin/central-bank-rates/series.ts +36 -0
  284. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +193 -255
  285. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +84 -46
  286. package/src/plugins/builtin/chart-composer/editor.tsx +5 -4
  287. package/src/plugins/builtin/chart-composer/field-series.ts +40 -0
  288. package/src/plugins/builtin/chart-composer/headless-schema.ts +1 -1
  289. package/src/plugins/builtin/chart-composer/headless.ts +70 -5
  290. package/src/plugins/builtin/chart-composer/index.tsx +15 -3
  291. package/src/plugins/builtin/chart-composer/pane.tsx +81 -38
  292. package/src/plugins/builtin/chart-composer/series-catalog.ts +58 -50
  293. package/src/plugins/builtin/chart-composer/series-expression.ts +18 -10
  294. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +59 -3
  295. package/src/plugins/builtin/chart-composer/user-series.ts +84 -0
  296. package/src/plugins/builtin/chat/content/composer-runtime.ts +6 -1
  297. package/src/plugins/builtin/chat/content/composer.tsx +5 -1
  298. package/src/plugins/builtin/chat/content/footer.tsx +12 -0
  299. package/src/plugins/builtin/chat/content/index.tsx +89 -5
  300. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -2
  301. package/src/plugins/builtin/chat/content/new-messages.tsx +89 -0
  302. package/src/plugins/builtin/chat/content/row-activity.ts +132 -0
  303. package/src/plugins/builtin/chat/content/scroll.ts +127 -27
  304. package/src/plugins/builtin/chat/content/shortcuts.ts +2 -2
  305. package/src/plugins/builtin/chat/content/transcript.tsx +145 -78
  306. package/src/plugins/builtin/chat/content/types.ts +1 -0
  307. package/src/plugins/builtin/chat/controller/fetch.ts +8 -2
  308. package/src/plugins/builtin/chat/controller/index.ts +123 -1
  309. package/src/plugins/builtin/chat/controller/message-loading.ts +3 -0
  310. package/src/plugins/builtin/chat/controller/messages.ts +7 -2
  311. package/src/plugins/builtin/chat/controller/realtime.ts +10 -1
  312. package/src/plugins/builtin/chat/controller/send.ts +61 -1
  313. package/src/plugins/builtin/chat/controller/state.ts +8 -0
  314. package/src/plugins/builtin/chat/ghost-user.ts +20 -0
  315. package/src/plugins/builtin/chat/index.tsx +23 -5
  316. package/src/plugins/builtin/chat/layout.ts +78 -5
  317. package/src/plugins/builtin/chat/message/ai-badge.tsx +18 -0
  318. package/src/plugins/builtin/chat/message/desktop.tsx +55 -6
  319. package/src/plugins/builtin/chat/message/header.tsx +16 -4
  320. package/src/plugins/builtin/chat/message/profile-popover.tsx +5 -1
  321. package/src/plugins/builtin/chat/message/reactions.tsx +210 -0
  322. package/src/plugins/builtin/chat/message/render-state.ts +18 -2
  323. package/src/plugins/builtin/chat/message/terminal.tsx +43 -4
  324. package/src/plugins/builtin/chat/message/types.ts +12 -0
  325. package/src/plugins/builtin/chat/reactions.ts +197 -0
  326. package/src/plugins/builtin/chat/share/flow.tsx +87 -0
  327. package/src/plugins/builtin/chat/share/targets.ts +27 -0
  328. package/src/plugins/builtin/chat/status-widget.tsx +6 -3
  329. package/src/plugins/builtin/chat/unread-inbox-pane.tsx +148 -27
  330. package/src/plugins/builtin/chat/unread-inbox.ts +22 -0
  331. package/src/plugins/builtin/cloud/askg/attached-pane.tsx +69 -0
  332. package/src/plugins/builtin/cloud/askg/controller.ts +111 -19
  333. package/src/plugins/builtin/cloud/askg/executor.ts +57 -3
  334. package/src/plugins/builtin/cloud/askg/manifest.ts +32 -7
  335. package/src/plugins/builtin/cloud/askg/model.ts +27 -8
  336. package/src/plugins/builtin/cloud/askg/pane-attachment.ts +94 -0
  337. package/src/plugins/builtin/cloud/askg/pane.tsx +141 -12
  338. package/src/plugins/builtin/cloud/askg/pending-question.ts +11 -0
  339. package/src/plugins/builtin/cloud/askg/protocol.ts +10 -1
  340. package/src/plugins/builtin/cloud/askg/tool-display.ts +3 -0
  341. package/src/plugins/builtin/cloud/askg/undo.ts +2 -0
  342. package/src/plugins/builtin/cloud/auth-actions.tsx +1 -1
  343. package/src/plugins/builtin/cloud/auth-commands.ts +1 -1
  344. package/src/plugins/builtin/cloud/auth-dialog.tsx +3 -3
  345. package/src/plugins/builtin/cloud/company-picker.tsx +1 -1
  346. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +3 -0
  347. package/src/plugins/builtin/cloud/plugin.tsx +19 -2
  348. package/src/plugins/builtin/cloud/team/model.ts +5 -0
  349. package/src/plugins/builtin/cloud/team/module.tsx +1 -0
  350. package/src/plugins/builtin/cloud/team/store.ts +8 -3
  351. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +77 -9
  352. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +6 -1
  353. package/src/plugins/builtin/cloud/terminal-relay/policy.ts +9 -0
  354. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +35 -11
  355. package/src/plugins/builtin/cloud/thesis/exposure.ts +1 -1
  356. package/src/plugins/builtin/cloud/thesis/module.tsx +1 -0
  357. package/src/plugins/builtin/cloud/thesis/prompts.tsx +2 -1
  358. package/src/plugins/builtin/company-attention/app-rank.tsx +1 -1
  359. package/src/plugins/builtin/company-attention/headless.ts +21 -7
  360. package/src/plugins/builtin/company-attention/index.tsx +2 -0
  361. package/src/plugins/builtin/company-attention/model.ts +26 -7
  362. package/src/plugins/builtin/company-attention/pane.tsx +12 -9
  363. package/src/plugins/builtin/company-attention/series.ts +52 -0
  364. package/src/plugins/builtin/company-kpis/headless.ts +97 -10
  365. package/src/plugins/builtin/company-kpis/model.ts +24 -2
  366. package/src/plugins/builtin/company-kpis/pane.tsx +17 -16
  367. package/src/plugins/builtin/composite-plugins.ts +19 -13
  368. package/src/plugins/builtin/connections/index.ts +1 -0
  369. package/src/plugins/builtin/cot/headless.ts +1 -1
  370. package/src/plugins/builtin/cot/index.tsx +3 -1
  371. package/src/plugins/builtin/cot/model.ts +40 -11
  372. package/src/plugins/builtin/cot/series.ts +27 -0
  373. package/src/plugins/builtin/cpi/headless.ts +3 -3
  374. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +10 -1
  375. package/src/plugins/builtin/credit-boards/client.ts +6 -2
  376. package/src/plugins/builtin/credit-boards/headless.ts +108 -31
  377. package/src/plugins/builtin/credit-boards/index.tsx +2 -0
  378. package/src/plugins/builtin/credit-boards/model.ts +11 -1
  379. package/src/plugins/builtin/credit-boards/series.ts +66 -0
  380. package/src/plugins/builtin/credit-conditions/client.ts +12 -9
  381. package/src/plugins/builtin/credit-conditions/headless.ts +13 -2
  382. package/src/plugins/builtin/credit-conditions/index.tsx +18 -9
  383. package/src/plugins/builtin/credit-conditions/model.ts +19 -11
  384. package/src/plugins/builtin/credit-conditions/series.ts +16 -0
  385. package/src/plugins/builtin/credit-documents/headless.ts +33 -3
  386. package/src/plugins/builtin/credit-documents/pane.tsx +3 -1
  387. package/src/plugins/builtin/crypto-board/headless.ts +2 -3
  388. package/src/plugins/builtin/crypto-board/index.tsx +2 -0
  389. package/src/plugins/builtin/crypto-board/model.ts +12 -0
  390. package/src/plugins/builtin/crypto-board/pane.tsx +19 -12
  391. package/src/plugins/builtin/crypto-board/series.ts +48 -0
  392. package/src/plugins/builtin/custom-view/live-quotes.ts +2 -2
  393. package/src/plugins/builtin/debt-maturities/headless.ts +17 -11
  394. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  395. package/src/plugins/builtin/debt-maturities/series.ts +45 -0
  396. package/src/plugins/builtin/dividend-yield/client.ts +3 -0
  397. package/src/plugins/builtin/dividend-yield/headless.ts +7 -4
  398. package/src/plugins/builtin/dividend-yield/index.tsx +3 -1
  399. package/src/plugins/builtin/dividend-yield/pane.tsx +3 -1
  400. package/src/plugins/builtin/dividend-yield/series.ts +20 -0
  401. package/src/plugins/builtin/dividend-yield/types.ts +2 -0
  402. package/src/plugins/builtin/docs/blocks.tsx +181 -0
  403. package/src/plugins/builtin/docs/index.tsx +68 -0
  404. package/src/plugins/builtin/docs/pane.tsx +426 -0
  405. package/src/plugins/builtin/docs/targets.ts +72 -0
  406. package/src/plugins/builtin/docs/use-docs.ts +60 -0
  407. package/src/plugins/builtin/doe/headless.ts +12 -8
  408. package/src/plugins/builtin/doe/index.tsx +2 -0
  409. package/src/plugins/builtin/doe/series.ts +62 -0
  410. package/src/plugins/builtin/earnings/client.ts +3 -2
  411. package/src/plugins/builtin/earnings/format.ts +1 -5
  412. package/src/plugins/builtin/earnings/headless.ts +58 -6
  413. package/src/plugins/builtin/earnings/history-model.ts +15 -1
  414. package/src/plugins/builtin/earnings/history-table.ts +13 -2
  415. package/src/plugins/builtin/earnings/history.tsx +7 -3
  416. package/src/plugins/builtin/earnings/index.tsx +9 -0
  417. package/src/plugins/builtin/earnings-calls/headless.ts +28 -2
  418. package/src/plugins/builtin/earnings-calls/index.tsx +1 -1
  419. package/src/plugins/builtin/earnings-ripple/index.tsx +2 -0
  420. package/src/plugins/builtin/econ/fred-catalog.ts +198 -0
  421. package/src/plugins/builtin/econ/fred-series-map.ts +0 -46
  422. package/src/plugins/builtin/econ/index.tsx +2 -0
  423. package/src/plugins/builtin/econ-statistics/defs.ts +5 -0
  424. package/src/plugins/builtin/econ-statistics/headless.ts +19 -4
  425. package/src/plugins/builtin/econ-statistics/stats.ts +1 -0
  426. package/src/plugins/builtin/equity-screener/headless.ts +3 -3
  427. package/src/plugins/builtin/equity-screener/pane.tsx +4 -11
  428. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -3
  429. package/src/plugins/builtin/exposure/drivers.ts +13 -0
  430. package/src/plugins/builtin/exposure/headless.ts +205 -13
  431. package/src/plugins/builtin/exposure/holdings.ts +1 -1
  432. package/src/plugins/builtin/exposure/index.tsx +1 -0
  433. package/src/plugins/builtin/exposure/model.ts +23 -3
  434. package/src/plugins/builtin/exposure/pane.tsx +14 -12
  435. package/src/plugins/builtin/fear-greed/index.tsx +18 -10
  436. package/src/plugins/builtin/fear-greed/series.ts +52 -0
  437. package/src/plugins/builtin/futures/index.tsx +43 -3
  438. package/src/plugins/builtin/futures/model.ts +1 -1
  439. package/src/plugins/builtin/futures/returns.ts +1 -1
  440. package/src/plugins/builtin/futures/series.ts +13 -0
  441. package/src/plugins/builtin/futures/table.tsx +1 -1
  442. package/src/plugins/builtin/futures/use-front-returns.ts +1 -1
  443. package/src/plugins/builtin/futures-curve/client.ts +12 -3
  444. package/src/plugins/builtin/futures-curve/headless.ts +71 -10
  445. package/src/plugins/builtin/futures-curve/index.tsx +1 -1
  446. package/src/plugins/builtin/futures-curve/model.ts +66 -11
  447. package/src/plugins/builtin/futures-curve/pane.tsx +52 -18
  448. package/src/plugins/builtin/fx-matrix/client.ts +63 -0
  449. package/src/plugins/builtin/fx-matrix/export.ts +2 -1
  450. package/src/plugins/builtin/fx-matrix/headless.ts +154 -0
  451. package/src/plugins/builtin/fx-matrix/index.tsx +4 -4
  452. package/src/plugins/builtin/gpu/board.tsx +13 -10
  453. package/src/plugins/builtin/gpu/changes.tsx +4 -4
  454. package/src/plugins/builtin/gpu/client.ts +19 -1
  455. package/src/plugins/builtin/gpu/equities.tsx +14 -10
  456. package/src/plugins/builtin/gpu/headless.ts +58 -27
  457. package/src/plugins/builtin/gpu/history.tsx +3 -3
  458. package/src/plugins/builtin/gpu/index.tsx +2 -0
  459. package/src/plugins/builtin/gpu/model.ts +101 -16
  460. package/src/plugins/builtin/gpu/pane.tsx +28 -12
  461. package/src/plugins/builtin/gpu/series.ts +38 -0
  462. package/src/plugins/builtin/help/function-card.tsx +25 -6
  463. package/src/plugins/builtin/help/function-index.ts +2 -0
  464. package/src/plugins/builtin/help/index.tsx +31 -9
  465. package/src/plugins/builtin/holders/beneficial-model.ts +90 -3
  466. package/src/plugins/builtin/holders/beneficial-report.ts +57 -5
  467. package/src/plugins/builtin/holders/beneficial-view.tsx +55 -11
  468. package/src/plugins/builtin/holders/client.ts +22 -3
  469. package/src/plugins/builtin/holders/format.ts +18 -3
  470. package/src/plugins/builtin/holders/headless.ts +36 -133
  471. package/src/plugins/builtin/holders/pane.tsx +11 -4
  472. package/src/plugins/builtin/holders/report-header.ts +40 -5
  473. package/src/plugins/builtin/holders/report-rows.ts +240 -0
  474. package/src/plugins/builtin/insider/client.ts +35 -20
  475. package/src/plugins/builtin/insider/headless.ts +41 -11
  476. package/src/plugins/builtin/insider/index.tsx +26 -9
  477. package/src/plugins/builtin/insider/insider-data.ts +10 -0
  478. package/src/plugins/builtin/insider/issuer.ts +49 -0
  479. package/src/plugins/builtin/insider/model.ts +3 -0
  480. package/src/plugins/builtin/ipo-calendar/headless.ts +1 -1
  481. package/src/plugins/builtin/iv-history/client.ts +20 -6
  482. package/src/plugins/builtin/iv-history/format.ts +9 -0
  483. package/src/plugins/builtin/iv-history/headless.ts +56 -21
  484. package/src/plugins/builtin/iv-history/index.tsx +2 -0
  485. package/src/plugins/builtin/iv-history/model.ts +143 -8
  486. package/src/plugins/builtin/iv-history/screen-pane.tsx +5 -9
  487. package/src/plugins/builtin/iv-history/series.ts +29 -0
  488. package/src/plugins/builtin/jobs/headless.ts +26 -3
  489. package/src/plugins/builtin/jobs/index.tsx +3 -1
  490. package/src/plugins/builtin/jobs/series.ts +19 -0
  491. package/src/plugins/builtin/kelly-sizer/index.tsx +2 -0
  492. package/src/plugins/builtin/kelly-sizer/pane.tsx +2 -1
  493. package/src/plugins/builtin/kelly-sizer/portfolio.ts +0 -39
  494. package/src/plugins/builtin/macro-day/client.ts +44 -3
  495. package/src/plugins/builtin/macro-day/headless.ts +13 -10
  496. package/src/plugins/builtin/macro-day/model.ts +56 -10
  497. package/src/plugins/builtin/macro-day/pane.tsx +30 -20
  498. package/src/plugins/builtin/market-heatmap/headless.ts +20 -5
  499. package/src/plugins/builtin/market-heatmap/index.tsx +6 -0
  500. package/src/plugins/builtin/market-heatmap/model.ts +19 -11
  501. package/src/plugins/builtin/market-heatmap/portfolio.ts +2 -2
  502. package/src/plugins/builtin/market-movers/client.ts +7 -5
  503. package/src/plugins/builtin/market-movers/index.tsx +3 -2
  504. package/src/plugins/builtin/market-movers/model.ts +30 -0
  505. package/src/plugins/builtin/market-movers/screener.ts +31 -0
  506. package/src/plugins/builtin/market-valuation/chart-series.ts +29 -69
  507. package/src/plugins/builtin/market-valuation/index.tsx +3 -3
  508. package/src/plugins/builtin/market-valuation/indicators.ts +0 -5
  509. package/src/plugins/builtin/members/headless.ts +8 -3
  510. package/src/plugins/builtin/members/model.ts +31 -3
  511. package/src/plugins/builtin/members/pane.tsx +6 -8
  512. package/src/plugins/builtin/mna/distress/headless.ts +4 -4
  513. package/src/plugins/builtin/mna/headless.ts +18 -6
  514. package/src/plugins/builtin/money-markets/headless.ts +5 -4
  515. package/src/plugins/builtin/money-markets/index.tsx +2 -0
  516. package/src/plugins/builtin/money-markets/series.ts +41 -0
  517. package/src/plugins/builtin/news/index.tsx +0 -2
  518. package/src/plugins/builtin/news/wire/news/detail-view.tsx +53 -104
  519. package/src/plugins/builtin/news/wire/news/footer.ts +2 -25
  520. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +0 -2
  521. package/src/plugins/builtin/notes/cli.ts +12 -7
  522. package/src/plugins/builtin/notes/index.tsx +1 -0
  523. package/src/plugins/builtin/options/index.tsx +3 -0
  524. package/src/plugins/builtin/options/view.tsx +1 -1
  525. package/src/plugins/builtin/options-calculator/inputs.ts +2 -1
  526. package/src/plugins/builtin/options-positioning/client.ts +7 -3
  527. package/src/plugins/builtin/options-positioning/headless.ts +4 -3
  528. package/src/plugins/builtin/options-positioning/pane.tsx +2 -2
  529. package/src/plugins/builtin/options-scenario/client.ts +2 -1
  530. package/src/plugins/builtin/options-scenario/headless.ts +1 -0
  531. package/src/plugins/builtin/options-scenario/hedge.ts +2 -1
  532. package/src/plugins/builtin/perps/client.ts +90 -16
  533. package/src/plugins/builtin/perps/equity-row.tsx +52 -17
  534. package/src/plugins/builtin/perps/freshness.ts +66 -0
  535. package/src/plugins/builtin/perps/headless.ts +47 -32
  536. package/src/plugins/builtin/perps/index.tsx +23 -4
  537. package/src/plugins/builtin/perps/list-perpetuals.ts +118 -0
  538. package/src/plugins/builtin/perps/model.ts +20 -5
  539. package/src/plugins/builtin/perps/open-market.ts +15 -0
  540. package/src/plugins/builtin/perps/pane.tsx +76 -20
  541. package/src/plugins/builtin/perps/series.ts +76 -0
  542. package/src/plugins/builtin/plugin-marketplace/index.tsx +1 -1
  543. package/src/plugins/builtin/plugin-marketplace/pane.tsx +73 -67
  544. package/src/plugins/builtin/plugin-module.ts +3 -0
  545. package/src/plugins/builtin/portfolio-list/account-metrics.ts +1 -1
  546. package/src/plugins/builtin/portfolio-list/allocation.ts +5 -4
  547. package/src/plugins/builtin/portfolio-list/cell-version.ts +8 -1
  548. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +161 -0
  549. package/src/plugins/builtin/portfolio-list/cli/import-13f.ts +109 -0
  550. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +384 -74
  551. package/src/plugins/builtin/portfolio-list/cli/render.ts +437 -71
  552. package/src/plugins/builtin/portfolio-list/cli/shared.ts +21 -4
  553. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +121 -47
  554. package/src/plugins/builtin/portfolio-list/column-values.ts +104 -26
  555. package/src/plugins/builtin/portfolio-list/grid.tsx +1 -1
  556. package/src/plugins/builtin/portfolio-list/headless.ts +84 -18
  557. package/src/plugins/builtin/portfolio-list/imported-from.ts +8 -0
  558. package/src/plugins/builtin/portfolio-list/index.tsx +5 -1
  559. package/src/plugins/builtin/portfolio-list/live-valuation.ts +6 -2
  560. package/src/plugins/builtin/portfolio-list/mutations.ts +2 -9
  561. package/src/plugins/builtin/portfolio-list/pane/data.ts +5 -1
  562. package/src/plugins/builtin/portfolio-list/pane/index.tsx +52 -9
  563. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +33 -11
  564. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +21 -1
  565. package/src/plugins/builtin/portfolio-list/settings.ts +17 -0
  566. package/src/plugins/builtin/portfolio-list/summary/index.tsx +12 -0
  567. package/src/plugins/builtin/portfolio-list/summary/totals.ts +9 -4
  568. package/src/plugins/builtin/portfolio-list/table.tsx +37 -7
  569. package/src/plugins/builtin/power/client.ts +16 -0
  570. package/src/plugins/builtin/power/evidence.ts +63 -10
  571. package/src/plugins/builtin/power/headless.ts +77 -9
  572. package/src/plugins/builtin/power/index.tsx +28 -3
  573. package/src/plugins/builtin/power/model.ts +73 -2
  574. package/src/plugins/builtin/power/pane.tsx +37 -9
  575. package/src/plugins/builtin/power/prices-client.ts +139 -0
  576. package/src/plugins/builtin/power/prices-headless.ts +137 -0
  577. package/src/plugins/builtin/power/prices-model.ts +103 -0
  578. package/src/plugins/builtin/power/prices.tsx +179 -0
  579. package/src/plugins/builtin/rate-path/headless.ts +46 -18
  580. package/src/plugins/builtin/realized-vol/headless.ts +5 -0
  581. package/src/plugins/builtin/relative-rotation/headless.ts +3 -3
  582. package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -2
  583. package/src/plugins/builtin/research/event-model.ts +68 -24
  584. package/src/plugins/builtin/research/events-headless.ts +2 -1
  585. package/src/plugins/builtin/research/headless.ts +2 -1
  586. package/src/plugins/builtin/research/index.tsx +2 -0
  587. package/src/plugins/builtin/research-search/article.ts +65 -0
  588. package/src/plugins/builtin/research-search/document-view.tsx +33 -215
  589. package/src/plugins/builtin/research-search/model.ts +0 -9
  590. package/src/plugins/builtin/research-search/pane.tsx +41 -30
  591. package/src/plugins/builtin/research-search/snippet.ts +0 -29
  592. package/src/plugins/builtin/revenue-breakdown/headless.ts +18 -6
  593. package/src/plugins/builtin/seasonality/client.ts +15 -7
  594. package/src/plugins/builtin/seasonality/headless.ts +36 -12
  595. package/src/plugins/builtin/seasonality/index.tsx +2 -2
  596. package/src/plugins/builtin/seasonality/model.ts +119 -0
  597. package/src/plugins/builtin/seasonality/pane.tsx +108 -37
  598. package/src/plugins/builtin/sec/headless.ts +25 -3
  599. package/src/plugins/builtin/sec/index.tsx +2 -1
  600. package/src/plugins/builtin/series-inventory.ts +93 -0
  601. package/src/plugins/builtin/shared/cloud-denied.ts +15 -0
  602. package/src/plugins/builtin/shared/cloud-upgrade.ts +1 -1
  603. package/src/plugins/builtin/shared/command-tab.ts +30 -12
  604. package/src/plugins/builtin/shared/earnings-report.ts +55 -0
  605. package/src/plugins/builtin/shared/fred-points.ts +20 -0
  606. package/src/plugins/builtin/shared/free-preview.ts +47 -0
  607. package/src/plugins/builtin/shared/fx-rate-freshness.ts +101 -0
  608. package/src/plugins/builtin/shared/open-description.ts +29 -0
  609. package/src/plugins/builtin/shared/report-freshness.ts +12 -1
  610. package/src/plugins/builtin/shared/series-warning.ts +5 -0
  611. package/src/plugins/builtin/shared/volatility/options.ts +4 -1
  612. package/src/plugins/builtin/short-interest/headless.ts +1 -0
  613. package/src/plugins/builtin/short-interest/index.tsx +2 -0
  614. package/src/plugins/builtin/short-interest/series.ts +36 -0
  615. package/src/plugins/builtin/short-interest/watch-headless.ts +3 -2
  616. package/src/plugins/builtin/short-interest/watch-model.ts +9 -5
  617. package/src/plugins/builtin/short-volume/headless.ts +2 -1
  618. package/src/plugins/builtin/short-volume/index.tsx +2 -0
  619. package/src/plugins/builtin/short-volume/series.ts +23 -0
  620. package/src/plugins/builtin/social-mentions/headless.ts +1 -1
  621. package/src/plugins/builtin/social-mentions/index.tsx +2 -0
  622. package/src/plugins/builtin/social-mentions/series.ts +23 -0
  623. package/src/plugins/builtin/supply-chain/graph-pane.tsx +3 -2
  624. package/src/plugins/builtin/supply-chain/headless.ts +43 -11
  625. package/src/plugins/builtin/supply-chain/model.ts +13 -0
  626. package/src/plugins/builtin/supply-chain/pane.tsx +8 -6
  627. package/src/plugins/builtin/themes/headless.ts +74 -10
  628. package/src/plugins/builtin/themes/model.ts +71 -4
  629. package/src/plugins/builtin/themes/pane.tsx +22 -5
  630. package/src/plugins/builtin/thirteenf/api.ts +1 -0
  631. package/src/plugins/builtin/thirteenf/data.ts +6 -4
  632. package/src/plugins/builtin/thirteenf/headless.ts +217 -36
  633. package/src/plugins/builtin/thirteenf/model.ts +39 -1
  634. package/src/plugins/builtin/thirteenf/overlap.ts +75 -0
  635. package/src/plugins/builtin/thirteenf/pane.tsx +10 -1
  636. package/src/plugins/builtin/thirteenf/report-notes.ts +103 -1
  637. package/src/plugins/builtin/thirteenf/types.ts +2 -0
  638. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +114 -0
  639. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +57 -2
  640. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +19 -55
  641. package/src/plugins/builtin/ticker-detail/headless-schema.ts +30 -0
  642. package/src/plugins/builtin/ticker-detail/headless.ts +86 -0
  643. package/src/plugins/builtin/ticker-detail/index.tsx +26 -11
  644. package/src/plugins/builtin/ticker-detail/overview/components.tsx +1 -1
  645. package/src/plugins/builtin/ticker-detail/overview/futures-contract.ts +31 -0
  646. package/src/plugins/builtin/ticker-detail/overview/model.ts +3 -3
  647. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
  648. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +49 -5
  649. package/src/plugins/builtin/ticker-detail/quote-monitor/index.tsx +13 -3
  650. package/src/plugins/builtin/time-sales/headless.ts +2 -1
  651. package/src/plugins/builtin/time-sales/index.tsx +2 -1
  652. package/src/plugins/builtin/treasury-auctions/headless.ts +16 -2
  653. package/src/plugins/builtin/treasury-auctions/index.tsx +1 -0
  654. package/src/plugins/builtin/treasury-auctions/model.ts +8 -0
  655. package/src/plugins/builtin/vol-surface/evidence.ts +7 -1
  656. package/src/plugins/builtin/vol-surface/headless.ts +51 -17
  657. package/src/plugins/builtin/vol-surface/heat-grid.tsx +113 -0
  658. package/src/plugins/builtin/vol-surface/model.ts +39 -6
  659. package/src/plugins/builtin/vol-surface/pane.tsx +14 -13
  660. package/src/plugins/builtin/vol-surface/stored.ts +63 -3
  661. package/src/plugins/builtin/vol-surface/surface.tsx +30 -2
  662. package/src/plugins/builtin/volatility/index.tsx +2 -0
  663. package/src/plugins/builtin/volatility/series.ts +84 -0
  664. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +6 -5
  665. package/src/plugins/builtin/world-venue-map/basemap.ts +6 -3
  666. package/src/plugins/builtin/world-venue-map/geo-draw.tsx +2 -1
  667. package/src/plugins/builtin/world-venue-map/geo-series.ts +26 -1
  668. package/src/plugins/builtin/world-venue-map/geo-svg.tsx +6 -6
  669. package/src/plugins/builtin/world-venue-map/headless.ts +4 -1
  670. package/src/plugins/builtin/world-venue-map/index.ts +2 -1
  671. package/src/plugins/builtin/world-venue-map/layered-pane.tsx +24 -13
  672. package/src/plugins/builtin/world-venue-map/layers.ts +29 -0
  673. package/src/plugins/builtin/world-venue-map/map.tsx +144 -13
  674. package/src/plugins/builtin/world-venue-map/model.ts +56 -19
  675. package/src/plugins/builtin/world-venue-map/pane.tsx +5 -2
  676. package/src/plugins/builtin/yield-curve/chart.ts +2 -2
  677. package/src/plugins/builtin/yield-curve/curves.ts +21 -8
  678. package/src/plugins/builtin/yield-curve/headless.ts +71 -18
  679. package/src/plugins/builtin/yield-curve/index.tsx +4 -2
  680. package/src/plugins/builtin/yield-curve/series.ts +86 -0
  681. package/src/plugins/catalog-browser.ts +2 -1
  682. package/src/plugins/installer.ts +2 -2
  683. package/src/plugins/loader.ts +15 -0
  684. package/src/plugins/manager-node.ts +1 -1
  685. package/src/plugins/{builtin/plugin-marketplace → marketplace}/feed.ts +2 -2
  686. package/src/plugins/{builtin/plugin-marketplace → marketplace}/model.ts +6 -6
  687. package/src/plugins/{builtin/plugin-marketplace → marketplace}/store.ts +1 -1
  688. package/src/plugins/registry/host-actions.ts +11 -0
  689. package/src/plugins/registry/index.ts +89 -4
  690. package/src/portfolio/collection-name.ts +31 -0
  691. package/src/{plugins/builtin/portfolio-list → portfolio}/position-metrics.ts +6 -6
  692. package/src/portfolio/position-value.ts +40 -0
  693. package/src/portfolio/valuation-basis.ts +79 -0
  694. package/src/public/__snapshots__/public-api.test.ts.snap +7 -0
  695. package/src/public/time-series.ts +17 -0
  696. package/src/react/auto-refresh.ts +13 -3
  697. package/src/react/input.ts +33 -1
  698. package/src/react/key-repeat.ts +86 -0
  699. package/src/remote/app-host.tsx +20 -4
  700. package/src/remote/confirm-change.tsx +85 -0
  701. package/src/remote/controller-utils.ts +8 -1
  702. package/src/remote/controller.ts +144 -7
  703. package/src/remote/pane-screenshot.ts +47 -0
  704. package/src/remote/schema.ts +65 -2
  705. package/src/remote/types.ts +30 -0
  706. package/src/remote/watchlist.ts +306 -0
  707. package/src/renderers/browser/main.tsx +4 -3
  708. package/src/renderers/browser/research-entry.ts +4 -2
  709. package/src/renderers/cloudflare/worker.ts +1 -1
  710. package/src/renderers/dom/data-table/frozen-column.ts +3 -1
  711. package/src/renderers/dom/data-table/index.tsx +33 -6
  712. package/src/renderers/dom/data-table/row.tsx +30 -1
  713. package/src/renderers/dom/desktop/control-styles.ts +63 -1
  714. package/src/renderers/dom/desktop/controls.tsx +30 -23
  715. package/src/renderers/dom/desktop/dialog-actions.tsx +170 -0
  716. package/src/renderers/dom/desktop/icons.tsx +16 -0
  717. package/src/renderers/dom/dom-ui-host.tsx +3 -0
  718. package/src/renderers/dom/host/block-glyph-canvas.tsx +6 -3
  719. package/src/renderers/dom/host/box.tsx +8 -0
  720. package/src/renderers/dom/host/chart-surface.tsx +33 -2
  721. package/src/renderers/dom/host/live-frame.ts +6 -2
  722. package/src/renderers/dom/host/overflow-fade.ts +14 -1
  723. package/src/renderers/dom/host/scroll-box.tsx +32 -0
  724. package/src/renderers/dom/host/size-observer.ts +41 -0
  725. package/src/renderers/dom/host/sticky-scroll.ts +128 -0
  726. package/src/renderers/dom/host/style.ts +1 -1
  727. package/src/renderers/dom/host/surface-3d.tsx +19 -7
  728. package/src/renderers/dom/host/surface-fit.ts +406 -0
  729. package/src/renderers/dom/host/text.tsx +1 -1
  730. package/src/renderers/dom/input-host.tsx +1 -0
  731. package/src/renderers/dom/styles.css +102 -5
  732. package/src/renderers/electrobun/bun/application-menu/click.ts +18 -0
  733. package/src/renderers/electrobun/bun/index.ts +3 -2
  734. package/src/renderers/electrobun/shared/protocol.ts +1 -1
  735. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +29 -2
  736. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +63 -20
  737. package/src/renderers/electrobun/view/cli-pane-shot-health.ts +10 -26
  738. package/src/renderers/electrobun/view/main.tsx +5 -3
  739. package/src/renderers/electrobun/view/remote/asset-data-client.ts +2 -0
  740. package/src/renderers/opentui/chart-surface.tsx +1 -0
  741. package/src/renderers/opentui/frame-capture.ts +33 -0
  742. package/src/renderers/opentui/host.tsx +10 -13
  743. package/src/renderers/opentui/pane-image/glyphs-license.txt +107 -0
  744. package/src/renderers/opentui/pane-image/glyphs.json +1 -0
  745. package/src/renderers/opentui/pane-image/index.ts +107 -0
  746. package/src/renderers/opentui/pane-image/raster.ts +428 -0
  747. package/src/renderers/opentui/start.tsx +3 -3
  748. package/src/renderers/opentui/test-utils.tsx +3 -0
  749. package/src/renderers/opentui/ui-host.tsx +29 -1
  750. package/src/series/capability.ts +75 -0
  751. package/src/series/csv.ts +160 -0
  752. package/src/series/files.ts +107 -0
  753. package/src/series/registry.ts +198 -0
  754. package/src/series/resolve.ts +108 -0
  755. package/src/series/standalone.ts +48 -0
  756. package/src/series/types.ts +153 -0
  757. package/src/series/validate.ts +171 -0
  758. package/src/shares/chat.ts +34 -0
  759. package/src/shares/dialog.tsx +295 -0
  760. package/src/shares/flow.tsx +56 -0
  761. package/src/shares/live.ts +14 -22
  762. package/src/shares/pane-image.ts +152 -0
  763. package/src/shares/personal-pane.ts +64 -0
  764. package/src/shares/portable-layout.ts +4 -2
  765. package/src/shares/prepare.ts +20 -0
  766. package/src/sources/gloomberb-cloud/index.ts +109 -10
  767. package/src/sources/gloomberb-cloud/normalizers.ts +3 -0
  768. package/src/sources/gloomberb-cloud/perpetuals.ts +249 -0
  769. package/src/sources/history-result.ts +1 -0
  770. package/src/sources/history-retention.ts +11 -0
  771. package/src/sources/listing-symbols.ts +4 -1
  772. package/src/sources/listing-target.ts +4 -0
  773. package/src/sources/provider-router/batches.ts +4 -1
  774. package/src/sources/provider-router/cache.ts +4 -2
  775. package/src/sources/provider-router/cached-routes.ts +1 -1
  776. package/src/sources/provider-router/financial-routes.ts +1 -0
  777. package/src/sources/provider-router/financials.ts +13 -0
  778. package/src/sources/provider-router/history.ts +43 -25
  779. package/src/sources/provider-router/index.ts +14 -0
  780. package/src/sources/provider-router/search.ts +1 -0
  781. package/src/state/hooks/inline-tickers.ts +49 -11
  782. package/src/sync/core-contributors.ts +1 -0
  783. package/src/test-support/shell-pane-keys.tsx +1 -0
  784. package/src/theme/theme-context.tsx +15 -1
  785. package/src/tickers/company-name.ts +75 -0
  786. package/src/tickers/instrument-kind.ts +34 -1
  787. package/src/tickers/listing-name.ts +34 -0
  788. package/src/tickers/listing-venues.ts +132 -0
  789. package/src/tickers/open-target.ts +13 -4
  790. package/src/tickers/perpetual-listing.ts +151 -0
  791. package/src/tickers/prediction-listing.ts +26 -0
  792. package/src/tickers/search/index.ts +72 -11
  793. package/src/tickers/search/ranking.ts +98 -20
  794. package/src/tickers/search/types.ts +7 -1
  795. package/src/tickers/ticker-changes.ts +213 -0
  796. package/src/tickers/us-listing.ts +34 -0
  797. package/src/time-series/economic.ts +2 -6
  798. package/src/time-series/hooks.ts +9 -0
  799. package/src/time-series/ice-credit.ts +39 -0
  800. package/src/time-series/resolve.ts +211 -29
  801. package/src/time-series/studies.ts +1 -0
  802. package/src/time-series/types.ts +12 -2
  803. package/src/time-series/use-chart-resolution.ts +32 -0
  804. package/src/types/config.ts +10 -2
  805. package/src/types/data-provider.ts +11 -0
  806. package/src/types/financials.ts +62 -1
  807. package/src/types/headless.ts +113 -0
  808. package/src/types/instrument.ts +4 -0
  809. package/src/types/plugin.ts +52 -2
  810. package/src/types/price-history.ts +7 -0
  811. package/src/types/ticker-changes.ts +26 -0
  812. package/src/types/ticker.ts +14 -0
  813. package/src/ui/context-menu.tsx +13 -1
  814. package/src/ui/host.tsx +57 -3
  815. package/src/ui/live-resize.ts +91 -0
  816. package/src/ui/live-stretch.ts +153 -0
  817. package/src/ui/measured-cells.ts +58 -0
  818. package/src/ui/sticky-scroll.ts +7 -0
  819. package/src/utils/basis-points.ts +17 -0
  820. package/src/utils/central-banks.ts +76 -0
  821. package/src/utils/cli-output.ts +131 -15
  822. package/src/utils/concurrency.ts +25 -0
  823. package/src/utils/crypto-pair.ts +20 -0
  824. package/src/utils/currency-pair.ts +19 -0
  825. package/src/utils/currency-units.ts +11 -0
  826. package/src/utils/datetime-format.ts +27 -6
  827. package/src/utils/decimal-comma.ts +19 -0
  828. package/src/utils/dom-screenshot-css.ts +265 -0
  829. package/src/utils/dom-screenshot-rasters.ts +276 -0
  830. package/src/utils/dom-screenshot.ts +439 -52
  831. package/src/utils/double-escape-close.ts +15 -1
  832. package/src/utils/exchange-rate-snapshot.ts +6 -2
  833. package/src/utils/exchanges.ts +143 -1
  834. package/src/utils/format.ts +35 -5
  835. package/src/utils/forward-dividend.ts +14 -0
  836. package/src/utils/fundamentals.ts +66 -0
  837. package/src/utils/futures-generic.ts +6 -12
  838. package/src/utils/fx-market-hours.ts +15 -5
  839. package/src/utils/fx-status.ts +6 -1
  840. package/src/utils/inline-content-tokenizer.ts +22 -3
  841. package/src/utils/market-capitalization.ts +8 -0
  842. package/src/utils/one-shot.ts +73 -0
  843. package/src/utils/options.ts +37 -8
  844. package/src/utils/price-history.ts +99 -42
  845. package/src/utils/sec-eps-basis.ts +24 -11
  846. package/src/utils/sec.ts +61 -7
  847. package/src/utils/utc-time.ts +63 -4
  848. package/src/plugins/builtin/fx-matrix/freshness.ts +0 -65
  849. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/activation.ts +0 -0
  850. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/ids.ts +0 -0
  851. /package/src/plugins/{builtin/plugin-marketplace → marketplace}/packs.ts +0 -0
  852. /package/src/{plugins/builtin/cloud → tickers}/starter-symbols.ts +0 -0
@@ -1,6 +1,17 @@
1
1
  /// <reference lib="dom" />
2
2
 
3
+ import {
4
+ cssUrl,
5
+ imageLayerRect,
6
+ objectFitRect,
7
+ parseBoxShadows,
8
+ parseLinearGradient,
9
+ splitTopLevel,
10
+ type Box,
11
+ } from "./dom-screenshot-css";
12
+ import { contentBox, prepareImages, type PreparedImages } from "./dom-screenshot-rasters";
3
13
  import { isScreenshotWatermarkVisible, setScreenshotWatermarkVisible } from "./screenshot-watermark";
14
+ import type { CapturePane } from "../remote/pane-screenshot";
4
15
 
5
16
  export interface PngScreenshot {
6
17
  pngBase64: string;
@@ -51,7 +62,10 @@ function localRect(rect: DOMRect, origin: CaptureOrigin) {
51
62
  };
52
63
  }
53
64
 
54
- function roundedRectPath(
65
+ type LocalRect = ReturnType<typeof localRect>;
66
+
67
+ /** Adds a rounded rectangle to the current path, as one closed subpath. */
68
+ function addRoundedRect(
55
69
  context: CanvasRenderingContext2D,
56
70
  x: number,
57
71
  y: number,
@@ -60,7 +74,6 @@ function roundedRectPath(
60
74
  radius: number,
61
75
  ): void {
62
76
  const r = Math.max(0, Math.min(radius, width / 2, height / 2));
63
- context.beginPath();
64
77
  context.moveTo(x + r, y);
65
78
  context.lineTo(x + width - r, y);
66
79
  context.quadraticCurveTo(x + width, y, x + width, y + r);
@@ -73,6 +86,18 @@ function roundedRectPath(
73
86
  context.closePath();
74
87
  }
75
88
 
89
+ function roundedRectPath(
90
+ context: CanvasRenderingContext2D,
91
+ x: number,
92
+ y: number,
93
+ width: number,
94
+ height: number,
95
+ radius: number,
96
+ ): void {
97
+ context.beginPath();
98
+ addRoundedRect(context, x, y, width, height, radius);
99
+ }
100
+
76
101
  function fillBackground(
77
102
  context: CanvasRenderingContext2D,
78
103
  style: CSSStyleDeclaration,
@@ -84,30 +109,202 @@ function fillBackground(
84
109
  context.fill();
85
110
  }
86
111
 
112
+ const BORDER_SIDES = ["top", "right", "bottom", "left"] as const;
113
+
114
+ interface BorderSide {
115
+ width: number;
116
+ color: string;
117
+ }
118
+
119
+ function borderSides(style: CSSStyleDeclaration): (BorderSide | null)[] {
120
+ return BORDER_SIDES.map((side) => {
121
+ const lineStyle = style.getPropertyValue(`border-${side}-style`);
122
+ const width = px(style.getPropertyValue(`border-${side}-width`));
123
+ const color = style.getPropertyValue(`border-${side}-color`);
124
+ return lineStyle === "none" || lineStyle === "hidden" || width <= 0 || !isPaintableColor(color)
125
+ ? null
126
+ : { width, color };
127
+ });
128
+ }
129
+
130
+ /** The border box less its borders, where backgrounds are placed and inset shadows fall. */
131
+ function paddingBox(rect: LocalRect, style: CSSStyleDeclaration): Box {
132
+ // Computed widths: zero for no border, and still taken by a transparent one.
133
+ const [top, right, bottom, left] = BORDER_SIDES.map((side) => px(style.getPropertyValue(`border-${side}-width`)));
134
+ return {
135
+ x: rect.x + left!,
136
+ y: rect.y + top!,
137
+ width: Math.max(0, rect.width - left! - right!),
138
+ height: Math.max(0, rect.height - top! - bottom!),
139
+ };
140
+ }
141
+
142
+ /**
143
+ * One CSS image layer (a `url()` image or a linear gradient) at its size and
144
+ * position in `area`. False when it cannot be painted.
145
+ */
146
+ function paintImageLayer(
147
+ context: CanvasRenderingContext2D,
148
+ layer: string,
149
+ area: Box,
150
+ size: string,
151
+ position: string,
152
+ urls: PreparedImages["urls"],
153
+ ): boolean {
154
+ const url = cssUrl(layer);
155
+ if (url) {
156
+ const image = urls.get(url);
157
+ if (!image) return false;
158
+ const target = imageLayerRect(area, { width: image.naturalWidth, height: image.naturalHeight }, size, position);
159
+ context.drawImage(image, target.x, target.y, target.width, target.height);
160
+ return true;
161
+ }
162
+ const tile = imageLayerRect(area, area, size === "contain" || size === "cover" ? "auto" : size, position);
163
+ const gradient = parseLinearGradient(layer, tile.width, tile.height);
164
+ if (!gradient) return false;
165
+ try {
166
+ const fill = context.createLinearGradient(
167
+ tile.x + gradient.x0,
168
+ tile.y + gradient.y0,
169
+ tile.x + gradient.x1,
170
+ tile.y + gradient.y1,
171
+ );
172
+ for (const stop of gradient.stops) fill.addColorStop(stop.offset, stop.color);
173
+ context.fillStyle = fill;
174
+ } catch {
175
+ // A stop colour the canvas cannot read.
176
+ return false;
177
+ }
178
+ context.fillRect(tile.x, tile.y, tile.width, tile.height);
179
+ return true;
180
+ }
181
+
182
+ /** Layer `index` of a comma-separated list that repeats when shorter, as CSS reads it. */
183
+ function layerValue(list: string[], index: number, fallback: string): string {
184
+ return list.length > 0 ? list[index % list.length]! : fallback;
185
+ }
186
+
187
+ /** Background images and gradients over the background colour, the last layer lowest. */
188
+ function paintBackgroundImages(
189
+ context: CanvasRenderingContext2D,
190
+ style: CSSStyleDeclaration,
191
+ rect: LocalRect,
192
+ urls: PreparedImages["urls"],
193
+ ): void {
194
+ const value = style.backgroundImage;
195
+ if (!value || value === "none") return;
196
+ const layers = splitTopLevel(value, ",");
197
+ const sizes = splitTopLevel(style.backgroundSize, ",");
198
+ const positions = splitTopLevel(style.backgroundPosition, ",");
199
+ const area = paddingBox(rect, style);
200
+ context.save();
201
+ roundedRectPath(context, rect.x, rect.y, rect.width, rect.height, px(style.borderTopLeftRadius));
202
+ context.clip();
203
+ for (let index = layers.length - 1; index >= 0; index -= 1) {
204
+ paintImageLayer(context, layers[index]!, area, layerValue(sizes, index, "auto"), layerValue(positions, index, "0% 0%"), urls);
205
+ }
206
+ context.restore();
207
+ }
208
+
209
+ function maskImage(style: CSSStyleDeclaration): string {
210
+ const value = style.getPropertyValue("mask-image") || style.getPropertyValue("-webkit-mask-image");
211
+ return value && value !== "none" ? value : "";
212
+ }
213
+
214
+ /** Each side in its own width and colour: a divider is often one side alone. */
87
215
  function strokeBorder(
88
216
  context: CanvasRenderingContext2D,
89
217
  style: CSSStyleDeclaration,
90
- rect: ReturnType<typeof localRect>,
218
+ rect: LocalRect,
91
219
  ): void {
92
- const widths = [
93
- px(style.borderTopWidth),
94
- px(style.borderRightWidth),
95
- px(style.borderBottomWidth),
96
- px(style.borderLeftWidth),
97
- ];
98
- if (widths.every((width) => width <= 0) || !isPaintableColor(style.borderTopColor)) return;
99
-
100
- context.strokeStyle = style.borderTopColor;
101
- context.lineWidth = Math.max(...widths);
102
- roundedRectPath(
103
- context,
104
- rect.x + context.lineWidth / 2,
105
- rect.y + context.lineWidth / 2,
106
- Math.max(0, rect.width - context.lineWidth),
107
- Math.max(0, rect.height - context.lineWidth),
108
- px(style.borderTopLeftRadius),
109
- );
110
- context.stroke();
220
+ const [top, right, bottom, left] = borderSides(style);
221
+ if (!top && !right && !bottom && !left) return;
222
+ const radius = px(style.borderTopLeftRadius);
223
+ if (radius > 0 && top && right && bottom && left
224
+ && [right, bottom, left].every((side) => side.width === top.width && side.color === top.color)) {
225
+ context.strokeStyle = top.color;
226
+ context.lineWidth = top.width;
227
+ roundedRectPath(
228
+ context,
229
+ rect.x + top.width / 2,
230
+ rect.y + top.width / 2,
231
+ Math.max(0, rect.width - top.width),
232
+ Math.max(0, rect.height - top.width),
233
+ radius,
234
+ );
235
+ context.stroke();
236
+ return;
237
+ }
238
+ const band = (side: BorderSide | null | undefined, x: number, y: number, width: number, height: number) => {
239
+ if (!side || width <= 0 || height <= 0) return;
240
+ context.fillStyle = side.color;
241
+ context.fillRect(x, y, width, height);
242
+ };
243
+ const topWidth = top?.width ?? 0;
244
+ const bottomWidth = bottom?.width ?? 0;
245
+ const middle = rect.height - topWidth - bottomWidth;
246
+ band(top, rect.x, rect.y, rect.width, topWidth);
247
+ band(bottom, rect.x, rect.y + rect.height - bottomWidth, rect.width, bottomWidth);
248
+ band(left, rect.x, rect.y + topWidth, left?.width ?? 0, middle);
249
+ band(right, rect.x + rect.width - (right?.width ?? 0), rect.y + topWidth, right?.width ?? 0, middle);
250
+ }
251
+
252
+ /**
253
+ * Sharp box shadows: the hairline dividers, focus rings and selection outlines
254
+ * the app draws with `inset 0 -1px 0` or `0 0 0 2px`. Blurred shadows are
255
+ * soft decoration around a box and are left out.
256
+ */
257
+ function paintBoxShadows(
258
+ context: CanvasRenderingContext2D,
259
+ style: CSSStyleDeclaration,
260
+ rect: LocalRect,
261
+ inset: boolean,
262
+ ): void {
263
+ if (style.boxShadow === "none") return;
264
+ const radius = px(style.borderTopLeftRadius);
265
+ // The first shadow is on top, so paint from the last.
266
+ for (const shadow of parseBoxShadows(style.boxShadow).reverse()) {
267
+ if (shadow.inset !== inset || shadow.blur > 0 || !isPaintableColor(shadow.color)) continue;
268
+ context.save();
269
+ context.fillStyle = shadow.color;
270
+ if (inset) {
271
+ const box = paddingBox(rect, style);
272
+ const innerRadius = Math.max(0, radius - Math.max(box.x - rect.x, box.y - rect.y));
273
+ roundedRectPath(context, box.x, box.y, box.width, box.height, innerRadius);
274
+ context.clip();
275
+ context.beginPath();
276
+ addRoundedRect(context, box.x, box.y, box.width, box.height, innerRadius);
277
+ addRoundedRect(
278
+ context,
279
+ box.x + shadow.x + shadow.spread,
280
+ box.y + shadow.y + shadow.spread,
281
+ Math.max(0, box.width - shadow.spread * 2),
282
+ Math.max(0, box.height - shadow.spread * 2),
283
+ Math.max(0, innerRadius - shadow.spread),
284
+ );
285
+ context.fill("evenodd");
286
+ } else {
287
+ const shape = {
288
+ x: rect.x + shadow.x - shadow.spread,
289
+ y: rect.y + shadow.y - shadow.spread,
290
+ width: rect.width + shadow.spread * 2,
291
+ height: rect.height + shadow.spread * 2,
292
+ };
293
+ // Outside the box only: an outer shadow never shows through a see-through background.
294
+ context.beginPath();
295
+ context.rect(
296
+ Math.min(shape.x, rect.x) - 1,
297
+ Math.min(shape.y, rect.y) - 1,
298
+ Math.max(shape.width, rect.width) + Math.abs(shadow.x) + 2,
299
+ Math.max(shape.height, rect.height) + Math.abs(shadow.y) + 2,
300
+ );
301
+ addRoundedRect(context, rect.x, rect.y, rect.width, rect.height, radius);
302
+ context.clip("evenodd");
303
+ roundedRectPath(context, shape.x, shape.y, shape.width, shape.height, radius > 0 ? radius + shadow.spread : 0);
304
+ context.fill();
305
+ }
306
+ context.restore();
307
+ }
111
308
  }
112
309
 
113
310
  function shouldClip(style: CSSStyleDeclaration): boolean {
@@ -119,12 +316,11 @@ function shouldClip(style: CSSStyleDeclaration): boolean {
119
316
  function applyClip(
120
317
  context: CanvasRenderingContext2D,
121
318
  style: CSSStyleDeclaration,
122
- rect: ReturnType<typeof localRect>,
123
- ): boolean {
124
- if (!shouldClip(style)) return false;
319
+ rect: LocalRect,
320
+ ): void {
321
+ if (!shouldClip(style)) return;
125
322
  roundedRectPath(context, rect.x, rect.y, rect.width, rect.height, px(style.borderTopLeftRadius));
126
323
  context.clip();
127
- return true;
128
324
  }
129
325
 
130
326
  function fontFor(style: CSSStyleDeclaration): string {
@@ -216,16 +412,48 @@ function drawTextNode(
216
412
  range.setEnd(textNode, end);
217
413
  return Array.from(range.getClientRects());
218
414
  });
415
+ const end = ellipsisEdge(parent, style);
219
416
  for (const fragment of fragments) {
220
- const text = style.whiteSpace === "normal" || style.whiteSpace === "nowrap"
417
+ const whole = style.whiteSpace === "normal" || style.whiteSpace === "nowrap"
221
418
  ? fragment.value.replace(/\s+/g, " ") : fragment.value.replace(/\r?\n/g, "");
222
- if (!text) continue;
223
419
  const rect = fragment.rect;
420
+ const text = end !== null && rect.left + rect.width > end + 0.5
421
+ ? ellipsized((value) => context.measureText(value).width, whole, end - rect.left)
422
+ : whole;
423
+ if (!text) continue;
224
424
  context.fillText(text, rect.left - origin.left, rect.top - origin.top + textBaselineOffset(style, rect));
225
425
  }
226
426
  } finally { range.detach(); }
227
427
  }
228
428
 
429
+ /**
430
+ * The right edge where the text's block cuts it with an ellipsis
431
+ * (text-overflow: ellipsis, set on the block, not inherited), or null.
432
+ */
433
+ function ellipsisEdge(element: Element, style: CSSStyleDeclaration): number | null {
434
+ let block: Element = element;
435
+ let blockStyle = style;
436
+ while (blockStyle.display === "inline" && block.parentElement) {
437
+ block = block.parentElement;
438
+ blockStyle = getComputedStyle(block);
439
+ }
440
+ if (blockStyle.textOverflow !== "ellipsis" || !shouldClip(blockStyle)) return null;
441
+ return block.getBoundingClientRect().right - px(blockStyle.borderRightWidth) - px(blockStyle.paddingRight);
442
+ }
443
+
444
+ /** The longest start of `text` that fits `width` with an ellipsis after it, as the screen cuts it. */
445
+ export function ellipsized(measure: (text: string) => number, text: string, width: number): string {
446
+ const characters = Array.from(text);
447
+ let low = 0;
448
+ let high = characters.length;
449
+ while (low < high) {
450
+ const middle = Math.ceil((low + high) / 2);
451
+ if (measure(`${characters.slice(0, middle).join("")}\u2026`) <= width) low = middle;
452
+ else high = middle - 1;
453
+ }
454
+ return `${characters.slice(0, low).join("")}\u2026`;
455
+ }
456
+
229
457
  function drawCanvasElement(
230
458
  context: CanvasRenderingContext2D,
231
459
  canvas: HTMLCanvasElement,
@@ -246,14 +474,17 @@ function drawInputElement(
246
474
  origin: CaptureOrigin,
247
475
  ): void {
248
476
  // Paint what the screen shows: a password field is dots, never its value.
249
- const value = element instanceof HTMLInputElement && element.type === "password"
477
+ const typed = element instanceof HTMLInputElement && element.type === "password"
250
478
  ? "\u2022".repeat(element.value.length)
251
479
  : element.value;
480
+ // An empty field shows its placeholder, in the placeholder's colour.
481
+ const value = typed || element.placeholder;
252
482
  if (!value) return;
253
483
  const style = getComputedStyle(element);
484
+ const color = typed ? style.color : getComputedStyle(element, "::placeholder").color;
254
485
  const rect = element.getBoundingClientRect();
255
- if (!isVisible(style) || !isPaintableColor(style.color) || rect.width <= 0 || rect.height <= 0) return;
256
- context.fillStyle = style.color;
486
+ if (!isVisible(style) || !isPaintableColor(color) || rect.width <= 0 || rect.height <= 0) return;
487
+ context.fillStyle = color;
257
488
  context.font = fontFor(style);
258
489
  const left = rect.left - origin.left + px(style.paddingLeft);
259
490
  const top = rect.top - origin.top + px(style.paddingTop) + textBaselineOffset(style, rect);
@@ -262,14 +493,99 @@ function drawInputElement(
262
493
  }
263
494
  }
264
495
 
265
- function drawElement(
496
+ /** An SVG or image the browser rasterized up front, in its content box. */
497
+ function drawRaster(
266
498
  context: CanvasRenderingContext2D,
267
499
  element: Element,
500
+ style: CSSStyleDeclaration,
501
+ raster: CanvasImageSource,
268
502
  origin: CaptureOrigin,
269
- skip?: (element: Element) => boolean,
270
503
  ): void {
504
+ const box = contentBox(element, style);
505
+ if (box.width <= 0 || box.height <= 0) return;
506
+ const local = { x: box.left - origin.left, y: box.top - origin.top, width: box.width, height: box.height };
507
+ try {
508
+ if (element instanceof HTMLImageElement) {
509
+ const fitted = objectFitRect(style.objectFit, local, { width: element.naturalWidth, height: element.naturalHeight });
510
+ context.save();
511
+ context.beginPath();
512
+ context.rect(local.x, local.y, local.width, local.height);
513
+ context.clip();
514
+ context.drawImage(raster, fitted.x, fitted.y, fitted.width, fitted.height);
515
+ context.restore();
516
+ } else {
517
+ context.drawImage(raster, local.x, local.y, local.width, local.height);
518
+ }
519
+ } catch {
520
+ // A raster that cannot be drawn is left out, like a failed one.
521
+ }
522
+ }
523
+
524
+ interface PaintPass {
525
+ context: CanvasRenderingContext2D;
526
+ origin: CaptureOrigin;
527
+ /** Device pixels per CSS pixel of the capture. */
528
+ scale: number;
529
+ skip?: (element: Element) => boolean;
530
+ /** SVGs, images and CSS image URLs, loaded before the paint (dom-screenshot-rasters). */
531
+ images: PreparedImages;
532
+ /** The masked element being painted into its own layer, so it is not masked twice. */
533
+ maskedElement?: Element;
534
+ }
535
+
536
+ /**
537
+ * A masked element (the chart toolbar's icons, a fading tab strip): painted
538
+ * into a layer of its own, cut by the mask's alpha, then laid down. A mask
539
+ * image that did not load hides the element, as an unloaded mask does on
540
+ * screen; a mask the capture cannot read (a radial gradient) returns false,
541
+ * and the element is painted unmasked instead.
542
+ */
543
+ function drawMasked(pass: PaintPass, element: Element, style: CSSStyleDeclaration, rect: LocalRect, mask: string): boolean {
544
+ const width = Math.ceil(rect.width * pass.scale);
545
+ const height = Math.ceil(rect.height * pass.scale);
546
+ if (width <= 0 || height <= 0) return true;
547
+ const layer = document.createElement("canvas");
548
+ layer.width = width;
549
+ layer.height = height;
550
+ const alpha = document.createElement("canvas");
551
+ alpha.width = width;
552
+ alpha.height = height;
553
+ const layerContext = layer.getContext("2d");
554
+ const alphaContext = alpha.getContext("2d");
555
+ if (!layerContext || !alphaContext) return false;
556
+
557
+ // Masks are placed in the border box.
558
+ const area = { x: 0, y: 0, width: rect.width, height: rect.height };
559
+ alphaContext.scale(pass.scale, pass.scale);
560
+ const layers = splitTopLevel(mask, ",");
561
+ const sizes = splitTopLevel(style.getPropertyValue("mask-size") || style.getPropertyValue("-webkit-mask-size"), ",");
562
+ const positions = splitTopLevel(style.getPropertyValue("mask-position") || style.getPropertyValue("-webkit-mask-position"), ",");
563
+ for (let index = layers.length - 1; index >= 0; index -= 1) {
564
+ const painted = paintImageLayer(
565
+ alphaContext,
566
+ layers[index]!,
567
+ area,
568
+ layerValue(sizes, index, "auto"),
569
+ layerValue(positions, index, "0% 0%"),
570
+ pass.images.urls,
571
+ );
572
+ if (!painted) return cssUrl(layers[index]!) !== null;
573
+ }
574
+
575
+ layerContext.scale(pass.scale, pass.scale);
576
+ layerContext.translate(-rect.x, -rect.y);
577
+ drawElement({ ...pass, context: layerContext, maskedElement: element }, element);
578
+ layerContext.setTransform(1, 0, 0, 1, 0, 0);
579
+ layerContext.globalCompositeOperation = "destination-in";
580
+ layerContext.drawImage(alpha, 0, 0);
581
+ pass.context.drawImage(layer, rect.x, rect.y, rect.width, rect.height);
582
+ return true;
583
+ }
584
+
585
+ function drawElement(pass: PaintPass, element: Element): void {
586
+ const { context, origin } = pass;
271
587
  if (!(element instanceof HTMLElement || element instanceof SVGElement)) return;
272
- if (skip?.(element)) return;
588
+ if (pass.skip?.(element)) return;
273
589
 
274
590
  const style = getComputedStyle(element);
275
591
  if (!isVisible(style)) return;
@@ -277,35 +593,71 @@ function drawElement(
277
593
  const rect = localRect(element.getBoundingClientRect(), origin);
278
594
  if (rect.width <= 0 || rect.height <= 0) return;
279
595
 
596
+ const mask = pass.maskedElement === element ? "" : maskImage(style);
597
+ if (mask && drawMasked(pass, element, style, rect, mask)) return;
598
+
280
599
  context.save();
281
600
  const opacity = Number.parseFloat(style.opacity || "1");
282
601
  if (Number.isFinite(opacity)) {
283
602
  context.globalAlpha *= Math.max(0, Math.min(opacity, 1));
284
603
  }
285
604
 
605
+ // CSS order: outer shadow, background, inset shadow, border, then content.
606
+ paintBoxShadows(context, style, rect, false);
286
607
  fillBackground(context, style, rect);
608
+ paintBackgroundImages(context, style, rect, pass.images.urls);
609
+ paintBoxShadows(context, style, rect, true);
287
610
  strokeBorder(context, style, rect);
288
- const clipped = applyClip(context, style, rect);
611
+ applyClip(context, style, rect);
289
612
 
290
- if (element instanceof HTMLCanvasElement) {
613
+ const raster = pass.images.elements.get(element);
614
+ if (raster) {
615
+ drawRaster(context, element, style, raster, origin);
616
+ } else if (element instanceof HTMLCanvasElement) {
291
617
  drawCanvasElement(context, element, origin);
292
618
  } else if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
293
619
  drawInputElement(context, element, origin);
294
620
  }
295
621
 
296
- for (const child of Array.from(element.childNodes)) {
297
- if (child.nodeType === Node.TEXT_NODE) {
298
- drawTextNode(context, child as Text, origin);
299
- } else if (child.nodeType === Node.ELEMENT_NODE) {
300
- drawElement(context, child as Element, origin, skip);
622
+ // An SVG's shapes and text are in its raster; they are not boxes to walk.
623
+ if (!(element instanceof SVGElement)) {
624
+ for (const child of paintOrder(element)) {
625
+ if (child.nodeType === Node.TEXT_NODE) {
626
+ drawTextNode(context, child as Text, origin);
627
+ } else {
628
+ drawElement(pass, child as Element);
629
+ }
301
630
  }
302
631
  }
303
632
 
304
- if (clipped) {
305
- context.restore();
306
- } else {
307
- context.restore();
633
+ context.restore();
634
+ }
635
+
636
+ /** Where a child falls in its parent's paint: below the flow, in it, or above it at its z-index. */
637
+ function paintLayer(child: Element): number {
638
+ const style = getComputedStyle(child);
639
+ if (style.position === "static") return 0;
640
+ const z = Number.parseInt(style.zIndex, 10);
641
+ return Number.isFinite(z) && z !== 0 ? z : 0.5;
642
+ }
643
+
644
+ /**
645
+ * A parent's children in the order the screen paints them, as CSS stacks
646
+ * them: negative z-index first, then text and in-flow boxes, then positioned
647
+ * boxes, then positive z-index by its value, each in document order. A chart
648
+ * toolbar placed over its canvas with a z-index comes before the canvas in
649
+ * the document and would otherwise be painted under it.
650
+ */
651
+ function paintOrder(element: Element): ChildNode[] {
652
+ const children = Array.from(element.childNodes)
653
+ .filter((child) => child.nodeType === Node.TEXT_NODE || child.nodeType === Node.ELEMENT_NODE);
654
+ if (!children.some((child) => child.nodeType === Node.ELEMENT_NODE && getComputedStyle(child as Element).position !== "static")) {
655
+ return children;
308
656
  }
657
+ return children
658
+ .map((child, index) => ({ child, index, layer: child.nodeType === Node.ELEMENT_NODE ? paintLayer(child as Element) : 0 }))
659
+ .sort((left, right) => left.layer - right.layer || left.index - right.index)
660
+ .map(({ child }) => child);
309
661
  }
310
662
 
311
663
  function blobToBase64(blob: Blob): Promise<string> {
@@ -342,11 +694,14 @@ async function waitForFonts(): Promise<void> {
342
694
  ]).catch(() => {});
343
695
  }
344
696
 
345
- function paintElement(
697
+ async function paintElement(
346
698
  element: HTMLElement,
347
699
  scale: number,
348
700
  options: { background?: string; skip?: (element: Element) => boolean } = {},
349
- ): { canvas: HTMLCanvasElement; width: number; height: number } {
701
+ ): Promise<{ canvas: HTMLCanvasElement; width: number; height: number }> {
702
+ await waitForFonts();
703
+ // Images load asynchronously, so SVGs and CSS images are ready before the synchronous paint.
704
+ const images = await prepareImages(element, options.skip);
350
705
  const rect = element.getBoundingClientRect();
351
706
  const width = Math.ceil(rect.width);
352
707
  const height = Math.ceil(rect.height);
@@ -372,7 +727,7 @@ function paintElement(
372
727
  const watermarkWasVisible = isScreenshotWatermarkVisible();
373
728
  setScreenshotWatermarkVisible(true);
374
729
  try {
375
- drawElement(context, element, { left: rect.left, top: rect.top }, options.skip);
730
+ drawElement({ context, origin: { left: rect.left, top: rect.top }, scale, skip: options.skip, images }, element);
376
731
  } finally {
377
732
  if (!watermarkWasVisible) setScreenshotWatermarkVisible(false);
378
733
  }
@@ -380,9 +735,8 @@ function paintElement(
380
735
  }
381
736
 
382
737
  async function captureElementPngBase64(element: HTMLElement): Promise<PngScreenshot> {
383
- await waitForFonts();
384
738
  const scale = Math.max(1, Math.min(globalThis.devicePixelRatio || 1, 3));
385
- const { canvas, width, height } = paintElement(element, scale);
739
+ const { canvas, width, height } = await paintElement(element, scale);
386
740
  return {
387
741
  pngBase64: await blobToBase64(await canvasToPngBlob(canvas)),
388
742
  width,
@@ -432,10 +786,9 @@ export async function captureAppScreenshotJpegBase64(options: {
432
786
  }): Promise<JpegScreenshot> {
433
787
  if (typeof document === "undefined") throw new Error("Screenshots need a window.");
434
788
  const root = document.getElementById("root") ?? document.body;
435
- await waitForFonts();
436
789
  const background = getComputedStyle(document.body).backgroundColor;
437
790
  const skipSelector = options.skipSelector;
438
- let { canvas } = paintElement(root, 1, {
791
+ let { canvas } = await paintElement(root, 1, {
439
792
  background: isPaintableColor(background) ? background : "#000",
440
793
  skip: skipSelector ? (element) => element.matches(skipSelector) : undefined,
441
794
  });
@@ -449,6 +802,40 @@ export async function captureAppScreenshotJpegBase64(options: {
449
802
  throw new Error("Screenshot is too large.");
450
803
  }
451
804
 
805
+ /**
806
+ * One pane of this window, for pane.screenshot: painted at the scale the
807
+ * request picks for its on-screen size, then shrunk until the PNG fits the
808
+ * byte cap. Unlike the copy action it never falls back to another pane.
809
+ */
810
+ export const capturePaneImage: CapturePane = async (request) => {
811
+ if (typeof document === "undefined") throw new Error("Screenshots need a window.");
812
+ const id = escapeAttributeValue(request.instanceId);
813
+ // A popped-out desktop window draws its one pane as the window itself.
814
+ const target = document.querySelector<HTMLElement>(
815
+ `[data-gloom-role='pane-window'][data-gloom-pane-id="${id}"], [data-gloom-role='detached-pane-window'][data-gloom-pane-id="${id}"]`,
816
+ );
817
+ const rect = target?.getBoundingClientRect();
818
+ if (!target || !rect || rect.width < 1 || rect.height < 1) {
819
+ throw new Error(`Pane "${request.instanceId}" is not drawn right now (behind another tab or a full-screen pane). Focus it and try again.`);
820
+ }
821
+ const screen = { width: Math.ceil(rect.width), height: Math.ceil(rect.height) };
822
+ let { canvas } = await paintElement(target, request.scaleFor(screen));
823
+ let reduced = false;
824
+ for (;;) {
825
+ const blob = await canvasToPngBlob(canvas);
826
+ if (blob.size <= request.maxBytes) {
827
+ return { pngBase64: await blobToBase64(blob), width: canvas.width, height: canvas.height, bytes: blob.size, screen, reduced };
828
+ }
829
+ // PNG size follows the pixel count, so shrink by the square root of the overshoot.
830
+ const factor = Math.min(0.9, Math.sqrt(request.maxBytes / blob.size) * 0.95);
831
+ if (Math.round(canvas.width * factor) < request.minWidth) {
832
+ throw new Error(`The pane's image stays over ${Math.max(1, Math.round(request.maxBytes / 1024))} KB even ${request.minWidth} px wide.`);
833
+ }
834
+ canvas = downscale(canvas, factor);
835
+ reduced = true;
836
+ }
837
+ };
838
+
452
839
  export async function capturePaneScreenshotPngBase64(paneId?: string): Promise<PngScreenshot> {
453
840
  const target = findPaneScreenshotTarget(paneId);
454
841
  if (!target) throw new Error("Pane is not visible.");
@@ -1,14 +1,19 @@
1
+ import { ONE_SHOT_COOLDOWN_MS } from "./one-shot";
2
+
1
3
  const DOUBLE_ESCAPE_CLOSE_MS = 650;
2
4
 
3
5
  export interface DoubleEscapeCloseState {
4
6
  lastAt: number;
5
7
  targetId: string | null;
8
+ /** The last Esc that closed a pane, or came while that close was still cooling down. */
9
+ closedAt: number;
6
10
  }
7
11
 
8
12
  export function createDoubleEscapeCloseState(): DoubleEscapeCloseState {
9
13
  return {
10
14
  lastAt: 0,
11
15
  targetId: null,
16
+ closedAt: Number.NEGATIVE_INFINITY,
12
17
  };
13
18
  }
14
19
 
@@ -30,7 +35,10 @@ export function takeDoubleEscapeClose(
30
35
  thresholdMs = DOUBLE_ESCAPE_CLOSE_MS,
31
36
  ): boolean {
32
37
  const matched = !!targetId && state.targetId === targetId && now - state.lastAt <= thresholdMs;
33
- if (matched) resetDoubleEscapeClose(state);
38
+ if (matched) {
39
+ resetDoubleEscapeClose(state);
40
+ state.closedAt = now;
41
+ }
34
42
  return matched;
35
43
  }
36
44
 
@@ -63,6 +71,12 @@ export function armDoubleEscapeClose(
63
71
  resetDoubleEscapeClose(state);
64
72
  return;
65
73
  }
74
+ // A held Esc is a stream of presses: after the close it arms nothing, so it
75
+ // cannot close the next pane too. Each Esc of the stream extends the pause.
76
+ if (now - state.closedAt < ONE_SHOT_COOLDOWN_MS) {
77
+ state.closedAt = now;
78
+ return;
79
+ }
66
80
  state.targetId = targetId;
67
81
  state.lastAt = now;
68
82
  }