@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,134 @@
|
|
|
1
|
+
import { validators, composerValidators } from '../../core/utils/validate/index.js';
|
|
2
|
+
|
|
3
|
+
/** Single source of truth for what this node can do */
|
|
4
|
+
const SUPPORTED_STATS = [
|
|
5
|
+
'dashboard',
|
|
6
|
+
'alerts',
|
|
7
|
+
'database',
|
|
8
|
+
'monitoring'
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
/** QoS level constants for performance (numeric comparison in hot path) */
|
|
12
|
+
export const QOS_FIRE_AND_FORGET = 0;
|
|
13
|
+
export const QOS_BEST_EFFORT = 1;
|
|
14
|
+
export const QOS_RELIABLE = 2;
|
|
15
|
+
|
|
16
|
+
/** Human-readable descriptions */
|
|
17
|
+
const STAT_DESCRIPTIONS = {
|
|
18
|
+
dashboard: 'Real-time dashboard connections',
|
|
19
|
+
alerts: 'Alert system connections',
|
|
20
|
+
database: 'Database sink connections',
|
|
21
|
+
monitoring: 'System monitoring connections'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** QoS level descriptions */
|
|
25
|
+
const QOS_DESCRIPTIONS = {
|
|
26
|
+
[ QOS_FIRE_AND_FORGET ]: 'Fire-and-forget: No queuing, drop on backpressure (fastest)',
|
|
27
|
+
[ QOS_BEST_EFFORT ]: 'Best-effort: Small queue, drop oldest on overflow (balanced)',
|
|
28
|
+
[ QOS_RELIABLE ]: 'Reliable: Large queue, backpressure monitoring (most reliable)'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** The type of this node */
|
|
32
|
+
const NODE_TYPE = 'SSE Emitter';
|
|
33
|
+
|
|
34
|
+
/** Node capabilities */
|
|
35
|
+
const CAPABILITIES = {
|
|
36
|
+
description: 'Broadcasts entire messages via Server-Sent Events with configurable QoS levels',
|
|
37
|
+
features: [
|
|
38
|
+
'Terminal node - broadcasts complete pipeline messages',
|
|
39
|
+
'Four endpoint types: dashboard, alerts, database, monitoring',
|
|
40
|
+
'Numeric QoS levels: 0 (fire-and-forget), 1 (best-effort), 2 (reliable)',
|
|
41
|
+
'High-performance broadcasting with buffer reuse',
|
|
42
|
+
'Production-ready connection management'
|
|
43
|
+
]
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Export functions for accessing metadata
|
|
47
|
+
export const getSupportedStats = () => SUPPORTED_STATS.slice();
|
|
48
|
+
export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
|
|
49
|
+
export const getNodeType = () => NODE_TYPE;
|
|
50
|
+
export const getCapabilities = () => ( { ...CAPABILITIES } );
|
|
51
|
+
export const getQoSDescriptions = () => ( { ...QOS_DESCRIPTIONS } );
|
|
52
|
+
|
|
53
|
+
// DSL Metadata
|
|
54
|
+
const DSL_METADATA = {
|
|
55
|
+
// Validation schema
|
|
56
|
+
specSchema: {
|
|
57
|
+
nodeType: {
|
|
58
|
+
type: 'string',
|
|
59
|
+
required: true,
|
|
60
|
+
value: NODE_TYPE,
|
|
61
|
+
validator: composerValidators.nodeType,
|
|
62
|
+
error: 'Invalid node type'
|
|
63
|
+
},
|
|
64
|
+
name: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
required: true,
|
|
67
|
+
validator: validators.identifier,
|
|
68
|
+
error: 'Name must be a valid JavaScript identifier'
|
|
69
|
+
},
|
|
70
|
+
// Note: No 'from' field - terminal node broadcasts entire message
|
|
71
|
+
port: {
|
|
72
|
+
type: 'number',
|
|
73
|
+
required: false,
|
|
74
|
+
default: 3000, // Documentation only!
|
|
75
|
+
min: 1024,
|
|
76
|
+
max: 65535,
|
|
77
|
+
integer: true,
|
|
78
|
+
error: 'Port must be between 1024 and 65535'
|
|
79
|
+
},
|
|
80
|
+
maxConnections: {
|
|
81
|
+
type: 'number',
|
|
82
|
+
required: false,
|
|
83
|
+
default: 4, // Documentation only!
|
|
84
|
+
min: 1,
|
|
85
|
+
max: 10,
|
|
86
|
+
integer: true,
|
|
87
|
+
validator: validators.positiveInteger,
|
|
88
|
+
error: 'Max connections must be between 1 and 10'
|
|
89
|
+
},
|
|
90
|
+
stats: {
|
|
91
|
+
type: 'object',
|
|
92
|
+
required: true,
|
|
93
|
+
minProperties: 1,
|
|
94
|
+
propertyNames: SUPPORTED_STATS, // Array of allowed endpoint names
|
|
95
|
+
propertySchema: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
required: true,
|
|
98
|
+
validator: composerValidators.statSpec, // Using composerValidator!
|
|
99
|
+
properties: {
|
|
100
|
+
qos: {
|
|
101
|
+
type: 'number',
|
|
102
|
+
required: false,
|
|
103
|
+
default: 0, // Documentation only!
|
|
104
|
+
integer: true,
|
|
105
|
+
validator: validators.oneOf( [ 0, 1, 2 ] ),
|
|
106
|
+
error: 'QoS must be 0 (fire-and-forget), 1 (best-effort), or 2 (reliable)'
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
error: 'Stats must define at least one endpoint with valid configuration'
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
// 3. Cross-field validators - none needed for SSE Emitter
|
|
115
|
+
crossFieldValidators: [],
|
|
116
|
+
|
|
117
|
+
// 4. Build spec from DSL
|
|
118
|
+
buildSpec: function ( port = 3000, maxConnections = 4 ) {
|
|
119
|
+
return {
|
|
120
|
+
nodeType: NODE_TYPE,
|
|
121
|
+
name: '{{AUTO_NAME}}',
|
|
122
|
+
port,
|
|
123
|
+
maxConnections,
|
|
124
|
+
stats: {
|
|
125
|
+
dashboard: { storeAs: 'dashConnected', qos: 0 }, // Default fire-and-forget
|
|
126
|
+
database: { storeAs: 'dbConnected', qos: 2 } // Default reliable
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
acceptsSpecObject: true
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const getDSLMetadata = () => ({ ...DSL_METADATA });
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const recompute = function ( state ) {
|
|
2
|
+
// Recompute total connection count from all endpoints
|
|
3
|
+
let totalConnections = 0;
|
|
4
|
+
|
|
5
|
+
for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
|
|
6
|
+
const endpointName = state.endpointNames[i];
|
|
7
|
+
totalConnections += state.connections[endpointName].length;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
state.totalConnections = totalConnections;
|
|
11
|
+
|
|
12
|
+
console.log( `composer/sseEmitter: Recomputed ${state.totalConnections} active connections across ${state.endpointNames.length} endpoints` );
|
|
13
|
+
return true;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default recompute;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const reset = function ( state ) {
|
|
2
|
+
// Reset statistics only (keep connections active)
|
|
3
|
+
state.totalSent = 0;
|
|
4
|
+
state.totalErrors = 0;
|
|
5
|
+
|
|
6
|
+
// Reset per-connection message counts
|
|
7
|
+
for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
|
|
8
|
+
const endpointName = state.endpointNames[ i ];
|
|
9
|
+
const connections = state.connections[ endpointName ];
|
|
10
|
+
|
|
11
|
+
for ( let j = 0; j < connections.length; j += 1 ) {
|
|
12
|
+
connections[ j ].messagesSent = 0;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return true;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default reset;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { buildMessage } from './utils/build-message.js';
|
|
2
|
+
import { QOS_HANDLERS } from './utils/qos-handler.js';
|
|
3
|
+
|
|
4
|
+
const cleanupDeadConnections = function ( state, connections, deadConnections ) {
|
|
5
|
+
// Remove dead connections in reverse order to maintain indices
|
|
6
|
+
for ( let i = deadConnections.length - 1; i >= 0; i -= 1 ) {
|
|
7
|
+
connections.splice( deadConnections[ i ], 1 );
|
|
8
|
+
state.totalConnections -= 1;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Return array to pool for reuse
|
|
12
|
+
state.deadConnectionsPool.push( deadConnections );
|
|
13
|
+
}; // cleanupDeadConnections()
|
|
14
|
+
|
|
15
|
+
const broadcastToEndpoint = function ( state, connections, message, endpointName ) {
|
|
16
|
+
// Get reusable dead connections array
|
|
17
|
+
const deadConnections = state.deadConnectionsPool.pop() || [];
|
|
18
|
+
deadConnections.length = 0;
|
|
19
|
+
|
|
20
|
+
// Fast iteration with minimal nesting
|
|
21
|
+
for ( let i = 0; i < connections.length; i += 1 ) {
|
|
22
|
+
const connection = connections[ i ];
|
|
23
|
+
|
|
24
|
+
if ( !connection.response.writable ) {
|
|
25
|
+
deadConnections.push( i );
|
|
26
|
+
continue; // eslint-disable-line no-continue
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
// O(1) QoS handler dispatch - no switch statement nesting
|
|
31
|
+
const qosHandler = QOS_HANDLERS[ connection.qos ] || QOS_HANDLERS[ 0 ];
|
|
32
|
+
qosHandler( connection, message, state, endpointName );
|
|
33
|
+
} catch {
|
|
34
|
+
deadConnections.push( i );
|
|
35
|
+
state.totalErrors += 1;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
cleanupDeadConnections( state, connections, deadConnections );
|
|
40
|
+
}; // broadcastToEndpoint()
|
|
41
|
+
|
|
42
|
+
// High-performance broadcast with zero allocations
|
|
43
|
+
const update = function ( state, msg ) {
|
|
44
|
+
// Fast path: no connections
|
|
45
|
+
if ( state.totalConnections === 0 ) return;
|
|
46
|
+
|
|
47
|
+
// Add connection counts directly to the message
|
|
48
|
+
for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
|
|
49
|
+
const endpointName = state.endpointNames[ i ];
|
|
50
|
+
const storeAs = state.stats[ endpointName ].storeAs;
|
|
51
|
+
msg[ storeAs ] = state.connections[ endpointName ].length;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Serialize entire message (only unavoidable allocation)
|
|
55
|
+
const jsonString = JSON.stringify( msg );
|
|
56
|
+
const messageToSend = buildMessage( state, jsonString );
|
|
57
|
+
|
|
58
|
+
// Broadcast to all configured endpoints
|
|
59
|
+
for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
|
|
60
|
+
const endpointName = state.endpointNames[ i ];
|
|
61
|
+
const connections = state.connections[ endpointName ];
|
|
62
|
+
|
|
63
|
+
if ( connections.length > 0 ) {
|
|
64
|
+
broadcastToEndpoint( state, connections, messageToSend, endpointName );
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}; // update()
|
|
68
|
+
|
|
69
|
+
export default update;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// utils/broadcast-heartbeat.js
|
|
2
|
+
|
|
3
|
+
const HEARTBEAT_MESSAGE = Buffer.from(':heartbeat\n\n');
|
|
4
|
+
|
|
5
|
+
export const broadcastHeartbeat = function (state) {
|
|
6
|
+
// SSE comment format (`:` prefix) keeps connection alive without triggering client events
|
|
7
|
+
|
|
8
|
+
for (let i = 0; i < state.endpointNames.length; i += 1) {
|
|
9
|
+
const endpointName = state.endpointNames[i];
|
|
10
|
+
const connections = state.connections[endpointName];
|
|
11
|
+
|
|
12
|
+
// Track dead connections
|
|
13
|
+
const deadIndices = [];
|
|
14
|
+
|
|
15
|
+
for (let j = 0; j < connections.length; j += 1) {
|
|
16
|
+
const connection = connections[j];
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
if (connection.response.writable) {
|
|
20
|
+
connection.response.write(HEARTBEAT_MESSAGE);
|
|
21
|
+
} else {
|
|
22
|
+
deadIndices.push(j);
|
|
23
|
+
}
|
|
24
|
+
} catch ( error ) {
|
|
25
|
+
console.error(`composer/emitter: Write error on ${endpointName}:`, error.message);
|
|
26
|
+
deadIndices.push(j);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Clean up dead connections
|
|
31
|
+
for (let k = deadIndices.length - 1; k >= 0; k -= 1) {
|
|
32
|
+
connections.splice(deadIndices[k], 1);
|
|
33
|
+
state.totalConnections -= 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// utils/build-message.js
|
|
2
|
+
|
|
3
|
+
const DATA_PREFIX = Buffer.from( 'data: ' );
|
|
4
|
+
const MESSAGE_SUFFIX = Buffer.from( '\n\n' );
|
|
5
|
+
|
|
6
|
+
const buildMessage = function ( state, jsonString ) {
|
|
7
|
+
const { messageBuffer, dataPrefix, messageSuffix } = state;
|
|
8
|
+
const jsonBuffer = Buffer.from( jsonString, 'utf8' );
|
|
9
|
+
const totalSize = dataPrefix.length + jsonBuffer.length + messageSuffix.length;
|
|
10
|
+
|
|
11
|
+
// Use reusable buffer for small messages
|
|
12
|
+
if ( totalSize <= messageBuffer.length ) {
|
|
13
|
+
let offset = 0;
|
|
14
|
+
|
|
15
|
+
dataPrefix.copy( messageBuffer, offset );
|
|
16
|
+
offset += dataPrefix.length;
|
|
17
|
+
|
|
18
|
+
jsonBuffer.copy( messageBuffer, offset );
|
|
19
|
+
offset += jsonBuffer.length;
|
|
20
|
+
|
|
21
|
+
messageSuffix.copy( messageBuffer, offset );
|
|
22
|
+
offset += messageSuffix.length;
|
|
23
|
+
|
|
24
|
+
return messageBuffer.subarray( 0, offset );
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Fallback for large messages
|
|
28
|
+
return Buffer.concat( [ dataPrefix, jsonBuffer, messageSuffix ] );
|
|
29
|
+
}; // buildSSEMessage()
|
|
30
|
+
|
|
31
|
+
export { buildMessage, DATA_PREFIX, MESSAGE_SUFFIX };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// utils/connection-manager.js
|
|
2
|
+
|
|
3
|
+
const createSSEHeaders = function () {
|
|
4
|
+
return {
|
|
5
|
+
'Content-Type': 'text/event-stream',
|
|
6
|
+
'Cache-Control': 'no-cache',
|
|
7
|
+
'Connection': 'keep-alive',
|
|
8
|
+
// eslint-disable-next-line no-warning-comments
|
|
9
|
+
// TODO: Remove next line in production - dashboard served from same port
|
|
10
|
+
'Access-Control-Allow-Origin': '*'
|
|
11
|
+
};
|
|
12
|
+
}; // createSSEHeaders()
|
|
13
|
+
|
|
14
|
+
const createConnection = function ( state, res, endpointName ) {
|
|
15
|
+
const connection = {
|
|
16
|
+
response: res,
|
|
17
|
+
endpoint: endpointName,
|
|
18
|
+
qos: state.endpointQoS[ endpointName ],
|
|
19
|
+
createdAt: Date.now(),
|
|
20
|
+
messagesSent: 0
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
state.connections[ endpointName ].push( connection );
|
|
24
|
+
state.totalConnections += 1;
|
|
25
|
+
|
|
26
|
+
return connection;
|
|
27
|
+
}; // createConnection()
|
|
28
|
+
|
|
29
|
+
const removeConnection = function ( state, connection, endpointName ) {
|
|
30
|
+
const connections = state.connections[ endpointName ];
|
|
31
|
+
const index = connections.indexOf( connection );
|
|
32
|
+
if ( index !== -1 ) {
|
|
33
|
+
connections.splice( index, 1 );
|
|
34
|
+
state.totalConnections -= 1;
|
|
35
|
+
console.log( `SSE ${endpointName} disconnected (${state.totalConnections}/${state.maxConnections})` );
|
|
36
|
+
}
|
|
37
|
+
}; // removeConnection()
|
|
38
|
+
|
|
39
|
+
const setupConnectionHandlers = function ( state, req, connection, endpointName ) {
|
|
40
|
+
const cleanup = () => removeConnection( state, connection, endpointName );
|
|
41
|
+
req.on( 'close', cleanup );
|
|
42
|
+
req.on( 'error', cleanup );
|
|
43
|
+
}; // setupConnectionHandlers()
|
|
44
|
+
|
|
45
|
+
export { createSSEHeaders, createConnection, removeConnection, setupConnectionHandlers };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// utils/endpoint-initializer.js
|
|
2
|
+
|
|
3
|
+
const initializeEndpoints = function ( state ) {
|
|
4
|
+
state.endpointNames = Object.keys( state.stats );
|
|
5
|
+
state.connections = Object.create( null );
|
|
6
|
+
state.endpointQoS = Object.create( null );
|
|
7
|
+
|
|
8
|
+
// Create connection arrays and store QoS levels
|
|
9
|
+
for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
|
|
10
|
+
const endpointName = state.endpointNames[ i ];
|
|
11
|
+
state.connections[ endpointName ] = [];
|
|
12
|
+
|
|
13
|
+
// Apply QoS defaults: dashboard=0, database=2, others=1
|
|
14
|
+
const defaultQoS = endpointName === 'dashboard' ? 0 :
|
|
15
|
+
endpointName === 'database' ? 2 : 1;
|
|
16
|
+
state.endpointQoS[ endpointName ] = state.stats[ endpointName ].qos || defaultQoS;
|
|
17
|
+
}
|
|
18
|
+
}; // initializeEndpoints()
|
|
19
|
+
|
|
20
|
+
export { initializeEndpoints };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// utils/health-monitor.js
|
|
2
|
+
|
|
3
|
+
const buildHealthResponse = function ( state ) {
|
|
4
|
+
const endpointStats = Object.create( null );
|
|
5
|
+
for ( let i = 0; i < state.endpointNames.length; i += 1 ) {
|
|
6
|
+
const endpointName = state.endpointNames[ i ];
|
|
7
|
+
endpointStats[ endpointName ] = state.connections[ endpointName ].length;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
nodeType: state.nodeType,
|
|
12
|
+
connections: {
|
|
13
|
+
total: state.totalConnections,
|
|
14
|
+
byEndpoint: endpointStats
|
|
15
|
+
},
|
|
16
|
+
stats: {
|
|
17
|
+
sent: state.totalSent,
|
|
18
|
+
errors: state.totalErrors
|
|
19
|
+
},
|
|
20
|
+
endpoints: state.endpointNames,
|
|
21
|
+
timestamp: Date.now()
|
|
22
|
+
};
|
|
23
|
+
}; // buildHealthResponse()
|
|
24
|
+
|
|
25
|
+
const handleHealthCheck = function ( state, res ) {
|
|
26
|
+
const healthData = buildHealthResponse( state );
|
|
27
|
+
res.writeHead( 200, {
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
// eslint-disable-next-line no-warning-comments
|
|
30
|
+
// TODO: Remove next 3 lines in production - dashboard served from same port
|
|
31
|
+
'Access-Control-Allow-Origin': '*',
|
|
32
|
+
'Access-Control-Allow-Methods': 'GET',
|
|
33
|
+
'Access-Control-Allow-Headers': 'Content-Type'
|
|
34
|
+
} );
|
|
35
|
+
res.end( JSON.stringify( healthData ) );
|
|
36
|
+
}; // handleHealthCheck()
|
|
37
|
+
|
|
38
|
+
export { buildHealthResponse, handleHealthCheck };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// utils/qos-handler.js
|
|
2
|
+
|
|
3
|
+
import { QOS_FIRE_AND_FORGET, QOS_BEST_EFFORT, QOS_RELIABLE } from '../introspect.js';
|
|
4
|
+
|
|
5
|
+
const fireAndForgetSend = function ( connection, message, state ) {
|
|
6
|
+
connection.response.write( message );
|
|
7
|
+
connection.messagesSent += 1;
|
|
8
|
+
state.totalSent += 1;
|
|
9
|
+
}; // fireAndForgetSend()
|
|
10
|
+
|
|
11
|
+
const bestEffortSend = function ( connection, message, state, endpointName ) {
|
|
12
|
+
const success = connection.response.write( message );
|
|
13
|
+
if ( success ) {
|
|
14
|
+
connection.messagesSent += 1;
|
|
15
|
+
state.totalSent += 1;
|
|
16
|
+
} else {
|
|
17
|
+
console.warn( `${endpointName} client backpressure - best effort` );
|
|
18
|
+
state.totalSent += 1; // Count as sent for metrics
|
|
19
|
+
}
|
|
20
|
+
}; // bestEffortSend()
|
|
21
|
+
|
|
22
|
+
const reliableSend = function ( connection, message, state, endpointName ) {
|
|
23
|
+
const success = connection.response.write( message );
|
|
24
|
+
if ( success ) {
|
|
25
|
+
connection.messagesSent += 1;
|
|
26
|
+
state.totalSent += 1;
|
|
27
|
+
} else {
|
|
28
|
+
console.warn( `${endpointName} client backpressure - reliable mode` );
|
|
29
|
+
// TO DO: Implement proper queuing for reliable delivery
|
|
30
|
+
state.totalSent += 1; // Count as sent for now
|
|
31
|
+
}
|
|
32
|
+
}; // reliableSend()
|
|
33
|
+
|
|
34
|
+
// O(1) QoS handler dispatch table
|
|
35
|
+
const QOS_HANDLERS = {
|
|
36
|
+
[ QOS_FIRE_AND_FORGET ]: fireAndForgetSend,
|
|
37
|
+
[ QOS_BEST_EFFORT ]: bestEffortSend,
|
|
38
|
+
[ QOS_RELIABLE ]: reliableSend
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { QOS_HANDLERS };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate that all required fields exist in message and contain categorical values
|
|
3
|
+
*
|
|
4
|
+
* @param {Object} msg - Message to validate
|
|
5
|
+
* @param {string[]} fieldNames - Array of required field names
|
|
6
|
+
* @param {number} fieldCount - Number of fields to validate
|
|
7
|
+
* @returns {boolean} True if all fields are present and categorical
|
|
8
|
+
*/
|
|
9
|
+
const validateCategoricalFields = function ( msg, fieldNames, fieldCount ) {
|
|
10
|
+
for ( let i = 0; i < fieldCount; i += 1 ) {
|
|
11
|
+
const field = fieldNames[ i ];
|
|
12
|
+
const value = msg[ field ];
|
|
13
|
+
|
|
14
|
+
// Missing field
|
|
15
|
+
if ( value === undefined ) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Check if categorical (string, number, or boolean)
|
|
20
|
+
const valueType = typeof value;
|
|
21
|
+
const isCategorical = (
|
|
22
|
+
valueType === 'string' ||
|
|
23
|
+
valueType === 'number' ||
|
|
24
|
+
valueType === 'boolean'
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
if ( !isCategorical ) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return true;
|
|
33
|
+
}; // validateCategoricalFields()
|
|
34
|
+
|
|
35
|
+
export { validateCategoricalFields };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { default as init } from './init.js';
|
|
2
|
+
export { default as update } from './update.js';
|
|
3
|
+
export { default as reset } from './reset.js';
|
|
4
|
+
export { default as recompute } from './recompute.js';
|
|
5
|
+
export { default as publishTo } from './publish-to.js';
|
|
6
|
+
// Direct imports for common control functions
|
|
7
|
+
export { default as disable } from '../../core/utils/node/disable.js';
|
|
8
|
+
export { default as enable } from '../../core/utils/node/enable.js';
|
|
9
|
+
export { default as pause } from '../../core/utils/node/pause.js';
|
|
10
|
+
export { default as unpause } from '../../core/utils/node/unpause.js';
|
|
11
|
+
// Re-export everything from introspection
|
|
12
|
+
export * from './introspect.js';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { validateSpec } from '../../core/utils/node/index.js';
|
|
2
|
+
import * as introspect from './introspect.js';
|
|
3
|
+
|
|
4
|
+
const init = function ( spec ) {
|
|
5
|
+
validateSpec( spec, introspect );
|
|
6
|
+
|
|
7
|
+
const state = Object.create( null );
|
|
8
|
+
// Standard input parameter health flag during update: false means healthy
|
|
9
|
+
state.inputValidationFailed = false;
|
|
10
|
+
// Ensure node is enabled by default
|
|
11
|
+
state.disable = false;
|
|
12
|
+
state.pause = false;
|
|
13
|
+
|
|
14
|
+
// Extract field names and count
|
|
15
|
+
state.fieldNames = spec.from.x;
|
|
16
|
+
state.fieldCount = state.fieldNames.length;
|
|
17
|
+
|
|
18
|
+
// Guards (apply defaults from introspect)
|
|
19
|
+
const defaults = introspect.DEFAULT_OPTIONS;
|
|
20
|
+
state.debounce = spec.debounce ?? defaults.debounce;
|
|
21
|
+
|
|
22
|
+
// Change detection mode (store as boolean for performance)
|
|
23
|
+
const changeMode = spec.changeMode ?? defaults.changeMode;
|
|
24
|
+
state.changeMode = ( changeMode === 'all' ); // true='all', false='any'
|
|
25
|
+
|
|
26
|
+
// Timestamp handling
|
|
27
|
+
state.useTimestampField = spec.timestampField !== undefined;
|
|
28
|
+
state.timestampField = spec.timestampField || null;
|
|
29
|
+
|
|
30
|
+
// Stats configuration
|
|
31
|
+
state.stats = spec.stats;
|
|
32
|
+
|
|
33
|
+
// Pre-allocate state tracking (NO allocations in hot path)
|
|
34
|
+
state.prevValues = Object.create( null );
|
|
35
|
+
for ( let i = 0; i < state.fieldCount; i += 1 ) {
|
|
36
|
+
const field = state.fieldNames[ i ];
|
|
37
|
+
state.prevValues[ field ] = null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Debounce and timing state
|
|
41
|
+
state.debounceCount = 0;
|
|
42
|
+
state.stateStartTime = null;
|
|
43
|
+
state.samplesInState = 0;
|
|
44
|
+
|
|
45
|
+
// stats to be published
|
|
46
|
+
state.dwellTime = null;
|
|
47
|
+
state.dwellSamples = null;
|
|
48
|
+
|
|
49
|
+
// Node metadata
|
|
50
|
+
state.nodeType = introspect.getNodeType();
|
|
51
|
+
state.resolvedTriggers = [];
|
|
52
|
+
|
|
53
|
+
return state;
|
|
54
|
+
}; // init()
|
|
55
|
+
|
|
56
|
+
export default init;
|