@nxtedition/lib 23.3.17 → 23.3.19

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 (4) hide show
  1. package/errors.js +16 -13
  2. package/http.js +135 -129
  3. package/package.json +1 -1
  4. package/serializers.js +15 -25
package/errors.js CHANGED
@@ -123,19 +123,22 @@ function _serializeError(error, { depth }) {
123
123
 
124
124
  return [
125
125
  JSON.parse(
126
- JSON.stringify({
127
- ...properties,
128
- message: message ?? 'Unknown error',
129
- type: type !== 'Object' ? type : undefined,
130
- code: code ?? undefined,
131
- exitCode: exitCode ?? undefined,
132
- signalCode: signalCode ?? undefined,
133
- statusCode: statusCode ?? undefined,
134
- headers: headers ?? undefined,
135
- data: data ?? undefined,
136
- cause: cause ?? undefined,
137
- errors: fp.isEmpty(errors) ? undefined : undefined,
138
- }),
126
+ JSON.stringify(
127
+ {
128
+ ...properties,
129
+ message: message ?? 'Unknown error',
130
+ type: type !== 'Object' ? type : undefined,
131
+ code: code ?? undefined,
132
+ exitCode: exitCode ?? undefined,
133
+ signalCode: signalCode ?? undefined,
134
+ statusCode: statusCode ?? undefined,
135
+ headers: headers ?? undefined,
136
+ data: data ?? undefined,
137
+ cause: cause ?? undefined,
138
+ errors: fp.isEmpty(errors) ? undefined : undefined,
139
+ },
140
+ (k, v) => (typeof v === 'bigint' ? v.toString() : v),
141
+ ),
139
142
  ),
140
143
  ]
141
144
  }
package/http.js CHANGED
@@ -251,135 +251,6 @@ export async function requestMiddleware(ctx, next) {
251
251
  }
252
252
  }
253
253
 
