@nxtedition/lib 15.0.34 → 15.0.36

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.
@@ -1,163 +0,0 @@
1
- const assert = require('node:assert')
2
- const { parseContentRange, isDisturbed, findHeader, retry: retryFn } = require('../utils.js')
3
-
4
- class Handler {
5
- constructor(opts, { dispatch, handler }) {
6
- this.dispatch = dispatch
7
- this.handler = handler
8
- this.opts = opts
9
- this.abort = null
10
- this.aborted = false
11
- this.reason = null
12
-
13
- this.count = 0
14
- this.pos = 0
15
- this.end = null
16
- this.error = null
17
- this.etag = null
18
-
19
- this.handler.onConnect?.((reason) => {
20
- this.aborted = true
21
- if (this.abort) {
22
- this.abort(reason)
23
- } else {
24
- this.reason = reason
25
- }
26
- })
27
- }
28
-
29
- onConnect(abort) {
30
- if (this.aborted) {
31
- abort(this.reason)
32
- } else {
33
- this.abort = abort
34
- }
35
- }
36
-
37
- onUpgrade(statusCode, rawHeaders, socket) {
38
- return this.handler.onUpgrade?.(statusCode, rawHeaders, socket)
39
- }
40
-
41
- onBodySent(chunk) {
42
- return this.handler.onBodySent?.(chunk)
43
- }
44
-
45
- onHeaders(statusCode, rawHeaders, resume, statusMessage) {
46
- const etag = findHeader(rawHeaders, 'etag')
47
-
48
- if (this.resume) {
49
- this.resume = null
50
-
51
- // TODO (fix): Support other statusCode with skip?
52
- if (statusCode !== 206) {
53
- throw this.error
54
- }
55
-
56
- // TODO (fix): strict vs weak etag?
57
- if (this.etag == null || this.etag !== etag) {
58
- throw this.error
59
- }
60
-
61
- const contentRange = parseContentRange(findHeader(rawHeaders, 'content-range'))
62
- if (!contentRange) {
63
- throw this.error
64
- }
65
-
66
- const { start, size, end = size } = contentRange
67
-
68
- assert(this.pos === start, 'content-range mismatch')
69
- assert(this.end == null || this.end === end, 'content-range mismatch')
70
-
71
- this.resume = resume
72
- return true
73
- }
74
-
75
- if (this.end == null) {
76
- if (statusCode === 206) {
77
- const contentRange = parseContentRange(findHeader(rawHeaders, 'content-range'))
78
- if (!contentRange) {
79
- return this.handler.onHeaders?.(
80
- statusCode,
81
- rawHeaders,
82
- () => this.resume(),
83
- statusMessage,
84
- )
85
- }
86
-
87
- const { start, size, end = size } = contentRange
88
-
89
- this.end = end
90
- this.pos = Number(start)
91
- } else {
92
- const contentLength = findHeader(rawHeaders, 'content-length')
93
- if (contentLength) {
94
- this.end = Number(contentLength)
95
- }
96
- }
97
-
98
- assert(Number.isFinite(this.pos))
99
- assert(this.end == null || Number.isFinite(this.end), 'invalid content-length')
100
- }
101
-
102
- this.etag = etag
103
- this.resume = resume
104
- return this.handler.onHeaders?.(statusCode, rawHeaders, () => this.resume(), statusMessage)
105
- }
106
-
107
- onData(chunk) {
108
- this.pos += chunk.length
109
- this.count = 0
110
- return this.handler.onData?.(chunk)
111
- }
112
-
113
- onComplete(rawTrailers) {
114
- return this.handler.onComplete?.(rawTrailers)
115
- }
116
-
117
- onError(err) {
118
- if (this.timeout) {
119
- clearTimeout(this.timeout)
120
- this.timeout = null
121
- }
122
-
123
- if (!this.resume || this.aborted || !this.etag || isDisturbed(this.opts.body)) {
124
- return this.handler.onError?.(err)
125
- }
126
-
127
- const retryPromise = retryFn(err, this.count++, this.opts)
128
- if (retryPromise == null) {
129
- return this.handler.onError?.(err)
130
- }
131
-
132
- retryPromise
133
- .then(() => {
134
- this.timeout = null
135
- try {
136
- this.dispatch(this.opts, this)
137
- } catch (err2) {
138
- this.handler.onError?.(err)
139
- }
140
- })
141
- .catch((err) => {
142
- this.handler.onError?.(err)
143
- })
144
-
145
- this.error = err
146
- this.opts = {
147
- ...this.opts,
148
- headers: {
149
- ...this.opts.headers,
150
- 'if-match': this.etag,
151
- range: `bytes=${this.pos}-${this.end ?? ''}`,
152
- },
153
- }
154
-
155
- this.opts.logger?.debug('retrying response body')
156
- }
157
- }
158
-
159
- module.exports = (dispatch) => (opts, handler) => {
160
- return opts.idempotent && opts.retry && opts.method === 'GET'
161
- ? dispatch(opts, new Handler(opts, { handler, dispatch }))
162
- : dispatch(opts, handler)
163
- }
@@ -1,89 +0,0 @@
1
- const { isDisturbed, retry: retryFn } = require('../utils.js')
2
-
3
- class Handler {
4
- constructor(opts, { dispatch, handler }) {
5
- this.dispatch = dispatch
6
- this.handler = handler
7
- this.opts = opts
8
- this.abort = null
9
- this.aborted = false
10
- this.reason = null
11
- this.timeout = null
12
- this.count = 0
13
- this.retryAfter = null
14
-
15
- this.handler.onConnect?.((reason) => {
16
- this.aborted = true
17
- if (this.abort) {
18
- this.abort(reason)
19
- } else {
20
- this.reason = reason
21
- }
22
- })
23
- }
24
-
25
- onConnect(abort) {
26
- if (this.aborted) {
27
- abort(this.reason)
28
- } else {
29
- this.abort = abort
30
- }
31
- }
32
-
33
- onUpgrade(statusCode, rawHeaders, socket) {
34
- return this.handler.onUpgrade?.(statusCode, rawHeaders, socket)
35
- }
36
-
37
- onBodySent(chunk) {
38
- return this.handler.onBodySent?.(chunk)
39
- }
40
-
41
- onHeaders(statusCode, rawHeaders, resume, statusMessage) {
42
- this.aborted = true
43
- return this.handler.onHeaders?.(statusCode, rawHeaders, resume, statusMessage)
44
- }
45
-
46
- onData(chunk) {
47
- return this.handler.onData?.(chunk)
48
- }
49
-
50
- onComplete(rawTrailers) {
51
- return this.handler.onComplete?.(rawTrailers)
52
- }
53
-
54
- onError(err) {
55
- if (this.timeout) {
56
- clearTimeout(this.timeout)
57
- this.timeout = null
58
- }
59
-
60
- if (this.aborted || isDisturbed(this.opts.body)) {
61
- return this.handler.onError?.(err)
62
- }
63
-
64
- const retryPromise = retryFn(err, this.count++, this.opts)
65
- if (retryPromise == null) {
66
- return this.handler.onError?.(err)
67
- }
68
-
69
- retryPromise
70
- .then(() => {
71
- this.timeout = null
72
- try {
73
- this.dispatch(this.opts, this)
74
- } catch (err2) {
75
- this.handler.onError?.(err)
76
- }
77
- })
78
- .catch((err) => {
79
- this.handler.onError?.(err)
80
- })
81
-
82
- this.opts.logger?.debug('retrying response')
83
- }
84
- }
85
-
86
- module.exports = (dispatch) => (opts, handler) =>
87
- opts.idempotent && opts.retry
88
- ? dispatch(opts, new Handler(opts, { handler, dispatch }))
89
- : dispatch(opts, handler)
@@ -1,104 +0,0 @@
1
- const { isDisturbed, retry: retryFn } = require('../utils')
2
- const createError = require('http-errors')
3
- const { parseHeaders } = require('../../../http')
4
-
5
- class Handler {
6
- constructor(opts, { dispatch, handler }) {
7
- this.dispatch = dispatch
8
- this.handler = handler
9
- this.opts = opts
10
- this.abort = null
11
- this.aborted = false
12
- this.reason = null
13
-
14
- this.timeout = null
15
- this.count = 0
16
- this.retryPromise = null
17
-
18
- this.handler.onConnect?.((reason) => {
19
- this.aborted = true
20
- if (this.abort) {
21
- this.abort(reason)
22
- } else {
23
- this.reason = reason
24
- }
25
- })
26
- }
27
-
28
- onConnect(abort) {
29
- if (this.aborted) {
30
- abort(this.reason)
31
- } else {
32
- this.abort = abort
33
- }
34
- }
35
-
36
- onUpgrade(statusCode, rawHeaders, socket) {
37
- return this.handler.onUpgrade?.(statusCode, rawHeaders, socket)
38
- }
39
-
40
- onBodySent(chunk) {
41
- return this.handler.onBodySent?.(chunk)
42
- }
43
-
44
- onHeaders(statusCode, rawHeaders, resume, statusMessage) {
45
- if (statusCode < 400) {
46
- return this.handler.onHeaders?.(statusCode, rawHeaders, resume, statusMessage)
47
- }
48
-
49
- const err = createError(statusCode, { headers: parseHeaders(rawHeaders) })
50
-
51
- const retryPromise = retryFn(err, this.count++, this.opts)
52
- if (retryPromise == null) {
53
- return this.handler.onHeaders?.(statusCode, rawHeaders, resume, statusMessage)
54
- }
55
-
56
- retryPromise.catch(() => {})
57
-
58
- this.retryPromise = retryPromise
59
-
60
- this.abort(err)
61
-
62
- return false
63
- }
64
-
65
- onData(chunk) {
66
- return this.handler.onData?.(chunk)
67
- }
68
-
69
- onComplete(rawTrailers) {
70
- return this.handler.onComplete?.(rawTrailers)
71
- }
72
-
73
- onError(err) {
74
- if (this.timeout) {
75
- clearTimeout(this.timeout)
76
- this.timeout = null
77
- }
78
-
79
- if (this.retryPromise == null || this.aborted || isDisturbed(this.opts.body)) {
80
- return this.handler.onError?.(err)
81
- }
82
-
83
- this.retryPromise
84
- .then(() => {
85
- this.timeout = null
86
- try {
87
- this.dispatch(this.opts, this)
88
- } catch (err) {
89
- this.handler.onError?.(err)
90
- }
91
- })
92
- .catch((err) => {
93
- this.handler.onError?.(err)
94
- })
95
- this.retryPromise = null
96
-
97
- this.opts.logger?.debug('retrying response status')
98
- }
99
- }
100
-
101
- module.exports = (dispatch) => (opts, handler) =>
102
- opts.idempotent && opts.retry
103
- ? dispatch(opts, new Handler(opts, { handler, dispatch }))
104
- : dispatch(opts, handler)
@@ -1,51 +0,0 @@
1
- class Handler {
2
- constructor(opts, signal, { handler }) {
3
- this.handler = handler
4
- this.signal = signal
5
- this.abort = null
6
- }
7
-
8
- onConnect(abort) {
9
- this.abort = () => {
10
- abort(this.signal.reason)
11
- }
12
- this.signal.addEventListener('abort', this.abort)
13
-
14
- if (this.signal.aborted) {
15
- abort(this.signal.reason)
16
- } else {
17
- this.handler.onConnect?.(abort)
18
- }
19
- }
20
-
21
- onUpgrade(statusCode, rawHeaders, socket) {
22
- return this.handler.onUpgrade?.(statusCode, rawHeaders, socket)
23
- }
24
-
25
- onBodySent(chunk) {
26
- return this.handler.onBodySent?.(chunk)
27
- }
28
-
29
- onHeaders(statusCode, rawHeaders, resume, statusMessage) {
30
- return this.handler.onHeaders?.(statusCode, rawHeaders, resume, statusMessage)
31
- }
32
-
33
- onData(chunk) {
34
- return this.handler.onData?.(chunk)
35
- }
36
-
37
- onComplete(rawTrailers) {
38
- this.signal.removeEventListener('abort', this.abort)
39
- return this.handler.onComplete?.(rawTrailers)
40
- }
41
-
42
- onError(err) {
43
- this.signal.removeEventListener('abort', this.abort)
44
- return this.handler.onError?.(err)
45
- }
46
- }
47
-
48
- module.exports =
49
- (dispatch) =>
50
- ({ signal, ...opts }, handler) =>
51
- signal ? dispatch(opts, new Handler(opts, signal, { handler })) : dispatch(opts, handler)
@@ -1,183 +0,0 @@
1
- const tp = require('node:timers/promises')
2
-
3
- function isDisturbed(body) {
4
- if (body == null || typeof body === 'string' || Buffer.isBuffer(body)) {
5
- return false
6
- }
7
-
8
- if (body.readableDidRead === false) {
9
- return false
10
- }
11
-
12
- return true
13
- }
14
-
15
- function parseContentRange(range) {
16
- if (typeof range !== 'string') {
17
- return null
18
- }
19
-
20
- const m = range.match(/^bytes (\d+)-(\d+)?\/(\d+|\*)$/)
21
- if (!m) {
22
- return null
23
- }
24
-
25
- const start = m[1] == null ? null : Number(m[1])
26
- if (!Number.isFinite(start)) {
27
- return null
28
- }
29
-
30
- const end = m[2] == null ? null : Number(m[2])
31
- if (end !== null && !Number.isFinite(end)) {
32
- return null
33
- }
34
-
35
- const size = m[2] === '*' ? null : Number(m[2])
36
- if (size !== null && !Number.isFinite(size)) {
37
- return null
38
- }
39
-
40
- return { start, end: end ? end + 1 : size, size }
41
- }
42
-
43
- function findHeader(rawHeaders, name) {
44
- const len = name.length
45
-
46
- for (let i = 0; i < rawHeaders.length; i += 2) {
47
- const key = rawHeaders[i + 0]
48
- if (key.length === len && key.toString().toLowerCase() === name) {
49
- return rawHeaders[i + 1].toString()
50
- }
51
- }
52
- return null
53
- }
54
-
55
- function retry(err, retryCount, opts) {
56
- if (opts.retry === null || opts.retry === false) {
57
- return null
58
- }
59
-
60
- if (typeof opts.retry === 'function') {
61
- return opts.retry(err, retryCount, opts)
62
- }
63
-
64
- const retryMax = opts.retry?.count ?? opts.maxRetries ?? 8
65
-
66
- if (retryCount > retryMax) {
67
- return null
68
- }
69
-
70
- if (err.statusCode && [420, 429, 502, 503, 504].includes(err.statusCode)) {
71
- let retryAfter = err.headers['retry-after'] ? err.headers['retry-after'] * 1e3 : null
72
- retryAfter = Number.isFinite(retryAfter) ? retryAfter : Math.min(10e3, retryCount * 1e3)
73
- if (retryAfter != null && Number.isFinite(retryAfter)) {
74
- return tp.setTimeout(retryAfter, undefined, { signal: opts.signal })
75
- } else {
76
- return null
77
- }
78
- }
79
-
80
- if (
81
- err.code &&
82
- [
83
- 'ECONNRESET',
84
- 'ECONNREFUSED',
85
- 'ENOTFOUND',
86
- 'ENETDOWN',
87
- 'ENETUNREACH',
88
- 'EHOSTDOWN',
89
- 'EHOSTUNREACH',
90
- 'EPIPE',
91
- ].includes(err.code)
92
- ) {
93
- return tp.setTimeout(Math.min(10e3, retryCount * 1e3), undefined, { signal: opts.signal })
94
- }
95
-
96
- if (err.message && ['other side closed'].includes(err.message)) {
97
- return tp.setTimeout(Math.min(10e3, retryCount * 1e3), undefined, { signal: opts.signal })
98
- }
99
-
100
- return null
101
- }
102
-
103
- function parseURL(url) {
104
- if (typeof url === 'string') {
105
- url = new URL(url)
106
-
107
- if (!/^https?:/.test(url.origin || url.protocol)) {
108
- throw new Error('Invalid URL protocol: the URL must start with `http:` or `https:`.')
109
- }
110
-
111
- return url
112
- }
113
-
114
- if (!url || typeof url !== 'object') {
115
- throw new Error('Invalid URL: The URL argument must be a non-null object.')
116
- }
117
-
118
- if (url.port != null && url.port !== '' && !Number.isFinite(parseInt(url.port))) {
119
- throw new Error(
120
- 'Invalid URL: port must be a valid integer or a string representation of an integer.',
121
- )
122
- }
123
-
124
- if (url.path != null && typeof url.path !== 'string') {
125
- throw new Error('Invalid URL path: the path must be a string or null/undefined.')
126
- }
127
-
128
- if (url.pathname != null && typeof url.pathname !== 'string') {
129
- throw new Error('Invalid URL pathname: the pathname must be a string or null/undefined.')
130
- }
131
-
132
- if (url.hostname != null && typeof url.hostname !== 'string') {
133
- throw new Error('Invalid URL hostname: the hostname must be a string or null/undefined.')
134
- }
135
-
136
- if (url.origin != null && typeof url.origin !== 'string') {
137
- throw new Error('Invalid URL origin: the origin must be a string or null/undefined.')
138
- }
139
-
140
- if (!/^https?:/.test(url.origin || url.protocol)) {
141
- throw new Error('Invalid URL protocol: the URL must start with `http:` or `https:`.')
142
- }
143
-
144
- if (!(url instanceof URL)) {
145
- const port = url.port != null ? url.port : url.protocol === 'https:' ? 443 : 80
146
- let origin = url.origin != null ? url.origin : `${url.protocol}//${url.hostname}:${port}`
147
- let path = url.path != null ? url.path : `${url.pathname || ''}${url.search || ''}`
148
-
149
- if (origin.endsWith('/')) {
150
- origin = origin.substring(0, origin.length - 1)
151
- }
152
-
153
- if (path && !path.startsWith('/')) {
154
- path = `/${path}`
155
- }
156
- // new URL(path, origin) is unsafe when `path` contains an absolute URL
157
- // From https://developer.mozilla.org/en-US/docs/Web/API/URL/URL:
158
- // If first parameter is a relative URL, second param is required, and will be used as the base URL.
159
- // If first parameter is an absolute URL, a given second param will be ignored.
160
- url = new URL(origin + path)
161
- }
162
-
163
- return url
164
- }
165
-
166
- function parseOrigin(url) {
167
- url = module.exports.parseURL(url)
168
-
169
- if (url.pathname !== '/' || url.search || url.hash) {
170
- throw new Error('invalid url')
171
- }
172
-
173
- return url
174
- }
175
-
176
- module.exports = {
177
- isDisturbed,
178
- parseContentRange,
179
- findHeader,
180
- retry,
181
- parseURL,
182
- parseOrigin,
183
- }
package/proxy.js DELETED
@@ -1,106 +0,0 @@
1
- const createError = require('http-errors')
2
- const net = require('net')
3
-
4
- // This expression matches hop-by-hop headers.
5
- // These headers are meaningful only for a single transport-level connection,
6
- // and must not be retransmitted by proxies or cached.
7
- const HOP_EXPR =
8
- /^(te|host|upgrade|trailers|connection|keep-alive|http2-settings|transfer-encoding|proxy-connection|proxy-authenticate|proxy-authorization)$/i
9
-
10
- // Removes hop-by-hop and pseudo headers.
11
- // Updates via and forwarded headers.
12
- // Only hop-by-hop headers may be set using the Connection general header.
13
- module.exports.reduceHeaders = function reduceHeaders(
14
- { id, headers, proxyName, httpVersion, socket },
15
- fn,
16
- acc,
17
- ) {
18
- let via
19
- let forwarded
20
- let host
21
- let authority
22
- let connection
23
-
24
- const entries = Object.entries(headers)
25
-
26
- for (const [key, val] of entries) {
27
- const len = key.length
28
- if (len === 3 && !via && key.toLowerCase() === 'via') {
29
- via = val
30
- } else if (len === 4 && !host && key.toLowerCase() === 'host') {
31
- host = val
32
- } else if (len === 9 && !forwarded && key.toLowerCase() === 'forwarded') {
33
- forwarded = val
34
- } else if (len === 10 && !connection && key.toLowerCase() === 'connection') {
35
- connection = val
36
- } else if (len === 10 && !authority && key.toLowerCase() === ':authority') {
37
- authority = val
38
- }
39
- }
40
-
41
- let remove
42
- if (connection && !HOP_EXPR.test(connection)) {
43
- remove = connection.split(/,\s*/)
44
- }
45
-
46
- for (const [key, val] of entries) {
47
- if (key.charAt(0) !== ':' && !remove?.includes(key) && !HOP_EXPR.test(key)) {
48
- acc = fn(acc, key, val)
49
- }
50
- }
51
-
52
- if (socket) {
53
- const forwardedHost = authority || host
54
- acc = fn(
55
- acc,
56
- 'forwarded',
57
- (forwarded ? forwarded + ', ' : '') +
58
- [
59
- socket.localAddress && `by=${printIp(socket.localAddress, socket.localPort)}`,
60
- socket.remoteAddress && `for=${printIp(socket.remoteAddress, socket.remotePort)}`,
61
- `proto=${socket.encrypted ? 'https' : 'http'}`,
62
- forwardedHost && `host="${forwardedHost}"`,
63
- ].join(';'),
64
- )
65
- } else if (forwarded) {
66
- // The forwarded header should not be included in response.
67
- throw new createError.BadGateway()
68
- }
69
-
70
- if (proxyName) {
71
- if (via) {
72
- if (via.split(',').some((name) => name.endsWith(proxyName))) {
73
- throw new createError.LoopDetected()
74
- }
75
- via += ', '
76
- } else {
77
- via = ''
78
- }
79
- via += `${httpVersion} ${proxyName}`
80
- }
81
-
82
- if (via) {
83
- acc = fn(acc, 'via', via)
84
- }
85
-
86
- if (id) {
87
- acc = fn(acc, 'request-id', id)
88
- }
89
-
90
- return acc
91
- }
92
-
93
- function printIp(address, port) {
94
- const isIPv6 = net.isIPv6(address)
95
- let str = `${address}`
96
- if (isIPv6) {
97
- str = `[${str}]`
98
- }
99
- if (port) {
100
- str = `${str}:${port}`
101
- }
102
- if (isIPv6 || port) {
103
- str = `"${str}"`
104
- }
105
- return str
106
- }
package/undici.js DELETED
@@ -1 +0,0 @@
1
- module.exports = require('./lib/undici/index.js')