dspx 0.1.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/.github/workflows/ci.yml +185 -0
  2. package/.vscode/c_cpp_properties.json +17 -0
  3. package/.vscode/settings.json +68 -0
  4. package/.vscode/tasks.json +28 -0
  5. package/DISCLAIMER.md +32 -0
  6. package/LICENSE +21 -0
  7. package/README.md +1803 -0
  8. package/ROADMAP.md +192 -0
  9. package/TECHNICAL_DEBT.md +165 -0
  10. package/binding.gyp +65 -0
  11. package/docs/ADVANCED_LOGGER_FEATURES.md +598 -0
  12. package/docs/AUTHENTICATION_SECURITY.md +396 -0
  13. package/docs/BACKEND_IMPROVEMENTS.md +399 -0
  14. package/docs/CHEBYSHEV_BIQUAD_EQ_IMPLEMENTATION.md +405 -0
  15. package/docs/FFT_IMPLEMENTATION.md +490 -0
  16. package/docs/FFT_IMPROVEMENTS_SUMMARY.md +387 -0
  17. package/docs/FFT_USER_GUIDE.md +494 -0
  18. package/docs/FILTERS_IMPLEMENTATION.md +260 -0
  19. package/docs/FILTER_API_GUIDE.md +418 -0
  20. package/docs/FIR_SIMD_OPTIMIZATION.md +175 -0
  21. package/docs/LOGGER_API_REFERENCE.md +350 -0
  22. package/docs/NOTCH_FILTER_QUICK_REF.md +121 -0
  23. package/docs/PHASE2_TESTS_AND_NOTCH_FILTER.md +341 -0
  24. package/docs/PHASES_5_7_SUMMARY.md +403 -0
  25. package/docs/PIPELINE_FILTER_INTEGRATION.md +446 -0
  26. package/docs/SIMD_OPTIMIZATIONS.md +211 -0
  27. package/docs/TEST_MIGRATION_SUMMARY.md +173 -0
  28. package/docs/TIMESERIES_IMPLEMENTATION_SUMMARY.md +322 -0
  29. package/docs/TIMESERIES_QUICK_REF.md +85 -0
  30. package/docs/advanced.md +559 -0
  31. package/docs/time-series-guide.md +617 -0
  32. package/docs/time-series-migration.md +376 -0
  33. package/jest.config.js +37 -0
  34. package/package.json +42 -0
  35. package/prebuilds/linux-x64/dsp-ts-redis.node +0 -0
  36. package/prebuilds/win32-x64/dsp-ts-redis.node +0 -0
  37. package/scripts/test.js +24 -0
  38. package/src/build/dsp-ts-redis.node +0 -0
  39. package/src/native/DspPipeline.cc +675 -0
  40. package/src/native/DspPipeline.h +44 -0
  41. package/src/native/FftBindings.cc +817 -0
  42. package/src/native/FilterBindings.cc +1001 -0
  43. package/src/native/IDspStage.h +53 -0
  44. package/src/native/adapters/InterpolatorStage.h +201 -0
  45. package/src/native/adapters/MeanAbsoluteValueStage.h +289 -0
  46. package/src/native/adapters/MovingAverageStage.h +306 -0
  47. package/src/native/adapters/RectifyStage.h +88 -0
  48. package/src/native/adapters/ResamplerStage.h +238 -0
  49. package/src/native/adapters/RmsStage.h +299 -0
  50. package/src/native/adapters/SscStage.h +121 -0
  51. package/src/native/adapters/VarianceStage.h +307 -0
  52. package/src/native/adapters/WampStage.h +114 -0
  53. package/src/native/adapters/WaveformLengthStage.h +115 -0
  54. package/src/native/adapters/ZScoreNormalizeStage.h +326 -0
  55. package/src/native/core/FftEngine.cc +441 -0
  56. package/src/native/core/FftEngine.h +224 -0
  57. package/src/native/core/FirFilter.cc +324 -0
  58. package/src/native/core/FirFilter.h +149 -0
  59. package/src/native/core/IirFilter.cc +576 -0
  60. package/src/native/core/IirFilter.h +210 -0
  61. package/src/native/core/MovingAbsoluteValueFilter.cc +17 -0
  62. package/src/native/core/MovingAbsoluteValueFilter.h +135 -0
  63. package/src/native/core/MovingAverageFilter.cc +18 -0
  64. package/src/native/core/MovingAverageFilter.h +135 -0
  65. package/src/native/core/MovingFftFilter.cc +291 -0
  66. package/src/native/core/MovingFftFilter.h +203 -0
  67. package/src/native/core/MovingVarianceFilter.cc +194 -0
  68. package/src/native/core/MovingVarianceFilter.h +114 -0
  69. package/src/native/core/MovingZScoreFilter.cc +215 -0
  70. package/src/native/core/MovingZScoreFilter.h +113 -0
  71. package/src/native/core/Policies.h +352 -0
  72. package/src/native/core/RmsFilter.cc +18 -0
  73. package/src/native/core/RmsFilter.h +131 -0
  74. package/src/native/core/SscFilter.cc +16 -0
  75. package/src/native/core/SscFilter.h +137 -0
  76. package/src/native/core/WampFilter.cc +16 -0
  77. package/src/native/core/WampFilter.h +101 -0
  78. package/src/native/core/WaveformLengthFilter.cc +17 -0
  79. package/src/native/core/WaveformLengthFilter.h +98 -0
  80. package/src/native/utils/CircularBufferArray.cc +336 -0
  81. package/src/native/utils/CircularBufferArray.h +62 -0
  82. package/src/native/utils/CircularBufferVector.cc +145 -0
  83. package/src/native/utils/CircularBufferVector.h +45 -0
  84. package/src/native/utils/NapiUtils.cc +53 -0
  85. package/src/native/utils/NapiUtils.h +21 -0
  86. package/src/native/utils/SimdOps.h +870 -0
  87. package/src/native/utils/SlidingWindowFilter.cc +239 -0
  88. package/src/native/utils/SlidingWindowFilter.h +159 -0
  89. package/src/native/utils/TimeSeriesBuffer.cc +205 -0
  90. package/src/native/utils/TimeSeriesBuffer.h +140 -0
  91. package/src/ts/CircularLogBuffer.ts +87 -0
  92. package/src/ts/DriftDetector.ts +331 -0
  93. package/src/ts/TopicRouter.ts +428 -0
  94. package/src/ts/__tests__/AdvancedDsp.test.ts +585 -0
  95. package/src/ts/__tests__/AuthAndEdgeCases.test.ts +241 -0
  96. package/src/ts/__tests__/Chaining.test.ts +387 -0
  97. package/src/ts/__tests__/ChebyshevBiquad.test.ts +229 -0
  98. package/src/ts/__tests__/CircularLogBuffer.test.ts +158 -0
  99. package/src/ts/__tests__/DriftDetector.test.ts +389 -0
  100. package/src/ts/__tests__/Fft.test.ts +484 -0
  101. package/src/ts/__tests__/ListState.test.ts +153 -0
  102. package/src/ts/__tests__/Logger.test.ts +208 -0
  103. package/src/ts/__tests__/LoggerAdvanced.test.ts +319 -0
  104. package/src/ts/__tests__/LoggerMinor.test.ts +247 -0
  105. package/src/ts/__tests__/MeanAbsoluteValue.test.ts +398 -0
  106. package/src/ts/__tests__/MovingAverage.test.ts +322 -0
  107. package/src/ts/__tests__/RMS.test.ts +315 -0
  108. package/src/ts/__tests__/Rectify.test.ts +272 -0
  109. package/src/ts/__tests__/Redis.test.ts +456 -0
  110. package/src/ts/__tests__/SlopeSignChange.test.ts +166 -0
  111. package/src/ts/__tests__/Tap.test.ts +164 -0
  112. package/src/ts/__tests__/TimeBasedExpiration.test.ts +124 -0
  113. package/src/ts/__tests__/TimeBasedRmsAndMav.test.ts +231 -0
  114. package/src/ts/__tests__/TimeBasedVarianceAndZScore.test.ts +284 -0
  115. package/src/ts/__tests__/TimeSeries.test.ts +254 -0
  116. package/src/ts/__tests__/TopicRouter.test.ts +332 -0
  117. package/src/ts/__tests__/TopicRouterAdvanced.test.ts +483 -0
  118. package/src/ts/__tests__/TopicRouterPriority.test.ts +487 -0
  119. package/src/ts/__tests__/Variance.test.ts +509 -0
  120. package/src/ts/__tests__/WaveformLength.test.ts +147 -0
  121. package/src/ts/__tests__/WillisonAmplitude.test.ts +197 -0
  122. package/src/ts/__tests__/ZScoreNormalize.test.ts +459 -0
  123. package/src/ts/advanced-dsp.ts +566 -0
  124. package/src/ts/backends.ts +1137 -0
  125. package/src/ts/bindings.ts +1225 -0
  126. package/src/ts/easter-egg.ts +42 -0
  127. package/src/ts/examples/MeanAbsoluteValue/test-state.ts +99 -0
  128. package/src/ts/examples/MeanAbsoluteValue/test-streaming.ts +269 -0
  129. package/src/ts/examples/MovingAverage/test-state.ts +85 -0
  130. package/src/ts/examples/MovingAverage/test-streaming.ts +188 -0
  131. package/src/ts/examples/RMS/test-state.ts +97 -0
  132. package/src/ts/examples/RMS/test-streaming.ts +253 -0
  133. package/src/ts/examples/Rectify/test-state.ts +107 -0
  134. package/src/ts/examples/Rectify/test-streaming.ts +242 -0
  135. package/src/ts/examples/Variance/test-state.ts +195 -0
  136. package/src/ts/examples/Variance/test-streaming.ts +260 -0
  137. package/src/ts/examples/ZScoreNormalize/test-state.ts +277 -0
  138. package/src/ts/examples/ZScoreNormalize/test-streaming.ts +306 -0
  139. package/src/ts/examples/advanced-dsp-examples.ts +397 -0
  140. package/src/ts/examples/callbacks/advanced-router-features.ts +326 -0
  141. package/src/ts/examples/callbacks/benchmark-circular-buffer.ts +109 -0
  142. package/src/ts/examples/callbacks/monitoring-example.ts +265 -0
  143. package/src/ts/examples/callbacks/pipeline-callbacks-example.ts +137 -0
  144. package/src/ts/examples/callbacks/pooled-callbacks-example.ts +274 -0
  145. package/src/ts/examples/callbacks/priority-routing-example.ts +277 -0
  146. package/src/ts/examples/callbacks/production-topic-router.ts +214 -0
  147. package/src/ts/examples/callbacks/topic-based-logging.ts +161 -0
  148. package/src/ts/examples/chaining/test-chaining-redis.ts +113 -0
  149. package/src/ts/examples/chaining/test-chaining.ts +52 -0
  150. package/src/ts/examples/emg-features-example.ts +284 -0
  151. package/src/ts/examples/fft-example.ts +309 -0
  152. package/src/ts/examples/fft-examples.ts +349 -0
  153. package/src/ts/examples/filter-examples.ts +320 -0
  154. package/src/ts/examples/list-state-example.ts +131 -0
  155. package/src/ts/examples/logger-example.ts +91 -0
  156. package/src/ts/examples/notch-filter-examples.ts +243 -0
  157. package/src/ts/examples/phase5/drift-detection-example.ts +290 -0
  158. package/src/ts/examples/phase6-7/production-observability.ts +476 -0
  159. package/src/ts/examples/phase6-7/redis-timeseries-integration.ts +446 -0
  160. package/src/ts/examples/redis/redis-example.ts +202 -0
  161. package/src/ts/examples/redis-example.ts +202 -0
  162. package/src/ts/examples/simd-benchmark.ts +126 -0
  163. package/src/ts/examples/tap-debugging.ts +230 -0
  164. package/src/ts/examples/timeseries/comparison-example.ts +290 -0
  165. package/src/ts/examples/timeseries/iot-sensor-example.ts +143 -0
  166. package/src/ts/examples/timeseries/redis-streaming-example.ts +233 -0
  167. package/src/ts/examples/waveform-length-example.ts +139 -0
  168. package/src/ts/fft.ts +722 -0
  169. package/src/ts/filters.ts +1078 -0
  170. package/src/ts/index.ts +120 -0
  171. package/src/ts/types.ts +589 -0
  172. package/tsconfig.json +15 -0
