gloomberb 0.13.2 → 0.14.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 (1402) hide show
  1. package/README.md +37 -302
  2. package/README.zh-CN.md +47 -239
  3. package/package.json +16 -8
  4. package/src/api-client/askg.test.ts +256 -0
  5. package/src/api-client/askg.ts +544 -0
  6. package/src/api-client/auth.ts +110 -50
  7. package/src/api-client/chat.ts +58 -24
  8. package/src/api-client/collections.ts +53 -0
  9. package/src/api-client/data.ts +260 -69
  10. package/src/api-client/errors.ts +31 -4
  11. package/src/api-client/index.test.ts +568 -303
  12. package/src/api-client/index.ts +374 -476
  13. package/src/api-client/normalizers.ts +43 -13
  14. package/src/api-client/notes.ts +89 -0
  15. package/src/api-client/paths.test.ts +32 -0
  16. package/src/api-client/paths.ts +169 -36
  17. package/src/api-client/request.test.ts +35 -18
  18. package/src/api-client/request.ts +170 -34
  19. package/src/api-client/research-activity.test.ts +316 -0
  20. package/src/api-client/research-activity.ts +339 -32
  21. package/src/api-client/session-request-lifetime.test.ts +184 -0
  22. package/src/api-client/socket-health.test.ts +18 -12
  23. package/src/api-client/socket-lifetime.test.ts +76 -0
  24. package/src/api-client/socket.ts +279 -75
  25. package/src/api-client/teams.test.ts +270 -0
  26. package/src/api-client/teams.ts +241 -0
  27. package/src/api-client/theses.ts +177 -0
  28. package/src/api-client/types.ts +757 -10
  29. package/src/api-client/views.ts +125 -0
  30. package/src/app/global-shortcuts.test.tsx +5 -37
  31. package/src/app/pane-runtime/plugin-bindings.ts +125 -6
  32. package/src/app/pane-runtime/ticker-navigation-runtime.test.ts +144 -0
  33. package/src/app/pane-runtime/ticker-open-runtime.test.tsx +170 -0
  34. package/src/app/pane-runtime/ticker-open-runtime.ts +68 -12
  35. package/src/app/runtime/desktop-deeplink.test.ts +44 -1
  36. package/src/app/runtime/desktop-deeplink.ts +22 -11
  37. package/src/app/runtime/layout-warmup.test.ts +73 -0
  38. package/src/app/runtime/layout-warmup.ts +118 -0
  39. package/src/app/runtime/startup.ts +47 -2
  40. package/src/app/runtime/ticker-refresh.test.tsx +115 -0
  41. package/src/app/runtime/ticker-refresh.ts +109 -157
  42. package/src/app.tsx +32 -6
  43. package/src/architecture/browser-entry-graph.test.ts +1 -0
  44. package/src/architecture/import-boundaries.test.ts +14 -0
  45. package/src/brokers/bond-price-basis.test.ts +35 -0
  46. package/src/brokers/broker-ticker-sync.ts +6 -2
  47. package/src/brokers/legacy-contract.test.ts +51 -0
  48. package/src/brokers/sync-broker-instance.test.ts +70 -0
  49. package/src/capabilities/factories.ts +4 -0
  50. package/src/capabilities/index.ts +1 -0
  51. package/src/capabilities/service-capabilities.ts +43 -3
  52. package/src/capabilities/stream-client.ts +39 -0
  53. package/src/cli/base-converter.test.ts +16 -0
  54. package/src/cli/base-converter.ts +5 -4
  55. package/src/cli/commands/automation.ts +1 -147
  56. package/src/cli/commands/futures-price-precision.test.tsx +65 -0
  57. package/src/cli/commands/market-fx.test.ts +59 -0
  58. package/src/cli/commands/market.ts +10 -5
  59. package/src/cli/commands/overview.ts +1 -32
  60. package/src/cli/commands/plugins.ts +461 -79
  61. package/src/cli/commands/quote-price-basis.test.ts +82 -0
  62. package/src/cli/commands/system.ts +83 -5
  63. package/src/cli/commands/ticker-financial-units.test.ts +43 -0
  64. package/src/cli/commands/ticker-period.test.ts +62 -0
  65. package/src/cli/commands/ticker.ts +170 -106
  66. package/src/cli/desktop-pane-shot.ts +98 -7
  67. package/src/cli/entry.test.ts +55 -0
  68. package/src/cli/entry.ts +13 -6
  69. package/src/cli/helpers.ts +5 -3
  70. package/src/cli/index.ts +6 -3
  71. package/src/cli/native-smoke.ts +16 -0
  72. package/src/cli/pane-functions/capabilities.ts +9 -383
  73. package/src/cli/pane-functions/catalog.ts +6 -5
  74. package/src/cli/pane-functions/cloud-session.test.ts +23 -0
  75. package/src/cli/pane-functions/cloud-session.ts +9 -0
  76. package/src/cli/pane-functions/data.ts +0 -6
  77. package/src/cli/pane-functions/discovery.test.ts +36 -0
  78. package/src/cli/pane-functions/discovery.ts +30 -18
  79. package/src/cli/pane-functions/headless.test.ts +67 -0
  80. package/src/cli/pane-functions/headless.ts +24 -6
  81. package/src/cli/pane-functions/index.test.ts +29 -0
  82. package/src/cli/pane-functions/index.ts +1 -1
  83. package/src/cli/pane-functions/intraday-shot.test.ts +84 -20
  84. package/src/cli/pane-functions/options.ts +5 -2
  85. package/src/cli/pane-functions/report.test.ts +6 -3
  86. package/src/cli/pane-functions/report.ts +5 -857
  87. package/src/cli/pane-functions/resolver.ts +1 -1
  88. package/src/cli/pane-functions/screenshot.test.ts +27 -6
  89. package/src/cli/pane-functions/screenshot.ts +179 -135
  90. package/src/cli/registry.test.ts +24 -50
  91. package/src/cli/result.test.ts +18 -0
  92. package/src/cli/result.ts +3 -1
  93. package/src/cli.test.ts +14 -5
  94. package/src/components/chart/composite/axis-overlays.tsx +4 -2
  95. package/src/components/chart/composite/column-layout.ts +2 -2
  96. package/src/components/chart/composite/composite-chart.test.tsx +164 -7
  97. package/src/components/chart/composite/composite-chart.tsx +131 -30
  98. package/src/components/chart/composite/format.test.ts +74 -0
  99. package/src/components/chart/composite/format.ts +85 -12
  100. package/src/components/chart/composite/fx-precision.test.ts +92 -0
  101. package/src/components/chart/composite/interactions.test.ts +13 -0
  102. package/src/components/chart/composite/interactions.ts +3 -1
  103. package/src/components/chart/composite/panel-series.ts +2 -0
  104. package/src/components/chart/composite/price-axis-labels.test.ts +8 -0
  105. package/src/components/chart/composite/price-axis-labels.tsx +3 -1
  106. package/src/components/chart/composite/price-series.ts +18 -11
  107. package/src/components/chart/composite/renderers.test.ts +5 -5
  108. package/src/components/chart/composite/scene-market-cursor.test.ts +148 -0
  109. package/src/components/chart/composite/scene.test.ts +166 -0
  110. package/src/components/chart/composite/scene.ts +57 -21
  111. package/src/{plugins/prediction-markets/chart.test.tsx → components/chart/composite/scroll-surface.test.tsx} +34 -22
  112. package/src/components/chart/composite/text-renderer.ts +5 -2
  113. package/src/components/chart/composite/time-axis.test.ts +11 -2
  114. package/src/components/chart/composite/time-axis.ts +8 -5
  115. package/src/components/chart/composite/types.ts +9 -0
  116. package/src/components/chart/native/kitty/index.test.ts +4 -79
  117. package/src/components/chart/static/chart-surface.test.tsx +13 -0
  118. package/src/components/chart/static/chart-surface.tsx +19 -11
  119. package/src/components/chart/static/series.ts +3 -3
  120. package/src/components/command-bar/assist/model.test.ts +66 -0
  121. package/src/components/command-bar/assist/model.ts +82 -7
  122. package/src/components/command-bar/commands/collection.ts +27 -7
  123. package/src/components/command-bar/commands/direct/runtime.ts +7 -2
  124. package/src/components/command-bar/list/model.ts +9 -0
  125. package/src/components/command-bar/list/view.tsx +25 -83
  126. package/src/components/command-bar/multi-select-picker.tsx +6 -8
  127. package/src/components/command-bar/pane-actions.ts +13 -7
  128. package/src/components/command-bar/pane-templates/workflow.ts +28 -3
  129. package/src/components/command-bar/panel/index.tsx +189 -76
  130. package/src/components/command-bar/panel/layout.test.ts +32 -0
  131. package/src/components/command-bar/panel/layout.ts +9 -1
  132. package/src/components/command-bar/panel/palette.ts +28 -0
  133. package/src/components/command-bar/panel/state.ts +6 -0
  134. package/src/components/command-bar/panel/types.ts +1 -14
  135. package/src/components/command-bar/routes/ticker-search/actions.ts +33 -12
  136. package/src/components/command-bar/routes/ticker-search/results.test.ts +42 -1
  137. package/src/components/command-bar/routes/ticker-search/results.ts +14 -11
  138. package/src/components/command-bar/routing/actions.ts +9 -8
  139. package/src/components/command-bar/surface/index.tsx +20 -1
  140. package/src/components/command-bar/surface/listing-selection.test.tsx +84 -0
  141. package/src/components/command-bar/surface/test-harness.tsx +11 -93
  142. package/src/components/command-bar/theme-picker.tsx +12 -27
  143. package/src/components/command-bar/workflow/body.tsx +8 -35
  144. package/src/components/command-bar/workflow/builtin.ts +55 -14
  145. package/src/components/command-bar/workflow/collection-actions.test.ts +11 -0
  146. package/src/components/command-bar/workflow/collection-actions.ts +50 -11
  147. package/src/components/command-bar/workflow/collection-identity.test.ts +180 -0
  148. package/src/components/command-bar/workflow/collection-ticker.ts +65 -0
  149. package/src/components/command-bar/workflow/coordinator.ts +0 -1
  150. package/src/components/command-bar/workflow/field-row.tsx +20 -35
  151. package/src/components/command-bar/workflow/ops.test.ts +167 -1
  152. package/src/components/command-bar/workflow/ops.ts +59 -3
  153. package/src/components/command-bar/workflow/runtime.ts +13 -0
  154. package/src/components/command-bar/workflow/submit.ts +9 -2
  155. package/src/components/command-bar/workflow/ticker-listing-picker.test.ts +41 -0
  156. package/src/components/command-bar/workflow/ticker-listing-picker.ts +35 -0
  157. package/src/components/command-bar/workflow/tickers.ts +42 -11
  158. package/src/components/data-table/export.ts +4 -1
  159. package/src/components/data-table/frozen-column.test.tsx +114 -0
  160. package/src/components/data-table/horizontal-navigation.test.tsx +154 -0
  161. package/src/components/data-table/stack-view.test.tsx +23 -18
  162. package/src/components/data-table/stack-view.tsx +37 -1
  163. package/src/components/data-table/view.test.tsx +107 -63
  164. package/src/components/data-table/view.tsx +40 -3
  165. package/src/components/feed-data-table/stack-view.tsx +20 -5
  166. package/src/components/index.ts +40 -15
  167. package/src/components/layout/detached-pane-shell.tsx +71 -17
  168. package/src/components/layout/floating-pane.tsx +7 -0
  169. package/src/components/layout/header.tsx +3 -0
  170. package/src/components/layout/market-summary.ts +1 -1
  171. package/src/components/layout/missing-pane.tsx +111 -0
  172. package/src/components/layout/pane/content.tsx +29 -9
  173. package/src/components/layout/pane/footer/current-actions.test.tsx +108 -0
  174. package/src/components/layout/pane/footer/index.tsx +44 -3
  175. package/src/components/layout/pane/footer/model.ts +11 -0
  176. package/src/components/layout/pane/footer/notice.desktop.test.tsx +56 -0
  177. package/src/components/layout/pane/footer/registration.tsx +32 -1
  178. package/src/components/layout/pane/header.tsx +31 -1
  179. package/src/components/layout/pane/index.tsx +3 -0
  180. package/src/components/layout/pane/sizing.test.ts +1 -0
  181. package/src/components/layout/pane/sizing.ts +4 -1
  182. package/src/components/layout/shell/chrome.ts +7 -2
  183. package/src/components/layout/shell/index.test.tsx +117 -34
  184. package/src/components/layout/shell/index.tsx +42 -22
  185. package/src/components/layout/shell/menu.test.ts +34 -0
  186. package/src/components/layout/shell/menu.ts +9 -0
  187. package/src/components/layout/shell/pane/actions.ts +20 -3
  188. package/src/components/layout/shell/pane/layers.tsx +26 -0
  189. package/src/components/layout/shell/pane-occlusion.test.ts +52 -0
  190. package/src/components/layout/shell/pane-occlusion.ts +63 -0
  191. package/src/components/layout/status-bar-groups.test.ts +92 -0
  192. package/src/components/layout/status-bar-groups.ts +85 -0
  193. package/src/components/layout/status-bar.test.tsx +6 -6
  194. package/src/components/layout/status-bar.tsx +140 -31
  195. package/src/components/layout/titlebar-overlay.ts +11 -1
  196. package/src/components/layout/window-fullscreen.ts +32 -0
  197. package/src/components/onboarding/account-step/form-panel.tsx +13 -32
  198. package/src/components/onboarding/account-step/index.tsx +13 -29
  199. package/src/components/onboarding/first-run-workspace.test.ts +81 -0
  200. package/src/components/onboarding/first-run-workspace.ts +215 -0
  201. package/src/components/onboarding/onboarding-frame.tsx +109 -35
  202. package/src/components/onboarding/onboarding-wizard.test.tsx +389 -202
  203. package/src/components/onboarding/onboarding-wizard.tsx +379 -303
  204. package/src/components/onboarding/portfolio-step/index.tsx +13 -0
  205. package/src/components/onboarding/portfolio-step/positions-panel.tsx +292 -0
  206. package/src/components/onboarding/portfolio-step/types.ts +7 -1
  207. package/src/components/onboarding/wizard-account.ts +38 -18
  208. package/src/components/onboarding/wizard-model.test.ts +67 -0
  209. package/src/components/onboarding/wizard-model.ts +99 -3
  210. package/src/components/onboarding/wizard-positions.ts +327 -0
  211. package/src/components/price-performance.tsx +1 -1
  212. package/src/components/sign-in-gate.test.tsx +10 -78
  213. package/src/components/table-view-shared.tsx +4 -3
  214. package/src/components/ticker/badge/format.test.ts +66 -0
  215. package/src/components/ticker/badge/format.ts +51 -19
  216. package/src/components/ticker/badge/index.tsx +12 -5
  217. package/src/components/ticker/badge/list.test.tsx +84 -0
  218. package/src/components/ticker/badge/list.tsx +69 -6
  219. package/src/components/ticker/list-table-view.tsx +8 -0
  220. package/src/components/ui/action-row.tsx +36 -0
  221. package/src/components/ui/button.tsx +44 -11
  222. package/src/components/ui/checkbox.tsx +5 -2
  223. package/src/components/ui/choice-dialog.tsx +15 -6
  224. package/src/components/ui/data-table/opentui/index.tsx +101 -33
  225. package/src/components/ui/data-table/stable-columns.ts +34 -0
  226. package/src/components/ui/data-table/types.ts +6 -1
  227. package/src/components/ui/display.desktop.test.tsx +55 -0
  228. package/src/components/ui/display.test.tsx +36 -0
  229. package/src/components/ui/display.tsx +124 -0
  230. package/src/components/ui/external-link.test.tsx +25 -0
  231. package/src/components/ui/external-link.tsx +11 -3
  232. package/src/components/ui/fields.tsx +17 -4
  233. package/src/components/ui/index.ts +19 -3
  234. package/src/components/ui/list-view.tsx +32 -16
  235. package/src/components/ui/loading.tsx +5 -4
  236. package/src/components/ui/native-select.tsx +14 -5
  237. package/src/components/ui/prose.tsx +110 -0
  238. package/src/components/ui/select-button.tsx +49 -18
  239. package/src/components/ui/status.tsx +63 -54
  240. package/src/components/ui/tabs.tsx +3 -1
  241. package/src/components/ui/toggle.tsx +22 -1
  242. package/src/components/ui/ui.test.tsx +62 -26
  243. package/src/components/use-pane-notice-footer.test.tsx +116 -0
  244. package/src/components/use-pane-notice-footer.tsx +128 -0
  245. package/src/core/app-runtime.test.ts +113 -0
  246. package/src/core/app-runtime.ts +97 -0
  247. package/src/core/app-services.ts +35 -103
  248. package/src/core/state/app/instrument.ts +77 -0
  249. package/src/core/state/app/layout-reducer.ts +60 -0
  250. package/src/core/state/app/layout.ts +149 -19
  251. package/src/core/state/app/state.ts +2 -2
  252. package/src/core/state/app/types.ts +14 -1
  253. package/src/core/state/session-persistence.ts +18 -48
  254. package/src/data/cached-query.test.ts +95 -0
  255. package/src/data/cached-query.ts +106 -0
  256. package/src/data/config/layout.ts +35 -1
  257. package/src/data/config/store/index.test.ts +41 -0
  258. package/src/data/config/store/normalize.ts +65 -7
  259. package/src/data/fred-series.ts +22 -66
  260. package/src/{renderers/browser/persistence.ts → data/json-persistence.ts} +8 -8
  261. package/src/{renderers/browser/storage.ts → data/json-storage.ts} +5 -5
  262. package/src/{renderers/browser/ticker-repository.ts → data/json-ticker-repository.ts} +7 -7
  263. package/src/data/memory-resource-store.test.ts +24 -0
  264. package/src/{renderers/electrobun/view/resource-store.ts → data/memory-resource-store.ts} +2 -2
  265. package/src/data/plugin-cache.test.ts +46 -0
  266. package/src/data/plugin-cache.ts +89 -0
  267. package/src/data/response-sequence.ts +6 -0
  268. package/src/i18n/es.ts +84 -3
  269. package/src/i18n/ja.ts +84 -3
  270. package/src/i18n/ko.ts +84 -3
  271. package/src/i18n/zh-cn.ts +84 -3
  272. package/src/i18n/zh-tw.ts +84 -3
  273. package/src/layout-marketplace/cloud.test.ts +154 -0
  274. package/src/layout-marketplace/cloud.ts +215 -0
  275. package/src/layout-marketplace/gallery-desktop.test.tsx +19 -74
  276. package/src/layout-marketplace/gallery-desktop.tsx +65 -3
  277. package/src/layout-marketplace/gallery-terminal.tsx +83 -5
  278. package/src/layout-marketplace/gallery.tsx +254 -18
  279. package/src/layout-marketplace/linked-sync.ts +104 -0
  280. package/src/layout-marketplace/linked.ts +119 -0
  281. package/src/layout-marketplace/mini-workspace.test.tsx +9 -62
  282. package/src/layout-marketplace/model.ts +71 -19
  283. package/src/layout-marketplace/payload.test.ts +156 -0
  284. package/src/layout-marketplace/payload.ts +77 -16
  285. package/src/layout-marketplace/use-marketplace.ts +68 -1
  286. package/src/market-data/coordinator/auxiliary.ts +40 -11
  287. package/src/market-data/coordinator/entries.ts +11 -1
  288. package/src/market-data/coordinator/events.test.ts +33 -3
  289. package/src/market-data/coordinator/events.ts +25 -1
  290. package/src/market-data/coordinator/financials.ts +2 -61
  291. package/src/market-data/coordinator/fx-refresh.test.ts +61 -0
  292. package/src/market-data/coordinator/index.test.ts +25 -0
  293. package/src/market-data/coordinator/index.ts +129 -27
  294. package/src/market-data/coordinator/quotes.ts +1 -0
  295. package/src/market-data/coordinator/subscriptions.test.ts +12 -5
  296. package/src/market-data/hooks.tsx +8 -13
  297. package/src/market-data/legacy-contract-hooks.test.tsx +49 -0
  298. package/src/market-data/legacy-contract.test.ts +99 -0
  299. package/src/market-data/market/format.test.ts +77 -1
  300. package/src/market-data/market/format.ts +100 -6
  301. package/src/market-data/market/freshness.ts +13 -1
  302. package/src/market-data/market/price-basis.ts +9 -0
  303. package/src/market-data/market/status.test.ts +15 -1
  304. package/src/market-data/market/status.ts +18 -22
  305. package/src/market-data/performance.ts +21 -6
  306. package/src/market-data/portfolio-financials.ts +27 -0
  307. package/src/market-data/portfolio-instrument.test.ts +80 -0
  308. package/src/market-data/quotes/contributions.ts +32 -9
  309. package/src/market-data/quotes/day-range.test.ts +84 -0
  310. package/src/market-data/quotes/day-range.ts +95 -0
  311. package/src/market-data/quotes/freshness.test.ts +63 -0
  312. package/src/market-data/quotes/freshness.ts +17 -11
  313. package/src/market-data/quotes/metadata.ts +55 -0
  314. package/src/market-data/quotes/observation-time.test.ts +74 -0
  315. package/src/market-data/quotes/price-basis.test.ts +44 -0
  316. package/src/market-data/quotes/resolution.test.ts +137 -0
  317. package/src/market-data/quotes/resolution.ts +57 -11
  318. package/src/market-data/request-types.ts +27 -13
  319. package/src/market-data/result-types.ts +3 -0
  320. package/src/market-data/selectors.ts +2 -23
  321. package/src/market-data/snapshot-contract.test.ts +110 -0
  322. package/src/market-data/snapshot-provider.test.ts +93 -0
  323. package/src/market-data/snapshot-provider.ts +175 -0
  324. package/src/market-data/ticker-price-returns.test.ts +26 -0
  325. package/src/market-data/ticker-price-returns.ts +18 -0
  326. package/src/news/aggregator.test.ts +20 -4
  327. package/src/news/aggregator.ts +40 -10
  328. package/src/news/news-model.ts +33 -2
  329. package/src/news/types.ts +2 -0
  330. package/src/pane-settings.ts +24 -0
  331. package/src/plugins/builtin/account-management/form-components.tsx +22 -94
  332. package/src/plugins/builtin/account-management/model.ts +26 -12
  333. package/src/plugins/builtin/account-management/navigation.ts +1 -1
  334. package/src/plugins/builtin/account-management/pane.tsx +31 -54
  335. package/src/plugins/builtin/alerts/index.test.tsx +52 -42
  336. package/src/plugins/builtin/alerts/index.tsx +7 -2
  337. package/src/plugins/builtin/alerts/quotes.ts +2 -2
  338. package/src/plugins/builtin/analytics/broker-performance.test.ts +79 -0
  339. package/src/plugins/builtin/analytics/broker-performance.ts +57 -70
  340. package/src/plugins/builtin/analytics/display.ts +6 -3
  341. package/src/plugins/builtin/analytics/index.test.tsx +262 -53
  342. package/src/plugins/builtin/analytics/index.tsx +85 -51
  343. package/src/plugins/builtin/analytics/metrics.test.ts +23 -6
  344. package/src/plugins/builtin/analytics/metrics.ts +97 -49
  345. package/src/plugins/builtin/analytics/pane-model.test.ts +191 -0
  346. package/src/plugins/builtin/analytics/pane-model.ts +194 -100
  347. package/src/plugins/builtin/analytics/portfolio-identity.test.tsx +272 -0
  348. package/src/plugins/builtin/analytics/return-window.test.ts +72 -0
  349. package/src/plugins/builtin/analytics/sector-model.test.ts +56 -0
  350. package/src/plugins/builtin/analytics/sector-model.ts +38 -23
  351. package/src/plugins/builtin/analytics/sharpe-cadence.test.ts +111 -0
  352. package/src/plugins/builtin/analytics/sharpe-cadence.ts +161 -0
  353. package/src/plugins/builtin/analytics/view.tsx +61 -66
  354. package/src/plugins/builtin/broker-manager/index.test.tsx +5 -9
  355. package/src/plugins/builtin/broker-manager/index.tsx +11 -12
  356. package/src/plugins/builtin/buildout/cells.test.tsx +31 -0
  357. package/src/plugins/builtin/buildout/cells.tsx +2 -12
  358. package/src/plugins/builtin/buildout/detail/company.tsx +23 -42
  359. package/src/plugins/builtin/buildout/detail/index.tsx +0 -1
  360. package/src/plugins/builtin/buildout/detail/intel.tsx +5 -10
  361. package/src/plugins/builtin/buildout/detail/site.tsx +15 -33
  362. package/src/plugins/builtin/buildout/detail/ui.tsx +17 -56
  363. package/src/plugins/builtin/buildout/pane/header.tsx +3 -11
  364. package/src/plugins/builtin/buildout/pane/status.tsx +3 -18
  365. package/src/plugins/builtin/cds/headless.test.ts +20 -2
  366. package/src/plugins/builtin/cds/model.test.ts +10 -0
  367. package/src/plugins/builtin/cds/model.ts +18 -8
  368. package/src/plugins/builtin/cds/pane.test.tsx +2 -2
  369. package/src/plugins/builtin/cds/pane.tsx +32 -41
  370. package/src/plugins/builtin/chart-composer/catalog-inventory.test.ts +17 -0
  371. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +57 -16
  372. package/src/plugins/builtin/chart-composer/cli-options.ts +7 -4
  373. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +24 -2
  374. package/src/plugins/builtin/chart-composer/editor/controller.ts +7 -1
  375. package/src/plugins/builtin/chart-composer/editor/opentui-view.tsx +2 -0
  376. package/src/plugins/builtin/chart-composer/editor.test.tsx +32 -23
  377. package/src/plugins/builtin/chart-composer/editor.tsx +3 -6
  378. package/src/plugins/builtin/chart-composer/financial-periods.fixture.json +225 -0
  379. package/src/plugins/builtin/chart-composer/headless-schema.ts +221 -0
  380. package/src/plugins/builtin/chart-composer/headless.test.ts +158 -0
  381. package/src/plugins/builtin/chart-composer/headless.ts +225 -0
  382. package/src/plugins/builtin/chart-composer/index.tsx +90 -8
  383. package/src/plugins/builtin/chart-composer/loading.test.tsx +134 -0
  384. package/src/plugins/builtin/chart-composer/pane-share.test.ts +74 -1
  385. package/src/plugins/builtin/chart-composer/pane.tsx +125 -134
  386. package/src/plugins/builtin/chart-composer/presets.test.ts +46 -0
  387. package/src/plugins/builtin/chart-composer/presets.ts +41 -13
  388. package/src/plugins/builtin/chart-composer/quick-add.tsx +7 -1
  389. package/src/plugins/builtin/chart-composer/quote-metadata.test.ts +176 -0
  390. package/src/plugins/builtin/chart-composer/semantic.ts +1 -0
  391. package/src/plugins/builtin/chart-composer/settings.test.ts +30 -0
  392. package/src/plugins/builtin/chart-composer/settings.ts +1 -1
  393. package/src/plugins/builtin/chart-composer/use-series-catalog.test.tsx +94 -0
  394. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +7 -2
  395. package/src/plugins/builtin/chat/channel-labels.ts +13 -0
  396. package/src/plugins/builtin/chat/channels.ts +2 -0
  397. package/src/plugins/builtin/chat/content/channel-navigation.ts +16 -3
  398. package/src/plugins/builtin/chat/content/composer.tsx +13 -46
  399. package/src/plugins/builtin/chat/content/index.tsx +3 -1
  400. package/src/plugins/builtin/chat/content/new-dm-dialog.tsx +10 -15
  401. package/src/plugins/builtin/chat/controller/channels.ts +5 -1
  402. package/src/plugins/builtin/chat/controller/index.ts +17 -4
  403. package/src/plugins/builtin/chat/controller/session-lifetime.test.ts +182 -0
  404. package/src/plugins/builtin/chat/controller/session-runtime.ts +16 -4
  405. package/src/plugins/builtin/chat/controller.test.ts +173 -296
  406. package/src/plugins/builtin/chat/message/desktop.tsx +9 -9
  407. package/src/plugins/builtin/chat/message/profile-popover.tsx +3 -23
  408. package/src/plugins/builtin/chat/message/terminal.tsx +9 -9
  409. package/src/plugins/builtin/chat/sidebar.test.tsx +107 -0
  410. package/src/plugins/builtin/chat/sidebar.tsx +71 -18
  411. package/src/plugins/builtin/chat/status-widget.tsx +6 -12
  412. package/src/plugins/builtin/chat/test-harness.test.ts +46 -0
  413. package/src/plugins/builtin/chat/test-harness.tsx +12 -6
  414. package/src/plugins/builtin/cloud/askg/controller.test.ts +275 -0
  415. package/src/plugins/builtin/cloud/askg/controller.ts +440 -0
  416. package/src/plugins/builtin/cloud/askg/host.ts +87 -0
  417. package/src/plugins/builtin/cloud/askg/model.test.ts +222 -0
  418. package/src/plugins/builtin/cloud/askg/model.ts +623 -0
  419. package/src/plugins/builtin/cloud/askg/pane.tsx +734 -0
  420. package/src/plugins/builtin/cloud/askg/pending-question.ts +38 -0
  421. package/src/plugins/builtin/cloud/askg/protocol.ts +11 -0
  422. package/src/plugins/builtin/cloud/auth-actions.tsx +49 -51
  423. package/src/plugins/builtin/cloud/auth-form.tsx +5 -7
  424. package/src/plugins/builtin/cloud/auth-model.ts +8 -6
  425. package/src/plugins/builtin/cloud/plugin.tsx +57 -3
  426. package/src/plugins/builtin/cloud/team/acm-tab.tsx +127 -0
  427. package/src/plugins/builtin/cloud/team/capability.ts +71 -0
  428. package/src/plugins/builtin/cloud/team/collections-sync.ts +222 -0
  429. package/src/plugins/builtin/cloud/team/collections.test.ts +126 -0
  430. package/src/plugins/builtin/cloud/team/collections.ts +181 -0
  431. package/src/plugins/builtin/cloud/team/command.ts +313 -0
  432. package/src/plugins/builtin/cloud/team/model.test.ts +174 -0
  433. package/src/plugins/builtin/cloud/team/model.ts +209 -0
  434. package/src/plugins/builtin/cloud/team/module.tsx +78 -0
  435. package/src/plugins/builtin/cloud/team/pane-model.test.ts +100 -0
  436. package/src/plugins/builtin/cloud/team/pane-model.ts +156 -0
  437. package/src/plugins/builtin/cloud/team/pane-request.ts +47 -0
  438. package/src/plugins/builtin/cloud/team/pane-sections.tsx +509 -0
  439. package/src/plugins/builtin/cloud/team/pane-ui.tsx +325 -0
  440. package/src/plugins/builtin/cloud/team/pane.test.tsx +196 -0
  441. package/src/plugins/builtin/cloud/team/pane.tsx +712 -0
  442. package/src/plugins/builtin/cloud/team/status-widget.tsx +75 -0
  443. package/src/plugins/builtin/cloud/team/store.test.ts +231 -0
  444. package/src/plugins/builtin/cloud/team/store.ts +318 -0
  445. package/src/plugins/builtin/cloud/team/team-state-host.ts +70 -0
  446. package/src/plugins/builtin/cloud/team/views.ts +185 -0
  447. package/src/plugins/builtin/cloud/thesis/board-pane.test.tsx +239 -0
  448. package/src/plugins/builtin/cloud/thesis/board-pane.tsx +471 -0
  449. package/src/plugins/builtin/cloud/thesis/detail.tsx +522 -0
  450. package/src/plugins/builtin/cloud/thesis/exposure.ts +119 -0
  451. package/src/plugins/builtin/cloud/thesis/flows.ts +552 -0
  452. package/src/plugins/builtin/cloud/thesis/model.test.ts +171 -0
  453. package/src/plugins/builtin/cloud/thesis/model.ts +406 -0
  454. package/src/plugins/builtin/cloud/thesis/module.tsx +63 -0
  455. package/src/plugins/builtin/cloud/thesis/pane-request.ts +47 -0
  456. package/src/plugins/builtin/cloud/thesis/prompts.tsx +214 -0
  457. package/src/plugins/builtin/cloud/thesis/store.ts +279 -0
  458. package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +131 -0
  459. package/src/plugins/builtin/cloud/upgrade-status-widget.tsx +2 -15
  460. package/src/plugins/builtin/cloud/verification-status-widget.tsx +72 -0
  461. package/src/plugins/builtin/cloud-tweets/model.ts +13 -0
  462. package/src/plugins/builtin/cloud-tweets/pane.tsx +4 -2
  463. package/src/plugins/builtin/cloud-tweets/table.test.tsx +125 -0
  464. package/src/plugins/builtin/cloud-tweets/table.tsx +66 -20
  465. package/src/plugins/builtin/composite-plugins.ts +2 -12
  466. package/src/plugins/builtin/congress-trades/detail.tsx +42 -7
  467. package/src/plugins/builtin/congress-trades/footer.ts +23 -7
  468. package/src/plugins/builtin/congress-trades/keyboard.ts +10 -1
  469. package/src/plugins/builtin/congress-trades/model.test.ts +29 -10
  470. package/src/plugins/builtin/congress-trades/model.ts +28 -3
  471. package/src/plugins/builtin/congress-trades/pane.tsx +24 -6
  472. package/src/plugins/builtin/congress-trades/table.tsx +0 -1
  473. package/src/plugins/builtin/connections/pane.test.tsx +12 -16
  474. package/src/plugins/builtin/connections/pane.tsx +18 -30
  475. package/src/plugins/builtin/correlation/compute.test.ts +53 -86
  476. package/src/plugins/builtin/correlation/compute.ts +54 -60
  477. package/src/plugins/builtin/correlation/headless-schema.ts +69 -0
  478. package/src/plugins/builtin/correlation/headless.test.ts +147 -0
  479. package/src/plugins/builtin/correlation/headless.ts +110 -0
  480. package/src/plugins/builtin/correlation/history.ts +16 -0
  481. package/src/plugins/builtin/correlation/index.test.tsx +27 -55
  482. package/src/plugins/builtin/correlation/index.tsx +31 -13
  483. package/src/plugins/builtin/correlation/matrix/model.ts +38 -21
  484. package/src/plugins/builtin/correlation/relationship/controls.tsx +0 -30
  485. package/src/plugins/builtin/correlation/relationship/history.test.tsx +62 -0
  486. package/src/plugins/builtin/correlation/relationship/history.ts +31 -57
  487. package/src/plugins/builtin/correlation/relationship/model.ts +29 -62
  488. package/src/plugins/builtin/correlation/relationship/pane.tsx +47 -38
  489. package/src/plugins/builtin/credit-conditions/client.test.ts +43 -1
  490. package/src/plugins/builtin/credit-conditions/client.ts +17 -6
  491. package/src/plugins/builtin/credit-conditions/index.test.tsx +59 -38
  492. package/src/plugins/builtin/credit-conditions/index.tsx +35 -60
  493. package/src/plugins/builtin/credit-conditions/model.test.ts +1 -0
  494. package/src/plugins/builtin/credit-conditions/model.ts +1 -0
  495. package/src/plugins/builtin/custom-view/index.tsx +69 -0
  496. package/src/plugins/builtin/custom-view/loader.ts +107 -0
  497. package/src/plugins/builtin/custom-view/pane.tsx +308 -0
  498. package/src/plugins/builtin/custom-view/view-spec.test.ts +107 -0
  499. package/src/plugins/builtin/custom-view/view-spec.ts +347 -0
  500. package/src/plugins/builtin/debug/index.tsx +65 -46
  501. package/src/plugins/builtin/debug/template.ts +8 -0
  502. package/src/plugins/builtin/dividend-yield/browser.tsx +26 -0
  503. package/src/plugins/builtin/dividend-yield/calendar.ts +9 -0
  504. package/src/plugins/builtin/dividend-yield/client.test.ts +204 -2
  505. package/src/plugins/builtin/dividend-yield/client.ts +148 -96
  506. package/src/plugins/builtin/dividend-yield/dividend-source-integrity.test.ts +232 -0
  507. package/src/plugins/builtin/dividend-yield/headless.test.ts +35 -1
  508. package/src/plugins/builtin/dividend-yield/headless.ts +48 -11
  509. package/src/plugins/builtin/dividend-yield/index.tsx +64 -51
  510. package/src/plugins/builtin/dividend-yield/pane.test.tsx +349 -0
  511. package/src/plugins/builtin/dividend-yield/pane.tsx +118 -117
  512. package/src/plugins/builtin/dividend-yield/provider-client.test.ts +61 -0
  513. package/src/plugins/builtin/dividend-yield/provider-client.ts +44 -0
  514. package/src/plugins/builtin/dividend-yield/reference-price.test.ts +115 -0
  515. package/src/plugins/builtin/dividend-yield/reference-price.ts +27 -0
  516. package/src/plugins/builtin/dividend-yield/view.test.ts +58 -0
  517. package/src/plugins/builtin/dividend-yield/view.ts +35 -0
  518. package/src/plugins/builtin/earnings/data/cache.test.ts +21 -1
  519. package/src/plugins/builtin/earnings/data/cache.ts +11 -86
  520. package/src/plugins/builtin/earnings/detail-model.test.ts +103 -0
  521. package/src/plugins/builtin/earnings/detail-model.ts +165 -0
  522. package/src/plugins/builtin/earnings/detail-view.tsx +131 -0
  523. package/src/plugins/builtin/earnings/estimate-basis.test.ts +158 -0
  524. package/src/plugins/builtin/earnings/estimate-basis.ts +76 -0
  525. package/src/plugins/builtin/earnings/estimate-fixtures.test-data.ts +327 -0
  526. package/src/plugins/builtin/earnings/headless.ts +29 -18
  527. package/src/plugins/builtin/earnings/index.tsx +114 -63
  528. package/src/plugins/builtin/earnings/model.test.ts +29 -1
  529. package/src/plugins/builtin/earnings/table.test.ts +60 -0
  530. package/src/plugins/builtin/earnings/table.ts +46 -36
  531. package/src/plugins/builtin/earnings-calls/data.test.ts +252 -0
  532. package/src/plugins/builtin/earnings-calls/data.ts +66 -28
  533. package/src/plugins/builtin/earnings-calls/headless-freshness.test.ts +41 -0
  534. package/src/plugins/builtin/earnings-calls/headless.test.ts +69 -3
  535. package/src/plugins/builtin/earnings-calls/headless.ts +82 -89
  536. package/src/plugins/builtin/earnings-calls/index.tsx +22 -22
  537. package/src/plugins/builtin/earnings-calls/model.ts +1 -0
  538. package/src/plugins/builtin/earnings-calls/pane.test.tsx +466 -0
  539. package/src/plugins/builtin/earnings-calls/pane.tsx +225 -65
  540. package/src/plugins/builtin/earnings-calls/prose.test.ts +16 -1
  541. package/src/plugins/builtin/earnings-calls/prose.ts +33 -30
  542. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +138 -115
  543. package/src/plugins/builtin/econ/calendar-model.ts +10 -61
  544. package/src/plugins/builtin/econ/detail-view.tsx +35 -81
  545. package/src/plugins/builtin/econ/fred-cache.test.ts +39 -1
  546. package/src/plugins/builtin/econ/fred-client.test.ts +34 -7
  547. package/src/plugins/builtin/econ/fred-series-map.ts +57 -36
  548. package/src/plugins/builtin/econ/index.test.tsx +10 -13
  549. package/src/plugins/builtin/econ-statistics/client.test.ts +108 -0
  550. package/src/plugins/builtin/econ-statistics/client.ts +42 -13
  551. package/src/plugins/builtin/econ-statistics/defs.ts +3 -0
  552. package/src/plugins/builtin/econ-statistics/detail.tsx +12 -13
  553. package/src/plugins/builtin/econ-statistics/headless.test.ts +1 -1
  554. package/src/plugins/builtin/econ-statistics/headless.ts +6 -1
  555. package/src/plugins/builtin/econ-statistics/pane.test.tsx +69 -0
  556. package/src/plugins/builtin/econ-statistics/pane.tsx +52 -87
  557. package/src/plugins/builtin/econ-statistics/stats.ts +30 -11
  558. package/src/plugins/builtin/econ-statistics/transform.test.ts +23 -0
  559. package/src/plugins/builtin/econ-statistics/transform.ts +13 -4
  560. package/src/plugins/builtin/econ-statistics/view.test.ts +27 -0
  561. package/src/plugins/builtin/econ-statistics/view.ts +20 -1
  562. package/src/plugins/builtin/executives/data.ts +126 -0
  563. package/src/plugins/builtin/executives/format.test.ts +23 -0
  564. package/src/plugins/builtin/executives/format.ts +58 -0
  565. package/src/plugins/builtin/executives/index.tsx +61 -0
  566. package/src/plugins/builtin/executives/pane.test.tsx +335 -0
  567. package/src/plugins/builtin/executives/pane.tsx +467 -0
  568. package/src/plugins/builtin/filing-events/feed.test.ts +146 -0
  569. package/src/plugins/builtin/filing-events/feed.ts +189 -0
  570. package/src/plugins/builtin/filing-events/index.tsx +50 -0
  571. package/src/plugins/builtin/filing-events/pane.test.tsx +107 -0
  572. package/src/plugins/builtin/filing-events/pane.tsx +253 -0
  573. package/src/plugins/builtin/futures/index.tsx +15 -8
  574. package/src/plugins/builtin/futures/model.test.ts +25 -0
  575. package/src/plugins/builtin/futures/model.ts +12 -3
  576. package/src/plugins/builtin/futures/pane.test.tsx +8 -28
  577. package/src/plugins/builtin/futures/table.tsx +2 -2
  578. package/src/plugins/builtin/fx-matrix/export.test.ts +30 -0
  579. package/src/plugins/builtin/fx-matrix/export.ts +32 -0
  580. package/src/plugins/builtin/fx-matrix/index.tsx +24 -41
  581. package/src/plugins/builtin/fx-matrix/pairs.test.ts +11 -0
  582. package/src/plugins/builtin/fx-matrix/pairs.ts +3 -2
  583. package/src/plugins/builtin/fx-matrix/pane.test.tsx +6 -9
  584. package/src/plugins/builtin/fx-matrix/refresh.test.tsx +69 -0
  585. package/src/plugins/builtin/help/components.tsx +6 -26
  586. package/src/plugins/builtin/help/index.tsx +34 -44
  587. package/src/plugins/builtin/holders/headless.ts +8 -0
  588. package/src/plugins/builtin/insider/amendments.test.ts +112 -0
  589. package/src/plugins/builtin/insider/amendments.ts +65 -0
  590. package/src/plugins/builtin/insider/client.ts +4 -8
  591. package/src/plugins/builtin/insider/headless.test.ts +14 -0
  592. package/src/plugins/builtin/insider/headless.ts +27 -5
  593. package/src/plugins/builtin/insider/index.tsx +70 -36
  594. package/src/plugins/builtin/insider/insider-data.test.ts +50 -37
  595. package/src/plugins/builtin/insider/insider-data.ts +100 -31
  596. package/src/plugins/builtin/insider/model.ts +102 -55
  597. package/src/plugins/builtin/insider/pane.test.tsx +87 -0
  598. package/src/plugins/builtin/jobs/client.ts +85 -0
  599. package/src/plugins/builtin/jobs/headless.ts +215 -0
  600. package/src/plugins/builtin/jobs/index.tsx +83 -0
  601. package/src/plugins/builtin/jobs/model.test.ts +119 -0
  602. package/src/plugins/builtin/jobs/model.ts +350 -0
  603. package/src/plugins/builtin/jobs/pages.test.tsx +103 -0
  604. package/src/plugins/builtin/jobs/pages.ts +48 -0
  605. package/src/plugins/builtin/jobs/pane.tsx +710 -0
  606. package/src/plugins/builtin/jobs/share-bars.tsx +93 -0
  607. package/src/plugins/builtin/kelly-sizer/model.test.ts +6 -0
  608. package/src/plugins/builtin/kelly-sizer/model.ts +2 -2
  609. package/src/plugins/builtin/kelly-sizer/pane.tsx +21 -13
  610. package/src/plugins/builtin/kelly-sizer/portfolio.ts +9 -11
  611. package/src/plugins/builtin/kelly-sizer/sections.tsx +17 -23
  612. package/src/plugins/builtin/kelly-sizer/view.test.tsx +11 -0
  613. package/src/plugins/builtin/kelly-sizer/view.tsx +20 -58
  614. package/src/plugins/builtin/market-movers/headless.ts +9 -8
  615. package/src/plugins/builtin/market-movers/index.tsx +26 -21
  616. package/src/plugins/builtin/market-movers/integrity.test.ts +119 -0
  617. package/src/plugins/builtin/market-movers/model.ts +44 -10
  618. package/src/plugins/builtin/market-movers/pane-research.test.tsx +138 -0
  619. package/src/plugins/builtin/market-movers/screener.ts +77 -51
  620. package/src/plugins/builtin/market-movers/table.ts +12 -12
  621. package/src/plugins/builtin/market-valuation/align.ts +28 -17
  622. package/src/plugins/builtin/market-valuation/cache.ts +9 -1
  623. package/src/plugins/builtin/market-valuation/chart-projection.ts +11 -9
  624. package/src/plugins/builtin/market-valuation/chart-series.ts +14 -4
  625. package/src/plugins/builtin/market-valuation/client.test.ts +160 -21
  626. package/src/plugins/builtin/market-valuation/client.ts +54 -16
  627. package/src/plugins/builtin/market-valuation/defs.ts +13 -1
  628. package/src/plugins/builtin/market-valuation/detail.tsx +25 -43
  629. package/src/plugins/builtin/market-valuation/headless.test.ts +19 -2
  630. package/src/plugins/builtin/market-valuation/headless.ts +11 -6
  631. package/src/plugins/builtin/market-valuation/indicators.ts +51 -84
  632. package/src/plugins/builtin/market-valuation/model.test.ts +79 -43
  633. package/src/plugins/builtin/market-valuation/pane.test.tsx +47 -53
  634. package/src/plugins/builtin/market-valuation/pane.tsx +87 -100
  635. package/src/plugins/builtin/market-valuation/series.ts +18 -1
  636. package/src/plugins/builtin/market-valuation/sources.ts +74 -10
  637. package/src/plugins/builtin/market-valuation/trend.ts +2 -4
  638. package/src/plugins/builtin/market-valuation/view.ts +26 -23
  639. package/src/plugins/builtin/news/index.tsx +8 -3
  640. package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +13 -41
  641. package/src/plugins/builtin/news/wire/breaking/pane.tsx +7 -3
  642. package/src/plugins/builtin/news/wire/index.tsx +30 -9
  643. package/src/plugins/builtin/news/wire/industry-pane.tsx +7 -3
  644. package/src/plugins/builtin/news/wire/news/detail-view.test.tsx +279 -0
  645. package/src/plugins/builtin/news/wire/news/detail-view.tsx +91 -47
  646. package/src/plugins/builtin/news/wire/news/footer.ts +17 -22
  647. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +7 -3
  648. package/src/plugins/builtin/news/wire/news/table.tsx +11 -1
  649. package/src/plugins/builtin/news/wire/persisted-articles.ts +23 -2
  650. package/src/plugins/builtin/news/wire/rss/feed-xml.ts +104 -0
  651. package/src/plugins/builtin/news/wire/rss/parser.test.ts +63 -1
  652. package/src/plugins/builtin/news/wire/rss/parser.ts +70 -96
  653. package/src/plugins/builtin/news/wire/rss/source.test.ts +38 -1
  654. package/src/plugins/builtin/news/wire/rss/source.ts +26 -25
  655. package/src/plugins/builtin/notes/export.ts +57 -0
  656. package/src/plugins/builtin/notes/files.ts +6 -1
  657. package/src/plugins/builtin/notes/index.tsx +85 -10
  658. package/src/plugins/builtin/notes/migration.ts +80 -0
  659. package/src/plugins/builtin/notes/owner.tsx +129 -0
  660. package/src/plugins/builtin/notes/quick-notes-pane.test.tsx +10 -2
  661. package/src/plugins/builtin/notes/quick-notes-pane.tsx +130 -42
  662. package/src/plugins/builtin/notes/store.test.ts +245 -0
  663. package/src/plugins/builtin/notes/store.ts +304 -0
  664. package/src/plugins/builtin/notes/ticker-notes-tab.test.tsx +38 -68
  665. package/src/plugins/builtin/notes/ticker-notes-tab.tsx +60 -13
  666. package/src/plugins/builtin/options/analytics.test.ts +65 -0
  667. package/src/plugins/builtin/options/analytics.ts +62 -23
  668. package/src/plugins/builtin/options/calc-seed.test.ts +15 -3
  669. package/src/plugins/builtin/options/calc-seed.ts +18 -6
  670. package/src/plugins/builtin/options/chain-integrity.test.tsx +251 -0
  671. package/src/plugins/builtin/options/expiry-catalogue.ts +43 -0
  672. package/src/plugins/builtin/options/expiry-selection.test.tsx +317 -0
  673. package/src/plugins/builtin/options/footer.test.ts +38 -1
  674. package/src/plugins/builtin/options/footer.ts +69 -3
  675. package/src/plugins/builtin/options/live-quotes.test.ts +18 -4
  676. package/src/plugins/builtin/options/live-quotes.ts +7 -2
  677. package/src/plugins/builtin/options/market-reference.test.ts +36 -0
  678. package/src/plugins/builtin/options/market-reference.ts +70 -0
  679. package/src/plugins/builtin/options/quote-context.tsx +29 -0
  680. package/src/plugins/builtin/options/table.test.ts +100 -0
  681. package/src/plugins/builtin/options/table.ts +41 -11
  682. package/src/plugins/builtin/options/types.ts +1 -0
  683. package/src/plugins/builtin/options/view.test.tsx +271 -43
  684. package/src/plugins/builtin/options/view.tsx +137 -65
  685. package/src/plugins/builtin/options-calculator/boundary-integrity.test.tsx +112 -0
  686. package/src/plugins/builtin/options-calculator/index.tsx +1 -1
  687. package/src/plugins/builtin/options-calculator/model.test.ts +70 -0
  688. package/src/plugins/builtin/options-calculator/model.ts +52 -6
  689. package/src/plugins/builtin/options-calculator/pane.test.tsx +44 -12
  690. package/src/plugins/builtin/options-calculator/pane.tsx +59 -61
  691. package/src/plugins/builtin/plugin-marketplace/ids.ts +2 -0
  692. package/src/plugins/builtin/plugin-marketplace/model.test.ts +238 -19
  693. package/src/plugins/builtin/plugin-marketplace/model.ts +219 -17
  694. package/src/plugins/builtin/plugin-marketplace/pane.tsx +426 -198
  695. package/src/plugins/builtin/plugin-marketplace/store.ts +56 -6
  696. package/src/plugins/builtin/plugin-module.ts +9 -6
  697. package/src/plugins/builtin/portfolio-list/account-metrics.test.ts +20 -0
  698. package/src/plugins/builtin/portfolio-list/account-metrics.ts +3 -4
  699. package/src/plugins/builtin/portfolio-list/bond-price-basis.test.ts +120 -0
  700. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +1 -1
  701. package/src/plugins/builtin/portfolio-list/cli/render.test.ts +261 -0
  702. package/src/plugins/builtin/portfolio-list/cli/render.ts +81 -27
  703. package/src/plugins/builtin/portfolio-list/cli/shared.ts +1 -1
  704. package/src/plugins/builtin/portfolio-list/column-values.ts +87 -123
  705. package/src/plugins/builtin/portfolio-list/command-bar.ts +1 -1
  706. package/src/plugins/builtin/portfolio-list/grid.tsx +3 -1
  707. package/src/plugins/builtin/portfolio-list/header.tsx +7 -41
  708. package/src/plugins/builtin/portfolio-list/metrics.test.ts +133 -1
  709. package/src/plugins/builtin/portfolio-list/mutations.test.ts +13 -0
  710. package/src/plugins/builtin/portfolio-list/mutations.ts +7 -1
  711. package/src/plugins/builtin/portfolio-list/pane/data.ts +4 -0
  712. package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +153 -88
  713. package/src/plugins/builtin/portfolio-list/pane/index.tsx +43 -10
  714. package/src/plugins/builtin/portfolio-list/pane/streaming.ts +22 -8
  715. package/src/plugins/builtin/portfolio-list/position-cost-integrity.test.ts +101 -0
  716. package/src/plugins/builtin/portfolio-list/position-metrics.ts +166 -90
  717. package/src/plugins/builtin/portfolio-list/summary/index.tsx +31 -3
  718. package/src/plugins/builtin/portfolio-list/summary/totals.ts +71 -31
  719. package/src/plugins/builtin/portfolio-list/table.tsx +15 -1
  720. package/src/plugins/builtin/portfolio-list/use-cursor-neighbor-prefetch.test.tsx +96 -0
  721. package/src/plugins/builtin/portfolio-list/use-cursor-neighbor-prefetch.ts +87 -0
  722. package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.test.tsx +8 -5
  723. package/src/plugins/builtin/portfolio-list/use-throttled-cursor-symbol.ts +4 -1
  724. package/src/plugins/builtin/research/analyst-headless.test.ts +28 -0
  725. package/src/plugins/builtin/research/analyst-headless.ts +26 -22
  726. package/src/plugins/builtin/research/analyst-model.test.ts +36 -0
  727. package/src/plugins/builtin/research/analyst-model.ts +61 -17
  728. package/src/plugins/builtin/research/analyst-pane.test.tsx +120 -0
  729. package/src/plugins/builtin/research/analyst-pane.tsx +15 -7
  730. package/src/plugins/builtin/research/corporate-actions-pane.test.tsx +68 -0
  731. package/src/plugins/builtin/research/corporate-actions-pane.tsx +122 -29
  732. package/src/plugins/builtin/research/equity-diagnostic-pane.test.tsx +17 -46
  733. package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +13 -24
  734. package/src/plugins/builtin/research/event-model.test.ts +137 -0
  735. package/src/plugins/builtin/research/event-model.ts +173 -33
  736. package/src/plugins/builtin/research/events-headless.test.ts +11 -0
  737. package/src/plugins/builtin/research/events-headless.ts +36 -19
  738. package/src/plugins/builtin/research/headless-schema.ts +16 -0
  739. package/src/plugins/builtin/research/headless.test.ts +18 -0
  740. package/src/plugins/builtin/research/headless.ts +19 -8
  741. package/src/plugins/builtin/research/index.test.ts +73 -5
  742. package/src/plugins/builtin/research/index.tsx +3 -0
  743. package/src/plugins/builtin/research/relative-valuation-headless.test.ts +192 -0
  744. package/src/plugins/builtin/research/relative-valuation-headless.ts +51 -0
  745. package/src/plugins/builtin/research/relative-valuation-model.ts +54 -0
  746. package/src/plugins/builtin/research/relative-valuation-pane.test.tsx +98 -0
  747. package/src/plugins/builtin/research/relative-valuation-pane.tsx +72 -71
  748. package/src/plugins/builtin/research-search/document-view.tsx +15 -28
  749. package/src/plugins/builtin/research-search/pane.test.tsx +11 -20
  750. package/src/plugins/builtin/research-search/pane.tsx +5 -9
  751. package/src/plugins/builtin/risk-factors/data.test.ts +53 -0
  752. package/src/plugins/builtin/risk-factors/data.ts +117 -0
  753. package/src/plugins/builtin/risk-factors/headless.test.ts +40 -0
  754. package/src/plugins/builtin/risk-factors/headless.ts +70 -0
  755. package/src/plugins/builtin/risk-factors/index.tsx +63 -0
  756. package/src/plugins/builtin/risk-factors/pane.test.tsx +52 -0
  757. package/src/plugins/builtin/risk-factors/pane.tsx +310 -0
  758. package/src/plugins/builtin/risk-factors/test-fixtures.ts +4 -0
  759. package/src/plugins/builtin/scanner/denied.tsx +7 -7
  760. package/src/plugins/builtin/scanner/feed.ts +2 -2
  761. package/src/plugins/builtin/scanner/flow-pane.tsx +17 -8
  762. package/src/plugins/builtin/scanner/hilo-pane.tsx +21 -7
  763. package/src/plugins/builtin/sec/filing-content.test.ts +16 -0
  764. package/src/plugins/builtin/sec/filing-content.ts +46 -5
  765. package/src/plugins/builtin/sec/filing-display.tsx +13 -7
  766. package/src/plugins/builtin/sec/filing-documents.ts +10 -0
  767. package/src/plugins/builtin/sec/headless.test.ts +27 -0
  768. package/src/plugins/builtin/sec/headless.ts +4 -2
  769. package/src/plugins/builtin/sec/index.tsx +125 -29
  770. package/src/plugins/builtin/sec/model.ts +41 -3
  771. package/src/plugins/builtin/sec/pane.test.tsx +152 -0
  772. package/src/plugins/builtin/sectors/client.test.ts +211 -0
  773. package/src/plugins/builtin/sectors/client.ts +89 -18
  774. package/src/plugins/builtin/sectors/headless.test.ts +59 -0
  775. package/src/plugins/builtin/sectors/headless.ts +20 -1
  776. package/src/plugins/builtin/sectors/index.tsx +21 -22
  777. package/src/plugins/builtin/sectors/pane-cache.test.tsx +78 -0
  778. package/src/plugins/builtin/sectors/sector-model.test.ts +59 -0
  779. package/src/plugins/builtin/sectors/sector-model.ts +89 -24
  780. package/src/plugins/builtin/shared/cloud-upgrade.ts +49 -15
  781. package/src/plugins/builtin/shared/headless-market-data.ts +40 -0
  782. package/src/plugins/builtin/shared/headless-options.ts +33 -0
  783. package/src/plugins/builtin/shared/pane-footer.ts +4 -6
  784. package/src/plugins/builtin/shared/research-cloud-session.test.tsx +143 -0
  785. package/src/plugins/builtin/shared/research-cloud-session.ts +16 -0
  786. package/src/plugins/builtin/shared/screener-live-quotes.test.ts +13 -0
  787. package/src/plugins/builtin/shared/screener-live-quotes.ts +10 -9
  788. package/src/plugins/builtin/shared/series-cache.test.ts +106 -0
  789. package/src/plugins/builtin/shared/series-cache.ts +94 -49
  790. package/src/plugins/builtin/shared/table-pane.ts +4 -1
  791. package/src/plugins/builtin/shared/ticker-request.test.tsx +137 -0
  792. package/src/plugins/builtin/shared/ticker-request.ts +11 -46
  793. package/src/plugins/builtin/shared/ticker-surface.test.ts +1 -1
  794. package/src/plugins/builtin/shared/ticker-surface.ts +4 -3
  795. package/src/plugins/builtin/shared/use-quote-board.test.tsx +73 -6
  796. package/src/plugins/builtin/shared/use-quote-board.ts +18 -10
  797. package/src/plugins/builtin/short-interest/client.test.ts +47 -0
  798. package/src/plugins/builtin/short-interest/client.ts +5 -10
  799. package/src/plugins/builtin/short-interest/model.ts +13 -4
  800. package/src/plugins/builtin/short-interest/pane.test.tsx +57 -0
  801. package/src/plugins/builtin/short-interest/pane.tsx +21 -69
  802. package/src/plugins/builtin/thirteenf/api.test.ts +91 -0
  803. package/src/plugins/builtin/thirteenf/api.ts +78 -88
  804. package/src/plugins/builtin/thirteenf/data.test.ts +177 -1
  805. package/src/plugins/builtin/thirteenf/data.ts +118 -38
  806. package/src/plugins/builtin/thirteenf/format.ts +2 -0
  807. package/src/plugins/builtin/thirteenf/headless.test.ts +36 -0
  808. package/src/plugins/builtin/thirteenf/headless.ts +27 -8
  809. package/src/plugins/builtin/thirteenf/model.test.ts +90 -24
  810. package/src/plugins/builtin/thirteenf/model.ts +129 -82
  811. package/src/plugins/builtin/thirteenf/pane.test.tsx +27 -92
  812. package/src/plugins/builtin/thirteenf/pane.tsx +55 -33
  813. package/src/plugins/builtin/thirteenf/table.ts +2 -3
  814. package/src/plugins/builtin/thirteenf/types.ts +13 -1
  815. package/src/plugins/builtin/ticker-detail/chart-tab-switch.test.tsx +17 -50
  816. package/src/plugins/builtin/ticker-detail/data-panes/historical-price-precision.test.tsx +120 -0
  817. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.test.tsx +41 -0
  818. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +36 -13
  819. package/src/plugins/builtin/ticker-detail/financials/aggregation.test.ts +79 -0
  820. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +90 -13
  821. package/src/plugins/builtin/ticker-detail/financials/model.test.ts +152 -0
  822. package/src/plugins/builtin/ticker-detail/financials/model.ts +139 -22
  823. package/src/plugins/builtin/ticker-detail/financials/period-integrity.test.tsx +77 -0
  824. package/src/plugins/builtin/ticker-detail/financials/schema.ts +3 -3
  825. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +71 -49
  826. package/src/plugins/builtin/ticker-detail/fund-profile.test.tsx +118 -0
  827. package/src/plugins/builtin/ticker-detail/headless-schema.ts +59 -0
  828. package/src/plugins/builtin/ticker-detail/headless.test.ts +165 -0
  829. package/src/plugins/builtin/ticker-detail/headless.ts +150 -0
  830. package/src/plugins/builtin/ticker-detail/index.tsx +34 -22
  831. package/src/plugins/builtin/ticker-detail/overview/components.tsx +21 -22
  832. package/src/plugins/builtin/ticker-detail/overview/model.test.ts +118 -0
  833. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -43
  834. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +2 -1
  835. package/src/plugins/builtin/ticker-detail/overview/types.ts +2 -0
  836. package/src/plugins/builtin/ticker-detail/overview-return-coverage.test.tsx +71 -0
  837. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +92 -80
  838. package/src/plugins/builtin/ticker-detail/pane.tsx +42 -19
  839. package/src/plugins/builtin/ticker-detail/quote-footer.ts +28 -0
  840. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +18 -9
  841. package/src/plugins/builtin/ticker-detail/quote-monitor/index.test.tsx +21 -29
  842. package/src/plugins/builtin/ticker-detail/quote-monitor/retained-status.test.tsx +134 -0
  843. package/src/plugins/builtin/ticker-detail/quote-status.test.tsx +116 -0
  844. package/src/plugins/builtin/ticker-detail/quote-time-integrity.test.ts +42 -0
  845. package/src/plugins/builtin/ticker-research-plugin.ts +8 -0
  846. package/src/plugins/builtin/treasury-auctions/cache.test.ts +43 -1
  847. package/src/plugins/builtin/treasury-auctions/cache.ts +29 -67
  848. package/src/plugins/builtin/treasury-auctions/client.test.ts +26 -8
  849. package/src/plugins/builtin/treasury-auctions/client.ts +28 -4
  850. package/src/plugins/builtin/treasury-auctions/headless.ts +2 -0
  851. package/src/plugins/builtin/treasury-auctions/model.test.ts +22 -0
  852. package/src/plugins/builtin/treasury-auctions/model.ts +28 -25
  853. package/src/plugins/builtin/treasury-auctions/pane.test.tsx +7 -22
  854. package/src/plugins/builtin/treasury-auctions/pane.tsx +32 -37
  855. package/src/plugins/builtin/treasury-auctions/types.ts +2 -2
  856. package/src/plugins/builtin/volatility/index.tsx +18 -47
  857. package/src/plugins/builtin/world-indices/headless.ts +4 -3
  858. package/src/plugins/builtin/world-indices/index.tsx +12 -5
  859. package/src/plugins/builtin/world-indices/pane.test.tsx +55 -15
  860. package/src/plugins/builtin/world-indices/table.tsx +3 -3
  861. package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +12 -73
  862. package/src/plugins/builtin/world-venue-map/pane.tsx +5 -7
  863. package/src/plugins/builtin/yield-curve/chart.test.ts +32 -0
  864. package/src/plugins/builtin/yield-curve/chart.ts +37 -0
  865. package/src/plugins/builtin/yield-curve/headless.test.ts +23 -7
  866. package/src/plugins/builtin/yield-curve/headless.ts +24 -7
  867. package/src/plugins/builtin/yield-curve/history.test.ts +124 -0
  868. package/src/plugins/builtin/yield-curve/history.ts +89 -0
  869. package/src/plugins/builtin/yield-curve/index.tsx +112 -97
  870. package/src/plugins/builtin/yield-curve/pane.test.tsx +137 -0
  871. package/src/plugins/builtin/yield-curve/treasury-data.test.ts +15 -5
  872. package/src/plugins/builtin/yield-curve/treasury-data.ts +25 -17
  873. package/src/plugins/bundle.test.ts +44 -1
  874. package/src/plugins/bundle.ts +59 -7
  875. package/src/plugins/catalog-backend.test.ts +1 -1
  876. package/src/plugins/catalog-backend.ts +0 -2
  877. package/src/plugins/catalog-browser.test.ts +9 -3
  878. package/src/plugins/catalog-browser.ts +37 -2
  879. package/src/plugins/catalog-manifest.ts +1 -3
  880. package/src/plugins/catalog-ui.ts +2 -6
  881. package/src/plugins/current-target.ts +17 -0
  882. package/src/plugins/external-runtime.ts +70 -0
  883. package/src/plugins/health.ts +21 -0
  884. package/src/plugins/host-contract.ts +26 -0
  885. package/src/plugins/host-link.test.ts +133 -0
  886. package/src/plugins/host-link.ts +49 -10
  887. package/src/plugins/host-module-imports.test.ts +94 -0
  888. package/src/plugins/host-module-imports.ts +73 -0
  889. package/src/plugins/host-modules.ts +2 -51
  890. package/src/plugins/host-resolver.test.ts +96 -0
  891. package/src/plugins/host-resolver.ts +102 -0
  892. package/src/plugins/host-smoke.ts +103 -0
  893. package/src/plugins/launch-layout.test.ts +131 -0
  894. package/src/plugins/launch-layout.ts +148 -0
  895. package/src/plugins/loader.test.ts +54 -0
  896. package/src/plugins/loader.ts +138 -36
  897. package/src/plugins/manager-node.ts +41 -0
  898. package/src/plugins/ownership.ts +4 -3
  899. package/src/plugins/pane-manager/dock-tree.ts +4 -2
  900. package/src/plugins/pane-manager/layout-state.ts +11 -4
  901. package/src/plugins/pane-manager/queries.ts +5 -4
  902. package/src/plugins/pane-manager.test.ts +22 -0
  903. package/src/plugins/pane-state.ts +48 -0
  904. package/src/plugins/plugin-names.ts +32 -0
  905. package/src/plugins/registry/contributions.ts +65 -126
  906. package/src/plugins/registry/index.test.ts +71 -5
  907. package/src/plugins/registry/index.ts +181 -102
  908. package/src/plugins/registry/pane-settings.ts +20 -14
  909. package/src/plugins/registry/plugin-state.ts +5 -20
  910. package/src/plugins/registry/setup-command.test.ts +62 -0
  911. package/src/plugins/registry/setup-command.ts +93 -0
  912. package/src/plugins/registry/shared.ts +1 -3
  913. package/src/plugins/registry/slots.ts +1 -1
  914. package/src/plugins/runtime/context.tsx +1 -0
  915. package/src/plugins/runtime/index.tsx +15 -49
  916. package/src/plugins/runtime/state.ts +28 -47
  917. package/src/plugins/seed.test.ts +57 -4
  918. package/src/plugins/seed.ts +28 -9
  919. package/src/plugins/team-state.ts +70 -0
  920. package/src/plugins/ticker-navigation.ts +5 -0
  921. package/src/plugins/web-bundled.ts +42 -0
  922. package/src/public/i18n.ts +17 -0
  923. package/src/public/layout.ts +12 -0
  924. package/src/public/market-data.ts +19 -0
  925. package/src/public/pane-hooks.ts +8 -1
  926. package/src/public/public-api.test.ts +39 -282
  927. package/src/public/quotes.ts +50 -0
  928. package/src/public/react.ts +44 -0
  929. package/src/public/remote.ts +23 -0
  930. package/src/public/test-support.ts +46 -1
  931. package/src/public/tickers.ts +40 -0
  932. package/src/public/time-series.ts +5 -0
  933. package/src/public/utils.ts +38 -2
  934. package/src/react/async-resource.test.tsx +106 -0
  935. package/src/react/async-resource.ts +65 -0
  936. package/src/react/plugins/plugin-slot.tsx +2 -10
  937. package/src/react/use-throttled-commit-value.ts +18 -1
  938. package/src/remote/app-host.tsx +17 -2
  939. package/src/remote/controller.test.ts +109 -3
  940. package/src/remote/controller.ts +44 -2
  941. package/src/remote/schema.ts +15 -0
  942. package/src/remote/semantic-tree.tsx +15 -7
  943. package/src/renderers/browser/app-services.ts +19 -52
  944. package/src/renderers/browser/bundled-plugins.test.ts +41 -0
  945. package/src/renderers/browser/bundled-plugins.ts +60 -0
  946. package/src/renderers/browser/cloud-transport.ts +8 -2
  947. package/src/renderers/browser/config-host.test.ts +70 -0
  948. package/src/renderers/browser/config-host.ts +75 -11
  949. package/src/renderers/browser/deeplink-bridge.test.ts +8 -4
  950. package/src/renderers/browser/deeplink-bridge.ts +18 -0
  951. package/src/renderers/browser/http-proxy-transport.test.ts +98 -0
  952. package/src/renderers/browser/http-proxy-transport.ts +83 -0
  953. package/src/renderers/browser/main.tsx +18 -2
  954. package/src/renderers/browser/research-entry.test.ts +24 -0
  955. package/src/renderers/browser/research-entry.ts +16 -2
  956. package/src/renderers/browser/storage.test.ts +7 -7
  957. package/src/renderers/cloudflare/http-proxy.test.ts +122 -0
  958. package/src/renderers/cloudflare/http-proxy.ts +197 -0
  959. package/src/renderers/cloudflare/worker.ts +7 -0
  960. package/src/renderers/electrobun/bun/core-capabilities.ts +0 -160
  961. package/src/renderers/electrobun/bun/desktop/host-requests.ts +4 -0
  962. package/src/renderers/electrobun/bun/external-plugins.ts +178 -63
  963. package/src/renderers/electrobun/bun/index.ts +49 -9
  964. package/src/renderers/electrobun/shared/protocol.ts +40 -4
  965. package/src/renderers/electrobun/view/app-services.ts +36 -90
  966. package/src/renderers/electrobun/view/backend-rpc.ts +12 -2
  967. package/src/renderers/electrobun/view/build-assets.ts +0 -1
  968. package/src/renderers/electrobun/view/capability-stream-client.ts +51 -0
  969. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +232 -416
  970. package/src/renderers/electrobun/view/cli-pane-shot-frame.test.tsx +67 -0
  971. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +39 -0
  972. package/src/renderers/electrobun/view/data-table/dom.ts +3 -0
  973. package/src/renderers/electrobun/view/data-table/frozen-column.test.tsx +73 -0
  974. package/src/renderers/electrobun/view/data-table/frozen-column.ts +22 -0
  975. package/src/renderers/electrobun/view/data-table/horizontal-navigation.test.tsx +77 -0
  976. package/src/renderers/electrobun/view/data-table/index.test.tsx +125 -0
  977. package/src/renderers/electrobun/view/data-table/index.tsx +48 -6
  978. package/src/renderers/electrobun/view/data-table/row.tsx +32 -3
  979. package/src/renderers/electrobun/view/desktop/control-styles.ts +7 -0
  980. package/src/renderers/electrobun/view/desktop/controls.test.tsx +141 -48
  981. package/src/renderers/electrobun/view/desktop/controls.tsx +86 -39
  982. package/src/renderers/electrobun/view/desktop/list-view.tsx +44 -9
  983. package/src/renderers/electrobun/view/dom-ui-host.tsx +4 -2
  984. package/src/renderers/electrobun/view/external-plugins.test.ts +13 -1
  985. package/src/renderers/electrobun/view/external-plugins.ts +47 -35
  986. package/src/renderers/electrobun/view/host/block-glyph-canvas.tsx +115 -0
  987. package/src/renderers/electrobun/view/host/box.test.tsx +50 -89
  988. package/src/renderers/electrobun/view/host/input.tsx +7 -1
  989. package/src/renderers/electrobun/view/host/media-surface.tsx +1 -2
  990. package/src/renderers/electrobun/view/host/scroll-box.desktop.test.tsx +26 -0
  991. package/src/renderers/electrobun/view/host/scroll-box.tsx +14 -6
  992. package/src/renderers/electrobun/view/host/text.tsx +28 -0
  993. package/src/renderers/electrobun/view/http-fetch.ts +3 -14
  994. package/src/renderers/electrobun/view/input-host.test.tsx +11 -47
  995. package/src/renderers/electrobun/view/input-host.tsx +1 -1
  996. package/src/renderers/electrobun/view/main.tsx +38 -6
  997. package/src/renderers/electrobun/view/native-stubs/native-stubs.test.ts +2 -7
  998. package/src/renderers/electrobun/view/remote/asset-data-client.ts +2 -0
  999. package/src/renderers/electrobun/view/remote/persistence.ts +2 -2
  1000. package/src/renderers/electrobun/view/remote/quote-subscription-registry.ts +6 -1
  1001. package/src/renderers/electrobun/view/rpc-codec.test.ts +64 -0
  1002. package/src/renderers/electrobun/view/rpc-codec.ts +35 -0
  1003. package/src/renderers/electrobun/view/screenshot-watermark.test.ts +48 -0
  1004. package/src/renderers/electrobun/view/screenshot-watermark.ts +105 -0
  1005. package/src/renderers/electrobun/view/styles.css +16 -0
  1006. package/src/renderers/electrobun/view/test-utils.tsx +76 -0
  1007. package/src/renderers/electrobun/view/toast-host.test.tsx +8 -25
  1008. package/src/renderers/electrobun/view/ui-host.tsx +0 -3
  1009. package/src/renderers/electrobun/view/window-fullscreen.ts +57 -0
  1010. package/src/renderers/opentui/interaction-performance.ts +29 -3
  1011. package/src/renderers/opentui/scrollbox-layout.ts +35 -0
  1012. package/src/renderers/opentui/start.tsx +7 -40
  1013. package/src/renderers/opentui/test-utils.tsx +117 -6
  1014. package/src/renderers/opentui/ui-host.tsx +1 -1
  1015. package/src/renderers/share/chart.test.ts +52 -0
  1016. package/src/renderers/share/chart.ts +74 -0
  1017. package/src/renderers/share/main.tsx +10 -2
  1018. package/src/renderers/share/styles.css +29 -0
  1019. package/src/renderers/share/view.test.tsx +20 -0
  1020. package/src/renderers/share/view.tsx +24 -15
  1021. package/src/shares/api.test.ts +15 -0
  1022. package/src/shares/live.ts +27 -0
  1023. package/src/shares/pane.ts +3 -0
  1024. package/src/shares/payload.ts +35 -3
  1025. package/src/sources/gloomberb-cloud/history-coverage.test.ts +119 -0
  1026. package/src/sources/gloomberb-cloud/index.test.ts +307 -20
  1027. package/src/sources/gloomberb-cloud/index.ts +176 -62
  1028. package/src/sources/gloomberb-cloud/news.ts +11 -3
  1029. package/src/sources/gloomberb-cloud/normalizers.test.ts +27 -1
  1030. package/src/sources/gloomberb-cloud/normalizers.ts +29 -8
  1031. package/src/sources/gloomberb-cloud/quote-metadata.test.ts +50 -0
  1032. package/src/sources/gloomberb-cloud/valuation-observations.ts +29 -0
  1033. package/src/sources/history-coverage.test.ts +40 -0
  1034. package/src/sources/history-coverage.ts +97 -0
  1035. package/src/sources/listing-history.ts +52 -0
  1036. package/src/sources/listing-target.ts +41 -0
  1037. package/src/sources/provider-router/arca-cache.test.ts +97 -0
  1038. package/src/sources/provider-router/batches.ts +21 -5
  1039. package/src/sources/provider-router/broker-session.test.ts +52 -0
  1040. package/src/sources/provider-router/brokers.ts +1 -0
  1041. package/src/sources/provider-router/cache.test.ts +133 -0
  1042. package/src/sources/provider-router/cache.ts +113 -8
  1043. package/src/sources/provider-router/cached-financials.test.ts +104 -14
  1044. package/src/sources/provider-router/cached-routes.test.ts +212 -0
  1045. package/src/sources/provider-router/cached-routes.ts +223 -0
  1046. package/src/sources/provider-router/connection-health.ts +1 -0
  1047. package/src/sources/provider-router/financial-routes.ts +90 -26
  1048. package/src/sources/provider-router/financials.test.ts +97 -1
  1049. package/src/sources/provider-router/financials.ts +217 -44
  1050. package/src/sources/provider-router/fixtures/quarterly-source-disagreements.json +438 -0
  1051. package/src/sources/provider-router/history-boundary-cache.test.ts +72 -0
  1052. package/src/sources/provider-router/history-gap-cache.test.ts +84 -0
  1053. package/src/sources/provider-router/history-gaps.test.ts +141 -0
  1054. package/src/sources/provider-router/history.test.ts +124 -3
  1055. package/src/sources/provider-router/history.ts +156 -46
  1056. package/src/sources/provider-router/index.test.ts +19 -13
  1057. package/src/sources/provider-router/index.ts +83 -18
  1058. package/src/sources/provider-router/listing-history.test.ts +139 -0
  1059. package/src/sources/provider-router/listing-identity.test.ts +128 -0
  1060. package/src/sources/provider-router/non-company-metadata.test.ts +95 -0
  1061. package/src/sources/provider-router/o-income-basis.test.ts +64 -0
  1062. package/src/sources/provider-router/primary.ts +44 -8
  1063. package/src/sources/provider-router/profile-enrichment.test.ts +171 -0
  1064. package/src/sources/provider-router/quote-completion.test.ts +62 -0
  1065. package/src/sources/provider-router/quote-domain.test.ts +92 -0
  1066. package/src/sources/provider-router/routing.ts +2 -30
  1067. package/src/sources/provider-router/search.ts +2 -11
  1068. package/src/sources/provider-router/shell-history-cache.test.ts +131 -0
  1069. package/src/sources/provider-router/statement-history.test.ts +71 -0
  1070. package/src/sources/provider-router/statement-history.ts +15 -0
  1071. package/src/sources/provider-router/statement-observations.test.ts +126 -0
  1072. package/src/sources/provider-router/streaming.ts +1 -1
  1073. package/src/sources/provider-router/supplemental.ts +2 -389
  1074. package/src/sources/provider-router/valuation-retractions.test.ts +280 -0
  1075. package/src/sources/sec-edgar-shares.fixture.json +188 -0
  1076. package/src/sources/sec-edgar-shares.test.ts +66 -0
  1077. package/src/sources/sec-edgar.test.ts +146 -0
  1078. package/src/sources/sec-edgar.ts +136 -37
  1079. package/src/sources/sec-income-attribution.test.ts +93 -0
  1080. package/src/sources/yahoo-finance/financials.ts +23 -23
  1081. package/src/sources/yahoo-finance/mappers.test.ts +95 -1
  1082. package/src/sources/yahoo-finance/mappers.ts +104 -43
  1083. package/src/sources/yahoo-finance/options.test.ts +13 -0
  1084. package/src/sources/yahoo-finance/options.ts +4 -2
  1085. package/src/sources/yahoo-finance/quote-summary.ts +25 -12
  1086. package/src/sources/yahoo-finance/requests.test.ts +37 -0
  1087. package/src/sources/yahoo-finance/requests.ts +9 -2
  1088. package/src/sources/yahoo-finance/snapshots.test.ts +140 -0
  1089. package/src/sources/yahoo-finance/snapshots.ts +21 -11
  1090. package/src/sources/yahoo-finance/symbols.test.ts +8 -0
  1091. package/src/sources/yahoo-finance/symbols.ts +60 -11
  1092. package/src/sources/yahoo-finance/types.ts +8 -0
  1093. package/src/sources/yahoo-finance/yahoo-chart-interval.ts +18 -0
  1094. package/src/sources/yahoo-finance.test.ts +20 -0
  1095. package/src/sources/yahoo-finance.ts +54 -20
  1096. package/src/state/app/bootstrap.test.ts +124 -0
  1097. package/src/state/app/bootstrap.ts +106 -130
  1098. package/src/state/app/context/index.test.tsx +56 -0
  1099. package/src/state/app/context/index.tsx +101 -31
  1100. package/src/state/app/context/selector.test.tsx +38 -2
  1101. package/src/state/config-save-scheduler.ts +16 -4
  1102. package/src/state/hooks/inline-ticker-failures.test.ts +77 -0
  1103. package/src/state/hooks/inline-ticker-failures.ts +100 -0
  1104. package/src/state/hooks/inline-tickers.test.tsx +47 -11
  1105. package/src/state/hooks/inline-tickers.ts +254 -85
  1106. package/src/state/hooks/quote-streaming.ts +6 -13
  1107. package/src/state/hooks/session-snapshot.ts +9 -5
  1108. package/src/state/persist-scheduler.test.ts +54 -1
  1109. package/src/state/persist-scheduler.ts +36 -3
  1110. package/src/state/session-persistence.test.ts +46 -0
  1111. package/src/sync/core-contributors.test.ts +35 -6
  1112. package/src/sync/core-contributors.ts +30 -27
  1113. package/src/test-support/market-session.ts +12 -0
  1114. package/src/test-support/pane.tsx +52 -0
  1115. package/src/test-support/plugin-runtime.ts +5 -0
  1116. package/src/theme/color-utils.ts +90 -33
  1117. package/src/tickers/instrument-label.ts +10 -0
  1118. package/src/tickers/list.test.ts +1 -0
  1119. package/src/tickers/list.ts +1 -1
  1120. package/src/tickers/metadata.ts +4 -1
  1121. package/src/tickers/open-target.test.ts +86 -0
  1122. package/src/tickers/open-target.ts +48 -9
  1123. package/src/tickers/search/identity.ts +19 -0
  1124. package/src/tickers/search/index.test.ts +263 -8
  1125. package/src/tickers/search/index.ts +164 -29
  1126. package/src/tickers/search/ranking.ts +85 -9
  1127. package/src/tickers/search/types.ts +5 -1
  1128. package/src/tickers/search/upsert.ts +14 -6
  1129. package/src/tickers/search-contract-context.test.tsx +161 -0
  1130. package/src/tickers/search-contract-templates.test.ts +83 -0
  1131. package/src/tickers/selection.ts +21 -0
  1132. package/src/time-series/alignment.ts +11 -3
  1133. package/src/time-series/bond-price-history.test.ts +52 -0
  1134. package/src/time-series/chart-data.test.ts +44 -12
  1135. package/src/time-series/chart-data.ts +36 -8
  1136. package/src/time-series/economic.test.ts +44 -0
  1137. package/src/time-series/economic.ts +42 -0
  1138. package/src/time-series/field-catalog.ts +3 -2
  1139. package/src/time-series/financial-history-request.test.ts +20 -0
  1140. package/src/time-series/financial-period-coverage.test.ts +37 -0
  1141. package/src/time-series/financial-period-coverage.ts +59 -0
  1142. package/src/time-series/financial-period-gaps.test.ts +128 -0
  1143. package/src/time-series/fixtures/q4-reported-common-income.json +394 -0
  1144. package/src/time-series/fixtures/q4-reported-per-share.json +305 -0
  1145. package/src/time-series/forward-valuation.test.ts +131 -0
  1146. package/src/time-series/forward-valuation.ts +247 -0
  1147. package/src/time-series/fundamentals.test.ts +111 -24
  1148. package/src/time-series/fundamentals.ts +260 -131
  1149. package/src/time-series/hooks.ts +7 -3
  1150. package/src/time-series/legacy-contract-live.test.ts +23 -0
  1151. package/src/time-series/live-quotes.test.ts +5 -2
  1152. package/src/time-series/live-quotes.ts +23 -29
  1153. package/src/time-series/market-price-units.test.ts +75 -0
  1154. package/src/time-series/market.ts +55 -15
  1155. package/src/time-series/price-comparison.test.ts +233 -0
  1156. package/src/time-series/price-comparison.ts +133 -0
  1157. package/src/time-series/price-history-integrity-window.test.ts +137 -0
  1158. package/src/time-series/price-history-integrity.test.ts +195 -0
  1159. package/src/time-series/q4-common-income.test.ts +63 -0
  1160. package/src/time-series/q4-per-share.test.ts +144 -0
  1161. package/src/time-series/reporting-currency.test.ts +99 -0
  1162. package/src/time-series/reporting-currency.ts +37 -0
  1163. package/src/time-series/reporting.ts +38 -2
  1164. package/src/time-series/resolve.test.ts +528 -366
  1165. package/src/time-series/resolve.ts +322 -76
  1166. package/src/time-series/sec-eps-research.test.ts +55 -0
  1167. package/src/time-series/session-history-domain.test.ts +160 -0
  1168. package/src/{cli/pane-functions/intraday-shot.ts → time-series/session-history.ts} +96 -42
  1169. package/src/time-series/spec-studies.test.ts +177 -6
  1170. package/src/time-series/studies.ts +173 -38
  1171. package/src/time-series/transforms.test.ts +38 -2
  1172. package/src/time-series/transforms.ts +5 -1
  1173. package/src/time-series/types.ts +30 -0
  1174. package/src/time-series/use-chart-resolution.test.tsx +72 -4
  1175. package/src/time-series/use-chart-resolution.ts +45 -28
  1176. package/src/time-series/valuation-currency.test.ts +127 -0
  1177. package/src/time-series/valuation-currency.ts +46 -0
  1178. package/src/time-series/valuation-denominator.test.ts +240 -0
  1179. package/src/time-series/valuation-live-status.test.ts +63 -0
  1180. package/src/time-series/valuation-price.test.ts +264 -0
  1181. package/src/time-series/valuation-price.ts +68 -0
  1182. package/src/types/broker.ts +2 -1
  1183. package/src/types/config.test.ts +31 -0
  1184. package/src/types/config.ts +49 -10
  1185. package/src/types/data-provider.ts +43 -0
  1186. package/src/types/exchange-rate.ts +13 -0
  1187. package/src/types/financials.ts +164 -2
  1188. package/src/types/headless.ts +23 -0
  1189. package/src/types/instrument.ts +11 -0
  1190. package/src/types/plugin.ts +108 -2
  1191. package/src/types/ticker.ts +10 -2
  1192. package/src/ui/context-menu.test.ts +2 -1
  1193. package/src/ui/context-menu.tsx +3 -3
  1194. package/src/ui/host.tsx +6 -2
  1195. package/src/ui/index.tsx +3 -4
  1196. package/src/updater.test.ts +17 -1
  1197. package/src/updater.ts +4 -2
  1198. package/src/utils/dom-screenshot.test.ts +52 -0
  1199. package/src/utils/dom-screenshot.ts +70 -15
  1200. package/src/utils/exchange-rate-snapshot.test.ts +22 -0
  1201. package/src/utils/exchange-rate-snapshot.ts +62 -0
  1202. package/src/utils/exchanges.test.ts +24 -0
  1203. package/src/utils/exchanges.ts +22 -11
  1204. package/src/utils/financial-statements.test.ts +74 -1
  1205. package/src/utils/financial-statements.ts +119 -14
  1206. package/src/utils/format.test.ts +21 -1
  1207. package/src/utils/format.ts +56 -23
  1208. package/src/utils/fundamentals.ts +15 -0
  1209. package/src/utils/fx-status.test.ts +16 -0
  1210. package/src/utils/fx-status.ts +46 -0
  1211. package/src/utils/http-proxy-response.ts +44 -0
  1212. package/src/utils/http-transport.ts +21 -1
  1213. package/src/utils/income-statement.ts +46 -0
  1214. package/src/utils/instrument-identity.test.ts +26 -0
  1215. package/src/utils/instrument-identity.ts +35 -0
  1216. package/src/utils/latest-financial-period.test.ts +19 -0
  1217. package/src/utils/latest-financial-period.ts +26 -0
  1218. package/src/utils/market-capitalization-consumers.test.ts +59 -0
  1219. package/src/utils/market-capitalization.test.ts +38 -0
  1220. package/src/utils/market-capitalization.ts +58 -0
  1221. package/src/utils/options.test.ts +20 -0
  1222. package/src/utils/options.ts +4 -4
  1223. package/src/utils/perf-marks.ts +26 -0
  1224. package/src/utils/plugin-proxy-hosts.json +16 -0
  1225. package/src/utils/plugin-proxy-hosts.ts +25 -0
  1226. package/src/utils/price-earnings.test.ts +39 -0
  1227. package/src/utils/price-earnings.ts +13 -0
  1228. package/src/utils/price-history-integrity.ts +61 -0
  1229. package/src/utils/price-history.test.ts +41 -3
  1230. package/src/utils/price-history.ts +90 -6
  1231. package/src/utils/reported-money.test.ts +25 -0
  1232. package/src/utils/reported-money.ts +31 -0
  1233. package/src/utils/screenshot-watermark.ts +27 -0
  1234. package/src/utils/sec-eps-basis.test.ts +82 -0
  1235. package/src/utils/sec-eps-basis.ts +152 -0
  1236. package/src/utils/sec.test.ts +12 -10
  1237. package/src/utils/sec.ts +4 -3
  1238. package/src/utils/semver.test.ts +31 -0
  1239. package/src/utils/semver.ts +48 -0
  1240. package/src/utils/sort-values.test.ts +11 -0
  1241. package/src/utils/sort-values.ts +2 -0
  1242. package/src/utils/statement-observations.ts +121 -0
  1243. package/src/cli/commands/automation.test.ts +0 -211
  1244. package/src/components/chart/native/surface/sync.ts +0 -34
  1245. package/src/components/command-bar/panel/body.tsx +0 -301
  1246. package/src/components/onboarding/account-step/chooser-panel.tsx +0 -51
  1247. package/src/plugins/builtin/ai/agent-history.ts +0 -143
  1248. package/src/plugins/builtin/ai/ask-ai-detail-tab.tsx +0 -466
  1249. package/src/plugins/builtin/ai/ask-ai.test.tsx +0 -365
  1250. package/src/plugins/builtin/ai/index.test.ts +0 -302
  1251. package/src/plugins/builtin/ai/index.tsx +0 -440
  1252. package/src/plugins/builtin/ai/pane-settings.test.ts +0 -155
  1253. package/src/plugins/builtin/ai/pane-settings.ts +0 -319
  1254. package/src/plugins/builtin/ai/pi/credential-store.test.ts +0 -80
  1255. package/src/plugins/builtin/ai/pi/credential-store.ts +0 -138
  1256. package/src/plugins/builtin/ai/pi/file-store.ts +0 -138
  1257. package/src/plugins/builtin/ai/pi/host.test.ts +0 -500
  1258. package/src/plugins/builtin/ai/pi/host.ts +0 -565
  1259. package/src/plugins/builtin/ai/pi/index.ts +0 -5
  1260. package/src/plugins/builtin/ai/pi/models-store.test.ts +0 -44
  1261. package/src/plugins/builtin/ai/pi/models-store.ts +0 -141
  1262. package/src/plugins/builtin/ai/pi/providers.ts +0 -68
  1263. package/src/plugins/builtin/ai/pi/runtime.test.ts +0 -240
  1264. package/src/plugins/builtin/ai/pi/runtime.ts +0 -636
  1265. package/src/plugins/builtin/ai/providers.test.ts +0 -68
  1266. package/src/plugins/builtin/ai/providers.ts +0 -191
  1267. package/src/plugins/builtin/ai/runner-selection.test.ts +0 -174
  1268. package/src/plugins/builtin/ai/runner-selection.ts +0 -193
  1269. package/src/plugins/builtin/ai/runner-selector.tsx +0 -153
  1270. package/src/plugins/builtin/ai/runner.test.ts +0 -198
  1271. package/src/plugins/builtin/ai/runner.ts +0 -316
  1272. package/src/plugins/builtin/ai/screener/contract.test.ts +0 -70
  1273. package/src/plugins/builtin/ai/screener/contract.ts +0 -136
  1274. package/src/plugins/builtin/ai/screener/editor-runtime.ts +0 -160
  1275. package/src/plugins/builtin/ai/screener/editor.tsx +0 -131
  1276. package/src/plugins/builtin/ai/screener/footer.ts +0 -104
  1277. package/src/plugins/builtin/ai/screener/keyboard.ts +0 -106
  1278. package/src/plugins/builtin/ai/screener/market-runtime.ts +0 -101
  1279. package/src/plugins/builtin/ai/screener/model.test.ts +0 -24
  1280. package/src/plugins/builtin/ai/screener/model.ts +0 -113
  1281. package/src/plugins/builtin/ai/screener/pane.test.tsx +0 -479
  1282. package/src/plugins/builtin/ai/screener/pane.tsx +0 -438
  1283. package/src/plugins/builtin/ai/screener/results-view.tsx +0 -144
  1284. package/src/plugins/builtin/ai/screener/results.ts +0 -139
  1285. package/src/plugins/builtin/ai/screener/runner.ts +0 -164
  1286. package/src/plugins/builtin/ai/screener/tabs-bar.tsx +0 -65
  1287. package/src/plugins/builtin/ai/settings.ts +0 -81
  1288. package/src/plugins/builtin/ai/ticker-context.ts +0 -65
  1289. package/src/plugins/builtin/ai/use-runtime-providers.ts +0 -28
  1290. package/src/plugins/builtin/ai/workspace/model.test.ts +0 -227
  1291. package/src/plugins/builtin/ai/workspace/model.ts +0 -283
  1292. package/src/plugins/builtin/ai/workspace/pane.test.tsx +0 -197
  1293. package/src/plugins/builtin/ai/workspace/pane.tsx +0 -907
  1294. package/src/plugins/builtin/chat/message/action-chip.tsx +0 -39
  1295. package/src/plugins/builtin/cloud/askg/verify.ts +0 -130
  1296. package/src/plugins/builtin/earnings/data/data.test.ts +0 -90
  1297. package/src/plugins/builtin/earnings/data/data.ts +0 -115
  1298. package/src/plugins/builtin/fear-greed/cache.test.ts +0 -90
  1299. package/src/plugins/builtin/fear-greed/cache.ts +0 -154
  1300. package/src/plugins/builtin/fear-greed/charts.tsx +0 -305
  1301. package/src/plugins/builtin/fear-greed/data.test.ts +0 -72
  1302. package/src/plugins/builtin/fear-greed/data.ts +0 -375
  1303. package/src/plugins/builtin/fear-greed/format.ts +0 -87
  1304. package/src/plugins/builtin/fear-greed/headless.test.ts +0 -53
  1305. package/src/plugins/builtin/fear-greed/headless.ts +0 -84
  1306. package/src/plugins/builtin/fear-greed/index.tsx +0 -43
  1307. package/src/plugins/builtin/fear-greed/pane.tsx +0 -169
  1308. package/src/plugins/builtin/ipo-calendar/cache.ts +0 -101
  1309. package/src/plugins/builtin/ipo-calendar/client.test.ts +0 -31
  1310. package/src/plugins/builtin/ipo-calendar/client.ts +0 -311
  1311. package/src/plugins/builtin/ipo-calendar/headless.test.ts +0 -89
  1312. package/src/plugins/builtin/ipo-calendar/headless.ts +0 -127
  1313. package/src/plugins/builtin/ipo-calendar/index.tsx +0 -68
  1314. package/src/plugins/builtin/ipo-calendar/model.ts +0 -133
  1315. package/src/plugins/builtin/ipo-calendar/pane.tsx +0 -328
  1316. package/src/plugins/builtin/ipo-calendar/types.ts +0 -19
  1317. package/src/plugins/builtin/market-halts/client.ts +0 -114
  1318. package/src/plugins/builtin/market-halts/index.tsx +0 -30
  1319. package/src/plugins/builtin/market-halts/model.test.ts +0 -187
  1320. package/src/plugins/builtin/market-halts/model.ts +0 -291
  1321. package/src/plugins/builtin/market-halts/pane.tsx +0 -256
  1322. package/src/plugins/builtin/market-heatmap/data.test.ts +0 -122
  1323. package/src/plugins/builtin/market-heatmap/data.ts +0 -305
  1324. package/src/plugins/builtin/market-heatmap/index.tsx +0 -400
  1325. package/src/plugins/builtin/market-valuation/model.ts +0 -8
  1326. package/src/plugins/builtin/notes/sync.test.ts +0 -49
  1327. package/src/plugins/builtin/notes/sync.ts +0 -98
  1328. package/src/plugins/builtin/polls/client.ts +0 -57
  1329. package/src/plugins/builtin/polls/hooks.ts +0 -20
  1330. package/src/plugins/builtin/polls/index.tsx +0 -35
  1331. package/src/plugins/builtin/polls/normalize.test.ts +0 -230
  1332. package/src/plugins/builtin/polls/normalize.ts +0 -319
  1333. package/src/plugins/builtin/polls/pane.tsx +0 -722
  1334. package/src/plugins/builtin/polls/types.ts +0 -77
  1335. package/src/plugins/builtin/scanner/waiting.tsx +0 -11
  1336. package/src/plugins/builtin/shared/public-share.ts +0 -23
  1337. package/src/plugins/builtin/tv/channels.ts +0 -27
  1338. package/src/plugins/builtin/tv/index.tsx +0 -40
  1339. package/src/plugins/builtin/tv/pane.tsx +0 -346
  1340. package/src/plugins/builtin/tv/youtube-embed.test.ts +0 -84
  1341. package/src/plugins/builtin/tv/youtube-embed.ts +0 -173
  1342. package/src/plugins/builtin/tv/youtube-stream.ts +0 -125
  1343. package/src/plugins/catalog-manifest.test.ts +0 -58
  1344. package/src/plugins/prediction-markets/backend-plugin.ts +0 -21
  1345. package/src/plugins/prediction-markets/cache.ts +0 -163
  1346. package/src/plugins/prediction-markets/capability.test.ts +0 -281
  1347. package/src/plugins/prediction-markets/capability.ts +0 -171
  1348. package/src/plugins/prediction-markets/categories.ts +0 -213
  1349. package/src/plugins/prediction-markets/chart.tsx +0 -158
  1350. package/src/plugins/prediction-markets/cli.ts +0 -28
  1351. package/src/plugins/prediction-markets/columns.ts +0 -134
  1352. package/src/plugins/prediction-markets/controller/catalog.ts +0 -395
  1353. package/src/plugins/prediction-markets/controller/data.ts +0 -177
  1354. package/src/plugins/prediction-markets/controller/detail.ts +0 -247
  1355. package/src/plugins/prediction-markets/controller/effects.ts +0 -253
  1356. package/src/plugins/prediction-markets/controller/index.ts +0 -368
  1357. package/src/plugins/prediction-markets/controller/keyboard.ts +0 -245
  1358. package/src/plugins/prediction-markets/controller/live-updates.ts +0 -86
  1359. package/src/plugins/prediction-markets/controller/selection.ts +0 -59
  1360. package/src/plugins/prediction-markets/controller/status.ts +0 -104
  1361. package/src/plugins/prediction-markets/detail/book.tsx +0 -144
  1362. package/src/plugins/prediction-markets/detail/outcomes.tsx +0 -101
  1363. package/src/plugins/prediction-markets/detail/overview.tsx +0 -84
  1364. package/src/plugins/prediction-markets/detail/pane.tsx +0 -344
  1365. package/src/plugins/prediction-markets/detail/rules.tsx +0 -31
  1366. package/src/plugins/prediction-markets/detail/shared.tsx +0 -49
  1367. package/src/plugins/prediction-markets/detail/trades.tsx +0 -101
  1368. package/src/plugins/prediction-markets/detail.test.tsx +0 -94
  1369. package/src/plugins/prediction-markets/headless.test.ts +0 -119
  1370. package/src/plugins/prediction-markets/headless.ts +0 -255
  1371. package/src/plugins/prediction-markets/index.tsx +0 -117
  1372. package/src/plugins/prediction-markets/keyboard.ts +0 -65
  1373. package/src/plugins/prediction-markets/launch.test.ts +0 -126
  1374. package/src/plugins/prediction-markets/launch.ts +0 -275
  1375. package/src/plugins/prediction-markets/metrics.ts +0 -328
  1376. package/src/plugins/prediction-markets/navigation.ts +0 -77
  1377. package/src/plugins/prediction-markets/outcome-order.ts +0 -19
  1378. package/src/plugins/prediction-markets/pane.test.tsx +0 -562
  1379. package/src/plugins/prediction-markets/pane.tsx +0 -347
  1380. package/src/plugins/prediction-markets/plugin.test.tsx +0 -645
  1381. package/src/plugins/prediction-markets/rows.ts +0 -229
  1382. package/src/plugins/prediction-markets/services/fetch.ts +0 -121
  1383. package/src/plugins/prediction-markets/services/kalshi/adapter.ts +0 -398
  1384. package/src/plugins/prediction-markets/services/kalshi/normalize.ts +0 -211
  1385. package/src/plugins/prediction-markets/services/kalshi/types.ts +0 -103
  1386. package/src/plugins/prediction-markets/services/polymarket/adapter.ts +0 -177
  1387. package/src/plugins/prediction-markets/services/polymarket/detail.ts +0 -356
  1388. package/src/plugins/prediction-markets/services/polymarket/normalize.ts +0 -239
  1389. package/src/plugins/prediction-markets/services/polymarket/types.ts +0 -66
  1390. package/src/plugins/prediction-markets/services/polymarket/ws.ts +0 -128
  1391. package/src/plugins/prediction-markets/settings.ts +0 -163
  1392. package/src/plugins/prediction-markets/test-helpers.tsx +0 -591
  1393. package/src/plugins/prediction-markets/types.ts +0 -179
  1394. package/src/plugins/registry/context.ts +0 -218
  1395. package/src/renderers/electrobun/bun/desktop/media.ts +0 -17
  1396. package/src/renderers/electrobun/view/ai-host.ts +0 -198
  1397. package/src/renderers/electrobun/view/native-stubs/chart/surface-sync.ts +0 -1
  1398. package/src/renderers/electrobun/view/resource-store.test.ts +0 -44
  1399. package/src/shares/chart-snapshot.test.ts +0 -34
  1400. package/src/shares/chart-snapshot.ts +0 -28
  1401. package/src/sources/provider-router/document-routes.ts +0 -203
  1402. package/src/types/media.ts +0 -19
