gloomberb 0.11.3 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (489) hide show
  1. package/README.md +6 -4
  2. package/README.zh-CN.md +4 -2
  3. package/package.json +28 -1
  4. package/src/api-client/auth.ts +10 -0
  5. package/src/api-client/data.ts +103 -1
  6. package/src/api-client/index.test.ts +127 -0
  7. package/src/api-client/index.ts +129 -1
  8. package/src/api-client/normalizers.ts +39 -0
  9. package/src/api-client/paths.ts +85 -1
  10. package/src/api-client/types.ts +196 -0
  11. package/src/app/pane-runtime/index.tsx +15 -12
  12. package/src/app/pane-runtime/layout-placement.test.ts +27 -0
  13. package/src/app/pane-runtime/layout-placement.ts +13 -0
  14. package/src/app/pane-runtime/plugin-bindings.ts +62 -0
  15. package/src/app.tsx +60 -18
  16. package/src/architecture/browser-entry-graph.test.ts +96 -0
  17. package/src/brokers/profile-form.test.ts +25 -27
  18. package/src/brokers/test-broker.ts +68 -0
  19. package/src/cli/commands/plugins.ts +39 -11
  20. package/src/cli/desktop-pane-shot.ts +285 -16
  21. package/src/cli/index.ts +1 -1
  22. package/src/cli/pane-functions/capabilities.ts +58 -28
  23. package/src/cli/pane-functions/catalog.ts +16 -4
  24. package/src/cli/pane-functions/discovery.ts +1 -0
  25. package/src/cli/pane-functions/headless.test.ts +247 -0
  26. package/src/cli/pane-functions/headless.ts +423 -0
  27. package/src/cli/pane-functions/index.test.ts +9 -0
  28. package/src/cli/pane-functions/index.ts +6 -2
  29. package/src/cli/pane-functions/options.ts +27 -2
  30. package/src/cli/pane-functions/report.ts +4 -0
  31. package/src/cli/pane-functions/resolver.ts +26 -8
  32. package/src/cli/pane-functions/screenshot.test.ts +76 -0
  33. package/src/cli/pane-functions/screenshot.ts +236 -20
  34. package/src/cli/restore-plugins.ts +34 -0
  35. package/src/components/chart/{static/chart → composite}/axis-overlays.test.tsx +3 -3
  36. package/src/components/chart/{static/chart → composite}/axis-overlays.tsx +6 -11
  37. package/src/components/chart/{static/chart → composite}/bitmap.ts +17 -3
  38. package/src/components/chart/composite/composite-chart.test.tsx +68 -20
  39. package/src/components/chart/composite/composite-chart.tsx +301 -204
  40. package/src/components/chart/composite/format.ts +8 -2
  41. package/src/components/chart/composite/interactions.test.ts +68 -102
  42. package/src/components/chart/composite/interactions.ts +214 -264
  43. package/src/components/chart/composite/price-axis-labels.test.ts +21 -0
  44. package/src/components/chart/{price-axis-labels.tsx → composite/price-axis-labels.tsx} +9 -4
  45. package/src/components/chart/composite/scene.ts +57 -3
  46. package/src/components/chart/composite/text-renderer.ts +3 -2
  47. package/src/components/chart/composite/time-scale.ts +138 -57
  48. package/src/components/chart/composite/types.ts +25 -1
  49. package/src/components/chart/core/data.ts +9 -13
  50. package/src/components/chart/core/date-window.ts +7 -1
  51. package/src/components/chart/core/pointer.ts +3 -0
  52. package/src/components/chart/core/types.ts +0 -45
  53. package/src/components/chart/native/chart-rasterizer.ts +0 -1
  54. package/src/components/chart/native/kitty/index.test.ts +0 -188
  55. package/src/components/chart/native/raster/crosshair.ts +6 -5
  56. package/src/components/chart/native/raster/primitives.ts +0 -23
  57. package/src/components/chart/native/renderer-selection.ts +81 -31
  58. package/src/components/chart/static/{chart/surface.test.tsx → chart-surface.test.tsx} +28 -80
  59. package/src/components/chart/static/chart-surface.tsx +150 -0
  60. package/src/components/chart/static/index.ts +8 -0
  61. package/src/components/chart/static/multi-line-chart-surface.tsx +51 -166
  62. package/src/components/chart/static/scatter-chart-surface.test.ts +30 -0
  63. package/src/components/chart/static/scatter-chart-surface.tsx +135 -34
  64. package/src/components/chart/static/series.ts +49 -0
  65. package/src/components/command-bar/action-runtime.ts +1 -3
  66. package/src/components/command-bar/assist/model.test.ts +17 -2
  67. package/src/components/command-bar/assist/model.ts +40 -9
  68. package/src/components/command-bar/commands/direct/index.ts +1 -1
  69. package/src/components/command-bar/commands/direct/runtime.ts +1 -1
  70. package/src/components/command-bar/commands/registry.ts +0 -11
  71. package/src/components/command-bar/helpers.test.ts +2 -2
  72. package/src/components/command-bar/helpers.ts +2 -6
  73. package/src/components/command-bar/keyboard-shortcuts.ts +0 -11
  74. package/src/components/command-bar/list/badge.test.ts +54 -0
  75. package/src/components/command-bar/list/badge.ts +62 -0
  76. package/src/components/command-bar/list/model.test.ts +103 -0
  77. package/src/components/command-bar/list/model.ts +61 -4
  78. package/src/components/command-bar/list/view.test.tsx +113 -0
  79. package/src/components/command-bar/list/view.tsx +147 -131
  80. package/src/components/command-bar/pane-templates/workflow.ts +1 -1
  81. package/src/components/command-bar/panel/body.tsx +51 -65
  82. package/src/components/command-bar/panel/index.tsx +48 -13
  83. package/src/components/command-bar/panel/layout.test.ts +139 -0
  84. package/src/components/command-bar/panel/layout.ts +65 -28
  85. package/src/components/command-bar/panel/native-surface.ts +24 -0
  86. package/src/components/command-bar/panel/prompt-binding.ts +54 -0
  87. package/src/components/command-bar/panel/runtime.ts +6 -3
  88. package/src/components/command-bar/panel/state.ts +41 -7
  89. package/src/components/command-bar/panel/types.ts +7 -1
  90. package/src/components/command-bar/routes/root/provider-search.ts +34 -15
  91. package/src/components/command-bar/routes/root/results.test.ts +161 -0
  92. package/src/components/command-bar/routes/root/results.ts +30 -28
  93. package/src/components/command-bar/routes/root/runtime.ts +37 -20
  94. package/src/components/command-bar/routes/root/search-providers.test.tsx +224 -0
  95. package/src/components/command-bar/routes/root/search-providers.ts +205 -0
  96. package/src/components/command-bar/routes/root/selection.ts +1 -12
  97. package/src/components/command-bar/routes/root/shortcuts.test.ts +8 -8
  98. package/src/components/command-bar/routes/ticker-search/actions.ts +10 -9
  99. package/src/components/command-bar/routes/ticker-search/results.test.ts +54 -1
  100. package/src/components/command-bar/routes/ticker-search/results.ts +60 -19
  101. package/src/components/command-bar/routes/ticker-search/route.ts +1 -0
  102. package/src/components/command-bar/routing/actions.ts +1 -81
  103. package/src/components/command-bar/routing/launch-request.ts +1 -1
  104. package/src/components/command-bar/routing/list-state.ts +6 -21
  105. package/src/components/command-bar/selection-runtime.ts +1 -1
  106. package/src/components/command-bar/surface/assist.test.tsx +14 -10
  107. package/src/components/command-bar/surface/environment.ts +8 -1
  108. package/src/components/command-bar/surface/index.test.tsx +84 -68
  109. package/src/components/command-bar/surface/index.tsx +33 -36
  110. package/src/components/command-bar/surface/test-harness.tsx +15 -3
  111. package/src/components/command-bar/theme-picker.tsx +43 -15
  112. package/src/components/command-bar/view-model.test.ts +53 -8
  113. package/src/components/command-bar/view-model.ts +43 -14
  114. package/src/components/command-bar/workflow/tickers.ts +1 -0
  115. package/src/components/command-bar/workflow/types.ts +1 -1
  116. package/src/components/data-table/view.test.tsx +45 -6
  117. package/src/components/data-table/view.tsx +55 -9
  118. package/src/components/index.ts +10 -2
  119. package/src/components/input-search-bar.test.tsx +36 -2
  120. package/src/components/input-search-bar.tsx +18 -1
  121. package/src/components/layout/header.test.tsx +57 -10
  122. package/src/components/layout/header.tsx +292 -149
  123. package/src/components/layout/market-summary.test.ts +81 -0
  124. package/src/components/layout/market-summary.ts +109 -0
  125. package/src/components/layout/shell/chrome.ts +96 -1
  126. package/src/components/layout/shell/index.tsx +11 -3
  127. package/src/components/layout/shell/menu.ts +9 -0
  128. package/src/components/layout/shell/pane/actions.ts +29 -0
  129. package/src/components/layout/shell/pane/management-shortcuts.ts +5 -0
  130. package/src/components/layout/shell/shortcuts.ts +3 -0
  131. package/src/components/layout/status-bar.test.tsx +9 -8
  132. package/src/components/layout/status-bar.tsx +85 -54
  133. package/src/components/onboarding/onboarding-frame.tsx +2 -26
  134. package/src/components/price-sparkline/index.ts +61 -34
  135. package/src/components/price-sparkline/view.tsx +1 -1
  136. package/src/components/sign-in-gate.test.tsx +128 -0
  137. package/src/components/sign-in-gate.tsx +149 -0
  138. package/src/components/speedometer-gauge/desktop.tsx +2 -12
  139. package/src/components/ticker/badge/list.tsx +17 -3
  140. package/src/components/ticker/list-table-view.tsx +6 -3
  141. package/src/components/ui/data-table/index.tsx +3 -2
  142. package/src/components/ui/data-table/opentui/index.tsx +165 -120
  143. package/src/components/ui/frame.tsx +28 -0
  144. package/src/components/ui/index.ts +3 -0
  145. package/src/components/ui/native-select.tsx +20 -10
  146. package/src/components/ui/select-button.tsx +138 -0
  147. package/src/components/ui/status.tsx +2 -2
  148. package/src/components/ui/table-layout.ts +1 -1
  149. package/src/components/use-double-click-activation.ts +7 -3
  150. package/src/core/app-services.ts +3 -3
  151. package/src/data/config/layout.ts +12 -6
  152. package/src/data/config/store/index.test.ts +97 -0
  153. package/src/data/config/store/migrations.ts +41 -0
  154. package/src/data/config/store/normalize.ts +5 -3
  155. package/src/i18n/es.ts +6 -2
  156. package/src/i18n/ja.ts +6 -2
  157. package/src/i18n/ko.ts +6 -2
  158. package/src/i18n/zh-cn.ts +6 -2
  159. package/src/i18n/zh-tw.ts +6 -2
  160. package/src/layout-marketplace/pane-imagery.ts +1 -0
  161. package/src/layout-marketplace/payload.test.ts +17 -0
  162. package/src/layout-marketplace/payload.ts +40 -5
  163. package/src/market-data/coordinator/index.ts +3 -2
  164. package/src/market-data/coordinator/quotes.ts +173 -66
  165. package/src/market-data/coordinator/subscriptions.test.ts +215 -37
  166. package/src/pane-settings.ts +1 -1
  167. package/src/plugins/builtin/analytics/pane-model.ts +1 -1
  168. package/src/plugins/builtin/analytics/view.tsx +1 -1
  169. package/src/plugins/builtin/broker-manager/index.test.tsx +3 -2
  170. package/src/plugins/builtin/broker-manager/model.test.ts +2 -2
  171. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +16 -2
  172. package/src/plugins/builtin/chart-composer/pane.tsx +22 -8
  173. package/src/plugins/builtin/chat/content/composer.tsx +8 -4
  174. package/src/plugins/builtin/cloud/auth-dialog.tsx +14 -228
  175. package/src/plugins/builtin/cloud/auth-form.tsx +277 -0
  176. package/src/plugins/builtin/cloud/plugin.tsx +1 -0
  177. package/src/plugins/builtin/composite-plugins.ts +14 -1
  178. package/src/plugins/builtin/correlation/relationship/model.ts +1 -1
  179. package/src/plugins/builtin/correlation/relationship/pane.tsx +2 -6
  180. package/src/plugins/builtin/correlation/relationship/view-model.ts +2 -2
  181. package/src/plugins/builtin/credit-conditions/index.test.tsx +12 -6
  182. package/src/plugins/builtin/credit-conditions/index.tsx +2 -21
  183. package/src/plugins/builtin/dividend-yield/index.tsx +1 -0
  184. package/src/plugins/builtin/dividend-yield/pane.tsx +1 -1
  185. package/src/plugins/builtin/earnings-calls/data.ts +223 -0
  186. package/src/plugins/builtin/earnings-calls/format.ts +49 -0
  187. package/src/plugins/builtin/earnings-calls/index.tsx +69 -0
  188. package/src/plugins/builtin/earnings-calls/pane.tsx +756 -0
  189. package/src/plugins/builtin/earnings-calls/prose.test.ts +36 -0
  190. package/src/plugins/builtin/earnings-calls/prose.ts +59 -0
  191. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +334 -0
  192. package/src/plugins/builtin/econ/detail-view.tsx +1 -2
  193. package/src/plugins/builtin/econ/fred-series-map.ts +16 -1
  194. package/src/plugins/builtin/econ/index.tsx +2 -1
  195. package/src/plugins/builtin/econ-statistics/cache.ts +4 -0
  196. package/src/plugins/builtin/econ-statistics/client.ts +92 -0
  197. package/src/plugins/builtin/econ-statistics/defs.ts +66 -0
  198. package/src/plugins/builtin/econ-statistics/detail.tsx +154 -0
  199. package/src/plugins/builtin/econ-statistics/headless.test.ts +54 -0
  200. package/src/plugins/builtin/econ-statistics/headless.ts +171 -0
  201. package/src/plugins/builtin/econ-statistics/index.tsx +54 -0
  202. package/src/plugins/builtin/econ-statistics/pane.tsx +356 -0
  203. package/src/plugins/builtin/econ-statistics/stats.ts +522 -0
  204. package/src/plugins/builtin/econ-statistics/transform.test.ts +86 -0
  205. package/src/plugins/builtin/econ-statistics/transform.ts +85 -0
  206. package/src/plugins/builtin/econ-statistics/trend.ts +57 -0
  207. package/src/plugins/builtin/econ-statistics/view.ts +90 -0
  208. package/src/plugins/builtin/fear-greed/charts.tsx +7 -18
  209. package/src/plugins/builtin/fear-greed/data.ts +6 -1
  210. package/src/plugins/builtin/help/index.tsx +4 -0
  211. package/src/plugins/builtin/holders/index.tsx +1 -0
  212. package/src/plugins/builtin/insider/index.tsx +1 -0
  213. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  214. package/src/plugins/builtin/kelly-sizer/sections.tsx +2 -3
  215. package/src/plugins/builtin/market-valuation/align.ts +122 -0
  216. package/src/plugins/builtin/market-valuation/cache.ts +32 -0
  217. package/src/plugins/builtin/market-valuation/chart-projection.ts +217 -0
  218. package/src/plugins/builtin/market-valuation/chart-series.ts +89 -0
  219. package/src/plugins/builtin/market-valuation/client.test.ts +141 -0
  220. package/src/plugins/builtin/market-valuation/client.ts +116 -0
  221. package/src/plugins/builtin/market-valuation/defs.ts +251 -0
  222. package/src/plugins/builtin/market-valuation/detail.tsx +159 -0
  223. package/src/plugins/builtin/market-valuation/headless.test.ts +58 -0
  224. package/src/plugins/builtin/market-valuation/headless.ts +170 -0
  225. package/src/plugins/builtin/market-valuation/index.tsx +64 -0
  226. package/src/plugins/builtin/market-valuation/indicators.ts +422 -0
  227. package/src/plugins/builtin/market-valuation/model.test.ts +350 -0
  228. package/src/plugins/builtin/market-valuation/model.ts +8 -0
  229. package/src/plugins/builtin/market-valuation/pane.test.tsx +247 -0
  230. package/src/plugins/builtin/market-valuation/pane.tsx +344 -0
  231. package/src/plugins/builtin/market-valuation/series.ts +12 -0
  232. package/src/plugins/builtin/market-valuation/settings.ts +38 -0
  233. package/src/plugins/builtin/market-valuation/sources.ts +130 -0
  234. package/src/plugins/builtin/market-valuation/trend.ts +89 -0
  235. package/src/plugins/builtin/market-valuation/view.ts +137 -0
  236. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +123 -0
  237. package/src/plugins/builtin/market-valuation/zone-scale/index.tsx +12 -0
  238. package/src/plugins/builtin/market-valuation/zone-scale/model.ts +60 -0
  239. package/src/plugins/builtin/market-valuation/zone-scale/terminal.tsx +94 -0
  240. package/src/plugins/builtin/news/wire/breaking/filters.test.ts +99 -0
  241. package/src/plugins/builtin/news/wire/breaking/filters.ts +110 -0
  242. package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +157 -53
  243. package/src/plugins/builtin/news/wire/breaking/notifications.ts +91 -25
  244. package/src/plugins/builtin/news/wire/index.tsx +31 -44
  245. package/src/plugins/builtin/options/index.tsx +1 -0
  246. package/src/plugins/builtin/options/view.test.tsx +29 -1
  247. package/src/plugins/builtin/options/view.tsx +1 -22
  248. package/src/plugins/builtin/plugin-marketplace/feed.ts +80 -0
  249. package/src/plugins/builtin/plugin-marketplace/index.tsx +31 -0
  250. package/src/plugins/builtin/plugin-marketplace/model.test.ts +200 -0
  251. package/src/plugins/builtin/plugin-marketplace/model.ts +204 -0
  252. package/src/plugins/builtin/plugin-marketplace/pane.tsx +385 -0
  253. package/src/plugins/builtin/plugin-marketplace/store.ts +46 -0
  254. package/src/plugins/builtin/plugin-module.ts +9 -1
  255. package/src/plugins/builtin/research/index.tsx +4 -0
  256. package/src/plugins/builtin/research-search/command-bar-search.test.ts +81 -0
  257. package/src/plugins/builtin/research-search/command-bar-search.ts +175 -0
  258. package/src/plugins/builtin/research-search/data.ts +109 -0
  259. package/src/plugins/builtin/research-search/document-view.test.tsx +75 -0
  260. package/src/plugins/builtin/research-search/document-view.tsx +254 -0
  261. package/src/plugins/builtin/research-search/filter-bar.tsx +62 -0
  262. package/src/plugins/builtin/research-search/focus-handoff.ts +47 -0
  263. package/src/plugins/builtin/research-search/index.tsx +85 -0
  264. package/src/plugins/builtin/research-search/model.test.ts +40 -0
  265. package/src/plugins/builtin/research-search/model.ts +291 -0
  266. package/src/plugins/builtin/research-search/pane.test.tsx +241 -0
  267. package/src/plugins/builtin/research-search/pane.tsx +678 -0
  268. package/src/plugins/builtin/research-search/saved-view.tsx +171 -0
  269. package/src/plugins/builtin/research-search/snippet-text.tsx +35 -0
  270. package/src/plugins/builtin/research-search/snippet.test.ts +78 -0
  271. package/src/plugins/builtin/research-search/snippet.ts +134 -0
  272. package/src/plugins/builtin/scanner/flow-model.test.ts +11 -1
  273. package/src/plugins/builtin/scanner/flow-model.ts +29 -1
  274. package/src/plugins/builtin/scanner/flow-pane.tsx +78 -22
  275. package/src/plugins/builtin/sec/index.tsx +1 -0
  276. package/src/plugins/builtin/shared/series-cache.ts +93 -0
  277. package/src/plugins/builtin/short-interest/index.tsx +1 -0
  278. package/src/plugins/builtin/short-interest/pane.tsx +1 -1
  279. package/src/plugins/builtin/thirteenf/index.tsx +1 -0
  280. package/src/plugins/builtin/ticker-detail/index.tsx +0 -14
  281. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +1 -1
  282. package/src/plugins/builtin/volatility/index.tsx +1 -1
  283. package/src/plugins/builtin/world-venue-map/map.desktop.test.tsx +106 -0
  284. package/src/plugins/builtin/world-venue-map/map.tsx +213 -69
  285. package/src/plugins/builtin/world-venue-map/model.test.ts +32 -0
  286. package/src/plugins/builtin/world-venue-map/model.ts +134 -13
  287. package/src/plugins/builtin/yield-curve/index.tsx +1 -1
  288. package/src/plugins/bundle.test.ts +109 -0
  289. package/src/plugins/bundle.ts +139 -0
  290. package/src/plugins/catalog-browser.test.ts +1 -0
  291. package/src/plugins/catalog-browser.ts +10 -0
  292. package/src/plugins/catalog-manifest.test.ts +43 -0
  293. package/src/plugins/catalog-manifest.ts +92 -0
  294. package/src/plugins/catalog-ui.ts +20 -4
  295. package/src/plugins/catalog.ts +9 -2
  296. package/src/plugins/current-target.ts +28 -0
  297. package/src/plugins/host-contract.ts +37 -0
  298. package/src/plugins/host-link.ts +158 -0
  299. package/src/plugins/host-modules.ts +61 -0
  300. package/src/plugins/loader.ts +41 -22
  301. package/src/plugins/ownership.ts +1 -0
  302. package/src/plugins/prediction-markets/index.tsx +1 -0
  303. package/src/plugins/registry/context.ts +3 -0
  304. package/src/plugins/registry/contributions.ts +27 -0
  305. package/src/plugins/registry/index.test.ts +25 -0
  306. package/src/plugins/registry/index.ts +8 -0
  307. package/src/plugins/registry/pane-settings.ts +6 -13
  308. package/src/plugins/seed.test.ts +83 -0
  309. package/src/plugins/seed.ts +80 -0
  310. package/src/public/broker.ts +31 -0
  311. package/src/public/market-data.ts +9 -0
  312. package/src/public/pane-hooks.ts +57 -0
  313. package/src/public/public-api.test.ts +285 -0
  314. package/src/public/react.ts +62 -0
  315. package/src/public/test-support.ts +23 -0
  316. package/src/public/time-series.ts +8 -0
  317. package/src/public/utils.ts +77 -0
  318. package/src/remote/layout-helpers.ts +6 -8
  319. package/src/remote/resources.ts +2 -0
  320. package/src/remote/schema.ts +1 -0
  321. package/src/remote/semantic-tree.test.tsx +105 -0
  322. package/src/remote/semantic-tree.tsx +53 -35
  323. package/src/renderers/browser/main.tsx +6 -0
  324. package/src/renderers/cloudflare/worker.test.ts +19 -0
  325. package/src/renderers/cloudflare/worker.ts +1 -1
  326. package/src/renderers/electrobun/bun/external-plugins.ts +140 -0
  327. package/src/renderers/electrobun/bun/index.ts +5 -2
  328. package/src/renderers/electrobun/shared/protocol.ts +21 -0
  329. package/src/renderers/electrobun/view/build-assets.ts +0 -1
  330. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +51 -1
  331. package/src/renderers/electrobun/view/external-plugins.test.ts +45 -0
  332. package/src/renderers/electrobun/view/external-plugins.ts +63 -0
  333. package/src/renderers/electrobun/view/host/ascii-text.test.ts +48 -0
  334. package/src/renderers/electrobun/view/host/ascii-text.ts +11 -1
  335. package/src/renderers/electrobun/view/host/chart-surface.tsx +38 -32
  336. package/src/renderers/electrobun/view/host/mouse.ts +16 -2
  337. package/src/renderers/electrobun/view/main.tsx +27 -2
  338. package/src/renderers/electrobun/view/styles.css +5 -0
  339. package/src/renderers/electrobun/view/toast-host.tsx +18 -0
  340. package/src/renderers/opentui/chart-surface.tsx +5 -1
  341. package/src/renderers/opentui/host.tsx +16 -2
  342. package/src/renderers/opentui/interaction-performance.test.ts +79 -0
  343. package/src/renderers/opentui/interaction-performance.ts +188 -0
  344. package/src/renderers/opentui/start.tsx +26 -1
  345. package/src/renderers/opentui/test-utils.tsx +13 -0
  346. package/src/renderers/opentui/toast-host.tsx +26 -2
  347. package/src/renderers/opentui/ui-host.tsx +1 -0
  348. package/src/sources/provider-router/search.test.ts +191 -0
  349. package/src/sources/provider-router/search.ts +92 -39
  350. package/src/state/app/context/index.tsx +2 -0
  351. package/src/state/app/context/selector.test.tsx +33 -1
  352. package/src/state/hooks/quote-streaming.test.tsx +93 -0
  353. package/src/state/hooks/quote-streaming.ts +106 -30
  354. package/src/state/pane-table-export-registry.ts +19 -0
  355. package/src/theme/color-utils.ts +1 -1
  356. package/src/theme/colors.ts +50 -0
  357. package/src/theme/themes.test.ts +15 -2
  358. package/src/theme/themes.ts +19 -1
  359. package/src/tickers/search/index.test.ts +26 -0
  360. package/src/tickers/search/index.ts +42 -17
  361. package/src/tickers/search/ranking.ts +14 -0
  362. package/src/time-series/chart-data.test.ts +216 -0
  363. package/src/time-series/resolution.test.ts +25 -26
  364. package/src/time-series/resolution.ts +41 -10
  365. package/src/time-series/resolve.ts +7 -0
  366. package/src/time-series/types.ts +3 -1
  367. package/src/time-series/use-chart-resolution.ts +5 -0
  368. package/src/types/config.ts +123 -3
  369. package/src/types/data-provider.ts +11 -0
  370. package/src/types/headless.ts +161 -0
  371. package/src/types/plugin.ts +102 -0
  372. package/src/ui/host.tsx +12 -1
  373. package/src/ui/index.tsx +1 -0
  374. package/src/ui/toast.tsx +8 -4
  375. package/src/utils/format.ts +35 -0
  376. package/src/utils/fuzzy-search.test.ts +94 -0
  377. package/src/utils/fuzzy-search.ts +81 -22
  378. package/src/utils/shortcut-labels.ts +14 -0
  379. package/src/components/chart/core/axis-format.ts +0 -157
  380. package/src/components/chart/core/index.test.ts +0 -1075
  381. package/src/components/chart/core/projection.ts +0 -357
  382. package/src/components/chart/core/render-utils.ts +0 -4
  383. package/src/components/chart/core/renderer.ts +0 -244
  384. package/src/components/chart/core/scene.ts +0 -180
  385. package/src/components/chart/core/time-axis.ts +0 -330
  386. package/src/components/chart/cursor-motion.ts +0 -47
  387. package/src/components/chart/indicators/types.ts +0 -26
  388. package/src/components/chart/market-session.ts +0 -176
  389. package/src/components/chart/multi-line/renderer.test.ts +0 -83
  390. package/src/components/chart/multi-line/renderer.ts +0 -161
  391. package/src/components/chart/multi-line/scene.ts +0 -188
  392. package/src/components/chart/native/raster/layout.ts +0 -129
  393. package/src/components/chart/native/raster/price-chart.ts +0 -244
  394. package/src/components/chart/rendering/chart-draw.ts +0 -270
  395. package/src/components/chart/rendering/geometry.ts +0 -95
  396. package/src/components/chart/rendering/pixel-buffer.ts +0 -267
  397. package/src/components/chart/scatter-chart-renderer.test.ts +0 -31
  398. package/src/components/chart/scatter-chart-renderer.ts +0 -223
  399. package/src/components/chart/static/chart/surface.tsx +0 -358
  400. package/src/components/command-bar/routes/root/article-results.test.ts +0 -83
  401. package/src/components/command-bar/routes/root/article-results.ts +0 -55
  402. package/src/plugins/builtin/news/wire/article-search.test.ts +0 -72
  403. package/src/plugins/builtin/news/wire/article-search.ts +0 -140
  404. package/src/plugins/builtin/substack/api/auth.ts +0 -185
  405. package/src/plugins/builtin/substack/api/cache.ts +0 -82
  406. package/src/plugins/builtin/substack/api/loaders.ts +0 -170
  407. package/src/plugins/builtin/substack/api/store.ts +0 -186
  408. package/src/plugins/builtin/substack/api/types.ts +0 -42
  409. package/src/plugins/builtin/substack/api.test.ts +0 -298
  410. package/src/plugins/builtin/substack/article-detail.tsx +0 -397
  411. package/src/plugins/builtin/substack/article-stack.tsx +0 -133
  412. package/src/plugins/builtin/substack/content.ts +0 -478
  413. package/src/plugins/builtin/substack/feed-tabs.tsx +0 -44
  414. package/src/plugins/builtin/substack/index.tsx +0 -49
  415. package/src/plugins/builtin/substack/login-view.tsx +0 -126
  416. package/src/plugins/builtin/substack/model.test.ts +0 -155
  417. package/src/plugins/builtin/substack/normalize.ts +0 -343
  418. package/src/plugins/builtin/substack/pane-footer.ts +0 -52
  419. package/src/plugins/builtin/substack/pane-state.ts +0 -170
  420. package/src/plugins/builtin/substack/pane.tsx +0 -547
  421. package/src/plugins/builtin/substack/read-state.ts +0 -30
  422. package/src/plugins/builtin/substack/table.ts +0 -111
  423. package/src/plugins/builtin/substack/types.ts +0 -71
  424. package/src/plugins/builtin/substack/utils.ts +0 -131
  425. package/src/plugins/builtin/ticker-detail/data-panes/provider-search.tsx +0 -229
  426. package/src/plugins/ibkr/account-cache.test.ts +0 -102
  427. package/src/plugins/ibkr/account-cache.ts +0 -24
  428. package/src/plugins/ibkr/broker-adapter.ts +0 -286
  429. package/src/plugins/ibkr/config.test.ts +0 -79
  430. package/src/plugins/ibkr/config.ts +0 -250
  431. package/src/plugins/ibkr/dialogs.tsx +0 -40
  432. package/src/plugins/ibkr/flex/index.test.ts +0 -264
  433. package/src/plugins/ibkr/flex/index.ts +0 -367
  434. package/src/plugins/ibkr/flex/statement-client.ts +0 -235
  435. package/src/plugins/ibkr/fundamental-parser.ts +0 -149
  436. package/src/plugins/ibkr/gateway/account-loaders.ts +0 -266
  437. package/src/plugins/ibkr/gateway/account-summary.ts +0 -164
  438. package/src/plugins/ibkr/gateway/client-lock.ts +0 -154
  439. package/src/plugins/ibkr/gateway/connection-events.ts +0 -114
  440. package/src/plugins/ibkr/gateway/connection.ts +0 -152
  441. package/src/plugins/ibkr/gateway/contracts.ts +0 -132
  442. package/src/plugins/ibkr/gateway/fundamentals.ts +0 -83
  443. package/src/plugins/ibkr/gateway/helpers.ts +0 -33
  444. package/src/plugins/ibkr/gateway/history-requests.ts +0 -158
  445. package/src/plugins/ibkr/gateway/history.ts +0 -120
  446. package/src/plugins/ibkr/gateway/instrument-lookup.ts +0 -117
  447. package/src/plugins/ibkr/gateway/market-data.ts +0 -345
  448. package/src/plugins/ibkr/gateway/order-execution.ts +0 -218
  449. package/src/plugins/ibkr/gateway/orders.ts +0 -63
  450. package/src/plugins/ibkr/gateway/price-normalization.test.ts +0 -44
  451. package/src/plugins/ibkr/gateway/price-normalization.ts +0 -50
  452. package/src/plugins/ibkr/gateway/quote-stream-controller.ts +0 -203
  453. package/src/plugins/ibkr/gateway/quote-stream.ts +0 -171
  454. package/src/plugins/ibkr/gateway/selection.ts +0 -51
  455. package/src/plugins/ibkr/gateway/service/index.test.ts +0 -675
  456. package/src/plugins/ibkr/gateway/service/index.ts +0 -429
  457. package/src/plugins/ibkr/gateway/service/lifecycle.ts +0 -191
  458. package/src/plugins/ibkr/gateway/service/manager.ts +0 -52
  459. package/src/plugins/ibkr/gateway/service/market-data.ts +0 -48
  460. package/src/plugins/ibkr/gateway/service/native-loader.ts +0 -12
  461. package/src/plugins/ibkr/gateway/service/native.ts +0 -543
  462. package/src/plugins/ibkr/gateway/timeouts.ts +0 -13
  463. package/src/plugins/ibkr/gateway/types.ts +0 -27
  464. package/src/plugins/ibkr/index.test.tsx +0 -162
  465. package/src/plugins/ibkr/index.tsx +0 -159
  466. package/src/plugins/ibkr/instance-selection.test.ts +0 -120
  467. package/src/plugins/ibkr/instance-selection.ts +0 -36
  468. package/src/plugins/ibkr/portfolio-performance.test.ts +0 -32
  469. package/src/plugins/ibkr/portfolio-performance.ts +0 -129
  470. package/src/plugins/ibkr/trade/badge.tsx +0 -28
  471. package/src/plugins/ibkr/trade/dialogs.tsx +0 -44
  472. package/src/plugins/ibkr/trade/preview-panel.tsx +0 -130
  473. package/src/plugins/ibkr/trade/tab/actions.tsx +0 -443
  474. package/src/plugins/ibkr/trade/tab/field-editors.tsx +0 -79
  475. package/src/plugins/ibkr/trade/tab/footer.ts +0 -53
  476. package/src/plugins/ibkr/trade/tab/header.tsx +0 -167
  477. package/src/plugins/ibkr/trade/tab/index.test.tsx +0 -178
  478. package/src/plugins/ibkr/trade/tab/index.tsx +0 -298
  479. package/src/plugins/ibkr/trade/tab/model.ts +0 -159
  480. package/src/plugins/ibkr/trade/tab/order-request.ts +0 -64
  481. package/src/plugins/ibkr/trade/tab/shortcuts.ts +0 -89
  482. package/src/plugins/ibkr/trade/tab/state-sync.ts +0 -86
  483. package/src/plugins/ibkr/trade/ticket-panel.tsx +0 -301
  484. package/src/plugins/ibkr/trade/utils.test.ts +0 -175
  485. package/src/plugins/ibkr/trade/utils.ts +0 -144
  486. package/src/plugins/ibkr/trading/pane-view.tsx +0 -237
  487. package/src/plugins/ibkr/trading/pane.tsx +0 -332
  488. package/src/plugins/ibkr/trading/state.test.ts +0 -109
  489. package/src/plugins/ibkr/trading/state.ts +0 -335
