@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,37 @@
|
|
|
1
|
+
// nodes/pass-if/update.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Update function for passIf node
|
|
5
|
+
*
|
|
6
|
+
* Hot path — evaluates user-supplied predicate with message and
|
|
7
|
+
* counter. Returns null to stop downstream flow when predicate
|
|
8
|
+
* is false. Predicate errors are caught and tracked per-episode.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const update = function ( state, msg ) {
|
|
12
|
+
if ( state.disable || state.pause ) return state;
|
|
13
|
+
|
|
14
|
+
// Increment counter for this message
|
|
15
|
+
state.counter += 1;
|
|
16
|
+
|
|
17
|
+
let shouldPass;
|
|
18
|
+
try {
|
|
19
|
+
// Evaluate predicate with message and current counter
|
|
20
|
+
shouldPass = state.predicate( msg, state.counter );
|
|
21
|
+
// Recovery: clear log-suppression flag on success
|
|
22
|
+
if ( state.predicateErrorLogged ) state.predicateErrorLogged = false;
|
|
23
|
+
} catch ( error ) {
|
|
24
|
+
// Assume it to be a case of predicate evaluating to false
|
|
25
|
+
shouldPass = false;
|
|
26
|
+
// Log first error per episode; suppress subsequent until recovery
|
|
27
|
+
if ( !state.predicateErrorLogged ) {
|
|
28
|
+
state.predicateErrorLogged = true;
|
|
29
|
+
console.error( `WinkComposer/passIf: predicate threw exception: ${error.message}` );
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Return null to stop flow, state to continue
|
|
34
|
+
return shouldPass ? state : null;
|
|
35
|
+
}; // update()
|
|
36
|
+
|
|
37
|
+
export default update;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// nodes/persist-if/helpers.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Helper functions for persistIf node
|
|
5
|
+
*
|
|
6
|
+
* The shared write-failure recording used by update.js, and the static
|
|
7
|
+
* fallback error for adapters that break the return contract. Mirrors
|
|
8
|
+
* emit-if/helpers.js — the two output gates share one failure model.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Static fallback error the framework substitutes when an adapter breaks
|
|
13
|
+
* the return contract — no result object at all, or `{ ok: false }` with
|
|
14
|
+
* no `error` (ADR-018 error vocabulary). A module-level singleton, so the
|
|
15
|
+
* hot path allocates nothing. Mirrors emit-if.
|
|
16
|
+
*/
|
|
17
|
+
const MALFORMED_RESULT_ERROR = {
|
|
18
|
+
code: 'MALFORMED_RESULT',
|
|
19
|
+
message: 'storage returned a malformed write result (expected { ok, error? })'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Throws when an annotate return is not a plain object — arrays pass a
|
|
24
|
+
* bare typeof check but are just as wrong. A flow-authoring bug surfaces
|
|
25
|
+
* in the node's own error episode (the predicate/annotate try in
|
|
26
|
+
* update.js), never downstream where it would masquerade as an adapter
|
|
27
|
+
* failure. Mirrors emit-if.
|
|
28
|
+
*
|
|
29
|
+
* @param {*} record - The annotate return value
|
|
30
|
+
* @throws {Error} Naming the offending type
|
|
31
|
+
*/
|
|
32
|
+
const assertAnnotateReturn = function ( record ) {
|
|
33
|
+
const got = record === null ? 'null' :
|
|
34
|
+
( Array.isArray( record ) ? 'array' : typeof record );
|
|
35
|
+
if ( got === 'object' ) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
throw new Error( `annotate must return an object, got ${got}` );
|
|
39
|
+
}; // assertAnnotateReturn()
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Warns, once per gate, about invented keys in an annotate record.
|
|
43
|
+
*
|
|
44
|
+
* An invented key is one the annotate function added that is neither a
|
|
45
|
+
* declared column nor a field of the message. Such a key is almost always
|
|
46
|
+
* a typo, and today it fails silently: the persist plan writes only
|
|
47
|
+
* declared columns, so the value never reaches storage. Keys that also
|
|
48
|
+
* exist in the message are skipped on purpose — a `...msg` spread carries
|
|
49
|
+
* many working fields, and naming those would bury the real finding.
|
|
50
|
+
*
|
|
51
|
+
* Runs once per gate. The `checked` flag lives on the wiring-stamped sweep
|
|
52
|
+
* object that every partition shares, and it flips before the comparison,
|
|
53
|
+
* so the check cannot repeat. The Object.keys call and the warning string
|
|
54
|
+
* allocate — once, on this single firing, inside the per-event allocation
|
|
55
|
+
* the function-form annotate already makes. Later firings never reach this
|
|
56
|
+
* function (update.js short-circuits on the flag), so the steady-state hot
|
|
57
|
+
* path stays allocation-free per ADR-004.
|
|
58
|
+
*
|
|
59
|
+
* @param {Object} state - Node state (name, insightType, annotateSweep)
|
|
60
|
+
* @param {Object} record - The record the annotate function returned
|
|
61
|
+
* @param {Object} msg - The message that produced it
|
|
62
|
+
*/
|
|
63
|
+
const sweepAnnotateKeys = function ( state, record, msg ) {
|
|
64
|
+
const sweep = state.annotateSweep;
|
|
65
|
+
sweep.checked = true;
|
|
66
|
+
|
|
67
|
+
const recordKeys = Object.keys( record );
|
|
68
|
+
const invented = [];
|
|
69
|
+
for ( let i = 0; i < recordKeys.length; i += 1 ) {
|
|
70
|
+
const key = recordKeys[ i ];
|
|
71
|
+
if ( !sweep.declaredColumns.has( key ) && !( key in msg ) ) {
|
|
72
|
+
invented.push( key );
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if ( invented.length > 0 ) {
|
|
77
|
+
console.warn(
|
|
78
|
+
`WinkComposer/persistIf: annotate for node '${state.name}' ` +
|
|
79
|
+
`(insightType '${state.insightType}') returned keys that are not declared columns: ` +
|
|
80
|
+
`${invented.join( ', ' )}. These values are never stored, because the persist plan ` +
|
|
81
|
+
'writes only declared columns. Check the key names against the asset class. ' +
|
|
82
|
+
'Reported once per gate.'
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}; // sweepAnnotateKeys()
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Records a failed write into the node's failure episode: updates the
|
|
89
|
+
* last* fields, and on the first failure of an episode captures the first*
|
|
90
|
+
* fields and logs one console.error (repeats stay quiet until a successful
|
|
91
|
+
* write closes the episode — see update.js). The first* fields keep the
|
|
92
|
+
* episode-opening error (the cause; later failures in a cascade are
|
|
93
|
+
* symptoms).
|
|
94
|
+
*
|
|
95
|
+
* @param {Object} state - Node state
|
|
96
|
+
* @param {Object} error - The `{ code, message }` from the storage's
|
|
97
|
+
* `{ ok: false }` return (ADR-018 sink return contract)
|
|
98
|
+
*/
|
|
99
|
+
const recordPersistFailure = function ( state, error ) {
|
|
100
|
+
state.persistErrors += 1;
|
|
101
|
+
state.lastPersistError = error.message;
|
|
102
|
+
state.lastPersistErrorCode = error.code;
|
|
103
|
+
if ( !state.writeErrorLogged ) {
|
|
104
|
+
state.writeErrorLogged = true;
|
|
105
|
+
state.firstPersistError = error.message;
|
|
106
|
+
state.firstPersistErrorCode = error.code;
|
|
107
|
+
console.error( state.writeErrorLogPrefix + error.code + '): ' + error.message );
|
|
108
|
+
}
|
|
109
|
+
}; // recordPersistFailure()
|
|
110
|
+
|
|
111
|
+
export { assertAnnotateReturn, sweepAnnotateKeys, recordPersistFailure, MALFORMED_RESULT_ERROR };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// nodes/persist-if/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
|
+
// Re-export everything from introspection
|
|
9
|
+
export * from './introspect.js';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// nodes/persist-if/init.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Initialization for persistIf node
|
|
5
|
+
*
|
|
6
|
+
* Validates specification and creates initial state with pre-allocated
|
|
7
|
+
* structures for zero-allocation hot path.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { validateWithSchema } from '../../core/utils/validate/index.js';
|
|
11
|
+
import { getDSLMetadata, getNodeType } from './introspect.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Initialize persistIf node state.
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} spec - Node specification
|
|
17
|
+
* @param {string} spec.nodeType - Must be 'Persist If'
|
|
18
|
+
* @param {string} spec.name - Node identifier
|
|
19
|
+
* @param {Function} spec.predicate - Function to evaluate for persistence
|
|
20
|
+
* @param {string} spec.insightType - Insight type (maps to storage table)
|
|
21
|
+
* @param {string} spec.storageName - Name of registered storage adapter
|
|
22
|
+
* @param {Function} [spec.annotate] - Shapes the stored record: write annotate( msg )
|
|
23
|
+
* instead of msg. Mirrors emitIf's annotate; the persist plan still writes only
|
|
24
|
+
* the insight type's declared columns, so the hook cannot widen the schema.
|
|
25
|
+
* @param {Object} [spec.annotateSweep] - Stamped by wiring, not by flow authors:
|
|
26
|
+
* the declared-column set plus a shared once-flag for the first-firing
|
|
27
|
+
* unknown-key warning (see helpers.js sweepAnnotateKeys)
|
|
28
|
+
* @returns {Object} Initialized state
|
|
29
|
+
*/
|
|
30
|
+
const init = function ( spec ) {
|
|
31
|
+
// Validate specification
|
|
32
|
+
const metadata = getDSLMetadata();
|
|
33
|
+
const validation = validateWithSchema(
|
|
34
|
+
{
|
|
35
|
+
...metadata.specSchema,
|
|
36
|
+
_crossFieldValidators: metadata.crossFieldValidators
|
|
37
|
+
},
|
|
38
|
+
spec,
|
|
39
|
+
'spec'
|
|
40
|
+
);
|
|
41
|
+
validation.throwIfInvalid( getNodeType() );
|
|
42
|
+
|
|
43
|
+
// Create state after validation passes
|
|
44
|
+
const state = Object.create( null );
|
|
45
|
+
|
|
46
|
+
// Core configuration
|
|
47
|
+
state.nodeType = getNodeType();
|
|
48
|
+
state.name = spec.name;
|
|
49
|
+
state.predicate = spec.predicate;
|
|
50
|
+
state.insightType = spec.insightType;
|
|
51
|
+
state.storageName = spec.storageName;
|
|
52
|
+
state.annotate = spec.annotate || null;
|
|
53
|
+
// Annotate key-sweep support, stamped by wiring (wire-storages) when a
|
|
54
|
+
// function-form annotate can be checked against declared columns. The
|
|
55
|
+
// object is shared by every partition of this gate on purpose: its
|
|
56
|
+
// `checked` flag makes the unknown-key warning fire once per gate, not
|
|
57
|
+
// once per partition. Unit tests and flows without an asset class have
|
|
58
|
+
// no stamp; null disables the check.
|
|
59
|
+
state.annotateSweep = spec.annotateSweep || null;
|
|
60
|
+
|
|
61
|
+
// Storage reference (injected by partition manager at runtime)
|
|
62
|
+
state.storage = null;
|
|
63
|
+
|
|
64
|
+
// State transition tracking (semantic — controls error tracking)
|
|
65
|
+
state.inErrorState = false;
|
|
66
|
+
// Log suppression: one log per error episode; reset on recovery.
|
|
67
|
+
state.predicateErrorLogged = false;
|
|
68
|
+
|
|
69
|
+
// Statistics for observability
|
|
70
|
+
state.persistCount = 0;
|
|
71
|
+
state.passCount = 0;
|
|
72
|
+
state.lastPersistTime = null;
|
|
73
|
+
|
|
74
|
+
// Error tracking
|
|
75
|
+
state.persistErrors = 0;
|
|
76
|
+
state.lastPersistError = null;
|
|
77
|
+
// Per ADR-018 the storage write returns { ok: false, error: { code, message } }
|
|
78
|
+
// on failure. We surface both fields: lastPersistError is the human message
|
|
79
|
+
// (predicate exceptions also write here as a string), lastPersistErrorCode
|
|
80
|
+
// is the structured code (null when the error came from a predicate exception
|
|
81
|
+
// since predicate failures are not classified by the contract).
|
|
82
|
+
state.lastPersistErrorCode = null;
|
|
83
|
+
// Write-failure episode: one console.error per episode; a successful
|
|
84
|
+
// write closes it. The first* fields keep the episode-opening error —
|
|
85
|
+
// in a cascade the LAST error is the symptom and the FIRST is the
|
|
86
|
+
// cause. They survive recovery for post-mortem reads and are
|
|
87
|
+
// overwritten only when the next episode opens.
|
|
88
|
+
state.writeErrorLogged = false;
|
|
89
|
+
state.firstPersistError = null;
|
|
90
|
+
state.firstPersistErrorCode = null;
|
|
91
|
+
// Static log prefix pre-built here per ADR-004 (no string building in
|
|
92
|
+
// update beyond the two runtime fields, and only once per episode).
|
|
93
|
+
state.writeErrorLogPrefix = `WinkComposer/persistIf: storage write failed (node=${state.name}, insightType=${state.insightType}, code=`;
|
|
94
|
+
|
|
95
|
+
return state;
|
|
96
|
+
}; // init()
|
|
97
|
+
|
|
98
|
+
export default init;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// nodes/persist-if/introspect.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Introspection metadata for persistIf node
|
|
5
|
+
*
|
|
6
|
+
* Single source of truth for DSL metadata, validation schema,
|
|
7
|
+
* and node capabilities. Used by flow transpiler and documentation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { validators } from '../../core/utils/validate/index.js';
|
|
11
|
+
|
|
12
|
+
/** Single source of truth for what this plugin can do */
|
|
13
|
+
const SUPPORTED_STATS = []; // Pass-through node, no stats to publish
|
|
14
|
+
|
|
15
|
+
/** Human-readable descriptions (for introspection) */
|
|
16
|
+
const STAT_DESCRIPTIONS = {}; // No stats, no descriptions
|
|
17
|
+
|
|
18
|
+
/** Control methods available for triggers (none - side-effect only node) */
|
|
19
|
+
const SUPPORTED_CONTROL_METHODS = {};
|
|
20
|
+
|
|
21
|
+
/** The type of this node */
|
|
22
|
+
const NODE_TYPE = 'Persist If';
|
|
23
|
+
|
|
24
|
+
/** Node capabilities for documentation (kept accurate to shipping code) */
|
|
25
|
+
const CAPABILITIES = {
|
|
26
|
+
description: 'Conditionally persists messages to storage without disrupting pipeline flow',
|
|
27
|
+
features: [
|
|
28
|
+
'Pure pass-through behavior - messages continue unchanged',
|
|
29
|
+
'Conditional persistence based on predicate function',
|
|
30
|
+
'Optional annotate hook shapes the stored record (mirrors emitIf); the persist plan still writes only the insight type\'s declared columns',
|
|
31
|
+
'On the first firing, annotate record keys are checked once per gate: a key that is neither a declared column nor a message field is named in a warning, because its value would otherwise vanish silently',
|
|
32
|
+
'Columns and types come from the declared semantics (asset class), never inferred from data',
|
|
33
|
+
'Writes through the storage handle\'s write and reads its classified { ok, error } result',
|
|
34
|
+
'Write failures open a loud error episode (one console.error per episode); the pipeline never stops',
|
|
35
|
+
'Per-partition persistence tracking'
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Export functions for accessing metadata
|
|
40
|
+
export const getSupportedStats = () => SUPPORTED_STATS.slice();
|
|
41
|
+
export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
|
|
42
|
+
export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
|
|
43
|
+
export const getNodeType = () => NODE_TYPE;
|
|
44
|
+
export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
|
|
45
|
+
|
|
46
|
+
/** Spec default values */
|
|
47
|
+
export const DEFAULT_OPTIONS = {};
|
|
48
|
+
|
|
49
|
+
// DSL Metadata for transpilation
|
|
50
|
+
const DSL_METADATA = {
|
|
51
|
+
// Validation schema
|
|
52
|
+
specSchema: {
|
|
53
|
+
nodeType: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
required: true,
|
|
56
|
+
value: NODE_TYPE
|
|
57
|
+
},
|
|
58
|
+
name: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
required: true,
|
|
61
|
+
validator: validators.identifier,
|
|
62
|
+
error: 'Name must be a valid JavaScript identifier'
|
|
63
|
+
},
|
|
64
|
+
predicate: {
|
|
65
|
+
type: 'function',
|
|
66
|
+
required: true,
|
|
67
|
+
arity: 1,
|
|
68
|
+
error: 'Predicate must be a function with exactly one parameter (msg)'
|
|
69
|
+
},
|
|
70
|
+
insightType: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
required: true,
|
|
73
|
+
error: 'Insight type must be specified (maps to storage table)'
|
|
74
|
+
},
|
|
75
|
+
storageName: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
required: true,
|
|
78
|
+
error: 'Storage name must reference a registered storage adapter'
|
|
79
|
+
},
|
|
80
|
+
annotate: {
|
|
81
|
+
type: 'function',
|
|
82
|
+
required: false,
|
|
83
|
+
arity: 1,
|
|
84
|
+
error: 'Annotate must be a function with exactly one parameter (msg)'
|
|
85
|
+
},
|
|
86
|
+
stats: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
required: false,
|
|
89
|
+
propertyNames: [], // No stats for pass-through node
|
|
90
|
+
error: 'PersistIf is a pass-through node and does not support stats'
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
// Cross-field validators
|
|
95
|
+
crossFieldValidators: [],
|
|
96
|
+
|
|
97
|
+
// Build spec from DSL
|
|
98
|
+
buildSpec: ( name, predicate, options ) => ( {
|
|
99
|
+
nodeType: NODE_TYPE,
|
|
100
|
+
name,
|
|
101
|
+
predicate,
|
|
102
|
+
...options
|
|
103
|
+
} )
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const getDSLMetadata = () => ( { ...DSL_METADATA } );
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// nodes/persist-if/publish-to.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview PublishTo function for persistIf node
|
|
5
|
+
*
|
|
6
|
+
* Pass-through node - message continues unchanged.
|
|
7
|
+
* No fields are added to the outgoing message.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Publish computed results to message.
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} _state - Node state (unused)
|
|
14
|
+
* @param {Object} _msg - Outgoing message (unchanged)
|
|
15
|
+
*/
|
|
16
|
+
const publishTo = function ( _state, _msg ) {
|
|
17
|
+
// Pure pass-through node - message continues unchanged
|
|
18
|
+
// No fields are added to the message
|
|
19
|
+
}; // publishTo()
|
|
20
|
+
|
|
21
|
+
export default publishTo;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// nodes/persist-if/recompute.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Recompute function for persistIf node
|
|
5
|
+
*
|
|
6
|
+
* No numerical computation to stabilize.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Recompute for numerical stability.
|
|
11
|
+
*
|
|
12
|
+
* @param {Object} _state - Node state (unused)
|
|
13
|
+
* @returns {boolean} Always true (no recomputation needed)
|
|
14
|
+
*/
|
|
15
|
+
const recompute = function ( _state ) {
|
|
16
|
+
// No numerical computation to stabilize
|
|
17
|
+
return true;
|
|
18
|
+
}; // recompute()
|
|
19
|
+
|
|
20
|
+
export default recompute;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// nodes/persist-if/reset.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Reset function for persistIf node
|
|
5
|
+
*
|
|
6
|
+
* Resets statistics and state tracking.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Reset node state.
|
|
11
|
+
*
|
|
12
|
+
* @param {Object} state - Node state
|
|
13
|
+
* @returns {boolean} Always true (ADR-004; parity with emitIf)
|
|
14
|
+
*/
|
|
15
|
+
const reset = function ( state ) {
|
|
16
|
+
// Reset statistics
|
|
17
|
+
state.persistCount = 0;
|
|
18
|
+
state.passCount = 0;
|
|
19
|
+
state.lastPersistTime = null;
|
|
20
|
+
state.persistErrors = 0;
|
|
21
|
+
state.lastPersistError = null;
|
|
22
|
+
state.lastPersistErrorCode = null;
|
|
23
|
+
state.firstPersistError = null;
|
|
24
|
+
state.firstPersistErrorCode = null;
|
|
25
|
+
|
|
26
|
+
// Reset state tracking
|
|
27
|
+
state.inErrorState = false;
|
|
28
|
+
// Clear error suppression so next error episode is logged
|
|
29
|
+
state.predicateErrorLogged = false;
|
|
30
|
+
state.writeErrorLogged = false;
|
|
31
|
+
|
|
32
|
+
return true;
|
|
33
|
+
}; // reset()
|
|
34
|
+
|
|
35
|
+
export default reset;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// nodes/persist-if/update.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Update function for persistIf node
|
|
5
|
+
*
|
|
6
|
+
* Hot path - zero allocation after first message (annotate, when configured,
|
|
7
|
+
* allocates only on the ticks that actually persist - the same per-event
|
|
8
|
+
* asymmetry as emitIf's annotate).
|
|
9
|
+
* Evaluates predicate, optionally shapes the record via annotate, and writes
|
|
10
|
+
* it to the storage buffer if the predicate passed.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { assertAnnotateReturn, sweepAnnotateKeys, recordPersistFailure, MALFORMED_RESULT_ERROR } from './helpers.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Process incoming message.
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} state - Node state
|
|
19
|
+
* @param {Object} msg - Incoming message
|
|
20
|
+
* @returns {Object} Updated state (always returns state for pass-through)
|
|
21
|
+
*/
|
|
22
|
+
const update = function ( state, msg ) {
|
|
23
|
+
// Always increment pass count for observability
|
|
24
|
+
state.passCount += 1;
|
|
25
|
+
|
|
26
|
+
// Early exit if storage not available
|
|
27
|
+
if ( !state.storage ) {
|
|
28
|
+
return state;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Evaluate predicate, then shape the record when persisting. Annotate
|
|
32
|
+
// mirrors emitIf: both run inside one try, so predicate and annotate
|
|
33
|
+
// share the same error episode (tracking, log suppression, recovery).
|
|
34
|
+
let shouldPersist = false;
|
|
35
|
+
let record = msg;
|
|
36
|
+
try {
|
|
37
|
+
shouldPersist = state.predicate( msg );
|
|
38
|
+
if ( shouldPersist && state.annotate ) {
|
|
39
|
+
record = state.annotate( msg );
|
|
40
|
+
// A flow-authoring bug (non-object return) throws here, into
|
|
41
|
+
// this node's error episode — never into storage.write where
|
|
42
|
+
// it would masquerade as a storage failure (SEND_FAILED).
|
|
43
|
+
assertAnnotateReturn( record );
|
|
44
|
+
// First firing only: warn about invented record keys — typos
|
|
45
|
+
// that would otherwise vanish silently (the persist plan writes
|
|
46
|
+
// only declared columns). Every later firing takes this
|
|
47
|
+
// two-read short-circuit; nothing allocates here.
|
|
48
|
+
if ( state.annotateSweep && !state.annotateSweep.checked ) {
|
|
49
|
+
sweepAnnotateKeys( state, record, msg );
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Clear error state on successful evaluation
|
|
54
|
+
if ( state.inErrorState ) {
|
|
55
|
+
state.inErrorState = false;
|
|
56
|
+
}
|
|
57
|
+
// Recovery: clear log-suppression flag on success
|
|
58
|
+
if ( state.predicateErrorLogged ) state.predicateErrorLogged = false;
|
|
59
|
+
} catch ( error ) {
|
|
60
|
+
// Handle predicate/annotate errors (semantic — tracks error state)
|
|
61
|
+
if ( !state.inErrorState ) {
|
|
62
|
+
state.inErrorState = true;
|
|
63
|
+
}
|
|
64
|
+
// Log first error per episode; suppress subsequent until recovery
|
|
65
|
+
if ( !state.predicateErrorLogged ) {
|
|
66
|
+
state.predicateErrorLogged = true;
|
|
67
|
+
console.error( `WinkComposer/persistIf: predicate threw exception: ${error.message}` );
|
|
68
|
+
}
|
|
69
|
+
state.persistErrors += 1;
|
|
70
|
+
state.lastPersistError = error.message;
|
|
71
|
+
// Predicate exceptions are persist-if-internal, not part of the
|
|
72
|
+
// ADR-018 adapter err.code vocabulary. Clear the code so the two
|
|
73
|
+
// fields stay in sync (a stale code from a prior storage error
|
|
74
|
+
// would mislead readers).
|
|
75
|
+
state.lastPersistErrorCode = null;
|
|
76
|
+
return state;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Write to storage if predicate returned true
|
|
80
|
+
if ( shouldPersist ) {
|
|
81
|
+
// Build record for storage (zero-alloc: storage.write handles it).
|
|
82
|
+
// storage.write() is synchronous per ADR-013; the actual I/O happens
|
|
83
|
+
// asynchronously via the storage adapter's background flush.
|
|
84
|
+
// Per the ADR-018 sink return contract, the storage answers
|
|
85
|
+
// { ok: true } on success or
|
|
86
|
+
// { ok: false, error: { code, message } } on failure.
|
|
87
|
+
const result = state.storage.write(
|
|
88
|
+
state.insightType,
|
|
89
|
+
record,
|
|
90
|
+
state.partitionId
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if ( result && result.ok ) {
|
|
94
|
+
state.persistCount += 1;
|
|
95
|
+
// Wall-clock marker of the last successful write (post-mortem
|
|
96
|
+
// reads only, like the first* error fields).
|
|
97
|
+
state.lastPersistTime = Date.now();
|
|
98
|
+
// Recovery: a successful write closes the failure episode.
|
|
99
|
+
if ( state.writeErrorLogged ) state.writeErrorLogged = false;
|
|
100
|
+
} else {
|
|
101
|
+
// A malformed result (no object at all, or ok:false with no
|
|
102
|
+
// error) counts as a failure with the static fallback error,
|
|
103
|
+
// so a non-conforming adapter can neither fail silently
|
|
104
|
+
// nor throw out of the hot path.
|
|
105
|
+
recordPersistFailure( state, ( result && result.error ) || MALFORMED_RESULT_ERROR );
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return state;
|
|
110
|
+
}; // update()
|
|
111
|
+
|
|
112
|
+
export default update;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// nodes/persistence-check/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,38 @@
|
|
|
1
|
+
// nodes/persistence-check/init.js
|
|
2
|
+
|
|
3
|
+
import { validateSpec } from '../../core/utils/node/index.js';
|
|
4
|
+
import * as introspect from './introspect.js';
|
|
5
|
+
|
|
6
|
+
const init = function ( spec ) {
|
|
7
|
+
validateSpec( spec, introspect );
|
|
8
|
+
|
|
9
|
+
// Create state after validation passes
|
|
10
|
+
const state = Object.create( null );
|
|
11
|
+
// Ensure node is enabled by default
|
|
12
|
+
state.disable = false;
|
|
13
|
+
state.pause = false;
|
|
14
|
+
|
|
15
|
+
// Extract validated predicate
|
|
16
|
+
state.predicate = spec.predicate;
|
|
17
|
+
state.requires = spec.requires;
|
|
18
|
+
state.stats = spec.stats;
|
|
19
|
+
|
|
20
|
+
// Apply defaults manually (validation doesn't enforce them)
|
|
21
|
+
state.minVotes = spec.minVotes || introspect.DEFAULT_OPTIONS.minVotes;
|
|
22
|
+
state.outOfTotal = spec.outOfTotal || introspect.DEFAULT_OPTIONS.outOfTotal;
|
|
23
|
+
|
|
24
|
+
// State variables
|
|
25
|
+
state.persistenceConfirmed = false;
|
|
26
|
+
state.voteCount = 0;
|
|
27
|
+
state.unvoteCount = 0;
|
|
28
|
+
|
|
29
|
+
state.nodeType = introspect.getNodeType();
|
|
30
|
+
state.inControlPhase = false;
|
|
31
|
+
|
|
32
|
+
// Log suppression: one log per error episode; reset on recovery.
|
|
33
|
+
state.predicateErrorLogged = false;
|
|
34
|
+
|
|
35
|
+
return state;
|
|
36
|
+
}; // init()
|
|
37
|
+
|
|
38
|
+
export default init;
|