@techstream/quark-core 1.1.0 → 1.2.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.
@@ -7,318 +7,318 @@ TAP version 13
7
7
  # Subtest: createAuthConfig returns valid config
8
8
  ok 1 - createAuthConfig returns valid config
9
9
  ---
10
- duration_ms: 0.59825
10
+ duration_ms: 0.58
11
11
  ...
12
12
  # Subtest: createAuthConfig throws when secret is missing
13
13
  ok 2 - createAuthConfig throws when secret is missing
14
14
  ---
15
- duration_ms: 0.971959
15
+ duration_ms: 0.200583
16
16
  ...
17
17
  # Subtest: createAuthConfig with custom options
18
18
  ok 3 - createAuthConfig with custom options
19
19
  ---
20
- duration_ms: 0.418417
20
+ duration_ms: 2.045958
21
21
  ...
22
22
  # Subtest: isAuthenticated returns true for valid session
23
23
  ok 4 - isAuthenticated returns true for valid session
24
24
  ---
25
- duration_ms: 0.14075
25
+ duration_ms: 0.199166
26
26
  ...
27
27
  # Subtest: isAuthenticated returns false for invalid session
28
28
  ok 5 - isAuthenticated returns false for invalid session
29
29
  ---
30
- duration_ms: 0.152584
30
+ duration_ms: 0.134083
31
31
  ...
32
32
  # Subtest: getUserId extracts user ID
33
33
  ok 6 - getUserId extracts user ID
34
34
  ---
35
- duration_ms: 0.248208
35
+ duration_ms: 0.248875
36
36
  ...
37
37
  # Subtest: getUserId returns null when missing
38
38
  ok 7 - getUserId returns null when missing
39
39
  ---
40
- duration_ms: 0.11875
40
+ duration_ms: 0.105833
41
41
  ...
42
42
  # Subtest: getUserEmail extracts user email
43
43
  ok 8 - getUserEmail extracts user email
44
44
  ---
45
- duration_ms: 0.397875
45
+ duration_ms: 0.249333
46
46
  ...
47
47
  # Subtest: getUserEmail returns null when missing
48
48
  ok 9 - getUserEmail returns null when missing
49
49
  ---
50
- duration_ms: 0.396833
50
+ duration_ms: 0.347875
51
51
  ...
52
52
  # Subtest: requireAuth returns user ID for authenticated session
53
53
  ok 10 - requireAuth returns user ID for authenticated session
54
54
  ---
55
- duration_ms: 0.364417
55
+ duration_ms: 0.399833
56
56
  ...
57
57
  # Subtest: requireAuth throws error for unauthenticated session
58
58
  ok 11 - requireAuth throws error for unauthenticated session
59
59
  ---
60
- duration_ms: 1.319792
60
+ duration_ms: 3.111042
61
61
  ...
62
62
  1..11
63
63
  ok 1 - Auth Module
64
64
  ---
65
- duration_ms: 7.596
65
+ duration_ms: 15.232709
66
66
  ...
67
67
  # Subtest: authorization
68
68
  # Subtest: can()
69
69
  # Subtest: returns true for admin with wildcard permissions
70
70
  ok 1 - returns true for admin with wildcard permissions
71
71
  ---
72
- duration_ms: 1.981833
72
+ duration_ms: 0.507625
73
73
  ...
74
74
  # Subtest: returns true for editor with post actions
75
75
  ok 2 - returns true for editor with post actions
76
76
  ---
77
- duration_ms: 0.387
77
+ duration_ms: 1.255542
78
78
  ...
79
79
  # Subtest: returns true for editor reading users
80
80
  ok 3 - returns true for editor reading users
81
81
  ---
82
- duration_ms: 0.103625
82
+ duration_ms: 0.320166
83
83
  ...
84
84
  # Subtest: returns false for editor trying to delete users
85
85
  ok 4 - returns false for editor trying to delete users
86
86
  ---
87
- duration_ms: 0.206708
87
+ duration_ms: 0.549416
88
88
  ...
89
89
  # Subtest: returns false for viewer trying to write
90
90
  ok 5 - returns false for viewer trying to write
91
91
  ---
92
- duration_ms: 0.325583
92
+ duration_ms: 1.045167
93
93
  ...
94
94
  # Subtest: returns true for viewer reading posts and users
95
95
  ok 6 - returns true for viewer reading posts and users
96
96
  ---
97
- duration_ms: 0.29475
97
+ duration_ms: 0.359541
98
98
  ...
99
99
  # Subtest: owner can update their own resource
100
100
  ok 7 - owner can update their own resource
101
101
  ---
102
- duration_ms: 0.118
102
+ duration_ms: 0.295208
103
103
  ...
104
104
  # Subtest: owner can delete their own resource
105
105
  ok 8 - owner can delete their own resource
106
106
  ---
107
- duration_ms: 0.066542
107
+ duration_ms: 0.181833
108
108
  ...
109
109
  # Subtest: non-owner cannot update another user's resource
110
110
  ok 9 - non-owner cannot update another user's resource
111
111
  ---
112
- duration_ms: 0.168083
112
+ duration_ms: 0.412
113
113
  ...
114
114
  # Subtest: ownership does not apply for non-owner actions
115
115
  ok 10 - ownership does not apply for non-owner actions
116
116
  ---
117
- duration_ms: 0.20525
117
+ duration_ms: 0.588875
118
118
  ...
119
119
  # Subtest: applies defaultRole when user has no role
120
120
  ok 11 - applies defaultRole when user has no role
121
121
  ---
122
- duration_ms: 0.063917
122
+ duration_ms: 0.178208
123
123
  ...
124
124
  1..11
125
125
  ok 1 - can()
126
126
  ---
127
- duration_ms: 4.926791
127
+ duration_ms: 6.784042
128
128
  type: 'suite'
129
129
  ...
130
130
  # Subtest: authorize()
131
131
  # Subtest: throws ForbiddenError when denied
132
132
  ok 1 - throws ForbiddenError when denied
133
133
  ---
134
- duration_ms: 0.982416
134
+ duration_ms: 2.188333
135
135
  ...
136
136
  # Subtest: does not throw when allowed
137
137
  ok 2 - does not throw when allowed
138
138
  ---
139
- duration_ms: 0.119834
139
+ duration_ms: 0.476291
140
140
  ...
141
141
  # Subtest: includes user and action information in error message
142
142
  ok 3 - includes user and action information in error message
143
143
  ---
144
- duration_ms: 0.271875
144
+ duration_ms: 0.675292
145
145
  ...
146
146
  1..3
147
147
  ok 2 - authorize()
148
148
  ---
149
- duration_ms: 1.439833
149
+ duration_ms: 3.576584
150
150
  type: 'suite'
151
151
  ...
152
152
  # Subtest: hasPermission()
153
153
  # Subtest: returns true for exact match
154
154
  ok 1 - returns true for exact match
155
155
  ---
156
- duration_ms: 0.095417
156
+ duration_ms: 0.232167
157
157
  ...
158
158
  # Subtest: returns false for no match
159
159
  ok 2 - returns false for no match
160
160
  ---
161
- duration_ms: 0.055166
161
+ duration_ms: 0.140833
162
162
  ...
163
163
  # Subtest: returns true with resource wildcard
164
164
  ok 3 - returns true with resource wildcard
165
165
  ---
166
- duration_ms: 0.078584
166
+ duration_ms: 0.497041
167
167
  ...
168
168
  # Subtest: returns true with action wildcard
169
169
  ok 4 - returns true with action wildcard
170
170
  ---
171
- duration_ms: 0.052917
171
+ duration_ms: 0.062375
172
172
  ...
173
173
  # Subtest: returns false for unknown role
174
174
  ok 5 - returns false for unknown role
175
175
  ---
176
- duration_ms: 0.050917
176
+ duration_ms: 0.054
177
177
  ...
178
178
  1..5
179
179
  ok 3 - hasPermission()
180
180
  ---
181
- duration_ms: 1.659917
181
+ duration_ms: 1.097583
182
182
  type: 'suite'
183
183
  ...
184
184
  # Subtest: getRolePermissions()
185
185
  # Subtest: returns permissions for a valid role
186
186
  ok 1 - returns permissions for a valid role
187
187
  ---
188
- duration_ms: 0.200041
188
+ duration_ms: 0.2155
189
189
  ...
190
190
  # Subtest: returns empty array for unknown role
191
191
  ok 2 - returns empty array for unknown role
192
192
  ---
193
- duration_ms: 0.051
193
+ duration_ms: 0.054833
194
194
  ...
195
195
  1..2
196
196
  ok 4 - getRolePermissions()
197
197
  ---
