@nxtedition/lib 19.0.30 → 19.0.32
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/package.json +1 -1
- package/s3.js +52 -25
package/package.json
CHANGED
package/s3.js
CHANGED
|
@@ -20,8 +20,9 @@ class PartUploader {
|
|
|
20
20
|
#callback
|
|
21
21
|
#hasher
|
|
22
22
|
#signal
|
|
23
|
+
#logger
|
|
23
24
|
|
|
24
|
-
constructor(dir, number, signal) {
|
|
25
|
+
constructor({ dir, number, signal, logger }) {
|
|
25
26
|
this.#writable = null
|
|
26
27
|
this.#callback = noop
|
|
27
28
|
this.#hasher = crypto.createHash('md5')
|
|
@@ -29,6 +30,7 @@ class PartUploader {
|
|
|
29
30
|
this.#signal = signal
|
|
30
31
|
this.#number = number
|
|
31
32
|
this.#path = path.join(dir, `${this.#number}.part`)
|
|
33
|
+
this.#logger = logger?.child({ part: this.#number, path: this.#path })
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
get size() {
|
|
@@ -36,16 +38,20 @@ class PartUploader {
|
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
async write(chunk) {
|
|
39
|
-
this.#writable
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
if (!this.#writable) {
|
|
42
|
+
this.#writable = fs
|
|
43
|
+
.createWriteStream(this.#path, { signal: this.#signal })
|
|
44
|
+
.on('drain', () => {
|
|
45
|
+
this.#callback(null)
|
|
46
|
+
this.#callback = noop
|
|
47
|
+
})
|
|
48
|
+
.on('error', (err) => {
|
|
49
|
+
this.#callback(err)
|
|
50
|
+
this.callback = noop
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
this.#logger?.debug('created part')
|
|
54
|
+
}
|
|
49
55
|
|
|
50
56
|
if (this.#writable.errored) {
|
|
51
57
|
throw this.#writable.errored
|
|
@@ -77,6 +83,7 @@ class PartUploader {
|
|
|
77
83
|
|
|
78
84
|
assert(this.#writable.bytesWritten === this.#size, 'Expected size to match bytesWritten')
|
|
79
85
|
|
|
86
|
+
this.#logger?.debug('uploading part')
|
|
80
87
|
const { ETag } = await s3.send(
|
|
81
88
|
new AWS.UploadPartCommand({
|
|
82
89
|
...params,
|
|
@@ -86,27 +93,28 @@ class PartUploader {
|
|
|
86
93
|
Body: fs.createReadStream(this.#path, { signal: this.#signal }),
|
|
87
94
|
}),
|
|
88
95
|
)
|
|
96
|
+
this.#logger?.debug({ etag: ETag }, 'uploaded part')
|
|
89
97
|
|
|
90
98
|
return { part: { ETag, PartNumber: this.#number } }
|
|
91
99
|
} catch (err) {
|
|
92
100
|
return { error: err }
|
|
93
101
|
} finally {
|
|
94
102
|
await fs.promises.unlink(this.#writable.path)
|
|
103
|
+
this.#logger?.debug('deleted part')
|
|
95
104
|
}
|
|
96
105
|
}
|
|
97
106
|
}
|
|
98
107
|
|
|
99
|
-
export async function upload(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
) {
|
|
108
|
+
export async function upload({
|
|
109
|
+
client: s3,
|
|
110
|
+
signal: outerSignal,
|
|
111
|
+
logger,
|
|
112
|
+
tmpdir = os.tmpdir(),
|
|
113
|
+
partSize = 64e6,
|
|
114
|
+
queueSize = 4,
|
|
115
|
+
leavePartsOnError = false,
|
|
116
|
+
params,
|
|
117
|
+
}) {
|
|
110
118
|
if (s3 == null) {
|
|
111
119
|
throw new Error('Invalid client')
|
|
112
120
|
}
|
|
@@ -119,6 +127,12 @@ export async function upload(
|
|
|
119
127
|
throw new Error('Invalid queueSize')
|
|
120
128
|
}
|
|
121
129
|
|
|
130
|
+
if (params == null || typeof params !== 'object') {
|
|
131
|
+
throw new Error('Invalid params')
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const { Body, Key, Bucket, ContentMD5, ContentLength } = params ?? {}
|
|
135
|
+
|
|
122
136
|
if (ContentMD5 != null && !CONTENT_MD5_EXPR.test(ContentMD5)) {
|
|
123
137
|
throw new Error(`Invalid ContentMD5: ${ContentMD5}`)
|
|
124
138
|
}
|
|
@@ -141,6 +155,7 @@ export async function upload(
|
|
|
141
155
|
let uploadDir
|
|
142
156
|
try {
|
|
143
157
|
uploadDir = await fs.promises.mkdtemp(path.join(tmpdir, 's3-upload-'))
|
|
158
|
+
logger?.debug({ uploadDir }, 'created upload directory')
|
|
144
159
|
signal.throwIfAborted()
|
|
145
160
|
|
|
146
161
|
const multipartUploadOutput = await s3.send(
|
|
@@ -150,21 +165,29 @@ export async function upload(
|
|
|
150
165
|
}),
|
|
151
166
|
)
|
|
152
167
|
uploadId = multipartUploadOutput.UploadId
|
|
168
|
+
logger = logger?.child({ uploadId })
|
|
169
|
+
logger?.debug('created multipart upload')
|
|
153
170
|
signal.throwIfAborted()
|
|
154
171
|
|
|
155
172
|
const uploader = {
|
|
156
173
|
size: 0,
|
|
157
174
|
hasher: crypto.createHash('md5'),
|
|
158
|
-
part: new PartUploader(uploadDir, 1, signal),
|
|
175
|
+
part: new PartUploader({ dir: uploadDir, number: 1, signal, logger }),
|
|
159
176
|
number: 1,
|
|
160
177
|
}
|
|
161
178
|
|
|
162
179
|
const maybeFlush = (minSize) => {
|
|
163
180
|
if (uploader.part.size && (minSize == null || uploader.part.size >= minSize)) {
|
|
164
181
|
const part = uploader.part
|
|
165
|
-
uploader.part = new PartUploader(
|
|
182
|
+
uploader.part = new PartUploader({
|
|
183
|
+
dir: uploadDir,
|
|
184
|
+
number: ++uploader.number,
|
|
185
|
+
logger,
|
|
186
|
+
signal,
|
|
187
|
+
})
|
|
166
188
|
|
|
167
189
|
const promise = queue.add(() => part.end(s3, { Bucket, Key, UploadId: uploadId }))
|
|
190
|
+
promise.catch(() => {})
|
|
168
191
|
promises.push(promise)
|
|
169
192
|
}
|
|
170
193
|
}
|
|
@@ -212,7 +235,6 @@ export async function upload(
|
|
|
212
235
|
MultipartUpload: { Parts: parts },
|
|
213
236
|
}),
|
|
214
237
|
)
|
|
215
|
-
signal.throwIfAborted()
|
|
216
238
|
|
|
217
239
|
const result = {
|
|
218
240
|
size: uploader.size,
|
|
@@ -221,6 +243,10 @@ export async function upload(
|
|
|
221
243
|
parts,
|
|
222
244
|
}
|
|
223
245
|
|
|
246
|
+
logger?.debug(result, 'completed multipart upload')
|
|
247
|
+
|
|
248
|
+
signal.throwIfAborted()
|
|
249
|
+
|
|
224
250
|
const size = ContentLength != null ? Number(ContentLength) : null
|
|
225
251
|
const hash = ContentMD5
|
|
226
252
|
|
|
@@ -245,6 +271,7 @@ export async function upload(
|
|
|
245
271
|
UploadId: uploadId,
|
|
246
272
|
}),
|
|
247
273
|
)
|
|
274
|
+
logger?.warn('aborted multipart upload')
|
|
248
275
|
} catch (er) {
|
|
249
276
|
throw new AggregateError([err, er])
|
|
250
277
|
}
|