@winkjs/composer 0.0.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +106 -80
  3. package/package.json +56 -28
  4. package/src/composer.js +75 -0
  5. package/src/core/batch/aoo-encoder.js +148 -0
  6. package/src/core/batch/index.js +12 -0
  7. package/src/core/batch/sliding-window.js +91 -0
  8. package/src/core/codec/index.js +137 -0
  9. package/src/core/emitter-manager/mqtt/constants.js +102 -0
  10. package/src/core/emitter-manager/mqtt/emitter.js +780 -0
  11. package/src/core/emitter-manager/mqtt/index.js +190 -0
  12. package/src/core/emitter-manager/mqtt/mqtt-store.js +538 -0
  13. package/src/core/emitter-manager/terminal/assert-columns.js +98 -0
  14. package/src/core/emitter-manager/terminal/formatters.js +160 -0
  15. package/src/core/emitter-manager/terminal/index.js +341 -0
  16. package/src/core/env-vars.js +245 -0
  17. package/src/core/mqtt-protocol.js +47 -0
  18. package/src/core/partition-manager/index.js +7 -0
  19. package/src/core/partition-manager/init.js +44 -0
  20. package/src/core/partition-manager/introspect.js +15 -0
  21. package/src/core/partition-manager/publish-to.js +6 -0
  22. package/src/core/partition-manager/recompute.js +5 -0
  23. package/src/core/partition-manager/reset.js +5 -0
  24. package/src/core/partition-manager/update.js +264 -0
  25. package/src/core/partition-manager/validate-flow.js +157 -0
  26. package/src/core/semantics/digest.js +128 -0
  27. package/src/core/semantics/index.js +83 -0
  28. package/src/core/semantics/loader.js +571 -0
  29. package/src/core/semantics/schemas/asset-class-schema.js +218 -0
  30. package/src/core/semantics/schemas/column-schema.js +651 -0
  31. package/src/core/semantics/schemas/enum-schema.js +153 -0
  32. package/src/core/semantics/schemas/index.js +51 -0
  33. package/src/core/semantics/warnings.js +141 -0
  34. package/src/core/shutdown-manager/index.js +289 -0
  35. package/src/core/source-manager/csv/index.js +171 -0
  36. package/src/core/source-manager/csv/start.js +456 -0
  37. package/src/core/source-manager/mqtt/client.js +406 -0
  38. package/src/core/source-manager/mqtt/constants.js +147 -0
  39. package/src/core/source-manager/mqtt/dedup.js +244 -0
  40. package/src/core/source-manager/mqtt/index.js +260 -0
  41. package/src/core/source-manager/mqtt/status.js +546 -0
  42. package/src/core/source-manager/test-harness/comparator.js +226 -0
  43. package/src/core/source-manager/test-harness/field-generator.js +85 -0
  44. package/src/core/source-manager/test-harness/fuzz.js +87 -0
  45. package/src/core/source-manager/test-harness/index.js +115 -0
  46. package/src/core/source-manager/test-harness/prng.js +57 -0
  47. package/src/core/source-manager/test-harness/start.js +232 -0
  48. package/src/core/source-manager/test-harness/validate.js +213 -0
  49. package/src/core/storage-manager/questdb/assert-columns.js +120 -0
  50. package/src/core/storage-manager/questdb/ensure-tables.js +187 -0
  51. package/src/core/storage-manager/questdb/index.js +1251 -0
  52. package/src/core/storage-manager/questdb/persist-plan.js +488 -0
  53. package/src/core/storage-manager/questdb/writers.js +142 -0
  54. package/src/core/test-utils/sealed-record.js +80 -0
  55. package/src/core/test-utils/soak-signature.js +149 -0
  56. package/src/core/test-utils/tcp-proxy.js +106 -0
  57. package/src/core/tunable/helpers.js +254 -0
  58. package/src/core/tunable/index.js +87 -0
  59. package/src/core/utils/console-formatter/index.js +207 -0
  60. package/src/core/utils/create-smart-store-as/index.js +98 -0
  61. package/src/core/utils/create-smart-store-as/sanitize-field.js +46 -0
  62. package/src/core/utils/create-smart-store-as/smart-truncate.js +93 -0
  63. package/src/core/utils/flow/index.js +5 -0
  64. package/src/core/utils/flow/make-collision-checker.js +23 -0
  65. package/src/core/utils/flow/to-kebab.js +20 -0
  66. package/src/core/utils/half-life/index.js +111 -0
  67. package/src/core/utils/node/disable.js +11 -0
  68. package/src/core/utils/node/enable.js +11 -0
  69. package/src/core/utils/node/execute-triggers.js +40 -0
  70. package/src/core/utils/node/index.js +10 -0
  71. package/src/core/utils/node/pause.js +11 -0
  72. package/src/core/utils/node/populate-predicate-inputs.js +14 -0
  73. package/src/core/utils/node/publish-nan.js +19 -0
  74. package/src/core/utils/node/reset-predicate-inputs.js +11 -0
  75. package/src/core/utils/node/unpause.js +11 -0
  76. package/src/core/utils/node/validate-spec.js +22 -0
  77. package/src/core/utils/options/resolve-field-keyed.js +115 -0
  78. package/src/core/utils/quantize/index.js +75 -0
  79. package/src/core/utils/stats/formulas.js +67 -0
  80. package/src/core/utils/stats/index.js +3 -0
  81. package/src/core/utils/validate/composer-validators.js +141 -0
  82. package/src/core/utils/validate/helpers.js +206 -0
  83. package/src/core/utils/validate/index.js +12 -0
  84. package/src/core/utils/validate/type-validators.js +538 -0
  85. package/src/core/utils/validate/validate.js +107 -0
  86. package/src/core/utils/validate/validators.js +177 -0
  87. package/src/core/wiring/assert-handle.js +57 -0
  88. package/src/core/wiring/assert-module.js +63 -0
  89. package/src/core/wiring/index.js +5 -0
  90. package/src/core/wiring/node-type-to-module.js +17 -0
  91. package/src/core/wiring/wire-emitters.js +256 -0
  92. package/src/core/wiring/wire-linear-graph.js +25 -0
  93. package/src/core/wiring/wire-node.js +157 -0
  94. package/src/core/wiring/wire-semantics.js +173 -0
  95. package/src/core/wiring/wire-storages.js +344 -0
  96. package/src/flow/check-output-collisions.js +93 -0
  97. package/src/flow/consts.js +9 -0
  98. package/src/flow/deep-clone-spec.js +64 -0
  99. package/src/flow/driver.js +171 -0
  100. package/src/flow/expand-single-input-array.js +76 -0
  101. package/src/flow/expand-template-spec.js +93 -0
  102. package/src/flow/flow-api-schemas.js +300 -0
  103. package/src/flow/flow.js +658 -0
  104. package/src/flow/for-each.js +225 -0
  105. package/src/flow/get-signature-pattern.js +31 -0
  106. package/src/flow/get-target-array.js +46 -0
  107. package/src/flow/inspect.js +67 -0
  108. package/src/flow/load-node-module.js +81 -0
  109. package/src/flow/make-node-method.js +112 -0
  110. package/src/flow/resolve-pick-by-field.js +77 -0
  111. package/src/flow/resolve-tunables.js +76 -0
  112. package/src/flow/run.js +392 -0
  113. package/src/flow/serialize.js +161 -0
  114. package/src/flow/signatures-schema.js +222 -0
  115. package/src/flow/spec-builder.js +65 -0
  116. package/src/flow/validate-triggers.js +250 -0
  117. package/src/flow/validate.js +261 -0
  118. package/src/nodes/accumulate/index.js +21 -0
  119. package/src/nodes/accumulate/init.js +48 -0
  120. package/src/nodes/accumulate/introspect.js +123 -0
  121. package/src/nodes/accumulate/publish-to.js +34 -0
  122. package/src/nodes/accumulate/recompute.js +27 -0
  123. package/src/nodes/accumulate/reset.js +25 -0
  124. package/src/nodes/accumulate/update.js +42 -0
  125. package/src/nodes/appraise/calibrate.js +64 -0
  126. package/src/nodes/appraise/decision.js +66 -0
  127. package/src/nodes/appraise/deviation.js +140 -0
  128. package/src/nodes/appraise/index.js +23 -0
  129. package/src/nodes/appraise/init.js +165 -0
  130. package/src/nodes/appraise/integrate.js +45 -0
  131. package/src/nodes/appraise/introspect.js +352 -0
  132. package/src/nodes/appraise/publish-to.js +93 -0
  133. package/src/nodes/appraise/receptor.js +69 -0
  134. package/src/nodes/appraise/recompute.js +79 -0
  135. package/src/nodes/appraise/reset.js +53 -0
  136. package/src/nodes/appraise/update.js +130 -0
  137. package/src/nodes/archive/csv/index.js +6 -0
  138. package/src/nodes/archive/csv/init.js +36 -0
  139. package/src/nodes/archive/csv/load.js +70 -0
  140. package/src/nodes/archive/csv/reset.js +14 -0
  141. package/src/nodes/archive/csv/simple-parser.js +216 -0
  142. package/src/nodes/archive/csv/test.js +173 -0
  143. package/src/nodes/archive/csv/update.js +63 -0
  144. package/src/nodes/butterworth-filter/index.js +18 -0
  145. package/src/nodes/butterworth-filter/init.js +184 -0
  146. package/src/nodes/butterworth-filter/introspect.js +228 -0
  147. package/src/nodes/butterworth-filter/publish-to.js +21 -0
  148. package/src/nodes/butterworth-filter/recompute.js +13 -0
  149. package/src/nodes/butterworth-filter/reset.js +30 -0
  150. package/src/nodes/butterworth-filter/update.js +38 -0
  151. package/src/nodes/categorize/index.js +19 -0
  152. package/src/nodes/categorize/init.js +58 -0
  153. package/src/nodes/categorize/introspect.js +177 -0
  154. package/src/nodes/categorize/publish-to.js +29 -0
  155. package/src/nodes/categorize/recompute.js +14 -0
  156. package/src/nodes/categorize/reset.js +16 -0
  157. package/src/nodes/categorize/update.js +53 -0
  158. package/src/nodes/controller/index.js +9 -0
  159. package/src/nodes/controller/init.js +55 -0
  160. package/src/nodes/controller/introspect.js +91 -0
  161. package/src/nodes/controller/publish-to.js +8 -0
  162. package/src/nodes/controller/recompute.js +9 -0
  163. package/src/nodes/controller/reset.js +17 -0
  164. package/src/nodes/controller/update.js +63 -0
  165. package/src/nodes/diff/index.js +19 -0
  166. package/src/nodes/diff/init.js +37 -0
  167. package/src/nodes/diff/introspect.js +132 -0
  168. package/src/nodes/diff/publish-to.js +21 -0
  169. package/src/nodes/diff/recompute.js +12 -0
  170. package/src/nodes/diff/reset.js +12 -0
  171. package/src/nodes/diff/update.js +37 -0
  172. package/src/nodes/digest-moments/formulas.js +12 -0
  173. package/src/nodes/digest-moments/index.js +14 -0
  174. package/src/nodes/digest-moments/init.js +67 -0
  175. package/src/nodes/digest-moments/introspect.js +154 -0
  176. package/src/nodes/digest-moments/publish-to.js +34 -0
  177. package/src/nodes/digest-moments/recompute.js +14 -0
  178. package/src/nodes/digest-moments/reset.js +14 -0
  179. package/src/nodes/digest-moments/update.js +120 -0
  180. package/src/nodes/dwell-time-tracker/index.js +14 -0
  181. package/src/nodes/dwell-time-tracker/init.js +59 -0
  182. package/src/nodes/dwell-time-tracker/introspect.js +137 -0
  183. package/src/nodes/dwell-time-tracker/publish-to.js +22 -0
  184. package/src/nodes/dwell-time-tracker/recompute.js +8 -0
  185. package/src/nodes/dwell-time-tracker/reset.js +23 -0
  186. package/src/nodes/dwell-time-tracker/update.js +103 -0
  187. package/src/nodes/emit-if/helpers.js +94 -0
  188. package/src/nodes/emit-if/index.js +16 -0
  189. package/src/nodes/emit-if/init.js +67 -0
  190. package/src/nodes/emit-if/introspect.js +102 -0
  191. package/src/nodes/emit-if/publish-to.js +13 -0
  192. package/src/nodes/emit-if/recompute.js +12 -0
  193. package/src/nodes/emit-if/reset.js +27 -0
  194. package/src/nodes/emit-if/update.js +93 -0
  195. package/src/nodes/es-correlation/index.js +19 -0
  196. package/src/nodes/es-correlation/init.js +73 -0
  197. package/src/nodes/es-correlation/introspect.js +176 -0
  198. package/src/nodes/es-correlation/publish-to.js +32 -0
  199. package/src/nodes/es-correlation/recompute.js +56 -0
  200. package/src/nodes/es-correlation/reset.js +27 -0
  201. package/src/nodes/es-correlation/update.js +110 -0
  202. package/src/nodes/es-mean/index.js +20 -0
  203. package/src/nodes/es-mean/init.js +58 -0
  204. package/src/nodes/es-mean/introspect.js +129 -0
  205. package/src/nodes/es-mean/publish-to.js +19 -0
  206. package/src/nodes/es-mean/recompute.js +16 -0
  207. package/src/nodes/es-mean/reset.js +24 -0
  208. package/src/nodes/es-mean/update.js +69 -0
  209. package/src/nodes/es-pairwise-correlation/index.js +19 -0
  210. package/src/nodes/es-pairwise-correlation/init.js +98 -0
  211. package/src/nodes/es-pairwise-correlation/introspect.js +187 -0
  212. package/src/nodes/es-pairwise-correlation/publish-to.js +31 -0
  213. package/src/nodes/es-pairwise-correlation/recompute.js +69 -0
  214. package/src/nodes/es-pairwise-correlation/reset.js +29 -0
  215. package/src/nodes/es-pairwise-correlation/update.js +89 -0
  216. package/src/nodes/es-stats/index.js +21 -0
  217. package/src/nodes/es-stats/init.js +105 -0
  218. package/src/nodes/es-stats/introspect.js +157 -0
  219. package/src/nodes/es-stats/publish-to.js +42 -0
  220. package/src/nodes/es-stats/recompute.js +74 -0
  221. package/src/nodes/es-stats/reset.js +49 -0
  222. package/src/nodes/es-stats/update-envelope.js +44 -0
  223. package/src/nodes/es-stats/update-welford.js +64 -0
  224. package/src/nodes/es-stats/update.js +59 -0
  225. package/src/nodes/index.js +83 -0
  226. package/src/nodes/invert-flag/index.js +20 -0
  227. package/src/nodes/invert-flag/init.js +36 -0
  228. package/src/nodes/invert-flag/introspect.js +115 -0
  229. package/src/nodes/invert-flag/publish-to.js +23 -0
  230. package/src/nodes/invert-flag/recompute.js +12 -0
  231. package/src/nodes/invert-flag/reset.js +12 -0
  232. package/src/nodes/invert-flag/update.js +32 -0
  233. package/src/nodes/kalman1d/index.js +20 -0
  234. package/src/nodes/kalman1d/init.js +103 -0
  235. package/src/nodes/kalman1d/introspect.js +250 -0
  236. package/src/nodes/kalman1d/publish-to.js +34 -0
  237. package/src/nodes/kalman1d/recompute.js +23 -0
  238. package/src/nodes/kalman1d/reset.js +29 -0
  239. package/src/nodes/kalman1d/update.js +144 -0
  240. package/src/nodes/kernel/index.js +18 -0
  241. package/src/nodes/kernel/init.js +66 -0
  242. package/src/nodes/kernel/introspect.js +163 -0
  243. package/src/nodes/kernel/presets.js +74 -0
  244. package/src/nodes/kernel/publish-to.js +25 -0
  245. package/src/nodes/kernel/recompute.js +14 -0
  246. package/src/nodes/kernel/reset.js +20 -0
  247. package/src/nodes/kernel/update.js +69 -0
  248. package/src/nodes/lag/index.js +21 -0
  249. package/src/nodes/lag/init.js +87 -0
  250. package/src/nodes/lag/introspect.js +202 -0
  251. package/src/nodes/lag/publish-to.js +64 -0
  252. package/src/nodes/lag/recompute.js +33 -0
  253. package/src/nodes/lag/reset.js +49 -0
  254. package/src/nodes/lag/update.js +133 -0
  255. package/src/nodes/median3/index.js +19 -0
  256. package/src/nodes/median3/init.js +40 -0
  257. package/src/nodes/median3/introspect.js +116 -0
  258. package/src/nodes/median3/publish-to.js +21 -0
  259. package/src/nodes/median3/recompute.js +12 -0
  260. package/src/nodes/median3/reset.js +15 -0
  261. package/src/nodes/median3/update.js +58 -0
  262. package/src/nodes/moments-digest/copy-from.js +12 -0
  263. package/src/nodes/moments-digest/flush.js +17 -0
  264. package/src/nodes/moments-digest/index.js +132 -0
  265. package/src/nodes/moments-digest/init.js +84 -0
  266. package/src/nodes/moments-digest/introspect.js +122 -0
  267. package/src/nodes/moments-digest/prelude.js +28 -0
  268. package/src/nodes/moments-digest/publish-to.js +31 -0
  269. package/src/nodes/moments-digest/recompute.js +9 -0
  270. package/src/nodes/moments-digest/reset.js +20 -0
  271. package/src/nodes/moments-digest/update.js +182 -0
  272. package/src/nodes/node-names.js +67 -0
  273. package/src/nodes/page-hinkley/index.js +20 -0
  274. package/src/nodes/page-hinkley/init.js +66 -0
  275. package/src/nodes/page-hinkley/introspect.js +193 -0
  276. package/src/nodes/page-hinkley/publish-to.js +28 -0
  277. package/src/nodes/page-hinkley/recompute.js +14 -0
  278. package/src/nodes/page-hinkley/reset.js +23 -0
  279. package/src/nodes/page-hinkley/update.js +105 -0
  280. package/src/nodes/pass-if/index.js +21 -0
  281. package/src/nodes/pass-if/init.js +37 -0
  282. package/src/nodes/pass-if/introspect.js +93 -0
  283. package/src/nodes/pass-if/publish-to.js +15 -0
  284. package/src/nodes/pass-if/recompute.js +15 -0
  285. package/src/nodes/pass-if/reset.js +18 -0
  286. package/src/nodes/pass-if/update.js +37 -0
  287. package/src/nodes/persist-if/helpers.js +111 -0
  288. package/src/nodes/persist-if/index.js +9 -0
  289. package/src/nodes/persist-if/init.js +98 -0
  290. package/src/nodes/persist-if/introspect.js +106 -0
  291. package/src/nodes/persist-if/publish-to.js +21 -0
  292. package/src/nodes/persist-if/recompute.js +20 -0
  293. package/src/nodes/persist-if/reset.js +35 -0
  294. package/src/nodes/persist-if/update.js +112 -0
  295. package/src/nodes/persistence-check/index.js +14 -0
  296. package/src/nodes/persistence-check/init.js +38 -0
  297. package/src/nodes/persistence-check/introspect.js +144 -0
  298. package/src/nodes/persistence-check/publish-to.js +11 -0
  299. package/src/nodes/persistence-check/recompute.js +7 -0
  300. package/src/nodes/persistence-check/reset.js +12 -0
  301. package/src/nodes/persistence-check/update.js +57 -0
  302. package/src/nodes/process-index/index.js +15 -0
  303. package/src/nodes/process-index/init.js +48 -0
  304. package/src/nodes/process-index/introspect.js +182 -0
  305. package/src/nodes/process-index/publish-to.js +29 -0
  306. package/src/nodes/process-index/recompute.js +8 -0
  307. package/src/nodes/process-index/reset.js +8 -0
  308. package/src/nodes/process-index/update.js +75 -0
  309. package/src/nodes/ratio/index.js +14 -0
  310. package/src/nodes/ratio/init.js +37 -0
  311. package/src/nodes/ratio/introspect.js +155 -0
  312. package/src/nodes/ratio/publish-to.js +15 -0
  313. package/src/nodes/ratio/recompute.js +7 -0
  314. package/src/nodes/ratio/reset.js +7 -0
  315. package/src/nodes/ratio/update.js +47 -0
  316. package/src/nodes/sanitize/index.js +82 -0
  317. package/src/nodes/sanitize/init.js +82 -0
  318. package/src/nodes/sanitize/introspect.js +194 -0
  319. package/src/nodes/sanitize/publish-to.js +15 -0
  320. package/src/nodes/sanitize/recompute.js +8 -0
  321. package/src/nodes/sanitize/reset.js +14 -0
  322. package/src/nodes/sanitize/update.js +102 -0
  323. package/src/nodes/spike-guard/index.js +14 -0
  324. package/src/nodes/spike-guard/init.js +47 -0
  325. package/src/nodes/spike-guard/introspect.js +130 -0
  326. package/src/nodes/spike-guard/publish-to.js +35 -0
  327. package/src/nodes/spike-guard/recompute.js +14 -0
  328. package/src/nodes/spike-guard/reset.js +19 -0
  329. package/src/nodes/spike-guard/update.js +89 -0
  330. package/src/nodes/sse-emitter/index.js +7 -0
  331. package/src/nodes/sse-emitter/init.js +105 -0
  332. package/src/nodes/sse-emitter/introspect.js +134 -0
  333. package/src/nodes/sse-emitter/publish-to.js +6 -0
  334. package/src/nodes/sse-emitter/recompute.js +16 -0
  335. package/src/nodes/sse-emitter/reset.js +19 -0
  336. package/src/nodes/sse-emitter/update.js +69 -0
  337. package/src/nodes/sse-emitter/utils/broadcast-heartbeat.js +36 -0
  338. package/src/nodes/sse-emitter/utils/build-message.js +31 -0
  339. package/src/nodes/sse-emitter/utils/connection-manager.js +45 -0
  340. package/src/nodes/sse-emitter/utils/endpoint-initializer.js +20 -0
  341. package/src/nodes/sse-emitter/utils/health-monitor.js +38 -0
  342. package/src/nodes/sse-emitter/utils/qos-handler.js +41 -0
  343. package/src/nodes/state-change-detector/helpers.js +35 -0
  344. package/src/nodes/state-change-detector/index.js +12 -0
  345. package/src/nodes/state-change-detector/init.js +56 -0
  346. package/src/nodes/state-change-detector/introspect.js +146 -0
  347. package/src/nodes/state-change-detector/publish-to.js +20 -0
  348. package/src/nodes/state-change-detector/recompute.js +6 -0
  349. package/src/nodes/state-change-detector/reset.js +20 -0
  350. package/src/nodes/state-change-detector/update.js +97 -0
  351. package/src/nodes/sw-stats/index.js +14 -0
  352. package/src/nodes/sw-stats/init.js +51 -0
  353. package/src/nodes/sw-stats/introspect.js +131 -0
  354. package/src/nodes/sw-stats/publish-to.js +45 -0
  355. package/src/nodes/sw-stats/recompute.js +33 -0
  356. package/src/nodes/sw-stats/reset.js +15 -0
  357. package/src/nodes/sw-stats/update.js +39 -0
  358. package/src/nodes/swing-watch/index.js +17 -0
  359. package/src/nodes/swing-watch/init.js +144 -0
  360. package/src/nodes/swing-watch/introspect.js +188 -0
  361. package/src/nodes/swing-watch/publish-to.js +53 -0
  362. package/src/nodes/swing-watch/recompute.js +22 -0
  363. package/src/nodes/swing-watch/reset.js +55 -0
  364. package/src/nodes/swing-watch/update.js +767 -0
  365. package/src/nodes/tally/index.js +15 -0
  366. package/src/nodes/tally/init.js +32 -0
  367. package/src/nodes/tally/introspect.js +116 -0
  368. package/src/nodes/tally/publish-to.js +28 -0
  369. package/src/nodes/tally/recompute.js +10 -0
  370. package/src/nodes/tally/reset.js +10 -0
  371. package/src/nodes/tally/update.js +44 -0
  372. package/src/nodes/threshold/index.js +14 -0
  373. package/src/nodes/threshold/init.js +121 -0
  374. package/src/nodes/threshold/introspect.js +192 -0
  375. package/src/nodes/threshold/publish-to.js +11 -0
  376. package/src/nodes/threshold/recompute.js +8 -0
  377. package/src/nodes/threshold/reset.js +14 -0
  378. package/src/nodes/threshold/update.js +54 -0
  379. package/src/nodes/transform/helpers.js +39 -0
  380. package/src/nodes/transform/index.js +15 -0
  381. package/src/nodes/transform/init.js +35 -0
  382. package/src/nodes/transform/introspect.js +118 -0
  383. package/src/nodes/transform/publish-to.js +23 -0
  384. package/src/nodes/transform/recompute.js +12 -0
  385. package/src/nodes/transform/reset.js +11 -0
  386. package/src/nodes/transform/update.js +32 -0
  387. package/src/nodes/trend/compute-confidence.js +112 -0
  388. package/src/nodes/trend/index.js +14 -0
  389. package/src/nodes/trend/init.js +81 -0
  390. package/src/nodes/trend/introspect.js +151 -0
  391. package/src/nodes/trend/publish-to.js +22 -0
  392. package/src/nodes/trend/recompute.js +15 -0
  393. package/src/nodes/trend/reset.js +26 -0
  394. package/src/nodes/trend/update.js +93 -0
  395. package/src/nodes/tw-stats/copy-from.js +16 -0
  396. package/src/nodes/tw-stats/flush.js +12 -0
  397. package/src/nodes/tw-stats/index.js +41 -0
  398. package/src/nodes/tw-stats/init.js +92 -0
  399. package/src/nodes/tw-stats/introspect.js +171 -0
  400. package/src/nodes/tw-stats/publish-to.js +108 -0
  401. package/src/nodes/tw-stats/recompute.js +9 -0
  402. package/src/nodes/tw-stats/reset.js +16 -0
  403. package/src/nodes/tw-stats/update.js +113 -0
  404. package/src/nodes/unbalance/index.js +15 -0
  405. package/src/nodes/unbalance/init.js +59 -0
  406. package/src/nodes/unbalance/introspect.js +167 -0
  407. package/src/nodes/unbalance/publish-to.js +52 -0
  408. package/src/nodes/unbalance/recompute.js +11 -0
  409. package/src/nodes/unbalance/reset.js +10 -0
  410. package/src/nodes/unbalance/update.js +83 -0
  411. package/src/nodes/vector-distance/index.js +14 -0
  412. package/src/nodes/vector-distance/init.js +54 -0
  413. package/src/nodes/vector-distance/introspect.js +149 -0
  414. package/src/nodes/vector-distance/publish-to.js +35 -0
  415. package/src/nodes/vector-distance/recompute.js +11 -0
  416. package/src/nodes/vector-distance/reset.js +20 -0
  417. package/src/nodes/vector-distance/update.js +139 -0
  418. package/src/nodes/winnow/index.js +12 -0
  419. package/src/nodes/winnow/init.js +82 -0
  420. package/src/nodes/winnow/introspect.js +253 -0
  421. package/src/nodes/winnow/publish-to.js +51 -0
  422. package/src/nodes/winnow/recompute.js +14 -0
  423. package/src/nodes/winnow/reset.js +34 -0
  424. package/src/nodes/winnow/update.js +203 -0
  425. package/src/tools/training/features.js +227 -0
  426. package/src/tools/training/index.js +21 -0
  427. package/src/tools/training/logistic.js +238 -0
  428. package/src/tools/training/metrics.js +126 -0
  429. package/src/tools/training/scale.js +239 -0
  430. package/src/tools/training/validate.js +103 -0
  431. package/src/windowing/count-sliding/create.js +16 -0
  432. package/src/windowing/count-sliding/get-reverse-chronological-index.js +19 -0
  433. package/src/windowing/count-sliding/index.js +6 -0
  434. package/src/windowing/count-sliding/is-not-full.js +5 -0
  435. package/src/windowing/count-sliding/push.js +15 -0
  436. package/src/windowing/count-sliding/reset.js +11 -0
  437. package/src/windowing/count-sliding/size.js +5 -0
  438. package/src/windowing/time-sliding/create.js +25 -0
  439. package/src/windowing/time-sliding/push.js +42 -0
  440. package/CODE_OF_CONDUCT.md +0 -46
  441. package/CONTRIBUTING.md +0 -132
  442. package/docs/.nojekyll +0 -0
  443. package/docs/CONTRIBUTING.md +0 -134
  444. package/docs/README.md +0 -132
  445. package/docs/_coverpage.md +0 -26
  446. package/docs/_media/bg.png +0 -0
  447. package/docs/_media/wink-logo.png +0 -0
  448. package/docs/_navbar.md +0 -14
  449. package/docs/_sidebar.md +0 -2
  450. package/docs/index.html +0 -44
  451. package/eslint.config.js +0 -283