@@ -0,0 +1,137 @@
1
+ import { createDspPipeline } from "../../bindings.js";
2
+ import type { PipelineCallbacks } from "../../types.js";
3
+
4
+ /**
5
+ * Example demonstrating the new pipeline callback API
6
+ * for monitoring, observability, and alerting
7
+ */
8
+
9
+ // Simulated metrics collector
10
+ const metrics = {
11
+ durations: [] as number[],
12
+ record(key: string, value: number) {
13
+ console.log(`Metric: ${key} = ${value.toFixed(2)}ms`);
14
+ this.durations.push(value);
15
+ },
16
+ getAverage() {
17
+ return this.durations.reduce((a, b) => a + b, 0) / this.durations.length;
18
+ },
19
+ };
20
+
21
+ // Simulated logger
22
+ const logger = {
23
+ error(msg: string, err: Error) {
24
+ console.error(`❌ ${msg}:`, err.message);
25
+ },
26
+ info(msg: string, ctx?: any) {
27
+ console.log(`${msg}`, ctx || "");
28
+ },
29
+ };
30
+
31
+ // Alert threshold
32
+ const THRESHOLD = 0.8;
33
+ let alertCount = 0;
34
+
35
+ function triggerAlert(index: number, stage: string, value: number) {
36
+ alertCount++;
37
+ console.log(
38
+ `ALERT #${alertCount}: Sample ${index} in ${stage} exceeded threshold: ${value.toFixed(
39
+ 4
40
+ )} > ${THRESHOLD}`
41
+ );
42
+ }
43
+
44
+ // Configure callbacks
45
+ const callbacks: PipelineCallbacks = {
46
+ onSample: (value, i, stage) => {
47
+ // Only trigger alerts for samples exceeding threshold
48
+ if (Math.abs(value) > THRESHOLD) {
49
+ triggerAlert(i, stage, value);
50
+ }
51
+ },
52
+
53
+ onStageComplete: (stage, durationMs) => {
54
+ metrics.record(`dsp.${stage}.duration`, durationMs);
55
+ },
56
+
57
+ onError: (stage, err) => {
58
+ logger.error(`Stage ${stage} failed`, err);
59
+ },
60
+
61
+ onLog: (level, msg, ctx) => {
62
+ // Filter out debug logs for cleaner output
63
+ if (level === "debug") return;
64
+
65
+ const emoji = {
66
+ info: "ℹ️",
67
+ warn: "⚠️",
68
+ error: "❌",
69
+ debug: "🔍",
70
+ }[level];
71
+
72
+ console.log(`${emoji} [${level.toUpperCase()}] ${msg}`, ctx || "");
73
+ },
74
+ };
75
+
76
+ async function main() {
77
+ console.log("=".repeat(60));
78
+ console.log("Pipeline Callbacks Example");
79
+ console.log("=".repeat(60));
80
+ console.log();
81
+
82
+ // Create pipeline with callbacks configured
83
+ const pipeline = createDspPipeline()
84
+ .pipeline(callbacks) // Configure callbacks first
85
+ .MovingAverage({ mode: "moving", windowSize: 3 })
86
+ .Rectify({ mode: "full" })
87
+ .Rms({ mode: "moving", windowSize: 5 });
88
+
89
+ // Generate test signal with some peaks
90
+ const sampleRate = 44100;
91
+ const duration = 0.01; // 10ms = 441 samples
92
+ const numSamples = Math.floor(sampleRate * duration);
93
+ const testSignal = new Float32Array(numSamples);
94
+
95
+ for (let i = 0; i < numSamples; i++) {
96
+ // Mix of normal samples and some peaks
97
+ if (i % 100 === 0) {
98
+ // Inject peaks that will trigger alerts
99
+ testSignal[i] = 0.9 + Math.random() * 0.1;
100
+ } else if (i % 50 === 0) {
101
+ testSignal[i] = -0.85;
102
+ } else {
103
+ // Normal random signal
104
+ testSignal[i] = Math.random() * 0.4 - 0.2;
105
+ }
106
+ }
107
+
108
+ console.log(`Input: ${numSamples} samples`);
109
+ console.log(`Pipeline: MovingAverage(3) → Rectify(full) → RMS(5)`);
110
+ console.log();
111
+
112
+ // Process with callbacks
113
+ const result = await pipeline.process(testSignal, {
114
+ sampleRate,
115
+ channels: 1,
116
+ });
117
+
118
+ console.log();
119
+ console.log("=".repeat(60));
120
+ console.log("Results Summary");
121
+ console.log("=".repeat(60));
122
+ console.log(`Output: ${result.length} samples`);
123
+ console.log(`Total alerts triggered: ${alertCount}`);
124
+ console.log(`Average processing time: ${metrics.getAverage().toFixed(3)}ms`);
125
+ console.log(
126
+ `Output range: [${Math.min(...result).toFixed(4)}, ${Math.max(
127
+ ...result
128
+ ).toFixed(4)}]`
129
+ );
130
+ console.log();
131
+ }
132
+
133
+ // Run the example
134
+ main().catch((err) => {
135
+ console.error("Example failed:", err);
136
+ process.exit(1);
137
+ });
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Pooled Callbacks Example
3
+ * Demonstrates the performance benefits of using batched callbacks
4
+ * over individual per-sample/per-log callbacks
5
+ */
6
+
7
+ import {
8
+ createDspPipeline,
9
+ type LogEntry,
10
+ type SampleBatch,
11
+ } from "../../index.js";
12
+
13
+ // Performance metrics collector using pooled callbacks
14
+ class PooledMonitor {
15
+ private batchCount = 0;
16
+ private totalSamples = 0;
17
+ private sampleSum = 0;
18
+ private sampleMin = Infinity;
19
+ private sampleMax = -Infinity;
20
+
21
+ onBatch(batch: SampleBatch): void {
22
+ this.batchCount++;
23
+ this.totalSamples += batch.count;
24
+
25
+ // Process entire batch efficiently (SIMD-friendly)
26
+ for (let i = 0; i < batch.samples.length; i++) {
27
+ const value = batch.samples[i];
28
+ this.sampleSum += value;
29
+ if (value < this.sampleMin) this.sampleMin = value;
30
+ if (value > this.sampleMax) this.sampleMax = value;
31
+ }
32
+ }
33
+
34
+ onLogBatch(logs: LogEntry[]): void {
35
+ console.log(`\n📦 Received ${logs.length} pooled log entries:`);
36
+ logs.forEach((log) => {
37
+ const emoji =
38
+ log.level === "debug"
39
+ ? "🐛"
40
+ : log.level === "info"
41
+ ? "ℹ️"
42
+ : log.level === "warn"
43
+ ? "⚠️"
44
+ : "❌";
45
+ console.log(
46
+ ` ${emoji} [${log.level.toUpperCase()}] ${log.message}`,
47
+ log.context || ""
48
+ );
49
+ });
50
+ }
51
+
52
+ report(): void {
53
+ console.log("\nPooled Monitoring Report:");
54
+ console.log(` Batches processed: ${this.batchCount}`);
55
+ console.log(` Total samples: ${this.totalSamples}`);
56
+ console.log(
57
+ ` Sample range: [${this.sampleMin.toFixed(4)}, ${this.sampleMax.toFixed(
58
+ 4
59
+ )}]`
60
+ );
61
+ console.log(
62
+ ` Sample average: ${(this.sampleSum / this.totalSamples).toFixed(4)}`
63
+ );
64
+ }
65
+ }
66
+
67
+ async function compareCallbackPerformance() {
68
+ console.log("Comparing Callback Performance\n");
69
+
70
+ // Generate test signal (10 batches of 4096 samples each)
71
+ const batchSize = 4096;
72
+ const numBatches = 10;
73
+
74
+ // ============================================================
75
+ // Test 1: Using POOLED callbacks (onBatch + onLogBatch)
76
+ // ============================================================
77
+ console.log("Test 1: POOLED Callbacks (onBatch + onLogBatch)");
78
+ const monitor1 = new PooledMonitor();
79
+ const pipeline1 = createDspPipeline()
80
+ .pipeline({
81
+ onBatch: (batch) => monitor1.onBatch(batch),
82
+ onLogBatch: (logs) => monitor1.onLogBatch(logs),
83
+ onStageComplete: (stage, duration) => {
84
+ console.log(`Stage ${stage} completed in ${duration.toFixed(3)}ms`);
85
+ },
86
+ })
87
+ .MovingAverage({ mode: "moving", windowSize: 10 })
88
+ .Rectify({ mode: "full" })
89
+ .Rms({ mode: "moving", windowSize: 10 });
90
+
91
+ const startPooled = performance.now();
92
+ for (let batch = 0; batch < numBatches; batch++) {
93
+ const input = Float32Array.from({ length: batchSize }, (_, i) =>
94
+ Math.sin(2 * Math.PI * 440 * (i / 48000))
95
+ );
96
+ await pipeline1.process(input, { sampleRate: 48000 });
97
+ }
98
+ const durationPooled = performance.now() - startPooled;
99
+
100
+ monitor1.report();
101
+ console.log(
102
+ `\nTotal time (pooled): ${durationPooled.toFixed(3)}ms for ${
103
+ numBatches * batchSize
104
+ } samples`
105
+ );
106
+ console.log(
107
+ ` Throughput: ${(
108
+ (numBatches * batchSize) /
109
+ (durationPooled / 1000)
110
+ ).toLocaleString()} samples/sec`
111
+ );
112
+
113
+ // ============================================================
114
+ // Test 2: Using INDIVIDUAL callbacks (onSample + onLog)
115
+ // ============================================================
116
+ console.log("\n\nTest 2: INDIVIDUAL Callbacks (onSample + onLog)");
117
+ console.log("⚠️ WARNING: This will make 40,960+ callback invocations!\n");
118
+
119
+ let sampleCallCount = 0;
120
+ let logCallCount = 0;
121
+ let sampleSum2 = 0;
122
+ let sampleMin2 = Infinity;
123
+ let sampleMax2 = -Infinity;
124
+
125
+ const pipeline2 = createDspPipeline()
126
+ .pipeline({
127
+ onSample: (value, _index, _stage) => {
128
+ sampleCallCount++;
129
+ // Realistic work: aggregate stats per sample (expensive!)
130
+ sampleSum2 += value;
131
+ if (value < sampleMin2) sampleMin2 = value;
132
+ if (value > sampleMax2) sampleMax2 = value;
133
+ },
134
+ onLog: (level, message, context) => {
135
+ logCallCount++;
136
+ // Realistic work: format and store log
137
+ const timestamp = Date.now();
138
+ const _logEntry = { level, message, context, timestamp };
139
+ // In real app: push to log buffer or write to file
140
+ },
141
+ onStageComplete: (stage, duration) => {
142
+ console.log(`Stage ${stage} completed in ${duration.toFixed(3)}ms`);
143
+ },
144
+ })
145
+ .MovingAverage({ mode: "moving", windowSize: 10 })
146
+ .Rectify({ mode: "full" })
147
+ .Rms({ mode: "moving", windowSize: 10 });
148
+
149
+ const startIndividual = performance.now();
150
+ for (let batch = 0; batch < numBatches; batch++) {
151
+ const input = Float32Array.from({ length: batchSize }, (_, i) =>
152
+ Math.sin(2 * Math.PI * 440 * (i / 48000))
153
+ );
154
+ await pipeline2.process(input, { sampleRate: 48000 });
155
+ }
156
+ const durationIndividual = performance.now() - startIndividual;
157
+
158
+ console.log(`\nIndividual Callbacks Report:`);
159
+ console.log(
160
+ ` onSample() called: ${sampleCallCount.toLocaleString()} times`
161
+ );
162
+ console.log(` onLog() called: ${logCallCount} times`);
163
+ console.log(
164
+ ` Sample range: [${sampleMin2.toFixed(4)}, ${sampleMax2.toFixed(4)}]`
165
+ );
166
+ console.log(
167
+ ` Sample average: ${(sampleSum2 / sampleCallCount).toFixed(4)}`
168
+ );
169
+ console.log(
170
+ `\nTotal time (individual): ${durationIndividual.toFixed(3)}ms for ${
171
+ numBatches * batchSize
172
+ } samples`
173
+ );
174
+ console.log(
175
+ ` Throughput: ${(
176
+ (numBatches * batchSize) /
177
+ (durationIndividual / 1000)
178
+ ).toLocaleString()} samples/sec`
179
+ );
180
+
181
+ // ============================================================
182
+ // Performance Comparison
183
+ // ============================================================
184
+ console.log("\n\nPerformance Comparison:");
185
+ console.log(
186
+ ` Pooled callbacks: ${durationPooled.toFixed(3)}ms (${(
187
+ (numBatches * batchSize) /
188
+ (durationPooled / 1000)
189
+ ).toFixed(1)} samples/sec)`
190
+ );
191
+ console.log(
192
+ ` Individual callbacks: ${durationIndividual.toFixed(3)}ms (${(
193
+ (numBatches * batchSize) /
194
+ (durationIndividual / 1000)
195
+ ).toFixed(1)} samples/sec)`
196
+ );
197
+
198
+ if (durationIndividual < durationPooled) {
199
+ console.log(
200
+ ` \n Individual is ${(durationPooled / durationIndividual).toFixed(
201
+ 2
202
+ )}x faster in raw speed`
203
+ );
204
+ } else {
205
+ console.log(
206
+ ` \n Pooled is ${(durationIndividual / durationPooled).toFixed(
207
+ 2
208
+ )}x faster`
209
+ );
210
+ }
211
+
212
+ console.log("\n\nProduction Architecture Analysis:");
213
+ console.log(" ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
214
+ console.log("\n ⚠️ Individual Callbacks (onSample, onLog):");
215
+ console.log(
216
+ ` • Raw speed: ~${(
217
+ (numBatches * batchSize) /
218
+ (durationIndividual / 1000) /
219
+ 1000000
220
+ ).toFixed(1)}M samples/sec`
221
+ );
222
+ console.log(
223
+ ` • Function calls: ${(
224
+ sampleCallCount + logCallCount
225
+ ).toLocaleString()} per ${numBatches} batches`
226
+ );
227
+ console.log(" • Event loop: BLOCKS on each callback invocation");
228
+ console.log(" • GC pressure: HIGH (per-call allocations)");
229
+ console.log(" • I/O operations: SYNCHRONOUS (stalls pipeline)");
230
+ console.log(" • Production safety: NOT RECOMMENDED");
231
+ console.log(" • Use case: Microbenchmarks, toy examples only");
232
+
233
+ console.log("\n Pooled Callbacks (onBatch, onLogBatch):");
234
+ console.log(
235
+ ` • Sustained throughput: ~${(
236
+ (numBatches * batchSize) /
237
+ (durationPooled / 1000) /
238
+ 1000000
239
+ ).toFixed(1)}M samples/sec`
240
+ );
241
+ console.log(
242
+ ` • Function calls: ${numBatches} batches (1 call per process)`
243
+ );
244
+ console.log(" • Event loop: NON-BLOCKING (batched execution)");
245
+ console.log(" • GC pressure: LOW (circular buffer reuse)");
246
+ console.log(" • I/O operations: BATCHED (network-friendly)");
247
+ console.log(" • Production safety: RECOMMENDED");
248
+ console.log(
249
+ " • Industry alignment: Kafka producers, Loki agents, OTLP exporters"
250
+ );
251
+
252
+ console.log("\n Trade-off Summary:");
253
+ console.log(" Individual mode: 2x faster in synthetic tests, but...");
254
+ console.log(" - Millions of synchronous callbacks block event loop");
255
+ console.log(" - Synchronous I/O in callbacks stalls entire pipeline");
256
+ console.log(" - Unpredictable GC pauses under load");
257
+ console.log(" - Cannot handle backpressure from external systems");
258
+ console.log("");
259
+ console.log(" Pooled mode: Slight raw speed reduction, but...");
260
+ console.log(" - Guaranteed non-blocking behavior");
261
+ console.log(" - Predictable memory footprint");
262
+ console.log(" - Natural backpressure handling");
263
+ console.log(" - Matches production telemetry patterns");
264
+
265
+ console.log("\n Recommendation:");
266
+ console.log(" Use onBatch and onLogBatch for production servers");
267
+ console.log(" Individual callbacks are fast but dangerous at scale");
268
+ console.log(
269
+ " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"
270
+ );
271
+ }
272
+
273
+ // Run the comparison
274
+ compareCallbackPerformance().catch(console.error);
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Priority-Based Routing Example
3
+ *
4
+ * Demonstrates 10-level priority system with smart routing:
5
+ * - Low priority (1-3): Debug logs → Console only
6
+ * - Normal priority (4-6): Info logs → Loki
7
+ * - High priority (7-8): Warnings → Prometheus + Loki
8
+ * - Critical priority (9-10): Errors → PagerDuty + All backends
9
+ */
10
+
11
+ import {
12
+ createDspPipeline,
13
+ createTopicRouter,
14
+ createConsoleHandler,
15
+ createMockHandler,
16
+ } from "../../index.js";
17
+ import type { LogEntry } from "../../types.js";
18
+
19
+ console.log("Priority-Based Routing Example\n");
20
+
21
+ // Example 1: Basic Priority Filtering
22
+ console.log("1. Basic Priority Filtering\n");
23
+ {
24
+ const lowPriority = createMockHandler((log) => {
25
+ console.log(` [LOW] Priority ${log.priority}: ${log.message}`);
26
+ });
27
+
28
+ const normalPriority = createMockHandler((log) => {
29
+ console.log(` [NORMAL] Priority ${log.priority}: ${log.message}`);
30
+ });
31
+
32
+ const highPriority = createMockHandler((log) => {
33
+ console.log(` [HIGH] Priority ${log.priority}: ${log.message}`);
34
+ });
35
+
36
+ const critical = createMockHandler((log) => {
37
+ console.log(` [CRITICAL] Priority ${log.priority}: ${log.message}`);
38
+ });
39
+
40
+ const router = createTopicRouter()
41
+ .custom(/^pipeline\./, lowPriority.handler, {
42
+ minPriority: 1,
43
+ maxPriority: 3,
44
+ })
45
+ .custom(/^pipeline\./, normalPriority.handler, {
46
+ minPriority: 4,
47
+ maxPriority: 6,
48
+ })
49
+ .custom(/^pipeline\./, highPriority.handler, {
50
+ minPriority: 7,
51
+ maxPriority: 8,
52
+ })
53
+ .custom(/^pipeline\./, critical.handler, {
54
+ minPriority: 9,
55
+ maxPriority: 10,
56
+ })
57
+ .build();
58
+
59
+ const pipeline = createDspPipeline();
60
+ pipeline
61
+ .pipeline({
62
+ onLogBatch: (logs) => router.routeBatch(logs),
63
+ })
64
+ .MovingAverage({ mode: "moving", windowSize: 3 });
65
+
66
+ const samples = new Float32Array([1, 2, 3]);
67
+ await pipeline.process(samples, { sampleRate: 1000 });
68
+
69
+ console.log(`\n Summary:`);
70
+ console.log(` • Low priority logs: ${lowPriority.getLogs().length}`);
71
+ console.log(` • Normal priority logs: ${normalPriority.getLogs().length}`);
72
+ console.log(` • High priority logs: ${highPriority.getLogs().length}`);
73
+ console.log(` • Critical logs: ${critical.getLogs().length}\n`);
74
+ }
75
+
76
+ // Example 2: Production Alert Routing
77
+ console.log("2. Production Alert Routing (Multi-Tier)\n");
78
+ {
79
+ console.log(" Routing Strategy:");
80
+ console.log(" • Priority 1-3 (Debug): Console only");
81
+ console.log(" • Priority 4-6 (Info): Loki (logs storage)");
82
+ console.log(" • Priority 7-8 (Warn): Prometheus + Loki");
83
+ console.log(" • Priority 9-10 (Critical): PagerDuty + Prometheus + Loki\n");
84
+
85
+ const consoleBackend = createMockHandler((log) => {
86
+ console.log(` [Console] ${log.message}`);
87
+ });
88
+
89
+ const lokiBackend = createMockHandler((log) => {
90
+ console.log(` [Loki] Storing: ${log.message}`);
91
+ });
92
+
93
+ const prometheusBackend = createMockHandler((log) => {
94
+ console.log(` [Prometheus] Recording metric for: ${log.message}`);
95
+ });
96
+
97
+ const pagerDutyBackend = createMockHandler((log) => {
98
+ console.log(` [PagerDuty] ALERT triggered: ${log.message}`);
99
+ });
100
+
101
+ const router = createTopicRouter()
102
+ // Low priority: Console only
103
+ .custom(/^pipeline\./, consoleBackend.handler, {
104
+ minPriority: 1,
105
+ maxPriority: 3,
106
+ })
107
+ // Normal priority: Loki
108
+ .custom(/^pipeline\./, lokiBackend.handler, {
109
+ minPriority: 4,
110
+ maxPriority: 10, // All normal and above
111
+ })
112
+ // High priority: Prometheus
113
+ .custom(/^pipeline\./, prometheusBackend.handler, {
114
+ minPriority: 7,
115
+ maxPriority: 10,
116
+ })
117
+ // Critical: PagerDuty
118
+ .custom(/^pipeline\./, pagerDutyBackend.handler, {
119
+ minPriority: 9,
120
+ maxPriority: 10,
121
+ concurrency: 3, // Rate-limit alerts
122
+ })
123
+ .build();
124
+
125
+ // Simulate logs with different priorities
126
+ await router.routeBatch([
127
+ {
128
+ level: "debug",
129
+ message: "Verbose debug info",
130
+ topic: "pipeline.debug",
131
+ timestamp: Date.now(),
132
+ priority: 2,
133
+ },
134
+ {
135
+ level: "info",
136
+ message: "Normal operation",
137
+ topic: "pipeline.info",
138
+ timestamp: Date.now(),
139
+ priority: 5,
140
+ },
141
+ {
142
+ level: "warn",
143
+ message: "High CPU usage detected",
144
+ topic: "pipeline.warn",
145
+ timestamp: Date.now(),
146
+ priority: 7,
147
+ },
148
+ {
149
+ level: "error",
150
+ message: "Critical system failure!",
151
+ topic: "pipeline.error",
152
+ timestamp: Date.now(),
153
+ priority: 10,
154
+ },
155
+ ]);
156
+
157
+ console.log(`\n Backend Summary:`);
158
+ console.log(` • Console: ${consoleBackend.getLogs().length} logs`);
159
+ console.log(` • Loki: ${lokiBackend.getLogs().length} logs`);
160
+ console.log(` • Prometheus: ${prometheusBackend.getLogs().length} logs`);
161
+ console.log(` • PagerDuty: ${pagerDutyBackend.getLogs().length} alerts\n`);
162
+ }
163
+
164
+ // Example 3: Priority with Metrics Tracking
165
+ console.log("3. Priority Tiers with Metrics Tracking\n");
166
+ {
167
+ const router = createTopicRouter()
168
+ .custom(/^pipeline\./, createConsoleHandler(), {
169
+ minPriority: 1,
170
+ maxPriority: 5,
171
+ trackMetrics: true,
172
+ })
173
+ .custom(/^pipeline\./, createConsoleHandler(), {
174
+ minPriority: 6,
175
+ maxPriority: 10,
176
+ trackMetrics: true,
177
+ })
178
+ .build();
179
+
180
+ const pipeline = createDspPipeline();
181
+ pipeline
182
+ .pipeline({
183
+ onLogBatch: (logs) => router.routeBatch(logs),
184
+ })
185
+ .MovingAverage({ mode: "moving", windowSize: 10 })
186
+ .Rectify()
187
+ .Rms({ mode: "moving", windowSize: 5 });
188
+
189
+ const samples = new Float32Array(100).map(() => Math.random() * 10 - 5);
190
+ await pipeline.process(samples, { sampleRate: 48000 });
191
+
192
+ console.log(" Metrics by Priority Tier:\n");
193
+ const metrics = router.getMetrics();
194
+
195
+ console.log(" ┌──────────────┬──────────┬─────────────┐");
196
+ console.log(" │ Priority │ Exec │ Avg (ms) │");
197
+ console.log(" ├──────────────┼──────────┼─────────────┤");
198
+
199
+ metrics.forEach((m, idx) => {
200
+ const tier = idx === 0 ? "Low (1-5)" : "High (6-10)";
201
+ const exec = String(m.executionCount).padEnd(8);
202
+ const avg = m.averageDuration.toFixed(2).padEnd(11);
203
+ console.log(` │ ${tier.padEnd(12)} │ ${exec} │ ${avg} │`);
204
+ });
205
+
206
+ console.log(" └──────────────┴──────────┴─────────────┘\n");
207
+ }
208
+
209
+ // Example 4: Dynamic Priority Assignment
210
+ console.log("4. Dynamic Priority Based on Context\n");
211
+ {
212
+ const mockHandler = createMockHandler((log) => {
213
+ const priority = log.priority ?? 1;
214
+ const emoji =
215
+ priority >= 9 ? "🚨" : priority >= 7 ? "⚠️" : priority >= 4 ? "ℹ️" : "🔍";
216
+ console.log(` ${emoji} [P${priority}] ${log.message}`);
217
+ });
218
+
219
+ const router = createTopicRouter()
220
+ .custom(/^pipeline\./, mockHandler.handler)
221
+ .build();
222
+
223
+ // Custom logs with varying priorities
224
+ const customLogs: LogEntry[] = [
225
+ {
226
+ level: "debug",
227
+ message: "Trace-level debugging",
228
+ topic: "pipeline.debug",
229
+ timestamp: Date.now(),
230
+ priority: 1,
231
+ },
232
+ {
233
+ level: "info",
234
+ message: "User action completed",
235
+ topic: "pipeline.info",
236
+ timestamp: Date.now(),
237
+ priority: 5,
238
+ },
239
+ {
240
+ level: "warn",
241
+ message: "Memory usage at 80%",
242
+ topic: "pipeline.warn",
243
+ timestamp: Date.now(),
244
+ priority: 7,
245
+ },
246
+ {
247
+ level: "error",
248
+ message: "Database connection lost",
249
+ topic: "pipeline.error",
250
+ timestamp: Date.now(),
251
+ priority: 9,
252
+ },
253
+ {
254
+ level: "error",
255
+ message: "SYSTEM CRITICAL: Out of memory",
256
+ topic: "pipeline.error",
257
+ timestamp: Date.now(),
258
+ priority: 10,
259
+ },
260
+ ];
261
+
262
+ await router.routeBatch(customLogs);
263
+ console.log();
264
+ }
265
+
266
+ console.log("Priority System Summary:");
267
+ console.log(" - 10-level priority (1=lowest, 10=highest)");
268
+ console.log(" - Default priorities: debug=2, info=5, warn=7, error=9");
269
+ console.log(" - Route filtering with minPriority/maxPriority");
270
+ console.log(" - Multi-tier routing (low→console, high→alerts)");
271
+ console.log(" - Priority-aware metrics tracking");
272
+
273
+ console.log("\nUse Cases:");
274
+ console.log(" • Route critical errors (9-10) to PagerDuty");
275
+ console.log(" • Send warnings (7-8) to Prometheus + Loki");
276
+ console.log(" • Store info logs (4-6) in Loki only");
277
+ console.log(" • Keep debug logs (1-3) local/console");