gloomberb 0.17.5 → 0.18.0

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 (922) hide show
  1. package/README.md +2 -0
  2. package/README.zh-CN.md +2 -0
  3. package/package.json +8 -1
  4. package/patches/electrobun@1.18.1.patch +74 -0
  5. package/src/account/auth-model.ts +3 -2
  6. package/src/account/device-signin-dialog.tsx +38 -13
  7. package/src/account/device-signin.ts +2 -1
  8. package/src/account/upgrade-dialog.tsx +6 -2
  9. package/src/api-client/askg.ts +5 -3
  10. package/src/api-client/bank-figures.ts +73 -0
  11. package/src/api-client/chat.ts +9 -0
  12. package/src/api-client/commodity-balances.ts +77 -0
  13. package/src/api-client/credit-boards.ts +21 -1
  14. package/src/api-client/crypto-markets.ts +88 -1
  15. package/src/api-client/data.ts +135 -6
  16. package/src/api-client/debt-maturities.ts +18 -0
  17. package/src/api-client/earnings.ts +10 -0
  18. package/src/api-client/equity-screener.ts +3 -0
  19. package/src/api-client/errors.ts +13 -0
  20. package/src/api-client/fund-facts.ts +72 -0
  21. package/src/api-client/futures-curve.ts +26 -3
  22. package/src/api-client/geo.ts +11 -1
  23. package/src/api-client/index.ts +30 -2
  24. package/src/api-client/insider-signals.ts +159 -0
  25. package/src/api-client/market-discovery.ts +1 -1
  26. package/src/api-client/normalizers.ts +2 -0
  27. package/src/api-client/paths.ts +28 -0
  28. package/src/api-client/request.ts +11 -3
  29. package/src/api-client/research-activity.ts +15 -8
  30. package/src/api-client/socket.ts +16 -3
  31. package/src/api-client/supply-chain-graph.ts +2 -2
  32. package/src/api-client/supply-chain.ts +8 -0
  33. package/src/api-client/tape.ts +12 -0
  34. package/src/api-client/types.ts +91 -3
  35. package/src/api-client/upgrade-experiment.ts +4 -3
  36. package/src/api-client/wall-experiments.ts +5 -3
  37. package/src/api-client/wall-summary.ts +3 -1
  38. package/src/api-client/web-experiments.ts +5 -2
  39. package/src/api-client/yield-curves.ts +17 -0
  40. package/src/app/command-bar-intro.ts +38 -0
  41. package/src/app/keybindings/actions.ts +1 -1
  42. package/src/app/pane-runtime/pane-template-runtime.ts +35 -7
  43. package/src/app/pane-runtime/plugin-bindings.ts +4 -0
  44. package/src/app/pane-runtime/ticker-open-runtime.ts +4 -14
  45. package/src/app/pane-runtime/ticker-open-target.ts +31 -0
  46. package/src/app/runtime/broker-import.ts +23 -21
  47. package/src/app/runtime/desktop-deeplink.ts +3 -4
  48. package/src/app/runtime/plugin-bindings.ts +16 -9
  49. package/src/app/runtime/startup.ts +3 -4
  50. package/src/app/runtime/ticker-refresh.ts +13 -12
  51. package/src/app/runtime/update.ts +17 -3
  52. package/src/architecture/core-builtin-allowlist.json +2 -13
  53. package/src/architecture/silent-catch-allowlist.json +3 -0
  54. package/src/architecture/ui-literals-allowlist.json +186 -0
  55. package/src/architecture/ui-tokens-allowlist.json +40 -0
  56. package/src/ask-gloom/pane-context.ts +3 -1
  57. package/src/brokers/broker-portfolio-sync.ts +66 -0
  58. package/src/brokers/signed-in/catalog.ts +2 -1
  59. package/src/brokers/signed-in/client.ts +7 -2
  60. package/src/brokers/signed-in/sign-in-dialog.tsx +120 -26
  61. package/src/brokers/signed-in/sign-in.ts +22 -20
  62. package/src/brokers/sync-broker-instance.ts +77 -42
  63. package/src/capabilities/chart-series.ts +2 -0
  64. package/src/capabilities/registry.ts +1 -3
  65. package/src/cli/bank-section.ts +147 -0
  66. package/src/cli/base-converter.ts +5 -2
  67. package/src/cli/board-coins.ts +70 -0
  68. package/src/cli/commands/fred-series.ts +90 -0
  69. package/src/cli/commands/market.ts +434 -96
  70. package/src/cli/commands/news-search.ts +35 -2
  71. package/src/cli/commands/options-chain.ts +25 -9
  72. package/src/cli/commands/options-leaps.ts +3 -3
  73. package/src/cli/commands/overview.ts +130 -40
  74. package/src/cli/commands/plugins.ts +1 -0
  75. package/src/cli/commands/search.ts +87 -24
  76. package/src/cli/commands/system.ts +5 -2
  77. package/src/cli/commands/ticker.ts +361 -64
  78. package/src/cli/context.ts +15 -1
  79. package/src/cli/desktop-pane-shot.ts +11 -3
  80. package/src/cli/earnings-calendar.ts +2 -1
  81. package/src/cli/errors.ts +25 -2
  82. package/src/cli/export-source.ts +18 -3
  83. package/src/cli/fx-pair.ts +77 -0
  84. package/src/cli/glossary.ts +196 -14
  85. package/src/cli/history-rows.ts +84 -19
  86. package/src/cli/index-roots.ts +26 -0
  87. package/src/cli/index.ts +57 -20
  88. package/src/cli/known-gaps.ts +156 -22
  89. package/src/cli/listing-arg.ts +217 -150
  90. package/src/cli/listing-suggestion.ts +7 -23
  91. package/src/cli/name-entries.ts +76 -0
  92. package/src/cli/not-a-ticker.ts +15 -6
  93. package/src/cli/pane-functions/access-gate.ts +22 -0
  94. package/src/cli/pane-functions/capabilities.ts +62 -4
  95. package/src/cli/pane-functions/catalog.ts +144 -39
  96. package/src/cli/pane-functions/data.ts +6 -5
  97. package/src/cli/pane-functions/discovery.ts +1 -1
  98. package/src/cli/pane-functions/dom.ts +3 -3
  99. package/src/cli/pane-functions/freshness.ts +93 -17
  100. package/src/cli/pane-functions/function-help.ts +20 -17
  101. package/src/cli/pane-functions/headless.ts +187 -40
  102. package/src/cli/pane-functions/index.ts +126 -12
  103. package/src/cli/pane-functions/options.ts +17 -3
  104. package/src/cli/pane-functions/report-notices.ts +17 -3
  105. package/src/cli/pane-functions/resolver.ts +74 -18
  106. package/src/cli/pane-functions/screenshot.ts +126 -23
  107. package/src/cli/pane-functions/shot-options.ts +68 -0
  108. package/src/cli/perpetual-contract.ts +3 -1
  109. package/src/cli/report-tables.ts +21 -6
  110. package/src/cli/result.ts +2 -0
  111. package/src/cli/series-search.ts +6 -1
  112. package/src/cli/staged-tickers.ts +5 -0
  113. package/src/cli/statement-filings.ts +261 -0
  114. package/src/cli/symbol-args.ts +47 -8
  115. package/src/cli/symbol-list.ts +9 -2
  116. package/src/cli/symbol-rows.ts +269 -29
  117. package/src/cli/ticker-resolution.ts +148 -35
  118. package/src/cli/treasury-yields.ts +86 -0
  119. package/src/cli/types.ts +3 -0
  120. package/src/cli/uncovered-instrument.ts +20 -0
  121. package/src/cli/unknown-command.ts +18 -0
  122. package/src/components/chart/composite/axis-overlays.tsx +16 -9
  123. package/src/components/chart/composite/composite-chart.tsx +163 -23
  124. package/src/components/chart/composite/downsample.ts +19 -3
  125. package/src/components/chart/composite/format.ts +13 -0
  126. package/src/components/chart/composite/legend.tsx +161 -68
  127. package/src/components/chart/composite/panel-bitmap.ts +8 -2
  128. package/src/components/chart/composite/panel-labels.ts +38 -0
  129. package/src/components/chart/composite/panel-series.ts +1 -0
  130. package/src/components/chart/composite/panel-surface.tsx +28 -10
  131. package/src/components/chart/composite/price-axis-labels.tsx +16 -3
  132. package/src/components/chart/composite/scene.ts +60 -2
  133. package/src/components/chart/composite/series-axis-tags.tsx +67 -0
  134. package/src/components/chart/composite/toolbar.tsx +12 -7
  135. package/src/components/chart/composite/tools.ts +2 -2
  136. package/src/components/chart/composite/types.ts +34 -0
  137. package/src/components/chart/composite/use-composite-chart-keyboard.ts +28 -1
  138. package/src/components/chart/core/view-reset.ts +46 -0
  139. package/src/components/chart/curve/curve-surface.tsx +1 -1
  140. package/src/components/chart/static/series.ts +39 -0
  141. package/src/components/chart/static/trail-chart-surface.tsx +2 -1
  142. package/src/components/command-bar/commands/collection-list.ts +45 -15
  143. package/src/components/command-bar/commands/collection.ts +11 -4
  144. package/src/components/command-bar/commands/direct/index.ts +1 -1
  145. package/src/components/command-bar/commands/registry.ts +2 -2
  146. package/src/components/command-bar/list/badge.ts +4 -3
  147. package/src/components/command-bar/list/model.ts +12 -0
  148. package/src/components/command-bar/list/view.tsx +1 -1
  149. package/src/components/command-bar/pane-templates/workflow.ts +5 -0
  150. package/src/components/command-bar/panel/index.tsx +19 -8
  151. package/src/components/command-bar/panel/native-surface.ts +6 -4
  152. package/src/components/command-bar/panel/prompt-example.ts +22 -0
  153. package/src/components/command-bar/routes/root/command-items.ts +1 -1
  154. package/src/components/command-bar/routes/root/pick-prefetch.ts +38 -0
  155. package/src/components/command-bar/routes/root/provider-search.ts +9 -9
  156. package/src/components/command-bar/routes/root/results.ts +13 -0
  157. package/src/components/command-bar/routes/root/runtime.ts +3 -0
  158. package/src/components/command-bar/routes/root/shortcut-feedback.ts +3 -1
  159. package/src/components/command-bar/routes/root/shortcut-items.ts +1 -1
  160. package/src/components/command-bar/routes/root/start-here.ts +90 -0
  161. package/src/components/command-bar/routes/ticker-search/actions.ts +34 -0
  162. package/src/components/command-bar/routes/ticker-search/results.ts +42 -3
  163. package/src/components/command-bar/routes/ticker-search/route.ts +3 -10
  164. package/src/components/command-bar/surface/index.tsx +5 -0
  165. package/src/components/command-bar/theme-picker.tsx +3 -1
  166. package/src/components/command-bar/workflow/builtin.ts +5 -1
  167. package/src/components/command-bar/workflow/collection-actions.ts +23 -13
  168. package/src/components/command-bar/workflow/ops.ts +25 -3
  169. package/src/components/command-bar/workflow/pane-reuse.ts +3 -2
  170. package/src/{plugins/builtin/portfolio-list/command-bar.ts → components/command-bar/workflow/portfolio-position.ts} +42 -9
  171. package/src/components/command-bar/workflow/tickers.ts +7 -5
  172. package/src/components/feedback-dialog.tsx +1 -1
  173. package/src/components/form-modal/broker-step.tsx +7 -63
  174. package/src/components/form-modal/content.tsx +7 -2
  175. package/src/components/form-modal/field-row.tsx +6 -8
  176. package/src/components/form-modal/host.tsx +3 -3
  177. package/src/components/form-modal/model.ts +3 -0
  178. package/src/components/form-modal/routes.ts +17 -2
  179. package/src/components/index.ts +6 -6
  180. package/src/components/input-search-bar.tsx +43 -6
  181. package/src/components/layout/detached-pane-shell.tsx +0 -1
  182. package/src/components/layout/floating-pane.tsx +0 -1
  183. package/src/components/layout/header.tsx +8 -7
  184. package/src/components/layout/pane/content.tsx +11 -8
  185. package/src/components/layout/pane/footer/index.tsx +7 -4
  186. package/src/components/layout/pane/footer/model.ts +28 -2
  187. package/src/components/layout/pane/header.tsx +9 -19
  188. package/src/components/layout/pane/index.tsx +0 -1
  189. package/src/components/layout/pane/instrument-coverage-gate.tsx +57 -0
  190. package/src/components/layout/pane/pane-tabs.tsx +4 -3
  191. package/src/components/layout/pane/sizing.ts +9 -0
  192. package/src/components/layout/pane/ticker-fate-gate.tsx +62 -0
  193. package/src/components/layout/shell/pane/capture.ts +44 -20
  194. package/src/components/layout/status-bar.tsx +3 -6
  195. package/src/components/markdown-text.tsx +17 -2
  196. package/src/components/market-board/index.tsx +19 -8
  197. package/src/components/metric-treemap/heat-surface.tsx +2 -7
  198. package/src/components/onboarding/account-step/qr-panel.tsx +5 -2
  199. package/src/components/onboarding/onboarding-frame.tsx +24 -21
  200. package/src/components/onboarding/portfolio-step/positions-panel.tsx +20 -10
  201. package/src/components/onboarding/wizard-model.ts +1 -1
  202. package/src/components/onboarding/wizard-positions.ts +56 -19
  203. package/src/components/pane-settings-dialog/desktop.tsx +12 -50
  204. package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -1
  205. package/src/components/price-performance.tsx +18 -2
  206. package/src/components/reader/article-reader.tsx +11 -10
  207. package/src/components/reader/detail-reader.tsx +9 -5
  208. package/src/components/reader/reader-text.tsx +51 -24
  209. package/src/components/sign-in-code-panel.tsx +129 -75
  210. package/src/components/ticker/badge/format.ts +64 -15
  211. package/src/components/ticker/badge/index.tsx +33 -11
  212. package/src/components/ticker/badge/list.tsx +4 -3
  213. package/src/components/ticker/badge/text.tsx +2 -2
  214. package/src/components/ticker/list-table-view.tsx +8 -1
  215. package/src/components/ui/action-row.tsx +5 -2
  216. package/src/components/ui/audio-player.tsx +70 -0
  217. package/src/components/ui/card.tsx +75 -0
  218. package/src/components/ui/data-table/index.tsx +4 -2
  219. package/src/components/ui/data-table/opentui/index.tsx +61 -20
  220. package/src/components/ui/data-table/opentui/model.ts +104 -0
  221. package/src/components/ui/data-table/types.ts +11 -0
  222. package/src/components/ui/detail-scroll-body.tsx +1 -1
  223. package/src/components/ui/dialog-actions.tsx +1 -21
  224. package/src/components/ui/display.tsx +13 -5
  225. package/src/components/ui/external-link.tsx +4 -2
  226. package/src/components/ui/fields.tsx +12 -0
  227. package/src/components/ui/figure.tsx +5 -3
  228. package/src/components/ui/frame.tsx +40 -6
  229. package/src/components/ui/icon.tsx +4 -0
  230. package/src/components/ui/index.ts +4 -1
  231. package/src/components/ui/inline-quick-add.tsx +4 -1
  232. package/src/components/ui/list-view.tsx +8 -0
  233. package/src/components/ui/prose.tsx +97 -25
  234. package/src/components/ui/query-bar-keys.tsx +32 -6
  235. package/src/components/ui/query-bar.tsx +35 -4
  236. package/src/components/ui/quote.ts +42 -0
  237. package/src/components/ui/range-track.tsx +15 -2
  238. package/src/components/ui/reveal-in-scroll-box.ts +21 -3
  239. package/src/components/ui/select-button.tsx +38 -3
  240. package/src/components/ui/status.tsx +73 -4
  241. package/src/components/ui/table-layout.ts +20 -0
  242. package/src/components/ui/windowed-list.tsx +27 -0
  243. package/src/components/use-pinned-moment.ts +19 -0
  244. package/src/core/app-runtime.ts +2 -2
  245. package/src/core/state/app/instrument.ts +18 -1
  246. package/src/core/state/app/layout.ts +6 -0
  247. package/src/core/state/app/state.ts +14 -2
  248. package/src/data/cached-query.ts +1 -1
  249. package/src/data/config/chart-settings.ts +3 -1
  250. package/src/data/config/home.ts +4 -1
  251. package/src/data/config/store/node.ts +9 -4
  252. package/src/data/config/store/normalize.ts +9 -0
  253. package/src/data/json-storage.ts +6 -3
  254. package/src/data/json-ticker-repository.ts +3 -1
  255. package/src/data/plugin-cache.ts +5 -1
  256. package/src/data/sqlite/json.ts +3 -1
  257. package/src/data/ticker-repository.ts +5 -2
  258. package/src/docs/snapshot.json +248 -5
  259. package/src/feedback/diagnostics.ts +2 -6
  260. package/src/i18n/es.ts +86 -6
  261. package/src/i18n/index.ts +3 -9
  262. package/src/i18n/ja.ts +86 -6
  263. package/src/i18n/ko.ts +86 -6
  264. package/src/i18n/zh-cn.ts +86 -6
  265. package/src/i18n/zh-tw.ts +86 -6
  266. package/src/layout-marketplace/cloud.ts +16 -5
  267. package/src/layout-marketplace/gallery-desktop.tsx +8 -4
  268. package/src/layout-marketplace/gallery.tsx +4 -4
  269. package/src/layout-marketplace/linked-sync.ts +9 -3
  270. package/src/layout-marketplace/linked.ts +24 -3
  271. package/src/layout-marketplace/model.ts +39 -4
  272. package/src/market-data/bars-per-year.ts +43 -0
  273. package/src/market-data/bond-funds.ts +85 -0
  274. package/src/market-data/coordinator/auxiliary.ts +5 -2
  275. package/src/market-data/coordinator/index.ts +39 -5
  276. package/src/market-data/futures-contract.ts +155 -5
  277. package/src/market-data/hooks.tsx +77 -12
  278. package/src/market-data/market/bar-period.ts +107 -0
  279. package/src/market-data/market/format.ts +18 -14
  280. package/src/market-data/market/freshness.ts +29 -4
  281. package/src/market-data/market/index-level.ts +51 -0
  282. package/src/market-data/market/status.ts +152 -13
  283. package/src/market-data/model-dividend-yield.ts +117 -0
  284. package/src/market-data/quotes/freshness.ts +30 -1
  285. package/src/{plugins/builtin/portfolio-list → market-data/quotes}/live-valuation.ts +52 -6
  286. package/src/market-data/quotes/regular-session-valuation.ts +32 -1
  287. package/src/market-data/realized-volatility.ts +16 -7
  288. package/src/market-data/tax-equivalent.ts +344 -0
  289. package/src/news/aggregator.ts +4 -2
  290. package/src/notifications/notification-log.ts +5 -3
  291. package/src/plugins/auto-update-node.ts +1 -0
  292. package/src/plugins/builtin/account-management/footer.ts +1 -1
  293. package/src/plugins/builtin/account-management/keyboard.ts +3 -0
  294. package/src/plugins/builtin/account-management/model.ts +1 -0
  295. package/src/plugins/builtin/account-management/pane.tsx +71 -19
  296. package/src/plugins/builtin/account-management/trial-cancel.ts +40 -0
  297. package/src/plugins/builtin/alerts/cli.ts +7 -18
  298. package/src/plugins/builtin/alerts/constants.ts +8 -0
  299. package/src/plugins/builtin/alerts/event-rows.ts +16 -0
  300. package/src/plugins/builtin/alerts/events-pane.tsx +2 -14
  301. package/src/plugins/builtin/alerts/headless.ts +182 -0
  302. package/src/plugins/builtin/alerts/index.tsx +3 -0
  303. package/src/plugins/builtin/alerts/pane.tsx +1 -7
  304. package/src/plugins/builtin/alerts/storage.ts +17 -1
  305. package/src/plugins/builtin/analytics/index.tsx +6 -1
  306. package/src/plugins/builtin/analytics/metrics.ts +55 -13
  307. package/src/plugins/builtin/analytics/risk-headless.ts +26 -7
  308. package/src/plugins/builtin/analytics/risk-math.ts +83 -0
  309. package/src/plugins/builtin/analytics/risk-model.ts +171 -19
  310. package/src/plugins/builtin/analytics/risk-pane.tsx +17 -12
  311. package/src/plugins/builtin/analytics/sector-model.ts +14 -3
  312. package/src/plugins/builtin/awards/headless.ts +6 -5
  313. package/src/plugins/builtin/awards/index.tsx +1 -1
  314. package/src/plugins/builtin/backtest/client.ts +38 -8
  315. package/src/plugins/builtin/backtest/engine.ts +25 -13
  316. package/src/plugins/builtin/backtest/export.ts +27 -0
  317. package/src/plugins/builtin/backtest/format.ts +19 -3
  318. package/src/plugins/builtin/backtest/headless.ts +42 -28
  319. package/src/plugins/builtin/backtest/index.tsx +3 -0
  320. package/src/plugins/builtin/backtest/pane.tsx +39 -10
  321. package/src/plugins/builtin/backtest/report.ts +160 -0
  322. package/src/plugins/builtin/backtest/rules.ts +2 -0
  323. package/src/plugins/builtin/backtest/window.ts +112 -0
  324. package/src/plugins/builtin/bond-calculator/headless.ts +3 -2
  325. package/src/plugins/builtin/broker-manager/add-flow.tsx +4 -4
  326. package/src/plugins/builtin/builtin-plugin-meta.ts +0 -1
  327. package/src/plugins/builtin/catalysts/headless.ts +24 -13
  328. package/src/plugins/builtin/catalysts/index.tsx +4 -2
  329. package/src/plugins/builtin/catalysts/model.ts +18 -1
  330. package/src/plugins/builtin/catalysts/pane.tsx +2 -2
  331. package/src/plugins/builtin/cds/client.ts +28 -5
  332. package/src/plugins/builtin/cds/headless.ts +183 -31
  333. package/src/plugins/builtin/cds/index.tsx +1 -1
  334. package/src/plugins/builtin/cds/model.ts +229 -53
  335. package/src/plugins/builtin/cds/pane.tsx +82 -26
  336. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -1
  337. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +39 -1
  338. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +77 -0
  339. package/src/plugins/builtin/chart-composer/chart-spec.ts +15 -0
  340. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +22 -2
  341. package/src/plugins/builtin/chart-composer/editor/controller.ts +14 -10
  342. package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +2 -2
  343. package/src/plugins/builtin/chart-composer/formula.ts +233 -0
  344. package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -2
  345. package/src/plugins/builtin/chart-composer/headless.ts +117 -15
  346. package/src/plugins/builtin/chart-composer/index.tsx +73 -15
  347. package/src/plugins/builtin/chart-composer/pane.tsx +86 -23
  348. package/src/plugins/builtin/chart-composer/presets.ts +165 -8
  349. package/src/plugins/builtin/chart-composer/quick-add.tsx +9 -2
  350. package/src/plugins/builtin/chart-composer/series-catalog.ts +85 -16
  351. package/src/plugins/builtin/chart-composer/series-expression.ts +10 -8
  352. package/src/plugins/builtin/chart-composer/series-listings.ts +178 -0
  353. package/src/plugins/builtin/chart-composer/session-range.ts +87 -0
  354. package/src/plugins/builtin/chart-composer/settings.ts +16 -4
  355. package/src/plugins/builtin/chart-composer/studies.ts +1 -1
  356. package/src/plugins/builtin/chat/attachments/desktop.tsx +4 -1
  357. package/src/plugins/builtin/chat/content/channel-navigation.ts +17 -6
  358. package/src/plugins/builtin/chat/content/composer-runtime.ts +49 -14
  359. package/src/plugins/builtin/chat/content/composer.tsx +22 -1
  360. package/src/plugins/builtin/chat/content/index.tsx +47 -10
  361. package/src/plugins/builtin/chat/content/layout-metrics.ts +3 -0
  362. package/src/plugins/builtin/chat/content/mentions.ts +50 -21
  363. package/src/plugins/builtin/chat/content/scroll.ts +12 -5
  364. package/src/plugins/builtin/chat/content/shortcuts.ts +32 -13
  365. package/src/plugins/builtin/chat/content/snapshot.ts +40 -6
  366. package/src/plugins/builtin/chat/content/transcript.tsx +48 -37
  367. package/src/plugins/builtin/chat/content/whole-message-copy.ts +44 -2
  368. package/src/plugins/builtin/chat/controller/index.ts +68 -17
  369. package/src/plugins/builtin/chat/controller/mention-candidates.ts +104 -0
  370. package/src/plugins/builtin/chat/controller/realtime.ts +9 -0
  371. package/src/plugins/builtin/chat/controller/state.ts +10 -0
  372. package/src/plugins/builtin/chat/controller/view.ts +2 -0
  373. package/src/plugins/builtin/chat/conversation-recency.ts +73 -0
  374. package/src/plugins/builtin/chat/conversations.ts +12 -5
  375. package/src/plugins/builtin/chat/ghost-user.ts +11 -3
  376. package/src/plugins/builtin/chat/layout.ts +25 -5
  377. package/src/plugins/builtin/chat/message/desktop.tsx +15 -5
  378. package/src/plugins/builtin/chat/message/header.tsx +26 -4
  379. package/src/plugins/builtin/chat/message/pane-chip.tsx +131 -35
  380. package/src/plugins/builtin/chat/message/render-state.ts +28 -1
  381. package/src/plugins/builtin/chat/message/terminal.tsx +9 -3
  382. package/src/plugins/builtin/chat/pane-links/composer.ts +87 -0
  383. package/src/plugins/builtin/chat/pane-links/model.ts +1 -1
  384. package/src/plugins/builtin/chat/share/flow.tsx +9 -73
  385. package/src/plugins/builtin/chat/sidebar-rows.ts +18 -5
  386. package/src/plugins/builtin/chat/sidebar.tsx +6 -1
  387. package/src/plugins/builtin/cloud/askg/controller.ts +5 -3
  388. package/src/plugins/builtin/cloud/askg/executor.ts +3 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +16 -0
  390. package/src/plugins/builtin/cloud/askg/manifest.ts +4 -3
  391. package/src/plugins/builtin/cloud/askg/pane.tsx +6 -2
  392. package/src/plugins/builtin/cloud/auth-actions.tsx +4 -2
  393. package/src/plugins/builtin/cloud/company-picker.tsx +21 -26
  394. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +5 -3
  395. package/src/plugins/builtin/cloud/plugin.tsx +2 -0
  396. package/src/plugins/builtin/cloud/team/module.tsx +5 -1
  397. package/src/plugins/builtin/cloud/team/pane.tsx +11 -4
  398. package/src/plugins/builtin/cloud/team/views.ts +11 -4
  399. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +9 -4
  400. package/src/plugins/builtin/cloud/terminal-relay/manifest.ts +16 -5
  401. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +3 -2
  402. package/src/plugins/builtin/cloud/thesis/detail.tsx +2 -1
  403. package/src/plugins/builtin/cloud/thesis/exposure.ts +3 -0
  404. package/src/plugins/builtin/cloud/thesis/prompts.tsx +3 -2
  405. package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +2 -1
  406. package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +2 -1
  407. package/src/plugins/builtin/cloud/verification-status-widget.tsx +2 -1
  408. package/src/plugins/builtin/commodities-energy/index.tsx +31 -9
  409. package/src/plugins/builtin/commodities-energy/view-state.ts +11 -0
  410. package/src/plugins/builtin/commodity-balances/client.ts +51 -193
  411. package/src/plugins/builtin/commodity-balances/headless.ts +10 -3
  412. package/src/plugins/builtin/commodity-balances/model.ts +5 -180
  413. package/src/plugins/builtin/commodity-balances/pane.tsx +3 -0
  414. package/src/plugins/builtin/company-attention/headless.ts +15 -7
  415. package/src/plugins/builtin/company-attention/index.tsx +1 -1
  416. package/src/plugins/builtin/company-attention/model.ts +49 -4
  417. package/src/plugins/builtin/company-attention/pane.tsx +11 -9
  418. package/src/plugins/builtin/company-kpis/headless.ts +4 -3
  419. package/src/plugins/builtin/company-kpis/index.tsx +2 -2
  420. package/src/plugins/builtin/company-kpis/pane.tsx +9 -3
  421. package/src/plugins/builtin/congress-trades/headless.ts +23 -2
  422. package/src/plugins/builtin/correlation/relationship/pane.tsx +18 -46
  423. package/src/plugins/builtin/cot/headless.ts +5 -2
  424. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +41 -13
  425. package/src/plugins/builtin/credit-boards/client.ts +9 -2
  426. package/src/plugins/builtin/credit-boards/headless.ts +93 -27
  427. package/src/plugins/builtin/credit-boards/index.tsx +15 -4
  428. package/src/plugins/builtin/credit-boards/model.ts +105 -6
  429. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +14 -3
  430. package/src/plugins/builtin/credit-documents/detail.tsx +2 -1
  431. package/src/plugins/builtin/credit-documents/index.tsx +3 -0
  432. package/src/plugins/builtin/credit-documents/model.ts +3 -10
  433. package/src/plugins/builtin/crypto-board/client.ts +152 -2
  434. package/src/plugins/builtin/crypto-board/headless.ts +138 -19
  435. package/src/plugins/builtin/crypto-board/index.tsx +5 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +210 -12
  437. package/src/plugins/builtin/crypto-board/pane.tsx +148 -9
  438. package/src/plugins/builtin/crypto-board/series.ts +52 -1
  439. package/src/plugins/builtin/crypto-board/supply.ts +123 -0
  440. package/src/plugins/builtin/custom-view/index.tsx +1 -1
  441. package/src/plugins/builtin/custom-view/loader.ts +57 -7
  442. package/src/plugins/builtin/custom-view/sources.ts +146 -0
  443. package/src/plugins/builtin/custom-view/view-spec.ts +37 -1
  444. package/src/plugins/builtin/debt-maturities/client.ts +54 -1
  445. package/src/plugins/builtin/debt-maturities/headless.ts +27 -3
  446. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  447. package/src/plugins/builtin/debt-maturities/model.ts +58 -13
  448. package/src/plugins/builtin/debt-maturities/pane.tsx +47 -7
  449. package/src/plugins/builtin/dividend-yield/client.ts +42 -36
  450. package/src/plugins/builtin/dividend-yield/headless.ts +113 -18
  451. package/src/plugins/builtin/dividend-yield/index.tsx +5 -2
  452. package/src/plugins/builtin/dividend-yield/pane.tsx +37 -13
  453. package/src/plugins/builtin/dividend-yield/provider-client.ts +7 -3
  454. package/src/plugins/builtin/dividend-yield/ranking.ts +187 -0
  455. package/src/plugins/builtin/dividend-yield/reference-price.ts +28 -5
  456. package/src/plugins/builtin/dividend-yield/types.ts +6 -1
  457. package/src/plugins/builtin/dividend-yield/view.ts +1 -1
  458. package/src/plugins/builtin/docs/blocks.tsx +54 -8
  459. package/src/plugins/builtin/docs/pane.tsx +8 -13
  460. package/src/plugins/builtin/earnings/board-model.ts +33 -3
  461. package/src/plugins/builtin/earnings/board-table.ts +59 -14
  462. package/src/plugins/builtin/earnings/board.tsx +36 -3
  463. package/src/plugins/builtin/earnings/headless.ts +27 -7
  464. package/src/plugins/builtin/earnings/history-model.ts +9 -1
  465. package/src/plugins/builtin/earnings/history-table.ts +16 -5
  466. package/src/plugins/builtin/earnings/history.tsx +40 -10
  467. package/src/plugins/builtin/earnings/index.tsx +3 -1
  468. package/src/plugins/builtin/earnings/no-earnings.ts +52 -0
  469. package/src/plugins/builtin/earnings-calls/data.ts +51 -0
  470. package/src/plugins/builtin/earnings-calls/headless.ts +7 -0
  471. package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
  472. package/src/plugins/builtin/earnings-calls/model.ts +97 -0
  473. package/src/plugins/builtin/earnings-calls/pane.tsx +107 -7
  474. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +140 -22
  475. package/src/plugins/builtin/earnings-calls/use-call-playback.ts +194 -0
  476. package/src/plugins/builtin/econ/calendar-model.ts +22 -0
  477. package/src/plugins/builtin/econ/calendar-source.ts +35 -0
  478. package/src/plugins/builtin/econ/index.tsx +40 -8
  479. package/src/plugins/builtin/econ-statistics/defs.ts +7 -0
  480. package/src/plugins/builtin/econ-statistics/detail.tsx +11 -1
  481. package/src/plugins/builtin/econ-statistics/headless.ts +31 -5
  482. package/src/plugins/builtin/econ-statistics/pane.tsx +5 -3
  483. package/src/plugins/builtin/econ-statistics/stats.ts +10 -0
  484. package/src/plugins/builtin/econ-statistics/view.ts +23 -0
  485. package/src/plugins/builtin/equity-screener/client.ts +1 -1
  486. package/src/plugins/builtin/equity-screener/model.ts +46 -4
  487. package/src/plugins/builtin/equity-screener/pane.tsx +3 -0
  488. package/src/plugins/builtin/estimate-revisions/client.ts +32 -22
  489. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  490. package/src/plugins/builtin/estimate-revisions/index.tsx +1 -0
  491. package/src/plugins/builtin/estimate-revisions/pane.tsx +5 -3
  492. package/src/plugins/builtin/executives/index.tsx +1 -0
  493. package/src/plugins/builtin/exposure/editor.tsx +3 -3
  494. package/src/plugins/builtin/fear-greed/index.tsx +9 -0
  495. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  496. package/src/plugins/builtin/futures/index.tsx +2 -2
  497. package/src/plugins/builtin/futures/model.ts +39 -25
  498. package/src/plugins/builtin/futures/series.ts +38 -1
  499. package/src/plugins/builtin/futures/table.tsx +1 -1
  500. package/src/plugins/builtin/futures/use-board-terms.ts +2 -2
  501. package/src/plugins/builtin/futures-curve/client.ts +4 -4
  502. package/src/plugins/builtin/futures-curve/headless.ts +24 -4
  503. package/src/plugins/builtin/futures-curve/index.tsx +2 -2
  504. package/src/plugins/builtin/futures-curve/model.ts +50 -9
  505. package/src/plugins/builtin/futures-curve/pane.tsx +14 -10
  506. package/src/plugins/builtin/help/index.tsx +55 -8
  507. package/src/plugins/builtin/help/shortcut-table.tsx +15 -2
  508. package/src/plugins/builtin/holders/headless.ts +12 -0
  509. package/src/plugins/builtin/insider/headless.ts +345 -5
  510. package/src/plugins/builtin/insider/index.tsx +304 -36
  511. package/src/plugins/builtin/insider/insiders.tsx +224 -0
  512. package/src/plugins/builtin/insider/signals-cells.tsx +52 -0
  513. package/src/plugins/builtin/insider/signals-client.ts +193 -0
  514. package/src/plugins/builtin/insider/signals-model.ts +718 -0
  515. package/src/plugins/builtin/insider/signals.tsx +376 -0
  516. package/src/plugins/builtin/ipo-calendar/headless.ts +17 -7
  517. package/src/plugins/builtin/ipo-calendar/index.tsx +23 -3
  518. package/src/plugins/builtin/ipo-calendar/model.ts +84 -36
  519. package/src/plugins/builtin/ipo-calendar/pane.tsx +20 -8
  520. package/src/plugins/builtin/iv-history/client.ts +41 -2
  521. package/src/plugins/builtin/iv-history/headless.ts +26 -16
  522. package/src/plugins/builtin/iv-history/screen-pane.tsx +25 -7
  523. package/src/plugins/builtin/jobs/headless.ts +1 -0
  524. package/src/plugins/builtin/jobs/index.tsx +1 -0
  525. package/src/plugins/builtin/jodi/client.ts +42 -205
  526. package/src/plugins/builtin/jodi/headless.ts +15 -4
  527. package/src/plugins/builtin/jodi/model.ts +18 -43
  528. package/src/plugins/builtin/jodi/pane.tsx +5 -0
  529. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  530. package/src/plugins/builtin/kelly-sizer/portfolio.ts +1 -1
  531. package/src/plugins/builtin/market-heatmap/headless.ts +1 -0
  532. package/src/plugins/builtin/market-heatmap/portfolio.ts +3 -1
  533. package/src/plugins/builtin/market-movers/client.ts +32 -6
  534. package/src/plugins/builtin/market-movers/headless.ts +7 -2
  535. package/src/plugins/builtin/market-movers/model.ts +64 -3
  536. package/src/plugins/builtin/market-movers/screener.ts +20 -9
  537. package/src/plugins/builtin/market-valuation/detail.tsx +7 -2
  538. package/src/plugins/builtin/market-valuation/headless.ts +17 -4
  539. package/src/plugins/builtin/market-valuation/pane.tsx +8 -4
  540. package/src/plugins/builtin/market-valuation/view.ts +10 -0
  541. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +31 -57
  542. package/src/plugins/builtin/mna/distress/headless.ts +2 -1
  543. package/src/plugins/builtin/mna/headless.ts +14 -2
  544. package/src/plugins/builtin/mna/index.tsx +1 -0
  545. package/src/plugins/builtin/news/headless.ts +4 -0
  546. package/src/plugins/builtin/news/wire/news/footer.ts +5 -3
  547. package/src/plugins/builtin/news/wire/news/table.tsx +57 -11
  548. package/src/plugins/builtin/notes/cli.ts +8 -4
  549. package/src/plugins/builtin/notes/files.ts +66 -20
  550. package/src/plugins/builtin/notes/migration.ts +18 -6
  551. package/src/plugins/builtin/notes/owner.tsx +3 -2
  552. package/src/plugins/builtin/notes/quick-notes-pane.tsx +3 -2
  553. package/src/plugins/builtin/options-positioning/client.ts +10 -0
  554. package/src/plugins/builtin/options-positioning/headless.ts +88 -13
  555. package/src/plugins/builtin/options-positioning/index.tsx +2 -2
  556. package/src/plugins/builtin/options-positioning/model.ts +33 -0
  557. package/src/plugins/builtin/options-positioning/pane.tsx +38 -16
  558. package/src/plugins/builtin/options-scenario/charts.tsx +13 -4
  559. package/src/plugins/builtin/options-scenario/client.ts +114 -17
  560. package/src/plugins/builtin/options-scenario/collar.ts +141 -0
  561. package/src/plugins/builtin/options-scenario/csp.ts +1 -1
  562. package/src/plugins/builtin/options-scenario/freshness.ts +27 -0
  563. package/src/plugins/builtin/options-scenario/headless.ts +30 -12
  564. package/src/plugins/builtin/options-scenario/index.tsx +1 -1
  565. package/src/plugins/builtin/options-scenario/model.ts +55 -5
  566. package/src/plugins/builtin/options-scenario/pane.tsx +24 -5
  567. package/src/plugins/builtin/pe-band/index.tsx +1 -1
  568. package/src/plugins/builtin/pe-band/model.ts +1 -15
  569. package/src/plugins/builtin/perps/headless.ts +30 -13
  570. package/src/plugins/builtin/perps/model.ts +45 -3
  571. package/src/plugins/builtin/perps/pane.tsx +7 -7
  572. package/src/plugins/builtin/portfolio-list/cell-version.ts +10 -4
  573. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +128 -14
  574. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +144 -63
  575. package/src/plugins/builtin/portfolio-list/cli/render.ts +373 -48
  576. package/src/plugins/builtin/portfolio-list/cli/shared.ts +23 -9
  577. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +25 -35
  578. package/src/plugins/builtin/portfolio-list/grid.tsx +3 -1
  579. package/src/plugins/builtin/portfolio-list/headless.ts +161 -32
  580. package/src/plugins/builtin/portfolio-list/income.ts +296 -0
  581. package/src/plugins/builtin/portfolio-list/metrics.ts +2 -2
  582. package/src/plugins/builtin/portfolio-list/pane/futures-terms.ts +58 -0
  583. package/src/plugins/builtin/portfolio-list/pane/index.tsx +63 -14
  584. package/src/plugins/builtin/portfolio-list/pane/remove-ticker.ts +1 -1
  585. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +47 -28
  586. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +38 -8
  587. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +12 -4
  588. package/src/plugins/builtin/portfolio-list/settings.ts +22 -0
  589. package/src/plugins/builtin/portfolio-list/since-last-seen.ts +197 -0
  590. package/src/plugins/builtin/portfolio-list/summary/index.tsx +26 -4
  591. package/src/plugins/builtin/portfolio-list/summary/totals.ts +32 -4
  592. package/src/plugins/builtin/portfolio-list/table.tsx +39 -7
  593. package/src/plugins/builtin/power/prices-headless.ts +2 -1
  594. package/src/plugins/builtin/realized-vol/chart-model.ts +29 -5
  595. package/src/plugins/builtin/realized-vol/charts.tsx +14 -8
  596. package/src/plugins/builtin/realized-vol/evidence.ts +2 -0
  597. package/src/plugins/builtin/realized-vol/headless.ts +6 -4
  598. package/src/plugins/builtin/realized-vol/model.ts +5 -1
  599. package/src/plugins/builtin/realized-vol/pane.tsx +31 -11
  600. package/src/plugins/builtin/realized-vol/settings.ts +1 -1
  601. package/src/plugins/builtin/research/analyst-headless.ts +4 -0
  602. package/src/plugins/builtin/research/corporate-actions-pane.tsx +16 -5
  603. package/src/plugins/builtin/research/event-model.ts +63 -51
  604. package/src/plugins/builtin/research/headless-schema.ts +1 -0
  605. package/src/plugins/builtin/research/headless.ts +4 -1
  606. package/src/plugins/builtin/research/index.tsx +3 -0
  607. package/src/plugins/builtin/research/relative-valuation-columns.ts +27 -5
  608. package/src/plugins/builtin/research/relative-valuation-headless.ts +2 -0
  609. package/src/plugins/builtin/revenue-breakdown/index.tsx +1 -0
  610. package/src/plugins/builtin/reverse-dcf/headless.ts +28 -9
  611. package/src/plugins/builtin/reverse-dcf/index.tsx +5 -2
  612. package/src/plugins/builtin/reverse-dcf/model.ts +87 -6
  613. package/src/plugins/builtin/reverse-dcf/pane.tsx +30 -7
  614. package/src/plugins/builtin/risk-factors/headless.ts +7 -0
  615. package/src/plugins/builtin/risk-factors/index.tsx +1 -0
  616. package/src/plugins/builtin/scanner/feed.ts +5 -3
  617. package/src/plugins/builtin/scanner/headless.ts +9 -57
  618. package/src/plugins/builtin/scanner/index.ts +1 -2
  619. package/src/plugins/builtin/sec/forms.ts +2 -6
  620. package/src/plugins/builtin/sec/fund-facts-view.tsx +53 -0
  621. package/src/plugins/builtin/sec/fund-facts.ts +328 -0
  622. package/src/plugins/builtin/sec/headless.ts +140 -44
  623. package/src/plugins/builtin/sec/index.tsx +95 -30
  624. package/src/plugins/builtin/sec/model.ts +2 -44
  625. package/src/plugins/builtin/shared/earnings-report.ts +48 -1
  626. package/src/plugins/builtin/shared/headless-options.ts +10 -0
  627. package/src/plugins/builtin/shared/history-span.ts +55 -0
  628. package/src/plugins/builtin/shared/locked-rows.tsx +3 -1
  629. package/src/plugins/builtin/shared/move-rank.ts +108 -0
  630. package/src/plugins/builtin/shared/report-freshness.ts +45 -20
  631. package/src/plugins/builtin/shared/scanner-capture.ts +95 -0
  632. package/src/plugins/builtin/shared/series-detail-chart.tsx +5 -2
  633. package/src/plugins/builtin/shared/series-list-detail.tsx +7 -3
  634. package/src/plugins/builtin/shared/ticker-surface.ts +16 -2
  635. package/src/plugins/builtin/shared/treasury-cutoffs.ts +15 -0
  636. package/src/plugins/builtin/shared/use-quote-board.ts +13 -5
  637. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -0
  638. package/src/plugins/builtin/shared/volatility-indices.ts +32 -0
  639. package/src/plugins/builtin/short-interest/headless.ts +3 -0
  640. package/src/plugins/builtin/short-interest/watch-model.ts +2 -2
  641. package/src/plugins/builtin/social-mentions/client.ts +8 -1
  642. package/src/plugins/builtin/social-mentions/pane.tsx +8 -6
  643. package/src/plugins/builtin/supply-chain/client.ts +12 -3
  644. package/src/plugins/builtin/supply-chain/disclosure-quote.tsx +9 -5
  645. package/src/plugins/builtin/supply-chain/evidence.ts +3 -1
  646. package/src/plugins/builtin/supply-chain/flow-layout.ts +2 -1
  647. package/src/plugins/builtin/supply-chain/flow.tsx +23 -16
  648. package/src/plugins/builtin/supply-chain/graph-client.ts +8 -5
  649. package/src/plugins/builtin/supply-chain/graph-evidence.ts +1 -1
  650. package/src/plugins/builtin/supply-chain/graph-model.ts +10 -2
  651. package/src/plugins/builtin/supply-chain/graph-pane.tsx +9 -7
  652. package/src/plugins/builtin/supply-chain/graph.tsx +8 -6
  653. package/src/plugins/builtin/supply-chain/headless.ts +69 -27
  654. package/src/plugins/builtin/supply-chain/index.tsx +1 -1
  655. package/src/plugins/builtin/supply-chain/model.ts +76 -15
  656. package/src/plugins/builtin/supply-chain/pane.tsx +29 -15
  657. package/src/plugins/builtin/supply-chain/row-evidence.tsx +5 -4
  658. package/src/plugins/builtin/themes/headless.ts +15 -2
  659. package/src/plugins/builtin/themes/model.ts +2 -5
  660. package/src/plugins/builtin/thirteenf/api.ts +50 -2
  661. package/src/plugins/builtin/thirteenf/data.ts +250 -11
  662. package/src/plugins/builtin/thirteenf/headless.ts +311 -28
  663. package/src/plugins/builtin/thirteenf/index.tsx +4 -1
  664. package/src/plugins/builtin/thirteenf/model.ts +244 -19
  665. package/src/plugins/builtin/thirteenf/overlap-pane.tsx +133 -33
  666. package/src/plugins/builtin/thirteenf/overlap.ts +1 -1
  667. package/src/plugins/builtin/thirteenf/pane.tsx +24 -5
  668. package/src/plugins/builtin/thirteenf/report-notes.ts +78 -0
  669. package/src/plugins/builtin/thirteenf/types.ts +49 -0
  670. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +106 -24
  671. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +108 -0
  672. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +26 -8
  673. package/src/plugins/builtin/ticker-detail/financials/model.ts +2 -42
  674. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +1 -1
  675. package/src/plugins/builtin/ticker-detail/headless-schema.ts +4 -2
  676. package/src/plugins/builtin/ticker-detail/headless.ts +109 -23
  677. package/src/plugins/builtin/ticker-detail/overview/components.tsx +27 -3
  678. package/src/plugins/builtin/ticker-detail/overview/dividend.ts +60 -0
  679. package/src/plugins/builtin/ticker-detail/overview/model.ts +46 -9
  680. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +3 -0
  681. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +37 -4
  682. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +18 -19
  683. package/src/plugins/builtin/time-sales/client.ts +7 -4
  684. package/src/plugins/builtin/time-sales/headless.ts +71 -22
  685. package/src/plugins/builtin/time-sales/model.ts +12 -0
  686. package/src/plugins/builtin/time-sales/pane.tsx +31 -7
  687. package/src/plugins/builtin/time-sales/window.ts +128 -0
  688. package/src/plugins/builtin/trace-bonds/client.ts +351 -33
  689. package/src/plugins/builtin/trace-bonds/headless.ts +60 -22
  690. package/src/plugins/builtin/trace-bonds/index.tsx +4 -2
  691. package/src/plugins/builtin/trace-bonds/model.ts +27 -25
  692. package/src/plugins/builtin/trace-bonds/pane.tsx +63 -45
  693. package/src/plugins/builtin/treasury-auctions/cache.ts +61 -15
  694. package/src/plugins/builtin/treasury-auctions/client.ts +45 -10
  695. package/src/plugins/builtin/treasury-auctions/headless.ts +35 -13
  696. package/src/plugins/builtin/treasury-auctions/index.tsx +5 -2
  697. package/src/plugins/builtin/treasury-auctions/model.ts +20 -16
  698. package/src/plugins/builtin/treasury-auctions/pane.tsx +29 -12
  699. package/src/plugins/builtin/vol-surface/charts.tsx +2 -1
  700. package/src/plugins/builtin/vol-surface/headless.ts +3 -2
  701. package/src/plugins/builtin/vol-surface/pane.tsx +2 -1
  702. package/src/plugins/builtin/vol-surface/stored.ts +4 -7
  703. package/src/plugins/builtin/volatility/chart-model.ts +16 -15
  704. package/src/plugins/builtin/volatility/charts.tsx +5 -5
  705. package/src/plugins/builtin/volatility/client.ts +73 -2
  706. package/src/plugins/builtin/volatility/evidence.ts +13 -14
  707. package/src/plugins/builtin/volatility/headless.ts +13 -7
  708. package/src/plugins/builtin/volatility/index.tsx +1 -1
  709. package/src/plugins/builtin/volatility/model.ts +104 -38
  710. package/src/plugins/builtin/volatility/pane.tsx +42 -24
  711. package/src/plugins/builtin/volatility/series.ts +22 -13
  712. package/src/plugins/builtin/world-venue-map/geo-series.ts +9 -0
  713. package/src/plugins/builtin/world-venue-map/headless.ts +25 -8
  714. package/src/plugins/builtin/world-venue-map/index.ts +16 -2
  715. package/src/plugins/builtin/world-venue-map/map.tsx +13 -17
  716. package/src/plugins/builtin/yield-curve/curves.ts +29 -5
  717. package/src/plugins/builtin/yield-curve/headless.ts +41 -8
  718. package/src/plugins/builtin/yield-curve/history.ts +5 -5
  719. package/src/plugins/builtin/yield-curve/index.tsx +30 -13
  720. package/src/plugins/compat.ts +3 -1
  721. package/src/plugins/dependencies.ts +8 -2
  722. package/src/plugins/host-link.ts +12 -5
  723. package/src/plugins/installer.ts +16 -7
  724. package/src/plugins/loader.ts +9 -2
  725. package/src/plugins/marketplace/activation.ts +10 -4
  726. package/src/plugins/registry/host-actions.ts +3 -0
  727. package/src/plugins/registry/index.ts +3 -1
  728. package/src/{plugins/builtin/portfolio-list → portfolio}/allocation.ts +82 -15
  729. package/src/{plugins/builtin/portfolio-list → portfolio}/column-values.ts +143 -55
  730. package/src/portfolio/futures-positions.ts +213 -0
  731. package/src/portfolio/futures-terms.ts +75 -0
  732. package/src/portfolio/manual-lots.ts +78 -0
  733. package/src/{plugins/builtin/portfolio-list → portfolio}/mutations.ts +59 -15
  734. package/src/portfolio/position-metrics.ts +44 -10
  735. package/src/portfolio/valuation-basis.ts +34 -24
  736. package/src/public/__snapshots__/public-api.test.ts.snap +6 -0
  737. package/src/public/time-series.ts +2 -1
  738. package/src/remote/confirm-change.tsx +2 -1
  739. package/src/remote/controller.ts +27 -7
  740. package/src/remote/schema.ts +25 -9
  741. package/src/remote/server.ts +1 -1
  742. package/src/remote/watchlist.ts +9 -1
  743. package/src/renderers/cloudflare/http-proxy.ts +21 -13
  744. package/src/renderers/dom/data-table/row.tsx +1 -1
  745. package/src/renderers/dom/desktop/audio-player.tsx +312 -0
  746. package/src/renderers/dom/desktop/control-styles.ts +17 -82
  747. package/src/renderers/dom/desktop/controls.tsx +39 -63
  748. package/src/renderers/dom/desktop/dialog-actions.tsx +13 -53
  749. package/src/renderers/dom/desktop/icons.tsx +8 -0
  750. package/src/renderers/dom/desktop/list-view.tsx +6 -6
  751. package/src/renderers/dom/desktop/popover.tsx +0 -3
  752. package/src/renderers/dom/desktop/query-bar.tsx +7 -5
  753. package/src/renderers/dom/desktop/select-field.tsx +9 -8
  754. package/src/renderers/dom/desktop/stack-header.ts +3 -0
  755. package/src/renderers/dom/dom-ui-host.tsx +5 -2
  756. package/src/renderers/dom/host/chart-surface.tsx +3 -3
  757. package/src/renderers/dom/host/size-observer.ts +33 -4
  758. package/src/renderers/dom/host/surface-3d.tsx +3 -2
  759. package/src/renderers/dom/host/surface-fit.ts +4 -1
  760. package/src/renderers/dom/host/tabs.tsx +22 -132
  761. package/src/renderers/dom/styles.css +358 -160
  762. package/src/renderers/dom/windowed-list.tsx +201 -0
  763. package/src/renderers/dom/windowed-rows.ts +65 -0
  764. package/src/renderers/electrobun/bun/core-capabilities.ts +1 -1
  765. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +2 -9
  766. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -1
  767. package/src/renderers/electrobun/bun/desktop/http-stream.ts +21 -6
  768. package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
  769. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +43 -1
  770. package/src/renderers/electrobun/bun/desktop/update.ts +21 -6
  771. package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +5 -1
  772. package/src/renderers/electrobun/shared/protocol.ts +4 -2
  773. package/src/renderers/electrobun/shared/rpc-codec.ts +7 -0
  774. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +21 -17
  775. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  776. package/src/renderers/electrobun/view/desktop/window/bridge.ts +6 -8
  777. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +18 -0
  778. package/src/renderers/electrobun/view/http-fetch.ts +12 -1
  779. package/src/series/capability.ts +1 -0
  780. package/src/series/files.ts +9 -3
  781. package/src/series/registry.ts +40 -14
  782. package/src/series/resolve.ts +121 -18
  783. package/src/series/standalone.ts +3 -2
  784. package/src/series/types.ts +55 -1
  785. package/src/series/validate.ts +39 -0
  786. package/src/shares/api.ts +26 -7
  787. package/src/shares/bug-report-dialog.tsx +2 -2
  788. package/src/shares/bug-report-flow.tsx +4 -7
  789. package/src/shares/capture-flow.ts +5 -4
  790. package/src/shares/capture-preview.tsx +2 -2
  791. package/src/shares/chat.ts +7 -27
  792. package/src/shares/flow.tsx +86 -40
  793. package/src/shares/location.ts +1 -3
  794. package/src/shares/pane-image.ts +11 -9
  795. package/src/shares/pane.ts +5 -2
  796. package/src/shares/payload.ts +1 -1
  797. package/src/shares/personal-pane.ts +3 -3
  798. package/src/shares/portable-layout.ts +9 -2
  799. package/src/shares/ready.ts +42 -0
  800. package/src/shares/test-harness.ts +62 -0
  801. package/src/sources/gloomberb-cloud/batched-lookups.ts +73 -0
  802. package/src/sources/gloomberb-cloud/index.ts +64 -12
  803. package/src/sources/gloomberb-cloud/normalizers.ts +31 -2
  804. package/src/sources/gloomberb-cloud/perpetuals.ts +20 -1
  805. package/src/sources/history-omitted.ts +34 -0
  806. package/src/sources/history-result.ts +3 -0
  807. package/src/sources/history-retention.ts +1 -1
  808. package/src/sources/listing-symbols.ts +8 -4
  809. package/src/sources/provider-errors.ts +43 -1
  810. package/src/sources/provider-router/batches.ts +3 -2
  811. package/src/sources/provider-router/cache.ts +2 -1
  812. package/src/sources/provider-router/cached-routes.ts +9 -3
  813. package/src/sources/provider-router/history.ts +9 -8
  814. package/src/sources/provider-router/index.ts +18 -3
  815. package/src/sources/provider-router/primary.ts +5 -4
  816. package/src/sources/provider-router/quote-route.ts +3 -1
  817. package/src/sources/provider-router/routing.ts +2 -1
  818. package/src/sources/provider-router/search.ts +47 -13
  819. package/src/sources/provider-router/streaming.ts +7 -4
  820. package/src/sources/sec-edgar.ts +1 -3
  821. package/src/state/app/context/index.tsx +9 -0
  822. package/src/state/app/tab-cursor.ts +222 -0
  823. package/src/state/hooks/quote-streaming.ts +3 -2
  824. package/src/state/hooks/session-snapshot.ts +3 -2
  825. package/src/state/persist-scheduler.ts +12 -4
  826. package/src/sync/controller.ts +22 -1
  827. package/src/sync/core-contributors.ts +264 -74
  828. package/src/team/collections-sync.ts +14 -4
  829. package/src/team/collections.ts +40 -11
  830. package/src/team/store.ts +5 -4
  831. package/src/telemetry/attention-counts.ts +8 -2
  832. package/src/telemetry/crash-reports-dom.ts +3 -0
  833. package/src/telemetry/crash-reports-node.ts +7 -4
  834. package/src/telemetry/crash-reports.ts +11 -11
  835. package/src/telemetry/usage-counts.ts +16 -12
  836. package/src/test-support/config-store.ts +31 -0
  837. package/src/test-support/moved-symbols.ts +64 -0
  838. package/src/theme/colors.ts +32 -0
  839. package/src/theme/font-scale.ts +2 -0
  840. package/src/theme/ui-tokens.ts +71 -0
  841. package/src/tickers/batched-lookups.ts +186 -0
  842. package/src/tickers/company-name-listing.ts +97 -0
  843. package/src/tickers/company-name.ts +13 -0
  844. package/src/tickers/instrument-coverage.ts +112 -0
  845. package/src/tickers/listing-fate.ts +282 -0
  846. package/src/tickers/listing-venues.ts +24 -5
  847. package/src/tickers/open-target.ts +13 -5
  848. package/src/tickers/search/index.ts +156 -37
  849. package/src/tickers/search/ranking.ts +68 -3
  850. package/src/tickers/search/types.ts +3 -0
  851. package/src/tickers/search/upsert.ts +22 -7
  852. package/src/tickers/terminal-codes.ts +79 -0
  853. package/src/tickers/ticker-changes.ts +100 -12
  854. package/src/tickers/us-listing.ts +2 -1
  855. package/src/time-series/bar-spacing.ts +19 -0
  856. package/src/time-series/chart-data.ts +116 -21
  857. package/src/time-series/field-catalog.ts +5 -2
  858. package/src/time-series/forward-valuation.ts +10 -7
  859. package/src/time-series/fundamentals.ts +103 -17
  860. package/src/time-series/hooks.ts +2 -0
  861. package/src/time-series/ice-credit.ts +17 -2
  862. package/src/time-series/live-bars.ts +24 -9
  863. package/src/time-series/live-quotes.ts +2 -3
  864. package/src/time-series/parsed-history-cache.ts +2 -0
  865. package/src/time-series/price-comparison.ts +6 -1
  866. package/src/time-series/price-units.ts +69 -0
  867. package/src/time-series/resolve.ts +114 -14
  868. package/src/time-series/session-bar.ts +138 -0
  869. package/src/time-series/spec.ts +14 -4
  870. package/src/time-series/studies.ts +214 -15
  871. package/src/time-series/transforms.ts +2 -0
  872. package/src/time-series/types.ts +33 -1
  873. package/src/time-series/use-chart-resolution.ts +2 -1
  874. package/src/time-series/valuation-price.ts +13 -0
  875. package/src/types/config.ts +17 -1
  876. package/src/types/data-provider.ts +20 -0
  877. package/src/types/financials.ts +2 -0
  878. package/src/types/headless.ts +169 -1
  879. package/src/types/instrument.ts +6 -0
  880. package/src/types/plugin.ts +39 -9
  881. package/src/types/price-history.ts +5 -0
  882. package/src/types/ticker-changes.ts +19 -0
  883. package/src/types/ticker.ts +10 -2
  884. package/src/ui/context-menu.tsx +2 -0
  885. package/src/ui/host.tsx +45 -4
  886. package/src/ui/measured-cells.ts +13 -7
  887. package/src/ui/qr.ts +7 -5
  888. package/src/updater/index.ts +8 -6
  889. package/src/utils/asset-category.ts +20 -0
  890. package/src/utils/calendar-date.ts +86 -27
  891. package/src/utils/currency-units.ts +17 -0
  892. package/src/utils/debug-log.ts +1 -1
  893. package/src/utils/decimal-comma.ts +83 -3
  894. package/src/utils/dividend-cash.ts +48 -0
  895. package/src/utils/dom-screenshot-rasters.ts +3 -1
  896. package/src/utils/dom-screenshot.ts +14 -10
  897. package/src/utils/exchange-rate-snapshot.ts +9 -4
  898. package/src/utils/external-url.ts +1 -0
  899. package/src/utils/fiscal-period.ts +47 -0
  900. package/src/utils/format.ts +5 -2
  901. package/src/utils/forward-dividend.ts +160 -11
  902. package/src/utils/fundamentals.ts +7 -2
  903. package/src/utils/futures-generic.ts +34 -8
  904. package/src/utils/http-proxy-response.ts +67 -9
  905. package/src/utils/local-utc-offset.ts +2 -0
  906. package/src/utils/log-failure.ts +31 -0
  907. package/src/utils/option-expiry.ts +12 -12
  908. package/src/utils/plugin-proxy-hosts.json +1 -5
  909. package/src/utils/price-history-integrity.ts +56 -0
  910. package/src/utils/price-history.ts +13 -1
  911. package/src/utils/sec-filings.ts +245 -0
  912. package/src/utils/selection-clipboard.ts +5 -2
  913. package/src/utils/throttled-fetch.ts +1 -0
  914. package/src/{plugins/builtin/dividend-yield/trailing-cash.ts → utils/trailing-dividend.ts} +55 -8
  915. package/src/utils/typo-distance.ts +22 -0
  916. package/src/utils/url.ts +1 -0
  917. package/src/utils/utc-time.ts +11 -0
  918. package/src/plugins/builtin/chat/share/targets.ts +0 -27
  919. package/src/plugins/builtin/shared/zip-text.ts +0 -46
  920. package/src/renderers/dom/host/top-surface.ts +0 -119
  921. package/src/shares/dialog.tsx +0 -221
  922. package/src/shares/live.ts +0 -19
