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,332 @@
1
+ /**
2
+ * Unit tests for TopicRouter
3
+ */
4
+
5
+ import { describe, it } from "node:test";
6
+ import assert from "node:assert";
7
+ import { TopicRouter, createTopicRouter } from "../TopicRouter.js";
8
+ import type { LogEntry } from "../types.js";
9
+
10
+ describe("TopicRouter", () => {
11
+ it("should route logs to matching handlers", async () => {
12
+ const router = new TopicRouter();
13
+ const routed: string[] = [];
14
+
15
+ router.addRoute(/^pipeline\.error/, (log) => {
16
+ routed.push(`error: ${log.message}`);
17
+ });
18
+
19
+ router.addRoute(/^pipeline\.info/, (log) => {
20
+ routed.push(`info: ${log.message}`);
21
+ });
22
+
23
+ await router.route({
24
+ topic: "pipeline.error",
25
+ level: "error",
26
+ message: "Test error",
27
+ timestamp: 1,
28
+ });
29
+
30
+ await router.route({
31
+ topic: "pipeline.info",
32
+ level: "info",
33
+ message: "Test info",
34
+ timestamp: 2,
35
+ });
36
+
37
+ assert.strictEqual(routed.length, 2);
38
+ assert.strictEqual(routed[0], "error: Test error");
39
+ assert.strictEqual(routed[1], "info: Test info");
40
+ });
41
+
42
+ it("should support async handlers", async () => {
43
+ const router = new TopicRouter();
44
+ const routed: string[] = [];
45
+
46
+ router.addRoute(/^pipeline\./, async (log) => {
47
+ await new Promise((resolve) => setTimeout(resolve, 10));
48
+ routed.push(log.message);
49
+ });
50
+
51
+ await router.route({
52
+ topic: "pipeline.test",
53
+ level: "info",
54
+ message: "Async test",
55
+ timestamp: 1,
56
+ });
57
+
58
+ assert.strictEqual(routed.length, 1);
59
+ assert.strictEqual(routed[0], "Async test");
60
+ });
61
+
62
+ it("should route to multiple matching handlers", async () => {
63
+ const router = new TopicRouter();
64
+ const calls: string[] = [];
65
+
66
+ router.addRoute(/^pipeline\./, () => {
67
+ calls.push("handler1");
68
+ });
69
+
70
+ router.addRoute(/^pipeline\.error/, () => {
71
+ calls.push("handler2");
72
+ });
73
+
74
+ await router.route({
75
+ topic: "pipeline.error",
76
+ level: "error",
77
+ message: "Test",
78
+ timestamp: 1,
79
+ });
80
+
81
+ assert.strictEqual(calls.length, 2);
82
+ assert.ok(calls.includes("handler1"));
83
+ assert.ok(calls.includes("handler2"));
84
+ });
85
+
86
+ it("should handle batch routing", async () => {
87
+ const router = new TopicRouter();
88
+ const routed: string[] = [];
89
+
90
+ router.addRoute(/^pipeline\./, (log) => {
91
+ routed.push(log.message);
92
+ });
93
+
94
+ const logs: LogEntry[] = [
95
+ {
96
+ topic: "pipeline.error",
97
+ level: "error",
98
+ message: "Error 1",
99
+ timestamp: 1,
100
+ },
101
+ {
102
+ topic: "pipeline.info",
103
+ level: "info",
104
+ message: "Info 1",
105
+ timestamp: 2,
106
+ },
107
+ {
108
+ topic: "pipeline.debug",
109
+ level: "debug",
110
+ message: "Debug 1",
111
+ timestamp: 3,
112
+ },
113
+ ];
114
+
115
+ await router.routeBatch(logs);
116
+
117
+ assert.strictEqual(routed.length, 3);
118
+ assert.ok(routed.includes("Error 1"));
119
+ assert.ok(routed.includes("Info 1"));
120
+ assert.ok(routed.includes("Debug 1"));
121
+ });
122
+
123
+ it("should skip logs without topics", async () => {
124
+ const router = new TopicRouter();
125
+ let called = false;
126
+
127
+ router.addRoute(/.*/, () => {
128
+ called = true;
129
+ });
130
+
131
+ await router.route({
132
+ level: "info",
133
+ message: "No topic",
134
+ timestamp: 1,
135
+ });
136
+
137
+ assert.strictEqual(called, false);
138
+ });
139
+
140
+ it("should handle errors in handlers gracefully", async () => {
141
+ const router = new TopicRouter();
142
+ const calls: string[] = [];
143
+
144
+ router.addRoute(/^pipeline\./, () => {
145
+ calls.push("before-error");
146
+ throw new Error("Handler error");
147
+ });
148
+
149
+ router.addRoute(/^pipeline\./, () => {
150
+ calls.push("after-error");
151
+ });
152
+
153
+ // Should not throw
154
+ await router.route({
155
+ topic: "pipeline.test",
156
+ level: "info",
157
+ message: "Test",
158
+ timestamp: 1,
159
+ });
160
+
161
+ // Both handlers should have been called
162
+ assert.strictEqual(calls.length, 2);
163
+ });
164
+
165
+ it("should support chainable addRoute", () => {
166
+ const router = new TopicRouter();
167
+
168
+ const result = router
169
+ .addRoute(/^pipeline\.error/, () => {})
170
+ .addRoute(/^pipeline\.info/, () => {})
171
+ .addRoute(/.*/, () => {});
172
+
173
+ assert.strictEqual(result, router);
174
+ assert.strictEqual(router.getRoutes().length, 3);
175
+ });
176
+
177
+ it("should clear routes", () => {
178
+ const router = new TopicRouter();
179
+
180
+ router.addRoute(/^pipeline\./, () => {});
181
+ router.addRoute(/.*/, () => {});
182
+
183
+ assert.strictEqual(router.getRoutes().length, 2);
184
+
185
+ router.clearRoutes();
186
+
187
+ assert.strictEqual(router.getRoutes().length, 0);
188
+ });
189
+ });
190
+
191
+ describe("TopicRouterBuilder", () => {
192
+ it("should build router with error route", async () => {
193
+ const routed: string[] = [];
194
+
195
+ const router = createTopicRouter()
196
+ .errors((log) => {
197
+ routed.push(`error: ${log.message}`);
198
+ })
199
+ .build();
200
+
201
+ await router.route({
202
+ topic: "pipeline.error",
203
+ level: "error",
204
+ message: "Test error",
205
+ timestamp: 1,
206
+ });
207
+
208
+ await router.route({
209
+ topic: "pipeline.stage.rms.error",
210
+ level: "error",
211
+ message: "Stage error",
212
+ timestamp: 2,
213
+ });
214
+
215
+ assert.strictEqual(routed.length, 2);
216
+ });
217
+
218
+ it("should build router with performance route", async () => {
219
+ const routed: string[] = [];
220
+
221
+ const router = createTopicRouter()
222
+ .performance((log) => {
223
+ routed.push(`perf: ${log.message}`);
224
+ })
225
+ .build();
226
+
227
+ await router.route({
228
+ topic: "pipeline.stage.rms.performance",
229
+ level: "info",
230
+ message: "RMS timing",
231
+ timestamp: 1,
232
+ });
233
+
234
+ assert.strictEqual(routed.length, 1);
235
+ assert.strictEqual(routed[0], "perf: RMS timing");
236
+ });
237
+
238
+ it("should build router with stage-specific route", async () => {
239
+ const routed: string[] = [];
240
+
241
+ const router = createTopicRouter()
242
+ .stage("rms", (log) => {
243
+ routed.push(`rms: ${log.message}`);
244
+ })
245
+ .build();
246
+
247
+ await router.route({
248
+ topic: "pipeline.stage.rms.performance",
249
+ level: "info",
250
+ message: "RMS log",
251
+ timestamp: 1,
252
+ });
253
+
254
+ await router.route({
255
+ topic: "pipeline.stage.movingAverage.performance",
256
+ level: "info",
257
+ message: "MA log",
258
+ timestamp: 2,
259
+ });
260
+
261
+ assert.strictEqual(routed.length, 1);
262
+ assert.strictEqual(routed[0], "rms: RMS log");
263
+ });
264
+
265
+ it("should build router with debug route", async () => {
266
+ const routed: string[] = [];
267
+
268
+ const router = createTopicRouter()
269
+ .debug((log) => {
270
+ routed.push(log.message);
271
+ })
272
+ .build();
273
+
274
+ await router.route({
275
+ topic: "pipeline.debug",
276
+ level: "debug",
277
+ message: "Debug message",
278
+ timestamp: 1,
279
+ });
280
+
281
+ assert.strictEqual(routed.length, 1);
282
+ });
283
+
284
+ it("should build router with default route", async () => {
285
+ const routed: string[] = [];
286
+
287
+ const router = createTopicRouter()
288
+ .default((log) => {
289
+ routed.push(log.message);
290
+ })
291
+ .build();
292
+
293
+ await router.route({
294
+ topic: "pipeline.anything",
295
+ level: "info",
296
+ message: "Any message",
297
+ timestamp: 1,
298
+ });
299
+
300
+ assert.strictEqual(routed.length, 1);
301
+ });
302
+
303
+ it("should build router with custom route", async () => {
304
+ const routed: string[] = [];
305
+
306
+ const router = createTopicRouter()
307
+ .custom(/^custom\./, (log) => {
308
+ routed.push(log.message);
309
+ })
310
+ .build();
311
+
312
+ await router.route({
313
+ topic: "custom.topic",
314
+ level: "info",
315
+ message: "Custom message",
316
+ timestamp: 1,
317
+ });
318
+
319
+ assert.strictEqual(routed.length, 1);
320
+ });
321
+
322
+ it("should support method chaining", () => {
323
+ const router = createTopicRouter()
324
+ .errors(() => {})
325
+ .performance(() => {})
326
+ .debug(() => {})
327
+ .default(() => {})
328
+ .build();
329
+
330
+ assert.strictEqual(router.getRoutes().length, 4);
331
+ });
332
+ });