198
- duration_ms: 0.290208
198
+ duration_ms: 0.312042
199
199
  type: 'suite'
200
200
  ...
201
201
  # Subtest: addRole() and removeRole()
202
202
  # Subtest: addRole() makes new role available
203
203
  ok 1 - addRole() makes new role available
204
204
  ---
205
- duration_ms: 0.079959
205
+ duration_ms: 0.086542
206
206
  ...
207
207
  # Subtest: removeRole() removes a role
208
208
  ok 2 - removeRole() removes a role
209
209
  ---
210
- duration_ms: 1.089333
210
+ duration_ms: 0.186833
211
211
  ...
212
212
  1..2
213
213
  ok 5 - addRole() and removeRole()
214
214
  ---
215
- duration_ms: 1.580583
215
+ duration_ms: 0.305125
216
216
  type: 'suite'
217
217
  ...
218
218
  # Subtest: extendPolicy()
219
219
  # Subtest: merges new roles into existing policy
220
220
  ok 1 - merges new roles into existing policy
221
221
  ---
222
- duration_ms: 0.301833
222
+ duration_ms: 0.107375
223
223
  ...
224
224
  # Subtest: preserves existing roles when extending
225
225
  ok 2 - preserves existing roles when extending
226
226
  ---
227
- duration_ms: 0.070334
227
+ duration_ms: 0.060708
228
228
  ...
229
229
  # Subtest: can override defaultRole
230
230
  ok 3 - can override defaultRole
231
231
  ---
232
- duration_ms: 0.057875
232
+ duration_ms: 0.05475
233
233
  ...
234
234
  1..3
235
235
  ok 6 - extendPolicy()
236
236
  ---
237
- duration_ms: 0.477916
237
+ duration_ms: 0.260583
238
238
  type: 'suite'
239
239
  ...
240
240
  # Subtest: requireRole()
241
241
  # Subtest: does not throw when session user has an allowed role
242
242
  ok 1 - does not throw when session user has an allowed role
243
243
  ---
244
- duration_ms: 0.102375
244
+ duration_ms: 0.319125
245
245
  ...
246
246
  # Subtest: throws ForbiddenError when session user role is not allowed
247
247
  ok 2 - throws ForbiddenError when session user role is not allowed
248
248
  ---
249
- duration_ms: 0.082125
249
+ duration_ms: 0.166958
250
250
  ...
251
251
  # Subtest: throws ForbiddenError when session has no role
252
252
  ok 3 - throws ForbiddenError when session has no role
253
253
  ---
254
- duration_ms: 0.074042
254
+ duration_ms: 0.078583
255
255
  ...
256
256
  # Subtest: throws ForbiddenError when session has no user
257
257
  ok 4 - throws ForbiddenError when session has no user
258
258
  ---
259
- duration_ms: 0.072792
259
+ duration_ms: 0.070334
260
260
  ...
261
261
  1..4
262
262
  ok 7 - requireRole()
263
263
  ---
264
- duration_ms: 0.376833
264
+ duration_ms: 0.788084
265
265
  type: 'suite'
266
266
  ...
267
267
  # Subtest: withAuthorization()
268
268
  # Subtest: calls handler when authorized
269
269
  ok 1 - calls handler when authorized
270
270
  ---
271
- duration_ms: 0.622167
271
+ duration_ms: 0.142541
272
272
  ...
273
273
  # Subtest: throws ForbiddenError when not authorized
274
274
  ok 2 - throws ForbiddenError when not authorized
275
275
  ---
276
- duration_ms: 0.183916
276
+ duration_ms: 0.142833
277
277
  ...
278
278
  # Subtest: throws ForbiddenError when no user in session
279
279
  ok 3 - throws ForbiddenError when no user in session
280
280
  ---
281
- duration_ms: 0.099125
281
+ duration_ms: 0.081917
282
282
  ...
283
283
  # Subtest: passes context from getContext to authorization
284
284
  ok 4 - passes context from getContext to authorization
285
285
  ---
286
- duration_ms: 0.086416
286
+ duration_ms: 0.150084
287
287
  ...
288
288
  1..4
289
289
  ok 8 - withAuthorization()
290
290
  ---
291
- duration_ms: 1.056459
291
+ duration_ms: 0.572833
292
292
  type: 'suite'
293
293
  ...
294
294
  # Subtest: default instance
295
295
  # Subtest: exports a working default authorization instance
296
296
  ok 1 - exports a working default authorization instance
297
297
  ---
298
- duration_ms: 0.07275
298
+ duration_ms: 0.088083
299
299
  ...
300
300
  1..1
301
301
  ok 9 - default instance
302
302
  ---
303
- duration_ms: 0.103833
303
+ duration_ms: 0.122041
304
304
  type: 'suite'
305
305
  ...
306
306
  # Subtest: defaultPolicy
307
307
  # Subtest: is exported and has expected structure
308
308
  ok 1 - is exported and has expected structure
309
309
  ---
310
- duration_ms: 0.111291
310
+ duration_ms: 0.125
311
311
  ...
312
312
  1..1
313
313
  ok 10 - defaultPolicy
314
314
  ---
315
- duration_ms: 0.146625
315
+ duration_ms: 0.157417
316
316
  type: 'suite'
317
317
  ...
318
318
  1..10
319
319
  ok 2 - authorization
320
320
  ---
321
- duration_ms: 13.10925
321
+ duration_ms: 14.719875
322
322
  type: 'suite'
323
323
  ...
324
324
  # Subtest: createCache
@@ -326,1044 +326,1044 @@ ok 2 - authorization
326
326
  # Subtest: returns null for a missing key
327
327
  ok 1 - returns null for a missing key
328
328
  ---
329
- duration_ms: 0.583625
329
+ duration_ms: 1.125792
330
330
  ...
331
331
  # Subtest: returns parsed JSON for an existing key
332
332
  ok 2 - returns parsed JSON for an existing key
333
333
  ---
334
- duration_ms: 0.405417
334
+ duration_ms: 0.845167
335
335
  ...
336
336
  # Subtest: returns null for invalid JSON
337
337
  ok 3 - returns null for invalid JSON
338
338
  ---
339
- duration_ms: 0.171625
339
+ duration_ms: 0.209209
340
340
  ...
341
341
  1..3
342
342
  ok 1 - get
343
343
  ---
344
- duration_ms: 1.559584
344
+ duration_ms: 2.914666
345
345
  type: 'suite'
346
346
  ...
347
347
  # Subtest: set
348
348
  # Subtest: round-trips JSON values through set/get
349
349
  ok 1 - round-trips JSON values through set/get
350
350
  ---
351
- duration_ms: 0.919625
351
+ duration_ms: 0.302791
352
352
  ...
353
353
  # Subtest: passes TTL to Redis expire
354
354
  ok 2 - passes TTL to Redis expire
355
355
  ---
356
- duration_ms: 0.51375
356
+ duration_ms: 0.200375
357
357
  ...
358
358
  # Subtest: uses defaultTTL when no TTL is provided
359
359
  ok 3 - uses defaultTTL when no TTL is provided
360
360
  ---
361
- duration_ms: 0.252459
361
+ duration_ms: 0.084875
362
362
  ...
363
363
  1..3
364
364
  ok 2 - set
365
365
  ---
366
- duration_ms: 2.268833
366
+ duration_ms: 0.813333
367
367
  type: 'suite'
368
368
  ...
369
369
  # Subtest: del
370
370
  # Subtest: removes a key
371
371
  ok 1 - removes a key
372
372
  ---
373
- duration_ms: 0.243625
373
+ duration_ms: 0.093417
374
374
  ...
375
375
  1..1
376
376
  ok 3 - del
377
377
  ---
378
- duration_ms: 0.35725
378
+ duration_ms: 0.13925
379
379
  type: 'suite'
380
380
  ...
381
381
  # Subtest: invalidate
382
382
  # Subtest: deletes all keys matching a pattern
383
383
  ok 1 - deletes all keys matching a pattern
384
384
  ---
385
- duration_ms: 2.748333
385
+ duration_ms: 3.474292
386
386
  ...
387
387
  # Subtest: does nothing when no keys match
388
388
  ok 2 - does nothing when no keys match
389
389
  ---
390
- duration_ms: 0.234625
390
+ duration_ms: 0.539709
391
391
  ...
392
392
  1..2
393
393
  ok 4 - invalidate
394
394
  ---
395
- duration_ms: 3.074875
395
+ duration_ms: 4.152541
396
396
  type: 'suite'
397
397
  ...
398
398
  # Subtest: getOrSet
399
399
  # Subtest: calls factory on cache miss and caches the result
400
400
  ok 1 - calls factory on cache miss and caches the result
401
401
  ---
