@nxtedition/lib 21.2.1 → 21.3.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.
- package/couch.js +5 -1
- package/http.js +53 -48
- package/package.json +1 -2
package/couch.js
CHANGED
|
@@ -117,6 +117,7 @@ export function makeCouch(opts) {
|
|
|
117
117
|
* @param {number} [options.heartbeat=60000] - The interval at which to send a heartbeat.
|
|
118
118
|
* @param {function} [options.retry=null] - The function to retry the request on error.
|
|
119
119
|
* @param {string} [options.since=null] - The sequence number to start from.
|
|
120
|
+
* @param {string} [options.highWaterMark=128 * 1024] - Buffering.
|
|
120
121
|
* @yields {Array<{ id: string, seq?: string, doc?: Object, deleted?: boolean, changes: Array<{ rev: string }> }>}
|
|
121
122
|
*/
|
|
122
123
|
async function* changes({ client = defaultClient, signal = null, logger, ...options } = {}) {
|
|
@@ -207,6 +208,7 @@ export function makeCouch(opts) {
|
|
|
207
208
|
}
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
const highWaterMark = options.highWaterMark
|
|
210
212
|
const live = options.live == null || !!options.live
|
|
211
213
|
const retry =
|
|
212
214
|
options.retry ??
|
|
@@ -220,6 +222,7 @@ export function makeCouch(opts) {
|
|
|
220
222
|
method,
|
|
221
223
|
live,
|
|
222
224
|
retry,
|
|
225
|
+
highWaterMark,
|
|
223
226
|
params,
|
|
224
227
|
body,
|
|
225
228
|
signal: ac.signal,
|
|
@@ -245,6 +248,7 @@ export function makeCouch(opts) {
|
|
|
245
248
|
body,
|
|
246
249
|
signal,
|
|
247
250
|
client,
|
|
251
|
+
highWaterMark = 128 * 1024,
|
|
248
252
|
blocking = live || !params.limit || params.limit > 256,
|
|
249
253
|
}) {
|
|
250
254
|
let retryCount = 0
|
|
@@ -270,7 +274,7 @@ export function makeCouch(opts) {
|
|
|
270
274
|
signal,
|
|
271
275
|
headersTimeout: 2 * 60e3,
|
|
272
276
|
bodyTimeout: 2 * (params.heartbeat || 60e3),
|
|
273
|
-
highWaterMark
|
|
277
|
+
highWaterMark,
|
|
274
278
|
dispatcher: client,
|
|
275
279
|
}
|
|
276
280
|
|
package/http.js
CHANGED
|
@@ -7,10 +7,9 @@ import querystring from 'fast-querystring'
|
|
|
7
7
|
import compose from 'koa-compose'
|
|
8
8
|
import http from 'http'
|
|
9
9
|
import fp from 'lodash/fp.js'
|
|
10
|
-
import cookie from 'cookie'
|
|
11
10
|
import tp from 'timers/promises'
|
|
12
11
|
|
|
13
|
-
const kAbortController = Symbol('abortController')
|
|
12
|
+
export const kAbortController = Symbol('abortController')
|
|
14
13
|
|
|
15
14
|
const ERR_HEADER_EXPR =
|
|
16
15
|
/^(content-length|content-type|te|host|upgrade|trailers|connection|keep-alive|http2-settings|transfer-encoding|proxy-connection|proxy-authenticate|proxy-authorization)$/i
|
|
@@ -41,9 +40,7 @@ export class Context {
|
|
|
41
40
|
#ac
|
|
42
41
|
#url
|
|
43
42
|
#logger
|
|
44
|
-
#headers
|
|
45
43
|
#query
|
|
46
|
-
#cookies
|
|
47
44
|
|
|
48
45
|
constructor(req, res, logger) {
|
|
49
46
|
assert(req)
|
|
@@ -54,17 +51,10 @@ export class Context {
|
|
|
54
51
|
this.#req = req
|
|
55
52
|
this.#res = res
|
|
56
53
|
this.#logger = logger.child({ reqId: this.#id, url: req.url })
|
|
57
|
-
this.#headers = {
|
|
58
|
-
'request-id': this.#id,
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
setHeader(name, value) {
|
|
63
|
-
this.#headers[name.toLowerCase()] = value
|
|
64
54
|
}
|
|
65
55
|
|
|
66
|
-
|
|
67
|
-
|
|
56
|
+
get id() {
|
|
57
|
+
return this.#id
|
|
68
58
|
}
|
|
69
59
|
|
|
70
60
|
get [kAbortController]() {
|
|
@@ -82,8 +72,13 @@ export class Context {
|
|
|
82
72
|
}
|
|
83
73
|
|
|
84
74
|
set url(value) {
|
|
75
|
+
if (typeof value !== 'string') {
|
|
76
|
+
throw new Error('url must be a string')
|
|
77
|
+
}
|
|
78
|
+
|
|
85
79
|
this.#req.url = value
|
|
86
|
-
this.#url =
|
|
80
|
+
this.#url = undefined
|
|
81
|
+
this.#query = undefined
|
|
87
82
|
}
|
|
88
83
|
|
|
89
84
|
get query() {
|
|
@@ -108,18 +103,6 @@ export class Context {
|
|
|
108
103
|
get method() {
|
|
109
104
|
return this.#req.method
|
|
110
105
|
}
|
|
111
|
-
|
|
112
|
-
get headers() {
|
|
113
|
-
return this.#headers
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
get cookies() {
|
|
117
|
-
if (this.#cookies === undefined) {
|
|
118
|
-
this.#cookies = this.req.headers.cookie ? cookie.parse(this.req.headers.cookie) : null
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return this.#cookies
|
|
122
|
-
}
|
|
123
106
|
}
|
|
124
107
|
|
|
125
108
|
export async function request2(ctx, next) {
|
|
@@ -133,7 +116,9 @@ export async function request2(ctx, next) {
|
|
|
133
116
|
|
|
134
117
|
const isHealthcheck = req.url === '/healthcheck' || req.url === '/_up'
|
|
135
118
|
|
|
136
|
-
if (
|
|
119
|
+
if (isHealthcheck) {
|
|
120
|
+
// Do nothing...
|
|
121
|
+
} else {
|
|
137
122
|
logger.debug({ req }, 'request started')
|
|
138
123
|
}
|
|
139
124
|
|
|
@@ -160,12 +145,12 @@ export async function request2(ctx, next) {
|
|
|
160
145
|
ctx[kAbortController]?.abort(err)
|
|
161
146
|
|
|
162
147
|
const statusCode = err.statusCode || err.$metadata?.httpStatusCode || 500
|
|
163
|
-
const
|
|
148
|
+
const elapsedTime = Math.ceil(performance.now() - startTime)
|
|
164
149
|
|
|
165
150
|
if (!res.headersSent && !res.destroyed) {
|
|
166
151
|
res.statusCode = statusCode
|
|
167
152
|
|
|
168
|
-
let reqId = req?.id || err.id
|
|
153
|
+
let reqId = ctx.id || req?.id || err.id
|
|
169
154
|
for (const name of res.getHeaderNames()) {
|
|
170
155
|
if (!reqId && name === 'request-id') {
|
|
171
156
|
reqId = res.getHeader(name)
|
|
@@ -177,8 +162,20 @@ export async function request2(ctx, next) {
|
|
|
177
162
|
res.setHeader('request-id', reqId)
|
|
178
163
|
}
|
|
179
164
|
|
|
180
|
-
|
|
181
|
-
|
|
165
|
+
const { headers } = err
|
|
166
|
+
|
|
167
|
+
if (fp.isPlainObject(headers)) {
|
|
168
|
+
for (const [key, val] of Object.entries(headers)) {
|
|
169
|
+
if (!ERR_HEADER_EXPR.test(key)) {
|
|
170
|
+
res.setHeader(key, val)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} else if (Array.isArray(err.headers)) {
|
|
174
|
+
assert(headers.length % 2 === 0)
|
|
175
|
+
assert(headers.length === 0 || typeof headers[0] === 'string')
|
|
176
|
+
for (let n = 0; n < headers.length; n += 2) {
|
|
177
|
+
const key = headers[n + 0]
|
|
178
|
+
const val = headers[n + 1]
|
|
182
179
|
if (!ERR_HEADER_EXPR.test(key)) {
|
|
183
180
|
res.setHeader(key, val)
|
|
184
181
|
}
|
|
@@ -187,23 +184,27 @@ export async function request2(ctx, next) {
|
|
|
187
184
|
|
|
188
185
|
if (fp.isPlainObject(err.body)) {
|
|
189
186
|
res.setHeader('content-type', 'application/json')
|
|
190
|
-
res.
|
|
187
|
+
res.end(JSON.stringify(err.body))
|
|
188
|
+
} else if (typeof err.body === 'string') {
|
|
189
|
+
res.end(err.body)
|
|
190
|
+
} else if (Buffer.isBuffer(err.body)) {
|
|
191
|
+
res.end(err.body)
|
|
192
|
+
} else {
|
|
193
|
+
res.end()
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
if (statusCode < 500) {
|
|
194
|
-
logger.warn({ req, res, err,
|
|
197
|
+
logger.warn({ req, res, err, elapsedTime }, 'request failed')
|
|
195
198
|
} else {
|
|
196
|
-
logger.error({ req, res, err,
|
|
199
|
+
logger.error({ req, res, err, elapsedTime }, 'request error')
|
|
197
200
|
}
|
|
198
|
-
|
|
199
|
-
res.end()
|
|
200
201
|
} else {
|
|
201
202
|
if (req.aborted || !res.writableEnded || err.name === 'AbortError') {
|
|
202
|
-
logger.debug({ req, res, err,
|
|
203
|
+
logger.debug({ req, res, err, elapsedTime }, 'request aborted')
|
|
203
204
|
} else if (statusCode < 500) {
|
|
204
|
-
logger.warn({ req, res, err,
|
|
205
|
+
logger.warn({ req, res, err, elapsedTime }, 'request failed')
|
|
205
206
|
} else {
|
|
206
|
-
logger.error({ req, res, err,
|
|
207
|
+
logger.error({ req, res, err, elapsedTime }, 'request error')
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
if (!res.writableEnded) {
|
|
@@ -276,7 +277,7 @@ export async function request(ctx, next) {
|
|
|
276
277
|
ac?.abort(err)
|
|
277
278
|
|
|
278
279
|
const statusCode = err.statusCode || err.$metadata?.httpStatusCode || 500
|
|
279
|
-
const
|
|
280
|
+
const elapsedTime = Math.ceil(performance.now() - startTime)
|
|
280
281
|
|
|
281
282
|
if (!res.headersSent && !res.destroyed) {
|
|
282
283
|
res.statusCode = statusCode
|
|
@@ -303,23 +304,27 @@ export async function request(ctx, next) {
|
|
|
303
304
|
|
|
304
305
|
if (fp.isPlainObject(err.body)) {
|
|
305
306
|
res.setHeader('content-type', 'application/json')
|
|
306
|
-
res.
|
|
307
|
+
res.end(JSON.stringify(err.body))
|
|
308
|
+
} else if (typeof err.body === 'string') {
|
|
309
|
+
res.end(err.body)
|
|
310
|
+
} else if (Buffer.isBuffer(err.body)) {
|
|
311
|
+
res.end(err.body)
|
|
312
|
+
} else {
|
|
313
|
+
res.end()
|
|
307
314
|
}
|
|
308
315
|
|
|
309
316
|
if (statusCode < 500) {
|
|
310
|
-
reqLogger.warn({ res, err,
|
|
317
|
+
reqLogger.warn({ res, err, elapsedTime }, 'request failed')
|
|
311
318
|
} else {
|
|
312
|
-
reqLogger.error({ res, err,
|
|
319
|
+
reqLogger.error({ res, err, elapsedTime }, 'request error')
|
|
313
320
|
}
|
|
314
|
-
|
|
315
|
-
res.end()
|
|
316
321
|
} else {
|
|
317
322
|
if (req.aborted || !res.writableEnded || err.name === 'AbortError') {
|
|
318
|
-
reqLogger.debug({ res, err,
|
|
323
|
+
reqLogger.debug({ res, err, elapsedTime }, 'request aborted')
|
|
319
324
|
} else if (statusCode < 500) {
|
|
320
|
-
reqLogger.warn({ res, err,
|
|
325
|
+
reqLogger.warn({ res, err, elapsedTime }, 'request failed')
|
|
321
326
|
} else {
|
|
322
|
-
reqLogger.error({ res, err,
|
|
327
|
+
reqLogger.error({ res, err, elapsedTime }, 'request error')
|
|
323
328
|
}
|
|
324
329
|
|
|
325
330
|
if (!res.writableEnded) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxtedition/lib",
|
|
3
|
-
"version": "21.
|
|
3
|
+
"version": "21.3.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Robert Nagy <robert.nagy@boffins.se>",
|
|
6
6
|
"type": "module",
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"@elastic/transport": "^8.7.1",
|
|
60
60
|
"@nxtedition/nxt-undici": "^4.2.13",
|
|
61
61
|
"content-type": "^1.0.5",
|
|
62
|
-
"cookie": "^0.7.2",
|
|
63
62
|
"date-fns": "^3.6.0",
|
|
64
63
|
"fast-querystring": "^1.1.1",
|
|
65
64
|
"hasha": "^6.0.0",
|