@winkjs/composer 0.0.2 → 0.4.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 (451) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +42 -103
  3. package/package.json +53 -29
  4. package/src/composer.js +75 -0
  5. package/src/core/batch/aoo-encoder.js +148 -0
  6. package/src/core/batch/index.js +12 -0
  7. package/src/core/batch/sliding-window.js +91 -0
  8. package/src/core/codec/index.js +137 -0
  9. package/src/core/emitter-manager/mqtt/constants.js +102 -0
  10. package/src/core/emitter-manager/mqtt/emitter.js +780 -0
  11. package/src/core/emitter-manager/mqtt/index.js +190 -0
  12. package/src/core/emitter-manager/mqtt/mqtt-store.js +538 -0
  13. package/src/core/emitter-manager/terminal/assert-columns.js +98 -0
  14. package/src/core/emitter-manager/terminal/formatters.js +160 -0
  15. package/src/core/emitter-manager/terminal/index.js +341 -0
  16. package/src/core/env-vars.js +245 -0
  17. package/src/core/mqtt-protocol.js +47 -0
  18. package/src/core/partition-manager/index.js +7 -0
  19. package/src/core/partition-manager/init.js +44 -0
  20. package/src/core/partition-manager/introspect.js +15 -0
  21. package/src/core/partition-manager/publish-to.js +6 -0
  22. package/src/core/partition-manager/recompute.js +5 -0
  23. package/src/core/partition-manager/reset.js +5 -0
  24. package/src/core/partition-manager/update.js +264 -0
  25. package/src/core/partition-manager/validate-flow.js +157 -0
  26. package/src/core/semantics/digest.js +128 -0
  27. package/src/core/semantics/index.js +83 -0
  28. package/src/core/semantics/loader.js +571 -0
  29. package/src/core/semantics/schemas/asset-class-schema.js +218 -0
  30. package/src/core/semantics/schemas/column-schema.js +651 -0
  31. package/src/core/semantics/schemas/enum-schema.js +153 -0
  32. package/src/core/semantics/schemas/index.js +51 -0
  33. package/src/core/semantics/warnings.js +141 -0
  34. package/src/core/shutdown-manager/index.js +289 -0
  35. package/src/core/source-manager/csv/index.js +171 -0
  36. package/src/core/source-manager/csv/start.js +456 -0
  37. package/src/core/source-manager/mqtt/client.js +406 -0
  38. package/src/core/source-manager/mqtt/constants.js +147 -0
  39. package/src/core/source-manager/mqtt/dedup.js +244 -0
  40. package/src/core/source-manager/mqtt/index.js +260 -0
  41. package/src/core/source-manager/mqtt/status.js +546 -0
  42. package/src/core/source-manager/test-harness/comparator.js +226 -0
  43. package/src/core/source-manager/test-harness/field-generator.js +85 -0
  44. package/src/core/source-manager/test-harness/fuzz.js +87 -0
  45. package/src/core/source-manager/test-harness/index.js +115 -0
  46. package/src/core/source-manager/test-harness/prng.js +57 -0
  47. package/src/core/source-manager/test-harness/start.js +232 -0
  48. package/src/core/source-manager/test-harness/validate.js +213 -0
  49. package/src/core/storage-manager/questdb/assert-columns.js +120 -0
  50. package/src/core/storage-manager/questdb/ensure-tables.js +187 -0
  51. package/src/core/storage-manager/questdb/index.js +1251 -0
  52. package/src/core/storage-manager/questdb/persist-plan.js +488 -0
  53. package/src/core/storage-manager/questdb/writers.js +142 -0
  54. package/src/core/test-utils/sealed-record.js +80 -0
  55. package/src/core/test-utils/soak-signature.js +149 -0
  56. package/src/core/test-utils/tcp-proxy.js +106 -0
  57. package/src/core/tunable/helpers.js +254 -0
  58. package/src/core/tunable/index.js +87 -0
  59. package/src/core/utils/console-formatter/index.js +207 -0
  60. package/src/core/utils/create-smart-store-as/index.js +98 -0
  61. package/src/core/utils/create-smart-store-as/sanitize-field.js +46 -0
  62. package/src/core/utils/create-smart-store-as/smart-truncate.js +93 -0
  63. package/src/core/utils/flow/index.js +5 -0
  64. package/src/core/utils/flow/make-collision-checker.js +23 -0
  65. package/src/core/utils/flow/to-kebab.js +20 -0
  66. package/src/core/utils/half-life/index.js +111 -0
  67. package/src/core/utils/node/disable.js +11 -0
  68. package/src/core/utils/node/enable.js +11 -0
  69. package/src/core/utils/node/execute-triggers.js +40 -0
  70. package/src/core/utils/node/index.js +10 -0
  71. package/src/core/utils/node/pause.js +11 -0
  72. package/src/core/utils/node/populate-predicate-inputs.js +14 -0
  73. package/src/core/utils/node/publish-nan.js +19 -0
  74. package/src/core/utils/node/reset-predicate-inputs.js +11 -0
  75. package/src/core/utils/node/unpause.js +11 -0
  76. package/src/core/utils/node/validate-spec.js +22 -0
  77. package/src/core/utils/options/resolve-field-keyed.js +115 -0
  78. package/src/core/utils/quantize/index.js +75 -0
  79. package/src/core/utils/stats/formulas.js +67 -0
  80. package/src/core/utils/stats/index.js +3 -0
  81. package/src/core/utils/validate/composer-validators.js +141 -0
  82. package/src/core/utils/validate/helpers.js +206 -0
  83. package/src/core/utils/validate/index.js +12 -0
  84. package/src/core/utils/validate/type-validators.js +538 -0
  85. package/src/core/utils/validate/validate.js +107 -0
  86. package/src/core/utils/validate/validators.js +177 -0
  87. package/src/core/wiring/assert-handle.js +57 -0
  88. package/src/core/wiring/assert-module.js +63 -0
  89. package/src/core/wiring/index.js +5 -0
  90. package/src/core/wiring/node-type-to-module.js +17 -0
  91. package/src/core/wiring/wire-emitters.js +256 -0
  92. package/src/core/wiring/wire-linear-graph.js +25 -0
  93. package/src/core/wiring/wire-node.js +157 -0
  94. package/src/core/wiring/wire-semantics.js +173 -0
  95. package/src/core/wiring/wire-storages.js +344 -0
  96. package/src/flow/check-output-collisions.js +93 -0
  97. package/src/flow/consts.js +9 -0
  98. package/src/flow/deep-clone-spec.js +64 -0
  99. package/src/flow/driver.js +171 -0
  100. package/src/flow/expand-single-input-array.js +76 -0
  101. package/src/flow/expand-template-spec.js +93 -0
  102. package/src/flow/flow-api-schemas.js +300 -0
  103. package/src/flow/flow.js +658 -0
  104. package/src/flow/for-each.js +225 -0
  105. package/src/flow/get-signature-pattern.js +31 -0
  106. package/src/flow/get-target-array.js +46 -0
  107. package/src/flow/inspect.js +67 -0
  108. package/src/flow/load-node-module.js +81 -0
  109. package/src/flow/make-node-method.js +112 -0
  110. package/src/flow/resolve-pick-by-field.js +77 -0
  111. package/src/flow/resolve-tunables.js +76 -0
  112. package/src/flow/run.js +392 -0
  113. package/src/flow/serialize.js +161 -0
  114. package/src/flow/signatures-schema.js +222 -0
  115. package/src/flow/spec-builder.js +65 -0
  116. package/src/flow/validate-triggers.js +250 -0
  117. package/src/flow/validate.js +261 -0
  118. package/src/nodes/accumulate/index.js +21 -0
  119. package/src/nodes/accumulate/init.js +48 -0
  120. package/src/nodes/accumulate/introspect.js +123 -0
  121. package/src/nodes/accumulate/publish-to.js +34 -0
  122. package/src/nodes/accumulate/recompute.js +27 -0
  123. package/src/nodes/accumulate/reset.js +25 -0
  124. package/src/nodes/accumulate/update.js +42 -0
  125. package/src/nodes/appraise/calibrate.js +64 -0
  126. package/src/nodes/appraise/decision.js +66 -0
  127. package/src/nodes/appraise/deviation.js +140 -0
  128. package/src/nodes/appraise/index.js +23 -0
  129. package/src/nodes/appraise/init.js +165 -0
  130. package/src/nodes/appraise/integrate.js +45 -0
  131. package/src/nodes/appraise/introspect.js +352 -0
  132. package/src/nodes/appraise/publish-to.js +93 -0
  133. package/src/nodes/appraise/receptor.js +69 -0
  134. package/src/nodes/appraise/recompute.js +79 -0
  135. package/src/nodes/appraise/reset.js +53 -0
  136. package/src/nodes/appraise/update.js +130 -0
  137. package/src/nodes/archive/csv/index.js +6 -0
  138. package/src/nodes/archive/csv/init.js +36 -0
  139. package/src/nodes/archive/csv/load.js +70 -0
  140. package/src/nodes/archive/csv/reset.js +14 -0
  141. package/src/nodes/archive/csv/simple-parser.js +216 -0
  142. package/src/nodes/archive/csv/test.js +173 -0
  143. package/src/nodes/archive/csv/update.js +63 -0
  144. package/src/nodes/butterworth-filter/index.js +18 -0
  145. package/src/nodes/butterworth-filter/init.js +184 -0
  146. package/src/nodes/butterworth-filter/introspect.js +228 -0
  147. package/src/nodes/butterworth-filter/publish-to.js +21 -0
  148. package/src/nodes/butterworth-filter/recompute.js +13 -0
  149. package/src/nodes/butterworth-filter/reset.js +30 -0
  150. package/src/nodes/butterworth-filter/update.js +38 -0
  151. package/src/nodes/categorize/index.js +19 -0
  152. package/src/nodes/categorize/init.js +58 -0
  153. package/src/nodes/categorize/introspect.js +177 -0
  154. package/src/nodes/categorize/publish-to.js +29 -0
  155. package/src/nodes/categorize/recompute.js +14 -0
  156. package/src/nodes/categorize/reset.js +16 -0
  157. package/src/nodes/categorize/update.js +53 -0
  158. package/src/nodes/controller/index.js +9 -0
  159. package/src/nodes/controller/init.js +55 -0
  160. package/src/nodes/controller/introspect.js +91 -0
  161. package/src/nodes/controller/publish-to.js +8 -0
  162. package/src/nodes/controller/recompute.js +9 -0
  163. package/src/nodes/controller/reset.js +17 -0
  164. package/src/nodes/controller/update.js +63 -0
  165. package/src/nodes/diff/index.js +19 -0
  166. package/src/nodes/diff/init.js +37 -0
  167. package/src/nodes/diff/introspect.js +132 -0
  168. package/src/nodes/diff/publish-to.js +21 -0
  169. package/src/nodes/diff/recompute.js +12 -0
  170. package/src/nodes/diff/reset.js +12 -0
  171. package/src/nodes/diff/update.js +37 -0
  172. package/src/nodes/digest-moments/formulas.js +12 -0
  173. package/src/nodes/digest-moments/index.js +14 -0
  174. package/src/nodes/digest-moments/init.js +67 -0
  175. package/src/nodes/digest-moments/introspect.js +154 -0
  176. package/src/nodes/digest-moments/publish-to.js +34 -0
  177. package/src/nodes/digest-moments/recompute.js +14 -0
  178. package/src/nodes/digest-moments/reset.js +14 -0
  179. package/src/nodes/digest-moments/update.js +120 -0
  180. package/src/nodes/dwell-time-tracker/index.js +14 -0
  181. package/src/nodes/dwell-time-tracker/init.js +59 -0
  182. package/src/nodes/dwell-time-tracker/introspect.js +137 -0
  183. package/src/nodes/dwell-time-tracker/publish-to.js +22 -0
  184. package/src/nodes/dwell-time-tracker/recompute.js +8 -0
  185. package/src/nodes/dwell-time-tracker/reset.js +23 -0
  186. package/src/nodes/dwell-time-tracker/update.js +103 -0
  187. package/src/nodes/emit-if/helpers.js +94 -0
  188. package/src/nodes/emit-if/index.js +16 -0
  189. package/src/nodes/emit-if/init.js +67 -0
  190. package/src/nodes/emit-if/introspect.js +102 -0
  191. package/src/nodes/emit-if/publish-to.js +13 -0
  192. package/src/nodes/emit-if/recompute.js +12 -0
  193. package/src/nodes/emit-if/reset.js +27 -0
  194. package/src/nodes/emit-if/update.js +93 -0
  195. package/src/nodes/es-correlation/index.js +19 -0
  196. package/src/nodes/es-correlation/init.js +73 -0
  197. package/src/nodes/es-correlation/introspect.js +176 -0
  198. package/src/nodes/es-correlation/publish-to.js +32 -0
  199. package/src/nodes/es-correlation/recompute.js +56 -0
  200. package/src/nodes/es-correlation/reset.js +27 -0
  201. package/src/nodes/es-correlation/update.js +110 -0
  202. package/src/nodes/es-mean/index.js +20 -0
  203. package/src/nodes/es-mean/init.js +58 -0
  204. package/src/nodes/es-mean/introspect.js +129 -0
  205. package/src/nodes/es-mean/publish-to.js +19 -0
  206. package/src/nodes/es-mean/recompute.js +16 -0
  207. package/src/nodes/es-mean/reset.js +24 -0
  208. package/src/nodes/es-mean/update.js +69 -0
  209. package/src/nodes/es-pairwise-correlation/index.js +19 -0
  210. package/src/nodes/es-pairwise-correlation/init.js +98 -0
  211. package/src/nodes/es-pairwise-correlation/introspect.js +187 -0
  212. package/src/nodes/es-pairwise-correlation/publish-to.js +31 -0
  213. package/src/nodes/es-pairwise-correlation/recompute.js +69 -0
  214. package/src/nodes/es-pairwise-correlation/reset.js +29 -0
  215. package/src/nodes/es-pairwise-correlation/update.js +89 -0
  216. package/src/nodes/es-stats/index.js +21 -0
  217. package/src/nodes/es-stats/init.js +105 -0
  218. package/src/nodes/es-stats/introspect.js +157 -0
  219. package/src/nodes/es-stats/publish-to.js +42 -0
  220. package/src/nodes/es-stats/recompute.js +74 -0
  221. package/src/nodes/es-stats/reset.js +49 -0
  222. package/src/nodes/es-stats/update-envelope.js +44 -0
  223. package/src/nodes/es-stats/update-welford.js +64 -0
  224. package/src/nodes/es-stats/update.js +59 -0
  225. package/src/nodes/index.js +83 -0
  226. package/src/nodes/invert-flag/index.js +20 -0
  227. package/src/nodes/invert-flag/init.js +36 -0
  228. package/src/nodes/invert-flag/introspect.js +115 -0
  229. package/src/nodes/invert-flag/publish-to.js +23 -0
  230. package/src/nodes/invert-flag/recompute.js +12 -0
  231. package/src/nodes/invert-flag/reset.js +12 -0
  232. package/src/nodes/invert-flag/update.js +32 -0
  233. package/src/nodes/kalman1d/index.js +20 -0
  234. package/src/nodes/kalman1d/init.js +103 -0
  235. package/src/nodes/kalman1d/introspect.js +250 -0
  236. package/src/nodes/kalman1d/publish-to.js +34 -0
  237. package/src/nodes/kalman1d/recompute.js +23 -0
  238. package/src/nodes/kalman1d/reset.js +29 -0
  239. package/src/nodes/kalman1d/update.js +144 -0
  240. package/src/nodes/kernel/index.js +18 -0
  241. package/src/nodes/kernel/init.js +66 -0
  242. package/src/nodes/kernel/introspect.js +163 -0
  243. package/src/nodes/kernel/presets.js +74 -0
  244. package/src/nodes/kernel/publish-to.js +25 -0
  245. package/src/nodes/kernel/recompute.js +14 -0
  246. package/src/nodes/kernel/reset.js +20 -0
  247. package/src/nodes/kernel/update.js +69 -0
  248. package/src/nodes/lag/index.js +21 -0
  249. package/src/nodes/lag/init.js +87 -0
  250. package/src/nodes/lag/introspect.js +202 -0
  251. package/src/nodes/lag/publish-to.js +64 -0
  252. package/src/nodes/lag/recompute.js +33 -0
  253. package/src/nodes/lag/reset.js +49 -0
  254. package/src/nodes/lag/update.js +133 -0
  255. package/src/nodes/median3/index.js +19 -0
  256. package/src/nodes/median3/init.js +40 -0
  257. package/src/nodes/median3/introspect.js +116 -0
  258. package/src/nodes/median3/publish-to.js +21 -0
  259. package/src/nodes/median3/recompute.js +12 -0
  260. package/src/nodes/median3/reset.js +15 -0
  261. package/src/nodes/median3/update.js +58 -0
  262. package/src/nodes/moments-digest/copy-from.js +12 -0
  263. package/src/nodes/moments-digest/flush.js +17 -0
  264. package/src/nodes/moments-digest/index.js +132 -0
  265. package/src/nodes/moments-digest/init.js +84 -0
  266. package/src/nodes/moments-digest/introspect.js +122 -0
  267. package/src/nodes/moments-digest/prelude.js +28 -0
  268. package/src/nodes/moments-digest/publish-to.js +31 -0
  269. package/src/nodes/moments-digest/recompute.js +9 -0
  270. package/src/nodes/moments-digest/reset.js +20 -0
  271. package/src/nodes/moments-digest/update.js +182 -0
  272. package/src/nodes/node-names.js +67 -0
  273. package/src/nodes/page-hinkley/index.js +20 -0
  274. package/src/nodes/page-hinkley/init.js +66 -0
  275. package/src/nodes/page-hinkley/introspect.js +193 -0
  276. package/src/nodes/page-hinkley/publish-to.js +28 -0
  277. package/src/nodes/page-hinkley/recompute.js +14 -0
  278. package/src/nodes/page-hinkley/reset.js +23 -0
  279. package/src/nodes/page-hinkley/update.js +105 -0
  280. package/src/nodes/pass-if/index.js +21 -0
  281. package/src/nodes/pass-if/init.js +37 -0
  282. package/src/nodes/pass-if/introspect.js +93 -0
  283. package/src/nodes/pass-if/publish-to.js +15 -0
  284. package/src/nodes/pass-if/recompute.js +15 -0
  285. package/src/nodes/pass-if/reset.js +18 -0
  286. package/src/nodes/pass-if/update.js +37 -0
  287. package/src/nodes/persist-if/helpers.js +111 -0
  288. package/src/nodes/persist-if/index.js +9 -0
  289. package/src/nodes/persist-if/init.js +98 -0
  290. package/src/nodes/persist-if/introspect.js +106 -0
  291. package/src/nodes/persist-if/publish-to.js +21 -0
  292. package/src/nodes/persist-if/recompute.js +20 -0
  293. package/src/nodes/persist-if/reset.js +35 -0
  294. package/src/nodes/persist-if/update.js +112 -0
  295. package/src/nodes/persistence-check/index.js +14 -0
  296. package/src/nodes/persistence-check/init.js +38 -0
  297. package/src/nodes/persistence-check/introspect.js +144 -0
  298. package/src/nodes/persistence-check/publish-to.js +11 -0
  299. package/src/nodes/persistence-check/recompute.js +7 -0
  300. package/src/nodes/persistence-check/reset.js +12 -0
  301. package/src/nodes/persistence-check/update.js +57 -0
  302. package/src/nodes/process-index/index.js +15 -0
  303. package/src/nodes/process-index/init.js +48 -0
  304. package/src/nodes/process-index/introspect.js +182 -0
  305. package/src/nodes/process-index/publish-to.js +29 -0
  306. package/src/nodes/process-index/recompute.js +8 -0
  307. package/src/nodes/process-index/reset.js +8 -0
  308. package/src/nodes/process-index/update.js +75 -0
  309. package/src/nodes/ratio/index.js +14 -0
  310. package/src/nodes/ratio/init.js +37 -0
  311. package/src/nodes/ratio/introspect.js +155 -0
  312. package/src/nodes/ratio/publish-to.js +15 -0
  313. package/src/nodes/ratio/recompute.js +7 -0
  314. package/src/nodes/ratio/reset.js +7 -0
  315. package/src/nodes/ratio/update.js +47 -0
  316. package/src/nodes/sanitize/index.js +82 -0
  317. package/src/nodes/sanitize/init.js +82 -0
  318. package/src/nodes/sanitize/introspect.js +194 -0
  319. package/src/nodes/sanitize/publish-to.js +15 -0
  320. package/src/nodes/sanitize/recompute.js +8 -0
  321. package/src/nodes/sanitize/reset.js +14 -0
  322. package/src/nodes/sanitize/update.js +102 -0
  323. package/src/nodes/spike-guard/index.js +14 -0
  324. package/src/nodes/spike-guard/init.js +47 -0
  325. package/src/nodes/spike-guard/introspect.js +130 -0
  326. package/src/nodes/spike-guard/publish-to.js +35 -0
  327. package/src/nodes/spike-guard/recompute.js +14 -0
  328. package/src/nodes/spike-guard/reset.js +19 -0
  329. package/src/nodes/spike-guard/update.js +89 -0
  330. package/src/nodes/sse-emitter/index.js +7 -0
  331. package/src/nodes/sse-emitter/init.js +105 -0
  332. package/src/nodes/sse-emitter/introspect.js +134 -0
  333. package/src/nodes/sse-emitter/publish-to.js +6 -0
  334. package/src/nodes/sse-emitter/recompute.js +16 -0
  335. package/src/nodes/sse-emitter/reset.js +19 -0
  336. package/src/nodes/sse-emitter/update.js +69 -0
  337. package/src/nodes/sse-emitter/utils/broadcast-heartbeat.js +36 -0
  338. package/src/nodes/sse-emitter/utils/build-message.js +31 -0
  339. package/src/nodes/sse-emitter/utils/connection-manager.js +45 -0
  340. package/src/nodes/sse-emitter/utils/endpoint-initializer.js +20 -0
  341. package/src/nodes/sse-emitter/utils/health-monitor.js +38 -0
  342. package/src/nodes/sse-emitter/utils/qos-handler.js +41 -0
  343. package/src/nodes/state-change-detector/helpers.js +35 -0
  344. package/src/nodes/state-change-detector/index.js +12 -0
  345. package/src/nodes/state-change-detector/init.js +56 -0
  346. package/src/nodes/state-change-detector/introspect.js +146 -0
  347. package/src/nodes/state-change-detector/publish-to.js +20 -0
  348. package/src/nodes/state-change-detector/recompute.js +6 -0
  349. package/src/nodes/state-change-detector/reset.js +20 -0
  350. package/src/nodes/state-change-detector/update.js +97 -0
  351. package/src/nodes/sw-stats/index.js +14 -0
  352. package/src/nodes/sw-stats/init.js +51 -0
  353. package/src/nodes/sw-stats/introspect.js +131 -0
  354. package/src/nodes/sw-stats/publish-to.js +45 -0
  355. package/src/nodes/sw-stats/recompute.js +33 -0
  356. package/src/nodes/sw-stats/reset.js +15 -0
  357. package/src/nodes/sw-stats/update.js +39 -0
  358. package/src/nodes/swing-watch/index.js +17 -0
  359. package/src/nodes/swing-watch/init.js +144 -0
  360. package/src/nodes/swing-watch/introspect.js +188 -0
  361. package/src/nodes/swing-watch/publish-to.js +53 -0
  362. package/src/nodes/swing-watch/recompute.js +22 -0
  363. package/src/nodes/swing-watch/reset.js +55 -0
  364. package/src/nodes/swing-watch/update.js +767 -0
  365. package/src/nodes/tally/index.js +15 -0
  366. package/src/nodes/tally/init.js +32 -0
  367. package/src/nodes/tally/introspect.js +116 -0
  368. package/src/nodes/tally/publish-to.js +28 -0
  369. package/src/nodes/tally/recompute.js +10 -0
  370. package/src/nodes/tally/reset.js +10 -0
  371. package/src/nodes/tally/update.js +44 -0
  372. package/src/nodes/threshold/index.js +14 -0
  373. package/src/nodes/threshold/init.js +121 -0
  374. package/src/nodes/threshold/introspect.js +192 -0
  375. package/src/nodes/threshold/publish-to.js +11 -0
  376. package/src/nodes/threshold/recompute.js +8 -0
  377. package/src/nodes/threshold/reset.js +14 -0
  378. package/src/nodes/threshold/update.js +54 -0
  379. package/src/nodes/transform/helpers.js +39 -0
  380. package/src/nodes/transform/index.js +15 -0
  381. package/src/nodes/transform/init.js +35 -0
  382. package/src/nodes/transform/introspect.js +118 -0
  383. package/src/nodes/transform/publish-to.js +23 -0
  384. package/src/nodes/transform/recompute.js +12 -0
  385. package/src/nodes/transform/reset.js +11 -0
  386. package/src/nodes/transform/update.js +32 -0
  387. package/src/nodes/trend/compute-confidence.js +112 -0
  388. package/src/nodes/trend/index.js +14 -0
  389. package/src/nodes/trend/init.js +81 -0
  390. package/src/nodes/trend/introspect.js +151 -0
  391. package/src/nodes/trend/publish-to.js +22 -0
  392. package/src/nodes/trend/recompute.js +15 -0
  393. package/src/nodes/trend/reset.js +26 -0
  394. package/src/nodes/trend/update.js +93 -0
  395. package/src/nodes/tw-stats/copy-from.js +16 -0
  396. package/src/nodes/tw-stats/flush.js +12 -0
  397. package/src/nodes/tw-stats/index.js +41 -0
  398. package/src/nodes/tw-stats/init.js +92 -0
  399. package/src/nodes/tw-stats/introspect.js +171 -0
  400. package/src/nodes/tw-stats/publish-to.js +108 -0
  401. package/src/nodes/tw-stats/recompute.js +9 -0
  402. package/src/nodes/tw-stats/reset.js +16 -0
  403. package/src/nodes/tw-stats/update.js +113 -0
  404. package/src/nodes/unbalance/index.js +15 -0
  405. package/src/nodes/unbalance/init.js +59 -0
  406. package/src/nodes/unbalance/introspect.js +167 -0
  407. package/src/nodes/unbalance/publish-to.js +52 -0
  408. package/src/nodes/unbalance/recompute.js +11 -0
  409. package/src/nodes/unbalance/reset.js +10 -0
  410. package/src/nodes/unbalance/update.js +83 -0
  411. package/src/nodes/vector-distance/index.js +14 -0
  412. package/src/nodes/vector-distance/init.js +54 -0
  413. package/src/nodes/vector-distance/introspect.js +149 -0
  414. package/src/nodes/vector-distance/publish-to.js +35 -0
  415. package/src/nodes/vector-distance/recompute.js +11 -0
  416. package/src/nodes/vector-distance/reset.js +20 -0
  417. package/src/nodes/vector-distance/update.js +139 -0
  418. package/src/nodes/winnow/index.js +12 -0
  419. package/src/nodes/winnow/init.js +82 -0
  420. package/src/nodes/winnow/introspect.js +253 -0
  421. package/src/nodes/winnow/publish-to.js +51 -0
  422. package/src/nodes/winnow/recompute.js +14 -0
  423. package/src/nodes/winnow/reset.js +34 -0
  424. package/src/nodes/winnow/update.js +203 -0
  425. package/src/tools/training/features.js +227 -0
  426. package/src/tools/training/index.js +21 -0
  427. package/src/tools/training/logistic.js +238 -0
  428. package/src/tools/training/metrics.js +126 -0
  429. package/src/tools/training/scale.js +239 -0
  430. package/src/tools/training/validate.js +103 -0
  431. package/src/windowing/count-sliding/create.js +16 -0
  432. package/src/windowing/count-sliding/get-reverse-chronological-index.js +19 -0
  433. package/src/windowing/count-sliding/index.js +6 -0
  434. package/src/windowing/count-sliding/is-not-full.js +5 -0
  435. package/src/windowing/count-sliding/push.js +15 -0
  436. package/src/windowing/count-sliding/reset.js +11 -0
  437. package/src/windowing/count-sliding/size.js +5 -0
  438. package/src/windowing/time-sliding/create.js +25 -0
  439. package/src/windowing/time-sliding/push.js +42 -0
  440. package/CODE_OF_CONDUCT.md +0 -46
  441. package/CONTRIBUTING.md +0 -132
  442. package/docs/.nojekyll +0 -0
  443. package/docs/CONTRIBUTING.md +0 -134
  444. package/docs/README.md +0 -132
  445. package/docs/_coverpage.md +0 -26
  446. package/docs/_media/bg.png +0 -0
  447. package/docs/_media/wink-logo.png +0 -0
  448. package/docs/_navbar.md +0 -14
  449. package/docs/_sidebar.md +0 -2
  450. package/docs/index.html +0 -44
  451. package/eslint.config.js +0 -283