402
- duration_ms: 0.152875
402
+ duration_ms: 0.363167
403
403
  ...
404
404
  # Subtest: returns cached value without calling factory on hit
405
405
  ok 2 - returns cached value without calling factory on hit
406
406
  ---
407
- duration_ms: 0.225792
407
+ duration_ms: 0.356667
408
408
  ...
409
409
  1..2
410
410
  ok 5 - getOrSet
411
411
  ---
412
- duration_ms: 0.417959
412
+ duration_ms: 0.81975
413
413
  type: 'suite'
414
414
  ...
415
415
  # Subtest: wrap
416
416
  # Subtest: creates a cached function
417
417
  ok 1 - creates a cached function
418
418
  ---
419
- duration_ms: 0.14725
419
+ duration_ms: 0.337709
420
420
  ...
421
421
  # Subtest: uses keyGenerator when provided
422
422
  ok 2 - uses keyGenerator when provided
423
423
  ---
424
- duration_ms: 0.112458
424
+ duration_ms: 0.310917
425
425
  ...
426
426
  # Subtest: caches different args separately
427
427
  ok 3 - caches different args separately
428
428
  ---
429
- duration_ms: 0.1055
429
+ duration_ms: 0.256291
430
430
  ...
431
431
  1..3
432
432
  ok 6 - wrap
433
433
  ---
434
- duration_ms: 0.40875
434
+ duration_ms: 1.0145
435
435
  type: 'suite'
436
436
  ...
437
437
  1..6
438
438
  ok 3 - createCache
439
439
  ---
440
- duration_ms: 9.401209
440
+ duration_ms: 10.707208
441
441
  type: 'suite'
442
442
  ...
443
443
  # Subtest: CSRF Module
444
444
  # Subtest: generateCsrfToken creates a secure token
445
445
  ok 1 - generateCsrfToken creates a secure token
446
446
  ---
447
- duration_ms: 1.917583
447
+ duration_ms: 1.233625
448
448
  ...
449
449
  # Subtest: validateCsrfToken accepts valid token
450
450
  ok 2 - validateCsrfToken accepts valid token
451
451
  ---
452
- duration_ms: 0.190167
452
+ duration_ms: 0.407167
453
453
  ...
454
454
  # Subtest: validateCsrfToken rejects missing header token
455
455
  ok 3 - validateCsrfToken rejects missing header token
456
456
  ---
457
- duration_ms: 4.459917
457
+ duration_ms: 8.670167
458
458
  ...
459
459
  # Subtest: validateCsrfToken rejects missing session token
460
460
  ok 4 - validateCsrfToken rejects missing session token
461
461
  ---
462
- duration_ms: 0.173167
462
+ duration_ms: 0.176042
463
463
  ...
464
464
  # Subtest: validateCsrfToken rejects mismatched tokens
465
465
  ok 5 - validateCsrfToken rejects mismatched tokens
466
466
  ---
467
- duration_ms: 0.402875
467
+ duration_ms: 0.137083
468
468
  ...
469
469
  # Subtest: validateCsrfToken rejects tokens of different lengths
470
470
  ok 6 - validateCsrfToken rejects tokens of different lengths
471
471
  ---
472
- duration_ms: 0.3295
472
+ duration_ms: 0.123417
473
473
  ...
474
474
  # Subtest: requireCsrfToken skips GET requests
475
475
  ok 7 - requireCsrfToken skips GET requests
476
476
  ---
477
- duration_ms: 0.3365
477
+ duration_ms: 0.086667
478
478
  ...
479
479
  # Subtest: requireCsrfToken skips NextAuth routes
480
480
  ok 8 - requireCsrfToken skips NextAuth routes
481
481
  ---
482
- duration_ms: 0.446958
482
+ duration_ms: 0.18725
483
483
  ...
484
484
  # Subtest: requireCsrfToken validates POST with cookie token
485
485
  ok 9 - requireCsrfToken validates POST with cookie token
486
486
  ---
487
- duration_ms: 0.6065
487
+ duration_ms: 0.262916
488
488
  ...
489
489
  # Subtest: requireCsrfToken throws when cookie is missing
490
490
  ok 10 - requireCsrfToken throws when cookie is missing
491
491
  ---
492
- duration_ms: 1.87775
492
+ duration_ms: 0.54325
493
493
  ...
494
494
  # Subtest: withCsrfProtection wraps handler
495
495
  ok 11 - withCsrfProtection wraps handler
496
496
  ---
497
- duration_ms: 0.192291
497
+ duration_ms: 1.465666
498
498
  ...
499
499
  1..11
500
500
  ok 4 - CSRF Module
501
501
  ---
502
- duration_ms: 13.338875
502
+ duration_ms: 15.138958
503
503
  ...
504
504
  # Subtest: Email Service
505
505
  # Subtest: createEmailService returns object with sendEmail method
506
506
  ok 1 - createEmailService returns object with sendEmail method
507
507
  ---
508
- duration_ms: 0.557292
508
+ duration_ms: 0.379625
509
509
  ...
510
510
  # Subtest: SMTP provider: uses Mailhog defaults when no SMTP_HOST set
511
511
  ok 2 - SMTP provider: uses Mailhog defaults when no SMTP_HOST set
512
512
  ---
513
- duration_ms: 0.091125
513
+ duration_ms: 0.0815
514
514
  ...
515
515
  # Subtest: SMTP provider: uses explicit SMTP_HOST/SMTP_PORT when set
516
516
  ok 3 - SMTP provider: uses explicit SMTP_HOST/SMTP_PORT when set
517
517
  ---
518
- duration_ms: 0.068416
518
+ duration_ms: 0.065
519
519
  ...
520
520
  # Subtest: Resend provider: throws if RESEND_API_KEY missing
521
521
  ok 4 - Resend provider: throws if RESEND_API_KEY missing
522
522
  ---
523
- duration_ms: 0.379291
523
+ duration_ms: 0.402167
524
524
  ...
525
525
  # Subtest: Resend provider: calls fetch with correct URL, headers, and body
526
526
  ok 5 - Resend provider: calls fetch with correct URL, headers, and body
527
527
  ---
528
- duration_ms: 1.266584
528
+ duration_ms: 0.6785
529
529
  ...
530
530
  # Subtest: Resend provider: throws on non-ok response
531
531
  ok 6 - Resend provider: throws on non-ok response
532
532
  ---
533
- duration_ms: 0.213209
533
+ duration_ms: 0.210583
534
534
  ...
535
535
  # Subtest: Resend provider: handles non-JSON error response
536
536
  ok 7 - Resend provider: handles non-JSON error response
537
537
  ---
538
- duration_ms: 0.194
538
+ duration_ms: 0.138333
539
539
  ...
540
540
  # Subtest: default provider is smtp
541
541
  ok 8 - default provider is smtp
542
542
  ---
543
- duration_ms: 0.20625
543
+ duration_ms: 0.19125
544
544
  ...
545
545
  # Subtest: respects options.from override
546
546
  ok 9 - respects options.from override
547
547
  ---
548
- duration_ms: 0.27
548
+ duration_ms: 0.25675
549
549
  ...
550
550
  # Subtest: input validation: rejects empty 'to'
551
551
  ok 10 - input validation: rejects empty 'to'
552
552
  ---
553
- duration_ms: 0.21125
553
+ duration_ms: 0.1935
554
554
  ...
555
555
  # Subtest: input validation: rejects empty 'subject'
556
556
  ok 11 - input validation: rejects empty 'subject'
557
557
  ---
558
- duration_ms: 0.07875
558
+ duration_ms: 0.838042
559
559
  ...
560
560
  # Subtest: input validation: rejects empty 'html'
561
561
  ok 12 - input validation: rejects empty 'html'
562
562
  ---
563
- duration_ms: 0.063958
563
+ duration_ms: 0.102958
564
564
  ...
565
565
  1..12
566
566
  ok 5 - Email Service
567
567
  ---
568
- duration_ms: 6.881417
568
+ duration_ms: 7.765042
569
569
  ...
