@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,244 @@
1
+ // core/source-manager/mqtt/dedup.js
2
+
3
+ /**
4
+ * @fileoverview Time-bounded, count-capped dedup cache for MQTT QoS 1
5
+ * retransmissions (ADR-022).
6
+ *
7
+ * QoS 1 is "at least once": a re-send after a connection break carries
8
+ * the same `winkDedupId` as its original, and this cache drops the
9
+ * repeat. A duplicate arrives roughly one outage after its original,
10
+ * so the cache is specified in TIME (catch any duplicate within
11
+ * `windowMs`) and guaranteed in MEMORY (never hold more than
12
+ * `maxEntries` ids). Whichever bound binds first wins; at high message
13
+ * rates the effective window is `maxEntries ÷ rate` — the trade is
14
+ * documented in ADR-022, not hidden.
15
+ *
16
+ * One structure, no modes, no timers:
17
+ * - A `Set` gives O(1) duplicate lookup.
18
+ * - A pre-allocated ring (id slots + a Float64Array of arrival
19
+ * timestamps) gives O(1) insertion and eviction in arrival order.
20
+ * - Expiry is checked at the ring head on each call — amortized O(1),
21
+ * no background sweep.
22
+ *
23
+ * Hot-path allocation profile (ADR-018 zero-alloc — allocation only where
24
+ * unavoidable, each residual stated, no overclaiming):
25
+ * - Our code allocates nothing per message: the ring, the timestamp
26
+ * array, and the Set are created at initialization; ids are stored
27
+ * by reference; no objects, arrays, or strings are built.
28
+ * - Two unavoidable residuals, both bounded: (1) `Set.add`/`Set.delete`
29
+ * maintain V8's internal hash table — amortized O(1), memory bounded
30
+ * by `maxEntries`, and the identical profile the pre-ADR-022 cache
31
+ * already had (JS offers no pre-sized Set). (2) `Date.now()` exceeds
32
+ * the small-integer range, so the timestamp is transiently boxed; it
33
+ * unboxes on store into the Float64Array and dies in the nursery.
34
+ * - Eviction clears the ring slot so an evicted id string is not
35
+ * retained past its window — that release is deliberate.
36
+ *
37
+ * Opt-in by construction: a message without a dedup id (null or
38
+ * undefined) bypasses the cache entirely — identity is never guessed
39
+ * from content (ADR-022 rejected content hashing: byte-identical
40
+ * telemetry is routinely two real readings).
41
+ *
42
+ * Crash residue (accepted, per ADR-022): the cache is in-memory, so a
43
+ * crash between processing and acknowledging a message means its
44
+ * broker redelivery after restart is processed once more. At most one
45
+ * duplicate per source crash; disk-backed dedup state was rejected.
46
+ *
47
+ * ASSUMPTIONS
48
+ * -----------
49
+ * 1. A dedup id is unique per message and repeats only on a QoS-1
50
+ * retransmission (the emitter stamps UUIDs).
51
+ * 2. The clock moves forward at millisecond granularity. A backward
52
+ * clock jump can expire entries early or hold them one window too
53
+ * long — bounded either way, and self-healing within one window.
54
+ *
55
+ * LIMITATIONS
56
+ * -----------
57
+ * 1. In-memory: the cache dies with the process, so a duplicate
58
+ * arriving just after a restart may slip through. Deliberate
59
+ * (ADR-022 rejected disk-backed state); at most one per crash;
60
+ * QuestDB's at-rest dedup is the backstop.
61
+ * 2. At high rates the count cap binds before the time window: the
62
+ * effective window is maxEntries ÷ rate (the full 120 s up to
63
+ * about 550 msg/s at defaults; ~6.5 s at 10 k msg/s). Stated in
64
+ * ADR-022, not hidden.
65
+ * 3. Memory, measured (benchmark/mqtt-source/dedup-memory.js,
66
+ * 2026-07-09): 86 bytes per production-shaped id, ~6.7 MB worst
67
+ * case at the 65,536 cap including bounded V8 Set slack.
68
+ *
69
+ * @see ADR-022 - The full decision
70
+ */
71
+
72
+ import {
73
+ DEFAULT_DEDUP_WINDOW_MS,
74
+ DEFAULT_DEDUP_MAX_ENTRIES
75
+ } from './constants.js';
76
+
77
+ // ============================================================================
78
+ // VALIDATION HELPER
79
+ // ============================================================================
80
+
81
+ /**
82
+ * Throws a classified INVALID_CONFIG error (ADR-018 fail-fast setup)
83
+ * when `value` is not a positive integer.
84
+ *
85
+ * @param {*} value - Candidate value
86
+ * @param {string} name - Field name for the error message
87
+ */
88
+ const assertPositiveInteger = function ( value, name ) {
89
+ if ( typeof value !== 'number' || value < 1 || !Number.isInteger( value ) ) {
90
+ const err = new Error( `WinkComposer/mqtt-source: ${name} must be a positive integer` );
91
+ err.code = 'INVALID_CONFIG';
92
+ throw err;
93
+ }
94
+ };
95
+
96
+ // ============================================================================
97
+ // DEDUP CACHE FACTORY
98
+ // ============================================================================
99
+
100
+ /**
101
+ * Create a time-bounded, count-capped dedup cache.
102
+ *
103
+ * All hot-path operations are O(1) (expiry amortized): Set lookup,
104
+ * ring-slot insertion, head eviction.
105
+ *
106
+ * @param {Object} [options={}] - Cache options
107
+ * @param {number} [options.windowMs=120000] - Time bound: an entry
108
+ * expires once its age reaches this many milliseconds
109
+ * @param {number} [options.maxEntries=65536] - Count cap: the memory
110
+ * guarantee; the oldest entry is evicted when the ring is full
111
+ * @param {function} [options.nowFn=Date.now] - Clock source. Injection
112
+ * point for deterministic tests; production uses the default
113
+ * @returns {Object} Cache instance with isDuplicate, size, clear, has
114
+ */
115
+ const createDedupCache = function ( options = {} ) {
116
+ if ( typeof options !== 'object' || options === null ) {
117
+ const err = new Error( 'WinkComposer/mqtt-source: dedup options must be an object' );
118
+ err.code = 'INVALID_CONFIG';
119
+ throw err;
120
+ }
121
+
122
+ const {
123
+ windowMs = DEFAULT_DEDUP_WINDOW_MS,
124
+ maxEntries = DEFAULT_DEDUP_MAX_ENTRIES,
125
+ nowFn = Date.now
126
+ } = options;
127
+
128
+ assertPositiveInteger( windowMs, 'windowMs' );
129
+ assertPositiveInteger( maxEntries, 'maxEntries' );
130
+ if ( typeof nowFn !== 'function' ) {
131
+ const err = new Error( 'WinkComposer/mqtt-source: nowFn must be a function' );
132
+ err.code = 'INVALID_CONFIG';
133
+ throw err;
134
+ }
135
+
136
+ // Pre-allocated structures (zero allocation on the hot path).
137
+ const seen = new Set(); // O(1) duplicate lookup
138
+ const ids = new Array( maxEntries ); // Ring: dedup ids in arrival order
139
+ const stamps = new Float64Array( maxEntries ); // Ring: arrival timestamps
140
+ let head = 0; // Oldest live entry
141
+ let tail = 0; // Next insert slot
142
+ let count = 0; // Live entries
143
+
144
+ /**
145
+ * Evict the entry at the ring head. The slot is cleared so the id
146
+ * string is not retained after eviction.
147
+ */
148
+ const evictHead = function () {
149
+ seen.delete( ids[ head ] );
150
+ ids[ head ] = undefined;
151
+ head = ( head + 1 ) % maxEntries;
152
+ count -= 1;
153
+ };
154
+
155
+ /**
156
+ * Check whether dedupId was seen within the window. New ids are
157
+ * cached; expired and cap-evicted ids count as new again.
158
+ *
159
+ * @param {string|null|undefined} dedupId - Deduplication identifier
160
+ * @returns {boolean} true if duplicate (skip), false if new (process)
161
+ */
162
+ const isDuplicate = function ( dedupId ) {
163
+ // No dedup id → bypass: the message is processed verbatim and
164
+ // the cache is not touched (opt-in by construction, ADR-022).
165
+ if ( dedupId === null || dedupId === undefined ) {
166
+ return false;
167
+ }
168
+
169
+ const now = nowFn();
170
+
171
+ // Sweep expired entries from the head. Bounded by the live
172
+ // count so the loop provably terminates; each entry is evicted
173
+ // at most once, so the sweep is amortized O(1) per call.
174
+ const live = count;
175
+ for ( let i = 0; i < live; i += 1 ) {
176
+ if ( ( now - stamps[ head ] ) < windowMs ) {
177
+ break;
178
+ }
179
+ evictHead();
180
+ }
181
+
182
+ if ( seen.has( dedupId ) ) {
183
+ return true;
184
+ }
185
+
186
+ // Cap bound: a full ring evicts its oldest to admit the newest.
187
+ if ( count === maxEntries ) {
188
+ evictHead();
189
+ }
190
+
191
+ ids[ tail ] = dedupId;
192
+ stamps[ tail ] = now;
193
+ seen.add( dedupId );
194
+ tail = ( tail + 1 ) % maxEntries;
195
+ count += 1;
196
+
197
+ return false;
198
+ };
199
+
200
+ /**
201
+ * Get current number of cached entries.
202
+ *
203
+ * @returns {number} Number of live entries
204
+ */
205
+ const size = function () {
206
+ return count;
207
+ };
208
+
209
+ /**
210
+ * Clear all cached entries. Used for testing or reset.
211
+ */
212
+ const clear = function () {
213
+ seen.clear();
214
+ ids.fill( undefined );
215
+ stamps.fill( 0 );
216
+ head = 0;
217
+ tail = 0;
218
+ count = 0;
219
+ };
220
+
221
+ /**
222
+ * Check if dedupId is in cache without modifying it. Test helper —
223
+ * does not add, evict, or sweep.
224
+ *
225
+ * @param {string} dedupId - Deduplication identifier
226
+ * @returns {boolean} true if in cache, false otherwise
227
+ */
228
+ const has = function ( dedupId ) {
229
+ return seen.has( dedupId );
230
+ };
231
+
232
+ return {
233
+ isDuplicate,
234
+ size,
235
+ clear,
236
+ has
237
+ };
238
+ };
239
+
240
+ // ============================================================================
241
+ // EXPORTS
242
+ // ============================================================================
243
+
244
+ export { createDedupCache };
@@ -0,0 +1,260 @@
1
+ // core/source-manager/mqtt/index.js
2
+
3
+ /**
4
+ * @fileoverview MQTT source adapter for WinkComposer aggregator.
5
+ *
6
+ * Subscribes to edge composer MQTT outputs with deduplication for QoS 1.
7
+ * Extracts winkDedupId from MQTT v5 user properties to filter retransmissions.
8
+ *
9
+ * Adapter contract (ADR-018):
10
+ * - Module-level exports: `id`, `configSchema`, `start`,
11
+ * `durabilityClass`, and the default aggregate referencing the same
12
+ * constants.
13
+ * - `start( config )` returns a `stopFn({ timeout })`.
14
+ * - Lifecycle and error contract details: see `client.js` file header.
15
+ *
16
+ * Durability (ADR-018): `'broker-queue'` — the source connects with a
17
+ * persistent broker session (`cleanStart: false`), so while it is
18
+ * disconnected the broker holds every QoS-1 message published to its
19
+ * subscribed topics and replays them on reconnect. What the source has
20
+ * not yet acknowledged is not lost; the broker owns the queue.
21
+ *
22
+ * `configSchema` declares the user-supplied config fields. The flow
23
+ * runtime calls `validateWithSchema( mqtt.configSchema, sourceConfig )`
24
+ * at DSL time (in `flow.source()`), so typos and bad types are caught
25
+ * before the flow ever runs. Per ADR-018 the schema is authoritative
26
+ * for the fields it covers; `client.js` does not re-enforce them. The
27
+ * schema carries `_propertyNames`, so an unknown key (e.g. the typo
28
+ * `brokerURL`) is rejected at definition time.
29
+ *
30
+ * Runtime-injected callbacks (`onMessage`, `onShutdown`) are not part
31
+ * of `configSchema` — the wiring layer adds them to the config at start
32
+ * time, after DSL validation. A user-supplied `onMessage` would be
33
+ * silently overwritten; the unknown-key rejection turns that mistake
34
+ * into a fail-fast error instead.
35
+ *
36
+ * ASSUMPTIONS
37
+ * -----------
38
+ * 1. Inside a flow, the runtime injects `onMessage` / `onShutdown`
39
+ * and wraps `onStatus`; a direct caller of `start()` supplies
40
+ * `onMessage` itself and owns calling the returned stop function.
41
+ * 2. Config passed through the DSL was validated by this schema;
42
+ * `client.js` re-checks only the three fields a direct caller
43
+ * could omit (brokerUrl, topics, onMessage).
44
+ *
45
+ * LIMITATIONS
46
+ * -----------
47
+ * 1. This is an infinite source: it never emits `phase: 'complete'`,
48
+ * so a flow's `whenComplete()` resolves only via `shutdown()`.
49
+ * 2. Duplicate filtering is opt-in per message: only messages that
50
+ * carry `winkDedupId` are protected. Watch the `dedupBypassed`
51
+ * counter to spot publishers that are not stamping ids.
52
+ *
53
+ * Usage in flow:
54
+ * import mqtt from './core/source-manager/mqtt/index.js';
55
+ *
56
+ * flow( 'aggregator' )
57
+ * .source( mqtt, {
58
+ * brokerUrl: 'mqtt://broker:1883',
59
+ * topics: [ 'edge/+/enriched' ],
60
+ * codec: msgpackCodec,
61
+ * dedupWindowMs: 120000
62
+ * } )
63
+ *
64
+ * @see src/core/emitter-manager/mqtt/index.js - Emitter counterpart
65
+ */
66
+
67
+ import { validators } from '../../utils/validate/index.js';
68
+ import { createMQTTSourceClient } from './client.js';
69
+
70
+ // ============================================================================
71
+ // SOURCE ADAPTER
72
+ // ============================================================================
73
+
74
+ /**
75
+ * Source adapter identifier.
76
+ * Used by the flow runtime to reference this adapter.
77
+ *
78
+ * @type {string}
79
+ */
80
+ const id = 'mqtt';
81
+
82
+ /**
83
+ * Crash-survival class per ADR-018. For a source the value describes
84
+ * the INPUT it can recover after a disconnect: the persistent broker
85
+ * session holds subscribed QoS-1 messages across the gap and replays
86
+ * them on reconnect.
87
+ *
88
+ * @type {string}
89
+ */
90
+ const durabilityClass = 'broker-queue';
91
+
92
+ /**
93
+ * Validates that a value is a non-empty topic string or a non-empty
94
+ * array of non-empty topic strings.
95
+ *
96
+ * @param {*} value
97
+ * @returns {boolean}
98
+ */
99
+ const isTopicOrTopicArray = function ( value ) {
100
+ if ( typeof value === 'string' && value.length > 0 ) return true;
101
+ if ( Array.isArray( value ) && value.length > 0 ) {
102
+ return value.every( ( t ) => typeof t === 'string' && t.length > 0 );
103
+ }
104
+ return false;
105
+ };
106
+
107
+ /**
108
+ * Schema for the MQTT source's user-supplied config. Consumed by the
109
+ * flow runtime (`flow.source()` → `validateWithSchema`) at DSL time.
110
+ *
111
+ * Required:
112
+ * - `brokerUrl` — MQTT broker URL (e.g., 'mqtt://broker.local:1883').
113
+ * - `topics` — topic string or non-empty array of topic strings
114
+ * (wildcards supported).
115
+ *
116
+ * Optional:
117
+ * - `codec` — payload decoder with an `unpack( buffer )` function.
118
+ * Default: JSON.parse of the payload.
119
+ * - `transform` — function( msg ) → msg, applied before `onMessage`;
120
+ * returning null/undefined drops the message (counted in `skipped`).
121
+ * A throw skips that one message with a per-record CALLBACK_FAILED
122
+ * report and the stream continues. Uniform with the CSV source.
123
+ * - `dedupWindowMs` — dedup time bound: a duplicate arriving within
124
+ * this many milliseconds of its original is dropped. Default 120000
125
+ * (ADR-022).
126
+ * - `dedupMaxEntries` — dedup count cap: the memory guarantee (~8 MB
127
+ * worst case at the default 65536). At high rates the effective
128
+ * window is maxEntries ÷ rate — see ADR-022.
129
+ * - `clientId` — MQTT client ID. Auto-generated when omitted.
130
+ * - `cleanStart` — override the persistent-session default (false).
131
+ * - `onStatus` — status callback. Receives the structured ADR-018
132
+ * status payload on every transition and per decode failure — the full
133
+ * vocabulary is documented in `client.js`.
134
+ * - `onMetrics` — counter-snapshot callback, ~1 Hz plus on every
135
+ * health transition (delivered, skipped, decodeErrors, reconnects,
136
+ * dedupHits, dedupMisses, dedupBypassed, dedupCacheSize).
137
+ * - `expectedQuietPeriodMs` — opt-in quiet rule: health goes yellow
138
+ * when no packet arrives for longer than this many milliseconds.
139
+ * Off when omitted (silence is normal for many sources).
140
+ * - `mqttConnectFn` — MQTT connect function injection point (tests,
141
+ * benchmarks).
142
+ *
143
+ * `_propertyNames` lists every accepted key — unknown keys throw at
144
+ * DSL time (the validator's only unknown-key mechanism).
145
+ *
146
+ * @type {Object}
147
+ */
148
+ const configSchema = {
149
+ _propertyNames: [
150
+ 'brokerUrl',
151
+ 'topics',
152
+ 'codec',
153
+ 'transform',
154
+ 'dedupWindowMs',
155
+ 'dedupMaxEntries',
156
+ 'clientId',
157
+ 'cleanStart',
158
+ 'onStatus',
159
+ 'onMetrics',
160
+ 'expectedQuietPeriodMs',
161
+ 'mqttConnectFn'
162
+ ],
163
+ brokerUrl: {
164
+ type: 'string',
165
+ required: true,
166
+ validator: validators.nonEmptyString,
167
+ error: 'brokerUrl must be a non-empty string (e.g., mqtt://broker.local:1883)'
168
+ },
169
+ topics: {
170
+ required: true,
171
+ validator: isTopicOrTopicArray,
172
+ error: 'topics must be a non-empty string or a non-empty array of non-empty strings'
173
+ },
174
+ codec: {
175
+ type: 'object',
176
+ required: false,
177
+ validator: ( v ) => v !== null && typeof v.unpack === 'function',
178
+ error: 'codec must be an object with an unpack() function'
179
+ },
180
+ transform: {
181
+ type: 'function',
182
+ required: false,
183
+ error: 'transform must be a function( msg ) returning a msg (or null/undefined to drop)'
184
+ },
185
+ dedupWindowMs: {
186
+ type: 'number',
187
+ required: false,
188
+ validator: validators.positiveInteger,
189
+ error: 'dedupWindowMs must be a positive integer (milliseconds; default 120000)'
190
+ },
191
+ dedupMaxEntries: {
192
+ type: 'number',
193
+ required: false,
194
+ validator: validators.positiveInteger,
195
+ error: 'dedupMaxEntries must be a positive integer (default 65536)'
196
+ },
197
+ clientId: {
198
+ type: 'string',
199
+ required: false,
200
+ validator: validators.noSpaces,
201
+ error: 'clientId must be a string without spaces'
202
+ },
203
+ cleanStart: {
204
+ type: 'boolean',
205
+ required: false,
206
+ error: 'cleanStart must be a boolean'
207
+ },
208
+ onStatus: {
209
+ type: 'function',
210
+ required: false,
211
+ error: 'onStatus must be a function'
212
+ },
213
+ onMetrics: {
214
+ type: 'function',
215
+ required: false,
216
+ error: 'onMetrics must be a function'
217
+ },
218
+ expectedQuietPeriodMs: {
219
+ type: 'number',
220
+ required: false,
221
+ validator: validators.positiveInteger,
222
+ error: 'expectedQuietPeriodMs must be a positive integer (milliseconds)'
223
+ },
224
+ mqttConnectFn: {
225
+ type: 'function',
226
+ required: false,
227
+ error: 'mqttConnectFn must be a function (test/benchmark injection point)'
228
+ }
229
+ };
230
+
231
+ /**
232
+ * Start the MQTT source.
233
+ *
234
+ * Called by the flow runtime (flow/run.js) with config from flow DSL.
235
+ * Returns a stop function for graceful shutdown.
236
+ *
237
+ * @param {Object} config - Source configuration
238
+ * @param {string} config.brokerUrl - MQTT broker URL
239
+ * @param {string|string[]} config.topics - Topic(s) to subscribe to
240
+ * @param {function} config.onMessage - Message handler (injected by the flow runtime)
241
+ * @param {Object} [config.codec] - Codec for payload decoding
242
+ * @param {function} [config.transform] - Optional message transform
243
+ * @param {number} [config.dedupWindowMs=120000] - Dedup time bound (ADR-022)
244
+ * @param {number} [config.dedupMaxEntries=65536] - Dedup count cap (ADR-022)
245
+ * @param {string} [config.clientId] - MQTT client ID
246
+ * @param {function} [config.onStatus] - Structured status callback (ADR-018)
247
+ * @param {function} [config.onMetrics] - Counter-snapshot callback (~1 Hz + transitions)
248
+ * @param {number} [config.expectedQuietPeriodMs] - Opt-in quiet rule threshold
249
+ * @returns {function} Stop function that returns a Promise
250
+ */
251
+ const start = function ( config ) {
252
+ return createMQTTSourceClient( config );
253
+ };
254
+
255
+ // ============================================================================
256
+ // EXPORTS
257
+ // ============================================================================
258
+
259
+ export { id, configSchema, durabilityClass, start };
260
+ export default { id, configSchema, durabilityClass, start };