gloomberb 0.11.0 → 0.11.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 (392) hide show
  1. package/README.md +38 -15
  2. package/README.zh-CN.md +12 -12
  3. package/package.json +10 -3
  4. package/src/api-client/auth.ts +14 -10
  5. package/src/api-client/data.ts +54 -0
  6. package/src/api-client/index.test.ts +124 -0
  7. package/src/api-client/index.ts +139 -4
  8. package/src/api-client/paths.ts +89 -0
  9. package/src/api-client/request.ts +15 -2
  10. package/src/api-client/socket-health.test.ts +1 -0
  11. package/src/api-client/socket.ts +2 -1
  12. package/src/api-client/types.ts +163 -0
  13. package/src/app/pane-runtime/index.tsx +4 -1
  14. package/src/app/pane-runtime/plugin-bindings.test.ts +117 -0
  15. package/src/app/pane-runtime/plugin-bindings.ts +25 -4
  16. package/src/app/pane-runtime/ticker-inspector-runtime.ts +25 -14
  17. package/src/app/runtime/desktop-deeplink.test.ts +16 -0
  18. package/src/app/runtime/desktop-deeplink.ts +66 -2
  19. package/src/app/runtime/desktop-menu.ts +3 -0
  20. package/src/app/runtime/plugin-bindings.ts +30 -28
  21. package/src/app/runtime/update.ts +8 -6
  22. package/src/app.tsx +21 -7
  23. package/src/architecture/import-boundaries.test.ts +5 -1
  24. package/src/capabilities/factories.ts +4 -0
  25. package/src/cli/commands/automation.test.ts +9 -0
  26. package/src/cli/commands/automation.ts +22 -73
  27. package/src/cli/index.ts +10 -6
  28. package/src/cli/registry.ts +1 -1
  29. package/src/components/chart/composite/composite-chart.test.tsx +45 -2
  30. package/src/components/chart/composite/composite-chart.tsx +16 -12
  31. package/src/components/chart/composite/format.test.ts +34 -0
  32. package/src/components/chart/composite/format.ts +33 -10
  33. package/src/components/chart/composite/scene.ts +0 -21
  34. package/src/components/chart/composite/tools.ts +49 -0
  35. package/src/components/chart/core/axis-format.ts +13 -3
  36. package/src/components/chart/core/index.test.ts +7 -0
  37. package/src/components/chart/core/renderer.ts +3 -4
  38. package/src/components/command-bar/commands/direct/index.ts +4 -0
  39. package/src/components/command-bar/commands/registry.ts +8 -1
  40. package/src/components/command-bar/layout-items/current-layout.ts +1 -1
  41. package/src/components/command-bar/pane-templates/workflow.ts +4 -0
  42. package/src/components/command-bar/routes/root/shortcut-feedback.ts +3 -0
  43. package/src/components/command-bar/routes/root/shortcuts.test.ts +19 -0
  44. package/src/components/command-bar/routes/root/shortcuts.ts +3 -1
  45. package/src/components/command-bar/surface/index.test.tsx +6 -6
  46. package/src/components/command-bar/surface/index.tsx +4 -1
  47. package/src/components/command-bar/surface/pane.test.tsx +66 -2
  48. package/src/components/command-bar/view-model.test.ts +2 -1
  49. package/src/components/command-bar/workflow/ops.test.ts +54 -0
  50. package/src/components/command-bar/workflow/ops.ts +1 -1
  51. package/src/components/company-logo.test.ts +19 -0
  52. package/src/components/company-logo.tsx +60 -0
  53. package/src/components/feed-data-table/stack-view.tsx +7 -1
  54. package/src/components/index.ts +1 -0
  55. package/src/components/layout/detached-pane-shell.tsx +85 -15
  56. package/src/components/layout/header.tsx +5 -5
  57. package/src/components/layout/pane/title.ts +31 -3
  58. package/src/components/layout/shell/active-drag.ts +4 -11
  59. package/src/components/layout/shell/drag/index.ts +4 -20
  60. package/src/components/layout/shell/drag/runtime.ts +3 -4
  61. package/src/components/layout/shell/index.test.tsx +17 -3
  62. package/src/components/layout/shell/index.tsx +89 -31
  63. package/src/components/layout/shell/menu.test.ts +37 -1
  64. package/src/components/layout/shell/menu.ts +14 -0
  65. package/src/components/layout/shell/native/pointer-runtime.ts +22 -8
  66. package/src/components/layout/shell/pane/actions.ts +0 -5
  67. package/src/components/layout/shell/pane/management-shortcuts.ts +9 -4
  68. package/src/components/layout/shell/shortcuts.ts +6 -3
  69. package/src/components/layout/shell/ticker-link-menu.test.ts +82 -0
  70. package/src/components/layout/shell/ticker-link-menu.ts +78 -0
  71. package/src/components/layout/status-bar.test.tsx +62 -61
  72. package/src/components/layout/status-bar.tsx +53 -75
  73. package/src/components/onboarding/account-step/form-panel.tsx +4 -2
  74. package/src/components/onboarding/account-step/index.tsx +1 -1
  75. package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
  76. package/src/components/onboarding/onboarding-wizard.test.tsx +44 -1
  77. package/src/components/onboarding/onboarding-wizard.tsx +13 -5
  78. package/src/components/onboarding/wizard-account.ts +4 -23
  79. package/src/components/table-view-shared.test.ts +11 -0
  80. package/src/components/table-view-shared.tsx +26 -0
  81. package/src/components/ui/data-table/index.tsx +19 -1
  82. package/src/components/ui/fields.tsx +5 -1
  83. package/src/core/state/app/layout-reducer.ts +36 -0
  84. package/src/core/state/app/layout.ts +10 -5
  85. package/src/core/state/app/state.ts +0 -13
  86. package/src/core/state/app/types.ts +6 -4
  87. package/src/data/config/chart-settings.ts +1 -1
  88. package/src/data/config/layout.ts +2 -0
  89. package/src/data/config/store/index.test.ts +27 -6
  90. package/src/data/config/store/normalize.ts +3 -5
  91. package/src/data/plugin-state-store.ts +11 -0
  92. package/src/data/sqlite/cache.test.ts +10 -0
  93. package/src/i18n/es.ts +13 -5
  94. package/src/i18n/ja.ts +13 -5
  95. package/src/i18n/ko.ts +13 -5
  96. package/src/i18n/zh-cn.ts +13 -5
  97. package/src/i18n/zh-tw.ts +13 -5
  98. package/src/layout-marketplace/api.test.ts +54 -0
  99. package/src/layout-marketplace/api.ts +65 -0
  100. package/src/layout-marketplace/gallery-desktop.test.tsx +262 -0
  101. package/src/layout-marketplace/gallery-desktop.tsx +375 -0
  102. package/src/layout-marketplace/gallery-terminal.tsx +376 -0
  103. package/src/layout-marketplace/gallery.test.tsx +84 -0
  104. package/src/layout-marketplace/gallery.tsx +323 -0
  105. package/src/layout-marketplace/geometry.test.ts +47 -0
  106. package/src/layout-marketplace/geometry.ts +80 -0
  107. package/src/layout-marketplace/mini-workspace.test.tsx +122 -0
  108. package/src/layout-marketplace/mini-workspace.tsx +428 -0
  109. package/src/layout-marketplace/model.test.ts +118 -0
  110. package/src/layout-marketplace/model.ts +171 -0
  111. package/src/layout-marketplace/name-dialog.tsx +60 -0
  112. package/src/layout-marketplace/pane-imagery.ts +85 -0
  113. package/src/layout-marketplace/pane.tsx +20 -0
  114. package/src/layout-marketplace/payload.test.ts +246 -0
  115. package/src/layout-marketplace/payload.ts +624 -0
  116. package/src/layout-marketplace/use-marketplace.ts +63 -0
  117. package/src/market-data/coordinator/index.test.ts +2 -2
  118. package/src/market-data/coordinator/index.ts +1 -1
  119. package/src/market-data/hooks.tsx +0 -41
  120. package/src/market-data/market/format.test.ts +7 -0
  121. package/src/market-data/market/freshness.ts +5 -2
  122. package/src/market-data/quotes/freshness.test.ts +16 -0
  123. package/src/news/aggregator.test.ts +92 -3
  124. package/src/news/aggregator.ts +98 -18
  125. package/src/news/hooks.test.tsx +2 -0
  126. package/src/news/hooks.ts +27 -1
  127. package/src/news/news-model.ts +5 -2
  128. package/src/news/types.ts +7 -0
  129. package/src/plugins/broker-sync/broker-sync.test.ts +58 -0
  130. package/src/plugins/broker-sync/normalize.ts +42 -5
  131. package/src/plugins/builtin/account-management/pane.tsx +5 -5
  132. package/src/plugins/builtin/ai/index.tsx +18 -2
  133. package/src/plugins/builtin/ai/screener/pane.test.tsx +47 -4
  134. package/src/plugins/builtin/ai/screener/pane.tsx +35 -12
  135. package/src/plugins/builtin/alerts/alert-engine.test.ts +53 -1
  136. package/src/plugins/builtin/alerts/alert-engine.ts +34 -1
  137. package/src/plugins/builtin/alerts/index.test.tsx +49 -6
  138. package/src/plugins/builtin/alerts/index.tsx +11 -6
  139. package/src/plugins/builtin/alerts/pane.tsx +51 -9
  140. package/src/plugins/builtin/alerts/quotes.ts +11 -3
  141. package/src/plugins/builtin/alerts/types.ts +1 -0
  142. package/src/plugins/builtin/analytics/index.tsx +11 -1
  143. package/src/plugins/builtin/analytics/pane-model.ts +6 -4
  144. package/src/plugins/builtin/broker-manager/index.tsx +3 -0
  145. package/src/plugins/builtin/buildout/model/index.ts +1 -1
  146. package/src/plugins/builtin/buildout/pane/index.tsx +17 -18
  147. package/src/plugins/builtin/cds/client.test.ts +83 -0
  148. package/src/plugins/builtin/cds/client.ts +67 -0
  149. package/src/plugins/builtin/cds/index.tsx +41 -0
  150. package/src/plugins/builtin/cds/model.test.ts +232 -0
  151. package/src/plugins/builtin/cds/model.ts +401 -0
  152. package/src/plugins/builtin/cds/pane.test.tsx +132 -0
  153. package/src/plugins/builtin/cds/pane.tsx +358 -0
  154. package/src/plugins/builtin/chart-composer/chart-spec.ts +31 -0
  155. package/src/plugins/builtin/chart-composer/index.tsx +88 -2
  156. package/src/plugins/builtin/chart-composer/pane-share.test.ts +71 -0
  157. package/src/plugins/builtin/chart-composer/pane.tsx +103 -15
  158. package/src/plugins/builtin/chat/content/index.tsx +4 -1
  159. package/src/plugins/builtin/chat/controller/channels.ts +7 -1
  160. package/src/plugins/builtin/chat/controller/index.ts +14 -9
  161. package/src/plugins/builtin/chat/controller/notifications.ts +13 -3
  162. package/src/plugins/builtin/chat/controller/persistence.ts +0 -3
  163. package/src/plugins/builtin/chat/controller/realtime.ts +3 -3
  164. package/src/plugins/builtin/chat/controller/send.ts +1 -3
  165. package/src/plugins/builtin/chat/controller/session-runtime.ts +18 -11
  166. package/src/plugins/builtin/chat/controller/state.ts +1 -3
  167. package/src/plugins/builtin/chat/controller/storage.ts +0 -2
  168. package/src/plugins/builtin/chat/controller/utils.ts +4 -6
  169. package/src/plugins/builtin/chat/controller/view.ts +2 -2
  170. package/src/plugins/builtin/chat/controller.test.ts +142 -14
  171. package/src/plugins/builtin/chat/message/desktop.test.tsx +88 -0
  172. package/src/plugins/builtin/chat/message/desktop.tsx +3 -1
  173. package/src/plugins/builtin/chat/message/profile-popover.test.tsx +1 -29
  174. package/src/plugins/builtin/chat/profile-popover.ts +53 -22
  175. package/src/plugins/builtin/chat/sidebar.test.tsx +81 -0
  176. package/src/plugins/builtin/chat/sidebar.tsx +63 -0
  177. package/src/plugins/builtin/chat/test-harness.tsx +29 -1
  178. package/src/plugins/builtin/cloud/auth-actions.tsx +14 -7
  179. package/src/plugins/builtin/cloud/auth-commands.ts +21 -51
  180. package/src/plugins/builtin/cloud/auth-dialog.tsx +296 -0
  181. package/src/{components/onboarding/account-step/model.test.ts → plugins/builtin/cloud/auth-model.test.ts} +1 -1
  182. package/src/{components/onboarding/account-step/model.ts → plugins/builtin/cloud/auth-model.ts} +37 -3
  183. package/src/plugins/builtin/cloud/browser.tsx +9 -0
  184. package/src/plugins/builtin/cloud/buildout-module.tsx +23 -0
  185. package/src/plugins/builtin/cloud/device-signin.ts +2 -8
  186. package/src/plugins/builtin/cloud/index.tsx +2 -0
  187. package/src/plugins/builtin/cloud/plugin.tsx +14 -24
  188. package/src/plugins/builtin/cloud/upgrade-command.ts +13 -6
  189. package/src/plugins/builtin/cloud-tweets/pane-share.test.ts +56 -0
  190. package/src/plugins/builtin/cloud-tweets/pane.tsx +20 -5
  191. package/src/plugins/builtin/cloud-tweets/registration.ts +50 -6
  192. package/src/plugins/builtin/composite-plugins.ts +3 -1
  193. package/src/plugins/builtin/congress-trades/detail.tsx +43 -1
  194. package/src/plugins/builtin/congress-trades/model.test.ts +85 -0
  195. package/src/plugins/builtin/congress-trades/model.ts +69 -1
  196. package/src/plugins/builtin/congress-trades/pane.tsx +51 -2
  197. package/src/plugins/builtin/connections/index.ts +3 -0
  198. package/src/plugins/builtin/dividend-yield/client.ts +18 -0
  199. package/src/plugins/builtin/dividend-yield/pane.tsx +7 -6
  200. package/src/plugins/builtin/earnings/index.tsx +5 -3
  201. package/src/plugins/builtin/earnings/model.test.ts +19 -1
  202. package/src/plugins/builtin/earnings/model.ts +17 -15
  203. package/src/plugins/builtin/econ/calendar-model.ts +0 -5
  204. package/src/plugins/builtin/econ/index.test.tsx +6 -1
  205. package/src/plugins/builtin/fear-greed/charts.tsx +12 -8
  206. package/src/plugins/builtin/help/index.tsx +2 -2
  207. package/src/plugins/builtin/holders/thirteenf-match.ts +1 -2
  208. package/src/plugins/builtin/insider/index.tsx +27 -11
  209. package/src/plugins/builtin/kelly-sizer/index.tsx +4 -1
  210. package/src/plugins/builtin/layout-manager/index.tsx +17 -4
  211. package/src/plugins/builtin/news/index.tsx +11 -6
  212. package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +2 -0
  213. package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +2 -0
  214. package/src/plugins/builtin/news/wire/breaking/pane.tsx +4 -1
  215. package/src/plugins/builtin/news/wire/feed-config.test.ts +15 -1
  216. package/src/plugins/builtin/news/wire/feed-config.ts +25 -5
  217. package/src/plugins/builtin/news/wire/index.tsx +3 -3
  218. package/src/plugins/builtin/news/wire/industry-pane.tsx +7 -2
  219. package/src/plugins/builtin/news/wire/news/footer.ts +34 -1
  220. package/src/plugins/builtin/news/wire/news/preset-pane.tsx +4 -1
  221. package/src/plugins/builtin/news/wire/news/table.tsx +8 -2
  222. package/src/plugins/builtin/news/wire/rss/source.test.ts +12 -0
  223. package/src/plugins/builtin/news/wire/rss/source.ts +1 -1
  224. package/src/plugins/builtin/notes/files.ts +80 -0
  225. package/src/plugins/builtin/notes/index.tsx +3 -0
  226. package/src/plugins/builtin/notes/sync.test.ts +49 -0
  227. package/src/plugins/builtin/notes/sync.ts +98 -0
  228. package/src/plugins/builtin/options/index.tsx +1 -0
  229. package/src/plugins/builtin/options/view.test.tsx +25 -3
  230. package/src/plugins/builtin/options/view.tsx +1 -0
  231. package/src/plugins/builtin/portfolio-list/account-metrics.test.ts +22 -0
  232. package/src/plugins/builtin/portfolio-list/account-metrics.ts +12 -7
  233. package/src/plugins/builtin/portfolio-list/cli/render.ts +5 -3
  234. package/src/plugins/builtin/portfolio-list/column-values.ts +15 -4
  235. package/src/plugins/builtin/portfolio-list/header.tsx +13 -3
  236. package/src/plugins/builtin/portfolio-list/index.tsx +8 -0
  237. package/src/plugins/builtin/portfolio-list/metrics.test.ts +31 -1
  238. package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +1 -0
  239. package/src/plugins/builtin/portfolio-list/pane/index.tsx +10 -7
  240. package/src/plugins/builtin/portfolio-list/pane/streaming.ts +6 -1
  241. package/src/plugins/builtin/portfolio-list/position-metrics.ts +25 -6
  242. package/src/plugins/builtin/portfolio-list/summary/index.tsx +35 -21
  243. package/src/plugins/builtin/portfolio-list/summary/totals.ts +20 -6
  244. package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -12
  245. package/src/plugins/builtin/research/equity-diagnostic-pane.test.tsx +329 -0
  246. package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +582 -0
  247. package/src/plugins/builtin/research/index.test.ts +14 -0
  248. package/src/plugins/builtin/research/index.tsx +29 -0
  249. package/src/plugins/builtin/sec/index.tsx +24 -9
  250. package/src/plugins/builtin/sectors/index.tsx +14 -0
  251. package/src/plugins/builtin/shared/cloud-upgrade.ts +18 -11
  252. package/src/plugins/builtin/shared/public-pane.test.ts +12 -0
  253. package/src/plugins/builtin/shared/public-pane.ts +9 -0
  254. package/src/plugins/builtin/shared/public-share.ts +23 -0
  255. package/src/plugins/builtin/shared/ticker-source.ts +32 -0
  256. package/src/plugins/builtin/shared/ticker-surface.test.ts +27 -0
  257. package/src/plugins/builtin/shared/ticker-surface.ts +17 -0
  258. package/src/plugins/builtin/substack/api/cache.ts +7 -3
  259. package/src/plugins/builtin/substack/api/loaders.ts +36 -12
  260. package/src/plugins/builtin/substack/api/types.ts +2 -0
  261. package/src/plugins/builtin/substack/pane-state.ts +1 -1
  262. package/src/plugins/builtin/substack/pane.tsx +55 -12
  263. package/src/plugins/builtin/thirteenf/api.test.ts +1 -1
  264. package/src/plugins/builtin/thirteenf/api.ts +40 -18
  265. package/src/plugins/builtin/thirteenf/data.ts +15 -7
  266. package/src/plugins/builtin/thirteenf/pane.tsx +45 -10
  267. package/src/plugins/builtin/ticker-detail/index.tsx +10 -0
  268. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +12 -4
  269. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +8 -2
  270. package/src/plugins/builtin/ticker-detail/settings.ts +12 -0
  271. package/src/plugins/builtin/treasury-auctions/index.tsx +2 -0
  272. package/src/plugins/builtin/world-indices/index.tsx +2 -0
  273. package/src/plugins/catalog-browser.test.ts +78 -0
  274. package/src/plugins/catalog-browser.ts +136 -0
  275. package/src/plugins/gridlock-notification.ts +2 -1
  276. package/src/plugins/ibkr/flex/index.test.ts +19 -0
  277. package/src/plugins/ibkr/flex/index.ts +1 -1
  278. package/src/plugins/pane-manager/gridlock.ts +87 -3
  279. package/src/plugins/pane-manager.test.ts +30 -0
  280. package/src/plugins/pane-manager.ts +6 -1
  281. package/src/plugins/prediction-markets/chart.tsx +2 -2
  282. package/src/plugins/prediction-markets/controller/catalog.ts +77 -2
  283. package/src/plugins/prediction-markets/controller/data.ts +7 -1
  284. package/src/plugins/prediction-markets/controller/index.ts +9 -2
  285. package/src/plugins/prediction-markets/controller/keyboard.ts +10 -14
  286. package/src/plugins/prediction-markets/detail/overview.tsx +21 -0
  287. package/src/plugins/prediction-markets/detail/pane.tsx +43 -34
  288. package/src/plugins/prediction-markets/detail/trades.tsx +34 -9
  289. package/src/plugins/prediction-markets/detail.test.tsx +29 -2
  290. package/src/plugins/prediction-markets/index.tsx +8 -4
  291. package/src/plugins/prediction-markets/navigation.ts +0 -1
  292. package/src/plugins/prediction-markets/pane.test.tsx +77 -0
  293. package/src/plugins/prediction-markets/pane.tsx +12 -0
  294. package/src/plugins/prediction-markets/plugin.test.tsx +36 -0
  295. package/src/plugins/prediction-markets/services/kalshi/adapter.ts +49 -9
  296. package/src/plugins/prediction-markets/services/polymarket/adapter.ts +31 -0
  297. package/src/plugins/prediction-markets/test-helpers.tsx +9 -0
  298. package/src/plugins/registry/index.ts +2 -0
  299. package/src/plugins/ticker-navigation.test.ts +24 -0
  300. package/src/plugins/ticker-navigation.ts +40 -0
  301. package/src/remote/schema.ts +1 -1
  302. package/src/renderers/browser/app-services.ts +61 -0
  303. package/src/renderers/browser/cloud-transport.test.ts +68 -0
  304. package/src/renderers/browser/cloud-transport.ts +48 -0
  305. package/src/renderers/browser/config-host.ts +58 -0
  306. package/src/renderers/browser/deeplink-bridge.test.ts +41 -0
  307. package/src/renderers/browser/deeplink-bridge.ts +22 -0
  308. package/src/renderers/browser/error-boundary.tsx +23 -0
  309. package/src/renderers/browser/main.tsx +64 -0
  310. package/src/renderers/browser/persistence.ts +74 -0
  311. package/src/renderers/browser/storage.test.ts +66 -0
  312. package/src/renderers/browser/storage.ts +50 -0
  313. package/src/renderers/browser/ticker-repository.ts +59 -0
  314. package/src/renderers/browser/ui-host.tsx +40 -0
  315. package/src/renderers/cloudflare/worker.test.ts +136 -0
  316. package/src/renderers/cloudflare/worker.ts +116 -0
  317. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -2
  318. package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
  319. package/src/renderers/electrobun/bun/desktop/plugin-state.ts +7 -1
  320. package/src/renderers/electrobun/view/app-services.ts +14 -3
  321. package/src/renderers/electrobun/view/build-assets.ts +12 -10
  322. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  323. package/src/renderers/electrobun/view/data-table/index.tsx +10 -1
  324. package/src/renderers/electrobun/view/desktop/controls.tsx +2 -0
  325. package/src/renderers/electrobun/view/dom-ui-host.tsx +143 -0
  326. package/src/renderers/electrobun/view/host/box.test.tsx +33 -0
  327. package/src/renderers/electrobun/view/host/box.tsx +11 -6
  328. package/src/renderers/electrobun/view/host/chart-surface.tsx +7 -1
  329. package/src/renderers/electrobun/view/host/input.tsx +11 -7
  330. package/src/renderers/electrobun/view/host/native.ts +0 -5
  331. package/src/renderers/electrobun/view/main.tsx +2 -0
  332. package/src/renderers/electrobun/view/remote/persistence.ts +5 -0
  333. package/src/renderers/electrobun/view/styles.css +107 -7
  334. package/src/renderers/electrobun/view/toast-host.test.tsx +78 -0
  335. package/src/renderers/electrobun/view/toast-host.tsx +69 -43
  336. package/src/renderers/electrobun/view/ui-host.tsx +6 -137
  337. package/src/renderers/opentui/start.tsx +2 -0
  338. package/src/renderers/share/layout-view.test.tsx +58 -0
  339. package/src/renderers/share/layout-view.tsx +133 -0
  340. package/src/renderers/share/main.tsx +102 -0
  341. package/src/renderers/share/styles.css +54 -0
  342. package/src/renderers/share/view.test.tsx +100 -0
  343. package/src/renderers/share/view.tsx +150 -0
  344. package/src/shares/api.test.ts +105 -0
  345. package/src/shares/api.ts +127 -0
  346. package/src/shares/chart-snapshot.test.ts +34 -0
  347. package/src/shares/chart-snapshot.ts +28 -0
  348. package/src/shares/location.test.ts +19 -0
  349. package/src/shares/location.ts +11 -0
  350. package/src/shares/pane.test.ts +110 -0
  351. package/src/shares/pane.ts +54 -0
  352. package/src/shares/payload.ts +177 -0
  353. package/src/sources/gloomberb-cloud/index.test.ts +61 -1
  354. package/src/sources/gloomberb-cloud/index.ts +86 -14
  355. package/src/sources/gloomberb-cloud/normalizers.test.ts +34 -0
  356. package/src/sources/gloomberb-cloud/normalizers.ts +5 -5
  357. package/src/sources/provider-router/history.test.ts +2 -2
  358. package/src/sources/provider-router/news.test.ts +34 -0
  359. package/src/sources/provider-router/news.ts +15 -1
  360. package/src/sources/sec-edgar.test.ts +59 -0
  361. package/src/sources/sec-edgar.ts +63 -23
  362. package/src/sources/yahoo-finance/mappers.ts +3 -0
  363. package/src/sources/yahoo-finance/snapshots.ts +10 -2
  364. package/src/sources/yahoo-finance/symbols.test.ts +10 -0
  365. package/src/sources/yahoo-finance/symbols.ts +13 -8
  366. package/src/sources/yahoo-finance.test.ts +1 -1
  367. package/src/sources/yahoo-finance.ts +6 -2
  368. package/src/state/app/bootstrap.ts +6 -7
  369. package/src/state/app/context/index.test.ts +41 -1
  370. package/src/state/app/context/index.test.tsx +34 -16
  371. package/src/state/selectors-ui.ts +0 -8
  372. package/src/sync/baseline.ts +32 -0
  373. package/src/sync/controller.test.ts +124 -1
  374. package/src/sync/controller.ts +54 -12
  375. package/src/sync/core-contributors.test.ts +44 -0
  376. package/src/sync/core-contributors.ts +59 -10
  377. package/src/sync/react.ts +22 -2
  378. package/src/sync/types.ts +12 -0
  379. package/src/theme/font-scale.ts +0 -11
  380. package/src/tickers/search/index.test.ts +27 -0
  381. package/src/tickers/search/upsert.ts +10 -0
  382. package/src/types/capability-route-source.ts +2 -1
  383. package/src/types/config.ts +35 -5
  384. package/src/types/desktop-menu.ts +1 -0
  385. package/src/types/plugin.ts +36 -0
  386. package/src/ui/context-menu.tsx +1 -1
  387. package/src/ui/host.tsx +4 -0
  388. package/src/ui/toast.tsx +2 -0
  389. package/src/utils/back-navigation.ts +0 -4
  390. package/src/utils/price-history.ts +11 -10
  391. package/src/utils/sec.test.ts +6 -0
  392. package/src/utils/sec.ts +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- <img src="https://gloomberb.com/gloomberb-logo-grayscale.svg" alt="Gloomberb logo" width="76" />
