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,476 @@
1
+ /**
2
+ * Phase 6: Production Observability Example
3
+ *
4
+ * Comprehensive monitoring patterns for production DSP pipelines:
5
+ * - Drift detection with alerting
6
+ * - Performance metrics tracking
7
+ * - Health checks
8
+ * - Graceful error handling
9
+ */
10
+
11
+ import {
12
+ createDspPipeline,
13
+ DriftDetector,
14
+ detectGaps,
15
+ validateMonotonicity,
16
+ estimateSampleRate,
17
+ } from "../../index.js";
18
+
19
+ console.log("=== Phase 6: Production Observability ===\n");
20
+
21
+ /**
22
+ * Example 1: Production Monitoring Setup
23
+ */
24
+ async function example1_ProductionMonitoring() {
25
+ console.log("\n--- Example 1: Production Monitoring Setup ---\n");
26
+
27
+ // Metrics collector
28
+ const metrics = {
29
+ samplesProcessed: 0,
30
+ driftEvents: 0,
31
+ gaps: 0,
32
+ nonMonotonic: 0,
33
+ processingTimeMs: [] as number[],
34
+ lastHealthCheck: Date.now(),
35
+ };
36
+
37
+ // Create pipeline with drift detection
38
+ const pipeline = createDspPipeline();
39
+ pipeline
40
+ .MovingAverage({ mode: "moving", windowDuration: 100 })
41
+ .Rms({ mode: "moving", windowDuration: 50 });
42
+
43
+ // Simulate sensor data with issues
44
+ const generateBatch = (startIdx: number, count: number) => {
45
+ const samples = new Float32Array(count);
46
+ const timestamps = new Float32Array(count);
47
+
48
+ for (let i = 0; i < count; i++) {
49
+ samples[i] = Math.sin((startIdx + i) * 0.1) * 100 + Math.random() * 10;
50
+
51
+ // Introduce timing issues
52
+ if (i === 10) {
53
+ // Gap: skip 50ms
54
+ timestamps[i] = Date.now() + (startIdx + i) * 10 + 50;
55
+ } else if (i === 20) {
56
+ // Backwards timestamp
57
+ timestamps[i] = Date.now() + (startIdx + i) * 10 - 20;
58
+ } else {
59
+ timestamps[i] = Date.now() + (startIdx + i) * 10;
60
+ }
61
+ }
62
+
63
+ return { samples, timestamps };
64
+ };
65
+
66
+ // Process 5 batches
67
+ console.log("Processing batches with monitoring:\n");
68
+
69
+ for (let batchIdx = 0; batchIdx < 5; batchIdx++) {
70
+ const { samples, timestamps } = generateBatch(batchIdx * 50, 50);
71
+
72
+ const startTime = performance.now();
73
+
74
+ try {
75
+ // Process with drift detection
76
+ const processed = await pipeline.process(samples, timestamps, {
77
+ channels: 1,
78
+ sampleRate: 100,
79
+ enableDriftDetection: true,
80
+ driftThreshold: 5.0, // 5% threshold
81
+ onDriftDetected: (stats) => {
82
+ metrics.driftEvents++;
83
+ console.log(
84
+ ` āš ļø Drift detected: ${stats.relativeDrift.toFixed(
85
+ 2
86
+ )}% (expected: ${
87
+ stats.expectedMs
88
+ }ms, actual: ${stats.deltaMs.toFixed(2)}ms)`
89
+ );
90
+ },
91
+ });
92
+
93
+ const endTime = performance.now();
94
+ const processingTime = endTime - startTime;
95
+ metrics.processingTimeMs.push(processingTime);
96
+
97
+ // Validate data quality
98
+ const gaps = detectGaps(timestamps, 100); // 100 Hz expected
99
+ const violations = validateMonotonicity(timestamps);
100
+
101
+ if (gaps.length > 0) {
102
+ metrics.gaps += gaps.length;
103
+ console.log(` āš ļø Batch ${batchIdx}: ${gaps.length} gaps detected`);
104
+ }
105
+
106
+ if (violations.length > 0) {
107
+ metrics.nonMonotonic++;
108
+ const first = violations[0];
109
+ console.log(
110
+ ` āš ļø Batch ${batchIdx}: Non-monotonic timestamps at index ${first.index} (${first.violation})`
111
+ );
112
+ }
113
+
114
+ metrics.samplesProcessed += samples.length;
115
+
116
+ console.log(
117
+ ` āœ… Batch ${batchIdx}: ${
118
+ samples.length
119
+ } samples processed in ${processingTime.toFixed(2)}ms`
120
+ );
121
+ } catch (error: any) {
122
+ console.error(` āŒ Batch ${batchIdx} failed: ${error.message}`);
123
+ }
124
+ }
125
+
126
+ // Health check summary
127
+ console.log("\nšŸ“Š Health Check Summary:");
128
+ console.log(` Total samples processed: ${metrics.samplesProcessed}`);
129
+ console.log(` Drift events: ${metrics.driftEvents}`);
130
+ console.log(` Gaps detected: ${metrics.gaps}`);
131
+ console.log(` Non-monotonic batches: ${metrics.nonMonotonic}`);
132
+
133
+ const avgProcessingTime =
134
+ metrics.processingTimeMs.reduce((a, b) => a + b, 0) /
135
+ metrics.processingTimeMs.length;
136
+ const maxProcessingTime = Math.max(...metrics.processingTimeMs);
137
+
138
+ console.log(` Avg processing time: ${avgProcessingTime.toFixed(2)}ms`);
139
+ console.log(` Max processing time: ${maxProcessingTime.toFixed(2)}ms`);
140
+
141
+ console.log("\nāœ… Example 1 complete\n");
142
+ }
143
+
144
+ /**
145
+ * Example 2: Alerting Thresholds
146
+ */
147
+ async function example2_AlertingThresholds() {
148
+ console.log("\n--- Example 2: Alerting Thresholds ---\n");
149
+
150
+ // Alert configuration
151
+ const alertConfig = {
152
+ maxDriftPercent: 5.0,
153
+ maxGapsPerBatch: 2,
154
+ maxProcessingTimeMs: 50,
155
+ alertCallback: (level: "warning" | "critical", message: string) => {
156
+ const prefix = level === "critical" ? "šŸ”“" : "🟔";
157
+ console.log(`${prefix} [${level.toUpperCase()}] ${message}`);
158
+ },
159
+ };
160
+
161
+ const pipeline = createDspPipeline();
162
+ pipeline.MovingAverage({ mode: "moving", windowDuration: 100 });
163
+
164
+ // Simulate problematic data
165
+ const samples = new Float32Array(100);
166
+ const timestamps = new Float32Array(100);
167
+
168
+ for (let i = 0; i < 100; i++) {
169
+ samples[i] = Math.sin(i * 0.1) * 100;
170
+
171
+ // Introduce multiple issues
172
+ if (i < 50) {
173
+ timestamps[i] = Date.now() + i * 10; // Normal
174
+ } else {
175
+ // Large drift in second half
176
+ timestamps[i] = Date.now() + i * 15; // 150 Hz instead of 100 Hz
177
+ }
178
+ }
179
+
180
+ console.log("Processing data with alerting thresholds:\n");
181
+
182
+ const startTime = performance.now();
183
+
184
+ await pipeline.process(samples, timestamps, {
185
+ channels: 1,
186
+ sampleRate: 100,
187
+ enableDriftDetection: true,
188
+ driftThreshold: alertConfig.maxDriftPercent,
189
+ onDriftDetected: (stats) => {
190
+ if (Math.abs(stats.relativeDrift) > alertConfig.maxDriftPercent * 2) {
191
+ alertConfig.alertCallback(
192
+ "critical",
193
+ `Severe drift: ${stats.relativeDrift.toFixed(2)}%`
194
+ );
195
+ } else {
196
+ alertConfig.alertCallback(
197
+ "warning",
198
+ `Drift: ${stats.relativeDrift.toFixed(2)}%`
199
+ );
200
+ }
201
+ },
202
+ });
203
+
204
+ const endTime = performance.now();
205
+ const processingTime = endTime - startTime;
206
+
207
+ // Check processing time
208
+ if (processingTime > alertConfig.maxProcessingTimeMs) {
209
+ alertConfig.alertCallback(
210
+ "warning",
211
+ `Processing time (${processingTime.toFixed(2)}ms) exceeded threshold (${
212
+ alertConfig.maxProcessingTimeMs
213
+ }ms)`
214
+ );
215
+ }
216
+
217
+ // Check for gaps
218
+ const gaps = detectGaps(timestamps, 100);
219
+ if (gaps.length > alertConfig.maxGapsPerBatch) {
220
+ alertConfig.alertCallback("critical", `Too many gaps: ${gaps.length}`);
221
+ }
222
+
223
+ console.log("\nāœ… Example 2 complete\n");
224
+ }
225
+
226
+ /**
227
+ * Example 3: Sample Rate Validation
228
+ */
229
+ async function example3_SampleRateValidation() {
230
+ console.log("\n--- Example 3: Sample Rate Validation ---\n");
231
+
232
+ const expectedRate = 100; // Hz
233
+ const tolerance = 0.05; // 5%
234
+
235
+ // Generate data with varying sample rates
236
+ const testCases = [
237
+ { name: "Correct rate (100 Hz)", rate: 100 },
238
+ { name: "Slightly fast (103 Hz)", rate: 103 },
239
+ { name: "Slightly slow (97 Hz)", rate: 97 },
240
+ { name: "Too fast (120 Hz)", rate: 120 },
241
+ { name: "Too slow (80 Hz)", rate: 80 },
242
+ ];
243
+
244
+ for (const testCase of testCases) {
245
+ const count = 100;
246
+ const timestamps = new Float32Array(count);
247
+ const intervalMs = 1000 / testCase.rate;
248
+
249
+ for (let i = 0; i < count; i++) {
250
+ timestamps[i] = Date.now() + i * intervalMs;
251
+ }
252
+
253
+ const rateInfo = estimateSampleRate(timestamps);
254
+ const deviation =
255
+ Math.abs(rateInfo.estimatedRate - expectedRate) / expectedRate;
256
+
257
+ if (deviation <= tolerance) {
258
+ console.log(
259
+ `āœ… ${testCase.name}: ${rateInfo.estimatedRate.toFixed(
260
+ 2
261
+ )} Hz (within tolerance)`
262
+ );
263
+ } else {
264
+ console.log(
265
+ `āš ļø ${testCase.name}: ${rateInfo.estimatedRate.toFixed(
266
+ 2
267
+ )} Hz (exceeds ${(tolerance * 100).toFixed(0)}% tolerance)`
268
+ );
269
+ }
270
+
271
+ console.log(` Regularity: ${rateInfo.regularity}`);
272
+ }
273
+
274
+ console.log("\nāœ… Example 3 complete\n");
275
+ }
276
+
277
+ /**
278
+ * Example 4: Production Health Check Endpoint
279
+ */
280
+ class DspHealthMonitor {
281
+ private metrics = {
282
+ totalSamples: 0,
283
+ totalBatches: 0,
284
+ failedBatches: 0,
285
+ driftEvents: 0,
286
+ gaps: 0,
287
+ processingTimes: [] as number[],
288
+ lastProcessedAt: 0,
289
+ };
290
+
291
+ private readonly maxMetricHistory = 100;
292
+
293
+ recordBatchSuccess(sampleCount: number, processingTimeMs: number): void {
294
+ this.metrics.totalSamples += sampleCount;
295
+ this.metrics.totalBatches++;
296
+ this.metrics.processingTimes.push(processingTimeMs);
297
+ this.metrics.lastProcessedAt = Date.now();
298
+
299
+ // Keep history bounded
300
+ if (this.metrics.processingTimes.length > this.maxMetricHistory) {
301
+ this.metrics.processingTimes.shift();
302
+ }
303
+ }
304
+
305
+ recordBatchFailure(): void {
306
+ this.metrics.failedBatches++;
307
+ this.metrics.totalBatches++;
308
+ }
309
+
310
+ recordDriftEvent(): void {
311
+ this.metrics.driftEvents++;
312
+ }
313
+
314
+ recordGap(): void {
315
+ this.metrics.gaps++;
316
+ }
317
+
318
+ getHealthStatus(): {
319
+ status: "healthy" | "degraded" | "unhealthy";
320
+ metrics: any;
321
+ issues: string[];
322
+ } {
323
+ const issues: string[] = [];
324
+ let status: "healthy" | "degraded" | "unhealthy" = "healthy";
325
+
326
+ // Check failure rate
327
+ const failureRate =
328
+ this.metrics.failedBatches / Math.max(1, this.metrics.totalBatches);
329
+ if (failureRate > 0.1) {
330
+ issues.push(`High failure rate: ${(failureRate * 100).toFixed(1)}%`);
331
+ status = "unhealthy";
332
+ } else if (failureRate > 0.05) {
333
+ issues.push(`Elevated failure rate: ${(failureRate * 100).toFixed(1)}%`);
334
+ status = status === "healthy" ? "degraded" : status;
335
+ }
336
+
337
+ // Check drift events
338
+ const driftRate =
339
+ this.metrics.driftEvents / Math.max(1, this.metrics.totalBatches);
340
+ if (driftRate > 0.2) {
341
+ issues.push(`High drift rate: ${(driftRate * 100).toFixed(1)}%`);
342
+ status = status === "healthy" ? "degraded" : status;
343
+ }
344
+
345
+ // Check processing time
346
+ if (this.metrics.processingTimes.length > 0) {
347
+ const avgTime =
348
+ this.metrics.processingTimes.reduce((a, b) => a + b, 0) /
349
+ this.metrics.processingTimes.length;
350
+
351
+ if (avgTime > 100) {
352
+ issues.push(`Slow processing: ${avgTime.toFixed(2)}ms avg`);
353
+ status = status === "healthy" ? "degraded" : status;
354
+ }
355
+ }
356
+
357
+ // Check last processed timestamp
358
+ const timeSinceLastProcess = Date.now() - this.metrics.lastProcessedAt;
359
+ if (this.metrics.lastProcessedAt > 0 && timeSinceLastProcess > 60000) {
360
+ issues.push("No data processed in last 60 seconds");
361
+ status = "unhealthy";
362
+ }
363
+
364
+ return {
365
+ status,
366
+ metrics: {
367
+ ...this.metrics,
368
+ avgProcessingTimeMs:
369
+ this.metrics.processingTimes.length > 0
370
+ ? this.metrics.processingTimes.reduce((a, b) => a + b, 0) /
371
+ this.metrics.processingTimes.length
372
+ : 0,
373
+ },
374
+ issues,
375
+ };
376
+ }
377
+ }
378
+
379
+ async function example4_HealthCheckEndpoint() {
380
+ console.log("\n--- Example 4: Production Health Check ---\n");
381
+
382
+ const monitor = new DspHealthMonitor();
383
+ const pipeline = createDspPipeline();
384
+ pipeline.MovingAverage({ mode: "moving", windowDuration: 100 });
385
+
386
+ // Simulate processing batches
387
+ console.log("Simulating production workload:\n");
388
+
389
+ for (let i = 0; i < 10; i++) {
390
+ const samples = new Float32Array(50);
391
+ const timestamps = new Float32Array(50);
392
+
393
+ for (let j = 0; j < 50; j++) {
394
+ samples[j] = Math.sin((i * 50 + j) * 0.1) * 100;
395
+ timestamps[j] = Date.now() + (i * 50 + j) * 10;
396
+ }
397
+
398
+ const startTime = performance.now();
399
+
400
+ try {
401
+ await pipeline.process(samples, timestamps, {
402
+ channels: 1,
403
+ sampleRate: 100,
404
+ enableDriftDetection: true,
405
+ driftThreshold: 5.0,
406
+ onDriftDetected: () => {
407
+ monitor.recordDriftEvent();
408
+ },
409
+ });
410
+
411
+ const endTime = performance.now();
412
+ monitor.recordBatchSuccess(samples.length, endTime - startTime);
413
+ } catch (error) {
414
+ monitor.recordBatchFailure();
415
+ }
416
+
417
+ // Simulate occasional issues
418
+ if (i === 5) {
419
+ monitor.recordGap();
420
+ }
421
+ }
422
+
423
+ // Get health status
424
+ const health = monitor.getHealthStatus();
425
+
426
+ console.log("šŸ“Š Health Check Result:");
427
+ console.log(` Status: ${health.status.toUpperCase()}`);
428
+ console.log(` Total samples: ${health.metrics.totalSamples}`);
429
+ console.log(` Total batches: ${health.metrics.totalBatches}`);
430
+ console.log(` Failed batches: ${health.metrics.failedBatches}`);
431
+ console.log(` Drift events: ${health.metrics.driftEvents}`);
432
+ console.log(` Gaps: ${health.metrics.gaps}`);
433
+ console.log(
434
+ ` Avg processing time: ${health.metrics.avgProcessingTimeMs.toFixed(2)}ms`
435
+ );
436
+
437
+ if (health.issues.length > 0) {
438
+ console.log("\n Issues:");
439
+ health.issues.forEach((issue) => {
440
+ console.log(` āš ļø ${issue}`);
441
+ });
442
+ }
443
+
444
+ console.log("\nšŸ’” Expose this as HTTP endpoint:");
445
+ console.log(" GET /health → { status, metrics, issues }");
446
+ console.log("\nāœ… Example 4 complete\n");
447
+ }
448
+
449
+ // Run all examples
450
+ async function main() {
451
+ console.log("šŸ“š Production observability patterns for DSP pipelines\n");
452
+
453
+ await example1_ProductionMonitoring();
454
+ await example2_AlertingThresholds();
455
+ await example3_SampleRateValidation();
456
+ await example4_HealthCheckEndpoint();
457
+
458
+ console.log("=== Phase 6 Complete ===\n");
459
+ console.log("āœ… Production observability includes:");
460
+ console.log(" • Comprehensive metrics tracking");
461
+ console.log(" • Alerting with configurable thresholds");
462
+ console.log(" • Sample rate validation");
463
+ console.log(" • Health check endpoints");
464
+ console.log(" • Graceful error handling\n");
465
+
466
+ console.log("šŸ’” Integration ideas:");
467
+ console.log(" • Export metrics to Prometheus");
468
+ console.log(" • Send alerts to PagerDuty/Slack");
469
+ console.log(" • Create Grafana dashboards");
470
+ console.log(" • Log to structured logging system\n");
471
+ }
472
+
473
+ main().catch((error) => {
474
+ console.error("Error:", error.message);
475
+ process.exit(1);
476
+ });