@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,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pauses a node — skips update() but still runs publishTo()
|
|
3
|
+
* @param {Object} state - The node's state object
|
|
4
|
+
* @returns {boolean} - Always returns true for consistency with control methods
|
|
5
|
+
*/
|
|
6
|
+
const pause = function ( state ) {
|
|
7
|
+
state.pause = true;
|
|
8
|
+
return true;
|
|
9
|
+
}; // pause()
|
|
10
|
+
|
|
11
|
+
export default pause;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Populates required fields and prepares projected inputs for predicate
|
|
3
|
+
* @param {Object} state - Node state containing requires and predicateInput
|
|
4
|
+
* @param {Object} msg - Message to validate
|
|
5
|
+
* @returns {string|null} - Name of invalid field or null if all valid
|
|
6
|
+
*/
|
|
7
|
+
const populatePredicateInput = function ( state, msg ) {
|
|
8
|
+
for ( let i = 0; i < state.requires.length; i += 1 ) {
|
|
9
|
+
const field = state.requires[ i ];
|
|
10
|
+
state.predicateInput[ field ] = msg[ field ];
|
|
11
|
+
}
|
|
12
|
+
}; // copyRequiredFields()
|
|
13
|
+
|
|
14
|
+
export default populatePredicateInput;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// core/utils/node/publish-nan.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Publishes NaN for all configured stats. It is needed for per node
|
|
5
|
+
* based fault isolation based on usage of NaNed parameters.
|
|
6
|
+
*
|
|
7
|
+
* Only call this AFTER checking state.inputValidationFailed is true!
|
|
8
|
+
*
|
|
9
|
+
* @param {Object} state - Node state containing stats configuration
|
|
10
|
+
* @param {Object} msg - Message to publish NaN values to
|
|
11
|
+
*/
|
|
12
|
+
const publishNaN = function ( state, msg ) {
|
|
13
|
+
// eslint-disable-next-line guard-for-in
|
|
14
|
+
for ( const stat in state.stats ) {
|
|
15
|
+
msg[ state.stats[ stat ].storeAs ] = NaN;
|
|
16
|
+
}
|
|
17
|
+
}; // publishNaN()
|
|
18
|
+
|
|
19
|
+
export default publishNaN;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resets predicateInput object for next message
|
|
3
|
+
* @param {Object} state - Node state containing requires and predicateInput
|
|
4
|
+
*/
|
|
5
|
+
const resetPredicateInput = function ( state ) {
|
|
6
|
+
for ( let i = 0; i < state.requires.length; i += 1 ) {
|
|
7
|
+
state.predicateInput[ state.requires[ i ] ] = undefined;
|
|
8
|
+
}
|
|
9
|
+
}; // resetPredicateInput()
|
|
10
|
+
|
|
11
|
+
export default resetPredicateInput;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resumes a paused node — update() runs again
|
|
3
|
+
* @param {Object} state - The node's state object
|
|
4
|
+
* @returns {boolean} - Always returns true for consistency with control methods
|
|
5
|
+
*/
|
|
6
|
+
const unpause = function ( state ) {
|
|
7
|
+
state.pause = false;
|
|
8
|
+
return true;
|
|
9
|
+
}; // unpause()
|
|
10
|
+
|
|
11
|
+
export default unpause;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { validateWithSchema } from '../validate/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validate a node specification against its DSL metadata schema.
|
|
5
|
+
* Standard validation for all nodes during initialization.
|
|
6
|
+
*
|
|
7
|
+
* @param {Object} spec - Node specification to validate
|
|
8
|
+
* @param {Function} introspect - Node's introspection module
|
|
9
|
+
* @throws {TypeError} If validation fails with detailed error messages
|
|
10
|
+
*/
|
|
11
|
+
const validateSpec = function ( spec, introspect ) {
|
|
12
|
+
const metadata = introspect.getDSLMetadata();
|
|
13
|
+
const schema = {
|
|
14
|
+
...metadata.specSchema,
|
|
15
|
+
_crossFieldValidators: metadata.crossFieldValidators
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const validation = validateWithSchema( schema, spec, 'spec' );
|
|
19
|
+
validation.throwIfInvalid( introspect.getNodeType() );
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default validateSpec;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Utility for resolving field-keyed options in node init.
|
|
3
|
+
*
|
|
4
|
+
* Supports uniform DX where parameters can be specified as either:
|
|
5
|
+
* - Direct values (same for all expanded fields)
|
|
6
|
+
* - Field-keyed objects (per-field values, extracted at init time)
|
|
7
|
+
*
|
|
8
|
+
* Three resolution patterns:
|
|
9
|
+
* 1. resolveScalar — for simple values (number, string, boolean, function)
|
|
10
|
+
* 2. resolveNestedObject — for structured objects (like { min, max })
|
|
11
|
+
* 3. resolveArray — for array values (like thresholds, categories)
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // Direct scalar
|
|
15
|
+
* resolveScalar( 20, 'temp' ) // → 20
|
|
16
|
+
*
|
|
17
|
+
* // Field-keyed scalar
|
|
18
|
+
* resolveScalar( { temp: 5, pressure: 20 }, 'temp' ) // → 5
|
|
19
|
+
*
|
|
20
|
+
* // Direct nested object
|
|
21
|
+
* resolveNestedObject( { min: 0, max: 100 }, 'temp', [ 'min', 'max' ] ) // → { min: 0, max: 100 }
|
|
22
|
+
*
|
|
23
|
+
* // Field-keyed nested object
|
|
24
|
+
* resolveNestedObject(
|
|
25
|
+
* { temp: { min: -40, max: 85 }, pressure: { min: 0, max: 120 } },
|
|
26
|
+
* 'temp',
|
|
27
|
+
* [ 'min', 'max' ]
|
|
28
|
+
* ) // → { min: -40, max: 85 }
|
|
29
|
+
*
|
|
30
|
+
* // Direct array
|
|
31
|
+
* resolveArray( [ 10, 50, 90 ], 'temp' ) // → [ 10, 50, 90 ]
|
|
32
|
+
*
|
|
33
|
+
* // Field-keyed array
|
|
34
|
+
* resolveArray( { temp: [ 10, 50, 90 ], pressure: [ 5, 25, 75 ] }, 'temp' ) // → [ 10, 50, 90 ]
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolve scalar option (number, string, boolean, function).
|
|
39
|
+
*
|
|
40
|
+
* @param {*} option - The option value from spec
|
|
41
|
+
* @param {string} fieldName - The node's input field (state.x)
|
|
42
|
+
* @returns {*} Resolved scalar value or undefined
|
|
43
|
+
*/
|
|
44
|
+
export const resolveScalar = function ( option, fieldName ) {
|
|
45
|
+
// Null/undefined passthrough
|
|
46
|
+
if ( option === null || option === undefined ) return undefined;
|
|
47
|
+
|
|
48
|
+
// Scalar or function — return directly
|
|
49
|
+
if ( typeof option !== 'object' ) return option;
|
|
50
|
+
|
|
51
|
+
// Array — not a scalar, return undefined (use resolveArray instead)
|
|
52
|
+
if ( Array.isArray( option ) ) return undefined;
|
|
53
|
+
|
|
54
|
+
// Object — try field-keyed extraction
|
|
55
|
+
if ( fieldName in option ) {
|
|
56
|
+
const value = option[ fieldName ];
|
|
57
|
+
// Accept scalar or function, reject nested objects (unless function)
|
|
58
|
+
if ( typeof value !== 'object' || typeof value === 'function' ) {
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Object without field key — not a valid scalar spec
|
|
64
|
+
return undefined;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Resolve nested object option (like ranges: { min, max }).
|
|
69
|
+
*
|
|
70
|
+
* @param {*} option - The option value from spec
|
|
71
|
+
* @param {string} fieldName - The node's input field (state.x)
|
|
72
|
+
* @param {string[]} expectedKeys - Keys that identify direct spec (e.g., [ 'min', 'max' ])
|
|
73
|
+
* @returns {Object|undefined} Resolved object or undefined
|
|
74
|
+
*/
|
|
75
|
+
export const resolveNestedObject = function ( option, fieldName, expectedKeys ) {
|
|
76
|
+
// Null/undefined/non-object passthrough
|
|
77
|
+
if ( option === null || option === undefined ) return undefined;
|
|
78
|
+
if ( typeof option !== 'object' || Array.isArray( option ) ) return undefined;
|
|
79
|
+
|
|
80
|
+
// Try field-keyed first: option[fieldName] is object with expected keys
|
|
81
|
+
const fieldKeyed = option[ fieldName ];
|
|
82
|
+
if ( fieldKeyed && typeof fieldKeyed === 'object' && !Array.isArray( fieldKeyed ) ) {
|
|
83
|
+
const hasExpectedKey = expectedKeys.some( ( k ) => k in fieldKeyed );
|
|
84
|
+
if ( hasExpectedKey ) return fieldKeyed;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Fall back to direct: option itself has expected keys
|
|
88
|
+
const hasDirect = expectedKeys.some( ( k ) => k in option );
|
|
89
|
+
if ( hasDirect ) return option;
|
|
90
|
+
|
|
91
|
+
return undefined;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Resolve array option (like thresholds, categories, valueList).
|
|
96
|
+
*
|
|
97
|
+
* @param {*} option - The option value from spec
|
|
98
|
+
* @param {string} fieldName - The node's input field (state.x)
|
|
99
|
+
* @returns {Array|undefined} Resolved array or undefined
|
|
100
|
+
*/
|
|
101
|
+
export const resolveArray = function ( option, fieldName ) {
|
|
102
|
+
// Null/undefined passthrough
|
|
103
|
+
if ( option === null || option === undefined ) return undefined;
|
|
104
|
+
|
|
105
|
+
// Direct array — return as-is
|
|
106
|
+
if ( Array.isArray( option ) ) return option;
|
|
107
|
+
|
|
108
|
+
// Object — try field-keyed extraction
|
|
109
|
+
if ( typeof option === 'object' ) {
|
|
110
|
+
const fieldValue = option[ fieldName ];
|
|
111
|
+
if ( Array.isArray( fieldValue ) ) return fieldValue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return undefined;
|
|
115
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// core/utils/quantize/index.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Snap a value to the nearest multiple of a declared
|
|
5
|
+
* resolution.
|
|
6
|
+
*
|
|
7
|
+
* Adapter authors honouring a column's `resolution` (declared in the
|
|
8
|
+
* semantics layer) need to round values to that resolution's grid before
|
|
9
|
+
* storing or displaying them. QuestDB does this when it writes float64
|
|
10
|
+
* columns; the terminal emitter does it when it formats float64 values
|
|
11
|
+
* for human reading. Both used to carry their own copy of the same
|
|
12
|
+
* formula; this module is the single source.
|
|
13
|
+
*
|
|
14
|
+
* The quantizer pre-computes the inverse resolution and the appropriate
|
|
15
|
+
* decimal-place count at build time, so the per-message hot path is one
|
|
16
|
+
* multiply, one round, one multiply, one `toFixed` — no allocation, no
|
|
17
|
+
* recomputation.
|
|
18
|
+
*
|
|
19
|
+
* Decimal places follow the natural rule:
|
|
20
|
+
* - `resolution = 0.001` → 3 decimal places
|
|
21
|
+
* - `resolution = 0.01` → 2 decimal places
|
|
22
|
+
* - `resolution = 0.1` → 1 decimal place
|
|
23
|
+
* - `resolution = 1` → 0 (returns `null`, signalling passthrough)
|
|
24
|
+
* - `resolution = 5` → 0 (whole-number resolution; values still
|
|
25
|
+
* snap to multiples of 5, but no decimals to
|
|
26
|
+
* format)
|
|
27
|
+
*
|
|
28
|
+
* The `toFixed` step cleans up floating-point noise — for example,
|
|
29
|
+
* `Math.round( 10.1 * 10 ) * 0.1` produces `10.100000000001` because
|
|
30
|
+
* of IEEE-754 rounding, and `toFixed(1)` returns the tidy `"10.1"`
|
|
31
|
+
* which `Number(...)` parses back to `10.1`.
|
|
32
|
+
*
|
|
33
|
+
* Returning `null` for `resolution === 1` (or undefined) is a small but
|
|
34
|
+
* load-bearing optimisation: the common case is "no resolution declared"
|
|
35
|
+
* (or `resolution: 1`, which is the schema's default), and callers can
|
|
36
|
+
* skip a wrapping closure entirely. QDB's `writers.js` uses this to
|
|
37
|
+
* route to its `QUEST_WRITERS.float64` passthrough writer; terminal's
|
|
38
|
+
* `formatters.js` uses it to skip per-column quantizer registration.
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Build a quantizer closure that snaps a value to the nearest multiple
|
|
43
|
+
* of `resolution`. Returns `null` when the resolution does not need
|
|
44
|
+
* quantization (undefined, or 1) — callers handle the null by treating
|
|
45
|
+
* the value as passthrough.
|
|
46
|
+
*
|
|
47
|
+
* Sample usage:
|
|
48
|
+
*
|
|
49
|
+
* const quantize = buildResolutionQuantizer( 0.1 );
|
|
50
|
+
* if ( quantize ) {
|
|
51
|
+
* const clean = quantize( 23.456 ); // → 23.5
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* @param {number|undefined} resolution - The declared resolution from
|
|
55
|
+
* the column's semantics. Must be a positive finite number for
|
|
56
|
+
* meaningful quantization; the caller is responsible for asserting
|
|
57
|
+
* that (we trust the input here).
|
|
58
|
+
* @returns {function(number): number|null} A quantizer function, or
|
|
59
|
+
* `null` when no quantization is needed.
|
|
60
|
+
*/
|
|
61
|
+
const buildResolutionQuantizer = function ( resolution ) {
|
|
62
|
+
if ( resolution === undefined || resolution === 1 ) return null;
|
|
63
|
+
|
|
64
|
+
const invResolution = 1 / resolution;
|
|
65
|
+
const decimalPlaces = resolution < 1 ?
|
|
66
|
+
Math.ceil( -Math.log10( resolution ) ) :
|
|
67
|
+
0;
|
|
68
|
+
|
|
69
|
+
return function ( v ) {
|
|
70
|
+
const quantized = Math.round( v * invResolution ) * resolution;
|
|
71
|
+
return Number( quantized.toFixed( decimalPlaces ) );
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export { buildResolutionQuantizer };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// core/utils/stats/formulas.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Pure functions that compute statistics from central moments.
|
|
5
|
+
*
|
|
6
|
+
* Shared by digestMoments (converts raw moments to stats) and twStats
|
|
7
|
+
* (tumbling window stats with deferred computation at publish time).
|
|
8
|
+
*
|
|
9
|
+
* All formulas use unnormalized central moments (M2 = sum of squared deviations,
|
|
10
|
+
* not M2/n) as input, consistent with Pébay's incremental algorithm output.
|
|
11
|
+
*
|
|
12
|
+
* @see https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
|
|
13
|
+
* @see Pébay, P. (2008). Sandia Report SAND2008-6212.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Compute sample variance from second central moment.
|
|
18
|
+
* @param {number} M2 - Second central moment (sum of squared deviations)
|
|
19
|
+
* @param {number} n - Sample count
|
|
20
|
+
* @param {boolean} biased - If true, divide by n (population); else by n-1 (sample)
|
|
21
|
+
* @returns {number} Variance
|
|
22
|
+
*/
|
|
23
|
+
export const computeVariance = function ( M2, n, biased ) {
|
|
24
|
+
const divisor = biased ? n : ( n - 1 );
|
|
25
|
+
return M2 / divisor;
|
|
26
|
+
}; // computeVariance()
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Compute coefficient of variation.
|
|
30
|
+
* @param {number} stddev - Standard deviation
|
|
31
|
+
* @param {number} mean - Arithmetic mean
|
|
32
|
+
* @param {number} eps - Epsilon for numerical stability
|
|
33
|
+
* @returns {number} CV or NaN if mean is near zero
|
|
34
|
+
*/
|
|
35
|
+
export const computeCV = function ( stddev, mean, eps ) {
|
|
36
|
+
return ( Math.abs( mean ) > eps ) ? ( stddev / Math.abs( mean ) ) : NaN;
|
|
37
|
+
}; // computeCV()
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Compute skewness: m3 / m2^1.5 (population skewness)
|
|
41
|
+
* @param {number} M3 - Third central moment
|
|
42
|
+
* @param {number} n - Sample count
|
|
43
|
+
* @param {number} m2 - Population variance (M2/n)
|
|
44
|
+
* @param {number} eps - Epsilon for numerical stability
|
|
45
|
+
* @returns {number} Skewness or NaN/0 for edge cases
|
|
46
|
+
*/
|
|
47
|
+
export const computeSkew = function ( M3, n, m2, eps ) {
|
|
48
|
+
if ( !Number.isFinite( M3 ) ) return NaN;
|
|
49
|
+
const m3 = M3 / n;
|
|
50
|
+
const denom = Math.pow( m2, 1.5 );
|
|
51
|
+
return ( denom > eps ) ? ( m3 / denom ) : 0;
|
|
52
|
+
}; // computeSkew()
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Compute excess kurtosis: (m4 / m2²) - 3
|
|
56
|
+
* @param {number} M4 - Fourth central moment
|
|
57
|
+
* @param {number} n - Sample count
|
|
58
|
+
* @param {number} m2 - Population variance (M2/n)
|
|
59
|
+
* @param {number} eps - Epsilon for numerical stability
|
|
60
|
+
* @returns {number} Excess kurtosis or NaN/-3 for edge cases
|
|
61
|
+
*/
|
|
62
|
+
export const computeKurtosis = function ( M4, n, m2, eps ) {
|
|
63
|
+
if ( !Number.isFinite( M4 ) ) return NaN;
|
|
64
|
+
const m4 = M4 / n;
|
|
65
|
+
const denom = m2 * m2;
|
|
66
|
+
return ( denom > eps ) ? ( ( m4 / denom ) - 3 ) : -3;
|
|
67
|
+
}; // computeKurtosis()
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WinkComposer-specific validators
|
|
3
|
+
* Domain-specific validation functions for streaming analytics nodes
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { validators } from './validators.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validates node field specification
|
|
10
|
+
*/
|
|
11
|
+
const nodeField = function ( value ) {
|
|
12
|
+
return typeof value === 'object' &&
|
|
13
|
+
value !== null &&
|
|
14
|
+
typeof value.field === 'string' &&
|
|
15
|
+
value.field.length > 0 &&
|
|
16
|
+
validators.identifier( value.field );
|
|
17
|
+
}; // nodeField()
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validates trigger specification
|
|
21
|
+
*/
|
|
22
|
+
const trigger = function ( value ) {
|
|
23
|
+
if ( typeof value !== 'object' || value === null ) return false;
|
|
24
|
+
|
|
25
|
+
// Control must be a valid method name
|
|
26
|
+
if ( typeof value.control !== 'string' || !validators.identifier( value.control ) ) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Targets must be an array of valid identifiers
|
|
31
|
+
if ( !Array.isArray( value.targets ) || value.targets.length === 0 ) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return value.targets.every( ( target ) =>
|
|
36
|
+
typeof target === 'string' && validators.identifier( target )
|
|
37
|
+
);
|
|
38
|
+
}; // trigger()
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Validates statistical output specification
|
|
42
|
+
*/
|
|
43
|
+
const statSpec = function ( value ) {
|
|
44
|
+
return typeof value === 'object' &&
|
|
45
|
+
value !== null &&
|
|
46
|
+
typeof value.storeAs === 'string' &&
|
|
47
|
+
validators.identifier( value.storeAs );
|
|
48
|
+
}; // statSpec()
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Validates predicate function
|
|
52
|
+
*/
|
|
53
|
+
const predicate = function ( value ) {
|
|
54
|
+
return typeof value === 'function' && value.length === 1;
|
|
55
|
+
}; // predicate()
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Validates EWMA alpha parameter
|
|
59
|
+
*/
|
|
60
|
+
const alpha = function ( value ) {
|
|
61
|
+
return typeof value === 'number' && value > 0 && value < 1;
|
|
62
|
+
}; // alpha()
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Validates EWMA half-life parameter
|
|
66
|
+
*/
|
|
67
|
+
const halfLife = function ( value ) {
|
|
68
|
+
return typeof value === 'number' && value > 0 && value < 999999;
|
|
69
|
+
}; // alpha()
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Validates window size
|
|
73
|
+
*/
|
|
74
|
+
const windowSize = function ( value ) {
|
|
75
|
+
return Number.isInteger( value ) && value > 0;
|
|
76
|
+
}; // windowSize()
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Validates decay factor (for exponential decay)
|
|
80
|
+
*/
|
|
81
|
+
const decayFactor = function ( value ) {
|
|
82
|
+
return typeof value === 'number' && value > 0 && value < 1;
|
|
83
|
+
}; // decayFactor()
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Validates threshold specification
|
|
87
|
+
*/
|
|
88
|
+
const threshold = function ( value ) {
|
|
89
|
+
return typeof value === 'number' && !Number.isNaN( value );
|
|
90
|
+
}; // threshold()
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Validates statistical method names
|
|
94
|
+
*/
|
|
95
|
+
const statMethod = function ( value ) {
|
|
96
|
+
const validMethods = [
|
|
97
|
+
'mean', 'variance', 'stddev', 'sum', 'count',
|
|
98
|
+
'min', 'max', 'range', 'skewness', 'kurtosis'
|
|
99
|
+
];
|
|
100
|
+
return typeof value === 'string' && validMethods.includes( value );
|
|
101
|
+
}; // statMethod()
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Validates node type specification
|
|
105
|
+
*/
|
|
106
|
+
const nodeType = function ( value ) {
|
|
107
|
+
return typeof value === 'string' &&
|
|
108
|
+
value.length > 0 &&
|
|
109
|
+
value.length <= 50; // Reasonable limit for node type names
|
|
110
|
+
}; // nodeType()
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Cross-field validator to prevent self-triggering
|
|
114
|
+
* Ensures a node doesn't list itself in trigger targets
|
|
115
|
+
*/
|
|
116
|
+
const noSelfTriggers = {
|
|
117
|
+
fields: [ 'name', 'triggers' ],
|
|
118
|
+
validator: ( spec ) => {
|
|
119
|
+
if ( !spec.triggers ) return true;
|
|
120
|
+
return spec.triggers.every( ( trgr ) =>
|
|
121
|
+
!trgr.targets.includes( spec.name )
|
|
122
|
+
);
|
|
123
|
+
},
|
|
124
|
+
error: 'composer/validation: Node cannot trigger control methods on itself'
|
|
125
|
+
}; // noSelfTriggers
|
|
126
|
+
|
|
127
|
+
// Export all composer validators
|
|
128
|
+
export const composerValidators = {
|
|
129
|
+
nodeField,
|
|
130
|
+
trigger,
|
|
131
|
+
statSpec,
|
|
132
|
+
predicate,
|
|
133
|
+
alpha,
|
|
134
|
+
halfLife,
|
|
135
|
+
windowSize,
|
|
136
|
+
decayFactor,
|
|
137
|
+
threshold,
|
|
138
|
+
statMethod,
|
|
139
|
+
nodeType,
|
|
140
|
+
noSelfTriggers
|
|
141
|
+
};
|