@nxtedition/lib 15.0.53 → 15.0.54

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 (2) hide show
  1. package/http.js +44 -39
  2. package/package.json +9 -9
package/http.js CHANGED
@@ -2,7 +2,6 @@ const createError = require('http-errors')
2
2
  const { performance } = require('perf_hooks')
3
3
  const requestTarget = require('request-target')
4
4
  const querystring = require('fast-querystring')
5
- const assert = require('assert')
6
5
  const compose = require('koa-compose')
7
6
  const http = require('http')
8
7
  const fp = require('lodash/fp')
@@ -24,6 +23,31 @@ function genReqId() {
24
23
  return `req-${nextReqId.toString(36)}`
25
24
  }
26
25
 
26
+ const kResolve = Symbol('resolve')
27
+
28
+ function onTimeout() {
29
+ this.destroy(new createError.RequestTimeout())
30
+ }
31
+
32
+ function onRequestError(err) {
33
+ this.log.error({ err }, 'request error')
34
+ }
35
+
36
+ function onRequestClose() {
37
+ this.log.debug('request closed')
38
+ this[kResolve](null)
39
+ }
40
+
41
+ function onResponseError(err) {
42
+ this.log.error({ err }, 'response error')
43
+ this[kResolve](Promise.reject(err))
44
+ }
45
+
46
+ function onResponseClose() {
47
+ this.log.debug('response closed')
48
+ this[kResolve](null)
49
+ }
50
+
27
51
  module.exports.request = async function request(ctx, next) {
28
52
  const { req, res, logger } = ctx
29
53
  const startTime = performance.now()
@@ -39,10 +63,10 @@ module.exports.request = async function request(ctx, next) {
39
63
  }
40
64
 
41
65
  ctx.id = req.id = req.headers['request-id'] || genReqId()
42
- ctx.logger = req.log = logger.child({ req })
66
+ ctx.logger = req.log = res.log = logger.child({ req })
43
67
  ctx.signal = signal
44
68
  ctx.method = req.method
45
- ctx.query = ctx.url.search ? querystring.parse(ctx.url.search.slice(1)) : {}
69
+ ctx.query = ctx.url.search.length > 1 ? querystring.parse(ctx.url.search.slice(1)) : {}
46
70
 
47
71
  if (req.method === 'GET' || req.method === 'HEAD') {
48
72
  req.resume() // Dump the body if there is one.
@@ -54,55 +78,34 @@ module.exports.request = async function request(ctx, next) {
54
78
 
55
79
  reqLogger = ctx.logger
56
80
  if (!isHealthcheck) {
57
- reqLogger.debug({ req }, 'request started')
81
+ reqLogger.debug('request started')
58
82
  } else {
59
- reqLogger.trace({ req }, 'request started')
83
+ reqLogger.trace('request started')
60
84
  }
61
85
 
62
86
  await Promise.all([
63
87
  next(),
64
- new Promise((resolve, reject) => {
65
- res
66
- .on('timeout', function () {
67
- this.destroy(new createError.RequestTimeout())
68
- })
69
- .on('error', function (err) {
70
- reqLogger.error({ err }, 'response error')
71
- reject(err)
72
- })
73
- .on('close', function () {
74
- reqLogger.debug('response closed')
75
- resolve(null)
76
- })
77
- req
78
- .on('timeout', function () {
79
- this.destroy(new createError.RequestTimeout())
80
- })
81
- .on('error', function (err) {
82
- reqLogger.error({ err }, 'request error')
83
- })
84
- .on('close', function () {
85
- reqLogger.debug('request closed')
86
- })
88
+ new Promise((resolve) => {
89
+ res[kResolve] = resolve
90
+
91
+ res.on('timeout', onTimeout).on('error', onResponseError).on('close', onResponseClose)
92
+
93
+ req.on('timeout', onTimeout).on('error', onRequestError).on('close', onRequestClose)
87
94
  }),
88
95
  ])
89
96
 
90
- assert(req.aborted || res.writableEnded)
91
-
92
97
  const responseTime = Math.round(performance.now() - startTime)
93
98
 
94
- reqLogger = reqLogger.child({ res, responseTime })
95
-
96
- if (req.aborted) {
97
- reqLogger.debug('request aborted')
99
+ if (!res.writableEnded) {
100
+ reqLogger.debug({ res, responseTime }, 'request aborted')
98
101
  } else if (res.statusCode >= 500) {
99
- reqLogger.error('request error')
102
+ reqLogger.error({ res, responseTime }, 'request error')
100
103
  } else if (res.statusCode >= 400) {
101
- reqLogger.warn('request failed')
104
+ reqLogger.warn({ res, responseTime }, 'request failed')
102
105
  } else if (!isHealthcheck) {
103
- reqLogger.debug('request completed')
106
+ reqLogger.debug({ res, responseTime }, 'request completed')
104
107
  } else {
105
- reqLogger.trace('request completed')
108
+ reqLogger.trace({ res, responseTime }, 'request completed')
106
109
  }
107
110
 
108
111
  ac.abort()
@@ -162,7 +165,7 @@ module.exports.request = async function request(ctx, next) {
162
165
  } else {
163
166
  reqLogger = reqLogger.child({ res, err, reason, responseTime })
164
167
 
165
- if (req.aborted || err.name === 'AbortError') {
168
+ if (req.aborted || !res.writableEnded || err.name === 'AbortError') {
166
169
  reqLogger.debug('request aborted')
167
170
  } else if (err.statusCode < 500) {
168
171
  reqLogger.warn('request failed')
@@ -179,6 +182,8 @@ module.exports.request = async function request(ctx, next) {
179
182
  }
180
183
 
181
184
  ac.abort(err)
185
+ } finally {
186
+ res.destroy()
182
187
  }
183
188
  }
184
189
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "15.0.53",
3
+ "version": "15.0.54",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "files": [
@@ -81,7 +81,7 @@
81
81
  "lodash": "^4.17.21",
82
82
  "mime": "^3.0.0",
83
83
  "moment-timezone": "^0.5.43",
84
- "nconf": "^0.12.0",
84
+ "nconf": "^0.12.1",
85
85
  "nested-error-stacks": "^2.1.1",
86
86
  "object-hash": "^3.0.0",
87
87
  "pino-std-serializers": "^6.2.2",
@@ -90,25 +90,25 @@
90
90
  "smpte-timecode": "^1.3.3",
91
91
  "split-string": "^6.0.0",
92
92
  "toobusy-js": "^0.5.1",
93
- "undici": "^5.25.4",
93
+ "undici": "^5.27.1",
94
94
  "url-join": "^4.0.0"
95
95
  },
96
96
  "devDependencies": {
97
- "@types/node": "^20.8.2",
98
- "eslint": "^8.50.0",
97
+ "@types/node": "^20.8.10",
98
+ "eslint": "^8.52.0",
99
99
  "eslint-config-prettier": "^9.0.0",
100
100
  "eslint-config-standard": "^17.0.0",
101
- "eslint-plugin-import": "^2.28.1",
102
- "eslint-plugin-n": "^16.1.0",
101
+ "eslint-plugin-import": "^2.29.0",
102
+ "eslint-plugin-n": "^16.2.0",
103
103
  "eslint-plugin-node": "^11.1.0",
104
104
  "eslint-plugin-promise": "^6.0.0",
105
105
  "husky": "^8.0.3",
106
- "lint-staged": "^14.0.1",
106
+ "lint-staged": "^15.0.2",
107
107
  "pinst": "^3.0.0",
108
108
  "prettier": "^3.0.3",
109
109
  "rxjs": "^7.5.6",
110
110
  "send": "^0.18.0",
111
- "tap": "^18.4.2"
111
+ "tap": "^18.5.6"
112
112
  },
113
113
  "peerDependencies": {
114
114
  "@elastic/elasticsearch": "^8.6.0",