570
- # 18:43:11.931 ERROR [quark] test error {"error":{"name":"AppError","message":"test error","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-14T18:43:11.930Z"},"context":{"requestId":"123","breadcrumbs":[]},"stack":"Error: test error\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:61:18)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Promise.all (index 0)\\n at async Suite.run (node:internal/test_runner/test:1358:7)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
571
- # 18:43:11.933 ERROR [quark] test {"error":{"name":"AppError","message":"test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-14T18:43:11.933Z"},"context":{"breadcrumbs":[]},"stack":"Error: test\\n at file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:81:46\\n at getActual (node:assert:840:5)\\n at Function.doesNotThrow (node:assert:1006:32)\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:81:11)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
572
- # 18:43:11.933 WARN  [quark] hello {"extra":true}
573
- # 18:43:11.934 INFO  [quark] hello
574
- # 18:43:11.934 ERROR [quark] test {"error":{"name":"AppError","message":"test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-14T18:43:11.934Z"},"context":{"user":{"id":"u1","email":"a@b.com"},"breadcrumbs":[]},"stack":"Error: test\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:121:20)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Promise.all (index 0)\\n at async Suite.run (node:internal/test_runner/test:1358:7)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
575
- # 18:43:11.935 ERROR [quark] test {"error":{"name":"AppError","message":"test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-14T18:43:11.935Z"},"context":{"breadcrumbs":[{"message":"clicked button","category":"ui","data":{"buttonId":"submit"},"timestamp":"2026-02-14T18:43:11.935Z"},{"message":"navigated","category":"navigation","data":{},"timestamp":"2026-02-14T18:43:11.935Z"}]},"stack":"Error: test\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:154:20)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Promise.all (index 0)\\n at async Suite.run (node:internal/test_runner/test:1358:7)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
576
- # 18:43:11.935 ERROR [quark] custom test {"error":{"name":"AppError","message":"custom test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-14T18:43:11.935Z"},"context":{"route":"/api/test","user":{"id":"u1"},"breadcrumbs":[{"message":"init","category":"app","data":{},"timestamp":"2026-02-14T18:43:11.935Z"}]},"stack":"Error: custom test\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:208:18)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Promise.all (index 0)\\n at async Suite.run (node:internal/test_runner/test:1358:7)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
577
- # 18:43:11.936 ERROR [quark] test {"error":{"name":"AppError","message":"test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-14T18:43:11.936Z"},"context":{"breadcrumbs":[]},"stack":"Error: test\\n at file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:233:46\\n at getActual (node:assert:840:5)\\n at Function.doesNotThrow (node:assert:1006:32)\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:233:11)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
570
+ # 08:02:47.492 ERROR [quark] test error {"error":{"name":"AppError","message":"test error","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-15T08:02:47.489Z"},"context":{"requestId":"123","breadcrumbs":[]},"stack":"Error: test error\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:61:18)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Promise.all (index 0)\\n at async Suite.run (node:internal/test_runner/test:1358:7)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
571
+ # 08:02:47.494 ERROR [quark] test {"error":{"name":"AppError","message":"test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-15T08:02:47.494Z"},"context":{"breadcrumbs":[]},"stack":"Error: test\\n at file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:81:46\\n at getActual (node:assert:840:5)\\n at Function.doesNotThrow (node:assert:1006:32)\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:81:11)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
572
+ # 08:02:47.494 WARN  [quark] hello {"extra":true}
573
+ # 08:02:47.494 ERROR [quark] test {"error":{"name":"AppError","message":"test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-15T08:02:47.494Z"},"context":{"user":{"id":"u1","email":"a@b.com"},"breadcrumbs":[]},"stack":"Error: test\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:121:20)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Promise.all (index 0)\\n at async Suite.run (node:internal/test_runner/test:1358:7)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
574
+ # 08:02:47.495 ERROR [quark] test {"error":{"name":"AppError","message":"test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-15T08:02:47.495Z"},"context":{"breadcrumbs":[{"message":"clicked button","category":"ui","data":{"buttonId":"submit"},"timestamp":"2026-02-15T08:02:47.495Z"},{"message":"navigated","category":"navigation","data":{},"timestamp":"2026-02-15T08:02:47.495Z"}]},"stack":"Error: test\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:154:20)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Promise.all (index 0)\\n at async Suite.run (node:internal/test_runner/test:1358:7)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
575
+ # 08:02:47.494 INFO  [quark] hello
576
+ # 08:02:47.496 ERROR [quark] custom test {"error":{"name":"AppError","message":"custom test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-15T08:02:47.496Z"},"context":{"route":"/api/test","user":{"id":"u1"},"breadcrumbs":[{"message":"init","category":"app","data":{},"timestamp":"2026-02-15T08:02:47.496Z"}]},"stack":"Error: custom test\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:208:18)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Promise.all (index 0)\\n at async Suite.run (node:internal/test_runner/test:1358:7)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
577
+ # 08:02:47.497 ERROR [quark] test {"error":{"name":"AppError","message":"test","code":"INTERNAL_ERROR","statusCode":500,"timestamp":"2026-02-15T08:02:47.497Z"},"context":{"breadcrumbs":[]},"stack":"Error: test\\n at file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:233:46\\n at getActual (node:assert:840:5)\\n at Function.doesNotThrow (node:assert:1006:32)\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/error-reporter.test.js:233:11)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at async Suite.processPendingSubtests (node:internal/test_runner/test:677:7)"}
578
578
  # Subtest: ErrorReporter
579
579
  # Subtest: default instance
580
580
  # Subtest: has console adapter registered by default
581
581
  ok 1 - has console adapter registered by default
582
582
  ---
583
- duration_ms: 0.615417
583
+ duration_ms: 0.591958
584
584
  ...
585
585
  # Subtest: global singleton has console adapter
586
586
  ok 2 - global singleton has console adapter
587
587
  ---
588
- duration_ms: 0.15525
588
+ duration_ms: 0.124
589
589
  ...
590
590
  1..2
591
591
  ok 1 - default instance
592
592
  ---
593
- duration_ms: 1.220041
593
+ duration_ms: 1.015125
594
594
  type: 'suite'
595
595
  ...
596
596
  # Subtest: use()
597
597
  # Subtest: adds an adapter
598
598
  ok 1 - adds an adapter
599
599
  ---
600
- duration_ms: 14.186458
600
+ duration_ms: 0.258292
601
601
  ...
602
602
  # Subtest: throws if adapter has no name
603
603
  ok 2 - throws if adapter has no name
604
604
  ---
605
- duration_ms: 14.95325
605
+ duration_ms: 0.373667
606
606
  ...
607
607
  # Subtest: throws if adapter has no report function
608
608
  ok 3 - throws if adapter has no report function
609
609
  ---
610
- duration_ms: 0.965625
610
+ duration_ms: 0.227333
611
611
  ...
612
612
  1..3
613
613
  ok 2 - use()
614
614
  ---
615
- duration_ms: 30.70625
615
+ duration_ms: 2.241208
616
616
  type: 'suite'
617
617
  ...
618
618
  # Subtest: report()
619
619
  # Subtest: calls all registered adapters
620
620
  ok 1 - calls all registered adapters
621
621
  ---
622
- duration_ms: 4.345083
622
+ duration_ms: 4.431458
623
623
  ...
624
624
  # Subtest: swallows adapter errors without throwing
625
625
  ok 2 - swallows adapter errors without throwing
626
626
  ---
627
- duration_ms: 0.391333
627
+ duration_ms: 0.367625
628
628
  ...
629
629
  1..2
630
630
  ok 3 - report()
631
631
  ---
632
- duration_ms: 5.039125
632
+ duration_ms: 5.000792
633
633
  type: 'suite'
634
634
  ...
635
635
  # Subtest: captureMessage()
636
636
  # Subtest: calls adapters that support captureMessage
637
637
  ok 1 - calls adapters that support captureMessage
638
638
  ---
639
- duration_ms: 0.185458
639
+ duration_ms: 0.17075
640
640
  ...
641
641
  # Subtest: skips adapters without captureMessage
642
642
  ok 2 - skips adapters without captureMessage
643
643
  ---
644
- duration_ms: 0.235125
644
+ duration_ms: 0.205916
645
645
  ...
646
646
  1..2
647
647
  ok 4 - captureMessage()
648
648
  ---
649
- duration_ms: 0.474333
649
+ duration_ms: 0.430625
650
650
  type: 'suite'
651
651
  ...
652
652
  # Subtest: setUser()
653
653
  # Subtest: includes user in subsequent reports
654
654
  ok 1 - includes user in subsequent reports
655
655
  ---
656
- duration_ms: 0.863166
656
+ duration_ms: 0.4615
657
657
  ...
658
658
  # Subtest: forwards user to adapters with setUser
659
659
  ok 2 - forwards user to adapters with setUser
660
660
  ---
661
- duration_ms: 0.093583
661
+ duration_ms: 0.082208
662
662
  ...
663
663
  1..2
664
664
  ok 5 - setUser()
665
665
  ---
666
- duration_ms: 1.005292
666
+ duration_ms: 0.584167
667
667
  type: 'suite'
668
668
  ...
669
669
  # Subtest: addBreadcrumb()
670
670
  # Subtest: stores breadcrumbs and attaches them to report context
671
671
  ok 1 - stores breadcrumbs and attaches them to report context
672
672
  ---
