@winkjs/composer 0.0.2 → 0.4.1

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 +106 -80
  3. package/package.json +56 -28
  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,58 @@
1
+ /**
2
+ * @fileoverview Initializes esMean node state from a validated spec.
3
+ *
4
+ * Derives the smoothing factor (alpha) from the configured half-life,
5
+ * pre-computes the MAD alpha for adaptive tracking (half-life × 1.5 to
6
+ * dampen flapping), and allocates all state properties up-front on a
7
+ * prototype-free object — no allocations occur on the hot path.
8
+ */
9
+
10
+ import { validateSpec } from '../../core/utils/node/index.js';
11
+ import * as introspect from './introspect.js';
12
+ import { halfLifeToAlpha } from '../../core/utils/half-life/index.js';
13
+ import { resolveScalar } from '../../core/utils/options/resolve-field-keyed.js';
14
+
15
+ const init = function ( spec ) {
16
+ // Validate against (updated) schema
17
+ validateSpec( spec, introspect );
18
+
19
+ const state = Object.create( null );
20
+ // Standard input parameter health flag during update: false means healthy
21
+ state.inputValidationFailed = false;
22
+ // Ensure node is enabled by default
23
+ state.disable = false;
24
+ state.pause = false;
25
+
26
+ // Required
27
+ state.x = spec.from.x;
28
+
29
+ // Config copy
30
+ state.stats = spec.stats;
31
+
32
+ // half-life based configuration (samples)
33
+ // Supports both direct: { halfLife: 20 } and field-keyed: { halfLife: { temp: 5, pressure: 20 } }
34
+ const halfLifeSpec = resolveScalar( spec.halfLife, state.x );
35
+ state.halfLife = ( typeof halfLifeSpec === 'number' ) ? halfLifeSpec : introspect.DEFAULT_OPTIONS.halfLife;
36
+
37
+ // Derive base alpha from half-life for hot-path math
38
+ state.alpha = halfLifeToAlpha( state.halfLife );
39
+ state.currentAlpha = state.alpha;
40
+
41
+ // New: adaptive half-life flag (renamed)
42
+ state.adaptiveHalfLife = !!spec.adaptiveHalfLife;
43
+
44
+ // Exponential smoothing of |innovation| (MAD-ish); alpha derived from main half-life
45
+ // Using a slightly longer half-life (×1.5) to avoid flapping under noise
46
+ state.madAlpha = halfLifeToAlpha( state.halfLife * 1.5 );
47
+ state.esAbsInnovation = null;
48
+
49
+ // State
50
+ state.esmValue = null;
51
+ state.isInitialized = false;
52
+ state.lastValue = null;
53
+
54
+ state.nodeType = introspect.getNodeType();
55
+ return state;
56
+ }; // init()
57
+
58
+ export default init;
@@ -0,0 +1,129 @@
1
+ /**
2
+ * @fileoverview Single source of truth for esMean node metadata.
3
+ *
4
+ * Exports supported stats, control methods, capabilities, default options,
5
+ * and the DSL spec schema used by both validation (init-time) and
6
+ * transpilation (DSL → spec). All getters return defensive copies.
7
+ */
8
+
9
+ import { validators, composerValidators } from '../../core/utils/validate/index.js';
10
+
11
+ /** Single source of truth for what this plugin can do */
12
+ const SUPPORTED_STATS = [
13
+ 'mean'
14
+ ];
15
+
16
+ /** Human-readable descriptions (for introspection) */
17
+ const STAT_DESCRIPTIONS = {
18
+ mean: 'Exponentially Smoothed Mean'
19
+ };
20
+
21
+ /** Control methods available for triggers */
22
+ const SUPPORTED_CONTROL_METHODS = {
23
+ reset: 'Clears accumulated state and restarts computation',
24
+ enable: 'Enables node processing',
25
+ disable: 'Disables node processing',
26
+ pause: 'Pauses node processing while keeping state visible',
27
+ unpause: 'Resumes node processing after pause'
28
+ };
29
+
30
+ /** The type of this node */
31
+ const NODE_TYPE = 'ES Mean';
32
+
33
+ /** Node capabilities for documentation */
34
+ const CAPABILITIES = {
35
+ description: 'Computes exponentially smoothed mean for smoothing time series data',
36
+ features: [
37
+ 'Half-life based smoothing (samples) for intuitive tuning',
38
+ 'Optional adaptive half-life based on absolute innovation (robust MAD-ish estimator)',
39
+ 'Numerically stable update form'
40
+ ]
41
+ };
42
+
43
+ // Export functions for accessing metadata
44
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
45
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
46
+ export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
47
+ export const getNodeType = () => NODE_TYPE;
48
+ export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
49
+
50
+ // Spec default values
51
+ export const DEFAULT_OPTIONS = {
52
+ // ≈ alpha 0.2
53
+ halfLife: 3.1062837195053903
54
+ };
55
+
56
+ // DSL Metadata for transpilation
57
+ const DSL_METADATA = {
58
+ // Spec schema for validation
59
+ specSchema: {
60
+ nodeType: {
61
+ type: 'string',
62
+ required: true,
63
+ value: NODE_TYPE
64
+ },
65
+ name: {
66
+ type: 'string',
67
+ required: true,
68
+ validator: validators.identifier,
69
+ error: 'Name must be a valid identifier'
70
+ },
71
+ from: {
72
+ type: 'object',
73
+ required: true,
74
+ properties: {
75
+ x: {
76
+ type: 'string',
77
+ required: true,
78
+ validator: validators.noSpaces,
79
+ error: 'Field name cannot contain spaces'
80
+ }
81
+ }
82
+ },
83
+ halfLife: {
84
+ type: 'numberOrFieldKeyed',
85
+ required: false,
86
+ default: DEFAULT_OPTIONS.halfLife,
87
+ validator: composerValidators.halfLife,
88
+ error: 'halfLife must be > 0 and < 999999'
89
+ },
90
+ adaptiveHalfLife: {
91
+ type: 'boolean',
92
+ required: false,
93
+ default: false
94
+ },
95
+ stats: {
96
+ type: 'object',
97
+ required: true,
98
+ propertyNames: SUPPORTED_STATS,
99
+ propertySchema: {
100
+ type: 'object',
101
+ required: true,
102
+ properties: {
103
+ storeAs: {
104
+ type: 'string',
105
+ required: true,
106
+ minLength: 1,
107
+ validator: validators.identifier,
108
+ error: 'storeAs must be a valid identifier'
109
+ }
110
+ }
111
+ }
112
+ }
113
+ },
114
+
115
+ // Cross-field validators
116
+ crossFieldValidators: [],
117
+
118
+ // How to build the spec from DSL params
119
+ buildSpec: ( name, x, stats, options ) => ( {
120
+ nodeType: NODE_TYPE,
121
+ name,
122
+ from: { x },
123
+ stats,
124
+ ...options
125
+ } ),
126
+
127
+ };
128
+
129
+ export const getDSLMetadata = () => ( { ...DSL_METADATA } );
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @fileoverview Copies the current EWMA estimate onto the message for
3
+ * downstream consumption. Propagates NaN when input validation has failed,
4
+ * ensuring downstream nodes see an explicit fault rather than stale data.
5
+ */
6
+ import { publishNaN } from '../../core/utils/node/index.js';
7
+
8
+ const publishTo = function ( state, msg ) {
9
+ if ( state.disable ) return;
10
+ // Propagate NaN if unhealthy
11
+ if ( state.inputValidationFailed ) {
12
+ publishNaN( state, msg );
13
+ return;
14
+ }
15
+
16
+ msg[ state.stats.mean.storeAs ] = state.esmValue;
17
+ }; // publishTo()
18
+
19
+ export default publishTo;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @fileoverview Recompute handler for the esMean node (intentional no-op).
3
+ *
4
+ * EWMA cannot be recomputed without the full observation history. The
5
+ * incremental update form is already numerically stable and bounded by
6
+ * the input range, so precision drift is not a concern.
7
+ */
8
+
9
+ const recompute = function () {
10
+ // It cannot be recomputed without full historical data.
11
+ // The incremental update form used is already numerically stable
12
+ // and bounded by input range, preventing unbounded error growth.
13
+ return true;
14
+ }; // recompute()
15
+
16
+ export default recompute;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @fileoverview Resets accumulated EWMA state to its pre-observation condition.
3
+ *
4
+ * Clears the estimate, initialization flag, adaptive innovation tracker, and
5
+ * last observed value. Restores currentAlpha to the base alpha derived at init,
6
+ * so the next observation seeds the estimate afresh.
7
+ */
8
+
9
+ const reset = function ( state ) {
10
+ state.esmValue = null;
11
+ state.isInitialized = false;
12
+
13
+ // Restore base alpha (derived from half-life at init)
14
+ state.currentAlpha = state.alpha;
15
+
16
+ // New adaptive state
17
+ state.esAbsInnovation = null;
18
+
19
+ state.lastValue = null;
20
+
21
+ return true;
22
+ }; // reset()
23
+
24
+ export default reset;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @fileoverview Hot-path EWMA computation for the esMean node.
3
+ *
4
+ * Applies the numerically stable incremental form: esmValue += α·(x − esmValue).
5
+ * When adaptive half-life is enabled, alpha is modulated per-message based on
6
+ * surprise — |innovation| relative to a MAD-estimated σ (σ ≈ 1.2533·E[|inno|],
7
+ * the normal-equivalence relation). A bounded boost keeps alpha within [base, 0.95],
8
+ * preventing degeneration to passthrough. Zero allocations; all reads from state.
9
+ */
10
+
11
+ // Sensible fixed constants (hot path reads only)
12
+ const adaptGain = 0.2; // sensitivity of alpha to surprise (bounded map)
13
+ const epsilon = 1e-12; // numerical floor
14
+
15
+ const update = function ( state, msg ) {
16
+ if ( state.disable || state.pause ) return state;
17
+ const xVal = msg[ state.x ];
18
+ // Reset on each update
19
+ state.inputValidationFailed = false;
20
+ // Handle faults gracefully: ensure their isolation
21
+ if ( !Number.isFinite( xVal ) ) {
22
+ // Signals publishing NaN for all demanded `stats` in publishTo.
23
+ state.inputValidationFailed = true;
24
+ return state;
25
+ }
26
+
27
+ if ( state.isInitialized ) {
28
+ // Optional adaptive half-life
29
+ if ( state.adaptiveHalfLife ) {
30
+ // Innovation relative to current estimate
31
+ const innovation = xVal - state.esmValue;
32
+
33
+ // Exponential smoothing of |innovation| (MAD-ish); using precomputed alpha for hot path
34
+ const absInnovation = Math.abs( innovation );
35
+ state.esAbsInnovation = ( state.esAbsInnovation === null ) ?
36
+ absInnovation :
37
+ state.esAbsInnovation + ( state.madAlpha * ( absInnovation - state.esAbsInnovation ) );
38
+
39
+ // σ ≈ 1.2533 * E[ |innovation| ] (normal equivalence), robust & sqrt-free
40
+ const sigma = ( 1.2533 * state.esAbsInnovation ) + epsilon;
41
+
42
+ // Surprise (unitless)
43
+ const z = Math.abs( innovation ) / sigma;
44
+
45
+ // Bounded boost of alpha: base * ( 1 + gain * z / ( 1 + z ) )
46
+ const targetAlpha = state.alpha * ( 1 + ( adaptGain * ( z / ( 1 + z ) ) ) );
47
+
48
+ // Preserve Exponential smoothing behavior (never degenerate to passthrough)
49
+ state.currentAlpha = ( targetAlpha > 0.95 ) ? 0.95 : targetAlpha;
50
+ }
51
+
52
+ // Numerically stable update
53
+ state.esmValue += state.currentAlpha * ( xVal - state.esmValue );
54
+ } else {
55
+ // Initialize
56
+ state.esmValue = xVal;
57
+ state.isInitialized = true;
58
+
59
+ // Initialize MAD tracker lazily when adaptive is enabled
60
+ if ( state.adaptiveHalfLife ) {
61
+ state.esAbsInnovation = 0;
62
+ }
63
+ }
64
+
65
+ state.lastValue = xVal;
66
+ return state;
67
+ }; // update()
68
+
69
+ export default update;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @fileoverview Barrel module for the es-pairwise-correlation node. Re-exports
3
+ * lifecycle methods (init, update, reset, recompute, publishTo), shared control
4
+ * signals (disable, enable, pause, unpause), and all introspection metadata.
5
+ */
6
+ // nodes/es-pairwise-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,98 @@
1
+ /**
2
+ * @fileoverview Initializes es-pairwise-correlation node state from a validated spec.
3
+ * Derives the smoothing factor (alpha) from the configured half-life, pre-allocates
4
+ * all buffers (means, variances, covariances, correlations) on a prototype-free
5
+ * object — no allocations occur on the hot path.
6
+ */
7
+ // nodes/es-pairwise-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 fisherZCapDefault = 0.9999;
14
+
15
+ const init = function ( spec ) {
16
+ // Validate against updated schema (halfLife-based)
17
+ validateSpec( spec, introspect ); // uses specSchema from introspect.js
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
+ // ── Configuration ────────────────────────────────────────────────────────────
28
+ // Input variables
29
+ state.x = spec.from.x;
30
+ state.n = state.x.length;
31
+ state.pairCount = ( state.n * ( state.n - 1 ) ) / 2;
32
+
33
+ // For publishing
34
+ state.varNames = state.x.slice( 0 );
35
+
36
+ // Output mappings
37
+ state.stats = spec.stats; // guaranteed by validateSpec
38
+
39
+ // Half-life config (samples) → derive alpha for hot path
40
+ state.halfLife = spec.halfLife ?? introspect.DEFAULT_OPTIONS.halfLife;
41
+ state.alpha = halfLifeToAlpha( state.halfLife );
42
+
43
+ // Numerics
44
+ state.minVariance = spec.minVariance ?? introspect.DEFAULT_OPTIONS.minVariance;
45
+
46
+ // Warm-up: default to ~85% settled if not provided
47
+ state.minSamples = ( spec.minSamples === undefined ) ?
48
+ halfLifeToWarmupSamples( state.halfLife, 0.85 ) :
49
+ spec.minSamples;
50
+
51
+ // Fisher-Z toggle uses the same cap semantics as the pair node
52
+ state.fisherZCap = ( spec.fisherZT === true ) ? fisherZCapDefault : 1;
53
+
54
+ // ── State & preallocations (zero-alloc hot path) ─────────────────────────────
55
+ // Per-variable stats
56
+ state.means = new Float64Array( state.n );
57
+ state.variances = new Float64Array( state.n );
58
+
59
+ // Pairwise stats (upper triangle order)
60
+ state.covariances = new Float64Array( state.pairCount );
61
+ state.correlations = new Float64Array( state.pairCount );
62
+
63
+ // Optional Fisher-Z vector
64
+ if ( spec.fisherZT ) {
65
+ state.fisherZT = new Float64Array( state.pairCount );
66
+ }
67
+
68
+ // Workspaces
69
+ state.values = new Float64Array( state.n );
70
+ state.deltas = new Float64Array( state.n );
71
+
72
+ // O(1) variable index lookup
73
+ state.variableLookup = Object.create( null );
74
+ for ( let i = 0; i < state.n; i += 1 ) {
75
+ state.variableLookup[ state.x[ i ] ] = i;
76
+ }
77
+
78
+ // Optional static pair names for debugging/visualization (precomputed)
79
+ if ( spec.stats?.pairNames ) {
80
+ const pairNames = new Array( state.pairCount );
81
+ let idx = 0;
82
+ for ( let i = 0; i < state.n; i += 1 ) {
83
+ for ( let j = i + 1; j < state.n; j += 1 ) {
84
+ pairNames[ idx ] = `${state.x[ i ]}-${state.x[ j ]}`;
85
+ idx += 1;
86
+ }
87
+ }
88
+ state.pairNames = pairNames;
89
+ }
90
+
91
+ // Counters / identity
92
+ state.sampleCount = 0;
93
+ state.nodeType = introspect.getNodeType();
94
+
95
+ return state;
96
+ }; // init()
97
+
98
+ export default init;
@@ -0,0 +1,187 @@
1
+ /**
2
+ * @fileoverview Single source of truth for the es-pairwise-correlation node's
3
+ * supported stats, control methods, capabilities, default options, and DSL schema.
4
+ * All getters return defensive copies to prevent caller mutation.
5
+ */
6
+ // nodes/es-pairwise-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
+ 'correlations', // Raw correlation coefficients vector
13
+ 'fisherZT', // Fisher Z transformed correlations
14
+ 'covariances', // Raw covariances vector
15
+ 'pairNames', // Pair identifiers (e.g., "temp-pressure")
16
+ 'varNames' // Original input variable names
17
+ ];
18
+
19
+ /** Human-readable descriptions (for introspection) */
20
+ const STAT_DESCRIPTIONS = {
21
+ correlations: 'Pairwise correlation coefficients (upper triangle)',
22
+ fisherZT: 'Fisher Z transformed correlation values',
23
+ covariances: 'Pairwise covariances (upper triangle)',
24
+ pairNames: 'Labels identifying each variable pair',
25
+ varNames: 'Original variable names in order'
26
+ };
27
+
28
+ /** Control methods available for triggers */
29
+ const SUPPORTED_CONTROL_METHODS = {
30
+ reset: 'Clears accumulated state and restarts computation',
31
+ enable: 'Enables node processing',
32
+ disable: 'Disables node processing',
33
+ pause: 'Pauses node processing while keeping state visible',
34
+ unpause: 'Resumes node processing after pause'
35
+ };
36
+
37
+ /** The type of this node */
38
+ const NODE_TYPE = 'ES Pairwise Correlation';
39
+
40
+ /** Node capabilities for documentation */
41
+ const CAPABILITIES = {
42
+ description: 'Computes all pairwise correlations between multiple variables using exponential smoothing',
43
+ features: [
44
+ 'Single-pass correlation computation for up to 12 variables',
45
+ 'Numerically stable exponentially smoothed (Welford-style) algorithm',
46
+ 'Zero-allocation operation after initialization',
47
+ 'Vector-native processing (no matrix overhead)',
48
+ 'Cache-efficient memory layout',
49
+ 'O(n²/2) optimal complexity for upper triangle',
50
+ 'Fisher Z transformation support',
51
+ 'Handles missing/invalid data gracefully',
52
+ 'Half-life (samples) supported for intuitive tuning'
53
+ ]
54
+ };
55
+
56
+ // Introspection accessors (return safe copies)
57
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
58
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
59
+ export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
60
+ export const getNodeType = () => NODE_TYPE;
61
+ // Deep-enough copy: clone root object and clone the features array
62
+ export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
63
+
64
+ /** Defaults (aligned with pair node) */
65
+ export const DEFAULT_OPTIONS = {
66
+ // halfLife roughly equivalent to alpha ≈ 0.05
67
+ halfLife: 13.5,
68
+ minVariance: 1e-12
69
+ };
70
+
71
+ // DSL Metadata for transpilation
72
+ const DSL_METADATA = {
73
+ // Spec schema for validation
74
+ specSchema: {
75
+ nodeType: {
76
+ type: 'string',
77
+ required: true,
78
+ value: NODE_TYPE
79
+ },
80
+ name: {
81
+ type: 'string',
82
+ required: true,
83
+ validator: validators.identifier,
84
+ error: 'Name must be a valid identifier'
85
+ },
86
+ from: {
87
+ type: 'object',
88
+ required: true,
89
+ properties: {
90
+ x: {
91
+ type: 'array',
92
+ required: true,
93
+ minItems: 2,
94
+ maxItems: 12,
95
+ itemSchema: {
96
+ type: 'string',
97
+ validator: validators.noSpaces,
98
+ error: 'Field names cannot contain spaces'
99
+ }
100
+ }
101
+ }
102
+ },
103
+ halfLife: {
104
+ type: 'number',
105
+ required: false,
106
+ default: DEFAULT_OPTIONS.halfLife,
107
+ validator: composerValidators.halfLife,
108
+ error: 'halfLife must be > 0 and < 999999'
109
+ },
110
+ minSamples: {
111
+ type: 'number',
112
+ required: false,
113
+ default: 10,
114
+ integer: true,
115
+ min: 1,
116
+ validator: validators.positiveInteger,
117
+ error: 'Minimum samples must be a positive integer'
118
+ },
119
+ minVariance: {
120
+ type: 'number',
121
+ required: false,
122
+ default: 1e-12,
123
+ validator: validators.positive,
124
+ error: 'Minimum variance must be positive'
125
+ },
126
+ fisherZT: {
127
+ type: 'boolean',
128
+ required: false,
129
+ default: false
130
+ },
131
+ stats: {
132
+ type: 'object',
133
+ required: true,
134
+ minProperties: 1,
135
+ propertyNames: SUPPORTED_STATS,
136
+ propertySchema: {
137
+ type: 'object',
138
+ required: true,
139
+ properties: {
140
+ storeAs: {
141
+ type: 'string',
142
+ required: true,
143
+ minLength: 1,
144
+ validator: validators.identifier,
145
+ error: 'storeAs must be a valid identifier'
146
+ }
147
+ }
148
+ }
149
+ }
150
+ },
151
+
152
+ // Cross-field validators
153
+ crossFieldValidators: [
154
+ {
155
+ fields: [ 'from.x' ],
156
+ validator: ( spec ) => {
157
+ const fields = spec.from.x;
158
+ const uniqueFields = new Set( fields );
159
+ return uniqueFields.size === fields.length;
160
+ },
161
+ error: 'Field names must be unique'
162
+ },
163
+ {
164
+ fields: [ 'fisherZT', 'stats.fisherZT' ],
165
+ validator: ( spec ) => {
166
+ // If fisherZT stat is requested, fisherZT must be enabled
167
+ if ( spec.stats && spec.stats.fisherZT ) {
168
+ return spec.fisherZT === true;
169
+ }
170
+ return true; // No fisherZT stat requested, so no constraint
171
+ },
172
+ error: 'stats.fisherZT requires fisherZT to be enabled'
173
+ }
174
+ ],
175
+
176
+ // How to build the spec from DSL params
177
+ buildSpec: ( name, x, stats, options ) => ( {
178
+ nodeType: NODE_TYPE,
179
+ name,
180
+ from: { x },
181
+ stats,
182
+ ...options
183
+ } ),
184
+
185
+ };
186
+
187
+ export const getDSLMetadata = () => ( { ...DSL_METADATA } );
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @fileoverview Copies the current pairwise correlation estimates, covariances,
3
+ * Fisher Z values, and/or pair labels onto the message for downstream consumption.
4
+ * Propagates NaN when input validation has failed; gates output until minSamples
5
+ * is reached.
6
+ */
7
+ // nodes/es-pairwise-correlation/publish-to.js
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
+ // Don't publish until we have reliable estimates
18
+ if ( state.sampleCount < state.minSamples ) {
19
+ return;
20
+ }
21
+
22
+ // Iterate only over configured stats
23
+ const stats = state.stats;
24
+ for ( const statName in stats ) {
25
+ if ( Object.prototype.hasOwnProperty.call( stats, statName ) ) {
26
+ msg[ stats[ statName ].storeAs ] = state[ statName ];
27
+ }
28
+ }
29
+ }; // publishTo()
30
+
31
+ export default publishTo;