@uploadcare/upload-client 2.0.0-alpha.8 → 2.2.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/README.md +35 -10
- package/dist/index.browser.cjs +73 -42
- package/dist/index.browser.js +110 -86
- package/dist/index.cjs +85 -49
- package/dist/index.js +119 -95
- package/dist/types.d.ts +102 -5
- package/package.json +32 -26
- package/CHANGELOG.md +0 -243
package/dist/index.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import https from 'https';
|
|
3
3
|
import { parse } from 'url';
|
|
4
4
|
import { Transform, Readable } from 'stream';
|
|
5
|
-
import
|
|
5
|
+
import NodeFormData from 'form-data';
|
|
6
6
|
import { AbortController } from 'abort-controller';
|
|
7
7
|
export { AbortController } from 'abort-controller';
|
|
8
|
-
import
|
|
8
|
+
import WebSocket from 'ws';
|
|
9
9
|
|
|
10
10
|
class UploadClientError extends Error {
|
|
11
|
-
constructor(message, request, response, headers) {
|
|
11
|
+
constructor(message, code, request, response, headers) {
|
|
12
12
|
super();
|
|
13
13
|
this.name = 'UploadClientError';
|
|
14
14
|
this.message = message;
|
|
15
|
+
this.code = code;
|
|
15
16
|
this.request = request;
|
|
16
17
|
this.response = response;
|
|
17
18
|
this.headers = headers;
|
|
@@ -82,7 +83,7 @@ const request = (params) => {
|
|
|
82
83
|
return undefined;
|
|
83
84
|
}
|
|
84
85
|
})
|
|
85
|
-
.then(length => new Promise((resolve, reject) => {
|
|
86
|
+
.then((length) => new Promise((resolve, reject) => {
|
|
86
87
|
const isFormData = !!length;
|
|
87
88
|
let aborted = false;
|
|
88
89
|
const options = parse(url);
|
|
@@ -95,19 +96,19 @@ const request = (params) => {
|
|
|
95
96
|
length || data.length;
|
|
96
97
|
}
|
|
97
98
|
const req = options.protocol !== 'https:'
|
|
98
|
-
? request
|
|
99
|
-
: request
|
|
99
|
+
? http.request(options)
|
|
100
|
+
: https.request(options);
|
|
100
101
|
onCancel(signal, () => {
|
|
101
102
|
aborted = true;
|
|
102
103
|
req.abort();
|
|
103
104
|
reject(cancelError());
|
|
104
105
|
});
|
|
105
|
-
req.on('response', res => {
|
|
106
|
+
req.on('response', (res) => {
|
|
106
107
|
if (aborted)
|
|
107
108
|
return;
|
|
108
109
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
109
110
|
const resChunks = [];
|
|
110
|
-
res.on('data', data => {
|
|
111
|
+
res.on('data', (data) => {
|
|
111
112
|
resChunks.push(data);
|
|
112
113
|
});
|
|
113
114
|
res.on('end', () => resolve({
|
|
@@ -117,7 +118,7 @@ const request = (params) => {
|
|
|
117
118
|
request: params
|
|
118
119
|
}));
|
|
119
120
|
});
|
|
120
|
-
req.on('error', err => {
|
|
121
|
+
req.on('error', (err) => {
|
|
121
122
|
if (aborted)
|
|
122
123
|
return;
|
|
123
124
|
reject(err);
|
|
@@ -136,18 +137,25 @@ const request = (params) => {
|
|
|
136
137
|
}));
|
|
137
138
|
};
|
|
138
139
|
|
|
140
|
+
function identity(obj) {
|
|
141
|
+
return obj;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const transformFile = identity;
|
|
139
145
|
var getFormData = () => new NodeFormData();
|
|
140
146
|
|
|
147
|
+
const isFileTuple = (tuple) => tuple[0] === 'file';
|
|
141
148
|
function buildFormData(body) {
|
|
142
149
|
const formData = getFormData();
|
|
143
|
-
const isTriple = (tuple) => tuple[0] === 'file';
|
|
144
150
|
for (const tuple of body) {
|
|
145
151
|
if (Array.isArray(tuple[1])) {
|
|
146
152
|
// refactor this
|
|
147
|
-
tuple[1].forEach(val => val && formData.append(tuple[0] + '[]', `${val}`));
|
|
153
|
+
tuple[1].forEach((val) => val && formData.append(tuple[0] + '[]', `${val}`));
|
|
148
154
|
}
|
|
149
|
-
else if (
|
|
150
|
-
|
|
155
|
+
else if (isFileTuple(tuple)) {
|
|
156
|
+
const name = tuple[2];
|
|
157
|
+
const file = transformFile(tuple[1]); // lgtm[js/superfluous-trailing-arguments]
|
|
158
|
+
formData.append(tuple[0], file, name);
|
|
151
159
|
}
|
|
152
160
|
else if (tuple[1] != null) {
|
|
153
161
|
formData.append(tuple[0], `${tuple[1]}`);
|
|
@@ -159,9 +167,9 @@ function buildFormData(body) {
|
|
|
159
167
|
const serializePair = (key, value) => typeof value !== 'undefined' ? `${key}=${encodeURIComponent(value)}` : null;
|
|
160
168
|
const createQuery = (query) => Object.entries(query)
|
|
161
169
|
.reduce((params, [key, value]) => params.concat(Array.isArray(value)
|
|
162
|
-
? value.map(value => serializePair(`${key}[]`, value))
|
|
170
|
+
? value.map((value) => serializePair(`${key}[]`, value))
|
|
163
171
|
: serializePair(key, value)), [])
|
|
164
|
-
.filter(x => !!x)
|
|
172
|
+
.filter((x) => !!x)
|
|
165
173
|
.join('&');
|
|
166
174
|
const getUrl = (base, path, query) => [
|
|
167
175
|
base,
|
|
@@ -192,7 +200,7 @@ const defaultSettings = {
|
|
|
192
200
|
const defaultContentType = 'application/octet-stream';
|
|
193
201
|
const defaultFilename = 'original';
|
|
194
202
|
|
|
195
|
-
var version = '
|
|
203
|
+
var version = '2.2.0';
|
|
196
204
|
|
|
197
205
|
/**
|
|
198
206
|
* Returns User Agent based on version and settings.
|
|
@@ -251,7 +259,7 @@ function camelizeKeys(source) {
|
|
|
251
259
|
*
|
|
252
260
|
* @param {number} ms Timeout in milliseconds.
|
|
253
261
|
*/
|
|
254
|
-
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
262
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
255
263
|
|
|
256
264
|
const defaultOptions = {
|
|
257
265
|
factor: 2,
|
|
@@ -273,7 +281,7 @@ function retrier(fn, options = defaultOptions) {
|
|
|
273
281
|
return runAttempt(fn);
|
|
274
282
|
}
|
|
275
283
|
|
|
276
|
-
const REQUEST_WAS_THROTTLED_CODE =
|
|
284
|
+
const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
|
|
277
285
|
const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
|
|
278
286
|
function getTimeoutFromThrottledRequest(error) {
|
|
279
287
|
const { headers } = error || {};
|
|
@@ -283,9 +291,8 @@ function getTimeoutFromThrottledRequest(error) {
|
|
|
283
291
|
}
|
|
284
292
|
function retryIfThrottled(fn, retryThrottledMaxTimes) {
|
|
285
293
|
return retrier(({ attempt, retry }) => fn().catch((error) => {
|
|
286
|
-
var _a;
|
|
287
294
|
if ('response' in error &&
|
|
288
|
-
(
|
|
295
|
+
(error === null || error === void 0 ? void 0 : error.code) === REQUEST_WAS_THROTTLED_CODE &&
|
|
289
296
|
attempt < retryThrottledMaxTimes) {
|
|
290
297
|
return retry(getTimeoutFromThrottledRequest(error));
|
|
291
298
|
}
|
|
@@ -324,7 +331,7 @@ function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, se
|
|
|
324
331
|
}).then(({ data, headers, request }) => {
|
|
325
332
|
const response = camelizeKeys(JSON.parse(data));
|
|
326
333
|
if ('error' in response) {
|
|
327
|
-
throw new UploadClientError(
|
|
334
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
328
335
|
}
|
|
329
336
|
else {
|
|
330
337
|
return response;
|
|
@@ -341,7 +348,6 @@ var TypeEnum;
|
|
|
341
348
|
/**
|
|
342
349
|
* Uploading files from URL.
|
|
343
350
|
*/
|
|
344
|
-
/* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key", "source_url", "check_URL_duplicates", "save_URL_duplicates"]}] */
|
|
345
351
|
function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
346
352
|
return retryIfThrottled(() => request({
|
|
347
353
|
method: 'POST',
|
|
@@ -364,7 +370,7 @@ function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, stor
|
|
|
364
370
|
}).then(({ data, headers, request }) => {
|
|
365
371
|
const response = camelizeKeys(JSON.parse(data));
|
|
366
372
|
if ('error' in response) {
|
|
367
|
-
throw new UploadClientError(
|
|
373
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
368
374
|
}
|
|
369
375
|
else {
|
|
370
376
|
return response;
|
|
@@ -406,7 +412,7 @@ function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, si
|
|
|
406
412
|
}).then(({ data, headers, request }) => {
|
|
407
413
|
const response = camelizeKeys(JSON.parse(data));
|
|
408
414
|
if ('error' in response && !isErrorResponse(response)) {
|
|
409
|
-
throw new UploadClientError(
|
|
415
|
+
throw new UploadClientError(response.error.content, undefined, request, response, headers);
|
|
410
416
|
}
|
|
411
417
|
else {
|
|
412
418
|
return response;
|
|
@@ -417,7 +423,6 @@ function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, si
|
|
|
417
423
|
/**
|
|
418
424
|
* Create files group.
|
|
419
425
|
*/
|
|
420
|
-
/* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key"]}] */
|
|
421
426
|
function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallback, secureSignature, secureExpire, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
422
427
|
return retryIfThrottled(() => request({
|
|
423
428
|
method: 'POST',
|
|
@@ -437,7 +442,7 @@ function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallb
|
|
|
437
442
|
}).then(({ data, headers, request }) => {
|
|
438
443
|
const response = camelizeKeys(JSON.parse(data));
|
|
439
444
|
if ('error' in response) {
|
|
440
|
-
throw new UploadClientError(
|
|
445
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
441
446
|
}
|
|
442
447
|
else {
|
|
443
448
|
return response;
|
|
@@ -448,7 +453,6 @@ function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallb
|
|
|
448
453
|
/**
|
|
449
454
|
* Get info about group.
|
|
450
455
|
*/
|
|
451
|
-
/* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key", "group_id"]}] */
|
|
452
456
|
function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
453
457
|
return retryIfThrottled(() => request({
|
|
454
458
|
method: 'GET',
|
|
@@ -465,7 +469,7 @@ function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, s
|
|
|
465
469
|
}).then(({ data, headers, request }) => {
|
|
466
470
|
const response = camelizeKeys(JSON.parse(data));
|
|
467
471
|
if ('error' in response) {
|
|
468
|
-
throw new UploadClientError(
|
|
472
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
469
473
|
}
|
|
470
474
|
else {
|
|
471
475
|
return response;
|
|
@@ -476,7 +480,6 @@ function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, s
|
|
|
476
480
|
/**
|
|
477
481
|
* Returns a JSON dictionary holding file info.
|
|
478
482
|
*/
|
|
479
|
-
/* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key", "file_id"]}] */
|
|
480
483
|
function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
481
484
|
return retryIfThrottled(() => request({
|
|
482
485
|
method: 'GET',
|
|
@@ -493,7 +496,7 @@ function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, sour
|
|
|
493
496
|
}).then(({ data, headers, request }) => {
|
|
494
497
|
const response = camelizeKeys(JSON.parse(data));
|
|
495
498
|
if ('error' in response) {
|
|
496
|
-
throw new UploadClientError(
|
|
499
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
497
500
|
}
|
|
498
501
|
else {
|
|
499
502
|
return response;
|
|
@@ -526,11 +529,11 @@ function multipartStart(size, { publicKey, contentType, fileName, multipartChunk
|
|
|
526
529
|
}).then(({ data, headers, request }) => {
|
|
527
530
|
const response = camelizeKeys(JSON.parse(data));
|
|
528
531
|
if ('error' in response) {
|
|
529
|
-
throw new UploadClientError(
|
|
532
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
530
533
|
}
|
|
531
534
|
else {
|
|
532
535
|
// convert to array
|
|
533
|
-
response.parts = Object.keys(response.parts).map(key => response.parts[key]);
|
|
536
|
+
response.parts = Object.keys(response.parts).map((key) => response.parts[key]);
|
|
534
537
|
return response;
|
|
535
538
|
}
|
|
536
539
|
}), retryThrottledRequestMaxTimes);
|
|
@@ -547,7 +550,7 @@ function multipartUpload(part, url, { signal, onProgress }) {
|
|
|
547
550
|
onProgress,
|
|
548
551
|
signal
|
|
549
552
|
})
|
|
550
|
-
.then(result => {
|
|
553
|
+
.then((result) => {
|
|
551
554
|
// hack for node ¯\_(ツ)_/¯
|
|
552
555
|
if (onProgress)
|
|
553
556
|
onProgress({ value: 1 });
|
|
@@ -575,7 +578,7 @@ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL,
|
|
|
575
578
|
}).then(({ data, headers, request }) => {
|
|
576
579
|
const response = camelizeKeys(JSON.parse(data));
|
|
577
580
|
if ('error' in response) {
|
|
578
|
-
throw new UploadClientError(
|
|
581
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
579
582
|
}
|
|
580
583
|
else {
|
|
581
584
|
return response;
|
|
@@ -589,6 +592,7 @@ class UploadcareFile {
|
|
|
589
592
|
this.size = null;
|
|
590
593
|
this.isStored = null;
|
|
591
594
|
this.isImage = null;
|
|
595
|
+
this.mimeType = null;
|
|
592
596
|
this.cdnUrl = null;
|
|
593
597
|
this.cdnUrlModifiers = null;
|
|
594
598
|
this.originalUrl = null;
|
|
@@ -607,6 +611,7 @@ class UploadcareFile {
|
|
|
607
611
|
this.size = fileInfo.size;
|
|
608
612
|
this.isStored = fileInfo.isStored;
|
|
609
613
|
this.isImage = fileInfo.isImage;
|
|
614
|
+
this.mimeType = fileInfo.mimeType;
|
|
610
615
|
this.cdnUrl = cdnUrl;
|
|
611
616
|
this.cdnUrlModifiers = cdnUrlModifiers;
|
|
612
617
|
this.originalUrl = originalUrl;
|
|
@@ -626,7 +631,7 @@ const poll = ({ check, interval = DEFAULT_INTERVAL, signal }) => new Promise((re
|
|
|
626
631
|
const tick = () => {
|
|
627
632
|
try {
|
|
628
633
|
Promise.resolve(check(signal))
|
|
629
|
-
.then(result => {
|
|
634
|
+
.then((result) => {
|
|
630
635
|
if (result) {
|
|
631
636
|
resolve(result);
|
|
632
637
|
}
|
|
@@ -634,7 +639,7 @@ const poll = ({ check, interval = DEFAULT_INTERVAL, signal }) => new Promise((re
|
|
|
634
639
|
timeoutId = setTimeout(tick, interval);
|
|
635
640
|
}
|
|
636
641
|
})
|
|
637
|
-
.catch(error => reject(error));
|
|
642
|
+
.catch((error) => reject(error));
|
|
638
643
|
}
|
|
639
644
|
catch (error) {
|
|
640
645
|
reject(error);
|
|
@@ -645,7 +650,7 @@ const poll = ({ check, interval = DEFAULT_INTERVAL, signal }) => new Promise((re
|
|
|
645
650
|
|
|
646
651
|
function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, signal, onProgress }) {
|
|
647
652
|
return poll({
|
|
648
|
-
check: signal => info(file, {
|
|
653
|
+
check: (signal) => info(file, {
|
|
649
654
|
publicKey,
|
|
650
655
|
baseURL,
|
|
651
656
|
signal,
|
|
@@ -653,7 +658,7 @@ function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent,
|
|
|
653
658
|
integration,
|
|
654
659
|
userAgent,
|
|
655
660
|
retryThrottledRequestMaxTimes
|
|
656
|
-
}).then(response => {
|
|
661
|
+
}).then((response) => {
|
|
657
662
|
if (response.isReady) {
|
|
658
663
|
return response;
|
|
659
664
|
}
|
|
@@ -692,7 +697,7 @@ const uploadFromObject = (file, { publicKey, fileName, baseURL, secureSignature,
|
|
|
692
697
|
signal
|
|
693
698
|
});
|
|
694
699
|
})
|
|
695
|
-
.then(fileInfo => new UploadcareFile(fileInfo, { baseCDN }));
|
|
700
|
+
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
|
|
696
701
|
};
|
|
697
702
|
|
|
698
703
|
const race = (fns, { signal } = {}) => {
|
|
@@ -704,21 +709,21 @@ const race = (fns, { signal } = {}) => {
|
|
|
704
709
|
controllers.forEach((controller, index) => index !== i && controller.abort());
|
|
705
710
|
};
|
|
706
711
|
onCancel(signal, () => {
|
|
707
|
-
controllers.forEach(controller => controller.abort());
|
|
712
|
+
controllers.forEach((controller) => controller.abort());
|
|
708
713
|
});
|
|
709
714
|
return Promise.all(fns.map((fn, i) => {
|
|
710
715
|
const stopRace = createStopRaceCallback(i);
|
|
711
716
|
return Promise.resolve()
|
|
712
717
|
.then(() => fn({ stopRace, signal: controllers[i].signal }))
|
|
713
|
-
.then(result => {
|
|
718
|
+
.then((result) => {
|
|
714
719
|
stopRace();
|
|
715
720
|
return result;
|
|
716
721
|
})
|
|
717
|
-
.catch(error => {
|
|
722
|
+
.catch((error) => {
|
|
718
723
|
lastError = error;
|
|
719
724
|
return null;
|
|
720
725
|
});
|
|
721
|
-
})).then(results => {
|
|
726
|
+
})).then((results) => {
|
|
722
727
|
if (winnerIndex === null) {
|
|
723
728
|
throw lastError;
|
|
724
729
|
}
|
|
@@ -734,7 +739,7 @@ class Events {
|
|
|
734
739
|
}
|
|
735
740
|
emit(event, data) {
|
|
736
741
|
var _a;
|
|
737
|
-
(_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.forEach(fn => fn(data));
|
|
742
|
+
(_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.forEach((fn) => fn(data));
|
|
738
743
|
}
|
|
739
744
|
on(event, callback) {
|
|
740
745
|
this.events[event] = this.events[event] || [];
|
|
@@ -742,7 +747,7 @@ class Events {
|
|
|
742
747
|
}
|
|
743
748
|
off(event, callback) {
|
|
744
749
|
if (callback) {
|
|
745
|
-
this.events[event] = this.events[event].filter(fn => fn !== callback);
|
|
750
|
+
this.events[event] = this.events[event].filter((fn) => fn !== callback);
|
|
746
751
|
}
|
|
747
752
|
else {
|
|
748
753
|
this.events[event] = [];
|
|
@@ -775,16 +780,16 @@ class Pusher {
|
|
|
775
780
|
if (!this.isConnected && !this.ws) {
|
|
776
781
|
const pusherUrl = `wss://ws.pusherapp.com/app/${this.key}?protocol=5&client=js&version=1.12.2`;
|
|
777
782
|
this.ws = new WebSocket(pusherUrl);
|
|
778
|
-
this.ws.addEventListener('error', error => {
|
|
783
|
+
this.ws.addEventListener('error', (error) => {
|
|
779
784
|
this.emmitter.emit('error', new Error(error.message));
|
|
780
785
|
});
|
|
781
786
|
this.emmitter.on('connected', () => {
|
|
782
787
|
this.isConnected = true;
|
|
783
|
-
this.queue.forEach(message => this.send(message.event, message.data));
|
|
788
|
+
this.queue.forEach((message) => this.send(message.event, message.data));
|
|
784
789
|
this.queue = [];
|
|
785
790
|
});
|
|
786
|
-
this.ws.addEventListener('message', e => {
|
|
787
|
-
const data = JSON.parse(e.data);
|
|
791
|
+
this.ws.addEventListener('message', (e) => {
|
|
792
|
+
const data = JSON.parse(e.data.toString());
|
|
788
793
|
switch (data.event) {
|
|
789
794
|
case 'pusher:connection_established': {
|
|
790
795
|
this.emmitter.emit('connected', undefined);
|
|
@@ -852,7 +857,7 @@ class Pusher {
|
|
|
852
857
|
this.send(message.event, message.data);
|
|
853
858
|
}
|
|
854
859
|
else {
|
|
855
|
-
this.queue = this.queue.filter(msg => msg.data.channel !== channel);
|
|
860
|
+
this.queue = this.queue.filter((msg) => msg.data.channel !== channel);
|
|
856
861
|
}
|
|
857
862
|
if (this.subscribers === 0) {
|
|
858
863
|
this.disconnect();
|
|
@@ -878,17 +883,17 @@ const preconnect = (key) => {
|
|
|
878
883
|
|
|
879
884
|
function pollStrategy({ token, publicKey, baseURL, integration, userAgent, retryThrottledRequestMaxTimes, onProgress, signal }) {
|
|
880
885
|
return poll({
|
|
881
|
-
check: signal => fromUrlStatus(token, {
|
|
886
|
+
check: (signal) => fromUrlStatus(token, {
|
|
882
887
|
publicKey,
|
|
883
888
|
baseURL,
|
|
884
889
|
integration,
|
|
885
890
|
userAgent,
|
|
886
891
|
retryThrottledRequestMaxTimes,
|
|
887
892
|
signal
|
|
888
|
-
}).then(response => {
|
|
893
|
+
}).then((response) => {
|
|
889
894
|
switch (response.status) {
|
|
890
895
|
case Status.Error: {
|
|
891
|
-
return new UploadClientError(response.error);
|
|
896
|
+
return new UploadClientError(response.error, response.errorCode);
|
|
892
897
|
}
|
|
893
898
|
case Status.Waiting: {
|
|
894
899
|
return false;
|
|
@@ -914,7 +919,7 @@ function pollStrategy({ token, publicKey, baseURL, integration, userAgent, retry
|
|
|
914
919
|
signal
|
|
915
920
|
});
|
|
916
921
|
}
|
|
917
|
-
const pushStrategy = ({ token, pusherKey, signal,
|
|
922
|
+
const pushStrategy = ({ token, pusherKey, signal, onProgress }) => new Promise((resolve, reject) => {
|
|
918
923
|
const pusher = getPusher(pusherKey);
|
|
919
924
|
const unsubErrorHandler = pusher.onError(reject);
|
|
920
925
|
const destroy = () => {
|
|
@@ -923,10 +928,9 @@ const pushStrategy = ({ token, pusherKey, signal, stopRace, onProgress }) => new
|
|
|
923
928
|
};
|
|
924
929
|
onCancel(signal, () => {
|
|
925
930
|
destroy();
|
|
926
|
-
reject(cancelError('
|
|
931
|
+
reject(cancelError('pusher cancelled'));
|
|
927
932
|
});
|
|
928
|
-
pusher.subscribe(token, result => {
|
|
929
|
-
stopRace();
|
|
933
|
+
pusher.subscribe(token, (result) => {
|
|
930
934
|
switch (result.status) {
|
|
931
935
|
case Status.Progress: {
|
|
932
936
|
if (onProgress) {
|
|
@@ -943,7 +947,7 @@ const pushStrategy = ({ token, pusherKey, signal, stopRace, onProgress }) => new
|
|
|
943
947
|
}
|
|
944
948
|
case Status.Error: {
|
|
945
949
|
destroy();
|
|
946
|
-
reject(new UploadClientError(result.msg));
|
|
950
|
+
reject(new UploadClientError(result.msg, result.error_code));
|
|
947
951
|
}
|
|
948
952
|
}
|
|
949
953
|
});
|
|
@@ -964,7 +968,12 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
|
|
|
964
968
|
userAgent,
|
|
965
969
|
retryThrottledRequestMaxTimes
|
|
966
970
|
}))
|
|
967
|
-
.
|
|
971
|
+
.catch((error) => {
|
|
972
|
+
const pusher = getPusher(pusherKey);
|
|
973
|
+
pusher === null || pusher === void 0 ? void 0 : pusher.disconnect();
|
|
974
|
+
return Promise.reject(error);
|
|
975
|
+
})
|
|
976
|
+
.then((urlResponse) => {
|
|
968
977
|
if (urlResponse.type === TypeEnum.FileInfo) {
|
|
969
978
|
return urlResponse;
|
|
970
979
|
}
|
|
@@ -980,22 +989,21 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
|
|
|
980
989
|
onProgress,
|
|
981
990
|
signal
|
|
982
991
|
}),
|
|
983
|
-
({
|
|
992
|
+
({ signal }) => pushStrategy({
|
|
984
993
|
token: urlResponse.token,
|
|
985
994
|
pusherKey,
|
|
986
|
-
stopRace,
|
|
987
995
|
signal,
|
|
988
996
|
onProgress
|
|
989
997
|
})
|
|
990
998
|
], { signal });
|
|
991
999
|
}
|
|
992
1000
|
})
|
|
993
|
-
.then(result => {
|
|
1001
|
+
.then((result) => {
|
|
994
1002
|
if (result instanceof UploadClientError)
|
|
995
1003
|
throw result;
|
|
996
1004
|
return result;
|
|
997
1005
|
})
|
|
998
|
-
.then(result => isReadyPoll({
|
|
1006
|
+
.then((result) => isReadyPoll({
|
|
999
1007
|
file: result.uuid,
|
|
1000
1008
|
publicKey,
|
|
1001
1009
|
baseURL,
|
|
@@ -1005,7 +1013,7 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
|
|
|
1005
1013
|
onProgress,
|
|
1006
1014
|
signal
|
|
1007
1015
|
}))
|
|
1008
|
-
.then(fileInfo => new UploadcareFile(fileInfo, { baseCDN }));
|
|
1016
|
+
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
|
|
1009
1017
|
|
|
1010
1018
|
const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN }) => {
|
|
1011
1019
|
return info(uuid, {
|
|
@@ -1017,8 +1025,8 @@ const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProg
|
|
|
1017
1025
|
userAgent,
|
|
1018
1026
|
retryThrottledRequestMaxTimes
|
|
1019
1027
|
})
|
|
1020
|
-
.then(fileInfo => new UploadcareFile(fileInfo, { baseCDN, fileName }))
|
|
1021
|
-
.then(result => {
|
|
1028
|
+
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
|
|
1029
|
+
.then((result) => {
|
|
1022
1030
|
// hack for node ¯\_(ツ)_/¯
|
|
1023
1031
|
if (onProgress)
|
|
1024
1032
|
onProgress({ value: 1 });
|
|
@@ -1067,6 +1075,16 @@ const isMultipart = (fileSize, multipartMinFileSize = defaultSettings.multipartM
|
|
|
1067
1075
|
return fileSize >= multipartMinFileSize;
|
|
1068
1076
|
};
|
|
1069
1077
|
|
|
1078
|
+
const sliceChunk = (file, index, fileSize, chunkSize) => {
|
|
1079
|
+
const start = chunkSize * index;
|
|
1080
|
+
const end = Math.min(start + chunkSize, fileSize);
|
|
1081
|
+
return file.slice(start, end);
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
function prepareChunks(file, fileSize, chunkSize) {
|
|
1085
|
+
return (index) => sliceChunk(file, index, fileSize, chunkSize);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1070
1088
|
const runWithConcurrency = (concurrency, tasks) => {
|
|
1071
1089
|
return new Promise((resolve, reject) => {
|
|
1072
1090
|
const results = [];
|
|
@@ -1090,7 +1108,7 @@ const runWithConcurrency = (concurrency, tasks) => {
|
|
|
1090
1108
|
resolve(results);
|
|
1091
1109
|
}
|
|
1092
1110
|
})
|
|
1093
|
-
.catch(error => {
|
|
1111
|
+
.catch((error) => {
|
|
1094
1112
|
rejected = true;
|
|
1095
1113
|
reject(error);
|
|
1096
1114
|
});
|
|
@@ -1102,15 +1120,12 @@ const runWithConcurrency = (concurrency, tasks) => {
|
|
|
1102
1120
|
});
|
|
1103
1121
|
};
|
|
1104
1122
|
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
const end = Math.min(start + chunkSize, fileSize);
|
|
1108
|
-
return file.slice(start, end);
|
|
1109
|
-
};
|
|
1110
|
-
const uploadPartWithRetry = (chunk, url, { onProgress, signal, multipartMaxAttempts }) => retrier(({ attempt, retry }) => multipartUpload(chunk, url, {
|
|
1123
|
+
const uploadPartWithRetry = (chunk, url, { publicKey, onProgress, signal, integration, multipartMaxAttempts }) => retrier(({ attempt, retry }) => multipartUpload(chunk, url, {
|
|
1124
|
+
publicKey,
|
|
1111
1125
|
onProgress,
|
|
1112
|
-
signal
|
|
1113
|
-
|
|
1126
|
+
signal,
|
|
1127
|
+
integration
|
|
1128
|
+
}).catch((error) => {
|
|
1114
1129
|
if (attempt < multipartMaxAttempts) {
|
|
1115
1130
|
return retry();
|
|
1116
1131
|
}
|
|
@@ -1145,14 +1160,19 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
|
|
|
1145
1160
|
userAgent,
|
|
1146
1161
|
retryThrottledRequestMaxTimes
|
|
1147
1162
|
})
|
|
1148
|
-
.then(({ uuid, parts }) =>
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1163
|
+
.then(({ uuid, parts }) => {
|
|
1164
|
+
const getChunk = prepareChunks(file, size, multipartChunkSize);
|
|
1165
|
+
return Promise.all([
|
|
1166
|
+
uuid,
|
|
1167
|
+
runWithConcurrency(maxConcurrentRequests, parts.map((url, index) => () => uploadPartWithRetry(getChunk(index), url, {
|
|
1168
|
+
publicKey,
|
|
1169
|
+
onProgress: createProgressHandler(parts.length, index),
|
|
1170
|
+
signal,
|
|
1171
|
+
integration,
|
|
1172
|
+
multipartMaxAttempts
|
|
1173
|
+
})))
|
|
1174
|
+
]);
|
|
1175
|
+
})
|
|
1156
1176
|
.then(([uuid]) => multipartComplete(uuid, {
|
|
1157
1177
|
publicKey,
|
|
1158
1178
|
baseURL,
|
|
@@ -1161,7 +1181,7 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
|
|
|
1161
1181
|
userAgent,
|
|
1162
1182
|
retryThrottledRequestMaxTimes
|
|
1163
1183
|
}))
|
|
1164
|
-
.then(fileInfo => {
|
|
1184
|
+
.then((fileInfo) => {
|
|
1165
1185
|
if (fileInfo.isReady) {
|
|
1166
1186
|
return fileInfo;
|
|
1167
1187
|
}
|
|
@@ -1179,13 +1199,13 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
|
|
|
1179
1199
|
});
|
|
1180
1200
|
}
|
|
1181
1201
|
})
|
|
1182
|
-
.then(fileInfo => new UploadcareFile(fileInfo, { baseCDN }));
|
|
1202
|
+
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
|
|
1183
1203
|
};
|
|
1184
1204
|
|
|
1185
1205
|
/**
|
|
1186
1206
|
* Uploads file from provided data.
|
|
1187
1207
|
*/
|
|
1188
|
-
function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartChunkSize
|
|
1208
|
+
function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartChunkSize, multipartMaxAttempts, maxConcurrentRequests, baseCDN = defaultSettings.baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, pusherKey }) {
|
|
1189
1209
|
if (isFileData(data)) {
|
|
1190
1210
|
const fileSize = getFileSize(data);
|
|
1191
1211
|
if (isMultipart(fileSize)) {
|
|
@@ -1193,6 +1213,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
|
|
|
1193
1213
|
publicKey,
|
|
1194
1214
|
contentType,
|
|
1195
1215
|
multipartChunkSize,
|
|
1216
|
+
multipartMaxAttempts,
|
|
1196
1217
|
fileName,
|
|
1197
1218
|
baseURL,
|
|
1198
1219
|
secureSignature,
|
|
@@ -1203,6 +1224,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
|
|
|
1203
1224
|
source,
|
|
1204
1225
|
integration,
|
|
1205
1226
|
userAgent,
|
|
1227
|
+
maxConcurrentRequests,
|
|
1206
1228
|
retryThrottledRequestMaxTimes,
|
|
1207
1229
|
baseCDN
|
|
1208
1230
|
});
|
|
@@ -1228,6 +1250,9 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
|
|
|
1228
1250
|
publicKey,
|
|
1229
1251
|
fileName,
|
|
1230
1252
|
baseURL,
|
|
1253
|
+
baseCDN,
|
|
1254
|
+
checkForUrlDuplicates,
|
|
1255
|
+
saveUrlForRecurrentUploads,
|
|
1231
1256
|
secureSignature,
|
|
1232
1257
|
secureExpire,
|
|
1233
1258
|
store,
|
|
@@ -1237,7 +1262,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
|
|
|
1237
1262
|
integration,
|
|
1238
1263
|
userAgent,
|
|
1239
1264
|
retryThrottledRequestMaxTimes,
|
|
1240
|
-
|
|
1265
|
+
pusherKey
|
|
1241
1266
|
});
|
|
1242
1267
|
}
|
|
1243
1268
|
if (isUuid(data)) {
|
|
@@ -1264,8 +1289,7 @@ class UploadcareGroup {
|
|
|
1264
1289
|
this.filesCount = groupInfo.filesCount;
|
|
1265
1290
|
this.totalSize = Object.values(groupInfo.files).reduce((acc, file) => acc + file.size, 0);
|
|
1266
1291
|
this.isStored = !!groupInfo.datetimeStored;
|
|
1267
|
-
this.isImage = !!Object.values(groupInfo.files).filter(file => file.isImage)
|
|
1268
|
-
.length;
|
|
1292
|
+
this.isImage = !!Object.values(groupInfo.files).filter((file) => file.isImage).length;
|
|
1269
1293
|
this.cdnUrl = groupInfo.cdnUrl;
|
|
1270
1294
|
this.files = files;
|
|
1271
1295
|
this.createdAt = groupInfo.datetimeCreated;
|
|
@@ -1341,8 +1365,8 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
|
|
|
1341
1365
|
contentType,
|
|
1342
1366
|
multipartChunkSize,
|
|
1343
1367
|
baseCDN
|
|
1344
|
-
}))).then(files => {
|
|
1345
|
-
const uuids = files.map(file => file.uuid);
|
|
1368
|
+
}))).then((files) => {
|
|
1369
|
+
const uuids = files.map((file) => file.uuid);
|
|
1346
1370
|
const addDefaultEffects = (file) => {
|
|
1347
1371
|
const cdnUrlModifiers = defaultEffects ? `-/${defaultEffects}` : null;
|
|
1348
1372
|
const cdnUrl = `${file.urlBase}${cdnUrlModifiers || ''}`;
|
|
@@ -1361,7 +1385,7 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
|
|
|
1361
1385
|
integration,
|
|
1362
1386
|
userAgent,
|
|
1363
1387
|
retryThrottledRequestMaxTimes
|
|
1364
|
-
}).then(groupInfo => new UploadcareGroup(groupInfo, filesInGroup));
|
|
1388
|
+
}).then((groupInfo) => new UploadcareGroup(groupInfo, filesInGroup));
|
|
1365
1389
|
});
|
|
1366
1390
|
}
|
|
1367
1391
|
|
|
@@ -1425,4 +1449,4 @@ class UploadClient {
|
|
|
1425
1449
|
}
|
|
1426
1450
|
}
|
|
1427
1451
|
|
|
1428
|
-
export { UploadClient, base, fromUrl, fromUrlStatus, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadFile, uploadFileGroup };
|
|
1452
|
+
export { UploadClient, UploadClientError, UploadcareFile, UploadcareGroup, base, fromUrl, fromUrlStatus, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadFromObject as uploadBase, uploadFile, uploadFileGroup, uploadFromUploaded, uploadFromUrl, uploadMultipart };
|