@nxtedition/lib 19.1.2 → 19.1.5
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 +6 -4
- package/errors.js +14 -4
- package/package.json +1 -1
- package/s3.js +37 -15
package/couch.js
CHANGED
|
@@ -930,6 +930,7 @@ class ErrorHandler extends undici.DecoratorHandler {
|
|
|
930
930
|
#opts
|
|
931
931
|
#handler
|
|
932
932
|
#error
|
|
933
|
+
#headers
|
|
933
934
|
|
|
934
935
|
constructor({ opts, handler }) {
|
|
935
936
|
super(handler)
|
|
@@ -949,11 +950,11 @@ class ErrorHandler extends undici.DecoratorHandler {
|
|
|
949
950
|
this.#statusText = statusText
|
|
950
951
|
|
|
951
952
|
if (this.#statusCode < 200 || this.#statusCode > 300) {
|
|
952
|
-
headers = Array.isArray(headers) ? undiciUtil.parseHeaders(headers) : headers
|
|
953
|
+
this.#headers = Array.isArray(headers) ? undiciUtil.parseHeaders(headers) : headers
|
|
953
954
|
|
|
954
955
|
this.#error = new Error(this.#statusText ?? this.#statusCode)
|
|
955
956
|
|
|
956
|
-
this.#contentType = parseContentType(headers['content-type'] ?? '')?.type
|
|
957
|
+
this.#contentType = parseContentType(this.#headers['content-type'] ?? '')?.type
|
|
957
958
|
if (this.#contentType !== 'application/json' && this.#contentType !== 'plain/text') {
|
|
958
959
|
throw this.#error
|
|
959
960
|
}
|
|
@@ -1003,10 +1004,11 @@ class ErrorHandler extends undici.DecoratorHandler {
|
|
|
1003
1004
|
} else if (this.#contentType === 'plain/text') {
|
|
1004
1005
|
throw Object.assign(this.#error, {
|
|
1005
1006
|
data: {
|
|
1006
|
-
|
|
1007
|
-
|
|
1007
|
+
ureq: this.#opts,
|
|
1008
|
+
ures: {
|
|
1008
1009
|
body: this.#str,
|
|
1009
1010
|
statusCode: this.#statusCode,
|
|
1011
|
+
headers: this.#headers,
|
|
1010
1012
|
},
|
|
1011
1013
|
},
|
|
1012
1014
|
})
|
package/errors.js
CHANGED
|
@@ -42,12 +42,16 @@ export function parseError(error) {
|
|
|
42
42
|
const kSeen = Symbol('kSeen')
|
|
43
43
|
|
|
44
44
|
export function serializeError(error) {
|
|
45
|
+
return _serializeError(error, { depth: 0 })
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function _serializeError(error, { depth }) {
|
|
45
49
|
if (!error) {
|
|
46
50
|
return null
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
if (typeof error === 'string') {
|
|
50
|
-
return [
|
|
54
|
+
return [_serializeError({ message: error }, { depth })]
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
if (Buffer.isBuffer(error)) {
|
|
@@ -55,13 +59,17 @@ export function serializeError(error) {
|
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
if (Array.isArray(error)) {
|
|
58
|
-
return error.map(
|
|
62
|
+
return error.map((x) => _serializeError(x, { depth })).filter(Boolean)
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
if (Object.prototype.hasOwnProperty.call(error, kSeen)) {
|
|
62
66
|
return null
|
|
63
67
|
}
|
|
64
68
|
|
|
69
|
+
if (depth > 8) {
|
|
70
|
+
return [{ messages: 'Maximum error serialization depth exceeded' }]
|
|
71
|
+
}
|
|
72
|
+
|
|
65
73
|
error[kSeen] = undefined
|
|
66
74
|
|
|
67
75
|
const type =
|
|
@@ -104,8 +112,10 @@ export function serializeError(error) {
|
|
|
104
112
|
signalCode = SIGNALS[signalCode] ?? signalCode
|
|
105
113
|
}
|
|
106
114
|
|
|
107
|
-
errors = Array.isArray(errors)
|
|
108
|
-
|
|
115
|
+
errors = Array.isArray(errors)
|
|
116
|
+
? errors.map((x) => _serializeError(x, { depth: depth + 1 })).filter(Boolean)
|
|
117
|
+
: undefined
|
|
118
|
+
cause = cause ? _serializeError(cause, { depth: depth + 1 }) : undefined
|
|
109
119
|
|
|
110
120
|
delete error[kSeen]
|
|
111
121
|
|
package/package.json
CHANGED
package/s3.js
CHANGED
|
@@ -4,12 +4,34 @@ import tp from 'node:timers/promises'
|
|
|
4
4
|
import AWS from '@aws-sdk/client-s3'
|
|
5
5
|
import PQueue from 'p-queue'
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
const QUEUE = new PQueue({ concurrency: 8 })
|
|
8
|
+
const MD5_HEX_EXPR = /^[A-F0-9]{32}$/i
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Uploads a file to S3 using multipart upload.
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} options - The options for the upload.
|
|
14
|
+
* @param {AWS.S3} options.client - The S3 client.
|
|
15
|
+
* @param {AbortSignal} options.signal - The signal to abort the upload.
|
|
16
|
+
* @param {Object} options.logger - The logger to use.
|
|
17
|
+
* @param {number} [options.partSize=16e6] - The size of each part in the multipart upload.
|
|
18
|
+
* @param {PQueue} [options.queue] - The queue to use for part uploads.
|
|
19
|
+
* @param {Object} options.params - The parameters for the upload.
|
|
20
|
+
* @param {Buffer|NodeJS.ReadStream} options.params.Body - The data to upload.
|
|
21
|
+
* @param {string} options.params.Key - The key of the object.
|
|
22
|
+
* @param {string} options.params.Bucket - The name of the bucket.
|
|
23
|
+
* @param {string} [options.params.ContentMD5] - The MD5 hash of the object as base64 string.
|
|
24
|
+
* @param {number} [options.params.ContentLength] - The length of the object.
|
|
25
|
+
* @returns {Promise<Object>} The result of the upload.
|
|
26
|
+
*/
|
|
27
|
+
export async function upload({
|
|
28
|
+
client: s3,
|
|
29
|
+
queue = QUEUE,
|
|
30
|
+
signal,
|
|
31
|
+
logger,
|
|
32
|
+
partSize = 16e6,
|
|
33
|
+
params,
|
|
34
|
+
}) {
|
|
13
35
|
if (s3 == null) {
|
|
14
36
|
throw new Error('Invalid client')
|
|
15
37
|
}
|
|
@@ -22,14 +44,17 @@ export async function upload({ client: s3, signal, logger, partSize = 16e6, para
|
|
|
22
44
|
throw new Error('Invalid params')
|
|
23
45
|
}
|
|
24
46
|
|
|
25
|
-
const { Body, Key, Bucket, ContentMD5, ContentLength } = params
|
|
47
|
+
const { Body, Key, Bucket, ContentMD5, ContentLength } = params
|
|
26
48
|
|
|
27
|
-
|
|
28
|
-
|
|
49
|
+
const size = ContentLength != null ? Number(ContentLength) : null
|
|
50
|
+
|
|
51
|
+
if (size != null && (!Number.isFinite(size) || size < 0)) {
|
|
52
|
+
throw new Error('Invalid params.ContentLength')
|
|
29
53
|
}
|
|
30
54
|
|
|
31
|
-
|
|
32
|
-
|
|
55
|
+
const hash = ContentMD5 != null ? Buffer.from(ContentMD5, 'base64').toString('hex') : null
|
|
56
|
+
if (hash != null && !MD5_HEX_EXPR.test(hash)) {
|
|
57
|
+
throw new Error('Invalid params.ContentMD5')
|
|
33
58
|
}
|
|
34
59
|
|
|
35
60
|
const promises = []
|
|
@@ -116,7 +141,7 @@ export async function upload({ client: s3, signal, logger, partSize = 16e6, para
|
|
|
116
141
|
} catch (err) {
|
|
117
142
|
logger?.warn({ err }, 'part upload failed')
|
|
118
143
|
|
|
119
|
-
if (retryCount <
|
|
144
|
+
if (retryCount < 5) {
|
|
120
145
|
logger?.debug({ retryCount }, 'part upload retry')
|
|
121
146
|
await tp.setTimeout(1e3, undefined, { signal: uploader.signal })
|
|
122
147
|
} else {
|
|
@@ -189,9 +214,6 @@ export async function upload({ client: s3, signal, logger, partSize = 16e6, para
|
|
|
189
214
|
parts,
|
|
190
215
|
}
|
|
191
216
|
|
|
192
|
-
const size = ContentLength != null ? Number(ContentLength) : null
|
|
193
|
-
const hash = ContentMD5
|
|
194
|
-
|
|
195
217
|
if (size != null && size !== result.size) {
|
|
196
218
|
throw new Error(`Expected size ${size} but got ${result.size}`)
|
|
197
219
|
}
|