3
+ <img src="https://gloom.sh/gloomberb-logo-grayscale.svg" alt="Gloomberb logo" width="76" />
4
4
 
5
5
  # Gloomberb
6
6
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  Desktop app for macOS and Windows. Terminal UI for macOS, Linux, and Windows.
10
10
 
11
- <a href="https://gloomberb.com/download/desktop"><strong>Download desktop</strong></a>
11
+ <a href="https://gloom.sh/download/desktop"><strong>Download desktop</strong></a>
12
12
  &nbsp;&middot;&nbsp;
13
13
  <a href="#install"><strong>Install the TUI</strong></a>
14
14
  &nbsp;&middot;&nbsp;
@@ -17,7 +17,7 @@ Desktop app for macOS and Windows. Terminal UI for macOS, Linux, and Windows.
17
17
  <br />
18
18
  <br />
19
19
 
20
- <img src="https://gloomberb.com/landing-terminal.png" alt="Gloomberb terminal showing portfolio, watchlists, market data, and chart panels." width="720" />
20
+ <img src="https://gloom.sh/landing-terminal.png" alt="Gloomberb terminal showing portfolio, watchlists, market data, and chart panels." width="720" />
21
21
 
22
22
  </div>
23
23
 
@@ -29,8 +29,24 @@ Gloomberb has two ways in:
29
29
  |---------|----------|-------------|
