@invinite-org/chartlang-runtime 1.1.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/CHANGELOG.md +307 -0
  2. package/dist/barPoint.d.ts +20 -0
  3. package/dist/barPoint.d.ts.map +1 -0
  4. package/dist/barPoint.js +72 -0
  5. package/dist/barPoint.js.map +1 -0
  6. package/dist/bufferSnapshot.d.ts +102 -0
  7. package/dist/bufferSnapshot.d.ts.map +1 -0
  8. package/dist/bufferSnapshot.js +119 -0
  9. package/dist/bufferSnapshot.js.map +1 -0
  10. package/dist/buildComputeContext.d.ts.map +1 -1
  11. package/dist/buildComputeContext.js +6 -1
  12. package/dist/buildComputeContext.js.map +1 -1
  13. package/dist/createScriptRunner.d.ts +6 -3
  14. package/dist/createScriptRunner.d.ts.map +1 -1
  15. package/dist/createScriptRunner.js +65 -11
  16. package/dist/createScriptRunner.js.map +1 -1
  17. package/dist/dep/DepRunner.d.ts +7 -0
  18. package/dist/dep/DepRunner.d.ts.map +1 -1
  19. package/dist/dep/DepRunner.js +4 -0
  20. package/dist/dep/DepRunner.js.map +1 -1
  21. package/dist/emit/barcolor.d.ts +44 -0
  22. package/dist/emit/barcolor.d.ts.map +1 -0
  23. package/dist/emit/barcolor.js +40 -0
  24. package/dist/emit/barcolor.js.map +1 -0
  25. package/dist/emit/bgcolor.d.ts +44 -0
  26. package/dist/emit/bgcolor.d.ts.map +1 -0
  27. package/dist/emit/bgcolor.js +45 -0
  28. package/dist/emit/bgcolor.js.map +1 -0
  29. package/dist/emit/draw/boxes/fillBetween.d.ts +45 -0
  30. package/dist/emit/draw/boxes/fillBetween.d.ts.map +1 -0
  31. package/dist/emit/draw/boxes/fillBetween.js +36 -0
  32. package/dist/emit/draw/boxes/fillBetween.js.map +1 -0
  33. package/dist/emit/draw/handle.d.ts +9 -0
  34. package/dist/emit/draw/handle.d.ts.map +1 -1
  35. package/dist/emit/draw/handle.js +65 -10
  36. package/dist/emit/draw/handle.js.map +1 -1
  37. package/dist/emit/draw/namespace.d.ts +4 -3
  38. package/dist/emit/draw/namespace.d.ts.map +1 -1
  39. package/dist/emit/draw/namespace.js +6 -3
  40. package/dist/emit/draw/namespace.js.map +1 -1
  41. package/dist/emit/index.d.ts +2 -0
  42. package/dist/emit/index.d.ts.map +1 -1
  43. package/dist/emit/index.js +2 -0
  44. package/dist/emit/index.js.map +1 -1
  45. package/dist/emit/plot.d.ts +30 -1
  46. package/dist/emit/plot.d.ts.map +1 -1
  47. package/dist/emit/plot.js +45 -1
  48. package/dist/emit/plot.js.map +1 -1
  49. package/dist/execution/dispose.d.ts.map +1 -1
  50. package/dist/execution/dispose.js +18 -0
  51. package/dist/execution/dispose.js.map +1 -1
  52. package/dist/execution/runComputeStep.d.ts.map +1 -1
  53. package/dist/execution/runComputeStep.js +12 -1
  54. package/dist/execution/runComputeStep.js.map +1 -1
  55. package/dist/index.d.ts +1 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +1 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/inputs/resolveInputs.js +1 -0
  60. package/dist/inputs/resolveInputs.js.map +1 -1
  61. package/dist/persistentStateStore.runtime.d.ts.map +1 -1
  62. package/dist/persistentStateStore.runtime.js +26 -7
  63. package/dist/persistentStateStore.runtime.js.map +1 -1
  64. package/dist/primitives.d.ts +1 -1
  65. package/dist/primitives.d.ts.map +1 -1
  66. package/dist/primitives.js +7 -1
  67. package/dist/primitives.js.map +1 -1
  68. package/dist/request/index.d.ts +2 -1
  69. package/dist/request/index.d.ts.map +1 -1
  70. package/dist/request/index.js +2 -1
  71. package/dist/request/index.js.map +1 -1
  72. package/dist/request/lowerTf.d.ts.map +1 -1
  73. package/dist/request/lowerTf.js +6 -0
  74. package/dist/request/lowerTf.js.map +1 -1
  75. package/dist/request/requestNamespace.d.ts.map +1 -1
  76. package/dist/request/requestNamespace.js +30 -3
  77. package/dist/request/requestNamespace.js.map +1 -1
  78. package/dist/request/security.d.ts +40 -4
  79. package/dist/request/security.d.ts.map +1 -1
  80. package/dist/request/security.js +114 -40
  81. package/dist/request/security.js.map +1 -1
  82. package/dist/request/securityExprRunner.d.ts +137 -0
  83. package/dist/request/securityExprRunner.d.ts.map +1 -0
  84. package/dist/request/securityExprRunner.js +253 -0
  85. package/dist/request/securityExprRunner.js.map +1 -0
  86. package/dist/request/streamBars.d.ts +14 -1
  87. package/dist/request/streamBars.d.ts.map +1 -1
  88. package/dist/request/streamBars.js +39 -1
  89. package/dist/request/streamBars.js.map +1 -1
  90. package/dist/ringBuffer.d.ts +19 -0
  91. package/dist/ringBuffer.d.ts.map +1 -1
  92. package/dist/ringBuffer.js +23 -0
  93. package/dist/ringBuffer.js.map +1 -1
  94. package/dist/runtimeContext.d.ts +90 -5
  95. package/dist/runtimeContext.d.ts.map +1 -1
  96. package/dist/runtimeContext.js.map +1 -1
  97. package/dist/seriesView.d.ts +42 -17
  98. package/dist/seriesView.d.ts.map +1 -1
  99. package/dist/seriesView.js +65 -42
  100. package/dist/seriesView.js.map +1 -1
  101. package/dist/state/arrayPersistence.d.ts +48 -0
  102. package/dist/state/arrayPersistence.d.ts.map +1 -0
  103. package/dist/state/arrayPersistence.js +88 -0
  104. package/dist/state/arrayPersistence.js.map +1 -0
  105. package/dist/state/arrayStateSlot.d.ts +78 -0
  106. package/dist/state/arrayStateSlot.d.ts.map +1 -0
  107. package/dist/state/arrayStateSlot.js +116 -0
  108. package/dist/state/arrayStateSlot.js.map +1 -0
  109. package/dist/state/index.d.ts +4 -1
  110. package/dist/state/index.d.ts.map +1 -1
  111. package/dist/state/index.js +4 -1
  112. package/dist/state/index.js.map +1 -1
  113. package/dist/state/lifecycle.d.ts +68 -0
  114. package/dist/state/lifecycle.d.ts.map +1 -1
  115. package/dist/state/lifecycle.js +89 -0
  116. package/dist/state/lifecycle.js.map +1 -1
  117. package/dist/state/seriesPersistence.d.ts +48 -0
  118. package/dist/state/seriesPersistence.d.ts.map +1 -0
  119. package/dist/state/seriesPersistence.js +87 -0
  120. package/dist/state/seriesPersistence.js.map +1 -0
  121. package/dist/state/seriesSlot.d.ts +105 -0
  122. package/dist/state/seriesSlot.d.ts.map +1 -0
  123. package/dist/state/seriesSlot.js +123 -0
  124. package/dist/state/seriesSlot.js.map +1 -0
  125. package/dist/state/stateNamespace.d.ts.map +1 -1
  126. package/dist/state/stateNamespace.js +55 -0
  127. package/dist/state/stateNamespace.js.map +1 -1
  128. package/dist/streamState.d.ts +25 -19
  129. package/dist/streamState.d.ts.map +1 -1
  130. package/dist/streamState.js +40 -66
  131. package/dist/streamState.js.map +1 -1
  132. package/dist/ta/adx.d.ts +3 -2
  133. package/dist/ta/adx.d.ts.map +1 -1
  134. package/dist/ta/adx.js +3 -2
  135. package/dist/ta/adx.js.map +1 -1
  136. package/dist/ta/alma.d.ts +6 -4
  137. package/dist/ta/alma.d.ts.map +1 -1
  138. package/dist/ta/alma.js +19 -6
  139. package/dist/ta/alma.js.map +1 -1
  140. package/dist/ta/atr.d.ts +3 -2
  141. package/dist/ta/atr.d.ts.map +1 -1
  142. package/dist/ta/atr.js +3 -2
  143. package/dist/ta/atr.js.map +1 -1
  144. package/dist/ta/bb.d.ts +3 -2
  145. package/dist/ta/bb.d.ts.map +1 -1
  146. package/dist/ta/bb.js +3 -2
  147. package/dist/ta/bb.js.map +1 -1
  148. package/dist/ta/chaikinOsc.d.ts +3 -2
  149. package/dist/ta/chaikinOsc.d.ts.map +1 -1
  150. package/dist/ta/chaikinOsc.js +3 -2
  151. package/dist/ta/chaikinOsc.js.map +1 -1
  152. package/dist/ta/crossover.d.ts +3 -2
  153. package/dist/ta/crossover.d.ts.map +1 -1
  154. package/dist/ta/crossover.js +3 -2
  155. package/dist/ta/crossover.js.map +1 -1
  156. package/dist/ta/crossunder.d.ts +3 -2
  157. package/dist/ta/crossunder.d.ts.map +1 -1
  158. package/dist/ta/crossunder.js +3 -2
  159. package/dist/ta/crossunder.js.map +1 -1
  160. package/dist/ta/dmi.d.ts +4 -3
  161. package/dist/ta/dmi.d.ts.map +1 -1
  162. package/dist/ta/dmi.js +4 -3
  163. package/dist/ta/dmi.js.map +1 -1
  164. package/dist/ta/ema.d.ts +3 -2
  165. package/dist/ta/ema.d.ts.map +1 -1
  166. package/dist/ta/ema.js +3 -2
  167. package/dist/ta/ema.js.map +1 -1
  168. package/dist/ta/eom.d.ts +3 -1
  169. package/dist/ta/eom.d.ts.map +1 -1
  170. package/dist/ta/eom.js +3 -1
  171. package/dist/ta/eom.js.map +1 -1
  172. package/dist/ta/highestbars.d.ts +25 -0
  173. package/dist/ta/highestbars.d.ts.map +1 -0
  174. package/dist/ta/highestbars.js +106 -0
  175. package/dist/ta/highestbars.js.map +1 -0
  176. package/dist/ta/historicalVolatility.d.ts +3 -2
  177. package/dist/ta/historicalVolatility.d.ts.map +1 -1
  178. package/dist/ta/historicalVolatility.js +3 -2
  179. package/dist/ta/historicalVolatility.js.map +1 -1
  180. package/dist/ta/ichimoku.d.ts +3 -1
  181. package/dist/ta/ichimoku.d.ts.map +1 -1
  182. package/dist/ta/ichimoku.js +3 -1
  183. package/dist/ta/ichimoku.js.map +1 -1
  184. package/dist/ta/lowestbars.d.ts +25 -0
  185. package/dist/ta/lowestbars.d.ts.map +1 -0
  186. package/dist/ta/lowestbars.js +102 -0
  187. package/dist/ta/lowestbars.js.map +1 -0
  188. package/dist/ta/macd.d.ts +3 -2
  189. package/dist/ta/macd.d.ts.map +1 -1
  190. package/dist/ta/macd.js +3 -2
  191. package/dist/ta/macd.js.map +1 -1
  192. package/dist/ta/massIndex.d.ts +3 -2
  193. package/dist/ta/massIndex.d.ts.map +1 -1
  194. package/dist/ta/massIndex.js +3 -2
  195. package/dist/ta/massIndex.js.map +1 -1
  196. package/dist/ta/mfi.d.ts +3 -1
  197. package/dist/ta/mfi.d.ts.map +1 -1
  198. package/dist/ta/mfi.js +3 -1
  199. package/dist/ta/mfi.js.map +1 -1
  200. package/dist/ta/netVolume.d.ts +3 -1
  201. package/dist/ta/netVolume.d.ts.map +1 -1
  202. package/dist/ta/netVolume.js +3 -1
  203. package/dist/ta/netVolume.js.map +1 -1
  204. package/dist/ta/nvi.d.ts +3 -1
  205. package/dist/ta/nvi.d.ts.map +1 -1
  206. package/dist/ta/nvi.js +3 -1
  207. package/dist/ta/nvi.js.map +1 -1
  208. package/dist/ta/persistence.d.ts.map +1 -1
  209. package/dist/ta/persistence.js +1 -40
  210. package/dist/ta/persistence.js.map +1 -1
  211. package/dist/ta/ppo.d.ts +3 -2
  212. package/dist/ta/ppo.d.ts.map +1 -1
  213. package/dist/ta/ppo.js +3 -2
  214. package/dist/ta/ppo.js.map +1 -1
  215. package/dist/ta/pvi.d.ts +3 -1
  216. package/dist/ta/pvi.d.ts.map +1 -1
  217. package/dist/ta/pvi.js +3 -1
  218. package/dist/ta/pvi.js.map +1 -1
  219. package/dist/ta/pvo.d.ts +3 -1
  220. package/dist/ta/pvo.d.ts.map +1 -1
  221. package/dist/ta/pvo.js +3 -1
  222. package/dist/ta/pvo.js.map +1 -1
  223. package/dist/ta/pvt.d.ts +3 -1
  224. package/dist/ta/pvt.d.ts.map +1 -1
  225. package/dist/ta/pvt.js +3 -1
  226. package/dist/ta/pvt.js.map +1 -1
  227. package/dist/ta/registry.d.ts +7 -1
  228. package/dist/ta/registry.d.ts.map +1 -1
  229. package/dist/ta/registry.js +4 -0
  230. package/dist/ta/registry.js.map +1 -1
  231. package/dist/ta/rsi.d.ts +3 -2
  232. package/dist/ta/rsi.d.ts.map +1 -1
  233. package/dist/ta/rsi.js +3 -2
  234. package/dist/ta/rsi.js.map +1 -1
  235. package/dist/ta/rvi.d.ts +3 -2
  236. package/dist/ta/rvi.d.ts.map +1 -1
  237. package/dist/ta/rvi.js +3 -2
  238. package/dist/ta/rvi.js.map +1 -1
  239. package/dist/ta/sessionVolumeProfile.d.ts.map +1 -1
  240. package/dist/ta/sessionVolumeProfile.js +1 -17
  241. package/dist/ta/sessionVolumeProfile.js.map +1 -1
  242. package/dist/ta/sma.d.ts +6 -3
  243. package/dist/ta/sma.d.ts.map +1 -1
  244. package/dist/ta/sma.js +6 -3
  245. package/dist/ta/sma.js.map +1 -1
  246. package/dist/ta/stdev.d.ts +3 -2
  247. package/dist/ta/stdev.d.ts.map +1 -1
  248. package/dist/ta/stdev.js +3 -2
  249. package/dist/ta/stdev.js.map +1 -1
  250. package/dist/ta/trendStrengthIndex.d.ts +3 -2
  251. package/dist/ta/trendStrengthIndex.d.ts.map +1 -1
  252. package/dist/ta/trendStrengthIndex.js +3 -2
  253. package/dist/ta/trendStrengthIndex.js.map +1 -1
  254. package/dist/ta/trix.d.ts +4 -3
  255. package/dist/ta/trix.d.ts.map +1 -1
  256. package/dist/ta/trix.js +4 -3
  257. package/dist/ta/trix.js.map +1 -1
  258. package/dist/ta/vortex.d.ts +3 -2
  259. package/dist/ta/vortex.d.ts.map +1 -1
  260. package/dist/ta/vortex.js +3 -2
  261. package/dist/ta/vortex.js.map +1 -1
  262. package/dist/time-accessors/civil.d.ts +73 -0
  263. package/dist/time-accessors/civil.d.ts.map +1 -0
  264. package/dist/time-accessors/civil.js +105 -0
  265. package/dist/time-accessors/civil.js.map +1 -0
  266. package/dist/time-accessors/index.d.ts +8 -0
  267. package/dist/time-accessors/index.d.ts.map +1 -0
  268. package/dist/time-accessors/index.js +9 -0
  269. package/dist/time-accessors/index.js.map +1 -0
  270. package/dist/time-accessors/sessionAccessors.d.ts +50 -0
  271. package/dist/time-accessors/sessionAccessors.d.ts.map +1 -0
  272. package/dist/time-accessors/sessionAccessors.js +79 -0
  273. package/dist/time-accessors/sessionAccessors.js.map +1 -0
  274. package/dist/time-accessors/sessionWindow.d.ts +17 -0
  275. package/dist/time-accessors/sessionWindow.d.ts.map +1 -0
  276. package/dist/time-accessors/sessionWindow.js +41 -0
  277. package/dist/time-accessors/sessionWindow.js.map +1 -0
  278. package/dist/time-accessors/timeAccessors.d.ts +54 -0
  279. package/dist/time-accessors/timeAccessors.d.ts.map +1 -0
  280. package/dist/time-accessors/timeAccessors.js +132 -0
  281. package/dist/time-accessors/timeAccessors.js.map +1 -0
  282. package/dist/time-accessors/tzDiagnostic.d.ts +17 -0
  283. package/dist/time-accessors/tzDiagnostic.d.ts.map +1 -0
  284. package/dist/time-accessors/tzDiagnostic.js +34 -0
  285. package/dist/time-accessors/tzDiagnostic.js.map +1 -0
  286. package/dist/time-accessors/tzOffset.d.ts +31 -0
  287. package/dist/time-accessors/tzOffset.d.ts.map +1 -0
  288. package/dist/time-accessors/tzOffset.js +67 -0
  289. package/dist/time-accessors/tzOffset.js.map +1 -0
  290. package/package.json +3 -3
  291. package/dist/ta/lib/applyOffset.d.ts +0 -19
  292. package/dist/ta/lib/applyOffset.d.ts.map +0 -1
  293. package/dist/ta/lib/applyOffset.js +0 -38
  294. package/dist/ta/lib/applyOffset.js.map +0 -1
