@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,64 @@
|
|
|
1
|
+
// nodes/lag/publish-to.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Publishes computed lag statistics to the output message.
|
|
5
|
+
*
|
|
6
|
+
* Only publishes requested stats. Uses publishNaN for fault isolation
|
|
7
|
+
* when input validation has failed. Follows ADR-004 patterns.
|
|
8
|
+
*
|
|
9
|
+
* @see ADR-004
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { publishNaN } from '../../core/utils/node/index.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Copies computed statistics to the output message.
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} state - Node state from update()
|
|
18
|
+
* @param {Object} msg - Output message to enrich
|
|
19
|
+
*/
|
|
20
|
+
const publishTo = function ( state, msg ) {
|
|
21
|
+
// Guard: skip if disabled
|
|
22
|
+
if ( state.disable ) return;
|
|
23
|
+
|
|
24
|
+
// Fault isolation: propagate NaN if input validation failed
|
|
25
|
+
if ( state.inputValidationFailed ) {
|
|
26
|
+
publishNaN( state, msg );
|
|
27
|
+
// cumDelta preserves its value (accumulation skipped, but sum is valid)
|
|
28
|
+
if ( state.hasCumDelta ) {
|
|
29
|
+
msg[ state.stats.cumDelta.storeAs ] = state.cumDelta;
|
|
30
|
+
}
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Publish only requested stats
|
|
35
|
+
if ( state.hasXLag ) {
|
|
36
|
+
msg[ state.stats.xLag.storeAs ] = state.xLag;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if ( state.hasDelta ) {
|
|
40
|
+
msg[ state.stats.delta.storeAs ] = state.delta;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if ( state.hasRatio ) {
|
|
44
|
+
msg[ state.stats.ratio.storeAs ] = state.ratio;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if ( state.hasRoc ) {
|
|
48
|
+
msg[ state.stats.roc.storeAs ] = state.roc;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if ( state.hasSlope ) {
|
|
52
|
+
msg[ state.stats.slope.storeAs ] = state.slope;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if ( state.hasLogReturn ) {
|
|
56
|
+
msg[ state.stats.logReturn.storeAs ] = state.logReturn;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ( state.hasCumDelta ) {
|
|
60
|
+
msg[ state.stats.cumDelta.storeAs ] = state.cumDelta;
|
|
61
|
+
}
|
|
62
|
+
}; // publishTo()
|
|
63
|
+
|
|
64
|
+
export default publishTo;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// nodes/lag/recompute.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Numerical stability handler for the lag node.
|
|
5
|
+
*
|
|
6
|
+
* Five of six stats (delta, ratio, roc, slope, logReturn) are inherently
|
|
7
|
+
* stable — each is computed fresh from (xVal, xLag) with no accumulated
|
|
8
|
+
* state, so no recomputation is needed.
|
|
9
|
+
*
|
|
10
|
+
* cumDelta is the exception: it maintains an unbounded running sum
|
|
11
|
+
* (`state.cumDelta += (xVal - xLag)`) subject to O(n * machineEpsilon)
|
|
12
|
+
* floating-point drift over n messages. In practice, drift is bounded by
|
|
13
|
+
* periodic reset signals from the controller node; recompute remains a
|
|
14
|
+
* no-op under this assumption. If long-term accumulation without periodic
|
|
15
|
+
* reset is ever required, switch cumDelta to Kahan compensated summation
|
|
16
|
+
* in update.js.
|
|
17
|
+
*
|
|
18
|
+
* @see ADR-004
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Recomputes internal state for numerical stability.
|
|
23
|
+
*
|
|
24
|
+
* No-op: five instantaneous stats have no drift; cumDelta drift is bounded
|
|
25
|
+
* by periodic controller resets (see fileoverview).
|
|
26
|
+
*
|
|
27
|
+
* @returns {boolean} Always returns true (no action needed)
|
|
28
|
+
*/
|
|
29
|
+
const recompute = function () {
|
|
30
|
+
return true;
|
|
31
|
+
}; // recompute()
|
|
32
|
+
|
|
33
|
+
export default recompute;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// nodes/lag/reset.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Resets the lag node state to initial conditions.
|
|
5
|
+
*
|
|
6
|
+
* Resets computed values to NaN. Without `hasCumDelta`, also clears the
|
|
7
|
+
* ring buffer(s), which must refill before stats become valid. With
|
|
8
|
+
* `hasCumDelta`, the ring buffer is preserved (ADR-008) so the first
|
|
9
|
+
* post-reset delta bridges the reset without losing one interval.
|
|
10
|
+
*
|
|
11
|
+
* @see ADR-004
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { reset as resetRing } from '../../windowing/count-sliding/index.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resets the node to its initial state.
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} state - Node state to reset
|
|
20
|
+
* @returns {boolean} Always returns true (success)
|
|
21
|
+
*/
|
|
22
|
+
const reset = function ( state ) {
|
|
23
|
+
// ADR-008: cumDelta integrates a continuous signal; the ring buffer
|
|
24
|
+
// is the reference point. Clearing it loses one delta per reset
|
|
25
|
+
// (~1-3% systematic error in metered signals). Preserve the buffer
|
|
26
|
+
// so the first post-reset delta bridges the boundary gap-free.
|
|
27
|
+
// Without cumDelta, instantaneous stats (delta, ratio, roc, slope,
|
|
28
|
+
// logReturn) need a clean startup to avoid cross-boundary artifacts.
|
|
29
|
+
if ( !state.hasCumDelta ) {
|
|
30
|
+
resetRing( state.ringX );
|
|
31
|
+
if ( state.ringT !== null ) {
|
|
32
|
+
resetRing( state.ringT );
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Reset computed values to NaN (startup state)
|
|
37
|
+
state.delta = NaN;
|
|
38
|
+
state.ratio = NaN;
|
|
39
|
+
state.roc = NaN;
|
|
40
|
+
state.slope = NaN;
|
|
41
|
+
state.logReturn = NaN;
|
|
42
|
+
state.xLag = NaN;
|
|
43
|
+
// cumDelta resets to 0 (new integration lower limit)
|
|
44
|
+
state.cumDelta = 0;
|
|
45
|
+
|
|
46
|
+
return true;
|
|
47
|
+
}; // reset()
|
|
48
|
+
|
|
49
|
+
export default reset;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// nodes/lag/update.js
|
|
2
|
+
/* eslint-disable complexity */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @fileoverview Hot path for lag node message processing.
|
|
6
|
+
*
|
|
7
|
+
* Computes lag-based statistics with zero allocation. Only requested stats
|
|
8
|
+
* are computed, using pre-computed flags from init(). Follows ADR-004.
|
|
9
|
+
*
|
|
10
|
+
* Complexity is disabled for this file because the five conditional stat
|
|
11
|
+
* computations are inherently complex but cannot be refactored without
|
|
12
|
+
* adding function call overhead to the hot path.
|
|
13
|
+
*
|
|
14
|
+
* @see ADR-004
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { push } from '../../windowing/count-sliding/index.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Processes a message and computes lag-based statistics.
|
|
21
|
+
*
|
|
22
|
+
* Algorithm:
|
|
23
|
+
* 1. Push x value to ring buffer, receive evicted x_lag
|
|
24
|
+
* 2. If slope requested, push timestamp, receive evicted t_lag
|
|
25
|
+
* 3. If buffer not full (xLag undefined), all stats are NaN
|
|
26
|
+
* 4. Otherwise, compute only requested stats
|
|
27
|
+
*
|
|
28
|
+
* Division by zero protection:
|
|
29
|
+
* - ratio, roc: return NaN if x_lag === 0
|
|
30
|
+
* - slope: return NaN if t - t_lag === 0
|
|
31
|
+
* - logReturn: return NaN if x <= 0 or x_lag <= 0
|
|
32
|
+
*
|
|
33
|
+
* @param {Object} state - Node state from init()
|
|
34
|
+
* @param {Object} msg - Incoming message with field values
|
|
35
|
+
* @returns {Object} Updated state
|
|
36
|
+
*/
|
|
37
|
+
const update = function ( state, msg ) {
|
|
38
|
+
// Guard: skip if disabled
|
|
39
|
+
if ( state.disable || state.pause ) return state;
|
|
40
|
+
|
|
41
|
+
// Extract input value
|
|
42
|
+
const xVal = msg[ state.x ];
|
|
43
|
+
|
|
44
|
+
// Reset health flag
|
|
45
|
+
state.inputValidationFailed = false;
|
|
46
|
+
|
|
47
|
+
// Validate x input (catches NaN, Infinity, undefined)
|
|
48
|
+
if ( !Number.isFinite( xVal ) ) {
|
|
49
|
+
state.inputValidationFailed = true;
|
|
50
|
+
return state;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Handle timestamp if slope is requested
|
|
54
|
+
let tVal;
|
|
55
|
+
if ( state.hasSlope ) {
|
|
56
|
+
tVal = msg[ state.timestamp ];
|
|
57
|
+
if ( !Number.isFinite( tVal ) ) {
|
|
58
|
+
state.inputValidationFailed = true;
|
|
59
|
+
return state;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Push x to ring buffer, get evicted x_lag (undefined during startup)
|
|
64
|
+
const xLag = push( state.ringX, xVal );
|
|
65
|
+
|
|
66
|
+
// Push timestamp if slope is needed
|
|
67
|
+
let tLag;
|
|
68
|
+
if ( state.hasSlope ) {
|
|
69
|
+
tLag = push( state.ringT, tVal );
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check if buffer is full (xLag is finite when evicted value exists)
|
|
73
|
+
const hasLag = Number.isFinite( xLag );
|
|
74
|
+
|
|
75
|
+
// Compute only requested stats
|
|
76
|
+
if ( hasLag ) {
|
|
77
|
+
// ── xLag: the lagged input value itself ────────────────────────
|
|
78
|
+
if ( state.hasXLag ) {
|
|
79
|
+
state.xLag = xLag;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ── delta: x - x_lag ───────────────────────────────────────────
|
|
83
|
+
if ( state.hasDelta ) {
|
|
84
|
+
state.delta = xVal - xLag;
|
|
85
|
+
if ( state.absolute ) {
|
|
86
|
+
state.delta = Math.abs( state.delta );
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── ratio: x / x_lag ───────────────────────────────────────────
|
|
91
|
+
if ( state.hasRatio ) {
|
|
92
|
+
state.ratio = ( xLag === 0 ) ? NaN : ( xVal / xLag );
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ── roc: (x - x_lag) / x_lag ───────────────────────────────────
|
|
96
|
+
if ( state.hasRoc ) {
|
|
97
|
+
state.roc = ( xLag === 0 ) ? NaN : ( ( xVal - xLag ) / xLag );
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ── slope: (x - x_lag) / (t - t_lag) ───────────────────────────
|
|
101
|
+
if ( state.hasSlope ) {
|
|
102
|
+
const tDiff = tVal - tLag;
|
|
103
|
+
state.slope = ( tDiff === 0 ) ? NaN : ( ( xVal - xLag ) / tDiff );
|
|
104
|
+
if ( state.absolute && Number.isFinite( state.slope ) ) {
|
|
105
|
+
state.slope = Math.abs( state.slope );
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ── logReturn: ln(x / x_lag) ───────────────────────────────────
|
|
110
|
+
if ( state.hasLogReturn ) {
|
|
111
|
+
state.logReturn = ( xVal > 0 && xLag > 0 ) ?
|
|
112
|
+
Math.log( xVal / xLag ) :
|
|
113
|
+
NaN;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── cumDelta: Σ(x - x_lag) ──────────────────────────────────────
|
|
117
|
+
if ( state.hasCumDelta ) {
|
|
118
|
+
state.cumDelta += ( xVal - xLag );
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
// Startup period: buffer not full, all requested stats are NaN
|
|
122
|
+
if ( state.hasXLag ) state.xLag = NaN;
|
|
123
|
+
if ( state.hasDelta ) state.delta = NaN;
|
|
124
|
+
if ( state.hasRatio ) state.ratio = NaN;
|
|
125
|
+
if ( state.hasRoc ) state.roc = NaN;
|
|
126
|
+
if ( state.hasSlope ) state.slope = NaN;
|
|
127
|
+
if ( state.hasLogReturn ) state.logReturn = NaN;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return state;
|
|
131
|
+
}; // update()
|
|
132
|
+
|
|
133
|
+
export default update;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Entry point for median3 node.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports all lifecycle functions (init, update, publishTo, reset, recompute),
|
|
5
|
+
* shared control signals (disable, enable, pause, unpause), and introspection metadata.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { default as init } from './init.js';
|
|
9
|
+
export { default as update } from './update.js';
|
|
10
|
+
export { default as reset } from './reset.js';
|
|
11
|
+
export { default as recompute } from './recompute.js';
|
|
12
|
+
export { default as publishTo } from './publish-to.js';
|
|
13
|
+
// Direct imports for common control functions
|
|
14
|
+
export { default as disable } from '../../core/utils/node/disable.js';
|
|
15
|
+
export { default as enable } from '../../core/utils/node/enable.js';
|
|
16
|
+
export { default as pause } from '../../core/utils/node/pause.js';
|
|
17
|
+
export { default as unpause } from '../../core/utils/node/unpause.js';
|
|
18
|
+
// Re-export everything from introspection.js
|
|
19
|
+
export * from './introspect.js';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Initialization for median3 node.
|
|
3
|
+
*
|
|
4
|
+
* Validates the spec, creates state with a 3-element ring buffer,
|
|
5
|
+
* and returns the fully initialized state object.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { validateSpec } from '../../core/utils/node/index.js';
|
|
9
|
+
import * as introspect from './introspect.js';
|
|
10
|
+
import { create } from '../../windowing/count-sliding/index.js';
|
|
11
|
+
|
|
12
|
+
const init = function ( spec ) {
|
|
13
|
+
validateSpec( spec, introspect );
|
|
14
|
+
|
|
15
|
+
// Create state after validation passes
|
|
16
|
+
const state = Object.create( null );
|
|
17
|
+
// Standard input parameter health flag during update: false means healthy
|
|
18
|
+
state.inputValidationFailed = false;
|
|
19
|
+
// Ensure node is enabled by default
|
|
20
|
+
state.disable = false;
|
|
21
|
+
state.pause = false;
|
|
22
|
+
|
|
23
|
+
// Extract field name
|
|
24
|
+
state.x = spec.from.x;
|
|
25
|
+
|
|
26
|
+
// Underlying ring buffer storing the last 3 values
|
|
27
|
+
state.ring = create( 3 );
|
|
28
|
+
|
|
29
|
+
// Config copy
|
|
30
|
+
state.stats = spec.stats;
|
|
31
|
+
|
|
32
|
+
// State variables
|
|
33
|
+
state.median3 = 0;
|
|
34
|
+
|
|
35
|
+
state.nodeType = introspect.getNodeType();
|
|
36
|
+
|
|
37
|
+
return state;
|
|
38
|
+
}; // init()
|
|
39
|
+
|
|
40
|
+
export default init;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Introspection metadata for median3 node.
|
|
3
|
+
*
|
|
4
|
+
* Defines supported stats, control methods, capabilities, DSL schema,
|
|
5
|
+
* and default options. All getters return defensive copies.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { validators } from '../../core/utils/validate/index.js';
|
|
9
|
+
|
|
10
|
+
/** Single source of truth for what this plugin can do */
|
|
11
|
+
const SUPPORTED_STATS = [
|
|
12
|
+
'median3'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
/** Human-readable descriptions (for introspection) */
|
|
16
|
+
const STAT_DESCRIPTIONS = {
|
|
17
|
+
median3: 'Fast median filter over last 3 values'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** Control methods available for triggers */
|
|
21
|
+
const SUPPORTED_CONTROL_METHODS = {
|
|
22
|
+
reset: 'Clears accumulated state and restarts computation',
|
|
23
|
+
enable: 'Enables node processing',
|
|
24
|
+
disable: 'Disables node processing',
|
|
25
|
+
pause: 'Pauses node processing while keeping state visible',
|
|
26
|
+
unpause: 'Resumes node processing after pause'
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** The type of this node */
|
|
30
|
+
const NODE_TYPE = 'Median3';
|
|
31
|
+
|
|
32
|
+
/** Node capabilities for documentation */
|
|
33
|
+
const CAPABILITIES = {
|
|
34
|
+
description: 'Computes the median of the last 3 values for noise reduction',
|
|
35
|
+
features: [
|
|
36
|
+
'Rolling window of exactly 3 values',
|
|
37
|
+
'Efficient sorting algorithm for small fixed window',
|
|
38
|
+
'Handles partial windows gracefully (1-2 values)',
|
|
39
|
+
'Ideal for removing spike noise from sensor data'
|
|
40
|
+
]
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Default options — median3 has no optional parameters */
|
|
44
|
+
export const DEFAULT_OPTIONS = {};
|
|
45
|
+
|
|
46
|
+
// Export functions for accessing metadata
|
|
47
|
+
export const getSupportedStats = () => SUPPORTED_STATS.slice();
|
|
48
|
+
export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
|
|
49
|
+
export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
|
|
50
|
+
export const getNodeType = () => NODE_TYPE;
|
|
51
|
+
export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
|
|
52
|
+
|
|
53
|
+
// DSL Metadata for transpilation
|
|
54
|
+
const DSL_METADATA = {
|
|
55
|
+
// Spec schema for validation
|
|
56
|
+
specSchema: {
|
|
57
|
+
nodeType: {
|
|
58
|
+
type: 'string',
|
|
59
|
+
required: true,
|
|
60
|
+
value: NODE_TYPE
|
|
61
|
+
},
|
|
62
|
+
name: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
required: true,
|
|
65
|
+
validator: validators.identifier,
|
|
66
|
+
error: 'Name must be a valid identifier'
|
|
67
|
+
},
|
|
68
|
+
from: {
|
|
69
|
+
type: 'object',
|
|
70
|
+
required: true,
|
|
71
|
+
properties: {
|
|
72
|
+
x: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
required: true,
|
|
75
|
+
validator: validators.noSpaces,
|
|
76
|
+
error: 'Field name cannot contain spaces'
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
stats: {
|
|
81
|
+
type: 'object',
|
|
82
|
+
required: true,
|
|
83
|
+
minProperties: 1,
|
|
84
|
+
propertyNames: SUPPORTED_STATS,
|
|
85
|
+
propertySchema: {
|
|
86
|
+
type: 'object',
|
|
87
|
+
required: true,
|
|
88
|
+
properties: {
|
|
89
|
+
storeAs: {
|
|
90
|
+
type: 'string',
|
|
91
|
+
required: true,
|
|
92
|
+
minLength: 1,
|
|
93
|
+
validator: validators.identifier,
|
|
94
|
+
error: 'storeAs must be a valid identifier'
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
// Cross-field validators (none needed for median3)
|
|
102
|
+
crossFieldValidators: [],
|
|
103
|
+
|
|
104
|
+
// How to build the spec from DSL params
|
|
105
|
+
// Pattern: NAME_X_OUTPUTS_OPTIONS -> (name, x, stats, options)
|
|
106
|
+
buildSpec: ( name, x, stats, options ) => ( {
|
|
107
|
+
nodeType: NODE_TYPE,
|
|
108
|
+
name,
|
|
109
|
+
from: { x },
|
|
110
|
+
stats,
|
|
111
|
+
...options
|
|
112
|
+
} ),
|
|
113
|
+
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const getDSLMetadata = () => ( { ...DSL_METADATA } );
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Publish function for median3 node.
|
|
3
|
+
*
|
|
4
|
+
* Copies the computed median value to the output message, or propagates
|
|
5
|
+
* NaN if the last input was invalid. Skipped entirely when disabled.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { publishNaN } from '../../core/utils/node/index.js';
|
|
9
|
+
|
|
10
|
+
const publishTo = function ( state, msg ) {
|
|
11
|
+
if ( state.disable ) return;
|
|
12
|
+
// Propagate NaN if unhealthy
|
|
13
|
+
if ( state.inputValidationFailed ) {
|
|
14
|
+
publishNaN( state, msg );
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
msg[ state.stats.median3.storeAs ] = state.median3;
|
|
19
|
+
}; // publishTo()
|
|
20
|
+
|
|
21
|
+
export default publishTo;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Recompute for median3 node.
|
|
3
|
+
*
|
|
4
|
+
* No-op: median is computed fresh from the raw ring buffer values on every
|
|
5
|
+
* update — there is no accumulated state that can drift over time.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const recompute = function () {
|
|
9
|
+
return true;
|
|
10
|
+
}; // recompute()
|
|
11
|
+
|
|
12
|
+
export default recompute;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Reset median3 node state.
|
|
3
|
+
*
|
|
4
|
+
* Clears the ring buffer and resets the computed median value.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { reset as resetRing } from '../../windowing/count-sliding/index.js';
|
|
8
|
+
|
|
9
|
+
const reset = function ( state ) {
|
|
10
|
+
resetRing( state.ring );
|
|
11
|
+
state.median3 = 0;
|
|
12
|
+
return true;
|
|
13
|
+
}; // reset()
|
|
14
|
+
|
|
15
|
+
export default reset;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Update function for median3 node.
|
|
3
|
+
*
|
|
4
|
+
* Computes the median of the last 3 values using a 3-element sorting network.
|
|
5
|
+
* For partial windows: 1 value returns itself, 2 values return their average.
|
|
6
|
+
*
|
|
7
|
+
* Algorithm: compare-swap (a,b), compare-swap (b,c), then max(a,b) yields
|
|
8
|
+
* the median. This is a standard 3-element sorting network requiring exactly
|
|
9
|
+
* 3 comparisons. Reference: Knuth, TAOCP Vol. 3, Section 5.3.4.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { push } from '../../windowing/count-sliding/index.js';
|
|
13
|
+
|
|
14
|
+
const update = function ( state, msg ) {
|
|
15
|
+
if ( state.disable || state.pause ) return state;
|
|
16
|
+
const xVal = msg[ state.x ];
|
|
17
|
+
// Reset on each update
|
|
18
|
+
state.inputValidationFailed = false;
|
|
19
|
+
// Handle faults gracefully: ensure their isolation
|
|
20
|
+
if ( !Number.isFinite( xVal ) ) {
|
|
21
|
+
// Signals publishing NaN for all demanded `stats` in publishTo.
|
|
22
|
+
state.inputValidationFailed = true;
|
|
23
|
+
return state;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
push( state.ring, xVal );
|
|
27
|
+
|
|
28
|
+
let a = state.ring.buffer[ 0 ];
|
|
29
|
+
let b = state.ring.buffer[ 1 ];
|
|
30
|
+
let c = state.ring.buffer[ 2 ];
|
|
31
|
+
|
|
32
|
+
if ( state.ring.used > 2 ) {
|
|
33
|
+
let tmp;
|
|
34
|
+
if ( a > b ) {
|
|
35
|
+
tmp = a;
|
|
36
|
+
a = b;
|
|
37
|
+
b = tmp;
|
|
38
|
+
}
|
|
39
|
+
if ( b > c ) {
|
|
40
|
+
tmp = b;
|
|
41
|
+
b = c;
|
|
42
|
+
c = tmp;
|
|
43
|
+
}
|
|
44
|
+
state.median3 = ( a > b ) ? a : b;
|
|
45
|
+
return state;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if ( state.ring.used === 2 ) {
|
|
49
|
+
state.median3 = ( a + b ) / 2;
|
|
50
|
+
return state;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
state.median3 = xVal;
|
|
54
|
+
|
|
55
|
+
return state;
|
|
56
|
+
}; // update()
|
|
57
|
+
|
|
58
|
+
export default update;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// nodes/moments-digest/copy-from.js
|
|
2
|
+
|
|
3
|
+
export const copyFrom = function ( source, destination ) {
|
|
4
|
+
destination.n = source.n;
|
|
5
|
+
destination.M1 = source.M1;
|
|
6
|
+
destination.M2 = source.M2;
|
|
7
|
+
destination.M3 = source.M3;
|
|
8
|
+
destination.M4 = source.M4;
|
|
9
|
+
destination.min = source.min;
|
|
10
|
+
destination.max = source.max;
|
|
11
|
+
return destination;
|
|
12
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Forces publication of incomplete window.
|
|
2
|
+
// Used for graceful shutdown or event driven snapshots.
|
|
3
|
+
const flush = function ( state ) {
|
|
4
|
+
// Cascade nodes cannot be directly flushed
|
|
5
|
+
if ( state.isCascading ) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
// Set flush true so that during publish, the stats will be
|
|
9
|
+
// published even if window is incomplete. Note, the publishTo()
|
|
10
|
+
// method calls reset in the end resetting everything including
|
|
11
|
+
// the `state.flush` to `false`.
|
|
12
|
+
state.flushLatched = true;
|
|
13
|
+
|
|
14
|
+
return true;
|
|
15
|
+
}; // reset()
|
|
16
|
+
|
|
17
|
+
export default flush;
|