673
- duration_ms: 0.219041
673
+ duration_ms: 0.226708
674
674
  ...
675
675
  # Subtest: circular buffer keeps max 50 breadcrumbs
676
676
  ok 2 - circular buffer keeps max 50 breadcrumbs
677
677
  ---
678
- duration_ms: 0.185958
678
+ duration_ms: 0.238708
679
679
  ...
680
680
  # Subtest: forwards breadcrumbs to adapters that support it
681
681
  ok 3 - forwards breadcrumbs to adapters that support it
682
682
  ---
683
- duration_ms: 0.083292
683
+ duration_ms: 0.301125
684
684
  ...
685
685
  1..3
686
686
  ok 6 - addBreadcrumb()
687
687
  ---
688
- duration_ms: 0.534708
688
+ duration_ms: 0.876333
689
689
  type: 'suite'
690
690
  ...
691
691
  # Subtest: custom adapter receives correct data
692
692
  # Subtest: passes error and enriched context
693
693
  ok 1 - passes error and enriched context
694
694
  ---
695
- duration_ms: 0.152375
695
+ duration_ms: 0.17775
696
696
  ...
697
697
  1..1
698
698
  ok 7 - custom adapter receives correct data
699
699
  ---
700
- duration_ms: 0.181833
700
+ duration_ms: 0.318208
701
701
  type: 'suite'
702
702
  ...
703
703
  # Subtest: createSentryAdapter()
704
704
  # Subtest: returns a valid adapter shape
705
705
  ok 1 - returns a valid adapter shape
706
706
  ---
707
- duration_ms: 0.141541
707
+ duration_ms: 0.711667
708
708
  ...
709
709
  # Subtest: can be registered without errors
710
710
  ok 2 - can be registered without errors
711
711
  ---
712
- duration_ms: 0.115792
712
+ duration_ms: 0.449166
713
713
  ...
714
714
  1..2
715
715
  ok 8 - createSentryAdapter()
716
716
  ---
717
- duration_ms: 0.292791
717
+ duration_ms: 1.244333
718
718
  type: 'suite'
719
719
  ...
720
720
  1..8
721
721
  ok 6 - ErrorReporter
722
722
  ---
723
- duration_ms: 39.971083
723
+ duration_ms: 12.297875
724
724
  type: 'suite'
725
725
  ...
726
- # 18:43:11.905 ERROR [quark] test {"error":{"name":"ValidationError","message":"test","code":"VALIDATION_ERROR","statusCode":400,"timestamp":"2026-02-14T18:43:11.904Z","details":null},"context":{"userId":"123","action":"test","breadcrumbs":[]},"stack":"ValidationError: test\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/errors.test.js:124:17)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at Test.start (node:internal/test_runner/test:877:17)\\n at TestContext.test (node:internal/test_runner/test:307:20)\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/errors.test.js:122:10)\\n at async Test.run (node:internal/test_runner/test:980:9)\\n at async startSubtestAfterBootstrap (node:internal/test_runner/harness:296:3)"}
726
+ # 08:02:47.506 ERROR [quark] test {"error":{"name":"ValidationError","message":"test","code":"VALIDATION_ERROR","statusCode":400,"timestamp":"2026-02-15T08:02:47.503Z","details":null},"context":{"userId":"123","action":"test","breadcrumbs":[]},"stack":"ValidationError: test\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/errors.test.js:124:17)\\n at Test.runInAsyncScope (node:async_hooks:211:14)\\n at Test.run (node:internal/test_runner/test:979:25)\\n at Test.start (node:internal/test_runner/test:877:17)\\n at TestContext.test (node:internal/test_runner/test:307:20)\\n at TestContext.<anonymous> (file:///Users/david/Projects/quark/packages/core/src/errors.test.js:122:10)\\n at async Test.run (node:internal/test_runner/test:980:9)\\n at async startSubtestAfterBootstrap (node:internal/test_runner/harness:296:3)"}
727
727
  # Subtest: Error Module
728
728
  # Subtest: AppError has correct properties
729
729
  ok 1 - AppError has correct properties
730
730
  ---
731
- duration_ms: 2.939125
731
+ duration_ms: 4.095334
732
732
  ...
733
733
  # Subtest: AppError.toJSON() serializes correctly
734
734
  ok 2 - AppError.toJSON() serializes correctly
735
735
  ---
736
- duration_ms: 0.107292
736
+ duration_ms: 0.205333
737
737
  ...
738
738
  # Subtest: ValidationError has status 400
739
739
  ok 3 - ValidationError has status 400
740
740
  ---
741
- duration_ms: 0.078916
741
+ duration_ms: 0.168375
742
742
  ...
743
743
  # Subtest: UnauthorizedError has status 401
744
744
  ok 4 - UnauthorizedError has status 401
745
745
  ---
746
- duration_ms: 0.314958
746
+ duration_ms: 0.631375
747
747
  ...
748
748
  # Subtest: ForbiddenError has status 403
749
749
  ok 5 - ForbiddenError has status 403
750
750
  ---
751
- duration_ms: 0.06525
751
+ duration_ms: 0.157625
752
752
  ...
753
753
  # Subtest: NotFoundError has status 404
754
754
  ok 6 - NotFoundError has status 404
755
755
  ---
756
- duration_ms: 0.114583
756
+ duration_ms: 0.268083
757
757
  ...
758
758
  # Subtest: ConflictError has status 409
759
759
  ok 7 - ConflictError has status 409
760
760
  ---
761
- duration_ms: 0.055833
761
+ duration_ms: 0.159625
762
762
  ...
763
763
  # Subtest: RateLimitError has status 429
764
764
  ok 8 - RateLimitError has status 429
765
765
  ---
766
- duration_ms: 0.910167
766
+ duration_ms: 0.430542
767
767
  ...
768
768
  # Subtest: DatabaseError wraps database errors
769
769
  ok 9 - DatabaseError wraps database errors
770
770
  ---
771
- duration_ms: 0.522709
771
+ duration_ms: 0.4655
772
772
  ...
773
773
  # Subtest: ServiceError includes service name
774
774
  ok 10 - ServiceError includes service name
775
775
  ---
776
- duration_ms: 0.393792
776
+ duration_ms: 0.348833
777
777
  ...
778
778
  # Subtest: getErrorMessage extracts from various types
779
779
  ok 11 - getErrorMessage extracts from various types
780
780
  ---
781
- duration_ms: 0.148209
781
+ duration_ms: 0.144458
782
782
  ...
783
783
  # Subtest: getStatusCode returns correct code
784
784
  ok 12 - getStatusCode returns correct code
785
785
  ---
786
- duration_ms: 0.211375
786
+ duration_ms: 0.23025
787
787
  ...
788
788
  # Subtest: normalizeError converts to AppError
789
789
  ok 13 - normalizeError converts to AppError
790
790
  ---
791
- duration_ms: 0.150834
791
+ duration_ms: 0.082208
792
792
  ...
793
793
  # Subtest: normalizeError handles string errors
794
794
  ok 14 - normalizeError handles string errors
795
795
  ---
796
- duration_ms: 0.057125
796
+ duration_ms: 0.046042
797
797
  ...
798
798
  # Subtest: normalizeError handles non-Error objects
799
799
  ok 15 - normalizeError handles non-Error objects
800
800
  ---
801
- duration_ms: 0.048333
801
+ duration_ms: 0.045125
802
802
  ...
803
803
  # Subtest: logError handles errors with context
804
804
  ok 16 - logError handles errors with context
805
805
  ---
806
- duration_ms: 3.156375
806
+ duration_ms: 3.53825
807
807
  ...
808
808
  1..16
809
809
  ok 7 - Error Module
810
810
  ---
811
- duration_ms: 11.603708
811
+ duration_ms: 13.927375
812
812
  ...
813
813
  # Subtest: Logger
814
814
  # Subtest: creates logger with default options
815
815
  ok 1 - creates logger with default options
816
816
  ---
817
- duration_ms: 2.076334
817
+ duration_ms: 3.107167
818
818
  ...
819
819
  # Subtest: default logger instance exists with name 'quark'
820
820
  ok 2 - default logger instance exists with name 'quark'
821
821
  ---
822
- duration_ms: 1.256958
822
+ duration_ms: 1.476708
823
823
  ...
824
824
  # Subtest: log level filtering: debug hidden at info level
825
825
  ok 3 - log level filtering: debug hidden at info level
826
826
  ---
827
- duration_ms: 0.34725
827
+ duration_ms: 0.350166
828
828
  ...
829
829
  # Subtest: log level filtering: debug visible at debug level
830
830
  ok 4 - log level filtering: debug visible at debug level
831
831
  ---
