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
@@ -1,9 +1,10 @@
1
- import type { CryptoAssetKind, StablecoinSupplyPayload } from "../../../api-client/crypto-markets";
1
+ import type { CryptoAssetKind, DefiTvlPayload, StablecoinSupplyPayload } from "../../../api-client/crypto-markets";
2
2
  import type { HeadlessExportTable, HeadlessPaneColumn } from "../../../types/headless";
3
3
  import type { HeadlessPaneDefinition } from "../../../types/plugin";
4
4
  import { formatCompact, formatCompactAmount } from "../../../utils/format";
5
5
  import { errorMessage } from "../../../utils/errors";
6
- import { fetchCryptoMarkets, fetchStablecoinSupply } from "./client";
6
+ import { fetchCryptoMarkets, fetchDefiTvl, fetchStablecoinSupply } from "./client";
7
+ import { buildDefiRows, defiHistoryRows, defiHistoryStart, defiSummaryLine, type DefiList, type DefiRow } from "./defi";
7
8
  import {
8
9
  buildCryptoRows,
9
10
  CRYPTO_BOARD_FRESHNESS,
@@ -102,30 +103,140 @@ function supplyMetadata(payload: StablecoinSupplyPayload) {
102
103
  };
103
104
  }
104
105
 
106
+ const PROTOCOL_COLUMNS: HeadlessPaneColumn[] = [
107
+ { key: "rank", header: "#", align: "right" },
108
+ { key: "name", header: "Protocol" },
109
+ { key: "category", header: "Category", stackPriority: 2, stackRows: 0 },
110
+ { key: "tvl", header: "TVL", align: "right", format: compact },
111
+ { key: "change1dPercent", header: "1D %", align: "right", format: percent, stackPriority: 3, stackRows: 0 },
112
+ { key: "change7d", header: "7D", align: "right", format: signedCompact, stackPriority: 1, stackRows: 0 },
113
+ { key: "change7dPercent", header: "7D %", align: "right", format: percent },
114
+ { key: "change30d", header: "30D", align: "right", format: signedCompact, stackPriority: 0.5, stackRows: 0 },
115
+ { key: "change30dPercent", header: "30D %", align: "right", format: percent },
116
+ { key: "chains", header: "Chains", align: "right", stackPriority: 4, stackRows: 0 },
117
+ ];
118
+
119
+ const CHAIN_COLUMNS: HeadlessPaneColumn[] = [
120
+ { key: "rank", header: "#", align: "right" },
121
+ { key: "name", header: "Chain" },
122
+ { key: "token", header: "Token", stackPriority: 2, stackRows: 0 },
123
+ { key: "tvl", header: "TVL", align: "right", format: compact },
124
+ { key: "change7d", header: "7D", align: "right", format: signedCompact, stackPriority: 1, stackRows: 0 },
125
+ { key: "change7dPercent", header: "7D %", align: "right", format: percent },
126
+ { key: "change30d", header: "30D", align: "right", format: signedCompact, stackPriority: 0.5, stackRows: 0 },
127
+ { key: "change30dPercent", header: "30D %", align: "right", format: percent },
128
+ { key: "share", header: "Share", align: "right", format: share },
129
+ ];
130
+
131
+ function defiRecord(row: DefiRow, list: DefiList) {
132
+ return {
133
+ rank: row.rank,
134
+ name: row.name,
135
+ ...(list === "chain" ? { token: row.detail } : { category: row.detail, chains: row.chains, change1dPercent: row.change1dPercent }),
136
+ tvl: row.tvl,
137
+ change7d: row.change7d,
138
+ change7dPercent: row.change7dPercent,
139
+ change30d: row.change30d,
140
+ change30dPercent: row.change30dPercent,
141
+ ...(list === "chain" ? { share: row.share } : {}),
142
+ };
143
+ }
144
+
145
+ /** The other list and the total's daily history, for `--csv`: one file carries the whole tab. */
146
+ function defiExportTables(payload: DefiTvlPayload, list: DefiList): HeadlessExportTable[] {
147
+ const other: DefiList = list === "chain" ? "protocol" : "chain";
148
+ const otherRows = buildDefiRows(payload, other).map((row) => defiRecord(row, other));
149
+ const history = defiHistoryRows(payload);
150
+ return [
151
+ ...(otherRows.length ? [{ title: other === "chain" ? "DeFi TVL by chain" : "DeFi TVL by protocol", unit: "USD", columns: other === "chain" ? CHAIN_COLUMNS : PROTOCOL_COLUMNS, rows: otherRows }] : []),
152
+ ...(history.length ? [{
153
+ title: "Total DeFi TVL",
154
+ unit: "USD",
155
+ interval: "1d",
156
+ columns: [{ key: "date", header: "Date" }, { key: "tvl", header: "TVL", align: "right" as const }],
157
+ rows: history,
158
+ }] : []),
159
+ ];
160
+ }
161
+
162
+ /**
163
+ * `--list defi`: the largest protocols (or chains, `--by chain`) by TVL with
164
+ * their 7D and 30D change, under the total's line. Dated by the total's day,
165
+ * from a source that publishes it daily.
166
+ */
167
+ async function loadDefi(list: DefiList, ctx: Parameters<HeadlessPaneDefinition<"rows">["load"]>[1]) {
168
+ const payload = await fetchDefiTvl(ctx.apiClient);
169
+ const rows = buildDefiRows(payload, list).map((row) => defiRecord(row, list));
170
+ const summary = defiSummaryLine(payload);
171
+ const exportTables = defiExportTables(payload, list);
172
+ return {
173
+ rows,
174
+ columns: list === "chain" ? CHAIN_COLUMNS : PROTOCOL_COLUMNS,
175
+ ...(exportTables.length ? { exportTables } : {}),
176
+ errors: payload.warnings,
177
+ ...(list === "protocol" && payload.protocolsAsOf ? { notes: [`Protocols as of ${isoMinute(payload.protocolsAsOf)}, the source's latest; their versions are counted together.`] } : {}),
178
+ empty: list === "chain" ? "No chains returned." : "No protocols returned.",
179
+ freshness: {
180
+ source: "Gloom Cloud",
181
+ publisher: payload.source.name,
182
+ status: "not-a-feed" as const,
183
+ basis: "daily TVL",
184
+ asOf: payload.asOf,
185
+ maxAgeMinutes: 36 * 60,
186
+ },
187
+ metadata: {
188
+ list: "defi",
189
+ by: list,
190
+ status: payload.status,
191
+ asOf: payload.asOf,
192
+ fetchedAt: payload.fetchedAt,
193
+ protocolsAsOf: payload.protocolsAsOf,
194
+ source: payload.source,
195
+ total: payload.total,
196
+ historyStart: defiHistoryStart(payload),
197
+ ...(summary ? { notices: [summary] } : {}),
198
+ },
199
+ };
200
+ }
201
+
105
202
  export const cryptoBoardHeadless: HeadlessPaneDefinition<"rows"> = {
106
203
  shape: "rows",
107
204
  argument: { kind: "none" },
108
205
  options: [{
109
206
  key: "list",
110
- description: "Coins or stablecoins.",
207
+ description: "Coins, stablecoins, or DeFi TVL.",
111
208
  type: "enum",
112
209
  values: [
113
210
  { value: "coin", aliases: ["coins"] },
114
211
  { value: "stablecoin", aliases: ["stablecoins", "stable", "stables"] },
212
+ { value: "defi", aliases: ["tvl"] },
115
213
  ],
116
214
  defaultValue: "coin",
117
215
  example: "--list stablecoin",
118
216
  pluginState: { pluginId: "market-overview", key: "activeTab" },
217
+ }, {
218
+ key: "by",
219
+ // No default: the coin and stablecoin reports carry no `by`, and a missing one is by protocol.
220
+ description: "DeFi TVL by protocol (the default) or by chain, with --list defi.",
221
+ type: "enum",
222
+ values: [
223
+ { value: "protocol", aliases: ["protocols"] },
224
+ { value: "chain", aliases: ["chains"] },
225
+ ],
226
+ example: "--list defi --by chain",
227
+ pluginState: { pluginId: "market-overview", key: "defiList" },
119
228
  }],
120
229
  columns: COIN_COLUMNS,
121
- describe: (args) => `Crypto | ${args.options.list === "stablecoin" ? "Stablecoins" : "Coins"}`,
230
+ describe: (args) => `Crypto | ${args.options.list === "defi" ? `DeFi TVL by ${args.options.by === "chain" ? "chain" : "protocol"}` : args.options.list === "stablecoin" ? "Stablecoins" : "Coins"}`,
122
231
  discovery: {
123
232
  aliases: ["CRYP"],
124
233
  dataRequirements: ["Gloom Cloud crypto markets"],
125
234
  },
126
- // A board snapshot refreshed every few minutes; the pane streams, the report does not.
127
- freshness: { status: "delayed", ...CRYPTO_BOARD_FRESHNESS },
235
+ // The board as the server read it, at most 15 seconds before; the pane streams, the report does not.
236
+ // Each row keeps the time of its own last trade, so a coin that has not traded lately reads its age.
237
+ freshness: CRYPTO_BOARD_FRESHNESS,
128
238
  async load(args, ctx) {
239
+ if (args.options.list === "defi") return loadDefi(args.options.by === "chain" ? "chain" : "protocol", ctx);
129
240
  const kind = args.options.list === "stablecoin" ? "stablecoin" : "coin" satisfies CryptoAssetKind;
130
241
  // Supply is its own request: a failure there leaves the prices whole.
131
242
  const [data, supplyResult] = await Promise.all([
@@ -1,6 +1,6 @@
1
1
  import type { PluginModule } from "../plugin-module";
2
2
  import { LIVE_STREAMING_QUICK_SETTING, withLiveStreamingSetting } from "../../../state/hooks/live-streaming";
3
- import { cryptoMarketsCache, STABLECOIN_SUPPLY_CACHES } from "./client";
3
+ import { cryptoMarketsCache, DEFI_TVL_CACHES, STABLECOIN_SUPPLY_CACHES } from "./client";
4
4
  import { cryptoBoardHeadless } from "./headless";
5
5
  import { CryptoBoardPane } from "./pane";
6
6
  import { CRYPTO_SERIES } from "./series";
@@ -27,8 +27,11 @@ export const cryptoBoardModule: PluginModule = {
27
27
  id: "crypto-board-pane",
28
28
  paneId: "crypto-board",
29
29
  label: "Crypto",
30
- description: "Top crypto assets by market cap with live prices, 7D, 30D and 1Y returns, volume and market cap, and stablecoin supply.",
31
- keywords: ["crypto", "cryp", "bitcoin", "ethereum", "coins", "stablecoins", "stablecoin supply", "digital", "currency"],
30
+ description: "Top crypto assets by market cap with live prices, 7D, 30D and 1Y returns, volume and market cap, stablecoin supply, and DeFi TVL by protocol and chain.",
31
+ keywords: [
32
+ "crypto", "cryp", "bitcoin", "ethereum", "coins", "stablecoins", "stablecoin supply", "digital", "currency",
33
+ "defi", "tvl", "total value locked", "defi tvl", "on-chain", "onchain", "aave", "lido", "protocols", "chains",
34
+ ],
32
35
  shortcut: { prefix: "CRYP" },
33
36
  headless: cryptoBoardHeadless,
34
37
  },
@@ -36,9 +39,11 @@ export const cryptoBoardModule: PluginModule = {
36
39
  setup(ctx) {
37
40
  cryptoMarketsCache.attach(ctx.persistence);
38
41
  for (const cache of STABLECOIN_SUPPLY_CACHES) cache.attach(ctx.persistence);
42
+ for (const cache of DEFI_TVL_CACHES) cache.attach(ctx.persistence);
39
43
  },
40
44
  dispose() {
41
45
  cryptoMarketsCache.reset();
42
46
  for (const cache of STABLECOIN_SUPPLY_CACHES) cache.reset();
47
+ for (const cache of DEFI_TVL_CACHES) cache.reset();
43
48
  },
44
49
  };
@@ -2,6 +2,7 @@ import type { CryptoAssetKind, CryptoMarketAsset, CryptoPeg } from "../../../api
2
2
  import type { DataTableColumn } from "../../../components";
3
3
  import { getTableWidth } from "../../../components/ui/table-layout";
4
4
  import { buildQuoteKey, resolveEntryData } from "../../../market-data/selectors";
5
+ import { delayedFeedLagMs } from "../../../market-data/market/freshness";
5
6
  import type { QueryEntry } from "../../../market-data/result-types";
6
7
  import type { PricePoint, Quote } from "../../../types/financials";
7
8
  import type { HeadlessPaneFreshness } from "../../../types/headless";
@@ -12,15 +13,24 @@ import { formatUtcWeekdayTime } from "../../../utils/utc-time";
12
13
 
13
14
  const DAY_MS = 86_400_000;
14
15
 
16
+ /** The venue code every coin is quoted under (`cryptoQuoteKey`). */
17
+ const CRYPTO_EXCHANGE = "CCC";
18
+
15
19
  /**
16
- * How the board's report, capture and footer date its prices: crypto trades around the clock, so a price an hour old
17
- * has stopped refreshing, and coins are quoted apart, so the line says how old the oldest is.
20
+ * How the board's report, capture and footer date its prices. Coins are priced apart, and a coin that has not traded
21
+ * lately keeps its own time, so the line says when the newest price is from and how old the oldest is, and no more: a
22
+ * price read from the board is neither real-time nor held back, so it claims no feed (`ageOnly`). Crypto trades
23
+ * around the clock, so a newest price an hour old means the board has stopped refreshing.
18
24
  */
19
- export const CRYPTO_BOARD_FRESHNESS: HeadlessPaneFreshness = { maxAgeMinutes: 60, oldestAge: true };
25
+ export const CRYPTO_BOARD_FRESHNESS: HeadlessPaneFreshness = { ageOnly: true, maxAgeMinutes: 60 };
26
+
27
+ /** A tab of the board: a list of assets, or DeFi's value locked. */
28
+ export type CryptoTab = CryptoAssetKind | "defi";
20
29
 
21
- export const CRYPTO_TABS: Array<{ value: CryptoAssetKind; label: string }> = [
30
+ export const CRYPTO_TABS: Array<{ value: CryptoTab; label: string }> = [
22
31
  { value: "coin", label: "Coins" },
23
32
  { value: "stablecoin", label: "Stablecoins" },
33
+ { value: "defi", label: "DeFi" },
24
34
  ];
25
35
 
26
36
  /** A stablecoin's supply as its row shows it; every field is null on the coin tab and for a coin the supply list lacks. */
@@ -72,7 +82,10 @@ export interface CryptoRow extends CryptoRowSupply {
72
82
  history: PricePoint[];
73
83
  /** Epoch ms of the price shown. */
74
84
  updatedAt: number | null;
85
+ /** The price is a streamed quote, so it moves between board refreshes. */
75
86
  live: boolean;
87
+ /** The price is a quote from a delayed feed, held back from the market. A price read from the board is not. */
88
+ delayed: boolean;
76
89
  /** A stablecoin's peg; null for a coin, or a server that does not send it. */
77
90
  peg: CryptoPeg | null;
78
91
  /** `USD`, `EUR 1.1242` (the target in dollars), `USD yield`; empty without a peg. */
@@ -90,7 +103,7 @@ export interface CryptoRow extends CryptoRowSupply {
90
103
  }
91
104
 
92
105
  export const cryptoQuoteKey = (asset: Pick<CryptoMarketAsset, "symbol">) =>
93
- buildQuoteKey({ symbol: asset.symbol, exchange: "CCC" });
106
+ buildQuoteKey({ symbol: asset.symbol, exchange: CRYPTO_EXCHANGE });
94
107
 
95
108
  const positive = (value: number | null | undefined): value is number => isFiniteNumber(value) && value > 0;
96
109
 
@@ -200,6 +213,7 @@ function buildCryptoRow(
200
213
  history,
201
214
  updatedAt: updated,
202
215
  live: !!quote && quote.delivery === "stream" && quote.stale !== true,
216
+ delayed: quote?.dataSource === "delayed",
203
217
  peg,
204
218
  pegText: formatPegTarget(peg),
205
219
  offPegBp: offPegBasisPoints(price, peg),
@@ -313,9 +327,27 @@ export function withCryptoSupply(rows: readonly CryptoRow[], supply: ReadonlyMap
313
327
  });
314
328
  }
315
329
 
316
- /** What a capture and the footer read of each row: when its price is from, and whether it is streaming live. */
317
- export function cryptoRowObservations(rows: readonly CryptoRow[]): Array<{ quoteTime: string; dataSource: "live" | "delayed" }> {
318
- return rows.flatMap((row) => row.updatedAt == null ? [] : [{ quoteTime: new Date(row.updatedAt).toISOString(), dataSource: row.live ? "live" as const : "delayed" as const }]);
330
+ /** One row's price as a capture and the footer date it: when it is from and, when it says so, how current it is. */
331
+ type CryptoRowObservation = {
332
+ quoteTime: string;
333
+ dataSource?: "live" | "delayed";
334
+ delayMinutes?: number;
335
+ };
336
+
337
+ /**
338
+ * What a capture and the footer read of each row: when its price is from and, when it is a feed's, how current it
339
+ * is. A quote from a delayed feed is held back by the feed's lag. A price read from the board (a coin the live feed
340
+ * does not carry, every coin without real-time access) states no feed, and is dated by its own time. A streamed row
341
+ * says `live` only when the whole view is streamed: one price minutes old beside it, and the line would call
342
+ * minutes-old data live.
343
+ */
344
+ export function cryptoRowObservations(rows: readonly CryptoRow[]): CryptoRowObservation[] {
345
+ const dated = rows.flatMap((row) => row.updatedAt == null ? [] : [{ row, quoteTime: new Date(row.updatedAt).toISOString() }]);
346
+ const allLive = dated.length > 0 && dated.every(({ row }) => row.live && !row.delayed);
347
+ return dated.map(({ row, quoteTime }): CryptoRowObservation => {
348
+ if (row.delayed) return { quoteTime, dataSource: "delayed", delayMinutes: delayedFeedLagMs(CRYPTO_EXCHANGE) / 60_000 };
349
+ return allLive ? { quoteTime, dataSource: "live" } : { quoteTime };
350
+ });
319
351
  }
320
352
 
321
353
  /**
@@ -1,5 +1,6 @@
1
1
  import { useCallback, useEffect, useMemo, useState } from "react";
2
- import { Box, TextAttributes } from "../../../ui";
2
+ import { Box, TextAttributes, useUiCapabilities } from "../../../ui";
3
+ import { withCompanyLogo } from "../../../components/company-logo";
3
4
  import {
4
5
  ChartTableHeader,
5
6
  DataTableView,
@@ -38,7 +39,9 @@ import { usePluginPaneState, usePluginTickerActions } from "../../runtime";
38
39
  import { useLiveStreamingSetting } from "../../../state/hooks/live-streaming";
39
40
  import { useResearchCloudSession } from "../shared/research-cloud-session";
40
41
  import { INITIAL_STREAM_RANGE, streamWindowRows } from "../shared/use-quote-board";
41
- import { cachedCryptoMarkets, cachedStablecoinSupply, loadCryptoMarkets, loadStablecoinSupply } from "./client";
42
+ import { cachedCryptoMarkets, cachedDefiTvl, cachedStablecoinSupply, loadCryptoMarkets, loadDefiTvl, loadStablecoinSupply } from "./client";
43
+ import { defiFailure } from "./defi";
44
+ import { DefiTvlView } from "./defi-view";
42
45
  import {
43
46
  buildCryptoColumns,
44
47
  buildCryptoRows,
@@ -56,6 +59,7 @@ import {
56
59
  type CryptoColumn,
57
60
  type CryptoRow,
58
61
  type CryptoSortPreference,
62
+ type CryptoTab,
59
63
  } from "./model";
60
64
  import { stackedSupply, SUPPLY_RANGES, supplyByCode, supplyFailure, type SupplyRangeId } from "./supply";
61
65
 
@@ -91,7 +95,8 @@ function quoteTargets(
91
95
  }));
92
96
  }
93
97
 
94
- function renderCryptoCell(row: CryptoRow, column: CryptoColumn): DataTableCell {
98
+ /** `logos`: the desktop and the web lead each name with the coin's logo; the terminal draws none. */
99
+ function renderCryptoCell(row: CryptoRow, column: CryptoColumn, logos: boolean): DataTableCell {
95
100
  const signed = (value: number | null) => ({
96
101
  text: formatCryptoPercent(value),
97
102
  color: value == null ? colors.textDim : priceColor(value),
@@ -102,7 +107,7 @@ function renderCryptoCell(row: CryptoRow, column: CryptoColumn): DataTableCell {
102
107
  case "code":
103
108
  return { text: row.code, color: colors.textBright, attributes: TextAttributes.BOLD };
104
109
  case "name":
105
- return { text: row.name };
110
+ return withCompanyLogo({ text: row.name }, { symbol: row.code, assetCategory: "CRYPTO", name: row.name }, logos);
106
111
  case "price":
107
112
  return { text: row.priceText };
108
113
  case "changePercent":
@@ -183,7 +188,7 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
183
188
  const data = resource.data?.payload;
184
189
  const { pinTicker } = usePluginTickerActions();
185
190
  const liveStreaming = useLiveStreamingSetting();
186
- const [activeTab, setActiveTab] = usePluginPaneState<CryptoAssetKind>("activeTab", "coin");
191
+ const [activeTab, setActiveTab] = usePluginPaneState<CryptoTab>("activeTab", "coin");
187
192
  const [selectedId, setSelectedId] = usePluginPaneState<string | null>("selected", null);
188
193
  const [sort, setSort] = useState<CryptoSortPreference>(DEFAULT_CRYPTO_SORT);
189
194
  const [visibleRange, setVisibleRange] = useState(INITIAL_STREAM_RANGE);
@@ -202,16 +207,29 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
202
207
  const [supplyRange, setSupplyRange] = usePluginPaneState<SupplyRangeId>("supplyRange", "1Y");
203
208
  const stablecoins = activeTab === "stablecoin";
204
209
 
210
+ // DeFi TVL likewise loads once its tab is first shown; the server reads it once a UTC day.
211
+ const defi = activeTab === "defi";
212
+ const [defiShown, setDefiShown] = useState(defi);
213
+ useEffect(() => {
214
+ if (defi) setDefiShown(true);
215
+ }, [defi]);
216
+ const defiLoader = useCallback((force: boolean) => loadDefiTvl(force), [session.requestKey]);
217
+ const defiResource = useAsyncResource(defiShown ? defiLoader : null, { initialData: cachedDefiTvl });
218
+ const defiPayload = defiResource.data?.payload ?? null;
219
+ useAutoRefresh(defiResource.updatedAt, defiResource.load, { intervalMs: SUPPLY_REFRESH_MS });
220
+
221
+ // The DeFi tab lists no assets; the coin and stablecoin streams stop while it shows.
222
+ const assetKind: CryptoAssetKind = activeTab === "stablecoin" ? "stablecoin" : "coin";
205
223
  const tabAssets = useMemo(
206
- () => data?.assets.filter((asset) => asset.kind === activeTab) ?? [],
207
- [activeTab, data],
224
+ () => (defi ? [] : data?.assets.filter((asset) => asset.kind === activeTab) ?? []),
225
+ [activeTab, data, defi],
208
226
  );
209
227
  // The stream follows the rows on screen. Ordering by the board snapshot keeps
210
228
  // live ticks from reshuffling the subscription; the overscan covers the drift.
211
229
  const streamedAssets = useMemo(() => {
212
- const ordered = sortCryptoRows(buildCryptoRows(tabAssets, activeTab, NO_QUOTES), sort).map((row) => row.asset);
230
+ const ordered = sortCryptoRows(buildCryptoRows(tabAssets, assetKind, NO_QUOTES), sort).map((row) => row.asset);
213
231
  return streamWindowRows(ordered, visibleRange, ordered.find((asset) => asset.symbol === selectedId));
214
- }, [activeTab, selectedId, sort, tabAssets, visibleRange]);
232
+ }, [assetKind, selectedId, sort, tabAssets, visibleRange]);
215
233
  const targets = useMemo(() => quoteTargets(streamedAssets, selectedId), [selectedId, streamedAssets]);
216
234
  const { entries, freshnessNow } = useLiveQuoteEntries(targets, {
217
235
  freshnessScopeKey: `crypto-board:${activeTab}`,
@@ -221,20 +239,20 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
221
239
  const supplyRows = useMemo(() => (stablecoins ? supplyByCode(supply) : null), [stablecoins, supply]);
222
240
  const rows = useMemo(
223
241
  () => {
224
- const built = buildCryptoRows(tabAssets, activeTab, entries, freshnessNow);
242
+ const built = buildCryptoRows(tabAssets, assetKind, entries, freshnessNow);
225
243
  return sortCryptoRows(supplyRows ? withCryptoSupply(built, supplyRows) : built, sort);
226
244
  },
227
- [activeTab, entries, freshnessNow, sort, supplyRows, tabAssets],
245
+ [assetKind, entries, freshnessNow, sort, supplyRows, tabAssets],
228
246
  );
229
247
  const streamedIds = useMemo(() => new Set(streamedAssets.map((asset) => asset.symbol)), [streamedAssets]);
230
248
  const allStreamedLive = liveStreaming && streamedIds.size > 0
231
249
  && rows.every((row) => !streamedIds.has(row.id) || row.live);
232
250
  const boardRefreshMs = allStreamedLive ? CRYPTO_BOARD_STREAMING_REFRESH_MS : CRYPTO_BOARD_REFRESH_MS;
233
251
  useEffect(() => {
234
- if (!paneVisible) return;
252
+ if (!paneVisible || defi) return;
235
253
  const timer = setInterval(() => void reloadBoard(false), boardRefreshMs);
236
254
  return () => clearInterval(timer);
237
- }, [boardRefreshMs, paneVisible, reloadBoard]);
255
+ }, [boardRefreshMs, defi, paneVisible, reloadBoard]);
238
256
  useEffect(() => {
239
257
  if (!rows.length) return;
240
258
  if (!selectedId || !rows.some((row) => row.id === selectedId)) setSelectedId(rows[0]!.id);
@@ -254,7 +272,7 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
254
272
  : null, [now, observations]);
255
273
  // Supply columns join only once there is supply to show; an outage leaves the price columns as they are.
256
274
  const hasSupply = !!supplyRows && supplyRows.size > 0;
257
- const columns = useMemo(() => buildCryptoColumns(width, activeTab, hasSupply), [activeTab, hasSupply, width]);
275
+ const columns = useMemo(() => buildCryptoColumns(width, assetKind, hasSupply), [assetKind, hasSupply, width]);
258
276
 
259
277
  // Other is muted against the theme it is drawn on; the coins take the shared series palette, which the chart themes.
260
278
  const otherColor = useThemeColors().textMuted;
@@ -282,7 +300,7 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
282
300
  value: tab.value,
283
301
  }));
284
302
  const selectTab = (value: string) => {
285
- setActiveTab(value as CryptoAssetKind);
303
+ setActiveTab(value as CryptoTab);
286
304
  setSelectedId(null);
287
305
  setVisibleRange(INITIAL_STREAM_RANGE);
288
306
  };
@@ -291,7 +309,10 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
291
309
  usePaneNoticeFooter({
292
310
  registrationId: "crypto-board:notices",
293
311
  focused,
294
- notices: [
312
+ notices: defi ? [
313
+ ...(defiPayload?.warnings ?? []),
314
+ ...(defiResource.data?.refreshError ? [defiFailure(defiResource.data.refreshError)] : []),
315
+ ] : [
295
316
  ...(data?.warnings ?? []),
296
317
  ...(resource.data?.refreshError ? [resource.data.refreshError] : []),
297
318
  ...(stablecoins ? [
@@ -302,16 +323,22 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
302
323
  ],
303
324
  });
304
325
  usePaneFooter("crypto-board", () => ({
305
- info: [
326
+ info: defi ? [
327
+ ...(defiResource.loading && !defiPayload ? [{ id: "loading", parts: [{ text: "loading", tone: "muted" as const }] }] : []),
328
+ ...(defiPayload && defiResource.error ? [{ id: "refresh", parts: [{ text: "refresh failed", tone: "warning" as const }] }] : []),
329
+ ...(defiResource.data?.stale ? [{ id: "cached", parts: [{ text: "cached", tone: "warning" as const }] }] : []),
330
+ ] : [
306
331
  // Background refreshes run every 15s; only the first load is worth a label.
307
332
  ...(resource.loading && !data ? [{ id: "loading", parts: [{ text: "loading", tone: "muted" as const }] }] : []),
308
333
  ...(data && resource.error ? [{ id: "refresh", parts: [{ text: "refresh failed", tone: "warning" as const }] }] : []),
309
334
  ...(statusLine ? [{ id: "updated", asOf: true, parts: [{ text: statusLine, tone: "muted" as const }] }] : []),
310
335
  ...(resource.data?.stale ? [{ id: "cached", parts: [{ text: "cached", tone: "warning" as const }] }] : []),
311
336
  ],
312
- }), [data, statusLine, resource.data?.stale, resource.error, resource.loading]);
337
+ }), [data, defi, defiPayload, defiResource.data?.stale, defiResource.error, defiResource.loading, statusLine, resource.data?.stale, resource.error, resource.loading]);
313
338
 
314
339
  const reloadSupply = supplyResource.reload;
340
+ const logos = useUiCapabilities().nativePaneChrome === true;
341
+ const renderCell = useCallback((row: CryptoRow, column: CryptoColumn) => renderCryptoCell(row, column, logos), [logos]);
315
342
  const handleKeyDown = useCallback((event: DataTableKeyEvent) => (
316
343
  handleRefreshKey(event, () => {
317
344
  void resource.reload();
@@ -321,10 +348,17 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
321
348
 
322
349
  const bodyHeight = Math.max(1, height - (tabStrip ? 1 : 0));
323
350
 
351
+ const defiState = useMemo(() => ({
352
+ payload: defiPayload,
353
+ loading: defiResource.loading,
354
+ error: defiResource.error,
355
+ reload: defiResource.reload,
356
+ }), [defiPayload, defiResource.error, defiResource.loading, defiResource.reload]);
357
+
324
358
  return (
325
359
  <Box width={width} height={height} flexDirection="column">
326
360
  {tabStrip && <Box height={1} paddingX={1}>{tabStrip}</Box>}
327
- <PaneStatusBody
361
+ {defi ? <DefiTvlView width={width} height={bodyHeight} focused={focused} resource={defiState} /> : <PaneStatusBody
328
362
  loading={resource.loading && !data}
329
363
  error={!data ? resource.error : null}
330
364
  subject="crypto prices"
@@ -357,7 +391,7 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
357
391
  })}
358
392
  visibleRangeKey={`${activeTab}:${sort.columnId}:${sort.direction}`}
359
393
  onVisibleRangeChange={setVisibleRange}
360
- renderCell={renderCryptoCell}
394
+ renderCell={renderCell}
361
395
  selectedTextOverridesCellColor
362
396
  emptyStateTitle="No crypto assets returned."
363
397
  rootBefore={stablecoins ? (
@@ -379,7 +413,7 @@ export function CryptoBoardPane({ width, height, focused }: PaneProps) {
379
413
  />
380
414
  ) : undefined}
381
415
  />
382
- </PaneStatusBody>
416
+ </PaneStatusBody>}
383
417
  </Box>
384
418
  );
385
419
  }
@@ -1,6 +1,6 @@
1
1
  import type { SeriesDefinition, SeriesPoint } from "../../../series/types";
2
2
  import { cachedSeriesWarning } from "../shared/series-warning";
3
- import { loadStablecoinSupply, loadStablecoinSupplyHistory } from "./client";
3
+ import { loadDefiTvl, loadStablecoinSupply, loadStablecoinSupplyHistory } from "./client";
4
4
 
5
5
  const DAY_MS = 86_400_000;
6
6
 
@@ -50,6 +50,23 @@ const STABLECOIN_SUPPLY_SERIES: readonly SeriesDefinition[] = [
50
50
  },
51
51
  ];
52
52
 
53
+ /** Total value locked in DeFi, as CRYP's DeFi tab charts it. */
54
+ const DEFI_TVL_SERIES: SeriesDefinition = {
55
+ id: "crypto:defi-tvl",
56
+ name: "Total DeFi TVL",
57
+ unit: "USD",
58
+ frequency: "daily",
59
+ group: "Crypto",
60
+ tags: ["defi", "tvl", "total value locked", "on-chain", "protocols", "chains"],
61
+ description: "Total value locked in DeFi protocols across every chain, valued in USD, daily since 2018, as DefiLlama measures it and CRYP's DeFi tab charts it.",
62
+ load: async () => {
63
+ const resource = await loadDefiTvl();
64
+ const history = resource.payload.history;
65
+ if (!history) throw new Error("DeFi TVL is not available yet.");
66
+ return { points: dailyPoints(history.start, history.total), warning: cachedSeriesWarning(resource) };
67
+ },
68
+ };
69
+
53
70
  const PAIRS: ReadonlyArray<{ symbol: string; name: string }> = [
54
71
  { symbol: "BTC-USD", name: "Bitcoin" },
55
72
  { symbol: "ETH-USD", name: "Ethereum" },
@@ -96,4 +113,5 @@ export const CRYPTO_SERIES: readonly SeriesDefinition[] = [
96
113
  expression: "{ticker}:price",
97
114
  },
98
115
  ...STABLECOIN_SUPPLY_SERIES,
116
+ DEFI_TVL_SERIES,
99
117
  ];
@@ -0,0 +1,60 @@
1
+ import { apiClient } from "../../../api-client";
2
+ import type { CryptoEtfFlowAsset, CryptoEtfFlowsPayload } from "../../../api-client/crypto-etf-flows";
3
+ import { createPluginCache } from "../../../data/plugin-cache";
4
+ import { cachedCloudResource, loadCloudResource, unavailableOnServer } from "../shared/cloud-resource";
5
+
6
+ export const cryptoEtfFlowsCache = createPluginCache<CryptoEtfFlowsPayload>({
7
+ kind: "crypto-etf-flows", source: "gloom-cloud", schemaVersion: 1,
8
+ // Flows post once a trading day, in the US evening and the next morning in Europe.
9
+ policy: { staleMs: 15 * 60_000, expireMs: 7 * 24 * 60 * 60_000 },
10
+ });
11
+
12
+ const date = (value: unknown): value is string => typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value)
13
+ && new Date(`${value}T00:00:00Z`).toISOString().slice(0, 10) === value;
14
+ const flow = (value: unknown) => value === null || (typeof value === "number" && Number.isFinite(value));
15
+ const text = (value: unknown): value is string => typeof value === "string" && value.trim().length > 0;
16
+ const textOrNull = (value: unknown) => value === null || text(value);
17
+
18
+ /**
19
+ * The flows as served, or an error: the asset asked for, its funds once each,
20
+ * every day newest first with a figure or none for each fund, and where they
21
+ * are from. A payload that breaks any of it is not drawn.
22
+ */
23
+ export function validateCryptoEtfFlows(payload: CryptoEtfFlowsPayload, asset: CryptoEtfFlowAsset): CryptoEtfFlowsPayload {
24
+ const invalid = (): never => { throw new Error("The server returned invalid crypto ETF flows"); };
25
+ if (!payload || payload.asset !== asset || payload.unit !== "USD millions" || !Array.isArray(payload.funds)
26
+ || !Array.isArray(payload.days) || !date(payload.asOf) || !text(payload.fetchedAt) || !Number.isFinite(Date.parse(payload.fetchedAt))
27
+ || typeof payload.stale !== "boolean" || !payload.source || !text(payload.source.publisher) || !text(payload.source.url)) return invalid();
28
+ const tickers = payload.funds.map((fund) => fund?.ticker);
29
+ if (!tickers.length || tickers.some((ticker) => !text(ticker)) || new Set(tickers).size !== tickers.length
30
+ || payload.funds.some((fund) => !textOrNull(fund.name) || !textOrNull(fund.issuer))) return invalid();
31
+ const known = new Set(tickers);
32
+ for (const [index, day] of payload.days.entries()) {
33
+ if (!day || !date(day.date) || (index > 0 && day.date >= payload.days[index - 1]!.date) || !flow(day.total)
34
+ || !day.flows || typeof day.flows !== "object" || Object.entries(day.flows).some(([ticker, value]) => !known.has(ticker) || !flow(value))
35
+ || !Array.isArray(day.pending) || day.pending.some((ticker) => !known.has(ticker))) return invalid();
36
+ }
37
+ if (payload.days[0] && payload.days[0].date !== payload.asOf) return invalid();
38
+ return payload;
39
+ }
40
+
41
+ export async function fetchCryptoEtfFlows(
42
+ asset: CryptoEtfFlowAsset,
43
+ client: Pick<typeof apiClient, "getCloudCryptoEtfFlows"> = apiClient,
44
+ ): Promise<CryptoEtfFlowsPayload> {
45
+ try {
46
+ return validateCryptoEtfFlows(await client.getCloudCryptoEtfFlows(asset), asset);
47
+ } catch (error) {
48
+ // 404 from a server without the route; 503 until the first read is stored.
49
+ throw unavailableOnServer(error, "Crypto ETF flows are not available yet.", [404, 503]);
50
+ }
51
+ }
52
+
53
+ export function cachedCryptoEtfFlows(asset: CryptoEtfFlowAsset) {
54
+ return cachedCloudResource(cryptoEtfFlowsCache, asset, (payload) => validateCryptoEtfFlows(payload, asset));
55
+ }
56
+
57
+ export function loadCryptoEtfFlows(asset: CryptoEtfFlowAsset, force = false) {
58
+ return loadCloudResource(cryptoEtfFlowsCache, asset, () => fetchCryptoEtfFlows(asset),
59
+ { force, validate: (payload) => validateCryptoEtfFlows(payload, asset) });
60
+ }