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,487 @@
1
+ /**
2
+ * TopicRouter Priority Tests
3
+ *
4
+ * Tests for 10-level priority system with routing filters
5
+ */
6
+
7
+ import { describe, it } from "node:test";
8
+ import assert from "node:assert/strict";
9
+ import { createTopicRouter, createMockHandler } from "../index.js";
10
+ import type { LogEntry } from "../types.js";
11
+
12
+ describe("TopicRouter Priority Filtering", () => {
13
+ it("should default log priority to 1 when not specified", async () => {
14
+ const mock = createMockHandler();
15
+
16
+ const router = createTopicRouter()
17
+ .errors(mock.handler, { minPriority: 1 })
18
+ .build();
19
+
20
+ await router.route({
21
+ level: "error",
22
+ message: "No priority specified",
23
+ topic: "pipeline.error",
24
+ timestamp: Date.now(),
25
+ // priority not specified
26
+ });
27
+
28
+ assert.equal(mock.getLogs().length, 1);
29
+ });
30
+
31
+ it("should route logs with priority >= minPriority", async () => {
32
+ const mock = createMockHandler();
33
+
34
+ const router = createTopicRouter()
35
+ .errors(mock.handler, { minPriority: 5 })
36
+ .build();
37
+
38
+ await router.routeBatch([
39
+ {
40
+ level: "error",
41
+ message: "Priority 3",
42
+ topic: "pipeline.error",
43
+ timestamp: Date.now(),
44
+ priority: 3,
45
+ },
46
+ {
47
+ level: "error",
48
+ message: "Priority 5",
49
+ topic: "pipeline.error",
50
+ timestamp: Date.now(),
51
+ priority: 5,
52
+ },
53
+ {
54
+ level: "error",
55
+ message: "Priority 7",
56
+ topic: "pipeline.error",
57
+ timestamp: Date.now(),
58
+ priority: 7,
59
+ },
60
+ ]);
61
+
62
+ // Should only route priority 5 and 7
63
+ const logs = mock.getLogs();
64
+ assert.equal(logs.length, 2);
65
+ assert.equal(logs[0].priority, 5);
66
+ assert.equal(logs[1].priority, 7);
67
+ });
68
+
69
+ it("should route logs with priority <= maxPriority", async () => {
70
+ const mock = createMockHandler();
71
+
72
+ const router = createTopicRouter()
73
+ .errors(mock.handler, { maxPriority: 5 })
74
+ .build();
75
+
76
+ await router.routeBatch([
77
+ {
78
+ level: "error",
79
+ message: "Priority 3",
80
+ topic: "pipeline.error",
81
+ timestamp: Date.now(),
82
+ priority: 3,
83
+ },
84
+ {
85
+ level: "error",
86
+ message: "Priority 5",
87
+ topic: "pipeline.error",
88
+ timestamp: Date.now(),
89
+ priority: 5,
90
+ },
91
+ {
92
+ level: "error",
93
+ message: "Priority 8",
94
+ topic: "pipeline.error",
95
+ timestamp: Date.now(),
96
+ priority: 8,
97
+ },
98
+ ]);
99
+
100
+ // Should only route priority 3 and 5
101
+ const logs = mock.getLogs();
102
+ assert.equal(logs.length, 2);
103
+ assert.equal(logs[0].priority, 3);
104
+ assert.equal(logs[1].priority, 5);
105
+ });
106
+
107
+ it("should route logs within priority range (minPriority and maxPriority)", async () => {
108
+ const mock = createMockHandler();
109
+
110
+ const router = createTopicRouter()
111
+ .errors(mock.handler, { minPriority: 4, maxPriority: 7 })
112
+ .build();
113
+
114
+ await router.routeBatch([
115
+ {
116
+ level: "error",
117
+ message: "Priority 2",
118
+ topic: "pipeline.error",
119
+ timestamp: Date.now(),
120
+ priority: 2,
121
+ },
122
+ {
123
+ level: "error",
124
+ message: "Priority 4",
125
+ topic: "pipeline.error",
126
+ timestamp: Date.now(),
127
+ priority: 4,
128
+ },
129
+ {
130
+ level: "error",
131
+ message: "Priority 6",
132
+ topic: "pipeline.error",
133
+ timestamp: Date.now(),
134
+ priority: 6,
135
+ },
136
+ {
137
+ level: "error",
138
+ message: "Priority 7",
139
+ topic: "pipeline.error",
140
+ timestamp: Date.now(),
141
+ priority: 7,
142
+ },
143
+ {
144
+ level: "error",
145
+ message: "Priority 9",
146
+ topic: "pipeline.error",
147
+ timestamp: Date.now(),
148
+ priority: 9,
149
+ },
150
+ ]);
151
+
152
+ // Should only route priority 4, 6, 7
153
+ const logs = mock.getLogs();
154
+ assert.equal(logs.length, 3);
155
+ assert.equal(logs[0].priority, 4);
156
+ assert.equal(logs[1].priority, 6);
157
+ assert.equal(logs[2].priority, 7);
158
+ });
159
+
160
+ it("should route all priorities when no filter is specified", async () => {
161
+ const mock = createMockHandler();
162
+
163
+ const router = createTopicRouter()
164
+ .errors(mock.handler) // No priority filter
165
+ .build();
166
+
167
+ await router.routeBatch([
168
+ {
169
+ level: "error",
170
+ message: "Priority 1",
171
+ topic: "pipeline.error",
172
+ timestamp: Date.now(),
173
+ priority: 1,
174
+ },
175
+ {
176
+ level: "error",
177
+ message: "Priority 5",
178
+ topic: "pipeline.error",
179
+ timestamp: Date.now(),
180
+ priority: 5,
181
+ },
182
+ {
183
+ level: "error",
184
+ message: "Priority 10",
185
+ topic: "pipeline.error",
186
+ timestamp: Date.now(),
187
+ priority: 10,
188
+ },
189
+ ]);
190
+
191
+ // Should route all logs
192
+ assert.equal(mock.getLogs().length, 3);
193
+ });
194
+ });
195
+
196
+ describe("TopicRouter Multi-Route Priority", () => {
197
+ it("should route to different handlers based on priority", async () => {
198
+ const lowPriority = createMockHandler();
199
+ const highPriority = createMockHandler();
200
+ const critical = createMockHandler();
201
+
202
+ const router = createTopicRouter()
203
+ .custom(/^pipeline\./, lowPriority.handler, {
204
+ minPriority: 1,
205
+ maxPriority: 3,
206
+ })
207
+ .custom(/^pipeline\./, highPriority.handler, {
208
+ minPriority: 4,
209
+ maxPriority: 8,
210
+ })
211
+ .custom(/^pipeline\./, critical.handler, {
212
+ minPriority: 9,
213
+ maxPriority: 10,
214
+ })
215
+ .build();
216
+
217
+ await router.routeBatch([
218
+ {
219
+ level: "debug",
220
+ message: "Low 1",
221
+ topic: "pipeline.debug",
222
+ timestamp: Date.now(),
223
+ priority: 1,
224
+ },
225
+ {
226
+ level: "info",
227
+ message: "Normal 5",
228
+ topic: "pipeline.info",
229
+ timestamp: Date.now(),
230
+ priority: 5,
231
+ },
232
+ {
233
+ level: "error",
234
+ message: "Critical 10",
235
+ topic: "pipeline.error",
236
+ timestamp: Date.now(),
237
+ priority: 10,
238
+ },
239
+ ]);
240
+
241
+ assert.equal(lowPriority.getLogs().length, 1);
242
+ assert.equal(highPriority.getLogs().length, 1);
243
+ assert.equal(critical.getLogs().length, 1);
244
+
245
+ assert.equal(lowPriority.getLogs()[0].priority, 1);
246
+ assert.equal(highPriority.getLogs()[0].priority, 5);
247
+ assert.equal(critical.getLogs()[0].priority, 10);
248
+ });
249
+
250
+ it("should route to multiple handlers when priorities overlap", async () => {
251
+ const handler1 = createMockHandler();
252
+ const handler2 = createMockHandler();
253
+
254
+ const router = createTopicRouter()
255
+ .custom(/^pipeline\./, handler1.handler, {
256
+ minPriority: 3,
257
+ maxPriority: 7,
258
+ })
259
+ .custom(/^pipeline\./, handler2.handler, {
260
+ minPriority: 5,
261
+ maxPriority: 10,
262
+ })
263
+ .build();
264
+
265
+ await router.routeBatch([
266
+ {
267
+ level: "info",
268
+ message: "Priority 4",
269
+ topic: "pipeline.info",
270
+ timestamp: Date.now(),
271
+ priority: 4,
272
+ },
273
+ {
274
+ level: "info",
275
+ message: "Priority 6",
276
+ topic: "pipeline.info",
277
+ timestamp: Date.now(),
278
+ priority: 6,
279
+ },
280
+ {
281
+ level: "info",
282
+ message: "Priority 8",
283
+ topic: "pipeline.info",
284
+ timestamp: Date.now(),
285
+ priority: 8,
286
+ },
287
+ ]);
288
+
289
+ // Priority 4: only handler1 (3-7 range)
290
+ // Priority 6: both handlers (overlap)
291
+ // Priority 8: only handler2 (5-10 range)
292
+ assert.equal(handler1.getLogs().length, 2); // 4, 6
293
+ assert.equal(handler2.getLogs().length, 2); // 6, 8
294
+ });
295
+ });
296
+
297
+ describe("TopicRouter Priority + Concurrency", () => {
298
+ it("should respect concurrency limits per priority tier", async () => {
299
+ let activeCount = 0;
300
+ let maxConcurrent = 0;
301
+
302
+ const handler = async () => {
303
+ activeCount++;
304
+ maxConcurrent = Math.max(maxConcurrent, activeCount);
305
+ await new Promise((resolve) => setTimeout(resolve, 10));
306
+ activeCount--;
307
+ };
308
+
309
+ const router = createTopicRouter()
310
+ .custom(/^pipeline\./, handler, {
311
+ minPriority: 7,
312
+ maxPriority: 10,
313
+ concurrency: 2,
314
+ })
315
+ .build();
316
+
317
+ // Only high-priority logs should be processed
318
+ await router.routeBatch([
319
+ {
320
+ level: "debug",
321
+ message: "Low",
322
+ topic: "pipeline.debug",
323
+ timestamp: Date.now(),
324
+ priority: 2,
325
+ },
326
+ {
327
+ level: "error",
328
+ message: "High 1",
329
+ topic: "pipeline.error",
330
+ timestamp: Date.now(),
331
+ priority: 8,
332
+ },
333
+ {
334
+ level: "error",
335
+ message: "High 2",
336
+ topic: "pipeline.error",
337
+ timestamp: Date.now(),
338
+ priority: 9,
339
+ },
340
+ {
341
+ level: "error",
342
+ message: "High 3",
343
+ topic: "pipeline.error",
344
+ timestamp: Date.now(),
345
+ priority: 10,
346
+ },
347
+ ]);
348
+
349
+ // Should process 3 high-priority logs with concurrency limit of 2
350
+ assert.ok(
351
+ maxConcurrent <= 2,
352
+ `Max concurrent was ${maxConcurrent}, expected <= 2`
353
+ );
354
+ });
355
+ });
356
+
357
+ describe("TopicRouter Priority + Metrics", () => {
358
+ it("should track metrics separately for different priority tiers", async () => {
359
+ const lowHandler = createMockHandler();
360
+ const highHandler = createMockHandler();
361
+
362
+ const router = createTopicRouter()
363
+ .custom(/^pipeline\./, lowHandler.handler, {
364
+ minPriority: 1,
365
+ maxPriority: 5,
366
+ trackMetrics: true,
367
+ })
368
+ .custom(/^pipeline\./, highHandler.handler, {
369
+ minPriority: 6,
370
+ maxPriority: 10,
371
+ trackMetrics: true,
372
+ })
373
+ .build();
374
+
375
+ await router.routeBatch([
376
+ {
377
+ level: "debug",
378
+ message: "Low 1",
379
+ topic: "pipeline.debug",
380
+ timestamp: Date.now(),
381
+ priority: 2,
382
+ },
383
+ {
384
+ level: "info",
385
+ message: "Low 2",
386
+ topic: "pipeline.info",
387
+ timestamp: Date.now(),
388
+ priority: 4,
389
+ },
390
+ {
391
+ level: "warn",
392
+ message: "High 1",
393
+ topic: "pipeline.warn",
394
+ timestamp: Date.now(),
395
+ priority: 7,
396
+ },
397
+ {
398
+ level: "error",
399
+ message: "High 2",
400
+ topic: "pipeline.error",
401
+ timestamp: Date.now(),
402
+ priority: 9,
403
+ },
404
+ {
405
+ level: "error",
406
+ message: "High 3",
407
+ topic: "pipeline.error",
408
+ timestamp: Date.now(),
409
+ priority: 10,
410
+ },
411
+ ]);
412
+
413
+ const metrics = router.getMetrics();
414
+ assert.equal(metrics.length, 2);
415
+
416
+ // Sort by execution count
417
+ const sorted = metrics.sort((a, b) => a.executionCount - b.executionCount);
418
+
419
+ assert.equal(sorted[0].executionCount, 2); // Low priority tier
420
+ assert.equal(sorted[1].executionCount, 3); // High priority tier
421
+ });
422
+ });
423
+
424
+ describe("Priority with Default Log Levels", () => {
425
+ it("should use default priorities based on log level", async () => {
426
+ const debugHandler = createMockHandler();
427
+ const infoHandler = createMockHandler();
428
+ const warnHandler = createMockHandler();
429
+ const errorHandler = createMockHandler();
430
+
431
+ const router = createTopicRouter()
432
+ .custom(/^pipeline\./, debugHandler.handler, {
433
+ minPriority: 1,
434
+ maxPriority: 3,
435
+ })
436
+ .custom(/^pipeline\./, infoHandler.handler, {
437
+ minPriority: 4,
438
+ maxPriority: 6,
439
+ })
440
+ .custom(/^pipeline\./, warnHandler.handler, {
441
+ minPriority: 7,
442
+ maxPriority: 8,
443
+ })
444
+ .custom(/^pipeline\./, errorHandler.handler, {
445
+ minPriority: 9,
446
+ maxPriority: 10,
447
+ })
448
+ .build();
449
+
450
+ // Logs with default priorities: debug=2, info=5, warn=7, error=9
451
+ await router.routeBatch([
452
+ {
453
+ level: "debug",
454
+ message: "Debug",
455
+ topic: "pipeline.debug",
456
+ timestamp: Date.now(),
457
+ priority: 2,
458
+ },
459
+ {
460
+ level: "info",
461
+ message: "Info",
462
+ topic: "pipeline.info",
463
+ timestamp: Date.now(),
464
+ priority: 5,
465
+ },
466
+ {
467
+ level: "warn",
468
+ message: "Warn",
469
+ topic: "pipeline.warn",
470
+ timestamp: Date.now(),
471
+ priority: 7,
472
+ },
473
+ {
474
+ level: "error",
475
+ message: "Error",
476
+ topic: "pipeline.error",
477
+ timestamp: Date.now(),
478
+ priority: 9,
479
+ },
480
+ ]);
481
+
482
+ assert.equal(debugHandler.getLogs().length, 1);
483
+ assert.equal(infoHandler.getLogs().length, 1);
484
+ assert.equal(warnHandler.getLogs().length, 1);
485
+ assert.equal(errorHandler.getLogs().length, 1);
486
+ });
487
+ });