@@ -1,3 +1,4 @@
1
+ import { logFailure } from "../../utils/log-failure";
1
2
  import type { PriceHistoryResult } from "../../types/price-history";
2
3
  import type { ResourceStore } from "../../data/resource-store";
3
4
  import type { ConnectionHealthRegistry } from "../../core/connection-health";
@@ -174,8 +175,8 @@ export class AssetDataRouter implements DataProvider {
174
175
  if (!provider.canProvide || await provider.canProvide(ticker, exchange, context)) {
175
176
  return true;
176
177
  }
177
- } catch {
178
- // continue through provider chain
178
+ } catch (error) {
179
+ logFailure("sources.provider-router.index", "Checking provider availability failed")(error);
179
180
  }
180
181
  }
181
182
  return false;
@@ -252,7 +253,9 @@ export class AssetDataRouter implements DataProvider {
252
253
  known = mergeQuoteMetadata(known, metadata);
253
254
  if (known?.currency && known.instrumentType) return known;
254
255
  }
255
- } catch { /* Optional listing metadata must not prevent historical research. */ }
256
+ } catch (error) {
257
+ logFailure("sources.provider-router.index", "Loading listing metadata failed")(error);
258
+ }
256
259
  }
257
260
  return known ?? null;
258
261
  }
@@ -289,6 +292,18 @@ export class AssetDataRouter implements DataProvider {
289
292
  return (await this.getCachedQuery("getCorporateActions", [ticker, exchange, context]).load({ force: context?.cacheMode === "refresh", background: this.revalidateInBackground })).value;
290
293
  }
