@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,27 @@
1
+ /**
2
+ * @fileoverview Reset function for emitIf node
3
+ *
4
+ * Resets statistics and state tracking.
5
+ */
6
+
7
+ const reset = function ( state ) {
8
+ // Reset statistics
9
+ state.emissionCount = 0;
10
+ state.passCount = 0;
11
+ state.lastEmissionTime = null;
12
+ state.emissionErrors = 0;
13
+ state.lastEmissionError = null;
14
+ state.lastEmissionErrorCode = null;
15
+ state.firstEmissionError = null;
16
+ state.firstEmissionErrorCode = null;
17
+
18
+ // Reset state tracking
19
+ state.inErrorState = false;
20
+ // Clear error suppression so next error episode is logged
21
+ state.predicateErrorLogged = false;
22
+ state.emitErrorLogged = false;
23
+
24
+ return true;
25
+ }; // reset()
26
+
27
+ export default reset;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @fileoverview Update function for emitIf node
3
+ *
4
+ * Hot path — evaluates user-supplied predicate and emits to external
5
+ * systems when true. Predicate errors are caught and tracked per-episode.
6
+ *
7
+ * Publishes unconditionally — no connectivity pre-check (ADR-018). The
8
+ * old isConnected() guard skipped publishes during MQTT disconnects, which
9
+ * kept messages OUT of the emitter's buffer: the exact loss buffering
10
+ * exists to prevent. (ADR-021 later replaced the on-disk offline store
11
+ * with an in-process buffer; the invariant is unchanged.) The emitter's
12
+ * { ok } return is the only truth
13
+ * the node consumes; a failure opens a loud episode (mirroring persistIf —
14
+ * the two output gates share one failure model).
15
+ */
16
+
17
+ import { assertAnnotateReturn, emitStatusSignal, recordEmissionFailure, MALFORMED_RESULT_ERROR } from './helpers.js';
18
+
19
+ const update = function ( state, msg ) {
20
+ // Always increment pass count for observability
21
+ state.passCount += 1;
22
+
23
+ // Early exit if emitter not available (mirrors persistIf's storage guard)
24
+ if ( !state.emitter ) {
25
+ return state;
26
+ }
27
+
28
+ // Evaluate predicate, then shape the payload when emitting. Annotate
29
+ // mirrors persistIf: both run inside one try, so predicate and
30
+ // annotate share the same error episode (tracking, log suppression,
31
+ // recovery).
32
+ try {
33
+ const shouldEmit = state.predicate( msg );
34
+ let data = msg;
35
+ if ( shouldEmit && state.annotate ) {
36
+ data = state.annotate( msg );
37
+ // A flow-authoring bug (non-object return) throws here, into
38
+ // this node's error episode — never published as-is (mirrors
39
+ // persistIf).
40
+ assertAnnotateReturn( data );
41
+ }
42
+
43
+ if ( shouldEmit ) {
44
+ // Per the ADR-018 sink return contract, the emitter answers
45
+ // { ok: true } on success or
46
+ // { ok: false, error: { code, message } } on failure.
47
+ const result = state.emitter.publishNow( state.topic, data );
48
+
49
+ if ( result && result.ok ) {
50
+ state.emissionCount += 1;
51
+ state.lastEmissionTime = Date.now();
52
+ // Recovery: a successful publish closes the failure episode.
53
+ if ( state.emitErrorLogged ) state.emitErrorLogged = false;
54
+ } else {
55
+ // A malformed result (no object at all, or ok:false with no
56
+ // error) counts as a failure with the static fallback error,
57
+ // so a non-conforming adapter can neither fail silently
58
+ // nor throw out of the hot path.
59
+ recordEmissionFailure( state, ( result && result.error ) || MALFORMED_RESULT_ERROR );
60
+ }
61
+ }
62
+
63
+ // Clear error state on successful evaluation
64
+ if ( state.inErrorState ) {
65
+ state.inErrorState = false;
66
+ emitStatusSignal( state, false, 'recovered' );
67
+ }
68
+ // Recovery: clear log-suppression flag on success
69
+ if ( state.predicateErrorLogged ) state.predicateErrorLogged = false;
70
+ } catch ( error ) {
71
+ // Handle predicate errors (semantic — emits status signal)
72
+ if ( !state.inErrorState ) {
73
+ state.inErrorState = true;
74
+ emitStatusSignal( state, true, error.message );
75
+ }
76
+ // Log first error per episode; suppress subsequent until recovery
77
+ if ( !state.predicateErrorLogged ) {
78
+ state.predicateErrorLogged = true;
79
+ console.error( `WinkComposer/emitIf: predicate threw exception: ${error.message}` );
80
+ }
81
+ state.emissionErrors += 1;
82
+ state.lastEmissionError = error.message;
83
+ // Predicate exceptions are emit-if-internal, not part of the
84
+ // ADR-018 adapter err.code vocabulary. Clear the code so the two
85
+ // fields stay in sync (a stale code from a prior publish failure
86
+ // would mislead readers).
87
+ state.lastEmissionErrorCode = null;
88
+ }
89
+
90
+ return state;
91
+ }; // update()
92
+
93
+ export default update;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @fileoverview Barrel module for the es-correlation node. Re-exports lifecycle
3
+ * methods (init, update, reset, recompute, publishTo), shared control signals
4
+ * (disable, enable, pause, unpause), and all introspection metadata.
5
+ */
6
+ // nodes/es-correlation/index.js
7
+
8
+ export { default as init } from './init.js';
9
+ export { default as update } from './update.js';
10
+ export { default as reset } from './reset.js';
11
+ export { default as recompute } from './recompute.js';
12
+ export { default as publishTo } from './publish-to.js';
13
+ // Direct imports for common control functions
14
+ export { default as disable } from '../../core/utils/node/disable.js';
15
+ export { default as enable } from '../../core/utils/node/enable.js';
16
+ export { default as pause } from '../../core/utils/node/pause.js';
17
+ export { default as unpause } from '../../core/utils/node/unpause.js';
18
+ // Re-export everything from introspection.js
19
+ export * from './introspect.js';
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @fileoverview Initializes es-correlation node state from a validated spec.
3
+ * Derives the smoothing factor (alpha) from the configured half-life,
4
+ * pre-allocates all state properties on a prototype-free object — no
5
+ * allocations occur on the hot path.
6
+ */
7
+ // nodes/es-correlation/init.js
8
+
9
+ import { validateSpec } from '../../core/utils/node/index.js';
10
+ import * as introspect from './introspect.js';
11
+ import { halfLifeToAlpha, halfLifeToWarmupSamples } from '../../core/utils/half-life/index.js';
12
+
13
+ const fisherZCap = 0.9999;
14
+
15
+ const init = function ( spec ) {
16
+ // Validate against (updated) schema that uses halfLife
17
+ validateSpec( spec, introspect );
18
+
19
+ // Create state after validation passes
20
+ const state = Object.create( null );
21
+ // Standard input parameter health flag during update: false means healthy
22
+ state.inputValidationFailed = false;
23
+ // Ensure node is enabled by default
24
+ state.disable = false;
25
+ state.pause = false;
26
+
27
+ // Required fields for correlation computation
28
+ state.x = spec.from.x;
29
+ state.y = spec.from.y;
30
+
31
+ // Config copy for output field mapping
32
+ state.stats = spec.stats;
33
+
34
+ // Half-life based configuration (samples). If not provided, fall back to introspect defaults.
35
+ state.halfLife = spec.halfLife ?? introspect.DEFAULT_OPTIONS.halfLife;
36
+
37
+ // Derive alpha from half-life for hot-path math
38
+ state.alpha = halfLifeToAlpha( state.halfLife );
39
+
40
+ // Variance floor (retain existing default behavior if unspecified)
41
+ state.minVariance = spec.minVariance ?? introspect.DEFAULT_OPTIONS.minVariance;
42
+
43
+ // Warmup: if not provided, compute minSamples to reach ~95% settled response
44
+ // Using HL→samples mapping keeps early estimates reliable without manual tuning
45
+ state.minSamples = spec.minSamples ?? halfLifeToWarmupSamples( state.halfLife, 0.85 );
46
+
47
+ // Optional Fisher Z transformation enablement; keep existing cap behavior
48
+ state.fisherZCap = ( spec.fisherZT === true ) ? fisherZCap : 1;
49
+
50
+ // Core state variables for numerically stable ES computation.
51
+ // Using Welford-style incremental updates with exponential weighting.
52
+ // Means will be initialized with first observation (x₀, y₀) in update() for
53
+ // faster convergence and more natural variance evolution.
54
+ state.meanX = 0;
55
+ state.meanY = 0;
56
+ state.varianceX = 0;
57
+ state.varianceY = 0;
58
+ state.covariance = 0;
59
+
60
+ // Output values.
61
+ state.correlation = 0;
62
+ state.r2 = 0; // Coefficient of determination (correlation squared)
63
+ state.fisherZT = 0;
64
+
65
+ // Track sample count for initialization phase.
66
+ state.sampleCount = 0;
67
+
68
+ state.nodeType = introspect.getNodeType();
69
+
70
+ return state;
71
+ }; // init()
72
+
73
+ export default init;
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @fileoverview Single source of truth for the es-correlation node's supported
3
+ * stats, control methods, capabilities, default options, and DSL schema.
4
+ * All getters return defensive copies to prevent caller mutation.
5
+ */
6
+ // nodes/es-correlation/introspect.js
7
+
8
+ import { validators, composerValidators } from '../../core/utils/validate/index.js';
9
+
10
+ /** Single source of truth for what this plugin can do */
11
+ const SUPPORTED_STATS = [
12
+ 'correlation',
13
+ 'covariance',
14
+ 'r2',
15
+ 'fisherZT'
16
+ ];
17
+
18
+ /** Human-readable descriptions (for introspection) */
19
+ const STAT_DESCRIPTIONS = {
20
+ correlation: 'Pearson correlation coefficient between x and y using EWMA, range [-1, 1]',
21
+ covariance: 'Covariance between x and y using EWMA',
22
+ r2: 'Coefficient of determination (r-squared), proportion of variance explained, range [0, 1]',
23
+ fisherZT: 'Fisher Z transformation of correlation to normalize it'
24
+ };
25
+
26
+ /** Control methods available for triggers */
27
+ const SUPPORTED_CONTROL_METHODS = {
28
+ reset: 'Clears accumulated state and restarts computation',
29
+ enable: 'Enables node processing',
30
+ disable: 'Disables node processing',
31
+ pause: 'Pauses node processing while keeping state visible',
32
+ unpause: 'Resumes node processing after pause'
33
+ };
34
+
35
+ /** The type of this node */
36
+ const NODE_TYPE = 'ES Correlation';
37
+
38
+ /** Node capabilities for documentation */
39
+ const CAPABILITIES = {
40
+ description: 'Computes exponentially smoothed correlation and covariance between two variables',
41
+ features: [
42
+ 'Numerically stable Welford-style algorithm',
43
+ 'Exponential weighting for dynamic tracking',
44
+ 'Handles near-zero variance gracefully',
45
+ 'Supports correlation, covariance, and r² output',
46
+ 'Half-life (samples) supported for intuitive tuning'
47
+ ]
48
+ };
49
+
50
+ // Attach static metadata once, from our constants by making a shallow copy.
51
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
52
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
53
+ export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
54
+ export const getNodeType = () => NODE_TYPE;
55
+ export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
56
+
57
+ export const DEFAULT_OPTIONS = {
58
+ // halfLife roughly equivalent to alpha = 0.05
59
+ halfLife: 13.5,
60
+ minVariance: 1e-12
61
+ };
62
+
63
+ // DSL Metadata for transpilation
64
+ const DSL_METADATA = {
65
+ // Full spec schema for validation
66
+ specSchema: {
67
+ nodeType: {
68
+ type: 'string',
69
+ required: true,
70
+ value: NODE_TYPE
71
+ },
72
+ name: {
73
+ type: 'string',
74
+ required: true,
75
+ validator: validators.identifier,
76
+ error: 'Name must be a valid identifier'
77
+ },
78
+ from: {
79
+ type: 'object',
80
+ required: true,
81
+ properties: {
82
+ x: {
83
+ type: 'string',
84
+ required: true,
85
+ validator: validators.noSpaces,
86
+ error: 'Field name cannot contain spaces'
87
+ },
88
+ y: {
89
+ type: 'string',
90
+ required: true,
91
+ validator: validators.noSpaces,
92
+ error: 'Field name cannot contain spaces'
93
+ }
94
+ }
95
+ },
96
+ halfLife: {
97
+ type: 'number',
98
+ required: false,
99
+ default: DEFAULT_OPTIONS.halfLife,
100
+ validator: composerValidators.halfLife,
101
+ error: 'halfLife must be > 0 and < 999999'
102
+ },
103
+ minVariance: {
104
+ type: 'number',
105
+ required: false,
106
+ default: DEFAULT_OPTIONS.minVariance,
107
+ min: 0,
108
+ validator: validators.positive,
109
+ error: 'Minimum variance must be positive'
110
+ },
111
+ minSamples: {
112
+ type: 'number',
113
+ required: false,
114
+ default: 10,
115
+ integer: true,
116
+ min: 1,
117
+ validator: validators.positiveInteger,
118
+ error: 'Minimum samples must be a positive integer'
119
+ },
120
+ fisherZT: {
121
+ type: 'boolean',
122
+ required: false,
123
+ default: false
124
+ },
125
+ stats: {
126
+ type: 'object',
127
+ required: true,
128
+ minProperties: 1,
129
+ propertyNames: SUPPORTED_STATS,
130
+ propertySchema: {
131
+ type: 'object',
132
+ properties: {
133
+ storeAs: {
134
+ type: 'string',
135
+ required: true,
136
+ validator: validators.identifier,
137
+ error: 'storeAs must be a valid identifier'
138
+ }
139
+ }
140
+ }
141
+ }
142
+ },
143
+
144
+ // Cross-field validators
145
+ crossFieldValidators: [
146
+ {
147
+ fields: [ 'from.x', 'from.y' ],
148
+ validator: ( spec ) => spec.from.x !== spec.from.y,
149
+ error: 'from.x and from.y must be different fields'
150
+ },
151
+ {
152
+ fields: [ 'fisherZT', 'stats.fisherZT' ],
153
+ validator: ( spec ) => {
154
+ // If fisherZT stat is requested, fisherZT must be enabled
155
+ if ( spec.stats && spec.stats.fisherZT ) {
156
+ return spec.fisherZT === true;
157
+ }
158
+ return true; // No fisherZT stat requested, so no constraint
159
+ },
160
+ error: 'stats.fisherZT requires fisherZT to be enabled'
161
+ }
162
+ ],
163
+
164
+ // Build spec from DSL parameters
165
+ // Pattern: NAME_X_Y_OUTPUTS_OPTIONS -> (name, x, y, stats, options)
166
+ buildSpec: ( name, x, y, stats, options ) => ( {
167
+ nodeType: NODE_TYPE,
168
+ name,
169
+ from: { x, y },
170
+ stats,
171
+ ...options
172
+ } ),
173
+
174
+ };
175
+
176
+ export const getDSLMetadata = () => ( { ...DSL_METADATA } );
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview Copies the current correlation, covariance, r², and/or Fisher Z
3
+ * estimates onto the message for downstream consumption. Propagates NaN when
4
+ * input validation has failed; gates output until minSamples is reached.
5
+ */
6
+ // nodes/es-correlation/publish-to.js
7
+
8
+ import { publishNaN } from '../../core/utils/node/index.js';
9
+
10
+ const publishTo = function ( state, msg ) {
11
+ if ( state.disable ) return;
12
+ // Propagate NaN if unhealthy
13
+ if ( state.inputValidationFailed ) {
14
+ publishNaN( state, msg );
15
+ return;
16
+ }
17
+ // Publish only after minimum samples collected to avoid unreliable early estimates.
18
+ // Align with update/recompute behavior by allowing publish at minSamples as well.
19
+ if ( state.sampleCount < state.minSamples ) {
20
+ return;
21
+ }
22
+
23
+ // Iterate only over configured stats
24
+ const stats = state.stats;
25
+ for ( const statName in stats ) {
26
+ if ( Object.prototype.hasOwnProperty.call( stats, statName ) ) {
27
+ msg[ stats[ statName ].storeAs ] = state[ statName ];
28
+ }
29
+ }
30
+ }; // publishTo()
31
+
32
+ export default publishTo;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @fileoverview Numerical stability handler for the es-correlation node.
3
+ * Floors negative variances (floating-point guard), recomputes correlation
4
+ * from current accumulated state, and clamps the result to [-1, 1].
5
+ */
6
+ // nodes/es-correlation/recompute.js
7
+
8
+ const recompute = function ( state ) {
9
+ // It doesn't store historical data, so traditional recomputation isn't possible.
10
+ // Instead, we perform numerical stability checks and adjustments.
11
+
12
+ // Check for numerical issues in variances.
13
+ // Variance should never be negative due to our update formula,
14
+ // but floating point errors could theoretically cause issues.
15
+ if ( state.varianceX < 0 ) {
16
+ state.varianceX = 0;
17
+ }
18
+ if ( state.varianceY < 0 ) {
19
+ state.varianceY = 0;
20
+ }
21
+
22
+ // Recompute correlation from current statistics to ensure consistency.
23
+ if ( state.sampleCount >= state.minSamples ) {
24
+ const stdX = Math.sqrt( Math.max( state.varianceX, state.minVariance ) );
25
+ const stdY = Math.sqrt( Math.max( state.varianceY, state.minVariance ) );
26
+
27
+ state.correlation = state.covariance / ( stdX * stdY );
28
+
29
+ // Ensure correlation is in valid range.
30
+ if ( state.correlation > 1 ) {
31
+ state.correlation = 1;
32
+ } else if ( state.correlation < -1 ) {
33
+ state.correlation = -1;
34
+ }
35
+
36
+ // Check for NaN (could occur if both variances are zero despite protection).
37
+ if ( Number.isNaN( state.correlation ) ) {
38
+ state.correlation = 0;
39
+ }
40
+
41
+ // Keep derived stats consistent with adjusted correlation.
42
+ if ( state.stats && state.stats.r2 ) {
43
+ state.r2 = state.correlation * state.correlation;
44
+ }
45
+ if ( ( state.fisherZCap < 1 ) && state.stats && state.stats.fisherZT ) {
46
+ const r = state.correlation;
47
+ const capped = ( r > state.fisherZCap ) ? state.fisherZCap :
48
+ ( r < -state.fisherZCap ? -state.fisherZCap : r );
49
+ state.fisherZT = 0.5 * Math.log( ( 1 + capped ) / ( 1 - capped ) );
50
+ }
51
+ }
52
+
53
+ return true;
54
+ }; // recompute()
55
+
56
+ export default recompute;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @fileoverview Resets all statistical accumulators (means, variances,
3
+ * covariance) and output values (correlation, r², fisherZT) to their
4
+ * initial state, allowing the node to restart computation from scratch.
5
+ */
6
+ // nodes/es-correlation/reset.js
7
+
8
+ const reset = function ( state ) {
9
+ // Reset all statistical accumulators to initial values.
10
+ state.meanX = 0;
11
+ state.meanY = 0;
12
+ state.varianceX = 0;
13
+ state.varianceY = 0;
14
+ state.covariance = 0;
15
+
16
+ // Reset output values.
17
+ state.correlation = 0;
18
+ state.r2 = 0;
19
+ state.fisherZT = 0;
20
+
21
+ // Reset sample counter.
22
+ state.sampleCount = 0;
23
+
24
+ return true;
25
+ }; // reset()
26
+
27
+ export default reset;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @fileoverview Hot-path exponentially weighted moving correlation computation.
3
+ * Uses a Welford-style incremental algorithm with exponential decay on means,
4
+ * variance, and covariance. Optionally computes r² and Fisher Z transform.
5
+ * Zero allocations; all reads/writes via the pre-allocated state object.
6
+ */
7
+ // nodes/es-correlation/update.js
8
+
9
+ const update = function ( state, msg ) {
10
+ if ( state.disable || state.pause ) return state;
11
+ const xVal = msg[ state.x ];
12
+ // Reset on each update
13
+ state.inputValidationFailed = false;
14
+ // Handle faults gracefully: ensure their isolation
15
+ if ( !Number.isFinite( xVal ) ) {
16
+ // Signals publishing NaN for all demanded `stats` in publishTo.
17
+ state.inputValidationFailed = true;
18
+ return state;
19
+ }
20
+
21
+ const yVal = msg[ state.y ];
22
+ // Handle faults gracefully: ensure their isolation
23
+ if ( !Number.isFinite( yVal ) ) {
24
+ // Signals publishing NaN for all demanded `stats` in publishTo.
25
+ state.inputValidationFailed = true;
26
+ return state;
27
+ }
28
+
29
+ // Special handling for first observation:
30
+ // Initialize means with the first sample for faster convergence
31
+ // and more natural variance evolution; no variance/covariance yet.
32
+ if ( state.sampleCount === 0 ) {
33
+ state.meanX = xVal;
34
+ state.meanY = yVal;
35
+ state.sampleCount = 1; // count the first sample
36
+ return state;
37
+ }
38
+
39
+ // Increment sample count for subsequent observations.
40
+ state.sampleCount += 1;
41
+
42
+ // Compute deltas BEFORE updating means (critical for numerical stability).
43
+ const deltaX = xVal - state.meanX;
44
+ const deltaY = yVal - state.meanY;
45
+
46
+ // Exponentially smoothed update for means.
47
+ state.meanX += state.alpha * deltaX;
48
+ state.meanY += state.alpha * deltaY;
49
+
50
+ // Numerically stable variance and covariance updates.
51
+ // Note: We use the NEW mean for the second delta computation.
52
+
53
+ // Update covariance using the stable formula.
54
+ // cov += α * δx * (y - mean_y_new)
55
+ state.covariance += state.alpha * ( ( deltaX * ( yVal - state.meanY ) ) - state.covariance );
56
+
57
+ // If neither correlation nor r2 is requested, we can skip the
58
+ // variance/correlation path (keeps hot path lean). r2 implies
59
+ // correlation at compute-time even if not explicitly requested.
60
+ if ( ( state.stats.correlation === undefined ) && ( state.stats.r2 === undefined ) ) {
61
+ return state;
62
+ }
63
+
64
+ // Update variances using the stable formula.
65
+ // var_x += α * δx * (x - mean_x_new)
66
+ state.varianceX += state.alpha * ( ( deltaX * ( xVal - state.meanX ) ) - state.varianceX );
67
+ state.varianceY += state.alpha * ( ( deltaY * ( yVal - state.meanY ) ) - state.varianceY );
68
+
69
+ // Compute correlation only after minimum samples collected.
70
+ if ( state.sampleCount >= state.minSamples ) {
71
+ // Compute standard deviations with minimum variance protection.
72
+ const stdX = Math.sqrt( Math.max( state.varianceX, state.minVariance ) );
73
+ const stdY = Math.sqrt( Math.max( state.varianceY, state.minVariance ) );
74
+
75
+ // Compute correlation coefficient.
76
+ // The max() ensures we never divide by zero.
77
+ state.correlation = state.covariance / ( stdX * stdY );
78
+
79
+ // Clamp correlation to [-1, 1] to handle numerical errors.
80
+ // Due to floating point arithmetic, we might get values like 1.0000000002.
81
+ if ( state.correlation >= 1 ) {
82
+ // Note: fisherZCap currently couples clamping and Z-publish enabling.
83
+ // We will decouple this in a subsequent Fisher-Z clarity pass.
84
+ state.correlation = state.fisherZCap;
85
+ } else if ( state.correlation <= -1 ) {
86
+ state.correlation = -state.fisherZCap;
87
+ }
88
+
89
+ // Compute r² (coefficient of determination) at publish time (if required)
90
+ // by squaring the correlation. r² is always in [0,1] and has a direct
91
+ // percentage interpretation (model quality, sensor agreement, etc).
92
+ if ( state.stats && state.stats.r2 ) {
93
+ state.r2 = state.correlation * state.correlation;
94
+ }
95
+
96
+ // Compute Fisher Z transform only when:
97
+ // - feature enabled (fisherZCap < 1), and
98
+ // - output mapping provided in stats.fisherZ.
99
+ if ( ( state.fisherZCap < 1 ) && state.stats && state.stats.fisherZT ) {
100
+ // Guard against |r| → 1 to prevent infinities; clamp with current cap.
101
+ const r = state.correlation;
102
+ const capped = ( r > state.fisherZCap ) ? state.fisherZCap : ( r < -state.fisherZCap ? -state.fisherZCap : r );
103
+ state.fisherZT = 0.5 * Math.log( ( 1 + capped ) / ( 1 - capped ) );
104
+ }
105
+ }
106
+
107
+ return state;
108
+ }; // update()
109
+
110
+ export default update;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @fileoverview Barrel module for the esMean node.
3
+ *
4
+ * Re-exports the standard node lifecycle methods (init, update, reset,
5
+ * recompute, publishTo), shared control signals (disable, enable, pause,
6
+ * unpause), and all introspection metadata.
7
+ */
8
+
9
+ export { default as init } from './init.js';
10
+ export { default as update } from './update.js';
11
+ export { default as reset } from './reset.js';
12
+ export { default as recompute } from './recompute.js';
13
+ export { default as publishTo } from './publish-to.js';
14
+ // Direct imports for common control functions
15
+ export { default as disable } from '../../core/utils/node/disable.js';
16
+ export { default as enable } from '../../core/utils/node/enable.js';
17
+ export { default as pause } from '../../core/utils/node/pause.js';
18
+ export { default as unpause } from '../../core/utils/node/unpause.js';
19
+ // Re-export everything from introspection.js
20
+ export * from './introspect.js';