@geekmidas/telescope 9.0.2 → 10.0.0-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 (128) hide show
  1. package/README.md +14 -4
  2. package/dist/{http-D5kn3_Mt.d.mts → http-DULM1u2L.d.cts} +3 -3
  3. package/dist/{http-Dvca6fC3.d.cts.map → http-DULM1u2L.d.cts.map} +1 -1
  4. package/dist/{http-Dvca6fC3.d.cts → http-GB-Nlvwc.d.mts} +3 -3
  5. package/dist/{http-D5kn3_Mt.d.mts.map → http-GB-Nlvwc.d.mts.map} +1 -1
  6. package/dist/instrumentation/http.d.cts +1 -1
  7. package/dist/instrumentation/http.d.mts +1 -1
  8. package/dist/instrumentation/index.cjs +2 -2
  9. package/dist/instrumentation/index.d.cts +3 -3
  10. package/dist/instrumentation/index.d.mts +3 -3
  11. package/dist/instrumentation/index.mjs +2 -2
  12. package/dist/instrumentation/middleware.cjs +1 -1
  13. package/dist/instrumentation/middleware.d.cts +1 -1
  14. package/dist/instrumentation/middleware.d.mts +1 -1
  15. package/dist/instrumentation/middleware.mjs +1 -1
  16. package/dist/instrumentation/otel.cjs +1 -1
  17. package/dist/instrumentation/otel.d.cts +1 -1
  18. package/dist/instrumentation/otel.d.mts +1 -1
  19. package/dist/instrumentation/otel.mjs +1 -1
  20. package/dist/logger/console.d.cts.map +1 -1
  21. package/dist/logger/console.d.mts.map +1 -1
  22. package/dist/logger/pino.d.cts +2 -2
  23. package/dist/{middleware-DqPQpcup.cjs → middleware-Bcq6XXGG.cjs} +2 -2
  24. package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
  25. package/dist/{middleware-4-GrQlOT.mjs → middleware-D1XEHvyy.mjs} +2 -2
  26. package/dist/middleware-D1XEHvyy.mjs.map +1 -0
  27. package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
  28. package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
  29. package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
  30. package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
  31. package/dist/{otel-40udNP5g.mjs → otel-B9bNoeZ2.mjs} +3 -3
  32. package/dist/otel-B9bNoeZ2.mjs.map +1 -0
  33. package/dist/{otel-1bJPb2Z7.d.mts → otel-Bk89b1lX.d.cts} +3 -3
  34. package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
  35. package/dist/{otel-COrpz_GZ.cjs → otel-BzjOtVxZ.cjs} +3 -3
  36. package/dist/otel-BzjOtVxZ.cjs.map +1 -0
  37. package/dist/{otel-SBVoVEHr.d.cts → otel-lPMsM26e.d.mts} +3 -3
  38. package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
  39. package/dist/storage/kysely.cjs +48 -38
  40. package/dist/storage/kysely.cjs.map +1 -1
  41. package/dist/storage/kysely.d.cts +29 -9
  42. package/dist/storage/kysely.d.cts.map +1 -1
  43. package/dist/storage/kysely.d.mts +29 -9
  44. package/dist/storage/kysely.d.mts.map +1 -1
  45. package/dist/storage/kysely.mjs +48 -38
  46. package/dist/storage/kysely.mjs.map +1 -1
  47. package/dist/tracing-BX8uY2nR.d.cts.map +1 -1
  48. package/dist/types-B1EIa_cQ.d.mts.map +1 -1
  49. package/dist/types-l7Rlb5Mg.d.cts.map +1 -1
  50. package/package.json +6 -3
  51. package/CHANGELOG.md +0 -72
  52. package/dist/middleware-4-GrQlOT.mjs.map +0 -1
  53. package/dist/middleware-DqPQpcup.cjs.map +0 -1
  54. package/dist/otel-40udNP5g.mjs.map +0 -1
  55. package/dist/otel-COrpz_GZ.cjs.map +0 -1
  56. package/src/Telescope.ts +0 -561
  57. package/src/__tests__/Telescope.spec.ts +0 -438
  58. package/src/__tests__/pino-transport.spec.ts +0 -115
  59. package/src/__tests__/redact.spec.ts +0 -336
  60. package/src/adapters/__tests__/lambda.spec.ts +0 -318
  61. package/src/adapters/__tests__/middy.spec.ts +0 -741
  62. package/src/adapters/index.ts +0 -22
  63. package/src/adapters/lambda.ts +0 -432
  64. package/src/adapters/middy.ts +0 -402
  65. package/src/adapters/types.ts +0 -181
  66. package/src/core.ts +0 -51
  67. package/src/index.ts +0 -34
  68. package/src/instrumentation/__tests__/core.spec.ts +0 -248
  69. package/src/instrumentation/__tests__/hono.spec.ts +0 -348
  70. package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
  71. package/src/instrumentation/__tests__/otel.spec.ts +0 -291
  72. package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
  73. package/src/instrumentation/core.ts +0 -228
  74. package/src/instrumentation/hono.ts +0 -270
  75. package/src/instrumentation/http.ts +0 -306
  76. package/src/instrumentation/index.ts +0 -90
  77. package/src/instrumentation/middleware.ts +0 -297
  78. package/src/instrumentation/otel.ts +0 -271
  79. package/src/instrumentation/setup.ts +0 -246
  80. package/src/instrumentation/tracing.ts +0 -145
  81. package/src/logger/__tests__/console.spec.ts +0 -366
  82. package/src/logger/__tests__/pino.spec.ts +0 -217
  83. package/src/logger/console.ts +0 -230
  84. package/src/logger/pino.ts +0 -201
  85. package/src/metrics/MetricsAggregator.ts +0 -555
  86. package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
  87. package/src/metrics/index.ts +0 -2
  88. package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
  89. package/src/metrics/storage/MetricsStorage.ts +0 -74
  90. package/src/metrics/storage/index.ts +0 -3
  91. package/src/metrics/storage/types.ts +0 -243
  92. package/src/otlp/__tests__/receiver.spec.ts +0 -367
  93. package/src/otlp/__tests__/transformer.spec.ts +0 -455
  94. package/src/otlp/hono.ts +0 -120
  95. package/src/otlp/index.ts +0 -22
  96. package/src/otlp/receiver.ts +0 -162
  97. package/src/otlp/transformer.ts +0 -367
  98. package/src/otlp/types.ts +0 -364
  99. package/src/redact.ts +0 -116
  100. package/src/server/__tests__/hono.spec.ts +0 -814
  101. package/src/server/hono.ts +0 -442
  102. package/src/storage/__tests__/kysely.spec.ts +0 -715
  103. package/src/storage/__tests__/memory.spec.ts +0 -694
  104. package/src/storage/kysely.ts +0 -599
  105. package/src/storage/memory.ts +0 -204
  106. package/src/types.ts +0 -447
  107. package/src/ui-assets.ts +0 -40
  108. package/tsconfig.json +0 -9
  109. package/ui/CHANGELOG.md +0 -7
  110. package/ui/index.html +0 -12
  111. package/ui/node_modules/.bin/tsc +0 -21
  112. package/ui/node_modules/.bin/tsserver +0 -21
  113. package/ui/node_modules/.bin/vite +0 -21
  114. package/ui/package.json +0 -24
  115. package/ui/src/App.tsx +0 -595
  116. package/ui/src/api.ts +0 -88
  117. package/ui/src/components/ExceptionDetail.tsx +0 -100
  118. package/ui/src/components/FilterBar.tsx +0 -162
  119. package/ui/src/components/LogDetail.tsx +0 -91
  120. package/ui/src/components/RequestDetail.tsx +0 -143
  121. package/ui/src/main.tsx +0 -10
  122. package/ui/src/styles.css +0 -11
  123. package/ui/src/types.ts +0 -63
  124. package/ui/src/vite-env.d.ts +0 -1
  125. package/ui/src/vite-plugin-gkm-config.ts +0 -54
  126. package/ui/tsconfig.json +0 -20
  127. package/ui/tsconfig.tsbuildinfo +0 -1
  128. package/ui/vite.config.ts +0 -13
