@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,134 @@
1
+ import { validators, composerValidators } from '../../core/utils/validate/index.js';
2
+
3
+ /** Single source of truth for what this node can do */
4
+ const SUPPORTED_STATS = [
5
+ 'dashboard',
6
+ 'alerts',
7
+ 'database',
8
+ 'monitoring'
9
+ ];
10
+
11
+ /** QoS level constants for performance (numeric comparison in hot path) */
12
+ export const QOS_FIRE_AND_FORGET = 0;
13
+ export const QOS_BEST_EFFORT = 1;
14
+ export const QOS_RELIABLE = 2;
15
+
16
+ /** Human-readable descriptions */
17
+ const STAT_DESCRIPTIONS = {
18
+ dashboard: 'Real-time dashboard connections',
19
+ alerts: 'Alert system connections',
20
+ database: 'Database sink connections',
21
+ monitoring: 'System monitoring connections'
22
+ };
23
+
24
+ /** QoS level descriptions */
25
+ const QOS_DESCRIPTIONS = {
26
+ [ QOS_FIRE_AND_FORGET ]: 'Fire-and-forget: No queuing, drop on backpressure (fastest)',
27
+ [ QOS_BEST_EFFORT ]: 'Best-effort: Small queue, drop oldest on overflow (balanced)',
28
+ [ QOS_RELIABLE ]: 'Reliable: Large queue, backpressure monitoring (most reliable)'
29
+ };
30
+
31
+ /** The type of this node */
32
+ const NODE_TYPE = 'SSE Emitter';
33
+
34
+ /** Node capabilities */
35
+ const CAPABILITIES = {
36
+ description: 'Broadcasts entire messages via Server-Sent Events with configurable QoS levels',
37
+ features: [
38
+ 'Terminal node - broadcasts complete pipeline messages',
39
+ 'Four endpoint types: dashboard, alerts, database, monitoring',
40
+ 'Numeric QoS levels: 0 (fire-and-forget), 1 (best-effort), 2 (reliable)',
41
+ 'High-performance broadcasting with buffer reuse',
42
+ 'Production-ready connection management'
43
+ ]
44
+ };
45
+
46
+ // Export functions for accessing metadata
47
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
48
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
49
+ export const getNodeType = () => NODE_TYPE;
50
+ export const getCapabilities = () => ( { ...CAPABILITIES } );
51
+ export const getQoSDescriptions = () => ( { ...QOS_DESCRIPTIONS } );
52
+
53
+ // DSL Metadata
54
+ const DSL_METADATA = {
55
+ // Validation schema
56
+ specSchema: {
57
+ nodeType: {
58
+ type: 'string',
59
+ required: true,
60
+ value: NODE_TYPE,
61
+ validator: composerValidators.nodeType,
62
+ error: 'Invalid node type'
63
+ },
64
+ name: {
65
+ type: 'string',
66
+ required: true,
67
+ validator: validators.identifier,
68
+ error: 'Name must be a valid JavaScript identifier'
69
+ },
70
+ // Note: No 'from' field - terminal node broadcasts entire message
71
+ port: {
72
+ type: 'number',
73
+ required: false,
74
+ default: 3000, // Documentation only!
75
+ min: 1024,
76
+ max: 65535,
77
+ integer: true,
78
+ error: 'Port must be between 1024 and 65535'
79
+ },
80
+ maxConnections: {
81
+ type: 'number',
82
+ required: false,
83
+ default: 4, // Documentation only!
84
+ min: 1,
85
+ max: 10,
86
+ integer: true,
87
+ validator: validators.positiveInteger,
88
+ error: 'Max connections must be between 1 and 10'
89
+ },
90
+ stats: {
91
+ type: 'object',
92
+ required: true,
93
+ minProperties: 1,
94
+ propertyNames: SUPPORTED_STATS, // Array of allowed endpoint names
95
+ propertySchema: {
96
+ type: 'object',
97
+ required: true,
98
+ validator: composerValidators.statSpec, // Using composerValidator!
99
+ properties: {
100
+ qos: {
101
+ type: 'number',
102
+ required: false,
103
+ default: 0, // Documentation only!
104
+ integer: true,
105
+ validator: validators.oneOf( [ 0, 1, 2 ] ),
106
+ error: 'QoS must be 0 (fire-and-forget), 1 (best-effort), or 2 (reliable)'
107
+ }
108
+ }
109
+ },
110
+ error: 'Stats must define at least one endpoint with valid configuration'
111
+ }
112
+ },
113
+
114
+ // 3. Cross-field validators - none needed for SSE Emitter
115
+ crossFieldValidators: [],
116
+
117
+ // 4. Build spec from DSL
118
+ buildSpec: function ( port = 3000, maxConnections = 4 ) {
119
+ return {
120
+ nodeType: NODE_TYPE,
121
+ name: '{{AUTO_NAME}}',
122
+ port,
123
+ maxConnections,
124
+ stats: {
125
+ dashboard: { storeAs: 'dashConnected', qos: 0 }, // Default fire-and-forget
126
+ database: { storeAs: 'dbConnected', qos: 2 } // Default reliable
127
+ }
128
+ };
129
+ },
130
+
131
+ acceptsSpecObject: true
132
+ };
133
+
134
+ export const getDSLMetadata = () => ({ ...DSL_METADATA });
@@ -0,0 +1,6 @@
1
+ const publishTo = function ( _state, _msg ) {
2
+ // Terminal node - nothing to publish for downstream
3
+ // Connection counts are already added in update() before broadcasting
4
+ }; // publishTo()
5
+
6
+ export default publishTo;
@@ -0,0 +1,16 @@
1
+ const recompute = function ( state ) {
2
+ // Recompute total connection count from all endpoints
3
+ let totalConnections = 0;
4
+
5
+ for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
6
+ const endpointName = state.endpointNames[i];
7
+ totalConnections += state.connections[endpointName].length;
8
+ }
9
+
10
+ state.totalConnections = totalConnections;
11
+
12
+ console.log( `composer/sseEmitter: Recomputed ${state.totalConnections} active connections across ${state.endpointNames.length} endpoints` );
13
+ return true;
14
+ };
15
+
16
+ export default recompute;
@@ -0,0 +1,19 @@
1
+ const reset = function ( state ) {
2
+ // Reset statistics only (keep connections active)
3
+ state.totalSent = 0;
4
+ state.totalErrors = 0;
5
+
6
+ // Reset per-connection message counts
7
+ for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
8
+ const endpointName = state.endpointNames[ i ];
9
+ const connections = state.connections[ endpointName ];
10
+
11
+ for ( let j = 0; j < connections.length; j += 1 ) {
12
+ connections[ j ].messagesSent = 0;
13
+ }
14
+ }
15
+
16
+ return true;
17
+ };
18
+
19
+ export default reset;
@@ -0,0 +1,69 @@
1
+ import { buildMessage } from './utils/build-message.js';
2
+ import { QOS_HANDLERS } from './utils/qos-handler.js';
3
+
4
+ const cleanupDeadConnections = function ( state, connections, deadConnections ) {
5
+ // Remove dead connections in reverse order to maintain indices
6
+ for ( let i = deadConnections.length - 1; i >= 0; i -= 1 ) {
7
+ connections.splice( deadConnections[ i ], 1 );
8
+ state.totalConnections -= 1;
9
+ }
10
+
11
+ // Return array to pool for reuse
12
+ state.deadConnectionsPool.push( deadConnections );
13
+ }; // cleanupDeadConnections()
14
+
15
+ const broadcastToEndpoint = function ( state, connections, message, endpointName ) {
16
+ // Get reusable dead connections array
17
+ const deadConnections = state.deadConnectionsPool.pop() || [];
18
+ deadConnections.length = 0;
19
+
20
+ // Fast iteration with minimal nesting
21
+ for ( let i = 0; i < connections.length; i += 1 ) {
22
+ const connection = connections[ i ];
23
+
24
+ if ( !connection.response.writable ) {
25
+ deadConnections.push( i );
26
+ continue; // eslint-disable-line no-continue
27
+ }
28
+
29
+ try {
30
+ // O(1) QoS handler dispatch - no switch statement nesting
31
+ const qosHandler = QOS_HANDLERS[ connection.qos ] || QOS_HANDLERS[ 0 ];
32
+ qosHandler( connection, message, state, endpointName );
33
+ } catch {
34
+ deadConnections.push( i );
35
+ state.totalErrors += 1;
36
+ }
37
+ }
38
+
39
+ cleanupDeadConnections( state, connections, deadConnections );
40
+ }; // broadcastToEndpoint()
41
+
42
+ // High-performance broadcast with zero allocations
43
+ const update = function ( state, msg ) {
44
+ // Fast path: no connections
45
+ if ( state.totalConnections === 0 ) return;
46
+
47
+ // Add connection counts directly to the message
48
+ for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
49
+ const endpointName = state.endpointNames[ i ];
50
+ const storeAs = state.stats[ endpointName ].storeAs;
51
+ msg[ storeAs ] = state.connections[ endpointName ].length;
52
+ }
53
+
54
+ // Serialize entire message (only unavoidable allocation)
55
+ const jsonString = JSON.stringify( msg );
56
+ const messageToSend = buildMessage( state, jsonString );
57
+
58
+ // Broadcast to all configured endpoints
59
+ for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
60
+ const endpointName = state.endpointNames[ i ];
61
+ const connections = state.connections[ endpointName ];
62
+
63
+ if ( connections.length > 0 ) {
64
+ broadcastToEndpoint( state, connections, messageToSend, endpointName );
65
+ }
66
+ }
67
+ }; // update()
68
+
69
+ export default update;
@@ -0,0 +1,36 @@
1
+ // utils/broadcast-heartbeat.js
2
+
3
+ const HEARTBEAT_MESSAGE = Buffer.from(':heartbeat\n\n');
4
+
5
+ export const broadcastHeartbeat = function (state) {
6
+ // SSE comment format (`:` prefix) keeps connection alive without triggering client events
7
+
8
+ for (let i = 0; i < state.endpointNames.length; i += 1) {
9
+ const endpointName = state.endpointNames[i];
10
+ const connections = state.connections[endpointName];
11
+
12
+ // Track dead connections
13
+ const deadIndices = [];
14
+
15
+ for (let j = 0; j < connections.length; j += 1) {
16
+ const connection = connections[j];
17
+
18
+ try {
19
+ if (connection.response.writable) {
20
+ connection.response.write(HEARTBEAT_MESSAGE);
21
+ } else {
22
+ deadIndices.push(j);
23
+ }
24
+ } catch ( error ) {
25
+ console.error(`composer/emitter: Write error on ${endpointName}:`, error.message);
26
+ deadIndices.push(j);
27
+ }
28
+ }
29
+
30
+ // Clean up dead connections
31
+ for (let k = deadIndices.length - 1; k >= 0; k -= 1) {
32
+ connections.splice(deadIndices[k], 1);
33
+ state.totalConnections -= 1;
34
+ }
35
+ }
36
+ };
@@ -0,0 +1,31 @@
1
+ // utils/build-message.js
2
+
3
+ const DATA_PREFIX = Buffer.from( 'data: ' );
4
+ const MESSAGE_SUFFIX = Buffer.from( '\n\n' );
5
+
6
+ const buildMessage = function ( state, jsonString ) {
7
+ const { messageBuffer, dataPrefix, messageSuffix } = state;
8
+ const jsonBuffer = Buffer.from( jsonString, 'utf8' );
9
+ const totalSize = dataPrefix.length + jsonBuffer.length + messageSuffix.length;
10
+
11
+ // Use reusable buffer for small messages
12
+ if ( totalSize <= messageBuffer.length ) {
13
+ let offset = 0;
14
+
15
+ dataPrefix.copy( messageBuffer, offset );
16
+ offset += dataPrefix.length;
17
+
18
+ jsonBuffer.copy( messageBuffer, offset );
19
+ offset += jsonBuffer.length;
20
+
21
+ messageSuffix.copy( messageBuffer, offset );
22
+ offset += messageSuffix.length;
23
+
24
+ return messageBuffer.subarray( 0, offset );
25
+ }
26
+
27
+ // Fallback for large messages
28
+ return Buffer.concat( [ dataPrefix, jsonBuffer, messageSuffix ] );
29
+ }; // buildSSEMessage()
30
+
31
+ export { buildMessage, DATA_PREFIX, MESSAGE_SUFFIX };
@@ -0,0 +1,45 @@
1
+ // utils/connection-manager.js
2
+
3
+ const createSSEHeaders = function () {
4
+ return {
5
+ 'Content-Type': 'text/event-stream',
6
+ 'Cache-Control': 'no-cache',
7
+ 'Connection': 'keep-alive',
8
+ // eslint-disable-next-line no-warning-comments
9
+ // TODO: Remove next line in production - dashboard served from same port
10
+ 'Access-Control-Allow-Origin': '*'
11
+ };
12
+ }; // createSSEHeaders()
13
+
14
+ const createConnection = function ( state, res, endpointName ) {
15
+ const connection = {
16
+ response: res,
17
+ endpoint: endpointName,
18
+ qos: state.endpointQoS[ endpointName ],
19
+ createdAt: Date.now(),
20
+ messagesSent: 0
21
+ };
22
+
23
+ state.connections[ endpointName ].push( connection );
24
+ state.totalConnections += 1;
25
+
26
+ return connection;
27
+ }; // createConnection()
28
+
29
+ const removeConnection = function ( state, connection, endpointName ) {
30
+ const connections = state.connections[ endpointName ];
31
+ const index = connections.indexOf( connection );
32
+ if ( index !== -1 ) {
33
+ connections.splice( index, 1 );
34
+ state.totalConnections -= 1;
35
+ console.log( `SSE ${endpointName} disconnected (${state.totalConnections}/${state.maxConnections})` );
36
+ }
37
+ }; // removeConnection()
38
+
39
+ const setupConnectionHandlers = function ( state, req, connection, endpointName ) {
40
+ const cleanup = () => removeConnection( state, connection, endpointName );
41
+ req.on( 'close', cleanup );
42
+ req.on( 'error', cleanup );
43
+ }; // setupConnectionHandlers()
44
+
45
+ export { createSSEHeaders, createConnection, removeConnection, setupConnectionHandlers };
@@ -0,0 +1,20 @@
1
+ // utils/endpoint-initializer.js
2
+
3
+ const initializeEndpoints = function ( state ) {
4
+ state.endpointNames = Object.keys( state.stats );
5
+ state.connections = Object.create( null );
6
+ state.endpointQoS = Object.create( null );
7
+
8
+ // Create connection arrays and store QoS levels
9
+ for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
10
+ const endpointName = state.endpointNames[ i ];
11
+ state.connections[ endpointName ] = [];
12
+
13
+ // Apply QoS defaults: dashboard=0, database=2, others=1
14
+ const defaultQoS = endpointName === 'dashboard' ? 0 :
15
+ endpointName === 'database' ? 2 : 1;
16
+ state.endpointQoS[ endpointName ] = state.stats[ endpointName ].qos || defaultQoS;
17
+ }
18
+ }; // initializeEndpoints()
19
+
20
+ export { initializeEndpoints };
@@ -0,0 +1,38 @@
1
+ // utils/health-monitor.js
2
+
3
+ const buildHealthResponse = function ( state ) {
4
+ const endpointStats = Object.create( null );
5
+ for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
6
+ const endpointName = state.endpointNames[ i ];
7
+ endpointStats[ endpointName ] = state.connections[ endpointName ].length;
8
+ }
9
+
10
+ return {
11
+ nodeType: state.nodeType,
12
+ connections: {
13
+ total: state.totalConnections,
14
+ byEndpoint: endpointStats
15
+ },
16
+ stats: {
17
+ sent: state.totalSent,
18
+ errors: state.totalErrors
19
+ },
20
+ endpoints: state.endpointNames,
21
+ timestamp: Date.now()
22
+ };
23
+ }; // buildHealthResponse()
24
+
25
+ const handleHealthCheck = function ( state, res ) {
26
+ const healthData = buildHealthResponse( state );
27
+ res.writeHead( 200, {
28
+ 'Content-Type': 'application/json',
29
+ // eslint-disable-next-line no-warning-comments
30
+ // TODO: Remove next 3 lines in production - dashboard served from same port
31
+ 'Access-Control-Allow-Origin': '*',
32
+ 'Access-Control-Allow-Methods': 'GET',
33
+ 'Access-Control-Allow-Headers': 'Content-Type'
34
+ } );
35
+ res.end( JSON.stringify( healthData ) );
36
+ }; // handleHealthCheck()
37
+
38
+ export { buildHealthResponse, handleHealthCheck };
@@ -0,0 +1,41 @@
1
+ // utils/qos-handler.js
2
+
3
+ import { QOS_FIRE_AND_FORGET, QOS_BEST_EFFORT, QOS_RELIABLE } from '../introspect.js';
4
+
5
+ const fireAndForgetSend = function ( connection, message, state ) {
6
+ connection.response.write( message );
7
+ connection.messagesSent += 1;
8
+ state.totalSent += 1;
9
+ }; // fireAndForgetSend()
10
+
11
+ const bestEffortSend = function ( connection, message, state, endpointName ) {
12
+ const success = connection.response.write( message );
13
+ if ( success ) {
14
+ connection.messagesSent += 1;
15
+ state.totalSent += 1;
16
+ } else {
17
+ console.warn( `${endpointName} client backpressure - best effort` );
18
+ state.totalSent += 1; // Count as sent for metrics
19
+ }
20
+ }; // bestEffortSend()
21
+
22
+ const reliableSend = function ( connection, message, state, endpointName ) {
23
+ const success = connection.response.write( message );
24
+ if ( success ) {
25
+ connection.messagesSent += 1;
26
+ state.totalSent += 1;
27
+ } else {
28
+ console.warn( `${endpointName} client backpressure - reliable mode` );
29
+ // TO DO: Implement proper queuing for reliable delivery
30
+ state.totalSent += 1; // Count as sent for now
31
+ }
32
+ }; // reliableSend()
33
+
34
+ // O(1) QoS handler dispatch table
35
+ const QOS_HANDLERS = {
36
+ [ QOS_FIRE_AND_FORGET ]: fireAndForgetSend,
37
+ [ QOS_BEST_EFFORT ]: bestEffortSend,
38
+ [ QOS_RELIABLE ]: reliableSend
39
+ };
40
+
41
+ export { QOS_HANDLERS };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Validate that all required fields exist in message and contain categorical values
3
+ *
4
+ * @param {Object} msg - Message to validate
5
+ * @param {string[]} fieldNames - Array of required field names
6
+ * @param {number} fieldCount - Number of fields to validate
7
+ * @returns {boolean} True if all fields are present and categorical
8
+ */
9
+ const validateCategoricalFields = function ( msg, fieldNames, fieldCount ) {
10
+ for ( let i = 0; i < fieldCount; i += 1 ) {
11
+ const field = fieldNames[ i ];
12
+ const value = msg[ field ];
13
+
14
+ // Missing field
15
+ if ( value === undefined ) {
16
+ return false;
17
+ }
18
+
19
+ // Check if categorical (string, number, or boolean)
20
+ const valueType = typeof value;
21
+ const isCategorical = (
22
+ valueType === 'string' ||
23
+ valueType === 'number' ||
24
+ valueType === 'boolean'
25
+ );
26
+
27
+ if ( !isCategorical ) {
28
+ return false;
29
+ }
30
+ }
31
+
32
+ return true;
33
+ }; // validateCategoricalFields()
34
+
35
+ export { validateCategoricalFields };
@@ -0,0 +1,12 @@
1
+ export { default as init } from './init.js';
2
+ export { default as update } from './update.js';
3
+ export { default as reset } from './reset.js';
4
+ export { default as recompute } from './recompute.js';
5
+ export { default as publishTo } from './publish-to.js';
6
+ // Direct imports for common control functions
7
+ export { default as disable } from '../../core/utils/node/disable.js';
8
+ export { default as enable } from '../../core/utils/node/enable.js';
9
+ export { default as pause } from '../../core/utils/node/pause.js';
10
+ export { default as unpause } from '../../core/utils/node/unpause.js';
11
+ // Re-export everything from introspection
12
+ export * from './introspect.js';
@@ -0,0 +1,56 @@
1
+ import { validateSpec } from '../../core/utils/node/index.js';
2
+ import * as introspect from './introspect.js';
3
+
4
+ const init = function ( spec ) {
5
+ validateSpec( spec, introspect );
6
+
7
+ const state = Object.create( null );
8
+ // Standard input parameter health flag during update: false means healthy
9
+ state.inputValidationFailed = false;
10
+ // Ensure node is enabled by default
11
+ state.disable = false;
12
+ state.pause = false;
13
+
14
+ // Extract field names and count
15
+ state.fieldNames = spec.from.x;
16
+ state.fieldCount = state.fieldNames.length;
17
+
18
+ // Guards (apply defaults from introspect)
19
+ const defaults = introspect.DEFAULT_OPTIONS;
20
+ state.debounce = spec.debounce ?? defaults.debounce;
21
+
22
+ // Change detection mode (store as boolean for performance)
23
+ const changeMode = spec.changeMode ?? defaults.changeMode;
24
+ state.changeMode = ( changeMode === 'all' ); // true='all', false='any'
25
+
26
+ // Timestamp handling
27
+ state.useTimestampField = spec.timestampField !== undefined;
28
+ state.timestampField = spec.timestampField || null;
29
+
30
+ // Stats configuration
31
+ state.stats = spec.stats;
32
+
33
+ // Pre-allocate state tracking (NO allocations in hot path)
34
+ state.prevValues = Object.create( null );
35
+ for ( let i = 0; i < state.fieldCount; i += 1 ) {
36
+ const field = state.fieldNames[ i ];
37
+ state.prevValues[ field ] = null;
38
+ }
39
+
40
+ // Debounce and timing state
41
+ state.debounceCount = 0;
42
+ state.stateStartTime = null;
43
+ state.samplesInState = 0;
44
+
45
+ // stats to be published
46
+ state.dwellTime = null;
47
+ state.dwellSamples = null;
48
+
49
+ // Node metadata
50
+ state.nodeType = introspect.getNodeType();
51
+ state.resolvedTriggers = [];
52
+
53
+ return state;
54
+ }; // init()
55
+
56
+ export default init;