@@ -0,0 +1,153 @@
1
+ // core/semantics/schemas/enum-schema.js
2
+
3
+ /**
4
+ * @fileoverview Enum Schema Definition
5
+ *
6
+ * Defines the validation schema for enum files used in semantics.
7
+ * Enums provide human-readable labels for column values of any type.
8
+ *
9
+ * Supported key types (as strings, no whitespace):
10
+ * - Numeric: "0", "1", "-1", "3.14" (for int64/float64 columns)
11
+ * - Boolean: "true", "false" (for bool columns like isWashing)
12
+ * - Text codes: "R", "G", "B", "idle" (for string columns)
13
+ *
14
+ * Example enum files:
15
+ *
16
+ * Numeric states:
17
+ * {
18
+ * "name": "machineState",
19
+ * "values": { "0": "Idle", "1": "Running", "2": "Error" }
20
+ * }
21
+ *
22
+ * Boolean states (e.g., for isWashing column):
23
+ * {
24
+ * "name": "washingState",
25
+ * "values": { "true": "Washing", "false": "Idle" }
26
+ * }
27
+ *
28
+ * Text codes:
29
+ * {
30
+ * "name": "colorCodes",
31
+ * "values": { "R": "Red", "G": "Green", "B": "Blue" }
32
+ * }
33
+ */
34
+
35
+ import { validators } from '../../utils/validate/index.js';
36
+
37
+ // ============================================================================
38
+ // CUSTOM VALIDATORS
39
+ // ============================================================================
40
+
41
+ /**
42
+ * Validates a single enum key.
43
+ * Keys must be one of:
44
+ * - Numeric string: Valid finite number in canonical form ("0", "-1", "3.14")
45
+ * - Boolean string: Exactly "true" or "false"
46
+ * - Identifier: Valid JS identifier for text codes ("R", "idle", "state_1")
47
+ *
48
+ * @param {string} key - Single enum key to validate
49
+ * @returns {boolean} True if key is valid
50
+ */
51
+ const validEnumKey = function ( key ) {
52
+ // Try numeric (most common for machine states)
53
+ if ( validators.numericString( key ) ) return true;
54
+ // Try boolean
55
+ if ( validators.booleanString( key ) ) return true;
56
+ // Try identifier (text codes)
57
+ return validators.identifier( key );
58
+ }; // validEnumKey()
59
+
60
+ /**
61
+ * Validates that enum values object has valid keys.
62
+ * Keys must be numeric strings, boolean strings, or valid identifiers.
63
+ *
64
+ * @param {Object} values - Enum values object
65
+ * @returns {boolean} True if all keys are valid
66
+ */
67
+ const validEnumKeys = function ( values ) {
68
+ if ( typeof values !== 'object' || values === null ) {
69
+ return false;
70
+ }
71
+
72
+ const keys = Object.keys( values );
73
+ if ( keys.length === 0 ) {
74
+ return false;
75
+ }
76
+
77
+ for ( let i = 0; i < keys.length; i += 1 ) {
78
+ if ( !validEnumKey( keys[ i ] ) ) {
79
+ return false;
80
+ }
81
+ }
82
+
83
+ return true;
84
+ };
85
+
86
+ /**
87
+ * Validates that enum values are all non-empty strings.
88
+ * Values can contain spaces (e.g., "Error State", "In Progress").
89
+ *
90
+ * @param {Object} values - Enum values object
91
+ * @returns {boolean} True if all values are non-empty strings
92
+ */
93
+ const validEnumValues = function ( values ) {
94
+ if ( typeof values !== 'object' || values === null ) {
95
+ return false;
96
+ }
97
+
98
+ const entries = Object.values( values );
99
+ for ( let i = 0; i < entries.length; i += 1 ) {
100
+ if ( !validators.nonEmptyString( entries[ i ] ) ) {
101
+ return false;
102
+ }
103
+ }
104
+
105
+ return true;
106
+ };
107
+
108
+ // ============================================================================
109
+ // SCHEMA DEFINITION
110
+ // ============================================================================
111
+
112
+ /**
113
+ * Schema for enum JSON files.
114
+ *
115
+ * Uses validate module's `keyValidator` and `propertySchema` features
116
+ * for detailed error messages on individual key/value failures.
117
+ *
118
+ * @type {Object}
119
+ */
120
+ const enumSchema = {
121
+ _propertyNames: [ 'name', 'description', 'values' ],
122
+ name: {
123
+ type: 'string',
124
+ required: true,
125
+ validator: validators.identifier,
126
+ error: 'Enum name must be a valid identifier'
127
+ },
128
+ description: {
129
+ type: 'string',
130
+ required: false,
131
+ default: ''
132
+ },
133
+ values: {
134
+ type: 'object',
135
+ required: true,
136
+ minProperties: 1,
137
+ keyValidator: validEnumKey,
138
+ propertySchema: {
139
+ type: 'string',
140
+ validator: validators.nonEmptyString,
141
+ error: 'Enum values must be non-empty strings'
142
+ },
143
+ error: 'Enum values must be an object with valid keys (numeric, boolean, or identifier) and non-empty string values'
144
+ }
145
+ };
146
+
147
+ // ============================================================================
148
+ // EXPORTS
149
+ // ============================================================================
150
+
151
+ export { enumSchema, validEnumKey, validEnumKeys, validEnumValues };
152
+
153
+ export default enumSchema;
@@ -0,0 +1,51 @@
1
+ // core/semantics/schemas/index.js
2
+
3
+ /**
4
+ * @fileoverview Semantics Schemas Index
5
+ *
6
+ * Exports all schema definitions and validators for semantics JSON files.
7
+ */
8
+
9
+ // ============================================================================
10
+ // ENUM SCHEMA
11
+ // ============================================================================
12
+
13
+ export {
14
+ enumSchema,
15
+ validEnumKey,
16
+ validEnumKeys,
17
+ validEnumValues
18
+ } from './enum-schema.js';
19
+
20
+ // ============================================================================
21
+ // COLUMN SCHEMA
22
+ // ============================================================================
23
+
24
+ export {
25
+ columnSchema,
26
+ validPhysicalRange,
27
+ validOperational,
28
+ validSpecification,
29
+ validWhen,
30
+ validContext,
31
+ validContexts,
32
+ validColumnType,
33
+ validInterpretation,
34
+ validLimitsMutualExclusivity,
35
+ validLimitsHierarchy,
36
+ validContextLimitsHierarchy,
37
+ COLUMN_TYPES,
38
+ COLUMN_DEFAULTS
39
+ } from './column-schema.js';
40
+
41
+ // ============================================================================
42
+ // ASSET CLASS SCHEMA
43
+ // ============================================================================
44
+
45
+ export {
46
+ assetClassSchema,
47
+ insightTypeSchema,
48
+ validColumnsStructure,
49
+ validInsightType,
50
+ validInsightTypes
51
+ } from './asset-class-schema.js';
@@ -0,0 +1,141 @@
1
+ // core/semantics/warnings.js
2
+
3
+ /**
4
+ * @fileoverview Warning Infrastructure for Semantic Loading
5
+ *
6
+ * Provides warning accumulation and emission utilities for semantic validation.
7
+ * Warnings are advisory (don't fail validation) but highlight potential issues
8
+ * in semantic definitions.
9
+ *
10
+ * Follows the accumulation pattern used in flow/validate.js:
11
+ * - Collect all warnings during validation phases
12
+ * - Emit all accumulated warnings at the end
13
+ * - Support suppressWarnings option and custom onWarning handler
14
+ *
15
+ * @see flow/validate.js for the accumulation pattern
16
+ * @see core/storage-manager/questdb/persist-plan.js for onWarning callback pattern
17
+ */
18
+
19
+ // ============================================================================
20
+ // CONSTANTS
21
+ // ============================================================================
22
+
23
+ /**
24
+ * Standard warning prefix for semantic validation warnings.
25
+ * @type {string}
26
+ */
27
+ const WARNING_PREFIX = 'WinkComposer/semantics';
28
+
29
+ // ============================================================================
30
+ // DEFAULT WARNING HANDLER
31
+ // ============================================================================
32
+
33
+ /**
34
+ * Default warning handler for semantic validation issues.
35
+ * Logs to console in WinkComposer format.
36
+ *
37
+ * @param {string} message - Warning message describing the issue
38
+ */
39
+ const defaultOnWarning = function ( message ) {
40
+ console.warn( `${WARNING_PREFIX}: ${message}` );
41
+ };
42
+
43
+ // ============================================================================
44
+ // WARNING COLLECTOR
45
+ // ============================================================================
46
+
47
+ /**
48
+ * Creates a warning collector for semantic validation.
49
+ *
50
+ * Follows the flow/validate.js accumulation pattern:
51
+ * - add() accumulates warnings to internal array
52
+ * - emit() outputs all accumulated warnings
53
+ * - getWarnings() returns copy of accumulated warnings
54
+ * - count() returns number of accumulated warnings
55
+ *
56
+ * @param {Object} options - Warning options
57
+ * @param {boolean} [options.suppressWarnings=false] - Suppress all warnings
58
+ * @param {Function} [options.onWarning] - Custom warning handler
59
+ * @returns {Object} Warning collector with add, emit, getWarnings, count methods
60
+ *
61
+ * @example
62
+ * // Default: logs to console on emit()
63
+ * const collector = createWarningCollector( {} );
64
+ * collector.add( 'Missing interpretation' );
65
+ * collector.add( 'Missing physicalRange' );
66
+ * collector.emit(); // Outputs both warnings
67
+ *
68
+ * // Suppress all warnings (useful for tests)
69
+ * const collector = createWarningCollector( { suppressWarnings: true } );
70
+ *
71
+ * // Custom handler
72
+ * const collector = createWarningCollector( {
73
+ * onWarning: ( msg ) => logger.warn( msg )
74
+ * } );
75
+ */
76
+ const createWarningCollector = function ( options = {} ) {
77
+ const { suppressWarnings = false, onWarning } = options;
78
+ const warnings = [];
79
+
80
+ /**
81
+ * Add a warning message to the collector.
82
+ *
83
+ * @param {string} message - Warning message
84
+ */
85
+ const add = function ( message ) {
86
+ warnings.push( message );
87
+ };
88
+
89
+ /**
90
+ * Emit all accumulated warnings.
91
+ * Does nothing if suppressWarnings is true.
92
+ */
93
+ const emit = function () {
94
+ if ( suppressWarnings ) {
95
+ return;
96
+ }
97
+
98
+ const handler = onWarning || defaultOnWarning;
99
+
100
+ for ( let i = 0; i < warnings.length; i += 1 ) {
101
+ handler( warnings[ i ] );
102
+ }
103
+ };
104
+
105
+ /**
106
+ * Get copy of accumulated warnings.
107
+ *
108
+ * @returns {Array<string>} Copy of warnings array
109
+ */
110
+ const getWarnings = function () {
111
+ return [ ...warnings ];
112
+ };
113
+
114
+ /**
115
+ * Get count of accumulated warnings.
116
+ *
117
+ * @returns {number} Number of accumulated warnings
118
+ */
119
+ const count = function () {
120
+ return warnings.length;
121
+ };
122
+
123
+ return {
124
+ add,
125
+ emit,
126
+ getWarnings,
127
+ count
128
+ };
129
+ };
130
+
131
+ // ============================================================================
132
+ // EXPORTS
133
+ // ============================================================================
134
+
135
+ export {
136
+ WARNING_PREFIX,
137
+ defaultOnWarning,
138
+ createWarningCollector
139
+ };
140
+
141
+ export default createWarningCollector;
@@ -0,0 +1,289 @@
1
+ // core/shutdown-manager/index.js
2
+
3
+ /**
4
+ * @fileoverview Process-layer shutdown manager.
5
+ *
6
+ * Per ADR-018, the framework has three layers — adapter, flow, and
7
+ * process — each owning a distinct concern in the lifecycle. This file
8
+ * is the process layer.
9
+ *
10
+ * What this layer owns:
11
+ * - **OS signal handlers (SIGINT/SIGTERM)** as the SOLE owner. The flow
12
+ * layer (`flow/run.js`) does NOT attach signal handlers; it auto-
13
+ * registers each running flow's `handle` here, and this file routes
14
+ * signals to `handle.shutdown()` for every registered handle.
15
+ * - **Top-level forced-shutdown timeout** that bounds the entire
16
+ * `handle.shutdown()` drain. If a flow takes longer than
17
+ * `ENV_VARS.shutdownForceTimeoutMs` (default 30000ms, matching
18
+ * Kubernetes' `terminationGracePeriodSeconds`), this layer logs and
19
+ * force-exits with code 1; otherwise exits with code 0 on graceful
20
+ * completion. The ADR documents three nested timeouts, each on a
21
+ * wider scope: the per-adapter `{ timeout }` (one adapter's drain),
22
+ * the per-flow stage budget, and this process-level ceiling on the
23
+ * whole exit.
24
+ *
25
+ * This layer owns NO storage. The storage-directory cleanup it used to
26
+ * run (an `fs.rm` of STORAGE_DIR at dev/test shutdown) was removed
27
+ * 2026-07-09: the emitter's LevelDB store — removed by ADR-021 — was
28
+ * the only thing that ever wrote there, and a recursive delete with no
29
+ * producer behind it is a hazard, not a feature.
30
+ *
31
+ * What this layer does NOT own:
32
+ * - Per-flow shutdown orchestration. Each registered handle's
33
+ * `handle.shutdown()` runs its own ordered teardown
34
+ * (source → emitters → storages) via `flow/run.js`'s closure.
35
+ *
36
+ * Idempotent attach. `attachHandlers()` is safe to call multiple times;
37
+ * the second call is a no-op via the internal `attached` flag. This
38
+ * closes the `MaxListenersExceededWarning` that earlier accumulated
39
+ * across test runs (each `flow.run()` had registered its own handlers
40
+ * without detach).
41
+ *
42
+ * Legacy path. The block below labelled "LEGACY PATH — scheduled for
43
+ * retirement" exists to serve the pre-DSL example flows
44
+ * (`cpd-run.js`, `rwm-csv-run.js` via their flow files) that wire
45
+ * emitters via `emitters.wire()` and rely on this manager's
46
+ * `emitters.shutdown()`. Modern `flow().run()` pipelines do not use
47
+ * that path — their registries are already drained by
48
+ * `handle.shutdown()` (called from the registered-handle iteration
49
+ * above), so the legacy block finds an empty registry and is a benign
50
+ * no-op for them. The sources half of this path (`wire-sources.js`,
51
+ * the OPC-UA example runners) was removed 2026-07-07 — see ADR-019.
52
+ * The emitters half retires when the legacy examples migrate to the
53
+ * modern flow API.
54
+ *
55
+ * @see ADR-018 (flow lifecycle and signal handling)
56
+ */
57
+
58
+ import { emitters } from '../wiring/index.js';
59
+ import { ENV_VARS } from '../env-vars.js';
60
+
61
+ /**
62
+ * Factory that produces a fresh shutdown-manager instance with isolated
63
+ * internal state. The default export below calls this once for the
64
+ * production singleton; tests call it per spec to get an isolated
65
+ * instance and avoid state bleed across cases. Same shape as the
66
+ * earlier in-file IIFE; the factoring is purely for testability.
67
+ *
68
+ * @returns {{shutdown, attachHandlers, register}} the manager API
69
+ */
70
+ const createShutdownManager = function () {
71
+ // ========================================================================
72
+ // PRIVATE STATE
73
+ // ========================================================================
74
+
75
+ // Guards against re-entry if a signal arrives mid-shutdown.
76
+ let isShuttingDown = false;
77
+
78
+ // `attachHandlers` idempotency flag. Multiple calls (e.g., from
79
+ // `flow().run()` auto-attach AND from a legacy example's explicit
80
+ // call) are no-ops after the first.
81
+ let attached = false;
82
+
83
+ // Map of registered flow handles. Keyed by the handle object itself,
84
+ // so registering the same handle twice is idempotent (a single entry)
85
+ // and a single unregister fully removes it. Map is purpose-built for
86
+ // this add/remove-over-time pattern; iteration via `.keys()` is
87
+ // clean and never deoptimises.
88
+ const handles = new Map();
89
+
90
+ // ========================================================================
91
+ // REGISTER: Add a flow handle to the shutdown roster
92
+ // ========================================================================
93
+ /**
94
+ * Register a flow `handle` so this manager calls `handle.shutdown()`
95
+ * on signal. `flow().run()` auto-registers its returned handle so
96
+ * the caller experience is unchanged from earlier versions.
97
+ *
98
+ * Idempotent: registering the same handle twice is a single entry,
99
+ * and a single unregister fully removes it. The Map is keyed by
100
+ * the handle object itself — no synthetic IDs needed.
101
+ *
102
+ * Returns an unregister function so a flow that has already shut
103
+ * down (via direct `handle.shutdown()` invocation by the caller)
104
+ * can detach itself, preventing this manager from re-invoking
105
+ * `handle.shutdown()` on a torn-down flow.
106
+ *
107
+ * @param {{shutdown: function}} handle - flow handle exposing shutdown
108
+ * @returns {function} unregister
109
+ */
110
+ const register = function ( handle ) {
111
+ handles.set( handle, true );
112
+ return function () {
113
+ handles.delete( handle );
114
+ };
115
+ };
116
+
117
+ // ========================================================================
118
+ // DRAIN HANDLES: Race per-flow shutdown against the forced timeout
119
+ // ========================================================================
120
+ /**
121
+ * Iterate every registered flow handle, calling `handle.shutdown()`
122
+ * on each in parallel via `Promise.allSettled`. Race the whole drain
123
+ * against `timeoutMs`; if the timeout wins, return false so the
124
+ * caller can log + force-exit with code 1.
125
+ *
126
+ * Returns true when no handles are registered (e.g., the legacy
127
+ * code path with no modern flows in process).
128
+ */
129
+ const drainHandles = async function ( timeoutMs ) {
130
+ if ( handles.size === 0 ) {
131
+ return true;
132
+ }
133
+
134
+ const drainAll = Promise.allSettled(
135
+ Array.from( handles.keys() ).map(
136
+ ( handle ) => Promise.resolve().then( () => handle.shutdown() )
137
+ )
138
+ );
139
+
140
+ // Distinct sentinel string so we can tell race winner apart from
141
+ // a Promise.allSettled result array.
142
+ const TIMED_OUT = '__SHUTDOWN_FORCE_TIMEOUT__';
143
+ let timerHandle;
144
+ const timeout = new Promise( ( resolve ) => {
145
+ timerHandle = setTimeout( () => resolve( TIMED_OUT ), timeoutMs );
146
+ } );
147
+
148
+ const winner = await Promise.race( [ drainAll, timeout ] );
149
+ // Cancel the loser. Without this, when drainAll wins the
150
+ // race, the unfired setTimeout still keeps the event loop
151
+ // alive until it fires (up to `timeoutMs` later) — a real
152
+ // tail-latency at end of test suites and in any process
153
+ // that runs the manager and then expects to exit cleanly.
154
+ // Same canonical pattern used by every source `stopFn`.
155
+ clearTimeout( timerHandle );
156
+ return winner !== TIMED_OUT;
157
+ };
158
+
159
+ // ========================================================================
160
+ // SHUTDOWN: Orchestrate the layered teardown
161
+ // ========================================================================
162
+ /**
163
+ * Run the full process-layer shutdown sequence. Re-entry is guarded
164
+ * via `isShuttingDown` (a second call returns immediately).
165
+ *
166
+ * Order:
167
+ * 1. Drain registered flow handles (modern path).
168
+ * 2. Run the legacy path block (clustered for retirement; warns once
169
+ * when actually doing work).
170
+ * 3. Return graceful (true) / forced (false) — the caller decides
171
+ * the exit code.
172
+ *
173
+ * @returns {Promise<boolean>} true on graceful completion, false on
174
+ * forced timeout
175
+ */
176
+ const shutdown = async function () {
177
+ if ( isShuttingDown ) {
178
+ return true;
179
+ }
180
+ isShuttingDown = true;
181
+
182
+ const timestamp = new Date().toISOString();
183
+ console.log( `\n[${timestamp}] Shutdown initiated` );
184
+
185
+ // Phase 1 (modern path): drain registered flow handles, racing
186
+ // against the forced-shutdown timeout.
187
+ const graceful = await drainHandles( ENV_VARS.shutdownForceTimeoutMs );
188
+ if ( !graceful ) {
189
+ console.warn(
190
+ ` ⚠ Forced shutdown — flow drain exceeded ${ENV_VARS.shutdownForceTimeoutMs}ms; ` +
191
+ 'some adapters may not have completed cleanly'
192
+ );
193
+ }
194
+
195
+ try {
196
+ // ================================================================
197
+ // LEGACY PATH — scheduled for retirement
198
+ // ================================================================
199
+ //
200
+ // The emitters.shutdown() call below serves the pre-DSL
201
+ // example flows (cpd-run.js, rwm-csv-run.js via their flow
202
+ // files) that wire emitters manually via emitters.wire()
203
+ // instead of using the modern flow().run() API.
204
+ //
205
+ // Modern flow().run() pipelines drain everything via
206
+ // handle.shutdown() (called from the registered-handle
207
+ // iteration above); by the time control reaches this block,
208
+ // the wire-emitters / wire-storages registries are already
209
+ // empty for those flows — the call finds nothing to do
210
+ // (benign no-op).
211
+ //
212
+ // The sources half of this path (wire-sources.js and the
213
+ // OPC-UA example runners) was removed 2026-07-07 (ADR-019).
214
+ // This remainder retires when the legacy examples migrate
215
+ // to the modern flow API.
216
+ // ================================================================
217
+
218
+ const emitterResults = await emitters.shutdown();
219
+ const failedEmitters = emitterResults.filter( ( r ) => r.status === 'rejected' );
220
+ if ( emitterResults.length > 0 ) {
221
+ if ( failedEmitters.length > 0 ) {
222
+ console.warn( ` ⚠ Warning: ${failedEmitters.length} legacy emitter(s) failed to shutdown cleanly` );
223
+ } else {
224
+ console.log( ' ✓ Legacy message queues flushed' );
225
+ }
226
+ }
227
+
228
+ // ================================================================
229
+ // END LEGACY PATH
230
+ // ================================================================
231
+
232
+ console.log( `[${new Date().toISOString()}] Shutdown complete\n` );
233
+
234
+ return graceful;
235
+
236
+ } catch ( error ) {
237
+ console.error( '✗ Shutdown error:', error );
238
+ process.exitCode = 1;
239
+ return false;
240
+ }
241
+ }; // shutdown()
242
+
243
+ // ========================================================================
244
+ // ATTACH HANDLERS: Wire up SIGINT/SIGTERM (idempotent)
245
+ // ========================================================================
246
+ /**
247
+ * Register process-level SIGINT and SIGTERM handlers. Idempotent —
248
+ * subsequent calls are no-ops via the internal `attached` flag.
249
+ * Both `flow().run()` (auto-attach) and legacy examples' explicit
250
+ * calls converge here, so handlers are registered exactly once per
251
+ * process regardless of caller.
252
+ *
253
+ * On signal: runs `shutdown()`, then `process.exit(0)` on graceful
254
+ * or `process.exit(1)` on forced timeout.
255
+ */
256
+ const attachHandlers = function () {
257
+ if ( attached ) {
258
+ return;
259
+ }
260
+ attached = true;
261
+
262
+ const signalHandler = async function ( signalName ) {
263
+ console.log( `\ncomposer: Received ${signalName}` );
264
+ const graceful = await shutdown();
265
+
266
+ /* c8 ignore next 2 -- fundamentally untestable: invoking the signal handler from a test would call process.exit and kill the test runner. The graceful/forced exit-code mapping is verified by the shutdown() return-value tests above. */
267
+ // eslint-disable-next-line no-process-exit
268
+ process.exit( graceful ? 0 : 1 );
269
+ };
270
+
271
+ process.on( 'SIGINT', () => signalHandler( 'SIGINT (Ctrl-C)' ) );
272
+ process.on( 'SIGTERM', () => signalHandler( 'SIGTERM' ) );
273
+ }; // attachHandlers()
274
+
275
+ // ========================================================================
276
+ // PUBLIC API
277
+ // ========================================================================
278
+ return {
279
+ shutdown,
280
+ attachHandlers,
281
+ register
282
+ };
283
+ }; // createShutdownManager()
284
+
285
+ // Production singleton — one instance per process, exported as default.
286
+ const shutdownManager = createShutdownManager();
287
+
288
+ export default shutdownManager;
289
+ export { createShutdownManager };