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,17 +1,26 @@
1
- import { describe, expect, test } from "bun:test";
1
+ import { FINANCIAL_VINTAGE_NOTICE } from "../utils/financial-statements";
2
+ import { describe, expect, spyOn, test } from "bun:test";
3
+ import { chartSeriesSourceKey } from "../capabilities";
2
4
  import type { FredSeriesData, FredSeriesLoadResult } from "../data/fred-series";
5
+ import { buildCustomChartPreset } from "../plugins/builtin/chart-composer/presets";
3
6
  import { createTestDataProvider } from "../test-support/data-provider";
4
7
  import type { TickerFinancials } from "../types/financials";
5
- import { CHART_SPEC_VERSION, type ChartSpec } from "./types";
8
+ import { chartQuoteOverrideKeyForSource } from "./live-quotes";
6
9
  import {
7
10
  ChartResolveCache,
8
11
  mergePriceHistoryWindows,
9
12
  resolveChartSpecData,
10
13
  seedChartResolutionResult,
11
14
  } from "./resolve";
12
- import { chartQuoteOverrideKeyForSource } from "./live-quotes";
13
- import { chartSeriesSourceKey } from "../capabilities";
14
- import { buildCustomChartPreset } from "../plugins/builtin/chart-composer/presets";
15
+ import { CHART_SPEC_VERSION, type ChartSeriesSpec, type ChartSpec } from "./types";
16
+
17
+ function chartSeries(input: Pick<ChartSeriesSpec, "source"> & Partial<ChartSeriesSpec>): ChartSeriesSpec {
18
+ return { id: "price", style: "line", transform: "raw", axis: "left", panelId: "main", interpolation: "none", ...input };
19
+ }
20
+
21
+ function chartSpec(input: Pick<ChartSpec, "viewport" | "series"> & Partial<ChartSpec>): ChartSpec {
22
+ return { version: CHART_SPEC_VERSION, panels: [{ id: "main" }], studies: [], ...input };
23
+ }
15
24
 
