gloomberb 0.19.0 → 0.19.2

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 (304) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/package.json +2 -1
  4. package/patches/electrobun@1.18.1.patch +23 -1
  5. package/src/api-client/app-attention.ts +3 -0
  6. package/src/api-client/beneficial-owners.ts +3 -0
  7. package/src/api-client/company-kpis.ts +3 -0
  8. package/src/api-client/data.ts +2 -1
  9. package/src/api-client/errors.ts +38 -0
  10. package/src/api-client/hiring.ts +3 -0
  11. package/src/api-client/index.ts +4 -0
  12. package/src/api-client/ipo.ts +24 -1
  13. package/src/api-client/mna.ts +3 -0
  14. package/src/api-client/paths.ts +9 -1
  15. package/src/api-client/roadmap.ts +85 -0
  16. package/src/api-client/types.ts +12 -0
  17. package/src/app/runtime/startup.ts +3 -1
  18. package/src/architecture/core-builtin-allowlist.json +2 -2
  19. package/src/capabilities/chart-series.ts +2 -1
  20. package/src/cli/commands/market.ts +44 -16
  21. package/src/cli/commands/news-search.ts +22 -0
  22. package/src/cli/commands/overview.ts +84 -19
  23. package/src/cli/commands/search.ts +13 -13
  24. package/src/cli/commands/ticker.ts +32 -2
  25. package/src/cli/context.ts +1 -0
  26. package/src/cli/errors.ts +17 -2
  27. package/src/cli/glossary.ts +8 -1
  28. package/src/cli/history-rows.ts +35 -7
  29. package/src/cli/index-roots.ts +0 -7
  30. package/src/cli/known-gaps.ts +11 -0
  31. package/src/cli/listing-arg.ts +74 -11
  32. package/src/cli/pane-functions/capabilities.ts +1 -0
  33. package/src/cli/pane-functions/discovery.ts +21 -1
  34. package/src/cli/pane-functions/freshness.ts +7 -1
  35. package/src/cli/pane-functions/function-help.ts +7 -0
  36. package/src/cli/pane-functions/index.ts +6 -3
  37. package/src/cli/quote-answer.ts +30 -7
  38. package/src/cli/saved-copy-persistence.ts +88 -0
  39. package/src/components/command-bar/list/model.ts +5 -0
  40. package/src/components/command-bar/routes/root/runtime.ts +29 -8
  41. package/src/components/command-bar/selection-runtime.ts +64 -32
  42. package/src/components/command-bar/surface/index.tsx +2 -0
  43. package/src/components/layout/detached-pane-shell.tsx +2 -2
  44. package/src/components/layout/header.tsx +2 -2
  45. package/src/components/layout/pane/capture-stamp.ts +2 -2
  46. package/src/components/layout/pane/footer/index.tsx +23 -6
  47. package/src/components/layout/pane/footer/model.ts +116 -16
  48. package/src/components/layout/pane/header.tsx +2 -2
  49. package/src/components/layout/pane/status-footer.ts +37 -3
  50. package/src/components/layout/status-widget-space.ts +9 -0
  51. package/src/components/onboarding/onboarding-frame.tsx +2 -1
  52. package/src/components/onboarding/onboarding-wizard.tsx +6 -3
  53. package/src/components/ticker/list-table-view.tsx +4 -20
  54. package/src/components/ui/display.tsx +29 -3
  55. package/src/components/ui/icon.tsx +12 -3
  56. package/src/core/app-services.ts +11 -2
  57. package/src/data/app-persistence.ts +9 -7
  58. package/src/data/plugin-cache.ts +20 -3
  59. package/src/data/plugin-state-store.ts +81 -24
  60. package/src/data/resource-store.ts +130 -58
  61. package/src/data/saved-copies.ts +8 -0
  62. package/src/data/session-store.ts +31 -8
  63. package/src/data/sqlite/access.ts +313 -0
  64. package/src/data/sqlite/checkpointer.ts +198 -0
  65. package/src/data/sqlite/database.ts +47 -4
  66. package/src/data/sqlite/retry.ts +50 -9
  67. package/src/data/ticker-store.ts +57 -23
  68. package/src/docs/snapshot.json +32 -5
  69. package/src/i18n/es.ts +2 -4
  70. package/src/i18n/ja.ts +2 -4
  71. package/src/i18n/ko.ts +2 -4
  72. package/src/i18n/zh-cn.ts +2 -4
  73. package/src/i18n/zh-tw.ts +2 -4
  74. package/src/market-data/depositary-pair.ts +25 -1
  75. package/src/market-data/quotes/metadata.ts +7 -0
  76. package/src/market-data/realized-volatility.ts +4 -2
  77. package/src/news/aggregator.ts +7 -1
  78. package/src/news/types.ts +6 -0
  79. package/src/plugins/auto-update-node.ts +10 -6
  80. package/src/plugins/builtin/alerts/calendar-events.ts +10 -4
  81. package/src/plugins/builtin/alerts/cli.ts +34 -11
  82. package/src/plugins/builtin/alerts/event-rows.ts +24 -3
  83. package/src/plugins/builtin/alerts/events-pane.tsx +15 -6
  84. package/src/plugins/builtin/alerts/headless.ts +10 -6
  85. package/src/plugins/builtin/cds/client.ts +142 -30
  86. package/src/plugins/builtin/cds/headless.ts +35 -8
  87. package/src/plugins/builtin/cds/model.ts +145 -18
  88. package/src/plugins/builtin/cds/pane.tsx +16 -5
  89. package/src/plugins/builtin/central-bank-rates/series.ts +2 -3
  90. package/src/plugins/builtin/chart-composer/cli-options.ts +16 -0
  91. package/src/plugins/builtin/chart-composer/follow-binding.ts +14 -2
  92. package/src/plugins/builtin/chart-composer/headless-schema.ts +5 -0
  93. package/src/plugins/builtin/chart-composer/index.tsx +4 -5
  94. package/src/plugins/builtin/chart-composer/pane.tsx +5 -1
  95. package/src/plugins/builtin/chart-composer/session-range.ts +5 -2
  96. package/src/plugins/builtin/chat/controller/index.ts +5 -1
  97. package/src/plugins/builtin/chat/controller/notifications.ts +33 -3
  98. package/src/plugins/builtin/chat/controller/state.ts +25 -2
  99. package/src/plugins/builtin/chat/controller/unread-people.ts +89 -23
  100. package/src/plugins/builtin/chat/controller/utils.ts +7 -2
  101. package/src/plugins/builtin/chat/status-preview.ts +79 -0
  102. package/src/plugins/builtin/chat/status-widget.tsx +147 -10
  103. package/src/plugins/builtin/chat/unread-badge.ts +51 -10
  104. package/src/plugins/builtin/clinical-trials/client.ts +49 -4
  105. package/src/plugins/builtin/clinical-trials/model.ts +86 -22
  106. package/src/plugins/builtin/clinical-trials/pane.tsx +46 -27
  107. package/src/plugins/builtin/clinical-trials/sponsor-listing.ts +90 -0
  108. package/src/plugins/builtin/clinical-trials/sponsor-tickers.ts +87 -9
  109. package/src/plugins/builtin/clinical-trials/trial-pages.ts +50 -0
  110. package/src/plugins/builtin/commodity-balances/client.ts +4 -1
  111. package/src/plugins/builtin/company-attention/headless.ts +2 -1
  112. package/src/plugins/builtin/company-attention/pane.tsx +3 -0
  113. package/src/plugins/builtin/company-kpis/headless.ts +8 -3
  114. package/src/plugins/builtin/company-kpis/model.ts +73 -5
  115. package/src/plugins/builtin/company-kpis/pane.tsx +15 -7
  116. package/src/plugins/builtin/composite-plugins.ts +2 -1
  117. package/src/plugins/builtin/cot/client.ts +28 -2
  118. package/src/plugins/builtin/cot/headless.ts +4 -1
  119. package/src/plugins/builtin/cot/index.tsx +4 -2
  120. package/src/plugins/builtin/cot/model.ts +58 -7
  121. package/src/plugins/builtin/cot/pane.tsx +6 -2
  122. package/src/plugins/builtin/cpi/client.ts +6 -5
  123. package/src/plugins/builtin/credit-boards/series.ts +3 -4
  124. package/src/plugins/builtin/credit-conditions/client.ts +22 -14
  125. package/src/plugins/builtin/credit-documents/headless.ts +3 -3
  126. package/src/plugins/builtin/crypto-board/client.ts +5 -5
  127. package/src/plugins/builtin/crypto-board/series.ts +4 -4
  128. package/src/plugins/builtin/debt-maturities/series.ts +3 -3
  129. package/src/plugins/builtin/doe/client.ts +6 -5
  130. package/src/plugins/builtin/doe/headless.ts +3 -2
  131. package/src/plugins/builtin/doe/pane.tsx +13 -3
  132. package/src/plugins/builtin/doe/prices.ts +2 -3
  133. package/src/plugins/builtin/doe/series.ts +4 -4
  134. package/src/plugins/builtin/earnings-calls/calendar.tsx +10 -2
  135. package/src/plugins/builtin/earnings-calls/data.ts +37 -17
  136. package/src/plugins/builtin/earnings-calls/headless.ts +13 -3
  137. package/src/plugins/builtin/earnings-calls/pane.tsx +34 -14
  138. package/src/plugins/builtin/econ/calendar-model.ts +48 -1
  139. package/src/plugins/builtin/econ/calendar-source.ts +4 -2
  140. package/src/plugins/builtin/econ/detail-view.tsx +18 -4
  141. package/src/plugins/builtin/econ/figures.ts +48 -0
  142. package/src/plugins/builtin/econ/index.tsx +14 -5
  143. package/src/plugins/builtin/econ/print-watch.ts +3 -1
  144. package/src/plugins/builtin/econ-statistics/client.ts +11 -0
  145. package/src/plugins/builtin/econ-statistics/headless.ts +10 -2
  146. package/src/plugins/builtin/econ-statistics/pane.tsx +8 -4
  147. package/src/plugins/builtin/econ-statistics/stats.ts +3 -0
  148. package/src/plugins/builtin/executives/data.ts +6 -1
  149. package/src/plugins/builtin/executives/pane.tsx +9 -21
  150. package/src/plugins/builtin/fear-greed/cache.ts +4 -0
  151. package/src/plugins/builtin/fear-greed/series.ts +6 -4
  152. package/src/plugins/builtin/gpu/client.ts +4 -1
  153. package/src/plugins/builtin/gpu/series.ts +2 -3
  154. package/src/plugins/builtin/help/index.tsx +61 -59
  155. package/src/plugins/builtin/help/shortcut-table.tsx +5 -6
  156. package/src/plugins/builtin/help/table-cells.tsx +13 -2
  157. package/src/plugins/builtin/holders/beneficial-client.ts +5 -1
  158. package/src/plugins/builtin/holders/beneficial-view.tsx +4 -2
  159. package/src/plugins/builtin/holders/headless.ts +4 -2
  160. package/src/plugins/builtin/holders/pane.tsx +3 -0
  161. package/src/plugins/builtin/holders/report-rows.ts +4 -1
  162. package/src/plugins/builtin/insider/headless.ts +2 -2
  163. package/src/plugins/builtin/ipo-calendar/client.ts +18 -2
  164. package/src/plugins/builtin/ipo-calendar/headless.ts +75 -11
  165. package/src/plugins/builtin/ipo-calendar/listing-ipo.ts +160 -0
  166. package/src/plugins/builtin/ipo-calendar/model.ts +98 -2
  167. package/src/plugins/builtin/jodi/client.ts +4 -1
  168. package/src/plugins/builtin/macro-day/headless.ts +12 -5
  169. package/src/plugins/builtin/macro-day/index.tsx +1 -1
  170. package/src/plugins/builtin/macro-day/model.ts +39 -5
  171. package/src/plugins/builtin/macro-day/pane.tsx +27 -19
  172. package/src/plugins/builtin/market-movers/client.ts +3 -0
  173. package/src/plugins/builtin/market-movers/headless.ts +3 -1
  174. package/src/plugins/builtin/market-movers/index.tsx +10 -5
  175. package/src/plugins/builtin/market-movers/screener.ts +27 -6
  176. package/src/plugins/builtin/market-movers/session-body.tsx +2 -1
  177. package/src/plugins/builtin/mna/headless.ts +2 -0
  178. package/src/plugins/builtin/mna/pane.tsx +3 -1
  179. package/src/plugins/builtin/money-markets/series.ts +3 -5
  180. package/src/plugins/builtin/news/headless.ts +3 -1
  181. package/src/plugins/builtin/news/index.tsx +3 -0
  182. package/src/plugins/builtin/portfolio-list/pane/index.tsx +2 -6
  183. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +0 -14
  184. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +2 -1
  185. package/src/plugins/builtin/portfolio-list/table.tsx +4 -6
  186. package/src/plugins/builtin/power/gas-client.ts +2 -1
  187. package/src/plugins/builtin/power/prices-client.ts +3 -2
  188. package/src/plugins/builtin/realized-vol/client.ts +13 -5
  189. package/src/plugins/builtin/realized-vol/evidence.ts +29 -4
  190. package/src/plugins/builtin/realized-vol/headless.ts +8 -4
  191. package/src/plugins/builtin/realized-vol/model.ts +37 -6
  192. package/src/plugins/builtin/realized-vol/pane.tsx +9 -7
  193. package/src/plugins/builtin/research/event-model.ts +30 -4
  194. package/src/plugins/builtin/research/index.tsx +7 -3
  195. package/src/plugins/builtin/research/relative-valuation-headless.ts +8 -25
  196. package/src/plugins/builtin/research/relative-valuation-pane.tsx +52 -15
  197. package/src/plugins/builtin/research/relative-valuation-peers.ts +217 -20
  198. package/src/plugins/builtin/research/relative-valuation-settings.ts +44 -0
  199. package/src/plugins/builtin/risk-factors/data.ts +12 -6
  200. package/src/plugins/builtin/risk-factors/headless.ts +5 -2
  201. package/src/plugins/builtin/risk-factors/index.tsx +3 -1
  202. package/src/plugins/builtin/risk-factors/pane.tsx +5 -8
  203. package/src/plugins/builtin/roadmap/index.tsx +28 -0
  204. package/src/plugins/builtin/roadmap/model.ts +67 -0
  205. package/src/plugins/builtin/roadmap/pane.tsx +244 -0
  206. package/src/plugins/builtin/scanner/live-headless.ts +21 -2
  207. package/src/plugins/builtin/scanner/lock-note.ts +26 -3
  208. package/src/plugins/builtin/sec/headless.ts +2 -1
  209. package/src/plugins/builtin/sec/index.tsx +3 -0
  210. package/src/plugins/builtin/shared/cloud-resource.ts +20 -7
  211. package/src/plugins/builtin/shared/fred-points.ts +6 -1
  212. package/src/plugins/builtin/shared/headless-market-data.ts +2 -2
  213. package/src/plugins/builtin/shared/pro-lock-note.ts +23 -8
  214. package/src/plugins/builtin/shared/report-freshness.ts +8 -0
  215. package/src/plugins/builtin/shared/research-cells.tsx +1 -1
  216. package/src/plugins/builtin/shared/series-cache.ts +4 -4
  217. package/src/plugins/builtin/shared/series-warning.ts +13 -4
  218. package/src/plugins/builtin/short-volume/series.ts +2 -3
  219. package/src/plugins/builtin/social-mentions/client.ts +15 -10
  220. package/src/plugins/builtin/social-mentions/series.ts +2 -3
  221. package/src/plugins/builtin/thirteenf/api.ts +15 -9
  222. package/src/plugins/builtin/thirteenf/data.ts +39 -11
  223. package/src/plugins/builtin/thirteenf/headless.ts +31 -4
  224. package/src/plugins/builtin/thirteenf/overlap-pane.tsx +5 -1
  225. package/src/plugins/builtin/thirteenf/pane.tsx +21 -5
  226. package/src/plugins/builtin/thirteenf/types.ts +2 -0
  227. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +5 -2
  228. package/src/plugins/builtin/ticker-detail/financials/model.ts +35 -2
  229. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +53 -18
  230. package/src/plugins/builtin/ticker-detail/headless.ts +59 -8
  231. package/src/plugins/builtin/ticker-detail/overview/model.ts +10 -2
  232. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +2 -1
  233. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -6
  234. package/src/plugins/builtin/treasury-auctions/cache.ts +20 -8
  235. package/src/plugins/builtin/treasury-auctions/client.ts +3 -3
  236. package/src/plugins/builtin/treasury-auctions/headless.ts +24 -13
  237. package/src/plugins/builtin/treasury-auctions/pane.tsx +18 -6
  238. package/src/plugins/builtin/volatility/client.ts +43 -16
  239. package/src/plugins/builtin/volatility/headless.ts +5 -2
  240. package/src/plugins/builtin/volatility/model.ts +17 -6
  241. package/src/plugins/builtin/volatility/pane.tsx +11 -4
  242. package/src/plugins/builtin/volatility/series.ts +2 -1
  243. package/src/plugins/builtin/yield-curve/client.ts +59 -1
  244. package/src/plugins/builtin/yield-curve/headless.ts +9 -6
  245. package/src/plugins/builtin/yield-curve/index.tsx +34 -10
  246. package/src/plugins/builtin/yield-curve/swaps.tsx +9 -5
  247. package/src/plugins/catalog-browser.ts +2 -1
  248. package/src/plugins/host-link.ts +1 -1
  249. package/src/plugins/installer.ts +50 -39
  250. package/src/portfolio/column-values.ts +11 -7
  251. package/src/renderers/dom/desktop/icons.tsx +10 -2
  252. package/src/renderers/electrobun/bun/desktop/backend.ts +9 -10
  253. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +23 -1
  254. package/src/renderers/electrobun/bun/desktop/host-requests.ts +8 -0
  255. package/src/renderers/electrobun/bun/desktop/initialization.ts +9 -1
  256. package/src/renderers/electrobun/bun/desktop/installer-folder.ts +731 -0
  257. package/src/renderers/electrobun/bun/desktop/relaunch.ts +102 -10
  258. package/src/renderers/electrobun/bun/desktop/windows-script.ts +92 -0
  259. package/src/renderers/electrobun/bun/index.ts +26 -2
  260. package/src/renderers/electrobun/bun/window/attention.ts +54 -0
  261. package/src/renderers/electrobun/bun/window/create.ts +45 -4
  262. package/src/renderers/electrobun/bun/window/events.ts +20 -0
  263. package/src/renderers/electrobun/bun/window/windows-custom-chrome.ts +9 -2
  264. package/src/renderers/electrobun/bun/window/windows-native.ts +78 -0
  265. package/src/renderers/electrobun/bun/window/windows-quit.ts +57 -0
  266. package/src/renderers/electrobun/launcher/preload.ts +13 -0
  267. package/src/renderers/electrobun/launcher/windows-emulation.ts +50 -0
  268. package/src/renderers/electrobun/shared/protocol.ts +2 -0
  269. package/src/renderers/electrobun/view/news-source.ts +2 -0
  270. package/src/renderers/electrobun/view/ui-host.tsx +16 -1
  271. package/src/series/resolve.ts +2 -1
  272. package/src/series/types.ts +5 -0
  273. package/src/sources/gloomberb-cloud/fred-series.ts +8 -4
  274. package/src/sources/gloomberb-cloud/index.ts +42 -8
  275. package/src/telemetry/stall-reports-node.ts +13 -2
  276. package/src/telemetry/stall-reports.ts +189 -13
  277. package/src/test-support/outage.ts +8 -0
  278. package/src/tickers/company-name-listing.ts +110 -40
  279. package/src/tickers/company-name.ts +71 -2
  280. package/src/tickers/index-roots.ts +7 -0
  281. package/src/tickers/listing-fate.ts +2 -2
  282. package/src/tickers/search/home-listing.ts +93 -8
  283. package/src/tickers/search/index.ts +7 -3
  284. package/src/tickers/search/ranking.ts +5 -1
  285. package/src/tickers/search/upsert.ts +13 -0
  286. package/src/tickers/ticker-changes.ts +8 -4
  287. package/src/time-series/market.ts +5 -3
  288. package/src/time-series/price-comparison.ts +20 -2
  289. package/src/time-series/resolve.ts +20 -1
  290. package/src/time-series/types.ts +7 -0
  291. package/src/types/company-from.ts +40 -0
  292. package/src/types/data-provider.ts +7 -0
  293. package/src/types/financials.ts +45 -3
  294. package/src/types/headless.ts +6 -0
  295. package/src/ui/host.tsx +6 -1
  296. package/src/utils/crypto-pair.ts +121 -7
  297. package/src/utils/declared-dividends.ts +1 -1
  298. package/src/utils/financial-statements.ts +73 -16
  299. package/src/utils/fundamentals.ts +53 -10
  300. package/src/utils/lease-liabilities.ts +54 -0
  301. package/src/utils/main-thread-stall.ts +47 -2
  302. package/src/utils/perf-marks.ts +23 -11
  303. package/src/utils/price-history-integrity.ts +47 -1
  304. package/src/version.ts +2 -2
