@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,207 @@
1
+ /**
2
+ * Console Formatter for WinkComposer
3
+ *
4
+ * Provides rich, colored console output with structured formatting
5
+ * for development, debugging, and edge device monitoring.
6
+ */
7
+
8
+ // ANSI color codes for terminal output
9
+ const colors = {
10
+ reset: '\x1b[0m',
11
+ bright: '\x1b[1m',
12
+ dim: '\x1b[2m',
13
+
14
+ // Foreground colors
15
+ black: '\x1b[30m',
16
+ red: '\x1b[31m',
17
+ green: '\x1b[32m',
18
+ yellow: '\x1b[33m',
19
+ blue: '\x1b[34m',
20
+ magenta: '\x1b[35m',
21
+ cyan: '\x1b[36m',
22
+ white: '\x1b[37m',
23
+ gray: '\x1b[90m',
24
+
25
+ // Background colors
26
+ bgRed: '\x1b[41m',
27
+ bgYellow: '\x1b[43m',
28
+ bgGreen: '\x1b[42m'
29
+ };
30
+
31
+ // Method-specific configurations
32
+ const methodConfig = {
33
+ log: {
34
+ color: colors.reset,
35
+ symbol: ' ',
36
+ label: 'INFO'
37
+ },
38
+ warn: {
39
+ color: colors.yellow,
40
+ symbol: '⚠️ ',
41
+ label: 'WARN'
42
+ },
43
+ error: {
44
+ color: colors.red,
45
+ symbol: '✗ ',
46
+ label: 'ERROR'
47
+ },
48
+ table: {
49
+ color: colors.cyan,
50
+ symbol: '📊',
51
+ label: 'DATA'
52
+ },
53
+ debug: {
54
+ color: colors.gray,
55
+ symbol: '🔍',
56
+ label: 'DEBUG'
57
+ },
58
+ success: {
59
+ color: colors.green,
60
+ symbol: '✓ ',
61
+ label: 'OK'
62
+ },
63
+ critical: {
64
+ color: `${colors.bright}${colors.bgRed}${colors.white}`,
65
+ symbol: '🔴',
66
+ label: 'CRITICAL'
67
+ }
68
+ };
69
+
70
+ /**
71
+ * Format timestamp for console output
72
+ */
73
+ const formatTimestamp = function () {
74
+ const now = new Date();
75
+ const time = now.toTimeString().split( ' ' )[ 0 ]; // HH:MM:SS
76
+ const ms = now.getMilliseconds().toString().padStart( 3, '0' );
77
+ return `${colors.gray}[${time}.${ms}]${colors.reset}`;
78
+ }; // formatTimestamp()
79
+
80
+ /**
81
+ * Format node identifier
82
+ */
83
+ const formatNodeId = function ( partitionKey ) {
84
+ const partition = partitionKey ? `/${partitionKey}` : '';
85
+ return `${colors.cyan}[${partition}]${colors.reset}`;
86
+ }; // formatNodeId()
87
+
88
+ /**
89
+ * Format structured data for console
90
+ */
91
+ const formatData = function ( data, indent = 2 ) {
92
+ if ( data === null || data === undefined ) {
93
+ return `${colors.gray}(empty)${colors.reset}`;
94
+ }
95
+
96
+ if ( typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean' ) {
97
+ return String( data );
98
+ }
99
+
100
+ // For objects, create indented key-value display
101
+ const spaces = ' '.repeat( indent );
102
+ const lines = [];
103
+
104
+ for ( const [ key, value ] of Object.entries( data ) ) {
105
+ const formattedKey = `${colors.bright}${key}:${colors.reset}`;
106
+
107
+ // Handle different value types
108
+ let formattedValue;
109
+ if ( typeof value === 'object' && value !== null ) {
110
+ // Nested object - use JSON stringify with indent
111
+ formattedValue = JSON.stringify( value, null, 2 )
112
+ .split( '\n' )
113
+ .map( ( line, i ) => ( i === 0 ? line : spaces + line ) )
114
+ .join( '\n' );
115
+ } else if ( typeof value === 'string' ) {
116
+ formattedValue = `"${value}"`;
117
+ } else {
118
+ formattedValue = String( value );
119
+ }
120
+
121
+ lines.push( `${spaces}${formattedKey} ${formattedValue}` );
122
+ }
123
+
124
+ return lines.join( '\n' );
125
+ }; // formatData()
126
+
127
+ /**
128
+ * Create formatted console output
129
+ */
130
+ const createConsoleFormatter = function () {
131
+
132
+ /**
133
+ * Format and emit to console
134
+ *
135
+ * @param {string} method - Console method (log, warn, error, table)
136
+ * @param {Object} data - Data to output
137
+ * @param {string} [partitionKey] - Optional partition identifier
138
+ * @param {Object} [metadata] - Optional metadata (UNS, etc.)
139
+ */
140
+ const format = function ( method, data, partitionKey, metadata ) {
141
+ const config = methodConfig[ method ] || methodConfig.log;
142
+
143
+ // Build header line
144
+ const timestamp = formatTimestamp();
145
+ const nodeId = formatNodeId( partitionKey );
146
+ const header = `${config.symbol} ${timestamp} ${nodeId}`;
147
+
148
+ // Handle table method specially
149
+ if ( method === 'table' && ( Array.isArray( data ) || typeof data === 'object' ) ) {
150
+ console.log( `${header} ${config.color}[TABLE]${colors.reset}` );
151
+ console.table( data );
152
+ return;
153
+ }
154
+
155
+ // Handle critical alerts with emphasis
156
+ if ( method === 'critical' ) {
157
+ console.log( `\n${config.color} ${config.label} ${colors.reset}` );
158
+ console.log( header );
159
+ console.log( formatData( data, 4 ) );
160
+ console.log( `${config.color} ${'═'.repeat( 40 )} ${colors.reset}\n` );
161
+ return;
162
+ }
163
+
164
+ // Standard formatted output
165
+ const output = [];
166
+ output.push( header );
167
+
168
+ // Add metadata if present (UNS path, etc.)
169
+ if ( metadata?.uns ) {
170
+ output.push( ` ${colors.gray}UNS: ${metadata.uns}${colors.reset}` );
171
+ }
172
+
173
+ // Format main data
174
+ if ( typeof data === 'string' ) {
175
+ output.push( ` ${config.color}${data}${colors.reset}` );
176
+ } else {
177
+ output.push( formatData( data, 2 ) );
178
+ }
179
+
180
+ // Output using appropriate console method
181
+ const consoleMethod = [ 'log', 'warn', 'error', 'table' ].includes( method ) ? method : 'log';
182
+
183
+ console[ consoleMethod ]( output.join( '\n' ) );
184
+ }; // format()
185
+
186
+ /**
187
+ * Create separator line for visual grouping
188
+ */
189
+ const separator = function ( label, char = '═' ) {
190
+ const line = char.repeat( 40 );
191
+ if ( label ) {
192
+ console.log( `${colors.cyan}${line}${colors.reset}` );
193
+ console.log( `${colors.bright}${colors.cyan} ${label}${colors.reset}` );
194
+ console.log( `${colors.cyan}${line}${colors.reset}` );
195
+ } else {
196
+ console.log( `${colors.gray}${line}${colors.reset}` );
197
+ }
198
+ }; // separator()
199
+
200
+ return {
201
+ format: format,
202
+ separator: separator,
203
+ colors: colors // Export for custom formatting
204
+ };
205
+ }; // createConsoleFormatter()
206
+
207
+ export default createConsoleFormatter;
@@ -0,0 +1,98 @@
1
+ import sanitizeField from './sanitize-field.js';
2
+ import { smartTruncate } from './smart-truncate.js';
3
+
4
+ /**
5
+ * Creates a smart, sanitized identifier for storing computed values.
6
+ * Ensures valid JavaScript identifiers while preserving readability.
7
+ *
8
+ * Examples:
9
+ * ('ewma', 'temperature') → 'ewma_temperature'
10
+ * ('diff', 'temperature', 'setpoint') → 'diff_temperature_setpoint'
11
+ * ('mean', 'sensor.pressure') → 'mean_sensor_pressure'
12
+ * ('ratio', 'inlet-flow', 'outlet-flow') → 'ratio_inlet_flow_outlet_flow'
13
+ *
14
+ * @param {string} statType - Type of computation (e.g., 'diff', 'ewma', 'mean')
15
+ * @param {string} x - First field name (required)
16
+ * @param {string} y - Second field name (optional for single-field nodes)
17
+ * @returns {string} A valid, meaningful identifier under 50 characters
18
+ */
19
+ const createSmartStoreAs = function ( statType, x, y ) {
20
+ // Maximum length for the final identifier
21
+ const MAX_LENGTH = 50;
22
+
23
+ // Ensure statType is valid and reasonable length
24
+ const cleanStatType = ( statType && typeof statType === 'string' && statType.length > 0 ) ?
25
+ ( statType.length > 10 ? statType.substring( 0, 10 ) : statType ) :
26
+ 'value';
27
+
28
+ // Sanitize the primary field
29
+ const cleanX = sanitizeField( x );
30
+
31
+ // Build name based on whether we have one or two fields
32
+ let fullName;
33
+ if ( y === null || y === undefined || y === '' ) {
34
+ // Single field pattern: statType_field
35
+ fullName = `${cleanStatType}_${cleanX}`;
36
+ } else {
37
+ // Two field pattern: statType_field1_field2
38
+ const cleanY = sanitizeField( y );
39
+ fullName = `${cleanStatType}_${cleanX}_${cleanY}`;
40
+ }
41
+
42
+ // If it fits within limit, use it as-is
43
+ if ( fullName.length <= MAX_LENGTH ) {
44
+ return fullName;
45
+ }
46
+
47
+ // For single field, just truncate it
48
+ if ( y === null || y === undefined || y === '' ) {
49
+ const prefixLen = cleanStatType.length + 1; // statType + 1 underscore
50
+ const availableLen = MAX_LENGTH - prefixLen - 5; // Reserve 5 for hash
51
+
52
+ if ( availableLen < 5 ) {
53
+ return smartTruncate( fullName, MAX_LENGTH );
54
+ }
55
+
56
+ const truncatedField = cleanX.length > availableLen ?
57
+ smartTruncate( cleanX, availableLen ) :
58
+ cleanX;
59
+
60
+ return `${cleanStatType}_${truncatedField}`;
61
+ }
62
+
63
+ // For two fields, sanitize y once and reuse
64
+ const cleanY = sanitizeField( y );
65
+
66
+ // Distribute space between both fields
67
+ const prefixLen = cleanStatType.length + 2; // statType + 2 underscores
68
+ const availableLen = MAX_LENGTH - prefixLen;
69
+
70
+ // If even the prefix is too long, truncate everything
71
+ if ( availableLen < 10 ) {
72
+ return smartTruncate( fullName, MAX_LENGTH );
73
+ }
74
+
75
+ // Distribute available space between both fields
76
+ const fieldMaxLen = Math.floor( ( availableLen - 10 ) / 2 );
77
+
78
+ // Truncate fields if needed
79
+ const shortX = cleanX.length > fieldMaxLen ?
80
+ smartTruncate( cleanX, fieldMaxLen ) :
81
+ cleanX;
82
+
83
+ const shortY = cleanY.length > fieldMaxLen ?
84
+ smartTruncate( cleanY, fieldMaxLen ) :
85
+ cleanY;
86
+
87
+ // Build shortened name
88
+ const shortName = `${cleanStatType}_${shortX}_${shortY}`;
89
+
90
+ // Final check - if still too long, truncate the whole thing
91
+ if ( shortName.length > MAX_LENGTH ) {
92
+ return smartTruncate( shortName, MAX_LENGTH );
93
+ }
94
+
95
+ return shortName;
96
+ }; // createSmartStoreAs()
97
+
98
+ export default createSmartStoreAs;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Sanitizes a field name to create a valid JavaScript identifier part.
3
+ * Converts common separators to underscores and removes invalid characters.
4
+ *
5
+ * @param {string} field - The field name to sanitize
6
+ * @returns {string} A valid identifier part, 'field' if input is invalid
7
+ */
8
+ const sanitizeField = function ( field ) {
9
+ // Handle invalid input
10
+ if ( !field || typeof field !== 'string' ) {
11
+ return 'field';
12
+ }
13
+
14
+ // Replace common separators with underscores
15
+ // This handles dots, hyphens, spaces, and slashes
16
+ let clean = field.replace( /[\s\-\.\/\\]+/g, '_' );
17
+
18
+ // Remove all non-alphanumeric characters except underscores
19
+ clean = clean.replace( /[^a-zA-Z0-9_]/g, '' );
20
+
21
+ // If nothing remains, return default
22
+ if ( !clean ) {
23
+ return 'field';
24
+ }
25
+
26
+ // Collapse multiple consecutive underscores into one
27
+ clean = clean.replace( /_+/g, '_' );
28
+
29
+ // Remove leading and trailing underscores
30
+ clean = clean.replace( /^_+|_+$/g, '' );
31
+
32
+ // If nothing remains after trimming underscores, return default
33
+ if ( !clean ) {
34
+ return 'field';
35
+ }
36
+
37
+ // Ensure it doesn't start with a number (invalid in JavaScript)
38
+ // Check AFTER removing leading underscores
39
+ if ( ( /^\d/ ).test( clean ) ) {
40
+ clean = '_' + clean;
41
+ }
42
+
43
+ return clean;
44
+ }; // sanitizeField()
45
+
46
+ export default sanitizeField;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Generates a simple hash from a string for uniqueness.
3
+ * Uses a variant of djb2 algorithm, returns 4-character base36 string.
4
+ *
5
+ * @param {string} str - String to hash
6
+ * @returns {string} 4-character hash
7
+ */
8
+ const generateHash = function ( str ) {
9
+ let hash = 5381;
10
+
11
+ for ( let i = 0; i < str.length; i += 1 ) {
12
+ // hash * 33 + char
13
+ hash = ( ( hash << 5 ) + hash ) + str.charCodeAt( i ); // eslint-disable-line no-bitwise
14
+ // Convert to 32-bit integer
15
+ hash &= hash; // eslint-disable-line no-bitwise
16
+ }
17
+
18
+ // Convert to base36 and take last 4 characters
19
+ return Math.abs( hash ).toString( 36 ).slice( -4 ).padStart( 4, '0' );
20
+ }; // generateHash()
21
+
22
+ /**
23
+ * Finds the best truncation point in a string, preferring word boundaries.
24
+ * Looks for underscores or camelCase transitions.
25
+ *
26
+ * @param {string} str - String to analyze
27
+ * @param {number} maxLen - Maximum length before truncation
28
+ * @returns {number} Best truncation index
29
+ */
30
+ const findBestBreakPoint = function ( str, maxLen ) {
31
+ // For very short strings, just return maxLen
32
+ if ( maxLen < 10 || str.length <= maxLen ) {
33
+ return maxLen;
34
+ }
35
+
36
+ const truncated = str.substring( 0, maxLen );
37
+
38
+ // Look for the last underscore
39
+ const lastUnderscore = truncated.lastIndexOf( '_' );
40
+
41
+ // Look for the last camelCase boundary (lowercase followed by uppercase)
42
+ let lastCamelBoundary = -1;
43
+ for ( let i = truncated.length - 2; i >= 0; i -= 1 ) {
44
+ if ( ( /[a-z]/ ).test( truncated[i] ) && ( /[A-Z]/ ).test( truncated[i + 1] ) ) {
45
+ lastCamelBoundary = i + 1;
46
+ break;
47
+ }
48
+ }
49
+
50
+ // Choose the better break point
51
+ const breakPoint = Math.max( lastUnderscore, lastCamelBoundary );
52
+
53
+ // Only use the break point if it's not too short (at least 60% of maxLen)
54
+ if ( breakPoint > maxLen * 0.6 ) {
55
+ return breakPoint;
56
+ }
57
+
58
+ return maxLen;
59
+ }; // findBestBreakPoint()
60
+
61
+ /**
62
+ * Intelligently truncates a string to fit within maxLength.
63
+ * Tries to break at word boundaries and adds a hash for uniqueness.
64
+ *
65
+ * @param {string} str - String to truncate
66
+ * @param {number} maxLen - Maximum allowed length
67
+ * @returns {string} Truncated string with hash suffix
68
+ */
69
+ const smartTruncate = function ( str, maxLen ) {
70
+ // No truncation needed
71
+ if ( str.length <= maxLen ) {
72
+ return str;
73
+ }
74
+
75
+ // Very short maxLen - just truncate directly
76
+ if ( maxLen < 10 ) {
77
+ return str.substring( 0, maxLen );
78
+ }
79
+
80
+ // Reserve space for underscore and 4-char hash
81
+ const availableLen = maxLen - 5;
82
+
83
+ // Find best break point
84
+ const breakPoint = findBestBreakPoint( str, availableLen );
85
+ const truncated = str.substring( 0, breakPoint );
86
+
87
+ // Generate hash from original string for uniqueness
88
+ const hash = generateHash( str );
89
+
90
+ return `${truncated}_${hash}`;
91
+ }; // smartTruncate()
92
+
93
+ export { smartTruncate, generateHash };
@@ -0,0 +1,5 @@
1
+ // Flow build-time utilities. The naming-policy helpers (renderName / template
2
+ // rendering) were retired when fan naming converged on the fixed
3
+ // ${field}_${label} rule shared by the forEach and pick fan constructs.
4
+ export { makeCollisionChecker } from './make-collision-checker.js';
5
+ export { toKebab } from './to-kebab.js';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Collision checker for generated identifiers.
3
+ * Throws on duplicates; keeps errors explicit and early.
4
+ */
5
+
6
+ const makeCollisionChecker = function () {
7
+ const seen = Object.create( null );
8
+
9
+ /**
10
+ * Assert identifier has not been seen before.
11
+ * @param {string} id
12
+ * @param {string=} hint Optional: human context for error messages
13
+ */
14
+ const isDuplicate = function ( id ) {
15
+ if ( seen[ id ] === 1 ) return true;
16
+ seen[ id ] = 1;
17
+ return false;
18
+ }; // assertUnique()
19
+
20
+ return isDuplicate;
21
+ }; // makeCollisionChecker()
22
+
23
+ export { makeCollisionChecker };
@@ -0,0 +1,20 @@
1
+ // core/utils/flow/to-kebab.js
2
+
3
+ /**
4
+ * Converts camelCase string to kebab-case.
5
+ * Used for mapping node module names to directory paths.
6
+ *
7
+ * @example
8
+ * toKebab('esMean') → 'es-mean'
9
+ * toKebab('pageHinkley') → 'page-hinkley'
10
+ * toKebab('threshold') → 'threshold'
11
+ *
12
+ * @param {string} str - camelCase string
13
+ * @returns {string} kebab-case string
14
+ */
15
+ export const toKebab = function ( str ) {
16
+ return str
17
+ .replace( /([A-Z])/g, '-$1' )
18
+ .toLowerCase()
19
+ .replace( /^-/, '' );
20
+ };
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Half-Life Parameter Utilities
3
+ *
4
+ * Converts between half-life (intuitive) and alpha (computational)
5
+ * parameterizations for exponential decay processes.
6
+ */
7
+
8
+ /**
9
+ * Convert half-life to EWMA alpha parameter.
10
+ * Uses expm1 for numerical stability with large half-life values.
11
+ *
12
+ * @param {number} halfLife Half-life in consistent units (samples or seconds)
13
+ * @returns {number} alpha in (0,1)
14
+ */
15
+ export const halfLifeToAlpha = function ( halfLife ) {
16
+ if ( typeof halfLife !== 'number' || !Number.isFinite( halfLife ) || ( halfLife <= 0 ) ) {
17
+ throw new Error( 'Half-life must be a finite number > 0' );
18
+ }
19
+ // alpha = 1 - exp( -ln(2) / halfLife ); use expm1 to avoid cancellation
20
+ let alpha = -Math.expm1( -( Math.LN2 / halfLife ) );
21
+
22
+ // Defensive clamps (never publish 0 or ≥1):
23
+ const MIN_ALPHA = ( 32 * Number.EPSILON ); // ~3.55e-15 on double
24
+ const MAX_ALPHA = ( 1 - ( 8 * Number.EPSILON ) );
25
+ if ( alpha < MIN_ALPHA ) alpha = MIN_ALPHA;
26
+ if ( alpha > MAX_ALPHA ) alpha = MAX_ALPHA;
27
+
28
+ return alpha;
29
+ }; // halfLifeToAlpha()
30
+
31
+ /**
32
+ * Convert EWMA alpha to half-life.
33
+ * Uses log1p for numerical stability with small alpha values.
34
+ *
35
+ * @param {number} alpha Smoothing factor in (0,1)
36
+ * @returns {number} Half-life in same units used to derive alpha (samples or seconds)
37
+ */
38
+ export const alphaToHalfLife = function ( alpha ) {
39
+ if ( typeof alpha !== 'number' || !Number.isFinite( alpha ) || ( alpha <= 0 ) || ( alpha >= 1 ) ) {
40
+ throw new Error( 'Alpha must be a finite number in (0,1)' );
41
+ }
42
+ // halfLife = ln(2) / -ln(1 - alpha) ; use log1p(-alpha) for stability
43
+ return Math.LN2 / ( -Math.log1p( -alpha ) );
44
+ }; // alphaToHalfLife()
45
+
46
+ /**
47
+ * Samples to warm up a slow EWMA so that the initial-condition influence
48
+ * has decayed to (1 - settledFraction). Half-life is in SAMPLES.
49
+ *
50
+ * @param {number} halfLifeSamples Half-life in samples (> 0)
51
+ * @param {number} settledFraction Target fraction absorbed in (0,1), e.g., 0.95
52
+ * @returns {number} Ceil’d samples to wait
53
+ */
54
+ export const halfLifeToWarmupSamples = function ( halfLifeSamples, settledFraction = 0.95 ) {
55
+ if ( typeof halfLifeSamples !== 'number' || !Number.isFinite( halfLifeSamples ) || ( halfLifeSamples <= 0 ) ) {
56
+ throw new Error( 'halfLifeSamples must be a finite number > 0' );
57
+ }
58
+ if ( typeof settledFraction !== 'number' || !Number.isFinite( settledFraction ) || ( settledFraction <= 0 ) || ( settledFraction >= 1 ) ) {
59
+ throw new Error( 'settledFraction must be a finite number in (0,1)' );
60
+ }
61
+ // nHL = -log2(1 - settledFraction) = -ln(1 - s)/ln2
62
+ const nHalfLives = ( -Math.log1p( -settledFraction ) ) / Math.LN2;
63
+ return Math.ceil( halfLifeSamples * nHalfLives );
64
+ }; // halfLifeToWarmupSamples()
65
+
66
+ /**
67
+ * Effective window (samples) for a chosen settled fraction.
68
+ * By default uses TWO HALF-LIVES → 75% response (settledFraction = 0.75).
69
+ *
70
+ * @param {number} halfLifeSamples Half-life in samples (> 0)
71
+ * @param {number} settledFraction=0.75 Desired settled fraction (0,1)
72
+ * @returns {number} Samples corresponding to the chosen settled fraction
73
+ */
74
+ export const halfLifeToEffectiveWindow = function ( halfLifeSamples, settledFraction = 0.75 ) {
75
+ return halfLifeToWarmupSamples( halfLifeSamples, settledFraction );
76
+ }; // halfLifeToEffectiveWindow()
77
+
78
+ /* Notes (samples + half-life only)
79
+ * Settled fraction s ∈ (0,1):
80
+ * nHalfLives = -log1p( -s ) / Math.LN2
81
+ *
82
+ * Quick refs (multiply your HLs by these and ceil):
83
+ * s=0.75 → 2.000 half-lives
84
+ * s=0.865 → 2.885 half-lives // ≈ 86.5% settled
85
+ * s=0.90 → 3.322 half-lives
86
+ * s=0.95 → 4.322 half-lives
87
+ * s=0.98 → 6.644 half-lives
88
+ *
89
+ * Example: HLs = 20, s = 0.95 → ceil( 20 × 4.322 ) = 87 samples.
90
+ */
91
+
92
+ /**
93
+ * Clamp a numeric value between lower and upper bounds.
94
+ *
95
+ * Uses a simple ternary chain, which is the fastest pattern in V8
96
+ * (monomorphic, inlined, no extra function calls). Preferred over
97
+ * Math.min/Math.max for hot-path use.
98
+ *
99
+ * @param {number} x Value to clamp
100
+ * @param {number} lo Lower bound (inclusive)
101
+ * @param {number} hi Upper bound (inclusive)
102
+ * @returns {number} x constrained to [lo, hi]
103
+ *
104
+ * @example
105
+ * clamp( 5, 0, 10 ); // → 5
106
+ * clamp( -3, 0, 10 ); // → 0
107
+ * clamp( 15, 0, 10 ); // → 10
108
+ */
109
+ export const clamp = function ( x, lo, hi ) {
110
+ return ( x < lo ) ? lo : ( x > hi ? hi : x );
111
+ }; // clamp()
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Disables a node by setting its disable flag to true
3
+ * @param {Object} state - The node's state object
4
+ * @returns {boolean} - Always returns true for consistency with control methods
5
+ */
6
+ const disable = function ( state ) {
7
+ state.disable = true;
8
+ return true;
9
+ }; // disable()
10
+
11
+ export default disable;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Enables a node by setting its disable flag to false
3
+ * @param {Object} state - The node's state object
4
+ * @returns {boolean} - Always returns true for consistency with control methods
5
+ */
6
+ const enable = function ( state ) {
7
+ state.disable = false;
8
+ return true;
9
+ }; // enable()
10
+
11
+ export default enable;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Execute control triggers with re-entrancy protection.
3
+ * Called by nodes during their update cycle when trigger conditions are met.
4
+ *
5
+ * @param {Object} state - Node state containing resolvedTriggers
6
+ * @returns {number} Number of triggers executed (0 if skipped or no triggers)
7
+ */
8
+ const executeTriggers = function ( state ) {
9
+ // No triggers to execute
10
+ if ( !state.resolvedTriggers || state.resolvedTriggers.length === 0 ) {
11
+ return 0;
12
+ }
13
+
14
+ // Prevent re-entrant execution
15
+ if ( state.inControlPhase ) {
16
+ // `skippedTriggers` property is being created on demand.
17
+ state.skippedTriggers = ( state.skippedTriggers || 0 ) + 1;
18
+ return 0;
19
+ }
20
+
21
+ state.inControlPhase = true;
22
+ let executed = 0;
23
+
24
+ try {
25
+ const triggers = state.resolvedTriggers;
26
+ for ( let i = 0; i < triggers.length; i += 1 ) {
27
+ const { control, targets } = triggers[ i ];
28
+ for ( let j = 0; j < targets.length; j += 1 ) {
29
+ control( targets[ j ] );
30
+ executed += 1;
31
+ }
32
+ }
33
+ } finally {
34
+ state.inControlPhase = false;
35
+ }
36
+
37
+ return executed;
38
+ };
39
+
40
+ export default executeTriggers;
@@ -0,0 +1,10 @@
1
+ export { default as executeTriggers } from './execute-triggers.js';
2
+ export { default as validateSpec } from './validate-spec.js';
3
+ export { default as publishNaN } from './publish-nan.js';
4
+ export { default as enable } from './enable.js';
5
+ export { default as disable } from './disable.js';
6
+ export { default as pause } from './pause.js';
7
+ export { default as unpause } from './unpause.js';
8
+ export { default as populatePredicateInput } from './populate-predicate-inputs.js';
9
+ export { default as resetPredicateInput } from './reset-predicate-inputs.js';
10
+