@winkjs/composer 0.0.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +42 -103
  3. package/package.json +53 -29
  4. package/src/composer.js +75 -0
  5. package/src/core/batch/aoo-encoder.js +148 -0
  6. package/src/core/batch/index.js +12 -0
  7. package/src/core/batch/sliding-window.js +91 -0
  8. package/src/core/codec/index.js +137 -0
  9. package/src/core/emitter-manager/mqtt/constants.js +102 -0
  10. package/src/core/emitter-manager/mqtt/emitter.js +780 -0
  11. package/src/core/emitter-manager/mqtt/index.js +190 -0
  12. package/src/core/emitter-manager/mqtt/mqtt-store.js +538 -0
  13. package/src/core/emitter-manager/terminal/assert-columns.js +98 -0
  14. package/src/core/emitter-manager/terminal/formatters.js +160 -0
  15. package/src/core/emitter-manager/terminal/index.js +341 -0
  16. package/src/core/env-vars.js +245 -0
  17. package/src/core/mqtt-protocol.js +47 -0
  18. package/src/core/partition-manager/index.js +7 -0
  19. package/src/core/partition-manager/init.js +44 -0
  20. package/src/core/partition-manager/introspect.js +15 -0
  21. package/src/core/partition-manager/publish-to.js +6 -0
  22. package/src/core/partition-manager/recompute.js +5 -0
  23. package/src/core/partition-manager/reset.js +5 -0
  24. package/src/core/partition-manager/update.js +264 -0
  25. package/src/core/partition-manager/validate-flow.js +157 -0
  26. package/src/core/semantics/digest.js +128 -0
  27. package/src/core/semantics/index.js +83 -0
  28. package/src/core/semantics/loader.js +571 -0
  29. package/src/core/semantics/schemas/asset-class-schema.js +218 -0
  30. package/src/core/semantics/schemas/column-schema.js +651 -0
  31. package/src/core/semantics/schemas/enum-schema.js +153 -0
  32. package/src/core/semantics/schemas/index.js +51 -0
  33. package/src/core/semantics/warnings.js +141 -0
  34. package/src/core/shutdown-manager/index.js +289 -0
  35. package/src/core/source-manager/csv/index.js +171 -0
  36. package/src/core/source-manager/csv/start.js +456 -0
  37. package/src/core/source-manager/mqtt/client.js +406 -0
  38. package/src/core/source-manager/mqtt/constants.js +147 -0
  39. package/src/core/source-manager/mqtt/dedup.js +244 -0
  40. package/src/core/source-manager/mqtt/index.js +260 -0
  41. package/src/core/source-manager/mqtt/status.js +546 -0
  42. package/src/core/source-manager/test-harness/comparator.js +226 -0
  43. package/src/core/source-manager/test-harness/field-generator.js +85 -0
  44. package/src/core/source-manager/test-harness/fuzz.js +87 -0
  45. package/src/core/source-manager/test-harness/index.js +115 -0
  46. package/src/core/source-manager/test-harness/prng.js +57 -0
  47. package/src/core/source-manager/test-harness/start.js +232 -0
  48. package/src/core/source-manager/test-harness/validate.js +213 -0
  49. package/src/core/storage-manager/questdb/assert-columns.js +120 -0
  50. package/src/core/storage-manager/questdb/ensure-tables.js +187 -0
  51. package/src/core/storage-manager/questdb/index.js +1251 -0
  52. package/src/core/storage-manager/questdb/persist-plan.js +488 -0
  53. package/src/core/storage-manager/questdb/writers.js +142 -0
  54. package/src/core/test-utils/sealed-record.js +80 -0
  55. package/src/core/test-utils/soak-signature.js +149 -0
  56. package/src/core/test-utils/tcp-proxy.js +106 -0
  57. package/src/core/tunable/helpers.js +254 -0
  58. package/src/core/tunable/index.js +87 -0
  59. package/src/core/utils/console-formatter/index.js +207 -0
  60. package/src/core/utils/create-smart-store-as/index.js +98 -0
  61. package/src/core/utils/create-smart-store-as/sanitize-field.js +46 -0
  62. package/src/core/utils/create-smart-store-as/smart-truncate.js +93 -0
  63. package/src/core/utils/flow/index.js +5 -0
  64. package/src/core/utils/flow/make-collision-checker.js +23 -0
  65. package/src/core/utils/flow/to-kebab.js +20 -0
  66. package/src/core/utils/half-life/index.js +111 -0
  67. package/src/core/utils/node/disable.js +11 -0
  68. package/src/core/utils/node/enable.js +11 -0
  69. package/src/core/utils/node/execute-triggers.js +40 -0
  70. package/src/core/utils/node/index.js +10 -0
  71. package/src/core/utils/node/pause.js +11 -0
  72. package/src/core/utils/node/populate-predicate-inputs.js +14 -0
  73. package/src/core/utils/node/publish-nan.js +19 -0
  74. package/src/core/utils/node/reset-predicate-inputs.js +11 -0
  75. package/src/core/utils/node/unpause.js +11 -0
  76. package/src/core/utils/node/validate-spec.js +22 -0
  77. package/src/core/utils/options/resolve-field-keyed.js +115 -0
  78. package/src/core/utils/quantize/index.js +75 -0
  79. package/src/core/utils/stats/formulas.js +67 -0
  80. package/src/core/utils/stats/index.js +3 -0
  81. package/src/core/utils/validate/composer-validators.js +141 -0
  82. package/src/core/utils/validate/helpers.js +206 -0
  83. package/src/core/utils/validate/index.js +12 -0
  84. package/src/core/utils/validate/type-validators.js +538 -0
  85. package/src/core/utils/validate/validate.js +107 -0
  86. package/src/core/utils/validate/validators.js +177 -0
  87. package/src/core/wiring/assert-handle.js +57 -0
  88. package/src/core/wiring/assert-module.js +63 -0
  89. package/src/core/wiring/index.js +5 -0
  90. package/src/core/wiring/node-type-to-module.js +17 -0
  91. package/src/core/wiring/wire-emitters.js +256 -0
  92. package/src/core/wiring/wire-linear-graph.js +25 -0
  93. package/src/core/wiring/wire-node.js +157 -0
  94. package/src/core/wiring/wire-semantics.js +173 -0
  95. package/src/core/wiring/wire-storages.js +344 -0
  96. package/src/flow/check-output-collisions.js +93 -0
  97. package/src/flow/consts.js +9 -0
  98. package/src/flow/deep-clone-spec.js +64 -0
  99. package/src/flow/driver.js +171 -0
  100. package/src/flow/expand-single-input-array.js +76 -0
  101. package/src/flow/expand-template-spec.js +93 -0
  102. package/src/flow/flow-api-schemas.js +300 -0
  103. package/src/flow/flow.js +658 -0
  104. package/src/flow/for-each.js +225 -0
  105. package/src/flow/get-signature-pattern.js +31 -0
  106. package/src/flow/get-target-array.js +46 -0
  107. package/src/flow/inspect.js +67 -0
  108. package/src/flow/load-node-module.js +81 -0
  109. package/src/flow/make-node-method.js +112 -0
  110. package/src/flow/resolve-pick-by-field.js +77 -0
  111. package/src/flow/resolve-tunables.js +76 -0
  112. package/src/flow/run.js +392 -0
  113. package/src/flow/serialize.js +161 -0
  114. package/src/flow/signatures-schema.js +222 -0
  115. package/src/flow/spec-builder.js +65 -0
  116. package/src/flow/validate-triggers.js +250 -0
  117. package/src/flow/validate.js +261 -0
  118. package/src/nodes/accumulate/index.js +21 -0
  119. package/src/nodes/accumulate/init.js +48 -0
  120. package/src/nodes/accumulate/introspect.js +123 -0
  121. package/src/nodes/accumulate/publish-to.js +34 -0
  122. package/src/nodes/accumulate/recompute.js +27 -0
  123. package/src/nodes/accumulate/reset.js +25 -0
  124. package/src/nodes/accumulate/update.js +42 -0
  125. package/src/nodes/appraise/calibrate.js +64 -0
  126. package/src/nodes/appraise/decision.js +66 -0
  127. package/src/nodes/appraise/deviation.js +140 -0
  128. package/src/nodes/appraise/index.js +23 -0
  129. package/src/nodes/appraise/init.js +165 -0
  130. package/src/nodes/appraise/integrate.js +45 -0
  131. package/src/nodes/appraise/introspect.js +352 -0
  132. package/src/nodes/appraise/publish-to.js +93 -0
  133. package/src/nodes/appraise/receptor.js +69 -0
  134. package/src/nodes/appraise/recompute.js +79 -0
  135. package/src/nodes/appraise/reset.js +53 -0
  136. package/src/nodes/appraise/update.js +130 -0
  137. package/src/nodes/archive/csv/index.js +6 -0
  138. package/src/nodes/archive/csv/init.js +36 -0
  139. package/src/nodes/archive/csv/load.js +70 -0
  140. package/src/nodes/archive/csv/reset.js +14 -0
  141. package/src/nodes/archive/csv/simple-parser.js +216 -0
  142. package/src/nodes/archive/csv/test.js +173 -0
  143. package/src/nodes/archive/csv/update.js +63 -0
  144. package/src/nodes/butterworth-filter/index.js +18 -0
  145. package/src/nodes/butterworth-filter/init.js +184 -0
  146. package/src/nodes/butterworth-filter/introspect.js +228 -0
  147. package/src/nodes/butterworth-filter/publish-to.js +21 -0
  148. package/src/nodes/butterworth-filter/recompute.js +13 -0
  149. package/src/nodes/butterworth-filter/reset.js +30 -0
  150. package/src/nodes/butterworth-filter/update.js +38 -0
  151. package/src/nodes/categorize/index.js +19 -0
  152. package/src/nodes/categorize/init.js +58 -0
  153. package/src/nodes/categorize/introspect.js +177 -0
  154. package/src/nodes/categorize/publish-to.js +29 -0
  155. package/src/nodes/categorize/recompute.js +14 -0
  156. package/src/nodes/categorize/reset.js +16 -0
  157. package/src/nodes/categorize/update.js +53 -0
  158. package/src/nodes/controller/index.js +9 -0
  159. package/src/nodes/controller/init.js +55 -0
  160. package/src/nodes/controller/introspect.js +91 -0
  161. package/src/nodes/controller/publish-to.js +8 -0
  162. package/src/nodes/controller/recompute.js +9 -0
  163. package/src/nodes/controller/reset.js +17 -0
  164. package/src/nodes/controller/update.js +63 -0
  165. package/src/nodes/diff/index.js +19 -0
  166. package/src/nodes/diff/init.js +37 -0
  167. package/src/nodes/diff/introspect.js +132 -0
  168. package/src/nodes/diff/publish-to.js +21 -0
  169. package/src/nodes/diff/recompute.js +12 -0
  170. package/src/nodes/diff/reset.js +12 -0
  171. package/src/nodes/diff/update.js +37 -0
  172. package/src/nodes/digest-moments/formulas.js +12 -0
  173. package/src/nodes/digest-moments/index.js +14 -0
  174. package/src/nodes/digest-moments/init.js +67 -0
  175. package/src/nodes/digest-moments/introspect.js +154 -0
  176. package/src/nodes/digest-moments/publish-to.js +34 -0
  177. package/src/nodes/digest-moments/recompute.js +14 -0
  178. package/src/nodes/digest-moments/reset.js +14 -0
  179. package/src/nodes/digest-moments/update.js +120 -0
  180. package/src/nodes/dwell-time-tracker/index.js +14 -0
  181. package/src/nodes/dwell-time-tracker/init.js +59 -0
  182. package/src/nodes/dwell-time-tracker/introspect.js +137 -0
  183. package/src/nodes/dwell-time-tracker/publish-to.js +22 -0
  184. package/src/nodes/dwell-time-tracker/recompute.js +8 -0
  185. package/src/nodes/dwell-time-tracker/reset.js +23 -0
  186. package/src/nodes/dwell-time-tracker/update.js +103 -0
  187. package/src/nodes/emit-if/helpers.js +94 -0
  188. package/src/nodes/emit-if/index.js +16 -0
  189. package/src/nodes/emit-if/init.js +67 -0
  190. package/src/nodes/emit-if/introspect.js +102 -0
  191. package/src/nodes/emit-if/publish-to.js +13 -0
  192. package/src/nodes/emit-if/recompute.js +12 -0
  193. package/src/nodes/emit-if/reset.js +27 -0
  194. package/src/nodes/emit-if/update.js +93 -0
  195. package/src/nodes/es-correlation/index.js +19 -0
  196. package/src/nodes/es-correlation/init.js +73 -0
  197. package/src/nodes/es-correlation/introspect.js +176 -0
  198. package/src/nodes/es-correlation/publish-to.js +32 -0
  199. package/src/nodes/es-correlation/recompute.js +56 -0
  200. package/src/nodes/es-correlation/reset.js +27 -0
  201. package/src/nodes/es-correlation/update.js +110 -0
  202. package/src/nodes/es-mean/index.js +20 -0
  203. package/src/nodes/es-mean/init.js +58 -0
  204. package/src/nodes/es-mean/introspect.js +129 -0
  205. package/src/nodes/es-mean/publish-to.js +19 -0
  206. package/src/nodes/es-mean/recompute.js +16 -0
  207. package/src/nodes/es-mean/reset.js +24 -0
  208. package/src/nodes/es-mean/update.js +69 -0
  209. package/src/nodes/es-pairwise-correlation/index.js +19 -0
  210. package/src/nodes/es-pairwise-correlation/init.js +98 -0
  211. package/src/nodes/es-pairwise-correlation/introspect.js +187 -0
  212. package/src/nodes/es-pairwise-correlation/publish-to.js +31 -0
  213. package/src/nodes/es-pairwise-correlation/recompute.js +69 -0
  214. package/src/nodes/es-pairwise-correlation/reset.js +29 -0
  215. package/src/nodes/es-pairwise-correlation/update.js +89 -0
  216. package/src/nodes/es-stats/index.js +21 -0
  217. package/src/nodes/es-stats/init.js +105 -0
  218. package/src/nodes/es-stats/introspect.js +157 -0
  219. package/src/nodes/es-stats/publish-to.js +42 -0
  220. package/src/nodes/es-stats/recompute.js +74 -0
  221. package/src/nodes/es-stats/reset.js +49 -0
  222. package/src/nodes/es-stats/update-envelope.js +44 -0
  223. package/src/nodes/es-stats/update-welford.js +64 -0
  224. package/src/nodes/es-stats/update.js +59 -0
  225. package/src/nodes/index.js +83 -0
  226. package/src/nodes/invert-flag/index.js +20 -0
  227. package/src/nodes/invert-flag/init.js +36 -0
  228. package/src/nodes/invert-flag/introspect.js +115 -0
  229. package/src/nodes/invert-flag/publish-to.js +23 -0
  230. package/src/nodes/invert-flag/recompute.js +12 -0
  231. package/src/nodes/invert-flag/reset.js +12 -0
  232. package/src/nodes/invert-flag/update.js +32 -0
  233. package/src/nodes/kalman1d/index.js +20 -0
  234. package/src/nodes/kalman1d/init.js +103 -0
  235. package/src/nodes/kalman1d/introspect.js +250 -0
  236. package/src/nodes/kalman1d/publish-to.js +34 -0
  237. package/src/nodes/kalman1d/recompute.js +23 -0
  238. package/src/nodes/kalman1d/reset.js +29 -0
  239. package/src/nodes/kalman1d/update.js +144 -0
  240. package/src/nodes/kernel/index.js +18 -0
  241. package/src/nodes/kernel/init.js +66 -0
  242. package/src/nodes/kernel/introspect.js +163 -0
  243. package/src/nodes/kernel/presets.js +74 -0
  244. package/src/nodes/kernel/publish-to.js +25 -0
  245. package/src/nodes/kernel/recompute.js +14 -0
  246. package/src/nodes/kernel/reset.js +20 -0
  247. package/src/nodes/kernel/update.js +69 -0
  248. package/src/nodes/lag/index.js +21 -0
  249. package/src/nodes/lag/init.js +87 -0
  250. package/src/nodes/lag/introspect.js +202 -0
  251. package/src/nodes/lag/publish-to.js +64 -0
  252. package/src/nodes/lag/recompute.js +33 -0
  253. package/src/nodes/lag/reset.js +49 -0
  254. package/src/nodes/lag/update.js +133 -0
  255. package/src/nodes/median3/index.js +19 -0
  256. package/src/nodes/median3/init.js +40 -0
  257. package/src/nodes/median3/introspect.js +116 -0
  258. package/src/nodes/median3/publish-to.js +21 -0
  259. package/src/nodes/median3/recompute.js +12 -0
  260. package/src/nodes/median3/reset.js +15 -0
  261. package/src/nodes/median3/update.js +58 -0
  262. package/src/nodes/moments-digest/copy-from.js +12 -0
  263. package/src/nodes/moments-digest/flush.js +17 -0
  264. package/src/nodes/moments-digest/index.js +132 -0
  265. package/src/nodes/moments-digest/init.js +84 -0
  266. package/src/nodes/moments-digest/introspect.js +122 -0
  267. package/src/nodes/moments-digest/prelude.js +28 -0
  268. package/src/nodes/moments-digest/publish-to.js +31 -0
  269. package/src/nodes/moments-digest/recompute.js +9 -0
  270. package/src/nodes/moments-digest/reset.js +20 -0
  271. package/src/nodes/moments-digest/update.js +182 -0
  272. package/src/nodes/node-names.js +67 -0
  273. package/src/nodes/page-hinkley/index.js +20 -0
  274. package/src/nodes/page-hinkley/init.js +66 -0
  275. package/src/nodes/page-hinkley/introspect.js +193 -0
  276. package/src/nodes/page-hinkley/publish-to.js +28 -0
  277. package/src/nodes/page-hinkley/recompute.js +14 -0
  278. package/src/nodes/page-hinkley/reset.js +23 -0
  279. package/src/nodes/page-hinkley/update.js +105 -0
  280. package/src/nodes/pass-if/index.js +21 -0
  281. package/src/nodes/pass-if/init.js +37 -0
  282. package/src/nodes/pass-if/introspect.js +93 -0
  283. package/src/nodes/pass-if/publish-to.js +15 -0
  284. package/src/nodes/pass-if/recompute.js +15 -0
  285. package/src/nodes/pass-if/reset.js +18 -0
  286. package/src/nodes/pass-if/update.js +37 -0
  287. package/src/nodes/persist-if/helpers.js +111 -0
  288. package/src/nodes/persist-if/index.js +9 -0
  289. package/src/nodes/persist-if/init.js +98 -0
  290. package/src/nodes/persist-if/introspect.js +106 -0
  291. package/src/nodes/persist-if/publish-to.js +21 -0
  292. package/src/nodes/persist-if/recompute.js +20 -0
  293. package/src/nodes/persist-if/reset.js +35 -0
  294. package/src/nodes/persist-if/update.js +112 -0
  295. package/src/nodes/persistence-check/index.js +14 -0
  296. package/src/nodes/persistence-check/init.js +38 -0
  297. package/src/nodes/persistence-check/introspect.js +144 -0
  298. package/src/nodes/persistence-check/publish-to.js +11 -0
  299. package/src/nodes/persistence-check/recompute.js +7 -0
  300. package/src/nodes/persistence-check/reset.js +12 -0
  301. package/src/nodes/persistence-check/update.js +57 -0
  302. package/src/nodes/process-index/index.js +15 -0
  303. package/src/nodes/process-index/init.js +48 -0
  304. package/src/nodes/process-index/introspect.js +182 -0
  305. package/src/nodes/process-index/publish-to.js +29 -0
  306. package/src/nodes/process-index/recompute.js +8 -0
  307. package/src/nodes/process-index/reset.js +8 -0
  308. package/src/nodes/process-index/update.js +75 -0
  309. package/src/nodes/ratio/index.js +14 -0
  310. package/src/nodes/ratio/init.js +37 -0
  311. package/src/nodes/ratio/introspect.js +155 -0
  312. package/src/nodes/ratio/publish-to.js +15 -0
  313. package/src/nodes/ratio/recompute.js +7 -0
  314. package/src/nodes/ratio/reset.js +7 -0
  315. package/src/nodes/ratio/update.js +47 -0
  316. package/src/nodes/sanitize/index.js +82 -0
  317. package/src/nodes/sanitize/init.js +82 -0
  318. package/src/nodes/sanitize/introspect.js +194 -0
  319. package/src/nodes/sanitize/publish-to.js +15 -0
  320. package/src/nodes/sanitize/recompute.js +8 -0
  321. package/src/nodes/sanitize/reset.js +14 -0
  322. package/src/nodes/sanitize/update.js +102 -0
  323. package/src/nodes/spike-guard/index.js +14 -0
  324. package/src/nodes/spike-guard/init.js +47 -0
  325. package/src/nodes/spike-guard/introspect.js +130 -0
  326. package/src/nodes/spike-guard/publish-to.js +35 -0
  327. package/src/nodes/spike-guard/recompute.js +14 -0
  328. package/src/nodes/spike-guard/reset.js +19 -0
  329. package/src/nodes/spike-guard/update.js +89 -0
  330. package/src/nodes/sse-emitter/index.js +7 -0
  331. package/src/nodes/sse-emitter/init.js +105 -0
  332. package/src/nodes/sse-emitter/introspect.js +134 -0
  333. package/src/nodes/sse-emitter/publish-to.js +6 -0
  334. package/src/nodes/sse-emitter/recompute.js +16 -0
  335. package/src/nodes/sse-emitter/reset.js +19 -0
  336. package/src/nodes/sse-emitter/update.js +69 -0
  337. package/src/nodes/sse-emitter/utils/broadcast-heartbeat.js +36 -0
  338. package/src/nodes/sse-emitter/utils/build-message.js +31 -0
  339. package/src/nodes/sse-emitter/utils/connection-manager.js +45 -0
  340. package/src/nodes/sse-emitter/utils/endpoint-initializer.js +20 -0
  341. package/src/nodes/sse-emitter/utils/health-monitor.js +38 -0
  342. package/src/nodes/sse-emitter/utils/qos-handler.js +41 -0
  343. package/src/nodes/state-change-detector/helpers.js +35 -0
  344. package/src/nodes/state-change-detector/index.js +12 -0
  345. package/src/nodes/state-change-detector/init.js +56 -0
  346. package/src/nodes/state-change-detector/introspect.js +146 -0
  347. package/src/nodes/state-change-detector/publish-to.js +20 -0
  348. package/src/nodes/state-change-detector/recompute.js +6 -0
  349. package/src/nodes/state-change-detector/reset.js +20 -0
  350. package/src/nodes/state-change-detector/update.js +97 -0
  351. package/src/nodes/sw-stats/index.js +14 -0
  352. package/src/nodes/sw-stats/init.js +51 -0
  353. package/src/nodes/sw-stats/introspect.js +131 -0
  354. package/src/nodes/sw-stats/publish-to.js +45 -0
  355. package/src/nodes/sw-stats/recompute.js +33 -0
  356. package/src/nodes/sw-stats/reset.js +15 -0
  357. package/src/nodes/sw-stats/update.js +39 -0
  358. package/src/nodes/swing-watch/index.js +17 -0
  359. package/src/nodes/swing-watch/init.js +144 -0
  360. package/src/nodes/swing-watch/introspect.js +188 -0
  361. package/src/nodes/swing-watch/publish-to.js +53 -0
  362. package/src/nodes/swing-watch/recompute.js +22 -0
  363. package/src/nodes/swing-watch/reset.js +55 -0
  364. package/src/nodes/swing-watch/update.js +767 -0
  365. package/src/nodes/tally/index.js +15 -0
  366. package/src/nodes/tally/init.js +32 -0
  367. package/src/nodes/tally/introspect.js +116 -0
  368. package/src/nodes/tally/publish-to.js +28 -0
  369. package/src/nodes/tally/recompute.js +10 -0
  370. package/src/nodes/tally/reset.js +10 -0
  371. package/src/nodes/tally/update.js +44 -0
  372. package/src/nodes/threshold/index.js +14 -0
  373. package/src/nodes/threshold/init.js +121 -0
  374. package/src/nodes/threshold/introspect.js +192 -0
  375. package/src/nodes/threshold/publish-to.js +11 -0
  376. package/src/nodes/threshold/recompute.js +8 -0
  377. package/src/nodes/threshold/reset.js +14 -0
  378. package/src/nodes/threshold/update.js +54 -0
  379. package/src/nodes/transform/helpers.js +39 -0
  380. package/src/nodes/transform/index.js +15 -0
  381. package/src/nodes/transform/init.js +35 -0
  382. package/src/nodes/transform/introspect.js +118 -0
  383. package/src/nodes/transform/publish-to.js +23 -0
  384. package/src/nodes/transform/recompute.js +12 -0
  385. package/src/nodes/transform/reset.js +11 -0
  386. package/src/nodes/transform/update.js +32 -0
  387. package/src/nodes/trend/compute-confidence.js +112 -0
  388. package/src/nodes/trend/index.js +14 -0
  389. package/src/nodes/trend/init.js +81 -0
  390. package/src/nodes/trend/introspect.js +151 -0
  391. package/src/nodes/trend/publish-to.js +22 -0
  392. package/src/nodes/trend/recompute.js +15 -0
  393. package/src/nodes/trend/reset.js +26 -0
  394. package/src/nodes/trend/update.js +93 -0
  395. package/src/nodes/tw-stats/copy-from.js +16 -0
  396. package/src/nodes/tw-stats/flush.js +12 -0
  397. package/src/nodes/tw-stats/index.js +41 -0
  398. package/src/nodes/tw-stats/init.js +92 -0
  399. package/src/nodes/tw-stats/introspect.js +171 -0
  400. package/src/nodes/tw-stats/publish-to.js +108 -0
  401. package/src/nodes/tw-stats/recompute.js +9 -0
  402. package/src/nodes/tw-stats/reset.js +16 -0
  403. package/src/nodes/tw-stats/update.js +113 -0
  404. package/src/nodes/unbalance/index.js +15 -0
  405. package/src/nodes/unbalance/init.js +59 -0
  406. package/src/nodes/unbalance/introspect.js +167 -0
  407. package/src/nodes/unbalance/publish-to.js +52 -0
  408. package/src/nodes/unbalance/recompute.js +11 -0
  409. package/src/nodes/unbalance/reset.js +10 -0
  410. package/src/nodes/unbalance/update.js +83 -0
  411. package/src/nodes/vector-distance/index.js +14 -0
  412. package/src/nodes/vector-distance/init.js +54 -0
  413. package/src/nodes/vector-distance/introspect.js +149 -0
  414. package/src/nodes/vector-distance/publish-to.js +35 -0
  415. package/src/nodes/vector-distance/recompute.js +11 -0
  416. package/src/nodes/vector-distance/reset.js +20 -0
  417. package/src/nodes/vector-distance/update.js +139 -0
  418. package/src/nodes/winnow/index.js +12 -0
  419. package/src/nodes/winnow/init.js +82 -0
  420. package/src/nodes/winnow/introspect.js +253 -0
  421. package/src/nodes/winnow/publish-to.js +51 -0
  422. package/src/nodes/winnow/recompute.js +14 -0
  423. package/src/nodes/winnow/reset.js +34 -0
  424. package/src/nodes/winnow/update.js +203 -0
  425. package/src/tools/training/features.js +227 -0
  426. package/src/tools/training/index.js +21 -0
  427. package/src/tools/training/logistic.js +238 -0
  428. package/src/tools/training/metrics.js +126 -0
  429. package/src/tools/training/scale.js +239 -0
  430. package/src/tools/training/validate.js +103 -0
  431. package/src/windowing/count-sliding/create.js +16 -0
  432. package/src/windowing/count-sliding/get-reverse-chronological-index.js +19 -0
  433. package/src/windowing/count-sliding/index.js +6 -0
  434. package/src/windowing/count-sliding/is-not-full.js +5 -0
  435. package/src/windowing/count-sliding/push.js +15 -0
  436. package/src/windowing/count-sliding/reset.js +11 -0
  437. package/src/windowing/count-sliding/size.js +5 -0
  438. package/src/windowing/time-sliding/create.js +25 -0
  439. package/src/windowing/time-sliding/push.js +42 -0
  440. package/CODE_OF_CONDUCT.md +0 -46
  441. package/CONTRIBUTING.md +0 -132
  442. package/docs/.nojekyll +0 -0
  443. package/docs/CONTRIBUTING.md +0 -134
  444. package/docs/README.md +0 -132
  445. package/docs/_coverpage.md +0 -26
  446. package/docs/_media/bg.png +0 -0
  447. package/docs/_media/wink-logo.png +0 -0
  448. package/docs/_navbar.md +0 -14
  449. package/docs/_sidebar.md +0 -2
  450. package/docs/index.html +0 -44
  451. package/eslint.config.js +0 -283
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @fileoverview Page-Hinkley change detection node — public API barrel file.
3
+ *
4
+ * Re-exports the standard node interface (init, update, publishTo, reset,
5
+ * recompute) plus shared control functions (disable, enable, pause, unpause)
6
+ * and all introspection metadata.
7
+ */
8
+
9
+ export { default as init } from './init.js';
10
+ export { default as update } from './update.js';
11
+ export { default as reset } from './reset.js';
12
+ export { default as recompute } from './recompute.js';
13
+ export { default as publishTo } from './publish-to.js';
14
+ // Direct imports for common control functions
15
+ export { default as disable } from '../../core/utils/node/disable.js';
16
+ export { default as enable } from '../../core/utils/node/enable.js';
17
+ export { default as pause } from '../../core/utils/node/pause.js';
18
+ export { default as unpause } from '../../core/utils/node/unpause.js';
19
+ // Re-export everything from introspection.js
20
+ export * from './introspect.js';
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @fileoverview Initializes Page-Hinkley node state from a validated spec.
3
+ *
4
+ * Creates the complete state object: input mapping, tunable parameters
5
+ * (delta, lambda), structural options (halfLife, detectDrop, minWarmUpSamples),
6
+ * and all accumulator/output fields at their initial values. No allocations
7
+ * occur after init — the hot path (update/publishTo) is allocation-free.
8
+ */
9
+
10
+ import { validateSpec } from '../../core/utils/node/index.js';
11
+ import * as introspect from './introspect.js';
12
+ import { resolveScalar } from '../../core/utils/options/resolve-field-keyed.js';
13
+ import { asTunable } from '../../core/tunable/index.js';
14
+ import { halfLifeToAlpha } from '../../core/utils/half-life/index.js';
15
+
16
+ const init = function ( spec ) {
17
+ validateSpec( spec, introspect );
18
+
19
+ // Create state after validation passes
20
+ const state = Object.create( null );
21
+ // Standard input parameter health flag during update: false means healthy
22
+ state.inputValidationFailed = false;
23
+ // Ensure node is enabled by default
24
+ state.disable = false;
25
+ state.pause = false;
26
+
27
+ // Extract field name
28
+ state.x = spec.from.x;
29
+
30
+ // Config copy
31
+ state.stats = spec.stats;
32
+
33
+ // Apply defaults from introspect (validation doesn't enforce them)
34
+ // Supports direct, field-keyed, and tunable specification for tunable params
35
+ const deltaSpec = resolveScalar( spec.delta, state.x );
36
+ const lambdaSpec = resolveScalar( spec.lambda, state.x );
37
+ // delta and lambda support tunables for adaptive change detection
38
+ state.deltaFn = asTunable( deltaSpec ?? introspect.DEFAULT_OPTIONS.delta );
39
+ state.lambdaFn = asTunable( lambdaSpec ?? introspect.DEFAULT_OPTIONS.lambda );
40
+ // halfLife is structural: selects exponentially smoothed vs running mean baseline.
41
+ // When absent → running mean (alpha=0). When present → alpha derived from halfLife.
42
+ const halfLifeSpec = resolveScalar( spec.halfLife, state.x );
43
+ state.alpha = ( typeof halfLifeSpec === 'number' ) ? halfLifeToAlpha( halfLifeSpec ) : 0;
44
+ state.detectDrop = spec.detectDrop ?? introspect.DEFAULT_OPTIONS.detectDrop;
45
+ state.minWarmUpSamples = spec.minWarmUpSamples ?? introspect.DEFAULT_OPTIONS.minWarmUpSamples;
46
+
47
+ // Seed tunable state fields with defaults — overwritten on every successful update()
48
+ state.delta = introspect.DEFAULT_OPTIONS.delta;
49
+ state.lambda = introspect.DEFAULT_OPTIONS.lambda;
50
+ state.tunableErrorLogged = false;
51
+
52
+ // State variables
53
+ state.cumSum = 0; // Cumulative sum
54
+ state.minCumSum = 0; // Running minimum of cumulative sum
55
+ state.mean = 0; // Adaptive mean estimate
56
+ state.count = 0; // Sample count for mean estimation
57
+ state.shiftDetected = false; // Previous shift detection state
58
+ state.testStatistic = 0; // Page-Hinkley test statistic
59
+
60
+ state.nodeType = introspect.getNodeType();
61
+ state.inControlPhase = false;
62
+
63
+ return state;
64
+ }; // init()
65
+
66
+ export default init;
@@ -0,0 +1,193 @@
1
+ /**
2
+ * @fileoverview Page-Hinkley node introspection metadata.
3
+ *
4
+ * Defines supported stats (phShift, phTestStatistic, phMean), control methods,
5
+ * default options, DSL spec schema with validators, and the buildSpec function
6
+ * for DSL transpilation. Single source of truth for the node's public contract.
7
+ */
8
+
9
+ import { validators, composerValidators } from '../../core/utils/validate/index.js';
10
+ import { resolveScalar } from '../../core/utils/options/resolve-field-keyed.js';
11
+
12
+ /** Single source of truth for what this plugin can do */
13
+ const SUPPORTED_STATS = [
14
+ 'phTestStatistic',
15
+ 'phMean',
16
+ 'phShift'
17
+ ];
18
+
19
+ /** Human-readable descriptions (for introspection) */
20
+ const STAT_DESCRIPTIONS = {
21
+ phTestStatistic: 'Page-Hinkley change detection statistic',
22
+ phMean: 'Running mean or EWMA based on value of alpha',
23
+ phShift: 'Boolean indicator of detected shift'
24
+ };
25
+
26
+ /** Control methods available for triggers */
27
+ const SUPPORTED_CONTROL_METHODS = {
28
+ reset: 'Clears accumulated state and restarts computation',
29
+ enable: 'Enables node processing',
30
+ disable: 'Disables node processing',
31
+ pause: 'Pauses node processing while keeping state visible',
32
+ unpause: 'Resumes node processing after pause'
33
+ };
34
+
35
+ /** The type of this node */
36
+ const NODE_TYPE = 'Page Hinkley';
37
+
38
+ /** Node capabilities for documentation */
39
+ const CAPABILITIES = {
40
+ description: 'Detects changes in data distribution using the Page-Hinkley test',
41
+ features: [
42
+ 'Sequential change point detection algorithm',
43
+ 'Configurable sensitivity via lambda threshold',
44
+ 'Adaptive baseline with running mean or EWMA',
45
+ 'Can detect both increases and decreases in mean'
46
+ ]
47
+ };
48
+
49
+ // Export functions for accessing metadata
50
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
51
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
52
+ export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
53
+ export const getNodeType = () => NODE_TYPE;
54
+ export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
55
+
56
+ export const DEFAULT_OPTIONS = {
57
+ delta: 0.005,
58
+ lambda: 45,
59
+ // halfLife: not specified → running mean (alpha=0). When specified,
60
+ // init.js converts halfLife → alpha via halfLifeToAlpha().
61
+ detectDrop: false,
62
+ minWarmUpSamples: 10
63
+ };
64
+
65
+ /** Parameters that support tunable (dynamic) values.
66
+ * halfLife is structural (selects running mean vs exponentially smoothed
67
+ * baseline at init time), not tunable per-message. */
68
+ export const TUNABLE_PARAMS = [ 'delta', 'lambda' ];
69
+
70
+ // DSL Metadata for transpilation
71
+ const DSL_METADATA = {
72
+ // Spec schema for validation
73
+ specSchema: {
74
+ nodeType: {
75
+ type: 'string',
76
+ required: true,
77
+ value: NODE_TYPE
78
+ },
79
+ name: {
80
+ type: 'string',
81
+ required: true,
82
+ validator: validators.identifier,
83
+ error: 'Name must be a valid identifier'
84
+ },
85
+ from: {
86
+ type: 'object',
87
+ required: true,
88
+ properties: {
89
+ x: {
90
+ type: 'string',
91
+ required: true,
92
+ validator: validators.noSpaces,
93
+ error: 'Field name cannot contain spaces'
94
+ }
95
+ }
96
+ },
97
+ delta: {
98
+ type: 'numberOrFunctionOrFieldKeyed',
99
+ required: false,
100
+ default: 0.005,
101
+ validator: validators.positiveOrFunction,
102
+ error: 'Delta must be a positive number or function'
103
+ },
104
+ lambda: {
105
+ type: 'numberOrFunctionOrFieldKeyed',
106
+ required: false,
107
+ default: 45,
108
+ validator: validators.positiveOrFunction,
109
+ error: 'Lambda must be a positive number or function'
110
+ },
111
+ halfLife: {
112
+ type: 'numberOrFieldKeyed',
113
+ required: false,
114
+ validator: composerValidators.halfLife,
115
+ error: 'halfLife must be > 0 and < 999999'
116
+ },
117
+ detectDrop: {
118
+ type: 'boolean',
119
+ required: false,
120
+ default: false
121
+ },
122
+ minWarmUpSamples: {
123
+ type: 'number',
124
+ required: false,
125
+ default: 10,
126
+ integer: true,
127
+ validator: validators.positiveInteger,
128
+ error: 'Minimum warm-up samples must be a positive integer'
129
+ },
130
+ stats: {
131
+ type: 'object',
132
+ required: true,
133
+ minProperties: 1,
134
+ propertyNames: SUPPORTED_STATS,
135
+ propertySchema: {
136
+ type: 'object',
137
+ properties: {
138
+ storeAs: {
139
+ type: 'string',
140
+ required: true,
141
+ validator: validators.identifier,
142
+ error: 'storeAs must be a valid identifier'
143
+ }
144
+ }
145
+ }
146
+ },
147
+ triggers: {
148
+ type: 'array',
149
+ required: false,
150
+ itemSchema: {
151
+ type: 'object',
152
+ validator: composerValidators.trigger,
153
+ error: 'Invalid trigger specification'
154
+ }
155
+ }
156
+ },
157
+
158
+ // Cross-field validators
159
+ crossFieldValidators: [
160
+ {
161
+ fields: [ 'delta', 'lambda' ],
162
+ validator: ( spec ) => {
163
+ // Resolve each for the node's field so a direct value and a
164
+ // field-keyed map are compared the same way (each resolves to a
165
+ // number, a function, or undefined).
166
+ const delta = resolveScalar( spec.delta, spec.from?.x );
167
+ const lambda = resolveScalar( spec.lambda, spec.from?.x );
168
+ // If either is a function (tunable), defer validation to runtime
169
+ if ( typeof delta === 'function' || typeof lambda === 'function' ) {
170
+ return true;
171
+ }
172
+ // Delta should be small relative to lambda for proper sensitivity
173
+ if ( !delta || !lambda ) return true; // Use defaults
174
+ return delta < lambda * 0.1;
175
+ },
176
+ error: 'Delta should be less than 10% of lambda for proper sensitivity'
177
+ },
178
+ composerValidators.noSelfTriggers
179
+ ],
180
+
181
+ // Build spec from DSL parameters
182
+ // Pattern: NAME_X_OUTPUTS_OPTIONS -> (name, x, stats, options)
183
+ buildSpec: ( name, x, stats, options ) => ( {
184
+ nodeType: NODE_TYPE,
185
+ name,
186
+ from: { x },
187
+ stats,
188
+ ...options
189
+ } ),
190
+
191
+ };
192
+
193
+ export const getDSLMetadata = () => ( { ...DSL_METADATA } );
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @fileoverview Publishes Page-Hinkley results to the downstream message.
3
+ *
4
+ * Copies requested stats (phShift, phTestStatistic, phMean) from internal
5
+ * state to the message. Gated by minWarmUpSamples — no output until the
6
+ * baseline has accumulated enough observations. Propagates NaN downstream
7
+ * when the input was invalid.
8
+ */
9
+
10
+ import { publishNaN } from '../../core/utils/node/index.js';
11
+
12
+ const publishTo = function ( state, msg ) {
13
+ if ( state.disable ) return;
14
+ // Propagate NaN if unhealthy
15
+ if ( state.inputValidationFailed ) {
16
+ publishNaN( state, msg );
17
+ return;
18
+ }
19
+
20
+ // Require minimum samples before publishing results.
21
+ if ( state.count < state.minWarmUpSamples ) return;
22
+ // Publish whatever is asked for.
23
+ if ( state.stats.phShift ) msg[ state.stats.phShift.storeAs ] = state.shiftDetected;
24
+ if ( state.stats.phTestStatistic ) msg[ state.stats.phTestStatistic.storeAs ] = state.testStatistic;
25
+ if ( state.stats.phMean ) msg[ state.stats.phMean.storeAs ] = state.mean;
26
+ }; // publishTo()
27
+
28
+ export default publishTo;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @fileoverview Recompute handler for Page-Hinkley — intentional no-op.
3
+ *
4
+ * The PHT cumulative sum depends on the entire history of observations.
5
+ * Unlike ring-buffer nodes (es-stats, kernel), there is no stored window
6
+ * to recompute from. The no-op is the correct implementation.
7
+ */
8
+
9
+ const recompute = function () {
10
+ // Page-Hinkley is inherently sequential — cannot recompute from stored values
11
+ return true;
12
+ }; // recompute()
13
+
14
+ export default recompute;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @fileoverview Resets Page-Hinkley state to initial values.
3
+ *
4
+ * Clears all accumulated state (cumulative sum, running minimum, baseline
5
+ * mean, sample count) and detection outputs (shiftDetected, testStatistic).
6
+ * Configuration (alpha, detectDrop, tunables, stats) is preserved.
7
+ */
8
+
9
+ const reset = function ( state ) {
10
+ // Reset accumulated computation state
11
+ state.cumSum = 0;
12
+ state.minCumSum = 0;
13
+ state.mean = 0;
14
+ state.count = 0;
15
+ // Reset detection outputs — avoids publishing stale results after reset
16
+ state.shiftDetected = false;
17
+ state.testStatistic = 0;
18
+ // Clear error suppression so next error episode is logged
19
+ state.tunableErrorLogged = false;
20
+ return true;
21
+ }; // reset()
22
+
23
+ export default reset;
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @fileoverview Page-Hinkley Test update function — processes one observation.
3
+ *
4
+ * Implements the standard PHT sequential recurrence (Page 1954, Hinkley 1971):
5
+ * 1. Update baseline estimate (running mean, or exponentially smoothed when
6
+ * halfLife is configured)
7
+ * 2. Accumulate cumulative sum of deviations from baseline minus drift allowance
8
+ * 3. Track running minimum of cumulative sum
9
+ * 4. Detect shift when test statistic (cumSum - minCumSum) exceeds lambda
10
+ *
11
+ * On detection, cumSum and minCumSum reset to 0; mean and count continue
12
+ * tracking the new regime. Triggers (if any) fire on detection.
13
+ *
14
+ * Design rationale — exponentially smoothed baseline vs exponentially smoothed
15
+ * cumsum (as in river.drift.PageHinkley):
16
+ *
17
+ * The composer applies exponential smoothing to the baseline mean, not the
18
+ * cumulative sum. This is deliberate for industrial streaming:
19
+ *
20
+ * 1. Non-stationary signals: Industrial sensors drift with operating
21
+ * conditions, ambient temperature, and equipment wear. A running mean
22
+ * of 10,000 samples is effectively a constant — useless as "current
23
+ * normal." An exponentially smoothed baseline tracks the actual
24
+ * operating point.
25
+ *
26
+ * 2. Undecayed evidence accumulation: The raw cumsum grows monotonically under
27
+ * a sustained shift — the mathematical foundation of the PHT.
28
+ * Exponentially smoothing the cumsum (river's approach) decays evidence
29
+ * over time; a gradual shift can decay away before reaching threshold.
30
+ *
31
+ * 3. Orthogonal tuning: halfLife controls baseline responsiveness;
32
+ * delta/lambda control detection sensitivity — independent knobs.
33
+ * river's alpha couples evidence decay with the effective detection
34
+ * window.
35
+ *
36
+ * 4. Architectural recovery: The control plane (controller node) explicitly
37
+ * resets baselines on confirmed change — clean, debuggable, no loss of
38
+ * detection power. river needs cumsum forgetting as a workaround.
39
+ */
40
+
41
+ import { executeTriggers } from '../../core/utils/node/index.js';
42
+
43
+ const update = function ( state, msg ) {
44
+ if ( state.disable || state.pause ) return state;
45
+ let xVal = msg[ state.x ];
46
+ // Reset on each update
47
+ state.inputValidationFailed = false;
48
+ // Handle faults gracefully: ensure their isolation
49
+ if ( !Number.isFinite( xVal ) ) {
50
+ // Signals publishing NaN for all demanded `stats` in publishTo.
51
+ state.inputValidationFailed = true;
52
+ return state;
53
+ }
54
+
55
+ if ( state.detectDrop ) {
56
+ xVal = -xVal;
57
+ }
58
+
59
+ // Resolve tunable parameters for this message
60
+ try {
61
+ state.delta = state.deltaFn( msg );
62
+ state.lambda = state.lambdaFn( msg );
63
+ if ( state.tunableErrorLogged ) state.tunableErrorLogged = false;
64
+ } catch ( error ) {
65
+ if ( !state.tunableErrorLogged ) {
66
+ state.tunableErrorLogged = true;
67
+ console.error( `WinkComposer/${state.nodeType}: tunable threw: ${error.message}` );
68
+ }
69
+ }
70
+
71
+ state.count += 1;
72
+ // Choose baseline update rule.
73
+ if ( state.alpha === 0 ) { // running mean
74
+ state.mean += ( xVal - state.mean ) / state.count;
75
+ } else if ( state.count === 1 ) { // ES baseline: seed with first observation
76
+ state.mean = xVal;
77
+ } else { // ES baseline: exponential smoothing
78
+ state.mean += state.alpha * ( xVal - state.mean );
79
+ }
80
+
81
+ // Page-Hinkley cumulative sum calculation.
82
+ // Detects positive changes (increase in mean).
83
+ state.cumSum += xVal - state.mean - state.delta;
84
+
85
+ // Update running minimum.
86
+ if ( state.cumSum < state.minCumSum ) {
87
+ state.minCumSum = state.cumSum;
88
+ }
89
+
90
+ // Change detection: test statistic exceeds threshold.
91
+ state.testStatistic = state.cumSum - state.minCumSum;
92
+ state.shiftDetected = state.testStatistic > state.lambda;
93
+ if ( state.shiftDetected ) {
94
+ state.minCumSum = 0;
95
+ state.cumSum = 0;
96
+
97
+ // Trigger controls if present.
98
+ executeTriggers( state );
99
+ }
100
+
101
+ return state;
102
+ }; // update()
103
+
104
+ export default update;
105
+
@@ -0,0 +1,21 @@
1
+ // nodes/pass-if/index.js
2
+
3
+ /**
4
+ * @fileoverview Public API for passIf node
5
+ *
6
+ * Re-exports lifecycle functions, shared control utilities,
7
+ * and introspection metadata.
8
+ */
9
+
10
+ export { default as init } from './init.js';
11
+ export { default as update } from './update.js';
12
+ export { default as reset } from './reset.js';
13
+ export { default as recompute } from './recompute.js';
14
+ export { default as publishTo } from './publish-to.js';
15
+ // Direct imports for common control functions
16
+ export { default as disable } from '../../core/utils/node/disable.js';
17
+ export { default as enable } from '../../core/utils/node/enable.js';
18
+ export { default as pause } from '../../core/utils/node/pause.js';
19
+ export { default as unpause } from '../../core/utils/node/unpause.js';
20
+ // Re-export everything from introspection.js
21
+ export * from './introspect.js';
@@ -0,0 +1,37 @@
1
+ // nodes/pass-if/init.js
2
+
3
+ /**
4
+ * @fileoverview Initialization for passIf node
5
+ *
6
+ * Validates spec via standard pipeline, creates state with
7
+ * counter, predicate reference, and control flags.
8
+ */
9
+
10
+ import { validateSpec } from '../../core/utils/node/index.js';
11
+ import * as introspect from './introspect.js';
12
+
13
+ const init = function ( spec ) {
14
+ validateSpec( spec, introspect );
15
+
16
+ // Create state after validation passes
17
+ const state = Object.create( null );
18
+ // Ensure node is enabled by default
19
+ state.disable = false;
20
+ state.pause = false;
21
+
22
+ // Extract validated predicate
23
+ state.predicate = spec.predicate;
24
+
25
+ // Initialize counter
26
+ state.counter = 0;
27
+
28
+ // Store node type for debugging
29
+ state.nodeType = introspect.getNodeType();
30
+
31
+ // Log suppression: one log per error episode; reset on recovery.
32
+ state.predicateErrorLogged = false;
33
+
34
+ return state;
35
+ }; // init()
36
+
37
+ export default init;
@@ -0,0 +1,93 @@
1
+ // nodes/pass-if/introspect.js
2
+
3
+ /**
4
+ * @fileoverview Introspection metadata for passIf node
5
+ *
6
+ * Single source of truth for DSL metadata, validation schema,
7
+ * default options, and node capabilities. Used by flow transpiler
8
+ * and documentation.
9
+ */
10
+
11
+ import { validators } from '../../core/utils/validate/index.js';
12
+
13
+ /** Single source of truth for what this plugin can do */
14
+ const SUPPORTED_STATS = []; // passIf doesn't publish stats - it's a pure gate
15
+
16
+ /** Human-readable descriptions (for introspection) */
17
+ const STAT_DESCRIPTIONS = {};
18
+
19
+ /** Control methods available for triggers */
20
+ const SUPPORTED_CONTROL_METHODS = {
21
+ reset: 'Clears accumulated state and restarts computation',
22
+ enable: 'Enables node processing',
23
+ disable: 'Disables node processing',
24
+ pause: 'Pauses node processing while keeping state visible',
25
+ unpause: 'Resumes node processing after pause'
26
+ };
27
+
28
+ /** The type of this node */
29
+ const NODE_TYPE = 'Pass If';
30
+
31
+ /** Node capabilities for documentation */
32
+ const CAPABILITIES = {
33
+ description: 'Binary gate that passes or stops messages based on a predicate function',
34
+ features: [
35
+ 'Evaluates predicate with message and counter arguments',
36
+ 'Stops downstream flow when predicate returns false',
37
+ 'Maintains message counter for deterministic sampling patterns',
38
+ 'Pure predicate functions with no side effects'
39
+ ]
40
+ };
41
+
42
+ // Export functions for accessing metadata
43
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
44
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
45
+ export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
46
+ export const getNodeType = () => NODE_TYPE;
47
+ export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
48
+ export const DEFAULT_OPTIONS = {};
49
+
50
+ // DSL Metadata for transpilation
51
+ const DSL_METADATA = {
52
+ // Spec schema for validation
53
+ specSchema: {
54
+ nodeType: {
55
+ type: 'string',
56
+ required: true,
57
+ value: NODE_TYPE
58
+ },
59
+ name: {
60
+ type: 'string',
61
+ required: true,
62
+ validator: validators.identifier,
63
+ error: 'Name must be a valid identifier'
64
+ },
65
+ predicate: {
66
+ type: 'function',
67
+ required: true,
68
+ arity: 2,
69
+ error: 'Predicate must be a function with exactly two parameters (msg, counter)'
70
+ },
71
+ stats: {
72
+ type: 'object',
73
+ required: false,
74
+ propertyNames: [], // No stats for pass-through node
75
+ error: 'PassIf is a gating node and does not support stats'
76
+ }
77
+ },
78
+
79
+ // No cross-field validators needed
80
+ crossFieldValidators: [],
81
+
82
+ // How to build the spec from DSL params
83
+ // Pattern: NAME_PREDICATE_OPTIONS -> (name, predicate, options)
84
+ buildSpec: ( name, predicate, options ) => ( {
85
+ nodeType: NODE_TYPE,
86
+ name,
87
+ predicate,
88
+ ...options
89
+ } ),
90
+
91
+ };
92
+
93
+ export const getDSLMetadata = () => ( { ...DSL_METADATA } );
@@ -0,0 +1,15 @@
1
+ // nodes/pass-if/publish-to.js
2
+
3
+ /**
4
+ * @fileoverview Publish-to function for passIf node
5
+ *
6
+ * No-op — pure gate node does not add any fields to the
7
+ * message. Messages that pass the predicate continue unchanged.
8
+ */
9
+
10
+ const publishTo = function ( _state, _msg ) {
11
+ // PassIf is a pure gate - it doesn't publish any data to the message
12
+ // Messages that pass through are unchanged
13
+ }; // publishTo()
14
+
15
+ export default publishTo;
@@ -0,0 +1,15 @@
1
+ // nodes/pass-if/recompute.js
2
+
3
+ /**
4
+ * @fileoverview Recompute function for passIf node
5
+ *
6
+ * No-op — counter is a simple integer with no numerical
7
+ * stability concerns.
8
+ */
9
+
10
+ const recompute = function () {
11
+ // Nothing to recompute - counter is a simple integer
12
+ return true;
13
+ }; // recompute()
14
+
15
+ export default recompute;
@@ -0,0 +1,18 @@
1
+ // nodes/pass-if/reset.js
2
+
3
+ /**
4
+ * @fileoverview Reset function for passIf node
5
+ *
6
+ * Clears message counter and error suppression flag,
7
+ * allowing counter-based predicates to restart.
8
+ */
9
+
10
+ const reset = function ( state ) {
11
+ // Reset counter to initial state
12
+ state.counter = 0;
13
+ // Clear error suppression so next error episode is logged
14
+ state.predicateErrorLogged = false;
15
+ return true;
16
+ }; // reset()
17
+
18
+ export default reset;