254
- export async function request(ctx, next) {
255
- const { req, res, logger } = ctx
256
- const startTime = performance.now()
257
-
258
- const ac = ctx.signal !== undefined ? null : new AbortController()
259
-
260
- let reqLogger = logger
261
-
262
- pendingSet.add(ctx)
263
- try {
264
- ctx.url = requestTarget(req)
265
- if (!ctx.url) {
266
- throw new createError.BadRequest('invalid url')
267
- }
268
-
269
- ctx.id = req.id = res.id = req.headers['request-id'] || genReqId()
270
- ctx.userAgent = req['user-agent'] || req['User-Agent'] || ''
271
- ctx.method = req.method
272
- ctx.query = ctx.url.search.length > 1 ? querystring.parse(ctx.url.search.slice(1)) : {}
273
- ctx.logger =
274
- req.log =
275
- res.log =
276
- logger.child({ req: { id: req.id, url: req.url, userAgent: ctx.userAgent } })
277
-
278
- if (ac) {
279
- ctx.signal = ac.signal
280
- }
281
-
282
- if (req.method === 'GET' || req.method === 'HEAD') {
283
- req.resume() // Dump the body if there is one.
284
- }
285
-
286
- res.setHeader('request-id', req.id)
287
-
288
- const isHealthcheck = ctx.url.pathname === '/healthcheck' || ctx.url.pathname === '/_up'
289
-
290
- reqLogger = logger.child({ req })
291
- if (!isHealthcheck) {
292
- reqLogger.debug('request started')
293
- }
294
-
295
- const nextPromise = next()
296
- const responsePromise = new Promise((resolve, reject) => {
297
- res.on('timeout', onTimeout).on('error', reject).on('close', resolve)
298
- })
299
-
300
- if (nextPromise) {
301
- await Promise.all([nextPromise, responsePromise])
302
- } else if (!res.closed) {
303
- await responsePromise
304
- }
305
-
306
- const elapsedTime = performance.now() - startTime
307
-
308
- if (isHealthcheck) {
309
- // Do nothing...
310
- } else if (!res.writableEnded) {
311
- reqLogger.debug({ res, elapsedTime }, 'request aborted')
312
- } else if (res.statusCode >= 500) {
313
- reqLogger.error({ res, elapsedTime }, 'request error')
314
- } else if (res.statusCode >= 400) {
315
- reqLogger.warn({ res, elapsedTime }, 'request failed')
316
- } else {
317
- reqLogger.debug({ res, elapsedTime }, 'request completed')
318
- }
319
- } catch (err) {
320
- ac?.abort(err)
321
-
322
- const statusCode = err.statusCode || err.$metadata?.httpStatusCode || 500
323
- const elapsedTime = performance.now() - startTime
324
-
325
- if (!res.headersSent && !res.destroyed) {
326
- res.statusCode = statusCode
327
-
328
- let reqId = req?.id || err.id
329
- for (const name of res.getHeaderNames()) {
330
- if (!reqId && name === 'request-id') {
331
- reqId = res.getHeader(name)
332
- }
333
- res.removeHeader(name)
334
- }
335
-
336
- if (reqId) {
337
- res.setHeader('request-id', reqId)
338
- }
339
-
340
- if (fp.isPlainObject(err.headers)) {
341
- for (const [key, val] of Object.entries(err.headers)) {
342
- if (!ERR_HEADER_EXPR.test(key)) {
343
- res.setHeader(key, val)
344
- }
345
- }
346
- }
347
-
348
- if (fp.isPlainObject(err.body)) {
349
- res.setHeader('content-type', 'application/json')
350
- res.end(JSON.stringify(err.body))
351
- } else if (typeof err.body === 'string') {
352
- res.end(err.body)
353
- } else if (Buffer.isBuffer(err.body)) {
354
- res.end(err.body)
355
- } else {
356
- res.end()
357
- }
358
-
359
- if (statusCode < 500) {
360
- reqLogger.warn({ res, err, elapsedTime }, 'request failed')
361
- } else {
362
- reqLogger.error({ res, err, elapsedTime }, 'request error')
363
- }
364
- } else {
365
- if (req.aborted || !res.writableEnded || err.name === 'AbortError') {
366
- reqLogger.debug({ res, err, elapsedTime }, 'request aborted')
367
- } else if (statusCode < 500) {
368
- reqLogger.warn({ res, err, elapsedTime }, 'request failed')
369
- } else {
370
- reqLogger.error({ res, err, elapsedTime }, 'request error')
371
- }
372
- }
373
- } finally {
374
- pendingSet.delete(ctx)
375
-
376
- if (!res.writableEnded) {
377
- res.destroy()
378
- logger.debug('request destroyed')
379
- }
380
- }
381
- }
382
-
383
254
  export class ServerResponse extends http.ServerResponse {
384
255
  #created = 0
385
256
  #bytesWritten = 0
@@ -570,6 +441,137 @@ export class Http2ServerResponse extends http2.Http2ServerResponse {
570
441
  }
571
442
  }
572
443
 
