@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.
- package/LICENSE +1 -1
- package/README.md +42 -103
- package/package.json +53 -29
- package/src/composer.js +75 -0
- package/src/core/batch/aoo-encoder.js +148 -0
- package/src/core/batch/index.js +12 -0
- package/src/core/batch/sliding-window.js +91 -0
- package/src/core/codec/index.js +137 -0
- package/src/core/emitter-manager/mqtt/constants.js +102 -0
- package/src/core/emitter-manager/mqtt/emitter.js +780 -0
- package/src/core/emitter-manager/mqtt/index.js +190 -0
- package/src/core/emitter-manager/mqtt/mqtt-store.js +538 -0
- package/src/core/emitter-manager/terminal/assert-columns.js +98 -0
- package/src/core/emitter-manager/terminal/formatters.js +160 -0
- package/src/core/emitter-manager/terminal/index.js +341 -0
- package/src/core/env-vars.js +245 -0
- package/src/core/mqtt-protocol.js +47 -0
- package/src/core/partition-manager/index.js +7 -0
- package/src/core/partition-manager/init.js +44 -0
- package/src/core/partition-manager/introspect.js +15 -0
- package/src/core/partition-manager/publish-to.js +6 -0
- package/src/core/partition-manager/recompute.js +5 -0
- package/src/core/partition-manager/reset.js +5 -0
- package/src/core/partition-manager/update.js +264 -0
- package/src/core/partition-manager/validate-flow.js +157 -0
- package/src/core/semantics/digest.js +128 -0
- package/src/core/semantics/index.js +83 -0
- package/src/core/semantics/loader.js +571 -0
- package/src/core/semantics/schemas/asset-class-schema.js +218 -0
- package/src/core/semantics/schemas/column-schema.js +651 -0
- package/src/core/semantics/schemas/enum-schema.js +153 -0
- package/src/core/semantics/schemas/index.js +51 -0
- package/src/core/semantics/warnings.js +141 -0
- package/src/core/shutdown-manager/index.js +289 -0
- package/src/core/source-manager/csv/index.js +171 -0
- package/src/core/source-manager/csv/start.js +456 -0
- package/src/core/source-manager/mqtt/client.js +406 -0
- package/src/core/source-manager/mqtt/constants.js +147 -0
- package/src/core/source-manager/mqtt/dedup.js +244 -0
- package/src/core/source-manager/mqtt/index.js +260 -0
- package/src/core/source-manager/mqtt/status.js +546 -0
- package/src/core/source-manager/test-harness/comparator.js +226 -0
- package/src/core/source-manager/test-harness/field-generator.js +85 -0
- package/src/core/source-manager/test-harness/fuzz.js +87 -0
- package/src/core/source-manager/test-harness/index.js +115 -0
- package/src/core/source-manager/test-harness/prng.js +57 -0
- package/src/core/source-manager/test-harness/start.js +232 -0
- package/src/core/source-manager/test-harness/validate.js +213 -0
- package/src/core/storage-manager/questdb/assert-columns.js +120 -0
- package/src/core/storage-manager/questdb/ensure-tables.js +187 -0
- package/src/core/storage-manager/questdb/index.js +1251 -0
- package/src/core/storage-manager/questdb/persist-plan.js +488 -0
- package/src/core/storage-manager/questdb/writers.js +142 -0
- package/src/core/test-utils/sealed-record.js +80 -0
- package/src/core/test-utils/soak-signature.js +149 -0
- package/src/core/test-utils/tcp-proxy.js +106 -0
- package/src/core/tunable/helpers.js +254 -0
- package/src/core/tunable/index.js +87 -0
- package/src/core/utils/console-formatter/index.js +207 -0
- package/src/core/utils/create-smart-store-as/index.js +98 -0
- package/src/core/utils/create-smart-store-as/sanitize-field.js +46 -0
- package/src/core/utils/create-smart-store-as/smart-truncate.js +93 -0
- package/src/core/utils/flow/index.js +5 -0
- package/src/core/utils/flow/make-collision-checker.js +23 -0
- package/src/core/utils/flow/to-kebab.js +20 -0
- package/src/core/utils/half-life/index.js +111 -0
- package/src/core/utils/node/disable.js +11 -0
- package/src/core/utils/node/enable.js +11 -0
- package/src/core/utils/node/execute-triggers.js +40 -0
- package/src/core/utils/node/index.js +10 -0
- package/src/core/utils/node/pause.js +11 -0
- package/src/core/utils/node/populate-predicate-inputs.js +14 -0
- package/src/core/utils/node/publish-nan.js +19 -0
- package/src/core/utils/node/reset-predicate-inputs.js +11 -0
- package/src/core/utils/node/unpause.js +11 -0
- package/src/core/utils/node/validate-spec.js +22 -0
- package/src/core/utils/options/resolve-field-keyed.js +115 -0
- package/src/core/utils/quantize/index.js +75 -0
- package/src/core/utils/stats/formulas.js +67 -0
- package/src/core/utils/stats/index.js +3 -0
- package/src/core/utils/validate/composer-validators.js +141 -0
- package/src/core/utils/validate/helpers.js +206 -0
- package/src/core/utils/validate/index.js +12 -0
- package/src/core/utils/validate/type-validators.js +538 -0
- package/src/core/utils/validate/validate.js +107 -0
- package/src/core/utils/validate/validators.js +177 -0
- package/src/core/wiring/assert-handle.js +57 -0
- package/src/core/wiring/assert-module.js +63 -0
- package/src/core/wiring/index.js +5 -0
- package/src/core/wiring/node-type-to-module.js +17 -0
- package/src/core/wiring/wire-emitters.js +256 -0
- package/src/core/wiring/wire-linear-graph.js +25 -0
- package/src/core/wiring/wire-node.js +157 -0
- package/src/core/wiring/wire-semantics.js +173 -0
- package/src/core/wiring/wire-storages.js +344 -0
- package/src/flow/check-output-collisions.js +93 -0
- package/src/flow/consts.js +9 -0
- package/src/flow/deep-clone-spec.js +64 -0
- package/src/flow/driver.js +171 -0
- package/src/flow/expand-single-input-array.js +76 -0
- package/src/flow/expand-template-spec.js +93 -0
- package/src/flow/flow-api-schemas.js +300 -0
- package/src/flow/flow.js +658 -0
- package/src/flow/for-each.js +225 -0
- package/src/flow/get-signature-pattern.js +31 -0
- package/src/flow/get-target-array.js +46 -0
- package/src/flow/inspect.js +67 -0
- package/src/flow/load-node-module.js +81 -0
- package/src/flow/make-node-method.js +112 -0
- package/src/flow/resolve-pick-by-field.js +77 -0
- package/src/flow/resolve-tunables.js +76 -0
- package/src/flow/run.js +392 -0
- package/src/flow/serialize.js +161 -0
- package/src/flow/signatures-schema.js +222 -0
- package/src/flow/spec-builder.js +65 -0
- package/src/flow/validate-triggers.js +250 -0
- package/src/flow/validate.js +261 -0
- package/src/nodes/accumulate/index.js +21 -0
- package/src/nodes/accumulate/init.js +48 -0
- package/src/nodes/accumulate/introspect.js +123 -0
- package/src/nodes/accumulate/publish-to.js +34 -0
- package/src/nodes/accumulate/recompute.js +27 -0
- package/src/nodes/accumulate/reset.js +25 -0
- package/src/nodes/accumulate/update.js +42 -0
- package/src/nodes/appraise/calibrate.js +64 -0
- package/src/nodes/appraise/decision.js +66 -0
- package/src/nodes/appraise/deviation.js +140 -0
- package/src/nodes/appraise/index.js +23 -0
- package/src/nodes/appraise/init.js +165 -0
- package/src/nodes/appraise/integrate.js +45 -0
- package/src/nodes/appraise/introspect.js +352 -0
- package/src/nodes/appraise/publish-to.js +93 -0
- package/src/nodes/appraise/receptor.js +69 -0
- package/src/nodes/appraise/recompute.js +79 -0
- package/src/nodes/appraise/reset.js +53 -0
- package/src/nodes/appraise/update.js +130 -0
- package/src/nodes/archive/csv/index.js +6 -0
- package/src/nodes/archive/csv/init.js +36 -0
- package/src/nodes/archive/csv/load.js +70 -0
- package/src/nodes/archive/csv/reset.js +14 -0
- package/src/nodes/archive/csv/simple-parser.js +216 -0
- package/src/nodes/archive/csv/test.js +173 -0
- package/src/nodes/archive/csv/update.js +63 -0
- package/src/nodes/butterworth-filter/index.js +18 -0
- package/src/nodes/butterworth-filter/init.js +184 -0
- package/src/nodes/butterworth-filter/introspect.js +228 -0
- package/src/nodes/butterworth-filter/publish-to.js +21 -0
- package/src/nodes/butterworth-filter/recompute.js +13 -0
- package/src/nodes/butterworth-filter/reset.js +30 -0
- package/src/nodes/butterworth-filter/update.js +38 -0
- package/src/nodes/categorize/index.js +19 -0
- package/src/nodes/categorize/init.js +58 -0
- package/src/nodes/categorize/introspect.js +177 -0
- package/src/nodes/categorize/publish-to.js +29 -0
- package/src/nodes/categorize/recompute.js +14 -0
- package/src/nodes/categorize/reset.js +16 -0
- package/src/nodes/categorize/update.js +53 -0
- package/src/nodes/controller/index.js +9 -0
- package/src/nodes/controller/init.js +55 -0
- package/src/nodes/controller/introspect.js +91 -0
- package/src/nodes/controller/publish-to.js +8 -0
- package/src/nodes/controller/recompute.js +9 -0
- package/src/nodes/controller/reset.js +17 -0
- package/src/nodes/controller/update.js +63 -0
- package/src/nodes/diff/index.js +19 -0
- package/src/nodes/diff/init.js +37 -0
- package/src/nodes/diff/introspect.js +132 -0
- package/src/nodes/diff/publish-to.js +21 -0
- package/src/nodes/diff/recompute.js +12 -0
- package/src/nodes/diff/reset.js +12 -0
- package/src/nodes/diff/update.js +37 -0
- package/src/nodes/digest-moments/formulas.js +12 -0
- package/src/nodes/digest-moments/index.js +14 -0
- package/src/nodes/digest-moments/init.js +67 -0
- package/src/nodes/digest-moments/introspect.js +154 -0
- package/src/nodes/digest-moments/publish-to.js +34 -0
- package/src/nodes/digest-moments/recompute.js +14 -0
- package/src/nodes/digest-moments/reset.js +14 -0
- package/src/nodes/digest-moments/update.js +120 -0
- package/src/nodes/dwell-time-tracker/index.js +14 -0
- package/src/nodes/dwell-time-tracker/init.js +59 -0
- package/src/nodes/dwell-time-tracker/introspect.js +137 -0
- package/src/nodes/dwell-time-tracker/publish-to.js +22 -0
- package/src/nodes/dwell-time-tracker/recompute.js +8 -0
- package/src/nodes/dwell-time-tracker/reset.js +23 -0
- package/src/nodes/dwell-time-tracker/update.js +103 -0
- package/src/nodes/emit-if/helpers.js +94 -0
- package/src/nodes/emit-if/index.js +16 -0
- package/src/nodes/emit-if/init.js +67 -0
- package/src/nodes/emit-if/introspect.js +102 -0
- package/src/nodes/emit-if/publish-to.js +13 -0
- package/src/nodes/emit-if/recompute.js +12 -0
- package/src/nodes/emit-if/reset.js +27 -0
- package/src/nodes/emit-if/update.js +93 -0
- package/src/nodes/es-correlation/index.js +19 -0
- package/src/nodes/es-correlation/init.js +73 -0
- package/src/nodes/es-correlation/introspect.js +176 -0
- package/src/nodes/es-correlation/publish-to.js +32 -0
- package/src/nodes/es-correlation/recompute.js +56 -0
- package/src/nodes/es-correlation/reset.js +27 -0
- package/src/nodes/es-correlation/update.js +110 -0
- package/src/nodes/es-mean/index.js +20 -0
- package/src/nodes/es-mean/init.js +58 -0
- package/src/nodes/es-mean/introspect.js +129 -0
- package/src/nodes/es-mean/publish-to.js +19 -0
- package/src/nodes/es-mean/recompute.js +16 -0
- package/src/nodes/es-mean/reset.js +24 -0
- package/src/nodes/es-mean/update.js +69 -0
- package/src/nodes/es-pairwise-correlation/index.js +19 -0
- package/src/nodes/es-pairwise-correlation/init.js +98 -0
- package/src/nodes/es-pairwise-correlation/introspect.js +187 -0
- package/src/nodes/es-pairwise-correlation/publish-to.js +31 -0
- package/src/nodes/es-pairwise-correlation/recompute.js +69 -0
- package/src/nodes/es-pairwise-correlation/reset.js +29 -0
- package/src/nodes/es-pairwise-correlation/update.js +89 -0
- package/src/nodes/es-stats/index.js +21 -0
- package/src/nodes/es-stats/init.js +105 -0
- package/src/nodes/es-stats/introspect.js +157 -0
- package/src/nodes/es-stats/publish-to.js +42 -0
- package/src/nodes/es-stats/recompute.js +74 -0
- package/src/nodes/es-stats/reset.js +49 -0
- package/src/nodes/es-stats/update-envelope.js +44 -0
- package/src/nodes/es-stats/update-welford.js +64 -0
- package/src/nodes/es-stats/update.js +59 -0
- package/src/nodes/index.js +83 -0
- package/src/nodes/invert-flag/index.js +20 -0
- package/src/nodes/invert-flag/init.js +36 -0
- package/src/nodes/invert-flag/introspect.js +115 -0
- package/src/nodes/invert-flag/publish-to.js +23 -0
- package/src/nodes/invert-flag/recompute.js +12 -0
- package/src/nodes/invert-flag/reset.js +12 -0
- package/src/nodes/invert-flag/update.js +32 -0
- package/src/nodes/kalman1d/index.js +20 -0
- package/src/nodes/kalman1d/init.js +103 -0
- package/src/nodes/kalman1d/introspect.js +250 -0
- package/src/nodes/kalman1d/publish-to.js +34 -0
- package/src/nodes/kalman1d/recompute.js +23 -0
- package/src/nodes/kalman1d/reset.js +29 -0
- package/src/nodes/kalman1d/update.js +144 -0
- package/src/nodes/kernel/index.js +18 -0
- package/src/nodes/kernel/init.js +66 -0
- package/src/nodes/kernel/introspect.js +163 -0
- package/src/nodes/kernel/presets.js +74 -0
- package/src/nodes/kernel/publish-to.js +25 -0
- package/src/nodes/kernel/recompute.js +14 -0
- package/src/nodes/kernel/reset.js +20 -0
- package/src/nodes/kernel/update.js +69 -0
- package/src/nodes/lag/index.js +21 -0
- package/src/nodes/lag/init.js +87 -0
- package/src/nodes/lag/introspect.js +202 -0
- package/src/nodes/lag/publish-to.js +64 -0
- package/src/nodes/lag/recompute.js +33 -0
- package/src/nodes/lag/reset.js +49 -0
- package/src/nodes/lag/update.js +133 -0
- package/src/nodes/median3/index.js +19 -0
- package/src/nodes/median3/init.js +40 -0
- package/src/nodes/median3/introspect.js +116 -0
- package/src/nodes/median3/publish-to.js +21 -0
- package/src/nodes/median3/recompute.js +12 -0
- package/src/nodes/median3/reset.js +15 -0
- package/src/nodes/median3/update.js +58 -0
- package/src/nodes/moments-digest/copy-from.js +12 -0
- package/src/nodes/moments-digest/flush.js +17 -0
- package/src/nodes/moments-digest/index.js +132 -0
- package/src/nodes/moments-digest/init.js +84 -0
- package/src/nodes/moments-digest/introspect.js +122 -0
- package/src/nodes/moments-digest/prelude.js +28 -0
- package/src/nodes/moments-digest/publish-to.js +31 -0
- package/src/nodes/moments-digest/recompute.js +9 -0
- package/src/nodes/moments-digest/reset.js +20 -0
- package/src/nodes/moments-digest/update.js +182 -0
- package/src/nodes/node-names.js +67 -0
- package/src/nodes/page-hinkley/index.js +20 -0
- package/src/nodes/page-hinkley/init.js +66 -0
- package/src/nodes/page-hinkley/introspect.js +193 -0
- package/src/nodes/page-hinkley/publish-to.js +28 -0
- package/src/nodes/page-hinkley/recompute.js +14 -0
- package/src/nodes/page-hinkley/reset.js +23 -0
- package/src/nodes/page-hinkley/update.js +105 -0
- package/src/nodes/pass-if/index.js +21 -0
- package/src/nodes/pass-if/init.js +37 -0
- package/src/nodes/pass-if/introspect.js +93 -0
- package/src/nodes/pass-if/publish-to.js +15 -0
- package/src/nodes/pass-if/recompute.js +15 -0
- package/src/nodes/pass-if/reset.js +18 -0
- package/src/nodes/pass-if/update.js +37 -0
- package/src/nodes/persist-if/helpers.js +111 -0
- package/src/nodes/persist-if/index.js +9 -0
- package/src/nodes/persist-if/init.js +98 -0
- package/src/nodes/persist-if/introspect.js +106 -0
- package/src/nodes/persist-if/publish-to.js +21 -0
- package/src/nodes/persist-if/recompute.js +20 -0
- package/src/nodes/persist-if/reset.js +35 -0
- package/src/nodes/persist-if/update.js +112 -0
- package/src/nodes/persistence-check/index.js +14 -0
- package/src/nodes/persistence-check/init.js +38 -0
- package/src/nodes/persistence-check/introspect.js +144 -0
- package/src/nodes/persistence-check/publish-to.js +11 -0
- package/src/nodes/persistence-check/recompute.js +7 -0
- package/src/nodes/persistence-check/reset.js +12 -0
- package/src/nodes/persistence-check/update.js +57 -0
- package/src/nodes/process-index/index.js +15 -0
- package/src/nodes/process-index/init.js +48 -0
- package/src/nodes/process-index/introspect.js +182 -0
- package/src/nodes/process-index/publish-to.js +29 -0
- package/src/nodes/process-index/recompute.js +8 -0
- package/src/nodes/process-index/reset.js +8 -0
- package/src/nodes/process-index/update.js +75 -0
- package/src/nodes/ratio/index.js +14 -0
- package/src/nodes/ratio/init.js +37 -0
- package/src/nodes/ratio/introspect.js +155 -0
- package/src/nodes/ratio/publish-to.js +15 -0
- package/src/nodes/ratio/recompute.js +7 -0
- package/src/nodes/ratio/reset.js +7 -0
- package/src/nodes/ratio/update.js +47 -0
- package/src/nodes/sanitize/index.js +82 -0
- package/src/nodes/sanitize/init.js +82 -0
- package/src/nodes/sanitize/introspect.js +194 -0
- package/src/nodes/sanitize/publish-to.js +15 -0
- package/src/nodes/sanitize/recompute.js +8 -0
- package/src/nodes/sanitize/reset.js +14 -0
- package/src/nodes/sanitize/update.js +102 -0
- package/src/nodes/spike-guard/index.js +14 -0
- package/src/nodes/spike-guard/init.js +47 -0
- package/src/nodes/spike-guard/introspect.js +130 -0
- package/src/nodes/spike-guard/publish-to.js +35 -0
- package/src/nodes/spike-guard/recompute.js +14 -0
- package/src/nodes/spike-guard/reset.js +19 -0
- package/src/nodes/spike-guard/update.js +89 -0
- package/src/nodes/sse-emitter/index.js +7 -0
- package/src/nodes/sse-emitter/init.js +105 -0
- package/src/nodes/sse-emitter/introspect.js +134 -0
- package/src/nodes/sse-emitter/publish-to.js +6 -0
- package/src/nodes/sse-emitter/recompute.js +16 -0
- package/src/nodes/sse-emitter/reset.js +19 -0
- package/src/nodes/sse-emitter/update.js +69 -0
- package/src/nodes/sse-emitter/utils/broadcast-heartbeat.js +36 -0
- package/src/nodes/sse-emitter/utils/build-message.js +31 -0
- package/src/nodes/sse-emitter/utils/connection-manager.js +45 -0
- package/src/nodes/sse-emitter/utils/endpoint-initializer.js +20 -0
- package/src/nodes/sse-emitter/utils/health-monitor.js +38 -0
- package/src/nodes/sse-emitter/utils/qos-handler.js +41 -0
- package/src/nodes/state-change-detector/helpers.js +35 -0
- package/src/nodes/state-change-detector/index.js +12 -0
- package/src/nodes/state-change-detector/init.js +56 -0
- package/src/nodes/state-change-detector/introspect.js +146 -0
- package/src/nodes/state-change-detector/publish-to.js +20 -0
- package/src/nodes/state-change-detector/recompute.js +6 -0
- package/src/nodes/state-change-detector/reset.js +20 -0
- package/src/nodes/state-change-detector/update.js +97 -0
- package/src/nodes/sw-stats/index.js +14 -0
- package/src/nodes/sw-stats/init.js +51 -0
- package/src/nodes/sw-stats/introspect.js +131 -0
- package/src/nodes/sw-stats/publish-to.js +45 -0
- package/src/nodes/sw-stats/recompute.js +33 -0
- package/src/nodes/sw-stats/reset.js +15 -0
- package/src/nodes/sw-stats/update.js +39 -0
- package/src/nodes/swing-watch/index.js +17 -0
- package/src/nodes/swing-watch/init.js +144 -0
- package/src/nodes/swing-watch/introspect.js +188 -0
- package/src/nodes/swing-watch/publish-to.js +53 -0
- package/src/nodes/swing-watch/recompute.js +22 -0
- package/src/nodes/swing-watch/reset.js +55 -0
- package/src/nodes/swing-watch/update.js +767 -0
- package/src/nodes/tally/index.js +15 -0
- package/src/nodes/tally/init.js +32 -0
- package/src/nodes/tally/introspect.js +116 -0
- package/src/nodes/tally/publish-to.js +28 -0
- package/src/nodes/tally/recompute.js +10 -0
- package/src/nodes/tally/reset.js +10 -0
- package/src/nodes/tally/update.js +44 -0
- package/src/nodes/threshold/index.js +14 -0
- package/src/nodes/threshold/init.js +121 -0
- package/src/nodes/threshold/introspect.js +192 -0
- package/src/nodes/threshold/publish-to.js +11 -0
- package/src/nodes/threshold/recompute.js +8 -0
- package/src/nodes/threshold/reset.js +14 -0
- package/src/nodes/threshold/update.js +54 -0
- package/src/nodes/transform/helpers.js +39 -0
- package/src/nodes/transform/index.js +15 -0
- package/src/nodes/transform/init.js +35 -0
- package/src/nodes/transform/introspect.js +118 -0
- package/src/nodes/transform/publish-to.js +23 -0
- package/src/nodes/transform/recompute.js +12 -0
- package/src/nodes/transform/reset.js +11 -0
- package/src/nodes/transform/update.js +32 -0
- package/src/nodes/trend/compute-confidence.js +112 -0
- package/src/nodes/trend/index.js +14 -0
- package/src/nodes/trend/init.js +81 -0
- package/src/nodes/trend/introspect.js +151 -0
- package/src/nodes/trend/publish-to.js +22 -0
- package/src/nodes/trend/recompute.js +15 -0
- package/src/nodes/trend/reset.js +26 -0
- package/src/nodes/trend/update.js +93 -0
- package/src/nodes/tw-stats/copy-from.js +16 -0
- package/src/nodes/tw-stats/flush.js +12 -0
- package/src/nodes/tw-stats/index.js +41 -0
- package/src/nodes/tw-stats/init.js +92 -0
- package/src/nodes/tw-stats/introspect.js +171 -0
- package/src/nodes/tw-stats/publish-to.js +108 -0
- package/src/nodes/tw-stats/recompute.js +9 -0
- package/src/nodes/tw-stats/reset.js +16 -0
- package/src/nodes/tw-stats/update.js +113 -0
- package/src/nodes/unbalance/index.js +15 -0
- package/src/nodes/unbalance/init.js +59 -0
- package/src/nodes/unbalance/introspect.js +167 -0
- package/src/nodes/unbalance/publish-to.js +52 -0
- package/src/nodes/unbalance/recompute.js +11 -0
- package/src/nodes/unbalance/reset.js +10 -0
- package/src/nodes/unbalance/update.js +83 -0
- package/src/nodes/vector-distance/index.js +14 -0
- package/src/nodes/vector-distance/init.js +54 -0
- package/src/nodes/vector-distance/introspect.js +149 -0
- package/src/nodes/vector-distance/publish-to.js +35 -0
- package/src/nodes/vector-distance/recompute.js +11 -0
- package/src/nodes/vector-distance/reset.js +20 -0
- package/src/nodes/vector-distance/update.js +139 -0
- package/src/nodes/winnow/index.js +12 -0
- package/src/nodes/winnow/init.js +82 -0
- package/src/nodes/winnow/introspect.js +253 -0
- package/src/nodes/winnow/publish-to.js +51 -0
- package/src/nodes/winnow/recompute.js +14 -0
- package/src/nodes/winnow/reset.js +34 -0
- package/src/nodes/winnow/update.js +203 -0
- package/src/tools/training/features.js +227 -0
- package/src/tools/training/index.js +21 -0
- package/src/tools/training/logistic.js +238 -0
- package/src/tools/training/metrics.js +126 -0
- package/src/tools/training/scale.js +239 -0
- package/src/tools/training/validate.js +103 -0
- package/src/windowing/count-sliding/create.js +16 -0
- package/src/windowing/count-sliding/get-reverse-chronological-index.js +19 -0
- package/src/windowing/count-sliding/index.js +6 -0
- package/src/windowing/count-sliding/is-not-full.js +5 -0
- package/src/windowing/count-sliding/push.js +15 -0
- package/src/windowing/count-sliding/reset.js +11 -0
- package/src/windowing/count-sliding/size.js +5 -0
- package/src/windowing/time-sliding/create.js +25 -0
- package/src/windowing/time-sliding/push.js +42 -0
- package/CODE_OF_CONDUCT.md +0 -46
- package/CONTRIBUTING.md +0 -132
- package/docs/.nojekyll +0 -0
- package/docs/CONTRIBUTING.md +0 -134
- package/docs/README.md +0 -132
- package/docs/_coverpage.md +0 -26
- package/docs/_media/bg.png +0 -0
- package/docs/_media/wink-logo.png +0 -0
- package/docs/_navbar.md +0 -14
- package/docs/_sidebar.md +0 -2
- package/docs/index.html +0 -44
- 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;
|