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,376 @@
1
+ # Time-Series Migration Plan
2
+
3
+ **Goal:** Transform dspx from a sample-based processor to a time-aware time-series processor.
4
+
5
+ ---
6
+
7
+ ## Architecture Decision
8
+
9
+ ### Current (Sample-Based)
10
+
11
+ ```typescript
12
+ // User provides raw samples, library assumes fixed intervals
13
+ pipeline.process(new Float32Array([1, 2, 3, 4, 5]), {
14
+ sampleRate: 100, // Assumes 100Hz = 10ms intervals
15
+ channels: 1,
16
+ });
17
+ ```
18
+
19
+ **Problems:**
20
+
21
+ - ❌ Breaks with irregular data (network jitter, sensor lag)
22
+ - ❌ Window size in "samples" is unintuitive (500 samples ≠ 5 seconds without mental math)
23
+ - ❌ Fragile to sample rate changes
24
+ - ❌ Redis persistence lacks context (what _time_ is this sample from?)
25
+
26
+ ### Proposed (Time-Based)
27
+
28
+ ```typescript
29
+ // Option 1: Parallel timestamps array
30
+ pipeline.process(
31
+ new Float32Array([1, 2, 3, 4, 5]),
32
+ new Float32Array([1000, 1010, 1020, 1030, 1040]), // millisecond timestamps
33
+ { channels: 1 }
34
+ );
35
+
36
+ // Option 2: Interleaved (value, timestamp) pairs
37
+ pipeline.process(
38
+ new Float32Array([1, 1000, 2, 1010, 3, 1020, 4, 1030, 5, 1040]),
39
+ { format: "interleaved", channels: 1 }
40
+ );
41
+
42
+ // Option 3: Fall back to sample-based for backwards compatibility
43
+ pipeline.process(
44
+ new Float32Array([1, 2, 3, 4, 5]),
45
+ { sampleRate: 100, channels: 1 } // Old API still works
46
+ );
47
+ ```
48
+
49
+ **Benefits:**
50
+
51
+ - ✅ Handles irregular data correctly
52
+ - ✅ Intuitive windowing: `windowDuration: 5000` = 5 seconds (regardless of sample rate)
53
+ - ✅ Robust to sample rate changes
54
+ - ✅ Redis persistence has full context
55
+ - ✅ Backwards compatible (sampleRate-based still works)
56
+
57
+ ---
58
+
59
+ ## Implementation Phases
60
+
61
+ ### Phase 1: TypeScript API Changes
62
+
63
+ #### 1.1 Update `ProcessOptions`
64
+
65
+ ```typescript
66
+ export interface ProcessOptions {
67
+ // Legacy sample-based mode (backwards compatible)
68
+ sampleRate?: number;
69
+ channels?: number;
70
+
71
+ // New time-based mode (mutually exclusive with sampleRate)
72
+ // If omitted, assumes millisecond increments: [0, 1, 2, 3, ...]
73
+ }
74
+ ```
75
+
76
+ #### 1.2 Update Filter Parameters
77
+
78
+ ```typescript
79
+ // Current
80
+ export interface MovingAverageParams {
81
+ mode: "batch" | "moving";
82
+ windowSize?: number; // in samples
83
+ }
84
+
85
+ // New (backwards compatible)
86
+ export interface MovingAverageParams {
87
+ mode: "batch" | "moving";
88
+
89
+ // Option 1: Sample-based (legacy)
90
+ windowSize?: number; // in samples (requires sampleRate in process())
91
+
92
+ // Option 2: Time-based (preferred)
93
+ windowDuration?: number; // in milliseconds
94
+ }
95
+ ```
96
+
97
+ #### 1.3 New `process()` Signatures
98
+
99
+ ```typescript
100
+ class DspProcessor {
101
+ // Legacy: Sample-based (backwards compatible)
102
+ process(
103
+ samples: Float32Array,
104
+ options: { sampleRate: number; channels?: number }
105
+ ): Promise<Float32Array>;
106
+
107
+ // New: Time-based with parallel arrays
108
+ process(
109
+ samples: Float32Array,
110
+ timestamps: Float32Array,
111
+ options: { channels?: number }
112
+ ): Promise<Float32Array>;
113
+
114
+ // Auto-generate timestamps if missing
115
+ process(
116
+ samples: Float32Array,
117
+ options: { channels?: number }
118
+ ): Promise<Float32Array>; // timestamps = [0, 1, 2, ...]
119
+ }
120
+ ```
121
+
122
+ ---
123
+
124
+ ### Phase 2: C++ Core Changes
125
+
126
+ #### 2.1 Update `SlidingWindowFilter` to Store Time
127
+
128
+ ```cpp
129
+ // Current: Stores only values
130
+ template <typename T, typename Policy>
131
+ class SlidingWindowFilter {
132
+ CircularBuffer<T> m_buffer; // [v1, v2, v3, ...]
133
+ Policy m_policy;
134
+ size_t m_windowSize; // Number of samples
135
+ };
136
+
137
+ // New: Stores (time, value) pairs
138
+ template <typename T, typename Policy>
139
+ class SlidingWindowFilter {
140
+ std::deque<std::pair<uint64_t, T>> m_buffer; // [(t1,v1), (t2,v2), ...]
141
+ Policy m_policy;
142
+ uint64_t m_windowDuration; // Duration in milliseconds
143
+
144
+ void add(T value, uint64_t timestamp) {
145
+ // Add new sample
146
+ m_buffer.push_back({timestamp, value});
147
+ m_policy.onAdd(value);
148
+
149
+ // Remove expired samples
150
+ while (!m_buffer.empty() &&
151
+ timestamp - m_buffer.front().first > m_windowDuration) {
152
+ T expired = m_buffer.front().second;
153
+ m_buffer.pop_front();
154
+ m_policy.onRemove(expired);
155
+ }
156
+ }
157
+ };
158
+ ```
159
+
160
+ #### 2.2 Update All Filters
161
+
162
+ - `MovingAverageFilter` - Time-based window
163
+ - `RmsFilter` - Time-based window
164
+ - `MovingAbsoluteValueFilter` - Time-based window
165
+ - `MovingVarianceFilter` - Time-based window
166
+ - `MovingZScoreFilter` - Time-based window
167
+
168
+ #### 2.3 Update N-API Bindings
169
+
170
+ ```cpp
171
+ // DspPipeline::ProcessAsync needs to accept optional timestamps
172
+ Napi::Value DspPipeline::Process(const Napi::CallbackInfo& info) {
173
+ Napi::Float32Array samples = info[0].As<Napi::Float32Array>();
174
+
175
+ // Check if second arg is timestamps or options
176
+ Napi::Float32Array timestamps;
177
+ if (info[1].IsTypedArray()) {
178
+ timestamps = info[1].As<Napi::Float32Array>();
179
+ // options is info[2]
180
+ } else {
181
+ // Legacy mode: auto-generate timestamps
182
+ // options is info[1]
183
+ }
184
+ }
185
+ ```
186
+
187
+ ---
188
+
189
+ ### Phase 3: State Serialization Updates
190
+
191
+ #### 3.1 JSON Format Changes
192
+
193
+ ```json
194
+ {
195
+ "timestamp": 1678886400000,
196
+ "stages": [
197
+ {
198
+ "index": 0,
199
+ "type": "movingAverage",
200
+ "state": {
201
+ "windowDuration": 5000, // NEW: milliseconds instead of sample count
202
+ "numChannels": 1,
203
+ "channels": [
204
+ {
205
+ "buffer": [
206
+ { "time": 1678886395000, "value": 3.0 },
207
+ { "time": 1678886396000, "value": 4.0 },
208
+ { "time": 1678886397000, "value": 5.0 }
209
+ ],
210
+ "runningSum": 12.0
211
+ }
212
+ ]
213
+ }
214
+ }
215
+ ]
216
+ }
217
+ ```
218
+
219
+ ---
220
+
221
+ ### Phase 4: Migration Strategy (Backwards Compatibility)
222
+
223
+ #### 4.1 Detection Logic
224
+
225
+ ```typescript
226
+ // In DspProcessor.process()
227
+ if (options.sampleRate) {
228
+ // Legacy sample-based mode
229
+ // Convert sampleRate to timestamps internally
230
+ const dt = 1000 / options.sampleRate; // milliseconds per sample
231
+ const timestamps = new Float32Array(samples.length);
232
+ for (let i = 0; i < samples.length; i++) {
233
+ timestamps[i] = i * dt;
234
+ }
235
+ return this.processWithTime(samples, timestamps, options);
236
+ } else {
237
+ // New time-based mode
238
+ return this.processWithTime(samples, timestamps, options);
239
+ }
240
+ ```
241
+
242
+ #### 4.2 Filter Configuration Migration
243
+
244
+ ```typescript
245
+ // Auto-convert windowSize to windowDuration
246
+ if (params.windowSize && options.sampleRate) {
247
+ const windowDuration = (params.windowSize / options.sampleRate) * 1000;
248
+ // Use windowDuration internally
249
+ }
250
+ ```
251
+
252
+ ---
253
+
254
+ ## Testing Strategy
255
+
256
+ ### 5.1 Backwards Compatibility Tests
257
+
258
+ - ✅ All existing tests should pass unchanged
259
+ - ✅ Legacy `windowSize` with `sampleRate` produces same results
260
+
261
+ ### 5.2 New Time-Based Tests
262
+
263
+ - ✅ Irregular timestamps handled correctly
264
+ - ✅ Variable sample rates work
265
+ - ✅ Window duration matches expected time span
266
+ - ✅ State serialization includes timestamps
267
+
268
+ ### 5.3 Performance Tests
269
+
270
+ - ✅ `std::deque` performance vs `CircularBuffer`
271
+ - ✅ Memory usage with time storage
272
+ - ✅ Throughput comparison (sample-based vs time-based)
273
+
274
+ ---
275
+
276
+ ## Documentation Updates
277
+
278
+ ### 6.1 README Changes
279
+
280
+ ```typescript
281
+ // Highlight time-based API
282
+ const pipeline = createDspPipeline();
283
+ pipeline.MovingAverage({ windowDuration: 5000 }); // 5 seconds
284
+
285
+ // Show irregular data handling
286
+ const samples = new Float32Array([1.2, 1.5, 1.8]);
287
+ const timestamps = new Float32Array([0, 100, 250]); // Irregular gaps
288
+ await pipeline.process(samples, timestamps, { channels: 1 });
289
+ ```
290
+
291
+ ### 6.2 Migration Guide
292
+
293
+ Create `docs/migration-to-time-series.md` with:
294
+
295
+ - Why time-based is better
296
+ - How to migrate existing code
297
+ - Performance implications
298
+ - Backwards compatibility guarantees
299
+
300
+ ---
301
+
302
+ ## Implementation Timeline
303
+
304
+ ### Week 1: TypeScript Layer
305
+
306
+ - [ ] Update `types.ts` with new interfaces
307
+ - [ ] Update `bindings.ts` with new `process()` signatures
308
+ - [ ] Add detection logic for legacy vs new mode
309
+ - [ ] Add backwards compatibility tests
310
+
311
+ ### Week 2: C++ Core (Simple Filters)
312
+
313
+ - [ ] Update `SlidingWindowFilter` to use `std::deque<pair<time, value>>`
314
+ - [ ] Update `MovingAverageFilter` to time-based windowing
315
+ - [ ] Update `RmsFilter` to time-based windowing
316
+ - [ ] Add C++ unit tests
317
+
318
+ ### Week 3: C++ Core (Complex Filters)
319
+
320
+ - [ ] Update `MovingVarianceFilter`
321
+ - [ ] Update `MovingZScoreFilter`
322
+ - [ ] Update `MovingAbsoluteValueFilter`
323
+ - [ ] Update N-API bindings
324
+
325
+ ### Week 4: State & Documentation
326
+
327
+ - [ ] Update state serialization format
328
+ - [ ] Add migration for old state format
329
+ - [ ] Update all documentation
330
+ - [ ] Create migration guide
331
+ - [ ] Performance benchmarks
332
+
333
+ ---
334
+
335
+ ## Open Questions
336
+
337
+ 1. **Timestamp Units**: Milliseconds (standard) or allow user-defined?
338
+ 2. **Timestamp Type**: `uint64_t` (C++) vs `number` (JS) precision?
339
+ 3. **Memory Trade-off**: `std::deque` vs custom circular buffer with time?
340
+ 4. **Multi-channel Time**: One timestamp per sample or per channel?
341
+ 5. **Batch vs Moving**: Should batch mode also support time?
342
+
343
+ ---
344
+
345
+ ## Risk Mitigation
346
+
347
+ ### Breaking Changes
348
+
349
+ - **Risk**: Changing C++ core may break existing code
350
+ - **Mitigation**: Full backwards compatibility via auto-conversion
351
+
352
+ ### Performance Regression
353
+
354
+ - **Risk**: `std::deque` slower than `CircularBuffer`
355
+ - **Mitigation**: Benchmark and optimize; consider custom time-aware circular buffer
356
+
357
+ ### State Migration
358
+
359
+ - **Risk**: Old Redis states won't load
360
+ - **Mitigation**: Add state version field and auto-upgrade logic
361
+
362
+ ---
363
+
364
+ ## Success Criteria
365
+
366
+ ✅ All existing tests pass without modification
367
+ ✅ New time-based API works with irregular data
368
+ ✅ Redis state includes timestamps
369
+ ✅ Documentation updated with examples
370
+ ✅ Performance within 10% of current implementation
371
+ ✅ Migration guide published
372
+
373
+ ---
374
+
375
+ **Status**: 📋 Planning Phase
376
+ **Next Action**: Implement TypeScript API changes (Phase 1)
package/jest.config.js ADDED
@@ -0,0 +1,37 @@
1
+ export default {
2
+ preset: "ts-jest/presets/default-esm",
3
+ testEnvironment: "node",
4
+ extensionsToTreatAsEsm: [".ts"],
5
+ moduleNameMapper: {
6
+ "^(\\.{1,2}/.*)\\.js$": "$1",
7
+ },
8
+ transform: {
9
+ "^.+\\.tsx?$": [
10
+ "ts-jest",
11
+ {
12
+ useESM: true,
13
+ tsconfig: {
14
+ module: "ES2022",
15
+ moduleResolution: "bundler",
16
+ target: "ES2022",
17
+ lib: ["ES2022"],
18
+ allowSyntheticDefaultImports: true,
19
+ esModuleInterop: true,
20
+ },
21
+ },
22
+ ],
23
+ },
24
+ testMatch: ["**/__tests__/**/*.test.ts", "**/?(*.)+(spec|test).ts"],
25
+ collectCoverageFrom: [
26
+ "src/ts/**/*.ts",
27
+ "!src/ts/**/*.d.ts",
28
+ "!src/ts/examples/**",
29
+ ],
30
+ coverageDirectory: "coverage",
31
+ coverageReporters: ["text", "lcov", "html"],
32
+ globals: {
33
+ "ts-jest": {
34
+ useESM: true,
35
+ },
36
+ },
37
+ };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "dspx",
3
+ "version": "0.1.1-alpha.0",
4
+ "description": "High-performance DSP library with native C++ acceleration and Redis state persistence",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "node scripts/test.js",
8
+ "build": "node-gyp rebuild && node -e \"const fs = require('fs'); fs.cpSync('build/Release/dspx.node', 'src/build/dspx.node', {force: true}); console.log('Copied build/Release/dspx.node to src/build/dspx.node');\"",
9
+ "prebuildify": "prebuildify --napi --strip --target 18.0.0 --target 20.0.0 --target 22.0.0"
10
+ },
11
+ "binary": {
12
+ "napi_versions": [
13
+ 8
14
+ ]
15
+ },
16
+ "keywords": [
17
+ "dsp",
18
+ "signal-processing",
19
+ "native",
20
+ "redis",
21
+ "real-time",
22
+ "audio",
23
+ "biosignal"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "type": "module",
28
+ "dependencies": {
29
+ "node-addon-api": "^8.5.0",
30
+ "node-gyp-build": "^4.8.0"
31
+ },
32
+ "devDependencies": {
33
+ "@jest/globals": "^30.2.0",
34
+ "@types/jest": "^30.0.0",
35
+ "@types/node": "^24.9.1",
36
+ "jest": "^30.2.0",
37
+ "prebuildify": "^6.0.1",
38
+ "redis": "^5.9.0",
39
+ "ts-jest": "^29.4.5",
40
+ "tsx": "^4.20.6"
41
+ }
42
+ }
@@ -0,0 +1,24 @@
1
+ import { readdirSync } from "fs";
2
+ import { join } from "path";
3
+ import { spawn } from "child_process";
4
+ import { fileURLToPath } from "url";
5
+ import { dirname } from "path";
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const testDir = join(__dirname, "../src/ts/__tests__");
9
+
10
+ // Get all test files
11
+ const testFiles = readdirSync(testDir)
12
+ .filter((file) => file.endsWith(".test.ts"))
13
+ .map((file) => join(testDir, file));
14
+
15
+ // Run node test runner with all test files
16
+ const args = ["--import", "tsx", "--test", ...testFiles];
17
+ const child = spawn("node", args, {
18
+ stdio: "inherit",
19
+ shell: true,
20
+ });
21
+
22
+ child.on("exit", (code) => {
23
+ process.exit(code);
24
+ });
Binary file