@@ -1,429 +0,0 @@
1
- import type { TimeRange } from "../../../../time-series/range";
2
- import type { ChartResolutionSupport, ManualChartResolution } from "../../../../time-series/resolution";
3
- import { getBrokerRemoteClient } from "../../../../brokers/remote-broker-adapter";
4
- import type { BrokerPosition } from "../../../../types/broker";
5
- import type { QuoteSubscriptionTarget } from "../../../../types/data-provider";
6
- import type { Quote, PricePoint, TickerFinancials } from "../../../../types/financials";
7
- import type { BrokerContractRef, InstrumentSearchResult } from "../../../../types/instrument";
8
- import type {
9
- BrokerAccount,
10
- BrokerExecution,
11
- BrokerOrder,
12
- BrokerOrderPreview,
13
- BrokerOrderRequest,
14
- } from "../../../../types/trading";
15
- import type {
16
- IbkrGatewayConfig,
17
- IbkrSnapshot,
18
- ResolvedIbkrGatewayConnection,
19
- } from "../types";
20
- import {
21
- loadNativeGatewayModule as loadDefaultNativeGatewayModule,
22
- type NativeGatewayModule,
23
- } from "./native-loader";
24
-
25
- export type {
26
- IbkrGatewayConfig,
27
- ResolvedIbkrGatewayConnection,
28
- } from "../types";
29
-
30
- type NativeGatewayManager = any;
31
- type NativeGatewayService = any;
32
- type Listener = () => void;
33
- type ResolvedGatewayListener = (
34
- instanceId: string | undefined,
35
- connection: ResolvedIbkrGatewayConnection,
36
- ) => void | Promise<void>;
37
-
38
- const DEFAULT_SNAPSHOT: IbkrSnapshot = {
39
- status: { state: "disconnected", updatedAt: Date.now() },
40
- accounts: [],
41
- openOrders: [],
42
- executions: [],
43
- };
44
-
45
- let resolvedGatewayListener: ResolvedGatewayListener | null = null;
46
- let loadedNativeGatewayModule: NativeGatewayModule | null = null;
47
- let nativeGatewayModulePromise: Promise<NativeGatewayModule> | null = null;
48
- let nativeGatewayManager: NativeGatewayManager | null = null;
49
- let nativeGatewayModuleLoader: () => Promise<NativeGatewayModule>;
50
-
51
- const snapshots = new Map<string, IbkrSnapshot>();
52
- const listeners = new Map<string, Set<Listener>>();
53
-
54
- function getSnapshotEntry(instanceId?: string): IbkrSnapshot {
55
- if (!instanceId) return DEFAULT_SNAPSHOT;
56
- return snapshots.get(instanceId) ?? DEFAULT_SNAPSHOT;
57
- }
58
-
59
- function defaultNativeGatewayModuleLoader(): Promise<NativeGatewayModule> {
60
- return loadDefaultNativeGatewayModule();
61
- }
62
-
63
- nativeGatewayModuleLoader = defaultNativeGatewayModuleLoader;
64
-
65
- export function setNativeIbkrGatewayModuleLoader(loader: (() => Promise<NativeGatewayModule>) | null): void {
66
- nativeGatewayModuleLoader = loader ?? defaultNativeGatewayModuleLoader;
67
- }
68
-
69
- function applySnapshot(instanceId: string, patch: Partial<IbkrSnapshot>, shouldNotify: boolean): IbkrSnapshot {
70
- const current = getSnapshotEntry(instanceId);
71
- const next = {
72
- ...current,
73
- ...patch,
74
- status: patch.status ?? current.status,
75
- accounts: patch.accounts ?? current.accounts,
76
- openOrders: patch.openOrders ?? current.openOrders,
77
- executions: patch.executions ?? current.executions,
78
- };
79
- if (
80
- next.status === current.status
81
- && next.accounts === current.accounts
82
- && next.openOrders === current.openOrders
83
- && next.executions === current.executions
84
- ) {
85
- return current;
86
- }
87
- snapshots.set(instanceId, next);
88
- if (shouldNotify) notify(instanceId);
89
- return next;
90
- }
91
-
92
- function updateSnapshot(instanceId: string, patch: Partial<IbkrSnapshot>): void {
93
- applySnapshot(instanceId, patch, true);
94
- }
95
-
96
- function cacheSnapshot(instanceId: string, patch: Partial<IbkrSnapshot>): IbkrSnapshot {
97
- return applySnapshot(instanceId, patch, false);
98
- }
99
-
100
- function notify(instanceId: string): void {
101
- for (const listener of listeners.get(instanceId) ?? []) {
102
- listener();
103
- }
104
- }
105
-
106
- async function loadNativeGatewayModule(): Promise<NativeGatewayModule> {
107
- if (!nativeGatewayModulePromise) {
108
- nativeGatewayModulePromise = nativeGatewayModuleLoader().catch((error) => {
109
- nativeGatewayModulePromise = null;
110
- throw error;
111
- });
112
- }
113
- const module = await nativeGatewayModulePromise;
114
- loadedNativeGatewayModule = module;
115
- nativeGatewayManager = module.ibkrGatewayManager;
116
- module.setResolvedIbkrGatewayListener(resolvedGatewayListener);
117
- return module;
118
- }
119
-
120
- async function getNativeService(instanceId: string): Promise<NativeGatewayService> {
121
- const module = await loadNativeGatewayModule();
122
- return module.ibkrGatewayManager.getService(instanceId);
123
- }
124
-
125
- export function setResolvedIbkrGatewayListener(listener: ResolvedGatewayListener | null): void {
126
- resolvedGatewayListener = listener;
127
- if (getBrokerRemoteClient()) return;
128
- if (loadedNativeGatewayModule) {
129
- loadedNativeGatewayModule.setResolvedIbkrGatewayListener(listener);
130
- return;
131
- }
132
- if (!nativeGatewayModulePromise) {
133
- return;
134
- }
135
- void nativeGatewayModulePromise.then((module) => {
136
- module.setResolvedIbkrGatewayListener(listener);
137
- }).catch(() => {});
138
- }
139
-
140
- class IbkrGatewayServiceFacade {
141
- constructor(private readonly instanceId: string) {}
142
-
143
- getSnapshot(): IbkrSnapshot {
144
- const remoteStatus = getBrokerRemoteClient()?.getStatus(this.instanceId);
145
- if (remoteStatus) {
146
- return cacheSnapshot(this.instanceId, { status: remoteStatus });
147
- }
148
- if (nativeGatewayManager) {
149
- return nativeGatewayManager.getService(this.instanceId).getSnapshot();
150
- }
151
- return getSnapshotEntry(this.instanceId);
152
- }
153
-
154
- getResolvedConnection(): ResolvedIbkrGatewayConnection | null {
155
- if (nativeGatewayManager) {
156
- return nativeGatewayManager.getService(this.instanceId).getResolvedConnection();
157
- }
158
- return null;
159
- }
160
-
161
- subscribe(listener: Listener): () => void {
162
- if (!listeners.has(this.instanceId)) listeners.set(this.instanceId, new Set());
163
- listeners.get(this.instanceId)!.add(listener);
164
-
165
- const remoteDispose = getBrokerRemoteClient()?.subscribeStatus(this.instanceId, () => {
166
- const status = getBrokerRemoteClient()?.getStatus(this.instanceId);
167
- if (status) {
168
- updateSnapshot(this.instanceId, { status });
169
- } else {
170
- listener();
171
- }
172
- });
173
-
174
- if (remoteDispose) {
175
- return () => {
176
- remoteDispose();
177
- listeners.get(this.instanceId)?.delete(listener);
178
- };
179
- }
180
-
181
- let nativeDispose: (() => void) | null = null;
182
- if (nativeGatewayManager) {
183
- const service = nativeGatewayManager.getService(this.instanceId);
184
- nativeDispose = service.subscribe(() => {
185
- updateSnapshot(this.instanceId, service.getSnapshot());
186
- });
187
- }
188
- listener();
189
-
190
- return () => {
191
- nativeDispose?.();
192
- listeners.get(this.instanceId)?.delete(listener);
193
- };
194
- }
195
-
196
- async connect(config: IbkrGatewayConfig): Promise<void> {
197
- const remote = getBrokerRemoteClient();
198
- if (remote) {
199
- await remote.invoke<void>(this.instanceId, "connect");
200
- return;
201
- }
202
- const service = await getNativeService(this.instanceId);
203
- await service.connect(config);
204
- updateSnapshot(this.instanceId, service.getSnapshot());
205
- }
206
-
207
- async disconnect(): Promise<void> {
208
- const remote = getBrokerRemoteClient();
209
- if (remote) return remote.invoke<void>(this.instanceId, "disconnect");
210
- const service = await getNativeService(this.instanceId);
211
- await service.disconnect();
212
- updateSnapshot(this.instanceId, service.getSnapshot());
213
- }
214
-
215
- async getAccounts(config: IbkrGatewayConfig): Promise<BrokerAccount[]> {
216
- const remote = getBrokerRemoteClient();
217
- const accounts = remote
218
- ? await remote.invoke<BrokerAccount[]>(this.instanceId, "listAccounts")
219
- : await (await getNativeService(this.instanceId)).getAccounts(config);
220
- updateSnapshot(this.instanceId, { accounts });
221
- return accounts;
222
- }
223
-
224
- async getPositions(config: IbkrGatewayConfig): Promise<BrokerPosition[]> {
225
- const remote = getBrokerRemoteClient();
226
- return remote
227
- ? remote.invoke(this.instanceId, "importPositions")
228
- : (await getNativeService(this.instanceId)).getPositions(config);
229
- }
230
-
231
- async listOpenOrders(config: IbkrGatewayConfig): Promise<BrokerOrder[]> {
232
- const remote = getBrokerRemoteClient();
233
- const openOrders = remote
234
- ? await remote.invoke<BrokerOrder[]>(this.instanceId, "listOpenOrders")
235
- : await (await getNativeService(this.instanceId)).listOpenOrders(config);
236
- updateSnapshot(this.instanceId, { openOrders });
237
- return openOrders;
238
- }
239
-
240
- async listExecutions(config: IbkrGatewayConfig): Promise<BrokerExecution[]> {
241
- const remote = getBrokerRemoteClient();
242
- const executions = remote
243
- ? await remote.invoke<BrokerExecution[]>(this.instanceId, "listExecutions")
244
- : await (await getNativeService(this.instanceId)).listExecutions(config);
245
- updateSnapshot(this.instanceId, { executions });
246
- return executions;
247
- }
248
-
249
- async searchInstruments(query: string, config: IbkrGatewayConfig): Promise<InstrumentSearchResult[]> {
250
- const remote = getBrokerRemoteClient();
251
- return remote
252
- ? remote.invoke(this.instanceId, "searchInstruments", [query])
253
- : (await getNativeService(this.instanceId)).searchInstruments(query, config);
254
- }
255
-
256
- async getTickerFinancials(
257
- ticker: string,
258
- config: IbkrGatewayConfig,
259
- exchange = "",
260
- instrument?: BrokerContractRef | null,
261
- ): Promise<TickerFinancials> {
262
- const remote = getBrokerRemoteClient();
263
- return remote
264
- ? remote.invoke(this.instanceId, "getTickerFinancials", [ticker, exchange, instrument])
265
- : (await getNativeService(this.instanceId)).getTickerFinancials(ticker, config, exchange, instrument);
266
- }
267
-
268
- async getQuote(
269
- ticker: string,
270
- config: IbkrGatewayConfig,
271
- exchange = "",
272
- instrument?: BrokerContractRef | null,
273
- ): Promise<Quote> {
274
- const remote = getBrokerRemoteClient();
275
- return remote
276
- ? remote.invoke(this.instanceId, "getQuote", [ticker, exchange, instrument])
277
- : (await getNativeService(this.instanceId)).getQuote(ticker, config, exchange, instrument);
278
- }
279
-
280
- async getPriceHistory(
281
- ticker: string,
282
- config: IbkrGatewayConfig,
283
- exchange: string,
284
- range: TimeRange,
285
- instrument?: BrokerContractRef | null,
286
- ): Promise<PricePoint[]> {
287
- const remote = getBrokerRemoteClient();
288
- return remote
289
- ? remote.invoke(this.instanceId, "getPriceHistory", [ticker, exchange, range, instrument])
290
- : (await getNativeService(this.instanceId)).getPriceHistory(ticker, config, exchange, range, instrument);
291
- }
292
-
293
- getChartResolutionSupport(
294
- ticker: string,
295
- config: IbkrGatewayConfig,
296
- exchange = "",
297
- instrument?: BrokerContractRef | null,
298
- ): Promise<ChartResolutionSupport[]> | ChartResolutionSupport[] {
299
- const remote = getBrokerRemoteClient();
300
- return remote
301
- ? remote.invoke(this.instanceId, "getChartResolutionSupport", [ticker, exchange, instrument])
302
- : getNativeService(this.instanceId).then((service) => service.getChartResolutionSupport(ticker, config, exchange, instrument));
303
- }
304
-
305
- async getPriceHistoryForResolution(
306
- ticker: string,
307
- config: IbkrGatewayConfig,
308
- exchange: string,
309
- bufferRange: TimeRange,
310
- resolution: ManualChartResolution,
311
- instrument?: BrokerContractRef | null,
312
- ): Promise<PricePoint[]> {
313
- const remote = getBrokerRemoteClient();
314
- return remote
315
- ? remote.invoke(this.instanceId, "getPriceHistoryForResolution", [ticker, exchange, bufferRange, resolution, instrument])
316
- : (await getNativeService(this.instanceId)).getPriceHistoryForResolution(ticker, config, exchange, bufferRange, resolution, instrument);
317
- }
318
-
319
- async getDetailedPriceHistory(
320
- ticker: string,
321
- config: IbkrGatewayConfig,
322
- exchange: string,
323
- startDate: Date,
324
- endDate: Date,
325
- barSize: string,
326
- instrument?: BrokerContractRef | null,
327
- ): Promise<PricePoint[]> {
328
- const remote = getBrokerRemoteClient();
329
- return remote
330
- ? remote.invoke(this.instanceId, "getDetailedPriceHistory", [ticker, exchange, startDate, endDate, barSize, instrument])
331
- : (await getNativeService(this.instanceId)).getDetailedPriceHistory(ticker, config, exchange, startDate, endDate, barSize, instrument);
332
- }
333
-
334
- subscribeQuotes(
335
- config: IbkrGatewayConfig,
336
- targets: QuoteSubscriptionTarget[],
337
- onQuote: (target: QuoteSubscriptionTarget, quote: Quote) => void,
338
- ): () => void {
339
- const remote = getBrokerRemoteClient();
340
- if (remote) return remote.subscribeQuotes(this.instanceId, targets, onQuote);
341
-
342
- let nativeDispose: (() => void) | null = null;
343
- let disposed = false;
344
- void getNativeService(this.instanceId).then((service) => {
345
- if (disposed) return;
346
- nativeDispose = service.subscribeQuotes(config, targets, onQuote);
347
- }).catch(() => {});
348
- return () => {
349
- disposed = true;
350
- nativeDispose?.();
351
- };
352
- }
353
-
354
- async previewOrder(config: IbkrGatewayConfig, request: BrokerOrderRequest): Promise<BrokerOrderPreview> {
355
- const remote = getBrokerRemoteClient();
356
- return remote
357
- ? remote.invoke(this.instanceId, "previewOrder", [request])
358
- : (await getNativeService(this.instanceId)).previewOrder(config, request);
359
- }
360
-
361
- async placeOrder(config: IbkrGatewayConfig, request: BrokerOrderRequest): Promise<BrokerOrder> {
362
- const remote = getBrokerRemoteClient();
363
- return remote
364
- ? remote.invoke(this.instanceId, "placeOrder", [request])
365
- : (await getNativeService(this.instanceId)).placeOrder(config, request);
366
- }
367
-
368
- async modifyOrder(config: IbkrGatewayConfig, orderId: number, request: BrokerOrderRequest): Promise<BrokerOrder> {
369
- const remote = getBrokerRemoteClient();
370
- return remote
371
- ? remote.invoke(this.instanceId, "modifyOrder", [orderId, request])
372
- : (await getNativeService(this.instanceId)).modifyOrder(config, orderId, request);
373
- }
374
-
375
- async cancelOrder(config: IbkrGatewayConfig, orderId: number): Promise<void> {
376
- const remote = getBrokerRemoteClient();
377
- return remote
378
- ? remote.invoke(this.instanceId, "cancelOrder", [orderId])
379
- : (await getNativeService(this.instanceId)).cancelOrder(config, orderId);
380
- }
381
- }
382
-
383
- class IbkrGatewayServiceManager {
384
- private services = new Map<string, IbkrGatewayServiceFacade>();
385
-
386
- getService(instanceId: string): IbkrGatewayServiceFacade {
387
- let service = this.services.get(instanceId);
388
- if (!service) {
389
- service = new IbkrGatewayServiceFacade(instanceId);
390
- this.services.set(instanceId, service);
391
- }
392
- return service;
393
- }
394
-
395
- getSnapshot(instanceId?: string): IbkrSnapshot {
396
- if (!instanceId) return DEFAULT_SNAPSHOT;
397
- return this.getService(instanceId).getSnapshot();
398
- }
399
-
400
- subscribe(instanceId: string | undefined, listener: Listener): () => void {
401
- if (!instanceId) return () => {};
402
- return this.getService(instanceId).subscribe(listener);
403
- }
404
-
405
- async removeInstance(instanceId: string): Promise<void> {
406
- const remote = getBrokerRemoteClient();
407
- if (remote) {
408
- await remote.removeInstance(instanceId);
409
- } else if (nativeGatewayManager) {
410
- await nativeGatewayManager.removeInstance(instanceId);
411
- }
412
- this.services.delete(instanceId);
413
- snapshots.delete(instanceId);
414
- notify(instanceId);
415
- }
416
-
417
- async destroyAll(): Promise<void> {
418
- const remote = getBrokerRemoteClient();
419
- if (remote) {
420
- await remote.destroyAll();
421
- } else if (nativeGatewayManager) {
422
- await nativeGatewayManager.destroyAll();
423
- }
424
- this.services.clear();
425
- snapshots.clear();
426
- }
427
- }
428
-
429
- export const ibkrGatewayManager = new IbkrGatewayServiceManager();
@@ -1,191 +0,0 @@
1
- import { ConnectionState, IBApiNext, type MarketDataType } from "@stoqey/ib";
2
- import { firstValueFrom, filter, take, timeout } from "rxjs";
3
- import { debugLog } from "../../../../utils/debug-log";
4
- import type { IbkrClientLockManager } from "../client-lock";
5
- import {
6
- buildConnectionNote,
7
- resolveGatewayConnection,
8
- } from "../connection";
9
- import {
10
- getIbErrorCode,
11
- getIbErrorMessage,
12
- isClientIdInUseError,
13
- marketDataTypeFromConfig,
14
- } from "../market-data";
15
- import type { IbkrGatewayConfig, IbkrSnapshot, ResolvedIbkrGatewayConnection } from "../types";
16
-
17
- const gatewayLifecycleLog = debugLog.createLogger("ibkr-gateway");
18
-
19
- export type ResolvedGatewayListener = (
20
- instanceId: string | undefined,
21
- connection: ResolvedIbkrGatewayConnection,
22
- ) => void | Promise<void>;
23
-
24
- export interface ConnectIbkrGatewayInternalContext {
25
- instanceId: string | undefined;
26
- bindConnectionEvents: (api: IBApiNext) => void;
27
- disconnect: () => Promise<void>;
28
- getApi: () => IBApiNext | null;
29
- getConfigKey: () => string | null;
30
- getRequestedClientId: () => number | undefined;
31
- getSnapshot: () => IbkrSnapshot;
32
- loadInitialSnapshot: () => Promise<void>;
33
- setActiveMarketDataType: (marketDataType: MarketDataType) => void;
34
- setApi: (api: IBApiNext | null) => void;
35
- setAutoMarketData: (auto: boolean) => void;
36
- setConfigKey: (configKey: string | null) => void;
37
- setConnectionNote: (connectionNote: string | undefined) => void;
38
- updateSnapshot: (snapshot: IbkrSnapshot) => void;
39
- }
40
-
41
- export async function connectIbkrGatewayInternal(
42
- context: ConnectIbkrGatewayInternalContext,
43
- config: IbkrGatewayConfig,
44
- configKey: string,
45
- connectionNote?: string,
46
- ): Promise<void> {
47
- if (context.getApi() && context.getConfigKey() !== configKey) {
48
- await context.disconnect();
49
- }
50
-
51
- context.setConnectionNote(connectionNote);
52
- context.updateSnapshot({
53
- ...context.getSnapshot(),
54
- status: {
55
- state: "connecting",
56
- updatedAt: Date.now(),
57
- mode: "gateway",
58
- message: connectionNote,
59
- },
60
- lastError: undefined,
61
- });
62
-
63
- let api = context.getApi();
64
- if (!api) {
65
- api = new IBApiNext({
66
- host: config.host,
67
- port: config.port,
68
- reconnectInterval: 2_000,
69
- });
70
- context.setApi(api);
71
- context.bindConnectionEvents(api);
72
- }
73
-
74
- let unsubscribeConflict = () => {};
75
- const conflictPromise = new Promise<never>((_, reject) => {
76
- const subscription = api!.error.subscribe((err) => {
77
- const code = getIbErrorCode(err);
78
- const message = getIbErrorMessage(err);
79
- if (!isClientIdInUseError(code, message)) return;
80
- subscription.unsubscribe();
81
- reject(new Error(message || `IBKR client ID ${config.clientId} is already in use.`));
82
- });
83
- unsubscribeConflict = () => subscription.unsubscribe();
84
- });
85
-
86
- api.connect(config.clientId);
87
- try {
88
- await Promise.race([
89
- firstValueFrom(api.connectionState.pipe(
90
- filter((state) => state === ConnectionState.Connected),
91
- take(1),
92
- timeout(10_000),
93
- )),
94
- conflictPromise,
95
- ]);
96
- } finally {
97
- unsubscribeConflict();
98
- }
99
-
100
- gatewayLifecycleLog.info("Connected to IBKR gateway", {
101
- instanceId: context.instanceId,
102
- requestedClientId: context.getRequestedClientId() ?? config.clientId,
103
- actualClientId: config.clientId,
104
- host: config.host,
105
- port: config.port,
106
- });
107
-
108
- context.setAutoMarketData((config.marketDataType ?? "auto") === "auto");
109
- const activeMarketDataType = marketDataTypeFromConfig(config);
110
- context.setActiveMarketDataType(activeMarketDataType);
111
- api.setMarketDataType(activeMarketDataType);
112
- context.setConfigKey(configKey);
113
- await context.loadInitialSnapshot();
114
- context.updateSnapshot({
115
- ...context.getSnapshot(),
116
- status: {
117
- state: "connected",
118
- updatedAt: Date.now(),
119
- mode: "gateway",
120
- message: connectionNote,
121
- },
122
- });
123
- }
124
-
125
- export async function connectWithClientFallback({
126
- config,
127
- configKey,
128
- clientLocks,
129
- snapshot,
130
- updateSnapshot,
131
- connectInternal,
132
- disconnect,
133
- onResolved,
134
- }: {
135
- config: IbkrGatewayConfig;
136
- configKey: string;
137
- clientLocks: IbkrClientLockManager;
138
- snapshot: IbkrSnapshot;
139
- updateSnapshot: (snapshot: IbkrSnapshot) => void;
140
- connectInternal: (config: IbkrGatewayConfig, configKey: string, connectionNote?: string) => Promise<void>;
141
- disconnect: () => Promise<void>;
142
- onResolved: (connection: ResolvedIbkrGatewayConnection) => void;
143
- }): Promise<void> {
144
- let resolvedConfig: ResolvedIbkrGatewayConnection;
145
- try {
146
- resolvedConfig = await resolveGatewayConnection(config);
147
- } catch (error: any) {
148
- const message = error?.message || String(error || "");
149
- updateSnapshot({
150
- ...snapshot,
151
- status: {
152
- state: "error",
153
- updatedAt: Date.now(),
154
- mode: "gateway",
155
- message,
156
- },
157
- lastError: message,
158
- });
159
- throw error;
160
- }
161
-
162
- const candidates = clientLocks.getClientIdCandidates(resolvedConfig.requestedClientId);
163
- let lastConflict: Error | null = null;
164
-
165
- for (const clientId of candidates) {
166
- const claimed = await clientLocks.tryClaim(resolvedConfig, clientId, resolvedConfig.requestedClientId);
167
- if (!claimed) continue;
168
-
169
- try {
170
- await connectInternal(
171
- { ...config, host: resolvedConfig.host, port: resolvedConfig.port, clientId },
172
- configKey,
173
- buildConnectionNote(resolvedConfig.requestedClientId, clientId, resolvedConfig.requestedPort, resolvedConfig.port),
174
- );
175
- onResolved({ ...resolvedConfig, clientId });
176
- return;
177
- } catch (error: any) {
178
- const code = getIbErrorCode(error);
179
- const message = getIbErrorMessage(error) || error?.message || String(error || "");
180
- await disconnect();
181
- if (!isClientIdInUseError(code, message)) {
182
- throw error;
183
- }
184
- lastConflict = new Error(message || `IBKR client ID ${clientId} is already in use.`);
185
- }
186
- }
187
-
188
- throw lastConflict ?? new Error(
189
- `No IBKR client IDs are available near ${resolvedConfig.requestedClientId}. Close other sessions or choose a different client ID.`,
190
- );
191
- }
@@ -1,52 +0,0 @@
1
- import type { IbkrSnapshot } from "../types";
2
-
3
- export interface IbkrGatewayServiceLike {
4
- getSnapshot(): IbkrSnapshot;
5
- subscribe(listener: () => void): () => void;
6
- disconnect(): Promise<void>;
7
- }
8
-
9
- export class IbkrGatewayServiceManager<T extends IbkrGatewayServiceLike = IbkrGatewayServiceLike> {
10
- private services = new Map<string, T>();
11
-
12
- constructor(
13
- private readonly createService?: (instanceId: string) => T,
14
- private readonly fallbackSnapshot?: IbkrSnapshot,
15
- ) {}
16
-
17
- getService(instanceId: string): T {
18
- let service = this.services.get(instanceId);
19
- if (!service) {
20
- if (!this.createService) throw new Error("IBKR gateway service factory is required.");
21
- service = this.createService(instanceId);
22
- this.services.set(instanceId, service);
23
- }
24
- return service;
25
- }
26
-
27
- getSnapshot(instanceId?: string): IbkrSnapshot {
28
- if (!instanceId) {
29
- if (!this.fallbackSnapshot) throw new Error("IBKR gateway snapshot fallback is required without an instance ID.");
30
- return this.fallbackSnapshot;
31
- }
32
- return this.getService(instanceId).getSnapshot();
33
- }
34
-
35
- subscribe(instanceId: string | undefined, listener: () => void): () => void {
36
- if (!instanceId) return () => {};
37
- return this.getService(instanceId).subscribe(listener);
38
- }
39
-
40
- async removeInstance(instanceId: string): Promise<void> {
41
- const service = this.services.get(instanceId);
42
- if (!service) return;
43
- await service.disconnect();
44
- this.services.delete(instanceId);
45
- }
46
-
47
- async destroyAll(): Promise<void> {
48
- const services = [...this.services.values()];
49
- this.services.clear();
50
- await Promise.allSettled(services.map((service) => service.disconnect()));
51
- }
52
- }