@@ -91,5 +91,24 @@ export declare class Float64RingBuffer implements RingBufferLike<number> {
91
91
  values: ReadonlyArray<number | null>;
92
92
  }>): void;
93
93
  reset(): void;
94
+ /**
95
+ * Overwrite this ring's entire state with a copy of `other`'s. A single
96
+ * `Float64Array.prototype.set()` memcpy plus a head/filled copy — `O(capacity)`
97
+ * with a small constant, not an element loop. `state.array`'s two-ring tick
98
+ * discipline (`packages/runtime/src/state/arrayStateSlot.ts`) calls this every
99
+ * tick to roll the tentative ring back to committed (and on close to commit it),
100
+ * so the typed-array `set()` is load-bearing for the hot path. Both rings in a
101
+ * slot share `capacity`, so this never reshapes the backing array.
102
+ *
103
+ * @since 1.3
104
+ * @stable
105
+ * @example
106
+ * const a = new Float64RingBuffer(4);
107
+ * const b = new Float64RingBuffer(4);
108
+ * a.append(1);
109
+ * b.copyFrom(a);
110
+ * b.at(0); // 1
111
+ */
112
+ copyFrom(other: Float64RingBuffer): void;
94
113
  }
95
114
  //# sourceMappingURL=ringBuffer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ringBuffer.d.ts","sourceRoot":"","sources":["../src/ringBuffer.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACnB,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAC7B,KAAK,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAU,CAAC,CAAC,CAAE,YAAW,cAAc,CAAC,CAAC,CAAC;aAKvB,QAAQ,EAAE,MAAM;IAJ5C,OAAO,CAAC,GAAG,CAAuB;IAClC,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,MAAM,CAAK;gBAES,QAAQ,EAAE,MAAM;IAI5C,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI;IAMlB,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI;IAQvB,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAK5B,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,KAAK,IAAI,IAAI;CAKhB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,iBAAkB,YAAW,cAAc,CAAC,MAAM,CAAC;aAKhC,QAAQ,EAAE,MAAM;IAJ5C,OAAO,CAAC,GAAG,CAAe;IAC1B,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,MAAM,CAAK;gBAES,QAAQ,EAAE,MAAM;IAI5C,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAMvB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ5B,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAKrB,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,uBAAuB,IAAI,QAAQ,CAAC;QAChC,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;KACxC,CAAC;IAYF,yBAAyB,CACrB,IAAI,EAAE,QAAQ,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;KACxC,CAAC,GACH,IAAI;IAwBP,KAAK,IAAI,IAAI;CAKhB"}
1
+ {"version":3,"file":"ringBuffer.d.ts","sourceRoot":"","sources":["../src/ringBuffer.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACnB,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;IAC7B,KAAK,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAU,CAAC,CAAC,CAAE,YAAW,cAAc,CAAC,CAAC,CAAC;aAKvB,QAAQ,EAAE,MAAM;IAJ5C,OAAO,CAAC,GAAG,CAAuB;IAClC,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,MAAM,CAAK;gBAES,QAAQ,EAAE,MAAM;IAI5C,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI;IAMlB,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI;IAQvB,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAK5B,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,KAAK,IAAI,IAAI;CAKhB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,iBAAkB,YAAW,cAAc,CAAC,MAAM,CAAC;aAKhC,QAAQ,EAAE,MAAM;IAJ5C,OAAO,CAAC,GAAG,CAAe;IAC1B,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,MAAM,CAAK;gBAES,QAAQ,EAAE,MAAM;IAI5C,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAMvB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ5B,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAKrB,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,uBAAuB,IAAI,QAAQ,CAAC;QAChC,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;KACxC,CAAC;IAYF,yBAAyB,CACrB,IAAI,EAAE,QAAQ,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;KACxC,CAAC,GACH,IAAI;IAwBP,KAAK,IAAI,IAAI;IAMb;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;CAK3C"}
@@ -142,5 +142,28 @@ export class Float64RingBuffer {
142
142
  this.head = -1;
143
143
  this.filled = 0;
144
144
  }
145
+ /**
146
+ * Overwrite this ring's entire state with a copy of `other`'s. A single
147
+ * `Float64Array.prototype.set()` memcpy plus a head/filled copy — `O(capacity)`
148
+ * with a small constant, not an element loop. `state.array`'s two-ring tick
149
+ * discipline (`packages/runtime/src/state/arrayStateSlot.ts`) calls this every
150
+ * tick to roll the tentative ring back to committed (and on close to commit it),
151
+ * so the typed-array `set()` is load-bearing for the hot path. Both rings in a
152
+ * slot share `capacity`, so this never reshapes the backing array.
153
+ *
154
+ * @since 1.3
155
+ * @stable
156
+ * @example
157
+ * const a = new Float64RingBuffer(4);
158
+ * const b = new Float64RingBuffer(4);
159
+ * a.append(1);
160
+ * b.copyFrom(a);
161
+ * b.at(0); // 1
162
+ */
163
+ copyFrom(other) {
164
+ this.buf.set(other.buf);
165
+ this.head = other.head;
166
+ this.filled = other.filled;
167
+ }
145
168
  }