832
- duration_ms: 0.33025
832
+ duration_ms: 0.33625
833
833
  ...
834
834
  # Subtest: respects LOG_LEVEL env var
835
835
  ok 5 - respects LOG_LEVEL env var
836
836
  ---
837
- duration_ms: 0.175042
837
+ duration_ms: 0.1785
838
838
  ...
839
839
  # Subtest: child logger inherits parent context
840
840
  ok 6 - child logger inherits parent context
841
841
  ---
842
- duration_ms: 0.129333
842
+ duration_ms: 0.127458
843
843
  ...
844
844
  # Subtest: child logger merges context without mutating parent
845
845
  ok 7 - child logger merges context without mutating parent
846
846
  ---
847
- duration_ms: 0.167417
847
+ duration_ms: 0.166583
848
848
  ...
849
849
  # Subtest: structured output contains required fields
850
850
  ok 8 - structured output contains required fields
851
851
  ---
852
- duration_ms: 0.10875
852
+ duration_ms: 0.10825
853
853
  ...
854
854
  # Subtest: error and fatal use console.error
855
855
  ok 9 - error and fatal use console.error
856
856
  ---
857
- duration_ms: 1.472333
857
+ duration_ms: 1.137416
858
858
  ...
859
859
  # Subtest: warn uses console.warn
860
860
  ok 10 - warn uses console.warn
861
861
  ---
862
- duration_ms: 0.293
862
+ duration_ms: 0.628625
863
863
  ...
864
864
  # Subtest: dev mode outputs colorized non-JSON string
865
865
  ok 11 - dev mode outputs colorized non-JSON string
866
866
  ---
867
- duration_ms: 0.218959
867
+ duration_ms: 0.511041
868
868
  ...
869
869
  # Subtest: call-site data overrides default context
870
870
  ok 12 - call-site data overrides default context
871
871
  ---
872
- duration_ms: 0.101
872
+ duration_ms: 0.255792
873
873
  ...
874
874
  1..12
875
875
  ok 8 - Logger
876
876
  ---
877
- duration_ms: 7.448875
877
+ duration_ms: 9.611084
878
878
  type: 'suite'
879
879
  ...
880
880
  # Subtest: requestLogger
881
881
  # Subtest: creates child logger with request fields
882
882
  ok 1 - creates child logger with request fields
883
883
  ---
884
- duration_ms: 0.169
884
+ duration_ms: 0.38825
885
885
  ...
886
886
  # Subtest: generates requestId when header is missing
887
887
  ok 2 - generates requestId when header is missing
888
888
  ---
889
- duration_ms: 2.116334
889
+ duration_ms: 1.539459
890
890
  ...
891
891
  1..2
892
892
  ok 9 - requestLogger
893
893
  ---
894
- duration_ms: 2.339875
894
+ duration_ms: 2.011083
895
895
  type: 'suite'
896
896
  ...
897
897
  # Subtest: Rate Limiter Module
898
898
  # Subtest: createRateLimiter creates memory limiter by default
899
899
  ok 1 - createRateLimiter creates memory limiter by default
900
900
  ---
901
- duration_ms: 0.432958
901
+ duration_ms: 0.345625
902
902
  ...
903
903
  # Subtest: createRateLimiter throws error for Redis without client
904
904
  ok 2 - createRateLimiter throws error for Redis without client
905
905
  ---
906
- duration_ms: 0.195541
906
+ duration_ms: 0.183167
907
907
  ...
908
908
  # Subtest: Memory rate limiter allows requests under limit
909
909
  ok 3 - Memory rate limiter allows requests under limit
910
910
  ---
911
- duration_ms: 0.162959
911
+ duration_ms: 0.153167
912
912
  ...
913
913
  # Subtest: Memory rate limiter blocks requests over limit
914
914
  ok 4 - Memory rate limiter blocks requests over limit
915
915
  ---
916
- duration_ms: 0.80725
916
+ duration_ms: 0.710458
917
917
  ...
918
918
  # Subtest: Memory rate limiter resets after window
919
919
  ok 5 - Memory rate limiter resets after window
920
920
  ---
921
- duration_ms: 22.261875
921
+ duration_ms: 21.516667
922
922
  ...
923
923
  # Subtest: Memory rate limiter can reset a key
924
924
  ok 6 - Memory rate limiter can reset a key
925
925
  ---
926
- duration_ms: 0.312458
926
+ duration_ms: 0.142125
927
927
  ...
928
928
  # Subtest: Memory rate limiter can clear all keys
929
929
  ok 7 - Memory rate limiter can clear all keys
930
930
  ---
931
- duration_ms: 0.115416
931
+ duration_ms: 0.093292
932
932
  ...
933
933
  # Subtest: RATE_LIMIT_PRESETS have correct structure
934
934
  ok 8 - RATE_LIMIT_PRESETS have correct structure
935
935
  ---
936
- duration_ms: 0.157292
936
+ duration_ms: 0.14525
937
937
  ...
938
938
  # Subtest: createRateLimitMiddleware returns a function
939
939
  ok 9 - createRateLimitMiddleware returns a function
940
940
  ---
941
- duration_ms: 0.238542
941
+ duration_ms: 0.224208
942
942
  ...
943
943
  # Subtest: createRateLimitMiddleware works with API preset
944
944
  ok 10 - createRateLimitMiddleware works with API preset
945
945
  ---
946
- duration_ms: 0.198292
946
+ duration_ms: 0.192458
947
947
  ...
948
948
  # Subtest: Cleanup interval is started for memory limiter
949
949
  ok 11 - Cleanup interval is started for memory limiter
950
950
  ---
951
- duration_ms: 0.525708
951
+ duration_ms: 0.106041
952
952
  ...
953
953
  1..11
954
954
  ok 10 - Rate Limiter Module
955
955
  ---
956
- duration_ms: 27.643167
956
+ duration_ms: 25.494834
957
957
  ...
958
958
  # Subtest: Factories
959
959
  # Subtest: createTestUser returns correct shape with defaults
960
960
  ok 1 - createTestUser returns correct shape with defaults
961
961
  ---
962
- duration_ms: 0.47975
962
+ duration_ms: 0.474084
963
963
  ...
964
964
  # Subtest: createTestUser applies overrides
965
965
  ok 2 - createTestUser applies overrides
966
966
  ---
967
- duration_ms: 0.079375
967
+ duration_ms: 0.078333
968
968
  ...
969
969
  # Subtest: createTestUser generates unique IDs
970
970
  ok 3 - createTestUser generates unique IDs
971
971
  ---
972
- duration_ms: 0.068708
972
+ duration_ms: 0.070208
973
973
  ...
974
974
  # Subtest: createTestPost returns correct shape with defaults
975
975
  ok 4 - createTestPost returns correct shape with defaults
976
976
  ---
977
- duration_ms: 0.076208
977
+ duration_ms: 0.075792
978
978
  ...
979
979
  # Subtest: createTestPost applies overrides including boolean false
980
980
  ok 5 - createTestPost applies overrides including boolean false
981
981
  ---
982
- duration_ms: 0.060333
982
+ duration_ms: 0.055584
983
983
  ...
984
984
  # Subtest: createTestPost keeps published false when explicitly set
985
985
  ok 6 - createTestPost keeps published false when explicitly set
986
986
  ---
987
- duration_ms: 0.110083
987
+ duration_ms: 0.105084
988
988
  ...
989
989
  # Subtest: createTestSession returns session with embedded user
990
990
  ok 7 - createTestSession returns session with embedded user
991
991
  ---
992
- duration_ms: 2.819166
992
+ duration_ms: 2.945625
993
993
  ...
994
994
  # Subtest: createTestSession applies user overrides
995
995
  ok 8 - createTestSession applies user overrides
996
996
  ---
997
- duration_ms: 0.615709
997
+ duration_ms: 0.536416
998
998
  ...
999
999
  # Subtest: createTestSession applies top-level overrides
1000
1000
  ok 9 - createTestSession applies top-level overrides
1001
1001
  ---
1002
- duration_ms: 0.31925
1002
+ duration_ms: 0.398
1003
1003
  ...
1004
1004
  1..9
1005
1005
  ok 11 - Factories
1006
1006
  ---
1007
- duration_ms: 5.724625
1007
+ duration_ms: 6.166041
1008
1008
  ...
1009
1009
  # Subtest: Mock Prisma
1010
1010
  # Subtest: records method calls with args
1011
1011
  ok 1 - records method calls with args
1012
1012
  ---
1013
- duration_ms: 0.469834
1013
+ duration_ms: 0.906834
1014
1014
  ...
1015
1015
  # Subtest: returns null by default for unconfigured methods
1016
1016
  ok 2 - returns null by default for unconfigured methods