30
30
  | Desktop app | A polished app window, pop-out panes, OS shortcuts, and built-in updates | Published for macOS and Windows. It also installs a `gloomberb` terminal command for the TUI. |
31
31
  | Terminal UI | Fast keyboard workflows inside your terminal, SSH/dev boxes, Linux machines, and script-friendly setups | Runs with `gloomberb` on macOS, Linux, and Windows. |
32
+ | Browser app | The shared DOM interface without an install | Open [term.gloom.sh](https://term.gloom.sh). |
32
33
 
33
- Both share the same command language, plugin system, market data surfaces, portfolios, watchlists, alerts, notes, and AI tools.
34
+ The desktop app and TUI share the full command language and plugin system. The browser app uses the same official DOM renderer and layout with a reviewed browser plugin catalog.
35
+
36
+ ## Browser App
37
+
38
+ [term.gloom.sh](https://term.gloom.sh) works anonymously with configuration, tickers, layouts, session state, and plugin state stored in the browser. Anonymous sessions receive rate-limited, 15-minute-delayed Gloom Cloud market data and read-only chat. Login remains optional and enables sync and chat posting; Pro accounts receive realtime market data. Cloud REST and WebSocket traffic uses the same-origin `/api` path, which the Worker forwards only to `https://api.gloom.sh`; it is not an arbitrary network proxy.
39
+
40
+ The browser build intentionally omits brokers and native integrations, filesystem notes, local AI, external plugins, updater/debug tools, application menus, native window controls, pop-out native windows, and native context menus. Modules that still depend on desktop-only or CORS-blocked feeds are also absent for now: RSS/Substack, prediction markets and polls, market halts/heatmap/movers, dividend/ownership/SEC panes, earnings/IPO, and TV. Public shares open under `/s/:id` in a separate slim bundle. Share creation and owner deletion use the signed-in Gloom Cloud session through the same fixed API path; public reads require no account.
41
+
42
+ Local browser development:
43
+
44
+ ```bash
45
+ bun run web:build
46
+ bunx wrangler dev
47
+ ```
48
+
49
+ Validate the public artifacts with `bun run web:audit` and `bun run cloudflare:dry-run`. `wrangler.jsonc` remains generic for local checks. After verification passes on `main`, GitHub Actions deploys `term.gloom.sh` with `wrangler.production.jsonc`. The private Gloom Cloud API is deployed separately.
34
50
 
35
51
  ## Install
36
52
 
@@ -41,21 +57,21 @@ Install the desktop app and the `gloomberb` terminal command:
41
57
  ```bash
42
58
  brew install --cask vincelwt/tap/gloomberb
43
59
  # or
44
- curl -fsSL gloomberb.com/install | bash
60
+ curl -fsSL gloom.sh/install | bash
45
61
  ```
46
62
 
47
63
  Both install `Gloomberb.app` and a `gloomberb` command that runs the TUI through the app bundle, so the bundled runtime is stored once.
48
64
 
49
65
  Prefer a direct download?
50
66
 
51
- - [Download Gloomberb for Mac](https://gloomberb.com/download/desktop)
67
+ - [Download Gloomberb for Mac](https://gloom.sh/download/desktop)
52
68
 
53
69
  ### Linux
54
70
 
55
71
  Install the standalone TUI binary:
56
72
 
57
73
  ```bash
58
- curl -fsSL gloomberb.com/install | bash
74
+ curl -fsSL gloom.sh/install | bash
59
75
  ```
60
76
 
61
77
  This installs `gloomberb` to `~/.local/bin` by default. A Linux desktop package is not published yet.
@@ -150,10 +166,9 @@ Human-readable output is the default. Automation can opt into structured output
150
166
  | `gloomberb portfolio [action]` | Manage manual portfolios |
151
167
  | `gloomberb watchlist [action]` | Manage watchlists |
152
168
  | `gloomberb notes|alerts [action]` | Manage local notes and alerts |
153
- | `gloomberb broker|ibkr [action]` | Inspect broker integrations; trading actions require explicit account/profile and `--yes` |
154
- | `gloomberb ai providers|ask|screen` | Use configured AI providers and screeners |
169
+ | `gloomberb broker|ibkr [action]` | Inspect broker profiles |
170
+ | `gloomberb ai providers|ask` | Use configured AI providers |
155
171
  | `gloomberb rss fetch <url>` | Fetch an RSS feed |
156
- | `gloomberb buildout|congress|substack|x-feed|tweets` | Access cloud and social data sources when an existing session is available |
157
172
  | `gloomberb provider status` | Inspect enabled data providers |
158
173
  | `gloomberb config|cache|plugin|layout|pane|debug|doctor|version|changelog` | Inspect and manage local app state |
159
174
  | `gloomberb fn [...]` | Run a pane-backed report command |
@@ -164,8 +179,6 @@ Human-readable output is the default. Automation can opt into structured output
164
179
  | `gloomberb remove <name>` | Remove an installed plugin |
165
180
  | `gloomberb update [name]` | Update plugins |
166
181
 
167
- Commands that need a signed-in cloud session may return `auth_required`; sign-in, account management, and chat workflows are still handled in the app UI for now.
168
-
169
182
  ## Plugins
170
183
 
171
184
  Everything from the portfolio list to broker integrations is a plugin. Plugins can add panes, tabs, columns, command bar commands, CLI commands, status bar widgets, and data providers.
@@ -190,7 +203,7 @@ See [PLUGINS.md](PLUGINS.md) for the plugin API and the shared UI surface availa
190
203
  | `Ctrl+Shift+M` | Move focused window (`WIN resize` starts resize mode) |
191
204
  | `Ctrl+Shift+D` | Dock or float focused pane |
192
205
  | `Ctrl+Shift+L` | Layout actions |
193
- | `Ctrl+Shift+G` | Gridlock all windows |
206
+ | `Ctrl+Shift+G` | Tidy windows |
194
207
  | `Tab` | Switch panes |
195
208
  | `j` / `k` | Navigate lists |
196
209
  | `h` / `l` | Switch tabs |
@@ -224,6 +237,7 @@ Use `HELP` inside Gloomberb for the live shortcut list. The common command-bar p
224
237
  | `CMP <tickers>` | Normalized price comparison |
225
238
  | `CORR <tickers>` | Ticker return correlations |
226
239
  | `ANR <ticker>` | Analyst targets and ratings |
240
+ | `DIAG <ticker>` | Equity Diagnostic with cited flags and anomalies |
227
241
  | `SEC <ticker>` | SEC filings and company disclosures |
228
242
  | `OMON <ticker>` | Options monitor |
229
243
  | `OVME` | Black-Scholes option calculator with Greeks and implied volatility |
@@ -272,6 +286,7 @@ The toolbar controls preset or exact date ranges, intervals from one minute thro
272
286
  | `AUCT` | Treasury auction results: high rate, bid-to-cover, indirect share, and size |
273
287
  | `VIX` | VIX 30-day/3-month implied-volatility curve |
274
288
  | `CRD` | Credit spreads |
289
+ | `CDS [ticker]` | Single-name corporate CDS activity: most-active issuers, or one issuer's trades |
275
290
  | `ERN` | Earnings calendar |
276
291
  | `IPO` | Upcoming and recent IPOs |
277
292
  | `HALT` | US trading halts with reason and resumption times |
@@ -301,16 +316,24 @@ The toolbar controls preset or exact date ranges, intervals from one minute thro
301
316
  | `AW` / `AP <ticker>` | Add a ticker to the active watchlist or portfolio |
302
317
  | `RW` / `RP <ticker>` | Remove a ticker from the active watchlist or portfolio |
303
318
  | `PS` | Open focused pane settings |
304
- | `LAY <action>` | Open layout actions |
319
+ | `LAY` | Open the layout browser to switch, publish, or add layouts |
320
+ | `LMA <query>` | Layout and pane arrangement actions |
305
321
  | `WIN move\|resize` | Move or resize the focused window |
306
- | `GL` | Gridlock all visible panes |
322
+ | `GL` | Tidy all windows |
307
323
  | `SB` | Toggle the status bar |
308
324
  | `VF` | Toggle quote value flashing |
309
325
  | `TH <theme>` | Change color theme |
326
+ | `FONT+` / `FONT-` | Increase or decrease desktop font size |
327
+ | `CONN` | Connection health |
328
+ | `POLL` | Prediction-market polls |
329
+ | `ART` | Loaded article lookup |
330
+ | `UPGRADE` | Account upgrade |
310
331
  | `CR` | Cycle chart renderer |
311
332
  | `LANG <locale>` | Change interface language (`auto`, `en`, `es`, `zh-CN`, `zh-TW`, `ja`, or `ko`) |
312
333
  | `PL <plugin>` | Manage plugins |
313
334
 
335
+ Published layouts preserve portable pane setup and state, including searches, chart viewport, and drawings. Credentials, accounts, portfolios, and pane fields marked private stay local. Publishing copies a durable `term.gloom.sh/l/...` link for social sharing.
336
+
314
337
  ## Gloom Cloud sign-in
315
338
 
316
339
  Sign in with email and password, or pick `Log In with QR Code` from the command bar and scan the code with the Gloomberb mobile companion app to sign the terminal in without typing. The onboarding wizard offers the same QR option as the recommended path, with email and password as the alternative.
package/README.zh-CN.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- <img src="https://gloomberb.com/gloomberb-logo-grayscale.svg" alt="Gloomberb logo" width="76" />
3
+ <img src="https://gloom.sh/gloomberb-logo-grayscale.svg" alt="Gloomberb logo" width="76" />
4
4
 
5
5
  # Gloomberb
6
6
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  桌面应用支持 macOS 和 Windows。终端界面(TUI)支持 macOS、Linux 和 Windows。
10
10
 
11
- <a href="https://gloomberb.com/download/desktop"><strong>下载桌面版</strong></a>
11
+ <a href="https://gloom.sh/download/desktop"><strong>下载桌面版</strong></a>
12
12
  &nbsp;&middot;&nbsp;
13
13
  <a href="#安装">安装 TUI</a>
14
14
  &nbsp;&middot;&nbsp;
@@ -17,7 +17,7 @@
17
17
  <br />
18
18
  <br />
19
19
 
20
- <img src="https://gloomberb.com/landing-terminal.png" alt="Gloomberb 终端界面,显示投资组合、自选列表、市场数据和图表面板。" width="720" />
20
+ <img src="https://gloom.sh/landing-terminal.png" alt="Gloomberb 终端界面,显示投资组合、自选列表、市场数据和图表面板。" width="720" />
21
21
 
22
22
  </div>
23
23
 
@@ -43,21 +43,21 @@ Gloomberb 有两种使用方式:
43
43
  ```bash
44
44
  brew install --cask vincelwt/tap/gloomberb
45
45
  # 或
46
- curl -fsSL gloomberb.com/install | bash
46
+ curl -fsSL gloom.sh/install | bash
47
47
  ```
48
48
 
49
49
  两种方式都会安装 `Gloomberb.app`,以及一个通过应用内置运行时执行 TUI 的 `gloomberb` 命令,运行时只会存储一份。
50
50
 
51
51
  想直接下载?
52
52
 
53
- - [下载 Gloomberb(Mac 版)](https://gloomberb.com/download/desktop)
53
+ - [下载 Gloomberb(Mac 版)](https://gloom.sh/download/desktop)
54
54
 
55
55
  ### Linux
56
56
 
57
57
  安装独立的 TUI 可执行文件:
58
58
 
59
59
  ```bash
60
- curl -fsSL gloomberb.com/install | bash
60
+ curl -fsSL gloom.sh/install | bash
61
61
  ```
62
62
 
63
63
  默认会将 `gloomberb` 安装到 `~/.local/bin`。Linux 桌面安装包暂未发布。
@@ -136,10 +136,9 @@ gloomberb
136
136
  | `gloomberb portfolio [action]` | 管理手动投资组合 |
137
137
  | `gloomberb watchlist [action]` | 管理自选列表 |
138
138
  | `gloomberb notes\|alerts [action]` | 管理本地笔记与提醒 |
139
- | `gloomberb broker\|ibkr [action]` | 查看券商集成状态;交易操作需要显式指定账户/配置并加 `--yes` |
140
- | `gloomberb ai providers\|ask\|screen` | 使用已配置的 AI 服务商与选股器 |
139
+ | `gloomberb broker\|ibkr [action]` | 查看券商配置 |
140
+ | `gloomberb ai providers\|ask` | 使用已配置的 AI 服务商 |
141
141
  | `gloomberb rss fetch <url>` | 抓取 RSS 订阅源 |
142
- | `gloomberb buildout\|congress\|substack\|x-feed\|tweets` | 在已有会话可用时访问云端与社交数据源 |
143
142
  | `gloomberb provider status` | 查看已启用的数据源 |
144
143
  | `gloomberb config\|cache\|plugin\|layout\|pane\|debug\|doctor\|version\|changelog` | 查看和管理本地应用状态 |
145
144
  | `gloomberb fn [...]` | 运行基于面板的报告命令 |
@@ -150,8 +149,6 @@ gloomberb
150
149
  | `gloomberb remove <name>` | 移除已安装插件 |
151
150
  | `gloomberb update [name]` | 更新插件 |
152
151
 
153
- 需要已登录云端会话的命令可能返回 `auth_required`;登录、账户管理与聊天相关操作目前仍需在应用界面中完成。
154
-
155
152
  ## 插件
156
153
 
157
154
  从投资组合列表到券商集成,一切皆为插件。插件可以添加面板、页签、列、命令栏命令、CLI 命令、状态栏组件与数据源。
@@ -260,7 +257,8 @@ gloomberb
260
257
  | `AW` / `AP <ticker>` | 将股票添加到活动自选列表或投资组合 |
261
258
  | `RW` / `RP <ticker>` | 从活动自选列表或投资组合中移除股票 |
262
259
  | `PS` | 打开聚焦面板的设置 |
263
- | `LAY <action>` | 打开布局操作 |
260
+ | `LAY` | 打开布局浏览器以切换、发布或添加布局 |
261
+ | `LMA <query>` | 布局与面板排列操作 |
264
262
  | `WIN move\|resize` | 移动或缩放聚焦窗口 |
265
263
  | `GL` | 所有可见面板网格对齐 |
266
264
  | `SB` | 切换状态栏 |
@@ -270,6 +268,8 @@ gloomberb
270
268
  | `LANG <locale>` | 切换界面语言(`auto`、`en`、`es`、`zh-CN`、`zh-TW`、`ja` 或 `ko`) |
271
269
  | `PL <plugin>` | 管理插件 |
272
270
 
271
+ 发布的布局会保留可移植的面板设置与状态,包括搜索条件、图表视窗和绘图;凭据、账户、投资组合以及标记为私密的字段始终保留在本地。发布后会自动复制一个长期有效的 `term.gloom.sh/l/...` 社交分享链接。
272
+
273
273
  ## 本地化界面
274
274
 
275
275
  Gloomberb 内置 English、简体中文、繁體中文、日本語和한국어界面支持;英文仍是默认回退语言。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gloomberb",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "packageManager": "bun@1.3.11",
5
5
  "description": "Market research and portfolio tracker for the terminal",
6
6
  "module": "src/index.tsx",
@@ -19,15 +19,21 @@
19
19
  "build": "bun run scripts/build.ts",
20
20
  "build:all": "bun run scripts/build.ts --all",
21
21
  "desktop:view:build": "bun run scripts/build-electrobun-view.ts",
22
+ "web:build": "bun run scripts/build-web.ts",
23
+ "web:audit": "bun run web:build && bun run scripts/audit-web-bundle.ts",
24
+ "cloudflare:typecheck": "tsc --project tsconfig.cloudflare.json",
25
+ "cloudflare:dry-run": "bun run web:build && wrangler deploy --dry-run",
22
26
  "desktop:dev": "bun run scripts/electrobun-dev.ts",
23
27
  "desktop:build": "electrobun build",
24
28
  "desktop:release": "electrobun build --env=stable",
25
29
  "desktop:release:windows": "electrobun build --env=stable --targets=win-x64",
26
30
  "i18n:audit": "bun run scripts/i18n-audit.ts",
27
- "typecheck": "bun run typecheck:opentui && bun run typecheck:electrobun-bun && bun run typecheck:electrobun-view && bun run typecheck:scripts",
31
+ "typecheck": "bun run typecheck:opentui && bun run typecheck:electrobun-bun && bun run typecheck:electrobun-view && bun run typecheck:browser && bun run typecheck:cloudflare && bun run typecheck:scripts",
28
32
  "typecheck:opentui": "tsc --project tsconfig.opentui.json",
29
33
  "typecheck:electrobun-bun": "tsc --project tsconfig.electrobun-bun.json",
30
34
  "typecheck:electrobun-view": "tsc --project tsconfig.electrobun-view.json",
35
+ "typecheck:browser": "tsc --project tsconfig.browser.json",
36
+ "typecheck:cloudflare": "tsc --project tsconfig.cloudflare.json",
31
37
  "typecheck:scripts": "tsc --project tsconfig.scripts.json",
32
38
  "test": "bun test",
33
39
  "test:global-upgrade": "bun run scripts/smoke-global-upgrade.ts",
@@ -52,7 +58,8 @@
52
58
  "electrobun": "^1.18.1",
53
59
  "happy-dom": "^20.11.1",
54
60
  "png-to-ico": "^2.1.8",
55
- "rcedit": "^4.0.1"
61
+ "rcedit": "^4.0.1",
62
+ "wrangler": "^4.0.0"
56
63
  },
57
64
  "peerDependencies": {
58
65
  "typescript": "^5.9.2"
@@ -18,6 +18,7 @@ type CloudApiRequest = <T>(path: string, options?: RequestInit) => Promise<T>;
18
18
  interface CloudAuthApiOptions {
19
19
  getCurrentUser(): AuthUser | null;
20
20
  getSessionToken(): string | null;
21
+ hasSessionCredential(): boolean;
21
22
  request: CloudApiRequest;
22
23
  requireCapturedSession(message: string): void;
23
24
  setCurrentUser(user: AuthUser | null): void;
@@ -29,7 +30,7 @@ export class CloudAuthApi {
29
30
  constructor(private readonly options: CloudAuthApiOptions) {}
30
31
 
31
32
  restoreCachedUser(user: PersistedAuthUser | null): void {
32
- if (!this.options.getSessionToken() || !user?.id) {
33
+ if (!this.options.hasSessionCredential() || !user?.id) {
33
34
  this.options.setCurrentUser(null);
34
35
  return;
35
36
  }
@@ -56,15 +57,6 @@ export class CloudAuthApi {
56
57
  });
57
58
  }
58
59
 
59
- async ensureVerifiedSession(): Promise<AuthUser | null> {
60
- if (!this.options.getSessionToken()) return null;
61
- if (!this.options.getCurrentUser()) {
62
- await this.getSession();
63
- }
64
- const user = this.options.getCurrentUser();
65
- return user?.emailVerified ? user : null;
66
- }
67
-
68
60
  async signUp(email: string, username: string, name: string, password: string): Promise<AuthUser> {
69
61
  const result = await this.options.request<{ user: AuthUser }>("/auth/sign-up/email", {
70
62
  method: "POST",
@@ -134,6 +126,18 @@ export class CloudAuthApi {
134
126
  }
135
127
  }
136
128
 
129
+ /**
130
+ * Emails a password reset link. The reset itself completes on the gloom.sh
131
+ * site, so the app only ever sends the email. The server answers the same
132
+ * way whether or not the address exists.
133
+ */
134
+ async requestPasswordReset(email: string): Promise<void> {
135
+ await this.options.request("/auth/request-password-reset", {
136
+ method: "POST",
137
+ body: JSON.stringify({ email }),
138
+ });
139
+ }
140
+
137
141
  async sendVerification(): Promise<CloudVerificationResponse> {
138
142
  return this.options.request<CloudVerificationResponse>("/cloud/auth/send-verification", {
139
143
  method: "POST",
@@ -2,8 +2,13 @@ import type { TickerFinancials } from "../types/financials";
2
2
  import type { InstrumentSearchResult } from "../types/instrument";
3
3
  import { normalizeTweetSearchResponse } from "./normalizers";
4
4
  import {
5
+ cloudCdsPath,
5
6
  cloudCongressHousePath,
6
7
  cloudExchangeRatePath,
8
+ cloudSec13FPath,
9
+ cloudSecFilingContentPath,
10
+ cloudSecFilingDocumentsPath,
11
+ cloudSecFilingsPath,
7
12
  cloudFredSeriesPath,
8
13
  cloudHistoryPath,
9
14
  cloudMarketSearchPath,
@@ -13,20 +18,26 @@ import {
13
18
  cloudStatementsPath,
14
19
  cloudTickerTweetsPath,
15
20
  cloudTweetSearchPath,
21
+ type CloudCdsParams,
16
22
  type CloudCongressHouseParams,
17
23
  type CloudFredSeriesParams,
18
24
  type CloudHistoryParams,
19
25
  type CloudNewsParams,
26
+ type CloudSecFilingParams,
27
+ type CloudSecFilingsParams,
20
28
  type CloudTickerTweetsParams,
21
29
  type CloudTweetSearchParams,
22
30
  } from "./paths";
23
31
  import type {
24
32
  CloudAnalystResearchPayload,
25
33
  CloudShortInterestPayload,
34
+ CloudCdsResponse,
26
35
  CloudCompanyProfile,
27
36
  CloudCongressHousePayload,
28
37
  CloudCorporateActionsPayload,
29
38
  CloudEconEventPayload,
39
+ CloudEquityDiagnosticMode,
40
+ CloudEquityDiagnosticResult,
30
41
  CloudFredSeriesPayload,
31
42
  CloudFundamentals,
32
43
  CloudHoldersPayload,
@@ -37,6 +48,9 @@ import type {
37
48
  CloudMarketScreenerPayload,
38
49
  CloudNewsListResponse,
39
50
  CloudNewsPayload,
51
+ CloudSecContentResponse,
52
+ CloudSecDocumentsResponse,
53
+ CloudSecFilingsResponse,
40
54
  CloudOptionsChainPayload,
41
55
  CloudPricePointPayload,
42
56
  CloudQuotePayload,
@@ -163,6 +177,26 @@ export class CloudDataApi {
163
177
  return this.request<CloudMarketResponse<{ rate: number }>>(cloudExchangeRatePath(fromCurrency));
164
178
  }
165
179
 
180
+ /**
181
+ * On-demand single-company evidence review. This is a cloud product endpoint,
182
+ * not a market-data capability, so it is called directly instead of routed
183
+ * through the asset-data provider.
184
+ */
185
+ async getCloudEquityDiagnostic(
186
+ symbol: string,
187
+ exchange?: string,
188
+ mode: CloudEquityDiagnosticMode = "cache-first",
189
+ ): Promise<CloudEquityDiagnosticResult> {
190
+ return this.request<CloudEquityDiagnosticResult>("/research/equity-diagnostic", {
191
+ method: "POST",
192
+ body: JSON.stringify({
193
+ symbol: symbol.trim().toUpperCase(),
194
+ ...(exchange ? { exchange } : {}),
195
+ mode,
196
+ }),
197
+ });
198
+ }
199
+
166
200
  async getCloudEconomicCalendar(): Promise<CloudEconEventPayload[]> {
167
201
  return this.request<CloudEconEventPayload[]>("/cloud/econ/calendar");
168
202
  }
@@ -178,10 +212,30 @@ export class CloudDataApi {
178
212
  return this.request<CloudYieldPointPayload[]>("/cloud/econ/yield-curve");
179
213
  }
180
214
 
215
+ async getCloudCds(params: CloudCdsParams = {}): Promise<CloudCdsResponse> {
216
+ return this.request<CloudCdsResponse>(cloudCdsPath(params));
217
+ }
218
+
181
219
  async getCloudCongressHouse(params: CloudCongressHouseParams = {}): Promise<CloudCongressHousePayload> {
182
220
  return this.request<CloudCongressHousePayload>(cloudCongressHousePath(params));
183
221
  }
184
222
 
223
+ async getCloudSecFilings(params: CloudSecFilingsParams): Promise<CloudSecFilingsResponse> {
224
+ return this.request<CloudSecFilingsResponse>(cloudSecFilingsPath(params));
225
+ }
226
+
227
+ async getCloudSecFilingDocuments(params: CloudSecFilingParams): Promise<CloudSecDocumentsResponse> {
228
+ return this.request<CloudSecDocumentsResponse>(cloudSecFilingDocumentsPath(params));
229
+ }
230
+
231
+ async getCloudSecFilingContent(params: CloudSecFilingParams): Promise<CloudSecContentResponse> {
232
+ return this.request<CloudSecContentResponse>(cloudSecFilingContentPath(params));
233
+ }
234
+
235
+ async getCloudSec13F(path: string, params: Record<string, string | number | undefined> = {}): Promise<unknown> {
236
+ return this.request<unknown>(cloudSec13FPath(path, params));
237
+ }
238
+
185
239
  async getCloudNews(params: CloudNewsParams = {}): Promise<CloudNewsListResponse> {
186
240
  return this.request<CloudNewsListResponse>(cloudNewsPath(params));
187
241
  }
@@ -1,6 +1,9 @@
1
1
  import { afterEach, describe, expect, jest, test } from "bun:test";
2
2
  import type { AuthUser } from "./index";
3
3
  import { apiClient, setCloudApiFetchTransport } from "./index";
4
+ import { publishableMarketplaceLayout } from "../layout-marketplace/payload";
5
+ import { createDefaultConfig } from "../types/config";
6
+ import type { PaneDef } from "../types/plugin";
4
7
 
5
8
  const originalFetch = globalThis.fetch;
6
9
  const originalWebSocket = globalThis.WebSocket;
@@ -104,10 +107,97 @@ afterEach(() => {
104
107
  setCloudApiFetchTransport(null);
105
108
  apiClient.setSessionToken(null);
106
109
  apiClient.setWebSocketToken(null);
110
+ apiClient.setCookieSessionMode(false);
107
111
  jest.useRealTimers();
108
112
  });
109
113
 
114
+ describe("apiClient layout marketplace", () => {
115
+ test("lists and publishes validated layouts through authenticated transport", async () => {
116
+ const config = createDefaultConfig("/tmp/api-layout-marketplace-test");
117
+ const panes = new Map(config.layout.instances.map((instance) => [instance.paneId, {
118
+ id: instance.paneId,
119
+ name: instance.paneId,
120
+ component: () => null,
121
+ defaultPosition: "right" as const,
122
+ } satisfies PaneDef]));
123
+ const payload = publishableMarketplaceLayout(config.layout, {}, panes);
124
+ const entry = {
125
+ id: "0123456789abcdef0123456789abcdef",
126
+ name: "Research Desk",
127
+ ...payload,
128
+ author: { username: "analyst", displayName: "Analyst" },
129
+ publishedAt: "2026-08-26T00:00:00.000Z",
130
+ };
131
+ const calls: Array<{ url: string; method: string; body?: unknown }> = [];
132
+ apiClient.setSessionToken("marketplace-session");
133
+ setCloudApiFetchTransport(async (url, init) => {
134
+ calls.push({
135
+ url,
136
+ method: init?.method ?? "GET",
137
+ ...(typeof init?.body === "string" ? { body: JSON.parse(init.body) } : {}),
138
+ });
139
+ const path = new URL(url).pathname;
140
+ return createResponse(path === `/layouts/${entry.id}` || init?.method === "POST"
141
+ ? entry
142
+ : { items: [entry] });
143
+ });
144
+
145
+ await expect(apiClient.listMarketplaceLayouts()).resolves.toEqual([entry]);
146
+ await expect(apiClient.getMarketplaceLayout(entry.id)).resolves.toEqual(entry);
147
+ await expect(apiClient.publishMarketplaceLayout(entry.name, payload)).resolves.toEqual(entry);
148
+
149
+ expect(calls.map((call) => [new URL(call.url).pathname, call.method])).toEqual([
150
+ ["/layouts", "GET"],
151
+ [`/layouts/${entry.id}`, "GET"],
152
+ ["/layouts", "POST"],
153
+ ]);
154
+ expect(calls[2]?.body).toMatchObject({ name: "Research Desk", schemaVersion: 2, paneState: {} });
155
+ });
156
+ });
157
+
110
158
  describe("apiClient auth cookies", () => {
159
+ test("accepts a browser-managed api.gloom.sh cookie without exposing its value", async () => {
160
+ apiClient.setCookieSessionMode(true);
161
+ setCloudApiFetchTransport(mockFetch(() => createResponse({ user: verifiedUser })));
162
+
163
+ await expect(apiClient.signIn("test@example.com", "password")).resolves.toEqual(verifiedUser);
164
+ expect(apiClient.getSessionToken()).toBeNull();
165
+ expect(apiClient.isVerified()).toBe(true);
166
+ });
167
+
168
+ test("reports signed-in from the restored user when the cookie hides the raw token", async () => {
169
+ apiClient.setCookieSessionMode(true);
170
+ setCloudApiFetchTransport(mockFetch(() => createResponse({ user: verifiedUser })));
171
+
172
+ expect(apiClient.isSignedIn()).toBe(false);
173
+ await apiClient.signIn("test@example.com", "password");
174
+ expect(apiClient.getSessionToken()).toBeNull();
175
+ expect(apiClient.isSignedIn()).toBe(true);
176
+ });
177
+
178
+ test("coalesces anonymous browser session checks and remembers the result", async () => {
179
+ apiClient.setCookieSessionMode(true);
180
+ let requests = 0;
181
+ let finishRequest!: () => void;
182
+ setCloudApiFetchTransport(async () => {
183
+ requests += 1;
184
+ await new Promise<void>((resolve) => { finishRequest = resolve; });
185
+ return createResponse({ user: null });
186
+ });
187
+
188
+ const checks = [
189
+ apiClient.ensureVerifiedSession(),
190
+ apiClient.ensureVerifiedSession(),
191
+ apiClient.ensureVerifiedSession(),
192
+ ];
193
+ expect(requests).toBe(1);
194
+ finishRequest();
195
+
196
+ await expect(Promise.all(checks)).resolves.toEqual([null, null, null]);
197
+ await expect(apiClient.ensureVerifiedSession()).resolves.toBeNull();
198
+ expect(requests).toBe(1);
199
+ });
200
+
111
201
  test("captures secure session cookies after login and reuses them on session refresh", async () => {
112
202
  const seenCookies: Array<string | null> = [];
113
203
 
@@ -1039,3 +1129,37 @@ describe("apiClient cloud news", () => {
1039
1129
  expect(story.id).toBe("story-1");
1040
1130
  });
1041
1131
  });
1132
+
1133
+ describe("apiClient equity diagnostic", () => {
1134
+ test("posts the symbol, exchange, and cache mode to the research route", async () => {
1135
+ let seenUrl = "";
1136
+ let seenInit: RequestInit | undefined;
1137
+ globalThis.fetch = mockFetch(async (input: Request | string | URL, init?: RequestInit) => {
1138
+ seenUrl = String(input);
1139
+ seenInit = init;
1140
+ return createResponse({ symbol: "AAPL", status: "complete" });
1141
+ });
1142
+
1143
+ await apiClient.getCloudEquityDiagnostic(" aapl ", "NASDAQ", "refresh");
1144
+
1145
+ expect(new URL(seenUrl).pathname).toBe("/research/equity-diagnostic");
1146
+ expect(seenInit?.method).toBe("POST");
1147
+ expect(JSON.parse(String(seenInit?.body))).toEqual({
1148
+ symbol: "AAPL",
1149
+ exchange: "NASDAQ",
1150
+ mode: "refresh",
1151
+ });
1152
+ });
1153
+
1154
+ test("omits an unknown exchange and defaults to the cached answer", async () => {
1155
+ let seenInit: RequestInit | undefined;
1156
+ globalThis.fetch = mockFetch(async (_input: Request | string | URL, init?: RequestInit) => {
1157
+ seenInit = init;
1158
+ return createResponse({ symbol: "AAPL", status: "complete" });
1159
+ });
1160
+
1161
+ await apiClient.getCloudEquityDiagnostic("AAPL");
1162
+
1163
+ expect(JSON.parse(String(seenInit?.body))).toEqual({ symbol: "AAPL", mode: "cache-first" });
1164
+ });
1165
+ });