package/README.md CHANGED
@@ -50,7 +50,7 @@ The script downloads the prebuilt release from GitHub and checks its SHA-256 aga
50
50
  With [Bun](https://bun.sh), on any supported OS:
51
51
 
52
52
  ```bash
53
- bun install -g gloomberb
53
+ bun install -g @gloom-sh/terminal
54
54
  ```
55
55
 
56
56
  Then run `gloom`. The command was called `gloomberb` before 0.18.4, and that name still works. For chart graphics, use a Kitty-compatible terminal such as Ghostty, Kitty, or WezTerm. Windows Terminal draws charts as text; the desktop app draws them in full.
package/README.zh-CN.md CHANGED
@@ -62,7 +62,7 @@ curl -fsSL gloom.sh/install | bash
62
62
  也可在 macOS、Linux 或 Windows x64 上通过 [Bun](https://bun.sh) 安装:
63
63
 
64
64
  ```bash
65
- bun install -g gloomberb
65
+ bun install -g @gloom-sh/terminal
66
66
  ```
67
67
 
68
68
  运行 `gloom` 即可启动。0.18.4 之前命令名为 `gloomberb`,该名称仍可使用。要显示图形,请使用兼容 Kitty 图形协议的终端,例如 Ghostty、Kitty 或 WezTerm。直接下载、安装位置与更新方式详见[安装指南(英文)](docs/installation.md)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gloomberb",
3
- "version": "0.19.0",
3
+ "version": "0.19.2",
4
4
  "packageManager": "bun@1.3.11",
5
5
  "description": "Market research and portfolio tracker for the terminal",
6
6
  "module": "src/public/index.ts",
@@ -91,6 +91,7 @@
91
91
  "check:pane-layout": "bun run scripts/pane-chrome/layout-sweep.ts",
92
92
  "check:ui-tokens": "bun run scripts/pane-chrome/ui-tokens.ts",
93
93
  "ui:benchmark": "bun run scripts/pane-chrome/ui-benchmark.ts",
94
+ "ui:badge-ink": "bun run scripts/pane-chrome/badge-ink.ts",
94
95
  "audit:ui": "bun run scripts/pane-chrome/ui-audit.ts",
95
96
  "check:call-player": "bun run scripts/pane-chrome/call-player.ts",
96
97
  "check:chart-axis-zoom": "bun run scripts/pane-chrome/chart-axis-zoom.ts",
@@ -1,3 +1,16 @@
1
+ diff --git a/dist/api/browser/index.ts b/dist/api/browser/index.ts
2
+ index 3e309b18fdbcec84a4a56f97df4debe7fb8246f8..03420222c1d9ba897835c5e7376c7153ede294fc 100644
3
+ --- a/dist/api/browser/index.ts
4
+ +++ b/dist/api/browser/index.ts
5
+ @@ -50,7 +50,7 @@ class Electroview<T extends RPCWithTransport> {
6
+ // Note: Using ws:// for localhost is intentional - all RPC messages are
7
+ // encrypted with per-webview AES-GCM keys, making TLS redundant
8
+ const socket = new WebSocket(
9
+ - `ws://localhost:${RPC_SOCKET_PORT}/socket?webviewId=${WEBVIEW_ID}`,
10
+ + `ws://127.0.0.1:${RPC_SOCKET_PORT}/socket?webviewId=${WEBVIEW_ID}`,
11
+ );
12
+
13
+ this.bunSocket = socket;
1
14
  diff --git a/dist/api/bun/core/BrowserWindow.ts b/dist/api/bun/core/BrowserWindow.ts
2
15
  index c26c2c977ee1fc25a8dc144b85bac8626a45f572..8920a2905380228c23cba66c20d9bfd19ee13e02 100644
3
16
  --- a/dist/api/bun/core/BrowserWindow.ts
@@ -54,7 +67,7 @@ index c26c2c977ee1fc25a8dc144b85bac8626a45f572..8920a2905380228c23cba66c20d9bfd1
54
67
  width: this.frame.width,
55
68
  height: this.frame.height,
56
69
  diff --git a/dist/api/bun/core/Socket.ts b/dist/api/bun/core/Socket.ts
57
- index cdaa2bca0fabe577cb667056aa6f8f84211189c2..3839e5232742c2467180c344f51a30f1ff3c797f 100644
70
+ index cdaa2bca0fabe577cb667056aa6f8f84211189c2..e9cdd82c934f6da58055dc8343ee3b953ec1ee81 100644
58
71
  --- a/dist/api/bun/core/Socket.ts
59
72
  +++ b/dist/api/bun/core/Socket.ts
60
73
  @@ -3,13 +3,8 @@ import { BrowserView } from "./BrowserView";
@@ -73,6 +86,15 @@ index cdaa2bca0fabe577cb667056aa6f8f84211189c2..3839e5232742c2467180c344f51a30f1
73
86
  }
74
87
 
75
88
  // Encrypt function
89
+ @@ -65,6 +60,8 @@ const startRPCServer = () => {
90
+ while (port <= endPort) {
91
+ try {
92
+ server = Bun.serve<{ webviewId: number }>({
93
+ + // Only this machine's webviews connect.
94
+ + hostname: "127.0.0.1",
95
+ port,
96
+ fetch(req: Request, server: Server<{ webviewId: number }>) {
97
+ const url = new URL(req.url);
76
98
  diff --git a/dist/api/bun/core/Updater.ts b/dist/api/bun/core/Updater.ts
77
99
  index 39daf6d341780af8e30c2c50327162863f5977ec..4f3d2bef8e4b41a13a5a522c0af8dd700879a5db 100644
78
100
  --- a/dist/api/bun/core/Updater.ts
@@ -1,3 +1,4 @@
1
+ import type { CompanyFrom } from "../types/company-from"
1
2
  type AppStore = "app-store" | "google-play"
2
3
  export type AppChart = "free" | "paid" | "grossing" | "unranked"
3
4
 
@@ -97,6 +98,8 @@ interface AppSourceState {
97
98
  export interface AppAttentionPayload {
98
99
  generatedAt: string
99
100
  requestedSymbol?: string
101
+ /** The company's home line the data is read from, when not the listing asked (a receipt, a foreign line). */
102
+ companyFrom?: CompanyFrom
100
103
  page?: { offset: number; limit: number; total: number; nextOffset: number | null }
101
104
  symbol: string | null
102
105
  access: "pro" | "preview"
@@ -1,3 +1,4 @@
1
+ import type { CompanyFrom } from "../types/company-from";
1
2
  /**
2
3
  * Schedule 13D and 13G beneficial ownership reports about one issuer, as
3
4
  * `GET /cloud/sec/beneficial-owners` returns them. Percentages are percent
@@ -71,6 +72,8 @@ export interface BeneficialOwnersCoverage {
71
72
 
72
73
  export interface BeneficialOwnersPayload {
73
74
  ticker: string;
75
+ /** The company's home line the owners are read from, when not the listing asked (a foreign line). */
76
+ companyFrom?: CompanyFrom;
74
77
  cik: string;
75
78
  companyName: string;
76
79
  /** When the server assembled the list, an ISO time. */
@@ -1,3 +1,4 @@
1
+ import type { CompanyFrom } from "../types/company-from"
1
2
  import { listingAbroad, type IssuerListingParams } from "./paths";
2
3
 
3
4
  type QuoteMatchMode = "exact" | "whitespace" | "nfkc_whitespace";
@@ -132,6 +133,8 @@ export interface KpiSeries {
132
133
  }
133
134
  export interface KpisPayload {
134
135
  symbol: string
136
+ /** The company's home line the data is read from, when not the listing asked (a receipt, a foreign line). */
137
+ companyFrom?: CompanyFrom
135
138
  status: "available" | "unavailable"
136
139
  asOf: string | null
137
140
  coverage: KpiCoverage
@@ -1284,8 +1284,9 @@ export class CloudDataApi {
1284
1284
  query: string,
1285
1285
  limit?: number,
1286
1286
  topics?: readonly string[],
1287
+ options: { closest?: boolean; tickers?: readonly string[] } = {},
1287
1288
  ): Promise<CloudNewsListResponse> {
1288
- return this.request<CloudNewsListResponse>(cloudNewsSearchPath(query, limit, topics));
1289
+ return this.request<CloudNewsListResponse>(cloudNewsSearchPath(query, limit, topics, options));
1289
1290
  }
1290
1291
 
1291
1292
  async getCloudNewsStory(storyId: string): Promise<CloudNewsPayload> {
@@ -1,3 +1,5 @@
1
+ import { isNetworkFailure } from "../utils/network-failure";
2
+
1
3
  const HARD_SESSION_INVALID_PATTERNS = [
2
4
  /\b(user|account)\b.*\b(not found|deleted|removed|disabled|deactivated|suspended)\b/i,
3
5
  /\b(user|account)\b.*\bdoes(?:\s+not|n't)\s+exist\b/i,
@@ -61,6 +63,42 @@ export function isRetryableApiError(error: unknown): boolean {
61
63
  return error.code === "retryable_error" || status === 408 || status === 429 || (status !== undefined && status >= 500);
62
64
  }
63
65
 
66
+ /**
67
+ * A 200 reply saying its data is unavailable this time (a board's `unavailable`
68
+ * status, a market answer's `retryable_error`): the server's own source did
69
+ * not answer. Like a 5xx it may pass, so a saved copy answers it with its note.
70
+ * A permanent reason (a route not served yet, an unsupported symbol or series,
71
+ * sign-in or entitlement) comes as its status, or as a plain error, and stays
72
+ * the error.
73
+ */
74
+ export function sourceDidNotAnswer(message: string): ApiRequestError {
75
+ return new ApiRequestError(message, undefined, undefined, "retryable_error");
76
+ }
77
+
78
+ /** Codes of a connection that dropped or stalled after it opened: Node's and the system's, then Bun's. */
79
+ const INTERRUPTED_CODES = new Set(["ECONNRESET", "ECONNABORTED", "EPIPE", "ETIMEDOUT", "ConnectionClosed"]);
80
+
81
+ /**
82
+ * A failure asking again later may get past, which a copy saved earlier may
83
+ * answer for: no connection, a connection that dropped, a timeout, or a server
84
+ * that was rate limited or overloaded (408, 429, 5xx). Anything else the
85
+ * server answered (another 4xx) and an answer that failed validation are
86
+ * refusals to show as errors, saved copy or not. A bare throw with nothing to
87
+ * classify is not taken for a refusal.
88
+ */
89
+ export function isTransientFailure(error: unknown): boolean {
90
+ if (!error || typeof error !== "object") return typeof error !== "string" || isNetworkFailure(error);
91
+ if (isNetworkFailure(error) || isRetryableApiError(error)) return true;
92
+ for (let current: unknown = error, depth = 0; current && typeof current === "object" && depth < 4; depth += 1) {
93
+ if (current instanceof ApiRequestError) return false;
94
+ const { name, code } = current as { name?: unknown; code?: unknown };
95
+ if (name === "AbortError" || name === "TimeoutError") return true;
96
+ if (typeof code === "string" && INTERRUPTED_CODES.has(code)) return true;
97
+ current = (current as { cause?: unknown }).cause;
98
+ }
99
+ return false;
100
+ }
101
+
64
102
  /** Reads `Retry-After` as milliseconds, accepting seconds or an HTTP date. */
65
103
  export function parseRetryAfterMs(
66
104
  header: string | null,
@@ -1,3 +1,4 @@
1
+ import type { CompanyFrom } from "../types/company-from"
1
2
  /** HIRING is an observed requisition series, not headcount or job creation. */
2
3
  interface HiringCompany {
3
4
  entityId: string
@@ -76,6 +77,8 @@ export interface HiringSummary extends HiringCompany {
76
77
  export interface HiringPayload extends HiringSummary {
77
78
  generatedAt: string
78
79
  requestedSymbol?: string
80
+ /** The company's home line the data is read from, when not the listing asked (a receipt, a foreign line). */
81
+ companyFrom?: CompanyFrom
79
82
  proRequired: true
80
83
  preview: boolean
81
84
  locked: { history: number; evidence: number; peers: number; signals: number; mix: number }
@@ -24,6 +24,7 @@ import { CloudApiRequestTransport, putWithRevision } from "./request";
24
24
  import { CloudApiSocket } from "./socket";
25
25
  import { CloudCollectionsApi } from "./collections";
26
26
  import { CloudFeedbackApi } from "./feedback";
27
+ import { CloudRoadmapApi } from "./roadmap";
27
28
  import { CloudNotesApi } from "./notes";
28
29
  import { CloudTeamsApi } from "./teams";
29
30
  import { CloudTelemetryApi } from "./telemetry";
@@ -154,6 +155,7 @@ class GloomApiClient {
154
155
  private readonly data: CloudDataApi = new CloudDataApi((path, options) => this.request(path, options));
155
156
  private readonly notes: CloudNotesApi = new CloudNotesApi((path, options) => this.request(path, options));
156
157
  private readonly feedback: CloudFeedbackApi = new CloudFeedbackApi((path, options) => this.request(path, options));
158
+ private readonly roadmap: CloudRoadmapApi = new CloudRoadmapApi((path, options) => this.request(path, options));
157
159
  private readonly telemetry: CloudTelemetryApi = new CloudTelemetryApi((path, options) => this.request(path, options));
158
160
  private readonly theses: CloudThesesApi = new CloudThesesApi((path, options) => this.request(path, options));
159
161
  private readonly collections: CloudCollectionsApi = new CloudCollectionsApi((path, options) => this.request(path, options));
@@ -874,6 +876,8 @@ class GloomApiClient {
874
876
  putCloudNote = this.notes.putNote.bind(this.notes);
875
877
  submitFeedback = this.feedback.submitFeedback.bind(this.feedback);
876
878
  listFeedback = this.feedback.listFeedback.bind(this.feedback);
879
+ getRoadmap = this.roadmap.getRoadmap.bind(this.roadmap);
880
+ setRoadmapVote = this.roadmap.setRoadmapVote.bind(this.roadmap);
877
881
  reportCrashErrors = this.telemetry.reportCrashErrors.bind(this.telemetry);
878
882
  reportUsageCounts = this.telemetry.reportUsageCounts.bind(this.telemetry);
879
883
  reportAttentionCounts = this.telemetry.reportAttentionCounts.bind(this.telemetry);
@@ -28,6 +28,24 @@ interface IpoFirstDay {
28
28
  returnPct: number | null;
29
29
  }
30
30
 
31
+ /**
32
+ * When a US IPO's lock-up is estimated to end: the final prospectus's date
33
+ * plus the period it states, or the first session plus the usual 180 days
34
+ * until the prospectus is read. An estimate: underwriters can release
35
+ * shares early, and some holders agree to other periods.
36
+ */
37
+ export interface IpoLockup {
38
+ /** YYYY-MM-DD. */
39
+ endsOn: string;
40
+ days: number;
41
+ /** `prospectus`: the period the final prospectus states; `typical`: 180 days, when it states none of a lock-up's length or was not read. */
42
+ basis: "prospectus" | "typical";
43
+ /** The date the final prospectus is dated, when it was read. */
44
+ prospectusDate: string | null;
45
+ /** The SEC document the period was read from. */
46
+ prospectusUrl: string | null;
47
+ }
48
+
31
49
  export interface IpoDeal {
32
50
  /** Assigned when the deal is first seen and never changed. */
33
51
  id: string;
@@ -66,6 +84,8 @@ export interface IpoDeal {
66
84
  listingType: IpoListingType;
67
85
  filedDate: string | null;
68
86
  firstDay: IpoFirstDay | null;
87
+ /** A priced or listed US IPO's estimated lock-up end; absent elsewhere, and from a server without the estimate. */
88
+ lockup?: IpoLockup | null;
69
89
  updatedAt: string;
70
90
  }
71
91
 
@@ -86,11 +106,14 @@ export interface IpoCalendarPayload {
86
106
 
87
107
  /**
88
108
  * Narrows or moves the window. Without any, the server sends its default:
89
- * 90 days back to 180 ahead, filed and withdrawn deals left out, 500 at most.
109
+ * a year back (90 days on a server before that) to 180 days ahead, filed
110
+ * and withdrawn deals left out.
90
111
  */
91
112
  export interface IpoCalendarParams {
92
113
  region?: IpoRegion;
93
114
  status?: IpoStatus;
115
+ /** Company (in either script) or symbol the deals' names contain. */
116
+ q?: string;
94
117
  /** First listing date, YYYY-MM-DD. */
95
118
  from?: string;
96
119
  /** Last listing date, YYYY-MM-DD. */
@@ -1,3 +1,4 @@
1
+ import type { CompanyFrom } from "../types/company-from";
1
2
  /**
2
3
  * Mergers and acquisitions read from news, press releases and SEC filings.
3
4
  * A deal is one target and one buyer; a target with competing bidders has a
@@ -84,6 +85,8 @@ export interface MnaDealsParams {
84
85
 
85
86
  export interface MnaDealsPayload {
86
87
  deals: MnaDeal[];
88
+ /** The company's home line the data is read from, when not the listing asked (a receipt, a foreign line). */
89
+ companyFrom?: CompanyFrom;
87
90
  hasMore: boolean;
88
91
  nextOffset: number;
89
92
  /** "delayed" hides deals first reported within `delayDays` from a free account. */
@@ -621,10 +621,18 @@ export function cloudNewsPath(params: CloudNewsParams = {}): string {
621
621
 
622
622
  /** Stories whose headline, summary or publisher matches the text, best match first; the service takes at most 100. */
623
623
  /** `topics` are NI codes the stories must carry: `query=gold&topics=metals` is gold's market news. */
624
- export function cloudNewsSearchPath(query: string, limit?: number, topics?: readonly string[]): string {
624
+ /**
625
+ * `closest`: when no story has every word, the stories with the most of them, marked `match: "closest"`.
626
+ * `tickers`: only the stories filed under them (`HAWK:NYSE`).
627
+ */
628
+ export function cloudNewsSearchPath(
629
+ query: string, limit?: number, topics?: readonly string[], options: { closest?: boolean; tickers?: readonly string[] } = {},
630
+ ): string {
625
631
  const search = new URLSearchParams({ query });
626
632
  if (limit != null) search.set("limit", String(limit));
627
633
  if (topics?.length) search.set("topics", topics.join(","));
634
+ if (options.tickers?.length) search.set("tickers", options.tickers.join(","));
635
+ if (options.closest) search.set("closest", "1");
628
636
  return appendQuery("/news/search", search);
629
637
  }
630
638
 
@@ -0,0 +1,85 @@
1
+ import type { CloudApiRequest } from "./request";
2
+
3
+ /**
4
+ * The public roadmap: what is being built, what is planned and what shipped,
5
+ * with the votes Pro members put on the first two. Anyone reads it; a signed-in
6
+ * Pro member votes once per item and can take the vote back.
7
+ */
8
+ const ROADMAP_STATUSES = ["building", "planned", "shipped"] as const;
9
+ export type RoadmapStatus = (typeof ROADMAP_STATUSES)[number];
10
+
11
+ export interface RoadmapItem {
12
+ id: string;
13
+ title: string;
14
+ /** One line on what it is. */
15
+ blurb: string;
16
+ status: RoadmapStatus;
17
+ /** ISO time it shipped; null until then. */
18
+ shippedAt: string | null;
19
+ votes: number;
20
+ /** Whether this account voted for it; false signed out. */
21
+ voted: boolean;
22
+ }
23
+
24
+ export interface RoadmapPayload {
25
+ items: RoadmapItem[];
26
+ /** The service's word on whether this session may vote (a verified Pro account). */
27
+ canVote: boolean;
28
+ }
29
+
30
+ export interface RoadmapVote {
31
+ id: string;
32
+ votes: number;
33
+ voted: boolean;
34
+ }
35
+
36
+ function isRecord(value: unknown): value is Record<string, unknown> {
37
+ return typeof value === "object" && value !== null && !Array.isArray(value);
38
+ }
39
+
40
+ function parseItem(value: unknown): RoadmapItem | null {
41
+ if (!isRecord(value)) return null;
42
+ const { id, title, blurb, status, shippedAt, votes, voted } = value;
43
+ if (typeof id !== "string" || !id || typeof title !== "string" || !title.trim()) return null;
44
+ if (!(ROADMAP_STATUSES as readonly unknown[]).includes(status)) return null;
45
+ return {
46
+ id,
47
+ title: title.trim(),
48
+ blurb: typeof blurb === "string" ? blurb.trim() : "",
49
+ status: status as RoadmapStatus,
50
+ shippedAt: typeof shippedAt === "string" && Number.isFinite(Date.parse(shippedAt)) ? shippedAt : null,
51
+ votes: typeof votes === "number" && Number.isFinite(votes) ? Math.max(0, Math.round(votes)) : 0,
52
+ voted: voted === true,
53
+ };
54
+ }
55
+
56
+ /** Items it cannot read (an unknown status from a newer service) are left out, not the whole list. */
57
+ function parseRoadmapPayload(value: unknown): RoadmapPayload {
58
+ if (!isRecord(value) || !Array.isArray(value.items)) throw new Error("The roadmap service returned invalid data.");
59
+ return {
60
+ items: value.items.map(parseItem).filter((item): item is RoadmapItem => item !== null),
61
+ canVote: value.canVote === true,
62
+ };
63
+ }
64
+
65
+ function parseVote(value: unknown): RoadmapVote {
66
+ if (!isRecord(value) || typeof value.id !== "string" || typeof value.votes !== "number" || typeof value.voted !== "boolean") {
67
+ throw new Error("The roadmap service returned invalid data.");
68
+ }
69
+ return { id: value.id, votes: value.votes, voted: value.voted };
70
+ }
71
+
72
+ export class CloudRoadmapApi {
73
+ constructor(private readonly request: CloudApiRequest) {}
74
+
75
+ async getRoadmap(signal?: AbortSignal): Promise<RoadmapPayload> {
76
+ return parseRoadmapPayload(await this.request<unknown>("/roadmap", { signal }));
77
+ }
78
+
79
+ /** Votes, or takes the vote back; the answer is the item's count after it. */
80
+ async setRoadmapVote(id: string, voted: boolean): Promise<RoadmapVote> {
81
+ return parseVote(await this.request<unknown>(`/roadmap/${encodeURIComponent(id)}/vote`, {
82
+ method: voted ? "POST" : "DELETE",
83
+ }));
84
+ }
85
+ }
@@ -1,3 +1,4 @@
1
+ import type { CompanyFrom } from "../types/company-from";
1
2
  import type {
2
3
  AnalystResearchData,
3
4
  CorporateActionsData,
@@ -1060,6 +1061,8 @@ export interface CloudEarningsCallListPayload {
1060
1061
  pending?: boolean;
1061
1062
  /** Set when the requested symbol is not one the SEC knows. */
1062
1063
  unknownTicker?: boolean;
1064
+ /** The company's home line the calls are read from, when not the listing asked (a receipt, a foreign line). */
1065
+ companyFrom?: CompanyFrom;
1063
1066
  }
1064
1067
 
1065
1068
  /** One row of a proxy statement's Summary Compensation Table, in dollars. */
@@ -1456,6 +1459,8 @@ export interface CloudSecFilingsResponse {
1456
1459
  filings: CloudSecFilingPayload[];
1457
1460
  hasMore: boolean;
1458
1461
  nextOffset: number;
1462
+ /** The company's home line the filings are read from, when not the listing asked (a foreign line). */
1463
+ companyFrom?: CompanyFrom;
1459
1464
  }
1460
1465
 
1461
1466
  export interface CloudSecDocumentsResponse {
@@ -1558,6 +1563,13 @@ export interface CloudNewsListResponse {
1558
1563
  nextCursor: string | null;
1559
1564
  /** Which news the service answered with, when it says: the live wire, or the one held back for a free account. */
1560
1565
  access?: "realtime" | "delayed";
1566
+ /**
1567
+ * A search asked for its closest stories: `all` when stories have every
1568
+ * word, `closest` when none does and these have the most of them.
1569
+ */
1570
+ match?: "all" | "closest";
1571
+ /** A receipt's or foreign line's feed is its company's: the home line it reads, when not the listing asked. */
1572
+ companyFrom?: CompanyFrom;
1561
1573
  }
1562
1574
 
1563
1575
  interface CloudTweetUserPayload {
@@ -32,7 +32,7 @@ import {
32
32
  type UsageFunction,
33
33
  } from "../../telemetry/usage-counts";
34
34
  import { debugLog } from "../../utils/debug-log";
35
- import { startMainThreadStallMonitor } from "../../utils/main-thread-stall";
35
+ import { markStartupComplete, startMainThreadStallMonitor } from "../../utils/main-thread-stall";
36
36
  import { measurePerfAsync } from "../../utils/perf-marks";
37
37
 
38
38
  const appLog = debugLog.createLogger("app");
@@ -161,6 +161,8 @@ export function useAppStartupRuntime({
161
161
  } catch (err) {
162
162
  logFailure("app.runtime.startup", "Workspace startup hydration failed")(err);
163
163
  }
164
+ // The workspace has its data (or gave up on it): stalls from here on are not startup ones.
165
+ markStartupComplete();
164
166
  })();
165
167
  }, [
166
168
  autoImportBrokerPositions,
@@ -9,7 +9,7 @@
9
9
  "src/cli/commands/options-chain.ts": ["options","options-calculator"],
10
10
  "src/cli/commands/options-leaps.ts": ["iv-history","options","vol-surface"],
11
11
  "src/cli/commands/overview.ts": ["correlation","econ","market-movers","sectors","world-indices"],
12
- "src/cli/commands/ticker.ts": ["notes"],
12
+ "src/cli/commands/ticker.ts": ["ipo-calendar","notes"],
13
13
  "src/cli/desktop-pane-shot.ts": ["market-valuation","time-sales"],
14
14
  "src/cli/pane-functions/data.ts": ["chart-composer","correlation","seasonality","ticker-detail"],
15
15
  "src/cli/pane-functions/financial-ratio-shot.ts": ["ticker-detail"],
@@ -27,7 +27,7 @@
27
27
  "src/components/layout/shell/index.tsx": ["cloud"],
28
28
  "src/components/onboarding/use-onboarding-upgrade.ts": ["chat"],
29
29
  "src/layout/desks.ts": ["chart-composer"],
30
- "src/plugins/catalog-browser.ts": ["alerts","analytics","attention","awards","backtest","bond-calculator","catalysts","cds","central-bank-rates","changelog","chart-composer","clinical-trials","cloud","comment-letters","commodities-energy","commodity-balances","company-attention","company-kpis","connections","correlation","cot","cpi","credit-boards","credit-conditions","credit-documents","crypto-board","crypto-etf-flows","debt-maturities","dividend-yield","docs","doe","earnings","earnings-calls","earnings-ripple","econ","econ-statistics","equity-screener","estimate-revisions","executives","exposure","fear-greed","filing-events","fixed-income","futures","futures-curve","fx-matrix","gpu","help","holders","insider","ipo-calendar","iv-history","jobs","jodi","kelly-sizer","layout-manager","macro-day","market-halts","market-heatmap","market-valuation","members","mna","money-markets","news","openfda","options","options-calculator","options-positioning","options-scenario","pe-band","perps","portfolio-list","power","primary-dealers","rate-path","realized-vol","relative-rotation","research","research-search","revenue-breakdown","reverse-dcf","risk-factors","scanner","seasonality","sec","sectors","short-interest","short-volume","social-mentions","supply-chain","thirteenf","ticker-detail","time-sales","trace-bonds","treasury-auctions","treasury-daily","vol-surface","volatility","world-indices","world-venue-map","yield-curve"],
30
+ "src/plugins/catalog-browser.ts": ["alerts","analytics","attention","awards","backtest","bond-calculator","catalysts","cds","central-bank-rates","changelog","chart-composer","clinical-trials","cloud","comment-letters","commodities-energy","commodity-balances","company-attention","company-kpis","connections","correlation","cot","cpi","credit-boards","credit-conditions","credit-documents","crypto-board","crypto-etf-flows","debt-maturities","dividend-yield","docs","doe","earnings","earnings-calls","earnings-ripple","econ","econ-statistics","equity-screener","estimate-revisions","executives","exposure","fear-greed","filing-events","fixed-income","futures","futures-curve","fx-matrix","gpu","help","holders","insider","ipo-calendar","iv-history","jobs","jodi","kelly-sizer","layout-manager","macro-day","market-halts","market-heatmap","market-valuation","members","mna","money-markets","news","openfda","options","options-calculator","options-positioning","options-scenario","pe-band","perps","portfolio-list","power","primary-dealers","rate-path","realized-vol","relative-rotation","research","research-search","revenue-breakdown","reverse-dcf","risk-factors","roadmap","scanner","seasonality","sec","sectors","short-interest","short-volume","social-mentions","supply-chain","thirteenf","ticker-detail","time-sales","trace-bonds","treasury-auctions","treasury-daily","vol-surface","volatility","world-indices","world-venue-map","yield-curve"],
31
31
  "src/plugins/catalog-ui.ts": ["alerts","clinical-trials","cloud","comment-letters","custom-view","fear-greed","ipo-calendar","market-halts","market-heatmap","members","news","notes","openfda","research-search"],
32
32
  "src/plugins/catalog.ts": ["debug"],
33
33
  "src/remote/controller.ts": ["custom-view"],
@@ -203,7 +203,7 @@ function resolvedOutput(value: unknown): ResolvedSeries {
203
203
  const input = object(value, "resolve output");
204
204
  onlyKeys(input, "resolve output", [
205
205
  "id", "label", "color", "unit", "unitGroup", "nativeFrequency", "timestampMode", "dataShape", "style", "transform",
206
- "axis", "panelId", "interpolation", "timeBasis", "latestChangePercent", "points", "warning", "hidden", "attribution",
206
+ "axis", "panelId", "interpolation", "timeBasis", "latestChangePercent", "points", "warning", "savedAt", "hidden", "attribution",
207
207
  "priceOf",
208
208
  ]);
209
209
  if (!Array.isArray(input.points)) fail("resolve output points", "expected an array.");
@@ -247,6 +247,7 @@ function resolvedOutput(value: unknown): ResolvedSeries {
247
247
  : {}),
248
248
  points: input.points.map(point),
249
249
  ...(warning !== undefined ? { warning } : {}),
250
+ ...(input.savedAt !== undefined ? { savedAt: finiteNumber(input.savedAt, "resolve output saved copy time") as number } : {}),
250
251
  ...(attribution ? { attribution: {
251
252
  source: boundedString(attribution.source, "resolve output source", 160),
252
253
  ...(publisher !== undefined ? { publisher } : {}),