1017
1017
  ---
1018
- duration_ms: 0.745875
1018
+ duration_ms: 0.672833
1019
1019
  ...
1020
1020
  # Subtest: returns configured values via mockReturn
1021
1021
  ok 3 - returns configured values via mockReturn
1022
1022
  ---
1023
- duration_ms: 0.072625
1023
+ duration_ms: 0.089708
1024
1024
  ...
1025
1025
  # Subtest: supports function return values
1026
1026
  ok 4 - supports function return values
1027
1027
  ---
1028
- duration_ms: 0.053958
1028
+ duration_ms: 0.061833
1029
1029
  ...
1030
1030
  # Subtest: supports overrides in constructor
1031
1031
  ok 5 - supports overrides in constructor
1032
1032
  ---
1033
- duration_ms: 0.055167
1033
+ duration_ms: 0.056583
1034
1034
  ...
1035
1035
  # Subtest: reset clears calls and return values
1036
1036
  ok 6 - reset clears calls and return values
1037
1037
  ---
1038
- duration_ms: 0.065792
1038
+ duration_ms: 0.067959
1039
1039
  ...
1040
1040
  # Subtest: handles multiple models independently
1041
1041
  ok 7 - handles multiple models independently
1042
1042
  ---
1043
- duration_ms: 0.103083
1043
+ duration_ms: 0.113417
1044
1044
  ...
1045
1045
  1..7
1046
1046
  ok 12 - Mock Prisma
1047
1047
  ---
1048
- duration_ms: 1.910667
1048
+ duration_ms: 2.54825
1049
1049
  ...
1050
1050
  # Subtest: Mock Request
1051
1051
  # Subtest: has correct defaults
1052
1052
  ok 1 - has correct defaults
1053
1053
  ---
1054
- duration_ms: 0.082458
1054
+ duration_ms: 0.085833
1055
1055
  ...
1056
1056
  # Subtest: headers.get is case-insensitive
1057
1057
  ok 2 - headers.get is case-insensitive
1058
1058
  ---
1059
- duration_ms: 0.056458
1059
+ duration_ms: 0.056916
1060
1060
  ...
1061
1061
  # Subtest: returns null for missing headers
1062
1062
  ok 3 - returns null for missing headers
1063
1063
  ---
1064
- duration_ms: 0.032084
1064
+ duration_ms: 0.032958
1065
1065
  ...
1066
1066
  # Subtest: json() returns body
1067
1067
  ok 4 - json() returns body
1068
1068
  ---
1069
- duration_ms: 0.045667
1069
+ duration_ms: 0.047792
1070
1070
  ...
1071
1071
  # Subtest: cookies.get returns cookie object
1072
1072
  ok 5 - cookies.get returns cookie object
1073
1073
  ---
1074
- duration_ms: 0.051167
1074
+ duration_ms: 0.05225
1075
1075
  ...
1076
1076
  # Subtest: cookies.get returns undefined for missing cookie
1077
1077
  ok 6 - cookies.get returns undefined for missing cookie
1078
1078
  ---
1079
- duration_ms: 0.033833
1079
+ duration_ms: 0.031292
1080
1080
  ...
1081
1081
  # Subtest: nextUrl is a URL object
1082
1082
  ok 7 - nextUrl is a URL object
1083
1083
  ---
1084
- duration_ms: 0.067458
1084
+ duration_ms: 0.063625
1085
1085
  ...
1086
1086
  1..7
1087
1087
  ok 13 - Mock Request
1088
1088
  ---
1089
- duration_ms: 0.528334
1089
+ duration_ms: 0.53225
1090
1090
  ...
1091
1091
  # Subtest: Mock Response
1092
1092
  # Subtest: has default status 200
1093
1093
  ok 1 - has default status 200
1094
1094
  ---
1095
- duration_ms: 0.059625
1095
+ duration_ms: 0.061167
1096
1096
  ...
1097
1097
  # Subtest: json() sets body and content-type
1098
1098
  ok 2 - json() sets body and content-type
1099
1099
  ---
1100
- duration_ms: 0.098292
1100
+ duration_ms: 0.105542
1101
1101
  ...
1102
1102
  # Subtest: redirect() sets status and location
1103
1103
  ok 3 - redirect() sets status and location
1104
1104
  ---
1105
- duration_ms: 0.037333
1105
+ duration_ms: 0.037084
1106
1106
  ...
1107
1107
  # Subtest: cookies can be set and retrieved
1108
1108
  ok 4 - cookies can be set and retrieved
1109
1109
  ---
1110
- duration_ms: 0.044833
1110
+ duration_ms: 0.042167
1111
1111
  ...
1112
1112
  1..4
1113
1113
  ok 14 - Mock Response
1114
1114
  ---
1115
- duration_ms: 0.349125
1115
+ duration_ms: 0.348667
1116
1116
  ...
1117
1117
  # Subtest: Mock Redis
1118
1118
  # Subtest: get/set stores and retrieves values
1119
1119
  ok 1 - get/set stores and retrieves values
1120
1120
  ---
1121
- duration_ms: 0.110875
1121
+ duration_ms: 0.110625
1122
1122
  ...
1123
1123
  # Subtest: get returns null for missing keys
1124
1124
  ok 2 - get returns null for missing keys
1125
1125
  ---
1126
- duration_ms: 0.039
1126
+ duration_ms: 0.038083
1127
1127
  ...
1128
1128
  # Subtest: initialData pre-populates the store
1129
1129
  ok 3 - initialData pre-populates the store
1130
1130
  ---
1131
- duration_ms: 0.035792
1131
+ duration_ms: 0.035416
1132
1132
  ...
1133
1133
  # Subtest: del removes keys and returns count
1134
1134
  ok 4 - del removes keys and returns count
1135
1135
  ---
1136
- duration_ms: 0.060333
1136
+ duration_ms: 0.059917
1137
1137
  ...
1138
1138
  # Subtest: keys filters by prefix pattern
1139
1139
  ok 5 - keys filters by prefix pattern
1140
1140
  ---
1141
- duration_ms: 0.1545
1141
+ duration_ms: 0.153834
1142
1142
  ...
1143
1143
  # Subtest: incr increments numeric values
1144
1144
  ok 6 - incr increments numeric values
1145
1145
  ---
1146
- duration_ms: 0.052708
1146
+ duration_ms: 0.053875
1147
1147
  ...
1148
1148
  # Subtest: exists returns count of existing keys
1149
1149
  ok 7 - exists returns count of existing keys
1150
1150
  ---
1151
- duration_ms: 0.056583
1151
+ duration_ms: 0.057083
1152
1152
  ...
1153
1153
  # Subtest: pipeline batches commands
1154
1154
  ok 8 - pipeline batches commands
1155
1155
  ---
1156
- duration_ms: 0.110125
1156
+ duration_ms: 0.286458
1157
1157
  ...
1158
1158
  # Subtest: records all method calls
1159
1159
  ok 9 - records all method calls
1160
1160
  ---
1161
- duration_ms: 0.038958
1161
+ duration_ms: 0.096792
1162
1162
  ...
1163
1163
  # Subtest: reset clears store and calls
1164
1164
  ok 10 - reset clears store and calls
1165
1165
  ---
1166
- duration_ms: 0.050625
1166
+ duration_ms: 0.067417
1167
1167
  ...
1168
1168
  # Subtest: ping returns PONG
1169
1169
  ok 11 - ping returns PONG
1170
1170
  ---
1171
- duration_ms: 0.035041
1171
+ duration_ms: 0.043875
1172
1172
  ...
1173
1173
  1..11
1174
1174
  ok 15 - Mock Redis
1175
1175
  ---
1176
- duration_ms: 1.41575
1176
+ duration_ms: 1.6705
1177
1177
  ...
1178
1178
  # Subtest: captureConsole
1179
1179
  # Subtest: captures console output and restores
1180
1180
  ok 1 - captures console output and restores
1181
1181
  ---
1182
- duration_ms: 0.094375
1182
+ duration_ms: 0.133416
1183
1183
  ...
1184
1184
  # Subtest: captures info and debug
1185
1185
  ok 2 - captures info and debug
1186
1186
  ---
1187
- duration_ms: 0.038
1187
+ duration_ms: 0.0445
1188
1188
  ...
1189
1189
  1..2
1190
1190
  ok 16 - captureConsole
1191
1191
  ---
1192
- duration_ms: 0.197125
1192
+ duration_ms: 0.256
1193
1193
  ...
1194
1194
  # Subtest: createTestContext
1195
1195
  # Subtest: saves and restores env variables
1196
1196
  ok 1 - saves and restores env variables
1197
1197
  ---