146
169
  //# sourceMappingURL=ringBuffer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ringBuffer.js","sourceRoot":"","sources":["../src/ringBuffer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\n/**\n * Shared contract for the two ring-buffer flavours the runtime ships\n * (`RingBuffer<T>` for object payloads, `Float64RingBuffer` for numeric\n * payloads). Both share one read contract — `at(n)` returns `undefined` on\n * out-of-range reads in the generic shape; `Float64RingBuffer` narrows\n * the return to `number` with `NaN` as the OOR sentinel.\n *\n * @since 0.1\n * @example\n * const buf: RingBufferLike<number> = new Float64RingBuffer(8);\n * buf.append(42);\n * buf.at(0); // 42\n */\nexport interface RingBufferLike<T> {\n readonly capacity: number;\n readonly length: number;\n append(v: T): void;\n replaceHead(v: T): void;\n at(n: number): T | undefined;\n reset(): void;\n}\n\n/**\n * Generic ring buffer over an `Array<T>`. Backs object-valued\n * `Series<T>` (e.g. Phase-3 drawing handles). For numeric series use\n * `Float64RingBuffer` — it avoids the array-pointer indirection on\n * every read.\n *\n * Out-of-range `at(n)` returns `undefined`. `replaceHead` on an empty\n * buffer behaves like `append` so the first call after construction\n * does not need a special-case branch in callers.\n *\n * @since 0.1\n * @example\n * const buf = new RingBuffer<string>(3);\n * buf.append(\"a\");\n * buf.append(\"b\");\n * buf.append(\"c\");\n * buf.append(\"d\"); // overwrites \"a\"\n * buf.at(0); // \"d\"\n * buf.at(2); // \"b\"\n */\nexport class RingBuffer<T> implements RingBufferLike<T> {\n private buf: Array<T | undefined>;\n private head = -1;\n private filled = 0;\n\n constructor(public readonly capacity: number) {\n this.buf = new Array<T | undefined>(capacity);\n }\n\n append(v: T): void {\n this.head = (this.head + 1) % this.capacity;\n this.buf[this.head] = v;\n if (this.filled < this.capacity) this.filled += 1;\n }\n\n replaceHead(v: T): void {\n if (this.head === -1) {\n this.append(v);\n return;\n }\n this.buf[this.head] = v;\n }\n\n at(n: number): T | undefined {\n if (n < 0 || n >= this.filled) return undefined;\n return this.buf[(this.head - n + this.capacity) % this.capacity];\n }\n\n get length(): number {\n return this.filled;\n }\n\n reset(): void {\n this.buf = new Array<T | undefined>(this.capacity);\n this.head = -1;\n this.filled = 0;\n }\n}\n\n/**\n * Numeric ring buffer backed by a `Float64Array`. Reads are direct\n * memory hits — no boxing, no map lookup. Out-of-range reads return\n * `NaN` (the language-wide warmup sentinel), which\n * is the correct value for unwarmed indicator slots.\n *\n * `at(n)` narrows the shared `RingBufferLike<T>`'s `T | undefined`\n * return to plain `number` in a covariant return position; callers\n * that hold this concrete class see `number`, callers that hold\n * the wider interface see `number | undefined`.\n *\n * @since 0.1\n * @example\n * const buf = new Float64RingBuffer(4);\n * buf.append(1.0);\n * buf.append(2.0);\n * buf.at(0); // 2\n * buf.at(5); // NaN\n */\nexport class Float64RingBuffer implements RingBufferLike<number> {\n private buf: Float64Array;\n private head = -1;\n private filled = 0;\n\n constructor(public readonly capacity: number) {\n this.buf = new Float64Array(capacity);\n }\n\n append(v: number): void {\n this.head = (this.head + 1) % this.capacity;\n this.buf[this.head] = v;\n if (this.filled < this.capacity) this.filled += 1;\n }\n\n replaceHead(v: number): void {\n if (this.head === -1) {\n this.append(v);\n return;\n }\n this.buf[this.head] = v;\n }\n\n at(n: number): number {\n if (n < 0 || n >= this.filled) return Number.NaN;\n return this.buf[(this.head - n + this.capacity) % this.capacity];\n }\n\n get length(): number {\n return this.filled;\n }\n\n serialiseSnapshotBuffer(): Readonly<{\n headIndex: number;\n filled: number;\n values: ReadonlyArray<number | null>;\n }> {\n const values: Array<number | null> = [];\n for (const value of this.buf) {\n values.push(Number.isNaN(value) ? null : value);\n }\n return Object.freeze({\n headIndex: this.head,\n filled: this.filled,\n values: Object.freeze(values),\n });\n }\n\n restoreFromSnapshotBuffer(\n args: Readonly<{\n headIndex: number;\n filled: number;\n values: ReadonlyArray<number | null>;\n }>,\n ): void {\n if (\n args.values.length !== this.capacity ||\n !Number.isInteger(args.headIndex) ||\n args.headIndex < -1 ||\n args.headIndex >= this.capacity ||\n !Number.isInteger(args.filled) ||\n args.filled < 0 ||\n args.filled > this.capacity ||\n (args.filled === 0 && args.headIndex !== -1) ||\n (args.filled > 0 && args.headIndex < 0)\n ) {\n throw new Error(\"invalid ring buffer snapshot\");\n }\n const next = new Float64Array(this.capacity);\n for (let i = 0; i < args.values.length; i += 1) {\n const value = args.values[i];\n next[i] = value === null ? Number.NaN : value;\n }\n this.buf = next;\n this.head = args.headIndex;\n this.filled = args.filled;\n }\n\n reset(): void {\n this.buf = new Float64Array(this.capacity);\n this.head = -1;\n this.filled = 0;\n }\n}\n"]}