291
294
 
295
+ searchBatch(queries: string[], options?: { limit?: number; signal?: AbortSignal }): Promise<Map<string, InstrumentSearchResult[]> | null> {
296
+ return this.searchRoutes.searchBatch(queries, options);
297
+ }
298
+
299
+ /** The first source that answers a batch of symbol changes; null when none can or it fails. */
300
+ async getTickerChangesBatch(symbols: string[], options?: { signal?: AbortSignal }): Promise<Map<string, TickerChanges | null> | null> {
301
+ const provider = this.providersInPriorityOrder().find((candidate) => candidate.getTickerChangesBatch);
302
+ if (!provider) return null;
303
+ return await provider.getTickerChangesBatch!(symbols, options)
304
+ .catch(logFailure("sources.provider-router.index", "Batched ticker changes failed", null));
305
+ }
306
+
292
307
  /** The first source that keeps symbol changes answers; one that fails is passed over. */
293
308
  async getTickerChanges(symbol: string, options?: { signal?: AbortSignal }): Promise<TickerChanges | null> {
294
309
  for (const provider of this.providersInPriorityOrder()) {
@@ -1,3 +1,4 @@
1
+ import { logFailure } from "../../utils/log-failure";
1
2
  import { selectCachedResource } from "./cache";
2
3
  import { financialHistoryVariants, hasReusableExtendedHistory } from "./statement-history";
3
4
  import type { MarketDataRequestContext } from "../../types/data-provider";
@@ -57,8 +58,8 @@ export class ProviderRouterPrimaryRoutes {
57
58
  this.options.resolveBrokerPolicy("financials", candidate.broker),
58
59
  );
59
60
  return { sourceKey: this.options.brokerSourceKey(candidate), value: result };
60
- } catch {
61
- // continue
61
+ } catch (error) {
62
+ logFailure("sources.provider-router.primary", "Loading broker financials failed")(error);
62
63
  }
63
64
  }