1198
- duration_ms: 0.091209
1198
+ duration_ms: 0.101167
1199
1199
  ...
1200
1200
  # Subtest: deletes env var when set to undefined
1201
1201
  ok 2 - deletes env var when set to undefined
1202
1202
  ---
1203
- duration_ms: 0.048917
1203
+ duration_ms: 0.065875
1204
1204
  ...
1205
1205
  # Subtest: runs cleanup functions in LIFO order
1206
1206
  ok 3 - runs cleanup functions in LIFO order
1207
1207
  ---
1208
- duration_ms: 0.056875
1208
+ duration_ms: 0.06975
1209
1209
  ...
1210
1210
  # Subtest: cleanup runs async cleanup functions
1211
1211
  ok 4 - cleanup runs async cleanup functions
1212
1212
  ---
1213
- duration_ms: 11.051375
1213
+ duration_ms: 12.176542
1214
1214
  ...
1215
1215
  1..4
1216
1216
  ok 17 - createTestContext
1217
1217
  ---
1218
- duration_ms: 11.384916
1218
+ duration_ms: 12.569541
1219
1219
  ...
1220
1220
  # Subtest: waitFor
1221
1221
  # Subtest: resolves when assertion passes immediately
1222
1222
  ok 1 - resolves when assertion passes immediately
1223
1223
  ---
1224
- duration_ms: 0.074583
1224
+ duration_ms: 0.0725
1225
1225
  ...
1226
1226
  # Subtest: resolves when assertion eventually passes
1227
1227
  ok 2 - resolves when assertion eventually passes
1228
1228
  ---
1229
- duration_ms: 21.530291
1229
+ duration_ms: 21.538375
1230
1230
  ...
1231
1231
  # Subtest: throws last error on timeout
1232
1232
  ok 3 - throws last error on timeout
1233
1233
  ---
1234
- duration_ms: 110.640542
1234
+ duration_ms: 109.074833
1235
1235
  ...
1236
1236
  1..3
1237
1237
  ok 18 - waitFor
1238
1238
  ---
1239
- duration_ms: 132.498
1239
+ duration_ms: 130.950542
1240
1240
  ...
1241
1241
  # Subtest: assertThrows
1242
1242
  # Subtest: passes when async function throws expected error
1243
1243
  ok 1 - passes when async function throws expected error
1244
1244
  ---
1245
- duration_ms: 0.15625
1245
+ duration_ms: 0.239834
1246
1246
  ...
1247
1247
  # Subtest: fails when function does not throw
1248
1248
  ok 2 - fails when function does not throw
1249
1249
  ---
1250
- duration_ms: 0.297459
1250
+ duration_ms: 0.377541
1251
1251
  ...
1252
1252
  # Subtest: fails when error class does not match
1253
1253
  ok 3 - fails when error class does not match
1254
1254
  ---
1255
- duration_ms: 0.086583
1255
+ duration_ms: 0.101167
1256
1256
  ...
1257
1257
  # Subtest: fails when message pattern does not match
1258
1258
  ok 4 - fails when message pattern does not match
1259
1259
  ---
1260
- duration_ms: 0.116541
1260
+ duration_ms: 0.144084
1261
1261
  ...
1262
1262
  # Subtest: works with string message pattern
1263
1263
  ok 5 - works with string message pattern
1264
1264
  ---
1265
- duration_ms: 0.0435
1265
+ duration_ms: 0.050042
1266
1266
  ...
1267
1267
  # Subtest: works without ErrorClass (just message)
1268
1268
  ok 6 - works without ErrorClass (just message)
1269
1269
  ---
1270
- duration_ms: 0.042375
1270
+ duration_ms: 0.044459
1271
1271
  ...
1272
1272
  1..6
1273
1273
  ok 19 - assertThrows
1274
1274
  ---
1275
- duration_ms: 0.974333
1275
+ duration_ms: 1.231875
1276
1276
  ...
1277
1277
  # Subtest: Utils Module
1278
1278
  # Subtest: retryAsync succeeds on first attempt
1279
1279
  ok 1 - retryAsync succeeds on first attempt
1280
1280
  ---
1281
- duration_ms: 0.316708
1281
+ duration_ms: 0.321417
1282
1282
  ...
1283
1283
  # Subtest: retryAsync retries on failure
1284
1284
  ok 2 - retryAsync retries on failure
1285
1285
  ---
1286
- duration_ms: 32.389917
1286
+ duration_ms: 31.962417
1287
1287
  ...
1288
1288
  # Subtest: retryAsync throws after max attempts
1289
1289
  ok 3 - retryAsync throws after max attempts
1290
1290
  ---
1291
- duration_ms: 31.83275
1291
+ duration_ms: 31.149042
1292
1292
  ...
1293
1293
  # Subtest: sleep delays execution
1294
1294
  ok 4 - sleep delays execution
1295
1295
  ---
1296
- duration_ms: 51.634333
1296
+ duration_ms: 51.887167
1297
1297
  ...
1298
1298
  # Subtest: validateEnv checks required variables
1299
1299
  ok 5 - validateEnv checks required variables
1300
1300
  ---
1301
- duration_ms: 0.182375
1301
+ duration_ms: 0.131708
1302
1302
  ...
1303
1303
  # Subtest: validateEnv throws on missing variables
1304
1304
  ok 6 - validateEnv throws on missing variables
1305
1305
  ---
1306
- duration_ms: 0.149208
1306
+ duration_ms: 0.150417
1307
1307
  ...
1308
1308
  # Subtest: deepMerge merges objects
1309
1309
  ok 7 - deepMerge merges objects
1310
1310
  ---
1311
- duration_ms: 0.426375
1311
+ duration_ms: 0.415542
1312
1312
  ...
1313
1313
  # Subtest: deepMerge handles nested objects
1314
1314
  ok 8 - deepMerge handles nested objects
1315
1315
  ---
1316
- duration_ms: 0.222959
1316
+ duration_ms: 0.220333
1317
1317
  ...
1318
1318
  # Subtest: isObject identifies objects
1319
1319
  ok 9 - isObject identifies objects
1320
1320
  ---
1321
- duration_ms: 0.204666
1321
+ duration_ms: 0.20025
1322
1322
  ...
1323
1323
  # Subtest: normalizeErrorMessage handles various types
1324
1324
  ok 10 - normalizeErrorMessage handles various types
1325
1325
  ---
1326
- duration_ms: 0.147834
1326
+ duration_ms: 0.135334
1327
1327
  ...
1328
1328
  # Subtest: randomString generates random strings
1329
1329
  ok 11 - randomString generates random strings
1330
1330
  ---
1331
- duration_ms: 0.169959
1331
+ duration_ms: 0.168958
1332
1332
  ...
1333
1333
  # Subtest: randomString respects length parameter
1334
1334
  ok 12 - randomString respects length parameter
1335
1335
  ---
1336
- duration_ms: 0.047542
1336
+ duration_ms: 0.046125
1337
1337
  ...
1338
1338
  # Subtest: sanitizeId converts to valid IDs
1339
1339
  ok 13 - sanitizeId converts to valid IDs
1340
1340
  ---
1341
- duration_ms: 0.135167
1341
+ duration_ms: 0.12375
1342
1342
  ...
1343
1343
  # Subtest: formatBytes formats file sizes
1344
1344
  ok 14 - formatBytes formats file sizes
1345
1345
  ---
1346
- duration_ms: 0.05175
1346
+ duration_ms: 0.053291
1347
1347
  ...
1348
1348
  # Subtest: debounce delays function execution
1349
1349
  ok 15 - debounce delays function execution
1350
1350
  ---
1351
- duration_ms: 50.813583
1351
+ duration_ms: 51.01325
1352
1352
  ...
1353
1353
  # Subtest: memoize caches function results
1354
1354
  ok 16 - memoize caches function results
1355
1355
  ---
1356
- duration_ms: 0.155459
1356
+ duration_ms: 0.146458
1357
1357
  ...
1358
1358
  # Subtest: memoize respects TTL
1359
1359
  ok 17 - memoize respects TTL
1360
1360
  ---
1361
- duration_ms: 50.572083
1361
+ duration_ms: 50.514458
1362
1362
  ...
1363
1363
  1..17
1364
1364
  ok 20 - Utils Module
1365
1365
  ---
1366
- duration_ms: 221.208417
1366
+ duration_ms: 220.542041
1367
1367
  ...
1368
1368
  1..20
1369
1369
  # tests 227
@@ -1373,4 +1373,4 @@ ok 20 - Utils Module
1373
1373
  # cancelled 0
1374
1374
  # skipped 0
1375
1375
  # todo 0
1376
- # duration_ms 501.633584
1376
+ # duration_ms 497.736