@@ -0,0 +1,15 @@
1
+ // nodes/trend/recompute.js
2
+
3
+ const recompute = function ( state ) {
4
+ // Ensure rate variance stays bounded
5
+ if ( state.rocVariance < 0 ) {
6
+ state.rocVariance = 0;
7
+ }
8
+
9
+ // No long-running accumulations that need recomputation
10
+ // Rate-based algorithm is inherently stable
11
+
12
+ return true;
13
+ }; // recompute()
14
+
15
+ export default recompute;
@@ -0,0 +1,26 @@
1
+ // nodes/trend/reset.js
2
+
3
+ const reset = function ( state ) {
4
+ state.previousValue = null;
5
+
6
+ state.rocMean = 0;
7
+ state.rocVariance = 0;
8
+
9
+ if ( state.stats.accelerationHint ) {
10
+ state.rocSmoothedFast = 0;
11
+ state.accelerationHint = null;
12
+ }
13
+
14
+ state.samples = 0;
15
+ state.consistentSamples = 0;
16
+
17
+ state.previousTrend = 'learning';
18
+ state.trend = 'learning';
19
+ state.confidence = 0;
20
+ // Clear error suppression so next error episode is logged
21
+ state.tunableErrorLogged = false;
22
+
23
+ return true;
24
+ }; // reset()
25
+
26
+ export default reset;
@@ -0,0 +1,93 @@
1
+ // nodes/trend/update.js
2
+
3
+ import { computeConfidence } from './compute-confidence.js';
4
+
5
+ const update = function ( state, msg ) {
6
+ if ( state.disable || state.pause ) return state;
7
+ const xVal = msg[ state.x ];
8
+ // Reset on each update
9
+ state.inputValidationFailed = false;
10
+ // Handle faults gracefully: ensure their isolation
11
+ if ( !Number.isFinite( xVal ) ) {
12
+ // Signals publishing NaN for all demanded `stats` in publishTo.
13
+ state.inputValidationFailed = true;
14
+ return state;
15
+ }
16
+
17
+ state.samples += 1;
18
+
19
+ if ( state.previousValue === null ) {
20
+ state.previousValue = xVal;
21
+ // This ensures the first roc value is a real one and not 0.
22
+ return state;
23
+ }
24
+
25
+ // Step 1: Lag(1) for roc
26
+ const roc = xVal - state.previousValue;
27
+ state.previousValue = xVal;
28
+
29
+ // Step 2: Track roc statistics
30
+ const rocResidual = roc - state.rocMean;
31
+ state.rocMean += ( state.rocAlpha * rocResidual );
32
+ state.rocVariance += ( state.rocAlpha * ( ( rocResidual * rocResidual ) - state.rocVariance ) );
33
+
34
+ // Step 3: Track roc at a faster roc for acceleration hint
35
+ if ( state.stats.accelerationHint ) {
36
+ state.rocSmoothedFast += ( state.accelAlpha * ( roc - state.rocSmoothedFast ) );
37
+ }
38
+
39
+ // Step 4: Classification
40
+ state.previousTrend = state.trend;
41
+
42
+ // Resolve rocThreshold tunable for this message
43
+ try {
44
+ // If tunable throws, last good value is retained.
45
+ state.rocThreshold = state.rocThresholdFn( msg );
46
+ if ( state.tunableErrorLogged ) state.tunableErrorLogged = false;
47
+ } catch ( error ) {
48
+ if ( !state.tunableErrorLogged ) {
49
+ state.tunableErrorLogged = true;
50
+ console.error( `WinkComposer/${state.nodeType}: tunable threw: ${error.message}` );
51
+ }
52
+ }
53
+
54
+ if ( state.samples < state.warmupSamples ) {
55
+ state.trend = 'learning';
56
+ } else if ( Math.abs( state.rocMean ) < state.rocThreshold ) {
57
+ state.trend = 'stable';
58
+ } else {
59
+ state.trend = state.rocMean > 0 ? 'rising' : 'falling';
60
+ }
61
+
62
+ // Track consistency
63
+ if ( state.trend === state.previousTrend ) {
64
+ state.consistentSamples += 1;
65
+ } else {
66
+ state.consistentSamples = 0;
67
+ }
68
+
69
+ // Step 5: Confidence computation
70
+ state.confidence = computeConfidence( state );
71
+
72
+ // Step 6: Acceleration hint
73
+ if ( state.stats.accelerationHint && ( state.samples > ( state.warmupSamplesForAccel ) ) ) {
74
+ // fast > mean ⇒ likely_accelerating
75
+ const accelProxy = state.rocSmoothedFast - state.rocMean;
76
+
77
+ // Basic SNR & persistence gates
78
+ const passesSNR = state.snr >= 1.5; // require decent roc SNR
79
+ const accelThreshold = 0.75 * state.rocThreshold; // derive from current rocThreshold
80
+ const passesBand = Math.abs( accelProxy ) >= accelThreshold; // ignore tiny curvature
81
+ const persistent = state.consistentSamples >= 3; // brief dwell
82
+
83
+ if ( passesSNR && passesBand && persistent ) {
84
+ state.accelerationHint = ( accelProxy > 0 ) ? 'likely_accelerating' : 'likely_decelerating';
85
+ } else {
86
+ state.accelerationHint = null;
87
+ }
88
+ }
89
+
90
+ return state;
91
+ }; // update()
92
+
93
+ export default update;
@@ -0,0 +1,16 @@
1
+ // nodes/tw-stats/copy-from.js
2
+
3
+ /**
4
+ * Copies Pébay accumulators from source to destination.
5
+ * Used to snapshot live state before reset at window completion or flush.
6
+ */
7
+ export const copyFrom = function ( source, destination ) {
8
+ destination.n = source.n;
9
+ destination.M1 = source.M1;
10
+ destination.M2 = source.M2;
11
+ destination.M3 = source.M3;
12
+ destination.M4 = source.M4;
13
+ destination.min = source.min;
14
+ destination.max = source.max;
15
+ return destination;
16
+ };
@@ -0,0 +1,12 @@
1
+ // nodes/tw-stats/flush.js
2
+
3
+ /**
4
+ * Forces publication of incomplete window.
5
+ * Used for graceful shutdown or event-driven snapshots.
6
+ */
7
+ const flush = function ( state ) {
8
+ state.flushLatched = true;
9
+ return true;
10
+ }; // flush()
11
+
12
+ export default flush;
@@ -0,0 +1,41 @@
1
+ // nodes/tw-stats/index.js
2
+
3
+ /**
4
+ * @fileoverview
5
+ * TW Stats — Tumbling window statistics with Pébay's numerically stable
6
+ * algorithm for incremental moment accumulation.
7
+ *
8
+ * ────────────────────────────────────────────────────────────────────────
9
+ * Replaces the two-node chain (momentsDigest → digestMoments) for the
10
+ * common case of computing statistics over count-based tumbling windows.
11
+ *
12
+ * Key properties:
13
+ * • O(1) memory per partition — no ring buffer; Pébay incremental accumulation
14
+ * • Selective moment accumulation — maxMoment (1–4) resolved at init from
15
+ * demanded stats; if/then gating in update, not closures (100K-safe)
16
+ * • Deferred stat conversion — moment-to-stat formulas applied only in
17
+ * publishTo on window completion or flush, not every update tick
18
+ * • Invalid samples skipped (not counted); window fills with valid samples only
19
+ * • Publishes on window completion or flush; scrubs to undefined on other ticks
20
+ * • Supports windowSize from 4 to 1,000,000
21
+ *
22
+ * ────────────────────────────────────────────────────────────────────────
23
+ * References
24
+ * [1] Pébay, P. (2008). Formulas for robust, one-pass parallel computation
25
+ * of covariances and arbitrary-order statistical moments.
26
+ * Sandia Report SAND2008-6212.
27
+ */
28
+
29
+ export { default as init } from './init.js';
30
+ export { default as update } from './update.js';
31
+ export { default as reset } from './reset.js';
32
+ export { default as recompute } from './recompute.js';
33
+ export { default as publishTo } from './publish-to.js';
34
+ export { default as flush } from './flush.js';
35
+ // Direct imports for common control functions
36
+ export { default as disable } from '../../core/utils/node/disable.js';
37
+ export { default as enable } from '../../core/utils/node/enable.js';
38
+ export { default as pause } from '../../core/utils/node/pause.js';
39
+ export { default as unpause } from '../../core/utils/node/unpause.js';
40
+ // Re-export everything from introspection.js
41
+ export * from './introspect.js';
@@ -0,0 +1,92 @@
1
+ // nodes/tw-stats/init.js
2
+
3
+ /**
4
+ * @fileoverview Initialization for twStats node.
5
+ *
6
+ * Resolves the selective accumulation tier (maxMoment 1–4) from demanded
7
+ * stats at init time. All allocations happen here; update() is zero-alloc.
8
+ */
9
+
10
+ import { validateSpec } from '../../core/utils/node/index.js';
11
+ import * as introspect from './introspect.js';
12
+ import { resolveScalar } from '../../core/utils/options/resolve-field-keyed.js';
13
+
14
+ // Stats that require M2 accumulation
15
+ const NEEDS_M2 = [ 'variance', 'stddev', 'cv', 'skew', 'kurtosis', 'rms', 'crestFactor' ];
16
+
17
+ const init = function ( spec ) {
18
+ validateSpec( spec, introspect );
19
+
20
+ const state = Object.create( null );
21
+
22
+ // Standard flags (all nodes)
23
+ state.inputValidationFailed = false;
24
+ state.disable = false;
25
+ state.pause = false;
26
+
27
+ // Preserve node's name — used for msg[name] = true on publish
28
+ state.name = spec.name;
29
+
30
+ // Input field name
31
+ state.x = spec.from.x;
32
+
33
+ // Resolve options (field-keyed support for windowSize)
34
+ const windowSizeSpec = resolveScalar( spec.windowSize, state.x );
35
+ state.windowSize = windowSizeSpec ?? introspect.DEFAULT_OPTIONS.windowSize;
36
+ state.biased = spec.biased || introspect.DEFAULT_OPTIONS.biased;
37
+ state.epsilon = spec.epsilon ?? introspect.DEFAULT_OPTIONS.epsilon;
38
+
39
+ // Copy stats config (Object.create(null) for clean prototype)
40
+ state.stats = Object.assign( Object.create( null ), spec.stats );
41
+
42
+ // Determine selective accumulation tier from demanded stats
43
+ const statsList = Object.keys( state.stats );
44
+ const needsM2 = statsList.some( ( s ) => NEEDS_M2.includes( s ) );
45
+ const needsM3 = statsList.includes( 'skew' ) || statsList.includes( 'kurtosis' );
46
+ const needsM4 = statsList.includes( 'kurtosis' );
47
+
48
+ if ( needsM4 ) {
49
+ state.maxMoment = 4;
50
+ } else if ( needsM3 ) {
51
+ state.maxMoment = 3;
52
+ } else if ( needsM2 ) {
53
+ state.maxMoment = 2;
54
+ } else {
55
+ state.maxMoment = 1;
56
+ }
57
+
58
+ state.needsMinMax = !!( state.stats.min || state.stats.max || state.stats.crestFactor );
59
+ state.needsRms = !!( state.stats.rms || state.stats.crestFactor );
60
+
61
+ // Pébay algorithm accumulators
62
+ state.n = 0;
63
+ state.M1 = 0;
64
+ state.M2 = 0;
65
+ state.M3 = 0;
66
+ state.M4 = 0;
67
+ state.min = Infinity;
68
+ state.max = -Infinity;
69
+
70
+ // Window management
71
+ state.currentCount = 0;
72
+
73
+ // Publish control
74
+ state.planPublish = false;
75
+ state.flushLatched = false;
76
+
77
+ // Snapshot: holds moments at window completion for publishTo to read
78
+ state.snapshot = Object.create( null );
79
+
80
+ // Pre-compute scrubKeys for efficient non-publish scrubbing
81
+ state.scrubKeys = [];
82
+ // eslint-disable-next-line guard-for-in
83
+ for ( const stat in state.stats ) {
84
+ state.scrubKeys.push( state.stats[ stat ].storeAs );
85
+ }
86
+
87
+ state.nodeType = introspect.getNodeType();
88
+
89
+ return state;
90
+ }; // init()
91
+
92
+ export default init;
@@ -0,0 +1,171 @@
1
+ // nodes/tw-stats/introspect.js
2
+
3
+ /**
4
+ * @fileoverview Introspection module for twStats node.
5
+ *
6
+ * Tumbling window statistics: accumulates Pébay moments over a count-based
7
+ * window, publishes computed statistics (mean, variance, stddev, cv, skew,
8
+ * kurtosis, min, max, n) on window completion or flush.
9
+ *
10
+ * Selective accumulation: only the moments needed by demanded stats are
11
+ * computed on the hot path. The maxMoment tier (1–4) is resolved at init.
12
+ */
13
+
14
+ import { validators } from '../../core/utils/validate/index.js';
15
+
16
+ /** Single source of truth for what statistics this node can compute */
17
+ const SUPPORTED_STATS = [
18
+ 'n',
19
+ 'mean',
20
+ 'variance',
21
+ 'stddev',
22
+ 'cv',
23
+ 'skew',
24
+ 'kurtosis',
25
+ 'min',
26
+ 'max',
27
+ 'rms',
28
+ 'crestFactor'
29
+ ];
30
+
31
+ /** Human-readable descriptions (for introspection) */
32
+ const STAT_DESCRIPTIONS = {
33
+ n: 'Number of valid samples in the completed window',
34
+ mean: 'Arithmetic mean (first moment M1)',
35
+ variance: 'Sample variance: M2 / (n - 1) for unbiased, M2 / n for biased',
36
+ stddev: 'Sample standard deviation: sqrt(variance)',
37
+ cv: 'Coefficient of variation: stddev / |mean|',
38
+ skew: 'Population skewness: m3 / m2^1.5',
39
+ kurtosis: 'Population excess kurtosis: m4 / m2^2 - 3',
40
+ min: 'Minimum value across all samples in the window',
41
+ max: 'Maximum value across all samples in the window',
42
+ rms: 'Root mean square: sqrt(M2/n + M1²)',
43
+ crestFactor: 'Crest factor: peak / RMS — max(|min|, |max|) / rms'
44
+ };
45
+
46
+ /** Control methods available for triggers */
47
+ const SUPPORTED_CONTROL_METHODS = {
48
+ reset: 'Clears accumulated state and restarts computation',
49
+ enable: 'Enables node processing',
50
+ disable: 'Disables node processing',
51
+ pause: 'Pauses update processing while allowing publishTo to continue',
52
+ unpause: 'Resumes update processing after a pause',
53
+ flush: 'Forces immediate output of partial window'
54
+ };
55
+
56
+ /** Node capabilities for documentation */
57
+ const CAPABILITIES = {
58
+ description: 'Tumbling window statistics using Pébay\'s numerically stable algorithm',
59
+ features: [
60
+ 'Configurable window-based aggregation (4 to 1,000,000 samples)',
61
+ 'Selective moment accumulation: only computes moments needed by demanded stats',
62
+ 'Deferred stat conversion: formulas applied only at publish time',
63
+ 'Numerically stable incremental computation (Pébay 2008)',
64
+ 'Invalid samples skipped without corrupting statistics',
65
+ 'Flush support for graceful shutdown with partial windows',
66
+ 'Zero allocations in hot path for maximum throughput',
67
+ 'O(1) memory regardless of window size'
68
+ ]
69
+ };
70
+
71
+ /** The type of this node */
72
+ const NODE_TYPE = 'TW Stats';
73
+
74
+ // Attach static metadata once, from our constants by making a shallow copy.
75
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
76
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
77
+ export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
78
+ export const getNodeType = () => NODE_TYPE;
79
+ export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
80
+
81
+ export const DEFAULT_OPTIONS = {
82
+ windowSize: 100,
83
+ biased: false,
84
+ epsilon: 1e-12
85
+ };
86
+
87
+ // DSL Metadata for transpilation
88
+ const DSL_METADATA = {
89
+ // Spec schema for validation
90
+ specSchema: {
91
+ nodeType: {
92
+ type: 'string',
93
+ required: true,
94
+ value: NODE_TYPE
95
+ },
96
+ name: {
97
+ type: 'string',
98
+ required: true,
99
+ validator: validators.identifier,
100
+ error: 'Name must be a valid identifier'
101
+ },
102
+ from: {
103
+ type: 'object',
104
+ required: true,
105
+ properties: {
106
+ x: {
107
+ type: 'string',
108
+ required: true,
109
+ validator: validators.noSpaces,
110
+ error: 'Field name cannot contain spaces'
111
+ }
112
+ }
113
+ },
114
+ windowSize: {
115
+ type: 'numberOrFieldKeyed',
116
+ required: false,
117
+ default: DEFAULT_OPTIONS.windowSize,
118
+ integer: true,
119
+ min: 4,
120
+ max: 1000000,
121
+ validator: validators.positiveInteger,
122
+ error: 'Window size must be a positive integer; minimum 4, maximum 1,000,000'
123
+ },
124
+ biased: {
125
+ type: 'boolean',
126
+ required: false,
127
+ default: DEFAULT_OPTIONS.biased
128
+ },
129
+ epsilon: {
130
+ type: 'number',
131
+ required: false,
132
+ default: DEFAULT_OPTIONS.epsilon,
133
+ min: 0,
134
+ error: 'Epsilon must be a non-negative number'
135
+ },
136
+ stats: {
137
+ type: 'object',
138
+ required: true,
139
+ minProperties: 1,
140
+ propertyNames: SUPPORTED_STATS,
141
+ propertySchema: {
142
+ type: 'object',
143
+ required: true,
144
+ properties: {
145
+ storeAs: {
146
+ type: 'string',
147
+ required: true,
148
+ minLength: 1,
149
+ validator: validators.identifier,
150
+ error: 'storeAs must be a valid identifier'
151
+ }
152
+ }
153
+ }
154
+ }
155
+ },
156
+
157
+ // Cross-field validators (none needed for twStats)
158
+ crossFieldValidators: [],
159
+
160
+ // How to build the spec from DSL params
161
+ // Pattern: NAME_X_OUTPUTS_OPTIONS -> (name, x, stats, options)
162
+ buildSpec: ( name, x, stats, options ) => ( {
163
+ nodeType: NODE_TYPE,
164
+ name,
165
+ from: { x },
166
+ stats,
167
+ ...options
168
+ } )
169
+ };
170
+
171
+ export const getDSLMetadata = () => ( { ...DSL_METADATA } );
@@ -0,0 +1,108 @@
1
+ // nodes/tw-stats/publish-to.js
2
+
3
+ /**
4
+ * @fileoverview TW Stats Publish — deferred stat conversion from snapshot.
5
+ *
6
+ * On publish ticks (window completion or flush): computes final statistics
7
+ * from the Pébay moment snapshot and writes them to the message.
8
+ *
9
+ * On non-publish ticks: scrubs all storeAs fields to undefined to prevent
10
+ * downstream from reading stale data.
11
+ *
12
+ * No publishNaN — invalid samples are skipped in update(); a flush snapshot
13
+ * planned in the prelude still publishes regardless of the current input.
14
+ */
15
+
16
+ import { computeVariance, computeCV, computeSkew, computeKurtosis } from '../../core/utils/stats/formulas.js';
17
+
18
+ /**
19
+ * Publish variance-dependent stats when m2 is above epsilon.
20
+ * Extracted to keep publishTo within nesting depth limits.
21
+ */
22
+ const publishVarianceStats = function ( state, msg, s, n, m2 ) {
23
+ const variance = computeVariance( s.M2, n, state.biased );
24
+ const stddev = Math.sqrt( variance );
25
+ const stats = state.stats;
26
+ const eps = state.epsilon;
27
+
28
+ if ( stats.variance ) msg[ stats.variance.storeAs ] = variance;
29
+ if ( stats.stddev ) msg[ stats.stddev.storeAs ] = stddev;
30
+ if ( stats.cv ) msg[ stats.cv.storeAs ] = computeCV( stddev, s.M1, eps );
31
+ if ( stats.skew ) msg[ stats.skew.storeAs ] = computeSkew( s.M3, n, m2, eps );
32
+ if ( stats.kurtosis ) msg[ stats.kurtosis.storeAs ] = computeKurtosis( s.M4, n, m2, eps );
33
+ }; // publishVarianceStats()
34
+
35
+ /**
36
+ * Set all variance-dependent stats to NaN.
37
+ * Used when n < 2 or variance is not computable.
38
+ */
39
+ const publishVarianceNaN = function ( stats, msg ) {
40
+ if ( stats.variance ) msg[ stats.variance.storeAs ] = NaN;
41
+ if ( stats.stddev ) msg[ stats.stddev.storeAs ] = NaN;
42
+ if ( stats.cv ) msg[ stats.cv.storeAs ] = NaN;
43
+ if ( stats.skew ) msg[ stats.skew.storeAs ] = NaN;
44
+ if ( stats.kurtosis ) msg[ stats.kurtosis.storeAs ] = NaN;
45
+ }; // publishVarianceNaN()
46
+
47
+ /**
48
+ * Set variance-dependent stats for near-zero variance (m2 < epsilon).
49
+ * Variance and stddev are 0; cv, skew, kurtosis degenerate.
50
+ */
51
+ const publishVarianceZero = function ( stats, msg ) {
52
+ if ( stats.variance ) msg[ stats.variance.storeAs ] = 0;
53
+ if ( stats.stddev ) msg[ stats.stddev.storeAs ] = 0;
54
+ if ( stats.cv ) msg[ stats.cv.storeAs ] = NaN;
55
+ if ( stats.skew ) msg[ stats.skew.storeAs ] = 0;
56
+ if ( stats.kurtosis ) msg[ stats.kurtosis.storeAs ] = -3;
57
+ }; // publishVarianceZero()
58
+
59
+ const publishTo = function ( state, msg ) {
60
+ if ( state.disable ) return;
61
+
62
+ if ( state.planPublish ) {
63
+ const s = state.snapshot;
64
+ const n = s.n;
65
+ const stats = state.stats;
66
+
67
+ // Always-available stats
68
+ if ( stats.n ) msg[ stats.n.storeAs ] = n;
69
+ if ( stats.mean ) msg[ stats.mean.storeAs ] = s.M1;
70
+ if ( stats.min ) msg[ stats.min.storeAs ] = s.min;
71
+ if ( stats.max ) msg[ stats.max.storeAs ] = s.max;
72
+
73
+ // Variance-dependent stats (require maxMoment >= 2)
74
+ if ( state.maxMoment >= 2 ) {
75
+ if ( n >= 2 ) {
76
+ const m2 = s.M2 / n;
77
+ if ( m2 >= state.epsilon ) {
78
+ publishVarianceStats( state, msg, s, n, m2 );
79
+ } else {
80
+ publishVarianceZero( stats, msg );
81
+ }
82
+ } else {
83
+ publishVarianceNaN( stats, msg );
84
+ }
85
+ }
86
+
87
+ // Derived stats: RMS and crest factor (cold-path only, from existing accumulators)
88
+ if ( state.needsRms ) {
89
+ const rms = Math.sqrt( ( s.M2 / n ) + ( s.M1 * s.M1 ) );
90
+ if ( stats.rms ) msg[ stats.rms.storeAs ] = rms;
91
+ if ( stats.crestFactor ) {
92
+ const peak = Math.max( Math.abs( s.min ), Math.abs( s.max ) );
93
+ msg[ stats.crestFactor.storeAs ] = ( rms > state.epsilon ) ? ( peak / rms ) : NaN;
94
+ }
95
+ }
96
+
97
+ msg[ state.name ] = true;
98
+ return;
99
+ }
100
+
101
+ // Non-publish tick: scrub all storeAs fields to undefined
102
+ const keys = state.scrubKeys;
103
+ for ( let i = 0; i < keys.length; i += 1 ) {
104
+ msg[ keys[ i ] ] = undefined;
105
+ }
106
+ }; // publishTo()
107
+
108
+ export default publishTo;
@@ -0,0 +1,9 @@
1
+ // nodes/tw-stats/recompute.js
2
+
3
+ const recompute = function () {
4
+ // Pébay moments are computed incrementally using a numerically stable
5
+ // algorithm. No recomputation needed (no ring buffer to reconstruct from).
6
+ return true;
7
+ }; // recompute()
8
+
9
+ export default recompute;
@@ -0,0 +1,16 @@
1
+ // nodes/tw-stats/reset.js
2
+
3
+ const reset = function ( state ) {
4
+ state.n = 0;
5
+ state.M1 = 0;
6
+ state.M2 = 0;
7
+ state.M3 = 0;
8
+ state.M4 = 0;
9
+ state.min = Infinity;
10
+ state.max = -Infinity;
11
+ state.currentCount = 0;
12
+
13
+ return true;
14
+ }; // reset()
15
+
16
+ export default reset;