@@ -1,6 +1,4 @@
1
1
  import { afterEach, beforeEach, describe, expect, jest, test } from "bun:test";
2
- import type { AppNotificationRequest } from "../../../types/plugin";
3
- import { MemoryPluginPersistence as MemoryPersistence } from "../../../test-support/plugin-persistence";
4
2
  import {
5
3
  apiClient,
6
4
  type ChatChannel,
@@ -9,9 +7,30 @@ import {
9
7
  type ChatStateResponse,
10
8
  } from "../../../api-client";
11
9
  import { ApiRequestError } from "../../../api-client/errors";
10
+ import { MemoryPluginPersistence as MemoryPersistence } from "../../../test-support/plugin-persistence";
11
+ import type { AppNotificationRequest } from "../../../types/plugin";
12
12
  import { ChatController } from "./controller";
13
13
  import { SESSION_RETRY_MS } from "./controller/state";
14
14
 
15
+ const testControllers = new Set<ChatController>();
16
+
17
+ function createController(): ChatController {
18
+ const controller = new ChatController();
19
+ testControllers.add(controller);
20
+ return controller;
21
+ }
22
+
23
+ function persistSession(persistence: MemoryPersistence, user: Record<string, unknown> = {}) {
24
+ persistence.setState("session", {
25
+ sessionToken: "token-123",
26
+ user: { id: "u1", username: "vince", ...user },
27
+ }, { schemaVersion: 1 });
28
+ }
29
+
30
+ function chatMessage(input: Pick<ChatMessage, "id" | "content" | "createdAt"> & Partial<ChatMessage>): ChatMessage {
31
+ return { channelId: "everyone", replyToId: null, user: { id: "u1", username: "vince", displayName: "Vince" }, ...input };
32
+ }
33
+
15
34
  const TRANSCRIPT_KIND = "channel-transcript";
16
35
  const TRANSCRIPT_KEY = "everyone";
17
36
  const TRANSCRIPT_SOURCE = "server";
@@ -100,6 +119,8 @@ beforeEach(() => {
100
119
  });
101
120
 
102
121
  afterEach(() => {
122
+ for (const controller of testControllers) controller.dispose();
123
+ testControllers.clear();
103
124
  jest.useRealTimers();
104
125
  apiClient.dispose();
105
126
  apiClient.setSessionToken(null);
@@ -121,20 +142,14 @@ afterEach(() => {
121
142
  describe("ChatController", () => {
122
143
  test("hydrates cached session, draft, and transcript from plugin persistence", () => {
123
144
  const persistence = new MemoryPersistence();
124
- const controller = new ChatController();
125
- const message: ChatMessage = {
145
+ const controller = createController();
146
+ const message: ChatMessage = chatMessage({
126
147
  id: "m1",
127
- channelId: "everyone",
128
148
  content: "hello",
129
- replyToId: null,
130
149
  createdAt: "2026-03-28T00:00:00.000Z",
131
- user: { id: "u1", username: "vince", displayName: "Vince" },
132
- };
150
+ });
133
151
 
134
- persistence.setState("session", {
135
- sessionToken: "token-123",
136
- user: { id: "u1", username: "vince" },
137
- }, { schemaVersion: 1 });
152
+ persistSession(persistence);
138
153
  persistence.setState("channel:everyone", {
139
154
  draft: "cached draft",
140
155
  replyToId: "m1",
@@ -161,7 +176,7 @@ describe("ChatController", () => {
161
176
 
162
177
  test("uses a browser cookie session without exposing its token", async () => {
163
178
  const persistence = new MemoryPersistence();
164
- const controller = new ChatController();
179
+ const controller = createController();
165
180
  const sentMessages: string[] = [];
166
181
 
167
182
  apiClient.setCookieSessionMode(true);
@@ -201,7 +216,7 @@ describe("ChatController", () => {
201
216
  });
202
217
 
203
218
  test("rejects unknown shortcut channels after the server list loads", async () => {
204
- const controller = new ChatController();
219
+ const controller = createController();
205
220
  apiClient.getChannels = async () => SERVER_CHAT_CHANNELS;
206
221
 
207
222
  await expect(controller.resolveRequiredChannelId("help")).resolves.toBe("help");
@@ -212,24 +227,28 @@ describe("ChatController", () => {
212
227
 
213
228
  test("keeps private channels when a public refresh finishes after chat state", async () => {
214
229
  const persistence = new MemoryPersistence();
215
- const controller = new ChatController();
230
+ const controller = createController();
216
231
  const directChannel: ChatChannel = {
217
232
  id: "dm:u2",
218
233
  name: "u2",
219
234
  kind: "direct",
220
235
  created_at: "2026-03-28T00:00:00.000Z",
221
236
  };
237
+ const teamChannel: ChatChannel = {
238
+ id: "team:org-1:trades",
239
+ name: "trades",
240
+ kind: "team",
241
+ teamId: "org-1",
242
+ created_at: "2026-09-14T00:00:00.000Z",
243
+ };
222
244
  let resolvePublicChannels: ((channels: ChatChannel[]) => void) | undefined;
223
245
 
224
- persistence.setState("session", {
225
- sessionToken: "token-123",
226
- user: { id: "u1", username: "vince", emailVerified: true },
227
- }, { schemaVersion: 1 });
246
+ persistSession(persistence, { emailVerified: true });
228
247
  apiClient.getChannels = () => new Promise((resolve) => {
229
248
  resolvePublicChannels = resolve;
230
249
  });
231
250
  apiClient.getChatState = async () => ({
232
- channels: [...SERVER_CHAT_CHANNELS, directChannel],
251
+ channels: [...SERVER_CHAT_CHANNELS, directChannel, teamChannel],
233
252
  onlineCount: 0,
234
253
  channelStates: [],
235
254
  notifications: [],
@@ -239,21 +258,20 @@ describe("ChatController", () => {
239
258
  const publicRefresh = controller.refreshChannels();
240
259
  await controller.refreshChatState();
241
260
  expect(controller.getChannels().map((channel) => channel.id)).toContain(directChannel.id);
261
+ expect(controller.getChannels().map((channel) => channel.id)).toContain(teamChannel.id);
242
262
 
243
263
  resolvePublicChannels!(SERVER_CHAT_CHANNELS);
244
264
  await publicRefresh;
245
265
 
246
266
  expect(controller.getChannels().map((channel) => channel.id)).toContain(directChannel.id);
267
+ expect(controller.getChannels().map((channel) => channel.id)).toContain(teamChannel.id);
247
268
  });
248
269
 
249
270
  test("hydrates a cached verified user into the api client for offline use", async () => {
250
271
  const persistence = new MemoryPersistence();
251
- const controller = new ChatController();
272
+ const controller = createController();
252
273
 
253
- persistence.setState("session", {
254
- sessionToken: "token-123",
255
- user: { id: "u1", username: "vince", emailVerified: true },
256
- }, { schemaVersion: 1 });
274
+ persistSession(persistence, { emailVerified: true });
257
275
 
258
276
  controller.attachPersistence(persistence);
259
277
 
@@ -271,7 +289,7 @@ describe("ChatController", () => {
271
289
 
272
290
  test("does not restore persisted websocket tokens", () => {
273
291
  const persistence = new MemoryPersistence();
274
- const controller = new ChatController();
292
+ const controller = createController();
275
293
 
276
294
  persistence.setState("session", {
277
295
  sessionToken: "token-123",
@@ -292,12 +310,9 @@ describe("ChatController", () => {
292
310
 
293
311
  test("reset clears persisted chat state and session token", () => {
294
312
  const persistence = new MemoryPersistence();
295
- const controller = new ChatController();
313
+ const controller = createController();
296
314
 
297
- persistence.setState("session", {
298
- sessionToken: "token-123",
299
- user: { id: "u1", username: "vince" },
300
- }, { schemaVersion: 1 });
315
+ persistSession(persistence);
301
316
  persistence.setState("channel:everyone", {
302
317
  draft: "cached draft",
303
318
  replyToId: null,
@@ -325,7 +340,7 @@ describe("ChatController", () => {
325
340
 
326
341
  test("defers draft persistence and subscriber sync until the user pauses or leaves", () => {
327
342
  const persistence = new TrackingPersistence();
328
- const controller = new ChatController();
343
+ const controller = createController();
329
344
  const draftSnapshots: string[] = [];
330
345
 
331
346
  controller.attachPersistence(persistence);
@@ -352,7 +367,7 @@ describe("ChatController", () => {
352
367
  });
353
368
 
354
369
  test("pauses verification polling while the app is backgrounded", () => {
355
- const controller = new ChatController();
370
+ const controller = createController();
356
371
 
357
372
  apiClient.setSessionToken("token-123");
358
373
  (controller as any).session.sessionToken = "token-123";
@@ -369,7 +384,7 @@ describe("ChatController", () => {
369
384
  });
370
385
 
371
386
  test("dispose stops verification polling and closes the live connection", () => {
372
- const controller = new ChatController();
387
+ const controller = createController();
373
388
  let closed = false;
374
389
 
375
390
  apiClient.setSessionToken("token-123");
@@ -398,7 +413,7 @@ describe("ChatController", () => {
398
413
 
399
414
  test("runs a quiet safety refresh while the live connection is active", async () => {
400
415
  const persistence = new MemoryPersistence();
401
- const controller = new ChatController();
416
+ const controller = createController();
402
417
  const originalSetInterval = globalThis.setInterval;
403
418
  const originalClearInterval = globalThis.clearInterval;
404
419
  const intervalCallbacks: Array<() => void> = [];
@@ -407,10 +422,7 @@ describe("ChatController", () => {
407
422
  let getMessagesCalls = 0;
408
423
  const loadingSnapshots: boolean[] = [];
409
424
 
410
- persistence.setState("session", {
411
- sessionToken: "token-123",
412
- user: { id: "u1", username: "vince", emailVerified: true },
413
- }, { schemaVersion: 1 });
425
+ persistSession(persistence, { emailVerified: true });
414
426
 
415
427
  (globalThis as any).setInterval = (callback: () => void, timeout: number) => {
416
428
  expect(timeout).toBe(30_000);
@@ -466,7 +478,7 @@ describe("ChatController", () => {
466
478
 
467
479
  test("validates a persisted native session through protected chat state", async () => {
468
480
  const persistence = new MemoryPersistence();
469
- const controller = new ChatController();
481
+ const controller = createController();
470
482
  const directChannel: ChatChannel = {
471
483
  id: "dm:u2",
472
484
  name: "u2",
@@ -474,10 +486,7 @@ describe("ChatController", () => {
474
486
  created_at: "2026-03-28T00:00:00.000Z",
475
487
  };
476
488
 
477
- persistence.setState("session", {
478
- sessionToken: "token-123",
479
- user: { id: "u1", username: "vince", emailVerified: true },
480
- }, { schemaVersion: 1 });
489
+ persistSession(persistence, { emailVerified: true });
481
490
 
482
491
  controller.attachPersistence(persistence);
483
492
  apiClient.getSession = async () => {
@@ -513,7 +522,7 @@ describe("ChatController", () => {
513
522
 
514
523
  test("clears an expired persisted session when protected chat rejects it", async () => {
515
524
  const persistence = new MemoryPersistence();
516
- const controller = new ChatController();
525
+ const controller = createController();
517
526
 
518
527
  persistence.setState("session", {
519
528
  sessionToken: "expired-token",
@@ -543,7 +552,7 @@ describe("ChatController", () => {
543
552
 
544
553
  test("clears an expired persisted session for an unverified user", async () => {
545
554
  const persistence = new MemoryPersistence();
546
- const controller = new ChatController();
555
+ const controller = createController();
547
556
  let profileRequests = 0;
548
557
 
549
558
  persistence.setState("session", {
@@ -572,12 +581,9 @@ describe("ChatController", () => {
572
581
 
573
582
  test("downgrades stale verification state when protected chat rejects it", async () => {
574
583
  const persistence = new MemoryPersistence();
575
- const controller = new ChatController();
584
+ const controller = createController();
576
585
 
577
- persistence.setState("session", {
578
- sessionToken: "token-123",
579
- user: { id: "u1", username: "vince", emailVerified: true },
580
- }, { schemaVersion: 1 });
586
+ persistSession(persistence, { emailVerified: true });
581
587
 
582
588
  controller.attachPersistence(persistence);
583
589
  apiClient.getSession = async () => {
@@ -602,7 +608,7 @@ describe("ChatController", () => {
602
608
 
603
609
  test("does not let a stale validation failure clear a replacement session", async () => {
604
610
  const persistence = new MemoryPersistence();
605
- const controller = new ChatController();
611
+ const controller = createController();
606
612
  let rejectProbe: ((error: Error) => void) | null = null;
607
613
  let markProbeStarted: (() => void) | null = null;
608
614
  const probeStarted = new Promise<void>((resolve) => {
@@ -649,7 +655,7 @@ describe("ChatController", () => {
649
655
 
650
656
  test("does not apply stale chat state after a replacement session", async () => {
651
657
  const persistence = new MemoryPersistence();
652
- const controller = new ChatController();
658
+ const controller = createController();
653
659
  let resolveProbe: ((state: ChatStateResponse) => void) | null = null;
654
660
  let markProbeStarted: (() => void) | null = null;
655
661
  const probeStarted = new Promise<void>((resolve) => {
@@ -701,12 +707,9 @@ describe("ChatController", () => {
701
707
  test("revalidates a persisted session after an offline validation probe", async () => {
702
708
  jest.useFakeTimers();
703
709
  const persistence = new MemoryPersistence();
704
- const controller = new ChatController();
710
+ const controller = createController();
705
711
 
706
- persistence.setState("session", {
707
- sessionToken: "token-123",
708
- user: { id: "u1", username: "vince", emailVerified: true },
709
- }, { schemaVersion: 1 });
712
+ persistSession(persistence, { emailVerified: true });
710
713
 
711
714
  controller.attachPersistence(persistence);
712
715
  apiClient.getSession = async () => {
@@ -739,7 +742,7 @@ describe("ChatController", () => {
739
742
 
740
743
  test("signs out when get-session returns no user and no token is stored", async () => {
741
744
  const persistence = new MemoryPersistence();
742
- const controller = new ChatController();
745
+ const controller = createController();
743
746
 
744
747
  persistence.setState("session", {
745
748
  sessionToken: null,
@@ -758,12 +761,9 @@ describe("ChatController", () => {
758
761
 
759
762
  test("keeps the cached session when session refresh fails transiently", async () => {
760
763
  const persistence = new MemoryPersistence();
761
- const controller = new ChatController();
764
+ const controller = createController();
762
765
 
763
- persistence.setState("session", {
764
- sessionToken: "token-123",
765
- user: { id: "u1", username: "vince", emailVerified: true },
766
- }, { schemaVersion: 1 });
766
+ persistSession(persistence, { emailVerified: true });
767
767
 
768
768
  controller.attachPersistence(persistence);
769
769
  apiClient.getSession = async () => {
@@ -790,15 +790,12 @@ describe("ChatController", () => {
790
790
 
791
791
  test("refreshes the public transcript without requiring a session", async () => {
792
792
  const persistence = new MemoryPersistence();
793
- const controller = new ChatController();
794
- const message: ChatMessage = {
793
+ const controller = createController();
794
+ const message: ChatMessage = chatMessage({
795
795
  id: "m1",
796
- channelId: "everyone",
797
796
  content: "hello from the lobby",
798
- replyToId: null,
799
797
  createdAt: "2026-03-28T00:00:00.000Z",
800
- user: { id: "u1", username: "vince", displayName: "Vince" },
801
- };
798
+ });
802
799
 
803
800
  controller.attachPersistence(persistence);
804
801
  apiClient.getMessages = async () => [message];
@@ -816,23 +813,19 @@ describe("ChatController", () => {
816
813
 
817
814
  test("keeps per-channel drafts and transcripts isolated", () => {
818
815
  const persistence = new MemoryPersistence();
819
- const controller = new ChatController();
820
- const everyoneMessage: ChatMessage = {
816
+ const controller = createController();
817
+ const everyoneMessage: ChatMessage = chatMessage({
821
818
  id: "m1",
822
- channelId: "everyone",
823
819
  content: "general",
824
- replyToId: null,
825
820
  createdAt: "2026-03-28T00:00:00.000Z",
826
- user: { id: "u1", username: "vince", displayName: "Vince" },
827
- };
828
- const optionsMessage: ChatMessage = {
821
+ });
822
+ const optionsMessage: ChatMessage = chatMessage({
829
823
  id: "m2",
830
824
  channelId: "options",
831
825
  content: "options note",
832
- replyToId: null,
833
826
  createdAt: "2026-03-28T00:01:00.000Z",
834
827
  user: { id: "u2", username: "bob", displayName: "Bob" },
835
- };
828
+ });
836
829
 
837
830
  persistence.setState("channel:everyone", {
838
831
  draft: "general draft",
@@ -868,23 +861,18 @@ describe("ChatController", () => {
868
861
 
869
862
  test("stores the latest message id as the incremental cursor", async () => {
870
863
  const persistence = new MemoryPersistence();
871
- const controller = new ChatController();
872
- const initial: ChatMessage = {
864
+ const controller = createController();
865
+ const initial: ChatMessage = chatMessage({
873
866
  id: "m1",
874
- channelId: "everyone",
875
867
  content: "hello",
876
- replyToId: null,
877
868
  createdAt: "2026-03-28T00:00:00.000Z",
878
- user: { id: "u1", username: "vince", displayName: "Vince" },
879
- };
880
- const next: ChatMessage = {
869
+ });
870
+ const next: ChatMessage = chatMessage({
881
871
  id: "m2",
882
- channelId: "everyone",
883
872
  content: "new message",
884
- replyToId: null,
885
873
  createdAt: "2026-03-28T00:01:00.000Z",
886
874
  user: { id: "u2", username: "bob", displayName: "Bob" },
887
- };
875
+ });
888
876
 
889
877
  persistence.setState("channel:everyone", {
890
878
  draft: "",
@@ -924,31 +912,24 @@ describe("ChatController", () => {
924
912
 
925
913
  test("recovers a message the cursor already moved past", async () => {
926
914
  const persistence = new MemoryPersistence();
927
- const controller = new ChatController();
928
- const asked: ChatMessage = {
915
+ const controller = createController();
916
+ const asked: ChatMessage = chatMessage({
929
917
  id: "m1",
930
- channelId: "everyone",
931
918
  content: "why is the chart glitching",
932
- replyToId: null,
933
919
  createdAt: "2026-03-28T00:00:00.000Z",
934
- user: { id: "u1", username: "vince", displayName: "Vince" },
935
- };
936
- const missed: ChatMessage = {
920
+ });
921
+ const missed: ChatMessage = chatMessage({
937
922
  id: "m2",
938
- channelId: "everyone",
939
923
  content: "charts open with GP",
940
924
  replyToId: "m1",
941
925
  createdAt: "2026-03-28T00:01:00.000Z",
942
926
  user: { id: "u2", username: "gloombot", displayName: "Gloombot" },
943
- };
944
- const acknowledged: ChatMessage = {
927
+ });
928
+ const acknowledged: ChatMessage = chatMessage({
945
929
  id: "m3",
946
- channelId: "everyone",
947
930
  content: "got it",
948
- replyToId: null,
949
931
  createdAt: "2026-03-28T00:02:00.000Z",
950
- user: { id: "u1", username: "vince", displayName: "Vince" },
951
- };
932
+ });
952
933
 
953
934
  // The cursor already sits on m3, so an incremental fetch can never ask for
954
935
  // m2 again even though the server still has it.
@@ -979,21 +960,16 @@ describe("ChatController", () => {
979
960
 
980
961
  test("hydrates missing transcript cache without marking history unread", async () => {
981
962
  const persistence = new MemoryPersistence();
982
- const controller = new ChatController();
963
+ const controller = createController();
983
964
  const notifications: AppNotificationRequest[] = [];
984
- const history: ChatMessage = {
965
+ const history: ChatMessage = chatMessage({
985
966
  id: "m1",
986
- channelId: "everyone",
987
967
  content: "already seen",
988
- replyToId: null,
989
968
  createdAt: "2026-03-28T00:00:00.000Z",
990
969
  user: { id: "u2", username: "bob", displayName: "Bob" },
991
- };
970
+ });
992
971
 
993
- persistence.setState("session", {
994
- sessionToken: "token-123",
995
- user: { id: "u1", username: "vince", emailVerified: true },
996
- }, { schemaVersion: 1 });
972
+ persistSession(persistence, { emailVerified: true });
997
973
  persistence.setState("channel:everyone", {
998
974
  draft: "",
999
975
  replyToId: null,
@@ -1027,23 +1003,18 @@ describe("ChatController", () => {
1027
1003
 
1028
1004
  test("backfills from cached transcript when persisted cursor is ahead of the cache", async () => {
1029
1005
  const persistence = new MemoryPersistence();
1030
- const controller = new ChatController();
1031
- const cached: ChatMessage = {
1006
+ const controller = createController();
1007
+ const cached: ChatMessage = chatMessage({
1032
1008
  id: "m1",
1033
- channelId: "everyone",
1034
1009
  content: "cached",
1035
- replyToId: null,
1036
1010
  createdAt: "2026-03-28T00:00:00.000Z",
1037
- user: { id: "u1", username: "vince", displayName: "Vince" },
1038
- };
1039
- const fresh: ChatMessage = {
1011
+ });
1012
+ const fresh: ChatMessage = chatMessage({
1040
1013
  id: "m2",
1041
- channelId: "everyone",
1042
1014
  content: "fresh",
1043
- replyToId: null,
1044
1015
  createdAt: "2026-03-28T00:01:00.000Z",
1045
1016
  user: { id: "u2", username: "bob", displayName: "Bob" },
1046
- };
1017
+ });
1047
1018
 
1048
1019
  persistence.setState("channel:everyone", {
1049
1020
  draft: "",
@@ -1083,29 +1054,22 @@ describe("ChatController", () => {
1083
1054
 
1084
1055
  test("shows a pending message immediately and replaces it when the send succeeds", async () => {
1085
1056
  const persistence = new MemoryPersistence();
1086
- const controller = new ChatController();
1087
- const replyTarget: ChatMessage = {
1057
+ const controller = createController();
1058
+ const replyTarget: ChatMessage = chatMessage({
1088
1059
  id: "m1",
1089
- channelId: "everyone",
1090
1060
  content: "first",
1091
- replyToId: null,
1092
1061
  createdAt: "2026-03-28T00:00:00.000Z",
1093
1062
  user: { id: "u2", username: "bob", displayName: "Bob" },
1094
- };
1095
- const sentMessage: ChatMessage = {
1063
+ });
1064
+ const sentMessage: ChatMessage = chatMessage({
1096
1065
  id: "m2",
1097
- channelId: "everyone",
1098
1066
  content: "hello",
1099
1067
  replyToId: "m1",
1100
1068
  createdAt: "2026-03-28T00:01:00.000Z",
1101
- user: { id: "u1", username: "vince", displayName: "Vince" },
1102
1069
  replyTo: { content: "first", user: { username: "bob" } },
1103
- };
1070
+ });
1104
1071
 
1105
- persistence.setState("session", {
1106
- sessionToken: "token-123",
1107
- user: { id: "u1", username: "vince", emailVerified: true },
1108
- }, { schemaVersion: 1 });
1072
+ persistSession(persistence, { emailVerified: true });
1109
1073
  persistence.setState("channel:everyone", {
1110
1074
  draft: "hello",
1111
1075
  replyToId: "m1",
@@ -1154,13 +1118,10 @@ describe("ChatController", () => {
1154
1118
 
1155
1119
  test("sends one idempotency key while the same message is pending", () => {
1156
1120
  const persistence = new MemoryPersistence();
1157
- const controller = new ChatController();
1121
+ const controller = createController();
1158
1122
  const clientMessageIds: Array<string | undefined> = [];
1159
1123
 
1160
- persistence.setState("session", {
1161
- sessionToken: "token-123",
1162
- user: { id: "u1", username: "vince", emailVerified: true },
1163
- }, { schemaVersion: 1 });
1124
+ persistSession(persistence, { emailVerified: true });
1164
1125
 
1165
1126
  controller.attachPersistence(persistence);
1166
1127
  apiClient.getMessages = async () => [];
@@ -1188,20 +1149,14 @@ describe("ChatController", () => {
1188
1149
 
1189
1150
  test("edits the latest message from the current user", async () => {
1190
1151
  const persistence = new MemoryPersistence();
1191
- const controller = new ChatController();
1192
- const original: ChatMessage = {
1152
+ const controller = createController();
1153
+ const original: ChatMessage = chatMessage({
1193
1154
  id: "m1",
1194
- channelId: "everyone",
1195
1155
  content: "helo",
1196
- replyToId: null,
1197
1156
  createdAt: recentChatTimestamp(),
1198
- user: { id: "u1", username: "vince", displayName: "Vince" },
1199
- };
1157
+ });
1200
1158
 
1201
- persistence.setState("session", {
1202
- sessionToken: "token-123",
1203
- user: { id: "u1", username: "vince", emailVerified: true },
1204
- }, { schemaVersion: 1 });
1159
+ persistSession(persistence, { emailVerified: true });
1205
1160
  persistence.setResource(TRANSCRIPT_KIND, TRANSCRIPT_KEY, {
1206
1161
  messages: [original],
1207
1162
  }, {
@@ -1230,21 +1185,15 @@ describe("ChatController", () => {
1230
1185
 
1231
1186
  test("refuses to edit after the edit window expires", async () => {
1232
1187
  const persistence = new MemoryPersistence();
1233
- const controller = new ChatController();
1188
+ const controller = createController();
1234
1189
  const notifications: AppNotificationRequest[] = [];
1235
- const original: ChatMessage = {
1190
+ const original: ChatMessage = chatMessage({
1236
1191
  id: "m1",
1237
- channelId: "everyone",
1238
1192
  content: "old typo",
1239
- replyToId: null,
1240
1193
  createdAt: recentChatTimestamp(16 * 60_000),
1241
- user: { id: "u1", username: "vince", displayName: "Vince" },
1242
- };
1194
+ });
1243
1195
 
1244
- persistence.setState("session", {
1245
- sessionToken: "token-123",
1246
- user: { id: "u1", username: "vince", emailVerified: true },
1247
- }, { schemaVersion: 1 });
1196
+ persistSession(persistence, { emailVerified: true });
1248
1197
  persistence.setResource(TRANSCRIPT_KIND, TRANSCRIPT_KEY, {
1249
1198
  messages: [original],
1250
1199
  }, {
@@ -1266,31 +1215,22 @@ describe("ChatController", () => {
1266
1215
 
1267
1216
  test("refuses to edit an older message from the current user", async () => {
1268
1217
  const persistence = new MemoryPersistence();
1269
- const controller = new ChatController();
1218
+ const controller = createController();
1270
1219
  const notifications: AppNotificationRequest[] = [];
1271
1220
  const messages: ChatMessage[] = [
1272
- {
1221
+ chatMessage({
1273
1222
  id: "m1",
1274
- channelId: "everyone",
1275
1223
  content: "older",
1276
- replyToId: null,
1277
1224
  createdAt: "2026-03-28T00:00:00.000Z",
1278
- user: { id: "u1", username: "vince", displayName: "Vince" },
1279
- },
1280
- {
1225
+ }),
1226
+ chatMessage({
1281
1227
  id: "m2",
1282
- channelId: "everyone",
1283
1228
  content: "newer",
1284
- replyToId: null,
1285
1229
  createdAt: "2026-03-28T00:01:00.000Z",
1286
- user: { id: "u1", username: "vince", displayName: "Vince" },
1287
- },
1230
+ }),
1288
1231
  ];
1289
1232
 
1290
- persistence.setState("session", {
1291
- sessionToken: "token-123",
1292
- user: { id: "u1", username: "vince", emailVerified: true },
1293
- }, { schemaVersion: 1 });
1233
+ persistSession(persistence, { emailVerified: true });
1294
1234
  persistence.setResource(TRANSCRIPT_KIND, TRANSCRIPT_KEY, {
1295
1235
  messages,
1296
1236
  }, {
@@ -1312,13 +1252,10 @@ describe("ChatController", () => {
1312
1252
 
1313
1253
  test("marks a pending message as failed when sending errors", async () => {
1314
1254
  const persistence = new MemoryPersistence();
1315
- const controller = new ChatController();
1255
+ const controller = createController();
1316
1256
  const notifications: AppNotificationRequest[] = [];
1317
1257
 
1318
- persistence.setState("session", {
1319
- sessionToken: "token-123",
1320
- user: { id: "u1", username: "vince", emailVerified: true },
1321
- }, { schemaVersion: 1 });
1258
+ persistSession(persistence, { emailVerified: true });
1322
1259
 
1323
1260
  controller.setNotifier((notification) => {
1324
1261
  notifications.push(notification);
@@ -1347,21 +1284,16 @@ describe("ChatController", () => {
1347
1284
 
1348
1285
  test("tracks unread mentions from fetched messages without issuing local notifications", () => {
1349
1286
  const persistence = new MemoryPersistence();
1350
- const controller = new ChatController();
1287
+ const controller = createController();
1351
1288
  const notifications: AppNotificationRequest[] = [];
1352
- const message: ChatMessage = {
1289
+ const message: ChatMessage = chatMessage({
1353
1290
  id: "m1",
1354
- channelId: "everyone",
1355
1291
  content: "hey @Vince can you take a look?",
1356
- replyToId: null,
1357
1292
  createdAt: "2026-03-28T00:00:00.000Z",
1358
1293
  user: { id: "u2", username: "bob", displayName: "Bob" },
1359
- };
1294
+ });
1360
1295
 
1361
- persistence.setState("session", {
1362
- sessionToken: "token-123",
1363
- user: { id: "u1", username: "vince", emailVerified: true },
1364
- }, { schemaVersion: 1 });
1296
+ persistSession(persistence, { emailVerified: true });
1365
1297
 
1366
1298
  controller.setNotifier((notification) => {
1367
1299
  notifications.push(notification);
@@ -1380,14 +1312,11 @@ describe("ChatController", () => {
1380
1312
 
1381
1313
  test("delivers background notifications while the focused chat stays unread", async () => {
1382
1314
  const persistence = new MemoryPersistence();
1383
- const controller = new ChatController();
1315
+ const controller = createController();
1384
1316
  const notifications: AppNotificationRequest[] = [];
1385
1317
  const deliveredIds: string[][] = [];
1386
1318
 
1387
- persistence.setState("session", {
1388
- sessionToken: "token-123",
1389
- user: { id: "u1", username: "vince", emailVerified: true },
1390
- }, { schemaVersion: 1 });
1319
+ persistSession(persistence, { emailVerified: true });
1391
1320
 
1392
1321
  controller.setNotifier((notification) => {
1393
1322
  notifications.push(notification);
@@ -1421,15 +1350,12 @@ describe("ChatController", () => {
1421
1350
 
1422
1351
  test("keeps undeliverable background notifications pending for email fallback", () => {
1423
1352
  const persistence = new MemoryPersistence();
1424
- const controller = new ChatController();
1353
+ const controller = createController();
1425
1354
  const deliveredIds: string[][] = [];
1426
1355
  let desktopAvailable = false;
1427
1356
  let presentationCount = 0;
1428
1357
 
1429
- persistence.setState("session", {
1430
- sessionToken: "token-123",
1431
- user: { id: "u1", username: "vince", emailVerified: true },
1432
- }, { schemaVersion: 1 });
1358
+ persistSession(persistence, { emailVerified: true });
1433
1359
  controller.setNotifier(() => {
1434
1360
  presentationCount += 1;
1435
1361
  return { toastVisible: false, desktopRequested: desktopAvailable };
@@ -1456,21 +1382,16 @@ describe("ChatController", () => {
1456
1382
 
1457
1383
  test("marks mentions viewed when a chat view opens", () => {
1458
1384
  const persistence = new MemoryPersistence();
1459
- const controller = new ChatController();
1385
+ const controller = createController();
1460
1386
  const notifications: AppNotificationRequest[] = [];
1461
- const message: ChatMessage = {
1387
+ const message: ChatMessage = chatMessage({
1462
1388
  id: "m1",
1463
- channelId: "everyone",
1464
1389
  content: "hey @vince",
1465
- replyToId: null,
1466
1390
  createdAt: "2026-03-28T00:00:00.000Z",
1467
1391
  user: { id: "u2", username: "bob", displayName: "Bob" },
1468
- };
1392
+ });
1469
1393
 
1470
- persistence.setState("session", {
1471
- sessionToken: "token-123",
1472
- user: { id: "u1", username: "vince", emailVerified: true },
1473
- }, { schemaVersion: 1 });
1394
+ persistSession(persistence, { emailVerified: true });
1474
1395
 
1475
1396
  controller.setNotifier((notification) => {
1476
1397
  notifications.push(notification);
@@ -1493,14 +1414,11 @@ describe("ChatController", () => {
1493
1414
 
1494
1415
  test("keeps focused foreground notifications read without presenting an alert", () => {
1495
1416
  const persistence = new MemoryPersistence();
1496
- const controller = new ChatController();
1417
+ const controller = createController();
1497
1418
  const notifications: AppNotificationRequest[] = [];
1498
1419
  const deliveredIds: string[][] = [];
1499
1420
 
1500
- persistence.setState("session", {
1501
- sessionToken: "token-123",
1502
- user: { id: "u1", username: "vince", emailVerified: true },
1503
- }, { schemaVersion: 1 });
1421
+ persistSession(persistence, { emailVerified: true });
1504
1422
 
1505
1423
  controller.setNotifier((notification) => {
1506
1424
  notifications.push(notification);
@@ -1526,14 +1444,11 @@ describe("ChatController", () => {
1526
1444
 
1527
1445
  test("keeps an unfocused foreground chat unread while presenting an in-app alert", () => {
1528
1446
  const persistence = new MemoryPersistence();
1529
- const controller = new ChatController();
1447
+ const controller = createController();
1530
1448
  const notifications: AppNotificationRequest[] = [];
1531
1449
  const deliveredIds: string[][] = [];
1532
1450
 
1533
- persistence.setState("session", {
1534
- sessionToken: "token-123",
1535
- user: { id: "u1", username: "vince", emailVerified: true },
1536
- }, { schemaVersion: 1 });
1451
+ persistSession(persistence, { emailVerified: true });
1537
1452
  controller.setNotifier((notification) => {
1538
1453
  notifications.push(notification);
1539
1454
  return { toastVisible: true, desktopRequested: false };
@@ -1559,14 +1474,11 @@ describe("ChatController", () => {
1559
1474
 
1560
1475
  test("loads server chat state, pending reply notifications, and acks delivery", async () => {
1561
1476
  const persistence = new MemoryPersistence();
1562
- const controller = new ChatController();
1477
+ const controller = createController();
1563
1478
  const notifications: AppNotificationRequest[] = [];
1564
1479
  const deliveredIds: string[][] = [];
1565
1480
 
1566
- persistence.setState("session", {
1567
- sessionToken: "token-123",
1568
- user: { id: "u1", username: "vince", emailVerified: true },
1569
- }, { schemaVersion: 1 });
1481
+ persistSession(persistence, { emailVerified: true });
1570
1482
  apiClient.getSession = async () => ({
1571
1483
  id: "u1",
1572
1484
  name: "Vince",
@@ -1592,7 +1504,7 @@ describe("ChatController", () => {
1592
1504
  channelId: "options",
1593
1505
  messageId: "m2",
1594
1506
  createdAt: "2026-03-28T00:02:00.000Z",
1595
- message: {
1507
+ message: chatMessage({
1596
1508
  id: "m2",
1597
1509
  channelId: "options",
1598
1510
  content: "answering you",
@@ -1600,7 +1512,7 @@ describe("ChatController", () => {
1600
1512
  createdAt: "2026-03-28T00:02:00.000Z",
1601
1513
  user: { id: "u2", username: "bob", displayName: "Bob" },
1602
1514
  replyTo: { content: "question", user: { id: "u1", username: "vince" } },
1603
- },
1515
+ }),
1604
1516
  }],
1605
1517
  });
1606
1518
  apiClient.markChatNotificationsDelivered = async (ids) => {
@@ -1638,13 +1550,10 @@ describe("ChatController", () => {
1638
1550
 
1639
1551
  test("toggles channel notifications optimistically and keeps the channel connected", async () => {
1640
1552
  const persistence = new MemoryPersistence();
1641
- const controller = new ChatController();
1553
+ const controller = createController();
1642
1554
  const connectedChannels: string[] = [];
1643
1555
 
1644
- persistence.setState("session", {
1645
- sessionToken: "token-123",
1646
- user: { id: "u1", username: "vince", emailVerified: true },
1647
- }, { schemaVersion: 1 });
1556
+ persistSession(persistence, { emailVerified: true });
1648
1557
  apiClient.updateChatChannelState = async (channelId, body) => ({
1649
1558
  channelId,
1650
1559
  notificationsEnabled: body.notificationsEnabled === true,
@@ -1673,7 +1582,7 @@ describe("ChatController", () => {
1673
1582
 
1674
1583
  test("dedupes reply notifications by message id", () => {
1675
1584
  const persistence = new MemoryPersistence();
1676
- const controller = new ChatController();
1585
+ const controller = createController();
1677
1586
  const notifications: AppNotificationRequest[] = [];
1678
1587
  const notification: ChatNotification = {
1679
1588
  id: "n1",
@@ -1681,21 +1590,17 @@ describe("ChatController", () => {
1681
1590
  channelId: "everyone",
1682
1591
  messageId: "m2",
1683
1592
  createdAt: "2026-03-28T00:02:00.000Z",
1684
- message: {
1593
+ message: chatMessage({
1685
1594
  id: "m2",
1686
- channelId: "everyone",
1687
1595
  content: "same reply",
1688
1596
  replyToId: "m1",
1689
1597
  createdAt: "2026-03-28T00:02:00.000Z",
1690
1598
  user: { id: "u2", username: "bob", displayName: "Bob" },
1691
1599
  replyTo: { content: "question", user: { id: "u1", username: "vince" } },
1692
- },
1600
+ }),
1693
1601
  };
1694
1602
 
1695
- persistence.setState("session", {
1696
- sessionToken: "token-123",
1697
- user: { id: "u1", username: "vince", emailVerified: true },
1698
- }, { schemaVersion: 1 });
1603
+ persistSession(persistence, { emailVerified: true });
1699
1604
  controller.setNotifier((entry) => {
1700
1605
  notifications.push(entry);
1701
1606
  return { toastVisible: true, desktopRequested: false };
@@ -1710,22 +1615,18 @@ describe("ChatController", () => {
1710
1615
 
1711
1616
  test("opens a server-issued channel notification at its exact message", () => {
1712
1617
  const persistence = new MemoryPersistence();
1713
- const controller = new ChatController();
1618
+ const controller = createController();
1714
1619
  const notifications: AppNotificationRequest[] = [];
1715
1620
  const openedMessages: string[] = [];
1716
- const message: ChatMessage = {
1621
+ const message: ChatMessage = chatMessage({
1717
1622
  id: "m1",
1718
1623
  channelId: "options",
1719
1624
  content: "new option flow",
1720
- replyToId: null,
1721
1625
  createdAt: "2026-03-28T00:00:00.000Z",
1722
1626
  user: { id: "u2", username: "bob", displayName: "Bob" },
1723
- };
1627
+ });
1724
1628
 
1725
- persistence.setState("session", {
1726
- sessionToken: "token-123",
1727
- user: { id: "u1", username: "vince", emailVerified: true },
1728
- }, { schemaVersion: 1 });
1629
+ persistSession(persistence, { emailVerified: true });
1729
1630
  controller.setNotifier((entry) => {
1730
1631
  notifications.push(entry);
1731
1632
  }, (channelId, messageId) => {
@@ -1755,7 +1656,7 @@ describe("ChatController", () => {
1755
1656
 
1756
1657
  test("uses direct channel labels in server-issued notification titles", async () => {
1757
1658
  const persistence = new MemoryPersistence();
1758
- const controller = new ChatController();
1659
+ const controller = createController();
1759
1660
  const notifications: AppNotificationRequest[] = [];
1760
1661
  const directChannel: ChatChannel = {
1761
1662
  id: "dm:u2",
@@ -1764,14 +1665,13 @@ describe("ChatController", () => {
1764
1665
  created_at: "2026-03-28T00:00:00.000Z",
1765
1666
  dmUser: { id: "u2", username: "bob", displayName: "Bob" },
1766
1667
  };
1767
- const message: ChatMessage = {
1668
+ const message: ChatMessage = chatMessage({
1768
1669
  id: "m1",
1769
1670
  channelId: directChannel.id,
1770
1671
  content: "ping",
1771
- replyToId: null,
1772
1672
  createdAt: "2026-03-28T00:00:00.000Z",
1773
1673
  user: { id: "u2", username: "bob", displayName: "Bob" },
1774
- };
1674
+ });
1775
1675
 
1776
1676
  apiClient.getChatState = async () => ({
1777
1677
  channels: [...SERVER_CHAT_CHANNELS, directChannel],
@@ -1784,10 +1684,7 @@ describe("ChatController", () => {
1784
1684
  })),
1785
1685
  notifications: [],
1786
1686
  });
1787
- persistence.setState("session", {
1788
- sessionToken: "token-123",
1789
- user: { id: "u1", username: "vince", emailVerified: true },
1790
- }, { schemaVersion: 1 });
1687
+ persistSession(persistence, { emailVerified: true });
1791
1688
  controller.setNotifier((entry) => {
1792
1689
  notifications.push(entry);
1793
1690
  });
@@ -1813,20 +1710,16 @@ describe("ChatController", () => {
1813
1710
 
1814
1711
  test("tracks unread channel messages and clears them when the channel opens", () => {
1815
1712
  const persistence = new MemoryPersistence();
1816
- const controller = new ChatController();
1817
- const message: ChatMessage = {
1713
+ const controller = createController();
1714
+ const message: ChatMessage = chatMessage({
1818
1715
  id: "m1",
1819
1716
  channelId: "options",
1820
1717
  content: "new option flow",
1821
- replyToId: null,
1822
1718
  createdAt: "2026-03-28T00:00:00.000Z",
1823
1719
  user: { id: "u2", username: "bob", displayName: "Bob" },
1824
- };
1720
+ });
1825
1721
 
1826
- persistence.setState("session", {
1827
- sessionToken: "token-123",
1828
- user: { id: "u1", username: "vince", emailVerified: true },
1829
- }, { schemaVersion: 1 });
1722
+ persistSession(persistence, { emailVerified: true });
1830
1723
  controller.attachPersistence(persistence);
1831
1724
 
1832
1725
  (controller as any).mergeMessages("options", [message]);
@@ -1845,9 +1738,9 @@ describe("ChatController", () => {
1845
1738
 
1846
1739
  test("server reply notifications fire even when channel notifications are disabled", () => {
1847
1740
  const persistence = new MemoryPersistence();
1848
- const controller = new ChatController();
1741
+ const controller = createController();
1849
1742
  const notifications: AppNotificationRequest[] = [];
1850
- const message: ChatMessage = {
1743
+ const message: ChatMessage = chatMessage({
1851
1744
  id: "m2",
1852
1745
  channelId: "options",
1853
1746
  content: "reply without channel notify",
@@ -1855,12 +1748,9 @@ describe("ChatController", () => {
1855
1748
  createdAt: "2026-03-28T00:00:00.000Z",
1856
1749
  user: { id: "u2", username: "bob", displayName: "Bob" },
1857
1750
  replyTo: { content: "question", user: { id: "u1", username: "vince" } },
1858
- };
1751
+ });
1859
1752
 
1860
- persistence.setState("session", {
1861
- sessionToken: "token-123",
1862
- user: { id: "u1", username: "vince", emailVerified: true },
1863
- }, { schemaVersion: 1 });
1753
+ persistSession(persistence, { emailVerified: true });
1864
1754
  controller.setNotifier((notification) => {
1865
1755
  notifications.push(notification);
1866
1756
  });
@@ -1885,25 +1775,20 @@ describe("ChatController", () => {
1885
1775
 
1886
1776
  test("recovers from a legacy timestamp cursor by falling back to a full transcript fetch", async () => {
1887
1777
  const persistence = new MemoryPersistence();
1888
- const controller = new ChatController();
1889
- const cached: ChatMessage = {
1778
+ const controller = createController();
1779
+ const cached: ChatMessage = chatMessage({
1890
1780
  id: "m1",
1891
- channelId: "everyone",
1892
1781
  content: "cached",
1893
- replyToId: null,
1894
1782
  createdAt: "2026-03-28T00:00:00.000Z",
1895
- user: { id: "u1", username: "vince", displayName: "Vince" },
1896
- };
1783
+ });
1897
1784
  const fullTranscript: ChatMessage[] = [
1898
1785
  cached,
1899
- {
1786
+ chatMessage({
1900
1787
  id: "m2",
1901
- channelId: "everyone",
1902
1788
  content: "fresh",
1903
- replyToId: null,
1904
1789
  createdAt: "2026-03-28T00:01:00.000Z",
1905
1790
  user: { id: "u2", username: "bob", displayName: "Bob" },
1906
- },
1791
+ }),
1907
1792
  ];
1908
1793
 
1909
1794
  persistence.setState("channel:everyone", {
@@ -1942,42 +1827,34 @@ describe("ChatController", () => {
1942
1827
 
1943
1828
  test("loads older messages before the oldest cached message without moving the latest cursor", async () => {
1944
1829
  const persistence = new MemoryPersistence();
1945
- const controller = new ChatController();
1830
+ const controller = createController();
1946
1831
  const cached: ChatMessage[] = [
1947
- {
1832
+ chatMessage({
1948
1833
  id: "m3",
1949
- channelId: "everyone",
1950
1834
  content: "cached older",
1951
- replyToId: null,
1952
1835
  createdAt: "2026-03-28T00:03:00.000Z",
1953
1836
  user: { id: "u3", username: "cara", displayName: "Cara" },
1954
- },
1955
- {
1837
+ }),
1838
+ chatMessage({
1956
1839
  id: "m4",
1957
- channelId: "everyone",
1958
1840
  content: "cached newer",
1959
- replyToId: null,
1960
1841
  createdAt: "2026-03-28T00:04:00.000Z",
1961
1842
  user: { id: "u4", username: "drew", displayName: "Drew" },
1962
- },
1843
+ }),
1963
1844
  ];
1964
1845
  const older: ChatMessage[] = [
1965
- {
1846
+ chatMessage({
1966
1847
  id: "m1",
1967
- channelId: "everyone",
1968
1848
  content: "oldest",
1969
- replyToId: null,
1970
1849
  createdAt: "2026-03-28T00:01:00.000Z",
1971
1850
  user: { id: "u1", username: "alice", displayName: "Alice" },
1972
- },
1973
- {
1851
+ }),
1852
+ chatMessage({
1974
1853
  id: "m2",
1975
- channelId: "everyone",
1976
1854
  content: "older",
1977
- replyToId: null,
1978
1855
  createdAt: "2026-03-28T00:02:00.000Z",
1979
1856
  user: { id: "u2", username: "bob", displayName: "Bob" },
1980
- },
1857
+ }),
1981
1858
  ];
1982
1859
 
1983
1860
  persistence.setState("channel:everyone", {