@363045841yyt/klinechart-core 0.8.11-alpha.0 → 0.8.12

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 (578) hide show
  1. package/dist/alerts/createAlertController.d.ts +30 -0
  2. package/dist/alerts/createAlertController.d.ts.map +1 -0
  3. package/dist/alerts/createAlertController.js +261 -0
  4. package/dist/alerts/createAlertController.js.map +1 -0
  5. package/dist/alerts/index.d.ts +5 -0
  6. package/dist/alerts/index.d.ts.map +1 -0
  7. package/dist/alerts/index.js +4 -0
  8. package/dist/alerts/index.js.map +1 -0
  9. package/dist/alerts/predicates.d.ts +28 -0
  10. package/dist/alerts/predicates.d.ts.map +1 -0
  11. package/dist/alerts/predicates.js +211 -0
  12. package/dist/alerts/predicates.js.map +1 -0
  13. package/dist/alerts/rollingVolume.d.ts +15 -0
  14. package/dist/alerts/rollingVolume.d.ts.map +1 -0
  15. package/dist/alerts/rollingVolume.js +42 -0
  16. package/dist/alerts/rollingVolume.js.map +1 -0
  17. package/dist/alerts/ruleSchema.d.ts +42 -0
  18. package/dist/alerts/ruleSchema.d.ts.map +1 -0
  19. package/dist/alerts/ruleSchema.js +240 -0
  20. package/dist/alerts/ruleSchema.js.map +1 -0
  21. package/dist/alerts/types.d.ts +169 -0
  22. package/dist/alerts/types.d.ts.map +1 -0
  23. package/dist/alerts/types.js +24 -0
  24. package/dist/alerts/types.js.map +1 -0
  25. package/dist/chartTypes/heikinAshi.d.ts +49 -0
  26. package/dist/chartTypes/heikinAshi.d.ts.map +1 -0
  27. package/dist/chartTypes/heikinAshi.js +94 -0
  28. package/dist/chartTypes/heikinAshi.js.map +1 -0
  29. package/dist/chartTypes/index.d.ts +6 -0
  30. package/dist/chartTypes/index.d.ts.map +1 -0
  31. package/dist/chartTypes/index.js +5 -0
  32. package/dist/chartTypes/index.js.map +1 -0
  33. package/dist/chartTypes/pointAndFigure.d.ts +83 -0
  34. package/dist/chartTypes/pointAndFigure.d.ts.map +1 -0
  35. package/dist/chartTypes/pointAndFigure.js +159 -0
  36. package/dist/chartTypes/pointAndFigure.js.map +1 -0
  37. package/dist/chartTypes/rangeBars.d.ts +61 -0
  38. package/dist/chartTypes/rangeBars.d.ts.map +1 -0
  39. package/dist/chartTypes/rangeBars.js +181 -0
  40. package/dist/chartTypes/rangeBars.js.map +1 -0
  41. package/dist/chartTypes/renko.d.ts +94 -0
  42. package/dist/chartTypes/renko.d.ts.map +1 -0
  43. package/dist/chartTypes/renko.js +207 -0
  44. package/dist/chartTypes/renko.js.map +1 -0
  45. package/dist/chartTypes/types.d.ts +97 -0
  46. package/dist/chartTypes/types.d.ts.map +1 -0
  47. package/dist/chartTypes/types.js +39 -0
  48. package/dist/chartTypes/types.js.map +1 -0
  49. package/dist/components/anchoredVwap/computeAnchoredVwap.d.ts +76 -0
  50. package/dist/components/anchoredVwap/computeAnchoredVwap.d.ts.map +1 -0
  51. package/dist/components/anchoredVwap/computeAnchoredVwap.js +155 -0
  52. package/dist/components/anchoredVwap/computeAnchoredVwap.js.map +1 -0
  53. package/dist/components/anchoredVwap/createAnchoredVwapController.d.ts +28 -0
  54. package/dist/components/anchoredVwap/createAnchoredVwapController.d.ts.map +1 -0
  55. package/dist/components/anchoredVwap/createAnchoredVwapController.js +282 -0
  56. package/dist/components/anchoredVwap/createAnchoredVwapController.js.map +1 -0
  57. package/dist/components/anchoredVwap/index.d.ts +11 -0
  58. package/dist/components/anchoredVwap/index.d.ts.map +1 -0
  59. package/dist/components/anchoredVwap/index.js +10 -0
  60. package/dist/components/anchoredVwap/index.js.map +1 -0
  61. package/dist/components/anchoredVwap/types.d.ts +171 -0
  62. package/dist/components/anchoredVwap/types.d.ts.map +1 -0
  63. package/dist/components/anchoredVwap/types.js +25 -0
  64. package/dist/components/anchoredVwap/types.js.map +1 -0
  65. package/dist/components/crosshairSync/createCrosshairSync.d.ts +94 -0
  66. package/dist/components/crosshairSync/createCrosshairSync.d.ts.map +1 -0
  67. package/dist/components/crosshairSync/createCrosshairSync.js +118 -0
  68. package/dist/components/crosshairSync/createCrosshairSync.js.map +1 -0
  69. package/dist/components/crosshairSync/index.d.ts +2 -0
  70. package/dist/components/crosshairSync/index.d.ts.map +1 -0
  71. package/dist/components/crosshairSync/index.js +2 -0
  72. package/dist/components/crosshairSync/index.js.map +1 -0
  73. package/dist/components/footprint/aggressor.d.ts +89 -0
  74. package/dist/components/footprint/aggressor.d.ts.map +1 -0
  75. package/dist/components/footprint/aggressor.js +106 -0
  76. package/dist/components/footprint/aggressor.js.map +1 -0
  77. package/dist/components/footprint/createFootprintController.d.ts +29 -0
  78. package/dist/components/footprint/createFootprintController.d.ts.map +1 -0
  79. package/dist/components/footprint/createFootprintController.js +264 -0
  80. package/dist/components/footprint/createFootprintController.js.map +1 -0
  81. package/dist/components/footprint/index.d.ts +7 -0
  82. package/dist/components/footprint/index.d.ts.map +1 -0
  83. package/dist/components/footprint/index.js +4 -0
  84. package/dist/components/footprint/index.js.map +1 -0
  85. package/dist/components/footprint/perBarStats.d.ts +63 -0
  86. package/dist/components/footprint/perBarStats.d.ts.map +1 -0
  87. package/dist/components/footprint/perBarStats.js +123 -0
  88. package/dist/components/footprint/perBarStats.js.map +1 -0
  89. package/dist/components/footprint/types.d.ts +197 -0
  90. package/dist/components/footprint/types.d.ts.map +1 -0
  91. package/dist/components/footprint/types.js +23 -0
  92. package/dist/components/footprint/types.js.map +1 -0
  93. package/dist/components/mtfOverlay/alignToBaseIndex.d.ts +45 -0
  94. package/dist/components/mtfOverlay/alignToBaseIndex.d.ts.map +1 -0
  95. package/dist/components/mtfOverlay/alignToBaseIndex.js +92 -0
  96. package/dist/components/mtfOverlay/alignToBaseIndex.js.map +1 -0
  97. package/dist/components/mtfOverlay/createMtfController.d.ts +7 -0
  98. package/dist/components/mtfOverlay/createMtfController.d.ts.map +1 -0
  99. package/dist/components/mtfOverlay/createMtfController.js +134 -0
  100. package/dist/components/mtfOverlay/createMtfController.js.map +1 -0
  101. package/dist/components/mtfOverlay/index.d.ts +19 -0
  102. package/dist/components/mtfOverlay/index.d.ts.map +1 -0
  103. package/dist/components/mtfOverlay/index.js +18 -0
  104. package/dist/components/mtfOverlay/index.js.map +1 -0
  105. package/dist/components/mtfOverlay/resampleBars.d.ts +37 -0
  106. package/dist/components/mtfOverlay/resampleBars.d.ts.map +1 -0
  107. package/dist/components/mtfOverlay/resampleBars.js +93 -0
  108. package/dist/components/mtfOverlay/resampleBars.js.map +1 -0
  109. package/dist/components/mtfOverlay/types.d.ts +132 -0
  110. package/dist/components/mtfOverlay/types.d.ts.map +1 -0
  111. package/dist/components/mtfOverlay/types.js +22 -0
  112. package/dist/components/mtfOverlay/types.js.map +1 -0
  113. package/dist/components/orderBookHeatmap/createHeatmapController.d.ts +21 -0
  114. package/dist/components/orderBookHeatmap/createHeatmapController.d.ts.map +1 -0
  115. package/dist/components/orderBookHeatmap/createHeatmapController.js +234 -0
  116. package/dist/components/orderBookHeatmap/createHeatmapController.js.map +1 -0
  117. package/dist/components/orderBookHeatmap/createOrderBookState.d.ts +18 -0
  118. package/dist/components/orderBookHeatmap/createOrderBookState.d.ts.map +1 -0
  119. package/dist/components/orderBookHeatmap/createOrderBookState.js +102 -0
  120. package/dist/components/orderBookHeatmap/createOrderBookState.js.map +1 -0
  121. package/dist/components/orderBookHeatmap/deltaArchive.d.ts +25 -0
  122. package/dist/components/orderBookHeatmap/deltaArchive.d.ts.map +1 -0
  123. package/dist/components/orderBookHeatmap/deltaArchive.js +106 -0
  124. package/dist/components/orderBookHeatmap/deltaArchive.js.map +1 -0
  125. package/dist/components/orderBookHeatmap/index.d.ts +13 -0
  126. package/dist/components/orderBookHeatmap/index.d.ts.map +1 -0
  127. package/dist/components/orderBookHeatmap/index.js +12 -0
  128. package/dist/components/orderBookHeatmap/index.js.map +1 -0
  129. package/dist/components/orderBookHeatmap/logColorScale.d.ts +20 -0
  130. package/dist/components/orderBookHeatmap/logColorScale.d.ts.map +1 -0
  131. package/dist/components/orderBookHeatmap/logColorScale.js +71 -0
  132. package/dist/components/orderBookHeatmap/logColorScale.js.map +1 -0
  133. package/dist/components/orderBookHeatmap/snapshotRing.d.ts +16 -0
  134. package/dist/components/orderBookHeatmap/snapshotRing.d.ts.map +1 -0
  135. package/dist/components/orderBookHeatmap/snapshotRing.js +61 -0
  136. package/dist/components/orderBookHeatmap/snapshotRing.js.map +1 -0
  137. package/dist/components/orderBookHeatmap/types.d.ts +128 -0
  138. package/dist/components/orderBookHeatmap/types.d.ts.map +1 -0
  139. package/dist/components/orderBookHeatmap/types.js +16 -0
  140. package/dist/components/orderBookHeatmap/types.js.map +1 -0
  141. package/dist/components/volumeProfile/binning.d.ts +54 -0
  142. package/dist/components/volumeProfile/binning.d.ts.map +1 -0
  143. package/dist/components/volumeProfile/binning.js +123 -0
  144. package/dist/components/volumeProfile/binning.js.map +1 -0
  145. package/dist/components/volumeProfile/createVolumeProfileController.d.ts +31 -0
  146. package/dist/components/volumeProfile/createVolumeProfileController.d.ts.map +1 -0
  147. package/dist/components/volumeProfile/createVolumeProfileController.js +179 -0
  148. package/dist/components/volumeProfile/createVolumeProfileController.js.map +1 -0
  149. package/dist/components/volumeProfile/index.d.ts +6 -0
  150. package/dist/components/volumeProfile/index.d.ts.map +1 -0
  151. package/dist/components/volumeProfile/index.js +5 -0
  152. package/dist/components/volumeProfile/index.js.map +1 -0
  153. package/dist/components/volumeProfile/poc.d.ts +35 -0
  154. package/dist/components/volumeProfile/poc.d.ts.map +1 -0
  155. package/dist/components/volumeProfile/poc.js +51 -0
  156. package/dist/components/volumeProfile/poc.js.map +1 -0
  157. package/dist/components/volumeProfile/types.d.ts +138 -0
  158. package/dist/components/volumeProfile/types.d.ts.map +1 -0
  159. package/dist/components/volumeProfile/types.js +19 -0
  160. package/dist/components/volumeProfile/types.js.map +1 -0
  161. package/dist/components/volumeProfile/valueArea.d.ts +58 -0
  162. package/dist/components/volumeProfile/valueArea.d.ts.map +1 -0
  163. package/dist/components/volumeProfile/valueArea.js +172 -0
  164. package/dist/components/volumeProfile/valueArea.js.map +1 -0
  165. package/dist/controllers/createChartController.d.ts.map +1 -1
  166. package/dist/controllers/createChartController.js +22 -11
  167. package/dist/controllers/createChartController.js.map +1 -1
  168. package/dist/controllers/types.d.ts +3 -1
  169. package/dist/controllers/types.d.ts.map +1 -1
  170. package/dist/data-fetchers/baostock.d.ts.map +1 -1
  171. package/dist/data-fetchers/baostock.js +2 -1
  172. package/dist/data-fetchers/baostock.js.map +1 -1
  173. package/dist/data-fetchers/dataBuffer.effects.d.ts.map +1 -1
  174. package/dist/data-fetchers/dataBuffer.effects.js +2 -1
  175. package/dist/data-fetchers/dataBuffer.effects.js.map +1 -1
  176. package/dist/data-fetchers/fetcherDefinitionRegistry.d.ts.map +1 -1
  177. package/dist/data-fetchers/fetcherDefinitionRegistry.js +2 -1
  178. package/dist/data-fetchers/fetcherDefinitionRegistry.js.map +1 -1
  179. package/dist/data-fetchers/gotdx.js +4 -3
  180. package/dist/data-fetchers/gotdx.js.map +1 -1
  181. package/dist/data-fetchers/router.d.ts.map +1 -1
  182. package/dist/data-fetchers/router.js +4 -3
  183. package/dist/data-fetchers/router.js.map +1 -1
  184. package/dist/data-fetchers/tradingview.js +3 -2
  185. package/dist/data-fetchers/tradingview.js.map +1 -1
  186. package/dist/engine/chart.d.ts +13 -0
  187. package/dist/engine/chart.d.ts.map +1 -1
  188. package/dist/engine/chart.js +109 -0
  189. package/dist/engine/chart.js.map +1 -1
  190. package/dist/engine/data/chartDataManager.d.ts +1 -0
  191. package/dist/engine/data/chartDataManager.d.ts.map +1 -1
  192. package/dist/engine/data/chartDataManager.js +27 -4
  193. package/dist/engine/data/chartDataManager.js.map +1 -1
  194. package/dist/engine/drawing/toolConfig.d.ts.map +1 -1
  195. package/dist/engine/drawing/toolConfig.js +2 -1
  196. package/dist/engine/drawing/toolConfig.js.map +1 -1
  197. package/dist/engine/indicators/chartIndicatorManager.d.ts.map +1 -1
  198. package/dist/engine/indicators/chartIndicatorManager.js +2 -1
  199. package/dist/engine/indicators/chartIndicatorManager.js.map +1 -1
  200. package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts.map +1 -1
  201. package/dist/engine/indicators/indicatorDefinitionRegistry.js +2 -1
  202. package/dist/engine/indicators/indicatorDefinitionRegistry.js.map +1 -1
  203. package/dist/engine/indicators/indicatorMetadata.d.ts.map +1 -1
  204. package/dist/engine/indicators/indicatorMetadata.js +2 -1
  205. package/dist/engine/indicators/indicatorMetadata.js.map +1 -1
  206. package/dist/engine/indicators/indicatorRegistry.d.ts.map +1 -1
  207. package/dist/engine/indicators/indicatorRegistry.js +6 -5
  208. package/dist/engine/indicators/indicatorRegistry.js.map +1 -1
  209. package/dist/engine/indicators/registerBuiltins.d.ts.map +1 -1
  210. package/dist/engine/indicators/registerBuiltins.js +2 -1
  211. package/dist/engine/indicators/registerBuiltins.js.map +1 -1
  212. package/dist/engine/indicators/scheduler.d.ts +6 -0
  213. package/dist/engine/indicators/scheduler.d.ts.map +1 -1
  214. package/dist/engine/indicators/scheduler.js +12 -0
  215. package/dist/engine/indicators/scheduler.js.map +1 -1
  216. package/dist/engine/indicators/soa.d.ts.map +1 -1
  217. package/dist/engine/indicators/soa.js +2 -1
  218. package/dist/engine/indicators/soa.js.map +1 -1
  219. package/dist/engine/indicators/stateComposer.d.ts.map +1 -1
  220. package/dist/engine/indicators/stateComposer.js +2 -1
  221. package/dist/engine/indicators/stateComposer.js.map +1 -1
  222. package/dist/engine/subPaneManager.d.ts.map +1 -1
  223. package/dist/engine/subPaneManager.js +2 -1
  224. package/dist/engine/subPaneManager.js.map +1 -1
  225. package/dist/engine/utils/chartZoomController.d.ts +2 -0
  226. package/dist/engine/utils/chartZoomController.d.ts.map +1 -1
  227. package/dist/engine/utils/chartZoomController.js +5 -1
  228. package/dist/engine/utils/chartZoomController.js.map +1 -1
  229. package/dist/errors-help.d.ts +72 -0
  230. package/dist/errors-help.d.ts.map +1 -0
  231. package/dist/errors-help.js +149 -0
  232. package/dist/errors-help.js.map +1 -0
  233. package/dist/errors.d.ts +64 -0
  234. package/dist/errors.d.ts.map +1 -0
  235. package/dist/errors.js +61 -0
  236. package/dist/errors.js.map +1 -0
  237. package/dist/index.d.ts +18 -0
  238. package/dist/index.d.ts.map +1 -1
  239. package/dist/index.js +22 -0
  240. package/dist/index.js.map +1 -1
  241. package/dist/indicators/alma.d.ts +27 -0
  242. package/dist/indicators/alma.d.ts.map +1 -0
  243. package/dist/indicators/alma.js +36 -0
  244. package/dist/indicators/alma.js.map +1 -0
  245. package/dist/indicators/awesomeOscillator.d.ts +19 -0
  246. package/dist/indicators/awesomeOscillator.d.ts.map +1 -0
  247. package/dist/indicators/awesomeOscillator.js +36 -0
  248. package/dist/indicators/awesomeOscillator.js.map +1 -0
  249. package/dist/indicators/dpo.d.ts +17 -0
  250. package/dist/indicators/dpo.d.ts.map +1 -0
  251. package/dist/indicators/dpo.js +24 -0
  252. package/dist/indicators/dpo.js.map +1 -0
  253. package/dist/indicators/fisherTransform.d.ts +26 -0
  254. package/dist/indicators/fisherTransform.d.ts.map +1 -0
  255. package/dist/indicators/fisherTransform.js +44 -0
  256. package/dist/indicators/fisherTransform.js.map +1 -0
  257. package/dist/indicators/frama.d.ts +25 -0
  258. package/dist/indicators/frama.d.ts.map +1 -0
  259. package/dist/indicators/frama.js +61 -0
  260. package/dist/indicators/frama.js.map +1 -0
  261. package/dist/indicators/index.d.ts +24 -0
  262. package/dist/indicators/index.d.ts.map +1 -0
  263. package/dist/indicators/index.js +26 -0
  264. package/dist/indicators/index.js.map +1 -0
  265. package/dist/indicators/lsma.d.ts +21 -0
  266. package/dist/indicators/lsma.d.ts.map +1 -0
  267. package/dist/indicators/lsma.js +37 -0
  268. package/dist/indicators/lsma.js.map +1 -0
  269. package/dist/indicators/schaffTrendCycle.d.ts +24 -0
  270. package/dist/indicators/schaffTrendCycle.d.ts.map +1 -0
  271. package/dist/indicators/schaffTrendCycle.js +70 -0
  272. package/dist/indicators/schaffTrendCycle.js.map +1 -0
  273. package/dist/indicators/stochRSI.d.ts +24 -0
  274. package/dist/indicators/stochRSI.d.ts.map +1 -0
  275. package/dist/indicators/stochRSI.js +86 -0
  276. package/dist/indicators/stochRSI.js.map +1 -0
  277. package/dist/indicators/t3.d.ts +31 -0
  278. package/dist/indicators/t3.d.ts.map +1 -0
  279. package/dist/indicators/t3.js +63 -0
  280. package/dist/indicators/t3.js.map +1 -0
  281. package/dist/indicators/ultimateOscillator.d.ts +26 -0
  282. package/dist/indicators/ultimateOscillator.d.ts.map +1 -0
  283. package/dist/indicators/ultimateOscillator.js +59 -0
  284. package/dist/indicators/ultimateOscillator.js.map +1 -0
  285. package/dist/indicators/vidya.d.ts +24 -0
  286. package/dist/indicators/vidya.d.ts.map +1 -0
  287. package/dist/indicators/vidya.js +54 -0
  288. package/dist/indicators/vidya.js.map +1 -0
  289. package/dist/indicators/zlema.d.ts +16 -0
  290. package/dist/indicators/zlema.d.ts.map +1 -0
  291. package/dist/indicators/zlema.js +26 -0
  292. package/dist/indicators/zlema.js.map +1 -0
  293. package/dist/input/gesture.d.ts +125 -0
  294. package/dist/input/gesture.d.ts.map +1 -0
  295. package/dist/input/gesture.js +249 -0
  296. package/dist/input/gesture.js.map +1 -0
  297. package/dist/input/index.d.ts +9 -0
  298. package/dist/input/index.d.ts.map +1 -0
  299. package/dist/input/index.js +9 -0
  300. package/dist/input/index.js.map +1 -0
  301. package/dist/input/keyboard.d.ts +140 -0
  302. package/dist/input/keyboard.d.ts.map +1 -0
  303. package/dist/input/keyboard.js +260 -0
  304. package/dist/input/keyboard.js.map +1 -0
  305. package/dist/mcp/chartBridge.d.ts +2 -2
  306. package/dist/mcp/chartBridge.d.ts.map +1 -1
  307. package/dist/mcp/chartBridge.js +27 -21
  308. package/dist/mcp/chartBridge.js.map +1 -1
  309. package/dist/plugin/PluginHost.d.ts +0 -3
  310. package/dist/plugin/PluginHost.d.ts.map +1 -1
  311. package/dist/plugin/PluginHost.js +7 -3
  312. package/dist/plugin/PluginHost.js.map +1 -1
  313. package/dist/plugin/PluginRegistry.d.ts +0 -3
  314. package/dist/plugin/PluginRegistry.d.ts.map +1 -1
  315. package/dist/plugin/PluginRegistry.js +5 -1
  316. package/dist/plugin/PluginRegistry.js.map +1 -1
  317. package/dist/render/Renderer.d.ts +116 -0
  318. package/dist/render/Renderer.d.ts.map +1 -0
  319. package/dist/render/Renderer.js +31 -0
  320. package/dist/render/Renderer.js.map +1 -0
  321. package/dist/render/SurfaceBackend.d.ts +83 -0
  322. package/dist/render/SurfaceBackend.d.ts.map +1 -0
  323. package/dist/render/SurfaceBackend.js +27 -0
  324. package/dist/render/SurfaceBackend.js.map +1 -0
  325. package/dist/render/index.d.ts +12 -0
  326. package/dist/render/index.d.ts.map +1 -0
  327. package/dist/render/index.js +11 -0
  328. package/dist/render/index.js.map +1 -0
  329. package/dist/renderer-tier/detectRendererTier.d.ts +57 -0
  330. package/dist/renderer-tier/detectRendererTier.d.ts.map +1 -0
  331. package/dist/renderer-tier/detectRendererTier.js +143 -0
  332. package/dist/renderer-tier/detectRendererTier.js.map +1 -0
  333. package/dist/renderer-tier/index.d.ts +12 -0
  334. package/dist/renderer-tier/index.d.ts.map +1 -0
  335. package/dist/renderer-tier/index.js +12 -0
  336. package/dist/renderer-tier/index.js.map +1 -0
  337. package/dist/renderer-tier/selectBackend.d.ts +106 -0
  338. package/dist/renderer-tier/selectBackend.d.ts.map +1 -0
  339. package/dist/renderer-tier/selectBackend.js +113 -0
  340. package/dist/renderer-tier/selectBackend.js.map +1 -0
  341. package/dist/renderer-tier/types.d.ts +50 -0
  342. package/dist/renderer-tier/types.d.ts.map +1 -0
  343. package/dist/renderer-tier/types.js +24 -0
  344. package/dist/renderer-tier/types.js.map +1 -0
  345. package/dist/replay/createReplayController.d.ts +3 -0
  346. package/dist/replay/createReplayController.d.ts.map +1 -0
  347. package/dist/replay/createReplayController.js +251 -0
  348. package/dist/replay/createReplayController.js.map +1 -0
  349. package/dist/replay/index.d.ts +5 -0
  350. package/dist/replay/index.d.ts.map +1 -0
  351. package/dist/replay/index.js +3 -0
  352. package/dist/replay/index.js.map +1 -0
  353. package/dist/replay/timeline.d.ts +50 -0
  354. package/dist/replay/timeline.d.ts.map +1 -0
  355. package/dist/replay/timeline.js +104 -0
  356. package/dist/replay/timeline.js.map +1 -0
  357. package/dist/replay/types.d.ts +94 -0
  358. package/dist/replay/types.d.ts.map +1 -0
  359. package/dist/replay/types.js +21 -0
  360. package/dist/replay/types.js.map +1 -0
  361. package/dist/scale/anchoredZoom.d.ts +64 -0
  362. package/dist/scale/anchoredZoom.d.ts.map +1 -0
  363. package/dist/scale/anchoredZoom.js +67 -0
  364. package/dist/scale/anchoredZoom.js.map +1 -0
  365. package/dist/scale/createPriceScale.d.ts +49 -0
  366. package/dist/scale/createPriceScale.d.ts.map +1 -0
  367. package/dist/scale/createPriceScale.js +175 -0
  368. package/dist/scale/createPriceScale.js.map +1 -0
  369. package/dist/scale/createTimeScale.d.ts +27 -0
  370. package/dist/scale/createTimeScale.d.ts.map +1 -0
  371. package/dist/scale/createTimeScale.js +139 -0
  372. package/dist/scale/createTimeScale.js.map +1 -0
  373. package/dist/scale/index.d.ts +6 -0
  374. package/dist/scale/index.d.ts.map +1 -0
  375. package/dist/scale/index.js +5 -0
  376. package/dist/scale/index.js.map +1 -0
  377. package/dist/scale/originShift.d.ts +69 -0
  378. package/dist/scale/originShift.d.ts.map +1 -0
  379. package/dist/scale/originShift.js +41 -0
  380. package/dist/scale/originShift.js.map +1 -0
  381. package/dist/scale/types.d.ts +90 -0
  382. package/dist/scale/types.d.ts.map +1 -0
  383. package/dist/scale/types.js +17 -0
  384. package/dist/scale/types.js.map +1 -0
  385. package/dist/scene/createScene.d.ts +22 -0
  386. package/dist/scene/createScene.d.ts.map +1 -0
  387. package/dist/scene/createScene.js +114 -0
  388. package/dist/scene/createScene.js.map +1 -0
  389. package/dist/scene/index.d.ts +13 -0
  390. package/dist/scene/index.d.ts.map +1 -0
  391. package/dist/scene/index.js +11 -0
  392. package/dist/scene/index.js.map +1 -0
  393. package/dist/scene/layerRegistry.d.ts +83 -0
  394. package/dist/scene/layerRegistry.d.ts.map +1 -0
  395. package/dist/scene/layerRegistry.js +43 -0
  396. package/dist/scene/layerRegistry.js.map +1 -0
  397. package/dist/scene/types.d.ts +128 -0
  398. package/dist/scene/types.d.ts.map +1 -0
  399. package/dist/scene/types.js +21 -0
  400. package/dist/scene/types.js.map +1 -0
  401. package/dist/scheduler/createFrameBudget.d.ts +91 -0
  402. package/dist/scheduler/createFrameBudget.d.ts.map +1 -0
  403. package/dist/scheduler/createFrameBudget.js +232 -0
  404. package/dist/scheduler/createFrameBudget.js.map +1 -0
  405. package/dist/scheduler/index.d.ts +2 -0
  406. package/dist/scheduler/index.d.ts.map +1 -0
  407. package/dist/scheduler/index.js +2 -0
  408. package/dist/scheduler/index.js.map +1 -0
  409. package/dist/tokens/themeToCssVars.d.ts.map +1 -1
  410. package/dist/tokens/themeToCssVars.js +2 -28
  411. package/dist/tokens/themeToCssVars.js.map +1 -1
  412. package/dist/version.d.ts +1 -1
  413. package/dist/version.d.ts.map +1 -1
  414. package/dist/version.js +1 -1
  415. package/dist/version.js.map +1 -1
  416. package/package.json +1 -1
  417. package/src/__bench__/indicators.bench.ts +215 -0
  418. package/src/__bench__/orderBookHeatmap.bench.ts +68 -0
  419. package/src/__bench__/scale.bench.ts +80 -0
  420. package/src/__bench__/signal.bench.ts +41 -0
  421. package/src/__bench__/volumeProfile.bench.ts +66 -0
  422. package/src/__tests__/errors-help.test.ts +184 -0
  423. package/src/__tests__/errors.test.ts +187 -0
  424. package/src/alerts/__tests__/controller.test.ts +231 -0
  425. package/src/alerts/__tests__/predicates.test.ts +374 -0
  426. package/src/alerts/__tests__/ruleSchema.test.ts +180 -0
  427. package/src/alerts/createAlertController.ts +312 -0
  428. package/src/alerts/index.ts +18 -0
  429. package/src/alerts/predicates.ts +231 -0
  430. package/src/alerts/rollingVolume.ts +51 -0
  431. package/src/alerts/ruleSchema.ts +278 -0
  432. package/src/alerts/types.ts +177 -0
  433. package/src/chartTypes/__tests__/heikinAshi.test.ts +122 -0
  434. package/src/chartTypes/__tests__/pointAndFigure.test.ts +167 -0
  435. package/src/chartTypes/__tests__/rangeBars.test.ts +146 -0
  436. package/src/chartTypes/__tests__/renko.test.ts +160 -0
  437. package/src/chartTypes/heikinAshi.ts +116 -0
  438. package/src/chartTypes/index.ts +5 -0
  439. package/src/chartTypes/pointAndFigure.ts +278 -0
  440. package/src/chartTypes/rangeBars.ts +303 -0
  441. package/src/chartTypes/renko.ts +311 -0
  442. package/src/chartTypes/types.ts +99 -0
  443. package/src/components/anchoredVwap/__tests__/computeAnchoredVwap.test.ts +331 -0
  444. package/src/components/anchoredVwap/__tests__/controller.test.ts +430 -0
  445. package/src/components/anchoredVwap/computeAnchoredVwap.ts +174 -0
  446. package/src/components/anchoredVwap/createAnchoredVwapController.ts +358 -0
  447. package/src/components/anchoredVwap/index.ts +17 -0
  448. package/src/components/anchoredVwap/types.ts +187 -0
  449. package/src/components/crosshairSync/__tests__/crosshairSync.test.ts +261 -0
  450. package/src/components/crosshairSync/createCrosshairSync.ts +187 -0
  451. package/src/components/crosshairSync/index.ts +5 -0
  452. package/src/components/footprint/__tests__/aggressor.test.ts +127 -0
  453. package/src/components/footprint/__tests__/controller.test.ts +130 -0
  454. package/src/components/footprint/__tests__/perBarStats.test.ts +114 -0
  455. package/src/components/footprint/aggressor.ts +165 -0
  456. package/src/components/footprint/createFootprintController.ts +338 -0
  457. package/src/components/footprint/index.ts +21 -0
  458. package/src/components/footprint/perBarStats.ts +137 -0
  459. package/src/components/footprint/types.ts +232 -0
  460. package/src/components/mtfOverlay/__tests__/alignToBaseIndex.test.ts +103 -0
  461. package/src/components/mtfOverlay/__tests__/controller.test.ts +172 -0
  462. package/src/components/mtfOverlay/__tests__/resampleBars.test.ts +106 -0
  463. package/src/components/mtfOverlay/alignToBaseIndex.ts +108 -0
  464. package/src/components/mtfOverlay/createMtfController.ts +180 -0
  465. package/src/components/mtfOverlay/index.ts +26 -0
  466. package/src/components/mtfOverlay/resampleBars.ts +134 -0
  467. package/src/components/mtfOverlay/types.ts +148 -0
  468. package/src/components/orderBookHeatmap/__tests__/controller.test.ts +237 -0
  469. package/src/components/orderBookHeatmap/__tests__/deltaArchive.test.ts +88 -0
  470. package/src/components/orderBookHeatmap/__tests__/logColorScale.test.ts +69 -0
  471. package/src/components/orderBookHeatmap/__tests__/orderBookState.test.ts +113 -0
  472. package/src/components/orderBookHeatmap/__tests__/snapshotRing.test.ts +53 -0
  473. package/src/components/orderBookHeatmap/computeShader.wgsl.md +130 -0
  474. package/src/components/orderBookHeatmap/createHeatmapController.ts +273 -0
  475. package/src/components/orderBookHeatmap/createOrderBookState.ts +116 -0
  476. package/src/components/orderBookHeatmap/deltaArchive.ts +113 -0
  477. package/src/components/orderBookHeatmap/index.ts +25 -0
  478. package/src/components/orderBookHeatmap/logColorScale.ts +77 -0
  479. package/src/components/orderBookHeatmap/snapshotRing.ts +65 -0
  480. package/src/components/orderBookHeatmap/types.ts +168 -0
  481. package/src/components/volumeProfile/__tests__/binning.test.ts +133 -0
  482. package/src/components/volumeProfile/__tests__/poc.test.ts +44 -0
  483. package/src/components/volumeProfile/__tests__/valueArea.test.ts +177 -0
  484. package/src/components/volumeProfile/binning.ts +133 -0
  485. package/src/components/volumeProfile/createVolumeProfileController.ts +213 -0
  486. package/src/components/volumeProfile/index.ts +12 -0
  487. package/src/components/volumeProfile/poc.ts +53 -0
  488. package/src/components/volumeProfile/types.ts +148 -0
  489. package/src/components/volumeProfile/valueArea.ts +187 -0
  490. package/src/controllers/createChartController.ts +23 -10
  491. package/src/controllers/types.ts +5 -1
  492. package/src/data-fetchers/baostock.ts +2 -1
  493. package/src/data-fetchers/dataBuffer.effects.ts +3 -1
  494. package/src/data-fetchers/fetcherDefinitionRegistry.ts +2 -1
  495. package/src/data-fetchers/gotdx.ts +4 -3
  496. package/src/data-fetchers/router.ts +6 -3
  497. package/src/data-fetchers/tradingview.ts +3 -2
  498. package/src/engine/chart.ts +126 -3
  499. package/src/engine/data/chartDataManager.ts +26 -4
  500. package/src/engine/drawing/toolConfig.ts +2 -1
  501. package/src/engine/indicators/chartIndicatorManager.ts +2 -1
  502. package/src/engine/indicators/indicatorDefinitionRegistry.ts +2 -1
  503. package/src/engine/indicators/indicatorMetadata.ts +2 -1
  504. package/src/engine/indicators/indicatorRegistry.ts +6 -5
  505. package/src/engine/indicators/registerBuiltins.ts +2 -1
  506. package/src/engine/indicators/scheduler.ts +15 -0
  507. package/src/engine/indicators/soa.ts +2 -1
  508. package/src/engine/indicators/stateComposer.ts +2 -1
  509. package/src/engine/subPaneManager.ts +2 -1
  510. package/src/engine/utils/chartZoomController.ts +7 -1
  511. package/src/errors-help.ts +218 -0
  512. package/src/errors.ts +128 -0
  513. package/src/index.ts +37 -0
  514. package/src/indicators/__tests__/maFamily.test.ts +159 -0
  515. package/src/indicators/__tests__/oscillators.test.ts +150 -0
  516. package/src/indicators/alma.ts +61 -0
  517. package/src/indicators/awesomeOscillator.ts +54 -0
  518. package/src/indicators/dpo.ts +37 -0
  519. package/src/indicators/fisherTransform.ts +63 -0
  520. package/src/indicators/frama.ts +87 -0
  521. package/src/indicators/index.ts +39 -0
  522. package/src/indicators/lsma.ts +58 -0
  523. package/src/indicators/schaffTrendCycle.ts +92 -0
  524. package/src/indicators/stochRSI.ts +108 -0
  525. package/src/indicators/t3.ts +96 -0
  526. package/src/indicators/ultimateOscillator.ts +83 -0
  527. package/src/indicators/vidya.ts +80 -0
  528. package/src/indicators/zlema.ts +41 -0
  529. package/src/input/__tests__/gesture.test.ts +271 -0
  530. package/src/input/__tests__/keyboard.test.ts +317 -0
  531. package/src/input/gesture.ts +357 -0
  532. package/src/input/index.ts +26 -0
  533. package/src/input/keyboard.ts +373 -0
  534. package/src/mcp/chartBridge.ts +98 -72
  535. package/src/plugin/PluginHost.ts +4 -3
  536. package/src/plugin/PluginRegistry.ts +2 -1
  537. package/src/render/Renderer.ts +127 -0
  538. package/src/render/SurfaceBackend.ts +94 -0
  539. package/src/render/__tests__/contract.test.ts +176 -0
  540. package/src/render/index.ts +27 -0
  541. package/src/renderer-tier/__tests__/detectRendererTier.test.ts +180 -0
  542. package/src/renderer-tier/__tests__/selectBackend.test.ts +253 -0
  543. package/src/renderer-tier/detectRendererTier.ts +168 -0
  544. package/src/renderer-tier/index.ts +30 -0
  545. package/src/renderer-tier/selectBackend.ts +201 -0
  546. package/src/renderer-tier/types.ts +59 -0
  547. package/src/replay/__tests__/controller.test.ts +309 -0
  548. package/src/replay/__tests__/timeline.test.ts +99 -0
  549. package/src/replay/createReplayController.ts +302 -0
  550. package/src/replay/index.ts +15 -0
  551. package/src/replay/timeline.ts +106 -0
  552. package/src/replay/types.ts +107 -0
  553. package/src/scale/__tests__/anchoredZoom.test.ts +125 -0
  554. package/src/scale/__tests__/originShift.test.ts +97 -0
  555. package/src/scale/__tests__/priceScale.test.ts +219 -0
  556. package/src/scale/__tests__/timeScale.test.ts +119 -0
  557. package/src/scale/anchoredZoom.ts +104 -0
  558. package/src/scale/createPriceScale.ts +226 -0
  559. package/src/scale/createTimeScale.ts +150 -0
  560. package/src/scale/index.ts +9 -0
  561. package/src/scale/originShift.ts +111 -0
  562. package/src/scale/types.ts +100 -0
  563. package/src/scene/__tests__/layerRegistry.test.ts +207 -0
  564. package/src/scene/__tests__/scene.test.ts +411 -0
  565. package/src/scene/createScene.ts +117 -0
  566. package/src/scene/index.ts +29 -0
  567. package/src/scene/layerRegistry.ts +117 -0
  568. package/src/scene/types.ts +143 -0
  569. package/src/scheduler/__tests__/createFrameBudget.test.ts +315 -0
  570. package/src/scheduler/createFrameBudget.ts +316 -0
  571. package/src/scheduler/index.ts +7 -0
  572. package/src/tokens/themeToCssVars.ts +3 -1
  573. package/src/version.ts +1 -1
  574. package/dist/data-fetchers/gotdx/gotdx.d.ts +0 -7
  575. package/dist/data-fetchers/gotdx/gotdx.d.ts.map +0 -1
  576. package/dist/data-fetchers/gotdx/gotdx.js +0 -7
  577. package/dist/data-fetchers/gotdx/gotdx.js.map +0 -1
  578. package/src/data-fetchers/gotdx/gotdx.ts +0 -6
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Tests for `selectBackend` / `selectBackendOrThrow`.
3
+ *
4
+ * Coverage:
5
+ * 1. Direct match — detected tier has a registered factory.
6
+ * 2. Downgrade — detected tier is webgpu but only webgl2 registered.
7
+ * 3. Floor — `minimum: 'webgl2'` rejects canvas2d even if registered.
8
+ * 4. Detection injection — `opts.detection` skips the sniffer.
9
+ * 5. Probe injection — `opts.detect.probes` flows through.
10
+ * 6. Empty registry → `tier: 'none'` with informative reason.
11
+ * 7. fallbackChain enumerates tried tiers high → low.
12
+ * 8. `factory` is the same function reference passed in.
13
+ * 9. `reason` strings differ between direct match and downgrade.
14
+ * 10. Invalid minimum → `KLineChartError('INVALID_PARAM')`.
15
+ * 11. `selectBackendOrThrow` throws `INVALID_STATE` on no match.
16
+ * 12. `detection.tier` is preserved even when downgrade occurs.
17
+ */
18
+
19
+ import { describe, it, expect } from 'vitest'
20
+
21
+ import {
22
+ selectBackend,
23
+ selectBackendOrThrow,
24
+ type BackendRegistry,
25
+ } from '..'
26
+ import type { RendererTierResult } from '../types'
27
+ import { isKLineChartError } from '../../errors'
28
+
29
+ const ALWAYS = (): boolean => true
30
+ const NEVER = (): boolean => false
31
+
32
+ function fakeFactory<T>(tag: T): () => T {
33
+ return () => tag
34
+ }
35
+
36
+ // Helper: build a detection result without running the sniffer.
37
+ function fakeDetection(tier: RendererTierResult['tier']): RendererTierResult {
38
+ return {
39
+ tier,
40
+ reason: `synthetic detection: ${tier}`,
41
+ tried: [tier],
42
+ }
43
+ }
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Direct match
47
+ // ---------------------------------------------------------------------------
48
+
49
+ describe('selectBackend — direct match', () => {
50
+ it('detected webgpu + webgpu factory registered → webgpu factory', () => {
51
+ const sel = selectBackend({
52
+ detection: fakeDetection('webgpu'),
53
+ registry: {
54
+ webgpu: fakeFactory('GPU'),
55
+ webgl2: fakeFactory('GL2'),
56
+ canvas2d: fakeFactory('C2D'),
57
+ },
58
+ })
59
+ expect(sel.tier).toBe('webgpu')
60
+ expect(sel.factory!()).toBe('GPU')
61
+ expect(sel.fallbackChain).toEqual(['webgpu'])
62
+ expect(sel.reason).toContain('direct match')
63
+ })
64
+
65
+ it('detected canvas2d + canvas2d factory registered → canvas2d factory', () => {
66
+ const sel = selectBackend({
67
+ detection: fakeDetection('canvas2d'),
68
+ registry: { canvas2d: fakeFactory('C2D') },
69
+ })
70
+ expect(sel.tier).toBe('canvas2d')
71
+ expect(sel.factory!()).toBe('C2D')
72
+ expect(sel.fallbackChain).toEqual(['canvas2d'])
73
+ })
74
+ })
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Downgrade
78
+ // ---------------------------------------------------------------------------
79
+
80
+ describe('selectBackend — downgrade', () => {
81
+ it('detected webgpu, only webgl2 registered → webgl2 factory', () => {
82
+ const sel = selectBackend({
83
+ detection: fakeDetection('webgpu'),
84
+ registry: { webgl2: fakeFactory('GL2') },
85
+ })
86
+ expect(sel.tier).toBe('webgl2')
87
+ expect(sel.factory!()).toBe('GL2')
88
+ expect(sel.fallbackChain).toEqual(['webgpu', 'webgl2'])
89
+ expect(sel.reason).toContain('downgrade')
90
+ expect(sel.reason).toContain('webgpu')
91
+ })
92
+
93
+ it('detected webgl2, only canvas2d registered → canvas2d factory', () => {
94
+ const sel = selectBackend({
95
+ detection: fakeDetection('webgl2'),
96
+ registry: { canvas2d: fakeFactory('C2D') },
97
+ })
98
+ expect(sel.tier).toBe('canvas2d')
99
+ expect(sel.fallbackChain).toEqual(['webgl2', 'canvas2d'])
100
+ })
101
+
102
+ it('null factory entries are skipped (treated as not registered)', () => {
103
+ const sel = selectBackend({
104
+ detection: fakeDetection('webgpu'),
105
+ registry: { webgpu: null, webgl2: fakeFactory('GL2') },
106
+ })
107
+ expect(sel.tier).toBe('webgl2')
108
+ })
109
+
110
+ it('detection.tier is preserved in the result even after downgrade', () => {
111
+ const sel = selectBackend({
112
+ detection: fakeDetection('webgpu'),
113
+ registry: { canvas2d: fakeFactory('C2D') },
114
+ })
115
+ expect(sel.tier).toBe('canvas2d')
116
+ expect(sel.detection.tier).toBe('webgpu')
117
+ })
118
+ })
119
+
120
+ // ---------------------------------------------------------------------------
121
+ // Floor
122
+ // ---------------------------------------------------------------------------
123
+
124
+ describe('selectBackend — minimum floor', () => {
125
+ it('minimum=webgl2 rejects canvas2d even if registered', () => {
126
+ const sel = selectBackend({
127
+ detection: fakeDetection('canvas2d'),
128
+ registry: { canvas2d: fakeFactory('C2D') },
129
+ minimum: 'webgl2',
130
+ })
131
+ expect(sel.tier).toBe('none')
132
+ expect(sel.factory).toBeNull()
133
+ expect(sel.reason).toContain('minimum=webgl2')
134
+ })
135
+
136
+ it('minimum=webgl2 accepts a higher tier', () => {
137
+ const sel = selectBackend({
138
+ detection: fakeDetection('webgl2'),
139
+ registry: { webgl2: fakeFactory('GL2') },
140
+ minimum: 'webgl2',
141
+ })
142
+ expect(sel.tier).toBe('webgl2')
143
+ })
144
+
145
+ it('minimum=canvas2d does not affect behaviour (effective default)', () => {
146
+ const sel = selectBackend({
147
+ detection: fakeDetection('canvas2d'),
148
+ registry: { canvas2d: fakeFactory('C2D') },
149
+ minimum: 'canvas2d',
150
+ })
151
+ expect(sel.tier).toBe('canvas2d')
152
+ })
153
+ })
154
+
155
+ // ---------------------------------------------------------------------------
156
+ // Empty / no-match registries
157
+ // ---------------------------------------------------------------------------
158
+
159
+ describe('selectBackend — no match', () => {
160
+ it('empty registry → tier:none + null factory', () => {
161
+ const sel = selectBackend({
162
+ detection: fakeDetection('webgpu'),
163
+ registry: {} as BackendRegistry,
164
+ })
165
+ expect(sel.tier).toBe('none')
166
+ expect(sel.factory).toBeNull()
167
+ expect(sel.reason).toContain('no registered backend')
168
+ })
169
+
170
+ it('detected none + no factories → tier:none with host reason', () => {
171
+ const sel = selectBackend({
172
+ detection: fakeDetection('none'),
173
+ registry: {} as BackendRegistry,
174
+ })
175
+ expect(sel.tier).toBe('none')
176
+ expect(sel.reason).toContain('no renderable tier')
177
+ })
178
+ })
179
+
180
+ // ---------------------------------------------------------------------------
181
+ // Detection / probe pass-through
182
+ // ---------------------------------------------------------------------------
183
+
184
+ describe('selectBackend — probe pass-through', () => {
185
+ it('detect.probes flows to detectRendererTier', () => {
186
+ const sel = selectBackend({
187
+ registry: { canvas2d: fakeFactory('C2D') },
188
+ detect: {
189
+ probes: { webgpu: NEVER, webgl2: NEVER, canvas2d: ALWAYS },
190
+ },
191
+ })
192
+ expect(sel.detection.tier).toBe('canvas2d')
193
+ expect(sel.tier).toBe('canvas2d')
194
+ })
195
+
196
+ it('explicit detection overrides probe detection', () => {
197
+ const sel = selectBackend({
198
+ registry: { canvas2d: fakeFactory('C2D') },
199
+ detection: fakeDetection('webgpu'),
200
+ // detect.probes here would say 'canvas2d' if consulted —
201
+ // but they shouldn't be, since explicit detection wins.
202
+ detect: { probes: { webgpu: NEVER, webgl2: NEVER, canvas2d: ALWAYS } },
203
+ })
204
+ expect(sel.detection.tier).toBe('webgpu')
205
+ })
206
+ })
207
+
208
+ // ---------------------------------------------------------------------------
209
+ // Validation
210
+ // ---------------------------------------------------------------------------
211
+
212
+ describe('selectBackend — input validation', () => {
213
+ it('throws KLineChartError(INVALID_PARAM) on unknown minimum', () => {
214
+ try {
215
+ selectBackend({
216
+ detection: fakeDetection('webgpu'),
217
+ registry: { webgpu: fakeFactory('X') },
218
+ minimum: 'doesNotExist' as never,
219
+ })
220
+ expect.fail('expected throw')
221
+ } catch (e) {
222
+ expect(isKLineChartError(e, 'INVALID_PARAM')).toBe(true)
223
+ }
224
+ })
225
+ })
226
+
227
+ // ---------------------------------------------------------------------------
228
+ // Strict variant
229
+ // ---------------------------------------------------------------------------
230
+
231
+ describe('selectBackendOrThrow', () => {
232
+ it('returns the selection unchanged when a factory was found', () => {
233
+ const sel = selectBackendOrThrow({
234
+ detection: fakeDetection('webgpu'),
235
+ registry: { webgpu: fakeFactory('GPU') },
236
+ })
237
+ expect(sel.tier).toBe('webgpu')
238
+ // Type-narrowed: factory is non-null at compile time.
239
+ expect(sel.factory()).toBe('GPU')
240
+ })
241
+
242
+ it('throws KLineChartError(INVALID_STATE) on no match', () => {
243
+ try {
244
+ selectBackendOrThrow({
245
+ detection: fakeDetection('none'),
246
+ registry: {} as BackendRegistry,
247
+ })
248
+ expect.fail('expected throw')
249
+ } catch (e) {
250
+ expect(isKLineChartError(e, 'INVALID_STATE')).toBe(true)
251
+ }
252
+ })
253
+ })
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Synchronous renderer tier detection.
3
+ *
4
+ * Probes (in descending capability order):
5
+ *
6
+ * 1. **webgpu** `'gpu' in navigator`. We deliberately do NOT call
7
+ * `navigator.gpu.requestAdapter()` here — that's async
8
+ * and the answer can change between probe and use
9
+ * (e.g. user toggles the WebGPU flag). The renderer
10
+ * should retry adapter acquisition at startup; this
11
+ * sync check is a pre-mount fast path.
12
+ *
13
+ * 2. **webgl2** `canvas.getContext('webgl2') !== null`. Probes a
14
+ * throwaway `<canvas>`; if the browser hard-disabled
15
+ * WebGL (some hardened policies do), this returns
16
+ * null and we fall through.
17
+ *
18
+ * 3. **canvas2d** `canvas.getContext('2d') !== null`. Universal
19
+ * fallback for browsers from the 2010s onwards.
20
+ *
21
+ * 4. **none** None of the above worked — likely SSR (no document)
22
+ * or a sandboxed environment. The caller can decide
23
+ * whether that's an error or a "render nothing" state.
24
+ *
25
+ * All exceptions from a probe are caught and folded into the `reason`
26
+ * field — a probe that throws is treated identically to one that
27
+ * returns false (no tier-skip cascade).
28
+ */
29
+
30
+ import { KLineChartError } from '../errors'
31
+ import {
32
+ RENDERER_TIER_RANK,
33
+ type DetectRendererTierOptions,
34
+ type RendererTier,
35
+ type RendererTierResult,
36
+ } from './types'
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // Production probes — only run when no override is supplied
40
+ // ---------------------------------------------------------------------------
41
+
42
+ function probeWebGpu(): boolean {
43
+ const nav = (globalThis as { navigator?: unknown }).navigator
44
+ if (typeof nav !== 'object' || nav === null) return false
45
+ return 'gpu' in (nav as object)
46
+ }
47
+
48
+ function probeWebGl2(): boolean {
49
+ const doc = (globalThis as { document?: { createElement?: (s: string) => unknown } }).document
50
+ if (typeof doc?.createElement !== 'function') return false
51
+ const canvas = doc.createElement('canvas') as {
52
+ getContext?: (id: string) => unknown
53
+ }
54
+ if (typeof canvas.getContext !== 'function') return false
55
+ return canvas.getContext('webgl2') !== null
56
+ }
57
+
58
+ function probeCanvas2d(): boolean {
59
+ const doc = (globalThis as { document?: { createElement?: (s: string) => unknown } }).document
60
+ if (typeof doc?.createElement !== 'function') return false
61
+ const canvas = doc.createElement('canvas') as {
62
+ getContext?: (id: string) => unknown
63
+ }
64
+ if (typeof canvas.getContext !== 'function') return false
65
+ return canvas.getContext('2d') !== null
66
+ }
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // runProbe — adapter that turns probe → "ok, false, or error string"
70
+ // ---------------------------------------------------------------------------
71
+
72
+ function runProbe(probe: () => boolean): { ok: boolean; error: string | null } {
73
+ try {
74
+ return { ok: probe() === true, error: null }
75
+ } catch (e) {
76
+ const msg = e instanceof Error ? e.message : String(e)
77
+ return { ok: false, error: msg }
78
+ }
79
+ }
80
+
81
+ // ---------------------------------------------------------------------------
82
+ // Public API
83
+ // ---------------------------------------------------------------------------
84
+
85
+ const TIER_ORDER: ReadonlyArray<RendererTier> = ['webgpu', 'webgl2', 'canvas2d']
86
+
87
+ /**
88
+ * Detect the best renderer tier available in the current environment.
89
+ *
90
+ * Returns synchronously. Use this at the call site of `createChart` to
91
+ * pick the renderer backend; persist the result if you re-mount, since
92
+ * recomputing is cheap but not free (probing creates a throwaway canvas).
93
+ */
94
+ export function detectRendererTier(
95
+ opts?: DetectRendererTierOptions,
96
+ ): RendererTierResult {
97
+ const probes = opts?.probes ?? {}
98
+ const reasonParts: string[] = []
99
+ const tried: RendererTier[] = []
100
+
101
+ for (const tier of TIER_ORDER) {
102
+ tried.push(tier)
103
+ const probe =
104
+ tier === 'webgpu'
105
+ ? (probes.webgpu ?? probeWebGpu)
106
+ : tier === 'webgl2'
107
+ ? (probes.webgl2 ?? probeWebGl2)
108
+ : (probes.canvas2d ?? probeCanvas2d)
109
+ const r = runProbe(probe)
110
+ if (r.ok) {
111
+ return {
112
+ tier,
113
+ reason: `selected ${tier} (${reasonParts.length === 0 ? 'first probe succeeded' : reasonParts.join('; ')})`,
114
+ tried: [...tried],
115
+ }
116
+ }
117
+ reasonParts.push(
118
+ r.error === null ? `${tier}: not available` : `${tier}: threw "${r.error}"`,
119
+ )
120
+ }
121
+
122
+ return {
123
+ tier: 'none',
124
+ reason: `no tier available — ${reasonParts.join('; ')}`,
125
+ tried: [...tried],
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Strict variant: throws `KLineChartError('INVALID_STATE')` when no
131
+ * renderable tier is found. Use when you want a hard failure rather
132
+ * than a silent `'none'`.
133
+ */
134
+ export function detectRendererTierOrThrow(
135
+ opts?: DetectRendererTierOptions,
136
+ ): RendererTierResult {
137
+ const r = detectRendererTier(opts)
138
+ if (r.tier === 'none') {
139
+ throw new KLineChartError(
140
+ 'INVALID_STATE',
141
+ `detectRendererTierOrThrow: ${r.reason}`,
142
+ )
143
+ }
144
+ return r
145
+ }
146
+
147
+ /**
148
+ * Three-way compare on the tier rank. `a > b → 1`, `a < b → -1`, equal → 0.
149
+ *
150
+ * compareRendererTier('webgpu', 'webgl2') === 1
151
+ * compareRendererTier('canvas2d', 'webgl2') === -1
152
+ * compareRendererTier('webgl2', 'webgl2') === 0
153
+ */
154
+ export function compareRendererTier(a: RendererTier, b: RendererTier): -1 | 0 | 1 {
155
+ const ra = RENDERER_TIER_RANK[a]
156
+ const rb = RENDERER_TIER_RANK[b]
157
+ if (ra > rb) return 1
158
+ if (ra < rb) return -1
159
+ return 0
160
+ }
161
+
162
+ /**
163
+ * `tier >= minimum` guard for renderer features that require a floor
164
+ * (e.g. GPU compute volume profile needs `>= 'webgl2'`).
165
+ */
166
+ export function isTierAtLeast(tier: RendererTier, minimum: RendererTier): boolean {
167
+ return compareRendererTier(tier, minimum) >= 0
168
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @klinechart-quant/core/renderer-tier — pre-mount renderer tier detection.
3
+ *
4
+ * Used by the `Renderer` factory to pick the highest backend the host
5
+ * environment supports (WebGPU → WebGL2 → Canvas2D → none).
6
+ *
7
+ * See `./detectRendererTier.ts` for design notes.
8
+ */
9
+
10
+ export {
11
+ detectRendererTier,
12
+ detectRendererTierOrThrow,
13
+ compareRendererTier,
14
+ isTierAtLeast,
15
+ } from './detectRendererTier'
16
+ export {
17
+ selectBackend,
18
+ selectBackendOrThrow,
19
+ type BackendFactory,
20
+ type BackendRegistry,
21
+ type BackendSelection,
22
+ type SelectBackendOptions,
23
+ } from './selectBackend'
24
+ export {
25
+ RENDERER_TIER_RANK,
26
+ type RendererTier,
27
+ type RendererTierResult,
28
+ type RendererTierProbes,
29
+ type DetectRendererTierOptions,
30
+ } from './types'
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Renderer backend selector — bridges the tier-detection layer
3
+ * ({@link detectRendererTier}) to the actual backend factory the
4
+ * `Renderer` interface will instantiate.
5
+ *
6
+ * Why this exists separately from {@link detectRendererTier}:
7
+ *
8
+ * - Detection answers "what's *possible*?".
9
+ * - Selection answers "what's *registered* and matches what's possible?".
10
+ *
11
+ * In practice the answers diverge. A consumer can:
12
+ *
13
+ * (a) Choose to omit a backend they don't want to ship (e.g. drop the
14
+ * WebGPU backend to save bundle size; the selector then falls
15
+ * through to WebGL2 even when the host supports WebGPU).
16
+ * (b) Override a backend for a specific tier (e.g. inject a Canvas2D
17
+ * backend stub during tests, so the chart still renders headless).
18
+ *
19
+ * Both shapes need a *structural* fallback chain, not just "give me the
20
+ * factory for the detected tier". This module formalises that chain so
21
+ * the wiring is consistent across React, Vue, Angular, and any future
22
+ * adapter.
23
+ *
24
+ * Pure data: no DOM, no async, no side effects. The returned factory is
25
+ * just the function the caller registered.
26
+ */
27
+
28
+ import { KLineChartError } from '../errors'
29
+ import {
30
+ RENDERER_TIER_RANK,
31
+ type DetectRendererTierOptions,
32
+ type RendererTier,
33
+ type RendererTierResult,
34
+ } from './types'
35
+ import { detectRendererTier, isTierAtLeast } from './detectRendererTier'
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Public shape
39
+ // ---------------------------------------------------------------------------
40
+
41
+ /**
42
+ * Opaque factory shape. We don't constrain the Renderer construction here —
43
+ * the consumer's backend implementation knows its own signature. The
44
+ * selector is purely about *which* factory to hand back.
45
+ */
46
+ export type BackendFactory<T = unknown> = () => T
47
+
48
+ /**
49
+ * Map of tier → registered factory. Tiers that are absent or `null` are
50
+ * treated as "not registered" and skipped during selection.
51
+ *
52
+ * `'none'` is intentionally absent from the type. A `'none'` tier is the
53
+ * absence of any rendering capability; there is nothing to register.
54
+ */
55
+ export type BackendRegistry<T = unknown> = Partial<
56
+ Record<Exclude<RendererTier, 'none'>, BackendFactory<T> | null>
57
+ >
58
+
59
+ /**
60
+ * Selection result. `tier` is the effective tier the chosen factory
61
+ * targets — which is at most the detected tier. `fallbackChain`
62
+ * enumerates the tiers the selector traversed (high → low). When no
63
+ * backend is registered for any tier ≤ the detected tier, returns
64
+ * `tier: 'none'` and `factory: null`.
65
+ */
66
+ export interface BackendSelection<T = unknown> {
67
+ readonly tier: RendererTier
68
+ readonly factory: BackendFactory<T> | null
69
+ readonly fallbackChain: ReadonlyArray<RendererTier>
70
+ readonly reason: string
71
+ /**
72
+ * The original tier-detection result. Useful for telemetry — when
73
+ * `tier < detection.tier` the consumer knows the host could have
74
+ * done better but the registry was the binding constraint.
75
+ */
76
+ readonly detection: RendererTierResult
77
+ }
78
+
79
+ export interface SelectBackendOptions<T = unknown> {
80
+ readonly registry: BackendRegistry<T>
81
+ /**
82
+ * Tier-detection probes pass-through for tests. Same shape as
83
+ * {@link DetectRendererTierOptions}.
84
+ */
85
+ readonly detect?: DetectRendererTierOptions
86
+ /**
87
+ * Optional pre-computed detection result. When provided, the selector
88
+ * skips `detectRendererTier()` and uses this directly. Useful when
89
+ * the caller cached the detection at app startup.
90
+ */
91
+ readonly detection?: RendererTierResult
92
+ /**
93
+ * Optional floor — refuse to select a backend below this tier even
94
+ * if a lower-tier factory is registered. Used by features that need
95
+ * GPU compute (`minimum: 'webgl2'`). When the floor can't be met,
96
+ * the result has `tier: 'none'` and `factory: null`.
97
+ */
98
+ readonly minimum?: RendererTier
99
+ }
100
+
101
+ // ---------------------------------------------------------------------------
102
+ // Selection
103
+ // ---------------------------------------------------------------------------
104
+
105
+ const SEARCH_ORDER: ReadonlyArray<Exclude<RendererTier, 'none'>> = [
106
+ 'webgpu',
107
+ 'webgl2',
108
+ 'canvas2d',
109
+ ]
110
+
111
+ /**
112
+ * Pick the highest registered backend at or below the detected tier
113
+ * (and at or above the optional minimum). Pure-data.
114
+ *
115
+ * const sel = selectBackend({
116
+ * registry: { webgpu: makeGpu, webgl2: makeGl2, canvas2d: makeC2d },
117
+ * })
118
+ * if (sel.factory === null) throw new Error('no renderer')
119
+ * const renderer = sel.factory()
120
+ *
121
+ * Telemetry pattern:
122
+ *
123
+ * if (sel.tier !== sel.detection.tier) {
124
+ * log('renderer downgrade', sel.detection.tier, '→', sel.tier, sel.reason)
125
+ * }
126
+ */
127
+ export function selectBackend<T = unknown>(
128
+ opts: SelectBackendOptions<T>,
129
+ ): BackendSelection<T> {
130
+ const detection = opts.detection ?? detectRendererTier(opts.detect)
131
+ const detectedTier = detection.tier
132
+ const minimum = opts.minimum ?? 'none'
133
+
134
+ // Validate the minimum is a known tier; reject 'none' as a minimum
135
+ // because a 'none' floor is meaningless — nothing can be below it.
136
+ if (!(minimum in RENDERER_TIER_RANK)) {
137
+ throw new KLineChartError(
138
+ 'INVALID_PARAM',
139
+ `selectBackend: minimum must be a RendererTier, got ${JSON.stringify(minimum)}`,
140
+ )
141
+ }
142
+
143
+ const chain: RendererTier[] = []
144
+ // Search from the detected tier downwards through SEARCH_ORDER.
145
+ for (const candidate of SEARCH_ORDER) {
146
+ // Skip tiers above the detected ceiling.
147
+ if (RENDERER_TIER_RANK[candidate] > RENDERER_TIER_RANK[detectedTier]) {
148
+ continue
149
+ }
150
+ chain.push(candidate)
151
+ // Skip below the configured minimum.
152
+ if (!isTierAtLeast(candidate, minimum)) {
153
+ // No further candidate will satisfy the minimum.
154
+ break
155
+ }
156
+ const factory = opts.registry[candidate] ?? null
157
+ if (factory !== null) {
158
+ return {
159
+ tier: candidate,
160
+ factory,
161
+ fallbackChain: chain,
162
+ reason:
163
+ candidate === detectedTier
164
+ ? `direct match: detected ${candidate} and ${candidate} backend is registered`
165
+ : `downgrade: detected ${detectedTier}, but only ${candidate} backend is registered`,
166
+ detection,
167
+ }
168
+ }
169
+ }
170
+
171
+ return {
172
+ tier: 'none',
173
+ factory: null,
174
+ fallbackChain: chain,
175
+ reason:
176
+ detectedTier === 'none'
177
+ ? `host has no renderable tier`
178
+ : `no registered backend at or below detected ${detectedTier}` +
179
+ (opts.minimum !== undefined && opts.minimum !== 'none'
180
+ ? ` (minimum=${opts.minimum})`
181
+ : ''),
182
+ detection,
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Strict variant: throws `KLineChartError('INVALID_STATE')` if no factory
188
+ * could be selected. Use when a renderable backend is mandatory.
189
+ */
190
+ export function selectBackendOrThrow<T = unknown>(
191
+ opts: SelectBackendOptions<T>,
192
+ ): BackendSelection<T> & { factory: BackendFactory<T> } {
193
+ const sel = selectBackend(opts)
194
+ if (sel.factory === null) {
195
+ throw new KLineChartError(
196
+ 'INVALID_STATE',
197
+ `selectBackendOrThrow: ${sel.reason}`,
198
+ )
199
+ }
200
+ return sel as BackendSelection<T> & { factory: BackendFactory<T> }
201
+ }