64
65
  return null;
@@ -179,8 +180,8 @@ export class ProviderRouterPrimaryRoutes {
179
180
  this.options.resolveBrokerPolicy("brokerQuote", candidate.broker),
180
181
  );
181
182
  return { sourceKey: this.options.brokerSourceKey(candidate), value: result };
182
- } catch {
183
- // continue
183
+ } catch (error) {
184
+ logFailure("sources.provider-router.primary", "Loading a broker quote failed")(error);
184
185
  }
185
186
  }
186
187
  return null;
@@ -1,3 +1,4 @@
1
+ import { logFailure } from "../../utils/log-failure";
1
2
  import type { QuoteSubscriptionTarget } from "../../types/data-provider";
2
3
  import { canonicalExchange, US_LISTING_EXCHANGES } from "../../utils/exchanges";
3
4
  import type { BrokerCandidate } from "./brokers";
@@ -54,7 +55,8 @@ export function resolveBrokerQuoteStreamState(
54
55
  const status = broker.getStatus?.(instance);
55
56
  if (status && status.state !== "connected") return "offline";
56
57
  return status?.quoteData === "delayed" || observedDelayed ? "delayed" : "live";
57
- } catch {
58
+ } catch (error) {
59
+ logFailure("sources.provider-router.quote-route", "Reading broker quote stream status failed")(error);
58
60
  return "unsupported";
59
61
  }