1
+ {"version":3,"file":"ringBuffer.js","sourceRoot":"","sources":["../src/ringBuffer.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\n/**\n * Shared contract for the two ring-buffer flavours the runtime ships\n * (`RingBuffer<T>` for object payloads, `Float64RingBuffer` for numeric\n * payloads). Both share one read contract — `at(n)` returns `undefined` on\n * out-of-range reads in the generic shape; `Float64RingBuffer` narrows\n * the return to `number` with `NaN` as the OOR sentinel.\n *\n * @since 0.1\n * @example\n * const buf: RingBufferLike<number> = new Float64RingBuffer(8);\n * buf.append(42);\n * buf.at(0); // 42\n */\nexport interface RingBufferLike<T> {\n readonly capacity: number;\n readonly length: number;\n append(v: T): void;\n replaceHead(v: T): void;\n at(n: number): T | undefined;\n reset(): void;\n}\n\n/**\n * Generic ring buffer over an `Array<T>`. Backs object-valued\n * `Series<T>` (e.g. Phase-3 drawing handles). For numeric series use\n * `Float64RingBuffer` — it avoids the array-pointer indirection on\n * every read.\n *\n * Out-of-range `at(n)` returns `undefined`. `replaceHead` on an empty\n * buffer behaves like `append` so the first call after construction\n * does not need a special-case branch in callers.\n *\n * @since 0.1\n * @example\n * const buf = new RingBuffer<string>(3);\n * buf.append(\"a\");\n * buf.append(\"b\");\n * buf.append(\"c\");\n * buf.append(\"d\"); // overwrites \"a\"\n * buf.at(0); // \"d\"\n * buf.at(2); // \"b\"\n */\nexport class RingBuffer<T> implements RingBufferLike<T> {\n private buf: Array<T | undefined>;\n private head = -1;\n private filled = 0;\n\n constructor(public readonly capacity: number) {\n this.buf = new Array<T | undefined>(capacity);\n }\n\n append(v: T): void {\n this.head = (this.head + 1) % this.capacity;\n this.buf[this.head] = v;\n if (this.filled < this.capacity) this.filled += 1;\n }\n\n replaceHead(v: T): void {\n if (this.head === -1) {\n this.append(v);\n return;\n }\n this.buf[this.head] = v;\n }\n\n at(n: number): T | undefined {\n if (n < 0 || n >= this.filled) return undefined;\n return this.buf[(this.head - n + this.capacity) % this.capacity];\n }\n\n get length(): number {\n return this.filled;\n }\n\n reset(): void {\n this.buf = new Array<T | undefined>(this.capacity);\n this.head = -1;\n this.filled = 0;\n }\n}\n\n/**\n * Numeric ring buffer backed by a `Float64Array`. Reads are direct\n * memory hits — no boxing, no map lookup. Out-of-range reads return\n * `NaN` (the language-wide warmup sentinel), which\n * is the correct value for unwarmed indicator slots.\n *\n * `at(n)` narrows the shared `RingBufferLike<T>`'s `T | undefined`\n * return to plain `number` in a covariant return position; callers\n * that hold this concrete class see `number`, callers that hold\n * the wider interface see `number | undefined`.\n *\n * @since 0.1\n * @example\n * const buf = new Float64RingBuffer(4);\n * buf.append(1.0);\n * buf.append(2.0);\n * buf.at(0); // 2\n * buf.at(5); // NaN\n */\nexport class Float64RingBuffer implements RingBufferLike<number> {\n private buf: Float64Array;\n private head = -1;\n private filled = 0;\n\n constructor(public readonly capacity: number) {\n this.buf = new Float64Array(capacity);\n }\n\n append(v: number): void {\n this.head = (this.head + 1) % this.capacity;\n this.buf[this.head] = v;\n if (this.filled < this.capacity) this.filled += 1;\n }\n\n replaceHead(v: number): void {\n if (this.head === -1) {\n this.append(v);\n return;\n }\n this.buf[this.head] = v;\n }\n\n at(n: number): number {\n if (n < 0 || n >= this.filled) return Number.NaN;\n return this.buf[(this.head - n + this.capacity) % this.capacity];\n }\n\n get length(): number {\n return this.filled;\n }\n\n serialiseSnapshotBuffer(): Readonly<{\n headIndex: number;\n filled: number;\n values: ReadonlyArray<number | null>;\n }> {\n const values: Array<number | null> = [];\n for (const value of this.buf) {\n values.push(Number.isNaN(value) ? null : value);\n }\n return Object.freeze({\n headIndex: this.head,\n filled: this.filled,\n values: Object.freeze(values),\n });\n }\n\n restoreFromSnapshotBuffer(\n args: Readonly<{\n headIndex: number;\n filled: number;\n values: ReadonlyArray<number | null>;\n }>,\n ): void {\n if (\n args.values.length !== this.capacity ||\n !Number.isInteger(args.headIndex) ||\n args.headIndex < -1 ||\n args.headIndex >= this.capacity ||\n !Number.isInteger(args.filled) ||\n args.filled < 0 ||\n args.filled > this.capacity ||\n (args.filled === 0 && args.headIndex !== -1) ||\n (args.filled > 0 && args.headIndex < 0)\n ) {\n throw new Error(\"invalid ring buffer snapshot\");\n }\n const next = new Float64Array(this.capacity);\n for (let i = 0; i < args.values.length; i += 1) {\n const value = args.values[i];\n next[i] = value === null ? Number.NaN : value;\n }\n this.buf = next;\n this.head = args.headIndex;\n this.filled = args.filled;\n }\n\n reset(): void {\n this.buf = new Float64Array(this.capacity);\n this.head = -1;\n this.filled = 0;\n }\n\n /**\n * Overwrite this ring's entire state with a copy of `other`'s. A single\n * `Float64Array.prototype.set()` memcpy plus a head/filled copy — `O(capacity)`\n * with a small constant, not an element loop. `state.array`'s two-ring tick\n * discipline (`packages/runtime/src/state/arrayStateSlot.ts`) calls this every\n * tick to roll the tentative ring back to committed (and on close to commit it),\n * so the typed-array `set()` is load-bearing for the hot path. Both rings in a\n * slot share `capacity`, so this never reshapes the backing array.\n *\n * @since 1.3\n * @stable\n * @example\n * const a = new Float64RingBuffer(4);\n * const b = new Float64RingBuffer(4);\n * a.append(1);\n * b.copyFrom(a);\n * b.at(0); // 1\n */\n copyFrom(other: Float64RingBuffer): void {\n this.buf.set(other.buf);\n this.head = other.head;\n this.filled = other.filled;\n }\n}\n"]}
@@ -2,6 +2,9 @@ import type { AlertConditionEmission, AlertEmission, Capabilities, DrawingEmissi
2
2
  import type { AlertConditionDefinition, Bar, DrawingBucket, DrawingCounts, DrawingKind, DrawingState, SecurityBar, Series } from "@invinite-org/chartlang-core";
3
3
  import type { DepOutputStore } from "./dep/DepOutputStore.js";
4
4
  import type { PersistentStateStore } from "./persistentStateStore.js";
5
+ import type { SecurityExprRunner } from "./request/securityExprRunner.js";
6
+ import type { ArrayStateSlot } from "./state/arrayStateSlot.js";
7
+ import type { SeriesSlot } from "./state/seriesSlot.js";
5
8
  import type { StateSlot } from "./state/stateSlot.js";
6
9
  import type { StateStore } from "./stateStore.js";
7
10
  import type { StreamState } from "./streamState.js";
@@ -14,6 +17,15 @@ import type { RuntimeViews } from "./views/index.js";
14
17
  * it and re-emit the full payload. `removed: true`
15
18
  * is sticky — further `update` / `remove` on the handle no-op.
16
19
  *
20
+ * `z` is the presentation-only render-order key `handle.ts`'s `splitZ`
21
+ * lifted out of the drawing's `state.style` (default `0`). It is stored
22
+ * **beside** `state` — never inside `state` / `state.style` — because
23
+ * the wire carries it as the top-level {@link DrawingEmission.z} field,
24
+ * not as part of {@link DrawingState}. It persists across bars; an
25
+ * `update` that does not re-specify a non-zero `z` retains it, a
26
+ * re-specified non-zero `z` overrides, and a cross-bar re-entry
27
+ * re-specifies it from the new call.
28
+ *
17
29
  * @since 0.3
18
30
  * @stable
19
31
  * @example
@@ -21,6 +33,7 @@ import type { RuntimeViews } from "./views/index.js";
21
33
  * // handleId: "x.chart.ts:1:1#0",
22
34
  * // kind: "line",
23
35
  * // state: { kind: "line", anchors: [...], style: {} },
36
+ * // z: 0,
24
37
  * // removed: false,
25
38
  * // };
26
39
  */
@@ -28,6 +41,7 @@ export type DrawingSlot = {
28
41
  readonly handleId: string;
29
42
  readonly kind: DrawingKind;
30
43
  state: DrawingState;
44
+ z: number;
31
45
  removed: boolean;
32
46
  };
33
47
  /**
@@ -139,20 +153,55 @@ export type RuntimeContext = {
139
153
  */
140
154
  readonly stateSlots: Map<string, StateSlot<unknown>>;
141
155
  /**
142
- * Secondary candle streams keyed by `IntervalDescriptor.value`.
143
- * Mutated only by `createScriptRunner` mount/restore/routing. @since 0.5
156
+ * Runtime `state.series` slot store keyed by
157
+ * `${slotIdPrefix ?? ""}${slotId}:series`. Each holds a history ring +
158
+ * the identity-stable script-facing view + the last committed head.
159
+ * The ring advances once per close (script-invisible lockstep), so
160
+ * `s[1]` is always one committed bar back. Cleared on `dispose` after
161
+ * the final snapshot captures it. @since 0.9
162
+ */
163
+ readonly seriesSlots: Map<string, SeriesSlot>;
164
+ /**
165
+ * Runtime `state.array` slot store keyed by
166
+ * `${slotIdPrefix ?? ""}${slotId}:array`. Each holds two
167
+ * `Float64RingBuffer`s (committed + tentative) behind an identity-stable
168
+ * bounded-FIFO handle. A parallel map (vs folding into `stateSlots`)
169
+ * mirrors the `state.series` precedent — both collection primitives share
170
+ * the two-ring shape and snapshot directly from the live map with no
171
+ * `StateStore` flush. Cleared on `dispose`. @since 1.3
172
+ */
173
+ readonly arraySlots: Map<string, ArrayStateSlot>;
174
+ /**
175
+ * The chart's own symbol, resolved once at mount from the adapter
176
+ * `syminfo.ticker` (`""` when the adapter supplies none). A
177
+ * `request.security` call that omits `symbol` — or passes this exact
178
+ * ticker — resolves to it and collapses to the bare-interval
179
+ * {@link feedKey}, so the chart-symbol path is byte-identical to the
180
+ * pre-multi-symbol baseline. Only a *different* symbol allocates a
181
+ * `"<symbol>@<interval>"` feed. @since 1.3
182
+ */
183
+ readonly chartSymbol: string;
184
+ /**
185
+ * Secondary candle streams keyed by the composite
186
+ * `feedKey(symbol, interval)` (the shared core helper). A symbol-omitted
187
+ * feed collapses to the bare interval — `feedKey(undefined, "1D") === "1D"`
188
+ * — so the chart-symbol path is byte-identical to the pre-multi-symbol
189
+ * baseline; a non-chart symbol keys as `"<symbol>@<interval>"`. Mutated only
190
+ * by `createScriptRunner` mount/restore/routing. @since 0.5
144
191
  */
145
192
  readonly secondaryStreams: Map<string, StreamState>;
146
193
  /**
147
- * Per-`request.security` slot cache keyed by `slotId|interval`. Phase 4
194
+ * Per-`request.security` slot cache keyed by `slotId|feedKey`. Phase 4
148
195
  * stores NaN fallback bars here; Phase 5 replaces the value producer with
149
- * aligned secondary stream series while preserving stable identity.
196
+ * aligned secondary stream series while preserving stable identity. The
197
+ * `feedKey` collapses to the bare interval for chart-symbol requests, so
198
+ * the omitted-symbol cache key is byte-identical to the baseline.
150
199
  * @since 0.4
151
200
  */
152
201
  readonly requestSecurityBars: Map<string, SecurityBar>;
153
202
  /**
154
203
  * Per-compute aligned numeric arrays keyed by
155
- * `slotId|interval|sourceKey`. Cleared on main-stream close/tick before
204
+ * `slotId|feedKey|sourceKey`. Cleared on main-stream close/tick before
156
205
  * `compute` so `request.security` re-aligns against the latest
157
206
  * secondary buffers. @since 0.5
158
207
  */
@@ -167,6 +216,34 @@ export type RuntimeContext = {
167
216
  * {@link requestSecurityAlignments}. @since 0.5
168
217
  */
169
218
  readonly requestSecurityAscendingBars: Map<StreamState, ReadonlyArray<Bar>>;
219
+ /**
220
+ * Mounted HTF expression runners keyed by `slotId`. One entry per
221
+ * `manifest.securityExpressions` callsite. `request.security(slotId,
222
+ * opts, expr)` dispatches the expression overload off this registry
223
+ * (rather than `expr !== undefined`) and captures the callback here.
224
+ * Absent on dep / sibling contexts and single-timeframe scripts.
225
+ * Cleared on `dispose`. @since 0.7
226
+ */
227
+ securityExprRunners?: Map<string, SecurityExprRunner>;
228
+ /**
229
+ * Per-feed index into {@link securityExprRunners}, keyed by the composite
230
+ * `feedKey(symbol, interval)`. `driveSecurityExpressions` fans a secondary
231
+ * close / tick (tagged with that same composite key on
232
+ * `CandleEvent.streamKey`) out to every runner on that feed. A
233
+ * symbol-omitted callsite collapses to the bare interval, byte-identical to
234
+ * the pre-multi-symbol baseline. Absent when no expression callsites are
235
+ * declared. Cleared on `dispose`. @since 0.7
236
+ */
237
+ securityExprRunnersByFeed?: ReadonlyMap<string, ReadonlyArray<SecurityExprRunner>>;
238
+ /**
239
+ * Per-compute aligned expression-output series cache keyed by
240
+ * `slotId|feedKey`. Holds the stable `Series<number>` Proxy each
241
+ * expression-form `request.security` returns; cleared each bar
242
+ * (alongside {@link requestSecurityAlignments}) so the proxy re-aligns
243
+ * the runner's output buffer against the latest secondary buffers.
244
+ * @since 0.7
245
+ */
246
+ requestSecurityExprSeries?: Map<string, Series<number>>;
170
247
  /**
171
248
  * Per-`request.lowerTf` slot cache keyed by `slotId|interval`. Values are
172
249
  * stable `Series<ReadonlyArray<Bar>>` proxies over the latest LTF bucket
@@ -178,6 +255,14 @@ export type RuntimeContext = {
178
255
  * `code|slotId|interval|kind`. Cleared on `dispose`. @since 0.4
179
256
  */
180
257
  readonly diagnosedRequestKeys: Set<string>;
258
+ /**
259
+ * Runtime diagnostic dedupe for `time.*` / `session.*` DST-zone
260
+ * fallbacks, keyed by `tz-dst-unsupported|<tz>`. The calendar accessors
261
+ * are `slot: false` (no slotId to key on), so they dedupe on the
262
+ * timezone string here — a DST zone warns at most once per distinct tz
263
+ * per mount. Cleared on `dispose`. @since 1.5
264
+ */
265
+ readonly diagnosedTzKeys: Set<string>;
181
266
  /**
182
267
  * Manifest-declared alert conditions keyed by condition id. Used by
183
268
  * `signal(conditionId, fired)` to reject unknown ids without
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeContext.d.ts","sourceRoot":"","sources":["../src/runtimeContext.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtimeContext.d.ts","sourceRoot":"","sources":["../src/runtimeContext.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeContext.js","sourceRoot":"","sources":["../src/runtimeContext.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AA2S/D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAuC;IACtE,OAAO,EAAE,IAAI;CAChB,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type {\n AlertConditionEmission,\n AlertEmission,\n Capabilities,\n DrawingEmission,\n LogEmission,\n PlotEmission,\n PlotOverride,\n RuntimeDiagnostic,\n} from \"@invinite-org/chartlang-adapter-kit\";\nimport type {\n AlertConditionDefinition,\n Bar,\n DrawingBucket,\n DrawingCounts,\n DrawingKind,\n DrawingState,\n SecurityBar,\n Series,\n} from \"@invinite-org/chartlang-core\";\n\nimport type { DepOutputStore } from \"./dep/DepOutputStore.js\";\nimport type { PersistentStateStore } from \"./persistentStateStore.js\";\nimport type { StateSlot } from \"./state/stateSlot.js\";\nimport type { StateStore } from \"./stateStore.js\";\nimport type { StreamState } from \"./streamState.js\";\nimport type { RuntimeViews } from \"./views/index.js\";\n\n/**\n * Per-handle drawing slot the runtime persists across bars. The key is\n * `slotId#subId` (compiler-injected callsite id + per-bar sub-id from\n * {@link nextSubId}). `state` holds the last full {@link DrawingState}\n * emitted for the handle; subsequent `update(patch)` calls merge into\n * it and re-emit the full payload. `removed: true`\n * is sticky — further `update` / `remove` on the handle no-op.\n *\n * @since 0.3\n * @stable\n * @example\n * // const slot: DrawingSlot = {\n * // handleId: \"x.chart.ts:1:1#0\",\n * // kind: \"line\",\n * // state: { kind: \"line\", anchors: [...], style: {} },\n * // removed: false,\n * // };\n */\nexport type DrawingSlot = {\n readonly handleId: string;\n readonly kind: DrawingKind;\n state: DrawingState;\n removed: boolean;\n};\n\n/**\n * Mutable counterpart of `RunnerEmissions` (from adapter-kit) that the\n * runtime accumulates into per bar. Task 6's execution loop pushes\n * here during `compute`; `drain()` snapshots into the readonly\n * `RunnerEmissions` shape the adapter receives.\n *\n * @since 0.1\n * @example\n * // const emissions: MutableRunnerEmissions = {\n * // plots: [],\n * // drawings: [],\n * // alerts: [],\n * // diagnostics: [],\n * // fromBar: 0,\n * // toBar: 0,\n * // };\n */\nexport type MutableRunnerEmissions = {\n plots: PlotEmission[];\n drawings: DrawingEmission[];\n alerts: AlertEmission[];\n alertConditions?: AlertConditionEmission[];\n logs: LogEmission[];\n diagnostics: RuntimeDiagnostic[];\n fromBar: number;\n toBar: number;\n};\n\n/**\n * The contract Task 6's execution loop hands to stateful primitives\n * (Tasks 7-8) inside a single `compute` step. Tasks 7-8 read this\n * through {@link ACTIVE_RUNTIME_CONTEXT} — the runtime sets `.current`\n * around `compute` in a `try/finally`, so primitives can find their\n * series, slot store, capability bag, emission destination, and bar\n * index without an explicit argument.\n *\n * `isTick` discriminates `onBarTick` calls (head-replace mode) from\n * `onBarClose` / `onHistory` (append mode). Stateful primitives in\n * Task 7 use it to swap append vs replace-head behaviour.\n *\n * `stateSlots` stores Phase-4 `state.*` / `state.tick.*` slots keyed by\n * `${slotId}:state`; values flush into `stateStore` at close/dispose.\n *\n * `views` is a mutable container whose fields are replaced with fresh frozen\n * `barstate.*`, `syminfo.*`, and `timeframe.*` snapshots as the runner\n * advances.\n *\n * `resolvedInputs` is the frozen bag handed to `compute({ inputs })`,\n * resolved once at mount from manifest defaults plus adapter overrides.\n *\n * @since 0.1\n * @example\n * // const ctx: RuntimeContext = {\n * // stream, stateStore, capabilities, emissions,\n * // barIndex: () => 0,\n * // isTick: false,\n * // };\n */\nexport type RuntimeContext = {\n readonly stream: StreamState;\n readonly stateStore: StateStore;\n readonly persistentStateStore?: PersistentStateStore;\n lastPersistTime: number;\n readonly capabilities: Capabilities;\n readonly emissions: MutableRunnerEmissions;\n readonly barIndex: () => number;\n isTick: boolean;\n /**\n * Per-handle drawing slot store keyed by `slotId#subId`. Allocated\n * on first `op: \"create\"`; mutated by `update(patch)` to merge the\n * patch into the slot's `state`; flagged `removed: true` on\n * `remove()`. Cleared on `dispose`. Persists across bars.\n * @since 0.3\n */\n readonly drawingSlots: Map<string, DrawingSlot>;\n /**\n * Per-callsite per-bar sub-id counter. Each `draw.<kind>(...)` call\n * inside a bar reads `nextSubId(ctx, slotId)`; the counter resets\n * at the top of each `onBarClose` / `onBarTick` so iteration `i` at\n * the same callsite yields the same `slotId#i` across bars.\n * Cleared on `dispose`. @since 0.3\n */\n readonly drawingSubIdCounters: Map<string, number>;\n /**\n * Live per-bucket allocation tally for the current script. Each\n * `op: \"create\"` increments the relevant bucket; each\n * `op: \"remove\"` decrements (clamped at 0). `op: \"update\"` is\n * free. `pushDrawing` drops the emission with\n * `drawing-budget-exceeded` once a bucket hits its effective\n * budget (min of adapter cap + `scriptMaxDrawings`). Reset to\n * zero on `dispose`. @since 0.3\n */\n readonly drawingBucketCounters: Record<DrawingBucket, number>;\n /**\n * The script's per-bucket cap from `defineIndicator({ maxDrawings:\n * ... })` / `defineDrawing({ maxDrawings: ... })`. `null` when\n * omitted — `pushDrawing` then enforces the adapter cap alone.\n * Effective budget is `min(scriptMaxDrawings[b],\n * capabilities.maxDrawingsPerScript[b])`. @since 0.3\n */\n readonly scriptMaxDrawings: DrawingCounts | null;\n /**\n * Runtime `state.*` / `state.tick.*` slot store keyed by\n * `${slotIdPrefix ?? \"\"}${slotId}:state`. Non-tick slots keep\n * committed/tentative values; tick slots commit writes immediately.\n * Cleared on `dispose` after flushing snapshots to `stateStore`.\n * @since 0.4\n */\n readonly stateSlots: Map<string, StateSlot<unknown>>;\n /**\n * Secondary candle streams keyed by `IntervalDescriptor.value`.\n * Mutated only by `createScriptRunner` mount/restore/routing. @since 0.5\n */\n readonly secondaryStreams: Map<string, StreamState>;\n /**\n * Per-`request.security` slot cache keyed by `slotId|interval`. Phase 4\n * stores NaN fallback bars here; Phase 5 replaces the value producer with\n * aligned secondary stream series while preserving stable identity.\n * @since 0.4\n */\n readonly requestSecurityBars: Map<string, SecurityBar>;\n /**\n * Per-compute aligned numeric arrays keyed by\n * `slotId|interval|sourceKey`. Cleared on main-stream close/tick before\n * `compute` so `request.security` re-aligns against the latest\n * secondary buffers. @since 0.5\n */\n readonly requestSecurityAlignments: Map<string, ReadonlyArray<number>>;\n /**\n * Per-compute cache of ascending `Bar[]` materialisations keyed by the\n * source `StreamState`. Shared by `request.security` and `request.lowerTf`\n * (via `request/streamBars.ts:ascendingBarsFor`) so a stable bar-array\n * identity is reused across every consumer in a bar — the `getOrAlign` /\n * `getOrBucket` WeakMap caches actually hit and the same ring buffer is\n * walked once per bar instead of 10×. Cleared alongside\n * {@link requestSecurityAlignments}. @since 0.5\n */\n readonly requestSecurityAscendingBars: Map<StreamState, ReadonlyArray<Bar>>;\n /**\n * Per-`request.lowerTf` slot cache keyed by `slotId|interval`. Values are\n * stable `Series<ReadonlyArray<Bar>>` proxies over the latest LTF bucket\n * materialisation. @since 0.6\n */\n readonly requestLowerTfViews: Map<string, Series<ReadonlyArray<Bar>>>;\n /**\n * Runtime diagnostic dedupe for `request.*` capability gates, keyed by\n * `code|slotId|interval|kind`. Cleared on `dispose`. @since 0.4\n */\n readonly diagnosedRequestKeys: Set<string>;\n /**\n * Manifest-declared alert conditions keyed by condition id. Used by\n * `signal(conditionId, fired)` to reject unknown ids without\n * re-reading the manifest each bar. @since 0.5\n */\n readonly alertConditions?: ReadonlyMap<string, AlertConditionDefinition>;\n /**\n * Dedupe for alert-condition capability/unknown-id diagnostics, keyed\n * by `code|conditionId`. Cleared on dispose. @since 0.5\n */\n readonly diagnosedAlertConditionKeys?: Set<string>;\n /**\n * Number of `runtime.log.*` emissions accepted in the active compute\n * step. Reset at the start of each close/tick. @since 0.5\n */\n logBudget: number;\n /**\n * Per-step dedupe flag for `runtime-log-budget-exceeded`. Reset with\n * `logBudget` at the start of each close/tick. @since 0.5\n */\n logBudgetExceededDiagnosed: boolean;\n /**\n * Frozen effective input values keyed by script input name. Resolved once\n * at mount and reused by every compute step. @since 0.4\n */\n resolvedInputs: Readonly<Record<string, unknown>>;\n /**\n * Mount-time script pane default. The runner sets it from\n * `manifest.overlay`:\n * - `overlay` absent / `true` → `\"overlay\"`.\n * - `overlay === false` → `\"script:<sanitised(manifest.name)>\"`.\n * `resolvePane` reads this value when a `plot()` / `hline()` call\n * has no explicit `pane` opt.\n * @since 0.2\n */\n readonly defaultPane: string;\n /**\n * Stable non-overlay pane key for this script. Explicit\n * `pane: \"new\"` resolves here even when `defaultPane === \"overlay\"`\n * so every `\"new\"` plot in a script joins one script-owned subpane.\n * @since 0.2\n */\n readonly scriptPane: string;\n /**\n * Host-supplied per-slot presentation overrides, keyed by\n * `PlotEmission.slotId`. Applied at emit time by `applyPlotOverride`.\n * Mutable — `setPlotOverrides` swaps it live (presentation-only, so\n * it does not break the frozen-input determinism guarantee). Entries\n * themselves are frozen. @since 0.8\n */\n plotOverrides: Readonly<Record<string, PlotOverride>>;\n /**\n * Runtime diagnostic dedupe for mount-time input override failures,\n * keyed by manifest input key. Cleared on `dispose`. @since 0.4\n */\n readonly diagnosedInputKeys: Set<string>;\n /**\n * Runtime `barstate.*`, `syminfo.*`, and `timeframe.*` views. The\n * container is mutable; each assigned view snapshot is frozen.\n * @since 0.4\n */\n readonly views: RuntimeViews;\n /**\n * Prefix prepended when emissions from this context flow into the\n * parent runner's queues, and mirrored into every `stateSlots` /\n * `StateStore` key written by `state.*` / `state.tick.*` so each\n * runner's persisted state is isolated. `\"dep:<localId>/\"` for\n * private dep runners, `\"export:<exportName>/\"` for sibling\n * runners, and `\"\"` (or absent) for primary single-script and\n * bundle-primary runners.\n *\n * @since 0.7\n */\n slotIdPrefix?: string;\n /**\n * `true` when this context belongs to a private dep runner — its\n * emissions are dropped (or captured into the dep output store) by\n * `applyDepEmissionPolicy`. `false` / absent for primary and\n * sibling runners.\n *\n * @since 0.7\n */\n isDep?: boolean;\n /**\n * Per-bar titled-output buffer shared by the primary and every\n * sibling of a `CompiledScriptBundle`. Populated by\n * `applyDepEmissionPolicy` after each dep/sibling's compute; read\n * by `__chartlang_depOutput` during the consumer's compute. `null`\n * / absent for single-script runners with no deps.\n *\n * @since 0.7\n */\n depOutputStore?: DepOutputStore | null;\n};\n\n/**\n * Process-wide context slot. Task 6's `createScriptRunner` mutates\n * `.current` inside `try { ... } finally { current = null }` around\n * every `compute` invocation; Tasks 7-8 read it inside primitive\n * implementations. JavaScript's single-threaded execution model\n * guarantees only one `compute` runs at a time, so this ambient\n * slot is safe.\n *\n * The export is intentionally just a holder — no class, no methods,\n * no validation. Responsibility for setting and clearing lives in\n * Task 6.\n *\n * @since 0.1\n * @example\n * // import { ACTIVE_RUNTIME_CONTEXT }\n * // from \"@invinite-org/chartlang-runtime\";\n * // ACTIVE_RUNTIME_CONTEXT.current; // null at module load\n */\nexport const ACTIVE_RUNTIME_CONTEXT: { current: RuntimeContext | null } = {\n current: null,\n};\n"]}
1
+ {"version":3,"file":"runtimeContext.js","sourceRoot":"","sources":["../src/runtimeContext.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAgY/D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAuC;IACtE,OAAO,EAAE,IAAI;CAChB,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type {\n AlertConditionEmission,\n AlertEmission,\n Capabilities,\n DrawingEmission,\n LogEmission,\n PlotEmission,\n PlotOverride,\n RuntimeDiagnostic,\n} from \"@invinite-org/chartlang-adapter-kit\";\nimport type {\n AlertConditionDefinition,\n Bar,\n DrawingBucket,\n DrawingCounts,\n DrawingKind,\n DrawingState,\n SecurityBar,\n Series,\n} from \"@invinite-org/chartlang-core\";\n\nimport type { DepOutputStore } from \"./dep/DepOutputStore.js\";\nimport type { PersistentStateStore } from \"./persistentStateStore.js\";\nimport type { SecurityExprRunner } from \"./request/securityExprRunner.js\";\nimport type { ArrayStateSlot } from \"./state/arrayStateSlot.js\";\nimport type { SeriesSlot } from \"./state/seriesSlot.js\";\nimport type { StateSlot } from \"./state/stateSlot.js\";\nimport type { StateStore } from \"./stateStore.js\";\nimport type { StreamState } from \"./streamState.js\";\nimport type { RuntimeViews } from \"./views/index.js\";\n\n/**\n * Per-handle drawing slot the runtime persists across bars. The key is\n * `slotId#subId` (compiler-injected callsite id + per-bar sub-id from\n * {@link nextSubId}). `state` holds the last full {@link DrawingState}\n * emitted for the handle; subsequent `update(patch)` calls merge into\n * it and re-emit the full payload. `removed: true`\n * is sticky — further `update` / `remove` on the handle no-op.\n *\n * `z` is the presentation-only render-order key `handle.ts`'s `splitZ`\n * lifted out of the drawing's `state.style` (default `0`). It is stored\n * **beside** `state` — never inside `state` / `state.style` — because\n * the wire carries it as the top-level {@link DrawingEmission.z} field,\n * not as part of {@link DrawingState}. It persists across bars; an\n * `update` that does not re-specify a non-zero `z` retains it, a\n * re-specified non-zero `z` overrides, and a cross-bar re-entry\n * re-specifies it from the new call.\n *\n * @since 0.3\n * @stable\n * @example\n * // const slot: DrawingSlot = {\n * // handleId: \"x.chart.ts:1:1#0\",\n * // kind: \"line\",\n * // state: { kind: \"line\", anchors: [...], style: {} },\n * // z: 0,\n * // removed: false,\n * // };\n */\nexport type DrawingSlot = {\n readonly handleId: string;\n readonly kind: DrawingKind;\n state: DrawingState;\n z: number;\n removed: boolean;\n};\n\n/**\n * Mutable counterpart of `RunnerEmissions` (from adapter-kit) that the\n * runtime accumulates into per bar. Task 6's execution loop pushes\n * here during `compute`; `drain()` snapshots into the readonly\n * `RunnerEmissions` shape the adapter receives.\n *\n * @since 0.1\n * @example\n * // const emissions: MutableRunnerEmissions = {\n * // plots: [],\n * // drawings: [],\n * // alerts: [],\n * // diagnostics: [],\n * // fromBar: 0,\n * // toBar: 0,\n * // };\n */\nexport type MutableRunnerEmissions = {\n plots: PlotEmission[];\n drawings: DrawingEmission[];\n alerts: AlertEmission[];\n alertConditions?: AlertConditionEmission[];\n logs: LogEmission[];\n diagnostics: RuntimeDiagnostic[];\n fromBar: number;\n toBar: number;\n};\n\n/**\n * The contract Task 6's execution loop hands to stateful primitives\n * (Tasks 7-8) inside a single `compute` step. Tasks 7-8 read this\n * through {@link ACTIVE_RUNTIME_CONTEXT} — the runtime sets `.current`\n * around `compute` in a `try/finally`, so primitives can find their\n * series, slot store, capability bag, emission destination, and bar\n * index without an explicit argument.\n *\n * `isTick` discriminates `onBarTick` calls (head-replace mode) from\n * `onBarClose` / `onHistory` (append mode). Stateful primitives in\n * Task 7 use it to swap append vs replace-head behaviour.\n *\n * `stateSlots` stores Phase-4 `state.*` / `state.tick.*` slots keyed by\n * `${slotId}:state`; values flush into `stateStore` at close/dispose.\n *\n * `views` is a mutable container whose fields are replaced with fresh frozen\n * `barstate.*`, `syminfo.*`, and `timeframe.*` snapshots as the runner\n * advances.\n *\n * `resolvedInputs` is the frozen bag handed to `compute({ inputs })`,\n * resolved once at mount from manifest defaults plus adapter overrides.\n *\n * @since 0.1\n * @example\n * // const ctx: RuntimeContext = {\n * // stream, stateStore, capabilities, emissions,\n * // barIndex: () => 0,\n * // isTick: false,\n * // };\n */\nexport type RuntimeContext = {\n readonly stream: StreamState;\n readonly stateStore: StateStore;\n readonly persistentStateStore?: PersistentStateStore;\n lastPersistTime: number;\n readonly capabilities: Capabilities;\n readonly emissions: MutableRunnerEmissions;\n readonly barIndex: () => number;\n isTick: boolean;\n /**\n * Per-handle drawing slot store keyed by `slotId#subId`. Allocated\n * on first `op: \"create\"`; mutated by `update(patch)` to merge the\n * patch into the slot's `state`; flagged `removed: true` on\n * `remove()`. Cleared on `dispose`. Persists across bars.\n * @since 0.3\n */\n readonly drawingSlots: Map<string, DrawingSlot>;\n /**\n * Per-callsite per-bar sub-id counter. Each `draw.<kind>(...)` call\n * inside a bar reads `nextSubId(ctx, slotId)`; the counter resets\n * at the top of each `onBarClose` / `onBarTick` so iteration `i` at\n * the same callsite yields the same `slotId#i` across bars.\n * Cleared on `dispose`. @since 0.3\n */\n readonly drawingSubIdCounters: Map<string, number>;\n /**\n * Live per-bucket allocation tally for the current script. Each\n * `op: \"create\"` increments the relevant bucket; each\n * `op: \"remove\"` decrements (clamped at 0). `op: \"update\"` is\n * free. `pushDrawing` drops the emission with\n * `drawing-budget-exceeded` once a bucket hits its effective\n * budget (min of adapter cap + `scriptMaxDrawings`). Reset to\n * zero on `dispose`. @since 0.3\n */\n readonly drawingBucketCounters: Record<DrawingBucket, number>;\n /**\n * The script's per-bucket cap from `defineIndicator({ maxDrawings:\n * ... })` / `defineDrawing({ maxDrawings: ... })`. `null` when\n * omitted — `pushDrawing` then enforces the adapter cap alone.\n * Effective budget is `min(scriptMaxDrawings[b],\n * capabilities.maxDrawingsPerScript[b])`. @since 0.3\n */\n readonly scriptMaxDrawings: DrawingCounts | null;\n /**\n * Runtime `state.*` / `state.tick.*` slot store keyed by\n * `${slotIdPrefix ?? \"\"}${slotId}:state`. Non-tick slots keep\n * committed/tentative values; tick slots commit writes immediately.\n * Cleared on `dispose` after flushing snapshots to `stateStore`.\n * @since 0.4\n */\n readonly stateSlots: Map<string, StateSlot<unknown>>;\n /**\n * Runtime `state.series` slot store keyed by\n * `${slotIdPrefix ?? \"\"}${slotId}:series`. Each holds a history ring +\n * the identity-stable script-facing view + the last committed head.\n * The ring advances once per close (script-invisible lockstep), so\n * `s[1]` is always one committed bar back. Cleared on `dispose` after\n * the final snapshot captures it. @since 0.9\n */\n readonly seriesSlots: Map<string, SeriesSlot>;\n /**\n * Runtime `state.array` slot store keyed by\n * `${slotIdPrefix ?? \"\"}${slotId}:array`. Each holds two\n * `Float64RingBuffer`s (committed + tentative) behind an identity-stable\n * bounded-FIFO handle. A parallel map (vs folding into `stateSlots`)\n * mirrors the `state.series` precedent — both collection primitives share\n * the two-ring shape and snapshot directly from the live map with no\n * `StateStore` flush. Cleared on `dispose`. @since 1.3\n */\n readonly arraySlots: Map<string, ArrayStateSlot>;\n /**\n * The chart's own symbol, resolved once at mount from the adapter\n * `syminfo.ticker` (`\"\"` when the adapter supplies none). A\n * `request.security` call that omits `symbol` — or passes this exact\n * ticker — resolves to it and collapses to the bare-interval\n * {@link feedKey}, so the chart-symbol path is byte-identical to the\n * pre-multi-symbol baseline. Only a *different* symbol allocates a\n * `\"<symbol>@<interval>\"` feed. @since 1.3\n */\n readonly chartSymbol: string;\n /**\n * Secondary candle streams keyed by the composite\n * `feedKey(symbol, interval)` (the shared core helper). A symbol-omitted\n * feed collapses to the bare interval — `feedKey(undefined, \"1D\") === \"1D\"`\n * — so the chart-symbol path is byte-identical to the pre-multi-symbol\n * baseline; a non-chart symbol keys as `\"<symbol>@<interval>\"`. Mutated only\n * by `createScriptRunner` mount/restore/routing. @since 0.5\n */\n readonly secondaryStreams: Map<string, StreamState>;\n /**\n * Per-`request.security` slot cache keyed by `slotId|feedKey`. Phase 4\n * stores NaN fallback bars here; Phase 5 replaces the value producer with\n * aligned secondary stream series while preserving stable identity. The\n * `feedKey` collapses to the bare interval for chart-symbol requests, so\n * the omitted-symbol cache key is byte-identical to the baseline.\n * @since 0.4\n */\n readonly requestSecurityBars: Map<string, SecurityBar>;\n /**\n * Per-compute aligned numeric arrays keyed by\n * `slotId|feedKey|sourceKey`. Cleared on main-stream close/tick before\n * `compute` so `request.security` re-aligns against the latest\n * secondary buffers. @since 0.5\n */\n readonly requestSecurityAlignments: Map<string, ReadonlyArray<number>>;\n /**\n * Per-compute cache of ascending `Bar[]` materialisations keyed by the\n * source `StreamState`. Shared by `request.security` and `request.lowerTf`\n * (via `request/streamBars.ts:ascendingBarsFor`) so a stable bar-array\n * identity is reused across every consumer in a bar — the `getOrAlign` /\n * `getOrBucket` WeakMap caches actually hit and the same ring buffer is\n * walked once per bar instead of 10×. Cleared alongside\n * {@link requestSecurityAlignments}. @since 0.5\n */\n readonly requestSecurityAscendingBars: Map<StreamState, ReadonlyArray<Bar>>;\n /**\n * Mounted HTF expression runners keyed by `slotId`. One entry per\n * `manifest.securityExpressions` callsite. `request.security(slotId,\n * opts, expr)` dispatches the expression overload off this registry\n * (rather than `expr !== undefined`) and captures the callback here.\n * Absent on dep / sibling contexts and single-timeframe scripts.\n * Cleared on `dispose`. @since 0.7\n */\n securityExprRunners?: Map<string, SecurityExprRunner>;\n /**\n * Per-feed index into {@link securityExprRunners}, keyed by the composite\n * `feedKey(symbol, interval)`. `driveSecurityExpressions` fans a secondary\n * close / tick (tagged with that same composite key on\n * `CandleEvent.streamKey`) out to every runner on that feed. A\n * symbol-omitted callsite collapses to the bare interval, byte-identical to\n * the pre-multi-symbol baseline. Absent when no expression callsites are\n * declared. Cleared on `dispose`. @since 0.7\n */\n securityExprRunnersByFeed?: ReadonlyMap<string, ReadonlyArray<SecurityExprRunner>>;\n /**\n * Per-compute aligned expression-output series cache keyed by\n * `slotId|feedKey`. Holds the stable `Series<number>` Proxy each\n * expression-form `request.security` returns; cleared each bar\n * (alongside {@link requestSecurityAlignments}) so the proxy re-aligns\n * the runner's output buffer against the latest secondary buffers.\n * @since 0.7\n */\n requestSecurityExprSeries?: Map<string, Series<number>>;\n /**\n * Per-`request.lowerTf` slot cache keyed by `slotId|interval`. Values are\n * stable `Series<ReadonlyArray<Bar>>` proxies over the latest LTF bucket\n * materialisation. @since 0.6\n */\n readonly requestLowerTfViews: Map<string, Series<ReadonlyArray<Bar>>>;\n /**\n * Runtime diagnostic dedupe for `request.*` capability gates, keyed by\n * `code|slotId|interval|kind`. Cleared on `dispose`. @since 0.4\n */\n readonly diagnosedRequestKeys: Set<string>;\n /**\n * Runtime diagnostic dedupe for `time.*` / `session.*` DST-zone\n * fallbacks, keyed by `tz-dst-unsupported|<tz>`. The calendar accessors\n * are `slot: false` (no slotId to key on), so they dedupe on the\n * timezone string here — a DST zone warns at most once per distinct tz\n * per mount. Cleared on `dispose`. @since 1.5\n */\n readonly diagnosedTzKeys: Set<string>;\n /**\n * Manifest-declared alert conditions keyed by condition id. Used by\n * `signal(conditionId, fired)` to reject unknown ids without\n * re-reading the manifest each bar. @since 0.5\n */\n readonly alertConditions?: ReadonlyMap<string, AlertConditionDefinition>;\n /**\n * Dedupe for alert-condition capability/unknown-id diagnostics, keyed\n * by `code|conditionId`. Cleared on dispose. @since 0.5\n */\n readonly diagnosedAlertConditionKeys?: Set<string>;\n /**\n * Number of `runtime.log.*` emissions accepted in the active compute\n * step. Reset at the start of each close/tick. @since 0.5\n */\n logBudget: number;\n /**\n * Per-step dedupe flag for `runtime-log-budget-exceeded`. Reset with\n * `logBudget` at the start of each close/tick. @since 0.5\n */\n logBudgetExceededDiagnosed: boolean;\n /**\n * Frozen effective input values keyed by script input name. Resolved once\n * at mount and reused by every compute step. @since 0.4\n */\n resolvedInputs: Readonly<Record<string, unknown>>;\n /**\n * Mount-time script pane default. The runner sets it from\n * `manifest.overlay`:\n * - `overlay` absent / `true` → `\"overlay\"`.\n * - `overlay === false` → `\"script:<sanitised(manifest.name)>\"`.\n * `resolvePane` reads this value when a `plot()` / `hline()` call\n * has no explicit `pane` opt.\n * @since 0.2\n */\n readonly defaultPane: string;\n /**\n * Stable non-overlay pane key for this script. Explicit\n * `pane: \"new\"` resolves here even when `defaultPane === \"overlay\"`\n * so every `\"new\"` plot in a script joins one script-owned subpane.\n * @since 0.2\n */\n readonly scriptPane: string;\n /**\n * Host-supplied per-slot presentation overrides, keyed by\n * `PlotEmission.slotId`. Applied at emit time by `applyPlotOverride`.\n * Mutable — `setPlotOverrides` swaps it live (presentation-only, so\n * it does not break the frozen-input determinism guarantee). Entries\n * themselves are frozen. @since 0.8\n */\n plotOverrides: Readonly<Record<string, PlotOverride>>;\n /**\n * Runtime diagnostic dedupe for mount-time input override failures,\n * keyed by manifest input key. Cleared on `dispose`. @since 0.4\n */\n readonly diagnosedInputKeys: Set<string>;\n /**\n * Runtime `barstate.*`, `syminfo.*`, and `timeframe.*` views. The\n * container is mutable; each assigned view snapshot is frozen.\n * @since 0.4\n */\n readonly views: RuntimeViews;\n /**\n * Prefix prepended when emissions from this context flow into the\n * parent runner's queues, and mirrored into every `stateSlots` /\n * `StateStore` key written by `state.*` / `state.tick.*` so each\n * runner's persisted state is isolated. `\"dep:<localId>/\"` for\n * private dep runners, `\"export:<exportName>/\"` for sibling\n * runners, and `\"\"` (or absent) for primary single-script and\n * bundle-primary runners.\n *\n * @since 0.7\n */\n slotIdPrefix?: string;\n /**\n * `true` when this context belongs to a private dep runner — its\n * emissions are dropped (or captured into the dep output store) by\n * `applyDepEmissionPolicy`. `false` / absent for primary and\n * sibling runners.\n *\n * @since 0.7\n */\n isDep?: boolean;\n /**\n * Per-bar titled-output buffer shared by the primary and every\n * sibling of a `CompiledScriptBundle`. Populated by\n * `applyDepEmissionPolicy` after each dep/sibling's compute; read\n * by `__chartlang_depOutput` during the consumer's compute. `null`\n * / absent for single-script runners with no deps.\n *\n * @since 0.7\n */\n depOutputStore?: DepOutputStore | null;\n};\n\n/**\n * Process-wide context slot. Task 6's `createScriptRunner` mutates\n * `.current` inside `try { ... } finally { current = null }` around\n * every `compute` invocation; Tasks 7-8 read it inside primitive\n * implementations. JavaScript's single-threaded execution model\n * guarantees only one `compute` runs at a time, so this ambient\n * slot is safe.\n *\n * The export is intentionally just a holder — no class, no methods,\n * no validation. Responsibility for setting and clearing lives in\n * Task 6.\n *\n * @since 0.1\n * @example\n * // import { ACTIVE_RUNTIME_CONTEXT }\n * // from \"@invinite-org/chartlang-runtime\";\n * // ACTIVE_RUNTIME_CONTEXT.current; // null at module load\n */\nexport const ACTIVE_RUNTIME_CONTEXT: { current: RuntimeContext | null } = {\n current: null,\n};\n"]}
@@ -10,6 +10,14 @@ import type { RingBufferLike } from "./ringBuffer.js";
10
10
  * Property reads dispatch as follows:
11
11
  * - `series.current` → `buf.at(0)`
12
12
  * - `series.length` → `buf.length`
13
+ * - `series.valueOf` / `series[Symbol.toPrimitive]` → a function returning
14
+ * `buf.at(0)`, so a numeric series coerces to its **current** value in any
15
+ * value context (`series * 2`, `series > x`, `` `${series}` ``,
16
+ * `Math.max(series, …)`). This is what lets `bar.close` be used both as a
17
+ * scalar and indexed as a series. Coercion is harmless for non-numeric
18
+ * buffers — nothing coerces those. Note `Number.isFinite(series)` is still
19
+ * `false` (it does not coerce) and `series === 42` is `false` (object vs
20
+ * number); use `series.current` / `+series` there.
13
21
  * - `series[n]` (string coerces to a non-negative integer) → `buf.at(n)`
14
22
  * - any other key → `undefined`
15
23
  *
@@ -30,30 +38,47 @@ import type { RingBufferLike } from "./ringBuffer.js";
30
38
  */
31
39
  export declare function makeSeriesView<T>(buf: RingBufferLike<T>): Series<T>;
32
40
  /**
33
- * Offset-shifted variant of {@link makeSeriesView}. `offset === 0`
34
- * returns the same Proxy shape (and is the identity-preserving fast
35
- * path callers should special-case at the call site). For
36
- * `offset === k > 0`, `view.current === buf.at(k)` i.e. the value
37
- * `k` bars ago, matching `lib/applyOffset`'s
38
- * `out[i] = values[i offset]` semantics. For `offset === -k`,
39
- * `view.current === buf.at(-k)` an OOR read returning the underlying
40
- * sentinel (NaN for `Float64RingBuffer`, `undefined` for object
41
- * `RingBuffer`).
41
+ * Offset-tagging variant of {@link makeSeriesView}. It returns the
42
+ * **unshifted** view (delegating to {@link makeSeriesView}) and, for a
43
+ * non-zero `offset`, records `view offset` in a module-level
44
+ * `WeakMap` side-table read by `plot()` via {@link seriesOffsetOf}. The
45
+ * offset is **presentation-only** — `view.current` is `buf.at(0)`, not a
46
+ * value `offset` bars ago so both shift directions are expressible and
47
+ * alerts / `state.*` see the unshifted value. `offset === 0` records
48
+ * nothing (byte-identical to a plain {@link makeSeriesView}).
42
49
  *
43
- * The shift is applied on every read no allocation, no per-bar
44
- * work. Callers cache the returned Proxy per `(slot, offset)` pair so
45
- * the view's identity stays stable across bars.
50
+ * Callers cache the returned view per `(slot, offset)` pair so the
51
+ * view's identity and therefore its recorded offset stays stable
52
+ * across bars.
46
53
  *
47
54
  * @since 0.2
55
+ * @stable
48
56
  * @example
49
- * // import { Float64RingBuffer, makeShiftedSeriesView }
57
+ * // import { Float64RingBuffer, makeShiftedSeriesView, seriesOffsetOf }
50
58
  * // from "@invinite-org/chartlang-runtime";
51
59
  * // const buf = new Float64RingBuffer(8);
52
60
  * // buf.append(10); buf.append(20); buf.append(30);
53
- * // const view = makeShiftedSeriesView<number>(buf, 1);
54
- * // view.current; // 20 (one bar ago)
55
- * // view[0]; // 20
56
- * // view[1]; // 10
61
+ * // const view = makeShiftedSeriesView<number>(buf, 5);
62
+ * // view.current; // 30 (unshifted the offset does NOT lag the read)
63
+ * // seriesOffsetOf(view); // 5 (presentation x-shift carried to the emission)
57
64
  */
58
65
  export declare function makeShiftedSeriesView<T>(buf: RingBufferLike<T>, offset: number): Series<T>;
66
+ /**
67
+ * Read the presentation x-shift recorded for `series` by
68
+ * {@link makeShiftedSeriesView}, or `0` when the series is untagged (a
69
+ * plain {@link makeSeriesView} view, an `offset === 0` view, or any
70
+ * non-runtime Series). `plot()` calls this to populate
71
+ * `PlotEmission.xShift`; a `0` result omits the field so a no-offset
72
+ * plot stays byte-identical to today.
73
+ *
74
+ * @since 0.2
75
+ * @stable
76
+ * @example
77
+ * // import { Float64RingBuffer, makeShiftedSeriesView, seriesOffsetOf }
78
+ * // from "@invinite-org/chartlang-runtime";
79
+ * // const buf = new Float64RingBuffer(8);
80
+ * // const shifted = makeShiftedSeriesView<number>(buf, -3);
81
+ * // seriesOffsetOf(shifted); // -3
82
+ */
83
+ export declare function seriesOffsetOf(series: Series<unknown>): number;
59
84
  //# sourceMappingURL=seriesView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"seriesView.d.ts","sourceRoot":"","sources":["../src/seriesView.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAoBnE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAqB1F"}
1
+ {"version":3,"file":"seriesView.d.ts","sourceRoot":"","sources":["../src/seriesView.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAuBnE;AAcD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAI1F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAE9D"}
@@ -10,6 +10,14 @@
10
10
  * Property reads dispatch as follows:
11
11
  * - `series.current` → `buf.at(0)`
12
12
  * - `series.length` → `buf.length`
13
+ * - `series.valueOf` / `series[Symbol.toPrimitive]` → a function returning
14
+ * `buf.at(0)`, so a numeric series coerces to its **current** value in any
15
+ * value context (`series * 2`, `series > x`, `` `${series}` ``,
16
+ * `Math.max(series, …)`). This is what lets `bar.close` be used both as a
17
+ * scalar and indexed as a series. Coercion is harmless for non-numeric
18
+ * buffers — nothing coerces those. Note `Number.isFinite(series)` is still
19
+ * `false` (it does not coerce) and `series === 42` is `false` (object vs
20
+ * number); use `series.current` / `+series` there.
13
21
  * - `series[n]` (string coerces to a non-negative integer) → `buf.at(n)`
14
22
  * - any other key → `undefined`
15
23
  *
@@ -35,6 +43,10 @@ export function makeSeriesView(buf) {
35
43
  return buf.at(0);
36
44
  if (prop === "length")
37
45
  return buf.length;
46
+ if (prop === "valueOf")
47
+ return () => buf.at(0);
48
+ if (prop === Symbol.toPrimitive)
49
+ return () => buf.at(0);
38
50
  if (typeof prop === "string") {
39
51
  const n = Number(prop);
40
52
  if (Number.isInteger(n) && n >= 0)
@@ -45,6 +57,8 @@ export function makeSeriesView(buf) {
45
57
  has(_target, prop) {
46
58
  if (prop === "current" || prop === "length")
47
59
  return true;
60
+ if (prop === "valueOf" || prop === Symbol.toPrimitive)
61
+ return true;
48
62
  if (typeof prop === "string") {
49
63
  const n = Number(prop);
50
64
  return Number.isInteger(n) && n >= 0;
@@ -54,56 +68,65 @@ export function makeSeriesView(buf) {
54
68
  });
55
69
  }
56
70
  /**
57
- * Offset-shifted variant of {@link makeSeriesView}. `offset === 0`
58
- * returns the same Proxy shape (and is the identity-preserving fast
59
- * path callers should special-case at the call site). For
60
- * `offset === k > 0`, `view.current === buf.at(k)` i.e. the value
61
- * `k` bars ago, matching `lib/applyOffset`'s
62
- * `out[i] = values[i offset]` semantics. For `offset === -k`,
63
- * `view.current === buf.at(-k)` an OOR read returning the underlying
64
- * sentinel (NaN for `Float64RingBuffer`, `undefined` for object
65
- * `RingBuffer`).
71
+ * Module-level side-table recording the **presentation x-shift** declared
72
+ * for an offset-tagged Series view. `offset` is no longer a value-read
73
+ * transform (Option A, bidirectional-plot-offset): the series value is
74
+ * always the unshifted `buf.at(0)`; the recorded offset rides the plot
75
+ * emission as `PlotEmission.xShift` so the adapter renders the series
76
+ * shifted (`+n` right / future, `−n` left / past) without changing the
77
+ * numbers alerts and `state.*` see. Keyed weakly on the view object so a
78
+ * dropped slot's tag is collected with it.
79
+ */
80
+ const seriesOffsets = new WeakMap();
81
+ /**
82
+ * Offset-tagging variant of {@link makeSeriesView}. It returns the
83
+ * **unshifted** view (delegating to {@link makeSeriesView}) and, for a
84
+ * non-zero `offset`, records `view → offset` in a module-level
85
+ * `WeakMap` side-table read by `plot()` via {@link seriesOffsetOf}. The
86
+ * offset is **presentation-only** — `view.current` is `buf.at(0)`, not a
87
+ * value `offset` bars ago — so both shift directions are expressible and
88
+ * alerts / `state.*` see the unshifted value. `offset === 0` records
89
+ * nothing (byte-identical to a plain {@link makeSeriesView}).
66
90
  *
67
- * The shift is applied on every read no allocation, no per-bar
68
- * work. Callers cache the returned Proxy per `(slot, offset)` pair so
69
- * the view's identity stays stable across bars.
91
+ * Callers cache the returned view per `(slot, offset)` pair so the
92
+ * view's identity and therefore its recorded offset stays stable
93
+ * across bars.
70
94
  *
71
95
  * @since 0.2
96
+ * @stable
72
97
  * @example
73
- * // import { Float64RingBuffer, makeShiftedSeriesView }
98
+ * // import { Float64RingBuffer, makeShiftedSeriesView, seriesOffsetOf }
74
99
  * // from "@invinite-org/chartlang-runtime";
75
100
  * // const buf = new Float64RingBuffer(8);
76
101
  * // buf.append(10); buf.append(20); buf.append(30);
77
- * // const view = makeShiftedSeriesView<number>(buf, 1);
78
- * // view.current; // 20 (one bar ago)
79
- * // view[0]; // 20
80
- * // view[1]; // 10
102
+ * // const view = makeShiftedSeriesView<number>(buf, 5);
103
+ * // view.current; // 30 (unshifted the offset does NOT lag the read)
104
+ * // seriesOffsetOf(view); // 5 (presentation x-shift carried to the emission)
81
105
  */
82
106
  export function makeShiftedSeriesView(buf, offset) {
83
- if (offset === 0)
84
- return makeSeriesView(buf);
85
- return new Proxy({}, {
86
- get(_target, prop) {
87
- if (prop === "current")
88
- return buf.at(offset);
89
- if (prop === "length")
90
- return buf.length;
91
- if (typeof prop === "string") {
92
- const n = Number(prop);
93
- if (Number.isInteger(n) && n >= 0)
94
- return buf.at(n + offset);
95
- }
96
- return undefined;
97
- },
98
- has(_target, prop) {
99
- if (prop === "current" || prop === "length")
100
- return true;
101
- if (typeof prop === "string") {
102
- const n = Number(prop);
103
- return Number.isInteger(n) && n >= 0;
104
- }
105
- return false;
106
- },
107
- });
107
+ const view = makeSeriesView(buf);
108
+ if (offset !== 0)
109
+ seriesOffsets.set(view, offset);
110
+ return view;
111
+ }
112
+ /**
113
+ * Read the presentation x-shift recorded for `series` by
114
+ * {@link makeShiftedSeriesView}, or `0` when the series is untagged (a
115
+ * plain {@link makeSeriesView} view, an `offset === 0` view, or any
116
+ * non-runtime Series). `plot()` calls this to populate
117
+ * `PlotEmission.xShift`; a `0` result omits the field so a no-offset
118
+ * plot stays byte-identical to today.
119
+ *
120
+ * @since 0.2
121
+ * @stable
122
+ * @example
123
+ * // import { Float64RingBuffer, makeShiftedSeriesView, seriesOffsetOf }
124
+ * // from "@invinite-org/chartlang-runtime";
125
+ * // const buf = new Float64RingBuffer(8);
126
+ * // const shifted = makeShiftedSeriesView<number>(buf, -3);
127
+ * // seriesOffsetOf(shifted); // -3
128
+ */
129
+ export function seriesOffsetOf(series) {
130
+ return seriesOffsets.get(series) ?? 0;
108
131
  }
109
132
  //# sourceMappingURL=seriesView.js.map