@winkjs/composer 0.0.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +106 -80
- package/package.json +56 -28
- 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,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Introspection metadata for diff 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
|
+
'diff'
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
/** Human-readable descriptions (for introspection) */
|
|
16
|
+
const STAT_DESCRIPTIONS = {
|
|
17
|
+
diff: 'Difference between two message values (x - y)',
|
|
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 = 'Diff';
|
|
31
|
+
|
|
32
|
+
/** Node capabilities for documentation */
|
|
33
|
+
const CAPABILITIES = {
|
|
34
|
+
description: 'Computes the difference between two numeric fields in a message',
|
|
35
|
+
features: [
|
|
36
|
+
'Simple arithmetic difference (x - y)',
|
|
37
|
+
'Optional absolute value mode |x - y|',
|
|
38
|
+
'Useful for computing spreads, or deviations'
|
|
39
|
+
]
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Attach static metadata once, from our constants by making a shallow copy.
|
|
43
|
+
export const getSupportedStats = () => SUPPORTED_STATS.slice();
|
|
44
|
+
export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
|
|
45
|
+
export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
|
|
46
|
+
export const getNodeType = () => NODE_TYPE;
|
|
47
|
+
export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
|
|
48
|
+
|
|
49
|
+
export const DEFAULT_OPTIONS = {
|
|
50
|
+
absolute: false
|
|
51
|
+
};
|
|
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
|
+
y: {
|
|
79
|
+
type: 'string',
|
|
80
|
+
required: true,
|
|
81
|
+
validator: validators.noSpaces,
|
|
82
|
+
error: 'Field name cannot contain spaces'
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
absolute: {
|
|
87
|
+
type: 'boolean',
|
|
88
|
+
required: false,
|
|
89
|
+
default: false
|
|
90
|
+
},
|
|
91
|
+
stats: {
|
|
92
|
+
type: 'object',
|
|
93
|
+
required: true,
|
|
94
|
+
propertyNames: SUPPORTED_STATS,
|
|
95
|
+
propertySchema: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
required: true,
|
|
98
|
+
properties: {
|
|
99
|
+
storeAs: {
|
|
100
|
+
type: 'string',
|
|
101
|
+
required: true,
|
|
102
|
+
minLength: 1,
|
|
103
|
+
validator: validators.identifier,
|
|
104
|
+
error: 'storeAs must be a valid identifier'
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// Cross-field validators
|
|
112
|
+
crossFieldValidators: [
|
|
113
|
+
{
|
|
114
|
+
fields: [ 'from.x', 'from.y' ],
|
|
115
|
+
validator: ( spec ) => spec.from.x !== spec.from.y,
|
|
116
|
+
error: 'from.x and from.y must be different fields'
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
|
|
120
|
+
// How to build the spec from DSL params
|
|
121
|
+
buildSpec: ( name, x, y, stats, options ) => ( {
|
|
122
|
+
nodeType: NODE_TYPE,
|
|
123
|
+
name,
|
|
124
|
+
from: { x, y },
|
|
125
|
+
stats,
|
|
126
|
+
...options
|
|
127
|
+
} ),
|
|
128
|
+
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const getDSLMetadata = () => ( { ...DSL_METADATA } );
|
|
132
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Publish function for diff node.
|
|
3
|
+
*
|
|
4
|
+
* Copies the computed difference 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.diff.storeAs ] = state.diff;
|
|
19
|
+
}; // publishTo()
|
|
20
|
+
|
|
21
|
+
export default publishTo;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Recompute for diff node.
|
|
3
|
+
*
|
|
4
|
+
* No-op: difference is computed fresh from raw input 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,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Update function for diff node.
|
|
3
|
+
*
|
|
4
|
+
* Computes the difference between two numeric message fields (x - y),
|
|
5
|
+
* with optional absolute value mode.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const update = function ( state, msg ) {
|
|
9
|
+
if ( state.disable || state.pause ) return state;
|
|
10
|
+
const xVal = msg[ state.x ];
|
|
11
|
+
// Reset on each update
|
|
12
|
+
state.inputValidationFailed = false;
|
|
13
|
+
// Handle faults gracefully: ensure their isolation
|
|
14
|
+
if ( !Number.isFinite( xVal ) ) {
|
|
15
|
+
// Signals publishing NaN for all demanded `stats` in publishTo.
|
|
16
|
+
state.inputValidationFailed = true;
|
|
17
|
+
return state;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const yVal = msg[ state.y ];
|
|
21
|
+
// Handle faults gracefully: ensure their isolation
|
|
22
|
+
if ( !Number.isFinite( yVal ) ) {
|
|
23
|
+
// Signals publishing NaN for all demanded `stats` in publishTo.
|
|
24
|
+
state.inputValidationFailed = true;
|
|
25
|
+
return state;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Compute difference
|
|
29
|
+
const difference = xVal - yVal;
|
|
30
|
+
|
|
31
|
+
// Apply absolute if configured
|
|
32
|
+
state.diff = state.absolute ? Math.abs( difference ) : difference;
|
|
33
|
+
|
|
34
|
+
return state;
|
|
35
|
+
}; // update()
|
|
36
|
+
|
|
37
|
+
export default update;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// nodes/digest-moments/formulas.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Re-exports shared statistical formulas.
|
|
5
|
+
*
|
|
6
|
+
* The canonical implementations live in core/utils/stats/formulas.js.
|
|
7
|
+
* This re-export preserves the local import path used by digest-moments/update.js.
|
|
8
|
+
*
|
|
9
|
+
* @see core/utils/stats/formulas.js
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export { computeVariance, computeCV, computeSkew, computeKurtosis } from '../../core/utils/stats/formulas.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// nodes/digest-moments/index.js
|
|
2
|
+
|
|
3
|
+
export { default as init } from './init.js';
|
|
4
|
+
export { default as update } from './update.js';
|
|
5
|
+
export { default as reset } from './reset.js';
|
|
6
|
+
export { default as recompute } from './recompute.js';
|
|
7
|
+
export { default as publishTo } from './publish-to.js';
|
|
8
|
+
// Direct imports for common control functions
|
|
9
|
+
export { default as disable } from '../../core/utils/node/disable.js';
|
|
10
|
+
export { default as enable } from '../../core/utils/node/enable.js';
|
|
11
|
+
export { default as pause } from '../../core/utils/node/pause.js';
|
|
12
|
+
export { default as unpause } from '../../core/utils/node/unpause.js';
|
|
13
|
+
// Re-export everything from introspection.js
|
|
14
|
+
export * from './introspect.js';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// nodes/digest-moments/init.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Initialization for digestMoments node.
|
|
5
|
+
*
|
|
6
|
+
* Creates state with pre-computed input field names for zero-allocation
|
|
7
|
+
* hot path. The node is stateless (no accumulation), but needs state for
|
|
8
|
+
* computed values and configuration.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { validateSpec } from '../../core/utils/node/index.js';
|
|
12
|
+
import * as introspect from './introspect.js';
|
|
13
|
+
|
|
14
|
+
const init = function ( spec ) {
|
|
15
|
+
validateSpec( spec, introspect );
|
|
16
|
+
|
|
17
|
+
// Create state after validation passes
|
|
18
|
+
const state = Object.create( null );
|
|
19
|
+
// Standard input parameter health flag during update: false means healthy
|
|
20
|
+
state.inputValidationFailed = false;
|
|
21
|
+
// Ensure node is enabled by default
|
|
22
|
+
state.disable = false;
|
|
23
|
+
state.pause = false;
|
|
24
|
+
// Preserve node's name
|
|
25
|
+
state.name = spec.name;
|
|
26
|
+
|
|
27
|
+
// Input field prefix (from.x contains the prefix, e.g., 'vibSD')
|
|
28
|
+
const prefix = spec.from.x;
|
|
29
|
+
|
|
30
|
+
// Pre-compute input field names (zero allocation in update)
|
|
31
|
+
// These are the output field names from upstream momentsDigest
|
|
32
|
+
state.fields = Object.create( null );
|
|
33
|
+
state.fields.n = prefix + '_n';
|
|
34
|
+
state.fields.M1 = prefix + '_M1';
|
|
35
|
+
state.fields.M2 = prefix + '_M2';
|
|
36
|
+
state.fields.M3 = prefix + '_M3';
|
|
37
|
+
state.fields.M4 = prefix + '_M4';
|
|
38
|
+
state.fields.min = prefix + '_min';
|
|
39
|
+
state.fields.max = prefix + '_max';
|
|
40
|
+
|
|
41
|
+
// Apply defaults from introspect (validation doesn't enforce them)
|
|
42
|
+
// Boolean defaults use || (since default is false)
|
|
43
|
+
// Numeric defaults use ?? (to preserve explicit zero)
|
|
44
|
+
state.biased = spec.biased || introspect.DEFAULT_OPTIONS.biased;
|
|
45
|
+
state.epsilon = spec.epsilon ?? introspect.DEFAULT_OPTIONS.epsilon;
|
|
46
|
+
|
|
47
|
+
// Store stats config for publish-to
|
|
48
|
+
state.stats = Object.assign( Object.create( null ), spec.stats );
|
|
49
|
+
|
|
50
|
+
// Output values (reused each update to avoid allocations)
|
|
51
|
+
// Only allocate slots for requested stats
|
|
52
|
+
state.n = state.stats.n ? NaN : undefined;
|
|
53
|
+
state.mean = state.stats.mean ? NaN : undefined;
|
|
54
|
+
state.variance = state.stats.variance ? NaN : undefined;
|
|
55
|
+
state.stddev = state.stats.stddev ? NaN : undefined;
|
|
56
|
+
state.cv = state.stats.cv ? NaN : undefined;
|
|
57
|
+
state.skew = state.stats.skew ? NaN : undefined;
|
|
58
|
+
state.kurtosis = state.stats.kurtosis ? NaN : undefined;
|
|
59
|
+
state.min = state.stats.min ? NaN : undefined;
|
|
60
|
+
state.max = state.stats.max ? NaN : undefined;
|
|
61
|
+
|
|
62
|
+
state.nodeType = introspect.getNodeType();
|
|
63
|
+
|
|
64
|
+
return state;
|
|
65
|
+
}; // init()
|
|
66
|
+
|
|
67
|
+
export default init;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// nodes/digest-moments/introspect.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Introspection module for digestMoments node.
|
|
5
|
+
*
|
|
6
|
+
* Converts raw moments (n, M1-M4, min, max) from momentsDigest into
|
|
7
|
+
* displayable statistics (mean, variance, stddev, skew, kurtosis, cv, min, max).
|
|
8
|
+
*
|
|
9
|
+
* Skewness and kurtosis use population moments (m3/m2^1.5 and m4/m2^2 - 3).
|
|
10
|
+
* Variance uses Bessel's correction by default (M2/(n-1)).
|
|
11
|
+
* Epsilon threshold ensures numerical stability in division operations.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { validators } from '../../core/utils/validate/index.js';
|
|
15
|
+
|
|
16
|
+
/** Single source of truth for what statistics this node can compute */
|
|
17
|
+
const SUPPORTED_STATS = [
|
|
18
|
+
'n', // Sample count (pass-through)
|
|
19
|
+
'mean', // Arithmetic mean (M1)
|
|
20
|
+
'variance', // Sample variance (unbiased by default)
|
|
21
|
+
'stddev', // Sample standard deviation
|
|
22
|
+
'skew', // Population skewness: m3 / m2^1.5
|
|
23
|
+
'kurtosis', // Excess kurtosis
|
|
24
|
+
'cv', // Coefficient of variation
|
|
25
|
+
'min', // Minimum (pass-through)
|
|
26
|
+
'max' // Maximum (pass-through)
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
/** Human-readable descriptions (for introspection) */
|
|
30
|
+
const STAT_DESCRIPTIONS = {
|
|
31
|
+
n: 'Sample count (pass-through from moments)',
|
|
32
|
+
mean: 'Arithmetic mean (M1)',
|
|
33
|
+
variance: 'Sample variance: M2 / (n - 1) for unbiased, M2 / n for biased',
|
|
34
|
+
stddev: 'Sample standard deviation: sqrt(variance)',
|
|
35
|
+
skew: 'Population skewness: m3 / m2^1.5 (requires n >= 3)',
|
|
36
|
+
kurtosis: 'Population excess kurtosis: m4 / m2^2 - 3 (requires n >= 4)',
|
|
37
|
+
cv: 'Coefficient of variation: stddev / |mean|',
|
|
38
|
+
min: 'Minimum value (pass-through from moments)',
|
|
39
|
+
max: 'Maximum value (pass-through from moments)'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/** Control methods available for triggers */
|
|
43
|
+
const SUPPORTED_CONTROL_METHODS = {
|
|
44
|
+
enable: 'Enables node processing',
|
|
45
|
+
disable: 'Disables node processing',
|
|
46
|
+
pause: 'Pauses node processing while keeping state visible',
|
|
47
|
+
unpause: 'Resumes node processing after pause'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** Node capabilities for documentation */
|
|
51
|
+
const CAPABILITIES = {
|
|
52
|
+
description: 'Stateless node that converts raw moments into displayable statistics',
|
|
53
|
+
features: [
|
|
54
|
+
'Computes n, mean, variance, stddev, skew, kurtosis, cv, min, max',
|
|
55
|
+
'Population skewness and excess kurtosis from central moments',
|
|
56
|
+
'Configurable biased/unbiased variance (sample vs population)',
|
|
57
|
+
'Epsilon threshold for numerical stability in divisions',
|
|
58
|
+
'Graceful NaN handling for edge cases (n < 2, variance ≈ 0, mean ≈ 0)',
|
|
59
|
+
'Zero allocations in hot path',
|
|
60
|
+
'Stateless design - no reset/recompute needed'
|
|
61
|
+
]
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** The type of this node */
|
|
65
|
+
const NODE_TYPE = 'Digest Moments';
|
|
66
|
+
|
|
67
|
+
// Attach static metadata once, from our constants by making a shallow copy.
|
|
68
|
+
export const getSupportedStats = () => SUPPORTED_STATS.slice();
|
|
69
|
+
export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
|
|
70
|
+
export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
|
|
71
|
+
export const getNodeType = () => NODE_TYPE;
|
|
72
|
+
export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
|
|
73
|
+
|
|
74
|
+
export const DEFAULT_OPTIONS = {
|
|
75
|
+
biased: false, // Use sample (unbiased) statistics by default
|
|
76
|
+
epsilon: 1e-12 // Numerical stability threshold for division
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// DSL Metadata for transpilation
|
|
80
|
+
const DSL_METADATA = {
|
|
81
|
+
// Spec schema for validation
|
|
82
|
+
specSchema: {
|
|
83
|
+
nodeType: {
|
|
84
|
+
type: 'string',
|
|
85
|
+
required: true,
|
|
86
|
+
value: NODE_TYPE
|
|
87
|
+
},
|
|
88
|
+
name: {
|
|
89
|
+
type: 'string',
|
|
90
|
+
required: true,
|
|
91
|
+
validator: validators.identifier,
|
|
92
|
+
error: 'Name must be a valid identifier'
|
|
93
|
+
},
|
|
94
|
+
from: {
|
|
95
|
+
type: 'object',
|
|
96
|
+
required: true,
|
|
97
|
+
properties: {
|
|
98
|
+
x: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
required: true,
|
|
101
|
+
validator: validators.noSpaces,
|
|
102
|
+
error: 'Prefix (from upstream momentsDigest) cannot contain spaces'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
biased: {
|
|
107
|
+
type: 'boolean',
|
|
108
|
+
required: false,
|
|
109
|
+
default: DEFAULT_OPTIONS.biased
|
|
110
|
+
},
|
|
111
|
+
epsilon: {
|
|
112
|
+
type: 'number',
|
|
113
|
+
required: false,
|
|
114
|
+
default: DEFAULT_OPTIONS.epsilon,
|
|
115
|
+
min: 0,
|
|
116
|
+
error: 'Epsilon must be a non-negative number'
|
|
117
|
+
},
|
|
118
|
+
stats: {
|
|
119
|
+
type: 'object',
|
|
120
|
+
required: true,
|
|
121
|
+
propertyNames: SUPPORTED_STATS,
|
|
122
|
+
propertySchema: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
required: true,
|
|
125
|
+
properties: {
|
|
126
|
+
storeAs: {
|
|
127
|
+
type: 'string',
|
|
128
|
+
required: true,
|
|
129
|
+
minLength: 1,
|
|
130
|
+
validator: validators.identifier,
|
|
131
|
+
error: 'storeAs must be a valid identifier'
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
error: `stats keys must be one of: ${SUPPORTED_STATS.join( ', ' )}`
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
// Cross-field validators (none needed for digestMoments)
|
|
140
|
+
crossFieldValidators: [],
|
|
141
|
+
|
|
142
|
+
// How to build the spec from DSL params
|
|
143
|
+
// DSL: .digestMoments( 'myStats', 'vibSD', { mean: {...} }, options )
|
|
144
|
+
// Pattern: nameXOutputsOptions
|
|
145
|
+
buildSpec: ( name, x, stats, options ) => ( {
|
|
146
|
+
nodeType: NODE_TYPE,
|
|
147
|
+
name,
|
|
148
|
+
from: { x },
|
|
149
|
+
stats,
|
|
150
|
+
...options
|
|
151
|
+
} )
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const getDSLMetadata = () => ( { ...DSL_METADATA } );
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// nodes/digest-moments/publish-to.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Publish function for digestMoments node.
|
|
5
|
+
*
|
|
6
|
+
* Publishes computed statistics to the message object.
|
|
7
|
+
* Uses publishNaN for graceful fault isolation when inputValidationFailed.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { publishNaN } from '../../core/utils/node/index.js';
|
|
11
|
+
|
|
12
|
+
const publishTo = function ( state, msg ) {
|
|
13
|
+
if ( state.disable ) return;
|
|
14
|
+
|
|
15
|
+
// Propagate NaN if unhealthy (fault isolation)
|
|
16
|
+
if ( state.inputValidationFailed ) {
|
|
17
|
+
publishNaN( state, msg );
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Publish only requested stats
|
|
22
|
+
const stats = state.stats;
|
|
23
|
+
if ( stats.n ) msg[ stats.n.storeAs ] = state.n;
|
|
24
|
+
if ( stats.mean ) msg[ stats.mean.storeAs ] = state.mean;
|
|
25
|
+
if ( stats.variance ) msg[ stats.variance.storeAs ] = state.variance;
|
|
26
|
+
if ( stats.stddev ) msg[ stats.stddev.storeAs ] = state.stddev;
|
|
27
|
+
if ( stats.cv ) msg[ stats.cv.storeAs ] = state.cv;
|
|
28
|
+
if ( stats.skew ) msg[ stats.skew.storeAs ] = state.skew;
|
|
29
|
+
if ( stats.kurtosis ) msg[ stats.kurtosis.storeAs ] = state.kurtosis;
|
|
30
|
+
if ( stats.min ) msg[ stats.min.storeAs ] = state.min;
|
|
31
|
+
if ( stats.max ) msg[ stats.max.storeAs ] = state.max;
|
|
32
|
+
}; // publishTo()
|
|
33
|
+
|
|
34
|
+
export default publishTo;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// nodes/digest-moments/recompute.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Recompute function for digestMoments node.
|
|
5
|
+
*
|
|
6
|
+
* This is a stateless node (no accumulation), so recompute is a no-op.
|
|
7
|
+
* Returns true to indicate the node can continue processing.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const recompute = function ( _state ) {
|
|
11
|
+
return true;
|
|
12
|
+
}; // recompute()
|
|
13
|
+
|
|
14
|
+
export default recompute;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// nodes/digest-moments/reset.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Reset function for digestMoments node.
|
|
5
|
+
*
|
|
6
|
+
* This is a stateless node (no accumulation), so reset is a no-op.
|
|
7
|
+
* Returns true to indicate the node can continue processing.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const reset = function ( _state ) {
|
|
11
|
+
return true;
|
|
12
|
+
}; // reset()
|
|
13
|
+
|
|
14
|
+
export default reset;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// nodes/digest-moments/update.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Update function for digestMoments node.
|
|
5
|
+
*
|
|
6
|
+
* Converts raw moments (n, M1-M4, min, max) into displayable statistics.
|
|
7
|
+
* Only computes stats that were requested in the spec.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { computeVariance, computeCV, computeSkew, computeKurtosis } from './formulas.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Set all variance-dependent stats to NaN.
|
|
14
|
+
* @param {Object} state - Node state
|
|
15
|
+
* @param {Object} stats - Requested stats config
|
|
16
|
+
*/
|
|
17
|
+
const setVarianceStatsNaN = function ( state, stats ) {
|
|
18
|
+
if ( stats.variance ) state.variance = NaN;
|
|
19
|
+
if ( stats.stddev ) state.stddev = NaN;
|
|
20
|
+
if ( stats.cv ) state.cv = NaN;
|
|
21
|
+
if ( stats.skew ) state.skew = NaN;
|
|
22
|
+
if ( stats.kurtosis ) state.kurtosis = NaN;
|
|
23
|
+
}; // setVarianceStatsNaN()
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Compute and store min/max pass-through stats.
|
|
27
|
+
* @param {Object} state - Node state
|
|
28
|
+
* @param {Object} stats - Requested stats config
|
|
29
|
+
* @param {Object} msg - Message with moment fields
|
|
30
|
+
*/
|
|
31
|
+
const computeMinMax = function ( state, stats, msg ) {
|
|
32
|
+
if ( stats.min ) {
|
|
33
|
+
const min = msg[ state.fields.min ];
|
|
34
|
+
state.min = Number.isFinite( min ) ? min : NaN;
|
|
35
|
+
}
|
|
36
|
+
if ( stats.max ) {
|
|
37
|
+
const max = msg[ state.fields.max ];
|
|
38
|
+
state.max = Number.isFinite( max ) ? max : NaN;
|
|
39
|
+
}
|
|
40
|
+
}; // computeMinMax()
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Compute and store variance-dependent stats.
|
|
44
|
+
* @param {Object} state - Node state
|
|
45
|
+
* @param {Object} stats - Requested stats config
|
|
46
|
+
* @param {Object} msg - Message with moment fields
|
|
47
|
+
* @param {number} M1 - Mean
|
|
48
|
+
* @param {number} M2 - Second central moment
|
|
49
|
+
* @param {number} n - Sample count
|
|
50
|
+
* @param {number} m2 - Population variance (M2/n)
|
|
51
|
+
* @param {number} eps - Epsilon for numerical stability
|
|
52
|
+
*/
|
|
53
|
+
const computeVarianceStats = function ( state, stats, msg, M1, M2, n, m2, eps ) {
|
|
54
|
+
const variance = computeVariance( M2, n, state.biased );
|
|
55
|
+
const stddev = Math.sqrt( variance );
|
|
56
|
+
|
|
57
|
+
if ( stats.variance ) state.variance = variance;
|
|
58
|
+
if ( stats.stddev ) state.stddev = stddev;
|
|
59
|
+
if ( stats.cv ) state.cv = computeCV( stddev, M1, eps );
|
|
60
|
+
if ( stats.skew ) state.skew = computeSkew( msg[ state.fields.M3 ], n, m2, eps );
|
|
61
|
+
if ( stats.kurtosis ) state.kurtosis = computeKurtosis( msg[ state.fields.M4 ], n, m2, eps );
|
|
62
|
+
}; // computeVarianceStats()
|
|
63
|
+
|
|
64
|
+
const update = function ( state, msg ) {
|
|
65
|
+
if ( state.disable || state.pause ) return state;
|
|
66
|
+
|
|
67
|
+
state.inputValidationFailed = false;
|
|
68
|
+
|
|
69
|
+
// Read required moment fields from upstream momentsDigest
|
|
70
|
+
const n = msg[ state.fields.n ];
|
|
71
|
+
const M1 = msg[ state.fields.M1 ];
|
|
72
|
+
const M2 = msg[ state.fields.M2 ];
|
|
73
|
+
|
|
74
|
+
// Validate required inputs (n, M1, M2 are always needed)
|
|
75
|
+
if ( !Number.isFinite( n ) || !Number.isFinite( M1 ) || !Number.isFinite( M2 ) ) {
|
|
76
|
+
state.inputValidationFailed = true;
|
|
77
|
+
return state;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const eps = state.epsilon;
|
|
81
|
+
const stats = state.stats;
|
|
82
|
+
|
|
83
|
+
// n is pass-through (already validated as finite)
|
|
84
|
+
if ( stats.n ) state.n = n;
|
|
85
|
+
|
|
86
|
+
// Mean is always M1
|
|
87
|
+
if ( stats.mean ) state.mean = M1;
|
|
88
|
+
|
|
89
|
+
// Min/max are pass-through
|
|
90
|
+
computeMinMax( state, stats, msg );
|
|
91
|
+
|
|
92
|
+
// Check if any variance-dependent stats requested
|
|
93
|
+
const needsVariance = stats.variance || stats.stddev || stats.cv || stats.skew || stats.kurtosis;
|
|
94
|
+
if ( !needsVariance ) return state;
|
|
95
|
+
|
|
96
|
+
// Variance-dependent stats require n >= 2
|
|
97
|
+
if ( n < 2 ) {
|
|
98
|
+
setVarianceStatsNaN( state, stats );
|
|
99
|
+
return state;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Population variance (M2/n) used for skew/kurtosis denominators
|
|
103
|
+
const m2 = M2 / n;
|
|
104
|
+
|
|
105
|
+
// When m2 < eps: variance/stddev are 0, cv/skew/kurtosis are NaN
|
|
106
|
+
if ( m2 < eps ) {
|
|
107
|
+
if ( stats.variance ) state.variance = 0;
|
|
108
|
+
if ( stats.stddev ) state.stddev = 0;
|
|
109
|
+
if ( stats.cv ) state.cv = NaN;
|
|
110
|
+
if ( stats.skew ) state.skew = NaN;
|
|
111
|
+
if ( stats.kurtosis ) state.kurtosis = NaN;
|
|
112
|
+
return state;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
computeVarianceStats( state, stats, msg, M1, M2, n, m2, eps );
|
|
116
|
+
|
|
117
|
+
return state;
|
|
118
|
+
}; // update()
|
|
119
|
+
|
|
120
|
+
export default update;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// nodes/dwell-time-tracker/index.js
|
|
2
|
+
|
|
3
|
+
export { default as init } from './init.js';
|
|
4
|
+
export { default as update } from './update.js';
|
|
5
|
+
export { default as reset } from './reset.js';
|
|
6
|
+
export { default as recompute } from './recompute.js';
|
|
7
|
+
export { default as publishTo } from './publish-to.js';
|
|
8
|
+
// Direct imports for common control functions
|
|
9
|
+
export { default as disable } from '../../core/utils/node/disable.js';
|
|
10
|
+
export { default as enable } from '../../core/utils/node/enable.js';
|
|
11
|
+
export { default as pause } from '../../core/utils/node/pause.js';
|
|
12
|
+
export { default as unpause } from '../../core/utils/node/unpause.js';
|
|
13
|
+
// Re-export everything from introspection.js
|
|
14
|
+
export * from './introspect.js';
|