60
62
  }
@@ -1,3 +1,4 @@
1
+ import { logFailure } from "../../utils/log-failure";
1
2
  import type { MarketDataRequestContext } from "../../types/data-provider";
2
3
  import type { ProviderRouterCoreDeps } from "./route-types";
3
4
  import { buildVariantKey } from "./cache";
@@ -35,7 +36,7 @@ export function scheduleRouterRevalidation(
35
36
  ): void {
36
37
  if (inFlight.has(key)) return;
37
38
  const promise = task()
38
- .catch(() => {})
39
+ .catch(logFailure("sources.provider-router.routing", "Refreshing a cached provider result failed"))
39
40
  .finally(() => {
40
41
  inFlight.delete(key);
41
42
  });
@@ -1,9 +1,10 @@
1
+ import { logFailure } from "../../utils/log-failure";
1
2
  import type { DataProvider, SearchRequestContext } from "../../types/data-provider";
2
3
  import type { InstrumentSearchResult } from "../../types/instrument";
3
4
  import type { BrokerCandidate } from "./brokers";
4
- import { shouldLogProviderError } from "../provider-errors";
5
+ import { isProviderBusy, ProviderBusyError, SEARCH_BUSY_MESSAGE, shouldLogProviderError } from "../provider-errors";
5
6
  import { searchInstrumentKey } from "../../tickers/search/identity";
6
- import { settleWithin } from "../../utils/async-deadline";
7
+ import { OperationTimeoutError, settleWithin, withDeadline } from "../../utils/async-deadline";
7
8
 
8
9
  const SEARCH_CACHE_TTL_MS = 30_000;
9
10
  const SEARCH_CACHE_MAX_ENTRIES = 100;
@@ -87,6 +88,25 @@ export class ProviderRouterSearchRoutes {
87
88
 
88
89
  constructor(private readonly deps: ProviderRouterSearchDeps) {}
89
90
 
91
+ /**
92
+ * Several searches answered by the preferred provider in a few requests,
93
+ * each merged as `search` merges that source's rows. Null while a broker can
94
+ * search: its rows join every search's answer, so those go one at a time.
95
+ */
96
+ async searchBatch(queries: string[], options?: { limit?: number; signal?: AbortSignal }): Promise<Map<string, InstrumentSearchResult[]> | null> {
97
+ if (this.deps.getBrokerCandidates().some((candidate) => candidate.broker.searchInstruments)) return null;
98
+ const [preferred] = this.deps.providersInPriorityOrder();
99
+ if (!preferred?.searchBatch) return null;
100
+ const answers = await preferred.searchBatch(queries, options)
101
+ .catch(logFailure("sources.provider-router.search", "Batched search failed", null));
102
+ if (!answers) return null;
103
+ return new Map([...answers].map(([query, items]) => {
104
+ const results: InstrumentSearchResult[] = [];
105
+ mergeSearchResults(results, new Map(), items);
106
+ return [query, results] as const;
107
+ }));
108
+ }
109
+
90
110
  async search(query: string, context?: SearchRequestContext): Promise<InstrumentSearchResult[]> {
91
111
  const cacheKey = buildSearchCacheKey(query, context);
92
112
  const cached = this.searchCache.get(cacheKey);
@@ -118,6 +138,10 @@ export class ProviderRouterSearchRoutes {
118
138
  * Ordering still matters, it just no longer costs latency: `mergeSearchResults`
119
139
  * keeps the richest entry per symbol, so a broker arriving after the cloud
120
140
  * still upgrades the row, and `onPartial` hands that upgrade to the caller.
141
+ *
142
+ * A search nothing answered because a provider was busy (rate limited,
143
+ * overloaded, out of time) rejects with a `ProviderBusyError` instead of
144
+ * reading as an empty one, and is not cached, so asking again asks again.
121
145
  */
122
146
  private fetchSearchResults(
123
147
  query: string,
@@ -141,10 +165,13 @@ export class ProviderRouterSearchRoutes {
141
165
  };
142
166
 
143
167
  let resolveFirst!: (value: InstrumentSearchResult[]) => void;
144
- const first = new Promise<InstrumentSearchResult[]>((resolve) => {
168
+ let rejectFirst!: (error: unknown) => void;
169
+ const first = new Promise<InstrumentSearchResult[]>((resolve, reject) => {
145
170
  resolveFirst = resolve;
171
+ rejectFirst = reject;
146
172
  });
147
173
  let answered = false;
174
+ let busy = false;
148
175
 
149
176
  const record = (items: InstrumentSearchResult[] | null) => {
150
177
  if (!items?.length) return;
@@ -167,16 +194,20 @@ export class ProviderRouterSearchRoutes {
167
194
  timeoutMs,
168
195
  );
169
196
  record(items && annotateBrokerSearchResults(items, candidate));
170
- } catch {
171
- // A broker that cannot answer must not hold up the ones that can.
197
+ } catch (error) {
198
+ logFailure("sources.provider-router.search", "Searching broker instruments failed")(error);
172
199
  }
173
200
  })();
174
201
 
175
202
  const searchProvider = (provider: DataProvider) => (async () => {
176
203
  try {
177
- record(await settleWithin(provider.search(query, context), timeoutMs));
204
+ record(await withDeadline(provider.search(query, context), timeoutMs, `${provider.id} search timed out`));
178
205
  } catch (error) {
179
- if (shouldLogProviderError(error)) {
206
+ const timedOut = error instanceof OperationTimeoutError;
207
+ // A keystroke gives up on a slow source by design and asks again on the next one; only a full wait is busy.
208
+ if (isProviderBusy(error) || (timedOut && !context?.interactive)) {
209
+ busy = true;
210
+ } else if (!timedOut && shouldLogProviderError(error)) {
180
211
  this.deps.logProviderError(`${provider.id} failed: ${error}`);
181
212
  }
182
213
  }
@@ -198,13 +229,16 @@ export class ProviderRouterSearchRoutes {
198
229
  await Promise.allSettled(fallbacks.map(searchProvider));
199
230
  }
200
231
  })().then(() => {
201
- if (!answered) {
202
- answered = true;
203
- // Nothing matched anywhere, so hold the empty answer briefly rather
204
- // than asking every source again on the next keystroke.
205
- cacheResults(Math.min(SEARCH_CACHE_TTL_MS, 5_000));
206
- resolveFirst([]);
232
+ if (answered) return;
233
+ answered = true;
234
+ if (busy) {
235
+ rejectFirst(new ProviderBusyError(SEARCH_BUSY_MESSAGE));
236
+ return;
207
237
  }
238
+ // Nothing matched anywhere, so hold the empty answer briefly rather
239
+ // than asking every source again on the next keystroke.
240
+ cacheResults(Math.min(SEARCH_CACHE_TTL_MS, 5_000));
241
+ resolveFirst([]);
208
242
  });
209
243
 
210
244
  return { first, settled };
@@ -1,3 +1,4 @@
1
+ import { logFailure } from "../../utils/log-failure";
1
2
  import type { DataProvider, MarketDataRequestContext, QuoteSubscriptionTarget } from "../../types/data-provider";
2
3
  import type { Quote } from "../../types/financials";
3
4
  import type { BrokerCandidate } from "./brokers";
@@ -51,7 +52,8 @@ function isBrokerConnected(candidate: BrokerCandidate): boolean {
51
52
  try {
52
53
  const status = candidate.broker.getStatus?.(candidate.instance);
53
54
  return !status || status.state === "connected";
54
- } catch {
55
+ } catch (error) {
56
+ logFailure("sources.provider-router.streaming", "Reading broker connection status failed")(error);
55
57
  return false;
56
58
  }
57
59
  }
@@ -62,7 +64,8 @@ function canWakeBroker(candidate: BrokerCandidate): boolean {
62
64
  try {
63
65
  const state = candidate.broker.getStatus?.(candidate.instance)?.state;
64
66
  return state === "disconnected" || state === "error";
65
- } catch {
67
+ } catch (error) {
68
+ logFailure("sources.provider-router.streaming", "Reading broker connection status failed")(error);
66
69
  return false;
67
70
  }
68
71
  }
@@ -195,8 +198,8 @@ export class ProviderRouterStreamingRoutes {
195
198
  scheduleApply();
196
199
  });
197
200
  if (unsubscribe) watchers.push(unsubscribe);
198
- } catch {
199
- // A broker that cannot report status keeps the route it has now.
201
+ } catch (error) {
202
+ logFailure("sources.provider-router.streaming", "Subscribing to broker connection status failed")(error);
200
203
  }
201
204
  }
202
205
  this.delayedSessionListeners.add(scheduleApply);
@@ -171,9 +171,7 @@ function resolveSecArchiveUrl(href: string, filingUrl: string): string | null {
171
171
  return new URL(ixviewerDocument, "https://www.sec.gov").toString();
172
172
  }
173
173
  return url.toString();
174
- } catch {
175
- return null;
176
- }
174
+ } catch { /* Intentional ignore: Malformed document hrefs are not usable archive links. */ return null; }
177
175
  }
178
176
 
179
177
  function isHtmlResponse(body: string): boolean {
@@ -458,6 +458,7 @@ export function AppProvider({
458
458
  const effectiveThemeId = getEffectiveThemeId(state);
459
459
  const previousRecentTickers = useRef(state.recentTickers);
460
460
  const previousRecentCommands = useRef(state.config.recentCommands);
461
+ const previousCommandBarOpens = useRef(state.config.commandBarOpens);
461
462
  const stateRef = useRef(state);
462
463
  const listenersRef = useRef(new Set<() => void>());
463
464
  const storeRef = useRef<AppContextStoreValue | null>(null);
@@ -538,6 +539,14 @@ export function AppProvider({
538
539
  scheduleConfigSave(() => ({ ...stateRef.current.config, recentTickers: stateRef.current.recentTickers }));
539
540
  }, [state.config.recentCommands]);
540
541
 
542
+ // Opening the empty bar changes only config.commandBarOpens, until it stops
543
+ // counting; nothing else saves it.
544
+ useEffect(() => {
545
+ if (previousCommandBarOpens.current === state.config.commandBarOpens) return;
546
+ previousCommandBarOpens.current = state.config.commandBarOpens;
547
+ scheduleConfigSave(() => ({ ...stateRef.current.config, recentTickers: stateRef.current.recentTickers }));
548
+ }, [state.config.commandBarOpens]);
549
+
541
550
  useEffect(() => {
542
551
  if (!desktopBridge) return;
543
552
  return desktopBridge.subscribeState((snapshot) => {
@@ -0,0 +1,222 @@
1
+ import { useCallback, useContext, useEffect, useMemo, useSyncExternalStore } from "react";
2
+ import type { AppState } from "../../core/state/app/state";
3
+ import { findPaneInstance, type SavedLayout } from "../../types/config";
4
+ import { AppContext, useOptionalAppSelector, useOptionalPaneInstanceId, type AppContextStoreValue } from "./context";
5
+
6
+ /**
7
+ * The time the pointer or keyboard cursor is at on one chart of a layout tab,
8
+ * which the tab's other charts show at the same moment: the last instant the
9
+ * cursor covers, so a chart reads its data as of then. It is held per tab, in
10
+ * memory only: a cursor moves on every pointer event, and the app store would
11
+ * re-run every pane's selectors on each one.
12
+ */
13
+ interface TabCursor {
14
+ time: number;
15
+ /** The chart the cursor is on; it never follows its own time back. */
16
+ sourceId: string;
17
+ }
18
+
19
+ const cursors = new Map<string, TabCursor>();
20
+ /**
21
+ * A pinned cursor belongs to no chart: every chart in the tab follows it, the
22
+ * one it was pinned from too, and no pointer leaving a chart takes it away.
23
+ */
24
+ const PINNED = "\u0000pinned";
25
+ /** How many charts in each tab are mounted to show its pin; see `useTabCursorLink`. */
26
+ const pinViewers = new Map<string, number>();
27
+ const listeners = new Set<() => void>();
28
+
29
+ /** A time a Date can hold. A pin is never NaN, infinite or past the Date range, whatever asks for it. */
30
+ function isMoment(time: number): boolean {
31
+ return Number.isFinite(time) && Math.abs(time) <= 8.64e15;
32
+ }
33
+
34
+ function setTabCursorTime(tabKey: string, sourceId: string | null, time: number | null): void {
35
+ const current = cursors.get(tabKey);
36
+ if (time === null) {
37
+ // Only the chart the cursor is on can take it away: a chart clearing a
38
+ // cursor it no longer holds must not clear another chart's. A null source
39
+ // clears whichever chart holds it.
40
+ if (!current || (sourceId !== null && current.sourceId !== sourceId)) return;
41
+ cursors.delete(tabKey);
42
+ } else {
43
+ if (sourceId === null || (current?.sourceId === sourceId && current.time === time)) return;
44
+ cursors.set(tabKey, { time, sourceId });
45
+ }
46
+ for (const listener of listeners) listener();
47
+ }
48
+
49
+ function subscribe(listener: () => void): () => void {
50
+ listeners.add(listener);
51
+ return () => listeners.delete(listener);
52
+ }
53
+
54
+ /** A chart's handle on the cursor its layout tab shares. */
55
+ export interface TabCursorLink {
56
+ /** Calls `listener` whenever a tab's cursor moves. */
57
+ subscribe(listener: () => void): () => void;
58
+ /** Where another chart's cursor is in this tab: null when none is, or the cursor is this chart's own. */
59
+ time(): number | null;
60
+ /** Whether this chart's cursor is the tab's. */
61
+ held(): boolean;
62
+ /** Reports this chart's cursor, or null when it leaves. */
63
+ publish(time: number | null): void;
64
+ /** Clears the tab's cursor, whichever chart holds it, a pinned one too. */
65
+ clear(): void;
66
+ /** Whether the tab's cursor is pinned. */
67
+ pinned?(): boolean;
68
+ /** Pins the tab's cursor at `time`, which no chart's pointer moves, or unpins it with null. */
69
+ pin?(time: number | null): void;
70
+ }
71
+
72
+ /** A layout tab is named by its id; older saved tabs have none, and go by position. */
73
+ const tabKeyAt = (layouts: readonly SavedLayout[], index: number): string => layouts[index]?.id ?? `index:${index}`;
74
+ const selectTabKey = (state: AppState): string => tabKeyAt(state.config.layouts, state.config.activeLayoutIndex);
75
+
76
+ /**
77
+ * Moves the cursors of a store's tabs with their tabs when the tab list
78
+ * changes. A tab with an id keeps its key while it is open. One without is
79
+ * keyed by its place, so when tabs open, close or move its cursor follows its
80
+ * name to the new place if no other tab shares that name, and goes otherwise.
81
+ * So a closed tab's pin goes with it, and a tab that takes its place never
82
+ * inherits it. Edits that leave every tab where it was keep every key, one
83
+ * tab renamed included.
84
+ */
85
+ function retargetTabCursors(before: readonly SavedLayout[], after: readonly SavedLayout[]): void {
86
+ const inPlace = before.length === after.length && before.every((tab, index) => tab.id === after[index]!.id);
87
+ if (inPlace && before.filter((tab, index) => tab.name !== after[index]!.name).length <= 1) return;
88
+ const afterKeys = new Set(after.map((_, index) => tabKeyAt(after, index)));
89
+ const named = (tabs: readonly SavedLayout[], name: string) => tabs.filter((tab) => tab.id === undefined && tab.name === name).length;
90
+ const moved = new Map<string, TabCursor>();
91
+ let changed = false;
92
+ before.forEach((tab, index) => {
93
+ const key = tabKeyAt(before, index);
94
+ const cursor = cursors.get(key);
95
+ if (!cursor) return;
96
+ cursors.delete(key);
97
+ let target: string | null = null;
98
+ if (tab.id !== undefined) target = afterKeys.has(key) ? key : null;
99
+ else if (named(before, tab.name) === 1 && named(after, tab.name) === 1) {
100
+ target = `index:${after.findIndex((next) => next.id === undefined && next.name === tab.name)}`;
101
+ }
102
+ if (target !== key) changed = true;
103
+ if (target !== null) moved.set(target, cursor);
104
+ });
105
+ for (const [key, cursor] of moved) cursors.set(key, cursor);
106
+ if (changed) for (const listener of listeners) listener();
107
+ }
108
+
109
+ const watchedStores = new WeakSet<AppContextStoreValue>();
110
+ /** Follows a store's tab list once, from the first chart that links to it. */
111
+ function watchTabs(store: AppContextStoreValue): void {
112
+ if (watchedStores.has(store)) return;
113
+ watchedStores.add(store);
114
+ let tabs = store.getState().config.layouts;
115
+ store.subscribe(() => {
116
+ const next = store.getState().config.layouts;
117
+ if (next === tabs) return;
118
+ const before = tabs;
119
+ tabs = next;
120
+ retargetTabCursors(before, next);
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Shares a chart's cursor time with the other charts in its layout tab.
126
+ * `sourceId` names the chart, unique in the tab: two charts in one pane each
127
+ * have their own, so either follows the other. Reading the handle does not
128
+ * re-render anything when the cursor moves: what draws the cursor
129
+ * subscribes, so a pointer move on one chart re-renders the other charts and
130
+ * nothing around them. A null `sourceId`, or no app around it (a test, a
131
+ * screenshot), shares nothing. `viewer` says whether the chart shows the pin
132
+ * and can lift it now; only such charts keep a pin from going (see below).
133
+ */
134
+ export function useTabCursorLink(sourceId: string | null, { viewer = true }: { viewer?: boolean } = {}): TabCursorLink | undefined {
135
+ const tabKey = useOptionalAppSelector<string | null>(selectTabKey, null);
136
+ const app = useContext(AppContext);
137
+ const paneId = useOptionalPaneInstanceId();
138
+ const link = useMemo<TabCursorLink | undefined>(() => tabKey === null || sourceId === null ? undefined : {
139
+ subscribe,
140
+ time: () => {
141
+ const cursor = cursors.get(tabKey);
142
+ return cursor && cursor.sourceId !== sourceId ? cursor.time : null;
143
+ },
144
+ held: () => cursors.get(tabKey)?.sourceId === sourceId,
145
+ publish: (time) => {
146
+ // A pinned cursor stays until it is unpinned: hovering a chart, or leaving it, does not move it.
147
+ if (cursors.get(tabKey)?.sourceId === PINNED) return;
148
+ setTabCursorTime(tabKey, sourceId, time !== null && Number.isFinite(time) ? time : null);
149
+ },
150
+ clear: () => setTabCursorTime(tabKey, null, null),
151
+ pinned: () => cursors.get(tabKey)?.sourceId === PINNED,
152
+ // Null unpins; a time no Date can hold changes nothing.
153
+ pin: (time) => {
154
+ if (time === null || isMoment(time)) setTabCursorTime(tabKey, PINNED, time);
155
+ },
156
+ }, [sourceId, tabKey]);
157
+ useEffect(() => {
158
+ if (app && "subscribe" in app) watchTabs(app);
159
+ }, [app]);
160
+ useEffect(() => {
161
+ if (!link) return;
162
+ // A chart closed or switched away from under the cursor takes its cursor with it.
163
+ return () => link.publish(null);
164
+ }, [link]);
165
+ useEffect(() => {
166
+ if (!link || tabKey === null || !viewer) return;
167
+ pinViewers.set(tabKey, (pinViewers.get(tabKey) ?? 0) + 1);
168
+ return () => {
169
+ const left = (pinViewers.get(tabKey) ?? 1) - 1;
170
+ if (left > 0) {
171
+ pinViewers.set(tabKey, left);
172
+ return;
173
+ }
174
+ pinViewers.delete(tabKey);
175
+ // The pin is the tab's, so it stays when the chart it was pinned on
176
+ // closes and others remain, and through a switch to another tab. When
177
+ // the last chart showing it closes, nothing in the tab could lift it,
178
+ // so it goes too: a chart that is not interactive (an overview's
179
+ // sparkline) shows no pin and does not count. Read once the commit
180
+ // settles, from the app's current state: a chart replaced in place, or
181
+ // one in a pane that is still open (reloading, under a dialog), keeps it.
182
+ // A closed tab's pin goes with the tab (`retargetTabCursors`).
183
+ queueMicrotask(() => {
184
+ if (pinViewers.has(tabKey) || !app) return;
185
+ const state = "getState" in app ? app.getState() : app.state;
186
+ if (selectTabKey(state) !== tabKey) return;
187
+ if (paneId !== null && findPaneInstance(state.config.layout, paneId)) return;
188
+ setTabCursorTime(tabKey, PINNED, null);
189
+ });
190
+ };
191
+ }, [app, link, paneId, tabKey, viewer]);
192
+ return link;
193
+ }
194
+
195
+ /**
196
+ * The moment the layout tab's crosshair is pinned at, for a pane that is not a
197
+ * chart (news, the tape): null while nothing is pinned. It follows the pin, not
198
+ * a pointer passing over a chart, so a list re-renders when the pin moves and
199
+ * never on a pointer move.
200
+ */
201
+ export function usePinnedTabTime(): number | null {
202
+ const tabKey = useOptionalAppSelector<string | null>(selectTabKey, null);
203
+ const pinnedTime = useCallback(() => {
204
+ const cursor = tabKey === null ? undefined : cursors.get(tabKey);
205
+ return cursor?.sourceId === PINNED ? cursor.time : null;
206
+ }, [tabKey]);
207
+ return useSyncExternalStore(subscribe, pinnedTime);
208
+ }
209
+
210
+ /** The moment the active layout tab has its crosshair pinned at, outside React: a shared link opens there. */
211
+ export function pinnedTabTime(state: AppState): number | null {
212
+ const cursor = cursors.get(selectTabKey(state));
213
+ return cursor?.sourceId === PINNED ? cursor.time : null;
214
+ }
215
+
216
+ /** Lifts the layout tab's pin from a pane that is not a chart, as Esc does on a chart. */
217
+ export function useUnpinTab(): () => void {
218
+ const tabKey = useOptionalAppSelector<string | null>(selectTabKey, null);
219
+ return useCallback(() => {
220
+ if (tabKey !== null) setTabCursorTime(tabKey, PINNED, null);
221
+ }, [tabKey]);
222
+ }
@@ -1,3 +1,4 @@
1
+ import { logFailure } from "../../utils/log-failure";
1
2
  import { useEffect, useMemo, useRef, useState } from "react";
2
3
  import { useAppVisible, usePaneInView } from "../app/activity";
3
4
  import type { QuoteSubscriptionTarget } from "../../types/data-provider";
@@ -252,8 +253,8 @@ export function useQuoteUpdates(
252
253
  lastPollRef.current = { key: instrumentKey, at: Date.now() };
253
254
  try {
254
255
  await coordinator.loadQuotesBatch(instruments, { forceRefresh: true });
255
- } catch {
256
- // Polling is best effort and the coordinator retains the last good quote.
256
+ } catch (error) {
257
+ logFailure("state.hooks.quote-streaming", "Polling broker quotes failed")(error);
257
258
  } finally {
258
259
  inFlight = false;
259
260
  }
@@ -1,3 +1,4 @@
1
+ import { logFailure } from "../../utils/log-failure";
1
2
  import { useEffect, useRef } from "react";
2
3
  import type { AppSessionStorePort } from "../../core/app-service-ports";
3
4
  import {
@@ -69,8 +70,8 @@ export function usePersistSessionSnapshot(
69
70
  recentTickers: currentState.recentTickers,
70
71
  tickers: currentState.tickers,
71
72
  }) satisfies AppSessionSnapshot;
72
- } catch {
73
- // Snapshot persistence is best-effort during teardown.
73
+ } catch (error) {
74
+ logFailure("persist", "Building the saved session snapshot failed")(error);
74
75
  return null;
75
76
  }
76
77
  };
@@ -1,3 +1,5 @@
1
+ import { logFailure } from "../utils/log-failure";
2
+
1
3
  export const CONFIG_SAVE_DEBOUNCE_MS = 500;
2
4
  /** For config fields that change on every cursor move (recent tickers, the live pane-state mirror). */
3
5
  export const LOW_PRIORITY_CONFIG_SAVE_DEBOUNCE_MS = 5_000;
@@ -51,7 +53,10 @@ export function createPersistScheduler<T>({
51
53
  try {
52
54
  await save(value);
53
55
  } catch (error) {
54
- if (reportError) onError?.(error);
56
+ if (reportError) {
57
+ if (onError) onError(error);
58
+ else logFailure("persist", "Scheduled persistence failed")(error);
59
+ }
55
60
  throw error;
56
61
  }
57
62
  });
@@ -60,11 +65,14 @@ export function createPersistScheduler<T>({
60
65
  inFlightSaves.add(saveTask);
61
66
  void saveTask.then(
62
67
  () => { inFlightSaves.delete(saveTask); },
63
- () => { inFlightSaves.delete(saveTask); },
68
+ () => {
69
+ // Intentional ignore: The returned saveTask or enqueueSave already reports this failure.
70
+ inFlightSaves.delete(saveTask);
71
+ },
64
72
  );
65
73
  // Keep the serialization chain usable after a failed immediate save while
66
74
  // still returning that failure to its caller.
67
- inFlight = saveTask.catch(() => {});
75
+ inFlight = saveTask.catch(() => { /* Intentional ignore: The returned saveTask reports to the caller; this rejection only keeps the queue usable. */ });
68
76
  return saveTask;
69
77
  };
70
78
 
@@ -76,7 +84,7 @@ export function createPersistScheduler<T>({
76
84
  const value = pendingValue as T;
77
85
  pendingValue = undefined;
78
86
  hasPendingValue = false;
79
- return enqueueSave(value, true).catch(() => {});
87
+ return enqueueSave(value, true).catch(() => { /* Intentional ignore: enqueueSave reports scheduled errors before this drain consumes them. */ });
80
88
  };
81
89
 
82
90
  return {
@@ -87,6 +87,13 @@ export class CloudSyncController {
87
87
  private syncQueued = false;
88
88
  private clientId: string | null = null;
89
89
  private lastSignature: string | null = null;
90
+ /**
91
+ * The content signature of the cloud's copy, with the revision and the
92
+ * write it belongs to. Each 15 s poll pulls the same copy again until a
93
+ * device writes; working its signature out every time was a third of an
94
+ * idle sync on a large workspace (GLO-925).
95
+ */
96
+ private cloudSignature: { transportId: string; revision: number; clientId: string; createdAt: string; signature: string } | null = null;
90
97
  private baseline: Record<string, unknown> | null = null;
91
98
  private baselineLoaded = false;
92
99
  private pulledContributors: SyncSnapshot["contributors"] = {};
@@ -302,7 +309,7 @@ export class CloudSyncController {
302
309
  });
303
310
  return {
304
311
  revision: response.snapshot ? response.revision : 0,
305
- signature: response.snapshot ? snapshotContentSignature(response.snapshot) : null,
312
+ signature: response.snapshot ? this.pulledSignature(transport, response.revision, response.snapshot) : null,
306
313
  };
307
314
  } catch (error) {
308
315
  if (!this.isCurrent(runtime, transport)) return null;
@@ -435,6 +442,19 @@ export class CloudSyncController {
435
442
  return this.runtime === runtime && runtime.getTransport()?.transport === transport;
436
443
  }
437
444
 
445
+ private pulledSignature(transport: SyncTransport, revision: number | null, snapshot: SyncSnapshot): string {
446
+ const kept = this.cloudSignature;
447
+ if (revision != null && kept && kept.transportId === transport.id && kept.revision === revision
448
+ && kept.clientId === snapshot.clientId && kept.createdAt === snapshot.createdAt) {
449
+ return kept.signature;
450
+ }
451
+ const signature = snapshotContentSignature(snapshot);
452
+ this.cloudSignature = revision == null
453
+ ? null
454
+ : { transportId: transport.id, revision, clientId: snapshot.clientId, createdAt: snapshot.createdAt, signature };
455
+ return signature;
456
+ }
457
+
438
458
  private shouldApplyPulledRevision(revision: number | null): boolean {
439
459
  return revision == null || this.appliedRevision == null || revision > this.appliedRevision;
440
460
  }
@@ -456,6 +476,7 @@ export class CloudSyncController {
456
476
  this.inFlight = null;
457
477
  this.syncQueued = false;
458
478
  this.lastSignature = null;
479
+ this.cloudSignature = null;
459
480
  this.appliedRevision = null;
460
481
  this.baseline = null;
461
482
  this.baselineLoaded = false;