@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,59 @@
1
+ /**
2
+ * Renderer tier types.
3
+ *
4
+ * `RendererTier` is a totally-ordered enum (`'webgpu' > 'webgl2' >
5
+ * 'canvas2d' > 'none'`). Consumers pick the highest tier the host
6
+ * environment supports and configure the {@link Renderer} accordingly.
7
+ *
8
+ * Why a string union (not a numeric enum):
9
+ * - Logs and analytics stay human-readable.
10
+ * - Tree-shakable; no runtime enum object.
11
+ * - Cross-package safe — string equality survives serialization
12
+ * and avoids the "two enum copies don't compare" footgun.
13
+ */
14
+
15
+ export type RendererTier = 'webgpu' | 'webgl2' | 'canvas2d' | 'none'
16
+
17
+ /**
18
+ * Numeric rank used for `compareRendererTier`. Higher = better.
19
+ * Exposed so consumers can write their own "at least X" guards.
20
+ */
21
+ export const RENDERER_TIER_RANK: Readonly<Record<RendererTier, number>> = {
22
+ webgpu: 3,
23
+ webgl2: 2,
24
+ canvas2d: 1,
25
+ none: 0,
26
+ }
27
+
28
+ /**
29
+ * Detection result. `tier` is the picked tier; `reason` is a one-line
30
+ * human-readable explanation (intended for diagnostics, not for
31
+ * branching — branch on `tier`).
32
+ *
33
+ * `tried` enumerates the tiers probed in order — useful when reporting
34
+ * "we wanted WebGPU but it threw" telemetry.
35
+ */
36
+ export interface RendererTierResult {
37
+ readonly tier: RendererTier
38
+ readonly reason: string
39
+ readonly tried: ReadonlyArray<RendererTier>
40
+ }
41
+
42
+ /**
43
+ * Probe injection — the unit tests use this to simulate every tier
44
+ * combination without poking globals. Production code passes nothing
45
+ * and the real `globalThis` probes run.
46
+ *
47
+ * Each probe returns `true` when the tier is detected, `false` when
48
+ * it is conclusively unavailable. Throwing is treated as "unavailable"
49
+ * with the message folded into `reason`.
50
+ */
51
+ export interface RendererTierProbes {
52
+ readonly webgpu?: () => boolean
53
+ readonly webgl2?: () => boolean
54
+ readonly canvas2d?: () => boolean
55
+ }
56
+
57
+ export interface DetectRendererTierOptions {
58
+ readonly probes?: RendererTierProbes
59
+ }
@@ -0,0 +1,309 @@
1
+ import { describe, it, expect, vi } from 'vitest'
2
+ import { createReplayController } from '../createReplayController'
3
+ import type { ReplayState } from '../types'
4
+
5
+ // A 1-minute bar interval so wall-clock math is easy to reason about:
6
+ // 1000ms of wall-clock at speed=1 advances 1000/60000 = 0.01666... bars.
7
+ // At speed=60, 1000ms advances 1 full bar.
8
+ const ONE_MINUTE_MS = 60_000
9
+
10
+ function build(initOverride: Partial<Parameters<typeof createReplayController>[0]> = {}) {
11
+ return createReplayController({
12
+ start: 0,
13
+ end: 99,
14
+ pacing: 'bar',
15
+ speed: 1,
16
+ barIntervalMs: ONE_MINUTE_MS,
17
+ ...initOverride,
18
+ })
19
+ }
20
+
21
+ describe('createReplayController', () => {
22
+ it('initialises position at start with mode=paused', () => {
23
+ const ctrl = build()
24
+ const s = ctrl.state.peek()
25
+ expect(s.position).toBe(0)
26
+ expect(s.start).toBe(0)
27
+ expect(s.end).toBe(99)
28
+ expect(s.mode).toBe('paused')
29
+ expect(s.pacing).toBe('bar')
30
+ expect(s.speed).toBe(1)
31
+ ctrl.dispose()
32
+ })
33
+
34
+ it('throws on construction when end < start', () => {
35
+ expect(() => build({ start: 10, end: 5 })).toThrow(/end.*start/i)
36
+ })
37
+
38
+ it('throws on construction when speed <= 0', () => {
39
+ expect(() => build({ speed: 0 })).toThrow(/speed/i)
40
+ expect(() => build({ speed: -1 })).toThrow(/speed/i)
41
+ })
42
+
43
+ it('seekTo within range updates state and notifies subscribers', () => {
44
+ const ctrl = build()
45
+ const fn = vi.fn()
46
+ const unsub = ctrl.state.subscribe(fn)
47
+ ctrl.seekTo(42)
48
+ expect(ctrl.state.peek().position).toBe(42)
49
+ expect(fn).toHaveBeenCalledTimes(1)
50
+ unsub()
51
+ ctrl.dispose()
52
+ })
53
+
54
+ it('seekTo above end clamps to end', () => {
55
+ const ctrl = build()
56
+ ctrl.seekTo(1_000_000)
57
+ expect(ctrl.state.peek().position).toBe(99)
58
+ ctrl.dispose()
59
+ })
60
+
61
+ it('seekTo below start clamps to start', () => {
62
+ const ctrl = build()
63
+ ctrl.seekTo(-50)
64
+ expect(ctrl.state.peek().position).toBe(0)
65
+ ctrl.dispose()
66
+ })
67
+
68
+ it('stepForward + stepBackward returns to the same position', () => {
69
+ const ctrl = build()
70
+ ctrl.seekTo(20)
71
+ ctrl.stepForward()
72
+ expect(ctrl.state.peek().position).toBe(21)
73
+ ctrl.stepBackward()
74
+ expect(ctrl.state.peek().position).toBe(20)
75
+ ctrl.dispose()
76
+ })
77
+
78
+ it('consecutive stepForward past end clamps to end and auto-pauses if playing', () => {
79
+ const ctrl = build({ end: 3 })
80
+ ctrl.seekTo(2)
81
+ ctrl.play()
82
+ expect(ctrl.state.peek().mode).toBe('playing')
83
+ ctrl.stepForward() // -> 3, hits end while playing => auto-paused
84
+ const s = ctrl.state.peek()
85
+ expect(s.position).toBe(3)
86
+ expect(s.mode).toBe('paused')
87
+ // Further forwards stay clamped.
88
+ ctrl.stepForward()
89
+ expect(ctrl.state.peek().position).toBe(3)
90
+ ctrl.dispose()
91
+ })
92
+
93
+ it('play() then pause() toggles mode and emits both transitions', () => {
94
+ const ctrl = build()
95
+ ctrl.seekTo(10)
96
+ const fn = vi.fn()
97
+ const unsub = ctrl.state.subscribe(fn)
98
+ ctrl.play()
99
+ expect(ctrl.state.peek().mode).toBe('playing')
100
+ ctrl.pause()
101
+ expect(ctrl.state.peek().mode).toBe('paused')
102
+ expect(fn).toHaveBeenCalledTimes(2)
103
+ unsub()
104
+ ctrl.dispose()
105
+ })
106
+
107
+ it('toggle() flips between paused and playing', () => {
108
+ const ctrl = build()
109
+ ctrl.seekTo(10)
110
+ expect(ctrl.state.peek().mode).toBe('paused')
111
+ ctrl.toggle()
112
+ expect(ctrl.state.peek().mode).toBe('playing')
113
+ ctrl.toggle()
114
+ expect(ctrl.state.peek().mode).toBe('paused')
115
+ ctrl.dispose()
116
+ })
117
+
118
+ it('play() at end stays paused (no observable mode flip)', () => {
119
+ const ctrl = build({ end: 5 })
120
+ ctrl.seekTo(5)
121
+ const fn = vi.fn()
122
+ const unsub = ctrl.state.subscribe(fn)
123
+ ctrl.play()
124
+ expect(ctrl.state.peek().mode).toBe('paused')
125
+ expect(fn).not.toHaveBeenCalled()
126
+ unsub()
127
+ ctrl.dispose()
128
+ })
129
+
130
+ it('tick() in bar mode is a no-op when playing', () => {
131
+ const ctrl = build({ pacing: 'bar' })
132
+ ctrl.play()
133
+ const before = ctrl.state.peek().position
134
+ const changed = ctrl.tick(1000)
135
+ expect(changed).toBe(false)
136
+ expect(ctrl.state.peek().position).toBe(before)
137
+ ctrl.dispose()
138
+ })
139
+
140
+ it('tick() in wallclock mode advances proportional to deltaMs * speed', () => {
141
+ const ctrl = build({ pacing: 'wallclock', speed: 1 })
142
+ ctrl.play()
143
+ // 1000ms at speed=1 with 60_000ms/bar → 1/60 of a bar.
144
+ const changed = ctrl.tick(1000)
145
+ expect(changed).toBe(true)
146
+ expect(ctrl.state.peek().position).toBeCloseTo(1 / 60, 10)
147
+
148
+ // Bump speed to 60 → 1000ms advances exactly 1 bar.
149
+ ctrl.setSpeed(60)
150
+ const before = ctrl.state.peek().position
151
+ ctrl.tick(1000)
152
+ expect(ctrl.state.peek().position).toBeCloseTo(before + 1, 10)
153
+ ctrl.dispose()
154
+ })
155
+
156
+ it('tick() in tick mode advances faster than wallclock at the same speed', () => {
157
+ const wallCtrl = build({ pacing: 'wallclock', speed: 1 })
158
+ const tickCtrl = build({ pacing: 'tick', speed: 1 })
159
+ wallCtrl.play()
160
+ tickCtrl.play()
161
+ wallCtrl.tick(1000)
162
+ tickCtrl.tick(1000)
163
+ const wallAdvance = wallCtrl.state.peek().position
164
+ const tickAdvance = tickCtrl.state.peek().position
165
+ expect(tickAdvance).toBeGreaterThan(wallAdvance)
166
+ // 1000ms / 100ms-per-bar * speed=1 = 10 bars
167
+ expect(tickAdvance).toBeCloseTo(10, 10)
168
+ wallCtrl.dispose()
169
+ tickCtrl.dispose()
170
+ })
171
+
172
+ it('reaching end via tick() auto-pauses and clamps to end', () => {
173
+ const ctrl = build({ pacing: 'wallclock', speed: 60, end: 5 })
174
+ ctrl.play()
175
+ // 10 bars worth of advance — far past the end (5).
176
+ ctrl.tick(10_000)
177
+ const s = ctrl.state.peek()
178
+ expect(s.position).toBe(5)
179
+ expect(s.mode).toBe('paused')
180
+ ctrl.dispose()
181
+ })
182
+
183
+ it('setPacing mid-play keeps mode=playing and switches tick math', () => {
184
+ const ctrl = build({ pacing: 'wallclock', speed: 1 })
185
+ ctrl.play()
186
+ ctrl.tick(1000)
187
+ const afterWall = ctrl.state.peek().position
188
+ expect(ctrl.state.peek().mode).toBe('playing')
189
+
190
+ ctrl.setPacing('bar')
191
+ // Still playing, but bar pacing means tick() no longer advances.
192
+ expect(ctrl.state.peek().mode).toBe('playing')
193
+ const changed = ctrl.tick(1000)
194
+ expect(changed).toBe(false)
195
+ expect(ctrl.state.peek().position).toBe(afterWall)
196
+ ctrl.dispose()
197
+ })
198
+
199
+ it('setSpeed(<=0) throws and does not mutate state', () => {
200
+ const ctrl = build()
201
+ const before = ctrl.state.peek()
202
+ expect(() => ctrl.setSpeed(0)).toThrow(/speed/i)
203
+ expect(() => ctrl.setSpeed(-2)).toThrow(/speed/i)
204
+ expect(ctrl.state.peek()).toBe(before) // same object reference
205
+ ctrl.dispose()
206
+ })
207
+
208
+ it('setRange clamps current position into the new range', () => {
209
+ const ctrl = build({ end: 100 })
210
+ ctrl.seekTo(80)
211
+ ctrl.setRange(0, 50)
212
+ const s = ctrl.state.peek()
213
+ expect(s.start).toBe(0)
214
+ expect(s.end).toBe(50)
215
+ expect(s.position).toBe(50)
216
+ ctrl.dispose()
217
+ })
218
+
219
+ it('setRange throws when end < start and leaves state untouched', () => {
220
+ const ctrl = build()
221
+ const before = ctrl.state.peek()
222
+ expect(() => ctrl.setRange(20, 10)).toThrow(/end.*start/i)
223
+ expect(ctrl.state.peek()).toBe(before)
224
+ ctrl.dispose()
225
+ })
226
+
227
+ it('tick() returns true only when position changed', () => {
228
+ const ctrl = build({ pacing: 'wallclock', speed: 60, end: 10 })
229
+ ctrl.play()
230
+ expect(ctrl.tick(1000)).toBe(true) // advanced ~1 bar
231
+ // Seek to the end manually so playback is at the right edge.
232
+ ctrl.seekTo(10)
233
+ // After clamping at end, the controller has auto-paused already, so
234
+ // tick() should refuse to advance (mode != 'playing').
235
+ expect(ctrl.tick(1000)).toBe(false)
236
+
237
+ // Negative or zero delta is ignored regardless of mode.
238
+ const fresh = build({ pacing: 'wallclock' })
239
+ fresh.play()
240
+ expect(fresh.tick(0)).toBe(false)
241
+ expect(fresh.tick(-100)).toBe(false)
242
+ ctrl.dispose()
243
+ fresh.dispose()
244
+ })
245
+
246
+ it('dispose silences subsequent mutators (no further emissions)', () => {
247
+ const ctrl = build()
248
+ ctrl.seekTo(10)
249
+ const fn = vi.fn()
250
+ const unsub = ctrl.state.subscribe(fn)
251
+ ctrl.dispose()
252
+ ctrl.seekTo(20)
253
+ ctrl.play()
254
+ ctrl.stepForward()
255
+ ctrl.setPacing('wallclock')
256
+ // Tick after dispose returns false and emits nothing.
257
+ expect(ctrl.tick(1000)).toBe(false)
258
+ expect(fn).not.toHaveBeenCalled()
259
+ // State observably unchanged from pre-dispose.
260
+ expect(ctrl.state.peek().position).toBe(10)
261
+ unsub()
262
+ })
263
+
264
+ it('seekBy clamps and notifies on net change', () => {
265
+ const ctrl = build()
266
+ ctrl.seekTo(50)
267
+ const fn = vi.fn()
268
+ const unsub = ctrl.state.subscribe(fn)
269
+ ctrl.seekBy(10)
270
+ expect(ctrl.state.peek().position).toBe(60)
271
+ ctrl.seekBy(1_000_000)
272
+ expect(ctrl.state.peek().position).toBe(99)
273
+ ctrl.seekBy(-1_000_000)
274
+ expect(ctrl.state.peek().position).toBe(0)
275
+ expect(fn).toHaveBeenCalledTimes(3)
276
+ unsub()
277
+ ctrl.dispose()
278
+ })
279
+
280
+ it('state is a single transactional snapshot — one notification per mutation', () => {
281
+ // Verifies the "single signal" design: setRange changes multiple
282
+ // fields but subscribers see one emission.
283
+ const ctrl = build()
284
+ ctrl.seekTo(80)
285
+ const captured: ReplayState[] = []
286
+ const unsub = ctrl.state.subscribe(() => {
287
+ captured.push(ctrl.state.peek())
288
+ })
289
+ ctrl.setRange(10, 50)
290
+ expect(captured).toHaveLength(1)
291
+ const snap = captured[0] as ReplayState
292
+ expect(snap.start).toBe(10)
293
+ expect(snap.end).toBe(50)
294
+ expect(snap.position).toBe(50) // clamped from 80
295
+ unsub()
296
+ ctrl.dispose()
297
+ })
298
+
299
+ it('no-op seekTo to current position does not notify', () => {
300
+ const ctrl = build()
301
+ ctrl.seekTo(25)
302
+ const fn = vi.fn()
303
+ const unsub = ctrl.state.subscribe(fn)
304
+ ctrl.seekTo(25)
305
+ expect(fn).not.toHaveBeenCalled()
306
+ unsub()
307
+ ctrl.dispose()
308
+ })
309
+ })
@@ -0,0 +1,99 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import {
3
+ barIndexToTimestamp,
4
+ timestampToBarIndex,
5
+ inferBarIntervalMs,
6
+ type BarCalendar,
7
+ } from '../timeline'
8
+
9
+ // 1-minute bars covering 10 bars starting at an arbitrary epoch.
10
+ const MINUTE_MS = 60_000
11
+ const T0 = 1_700_000_000_000
12
+ function uniformCalendar(n: number, intervalMs = MINUTE_MS): BarCalendar {
13
+ const out: number[] = []
14
+ for (let i = 0; i < n; i++) out.push(T0 + i * intervalMs)
15
+ return out
16
+ }
17
+
18
+ describe('timeline', () => {
19
+ describe('barIndexToTimestamp + timestampToBarIndex', () => {
20
+ it('round-trips on a uniform calendar', () => {
21
+ const cal = uniformCalendar(10)
22
+ for (let i = 0; i < cal.length; i++) {
23
+ const ts = barIndexToTimestamp(cal, i)
24
+ expect(ts).not.toBeNull()
25
+ const back = timestampToBarIndex(cal, ts as number)
26
+ expect(back).toBe(i)
27
+ }
28
+ })
29
+
30
+ it('returns null for out-of-range bar indices', () => {
31
+ const cal = uniformCalendar(5)
32
+ expect(barIndexToTimestamp(cal, -1)).toBeNull()
33
+ expect(barIndexToTimestamp(cal, 5)).toBeNull()
34
+ expect(barIndexToTimestamp(cal, 999)).toBeNull()
35
+ expect(barIndexToTimestamp(cal, Number.NaN)).toBeNull()
36
+ })
37
+
38
+ it('returns null for empty calendars on both directions', () => {
39
+ const empty: BarCalendar = []
40
+ expect(barIndexToTimestamp(empty, 0)).toBeNull()
41
+ expect(timestampToBarIndex(empty, T0)).toBeNull()
42
+ })
43
+
44
+ it('honors non-uniform gaps (e.g. weekend close)', () => {
45
+ // Friday 16:00 close, then Monday 09:30 open — a ~65h gap.
46
+ // bars 0..3 are 1-minute Friday afternoon; bar 4 is Monday open.
47
+ const friday = T0
48
+ const cal: BarCalendar = [
49
+ friday + 0 * MINUTE_MS,
50
+ friday + 1 * MINUTE_MS,
51
+ friday + 2 * MINUTE_MS,
52
+ friday + 3 * MINUTE_MS,
53
+ friday + (65 * 60 + 30) * MINUTE_MS, // ~65.5h later
54
+ ]
55
+
56
+ // Sanity: bar 4 timestamp matches what we put in.
57
+ expect(barIndexToTimestamp(cal, 4)).toBe(cal[4])
58
+ // A timestamp inside the weekend gap resolves to the last
59
+ // pre-gap bar (Friday's close), not the Monday open.
60
+ const insideGap = (cal[3] as number) + 12 * 60 * MINUTE_MS // Saturday noon
61
+ expect(timestampToBarIndex(cal, insideGap)).toBe(3)
62
+ // A timestamp at or after the Monday open resolves to bar 4.
63
+ expect(timestampToBarIndex(cal, cal[4] as number)).toBe(4)
64
+ expect(timestampToBarIndex(cal, (cal[4] as number) + MINUTE_MS)).toBe(4)
65
+ })
66
+
67
+ it('clamps timestamps below the first bar to null and above the last bar to the final index', () => {
68
+ const cal = uniformCalendar(5)
69
+ expect(timestampToBarIndex(cal, (cal[0] as number) - 1)).toBeNull()
70
+ expect(timestampToBarIndex(cal, (cal[4] as number) + 999_999)).toBe(4)
71
+ })
72
+ })
73
+
74
+ describe('inferBarIntervalMs', () => {
75
+ it('returns the dominant interval on a uniform calendar', () => {
76
+ expect(inferBarIntervalMs(uniformCalendar(10))).toBe(MINUTE_MS)
77
+ })
78
+
79
+ it('uses the median so outlier gaps do not skew the estimate', () => {
80
+ // Mostly 1-minute, with one massive weekend gap.
81
+ const cal: BarCalendar = [
82
+ 0,
83
+ MINUTE_MS,
84
+ 2 * MINUTE_MS,
85
+ 3 * MINUTE_MS,
86
+ // 3-day gap
87
+ 3 * MINUTE_MS + 3 * 24 * 60 * MINUTE_MS,
88
+ 3 * MINUTE_MS + 3 * 24 * 60 * MINUTE_MS + MINUTE_MS,
89
+ 3 * MINUTE_MS + 3 * 24 * 60 * MINUTE_MS + 2 * MINUTE_MS,
90
+ ]
91
+ expect(inferBarIntervalMs(cal)).toBe(MINUTE_MS)
92
+ })
93
+
94
+ it('returns null when the calendar has fewer than two bars', () => {
95
+ expect(inferBarIntervalMs([])).toBeNull()
96
+ expect(inferBarIntervalMs([T0])).toBeNull()
97
+ })
98
+ })
99
+ })