@winkjs/composer 0.0.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +106 -80
  3. package/package.json +56 -28
  4. package/src/composer.js +75 -0
  5. package/src/core/batch/aoo-encoder.js +148 -0
  6. package/src/core/batch/index.js +12 -0
  7. package/src/core/batch/sliding-window.js +91 -0
  8. package/src/core/codec/index.js +137 -0
  9. package/src/core/emitter-manager/mqtt/constants.js +102 -0
  10. package/src/core/emitter-manager/mqtt/emitter.js +780 -0
  11. package/src/core/emitter-manager/mqtt/index.js +190 -0
  12. package/src/core/emitter-manager/mqtt/mqtt-store.js +538 -0
  13. package/src/core/emitter-manager/terminal/assert-columns.js +98 -0
  14. package/src/core/emitter-manager/terminal/formatters.js +160 -0
  15. package/src/core/emitter-manager/terminal/index.js +341 -0
  16. package/src/core/env-vars.js +245 -0
  17. package/src/core/mqtt-protocol.js +47 -0
  18. package/src/core/partition-manager/index.js +7 -0
  19. package/src/core/partition-manager/init.js +44 -0
  20. package/src/core/partition-manager/introspect.js +15 -0
  21. package/src/core/partition-manager/publish-to.js +6 -0
  22. package/src/core/partition-manager/recompute.js +5 -0
  23. package/src/core/partition-manager/reset.js +5 -0
  24. package/src/core/partition-manager/update.js +264 -0
  25. package/src/core/partition-manager/validate-flow.js +157 -0
  26. package/src/core/semantics/digest.js +128 -0
  27. package/src/core/semantics/index.js +83 -0
  28. package/src/core/semantics/loader.js +571 -0
  29. package/src/core/semantics/schemas/asset-class-schema.js +218 -0
  30. package/src/core/semantics/schemas/column-schema.js +651 -0
  31. package/src/core/semantics/schemas/enum-schema.js +153 -0
  32. package/src/core/semantics/schemas/index.js +51 -0
  33. package/src/core/semantics/warnings.js +141 -0
  34. package/src/core/shutdown-manager/index.js +289 -0
  35. package/src/core/source-manager/csv/index.js +171 -0
  36. package/src/core/source-manager/csv/start.js +456 -0
  37. package/src/core/source-manager/mqtt/client.js +406 -0
  38. package/src/core/source-manager/mqtt/constants.js +147 -0
  39. package/src/core/source-manager/mqtt/dedup.js +244 -0
  40. package/src/core/source-manager/mqtt/index.js +260 -0
  41. package/src/core/source-manager/mqtt/status.js +546 -0
  42. package/src/core/source-manager/test-harness/comparator.js +226 -0
  43. package/src/core/source-manager/test-harness/field-generator.js +85 -0
  44. package/src/core/source-manager/test-harness/fuzz.js +87 -0
  45. package/src/core/source-manager/test-harness/index.js +115 -0
  46. package/src/core/source-manager/test-harness/prng.js +57 -0
  47. package/src/core/source-manager/test-harness/start.js +232 -0
  48. package/src/core/source-manager/test-harness/validate.js +213 -0
  49. package/src/core/storage-manager/questdb/assert-columns.js +120 -0
  50. package/src/core/storage-manager/questdb/ensure-tables.js +187 -0
  51. package/src/core/storage-manager/questdb/index.js +1251 -0
  52. package/src/core/storage-manager/questdb/persist-plan.js +488 -0
  53. package/src/core/storage-manager/questdb/writers.js +142 -0
  54. package/src/core/test-utils/sealed-record.js +80 -0
  55. package/src/core/test-utils/soak-signature.js +149 -0
  56. package/src/core/test-utils/tcp-proxy.js +106 -0
  57. package/src/core/tunable/helpers.js +254 -0
  58. package/src/core/tunable/index.js +87 -0
  59. package/src/core/utils/console-formatter/index.js +207 -0
  60. package/src/core/utils/create-smart-store-as/index.js +98 -0
  61. package/src/core/utils/create-smart-store-as/sanitize-field.js +46 -0
  62. package/src/core/utils/create-smart-store-as/smart-truncate.js +93 -0
  63. package/src/core/utils/flow/index.js +5 -0
  64. package/src/core/utils/flow/make-collision-checker.js +23 -0
  65. package/src/core/utils/flow/to-kebab.js +20 -0
  66. package/src/core/utils/half-life/index.js +111 -0
  67. package/src/core/utils/node/disable.js +11 -0
  68. package/src/core/utils/node/enable.js +11 -0
  69. package/src/core/utils/node/execute-triggers.js +40 -0
  70. package/src/core/utils/node/index.js +10 -0
  71. package/src/core/utils/node/pause.js +11 -0
  72. package/src/core/utils/node/populate-predicate-inputs.js +14 -0
  73. package/src/core/utils/node/publish-nan.js +19 -0
  74. package/src/core/utils/node/reset-predicate-inputs.js +11 -0
  75. package/src/core/utils/node/unpause.js +11 -0
  76. package/src/core/utils/node/validate-spec.js +22 -0
  77. package/src/core/utils/options/resolve-field-keyed.js +115 -0
  78. package/src/core/utils/quantize/index.js +75 -0
  79. package/src/core/utils/stats/formulas.js +67 -0
  80. package/src/core/utils/stats/index.js +3 -0
  81. package/src/core/utils/validate/composer-validators.js +141 -0
  82. package/src/core/utils/validate/helpers.js +206 -0
  83. package/src/core/utils/validate/index.js +12 -0
  84. package/src/core/utils/validate/type-validators.js +538 -0
  85. package/src/core/utils/validate/validate.js +107 -0
  86. package/src/core/utils/validate/validators.js +177 -0
  87. package/src/core/wiring/assert-handle.js +57 -0
  88. package/src/core/wiring/assert-module.js +63 -0
  89. package/src/core/wiring/index.js +5 -0
  90. package/src/core/wiring/node-type-to-module.js +17 -0
  91. package/src/core/wiring/wire-emitters.js +256 -0
  92. package/src/core/wiring/wire-linear-graph.js +25 -0
  93. package/src/core/wiring/wire-node.js +157 -0
  94. package/src/core/wiring/wire-semantics.js +173 -0
  95. package/src/core/wiring/wire-storages.js +344 -0
  96. package/src/flow/check-output-collisions.js +93 -0
  97. package/src/flow/consts.js +9 -0
  98. package/src/flow/deep-clone-spec.js +64 -0
  99. package/src/flow/driver.js +171 -0
  100. package/src/flow/expand-single-input-array.js +76 -0
  101. package/src/flow/expand-template-spec.js +93 -0
  102. package/src/flow/flow-api-schemas.js +300 -0
  103. package/src/flow/flow.js +658 -0
  104. package/src/flow/for-each.js +225 -0
  105. package/src/flow/get-signature-pattern.js +31 -0
  106. package/src/flow/get-target-array.js +46 -0
  107. package/src/flow/inspect.js +67 -0
  108. package/src/flow/load-node-module.js +81 -0
  109. package/src/flow/make-node-method.js +112 -0
  110. package/src/flow/resolve-pick-by-field.js +77 -0
  111. package/src/flow/resolve-tunables.js +76 -0
  112. package/src/flow/run.js +392 -0
  113. package/src/flow/serialize.js +161 -0
  114. package/src/flow/signatures-schema.js +222 -0
  115. package/src/flow/spec-builder.js +65 -0
  116. package/src/flow/validate-triggers.js +250 -0
  117. package/src/flow/validate.js +261 -0
  118. package/src/nodes/accumulate/index.js +21 -0
  119. package/src/nodes/accumulate/init.js +48 -0
  120. package/src/nodes/accumulate/introspect.js +123 -0
  121. package/src/nodes/accumulate/publish-to.js +34 -0
  122. package/src/nodes/accumulate/recompute.js +27 -0
  123. package/src/nodes/accumulate/reset.js +25 -0
  124. package/src/nodes/accumulate/update.js +42 -0
  125. package/src/nodes/appraise/calibrate.js +64 -0
  126. package/src/nodes/appraise/decision.js +66 -0
  127. package/src/nodes/appraise/deviation.js +140 -0
  128. package/src/nodes/appraise/index.js +23 -0
  129. package/src/nodes/appraise/init.js +165 -0
  130. package/src/nodes/appraise/integrate.js +45 -0
  131. package/src/nodes/appraise/introspect.js +352 -0
  132. package/src/nodes/appraise/publish-to.js +93 -0
  133. package/src/nodes/appraise/receptor.js +69 -0
  134. package/src/nodes/appraise/recompute.js +79 -0
  135. package/src/nodes/appraise/reset.js +53 -0
  136. package/src/nodes/appraise/update.js +130 -0
  137. package/src/nodes/archive/csv/index.js +6 -0
  138. package/src/nodes/archive/csv/init.js +36 -0
  139. package/src/nodes/archive/csv/load.js +70 -0
  140. package/src/nodes/archive/csv/reset.js +14 -0
  141. package/src/nodes/archive/csv/simple-parser.js +216 -0
  142. package/src/nodes/archive/csv/test.js +173 -0
  143. package/src/nodes/archive/csv/update.js +63 -0
  144. package/src/nodes/butterworth-filter/index.js +18 -0
  145. package/src/nodes/butterworth-filter/init.js +184 -0
  146. package/src/nodes/butterworth-filter/introspect.js +228 -0
  147. package/src/nodes/butterworth-filter/publish-to.js +21 -0
  148. package/src/nodes/butterworth-filter/recompute.js +13 -0
  149. package/src/nodes/butterworth-filter/reset.js +30 -0
  150. package/src/nodes/butterworth-filter/update.js +38 -0
  151. package/src/nodes/categorize/index.js +19 -0
  152. package/src/nodes/categorize/init.js +58 -0
  153. package/src/nodes/categorize/introspect.js +177 -0
  154. package/src/nodes/categorize/publish-to.js +29 -0
  155. package/src/nodes/categorize/recompute.js +14 -0
  156. package/src/nodes/categorize/reset.js +16 -0
  157. package/src/nodes/categorize/update.js +53 -0
  158. package/src/nodes/controller/index.js +9 -0
  159. package/src/nodes/controller/init.js +55 -0
  160. package/src/nodes/controller/introspect.js +91 -0
  161. package/src/nodes/controller/publish-to.js +8 -0
  162. package/src/nodes/controller/recompute.js +9 -0
  163. package/src/nodes/controller/reset.js +17 -0
  164. package/src/nodes/controller/update.js +63 -0
  165. package/src/nodes/diff/index.js +19 -0
  166. package/src/nodes/diff/init.js +37 -0
  167. package/src/nodes/diff/introspect.js +132 -0
  168. package/src/nodes/diff/publish-to.js +21 -0
  169. package/src/nodes/diff/recompute.js +12 -0
  170. package/src/nodes/diff/reset.js +12 -0
  171. package/src/nodes/diff/update.js +37 -0
  172. package/src/nodes/digest-moments/formulas.js +12 -0
  173. package/src/nodes/digest-moments/index.js +14 -0
  174. package/src/nodes/digest-moments/init.js +67 -0
  175. package/src/nodes/digest-moments/introspect.js +154 -0
  176. package/src/nodes/digest-moments/publish-to.js +34 -0
  177. package/src/nodes/digest-moments/recompute.js +14 -0
  178. package/src/nodes/digest-moments/reset.js +14 -0
  179. package/src/nodes/digest-moments/update.js +120 -0
  180. package/src/nodes/dwell-time-tracker/index.js +14 -0
  181. package/src/nodes/dwell-time-tracker/init.js +59 -0
  182. package/src/nodes/dwell-time-tracker/introspect.js +137 -0
  183. package/src/nodes/dwell-time-tracker/publish-to.js +22 -0
  184. package/src/nodes/dwell-time-tracker/recompute.js +8 -0
  185. package/src/nodes/dwell-time-tracker/reset.js +23 -0
  186. package/src/nodes/dwell-time-tracker/update.js +103 -0
  187. package/src/nodes/emit-if/helpers.js +94 -0
  188. package/src/nodes/emit-if/index.js +16 -0
  189. package/src/nodes/emit-if/init.js +67 -0
  190. package/src/nodes/emit-if/introspect.js +102 -0
  191. package/src/nodes/emit-if/publish-to.js +13 -0
  192. package/src/nodes/emit-if/recompute.js +12 -0
  193. package/src/nodes/emit-if/reset.js +27 -0
  194. package/src/nodes/emit-if/update.js +93 -0
  195. package/src/nodes/es-correlation/index.js +19 -0
  196. package/src/nodes/es-correlation/init.js +73 -0
  197. package/src/nodes/es-correlation/introspect.js +176 -0
  198. package/src/nodes/es-correlation/publish-to.js +32 -0
  199. package/src/nodes/es-correlation/recompute.js +56 -0
  200. package/src/nodes/es-correlation/reset.js +27 -0
  201. package/src/nodes/es-correlation/update.js +110 -0
  202. package/src/nodes/es-mean/index.js +20 -0
  203. package/src/nodes/es-mean/init.js +58 -0
  204. package/src/nodes/es-mean/introspect.js +129 -0
  205. package/src/nodes/es-mean/publish-to.js +19 -0
  206. package/src/nodes/es-mean/recompute.js +16 -0
  207. package/src/nodes/es-mean/reset.js +24 -0
  208. package/src/nodes/es-mean/update.js +69 -0
  209. package/src/nodes/es-pairwise-correlation/index.js +19 -0
  210. package/src/nodes/es-pairwise-correlation/init.js +98 -0
  211. package/src/nodes/es-pairwise-correlation/introspect.js +187 -0
  212. package/src/nodes/es-pairwise-correlation/publish-to.js +31 -0
  213. package/src/nodes/es-pairwise-correlation/recompute.js +69 -0
  214. package/src/nodes/es-pairwise-correlation/reset.js +29 -0
  215. package/src/nodes/es-pairwise-correlation/update.js +89 -0
  216. package/src/nodes/es-stats/index.js +21 -0
  217. package/src/nodes/es-stats/init.js +105 -0
  218. package/src/nodes/es-stats/introspect.js +157 -0
  219. package/src/nodes/es-stats/publish-to.js +42 -0
  220. package/src/nodes/es-stats/recompute.js +74 -0
  221. package/src/nodes/es-stats/reset.js +49 -0
  222. package/src/nodes/es-stats/update-envelope.js +44 -0
  223. package/src/nodes/es-stats/update-welford.js +64 -0
  224. package/src/nodes/es-stats/update.js +59 -0
  225. package/src/nodes/index.js +83 -0
  226. package/src/nodes/invert-flag/index.js +20 -0
  227. package/src/nodes/invert-flag/init.js +36 -0
  228. package/src/nodes/invert-flag/introspect.js +115 -0
  229. package/src/nodes/invert-flag/publish-to.js +23 -0
  230. package/src/nodes/invert-flag/recompute.js +12 -0
  231. package/src/nodes/invert-flag/reset.js +12 -0
  232. package/src/nodes/invert-flag/update.js +32 -0
  233. package/src/nodes/kalman1d/index.js +20 -0
  234. package/src/nodes/kalman1d/init.js +103 -0
  235. package/src/nodes/kalman1d/introspect.js +250 -0
  236. package/src/nodes/kalman1d/publish-to.js +34 -0
  237. package/src/nodes/kalman1d/recompute.js +23 -0
  238. package/src/nodes/kalman1d/reset.js +29 -0
  239. package/src/nodes/kalman1d/update.js +144 -0
  240. package/src/nodes/kernel/index.js +18 -0
  241. package/src/nodes/kernel/init.js +66 -0
  242. package/src/nodes/kernel/introspect.js +163 -0
  243. package/src/nodes/kernel/presets.js +74 -0
  244. package/src/nodes/kernel/publish-to.js +25 -0
  245. package/src/nodes/kernel/recompute.js +14 -0
  246. package/src/nodes/kernel/reset.js +20 -0
  247. package/src/nodes/kernel/update.js +69 -0
  248. package/src/nodes/lag/index.js +21 -0
  249. package/src/nodes/lag/init.js +87 -0
  250. package/src/nodes/lag/introspect.js +202 -0
  251. package/src/nodes/lag/publish-to.js +64 -0
  252. package/src/nodes/lag/recompute.js +33 -0
  253. package/src/nodes/lag/reset.js +49 -0
  254. package/src/nodes/lag/update.js +133 -0
  255. package/src/nodes/median3/index.js +19 -0
  256. package/src/nodes/median3/init.js +40 -0
  257. package/src/nodes/median3/introspect.js +116 -0
  258. package/src/nodes/median3/publish-to.js +21 -0
  259. package/src/nodes/median3/recompute.js +12 -0
  260. package/src/nodes/median3/reset.js +15 -0
  261. package/src/nodes/median3/update.js +58 -0
  262. package/src/nodes/moments-digest/copy-from.js +12 -0
  263. package/src/nodes/moments-digest/flush.js +17 -0
  264. package/src/nodes/moments-digest/index.js +132 -0
  265. package/src/nodes/moments-digest/init.js +84 -0
  266. package/src/nodes/moments-digest/introspect.js +122 -0
  267. package/src/nodes/moments-digest/prelude.js +28 -0
  268. package/src/nodes/moments-digest/publish-to.js +31 -0
  269. package/src/nodes/moments-digest/recompute.js +9 -0
  270. package/src/nodes/moments-digest/reset.js +20 -0
  271. package/src/nodes/moments-digest/update.js +182 -0
  272. package/src/nodes/node-names.js +67 -0
  273. package/src/nodes/page-hinkley/index.js +20 -0
  274. package/src/nodes/page-hinkley/init.js +66 -0
  275. package/src/nodes/page-hinkley/introspect.js +193 -0
  276. package/src/nodes/page-hinkley/publish-to.js +28 -0
  277. package/src/nodes/page-hinkley/recompute.js +14 -0
  278. package/src/nodes/page-hinkley/reset.js +23 -0
  279. package/src/nodes/page-hinkley/update.js +105 -0
  280. package/src/nodes/pass-if/index.js +21 -0
  281. package/src/nodes/pass-if/init.js +37 -0
  282. package/src/nodes/pass-if/introspect.js +93 -0
  283. package/src/nodes/pass-if/publish-to.js +15 -0
  284. package/src/nodes/pass-if/recompute.js +15 -0
  285. package/src/nodes/pass-if/reset.js +18 -0
  286. package/src/nodes/pass-if/update.js +37 -0
  287. package/src/nodes/persist-if/helpers.js +111 -0
  288. package/src/nodes/persist-if/index.js +9 -0
  289. package/src/nodes/persist-if/init.js +98 -0
  290. package/src/nodes/persist-if/introspect.js +106 -0
  291. package/src/nodes/persist-if/publish-to.js +21 -0
  292. package/src/nodes/persist-if/recompute.js +20 -0
  293. package/src/nodes/persist-if/reset.js +35 -0
  294. package/src/nodes/persist-if/update.js +112 -0
  295. package/src/nodes/persistence-check/index.js +14 -0
  296. package/src/nodes/persistence-check/init.js +38 -0
  297. package/src/nodes/persistence-check/introspect.js +144 -0
  298. package/src/nodes/persistence-check/publish-to.js +11 -0
  299. package/src/nodes/persistence-check/recompute.js +7 -0
  300. package/src/nodes/persistence-check/reset.js +12 -0
  301. package/src/nodes/persistence-check/update.js +57 -0
  302. package/src/nodes/process-index/index.js +15 -0
  303. package/src/nodes/process-index/init.js +48 -0
  304. package/src/nodes/process-index/introspect.js +182 -0
  305. package/src/nodes/process-index/publish-to.js +29 -0
  306. package/src/nodes/process-index/recompute.js +8 -0
  307. package/src/nodes/process-index/reset.js +8 -0
  308. package/src/nodes/process-index/update.js +75 -0
  309. package/src/nodes/ratio/index.js +14 -0
  310. package/src/nodes/ratio/init.js +37 -0
  311. package/src/nodes/ratio/introspect.js +155 -0
  312. package/src/nodes/ratio/publish-to.js +15 -0
  313. package/src/nodes/ratio/recompute.js +7 -0
  314. package/src/nodes/ratio/reset.js +7 -0
  315. package/src/nodes/ratio/update.js +47 -0
  316. package/src/nodes/sanitize/index.js +82 -0
  317. package/src/nodes/sanitize/init.js +82 -0
  318. package/src/nodes/sanitize/introspect.js +194 -0
  319. package/src/nodes/sanitize/publish-to.js +15 -0
  320. package/src/nodes/sanitize/recompute.js +8 -0
  321. package/src/nodes/sanitize/reset.js +14 -0
  322. package/src/nodes/sanitize/update.js +102 -0
  323. package/src/nodes/spike-guard/index.js +14 -0
  324. package/src/nodes/spike-guard/init.js +47 -0
  325. package/src/nodes/spike-guard/introspect.js +130 -0
  326. package/src/nodes/spike-guard/publish-to.js +35 -0
  327. package/src/nodes/spike-guard/recompute.js +14 -0
  328. package/src/nodes/spike-guard/reset.js +19 -0
  329. package/src/nodes/spike-guard/update.js +89 -0
  330. package/src/nodes/sse-emitter/index.js +7 -0
  331. package/src/nodes/sse-emitter/init.js +105 -0
  332. package/src/nodes/sse-emitter/introspect.js +134 -0
  333. package/src/nodes/sse-emitter/publish-to.js +6 -0
  334. package/src/nodes/sse-emitter/recompute.js +16 -0
  335. package/src/nodes/sse-emitter/reset.js +19 -0
  336. package/src/nodes/sse-emitter/update.js +69 -0
  337. package/src/nodes/sse-emitter/utils/broadcast-heartbeat.js +36 -0
  338. package/src/nodes/sse-emitter/utils/build-message.js +31 -0
  339. package/src/nodes/sse-emitter/utils/connection-manager.js +45 -0
  340. package/src/nodes/sse-emitter/utils/endpoint-initializer.js +20 -0
  341. package/src/nodes/sse-emitter/utils/health-monitor.js +38 -0
  342. package/src/nodes/sse-emitter/utils/qos-handler.js +41 -0
  343. package/src/nodes/state-change-detector/helpers.js +35 -0
  344. package/src/nodes/state-change-detector/index.js +12 -0
  345. package/src/nodes/state-change-detector/init.js +56 -0
  346. package/src/nodes/state-change-detector/introspect.js +146 -0
  347. package/src/nodes/state-change-detector/publish-to.js +20 -0
  348. package/src/nodes/state-change-detector/recompute.js +6 -0
  349. package/src/nodes/state-change-detector/reset.js +20 -0
  350. package/src/nodes/state-change-detector/update.js +97 -0
  351. package/src/nodes/sw-stats/index.js +14 -0
  352. package/src/nodes/sw-stats/init.js +51 -0
  353. package/src/nodes/sw-stats/introspect.js +131 -0
  354. package/src/nodes/sw-stats/publish-to.js +45 -0
  355. package/src/nodes/sw-stats/recompute.js +33 -0
  356. package/src/nodes/sw-stats/reset.js +15 -0
  357. package/src/nodes/sw-stats/update.js +39 -0
  358. package/src/nodes/swing-watch/index.js +17 -0
  359. package/src/nodes/swing-watch/init.js +144 -0
  360. package/src/nodes/swing-watch/introspect.js +188 -0
  361. package/src/nodes/swing-watch/publish-to.js +53 -0
  362. package/src/nodes/swing-watch/recompute.js +22 -0
  363. package/src/nodes/swing-watch/reset.js +55 -0
  364. package/src/nodes/swing-watch/update.js +767 -0
  365. package/src/nodes/tally/index.js +15 -0
  366. package/src/nodes/tally/init.js +32 -0
  367. package/src/nodes/tally/introspect.js +116 -0
  368. package/src/nodes/tally/publish-to.js +28 -0
  369. package/src/nodes/tally/recompute.js +10 -0
  370. package/src/nodes/tally/reset.js +10 -0
  371. package/src/nodes/tally/update.js +44 -0
  372. package/src/nodes/threshold/index.js +14 -0
  373. package/src/nodes/threshold/init.js +121 -0
  374. package/src/nodes/threshold/introspect.js +192 -0
  375. package/src/nodes/threshold/publish-to.js +11 -0
  376. package/src/nodes/threshold/recompute.js +8 -0
  377. package/src/nodes/threshold/reset.js +14 -0
  378. package/src/nodes/threshold/update.js +54 -0
  379. package/src/nodes/transform/helpers.js +39 -0
  380. package/src/nodes/transform/index.js +15 -0
  381. package/src/nodes/transform/init.js +35 -0
  382. package/src/nodes/transform/introspect.js +118 -0
  383. package/src/nodes/transform/publish-to.js +23 -0
  384. package/src/nodes/transform/recompute.js +12 -0
  385. package/src/nodes/transform/reset.js +11 -0
  386. package/src/nodes/transform/update.js +32 -0
  387. package/src/nodes/trend/compute-confidence.js +112 -0
  388. package/src/nodes/trend/index.js +14 -0
  389. package/src/nodes/trend/init.js +81 -0
  390. package/src/nodes/trend/introspect.js +151 -0
  391. package/src/nodes/trend/publish-to.js +22 -0
  392. package/src/nodes/trend/recompute.js +15 -0
  393. package/src/nodes/trend/reset.js +26 -0
  394. package/src/nodes/trend/update.js +93 -0
  395. package/src/nodes/tw-stats/copy-from.js +16 -0
  396. package/src/nodes/tw-stats/flush.js +12 -0
  397. package/src/nodes/tw-stats/index.js +41 -0
  398. package/src/nodes/tw-stats/init.js +92 -0
  399. package/src/nodes/tw-stats/introspect.js +171 -0
  400. package/src/nodes/tw-stats/publish-to.js +108 -0
  401. package/src/nodes/tw-stats/recompute.js +9 -0
  402. package/src/nodes/tw-stats/reset.js +16 -0
  403. package/src/nodes/tw-stats/update.js +113 -0
  404. package/src/nodes/unbalance/index.js +15 -0
  405. package/src/nodes/unbalance/init.js +59 -0
  406. package/src/nodes/unbalance/introspect.js +167 -0
  407. package/src/nodes/unbalance/publish-to.js +52 -0
  408. package/src/nodes/unbalance/recompute.js +11 -0
  409. package/src/nodes/unbalance/reset.js +10 -0
  410. package/src/nodes/unbalance/update.js +83 -0
  411. package/src/nodes/vector-distance/index.js +14 -0
  412. package/src/nodes/vector-distance/init.js +54 -0
  413. package/src/nodes/vector-distance/introspect.js +149 -0
  414. package/src/nodes/vector-distance/publish-to.js +35 -0
  415. package/src/nodes/vector-distance/recompute.js +11 -0
  416. package/src/nodes/vector-distance/reset.js +20 -0
  417. package/src/nodes/vector-distance/update.js +139 -0
  418. package/src/nodes/winnow/index.js +12 -0
  419. package/src/nodes/winnow/init.js +82 -0
  420. package/src/nodes/winnow/introspect.js +253 -0
  421. package/src/nodes/winnow/publish-to.js +51 -0
  422. package/src/nodes/winnow/recompute.js +14 -0
  423. package/src/nodes/winnow/reset.js +34 -0
  424. package/src/nodes/winnow/update.js +203 -0
  425. package/src/tools/training/features.js +227 -0
  426. package/src/tools/training/index.js +21 -0
  427. package/src/tools/training/logistic.js +238 -0
  428. package/src/tools/training/metrics.js +126 -0
  429. package/src/tools/training/scale.js +239 -0
  430. package/src/tools/training/validate.js +103 -0
  431. package/src/windowing/count-sliding/create.js +16 -0
  432. package/src/windowing/count-sliding/get-reverse-chronological-index.js +19 -0
  433. package/src/windowing/count-sliding/index.js +6 -0
  434. package/src/windowing/count-sliding/is-not-full.js +5 -0
  435. package/src/windowing/count-sliding/push.js +15 -0
  436. package/src/windowing/count-sliding/reset.js +11 -0
  437. package/src/windowing/count-sliding/size.js +5 -0
  438. package/src/windowing/time-sliding/create.js +25 -0
  439. package/src/windowing/time-sliding/push.js +42 -0
  440. package/CODE_OF_CONDUCT.md +0 -46
  441. package/CONTRIBUTING.md +0 -132
  442. package/docs/.nojekyll +0 -0
  443. package/docs/CONTRIBUTING.md +0 -134
  444. package/docs/README.md +0 -132
  445. package/docs/_coverpage.md +0 -26
  446. package/docs/_media/bg.png +0 -0
  447. package/docs/_media/wink-logo.png +0 -0
  448. package/docs/_navbar.md +0 -14
  449. package/docs/_sidebar.md +0 -2
  450. package/docs/index.html +0 -44
  451. package/eslint.config.js +0 -283
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright (c) 2024-25 GRAYPE Systems Private Limited
3
+ Copyright (c) 2024-26 GRAYPE Systems Private Limited
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
package/README.md CHANGED
@@ -1,132 +1,158 @@
1
- # wink-composer ♫
1
+ # winkComposer
2
2
 
