gloomberb 0.11.3 → 0.13.1

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 (574) hide show
  1. package/README.md +8 -4
  2. package/README.zh-CN.md +4 -2
  3. package/package.json +28 -2
  4. package/src/api-client/auth.ts +12 -1
  5. package/src/api-client/data.ts +103 -1
  6. package/src/api-client/index.test.ts +127 -0
  7. package/src/api-client/index.ts +139 -3
  8. package/src/api-client/normalizers.ts +39 -0
  9. package/src/api-client/paths.ts +85 -1
  10. package/src/api-client/research-activity.ts +61 -0
  11. package/src/api-client/types.ts +197 -0
  12. package/src/app/pane-runtime/index.tsx +15 -12
  13. package/src/app/pane-runtime/layout-placement.test.ts +27 -0
  14. package/src/app/pane-runtime/layout-placement.ts +13 -0
  15. package/src/app/pane-runtime/plugin-bindings.ts +62 -0
  16. package/src/app.tsx +60 -18
  17. package/src/architecture/browser-entry-graph.test.ts +96 -0
  18. package/src/brokers/profile-form.test.ts +25 -27
  19. package/src/brokers/test-broker.ts +68 -0
  20. package/src/cli/commands/plugins.ts +43 -14
  21. package/src/cli/desktop-pane-shot.ts +362 -24
  22. package/src/cli/index.ts +1 -1
  23. package/src/cli/pane-functions/capabilities.ts +126 -43
  24. package/src/cli/pane-functions/catalog.ts +16 -4
  25. package/src/cli/pane-functions/discovery.ts +1 -0
  26. package/src/cli/pane-functions/dom.test.ts +41 -0
  27. package/src/cli/pane-functions/dom.ts +199 -0
  28. package/src/cli/pane-functions/headless.test.ts +247 -0
  29. package/src/cli/pane-functions/headless.ts +423 -0
  30. package/src/cli/pane-functions/index.test.ts +20 -0
  31. package/src/cli/pane-functions/index.ts +10 -6
  32. package/src/cli/pane-functions/intraday-shot.test.ts +307 -0
  33. package/src/cli/pane-functions/intraday-shot.ts +334 -0
  34. package/src/cli/pane-functions/options.ts +27 -2
  35. package/src/cli/pane-functions/report.test.ts +29 -1
  36. package/src/cli/pane-functions/report.ts +69 -4
  37. package/src/cli/pane-functions/resolver.ts +26 -8
  38. package/src/cli/pane-functions/screenshot.test.ts +76 -0
  39. package/src/cli/pane-functions/screenshot.ts +428 -42
  40. package/src/cli/restore-plugins.ts +41 -0
  41. package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
  42. package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
  43. package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
  44. package/src/components/chart/composite/composite-chart.test.tsx +136 -21
  45. package/src/components/chart/composite/composite-chart.tsx +378 -215
  46. package/src/components/chart/composite/format.ts +8 -2
  47. package/src/components/chart/composite/interactions.test.ts +68 -102
  48. package/src/components/chart/composite/interactions.ts +214 -264
  49. package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
  50. package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
  51. package/src/components/chart/composite/rasterizer.ts +33 -0
  52. package/src/components/chart/composite/renderers.test.ts +51 -4
  53. package/src/components/chart/composite/scene.test.ts +128 -2
  54. package/src/components/chart/composite/scene.ts +149 -19
  55. package/src/components/chart/composite/text-renderer.ts +16 -2
  56. package/src/components/chart/composite/time-scale.ts +163 -62
  57. package/src/components/chart/composite/types.ts +51 -1
  58. package/src/components/chart/core/data.ts +9 -13
  59. package/src/components/chart/core/date-window.ts +7 -1
  60. package/src/components/chart/core/pointer.ts +3 -0
  61. package/src/components/chart/core/types.ts +0 -45
  62. package/src/components/chart/native/chart-rasterizer.ts +0 -1
  63. package/src/components/chart/native/kitty/index.test.ts +0 -188
  64. package/src/components/chart/native/raster/crosshair.ts +6 -5
  65. package/src/components/chart/native/raster/primitives.ts +0 -23
  66. package/src/components/chart/native/renderer-selection.ts +81 -31
  67. package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
  68. package/src/components/chart/static/chart-surface.tsx +150 -0
  69. package/src/components/chart/static/index.ts +8 -0
  70. package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
  71. package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
  72. package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
  73. package/src/components/chart/static/series.ts +49 -0
  74. package/src/components/command-bar/action-runtime.ts +1 -3
  75. package/src/components/command-bar/assist/model.test.ts +17 -2
  76. package/src/components/command-bar/assist/model.ts +40 -9
  77. package/src/components/command-bar/commands/direct/index.ts +1 -1
  78. package/src/components/command-bar/commands/direct/runtime.ts +1 -1
  79. package/src/components/command-bar/commands/registry.ts +0 -11
  80. package/src/components/command-bar/helpers.test.ts +2 -2
  81. package/src/components/command-bar/helpers.ts +2 -6
  82. package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
  83. package/src/components/command-bar/list/badge.test.ts +54 -0
  84. package/src/components/command-bar/list/badge.ts +62 -0
  85. package/src/components/command-bar/list/model.test.ts +103 -0
  86. package/src/components/command-bar/list/model.ts +61 -4
  87. package/src/components/command-bar/list/view.test.tsx +113 -0
  88. package/src/components/command-bar/list/view.tsx +147 -131
  89. package/src/components/command-bar/pane-templates/workflow.ts +1 -1
  90. package/src/components/command-bar/panel/body.tsx +51 -65
  91. package/src/components/command-bar/panel/index.tsx +48 -13
  92. package/src/components/command-bar/panel/layout.test.ts +139 -0
  93. package/src/components/command-bar/panel/layout.ts +65 -28
  94. package/src/components/command-bar/panel/native-surface.ts +24 -0
  95. package/src/components/command-bar/panel/prompt-binding.ts +54 -0
  96. package/src/components/command-bar/panel/runtime.ts +6 -3
  97. package/src/components/command-bar/panel/state.ts +41 -7
  98. package/src/components/command-bar/panel/types.ts +7 -1
  99. package/src/components/command-bar/routes/root/provider-search.ts +34 -15
  100. package/src/components/command-bar/routes/root/results.test.ts +161 -0
  101. package/src/components/command-bar/routes/root/results.ts +30 -28
  102. package/src/components/command-bar/routes/root/runtime.ts +37 -20
  103. package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
  104. package/src/components/command-bar/routes/root/search-providers.ts +205 -0
  105. package/src/components/command-bar/routes/root/selection.ts +1 -12
  106. package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
  107. package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
  108. package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
  109. package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
  110. package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
  111. package/src/components/command-bar/routing/actions.ts +1 -81
  112. package/src/components/command-bar/routing/launch-request.ts +1 -1
  113. package/src/components/command-bar/routing/list-state.ts +6 -21
  114. package/src/components/command-bar/selection-runtime.ts +1 -1
  115. package/src/components/command-bar/surface/assist.test.tsx +34 -19
  116. package/src/components/command-bar/surface/environment.ts +8 -1
  117. package/src/components/command-bar/surface/index.test.tsx +84 -68
  118. package/src/components/command-bar/surface/index.tsx +33 -36
  119. package/src/components/command-bar/surface/test-harness.tsx +38 -7
  120. package/src/components/command-bar/theme-picker.tsx +43 -15
  121. package/src/components/command-bar/view-model.test.ts +53 -8
  122. package/src/components/command-bar/view-model.ts +43 -14
  123. package/src/components/command-bar/workflow/tickers.ts +1 -0
  124. package/src/components/command-bar/workflow/types.ts +1 -1
  125. package/src/components/data-table/view.test.tsx +45 -6
  126. package/src/components/data-table/view.tsx +55 -9
  127. package/src/components/index.ts +10 -2
  128. package/src/components/input-search-bar.test.tsx +36 -2
  129. package/src/components/input-search-bar.tsx +18 -1
  130. package/src/components/layout/header.test.tsx +57 -10
  131. package/src/components/layout/header.tsx +292 -149
  132. package/src/components/layout/market-summary.test.ts +81 -0
  133. package/src/components/layout/market-summary.ts +109 -0
  134. package/src/components/layout/shell/chrome.ts +96 -1
  135. package/src/components/layout/shell/index.tsx +11 -3
  136. package/src/components/layout/shell/menu.ts +9 -0
  137. package/src/components/layout/shell/pane/actions.ts +29 -0
  138. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  139. package/src/components/layout/shell/shortcuts.ts +3 -0
  140. package/src/components/layout/status-bar.test.tsx +9 -8
  141. package/src/components/layout/status-bar.tsx +85 -54
  142. package/src/components/onboarding/account-step/chooser-panel.tsx +2 -2
  143. package/src/components/onboarding/account-step/qr-panel.tsx +2 -10
  144. package/src/components/onboarding/onboarding-frame.tsx +2 -26
  145. package/src/components/onboarding/onboarding-wizard.test.tsx +38 -12
  146. package/src/components/onboarding/onboarding-wizard.tsx +49 -14
  147. package/src/components/price-sparkline/index.ts +61 -34
  148. package/src/components/price-sparkline/view.tsx +1 -1
  149. package/src/components/sign-in-gate.test.tsx +128 -0
  150. package/src/components/sign-in-gate.tsx +149 -0
  151. package/src/components/speedometer-gauge/desktop.tsx +2 -12
  152. package/src/components/ticker/badge/list.tsx +17 -3
  153. package/src/components/ticker/list-table-view.tsx +6 -3
  154. package/src/components/ui/data-table/index.tsx +3 -2
  155. package/src/components/ui/data-table/opentui/index.tsx +165 -120
  156. package/src/components/ui/frame.tsx +28 -0
  157. package/src/components/ui/index.ts +3 -0
  158. package/src/components/ui/native-select.tsx +20 -10
  159. package/src/components/ui/select-button.tsx +138 -0
  160. package/src/components/ui/status.tsx +2 -2
  161. package/src/components/ui/table-layout.ts +1 -1
  162. package/src/components/use-double-click-activation.ts +7 -3
  163. package/src/core/app-services.ts +3 -3
  164. package/src/data/config/layout.ts +12 -6
  165. package/src/data/config/store/index.test.ts +120 -0
  166. package/src/data/config/store/migrations.ts +41 -0
  167. package/src/data/config/store/node.ts +7 -1
  168. package/src/data/config/store/normalize.ts +9 -3
  169. package/src/i18n/es.ts +6 -2
  170. package/src/i18n/ja.ts +6 -2
  171. package/src/i18n/ko.ts +6 -2
  172. package/src/i18n/zh-cn.ts +6 -2
  173. package/src/i18n/zh-tw.ts +6 -2
  174. package/src/layout-marketplace/pane-imagery.ts +1 -0
  175. package/src/layout-marketplace/payload.test.ts +17 -0
  176. package/src/layout-marketplace/payload.ts +40 -5
  177. package/src/market-data/coordinator/index.ts +3 -2
  178. package/src/market-data/coordinator/quotes.ts +173 -66
  179. package/src/market-data/coordinator/subscriptions.test.ts +215 -37
  180. package/src/pane-settings.ts +1 -1
  181. package/src/plugins/builtin/analytics/pane-model.ts +1 -1
  182. package/src/plugins/builtin/analytics/view.tsx +1 -1
  183. package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
  184. package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
  185. package/src/plugins/builtin/cds/client.test.ts +20 -0
  186. package/src/plugins/builtin/cds/client.ts +13 -3
  187. package/src/plugins/builtin/cds/headless.test.ts +30 -0
  188. package/src/plugins/builtin/cds/headless.ts +113 -0
  189. package/src/plugins/builtin/cds/index.tsx +4 -0
  190. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
  191. package/src/plugins/builtin/chart-composer/cli-options.ts +4 -1
  192. package/src/plugins/builtin/chart-composer/index.tsx +1 -1
  193. package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
  194. package/src/plugins/builtin/chat/content/composer.tsx +8 -4
  195. package/src/plugins/builtin/cloud/askg/protocol.test.ts +189 -0
  196. package/src/plugins/builtin/cloud/askg/protocol.ts +274 -0
  197. package/src/plugins/builtin/cloud/auth-dialog.tsx +19 -227
  198. package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
  199. package/src/plugins/builtin/cloud/device-signin-dialog.tsx +21 -8
  200. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  201. package/src/plugins/builtin/cloud/verification-panel.tsx +56 -0
  202. package/src/plugins/builtin/composite-plugins.ts +14 -1
  203. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  204. package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
  205. package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
  206. package/src/plugins/builtin/credit-conditions/client.ts +1 -1
  207. package/src/plugins/builtin/credit-conditions/headless.test.ts +31 -0
  208. package/src/plugins/builtin/credit-conditions/headless.ts +55 -0
  209. package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
  210. package/src/plugins/builtin/credit-conditions/index.tsx +6 -21
  211. package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
  212. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  213. package/src/plugins/builtin/earnings-calls/data.ts +223 -0
  214. package/src/plugins/builtin/earnings-calls/format.ts +49 -0
  215. package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
  216. package/src/plugins/builtin/earnings-calls/pane.tsx +760 -0
  217. package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
  218. package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
  219. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +337 -0
  220. package/src/plugins/builtin/econ/detail-view.tsx +1 -2
  221. package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
  222. package/src/plugins/builtin/econ/index.tsx +2 -1
  223. package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
  224. package/src/plugins/builtin/econ-statistics/client.ts +92 -0
  225. package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
  226. package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
  227. package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
  228. package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
  229. package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
  230. package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
  231. package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
  232. package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
  233. package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
  234. package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
  235. package/src/plugins/builtin/econ-statistics/view.ts +90 -0
  236. package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
  237. package/src/plugins/builtin/fear-greed/data.ts +6 -1
  238. package/src/plugins/builtin/fear-greed/headless.test.ts +53 -0
  239. package/src/plugins/builtin/fear-greed/headless.ts +84 -0
  240. package/src/plugins/builtin/fear-greed/index.tsx +4 -0
  241. package/src/plugins/builtin/help/index.tsx +4 -0
  242. package/src/plugins/builtin/holders/index.tsx +1 -0
  243. package/src/plugins/builtin/insider/index.tsx +1 -0
  244. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  245. package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
  246. package/src/plugins/builtin/market-movers/client.ts +76 -0
  247. package/src/plugins/builtin/market-movers/headless.test.ts +34 -0
  248. package/src/plugins/builtin/market-movers/headless.ts +73 -0
  249. package/src/plugins/builtin/market-movers/index.tsx +11 -51
  250. package/src/plugins/builtin/market-valuation/align.ts +122 -0
  251. package/src/plugins/builtin/market-valuation/cache.ts +32 -0
  252. package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
  253. package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
  254. package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
  255. package/src/plugins/builtin/market-valuation/client.ts +116 -0
  256. package/src/plugins/builtin/market-valuation/defs.ts +251 -0
  257. package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
  258. package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
  259. package/src/plugins/builtin/market-valuation/headless.ts +170 -0
  260. package/src/plugins/builtin/market-valuation/index.tsx +64 -0
  261. package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
  262. package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
  263. package/src/plugins/builtin/market-valuation/model.ts +8 -0
  264. package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
  265. package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
  266. package/src/plugins/builtin/market-valuation/series.ts +12 -0
  267. package/src/plugins/builtin/market-valuation/settings.ts +38 -0
  268. package/src/plugins/builtin/market-valuation/sources.ts +130 -0
  269. package/src/plugins/builtin/market-valuation/trend.ts +89 -0
  270. package/src/plugins/builtin/market-valuation/view.ts +137 -0
  271. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
  272. package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
  273. package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
  274. package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
  275. package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
  276. package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
  277. package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
  278. package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
  279. package/src/plugins/builtin/news/wire/index.tsx +31 -44
  280. package/src/plugins/builtin/options/index.tsx +1 -0
  281. package/src/plugins/builtin/options/view.test.tsx +29 -1
  282. package/src/plugins/builtin/options/view.tsx +1 -22
  283. package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
  284. package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
  285. package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
  286. package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
  287. package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
  288. package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
  289. package/src/plugins/builtin/plugin-module.ts +9 -1
  290. package/src/plugins/builtin/research/corporate-actions-pane.tsx +3 -237
  291. package/src/plugins/builtin/research/event-model.ts +245 -0
  292. package/src/plugins/builtin/research/events-headless.test.ts +32 -0
  293. package/src/plugins/builtin/research/events-headless.ts +87 -0
  294. package/src/plugins/builtin/research/index.tsx +8 -0
  295. package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
  296. package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
  297. package/src/plugins/builtin/research-search/data.ts +109 -0
  298. package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
  299. package/src/plugins/builtin/research-search/document-view.tsx +254 -0
  300. package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
  301. package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
  302. package/src/plugins/builtin/research-search/index.tsx +85 -0
  303. package/src/plugins/builtin/research-search/model.test.ts +40 -0
  304. package/src/plugins/builtin/research-search/model.ts +291 -0
  305. package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
  306. package/src/plugins/builtin/research-search/pane.tsx +682 -0
  307. package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
  308. package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
  309. package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
  310. package/src/plugins/builtin/research-search/snippet.ts +134 -0
  311. package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
  312. package/src/plugins/builtin/scanner/flow-model.ts +29 -1
  313. package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
  314. package/src/plugins/builtin/scanner/headless.test.ts +59 -0
  315. package/src/plugins/builtin/scanner/headless.ts +125 -0
  316. package/src/plugins/builtin/scanner/index.ts +4 -0
  317. package/src/plugins/builtin/sec/index.tsx +1 -0
  318. package/src/plugins/builtin/sectors/client.ts +54 -0
  319. package/src/plugins/builtin/sectors/headless.test.ts +28 -0
  320. package/src/plugins/builtin/sectors/headless.ts +80 -0
  321. package/src/plugins/builtin/sectors/index.tsx +6 -51
  322. package/src/plugins/builtin/shared/cloud-upgrade.ts +8 -4
  323. package/src/plugins/builtin/shared/series-cache.ts +93 -0
  324. package/src/plugins/builtin/short-interest/index.tsx +1 -0
  325. package/src/plugins/builtin/short-interest/pane.tsx +1 -1
  326. package/src/plugins/builtin/thirteenf/index.tsx +1 -0
  327. package/src/plugins/builtin/ticker-detail/index.tsx +0 -14
  328. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
  329. package/src/plugins/builtin/ticker-detail/pane.tsx +14 -0
  330. package/src/plugins/builtin/treasury-auctions/headless.test.ts +34 -0
  331. package/src/plugins/builtin/treasury-auctions/headless.ts +95 -0
  332. package/src/plugins/builtin/treasury-auctions/index.tsx +4 -0
  333. package/src/plugins/builtin/volatility/client.ts +16 -3
  334. package/src/plugins/builtin/volatility/headless.test.ts +35 -0
  335. package/src/plugins/builtin/volatility/headless.ts +75 -0
  336. package/src/plugins/builtin/volatility/index.tsx +5 -1
  337. package/src/plugins/builtin/world-indices/client.ts +43 -0
  338. package/src/plugins/builtin/world-indices/headless.test.ts +32 -0
  339. package/src/plugins/builtin/world-indices/headless.ts +109 -0
  340. package/src/plugins/builtin/world-indices/index.tsx +4 -0
  341. package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
  342. package/src/plugins/builtin/world-venue-map/map.tsx +213 -69
  343. package/src/plugins/builtin/world-venue-map/model.test.ts +32 -0
  344. package/src/plugins/builtin/world-venue-map/model.ts +134 -13
  345. package/src/plugins/builtin/yield-curve/headless.test.ts +24 -0
  346. package/src/plugins/builtin/yield-curve/headless.ts +67 -0
  347. package/src/plugins/builtin/yield-curve/index.tsx +7 -9
  348. package/src/plugins/builtin/yield-curve/treasury-data.ts +16 -6
  349. package/src/plugins/bundle.test.ts +166 -0
  350. package/src/plugins/bundle.ts +141 -0
  351. package/src/plugins/catalog-backend.test.ts +26 -0
  352. package/src/plugins/catalog-backend.ts +9 -2
  353. package/src/plugins/catalog-browser.test.ts +1 -13
  354. package/src/plugins/catalog-browser.ts +14 -0
  355. package/src/plugins/catalog-manifest.test.ts +58 -0
  356. package/src/plugins/catalog-manifest.ts +99 -0
  357. package/src/plugins/catalog-ui.ts +20 -10
  358. package/src/plugins/catalog.ts +9 -2
  359. package/src/plugins/current-target.ts +28 -0
  360. package/src/plugins/host-contract.ts +46 -0
  361. package/src/plugins/host-link.ts +158 -0
  362. package/src/plugins/host-modules.ts +73 -0
  363. package/src/plugins/loader.ts +90 -23
  364. package/src/plugins/ownership.ts +1 -0
  365. package/src/plugins/prediction-markets/index.tsx +1 -0
  366. package/src/plugins/registry/context.ts +3 -0
  367. package/src/plugins/registry/contributions.ts +27 -0
  368. package/src/plugins/registry/index.test.ts +25 -0
  369. package/src/plugins/registry/index.ts +8 -0
  370. package/src/plugins/registry/pane-settings.ts +6 -13
  371. package/src/plugins/seed.test.ts +83 -0
  372. package/src/plugins/seed.ts +83 -0
  373. package/src/public/broker.ts +37 -0
  374. package/src/public/market-data.ts +9 -0
  375. package/src/public/pane-hooks.ts +57 -0
  376. package/src/public/public-api.test.ts +285 -0
  377. package/src/public/react.ts +62 -0
  378. package/src/public/test-support.ts +23 -0
  379. package/src/public/time-series.ts +8 -0
  380. package/src/public/utils.ts +77 -0
  381. package/src/remote/layout-helpers.ts +6 -8
  382. package/src/remote/resources.ts +2 -0
  383. package/src/remote/schema.test.ts +65 -0
  384. package/src/remote/schema.ts +323 -39
  385. package/src/remote/semantic-tree.test.tsx +105 -0
  386. package/src/remote/semantic-tree.tsx +53 -35
  387. package/src/remote/types.ts +49 -2
  388. package/src/renderers/browser/app-services.ts +3 -0
  389. package/src/renderers/browser/config-host.ts +24 -8
  390. package/src/renderers/browser/deeplink-bridge.test.ts +11 -0
  391. package/src/renderers/browser/deeplink-bridge.ts +15 -3
  392. package/src/renderers/browser/main.tsx +8 -0
  393. package/src/renderers/browser/research-entry.test.ts +8 -0
  394. package/src/renderers/browser/research-entry.ts +7 -0
  395. package/src/renderers/cloudflare/worker.test.ts +19 -0
  396. package/src/renderers/cloudflare/worker.ts +1 -1
  397. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +2 -2
  398. package/src/renderers/electrobun/bun/desktop/initialization.ts +10 -3
  399. package/src/renderers/electrobun/bun/external-plugins.ts +156 -0
  400. package/src/renderers/electrobun/bun/index.ts +5 -2
  401. package/src/renderers/electrobun/shared/protocol.ts +21 -0
  402. package/src/renderers/electrobun/view/build-assets.ts +0 -3
  403. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +114 -11
  404. package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
  405. package/src/renderers/electrobun/view/external-plugins.ts +63 -0
  406. package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
  407. package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
  408. package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
  409. package/src/renderers/electrobun/view/host/mouse.ts +16 -2
  410. package/src/renderers/electrobun/view/main.tsx +27 -2
  411. package/src/renderers/electrobun/view/styles.css +5 -0
  412. package/src/renderers/electrobun/view/toast-host.tsx +18 -0
  413. package/src/renderers/opentui/chart-surface.tsx +5 -1
  414. package/src/renderers/opentui/host.tsx +16 -2
  415. package/src/renderers/opentui/interaction-performance.test.ts +79 -0
  416. package/src/renderers/opentui/interaction-performance.ts +188 -0
  417. package/src/renderers/opentui/start.tsx +26 -1
  418. package/src/renderers/opentui/test-utils.tsx +13 -0
  419. package/src/renderers/opentui/toast-host.tsx +26 -2
  420. package/src/renderers/opentui/ui-host.tsx +1 -0
  421. package/src/sources/provider-router/search.test.ts +191 -0
  422. package/src/sources/provider-router/search.ts +92 -39
  423. package/src/state/app/context/index.tsx +2 -0
  424. package/src/state/app/context/selector.test.tsx +33 -1
  425. package/src/state/hooks/quote-streaming.test.tsx +93 -0
  426. package/src/state/hooks/quote-streaming.ts +106 -30
  427. package/src/state/pane-table-export-registry.ts +19 -0
  428. package/src/sync/core-contributors.test.ts +111 -0
  429. package/src/sync/core-contributors.ts +155 -1
  430. package/src/theme/color-utils.ts +1 -1
  431. package/src/theme/colors.ts +50 -0
  432. package/src/theme/themes.test.ts +15 -2
  433. package/src/theme/themes.ts +19 -1
  434. package/src/tickers/search/index.test.ts +26 -0
  435. package/src/tickers/search/index.ts +42 -17
  436. package/src/tickers/search/ranking.ts +14 -0
  437. package/src/time-series/chart-data.test.ts +216 -0
  438. package/src/time-series/resolution.test.ts +25 -26
  439. package/src/time-series/resolution.ts +41 -10
  440. package/src/time-series/resolve.test.ts +118 -1
  441. package/src/time-series/resolve.ts +21 -16
  442. package/src/time-series/types.ts +3 -1
  443. package/src/time-series/use-chart-resolution.ts +5 -0
  444. package/src/types/config.ts +125 -3
  445. package/src/types/data-provider.ts +11 -0
  446. package/src/types/headless.ts +161 -0
  447. package/src/types/plugin.ts +102 -0
  448. package/src/ui/host.tsx +12 -1
  449. package/src/ui/index.tsx +1 -0
  450. package/src/ui/toast.tsx +8 -4
  451. package/src/utils/format.ts +35 -0
  452. package/src/utils/fuzzy-search.test.ts +94 -0
  453. package/src/utils/fuzzy-search.ts +81 -22
  454. package/src/utils/shortcut-labels.ts +14 -0
  455. package/src/components/chart/core/axis-format.ts +0 -157
  456. package/src/components/chart/core/index.test.ts +0 -1075
  457. package/src/components/chart/core/projection.ts +0 -357
  458. package/src/components/chart/core/render-utils.ts +0 -4
  459. package/src/components/chart/core/renderer.ts +0 -244
  460. package/src/components/chart/core/scene.ts +0 -180
  461. package/src/components/chart/core/time-axis.ts +0 -330
  462. package/src/components/chart/cursor-motion.ts +0 -47
  463. package/src/components/chart/indicators/types.ts +0 -26
  464. package/src/components/chart/market-session.ts +0 -176
  465. package/src/components/chart/multi-line/renderer.test.ts +0 -83
  466. package/src/components/chart/multi-line/renderer.ts +0 -161
  467. package/src/components/chart/multi-line/scene.ts +0 -188
  468. package/src/components/chart/native/raster/layout.ts +0 -129
  469. package/src/components/chart/native/raster/price-chart.ts +0 -244
  470. package/src/components/chart/rendering/chart-draw.ts +0 -270
  471. package/src/components/chart/rendering/geometry.ts +0 -95
  472. package/src/components/chart/rendering/pixel-buffer.ts +0 -267
  473. package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
  474. package/src/components/chart/scatter-chart-renderer.ts +0 -223
  475. package/src/components/chart/static/chart/surface.tsx +0 -358
  476. package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
  477. package/src/components/command-bar/routes/root/article-results.ts +0 -55
  478. package/src/plugins/broker-sync/broker-sync.test.ts +0 -188
  479. package/src/plugins/broker-sync/native-loader.ts +0 -10
  480. package/src/plugins/broker-sync/normalize.ts +0 -308
  481. package/src/plugins/broker-sync/public.ts +0 -122
  482. package/src/plugins/broker-sync/robinhood-native.ts +0 -367
  483. package/src/plugins/broker-sync/robinhood.ts +0 -114
  484. package/src/plugins/broker-sync/simplefin-native.ts +0 -201
  485. package/src/plugins/broker-sync/simplefin.ts +0 -70
  486. package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
  487. package/src/plugins/builtin/news/wire/article-search.ts +0 -140
  488. package/src/plugins/builtin/substack/api/auth.ts +0 -185
  489. package/src/plugins/builtin/substack/api/cache.ts +0 -82
  490. package/src/plugins/builtin/substack/api/loaders.ts +0 -170
  491. package/src/plugins/builtin/substack/api/store.ts +0 -186
  492. package/src/plugins/builtin/substack/api/types.ts +0 -42
  493. package/src/plugins/builtin/substack/api.test.ts +0 -298
  494. package/src/plugins/builtin/substack/article-detail.tsx +0 -397
  495. package/src/plugins/builtin/substack/article-stack.tsx +0 -133
  496. package/src/plugins/builtin/substack/content.ts +0 -478
  497. package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
  498. package/src/plugins/builtin/substack/index.tsx +0 -49
  499. package/src/plugins/builtin/substack/login-view.tsx +0 -126
  500. package/src/plugins/builtin/substack/model.test.ts +0 -155
  501. package/src/plugins/builtin/substack/normalize.ts +0 -343
  502. package/src/plugins/builtin/substack/pane-footer.ts +0 -52
  503. package/src/plugins/builtin/substack/pane-state.ts +0 -170
  504. package/src/plugins/builtin/substack/pane.tsx +0 -547
  505. package/src/plugins/builtin/substack/read-state.ts +0 -30
  506. package/src/plugins/builtin/substack/table.ts +0 -111
  507. package/src/plugins/builtin/substack/types.ts +0 -71
  508. package/src/plugins/builtin/substack/utils.ts +0 -131
  509. package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
  510. package/src/plugins/ibkr/account-cache.test.ts +0 -102
  511. package/src/plugins/ibkr/account-cache.ts +0 -24
  512. package/src/plugins/ibkr/broker-adapter.ts +0 -286
  513. package/src/plugins/ibkr/config.test.ts +0 -79
  514. package/src/plugins/ibkr/config.ts +0 -250
  515. package/src/plugins/ibkr/dialogs.tsx +0 -40
  516. package/src/plugins/ibkr/flex/index.test.ts +0 -264
  517. package/src/plugins/ibkr/flex/index.ts +0 -367
  518. package/src/plugins/ibkr/flex/statement-client.ts +0 -235
  519. package/src/plugins/ibkr/fundamental-parser.ts +0 -149
  520. package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
  521. package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
  522. package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
  523. package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
  524. package/src/plugins/ibkr/gateway/connection.ts +0 -152
  525. package/src/plugins/ibkr/gateway/contracts.ts +0 -132
  526. package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
  527. package/src/plugins/ibkr/gateway/helpers.ts +0 -33
  528. package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
  529. package/src/plugins/ibkr/gateway/history.ts +0 -120
  530. package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
  531. package/src/plugins/ibkr/gateway/market-data.ts +0 -345
  532. package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
  533. package/src/plugins/ibkr/gateway/orders.ts +0 -63
  534. package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
  535. package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
  536. package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
  537. package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
  538. package/src/plugins/ibkr/gateway/selection.ts +0 -51
  539. package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
  540. package/src/plugins/ibkr/gateway/service/index.ts +0 -429
  541. package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
  542. package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
  543. package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
  544. package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
  545. package/src/plugins/ibkr/gateway/service/native.ts +0 -543
  546. package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
  547. package/src/plugins/ibkr/gateway/types.ts +0 -27
  548. package/src/plugins/ibkr/index.test.tsx +0 -162
  549. package/src/plugins/ibkr/index.tsx +0 -159
  550. package/src/plugins/ibkr/instance-selection.test.ts +0 -120
  551. package/src/plugins/ibkr/instance-selection.ts +0 -36
  552. package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
  553. package/src/plugins/ibkr/portfolio-performance.ts +0 -129
  554. package/src/plugins/ibkr/trade/badge.tsx +0 -28
  555. package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
  556. package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
  557. package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
  558. package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
  559. package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
  560. package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
  561. package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
  562. package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
  563. package/src/plugins/ibkr/trade/tab/model.ts +0 -159
  564. package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
  565. package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
  566. package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
  567. package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
  568. package/src/plugins/ibkr/trade/utils.test.ts +0 -175
  569. package/src/plugins/ibkr/trade/utils.ts +0 -144
  570. package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
  571. package/src/plugins/ibkr/trading/pane.tsx +0 -332
  572. package/src/plugins/ibkr/trading/state.test.ts +0 -109
  573. package/src/plugins/ibkr/trading/state.ts +0 -335
  574. package/src/renderers/electrobun/view/native-stubs/broker-sync-native-loader.ts +0 -7
