@uploadcare/upload-client 2.2.1-alpha.0 → 3.1.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 +21 -3
- package/dist/index.browser.cjs +222 -115
- package/dist/index.browser.js +219 -109
- package/dist/index.cjs +217 -115
- package/dist/index.js +214 -109
- package/dist/types.d.ts +43 -13
- package/package.json +3 -3
package/dist/index.browser.js
CHANGED
|
@@ -94,7 +94,15 @@ const request = ({ method, url, data, headers = {}, signal, onProgress }) => new
|
|
|
94
94
|
};
|
|
95
95
|
if (onProgress && typeof onProgress === 'function') {
|
|
96
96
|
xhr.upload.onprogress = (event) => {
|
|
97
|
-
|
|
97
|
+
if (event.lengthComputable) {
|
|
98
|
+
onProgress({
|
|
99
|
+
isComputable: true,
|
|
100
|
+
value: event.loaded / event.total
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
onProgress({ isComputable: false });
|
|
105
|
+
}
|
|
98
106
|
};
|
|
99
107
|
}
|
|
100
108
|
if (data) {
|
|
@@ -112,31 +120,97 @@ function identity(obj) {
|
|
|
112
120
|
const transformFile = identity;
|
|
113
121
|
var getFormData = () => new FormData();
|
|
114
122
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
/**
|
|
124
|
+
* FileData type guard.
|
|
125
|
+
*/
|
|
126
|
+
const isFileData = (data) => {
|
|
127
|
+
return (data !== undefined &&
|
|
128
|
+
((typeof Blob !== 'undefined' && data instanceof Blob) ||
|
|
129
|
+
(typeof File !== 'undefined' && data instanceof File) ||
|
|
130
|
+
(typeof Buffer !== 'undefined' && data instanceof Buffer)));
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Uuid type guard.
|
|
134
|
+
*/
|
|
135
|
+
const isUuid = (data) => {
|
|
136
|
+
const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
|
|
137
|
+
const regExp = new RegExp(UUID_REGEX);
|
|
138
|
+
return !isFileData(data) && regExp.test(data);
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Url type guard.
|
|
142
|
+
*
|
|
143
|
+
* @param {NodeFile | BrowserFile | Url | Uuid} data
|
|
144
|
+
*/
|
|
145
|
+
const isUrl = (data) => {
|
|
146
|
+
const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
|
|
147
|
+
const regExp = new RegExp(URL_REGEX);
|
|
148
|
+
return !isFileData(data) && regExp.test(data);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const isSimpleValue = (value) => {
|
|
152
|
+
return (typeof value === 'string' ||
|
|
153
|
+
typeof value === 'number' ||
|
|
154
|
+
typeof value === 'undefined');
|
|
155
|
+
};
|
|
156
|
+
const isObjectValue = (value) => {
|
|
157
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
158
|
+
};
|
|
159
|
+
const isFileValue = (value) => !!value &&
|
|
160
|
+
typeof value === 'object' &&
|
|
161
|
+
'data' in value &&
|
|
162
|
+
isFileData(value.data);
|
|
163
|
+
function collectParams(params, inputKey, inputValue) {
|
|
164
|
+
if (isFileValue(inputValue)) {
|
|
165
|
+
const name = inputValue.name;
|
|
166
|
+
const file = transformFile(inputValue.data); // lgtm [js/superfluous-trailing-arguments]
|
|
167
|
+
params.push(name ? [inputKey, file, name] : [inputKey, file]);
|
|
168
|
+
}
|
|
169
|
+
else if (isObjectValue(inputValue)) {
|
|
170
|
+
for (const [key, value] of Object.entries(inputValue)) {
|
|
171
|
+
if (typeof value !== 'undefined') {
|
|
172
|
+
params.push([`${inputKey}[${key}]`, String(value)]);
|
|
173
|
+
}
|
|
130
174
|
}
|
|
131
175
|
}
|
|
176
|
+
else if (isSimpleValue(inputValue) && inputValue) {
|
|
177
|
+
params.push([inputKey, inputValue.toString()]);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function getFormDataParams(options) {
|
|
181
|
+
const params = [];
|
|
182
|
+
for (const [key, value] of Object.entries(options)) {
|
|
183
|
+
collectParams(params, key, value);
|
|
184
|
+
}
|
|
185
|
+
return params;
|
|
186
|
+
}
|
|
187
|
+
function buildFormData(options) {
|
|
188
|
+
const formData = getFormData();
|
|
189
|
+
const params = getFormDataParams(options);
|
|
190
|
+
for (const param of params) {
|
|
191
|
+
formData.append(...param);
|
|
192
|
+
}
|
|
132
193
|
return formData;
|
|
133
194
|
}
|
|
134
195
|
|
|
135
196
|
const serializePair = (key, value) => typeof value !== 'undefined' ? `${key}=${encodeURIComponent(value)}` : null;
|
|
197
|
+
// TODO: generalize value transforming logic and use it here and inside `buildFormData`
|
|
136
198
|
const createQuery = (query) => Object.entries(query)
|
|
137
|
-
.reduce((params, [key, value]) =>
|
|
138
|
-
|
|
139
|
-
|
|
199
|
+
.reduce((params, [key, value]) => {
|
|
200
|
+
let param;
|
|
201
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
202
|
+
param = Object.entries(value)
|
|
203
|
+
.filter((entry) => typeof entry[1] !== 'undefined')
|
|
204
|
+
.map((entry) => serializePair(`${key}[${entry[0]}]`, String(entry[1])));
|
|
205
|
+
}
|
|
206
|
+
else if (Array.isArray(value)) {
|
|
207
|
+
param = value.map((val) => serializePair(`${key}[]`, val));
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
param = serializePair(key, value);
|
|
211
|
+
}
|
|
212
|
+
return params.concat(param);
|
|
213
|
+
}, [])
|
|
140
214
|
.filter((x) => !!x)
|
|
141
215
|
.join('&');
|
|
142
216
|
const getUrl = (base, path, query) => [
|
|
@@ -168,7 +242,7 @@ const defaultSettings = {
|
|
|
168
242
|
const defaultContentType = 'application/octet-stream';
|
|
169
243
|
const defaultFilename = 'original';
|
|
170
244
|
|
|
171
|
-
var version = '
|
|
245
|
+
var version = '3.1.0';
|
|
172
246
|
|
|
173
247
|
/**
|
|
174
248
|
* Returns User Agent based on version and settings.
|
|
@@ -268,11 +342,15 @@ function retryIfThrottled(fn, retryThrottledMaxTimes) {
|
|
|
268
342
|
}));
|
|
269
343
|
}
|
|
270
344
|
|
|
345
|
+
function getStoreValue(store) {
|
|
346
|
+
return typeof store === 'undefined' ? 'auto' : store ? '1' : '0';
|
|
347
|
+
}
|
|
348
|
+
|
|
271
349
|
/**
|
|
272
350
|
* Performs file uploading request to Uploadcare Upload API.
|
|
273
351
|
* Can be canceled and has progress.
|
|
274
352
|
*/
|
|
275
|
-
function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
353
|
+
function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
276
354
|
return retryIfThrottled(() => {
|
|
277
355
|
var _a;
|
|
278
356
|
return request({
|
|
@@ -283,17 +361,18 @@ function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, se
|
|
|
283
361
|
headers: {
|
|
284
362
|
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
285
363
|
},
|
|
286
|
-
data: buildFormData(
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
364
|
+
data: buildFormData({
|
|
365
|
+
file: {
|
|
366
|
+
data: file,
|
|
367
|
+
name: (_a = fileName !== null && fileName !== void 0 ? fileName : file.name) !== null && _a !== void 0 ? _a : defaultFilename
|
|
368
|
+
},
|
|
369
|
+
UPLOADCARE_PUB_KEY: publicKey,
|
|
370
|
+
UPLOADCARE_STORE: getStoreValue(store),
|
|
371
|
+
signature: secureSignature,
|
|
372
|
+
expire: secureExpire,
|
|
373
|
+
source: source,
|
|
374
|
+
metadata
|
|
375
|
+
}),
|
|
297
376
|
signal,
|
|
298
377
|
onProgress
|
|
299
378
|
}).then(({ data, headers, request }) => {
|
|
@@ -316,7 +395,7 @@ var TypeEnum;
|
|
|
316
395
|
/**
|
|
317
396
|
* Uploading files from URL.
|
|
318
397
|
*/
|
|
319
|
-
function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
398
|
+
function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
320
399
|
return retryIfThrottled(() => request({
|
|
321
400
|
method: 'POST',
|
|
322
401
|
headers: {
|
|
@@ -326,13 +405,14 @@ function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, stor
|
|
|
326
405
|
jsonerrors: 1,
|
|
327
406
|
pub_key: publicKey,
|
|
328
407
|
source_url: sourceUrl,
|
|
329
|
-
store:
|
|
408
|
+
store: getStoreValue(store),
|
|
330
409
|
filename: fileName,
|
|
331
410
|
check_URL_duplicates: checkForUrlDuplicates ? 1 : undefined,
|
|
332
411
|
save_URL_duplicates: saveUrlForRecurrentUploads ? 1 : undefined,
|
|
333
412
|
signature: secureSignature,
|
|
334
413
|
expire: secureExpire,
|
|
335
|
-
source: source
|
|
414
|
+
source: source,
|
|
415
|
+
metadata
|
|
336
416
|
}),
|
|
337
417
|
signal
|
|
338
418
|
}).then(({ data, headers, request }) => {
|
|
@@ -475,24 +555,25 @@ function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, sour
|
|
|
475
555
|
/**
|
|
476
556
|
* Start multipart uploading.
|
|
477
557
|
*/
|
|
478
|
-
function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
558
|
+
function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
479
559
|
return retryIfThrottled(() => request({
|
|
480
560
|
method: 'POST',
|
|
481
561
|
url: getUrl(baseURL, '/multipart/start/', { jsonerrors: 1 }),
|
|
482
562
|
headers: {
|
|
483
563
|
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
484
564
|
},
|
|
485
|
-
data: buildFormData(
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
565
|
+
data: buildFormData({
|
|
566
|
+
filename: fileName !== null && fileName !== void 0 ? fileName : defaultFilename,
|
|
567
|
+
size: size,
|
|
568
|
+
content_type: contentType !== null && contentType !== void 0 ? contentType : defaultContentType,
|
|
569
|
+
part_size: multipartChunkSize,
|
|
570
|
+
UPLOADCARE_STORE: getStoreValue(store),
|
|
571
|
+
UPLOADCARE_PUB_KEY: publicKey,
|
|
572
|
+
signature: secureSignature,
|
|
573
|
+
expire: secureExpire,
|
|
574
|
+
source: source,
|
|
575
|
+
metadata
|
|
576
|
+
}),
|
|
496
577
|
signal
|
|
497
578
|
}).then(({ data, headers, request }) => {
|
|
498
579
|
const response = camelizeKeys(JSON.parse(data));
|
|
@@ -515,13 +596,17 @@ function multipartUpload(part, url, { signal, onProgress }) {
|
|
|
515
596
|
method: 'PUT',
|
|
516
597
|
url,
|
|
517
598
|
data: part,
|
|
518
|
-
|
|
599
|
+
// Upload request can't be non-computable because we always know exact size
|
|
600
|
+
onProgress: onProgress,
|
|
519
601
|
signal
|
|
520
602
|
})
|
|
521
603
|
.then((result) => {
|
|
522
604
|
// hack for node ¯\_(ツ)_/¯
|
|
523
605
|
if (onProgress)
|
|
524
|
-
onProgress({
|
|
606
|
+
onProgress({
|
|
607
|
+
isComputable: true,
|
|
608
|
+
value: 1
|
|
609
|
+
});
|
|
525
610
|
return result;
|
|
526
611
|
})
|
|
527
612
|
.then(({ status }) => ({ code: status }));
|
|
@@ -537,11 +622,11 @@ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL,
|
|
|
537
622
|
headers: {
|
|
538
623
|
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
539
624
|
},
|
|
540
|
-
data: buildFormData(
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
625
|
+
data: buildFormData({
|
|
626
|
+
uuid: uuid,
|
|
627
|
+
UPLOADCARE_PUB_KEY: publicKey,
|
|
628
|
+
source: source
|
|
629
|
+
}),
|
|
545
630
|
signal
|
|
546
631
|
}).then(({ data, headers, request }) => {
|
|
547
632
|
const response = camelizeKeys(JSON.parse(data));
|
|
@@ -567,6 +652,8 @@ class UploadcareFile {
|
|
|
567
652
|
this.originalFilename = null;
|
|
568
653
|
this.imageInfo = null;
|
|
569
654
|
this.videoInfo = null;
|
|
655
|
+
this.contentInfo = null;
|
|
656
|
+
this.metadata = null;
|
|
570
657
|
const { uuid, s3Bucket } = fileInfo;
|
|
571
658
|
const urlBase = s3Bucket
|
|
572
659
|
? `https://${s3Bucket}.s3.amazonaws.com/${uuid}/${fileInfo.filename}`
|
|
@@ -586,6 +673,8 @@ class UploadcareFile {
|
|
|
586
673
|
this.originalFilename = fileInfo.originalFilename;
|
|
587
674
|
this.imageInfo = camelizeKeys(fileInfo.imageInfo);
|
|
588
675
|
this.videoInfo = camelizeKeys(fileInfo.videoInfo);
|
|
676
|
+
this.contentInfo = camelizeKeys(fileInfo.contentInfo);
|
|
677
|
+
this.metadata = fileInfo.metadata || null;
|
|
589
678
|
}
|
|
590
679
|
}
|
|
591
680
|
|
|
@@ -630,14 +719,14 @@ function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent,
|
|
|
630
719
|
if (response.isReady) {
|
|
631
720
|
return response;
|
|
632
721
|
}
|
|
633
|
-
onProgress && onProgress({ value: 1 });
|
|
722
|
+
onProgress && onProgress({ isComputable: true, value: 1 });
|
|
634
723
|
return false;
|
|
635
724
|
}),
|
|
636
725
|
signal
|
|
637
726
|
});
|
|
638
727
|
}
|
|
639
728
|
|
|
640
|
-
const uploadFromObject = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN }) => {
|
|
729
|
+
const uploadFromObject = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN, metadata }) => {
|
|
641
730
|
return base(file, {
|
|
642
731
|
publicKey,
|
|
643
732
|
fileName,
|
|
@@ -650,7 +739,8 @@ const uploadFromObject = (file, { publicKey, fileName, baseURL, secureSignature,
|
|
|
650
739
|
source,
|
|
651
740
|
integration,
|
|
652
741
|
userAgent,
|
|
653
|
-
retryThrottledRequestMaxTimes
|
|
742
|
+
retryThrottledRequestMaxTimes,
|
|
743
|
+
metadata
|
|
654
744
|
})
|
|
655
745
|
.then(({ file }) => {
|
|
656
746
|
return isReadyPoll({
|
|
@@ -880,13 +970,25 @@ function pollStrategy({ token, publicKey, baseURL, integration, userAgent, retry
|
|
|
880
970
|
return new UploadClientError(`Token "${token}" was not found.`);
|
|
881
971
|
}
|
|
882
972
|
case Status.Progress: {
|
|
883
|
-
if (onProgress)
|
|
884
|
-
|
|
973
|
+
if (onProgress) {
|
|
974
|
+
if (response.total === 'unknown') {
|
|
975
|
+
onProgress({ isComputable: false });
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
onProgress({
|
|
979
|
+
isComputable: true,
|
|
980
|
+
value: response.done / response.total
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
}
|
|
885
984
|
return false;
|
|
886
985
|
}
|
|
887
986
|
case Status.Success: {
|
|
888
987
|
if (onProgress)
|
|
889
|
-
onProgress({
|
|
988
|
+
onProgress({
|
|
989
|
+
isComputable: true,
|
|
990
|
+
value: response.done / response.total
|
|
991
|
+
});
|
|
890
992
|
return response;
|
|
891
993
|
}
|
|
892
994
|
default: {
|
|
@@ -912,14 +1014,25 @@ const pushStrategy = ({ token, pusherKey, signal, onProgress }) => new Promise((
|
|
|
912
1014
|
switch (result.status) {
|
|
913
1015
|
case Status.Progress: {
|
|
914
1016
|
if (onProgress) {
|
|
915
|
-
|
|
1017
|
+
if (result.total === 'unknown') {
|
|
1018
|
+
onProgress({ isComputable: false });
|
|
1019
|
+
}
|
|
1020
|
+
else {
|
|
1021
|
+
onProgress({
|
|
1022
|
+
isComputable: true,
|
|
1023
|
+
value: result.done / result.total
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
916
1026
|
}
|
|
917
1027
|
break;
|
|
918
1028
|
}
|
|
919
1029
|
case Status.Success: {
|
|
920
1030
|
destroy();
|
|
921
1031
|
if (onProgress)
|
|
922
|
-
onProgress({
|
|
1032
|
+
onProgress({
|
|
1033
|
+
isComputable: true,
|
|
1034
|
+
value: result.done / result.total
|
|
1035
|
+
});
|
|
923
1036
|
resolve(result);
|
|
924
1037
|
break;
|
|
925
1038
|
}
|
|
@@ -930,7 +1043,7 @@ const pushStrategy = ({ token, pusherKey, signal, onProgress }) => new Promise((
|
|
|
930
1043
|
}
|
|
931
1044
|
});
|
|
932
1045
|
});
|
|
933
|
-
const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, pusherKey = defaultSettings.pusherKey }) => Promise.resolve(preconnect(pusherKey))
|
|
1046
|
+
const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, pusherKey = defaultSettings.pusherKey, metadata }) => Promise.resolve(preconnect(pusherKey))
|
|
934
1047
|
.then(() => fromUrl(sourceUrl, {
|
|
935
1048
|
publicKey,
|
|
936
1049
|
fileName,
|
|
@@ -944,7 +1057,8 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
|
|
|
944
1057
|
source,
|
|
945
1058
|
integration,
|
|
946
1059
|
userAgent,
|
|
947
|
-
retryThrottledRequestMaxTimes
|
|
1060
|
+
retryThrottledRequestMaxTimes,
|
|
1061
|
+
metadata
|
|
948
1062
|
}))
|
|
949
1063
|
.catch((error) => {
|
|
950
1064
|
const pusher = getPusher(pusherKey);
|
|
@@ -1007,39 +1121,14 @@ const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProg
|
|
|
1007
1121
|
.then((result) => {
|
|
1008
1122
|
// hack for node ¯\_(ツ)_/¯
|
|
1009
1123
|
if (onProgress)
|
|
1010
|
-
onProgress({
|
|
1124
|
+
onProgress({
|
|
1125
|
+
isComputable: true,
|
|
1126
|
+
value: 1
|
|
1127
|
+
});
|
|
1011
1128
|
return result;
|
|
1012
1129
|
});
|
|
1013
1130
|
};
|
|
1014
1131
|
|
|
1015
|
-
/**
|
|
1016
|
-
* FileData type guard.
|
|
1017
|
-
*/
|
|
1018
|
-
const isFileData = (data) => {
|
|
1019
|
-
return (data !== undefined &&
|
|
1020
|
-
((typeof Blob !== 'undefined' && data instanceof Blob) ||
|
|
1021
|
-
(typeof File !== 'undefined' && data instanceof File) ||
|
|
1022
|
-
(typeof Buffer !== 'undefined' && data instanceof Buffer)));
|
|
1023
|
-
};
|
|
1024
|
-
/**
|
|
1025
|
-
* Uuid type guard.
|
|
1026
|
-
*/
|
|
1027
|
-
const isUuid = (data) => {
|
|
1028
|
-
const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
|
|
1029
|
-
const regExp = new RegExp(UUID_REGEX);
|
|
1030
|
-
return !isFileData(data) && regExp.test(data);
|
|
1031
|
-
};
|
|
1032
|
-
/**
|
|
1033
|
-
* Url type guard.
|
|
1034
|
-
*
|
|
1035
|
-
* @param {NodeFile | BrowserFile | Url | Uuid} data
|
|
1036
|
-
*/
|
|
1037
|
-
const isUrl = (data) => {
|
|
1038
|
-
const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
|
|
1039
|
-
const regExp = new RegExp(URL_REGEX);
|
|
1040
|
-
return !isFileData(data) && regExp.test(data);
|
|
1041
|
-
};
|
|
1042
|
-
|
|
1043
1132
|
/**
|
|
1044
1133
|
* Get file size.
|
|
1045
1134
|
*/
|
|
@@ -1109,19 +1198,25 @@ const uploadPartWithRetry = (chunk, url, { publicKey, onProgress, signal, integr
|
|
|
1109
1198
|
}
|
|
1110
1199
|
throw error;
|
|
1111
1200
|
}));
|
|
1112
|
-
const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, maxConcurrentRequests = defaultSettings.maxConcurrentRequests, multipartMaxAttempts = defaultSettings.multipartMaxAttempts, baseCDN }) => {
|
|
1201
|
+
const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, maxConcurrentRequests = defaultSettings.maxConcurrentRequests, multipartMaxAttempts = defaultSettings.multipartMaxAttempts, baseCDN, metadata }) => {
|
|
1113
1202
|
const size = fileSize || getFileSize(file);
|
|
1114
1203
|
let progressValues;
|
|
1115
|
-
const createProgressHandler = (
|
|
1204
|
+
const createProgressHandler = (totalChunks, chunkIdx) => {
|
|
1116
1205
|
if (!onProgress)
|
|
1117
1206
|
return;
|
|
1118
1207
|
if (!progressValues) {
|
|
1119
|
-
progressValues = Array(
|
|
1208
|
+
progressValues = Array(totalChunks).fill(0);
|
|
1120
1209
|
}
|
|
1121
1210
|
const sum = (values) => values.reduce((sum, next) => sum + next, 0);
|
|
1122
|
-
return (
|
|
1123
|
-
|
|
1124
|
-
|
|
1211
|
+
return (info) => {
|
|
1212
|
+
if (!info.isComputable) {
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
progressValues[chunkIdx] = info.value;
|
|
1216
|
+
onProgress({
|
|
1217
|
+
isComputable: true,
|
|
1218
|
+
value: sum(progressValues) / totalChunks
|
|
1219
|
+
});
|
|
1125
1220
|
};
|
|
1126
1221
|
};
|
|
1127
1222
|
return multipartStart(size, {
|
|
@@ -1136,7 +1231,8 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
|
|
|
1136
1231
|
source,
|
|
1137
1232
|
integration,
|
|
1138
1233
|
userAgent,
|
|
1139
|
-
retryThrottledRequestMaxTimes
|
|
1234
|
+
retryThrottledRequestMaxTimes,
|
|
1235
|
+
metadata
|
|
1140
1236
|
})
|
|
1141
1237
|
.then(({ uuid, parts }) => {
|
|
1142
1238
|
const getChunk = prepareChunks(file, size, multipartChunkSize);
|
|
@@ -1183,10 +1279,10 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
|
|
|
1183
1279
|
/**
|
|
1184
1280
|
* Uploads file from provided data.
|
|
1185
1281
|
*/
|
|
1186
|
-
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 }) {
|
|
1282
|
+
function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartMinFileSize, multipartChunkSize, multipartMaxAttempts, maxConcurrentRequests, baseCDN = defaultSettings.baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, pusherKey, metadata }) {
|
|
1187
1283
|
if (isFileData(data)) {
|
|
1188
1284
|
const fileSize = getFileSize(data);
|
|
1189
|
-
if (isMultipart(fileSize)) {
|
|
1285
|
+
if (isMultipart(fileSize, multipartMinFileSize)) {
|
|
1190
1286
|
return uploadMultipart(data, {
|
|
1191
1287
|
publicKey,
|
|
1192
1288
|
contentType,
|
|
@@ -1204,7 +1300,8 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
|
|
|
1204
1300
|
userAgent,
|
|
1205
1301
|
maxConcurrentRequests,
|
|
1206
1302
|
retryThrottledRequestMaxTimes,
|
|
1207
|
-
baseCDN
|
|
1303
|
+
baseCDN,
|
|
1304
|
+
metadata
|
|
1208
1305
|
});
|
|
1209
1306
|
}
|
|
1210
1307
|
return uploadFromObject(data, {
|
|
@@ -1220,7 +1317,8 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
|
|
|
1220
1317
|
integration,
|
|
1221
1318
|
userAgent,
|
|
1222
1319
|
retryThrottledRequestMaxTimes,
|
|
1223
|
-
baseCDN
|
|
1320
|
+
baseCDN,
|
|
1321
|
+
metadata
|
|
1224
1322
|
});
|
|
1225
1323
|
}
|
|
1226
1324
|
if (isUrl(data)) {
|
|
@@ -1240,7 +1338,8 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
|
|
|
1240
1338
|
integration,
|
|
1241
1339
|
userAgent,
|
|
1242
1340
|
retryThrottledRequestMaxTimes,
|
|
1243
|
-
pusherKey
|
|
1341
|
+
pusherKey,
|
|
1342
|
+
metadata
|
|
1244
1343
|
});
|
|
1245
1344
|
}
|
|
1246
1345
|
if (isUuid(data)) {
|
|
@@ -1314,6 +1413,7 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
|
|
|
1314
1413
|
throw new TypeError(`Group uploading from "${data}" is not supported`);
|
|
1315
1414
|
}
|
|
1316
1415
|
let progressValues;
|
|
1416
|
+
let isStillComputable = true;
|
|
1317
1417
|
const filesCount = data.length;
|
|
1318
1418
|
const createProgressHandler = (size, index) => {
|
|
1319
1419
|
if (!onProgress)
|
|
@@ -1322,9 +1422,14 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
|
|
|
1322
1422
|
progressValues = Array(size).fill(0);
|
|
1323
1423
|
}
|
|
1324
1424
|
const normalize = (values) => values.reduce((sum, next) => sum + next) / size;
|
|
1325
|
-
return (
|
|
1326
|
-
|
|
1327
|
-
|
|
1425
|
+
return (info) => {
|
|
1426
|
+
if (!info.isComputable || !isStillComputable) {
|
|
1427
|
+
isStillComputable = false;
|
|
1428
|
+
onProgress({ isComputable: false });
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
progressValues[index] = info.value;
|
|
1432
|
+
onProgress({ isComputable: true, value: normalize(progressValues) });
|
|
1328
1433
|
};
|
|
1329
1434
|
};
|
|
1330
1435
|
return Promise.all(data.map((file, index) => uploadFile(file, {
|
|
@@ -1363,7 +1468,12 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
|
|
|
1363
1468
|
integration,
|
|
1364
1469
|
userAgent,
|
|
1365
1470
|
retryThrottledRequestMaxTimes
|
|
1366
|
-
})
|
|
1471
|
+
})
|
|
1472
|
+
.then((groupInfo) => new UploadcareGroup(groupInfo, filesInGroup))
|
|
1473
|
+
.then((group) => {
|
|
1474
|
+
onProgress && onProgress({ isComputable: true, value: 1 });
|
|
1475
|
+
return group;
|
|
1476
|
+
});
|
|
1367
1477
|
});
|
|
1368
1478
|
}
|
|
1369
1479
|
|