@@ -1,694 +0,0 @@
1
- import { beforeEach, describe, expect, it } from 'vitest';
2
- import type { ExceptionEntry, LogEntry, RequestEntry } from '../../types';
3
- import { InMemoryStorage } from '../memory';
4
-
5
- describe('InMemoryStorage', () => {
6
- let storage: InMemoryStorage;
7
-
8
- beforeEach(() => {
9
- storage = new InMemoryStorage();
10
- });
11
-
12
- describe('requests', () => {
13
- const createRequest = (
14
- overrides: Partial<RequestEntry> = {},
15
- ): RequestEntry => ({
16
- id: `req-${Math.random().toString(36).slice(2)}`,
17
- method: 'GET',
18
- path: '/api/users',
19
- url: 'http://localhost:3000/api/users',
20
- headers: { 'content-type': 'application/json' },
21
- query: {},
22
- status: 200,
23
- responseHeaders: {},
24
- duration: 50,
25
- timestamp: new Date(),
26
- ...overrides,
27
- });
28
-
29
- it('should save and retrieve a request', async () => {
30
- const request = createRequest({ id: 'req-123' });
31
- await storage.saveRequest(request);
32
-
33
- const retrieved = await storage.getRequest('req-123');
34
- expect(retrieved).toEqual(request);
35
- });
36
-
37
- it('should return null for non-existent request', async () => {
38
- const result = await storage.getRequest('non-existent');
39
- expect(result).toBeNull();
40
- });
41
-
42
- it('should list requests in reverse chronological order', async () => {
43
- const req1 = createRequest({
44
- id: 'req-1',
45
- timestamp: new Date('2024-01-01T10:00:00Z'),
46
- });
47
- const req2 = createRequest({
48
- id: 'req-2',
49
- timestamp: new Date('2024-01-01T11:00:00Z'),
50
- });
51
- const req3 = createRequest({
52
- id: 'req-3',
53
- timestamp: new Date('2024-01-01T12:00:00Z'),
54
- });
55
-
56
- await storage.saveRequest(req1);
57
- await storage.saveRequest(req2);
58
- await storage.saveRequest(req3);
59
-
60
- const requests = await storage.getRequests();
61
- expect(requests.map((r) => r.id)).toEqual(['req-3', 'req-2', 'req-1']);
62
- });
63
-
64
- it('should respect limit and offset options', async () => {
65
- for (let i = 0; i < 10; i++) {
66
- await storage.saveRequest(
67
- createRequest({
68
- id: `req-${i}`,
69
- timestamp: new Date(Date.now() + i * 1000),
70
- }),
71
- );
72
- }
73
-
74
- const page1 = await storage.getRequests({ limit: 3, offset: 0 });
75
- expect(page1).toHaveLength(3);
76
- expect(page1[0].id).toBe('req-9');
77
-
78
- const page2 = await storage.getRequests({ limit: 3, offset: 3 });
79
- expect(page2).toHaveLength(3);
80
- expect(page2[0].id).toBe('req-6');
81
- });
82
-
83
- it('should filter by search term in path', async () => {
84
- await storage.saveRequest(
85
- createRequest({
86
- id: 'req-1',
87
- path: '/api/users',
88
- url: 'http://localhost/api/users',
89
- }),
90
- );
91
- await storage.saveRequest(
92
- createRequest({
93
- id: 'req-2',
94
- path: '/api/posts',
95
- url: 'http://localhost/api/posts',
96
- }),
97
- );
98
- await storage.saveRequest(
99
- createRequest({
100
- id: 'req-3',
101
- path: '/api/orders',
102
- url: 'http://localhost/api/orders',
103
- }),
104
- );
105
-
106
- const results = await storage.getRequests({ search: 'posts' });
107
- expect(results).toHaveLength(1);
108
- expect(results[0].id).toBe('req-2');
109
- });
110
-
111
- it('should filter by date range', async () => {
112
- await storage.saveRequest(
113
- createRequest({ id: 'req-1', timestamp: new Date('2024-01-01') }),
114
- );
115
- await storage.saveRequest(
116
- createRequest({ id: 'req-2', timestamp: new Date('2024-01-15') }),
117
- );
118
- await storage.saveRequest(
119
- createRequest({ id: 'req-3', timestamp: new Date('2024-02-01') }),
120
- );
121
-
122
- const results = await storage.getRequests({
123
- after: new Date('2024-01-10'),
124
- before: new Date('2024-01-20'),
125
- });
126
-
127
- expect(results).toHaveLength(1);
128
- expect(results[0].id).toBe('req-2');
129
- });
130
-
131
- it('should filter by tags', async () => {
132
- await storage.saveRequest(
133
- createRequest({ id: 'req-1', tags: ['auth', 'api'] }),
134
- );
135
- await storage.saveRequest(createRequest({ id: 'req-2', tags: ['api'] }));
136
- await storage.saveRequest(
137
- createRequest({ id: 'req-3', tags: ['admin'] }),
138
- );
139
-
140
- const results = await storage.getRequests({ tags: ['auth'] });
141
- expect(results).toHaveLength(1);
142
- expect(results[0].id).toBe('req-1');
143
- });
144
-
145
- it('should enforce maxEntries limit', async () => {
146
- const smallStorage = new InMemoryStorage({ maxEntries: 5 });
147
-
148
- for (let i = 0; i < 10; i++) {
149
- await smallStorage.saveRequest(
150
- createRequest({
151
- id: `req-${i}`,
152
- timestamp: new Date(Date.now() + i * 1000),
153
- }),
154
- );
155
- }
156
-
157
- const requests = await smallStorage.getRequests();
158
- expect(requests).toHaveLength(5);
159
- // Should keep the newest entries
160
- expect(requests[0].id).toBe('req-9');
161
- expect(requests[4].id).toBe('req-5');
162
- });
163
- });
164
-
165
- describe('exceptions', () => {
166
- const createException = (
167
- overrides: Partial<ExceptionEntry> = {},
168
- ): ExceptionEntry => ({
169
- id: `exc-${Math.random().toString(36).slice(2)}`,
170
- name: 'Error',
171
- message: 'Something went wrong',
172
- stack: [
173
- {
174
- file: '/app/src/index.ts',
175
- line: 10,
176
- column: 5,
177
- function: 'main',
178
- isApp: true,
179
- },
180
- ],
181
- timestamp: new Date(),
182
- handled: false,
183
- ...overrides,
184
- });
185
-
186
- it('should save and retrieve an exception', async () => {
187
- const exception = createException({ id: 'exc-123' });
188
- await storage.saveException(exception);
189
-
190
- const retrieved = await storage.getException('exc-123');
191
- expect(retrieved).toEqual(exception);
192
- });
193
-
194
- it('should return null for non-existent exception', async () => {
195
- const result = await storage.getException('non-existent');
196
- expect(result).toBeNull();
197
- });
198
-
199
- it('should list exceptions in reverse chronological order', async () => {
200
- await storage.saveException(
201
- createException({
202
- id: 'exc-1',
203
- timestamp: new Date('2024-01-01T10:00:00Z'),
204
- }),
205
- );
206
- await storage.saveException(
207
- createException({
208
- id: 'exc-2',
209
- timestamp: new Date('2024-01-01T11:00:00Z'),
210
- }),
211
- );
212
-
213
- const exceptions = await storage.getExceptions();
214
- expect(exceptions.map((e) => e.id)).toEqual(['exc-2', 'exc-1']);
215
- });
216
-
217
- it('should filter exceptions by search term in message', async () => {
218
- await storage.saveException(
219
- createException({ id: 'exc-1', message: 'Database connection failed' }),
220
- );
221
- await storage.saveException(
222
- createException({ id: 'exc-2', message: 'Invalid user input' }),
223
- );
224
-
225
- const results = await storage.getExceptions({ search: 'database' });
226
- expect(results).toHaveLength(1);
227
- expect(results[0].id).toBe('exc-1');
228
- });
229
- });
230
-
231
- describe('logs', () => {
232
- const createLog = (overrides: Partial<LogEntry> = {}): LogEntry => ({
233
- id: `log-${Math.random().toString(36).slice(2)}`,
234
- level: 'info',
235
- message: 'Test log message',
236
- timestamp: new Date(),
237
- ...overrides,
238
- });
239
-
240
- it('should save and retrieve logs', async () => {
241
- await storage.saveLog(createLog({ id: 'log-1', message: 'First log' }));
242
- await storage.saveLog(createLog({ id: 'log-2', message: 'Second log' }));
243
-
244
- const logs = await storage.getLogs();
245
- expect(logs).toHaveLength(2);
246
- });
247
-
248
- it('should filter logs by level via search', async () => {
249
- await storage.saveLog(createLog({ id: 'log-1', level: 'debug' }));
250
- await storage.saveLog(createLog({ id: 'log-2', level: 'error' }));
251
- await storage.saveLog(createLog({ id: 'log-3', level: 'error' }));
252
-
253
- const results = await storage.getLogs({ search: 'error' });
254
- expect(results).toHaveLength(2);
255
- });
256
-
257
- it('should include context in logs', async () => {
258
- await storage.saveLog(
259
- createLog({
260
- id: 'log-1',
261
- context: { userId: '123', action: 'login' },
262
- }),
263
- );
264
-
265
- const logs = await storage.getLogs();
266
- expect(logs[0].context).toEqual({ userId: '123', action: 'login' });
267
- });
268
- });
269
-
270
- describe('prune', () => {
271
- it('should remove entries older than specified date', async () => {
272
- const oldDate = new Date('2024-01-01');
273
- const newDate = new Date('2024-06-01');
274
-
275
- await storage.saveRequest({
276
- id: 'req-old',
277
- method: 'GET',
278
- path: '/old',
279
- url: 'http://localhost/old',
280
- headers: {},
281
- query: {},
282
- status: 200,
283
- responseHeaders: {},
284
- duration: 10,
285
- timestamp: oldDate,
286
- });
287
-
288
- await storage.saveRequest({
289
- id: 'req-new',
290
- method: 'GET',
291
- path: '/new',
292
- url: 'http://localhost/new',
293
- headers: {},
294
- query: {},
295
- status: 200,
296
- responseHeaders: {},
297
- duration: 10,
298
- timestamp: newDate,
299
- });
300
-
301
- await storage.saveException({
302
- id: 'exc-old',
303
- name: 'Error',
304
- message: 'Old error',
305
- stack: [],
306
- timestamp: oldDate,
307
- handled: false,
308
- });
309
-
310
- await storage.saveLog({
311
- id: 'log-old',
312
- level: 'info',
313
- message: 'Old log',
314
- timestamp: oldDate,
315
- });
316
-
317
- const pruneDate = new Date('2024-03-01');
318
- const deleted = await storage.prune(pruneDate);
319
-
320
- expect(deleted).toBe(3);
321
-
322
- const requests = await storage.getRequests();
323
- expect(requests).toHaveLength(1);
324
- expect(requests[0].id).toBe('req-new');
325
-
326
- const exceptions = await storage.getExceptions();
327
- expect(exceptions).toHaveLength(0);
328
-
329
- const logs = await storage.getLogs();
330
- expect(logs).toHaveLength(0);
331
- });
332
- });
333
-
334
- describe('getStats', () => {
335
- it('should return correct statistics', async () => {
336
- await storage.saveRequest({
337
- id: 'req-1',
338
- method: 'GET',
339
- path: '/api',
340
- url: 'http://localhost/api',
341
- headers: {},
342
- query: {},
343
- status: 200,
344
- responseHeaders: {},
345
- duration: 10,
346
- timestamp: new Date(),
347
- });
348
-
349
- await storage.saveException({
350
- id: 'exc-1',
351
- name: 'Error',
352
- message: 'Test',
353
- stack: [],
354
- timestamp: new Date(),
355
- handled: false,
356
- });
357
-
358
- await storage.saveLog({
359
- id: 'log-1',
360
- level: 'info',
361
- message: 'Test',
362
- timestamp: new Date(),
363
- });
364
- await storage.saveLog({
365
- id: 'log-2',
366
- level: 'error',
367
- message: 'Test',
368
- timestamp: new Date(),
369
- });
370
-
371
- const stats = await storage.getStats();
372
-
373
- expect(stats.requests).toBe(1);
374
- expect(stats.exceptions).toBe(1);
375
- expect(stats.logs).toBe(2);
376
- });
377
- });
378
-
379
- describe('clear', () => {
380
- it('should remove all entries', async () => {
381
- await storage.saveRequest({
382
- id: 'req-1',
383
- method: 'GET',
384
- path: '/api',
385
- url: 'http://localhost/api',
386
- headers: {},
387
- query: {},
388
- status: 200,
389
- responseHeaders: {},
390
- duration: 10,
391
- timestamp: new Date(),
392
- });
393
-
394
- await storage.saveException({
395
- id: 'exc-1',
396
- name: 'Error',
397
- message: 'Test',
398
- stack: [],
399
- timestamp: new Date(),
400
- handled: false,
401
- });
402
-
403
- storage.clear();
404
-
405
- const stats = await storage.getStats();
406
- expect(stats.requests).toBe(0);
407
- expect(stats.exceptions).toBe(0);
408
- expect(stats.logs).toBe(0);
409
- });
410
- });
411
-
412
- describe('bulk operations', () => {
413
- it('should save multiple requests at once', async () => {
414
- await storage.saveRequests([
415
- {
416
- id: 'req-1',
417
- method: 'GET',
418
- path: '/api/a',
419
- url: 'http://localhost/api/a',
420
- headers: {},
421
- query: {},
422
- status: 200,
423
- responseHeaders: {},
424
- duration: 10,
425
- timestamp: new Date(),
426
- },
427
- {
428
- id: 'req-2',
429
- method: 'POST',
430
- path: '/api/b',
431
- url: 'http://localhost/api/b',
432
- headers: {},
433
- query: {},
434
- status: 201,
435
- responseHeaders: {},
436
- duration: 20,
437
- timestamp: new Date(),
438
- },
439
- ]);
440
-
441
- const requests = await storage.getRequests();
442
- expect(requests).toHaveLength(2);
443
- });
444
-
445
- it('should save multiple exceptions at once', async () => {
446
- await storage.saveExceptions([
447
- {
448
- id: 'exc-1',
449
- name: 'Error',
450
- message: 'First',
451
- stack: [],
452
- timestamp: new Date(),
453
- handled: false,
454
- },
455
- {
456
- id: 'exc-2',
457
- name: 'Error',
458
- message: 'Second',
459
- stack: [],
460
- timestamp: new Date(),
461
- handled: true,
462
- },
463
- ]);
464
-
465
- const exceptions = await storage.getExceptions();
466
- expect(exceptions).toHaveLength(2);
467
- });
468
-
469
- it('should save multiple logs at once', async () => {
470
- await storage.saveLogs([
471
- { id: 'log-1', level: 'info', message: 'First', timestamp: new Date() },
472
- {
473
- id: 'log-2',
474
- level: 'error',
475
- message: 'Second',
476
- timestamp: new Date(),
477
- },
478
- ]);
479
-
480
- const logs = await storage.getLogs();
481
- expect(logs).toHaveLength(2);
482
- });
483
- });
484
-
485
- describe('request filters', () => {
486
- it('should filter by HTTP method', async () => {
487
- await storage.saveRequest({
488
- id: 'req-1',
489
- method: 'GET',
490
- path: '/api',
491
- url: 'http://localhost/api',
492
- headers: {},
493
- query: {},
494
- status: 200,
495
- responseHeaders: {},
496
- duration: 10,
497
- timestamp: new Date(),
498
- });
499
- await storage.saveRequest({
500
- id: 'req-2',
501
- method: 'POST',
502
- path: '/api',
503
- url: 'http://localhost/api',
504
- headers: {},
505
- query: {},
506
- status: 201,
507
- responseHeaders: {},
508
- duration: 10,
509
- timestamp: new Date(),
510
- });
511
-
512
- const getRequests = await storage.getRequests({ method: 'GET' });
513
- expect(getRequests).toHaveLength(1);
514
- expect(getRequests[0].id).toBe('req-1');
515
- });
516
-
517
- it('should filter by exact status code', async () => {
518
- await storage.saveRequest({
519
- id: 'req-1',
520
- method: 'GET',
521
- path: '/api',
522
- url: 'http://localhost/api',
523
- headers: {},
524
- query: {},
525
- status: 200,
526
- responseHeaders: {},
527
- duration: 10,
528
- timestamp: new Date(),
529
- });
530
- await storage.saveRequest({
531
- id: 'req-2',
532
- method: 'GET',
533
- path: '/api',
534
- url: 'http://localhost/api',
535
- headers: {},
536
- query: {},
537
- status: 404,
538
- responseHeaders: {},
539
- duration: 10,
540
- timestamp: new Date(),
541
- });
542
-
543
- const notFoundRequests = await storage.getRequests({ status: '404' });
544
- expect(notFoundRequests).toHaveLength(1);
545
- expect(notFoundRequests[0].id).toBe('req-2');
546
- });
547
-
548
- it('should filter by status category (2xx)', async () => {
549
- await storage.saveRequest({
550
- id: 'req-1',
551
- method: 'GET',
552
- path: '/api',
553
- url: 'http://localhost/api',
554
- headers: {},
555
- query: {},
556
- status: 200,
557
- responseHeaders: {},
558
- duration: 10,
559
- timestamp: new Date(),
560
- });
561
- await storage.saveRequest({
562
- id: 'req-2',
563
- method: 'GET',
564
- path: '/api',
565
- url: 'http://localhost/api',
566
- headers: {},
567
- query: {},
568
- status: 201,
569
- responseHeaders: {},
570
- duration: 10,
571
- timestamp: new Date(),
572
- });
573
- await storage.saveRequest({
574
- id: 'req-3',
575
- method: 'GET',
576
- path: '/api',
577
- url: 'http://localhost/api',
578
- headers: {},
579
- query: {},
580
- status: 500,
581
- responseHeaders: {},
582
- duration: 10,
583
- timestamp: new Date(),
584
- });
585
-
586
- const successRequests = await storage.getRequests({ status: '2xx' });
587
- expect(successRequests).toHaveLength(2);
588
- });
589
-
590
- it('should filter by status category (5xx)', async () => {
591
- await storage.saveRequest({
592
- id: 'req-1',
593
- method: 'GET',
594
- path: '/api',
595
- url: 'http://localhost/api',
596
- headers: {},
597
- query: {},
598
- status: 200,
599
- responseHeaders: {},
600
- duration: 10,
601
- timestamp: new Date(),
602
- });
603
- await storage.saveRequest({
604
- id: 'req-2',
605
- method: 'GET',
606
- path: '/api',
607
- url: 'http://localhost/api',
608
- headers: {},
609
- query: {},
610
- status: 500,
611
- responseHeaders: {},
612
- duration: 10,
613
- timestamp: new Date(),
614
- });
615
- await storage.saveRequest({
616
- id: 'req-3',
617
- method: 'GET',
618
- path: '/api',
619
- url: 'http://localhost/api',
620
- headers: {},
621
- query: {},
622
- status: 503,
623
- responseHeaders: {},
624
- duration: 10,
625
- timestamp: new Date(),
626
- });
627
-
628
- const errorRequests = await storage.getRequests({ status: '5xx' });
629
- expect(errorRequests).toHaveLength(2);
630
- });
631
- });
632
-
633
- describe('log filters', () => {
634
- it('should filter logs by level', async () => {
635
- await storage.saveLog({
636
- id: 'log-1',
637
- level: 'info',
638
- message: 'Info message',
639
- timestamp: new Date(),
640
- });
641
- await storage.saveLog({
642
- id: 'log-2',
643
- level: 'error',
644
- message: 'Error message',
645
- timestamp: new Date(),
646
- });
647
- await storage.saveLog({
648
- id: 'log-3',
649
- level: 'error',
650
- message: 'Another error',
651
- timestamp: new Date(),
652
- });
653
-
654
- const errorLogs = await storage.getLogs({ level: 'error' });
655
- expect(errorLogs).toHaveLength(2);
656
- });
657
- });
658
-
659
- describe('enforceLimit', () => {
660
- it('should enforce limit on exceptions', async () => {
661
- const smallStorage = new InMemoryStorage({ maxEntries: 3 });
662
-
663
- for (let i = 0; i < 5; i++) {
664
- await smallStorage.saveException({
665
- id: `exc-${i}`,
666
- name: 'Error',
667
- message: `Error ${i}`,
668
- stack: [],
669
- timestamp: new Date(Date.now() + i * 1000),
670
- handled: false,
671
- });
672
- }
673
-
674
- const exceptions = await smallStorage.getExceptions();
675
- expect(exceptions).toHaveLength(3);
676
- });
677
-
678
- it('should enforce limit on logs', async () => {
679
- const smallStorage = new InMemoryStorage({ maxEntries: 3 });
680
-
681
- for (let i = 0; i < 5; i++) {
682
- await smallStorage.saveLog({
683
- id: `log-${i}`,
684
- level: 'info',
685
- message: `Log ${i}`,
686
- timestamp: new Date(Date.now() + i * 1000),
687
- });
688
- }
689
-
690
- const logs = await smallStorage.getLogs();
691
- expect(logs).toHaveLength(3);
692
- });
693
- });
694
- });