@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,177 @@
1
+ /**
2
+ * General-purpose validators
3
+ * Reusable validation functions for common patterns
4
+ */
5
+
6
+ /**
7
+ * Validates JavaScript identifiers
8
+ */
9
+ const identifier = function ( value ) {
10
+ return typeof value === 'string' && ( /^[a-zA-Z_$][a-zA-Z0-9_$]*$/ ).test( value );
11
+ }; // identifier()
12
+
13
+ /**
14
+ * Validates non-empty string with no whitespace characters.
15
+ * Rejects empty strings and strings containing spaces, tabs, or newlines.
16
+ */
17
+ const noSpaces = function ( value ) {
18
+ return typeof value === 'string' && value.length > 0 && !( /\s/ ).test( value );
19
+ }; // noSpaces()
20
+
21
+ /**
22
+ * Creates a range validator
23
+ */
24
+ const inRange = function ( min, max ) {
25
+ return function ( value ) {
26
+ return typeof value === 'number' && value >= min && value <= max;
27
+ };
28
+ }; // inRange()
29
+
30
+ /**
31
+ * Creates an enum validator
32
+ */
33
+ const oneOf = function ( options ) {
34
+ return function ( value ) {
35
+ return options.includes( value );
36
+ };
37
+ }; // oneOf()
38
+
39
+ /**
40
+ * Creates a pattern validator
41
+ */
42
+ const matches = function ( pattern ) {
43
+ return function ( value ) {
44
+ return typeof value === 'string' && pattern.test( value );
45
+ };
46
+ }; // matches()
47
+
48
+ /**
49
+ * Validates positive numbers
50
+ */
51
+ const positive = function ( value ) {
52
+ return typeof value === 'number' && value > 0;
53
+ }; // positive()
54
+
55
+ /**
56
+ * Validates non-negative numbers
57
+ */
58
+ const nonNegative = function ( value ) {
59
+ return typeof value === 'number' && value >= 0;
60
+ }; // nonNegative()
61
+
62
+ /**
63
+ * Validates non-negative finite numbers (rejects NaN, Infinity).
64
+ */
65
+ const nonNegativeFinite = function ( value ) {
66
+ return typeof value === 'number' && Number.isFinite( value ) && value >= 0;
67
+ }; // nonNegativeFinite()
68
+
69
+ /**
70
+ * Validates integers
71
+ */
72
+ const integer = function ( value ) {
73
+ return Number.isInteger( value );
74
+ }; // integer()
75
+
76
+ /**
77
+ * Validates positive integers
78
+ */
79
+ const positiveInteger = function ( value ) {
80
+ return Number.isInteger( value ) && value > 0;
81
+ }; // positiveInteger()
82
+
83
+ /**
84
+ * Validates value is a finite number (not NaN, not Infinity).
85
+ */
86
+ const isFinite = function ( value ) {
87
+ return typeof value === 'number' && Number.isFinite( value );
88
+ }; // isFinite()
89
+
90
+ /**
91
+ * Validates non-negative finite numbers OR functions (for tunable support).
92
+ */
93
+ const nonNegativeOrFunction = function ( value ) {
94
+ if ( typeof value === 'function' ) return true;
95
+ return typeof value === 'number' && Number.isFinite( value ) && value >= 0;
96
+ }; // nonNegativeOrFunction()
97
+
98
+ /**
99
+ * Validates positive finite numbers OR functions (for tunable support).
100
+ */
101
+ const positiveOrFunction = function ( value ) {
102
+ if ( typeof value === 'function' ) return true;
103
+ return typeof value === 'number' && Number.isFinite( value ) && value > 0;
104
+ }; // positiveOrFunction()
105
+
106
+ /**
107
+ * Validates nonzero numbers
108
+ */
109
+ const nonZero = function ( value ) {
110
+ return typeof value === 'number' && value !== 0;
111
+ }; // nonZero()
112
+
113
+ /**
114
+ * Validates non-empty strings
115
+ */
116
+ const nonEmptyString = function ( value ) {
117
+ return typeof value === 'string' && value.length > 0;
118
+ }; // nonEmptyString()
119
+
120
+ /**
121
+ * Validates string representations of non-negative integers ("0", "1", "123")
122
+ * Used for enum keys which must be numeric string indices.
123
+ * Rejects leading zeros (e.g., "01", "007") to enforce canonical representation.
124
+ */
125
+ const integerString = function ( value ) {
126
+ if ( typeof value !== 'string' ) return false;
127
+ if ( value.length === 0 ) return false;
128
+ // Must be digits only
129
+ if ( !( /^\d+$/ ).test( value ) ) return false;
130
+ // No leading zeros except for "0" itself
131
+ if ( value.length > 1 && value[ 0 ] === '0' ) return false;
132
+ return true;
133
+ }; // integerString()
134
+
135
+ /**
136
+ * Validates string representations of finite numbers.
137
+ * Accepts: "0", "-1", "3.14", "-2.5"
138
+ * Rejects: "", "NaN", "Infinity", "3.14.5", "abc"
139
+ * Uses roundtrip validation: String(Number(value)) === value
140
+ */
141
+ const numericString = function ( value ) {
142
+ if ( typeof value !== 'string' || value.length === 0 ) return false;
143
+ const num = Number( value );
144
+ if ( !Number.isFinite( num ) ) return false;
145
+ // Roundtrip validation ensures canonical form
146
+ return String( num ) === value;
147
+ }; // numericString()
148
+
149
+ /**
150
+ * Validates boolean string literals.
151
+ * Accepts: exactly "true" or "false"
152
+ */
153
+ const booleanString = function ( value ) {
154
+ return value === 'true' || value === 'false';
155
+ }; // booleanString()
156
+
157
+ // Export all validators
158
+ export const validators = {
159
+ identifier,
160
+ noSpaces,
161
+ inRange,
162
+ oneOf,
163
+ matches,
164
+ positive,
165
+ nonNegative,
166
+ nonNegativeFinite,
167
+ integer,
168
+ positiveInteger,
169
+ nonZero,
170
+ isFinite,
171
+ nonNegativeOrFunction,
172
+ positiveOrFunction,
173
+ nonEmptyString,
174
+ integerString,
175
+ numericString,
176
+ booleanString
177
+ };
@@ -0,0 +1,57 @@
1
+ // core/wiring/assert-handle.js
2
+
3
+ /**
4
+ * @fileoverview Checks that a sink (emitter or storage) gives back a handle
5
+ * with all the methods we need, at the moment the flow starts up.
6
+ *
7
+ * Each sink's factory returns an object — the "handle" — that the flow uses
8
+ * later to publish or write messages. The contract (ADR-018) lists
9
+ * which methods that handle must have. This helper checks the list at
10
+ * startup and throws a clear error if anything is missing.
11
+ *
12
+ * Why check at startup instead of when messages start flowing:
13
+ * - If a method is missing, the alternative is a confusing crash later
14
+ * ("X is not a function") deep inside the per-message code path. By
15
+ * checking at startup, the error points straight at the misconfigured
16
+ * adapter and says exactly which method is missing.
17
+ * - Startup runs once per flow; the check costs nothing at runtime.
18
+ *
19
+ * Error message format (same across sinks):
20
+ * `WinkComposer/adapter: '<adapterId>' missing required method '<name>'`
21
+ *
22
+ * @see ADR-018 (sink method surface)
23
+ */
24
+
25
+ /**
26
+ * Throws if `handle` is not an object or if any of the listed methods are
27
+ * missing / non-function. Used by wire-emitters and wire-storages just
28
+ * after the factory's return is awaited.
29
+ *
30
+ * @param {string} adapterId - identifier used in the error message (the
31
+ * adapter's registry key — emit-target name, storage name)
32
+ * @param {*} handle - the value returned from the factory
33
+ * @param {string[]} requiredMethods - method names that must be functions
34
+ * on the handle (e.g., [ 'publishNow', 'shutdown', 'getHealth' ])
35
+ * @throws {Error} `WinkComposer/adapter: '<adapterId>' factory returned non-object handle`
36
+ * if `handle` is null/undefined/non-object.
37
+ * @throws {Error} `WinkComposer/adapter: '<adapterId>' missing required method '<name>'`
38
+ * on the first missing or non-function method (fails fast — does not
39
+ * enumerate every gap, since one is enough to abort wiring).
40
+ */
41
+ const assertHandle = function ( adapterId, handle, requiredMethods ) {
42
+ if ( !handle || typeof handle !== 'object' ) {
43
+ throw new Error(
44
+ `WinkComposer/adapter: '${adapterId}' factory returned non-object handle`
45
+ );
46
+ }
47
+ for ( let i = 0; i < requiredMethods.length; i += 1 ) {
48
+ const name = requiredMethods[ i ];
49
+ if ( typeof handle[ name ] !== 'function' ) {
50
+ throw new Error(
51
+ `WinkComposer/adapter: '${adapterId}' missing required method '${name}'`
52
+ );
53
+ }
54
+ }
55
+ }; // assertHandle()
56
+
57
+ export { assertHandle };
@@ -0,0 +1,63 @@
1
+ // core/wiring/assert-module.js
2
+
3
+ /**
4
+ * @fileoverview Checks that an adapter module declares its durability
5
+ * class, at the moment the flow wires it up.
6
+ *
7
+ * Every adapter module must export `durabilityClass` — one word saying
8
+ * what happens to data it has accepted but not yet delivered if the
9
+ * process crashes (ADR-018 defines the export and its four values). For
10
+ * a source the same word describes the input it can recover after a
11
+ * disconnect.
12
+ *
13
+ * Why check at wire time: an adapter without the export still moves
14
+ * messages perfectly well — the gap only surfaces when an operator asks
15
+ * "what does a crash cost here" and nobody can answer from the module.
16
+ * Failing at startup keeps the declaration from silently eroding as
17
+ * adapters are added (the ADR-018 module-surface gate). The companion
18
+ * data-driven test over all shipped adapters is
19
+ * `src/core/test/adapter-module-surface.specs.js`.
20
+ *
21
+ * Error message format (same shape as assert-handle.js):
22
+ * `WinkComposer/adapter: '<adapterId>' module missing valid
23
+ * 'durabilityClass' export — got <value>; expected one of ...`
24
+ *
25
+ * @see ADR-018 (module surface, durability)
26
+ */
27
+
28
+ /**
29
+ * The four crash-survival classes ADR-018 defines. Anything else in a
30
+ * module's `durabilityClass` export is a typo or an invented class, and
31
+ * both should fail loudly at wire time.
32
+ * @type {string[]}
33
+ */
34
+ const DURABILITY_CLASSES = [ 'in-memory', 'wal-backed', 'broker-queue', 'best-effort' ];
35
+
36
+ /**
37
+ * Throws if `module.durabilityClass` is not one of the four contract
38
+ * values. Used by wire-emitters, wire-storages, and the flow runtime's
39
+ * source start path, just before each adapter's factory is invoked.
40
+ *
41
+ * @param {string} adapterId - identifier used in the error message (the
42
+ * adapter's registry key or its `id` export)
43
+ * @param {Object} module - the adapter module (named exports or the
44
+ * default aggregate — both carry `durabilityClass` per ADR-018)
45
+ * @throws {Error} with `err.code = 'INVALID_ADAPTER'` when the export is
46
+ * missing, non-string, or not one of the four values.
47
+ */
48
+ const assertModuleDurability = function ( adapterId, module ) {
49
+ const value = module && module.durabilityClass;
50
+ if ( DURABILITY_CLASSES.includes( value ) ) {
51
+ return;
52
+ }
53
+ const got = ( typeof value === 'string' ) ? `'${value}'` : String( value );
54
+ const err = new Error(
55
+ `WinkComposer/adapter: '${adapterId}' module missing valid 'durabilityClass' export ` +
56
+ `(ADR-018) — got ${got}; expected one of ` +
57
+ `${DURABILITY_CLASSES.map( ( c ) => `'${c}'` ).join( ' | ' )}`
58
+ );
59
+ err.code = 'INVALID_ADAPTER';
60
+ throw err;
61
+ }; // assertModuleDurability()
62
+
63
+ export { assertModuleDurability, DURABILITY_CLASSES };
@@ -0,0 +1,5 @@
1
+ export { default as wireNode } from './wire-node.js';
2
+ export { default as wireLinearGraph } from './wire-linear-graph.js';
3
+ export { default as emitters } from './wire-emitters.js';
4
+ export { default as storages } from './wire-storages.js';
5
+ export { assertModuleDurability } from './assert-module.js';
@@ -0,0 +1,17 @@
1
+ const nodeTypeToModule = function ( nodeType ) {
2
+ // Trim to handle any whitespace issues
3
+ const trimmed = nodeType.trim();
4
+
5
+ // Handle acronyms and simple names
6
+ if ( trimmed === trimmed.toUpperCase() ) {
7
+ return trimmed.toLowerCase();
8
+ }
9
+
10
+ // Handle multi-word names: 'Page Hinkley' → 'pageHinkley'
11
+ return trimmed
12
+ .split(' ')
13
+ .map( ( word, i ) => ( i === 0 ? word.toLowerCase() : word ) )
14
+ .join('');
15
+ };
16
+
17
+ export default nodeTypeToModule;
@@ -0,0 +1,256 @@
1
+ // core/wiring/wire-emitters.js
2
+
3
+ /**
4
+ * @fileoverview Holds the running emitter instances for a flow and creates
5
+ * them on demand from the spec.
6
+ *
7
+ * An "emitter" is the thing that publishes messages out (MQTT broker,
8
+ * terminal/stdout, etc.). One emitter per target name is enough — many
9
+ * partitions can share it — so we keep them in a small registry keyed by
10
+ * target name and only build a new one if we haven't seen that name before.
11
+ *
12
+ * This file is responsible for four things:
13
+ * - Building each emitter at flow startup, by calling its module's
14
+ * `createEmitter(config)` factory and storing the returned handle.
15
+ * - Calling `applySemanticsRequirement` (from `wire-semantics.js`) on each
16
+ * emitter so adapters that declare `semanticsRequirement` get the
17
+ * requested slice of `assetClass` injected before their factory is
18
+ * called (capability-indexed injection per ADR-018).
19
+ * No current emitter declares one; the parity machinery is plumbed
20
+ * for future emitters that will opt in
21
+ * without further wiring changes. `runtime.assetClass` is threaded in
22
+ * via a new `assetClass` parameter on `wire()` (default null preserves
23
+ * any caller that does not pass it).
24
+ * - Checking, the moment we get the handle back, that it has the methods
25
+ * the rest of the framework will call later (fail loudly at startup
26
+ * rather than crash deep in the per-message hot path). See
27
+ * `assert-handle.js` for the check helper and the error format.
28
+ * - Telling the partition manager which emitters expose `getPressure()` so
29
+ * the pressure-aware yield decision (ADR-020, Draft) can poll them. The
30
+ * list is exposed via `getBackpressureAwareSinks()` and assembled by
31
+ * `flow/run.js` after the flow's partition state is set up.
32
+ *
33
+ * Restart safety: `shutdown()` clears the registry after stopping every
34
+ * emitter, so a follow-up `wire()` call on the same process gets a fresh
35
+ * set of handles. (Mirrors `wire-storages.js`; an earlier version cleared
36
+ * only the storage registry.)
37
+ *
38
+ * The IIFE around the registry hides it from outside callers; only the
39
+ * exported methods can read or change it.
40
+ *
41
+ * @see ADR-018 (sink method surface)
42
+ * @see ADR-020 (backpressure-aware-sinks collection; Draft)
43
+ */
44
+
45
+ import { assertHandle } from './assert-handle.js';
46
+ import { assertModuleDurability } from './assert-module.js';
47
+ import { applySemanticsRequirement } from './wire-semantics.js';
48
+
49
+ /**
50
+ * Methods the framework calls on an emitter handle later, so they have to
51
+ * be present at wire time per ADR-018.
52
+ * Note `getStats` was previously here and was later removed from the
53
+ * contract's method surface.
54
+ * `getPressure` is optional — its presence decides whether the handle is
55
+ * collected into `backpressureAwareSinks`, not whether the wire succeeds.
56
+ */
57
+ const REQUIRED_EMITTER_METHODS = [ 'publishNow', 'shutdown', 'getHealth' ];
58
+
59
+ /**
60
+ * Serializes a rejection's `dropped` payload for the shutdown log. A
61
+ * third-party adapter can reject with anything — including structures
62
+ * JSON.stringify throws on (circular references). The log line must never
63
+ * throw: a throw here used to skip the registry clear that followed it.
64
+ * Mirrors `wire-storages.js`.
65
+ *
66
+ * @param {*} dropped - the rejection's dropped payload
67
+ * @returns {string} JSON, or a fallback marker when unserializable
68
+ */
69
+ const describeDropped = function ( dropped ) {
70
+ try {
71
+ return JSON.stringify( dropped );
72
+ } catch {
73
+ return '[unserializable]';
74
+ }
75
+ }; // describeDropped()
76
+
77
+ const emitters = ( function () {
78
+ // ========================================================================
79
+ // PRIVATE STATE: Singleton Registry
80
+ // ========================================================================
81
+ // Holds one emitter per target name. Object.create(null) avoids
82
+ // prototype-pollution surprises since target names come from runtime
83
+ // config (DSL `.emitter()` calls).
84
+ const singletons = Object.create( null );
85
+
86
+ // ========================================================================
87
+ // WIRE: Discover and Create Emitter Singletons
88
+ // ========================================================================
89
+ /**
90
+ * Scans node specs for Emit-If targets, creates the emitter for each
91
+ * unseen target via its module's `createEmitter(config)` factory,
92
+ * verifies the returned handle has the required methods, and stores
93
+ * it. Idempotent — running `wire()` twice on the same target reuses
94
+ * the existing handle and skips the factory call.
95
+ *
96
+ * `assetClass` is the runtime asset class from `flow.assetClass()`,
97
+ * passed through so emitters that declare `semanticsRequirement` can
98
+ * receive their requested slice (capability-indexed injection per
99
+ * ADR-018). No current emitter declares one; the parameter is
100
+ * plumbed for future emitters (e.g., a structured-MQTT emitter that
101
+ * publishes to `${assetClass}/...` topics) that will opt in without
102
+ * further wiring changes.
103
+ *
104
+ * @param {Array} specs - flow node specs (filtered for Emit If)
105
+ * @param {Object} targetConfigs - map from target name to user config
106
+ * @param {Object} emitterModules - map from target name to adapter module
107
+ * @param {Object|null} [assetClass] - runtime asset class from `flow.assetClass()`,
108
+ * or null if the flow author did not call it. Default null preserves
109
+ * backward compatibility for any caller that does not pass it.
110
+ */
111
+ const wire = async function ( specs, targetConfigs, emitterModules, assetClass = null ) {
112
+ for ( const spec of specs ) {
113
+ if ( spec.nodeType !== 'Emit If' || !spec.target ) {
114
+ // eslint-disable-next-line no-continue
115
+ continue;
116
+ }
117
+
118
+ const target = spec.target;
119
+
120
+ if ( !singletons[ target ] ) {
121
+ const module = emitterModules[ target ];
122
+ const factory = module && module.createEmitter;
123
+ if ( typeof factory !== 'function' ) {
124
+ throw new Error( `composer: Invalid emitter module: ${target}` );
125
+ }
126
+
127
+ // ADR-018 module-surface check: the module must say what
128
+ // a crash costs — before the factory runs.
129
+ assertModuleDurability( target, module );
130
+
131
+ // Build effective config; capability-indexed injection per
132
+ // ADR-018 if the adapter declared `semanticsRequirement`.
133
+ // No current emitter declares one, so for today's adapters
134
+ // this is a no-op spread of user config. Future emitters
135
+ // opt in by exporting a declaration; no further wiring
136
+ // changes needed.
137
+ const effectiveConfig = { ...( targetConfigs[ target ] || {} ) };
138
+ applySemanticsRequirement( target, module, assetClass, effectiveConfig );
139
+
140
+ // Await per ADR-018 — sync factories are unaffected (await on
141
+ // a non-Promise resolves immediately); async factories that
142
+ // need real init time (e.g., a future Kafka emitter) are
143
+ // supported transparently.
144
+ // eslint-disable-next-line no-await-in-loop
145
+ const handle = await factory( effectiveConfig );
146
+
147
+ // Wire-time shape check (ADR-018). Fails fast with a
148
+ // descriptive error instead of letting a missing method
149
+ // crash the per-message hot path later.
150
+ assertHandle( target, handle, REQUIRED_EMITTER_METHODS );
151
+
152
+ singletons[ target ] = handle;
153
+ }
154
+
155
+ spec.emitter = singletons[ target ];
156
+ }
157
+ }; // wire()
158
+
159
+ // ========================================================================
160
+ // GET BACKPRESSURE-AWARE SINKS
161
+ // ========================================================================
162
+ /**
163
+ * Returns the subset of wired emitters that expose `getPressure()`.
164
+ * Keys are namespaced as `emitter:<target>` so a debug log at the
165
+ * call site (the pressure-aware yield decision, ADR-020) immediately
166
+ * tells the operator which sink crossed the threshold. See
167
+ * `flow/run.js` for the assembly into
168
+ * `composerState.partitionState.backpressureAwareSinks`.
169
+ */
170
+ const getBackpressureAwareSinks = function () {
171
+ const map = Object.create( null );
172
+ for ( const [ target, handle ] of Object.entries( singletons ) ) {
173
+ if ( typeof handle.getPressure === 'function' ) {
174
+ map[ `emitter:${target}` ] = handle;
175
+ }
176
+ }
177
+ return map;
178
+ }; // getBackpressureAwareSinks()
179
+
180
+ // ========================================================================
181
+ // GET: Retrieve All Singletons (Defensive Copy)
182
+ // ========================================================================
183
+ // Returns a shallow copy so external callers can inspect the registry
184
+ // without being able to mutate the private one. Used for health
185
+ // monitoring and debugging.
186
+ const get = function () {
187
+ return { ...singletons };
188
+ }; // get()
189
+
190
+ // ========================================================================
191
+ // SHUTDOWN: Graceful Termination of All Emitters
192
+ // ========================================================================
193
+ /**
194
+ * Stops every emitter in parallel via `Promise.allSettled`, so one
195
+ * stuck shutdown does not block the others. Then clears the registry
196
+ * — that way a follow-up `wire()` on the same process (e.g., a test
197
+ * tearing down and bringing the flow back up) gets fresh handles
198
+ * instead of stale, already-stopped ones. Mirrors `wire-storages.js`.
199
+ */
200
+ // Per ADR-018, each emitter's own shutdown takes `{ timeout }`.
201
+ // We pass it through so the flow's per-stage time budget (set in
202
+ // flow/run.js) reaches every emitter the same way.
203
+ const shutdown = async function ( { timeout } = {} ) {
204
+ const opts = ( timeout === undefined ) ? undefined : { timeout };
205
+ const names = Object.keys( singletons );
206
+ const results = await Promise.allSettled(
207
+ names.map( ( name ) => {
208
+ // A non-conforming adapter may THROW from shutdown()
209
+ // instead of rejecting. Convert the throw into this
210
+ // adapter's own rejection slot — escaping here would
211
+ // skip the siblings' drain and the registry clear.
212
+ try {
213
+ return opts ? singletons[ name ].shutdown( opts ) : singletons[ name ].shutdown();
214
+ } catch ( err ) {
215
+ return Promise.reject( err );
216
+ }
217
+ } )
218
+ );
219
+ // Restart safety FIRST: drop stale handles so the next wire()
220
+ // rebuilds them. This must not depend on the logging below — a
221
+ // hostile rejection payload used to throw mid-log and leave the
222
+ // stale handles behind.
223
+ for ( const key of names ) {
224
+ delete singletons[ key ];
225
+ }
226
+ // A rejected drain must reach a human (ADR-018's two-party
227
+ // rule). allSettled keeps one failing emitter from blocking its
228
+ // siblings' drain — but the swallowed rejection is a data loss
229
+ // that would otherwise be visible only to callers inspecting the
230
+ // settled results. Log each one, classified, naming the adapter.
231
+ // String( err ) rather than interpolation: a Symbol rejection
232
+ // reason throws inside a template literal.
233
+ results.forEach( ( result, i ) => {
234
+ if ( result.status === 'rejected' ) {
235
+ const err = result.reason || {};
236
+ const dropped = err.dropped ? ` dropped=${describeDropped( err.dropped )}` : '';
237
+ console.error(
238
+ `WinkComposer/wiring: emitter '${names[ i ]}' shutdown failed [${err.code || 'UNKNOWN'}]: ${err.message || String( err )}${dropped}`
239
+ );
240
+ }
241
+ } );
242
+ return results;
243
+ }; // shutdown()
244
+
245
+ // ========================================================================
246
+ // PUBLIC API
247
+ // ========================================================================
248
+ return {
249
+ wire,
250
+ get,
251
+ getBackpressureAwareSinks,
252
+ shutdown
253
+ };
254
+ }() ); // emitters()
255
+
256
+ export default emitters;
@@ -0,0 +1,25 @@
1
+ import wireNode from './wire-node.js';
2
+ import nodeTypeToModule from './node-type-to-module.js';
3
+
4
+ const wireLinearGraph = function ( specs, nodeModules, options = {} ) {
5
+ let nextHop = null;
6
+
7
+ // Wire in reverse - terminal to root
8
+ for ( let i = specs.length - 1; i >= 0; i -= 1 ) {
9
+ const spec = specs[ i ];
10
+ const moduleName = nodeTypeToModule( spec.nodeType );
11
+ const nodeModule = nodeModules[ moduleName ];
12
+
13
+ if (!nodeModule) {
14
+ throw new Error( `composer/wireGraph: Node module '${moduleName}' not found for nodeType '${spec.nodeType}'` );
15
+ }
16
+
17
+ const nextHops = nextHop ? [ nextHop ] : [];
18
+ nextHop = wireNode( nodeModule, i, nextHops, options );
19
+ }
20
+
21
+ // After loop, nextHop is the root node
22
+ return nextHop;
23
+ };
24
+
25
+ export default wireLinearGraph;