16
25
  const emptyFinancials = (): TickerFinancials => ({
17
26
  annualStatements: [],
@@ -31,26 +40,109 @@ const fredLoad = (
31
40
  });
32
41
 
33
42
  describe("resolveChartSpecData", () => {
43
+ test("credit stress windows disclose source coverage without clipping buffers or scaling effective yields", async () => {
44
+ const spec = buildCustomChartPreset("FRED:BAMLC0A0CM,FRED:BAMLC0A0CMEY");
45
+ const requests: string[] = [];
46
+ const sources = {
47
+ now: new Date("2026-09-11"),
48
+ loadFredSeries: async (request: { seriesId: string; startDate?: string }) => {
49
+ requests.push(request.startDate!);
50
+ const yieldSeries = request.seriesId.endsWith("EY");
51
+ return fredLoad({
52
+ observations: [
53
+ { date: "2023-09-12", value: yieldSeries ? 5.82 : 1.23 },
54
+ { date: "2025-04-09", value: yieldSeries ? 5.5 : 1.21 },
55
+ { date: "2026-09-10", value: yieldSeries ? 5.68 : 0.8 },
56
+ ],
57
+ info: { id: request.seriesId, title: yieldSeries ? "IG effective yield" : "IG OAS", units: "Percent",
58
+ frequency: "Daily, Close", seasonalAdjustment: "Not Seasonally Adjusted", source: "FRED", notes: "",
59
+ observationStart: "2023-09-12", observationEnd: "2026-09-10" },
60
+ });
61
+ },
62
+ };
63
+ const fiveYear = await resolveChartSpecData(spec, sources);
64
+ expect(fiveYear.warnings.filter((warning) => warning.includes("FRED coverage"))).toHaveLength(2);
65
+ expect(fiveYear.warnings.some((warning) => warning.includes("vintage dates"))).toBe(true);
66
+ expect(fiveYear.series.map((series) => series.points.at(-1)?.value)).toEqual([0.8, 5.68]);
67
+ expect(fiveYear.series.map((series) => series.unit)).toEqual(["%", "%"]);
68
+ const recent = await resolveChartSpecData({ ...spec, viewport: { ...spec.viewport, range: "1Y" } }, sources);
69
+ expect(requests.at(-1)! < "2023-09-12").toBe(true); // Calculation buffer predates the visible window.
70
+ expect(recent.warnings.some((warning) => warning.includes("FRED coverage"))).toBe(false);
71
+ const old = await resolveChartSpecData({ ...spec, viewport: { ...spec.viewport,
72
+ dateWindow: { start: "2020-01-01", end: "2020-06-30" } } }, sources);
73
+ expect(old.series.every((series) => series.points.length === 0)).toBe(true);
74
+ expect(old.warnings.filter((warning) => warning.includes("Earlier dates are unavailable"))).toHaveLength(2);
75
+ expect(old.viewport.start?.toISOString().slice(0, 10)).toBe("2020-01-01");
76
+ });
77
+
78
+ test("credit history keeps newer observations when source coverage metadata lags", async () => {
79
+ const spec = buildCustomChartPreset("FRED:BAMLC0A0CM");
80
+ spec.viewport.dateWindow = { start: "2021-09-16", end: "2026-09-16" };
81
+ const data: FredSeriesData = {
82
+ observations: [{ date: "2023-09-18", value: 1.22 }, { date: "2026-09-14", value: 0.8 }],
83
+ info: { id: "BAMLC0A0CM", title: "IG OAS", units: "Percent", frequency: "Daily, Close",
84
+ seasonalAdjustment: "Not Seasonally Adjusted", source: "FRED", notes: "",
85
+ observationStart: "2023-09-12", observationEnd: "2026-09-10" },
86
+ };
87
+ const sources = { loadFredSeries: async () => fredLoad(data) };
88
+ const before = await resolveChartSpecData(spec, sources);
89
+ expect(before.series[0]?.points.at(-1)?.value).toBe(0.8);
90
+ expect(before.series[0]?.points.at(-1)?.date.toISOString()).toBe("2026-09-14T00:00:00.000Z");
91
+ expect(before.warnings.some((warning) => warning.includes("exact coverage dates are unavailable"))).toBe(true);
92
+ expect(before.warnings.some((warning) => warning.includes("2026-09-10"))).toBe(false);
93
+ data.info = { ...data.info!, observationStart: "2023-09-18", observationEnd: "2026-09-14" };
94
+ const recovered = await resolveChartSpecData(spec, sources);
95
+ expect(recovered.series[0]?.points).toEqual(before.series[0]?.points);
96
+ expect(recovered.warnings.some((warning) => warning.includes("2023-09-18 to 2026-09-14"))).toBe(true);
97
+ expect(recovered.warnings.some((warning) => warning.includes("exact coverage dates are unavailable"))).toBe(false);
98
+ });
99
+
100
+ test("qualified price charts retain quote metadata without injecting the fetched snapshot into history", async () => {
101
+ let quoteCalls = 0;
102
+ let financialCalls = 0;
103
+ const history = [{ date: new Date("2026-01-15"), close: 77.53, volume: 1234 }];
104
+ const provider = createTestDataProvider({
105
+ getQuote: async () => { quoteCalls++; return { symbol: "NESN", listingExchangeName: "SWX", currency: "CHF", instrumentType: "EQUITY", price: 999, change: 0, changePercent: 0, lastUpdated: Date.parse("2026-01-16") }; },
106
+ getTickerFinancials: async () => { financialCalls++; return emptyFinancials(); },
107
+ getPriceHistory: async () => history,
108
+ getPriceHistoryForResolution: async () => history,
109
+ });
110
+ const spec = chartSpec({ viewport: { range: "1M", resolution: "1d" }, series: [chartSeries({ source: { kind: "security", instrument: { symbol: "NESN", exchange: "SWX" }, fieldId: "market.close" } })] });
111
+ const cache = new ChartResolveCache();
112
+ const sources = { dataProvider: provider, loadFredSeries: async () => fredLoad(), now: new Date("2026-01-16") };
113
+ const result = await resolveChartSpecData(spec, sources, cache);
114
+ expect(result.series[0]).toMatchObject({ unit: "CHF/share", unitGroup: "price:CHF", volumeUnit: "shares" });
115
+ expect(result.series[0]?.points.map((point) => point.value)).toEqual([77.53]);
116
+ await resolveChartSpecData(spec, sources, cache);
117
+ expect(quoteCalls).toBe(1);
118
+ expect(financialCalls).toBe(0);
119
+
120
+ const unavailable = createTestDataProvider({
121
+ // Optional metadata can also fail synchronously in a provider adapter.
122
+ getQuote: () => { throw new Error("Quote temporarily unavailable"); },
123
+ getPriceHistory: async () => history,
124
+ getPriceHistoryForResolution: async () => history,
125
+ });
126
+ const withoutMetadata = await resolveChartSpecData(spec, { ...sources, dataProvider: unavailable });
127
+ expect(withoutMetadata.errors).toEqual([]);
128
+ expect(withoutMetadata.series[0]?.points.map((point) => point.value)).toEqual([77.53]);
129
+ expect(withoutMetadata.series[0]?.unit).toBe("currency");
130
+ });
131
+
34
132
  test("seeds study series so their panels survive the wait for real data", async () => {
35
133
  const date = new Date("2026-01-05T00:00:00.000Z");
36
134
  const seeded = seedChartResolutionResult(
37
- {
38
- version: CHART_SPEC_VERSION,
135
+ chartSpec({
39
136
  viewport: { range: "1M", resolution: "auto" },
40
137
  panels: [{ id: "main" }, { id: "volume" }],
41
- series: [{
42
- id: "price",
138
+ series: [chartSeries({
43
139
  source: {
44
140
  kind: "security",
45
141
  instrument: { symbol: "TEST", exchange: "NASDAQ" },
46
142
  fieldId: "market.ohlcv",
47
143
  },
48
144
  style: "candles",
49
- transform: "raw",
50
- axis: "left",
51
- panelId: "main",
52
- interpolation: "none",
53
- }],
145
+ })],
54
146
  studies: [{
55
147
  id: "volume",
56
148
  kind: "volume",
@@ -59,7 +151,7 @@ describe("resolveChartSpecData", () => {
59
151
  panelId: "volume",
60
152
  axis: "left",
61
153
  }],
62
- },
154
+ }),
63
155
  new Map([[
64
156
  chartQuoteOverrideKeyForSource({
65
157
  kind: "security",
@@ -72,7 +164,98 @@ describe("resolveChartSpecData", () => {
72
164
 
73
165
  const volume = seeded?.series.find((entry) => entry.panelId === "volume");
74
166
  expect(volume?.points.map((point) => point.value)).toEqual([5_000]);
75
- expect(seeded?.bufferedSeries).toBe(seeded?.series);
167
+ expect(seeded?.bufferedSeries?.find((entry) => entry.panelId === "volume")?.points).toHaveLength(1);
168
+ });
169
+
170
+ test("a currency-only live quote still loads security type without replacing its price", async () => {
171
+ let quoteCalls = 0;
172
+ let financialCalls = 0;
173
+ const source = { kind: "security" as const, instrument: { symbol: "NVDA", exchange: "XNAS" }, fieldId: "market.close" };
174
+ const history = [{ date: new Date("2026-01-15T14:30:00Z"), close: 77.53, volume: 1234 }];
175
+ const provider = createTestDataProvider({
176
+ getQuote: async () => { quoteCalls++; return { symbol: "NVDA", listingExchangeName: "NASDAQ", currency: "USD", instrumentType: "Common Stock", price: 999, change: 0, changePercent: 0, lastUpdated: Date.parse("2026-01-16T16:00:00Z") }; },
177
+ getTickerFinancials: async () => { financialCalls++; return emptyFinancials(); },
178
+ getPriceHistory: async () => history,
179
+ getPriceHistoryForResolution: async () => history,
180
+ });
181
+ const spec = chartSpec({ viewport: { range: "1M", resolution: "1d" }, series: [chartSeries({ source })],
182
+ studies: [{ id: "volume", kind: "volume", inputSeriesIds: ["price"], parameters: {}, panelId: "main", axis: "left" }] });
183
+ const sources = { dataProvider: provider, loadFredSeries: async () => fredLoad(), now: new Date("2026-01-16T16:00:00Z"),
184
+ quoteOverrides: new Map([[chartQuoteOverrideKeyForSource(source), { symbol: "NVDA", currency: "USD", price: 78, change: 0, changePercent: 0, lastUpdated: Date.parse("2026-01-16T16:00:00Z") }]]) };
185
+ const cache = new ChartResolveCache();
186
+ const result = await resolveChartSpecData(spec, sources, cache);
187
+ expect(result.series[0]).toMatchObject({ unit: "USD/share", volumeUnit: "shares" });
188
+ expect(result.series.find((series) => series.id === "volume")?.unit).toBe("shares");
189
+ expect(result.series[0]?.points.map((point) => point.value)).toEqual([77.53, 78]);
190
+ expect(result.warnings.some((warning) => warning.includes("Volume unit unknown"))).toBe(false);
191
+ await resolveChartSpecData(spec, sources, cache);
192
+ expect(quoteCalls).toBe(1);
193
+ expect(financialCalls).toBe(0);
194
+ });
195
+
196
+ test("direct volume fields and volume studies retain established units without labeling crypto volume as shares", async () => {
197
+ for (const [instrumentType, expectedUnit] of [["EQUITY", "shares"], ["Common Stock", "shares"], ["FUTURE", "contracts"], ["CRYPTOCURRENCY", ""], [undefined, ""]] as const) {
198
+ const history = [{ date: new Date("2026-01-15"), close: 1, volume: 1234 }];
199
+ const financials = { ...emptyFinancials(), quote: { symbol: "TEST", currency: "USD", price: 1, change: 0, changePercent: 0, lastUpdated: Date.parse("2026-01-15"), instrumentType }, priceHistory: history };
200
+ const provider = createTestDataProvider({
201
+ getQuote: async () => financials.quote,
202
+ getTickerFinancials: async () => financials,
203
+ getPriceHistory: async () => history,
204
+ getPriceHistoryForResolution: async () => history,
205
+ });
206
+ const result = await resolveChartSpecData(chartSpec({
207
+ viewport: { range: "1M", resolution: "1d" },
208
+ series: [chartSeries({ id: "direct", source: { kind: "security", instrument: { symbol: "TEST" }, fieldId: "market.volume" } }), chartSeries({ id: "price", source: { kind: "security", instrument: { symbol: "TEST" }, fieldId: "market.close" } })],
209
+ studies: [{ id: "volume", kind: "volume", inputSeriesIds: ["price"], parameters: {}, panelId: "main", axis: "left" }],
210
+ }), { dataProvider: provider, loadFredSeries: async () => fredLoad(), now: new Date("2026-01-16") });
211
+ for (const id of ["direct", "volume"]) {
212
+ expect(result.series.find((entry) => entry.id === id)?.unit).toBe(expectedUnit);
213
+ expect(result.series.find((entry) => entry.id === id)?.points.map((point) => point.value)).toEqual([1234]);
214
+ }
215
+ expect(result.warnings.some((warning) => warning.includes("Volume unit unknown"))).toBe(!expectedUnit);
216
+ }
217
+ });
218
+
219
+ test("cached history honors the visible date range before the network resolves", () => {
220
+ const source = { kind: "security" as const, instrument: { symbol: "TEST", exchange: "NASDAQ" }, fieldId: "market.close" };
221
+ const history = ["2021-01-01", "2026-08-01", "2026-08-15", "2026-09-10"].map((day, i) => ({
222
+ date: new Date(`${day}T00:00:00Z`), close: 100 + i, volume: 1_000 + i,
223
+ }));
224
+ const seeded = seedChartResolutionResult(chartSpec({
225
+ viewport: { range: "1M", resolution: "auto" },
226
+ series: [chartSeries({ source, transform: "percent" })],
227
+ }), new Map([[chartQuoteOverrideKeyForSource(source), history]]));
228
+ expect(seeded?.viewport?.start.toISOString()).toBe("2026-08-10T00:00:00.000Z");
229
+ expect(seeded?.viewport?.end.toISOString()).toBe("2026-09-10T00:00:00.000Z");
230
+ expect(seeded?.series[0]?.points.map((p) => p.date.toISOString().slice(0, 10))).toEqual(["2026-08-15", "2026-09-10"]);
231
+ expect(seeded?.series[0]?.points[0]?.value).toBe(0);
232
+ expect(seeded?.bufferedSeries?.[0]?.points).toHaveLength(4);
233
+ });
234
+
235
+ test("a point-limited seed exposes a viewport only for an explicit date window", () => {
236
+ const source = { kind: "security" as const, instrument: { symbol: "TEST", exchange: "NASDAQ" }, fieldId: "market.close" };
237
+ const history = ["2026-08-01", "2026-08-15", "2026-09-10"].map((day, index) => ({
238
+ date: new Date(`${day}T00:00:00Z`), close: 100 + index,
239
+ }));
240
+ const cached = new Map([[chartQuoteOverrideKeyForSource(source), history]]);
241
+ const spec = chartSpec({ viewport: { range: "1Y", resolution: "auto", maxPoints: 2 }, series: [chartSeries({ source })] });
242
+ const seed = seedChartResolutionResult(spec, cached);
243
+ expect(seed?.series[0]?.points).toHaveLength(2);
244
+ expect(seed?.viewport).toBeUndefined();
245
+ expect(seed?.bufferedSeries).toBeUndefined();
246
+ const explicit = seedChartResolutionResult({ ...spec, viewport: {
247
+ ...spec.viewport, dateWindow: { start: "2026-08-01", end: "2026-09-10" },
248
+ } }, cached);
249
+ expect(explicit?.viewport?.start.toISOString()).toBe("2026-08-01T00:00:00.000Z");
250
+ expect(explicit?.viewport?.end.toISOString()).toBe("2026-09-10T23:59:59.999Z");
251
+ });
252
+
253
+ test("stale cached observations cannot move a current preset window into the past", () => {
254
+ const source = { kind: "security" as const, instrument: { symbol: "TEST" }, fieldId: "market.close" };
255
+ const cached = new Map([[chartQuoteOverrideKeyForSource(source), [{ date: new Date("2026-08-31T00:00:00Z"), close: 100 }]]]);
256
+ const result = seedChartResolutionResult(chartSpec({ viewport: { range: "1M", resolution: "auto" },
257
+ series: [chartSeries({ source })] }), cached, new Date("2026-09-10T18:00:00Z"));
258
+ expect(result?.viewport).toEqual({ start: new Date("2026-08-10T18:00:00Z"), end: new Date("2026-09-10T18:00:00Z") });
76
259
  });
77
260
 
78
261
  test("keeps study output over the whole buffered history its base series carries", async () => {
@@ -88,23 +271,16 @@ describe("resolveChartSpecData", () => {
88
271
  getPriceHistoryForResolution: async () => history,
89
272
  getDetailedPriceHistory: async () => history,
90
273
  });
91
- const spec: ChartSpec = {
92
- version: CHART_SPEC_VERSION,
274
+ const spec: ChartSpec = chartSpec({
93
275
  viewport: { range: "1Y", resolution: "1d" },
94
276
  panels: [{ id: "main" }, { id: "volume", label: "Volume", height: 0.24 }],
95
- series: [{
96
- id: "price",
277
+ series: [chartSeries({
97
278
  source: {
98
279
  kind: "security",
99
280
  instrument: { symbol: "TEST", exchange: "NASDAQ" },
100
281
  fieldId: "market.close",
101
282
  },
102
- style: "line",
103
- transform: "raw",
104
- axis: "left",
105
- panelId: "main",
106
- interpolation: "none",
107
- }],
283
+ })],
108
284
  studies: [{
109
285
  id: "volume",
110
286
  kind: "volume",
@@ -113,7 +289,7 @@ describe("resolveChartSpecData", () => {
113
289
  panelId: "volume",
114
290
  axis: "left",
115
291
  }],
116
- };
292
+ });
117
293
  const sources = {
118
294
  dataProvider: provider,
119
295
  now: new Date("2026-06-15T00:00:00.000Z"),
@@ -177,21 +353,15 @@ describe("resolveChartSpecData", () => {
177
353
  });
178
354
 
179
355
  test("keeps missing capability series visible with a useful error and resolves them through the injected boundary", async () => {
180
- const spec: ChartSpec = {
181
- version: CHART_SPEC_VERSION,
356
+ const spec: ChartSpec = chartSpec({
182
357
  viewport: { range: "1M", resolution: "auto" },
183
- panels: [{ id: "main" }],
184
- series: [{
358
+ series: [chartSeries({
185
359
  id: "plugin-series",
186
360
  source: { kind: "capability", capabilityId: "charts.test", seriesId: "one" },
187
361
  style: "area",
188
- transform: "raw",
189
362
  axis: "auto",
190
- panelId: "main",
191
- interpolation: "none",
192
- }],
193
- studies: [],
194
- };
363
+ })],
364
+ });
195
365
  const sources = { dataProvider: null, loadFredSeries: async () => fredLoad(), now: new Date("2026-02-01") };
196
366
  const missing = await resolveChartSpecData(spec, sources);
197
367
  expect(missing.series).toHaveLength(1);
@@ -222,21 +392,13 @@ describe("resolveChartSpecData", () => {
222
392
  });
223
393
 
224
394
  test("resolves capability coverage for each effective panned viewport and caches by structured bounds", async () => {
225
- const spec: ChartSpec = {
226
- version: CHART_SPEC_VERSION,
395
+ const spec: ChartSpec = chartSpec({
227
396
  viewport: { range: "1M", resolution: "auto" },
228
- panels: [{ id: "main" }],
229
- series: [{
397
+ series: [chartSeries({
230
398
  id: "plugin-series",
231
399
  source: { kind: "capability", capabilityId: "charts.test", seriesId: "provider/series" },
232
- style: "line",
233
- transform: "raw",
234
- axis: "left",
235
- panelId: "main",
236
- interpolation: "none",
237
- }],
238
- studies: [],
239
- };
400
+ })],
401
+ });
240
402
  const requested: ChartSpec["viewport"][] = [];
241
403
  const cache = new ChartResolveCache();
242
404
  const sources = {
@@ -296,11 +458,9 @@ describe("resolveChartSpecData", () => {
296
458
  return [{ date: new Date("2025-01-07T16:00:00Z"), close: 100 }];
297
459
  },
298
460
  });
299
- const spec: ChartSpec = {
300
- version: CHART_SPEC_VERSION,
461
+ const spec: ChartSpec = chartSpec({
301
462
  viewport: { range: scenario.range, resolution: "auto" },
302
- panels: [{ id: "main" }],
303
- series: scenario.periods.map((period, index) => ({
463
+ series: scenario.periods.map((period, index) => (chartSeries({
304
464
  id: `price-${index}`,
305
465
  source: {
306
466
  kind: "security" as const,
@@ -311,11 +471,9 @@ describe("resolveChartSpecData", () => {
311
471
  style: "line" as const,
312
472
  transform: "raw" as const,
313
473
  axis: "left" as const,
314
- panelId: "main",
315
474
  interpolation: "none" as const,
316
- })),
317
- studies: [],
318
- };
475
+ }))),
476
+ });
319
477
 
320
478
  const result = await resolveChartSpecData(spec, {
321
479
  dataProvider: provider,
@@ -347,25 +505,17 @@ describe("resolveChartSpecData", () => {
347
505
  { date: new Date("2025-01-07T16:00:00Z"), close: 100 },
348
506
  ],
349
507
  });
350
- const spec: ChartSpec = {
351
- version: CHART_SPEC_VERSION,
508
+ const spec: ChartSpec = chartSpec({
352
509
  viewport: { range: "5Y", resolution: "auto" },
353
- panels: [{ id: "main" }],
354
- series: [{
355
- id: "price",
510
+ series: [chartSeries({
356
511
  source: {
357
512
  kind: "security",
358
513
  instrument: { symbol: "TEST", exchange: "NASDAQ" },
359
514
  fieldId: "market.ohlcv",
360
515
  },
361
516
  style: "candles",
362
- transform: "raw",
363
- axis: "left",
364
- panelId: "main",
365
- interpolation: "none",
366
- }],
367
- studies: [],
368
- };
517
+ })],
518
+ });
369
519
 
370
520
  const result = await Promise.race([
371
521
  resolveChartSpecData(spec, {
@@ -394,21 +544,12 @@ describe("resolveChartSpecData", () => {
394
544
  return [{ date: new Date("2025-01-07T16:00:00Z"), close: 100 }];
395
545
  },
396
546
  });
397
- const spec: ChartSpec = {
398
- version: CHART_SPEC_VERSION,
547
+ const spec: ChartSpec = chartSpec({
399
548
  viewport: { range: "1W", resolution: "5m" },
400
- panels: [{ id: "main" }],
401
- series: [{
402
- id: "price",
549
+ series: [chartSeries({
403
550
  source: { kind: "security", instrument: { symbol: "TEST" }, fieldId: "market.close" },
404
- style: "line",
405
- transform: "raw",
406
- axis: "left",
407
- panelId: "main",
408
- interpolation: "none",
409
- }],
410
- studies: [],
411
- };
551
+ })],
552
+ });
412
553
 
413
554
  const result = await resolveChartSpecData(spec, {
414
555
  dataProvider: provider,
@@ -438,25 +579,16 @@ describe("resolveChartSpecData", () => {
438
579
  return [{ date: new Date("2026-07-30T15:00:00Z"), close: 100 }];
439
580
  },
440
581
  });
441
- const spec: ChartSpec = {
442
- version: CHART_SPEC_VERSION,
582
+ const spec: ChartSpec = chartSpec({
443
583
  viewport: { range: "1M", resolution: "45m" },
444
- panels: [{ id: "main" }],
445
- series: [{
446
- id: "price",
584
+ series: [chartSeries({
447
585
  source: {
448
586
  kind: "security",
449
587
  instrument: { symbol: "TEST", exchange: "NASDAQ" },
450
588
  fieldId: "market.close",
451
589
  },
452
- style: "line",
453
- transform: "raw",
454
- axis: "left",
455
- panelId: "main",
456
- interpolation: "none",
457
- }],
458
- studies: [],
459
- };
590
+ })],
591
+ });
460
592
 
461
593
  const result = await resolveChartSpecData(spec, {
462
594
  dataProvider: provider,
@@ -475,6 +607,97 @@ describe("resolveChartSpecData", () => {
475
607
  ]);
476
608
  });
477
609
 
610
+ test.each([
611
+ { selected: "1wk", maxRange: "ALL", range: "ALL", expected: "1wk" },
612
+ { selected: "1mo", maxRange: "ALL", range: "ALL", expected: "1mo" },
613
+ { selected: "1wk", maxRange: "5Y", range: "ALL", expected: "1mo" },
614
+ { selected: "5m", maxRange: "1W", range: "ALL", expected: "1mo" },
615
+ { selected: "1wk", maxRange: "5Y", range: "1Y", expected: "1wk" },
616
+ ] as const)("honors $selected/$range only within the provider's $maxRange limit", async ({ selected, maxRange, range, expected }) => {
617
+ const requests: string[] = [];
618
+ const provider = createTestDataProvider({
619
+ getTickerFinancials: async () => emptyFinancials(),
620
+ getChartResolutionSupport: () => [
621
+ { resolution: selected, maxRange },
622
+ { resolution: "1mo", maxRange: "ALL" },
623
+ ],
624
+ getPriceHistoryForResolution: async (_symbol, _exchange, _range, resolution) => {
625
+ requests.push(resolution);
626
+ return [{ date: new Date("2026-08-03"), close: resolution === "1wk" ? 35 : 33 }];
627
+ },
628
+ });
629
+ const spec = chartSpec({
630
+ viewport: { range, resolution: selected },
631
+ series: [chartSeries({ source: {
632
+ kind: "security", instrument: { symbol: "TEST", exchange: "LSE" }, fieldId: "market.close",
633
+ } })],
634
+ });
635
+ const result = await resolveChartSpecData(spec, {
636
+ dataProvider: provider, now: new Date("2026-09-11"), loadFredSeries: async () => fredLoad(),
637
+ });
638
+
639
+ expect(requests).toEqual([expected]);
640
+ expect(result.resolution).toBe(expected);
641
+ expect(result.series[0]?.points.at(-1)?.value).toBe(expected === "1wk" ? 35 : 33);
642
+ expect(result.errors).toEqual([]);
643
+ expect(result.warnings.some((warning) => warning.includes("Auto resolution was used instead")))
644
+ .toBe(expected !== selected);
645
+ });
646
+
647
+ test.each(["ALL", "5Y"] as const)("checks explicit long date windows against the %s manual limit", async (maxRange) => {
648
+ const requests: string[] = [];
649
+ const provider = createTestDataProvider({
650
+ getTickerFinancials: async () => emptyFinancials(),
651
+ getChartResolutionSupport: () => [
652
+ { resolution: "1wk", maxRange },
653
+ { resolution: "1mo", maxRange: "ALL" },
654
+ ],
655
+ getDetailedPriceHistory: async (_symbol, _exchange, _start, _end, resolution) => {
656
+ requests.push(resolution);
657
+ return [{ date: new Date("1997-07-01"), close: 10 }];
658
+ },
659
+ });
660
+ const spec = chartSpec({
661
+ viewport: { range: "ALL", resolution: "1wk", dateWindow: { start: "1997-01-01", end: "2026-09-11" } },
662
+ series: [chartSeries({ source: {
663
+ kind: "security", instrument: { symbol: "TEST", exchange: "LSE" }, fieldId: "market.close",
664
+ } })],
665
+ });
666
+ const result = await resolveChartSpecData(spec, {
667
+ dataProvider: provider, now: new Date("2026-09-11"), loadFredSeries: async () => fredLoad(),
668
+ });
669
+ expect(requests).toEqual([maxRange === "ALL" ? "1wk" : "1mo"]);
670
+ expect(result.errors).toEqual([]);
671
+ });
672
+
673
+ test("requires every comparison source to support the manual ALL interval", async () => {
674
+ const requests: string[] = [];
675
+ const provider = createTestDataProvider({
676
+ getTickerFinancials: async () => emptyFinancials(),
677
+ getChartResolutionSupport: (symbol) => [
678
+ { resolution: "1wk", maxRange: symbol === "UNLIMITED" ? "ALL" : "5Y" },
679
+ { resolution: "1mo", maxRange: "ALL" },
680
+ ],
681
+ getPriceHistoryForResolution: async (symbol, _exchange, _range, resolution) => {
682
+ requests.push(`${symbol}:${resolution}`);
683
+ return [{ date: new Date("2026-08-03"), close: 33 }];
684
+ },
685
+ });
686
+ const spec = chartSpec({
687
+ viewport: { range: "ALL", resolution: "1wk" },
688
+ series: ["UNLIMITED", "LIMITED"].map((symbol) => chartSeries({ id: symbol, source: {
689
+ kind: "security", instrument: { symbol, exchange: "LSE" }, fieldId: "market.close",
690
+ } })),
691
+ });
692
+ const result = await resolveChartSpecData(spec, {
693
+ dataProvider: provider, now: new Date("2026-09-11"), loadFredSeries: async () => fredLoad(),
694
+ });
695
+ expect(requests.sort()).toEqual(["LIMITED:1mo", "UNLIMITED:1mo"]);
696
+ expect(result.resolution).toBe("1mo");
697
+ expect(result.resolutionSupport).toContainEqual({ resolution: "1wk", maxRange: "5Y" });
698
+ expect(result.warnings).toContain("1WK data is unavailable for this range. Auto resolution was used instead.");
699
+ });
700
+
478
701
  test("keeps the snapshot exchange when a newer quote omits it", async () => {
479
702
  const historyExchanges: string[] = [];
480
703
  const source = {
@@ -506,10 +729,8 @@ describe("resolveChartSpecData", () => {
506
729
  }];
507
730
  },
508
731
  });
509
- const spec: ChartSpec = {
510
- version: CHART_SPEC_VERSION,
732
+ const spec: ChartSpec = chartSpec({
511
733
  viewport: { range: "1D", resolution: "5m" },
512
- panels: [{ id: "main" }],
513
734
  series: [{
514
735
  id: "price",
515
736
  source,
@@ -519,8 +740,7 @@ describe("resolveChartSpecData", () => {
519
740
  panelId: "main",
520
741
  interpolation: "none",
521
742
  }],
522
- studies: [],
523
- };
743
+ });
524
744
 
525
745
  const result = await resolveChartSpecData(spec, {
526
746
  dataProvider: provider,
@@ -577,25 +797,16 @@ describe("resolveChartSpecData", () => {
577
797
  return [{ date: new Date("2026-07-30T15:20:00Z"), close: 1_240 }];
578
798
  },
579
799
  });
580
- const spec: ChartSpec = {
581
- version: CHART_SPEC_VERSION,
800
+ const spec: ChartSpec = chartSpec({
582
801
  viewport: { range: "1D", resolution: "auto" },
583
- panels: [{ id: "main" }],
584
- series: [{
585
- id: "price",
802
+ series: [chartSeries({
586
803
  source: {
587
804
  kind: "security",
588
805
  instrument: { symbol: "SNDK" },
589
806
  fieldId: "market.close",
590
807
  },
591
- style: "line",
592
- transform: "raw",
593
- axis: "left",
594
- panelId: "main",
595
- interpolation: "none",
596
- }],
597
- studies: [],
598
- };
808
+ })],
809
+ });
599
810
 
600
811
  const result = await resolveChartSpecData(
601
812
  spec,
@@ -631,21 +842,12 @@ describe("resolveChartSpecData", () => {
631
842
  return [{ date: new Date("2025-01-07T16:00:00Z"), close: 100 }];
632
843
  },
633
844
  });
634
- const spec: ChartSpec = {
635
- version: CHART_SPEC_VERSION,
845
+ const spec: ChartSpec = chartSpec({
636
846
  viewport: { range: "1W", resolution: "auto" },
637
- panels: [{ id: "main" }],
638
- series: [{
639
- id: "price",
847
+ series: [chartSeries({
640
848
  source: { kind: "security", instrument: { symbol: "TEST" }, fieldId: "market.close" },
641
- style: "line",
642
- transform: "raw",
643
- axis: "left",
644
- panelId: "main",
645
- interpolation: "none",
646
- }],
647
- studies: [],
648
- };
849
+ })],
850
+ });
649
851
 
650
852
  const result = await resolveChartSpecData(spec, {
651
853
  dataProvider: provider,
@@ -668,21 +870,12 @@ describe("resolveChartSpecData", () => {
668
870
  return [{ date: new Date("2025-01-07T16:00:00Z"), close: 100 }];
669
871
  },
670
872
  });
671
- const spec: ChartSpec = {
672
- version: CHART_SPEC_VERSION,
873
+ const spec: ChartSpec = chartSpec({
673
874
  viewport: { range: "1W", resolution: "auto" },
674
- panels: [{ id: "main" }],
675
- series: [{
676
- id: "price",
875
+ series: [chartSeries({
677
876
  source: { kind: "security", instrument: { symbol: "TEST" }, fieldId: "market.close" },
678
- style: "line",
679
- transform: "raw",
680
- axis: "left",
681
- panelId: "main",
682
- interpolation: "none",
683
- }],
684
- studies: [],
685
- };
877
+ })],
878
+ });
686
879
 
687
880
  const result = await resolveChartSpecData(spec, {
688
881
  dataProvider: provider,
@@ -716,25 +909,16 @@ describe("resolveChartSpecData", () => {
716
909
  return [{ date: new Date("2025-01-15T16:00:00.000Z"), close: 100 }];
717
910
  },
718
911
  });
719
- const spec: ChartSpec = {
720
- version: CHART_SPEC_VERSION,
912
+ const spec: ChartSpec = chartSpec({
721
913
  viewport: { range: "3M", resolution: "auto" },
722
- panels: [{ id: "main" }],
723
- series: [{
724
- id: "price",
914
+ series: [chartSeries({
725
915
  source: {
726
916
  kind: "security",
727
917
  instrument: { symbol: "TEST", exchange: "NASDAQ" },
728
918
  fieldId: "market.close",
729
919
  },
730
- style: "line",
731
- transform: "raw",
732
- axis: "left",
733
- panelId: "main",
734
- interpolation: "none",
735
- }],
736
- studies: [],
737
- };
920
+ })],
921
+ });
738
922
 
739
923
  const result = await resolveChartSpecData(
740
924
  spec,
@@ -795,25 +979,16 @@ describe("resolveChartSpecData", () => {
795
979
  return historicalHistory;
796
980
  },
797
981
  });
798
- const spec: ChartSpec = {
799
- version: CHART_SPEC_VERSION,
982
+ const spec: ChartSpec = chartSpec({
800
983
  viewport: { range: "1Y", resolution: "1h" },
801
- panels: [{ id: "main" }],
802
- series: [{
803
- id: "price",
984
+ series: [chartSeries({
804
985
  source: {
805
986
  kind: "security",
806
987
  instrument: { symbol: "TEST", exchange: "NASDAQ" },
807
988
  fieldId: "market.close",
808
989
  },
809
- style: "line",
810
- transform: "raw",
811
- axis: "left",
812
- panelId: "main",
813
- interpolation: "none",
814
- }],
815
- studies: [],
816
- };
990
+ })],
991
+ });
817
992
  const sources = {
818
993
  dataProvider: provider,
819
994
  now: new Date("2026-07-30T16:00:00.000Z"),
@@ -871,25 +1046,16 @@ describe("resolveChartSpecData", () => {
871
1046
  getPriceHistoryForResolution: async () => currentHistory,
872
1047
  getDetailedPriceHistory: async () => historicalHistory,
873
1048
  });
874
- const spec: ChartSpec = {
875
- version: CHART_SPEC_VERSION,
1049
+ const spec: ChartSpec = chartSpec({
876
1050
  viewport: { range: "1Y", resolution: "1d" },
877
- panels: [{ id: "main" }],
878
- series: [{
879
- id: "price",
1051
+ series: [chartSeries({
880
1052
  source: {
881
1053
  kind: "security",
882
1054
  instrument: { symbol: "TEST", exchange: "NASDAQ" },
883
1055
  fieldId: "market.close",
884
1056
  },
885
- style: "line",
886
- transform: "raw",
887
- axis: "left",
888
- panelId: "main",
889
- interpolation: "none",
890
- }],
891
- studies: [],
892
- };
1057
+ })],
1058
+ });
893
1059
  const sources = {
894
1060
  dataProvider: provider,
895
1061
  now: new Date("2026-07-30T16:00:00.000Z"),
@@ -923,23 +1089,16 @@ describe("resolveChartSpecData", () => {
923
1089
  { date: new Date("2024-10-16T16:00:00.000Z"), close: 110 },
924
1090
  ],
925
1091
  });
926
- const spec: ChartSpec = {
927
- version: CHART_SPEC_VERSION,
1092
+ const spec: ChartSpec = chartSpec({
928
1093
  viewport: { range: "3M", resolution: "1d" },
929
- panels: [{ id: "main" }],
930
- series: [{
931
- id: "price",
1094
+ series: [chartSeries({
932
1095
  source: {
933
1096
  kind: "security",
934
1097
  instrument: { symbol: "TEST", exchange: "NASDAQ" },
935
1098
  fieldId: "market.close",
936
1099
  },
937
- style: "line",
938
1100
  transform: "percent",
939
- axis: "left",
940
- panelId: "main",
941
- interpolation: "none",
942
- }],
1101
+ })],
943
1102
  studies: [{
944
1103
  id: "sma",
945
1104
  kind: "sma",
@@ -948,7 +1107,7 @@ describe("resolveChartSpecData", () => {
948
1107
  panelId: "main",
949
1108
  axis: "left",
950
1109
  }],
951
- };
1110
+ });
952
1111
 
953
1112
  const result = await resolveChartSpecData(
954
1113
  spec,
@@ -996,21 +1155,17 @@ describe("resolveChartSpecData", () => {
996
1155
  ];
997
1156
  },
998
1157
  });
999
- const spec: ChartSpec = {
1000
- version: CHART_SPEC_VERSION,
1158
+ const spec: ChartSpec = chartSpec({
1001
1159
  viewport: { range: "1Y", resolution: "1d" },
1002
1160
  panels: [{ id: "main" }, { id: "macro", height: 0.4 }],
1003
1161
  series: [
1004
- {
1162
+ chartSeries({
1005
1163
  id: "aapl-price",
1006
1164
  source: { kind: "security", instrument: { symbol: "AAPL" }, fieldId: "market.close" },
1007
- style: "line",
1008
1165
  transform: "percent",
1009
1166
  axis: "auto",
1010
- panelId: "main",
1011
- interpolation: "none",
1012
- },
1013
- {
1167
+ }),
1168
+ chartSeries({
1014
1169
  id: "msft-revenue",
1015
1170
  source: {
1016
1171
  kind: "security",
@@ -1020,23 +1175,19 @@ describe("resolveChartSpecData", () => {
1020
1175
  timestampMode: "available-at",
1021
1176
  },
1022
1177
  style: "columns",
1023
- transform: "raw",
1024
1178
  axis: "auto",
1025
- panelId: "main",
1026
1179
  interpolation: "step-after",
1027
- },
1028
- {
1180
+ }),
1181
+ chartSeries({
1029
1182
  id: "cpi",
1030
1183
  source: { kind: "economic", provider: "fred", seriesId: "CPIAUCSL" },
1031
1184
  style: "step",
1032
- transform: "raw",
1033
1185
  axis: "auto",
1034
1186
  panelId: "macro",
1035
1187
  interpolation: "step-after",
1036
- },
1188
+ }),
1037
1189
  ],
1038
- studies: [],
1039
- };
1190
+ });
1040
1191
 
1041
1192
  const result = await resolveChartSpecData(spec, {
1042
1193
  dataProvider: provider,
@@ -1101,23 +1252,15 @@ describe("resolveChartSpecData", () => {
1101
1252
  ];
1102
1253
  },
1103
1254
  });
1104
- const spec: ChartSpec = {
1105
- version: CHART_SPEC_VERSION,
1255
+ const spec: ChartSpec = chartSpec({
1106
1256
  viewport: {
1107
1257
  range: "1Y",
1108
1258
  resolution: "auto",
1109
1259
  dateWindow: { start: "2025-01-01", end: "2025-01-31" },
1110
1260
  },
1111
- panels: [{ id: "main" }],
1112
- series: [{
1113
- id: "price",
1261
+ series: [chartSeries({
1114
1262
  source: { kind: "security", instrument: { symbol: "TEST" }, fieldId: "market.close" },
1115
- style: "line",
1116
- transform: "raw",
1117
- axis: "left",
1118
- panelId: "main",
1119
- interpolation: "none",
1120
- }],
1263
+ })],
1121
1264
  studies: [{
1122
1265
  id: "sma",
1123
1266
  kind: "sma",
@@ -1126,7 +1269,7 @@ describe("resolveChartSpecData", () => {
1126
1269
  panelId: "main",
1127
1270
  axis: "left",
1128
1271
  }],
1129
- };
1272
+ });
1130
1273
 
1131
1274
  const result = await resolveChartSpecData(spec, {
1132
1275
  dataProvider: provider,
@@ -1165,25 +1308,16 @@ describe("resolveChartSpecData", () => {
1165
1308
  return [{ date: new Date("2025-01-31T16:00:00Z"), close: 40 }];
1166
1309
  },
1167
1310
  });
1168
- const spec: ChartSpec = {
1169
- version: CHART_SPEC_VERSION,
1311
+ const spec: ChartSpec = chartSpec({
1170
1312
  viewport: {
1171
1313
  range: "1D",
1172
1314
  resolution: "auto",
1173
1315
  dateWindow: { start: "2025-01-01", end: "2025-01-31" },
1174
1316
  },
1175
- panels: [{ id: "main" }],
1176
- series: [{
1177
- id: "price",
1317
+ series: [chartSeries({
1178
1318
  source: { kind: "security", instrument: { symbol: "TEST" }, fieldId: "market.close" },
1179
- style: "line",
1180
- transform: "raw",
1181
- axis: "left",
1182
- panelId: "main",
1183
- interpolation: "none",
1184
- }],
1185
- studies: [],
1186
- };
1319
+ })],
1320
+ });
1187
1321
 
1188
1322
  const result = await resolveChartSpecData(spec, {
1189
1323
  dataProvider: provider,
@@ -1209,15 +1343,13 @@ describe("resolveChartSpecData", () => {
1209
1343
  }],
1210
1344
  }),
1211
1345
  });
1212
- const spec: ChartSpec = {
1213
- version: CHART_SPEC_VERSION,
1346
+ const spec: ChartSpec = chartSpec({
1214
1347
  viewport: {
1215
1348
  range: "1M",
1216
1349
  resolution: "auto",
1217
1350
  dateWindow: { start: "2025-01-01", end: "2025-01-31" },
1218
1351
  },
1219
- panels: [{ id: "main" }],
1220
- series: [{
1352
+ series: [chartSeries({
1221
1353
  id: "revenue",
1222
1354
  source: {
1223
1355
  kind: "security",
@@ -1227,13 +1359,9 @@ describe("resolveChartSpecData", () => {
1227
1359
  timestampMode: "available-at",
1228
1360
  },
1229
1361
  style: "step",
1230
- transform: "raw",
1231
- axis: "left",
1232
- panelId: "main",
1233
1362
  interpolation: "step-after",
1234
- }],
1235
- studies: [],
1236
- };
1363
+ })],
1364
+ });
1237
1365
 
1238
1366
  const result = await resolveChartSpecData(spec, {
1239
1367
  dataProvider: provider,
@@ -1251,6 +1379,7 @@ describe("resolveChartSpecData", () => {
1251
1379
  const provider = createTestDataProvider({
1252
1380
  getTickerFinancials: async (symbol) => ({
1253
1381
  ...emptyFinancials(),
1382
+ financialCurrency: "USD",
1254
1383
  quarterlyStatements: symbol === "LEFT"
1255
1384
  ? [
1256
1385
  {
@@ -1282,7 +1411,7 @@ describe("resolveChartSpecData", () => {
1282
1411
  ],
1283
1412
  }),
1284
1413
  });
1285
- const fundamental = (id: string, symbol: string): ChartSpec["series"][number] => ({
1414
+ const fundamental = (id: string, symbol: string): ChartSpec["series"][number] => (chartSeries({
1286
1415
  id,
1287
1416
  source: {
1288
1417
  kind: "security",
@@ -1294,13 +1423,8 @@ describe("resolveChartSpecData", () => {
1294
1423
  // The built-in fundamental comparison preset uses columns without
1295
1424
  // display interpolation; formula calculation still uses as-of values.
1296
1425
  style: "columns",
1297
- transform: "raw",
1298
- axis: "left",
1299
- panelId: "main",
1300
- interpolation: "none",
1301
- });
1302
- const spec: ChartSpec = {
1303
- version: CHART_SPEC_VERSION,
1426
+ }));
1427
+ const spec: ChartSpec = chartSpec({
1304
1428
  viewport: {
1305
1429
  range: "1Y",
1306
1430
  resolution: "auto",
@@ -1326,7 +1450,7 @@ describe("resolveChartSpecData", () => {
1326
1450
  axis: "left",
1327
1451
  },
1328
1452
  ],
1329
- };
1453
+ });
1330
1454
 
1331
1455
  const result = await resolveChartSpecData(spec, {
1332
1456
  dataProvider: provider,
@@ -1373,16 +1497,14 @@ describe("resolveChartSpecData", () => {
1373
1497
  ],
1374
1498
  }),
1375
1499
  });
1376
- const spec: ChartSpec = {
1377
- version: CHART_SPEC_VERSION,
1500
+ const spec: ChartSpec = chartSpec({
1378
1501
  viewport: {
1379
1502
  range: "ALL",
1380
1503
  resolution: "auto",
1381
1504
  dateWindow: { start: "2025-01-01", end: "2025-02-28" },
1382
1505
  maxPoints: 1,
1383
1506
  },
1384
- panels: [{ id: "main" }],
1385
- series: [{
1507
+ series: [chartSeries({
1386
1508
  id: "revenue",
1387
1509
  source: {
1388
1510
  kind: "security",
@@ -1392,13 +1514,9 @@ describe("resolveChartSpecData", () => {
1392
1514
  timestampMode: "available-at",
1393
1515
  },
1394
1516
  style: "step",
1395
- transform: "raw",
1396
- axis: "left",
1397
- panelId: "main",
1398
1517
  interpolation: "step-after",
1399
- }],
1400
- studies: [],
1401
- };
1518
+ })],
1519
+ });
1402
1520
 
1403
1521
  const result = await resolveChartSpecData(spec, {
1404
1522
  dataProvider: provider,
@@ -1422,24 +1540,16 @@ describe("resolveChartSpecData", () => {
1422
1540
  { date: new Date("2025-01-03T16:00:00Z"), close: 30 },
1423
1541
  ],
1424
1542
  });
1425
- const spec: ChartSpec = {
1426
- version: CHART_SPEC_VERSION,
1543
+ const spec: ChartSpec = chartSpec({
1427
1544
  viewport: { range: "1Y", resolution: "1d" },
1428
- panels: [{ id: "main" }],
1429
- series: [{
1430
- id: "price",
1545
+ series: [chartSeries({
1431
1546
  source: {
1432
1547
  kind: "security",
1433
1548
  instrument: { symbol: "TEST", exchange: "NASDAQ" },
1434
1549
  fieldId: "market.close",
1435
1550
  },
1436
- style: "line",
1437
- transform: "raw",
1438
- axis: "left",
1439
- panelId: "main",
1440
- interpolation: "none",
1441
1551
  visible: false,
1442
- }],
1552
+ })],
1443
1553
  studies: [{
1444
1554
  id: "sma",
1445
1555
  kind: "sma",
@@ -1448,7 +1558,7 @@ describe("resolveChartSpecData", () => {
1448
1558
  panelId: "main",
1449
1559
  axis: "left",
1450
1560
  }],
1451
- };
1561
+ });
1452
1562
 
1453
1563
  const result = await resolveChartSpecData(spec, {
1454
1564
  dataProvider: provider,
@@ -1491,10 +1601,8 @@ describe("resolveChartSpecData", () => {
1491
1601
  { date: new Date(now - 86_400_000), close: 110 },
1492
1602
  ],
1493
1603
  });
1494
- const spec: ChartSpec = {
1495
- version: CHART_SPEC_VERSION,
1604
+ const spec: ChartSpec = chartSpec({
1496
1605
  viewport: { range: "1Y", resolution: "1d" },
1497
- panels: [{ id: "main" }],
1498
1606
  series: [{
1499
1607
  id: "price",
1500
1608
  source,
@@ -1512,7 +1620,7 @@ describe("resolveChartSpecData", () => {
1512
1620
  panelId: "main",
1513
1621
  axis: "left",
1514
1622
  }],
1515
- };
1623
+ });
1516
1624
  const quoteOverrides = new Map([[
1517
1625
  chartQuoteOverrideKeyForSource(source),
1518
1626
  {
@@ -1543,9 +1651,10 @@ describe("resolveChartSpecData", () => {
1543
1651
  expect(sma.points.at(-1)?.value).toBeCloseTo(15.5);
1544
1652
  });
1545
1653
 
1546
- test("keeps a quote received after resolution starts inside the latest viewport", async () => {
1547
- const now = Date.parse("2026-08-05T14:00:00Z");
1654
+ test.each([0, 60_000])("validates a quote received after resolution starts against %i ms elapsed", async (elapsed) => {
1655
+ const now = Date.parse("2026-08-05T22:00:00Z");
1548
1656
  const quoteTime = now + 60_000;
1657
+ const clock = spyOn(Date, "now").mockReturnValue(now);
1549
1658
  const provider = createTestDataProvider({
1550
1659
  getTickerFinancials: async () => ({
1551
1660
  ...emptyFinancials(),
@@ -1563,28 +1672,24 @@ describe("resolveChartSpecData", () => {
1563
1672
  postMarketChangePercent: -0.77,
1564
1673
  },
1565
1674
  }),
1566
- getPriceHistoryForResolution: async () => [
1567
- { date: new Date(now - 2 * 86_400_000), open: 99, high: 102, low: 98, close: 100 },
1568
- { date: new Date(now - 86_400_000), open: 100, high: 101, low: 99, close: 100 },
1569
- ],
1675
+ getPriceHistoryForResolution: async () => {
1676
+ clock.mockReturnValue(now + elapsed);
1677
+ return [
1678
+ { date: new Date(now - 2 * 86_400_000), open: 99, high: 102, low: 98, close: 100 },
1679
+ { date: new Date(now - 86_400_000), open: 100, high: 101, low: 99, close: 100 },
1680
+ ];
1681
+ },
1570
1682
  });
1571
- const spec: ChartSpec = {
1572
- version: CHART_SPEC_VERSION,
1683
+ const spec: ChartSpec = chartSpec({
1573
1684
  viewport: { range: "6M", resolution: "1d" },
1574
- panels: [{ id: "main" }],
1575
- series: [{
1576
- id: "price",
1685
+ series: [chartSeries({
1577
1686
  source: {
1578
1687
  kind: "security",
1579
1688
  instrument: { symbol: "FRESH", exchange: "XNAS" },
1580
1689
  fieldId: "market.ohlcv",
1581
1690
  },
1582
1691
  style: "candles",
1583
- transform: "raw",
1584
- axis: "left",
1585
- panelId: "main",
1586
- interpolation: "none",
1587
- }],
1692
+ })],
1588
1693
  studies: [{
1589
1694
  id: "sma",
1590
1695
  kind: "sma",
@@ -1593,42 +1698,89 @@ describe("resolveChartSpecData", () => {
1593
1698
  panelId: "main",
1594
1699
  axis: "left",
1595
1700
  }],
1596
- };
1701
+ });
1597
1702
 
1598
- const result = await resolveChartSpecData(spec, {
1703
+ try {
1704
+ const result = await resolveChartSpecData(spec, {
1705
+ dataProvider: provider,
1706
+ now: new Date(now),
1707
+ quoteOverrides: new Map([[
1708
+ chartQuoteOverrideKeyForSource({
1709
+ kind: "security",
1710
+ instrument: { symbol: "FRESH", exchange: "XNAS" },
1711
+ fieldId: "market.ohlcv",
1712
+ }),
1713
+ {
1714
+ symbol: "FRESH",
1715
+ price: 130,
1716
+ currency: "USD",
1717
+ change: 30,
1718
+ changePercent: 30,
1719
+ lastUpdated: quoteTime,
1720
+ listingExchangeName: "XNAS",
1721
+ marketState: "POST",
1722
+ postMarketPrice: 129,
1723
+ postMarketChange: -1,
1724
+ postMarketChangePercent: -0.77,
1725
+ },
1726
+ ]]),
1727
+ loadFredSeries: async () => fredLoad(),
1728
+ });
1729
+
1730
+ expect(result.errors).toEqual([]);
1731
+ expect(result.viewport?.end.getTime()).toBe(elapsed ? quoteTime : now);
1732
+ const price = result.series.find((entry) => entry.id === "price");
1733
+ const sma = result.series.find((entry) => entry.id === "sma");
1734
+ expect(price?.points.at(-1)?.date.getTime()).toBe(elapsed ? quoteTime : now - 86_400_000);
1735
+ expect(price?.points.at(-1)?.close).toBe(elapsed ? 129 : 100);
1736
+ expect(price?.latestChangePercent).toBe(elapsed ? 30 : undefined);
1737
+ expect(sma?.points.at(-1)?.date.getTime()).toBe(elapsed ? quoteTime : now - 86_400_000);
1738
+ } finally { clock.mockRestore(); }
1739
+ });
1740
+
1741
+ test.each(["line", "candles"] as const)("keeps one daily bar when a live quote updates a %s chart", async (style) => {
1742
+ const now = Date.parse("2026-09-10T18:44:00Z");
1743
+ const source = { kind: "security" as const, instrument: { symbol: "SQQQ", exchange: "NASDAQ" }, fieldId: "market.close" };
1744
+ const provider = createTestDataProvider({
1745
+ getPriceHistoryForResolution: async () => [{
1746
+ date: new Date("2026-09-10T13:30:00Z"), open: 40, high: 41, low: 39, close: 39.77, volume: 1000,
1747
+ }],
1748
+ });
1749
+ const result = await resolveChartSpecData(chartSpec({
1750
+ viewport: { range: "1M", resolution: "1d" },
1751
+ series: [{ id: "price", source, style, transform: "raw", axis: "left", panelId: "main", interpolation: "none" }],
1752
+ }), {
1599
1753
  dataProvider: provider,
1600
1754
  now: new Date(now),
1601
- quoteOverrides: new Map([[
1602
- chartQuoteOverrideKeyForSource({
1603
- kind: "security",
1604
- instrument: { symbol: "FRESH", exchange: "XNAS" },
1605
- fieldId: "market.ohlcv",
1606
- }),
1607
- {
1608
- symbol: "FRESH",
1609
- price: 130,
1610
- currency: "USD",
1611
- change: 30,
1612
- changePercent: 30,
1613
- lastUpdated: quoteTime,
1614
- listingExchangeName: "XNAS",
1615
- marketState: "POST",
1616
- postMarketPrice: 129,
1617
- postMarketChange: -1,
1618
- postMarketChangePercent: -0.77,
1619
- },
1620
- ]]),
1621
- loadFredSeries: async () => fredLoad(),
1755
+ quoteOverrides: new Map([[chartQuoteOverrideKeyForSource(source), {
1756
+ symbol: "SQQQ", price: 39.75, currency: "USD", change: 0, changePercent: 0,
1757
+ lastUpdated: now, listingExchangeName: "NASDAQ", marketState: "REGULAR",
1758
+ }]]),
1622
1759
  });
1760
+ expect(result.errors).toEqual([]);
1761
+ expect(result.series[0]?.points).toHaveLength(1);
1762
+ expect(result.series[0]?.points[0]).toMatchObject({ value: 39.75, open: 40, high: 41, low: 39, volume: 1000 });
1763
+ });
1623
1764
 
1765
+ test("retains the known listing session when the quote omits exchange metadata", async () => {
1766
+ const now = Date.parse("2026-09-11T00:01:00Z");
1767
+ const source = { kind: "security" as const, instrument: { symbol: "SQQQ", exchange: "NASDAQ" }, fieldId: "market.close" };
1768
+ const result = await resolveChartSpecData(chartSpec({
1769
+ viewport: { range: "1M", resolution: "1d" },
1770
+ series: [{ id: "price", source, style: "line", transform: "raw", axis: "left", panelId: "main", interpolation: "none" }],
1771
+ }), {
1772
+ dataProvider: createTestDataProvider({ getPriceHistoryForResolution: async () => [
1773
+ { date: new Date("2026-09-10T00:00:00Z"), close: 100 },
1774
+ ] }),
1775
+ now: new Date(now),
1776
+ quoteOverrides: new Map([[chartQuoteOverrideKeyForSource(source), {
1777
+ symbol: "SQQQ", price: 100, postMarketPrice: 105, currency: "USD", change: 0, changePercent: 0,
1778
+ lastUpdated: now - 60_000, marketState: "POST",
1779
+ }]]),
1780
+ });
1624
1781
  expect(result.errors).toEqual([]);
1625
- expect(result.viewport?.end.getTime()).toBe(quoteTime);
1626
- const price = result.series.find((entry) => entry.id === "price");
1627
- const sma = result.series.find((entry) => entry.id === "sma");
1628
- expect(price?.points.at(-1)?.date.getTime()).toBe(quoteTime);
1629
- expect(price?.points.at(-1)?.close).toBe(129);
1630
- expect(price?.latestChangePercent).toBe(30);
1631
- expect(sma?.points.at(-1)?.date.getTime()).toBe(quoteTime);
1782
+ expect(result.series[0]?.points).toHaveLength(1);
1783
+ expect(result.series[0]?.points[0]?.value).toBe(105);
1632
1784
  });
1633
1785
 
1634
1786
  test("reuses raw source loads while live quotes recompute the chart tail", async () => {
@@ -1651,10 +1803,8 @@ describe("resolveChartSpecData", () => {
1651
1803
  return [{ date: new Date(now - 86_400_000), close: 100 }];
1652
1804
  },
1653
1805
  });
1654
- const spec: ChartSpec = {
1655
- version: CHART_SPEC_VERSION,
1806
+ const spec: ChartSpec = chartSpec({
1656
1807
  viewport: { range: "1Y", resolution: "1d" },
1657
- panels: [{ id: "main" }],
1658
1808
  series: [{
1659
1809
  id: "price",
1660
1810
  source,
@@ -1663,17 +1813,12 @@ describe("resolveChartSpecData", () => {
1663
1813
  axis: "left",
1664
1814
  panelId: "main",
1665
1815
  interpolation: "none",
1666
- }, {
1816
+ }, chartSeries({
1667
1817
  id: "cpi",
1668
1818
  source: { kind: "economic", provider: "fred", seriesId: "CPIAUCSL" },
1669
- style: "line",
1670
- transform: "raw",
1671
1819
  axis: "right",
1672
- panelId: "main",
1673
- interpolation: "none",
1674
- }],
1675
- studies: [],
1676
- };
1820
+ })],
1821
+ });
1677
1822
  const loadFredSeries = async () => {
1678
1823
  fredCalls += 1;
1679
1824
  return fredLoad({
@@ -1776,6 +1921,7 @@ describe("resolveChartSpecData", () => {
1776
1921
  getTickerFinancials: async () => ({
1777
1922
  ...emptyFinancials(),
1778
1923
  quarterlyStatements: statements,
1924
+ financialCurrency: "USD",
1779
1925
  quote: {
1780
1926
  symbol: "LIVE",
1781
1927
  price: 50,
@@ -1799,7 +1945,7 @@ describe("resolveChartSpecData", () => {
1799
1945
  "evEbitda",
1800
1946
  "priceFcf",
1801
1947
  ] as const;
1802
- const makeSeries = (metric: typeof valuationFields[number]): ChartSpec["series"][number] => ({
1948
+ const makeSeries = (metric: typeof valuationFields[number]): ChartSpec["series"][number] => (chartSeries({
1803
1949
  id: metric,
1804
1950
  source: {
1805
1951
  kind: "security",
@@ -1809,18 +1955,12 @@ describe("resolveChartSpecData", () => {
1809
1955
  timestampMode: "available-at",
1810
1956
  },
1811
1957
  style: "step",
1812
- transform: "raw",
1813
- axis: "left",
1814
- panelId: "main",
1815
1958
  interpolation: "step-after",
1816
- });
1817
- const spec: ChartSpec = {
1818
- version: CHART_SPEC_VERSION,
1959
+ }));
1960
+ const spec: ChartSpec = chartSpec({
1819
1961
  viewport: { range: "1Y", resolution: "1d" },
1820
- panels: [{ id: "main" }],
1821
1962
  series: valuationFields.map(makeSeries),
1822
- studies: [],
1823
- };
1963
+ });
1824
1964
  const firstSource = spec.series[0]!.source;
1825
1965
  if (firstSource.kind !== "security") throw new Error("expected security source");
1826
1966
  const quoteOverrides = new Map([[
@@ -1881,7 +2021,7 @@ describe("resolveChartSpecData", () => {
1881
2021
  return [];
1882
2022
  },
1883
2023
  });
1884
- const makeSeries = (metric: "forwardPE" | "pegRatio"): ChartSpec["series"][number] => ({
2024
+ const makeSeries = (metric: "forwardPE" | "pegRatio"): ChartSpec["series"][number] => (chartSeries({
1885
2025
  id: metric,
1886
2026
  source: {
1887
2027
  kind: "security",
@@ -1890,18 +2030,12 @@ describe("resolveChartSpecData", () => {
1890
2030
  timestampMode: "available-at",
1891
2031
  },
1892
2032
  style: "step",
1893
- transform: "raw",
1894
- axis: "left",
1895
- panelId: "main",
1896
2033
  interpolation: "step-after",
1897
- });
1898
- const spec: ChartSpec = {
1899
- version: CHART_SPEC_VERSION,
2034
+ }));
2035
+ const spec: ChartSpec = chartSpec({
1900
2036
  viewport: { range: "1Y", resolution: "1d" },
1901
- panels: [{ id: "main" }],
1902
2037
  series: [makeSeries("forwardPE"), makeSeries("pegRatio")],
1903
- studies: [],
1904
- };
2038
+ });
1905
2039
  const firstSource = spec.series[0]!.source;
1906
2040
  if (firstSource.kind !== "security") throw new Error("expected security source");
1907
2041
  const quoteOverrides = new Map([[
@@ -1961,10 +2095,8 @@ describe("resolveChartSpecData", () => {
1961
2095
  },
1962
2096
  ],
1963
2097
  });
1964
- const spec: ChartSpec = {
1965
- version: CHART_SPEC_VERSION,
2098
+ const spec: ChartSpec = chartSpec({
1966
2099
  viewport: { range: "1D", resolution: "5m" },
1967
- panels: [{ id: "main" }],
1968
2100
  series: [{
1969
2101
  id: "price",
1970
2102
  source,
@@ -1974,8 +2106,7 @@ describe("resolveChartSpecData", () => {
1974
2106
  panelId: "main",
1975
2107
  interpolation: "none",
1976
2108
  }],
1977
- studies: [],
1978
- };
2109
+ });
1979
2110
  const quoteOverrides = new Map([[
1980
2111
  chartQuoteOverrideKeyForSource(source),
1981
2112
  {
@@ -2022,17 +2153,12 @@ describe("resolveChartSpecData", () => {
2022
2153
  { date: new Date("2025-01-02T00:00:00Z"), close: 240, volume: 2_400 },
2023
2154
  ],
2024
2155
  });
2025
- const makeSeries = (id: string, symbol: string): ChartSpec["series"][number] => ({
2156
+ const makeSeries = (id: string, symbol: string): ChartSpec["series"][number] => (chartSeries({
2026
2157
  id,
2027
2158
  source: { kind: "security", instrument: { symbol }, fieldId: "market.ohlcv" },
2028
- style: "line",
2029
2159
  transform: "percent",
2030
- axis: "left",
2031
- panelId: "main",
2032
- interpolation: "none",
2033
- });
2034
- const spec: ChartSpec = {
2035
- version: CHART_SPEC_VERSION,
2160
+ }));
2161
+ const spec: ChartSpec = chartSpec({
2036
2162
  viewport: { range: "1Y", resolution: "1d" },
2037
2163
  panels: [{ id: "main" }, { id: "formula" }, { id: "volume" }],
2038
2164
  series: [makeSeries("left", "LEFT"), makeSeries("right", "RIGHT")],
@@ -2062,7 +2188,7 @@ describe("resolveChartSpecData", () => {
2062
2188
  axis: "left",
2063
2189
  },
2064
2190
  ],
2065
- };
2191
+ });
2066
2192
 
2067
2193
  const result = await resolveChartSpecData(spec, {
2068
2194
  dataProvider: provider,
@@ -2133,3 +2259,39 @@ describe("mergePriceHistoryWindows", () => {
2133
2259
  }
2134
2260
  });
2135
2261
  });
2262
+
2263
+ test("financial charts disclose snapshot vintages once without changing period or availability timestamps", async () => {
2264
+ const dataProvider = createTestDataProvider({ getTickerFinancials: async () => ({
2265
+ annualStatements: [{ date: "2017-06-30", totalRevenue: 96_571_000_000, netIncome: 25_489_000_000, fieldAvailability: { totalRevenue: "2018-08-03", netIncome: "2018-08-03" } }],
2266
+ quarterlyStatements: [], priceHistory: [],
2267
+ }) });
2268
+ for (const timestampMode of ["period-end", "available-at"] as const) {
2269
+ const result = await resolveChartSpecData(chartSpec({ viewport: { range: "ALL", resolution: "auto" },
2270
+ series: ["totalRevenue", "netIncome"].map((field) => chartSeries({ id: field, style: "columns",
2271
+ source: { kind: "security", instrument: { symbol: "MSFT", exchange: "NASDAQ" }, fieldId: `fundamental.${field}`, period: "annual", timestampMode },
2272
+ })),
2273
+ }), { dataProvider });
2274
+ expect(result.warnings.filter((warning) => warning === FINANCIAL_VINTAGE_NOTICE)).toHaveLength(1);
2275
+ expect(result.series[0]?.points[0]).toMatchObject({ value: 96_571_000_000, observedAt: new Date("2017-06-30T00:00:00Z"), availableAt: new Date("2018-08-03T00:00:00Z"), date: new Date(timestampMode === "period-end" ? "2017-06-30T00:00:00Z" : "2018-08-03T00:00:00Z") });
2276
+ }
2277
+ });
2278
+
2279
+ test.each([-9, 0, 12])("forward P/E chart handles reported multiple %s without inventing comparable points", async (forwardPE) => {
2280
+ const now = new Date("2026-06-01T16:00:00Z");
2281
+ const financials = { ...emptyFinancials(), fundamentals: { forwardPE },
2282
+ quote: { symbol: "TEST", price: 20, currency: "USD", change: 0, changePercent: 0, lastUpdated: now.getTime() } };
2283
+ const provider = createTestDataProvider({ getTickerFinancials: async () => financials });
2284
+ const spec = chartSpec({ viewport: { range: "1Y", resolution: "auto" }, series: [chartSeries({
2285
+ source: { kind: "security", instrument: { symbol: "TEST" }, fieldId: "valuation.forwardPE" },
2286
+ })] });
2287
+ const result = await resolveChartSpecData(spec, { dataProvider: provider, now, loadFredSeries: async () => fredLoad() });
2288
+ expect(result.errors).toEqual([]);
2289
+ if (forwardPE > 0) {
2290
+ expect(result.series[0]?.points.map((point) => point.value)).toEqual([12]);
2291
+ expect(result.series[0]?.warning).toBeUndefined();
2292
+ } else {
2293
+ expect(result.series[0]?.points).toEqual([]);
2294
+ expect(result.series[0]?.warning).toContain("not meaningful");
2295
+ }
2296
+ expect(financials.fundamentals.forwardPE).toBe(forwardPE);
2297
+ });