3
- ### [![Stability](https://img.shields.io/badge/stability-1--experimental-orange.svg)](https://nodejs.org/api/documentation.html#documentation_stability_index)
3
+ [![npm version](https://img.shields.io/npm/v/@winkjs/composer.svg)](https://www.npmjs.com/package/@winkjs/composer)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
5
 
5
- ## ✨ Real-time analytics that sparks joy
6
+ ## Composable Streaming Intelligence
7
+ [<img align="right" src="https://decisively.github.io/wink-logos/logo-title.png" width="100px" >](https://winkjs.org/)
6
8
 
7
- [<img align="right" src="https://decisively.github.io/wink-logos/logo-title.png" width="100px" >](http://winkjs.org/)
9
+ winkComposer is a JavaScript framework for turning live data streams into insights and decisions — while the data is still moving. There is no batch job to wait for. On the plant floor, a delayed insight is a lost opportunity. It is open source, purpose-built for SMBs and MSMEs.
8
10
 
9
- WinkComposer is an upcoming open-source framework that makes building streaming intelligence playfully simple. Connect intuitive nodes, experiment freely, perfect it in an iteration or two. From edge-ready AI algorithms to built-in resilience, everything you need for production comes standard. No complexity, no black boxes - just the joy of creating exactly what you need.
10
11
 
11
- ## Why Composability Matters
12
+ ## See It in Action
12
13
 
13
- **🎯 Create What You Need** — With composability, you're the inventor: Correlate vibration with weather? Done. Detect micro-trends before they become macro? Built.
14
+ The fastest way to understand winkComposer is to watch it work. The demos below run in your browser — real nodes, live data, no install, nothing to sign up for. Each one uses the same core that runs from edge to cloud.
14
15
 
15
- **💫 Countless Possibilities** — Dozens of nodes → Endless pipelines. Like few music notes creating captivating symphonies.
16
+ | [![Bearing Health](https://composer.winkjs.org/readme-bearing-health.png)](https://composer.winkjs.org/docs/use-cases/bearing-health) | [![Server Health](https://composer.winkjs.org/readme-server-health.png)](https://composer.winkjs.org/docs/use-cases/server-health) | [![Process Quality](https://composer.winkjs.org/readme-process-quality.png)](https://composer.winkjs.org/docs/use-cases/process-quality) |
17
+ |:---:|:---:|:---:|
18
+ | [**Detecting Bearing Failure**](https://composer.winkjs.org/docs/use-cases/bearing-health) | [**Detecting Server Latency Degradation**](https://composer.winkjs.org/docs/use-cases/server-health) | [**Catching Process Drift**](https://composer.winkjs.org/docs/use-cases/process-quality) |
19
+ | Predictive Maintenance | AIOps | Process Control |
16
20
 
17
- **🌱 Evolve Naturally** — Start: `sensor → threshold → alert`. Grow: Add intelligence: `sensor → normalize → smooth → detect → confirm → alert`. Unconstrained by vendor feature lists.
21
+ Other end-to-end examples include [diagnosing Wi-Fi access-point health](https://composer.winkjs.org/docs/use-cases/wifi-ap-health), [classifying driving conditions](https://composer.winkjs.org/docs/use-cases/driving-modes) from OBD-II telematics, and [tracking wash-cycle quality](https://composer.winkjs.org/docs/use-cases/wash-cycle-quality).
18
22
 
19
- **🔍 Total Transparency** — See which node triggered, what threshold crossed, why it alerted. Every decision is explainable.
23
+ Prefer to start with a failure mode instead of an industry? [Recipes](https://composer.winkjs.org/docs/playground/recipes) are short, runnable patterns for recurring problems. They cover gradual drift, directional trends, sudden shifts, hidden parasitic drain, PID-loop hunting, frozen sensors, and subtle process shifts — plus adaptive compression for storage.
20
24
 
21
- ## Build Exactly What You Need
22
25
 
23
- Build precise analytics for your unique patterns:
26
+ ## How It Works
24
27
 
25
- ```javascript
26
- // Detect bearing failure in rotating equipment
27
- vibration → isolateSignal → extractPeaks → measureIntensity →
28
- trackChanges → triggerAlert
28
+ A flow is a [pipeline](docs/handbook/understanding-composer.md) of small, single-purpose [nodes](docs/handbook/nodes/index.md). Each node reads fields from the message, computes its result, and adds the result onto the same message for the nodes downstream. The message that leaves the pipeline carries its whole history. A message can also stop early — a failed check drops it, and nothing downstream fires.
29
+
30
+ The intelligence emerges from composition. Together the nodes cover the whole path from raw signal to decision: clean signals, extract features, detect change, fuse evidence, and act. The repertoire runs from a simple threshold, through a [Kalman filter, to a two-layer spiking neural network](docs/handbook/nodes/intelligence.md). The filter estimates what sensors cannot directly measure. The network weighs many weak signals into one confident verdict.
31
+
32
+ You define such a pipeline in code — a [linear flow](docs/handbook/flow-language.md) that reads top to bottom, not a drag-and-drop graph. Explicit control signals handle orchestration, so a flow stays readable as it grows. And when many machines share one flow, each gets its own [isolated state](docs/handbook/understanding-composer.md) — one flow, thousands of assets.
33
+
34
+ Results leave through emitters and storage: alerts to an MQTT broker like Mosquitto or the terminal, insights to QuestDB. [Grafana dashboards](docs/handbook/visualization.md) read from there. The stack is open source end to end.
29
35
 
30
- // Monitor chemical process quality
31
- temperature → removeNoise → smoothFast → smoothSlow → findDivergence →
32
- detectChange → waitForPersistence
36
+ The Quick Start below builds one such pipeline end to end.
33
37
 
34
- // Find correlated sensor behaviors
35
- [sensor1, sensor2] → trackCorrelation → compareToNormal → raiseFlag
36
38
 
37
- // Calculate real-time OEE
38
- machine → trackState → sumTime → countOutput →
39
- checkQuality → calculateScore
39
+ ## Quick Start
40
+
41
+ ```bash
42
+ npm install @winkjs/composer
40
43
  ```
41
44
 
42
- Each node is simple:
43
- - `removeNoise`: Median of last few values (removes sensor spikes).
44
- - `smoothFast`: Average of last 10 values (recent trend).
45
- - `smoothSlow`: Average of last 100 values (baseline trend).
46
- - `findDivergence`: Fast trend - slow trend (unusual behavior?).
47
- - `trackCorrelation`: Smart correlation (learns relationships between sensors)
45
+ Requires Node.js 22 or newer.
46
+
47
+ A complete flow — replay a CSV feed, clean each reading, flag a hot pump motor, confirm it is not a blip, and print an alert:
48
48
 
49
- _Node names and details are illustrative - actual implementations may vary._
49
+ ```javascript
50
+ import { flow, csv, terminal } from '@winkjs/composer';
50
51
 
51
- Every arrow is a conscious choice. Every node has a purpose. No magic, just simple intuitive math.
52
+ const handle = await flow( 'hello-flow' )
52
53
 
54
+ // Replay the CSV like a live feed: one reading every 200 ms.
55
+ .source( csv, { path: 'data/pump-temps.csv', delayMs: 200 } )
53
56
 
54
- ## Your Analytics Journey
57
+ // Alerts print to the terminal here. A production flow points this
58
+ // at an MQTT broker instead, with QuestDB for storage.
59
+ .emitter( terminal, { verbose: true, prefix: '[pump]' } )
55
60
 
56
- **Start Simple**
57
- `sensor → threshold → alert`
61
+ // One isolated pipeline per pump, and alerts name the pump in
62
+ // their topic. This feed has a single pump; a fleet needs no
63
+ // code change.
64
+ .assetId( 'id' )
65
+
66
+ // 1. clean — reject readings outside a sane range
67
+ .sanitize( 'clean', 'motor_t',
68
+ { failureReason: 'reject_reason' },
69
+ { ranges: { min: 0, max: 120 } } )
70
+
71
+ // 2. detect — flag when the motor runs hot
72
+ .threshold( 'tooHot', 'motor_t',
73
+ { active: 'is_hot' },
74
+ { mode: 'above', threshold: 80, hysteresis: 3 } )
75
+
76
+ // 3. confirm — hot across several readings, not one spike
77
+ .persistenceCheck( 'confirmHot',
78
+ ( msg ) => msg.is_hot,
79
+ { persistenceConfirmed: 'hot_confirmed' },
80
+ { minVotes: 3, outOfTotal: 5 } )
81
+
82
+ // 4. broadcast — print an alert once confirmed
83
+ .emitIf( 'alert',
84
+ ( msg ) => msg.hot_confirmed,
85
+ { target: 'terminal', insightType: 'overheat' } )
86
+
87
+ .run();
88
+ ```
58
89
 
59
- **Evolve Naturally**
60
- `sensor → validate → normalize → threshold → debounce → alert`
90
+ The same flow ships as a runnable project in [`examples/hello-flow`](examples/hello-flow), data included. Run it with `npm install && npm start`.
61
91
 
62
- **Scale Intelligently**
63
- `sensor → [parallel: statistics | patterns | anomalies] → correlate → decide → act`
92
+ Prefer zero install? [Build this flow interactively](https://composer.winkjs.org/docs/playground/hello-flow) in the browser playground.
64
93
 
65
- Your analytics grow with your understanding, and are never limited by any tool's feature list.
94
+ The example above replays a CSV file. A live deployment reads from an MQTT broker instead — or runs [headless](docs/handbook/headless-flow.md), where your own code feeds the flow. Headless takes any source you already run: an OPC-UA client, a Kafka consumer.
66
95
 
67
- ## Designed for the Real World
68
96
 
69
- ### Industrial IoT
70
- From simple threshold monitoring to complex predictive maintenance - compose what fits your equipment, your patterns, your physics. **Move intelligence to the edge** with analytics that run on industrial Raspberry Pis. Works alongside your existing systems to handle your unique requirements.
97
+ ## Performance
71
98
 
72
- ### Financial Services
73
- Build fraud detection you can explain to auditors. Every decision traceable, every threshold justified.
99
+ The numbers below come from a pure compute benchmark — every step a live message takes through an 8-node flow, from arrival to final output. **Storage and MQTT I/O are excluded** — these are compute ceilings, not full-deployment numbers.
74
100
 
75
- ### Smart Infrastructure
76
- Energy optimization with transparent logic. See why the system made each decision.
101
+ | Configuration | Throughput |
102
+ |----------------------|-------------------------|
103
+ | Raspberry Pi 5 | ~100K messages/second |
104
+ | Modern server | ~1.2M messages/second |
105
+ | Tracking 10K assets | ~500K messages/second |
77
106
 
78
- ## Production-Grade Resilience
79
- Real streams have noise. Sensors fail. Networks hiccup. WinkComposer handles it all:
107
+ Two configurations produced these numbers. The first two rows interleave 10 asset pipelines in random order — 4.5 million messages (10 pipelines × 900 data points × 500 iterations). The third row runs the same flow with 10,000 assets — 10,000 isolated states alive at once, 9 million messages, under 140 MB of heap. Pipelines are created dynamically as each asset first appears; timing uses `process.hrtime.bigint()`. The same pipeline [runs in your browser](https://composer.winkjs.org/docs/benchmark) — browser performance varies from native Node.js due to JIT differences.
80
108
 
81
- - **Node-level fault isolation** - One bad reading doesn't crash your pipeline
82
- - **Automatic state recovery** - Snapshot and restore without missing a beat
83
- - **Built-in observability** - Know what's happening in every node, every partition
84
- - **Adaptive execution** - Maintains responsiveness under varying load
85
109
 
110
+ ## Built for the Real World
86
111
 
87
- ## Core Principles
112
+ Write a flow once and run it anywhere Node.js does — an industrial-grade Raspberry Pi, a production server, a Kubernetes cluster. Each asset's state is isolated, so a fault in one stays in one. Messages [queue locally](docs/handbook/resilience.md) when the network drops and drain cleanly on reconnect. Shutdown is ordered and deterministic: sources close first, storage last. A misconfigured flow fails when you define it, not in production — unknown options, output collisions, and bad triggers are all caught at definition time.
88
113
 
89
- | Principle | What it means |
90
- |-----------|---------------|
91
- | **Atomic Operations** | Each node does one thing perfectly |
92
- | **Pure Functions** | Predictable, testable, composable |
93
- | **Transparent Logic** | Understand every decision |
94
- | **Production Ready** | Built for high-throughput streaming with microsecond-scale latency |
95
- | **AI-Native Intelligence** | From statistical learning nodes to LLM reasoning - intelligence at every level |
96
- | **Built for Reality** | Node-level fault isolation, automatic recovery, and comprehensive observability |
114
+ The test suite holds over 6,500 tests behind a 99.5% coverage gate. Integration tests run against real Mosquitto and QuestDB services, not mocks. Every npm release carries SLSA provenance — a public, verifiable link from the package back to the exact source commit and the build that produced it. `npm audit signatures` verifies it.
97
115
 
98
- ## What's Coming
116
+ The documentation also relates winkComposer's concepts to two industrial standards: [ISO 13374](https://composer.winkjs.org/docs/reference/iso-13374-mapping) for condition monitoring, the [NIST AI RMF](https://composer.winkjs.org/docs/reference/nist-ai-rmf-mapping) for AI risk management.
99
117
 
100
- ### 🎉 **Opening Our Doors in 2025**
101
- WinkComposer is transitioning to open source development in 2025. Join the [early conversation](https://github.com/winkjs/composer/discussions) and help shape the future of composable streaming analytics. You can even reach out directly at wink@graype.in.
118
+ Flows can run headless inside your own application — no broker, no services. Your code feeds messages in from any source you already run. Already running a historian (the plant's time-series system of record)? winkComposer adds value beside it — it watches the live stream and acts, while the historian keeps the record.
102
119
 
103
- **Together, we're building:**
104
120
 
105
- - **Rich Node Library**: Statistical, filtering, detection, transformation, and control nodes
106
- - **Edge-Ready Intelligence**: Advanced algorithms like smart correlation, change point detection, and regression inference - AI-like capabilities without heavyweight frameworks
107
- - **Pipeline Builder**: Define your analytics flows declaratively (visual tools planned)
108
- - **Edge-Ready Performance**: Process data efficiently, even on resource-constrained devices (**tested on Raspberry Pi**)
109
- - **Knowledge Graph Integration**: Build digital twins with Neo4j/ArangoDB for contextual intelligence
110
- - **AI-Native Reasoning**: When patterns emerge, LLMs explain why. When anomalies occur, get actionable recommendations. Open-source models keep intelligence at the edge.
121
+ ## Documentation
111
122
 
123
+ The documentation lives in two places: the [documentation site](https://composer.winkjs.org) for interactive learning, and the in-repo handbook for version-matched reference.
112
124
 
113
- ## The Vision
125
+ | Resource | What it covers |
126
+ |---|---|
127
+ | [**Hello Flow!**](https://composer.winkjs.org/docs/playground/hello-flow) | Build a 4-node temperature monitor from scratch — smooth, detect, confirm, broadcast — with an interactive demo running real nodes in your browser. The natural starting point. |
128
+ | [**Recipes**](https://composer.winkjs.org/docs/playground/recipes) | Short, runnable patterns for recurring failure modes — each names the nodes it uses and runs in the browser. |
129
+ | [**Explore Nodes**](https://composer.winkjs.org/docs/playground/explore-nodes) | Single-node sandboxes — drag a slider, watch the node respond in real time. Covers the Kalman 1D filter and the kernel convolution node, with more to come. |
130
+ | [**Under the Hood**](https://composer.winkjs.org/docs/concepts/under-the-hood) | How messages flow and get enriched node by node, how bad data and throwing functions are handled without crashing the pipeline, how per-asset isolation works, and timestamp requirements. |
131
+ | [**Flow Language**](https://composer.winkjs.org/docs/concepts/flow-language) | The complete DSL reference — flow anatomy, node call signatures, dynamic options (tunables), single vs. multi-field processing, naming policies, and node processing types. |
132
+ | [**Composition Patterns**](https://composer.winkjs.org/docs/concepts/composition-patterns) | Proven node combinations for recurring problems: noise-tolerant alarms, drift detection, adaptive diagnostics, layered flows, and downsampling for storage. Includes clear guidance on when to use passIf, emitIf, or controller/disable. |
133
+ | [**Semantics**](https://composer.winkjs.org/docs/concepts/semantics) | How to define what computed values mean — types, units, physical ranges, operational limits — as a single source of truth shared by storage, dashboards, and query engines. Covers the facts-vs-decisions design principle. |
134
+ | [**Node Index**](https://composer.winkjs.org/docs/reference/node-index) | Every node grouped by category — Signal Conditioning, Detection, Feature Extraction, Intelligence, and more — with what each computes and what it adds to the message. |
135
+ | [**Handbook**](docs/handbook/index.md) | The complete reference, right here in the repo and version-matched: the handbook at any release tag describes exactly that release's code. |
136
+ | [**Changelog**](CHANGELOG.md) | Release notes for every published version — what changed, what broke, and what to do about it. |
137
+ | [**Roadmap**](ROADMAP.md) | What is planned next, item by item, with complexity and status. |
114
138
 
115
- Finally, build solutions that fit your exact problems, not the other way around.
116
139
 
117
- Every industry has unique patterns. Every process has specific physics. Every business has particular rules. WinkComposer gives you the building blocks to create exactly what you need.
140
+ ## Get Involved
118
141
 
119
- Domain-specific platforms excel at standard use cases. WinkComposer shines when you need something unique, beyond standard use cases. Standard use cases always included - they're just the beginning of what's possible!
142
+ | [**Star winkComposer**](https://github.com/winkjs/composer) | [**Follow @winkjs**](https://github.com/winkjs) | [**Discussions**](https://github.com/winkjs/composer/discussions) |
143
+ |:---:|:---:|:---:|
144
+ | Support open-source streaming intelligence. | Stay updated on releases and ecosystem developments. | Questions, ideas, or feedback — all welcome. |
120
145
 
146
+ Want to contribute code or docs? Start with the [contributing guide](CONTRIBUTING.md). The project follows the [Contributor Covenant](CODE_OF_CONDUCT.md).
121
147
 
122
148
 
123
149
  ## About winkJS
124
150
 
125
- WinkComposer joins the winkJS family - production-grade open-source packages for Natural Language Processing, Machine Learning, and Statistical Analysis in JavaScript. Built for reliability with ~100% test coverage.
151
+ [winkJS](https://winkjs.org) is the open-source home of high-performance JavaScript tools. winkNLP covers natural language processing; winkComposer covers streaming intelligence. Both follow the same discipline: developer-friendly APIs, measured performance, and well-tested code.
126
152
 
127
153
 
128
- ## Copyright & License
154
+ ## License
129
155
 
130
- **Wink Composer** is copyright 2017-25 [GRAYPE Systems Private Limited](https://graype.in/).
156
+ winkComposer is released under the [MIT License](LICENSE).
131
157
 
132
- It is licensed under the terms of the MIT License.
158
+ Copyright (c) 2024-26 GRAYPE Systems Private Limited.
package/package.json CHANGED
@@ -1,30 +1,36 @@
1
1
  {
2
2
  "name": "@winkjs/composer",
3
- "version": "0.0.2",
4
- "description": "Composable Streaming Intelligence.",
3
+ "version": "0.4.1",
4
+ "description": "Composable Streaming Intelligence — turn streaming data into actionable insights, from edge to cloud",
5
5
  "keywords": [
6
+ "streaming",
7
+ "streaming-intelligence",
8
+ "streaming-analytics",
9
+ "real-time",
10
+ "edge-computing",
6
11
  "iot",
7
- "statistical-learning",
8
- "stream-processing",
9
- "statistical-analysis",
10
- "event-driven",
11
- "composable",
12
- "real-time-analytics",
12
+ "iiot",
13
+ "industrial-iot",
14
+ "time-series",
15
+ "signal-processing",
13
16
  "anomaly-detection",
14
- "edge-computing",
15
- "edgi-ai",
16
- "streaming-analytics",
17
- "industrial-iot"
17
+ "predictive-maintenance",
18
+ "mqtt",
19
+ "questdb",
20
+ "winkjs",
21
+ "wink"
18
22
  ],
19
23
  "main": "src/composer.js",
24
+ "module": "src/composer.js",
25
+ "exports": {
26
+ ".": "./src/composer.js"
27
+ },
20
28
  "scripts": {
21
29
  "pretest": "npm run lint",
22
- "test": "nyc --reporter=html --reporter=lcov --reporter=text mocha ./test/",
23
- "coverage": "nyc report --reporter=text-lcov | coveralls",
24
- "sourcedocs": "docker -i src -o ./sourcedocs --sidebar yes",
25
- "lint": "eslint ./src/*.js ./test/*.js",
26
- "perf": "node benchmark/run.js",
27
- "dtslint": "dtslint types",
30
+ "test": "mocha --recursive 'src/**/*.specs.js' --ignore 'src/**/slow-*.specs.js'",
31
+ "test:hardening": "node --expose-gc node_modules/.bin/mocha --recursive 'src/**/slow-*.specs.js' --timeout 300000 --exit",
32
+ "test:coverage": "c8 --reporter=html mocha --recursive 'src/**/*.specs.js' --ignore 'src/**/slow-*.specs.js'",
33
+ "lint": "eslint 'src/**/*.js'",
28
34
  "docs-serve": "docsify serve ./docs"
29
35
  },
30
36
  "repository": {
@@ -33,19 +39,41 @@
33
39
  },
34
40
  "author": "Sanjaya Kumar Saxena",
35
41
  "license": "MIT",
42
+ "type": "module",
43
+ "engines": {
44
+ "node": ">=22"
45
+ },
46
+ "files": [
47
+ "src/composer.js",
48
+ "src/core/**/*.js",
49
+ "src/flow/**/*.js",
50
+ "src/nodes/**/*.js",
51
+ "src/tools/**/*.js",
52
+ "src/windowing/**/*.js",
53
+ "!src/**/*.specs.js",
54
+ "!src/**/test/"
55
+ ],
36
56
  "bugs": {
37
57
  "url": "https://github.com/winkjs/composer/issues"
38
58
  },
39
- "homepage": "http://winkjs.org/composer/#/",
59
+ "homepage": "https://composer.winkjs.org/",
60
+ "publishConfig": {
61
+ "access": "public"
62
+ },
40
63
  "devDependencies": {
41
- "benchmark": "^2.1.4",
42
- "chai": "^4.3.7",
43
- "coveralls": "^3.1.1",
44
- "docker": "^1.0.0",
45
- "docsify-cli": "^4.4.4",
46
- "dtslint": "^4.2.1",
47
- "eslint": "^8.36.0",
48
- "mocha": "^10.2.0",
49
- "nyc": "^15.1.0"
64
+ "c8": "^10.1.3",
65
+ "chai": "^5.2.0",
66
+ "eslint": "^9.21.0",
67
+ "eslint-plugin-security": "^4.0.0",
68
+ "mocha": "^11.1.0",
69
+ "sinon": "^19.0.2"
70
+ },
71
+ "dependencies": {
72
+ "@questdb/nodejs-client": "^4.2.0",
73
+ "classic-level": "^3.0.0",
74
+ "glob": "^13.0.6",
75
+ "mqtt": "^5.15.1",
76
+ "msgpackr": "^1.11.10",
77
+ "pg": "^8.20.0"
50
78
  }
51
79
  }
@@ -0,0 +1,75 @@
1
+ // src/composer.js
2
+
3
+ /**
4
+ * @fileoverview Main entry point for @winkjs/composer.
5
+ *
6
+ * Provides flat exports for the DSL, source adapters, emitter adapters,
7
+ * codecs, and tunable helpers.
8
+ *
9
+ * @example
10
+ * import { flow, csv, mqttEmitter } from '@winkjs/composer';
11
+ *
12
+ * flow('myPipeline')
13
+ * .sanitize(...)
14
+ * .threshold(...)
15
+ * .source(csv, { path: './data.csv' })
16
+ * .emitter(mqttEmitter, { brokerUrl: 'mqtt://localhost' })
17
+ * .run();
18
+ */
19
+
20
+ // DSL
21
+ export { flow } from './flow/flow.js';
22
+
23
+ // Headless driver — feed a flow that has no source (see docs/handbook/headless-flow.md)
24
+ export { headlessDriver } from './flow/driver.js';
25
+
26
+ // Emitters
27
+ export * as mqttEmitter from './core/emitter-manager/mqtt/index.js';
28
+ export * as terminal from './core/emitter-manager/terminal/index.js';
29
+
30
+ // Sources
31
+ export * as csv from './core/source-manager/csv/index.js';
32
+ export * as mqttSource from './core/source-manager/mqtt/index.js';
33
+
34
+ // Storage
35
+ export { default as questdbAdapter } from './core/storage-manager/questdb/index.js';
36
+
37
+ // Semantics
38
+ export { loadSemantics } from './core/semantics/loader.js';
39
+
40
+ // Codecs
41
+ export { jsonCodec, msgpackCodec } from './core/codec/index.js';
42
+
43
+ // Tunable helpers
44
+ export {
45
+ lookupByField,
46
+ pickByField,
47
+ scaleBy,
48
+ chooseWhen,
49
+ clampTo,
50
+ fromField,
51
+ offsetBy
52
+ } from './core/tunable/helpers.js';
53
+
54
+ // Transform helpers
55
+ export {
56
+ square,
57
+ abs,
58
+ sqrt,
59
+ log,
60
+ log10,
61
+ reciprocal,
62
+ negate
63
+ } from './nodes/transform/helpers.js';
64
+
65
+ // Training utilities
66
+ export {
67
+ computeStandardParams,
68
+ computeMinMaxParams,
69
+ computeRobustParams,
70
+ scale,
71
+ standardize
72
+ } from './tools/training/scale.js';
73
+ export { sigmoid, train, predict, classify } from './tools/training/logistic.js';
74
+ export { confusionMatrix, classificationMetrics, sweepThresholds } from './tools/training/metrics.js';
75
+
@@ -0,0 +1,148 @@
1
+ // core/batch/aoo-encoder/index.js
2
+ // Purpose:
3
+ // Array-of-Objects (AoO) encoder for efficient batch transmission of tabular data.
4
+ // Optimized for downsampled time-series data where rows have consistent shape.
5
+ // Designed to work with msgpackr's structure learning for maximum compression.
6
+ //
7
+ // Design Philosophy:
8
+ // - Zero allocations in hot path - reuse all objects and arrays
9
+ // - Stable object shapes - enables msgpackr structure learning
10
+ // - Predictable field order - consistent compression ratios
11
+ // - Null preservation - maintains shape even with missing data
12
+ //
13
+ // Use Case:
14
+ // Downsampled sensor data often arrives as rows of readings:
15
+ // [{ timestamp: 1234, temp: 23.5, pressure: 101.3 }, ...]
16
+ // This encoder batches these rows efficiently for MQTT transmission.
17
+ //
18
+ // Compression Strategy:
19
+ // By maintaining stable object shapes and field order, msgpackr learns the
20
+ // structure after ~5 messages. Subsequent messages only send structure ID + values,
21
+ // achieving 80-90% size reduction compared to JSON.
22
+
23
+ /**
24
+ * Create an Array-of-Objects encoder for batch data transmission.
25
+ *
26
+ * @param {Object} options - Encoder configuration
27
+ * @param {number} options.maxRows - Maximum rows per batch (pre-allocation size)
28
+ * @param {string[]} options.fieldOrder - Field names in consistent order
29
+ * @param {Object} options.codec - Codec instance from createCodec()
30
+ *
31
+ * @returns {Object} Encoder with encode() method and fieldOrder reference
32
+ *
33
+ * @example
34
+ * const encoder = createAooEncoder({
35
+ * maxRows: 100,
36
+ * fieldOrder: ['timestamp', 'temperature', 'pressure'],
37
+ * codec: msgpackCodec
38
+ * });
39
+ *
40
+ * const { payload, props } = encoder.encode('sensor-01', 1, readings, 50);
41
+ * mqttClient.publish('telemetry/batch', payload, { properties: props });
42
+ */
43
+ export const createAooEncoder = function ( { maxRows, fieldOrder, codec } ) {
44
+ // Input validation - fail fast on misconfiguration
45
+ if ( !Array.isArray( fieldOrder ) || fieldOrder.length === 0 ) {
46
+ throw new Error( 'fieldOrder must be non-empty array of field names' );
47
+ }
48
+ if ( !maxRows || maxRows <= 0 ) {
49
+ throw new Error( 'maxRows must be positive integer' );
50
+ }
51
+ if ( !codec || typeof codec.pack !== 'function' ) {
52
+ throw new Error( 'codec must have pack() method');
53
+ }
54
+
55
+ // Pre-allocate row objects with stable shape.
56
+ // Critical for msgpackr structure learning:
57
+ // - Same fields in same order = same structure ID
58
+ // - null instead of undefined = consistent serialization
59
+ // - Object.create(null) = no prototype pollution
60
+ const rows = new Array( maxRows );
61
+ for ( let i = 0; i < maxRows; i += 1 ) {
62
+ const r = Object.create( null );
63
+ // Initialize all fields to null (not undefined!)
64
+ // This ensures consistent object shape even when values are missing
65
+ for ( let k = 0; k < fieldOrder.length; k += 1 ) {
66
+ r[ fieldOrder[ k ] ] = null;
67
+ }
68
+ rows[ i ] = r;
69
+ }
70
+
71
+ // Pre-allocate batch array that references row objects.
72
+ // We'll adjust its length per batch but never reallocate.
73
+ // slice() here is a one-time shallow copy of references.
74
+ const batch = rows.slice();
75
+
76
+ // Cache MQTT properties to avoid repeated calls.
77
+ // These properties hint the wire format to subscribers.
78
+ const props = codec.properties || {};
79
+
80
+ /**
81
+ * Encode source rows into a compressed batch payload.
82
+ *
83
+ * Design decisions:
84
+ * - Copy values field-by-field to maintain stable shape
85
+ * - Preserve null but normalize undefined to null
86
+ * - Reuse pre-allocated objects to avoid GC
87
+ * - Temporarily adjust batch.length without reallocation
88
+ *
89
+ * @param {string} producerId - Identifies the data source (e.g., device ID)
90
+ * @param {number} seq - Sequence number for gap detection on receiver side
91
+ * @param {Array} srcRows - Source rows to encode (not modified)
92
+ * @param {number} count - Number of rows to encode (may be < srcRows.length)
93
+ *
94
+ * @returns {Object} { payload: Uint8Array|Buffer, props: Object }
95
+ * payload: Compressed binary data
96
+ * props: MQTT v5 properties for content type hint
97
+ */
98
+ const encode = function ( producerId, seq, srcRows, count ) {
99
+ // Validate count doesn't exceed pre-allocated capacity
100
+ if ( count > maxRows ) {
101
+ throw new Error( `Cannot encode ${count} rows, max capacity is ${maxRows}` );
102
+ }
103
+
104
+ // Copy source data into pre-allocated row objects
105
+ for ( let i = 0; i < count; i += 1 ) {
106
+ const src = srcRows[ i ];
107
+ const dst = rows[ i ];
108
+
109
+ // Copy only declared fields in consistent order
110
+ for ( let k = 0; k < fieldOrder.length; k += 1 ) {
111
+ const key = fieldOrder[ k ];
112
+ const v = src[ key ];
113
+ // FIXED: Normalize undefined to null for consistent serialization
114
+ dst[ key ] = ( v === undefined ) ? null : v;
115
+ }
116
+
117
+ // Point batch array to this row (reference, not copy)
118
+ batch[ i ] = dst;
119
+ }
120
+
121
+ // Temporarily adjust batch length for this encoding
122
+ const cap = batch.length;
123
+ batch.length = count;
124
+
125
+ // Pack the message with consistent structure
126
+ const payload = codec.pack( {
127
+ producerId: producerId,
128
+ seq: seq,
129
+ items: batch
130
+ } );
131
+
132
+ // Restore batch array to full capacity for next call
133
+ batch.length = cap;
134
+
135
+ return {
136
+ payload: payload,
137
+ props: props
138
+ };
139
+ }; // encode()
140
+
141
+ // Public API
142
+ // Expose encode function and field order for reference.
143
+ // slice() returns a defensive copy of fieldOrder.
144
+ return {
145
+ encode: encode,
146
+ fieldOrder: fieldOrder.slice()
147
+ };
148
+ };
@@ -0,0 +1,12 @@
1
+ // core/batch/index.js
2
+ // Purpose:
3
+ // Batch data handling subsystem for efficient transmission of tabular data.
4
+ // Provides sliding windows for history retention and encoders for compression.
5
+
6
+ export { createAooEncoder } from './aoo-encoder.js';
7
+ export { createWindow } from './sliding-window.js';
8
+
9
+ // These work together:
10
+ // 1. Window maintains recent history (sliding-window.js)
11
+ // 2. Encoder compresses for transmission (aoo-encoder.js)
12
+ // 3. Both use same field order for structure stability