444
+ /** @deprecated */
445
+ export async function request(ctx, next) {
446
+ const { req, res, logger } = ctx
447
+ const startTime = performance.now()
448
+
449
+ const ac = ctx.signal !== undefined ? null : new AbortController()
450
+
451
+ let reqLogger = logger
452
+
453
+ pendingSet.add(ctx)
454
+ try {
455
+ ctx.url = requestTarget(req)
456
+ if (!ctx.url) {
457
+ throw new createError.BadRequest('invalid url')
458
+ }
459
+
460
+ ctx.id = req.id = res.id = req.headers['request-id'] || genReqId()
461
+ ctx.userAgent = req['user-agent'] || req['User-Agent'] || ''
462
+ ctx.method = req.method
463
+ ctx.query = ctx.url.search.length > 1 ? querystring.parse(ctx.url.search.slice(1)) : {}
464
+ ctx.logger =
465
+ req.log =
466
+ res.log =
467
+ logger.child({ req: { id: req.id, url: req.url, userAgent: ctx.userAgent } })
468
+
469
+ if (ac) {
470
+ ctx.signal = ac.signal
471
+ }
472
+
473
+ if (req.method === 'GET' || req.method === 'HEAD') {
474
+ req.resume() // Dump the body if there is one.
475
+ }
476
+
477
+ res.setHeader('request-id', req.id)
478
+
479
+ const isHealthcheck = ctx.url.pathname === '/healthcheck' || ctx.url.pathname === '/_up'
480
+
481
+ reqLogger = logger.child({ req })
482
+ if (!isHealthcheck) {
483
+ reqLogger.debug('request started')
484
+ }
485
+
486
+ const nextPromise = next()
487
+ const responsePromise = new Promise((resolve, reject) => {
488
+ res.on('timeout', onTimeout).on('error', reject).on('close', resolve)
489
+ })
490
+
491
+ if (nextPromise) {
492
+ await Promise.all([nextPromise, responsePromise])
493
+ } else if (!res.closed) {
494
+ await responsePromise
495
+ }
496
+
497
+ const elapsedTime = performance.now() - startTime
498
+
499
+ if (isHealthcheck) {
500
+ // Do nothing...
501
+ } else if (!res.writableEnded) {
502
+ reqLogger.debug({ res, elapsedTime }, 'request aborted')
503
+ } else if (res.statusCode >= 500) {
504
+ reqLogger.error({ res, elapsedTime }, 'request error')
505
+ } else if (res.statusCode >= 400) {
506
+ reqLogger.warn({ res, elapsedTime }, 'request failed')
507
+ } else {
508
+ reqLogger.debug({ res, elapsedTime }, 'request completed')
509
+ }
510
+ } catch (err) {
511
+ ac?.abort(err)
512
+
513
+ const statusCode = err.statusCode || err.$metadata?.httpStatusCode || 500
514
+ const elapsedTime = performance.now() - startTime
515
+
516
+ if (!res.headersSent && !res.destroyed) {
517
+ res.statusCode = statusCode
518
+
519
+ let reqId = req?.id || err.id
520
+ for (const name of res.getHeaderNames()) {
521
+ if (!reqId && name === 'request-id') {
522
+ reqId = res.getHeader(name)
523
+ }
524
+ res.removeHeader(name)
525
+ }
526
+
527
+ if (reqId) {
528
+ res.setHeader('request-id', reqId)
529
+ }
530
+
531
+ if (fp.isPlainObject(err.headers)) {
532
+ for (const [key, val] of Object.entries(err.headers)) {
533
+ if (!ERR_HEADER_EXPR.test(key)) {
534
+ res.setHeader(key, val)
535
+ }
536
+ }
537
+ }
538
+
539
+ if (fp.isPlainObject(err.body)) {
540
+ res.setHeader('content-type', 'application/json')
541
+ res.end(JSON.stringify(err.body))
542
+ } else if (typeof err.body === 'string') {
543
+ res.end(err.body)
544
+ } else if (Buffer.isBuffer(err.body)) {
545
+ res.end(err.body)
546
+ } else {
547
+ res.end()
548
+ }
549
+
550
+ if (statusCode < 500) {
551
+ reqLogger.warn({ res, err, elapsedTime }, 'request failed')
552
+ } else {
553
+ reqLogger.error({ res, err, elapsedTime }, 'request error')
554
+ }
555
+ } else {
556
+ if (req.aborted || !res.writableEnded || err.name === 'AbortError') {
557
+ reqLogger.debug({ res, err, elapsedTime }, 'request aborted')
558
+ } else if (statusCode < 500) {
559
+ reqLogger.warn({ res, err, elapsedTime }, 'request failed')
560
+ } else {
561
+ reqLogger.error({ res, err, elapsedTime }, 'request error')
562
+ }
563
+ }
564
+ } finally {
565
+ pendingSet.delete(ctx)
566
+
567
+ if (!res.writableEnded) {
568
+ res.destroy()
569
+ logger.debug('request destroyed')
570
+ }
571
+ }
572
+ }
573
+
574
+ /** @deprecated */
573
575
  export function createServer(options, ctx, middleware) {
574
576
  middleware = Array.isArray(middleware) ? middleware : [middleware]
575
577
  middleware = fp.values(middleware)
@@ -598,6 +600,7 @@ export function createServer(options, ctx, middleware) {
598
600
  return server
599
601
  }
600
602
 
603
+ /** @deprecated */
601
604
  export async function upgrade(ctx, next) {
602
605
  const { req, res, socket = res, logger } = ctx
603
606
 
@@ -674,6 +677,7 @@ export async function upgrade(ctx, next) {
674
677
  }
675
678
  }
676
679
 
680
+ /** @deprecated */
677
681
  export function isConnectionError(err) {
678
682
  // AWS compat.
679
683
  const statusCode = err?.statusCode ?? err?.$metadata?.httpStatusCode
@@ -696,6 +700,7 @@ export function isConnectionError(err) {
696
700
  : false
697
701
  }
698
702
 
703
+ /** @deprecated */
699
704
  export function defaultDelay(err, retryCount, options) {
700
705
  const { signal, logger = null } = options ?? {}
701
706
  if (isConnectionError(err)) {
@@ -708,6 +713,7 @@ export function defaultDelay(err, retryCount, options) {
708
713
  }
709
714
  }
710
715
 
716
+ /** @deprecated */
711
717
  export async function retry(fn, options) {
712
718
  const { maxRetries = 8, count = maxRetries, delay = defaultDelay, signal } = options ?? {}
713
719
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "23.3.17",
3
+ "version": "23.3.19",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "type": "module",
package/serializers.js CHANGED
@@ -214,34 +214,24 @@ Object.defineProperty(pinoErrProto, rawSymbol, {
214
214
  value: {},
215
215
  })
216
216
 
217
- function copyAndReplaceBigInts(obj) {
218
- if (typeof obj === 'bigint') {
219
- return obj.toString()
220
- }
221
-
222
- if (Array.isArray(obj)) {
223
- return obj.map(copyAndReplaceBigInts)
217
+ function errSerializer(err) {
218
+ if (Array.isArray(err)) {
219
+ return err.length === 0 ? undefined : errSerializer({ message: '', errors: err })
224
220
  }
225
221
 
226
- if (obj !== null && typeof obj === 'object') {
227
- const dst = {}
228
- for (const [key, value] of Object.entries(obj)) {
229
- dst[key] = copyAndReplaceBigInts(value)
230
- }
231
- return dst
222
+ if (!isErrorLike(err)) {
223
+ return undefined
232
224
  }
233
225
 
234
- return obj
235
- }
226
+ const errors = Array.isArray(err?.errors)
227
+ ? err.errors.map((err) => errSerializer(err)).filter(Boolean)
228
+ : null
236
229
 
237
- function errSerializer(err) {
238
- if (Array.isArray(err)) {
239
- return err.length === 0 ? undefined : errSerializer({ message: '', errors: err })
240
- } else if (!isErrorLike(err)) {
230
+ if (err.message === '' && errors != null && errors.length === 0) {
241
231
  return undefined
242
- } else if (err.message === '' && Array.isArray(err.errors) && err.errors.length === 0) {
243
- return undefined
244
- } else if (err.message === '' && Array.isArray(err.errors) && err.errors.length === 1) {
232
+ }
233
+
234
+ if (err.message === '' && errors != null && errors.length === 1) {
245
235
  return errSerializer(err.errors[0])
246
236
  }
247
237
 
@@ -253,8 +243,8 @@ function errSerializer(err) {
253
243
  _err.message = err.message
254
244
  _err.stack = err.stack
255
245
 
256
- if (Array.isArray(err.errors)) {
257
- _err.aggregateErrors = err.errors.map((err) => errSerializer(err))
246
+ if (errors != null) {
247
+ _err.aggregateErrors = errors
258
248
  }
259
249
 
260
250
  if (isErrorLike(err.cause) && !Object.prototype.hasOwnProperty.call(err.cause, seen)) {
@@ -271,7 +261,7 @@ function errSerializer(err) {
271
261
  } else if (typeof val === 'bigint') {
272
262
  _err[key] = `${val.toString()}`
273
263
  } else if (val != null && !/^[A-Z0-9_]+$/.test(key)) {
274
- _err[key] = copyAndReplaceBigInts(val)
264
+ _err[key] = val
275
265
  }
276
266
  }
277
267
  }