@@ -9,7 +9,9 @@ import { CloudApiSocket } from "./socket";
9
9
  import type {
10
10
  CloudCdsParams,
11
11
  CloudCongressHouseParams,
12
+ CloudEarningsCallsParams,
12
13
  CloudFredSeriesParams,
14
+ CloudSearchParams,
13
15
  CloudSecFilingParams,
14
16
  CloudSecFilingsParams,
15
17
  CloudHistoryParams,
@@ -48,9 +50,19 @@ import type {
48
50
  CloudEquityDiagnosticResult,
49
51
  CloudCdsResponse,
50
52
  CloudFredSeriesPayload,
53
+ CloudShillerPayload,
51
54
  CloudYieldPointPayload,
52
55
  CloudCongressHousePayload,
56
+ CloudEarningsCallListPayload,
57
+ CloudEarningsTranscriptPayload,
53
58
  CloudNewsPayload,
59
+ CloudSavedSearch,
60
+ CloudSavedSearchInput,
61
+ CloudSearchDocType,
62
+ CloudSearchDocument,
63
+ CloudSearchDocumentResponse,
64
+ CloudSearchHit,
65
+ CloudSearchResponse,
54
66
  CloudSecContentResponse,
55
67
  CloudSecDocumentsResponse,
56
68
  CloudSecFilingsResponse,
@@ -92,6 +104,8 @@ const ASSIST_REQUEST_TIMEOUT_MS = 6_000;
92
104
  class GloomApiClient {
93
105
  private currentUser: AuthUser | null = null;
94
106
  private sessionChecked = false;
107
+ /** Last few session transitions, content-free, for app://auth. */
108
+ private authTrace: Array<{ at: number; event: string; token: boolean; user: string }> = [];
95
109
  private sessionRequest: Promise<AuthUser | null> | null = null;
96
110
  private readonly currentUserListeners = new Set<() => void>();
97
111
  private readonly transport = new CloudApiRequestTransport();
@@ -154,6 +168,7 @@ class GloomApiClient {
154
168
  const changed = this.transport.getSessionToken() !== token;
155
169
  this.sessionChecked = false;
156
170
  this.transport.setSessionToken(token);
171
+ this.traceAuth(changed ? "setSessionToken:changed" : "setSessionToken:same");
157
172
  if (!token) {
158
173
  this.currentUser = null;
159
174
  this.emitCurrentUserChange();
@@ -196,8 +211,58 @@ class GloomApiClient {
196
211
  return this.transport.hasSessionCredential() && !!this.currentUser?.emailVerified;
197
212
  }
198
213
 
214
+ /**
215
+ * What this client currently believes about its session, with no secrets.
216
+ * Exposed over remote control so a "shows my username but not my
217
+ * subscription" report can be answered from the running app instead of
218
+ * from guesses about it.
219
+ */
220
+ describeAuthState(): {
221
+ hasSessionCredential: boolean;
222
+ hasSessionToken: boolean;
223
+ sessionChecked: boolean;
224
+ sessionRequestInFlight: boolean;
225
+ trace: Array<{ at: number; event: string; token: boolean; user: string }>;
226
+ currentUser: {
227
+ id: string;
228
+ emailVerified: boolean;
229
+ plan: string | null;
230
+ effectivePlan: string | null;
231
+ trialEndsAt: string | null;
232
+ } | null;
233
+ } {
234
+ const user = this.currentUser;
235
+ return {
236
+ hasSessionCredential: this.transport.hasSessionCredential(),
237
+ hasSessionToken: !!this.transport.getSessionToken(),
238
+ sessionChecked: this.sessionChecked,
239
+ sessionRequestInFlight: !!this.sessionRequest,
240
+ trace: [...this.authTrace],
241
+ currentUser: user
242
+ ? {
243
+ id: user.id,
244
+ emailVerified: user.emailVerified === true,
245
+ plan: user.plan ?? null,
246
+ effectivePlan: user.effectivePlan ?? null,
247
+ trialEndsAt: user.trialEndsAt ?? null,
248
+ }
249
+ : null,
250
+ };
251
+ }
252
+
253
+ private traceAuth(event: string, user: AuthUser | null = this.currentUser): void {
254
+ this.authTrace.push({
255
+ at: Date.now(),
256
+ event,
257
+ token: !!this.transport.getSessionToken(),
258
+ user: user ? (user.emailVerified ? "verified" : "unverified") : "none",
259
+ });
260
+ if (this.authTrace.length > 24) this.authTrace.shift();
261
+ }
262
+
199
263
  private setCurrentUser(user: AuthUser | null): void {
200
264
  const changed = this.socketEntitlementKey(this.currentUser) !== this.socketEntitlementKey(user);
265
+ this.traceAuth("setCurrentUser", user);
201
266
  this.currentUser = user;
202
267
  this.socket.syncAuthState({ reconnect: changed });
203
268
  this.emitCurrentUserChange();
@@ -265,12 +330,20 @@ class GloomApiClient {
265
330
  }
266
331
 
267
332
  async getSession(): Promise<AuthUser | null> {
268
- if (this.sessionRequest) return this.sessionRequest;
333
+ if (this.sessionRequest) {
334
+ this.traceAuth("getSession:joined-inflight");
335
+ return this.sessionRequest;
336
+ }
337
+ this.traceAuth("getSession:start");
269
338
  this.sessionRequest = this.auth.getSession();
270
339
  try {
271
340
  const user = await this.sessionRequest;
272
341
  this.sessionChecked = true;
342
+ this.traceAuth("getSession:done", user);
273
343
  return user;
344
+ } catch (error) {
345
+ this.traceAuth(`getSession:error:${error instanceof Error ? error.message.slice(0, 60) : "unknown"}`);
346
+ throw error;
274
347
  } finally {
275
348
  this.sessionRequest = null;
276
349
  }
@@ -289,8 +362,16 @@ class GloomApiClient {
289
362
  }
290
363
 
291
364
  /** Creates a Stripe checkout session for Cloud Pro; the URL opens in a browser. */
292
- async createCloudCheckout(): Promise<{ url: string }> {
293
- return this.request<{ url: string }>("/stripe/checkout", { method: "POST", body: JSON.stringify({}) });
365
+ async createCloudCheckout(returnTo?: string): Promise<{ url: string }> {
366
+ return this.request<{ url: string }>("/stripe/checkout", { method: "POST", body: JSON.stringify({ returnTo }) });
367
+ }
368
+
369
+ async recordResearchActivity(payload: {
370
+ event: import("./research-activity").ResearchActivity; eventId: string;
371
+ surface: "web" | "desktop" | "tui" | "cli"; anonymousId?: string;
372
+ attribution?: Record<string, string>; feature?: import("./research-activity").ResearchFeature;
373
+ }): Promise<void> {
374
+ await this.request("/activity/research", { method: "POST", body: JSON.stringify(payload) });
294
375
  }
295
376
 
296
377
  /** Stores a verified user's public terminal snapshot or pane handoff. */
@@ -640,6 +721,10 @@ class GloomApiClient {
640
721
  return this.data.getCloudFredSeries(seriesId, params);
641
722
  }
642
723
 
724
+ async getCloudShiller(): Promise<CloudShillerPayload> {
725
+ return this.data.getCloudShiller();
726
+ }
727
+
643
728
  async getCloudYieldCurve(): Promise<CloudYieldPointPayload[]> {
644
729
  return this.data.getCloudYieldCurve();
645
730
  }
@@ -652,6 +737,16 @@ class GloomApiClient {
652
737
  return this.data.getCloudCongressHouse(params);
653
738
  }
654
739
 
740
+ async getCloudEarningsCalls(
741
+ params: CloudEarningsCallsParams = {},
742
+ ): Promise<CloudEarningsCallListPayload> {
743
+ return this.data.getCloudEarningsCalls(params);
744
+ }
745
+
746
+ async getCloudEarningsTranscript(id: string): Promise<CloudEarningsTranscriptPayload> {
747
+ return this.data.getCloudEarningsTranscript(id);
748
+ }
749
+
655
750
  async getCloudSecFilings(params: CloudSecFilingsParams): Promise<CloudSecFilingsResponse> {
656
751
  return this.data.getCloudSecFilings(params);
657
752
  }
@@ -668,6 +763,47 @@ class GloomApiClient {
668
763
  return this.data.getCloudSec13F(path, params);
669
764
  }
670
765
 
766
+ async searchCloudDocuments(
767
+ params: CloudSearchParams,
768
+ options?: { signal?: AbortSignal },
769
+ ): Promise<CloudSearchResponse> {
770
+ return this.data.searchCloudDocuments(params, options);
771
+ }
772
+
773
+ async getCloudSearchDocument(
774
+ docType: CloudSearchDocType,
775
+ sourceId: string,
776
+ options?: { signal?: AbortSignal },
777
+ ): Promise<CloudSearchDocument> {
778
+ return this.data.getCloudSearchDocument(docType, sourceId, options);
779
+ }
780
+
781
+ async getCloudSavedSearches(options?: { signal?: AbortSignal }): Promise<CloudSavedSearch[]> {
782
+ return this.data.getCloudSavedSearches(options);
783
+ }
784
+
785
+ async createCloudSavedSearch(input: CloudSavedSearchInput): Promise<CloudSavedSearch> {
786
+ return this.data.createCloudSavedSearch(input);
787
+ }
788
+
789
+ async updateCloudSavedSearch(
790
+ id: string,
791
+ update: Partial<CloudSavedSearchInput>,
792
+ ): Promise<CloudSavedSearch> {
793
+ return this.data.updateCloudSavedSearch(id, update);
794
+ }
795
+
796
+ async deleteCloudSavedSearch(id: string): Promise<void> {
797
+ return this.data.deleteCloudSavedSearch(id);
798
+ }
799
+
800
+ async getCloudSavedSearchHits(
801
+ id: string,
802
+ options?: { signal?: AbortSignal },
803
+ ): Promise<CloudSearchHit[]> {
804
+ return this.data.getCloudSavedSearchHits(id, options);
805
+ }
806
+
671
807
  async getCloudNews(params: CloudNewsParams = {}): Promise<CloudNewsListResponse> {
672
808
  return this.data.getCloudNews(params);
673
809
  }
@@ -3,11 +3,50 @@ import type {
3
3
  ChatMessage,
4
4
  ChatNotification,
5
5
  ChatStateResponse,
6
+ CloudSavedSearch,
7
+ CloudSearchHit,
8
+ CloudSearchResponse,
6
9
  CloudTweetPayload,
7
10
  CloudTweetSearchResponse,
8
11
  } from "./types";
9
12
  import { normalizeTimestamp } from "../utils/timestamp";
10
13
 
14
+ /**
15
+ * Saved-search writes answer with either the record itself or `{ search }`.
16
+ * Both shapes are accepted so a server-side envelope change cannot silently
17
+ * hand the pane an object with no `id`.
18
+ */
19
+ export function normalizeSavedSearchResponse(response: unknown): CloudSavedSearch {
20
+ const envelope = response as { search?: CloudSavedSearch } | CloudSavedSearch | null;
21
+ const search = envelope && "search" in envelope && envelope.search
22
+ ? envelope.search
23
+ : envelope as CloudSavedSearch | null;
24
+ if (!search?.id) throw new Error("The saved search response was missing a record.");
25
+ return search;
26
+ }
27
+
28
+ export function normalizeSavedSearchHits(response: unknown): CloudSearchHit[] {
29
+ const hits = (response as { hits?: unknown } | null)?.hits;
30
+ return Array.isArray(hits) ? (hits as CloudSearchHit[]).map(normalizeSearchHit) : [];
31
+ }
32
+
33
+ /**
34
+ * A wire story or filing need not name an issuer, and the server sends `ticker:
35
+ * null` when it does not. Coerced to an empty string at the boundary so the
36
+ * declared `string` is true of every hit: consumers test it for truthiness,
37
+ * join it into search text, and hand it to a badge, and a null reaches each of
38
+ * those as an empty chip, the literal "null", or a crash.
39
+ */
40
+ export function normalizeSearchHit(hit: CloudSearchHit): CloudSearchHit {
41
+ return hit.ticker ? hit : { ...hit, ticker: "" };
42
+ }
43
+
44
+ export function normalizeSearchResponse(response: CloudSearchResponse): CloudSearchResponse {
45
+ const hits = response.hits;
46
+ if (!Array.isArray(hits)) return { ...response, hits: [] };
47
+ return { ...response, hits: hits.map(normalizeSearchHit) };
48
+ }
49
+
11
50
  export function normalizeChatMessage(message: ChatMessage): ChatMessage {
12
51
  return {
13
52
  ...message,
@@ -1,4 +1,4 @@
1
- import type { CloudTweetQueryType } from "./types";
1
+ import type { CloudSearchDocType, CloudSearchSort, CloudTweetQueryType } from "./types";
2
2
  import { normalizeSymbol, publicTickerKey } from "../utils/exchanges";
3
3
 
4
4
  export type CloudHistoryParams = {
@@ -34,6 +34,14 @@ export type CloudCongressHouseParams = {
34
34
  refresh?: boolean;
35
35
  };
36
36
 
37
+ export type CloudEarningsCallsParams = {
38
+ ticker?: string;
39
+ limit?: number;
40
+ offset?: number;
41
+ /** Include calls still working through the transcription pipeline. */
42
+ includePending?: boolean;
43
+ };
44
+
37
45
  export type CloudNewsParams = {
38
46
  feed?: "latest" | "top" | "breaking" | "ticker" | "sector" | "topic";
39
47
  ticker?: string;
@@ -131,6 +139,10 @@ export function cloudHistoryPath(symbol: string, exchange: string, params: Cloud
131
139
  return appendQuery("/market/history", search);
132
140
  }
133
141
 
142
+ export function cloudShillerPath(): string {
143
+ return "/cloud/econ/shiller";
144
+ }
145
+
134
146
  export function cloudExchangeRatePath(fromCurrency: string): string {
135
147
  return appendQuery("/market/exchange-rate", new URLSearchParams({ fromCurrency }));
136
148
  }
@@ -181,6 +193,19 @@ export function cloudCongressHousePath(params: CloudCongressHouseParams = {}): s
181
193
  return appendQuery("/cloud/congress/house", search);
182
194
  }
183
195
 
196
+ export function cloudEarningsCallsPath(params: CloudEarningsCallsParams = {}): string {
197
+ const search = new URLSearchParams();
198
+ if (params.ticker) search.set("ticker", params.ticker);
199
+ if (params.limit != null) search.set("limit", String(params.limit));
200
+ if (params.offset != null) search.set("offset", String(params.offset));
201
+ if (params.includePending) search.set("includePending", "true");
202
+ return appendQuery("/cloud/transcripts", search);
203
+ }
204
+
205
+ export function cloudEarningsTranscriptPath(id: string): string {
206
+ return `/cloud/transcripts/${encodeURIComponent(id)}`;
207
+ }
208
+
184
209
  export function cloudSecFilingsPath(params: CloudSecFilingsParams): string {
185
210
  const search = new URLSearchParams({ ticker: params.ticker });
186
211
  if (params.limit != null) search.set("limit", String(params.limit));
@@ -218,6 +243,65 @@ export function cloudSec13FPath(path: string, params: Record<string, string | nu
218
243
  return appendQuery(`/cloud/sec/13f/${normalized}`, search);
219
244
  }
220
245
 
246
+ export type CloudSearchParams = {
247
+ query: string;
248
+ tickers?: readonly string[];
249
+ docTypes?: readonly CloudSearchDocType[];
250
+ sources?: readonly string[];
251
+ /** Inclusive ISO date or timestamp bounds on `publishedAt`. */
252
+ from?: string;
253
+ to?: string;
254
+ sort?: CloudSearchSort;
255
+ limit?: number;
256
+ offset?: number;
257
+ /** Set false to skip the total-count pass when only the top hits are shown. */
258
+ count?: boolean;
259
+ /** One row per source document instead of one per matching chunk. */
260
+ distinct?: boolean;
261
+ };
262
+
263
+ function csvParam(values: readonly string[] | undefined): string | null {
264
+ if (!values) return null;
265
+ const cleaned = values.map((value) => value.trim()).filter((value) => value.length > 0);
266
+ return cleaned.length > 0 ? cleaned.join(",") : null;
267
+ }
268
+
269
+ export function cloudSearchPath(params: CloudSearchParams): string {
270
+ const search = new URLSearchParams({ q: params.query.trim() });
271
+ const tickers = csvParam(params.tickers?.map(normalizeSymbol));
272
+ if (tickers) search.set("tickers", tickers);
273
+ const docTypes = csvParam(params.docTypes);
274
+ if (docTypes) search.set("docTypes", docTypes);
275
+ const sources = csvParam(params.sources);
276
+ if (sources) search.set("sources", sources);
277
+ if (params.from) search.set("from", params.from);
278
+ if (params.to) search.set("to", params.to);
279
+ if (params.sort) search.set("sort", params.sort);
280
+ if (params.limit != null) search.set("limit", String(params.limit));
281
+ // Offset 0 is the default page, so sending it only lengthens the cache key.
282
+ if (params.offset) search.set("offset", String(params.offset));
283
+ // Counting is the server default, so only opting out is worth a parameter.
284
+ if (params.count === false) search.set("count", "false");
285
+ if (params.distinct) search.set("distinct", "true");
286
+ return appendQuery("/cloud/search", search);
287
+ }
288
+
289
+ export function cloudSearchDocumentPath(docType: CloudSearchDocType, sourceId: string): string {
290
+ return `/cloud/search/documents/${encodeURIComponent(docType)}/${encodeURIComponent(sourceId)}`;
291
+ }
292
+
293
+ export function cloudSavedSearchesPath(): string {
294
+ return "/cloud/search/saved";
295
+ }
296
+
297
+ export function cloudSavedSearchPath(id: string): string {
298
+ return `/cloud/search/saved/${encodeURIComponent(id)}`;
299
+ }
300
+
301
+ export function cloudSavedSearchHitsPath(id: string): string {
302
+ return `${cloudSavedSearchPath(id)}/hits`;
303
+ }
304
+
221
305
  export function cloudNewsPath(params: CloudNewsParams = {}): string {
222
306
  const search = new URLSearchParams();
223
307
  if (params.feed) search.set("feed", params.feed);
@@ -0,0 +1,61 @@
1
+ import { apiClient } from "./index";
2
+ import { getCurrentPluginTarget } from "../plugins/current-target";
3
+
4
+ export type ResearchActivity = "workspace_opened" | "research_viewed" | "ticker_saved" | "pro_feature_used" | "upgrade_intent";
5
+ export type ResearchFeature = "overview" | "chart" | "financials" | "news" | "transcripts" | "search" | "research";
6
+ const sent = new Set<string>();
7
+ let anonymousId: string | undefined;
8
+ let attribution: Record<string, string> = {};
9
+
10
+ /** Hosted web analytics only. Native local use never creates an identifier. */
11
+ export function initializeBrowserResearchActivity(): void {
12
+ try {
13
+ if (navigator.doNotTrack === "1" || (navigator as Navigator & { globalPrivacyControl?: boolean }).globalPrivacyControl) return;
14
+ const url = new URL(location.href);
15
+ const incoming = url.searchParams.get("_gloom");
16
+ const stored = localStorage.getItem("gloomberb.web.anonymous-id");
17
+ anonymousId = [incoming, stored].find((value) => value && /^[a-f0-9-]{36}$/.test(value)) ?? crypto.randomUUID();
18
+ localStorage.setItem("gloomberb.web.anonymous-id", anonymousId);
19
+ const keys = ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term", "twclid"];
20
+ const saved = JSON.parse(localStorage.getItem("gloomberb.web.attribution") ?? "{}");
21
+ const age = Date.now() - Date.parse(saved?.last_touch_at ?? "");
22
+ attribution = Number.isFinite(age) && age >= 0 && age < 30 * 24 * 60 * 60 * 1000 ? saved : {};
23
+ if (keys.some((key) => url.searchParams.has(key))) {
24
+ // A new campaign replaces the old click id instead of inheriting it.
25
+ attribution = { last_touch_at: new Date().toISOString() };
26
+ for (const key of keys) {
27
+ const value = url.searchParams.get(key);
28
+ if (value) attribution[key] = value.slice(0, 300);
29
+ }
30
+ }
31
+ localStorage.setItem("gloomberb.web.attribution", JSON.stringify(attribution));
32
+ url.searchParams.delete("_gloom");
33
+ history.replaceState(history.state, "", url.href);
34
+ } catch { /* Private browsing must still work. */ }
35
+ }
36
+
37
+ /** Counts milestones once per feature/session/account, never their content. */
38
+ export function recordResearchActivity(event: ResearchActivity, feature?: ResearchFeature): void {
39
+ const target = getCurrentPluginTarget();
40
+ const user = apiClient.getCurrentUser();
41
+ if (target === "web" ? !anonymousId : !user) return;
42
+ const key = `${user?.id ?? "guest"}:${event}:${feature ?? ""}`;
43
+ if (sent.has(key)) return;
44
+ sent.add(key);
45
+ if (event !== "workspace_opened") recordResearchActivity("workspace_opened");
46
+ void apiClient.recordResearchActivity({ event, eventId: crypto.randomUUID(),
47
+ surface: target === "desktop" ? "desktop" : target,
48
+ anonymousId: target === "web" ? anonymousId : undefined,
49
+ attribution: target === "web" ? attribution : undefined, feature,
50
+ }).catch(() => { sent.delete(key); });
51
+ }
52
+
53
+ export function researchUpgradeUrl(returnTo?: string): string {
54
+ const url = new URL("https://gloom.sh/cloud?upgrade=pro");
55
+ if (returnTo) url.searchParams.set("returnTo", returnTo);
56
+ if (anonymousId) url.searchParams.set("_gloom", anonymousId);
57
+ for (const [key, value] of Object.entries(attribution)) {
58
+ if (/^(utm_(source|medium|campaign|content|term)|twclid)$/.test(key)) url.searchParams.set(key, value);
59
+ }
60
+ return url.href;
61
+ }
@@ -346,6 +346,28 @@ export interface CloudFredSeriesPayload {
346
346
  info: CloudFredSeriesInfoPayload | null;
347
347
  }
348
348
 
349
+ /**
350
+ * One month of Robert Shiller's dataset. FRED carries no long-run S&P earnings,
351
+ * so this is what every earnings-based valuation ratio is built from.
352
+ */
353
+ export interface CloudShillerObservationPayload {
354
+ date: string;
355
+ price: number | null;
356
+ dividend: number | null;
357
+ earnings: number | null;
358
+ cpi: number | null;
359
+ longRate: number | null;
360
+ cape: number | null;
361
+ /** CAPE earnings yield over the real 10-year rate; Shiller's equity risk premium. */
362
+ excessCapeYield: number | null;
363
+ }
364
+
365
+ export interface CloudShillerPayload {
366
+ observations: CloudShillerObservationPayload[];
367
+ sourceUrl: string;
368
+ fetchedAt: string;
369
+ }
370
+
349
371
  /** One publicly disseminated single-name CDS transaction report. */
350
372
  export interface CloudCdsTradePayload {
351
373
  disseminationId: string;
@@ -466,6 +488,181 @@ export interface CloudCongressHousePayload {
466
488
  members: CloudCongressMemberPayload[];
467
489
  }
468
490
 
491
+ export interface CloudEarningsCallPayload {
492
+ id: string;
493
+ ticker: string;
494
+ companyName: string | null;
495
+ fiscalYear: number | null;
496
+ fiscalQuarter: number | null;
497
+ callAt: string | null;
498
+ status: string;
499
+ durationSeconds: number | null;
500
+ wordCount: number | null;
501
+ hasTranscript: boolean;
502
+ sentiment: number | null;
503
+ /** The replay or event page the transcript came from. */
504
+ webcastUrl?: string | null;
505
+ }
506
+
507
+ export interface CloudEarningsCallListPayload {
508
+ calls: CloudEarningsCallPayload[];
509
+ /** Set when asking about a company started a search that is still running. */
510
+ pending?: boolean;
511
+ /** Set when the requested symbol is not one the SEC knows. */
512
+ unknownTicker?: boolean;
513
+ }
514
+
515
+ export interface CloudTranscriptTurnPayload {
516
+ speaker: string;
517
+ role?: string;
518
+ company?: string;
519
+ text: string;
520
+ isQa: boolean;
521
+ /** Offset into the recording; null when the company published the transcript as a document. */
522
+ startSeconds: number | null;
523
+ }
524
+
525
+ export interface CloudTranscriptParticipantPayload {
526
+ name: string;
527
+ role?: string;
528
+ company?: string;
529
+ }
530
+
531
+ export interface CloudEarningsTranscriptPayload {
532
+ id: string;
533
+ ticker: string;
534
+ companyName: string | null;
535
+ fiscalYear: number | null;
536
+ fiscalQuarter: number | null;
537
+ callAt: string | null;
538
+ timing: string | null;
539
+ webcastUrl: string | null;
540
+ durationSeconds: number | null;
541
+ status: string;
542
+ fullText: string;
543
+ turns: CloudTranscriptTurnPayload[];
544
+ participants: CloudTranscriptParticipantPayload[];
545
+ summary: string | null;
546
+ guidance: string | null;
547
+ riskFactors: string | null;
548
+ analystFocus: string | null;
549
+ notable: string | null;
550
+ sentiment: number | null;
551
+ sentimentRationale: string | null;
552
+ qaStartTurn: number | null;
553
+ wordCount: number | null;
554
+ asrModel: string | null;
555
+ updatedAt: string | null;
556
+ }
557
+
558
+ export type CloudSearchDocType = "transcript" | "news" | "filing";
559
+
560
+ export type CloudSearchSort = "relevance" | "newest" | "oldest";
561
+
562
+ /**
563
+ * Per-chunk provenance. Which keys are present depends on `docType`: transcripts
564
+ * carry speaker attribution, news carries the wire source, filings carry the
565
+ * form and section. Kept as one optional-key record so an unknown docType from a
566
+ * newer server still renders instead of failing to parse.
567
+ */
568
+ export interface CloudSearchChunkMetadata {
569
+ speaker?: string;
570
+ role?: string;
571
+ company?: string;
572
+ isQa?: boolean;
573
+ startSeconds?: number;
574
+ turnIndex?: number;
575
+ source?: string;
576
+ summary?: string;
577
+ form?: string;
578
+ accession?: string;
579
+ section?: string;
580
+ }
581
+
582
+ export interface CloudSearchHit {
583
+ id: string;
584
+ docType: CloudSearchDocType;
585
+ sourceId: string;
586
+ chunkIndex: number;
587
+ ticker: string;
588
+ publishedAt: string;
589
+ title: string;
590
+ url: string;
591
+ /** Matched terms wrapped in `<mark>`, fragments joined by an ellipsis. */
592
+ snippet: string;
593
+ score: number;
594
+ metadata: CloudSearchChunkMetadata;
595
+ /**
596
+ * Chunks of this document that matched. Only sent for a distinct search,
597
+ * where the row stands for the document rather than for one chunk.
598
+ */
599
+ matchCount?: number;
600
+ }
601
+
602
+ export interface CloudSearchResponse {
603
+ hits: CloudSearchHit[];
604
+ total: number;
605
+ /** The server stopped counting past its cap, so `total` is a lower bound. */
606
+ countCapped: boolean;
607
+ hasMore: boolean;
608
+ nextOffset: number;
609
+ tookMs: number;
610
+ }
611
+
612
+ export interface CloudSearchDocumentChunk {
613
+ id: string;
614
+ chunkIndex: number;
615
+ body: string;
616
+ metadata: CloudSearchChunkMetadata;
617
+ }
618
+
619
+ export interface CloudSearchDocument {
620
+ docType: CloudSearchDocType;
621
+ sourceId: string;
622
+ ticker: string;
623
+ title: string;
624
+ url: string;
625
+ publishedAt: string;
626
+ chunks: CloudSearchDocumentChunk[];
627
+ }
628
+
629
+ export interface CloudSearchDocumentResponse {
630
+ document: CloudSearchDocument;
631
+ }
632
+
633
+ export interface CloudSavedSearchFilters {
634
+ tickers?: string[];
635
+ docTypes?: CloudSearchDocType[];
636
+ sources?: string[];
637
+ from?: string;
638
+ to?: string;
639
+ }
640
+
641
+ export interface CloudSavedSearch {
642
+ id: string;
643
+ name: string;
644
+ query: string;
645
+ filters: CloudSavedSearchFilters;
646
+ alertEnabled: boolean;
647
+ alertChannels: string[];
648
+ lastRunAt: string | null;
649
+ lastMatchAt: string | null;
650
+ matchCount: number;
651
+ createdAt: string;
652
+ }
653
+
654
+ export interface CloudSavedSearchListResponse {
655
+ searches: CloudSavedSearch[];
656
+ }
657
+
658
+ export interface CloudSavedSearchInput {
659
+ name: string;
660
+ query: string;
661
+ filters?: CloudSavedSearchFilters;
662
+ alertEnabled?: boolean;
663
+ alertChannels?: string[];
664
+ }
665
+
469
666
  export interface CloudSecFilingPayload {
470
667
  accessionNumber: string;
471
668
  form: string;