@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 CHANGED
@@ -81,8 +81,8 @@ You can track uploading progress:
81
81
 
82
82
  ```javascript
83
83
  const fileUUID = 'edfdf045-34c0-4087-bbdd-e3834921f890'
84
- const onProgress = ({ value }) => {
85
- console.log(value)
84
+ const onProgress = ({ isComputable, value }) => {
85
+ console.log(isComputable, value)
86
86
  }
87
87
 
88
88
  client
@@ -90,6 +90,10 @@ client
90
90
  .then(file => console.log(file.uuid))
91
91
  ```
92
92
 
93
+ Note that `isComputable` flag can be `false` is some cases of uploading from the URL.
94
+ If we can't calculate the file size, progress info will look like `{ isComputable: false }` without a `value`.
95
+ Successful uploading progress will be always `{ isComputable: true, value: 1 }`.
96
+
93
97
  You can cancel file uploading and track this event:
94
98
 
95
99
  ```javascript
@@ -183,7 +187,7 @@ Also, you can use low-level wrappers to call the API endpoints directly:
183
187
  ```javascript
184
188
  import { base, AbortController } from '@uploadcare/upload-client'
185
189
 
186
- const onProgress = ({ value }) => console.log(value)
190
+ const onProgress = ({ isComputable, value }) => console.log(isComputable, value)
187
191
  const abortController = new AbortController()
188
192
 
189
193
  base(fileData, { onProgress, signal: abortController }) // fileData must be `Blob` or `File` or `Buffer`
@@ -393,6 +397,20 @@ This setting is needed for correct multipart uploads.
393
397
 
394
398
  Defaults to `application/octet-stream`.
395
399
 
400
+ ### `metadata: Metadata`
401
+
402
+ ```typescript
403
+ type Metadata = {
404
+ [key: string]: string
405
+ }
406
+
407
+ Metadata is additional, arbitrary data, associated with uploaded file.
408
+
409
+ Non-string values will be converted to `string`. `undefined` values will be ignored.
410
+
411
+ See [https://uploadcare.com/api-refs/rest-api/v0.7.0/#tag/File-Metadata][REST API reference] for details.
412
+
413
+
396
414
  ## Testing
397
415
 
398
416
  ```
@@ -152,7 +152,15 @@ var request = function (_a) {
152
152
  };
153
153
  if (onProgress && typeof onProgress === 'function') {
154
154
  xhr.upload.onprogress = function (event) {
155
- onProgress({ value: event.loaded / event.total });
155
+ if (event.lengthComputable) {
156
+ onProgress({
157
+ isComputable: true,
158
+ value: event.loaded / event.total
159
+ });
160
+ }
161
+ else {
162
+ onProgress({ isComputable: false });
163
+ }
156
164
  };
157
165
  }
158
166
  if (data) {
@@ -171,28 +179,80 @@ function identity(obj) {
171
179
  var transformFile = identity;
172
180
  var getFormData = (function () { return new FormData(); });
173
181
 
174
- var isFileTuple = function (tuple) {
175
- return tuple[0] === 'file';
182
+ /**
183
+ * FileData type guard.
184
+ */
185
+ var isFileData = function (data) {
186
+ return (data !== undefined &&
187
+ ((typeof Blob !== 'undefined' && data instanceof Blob) ||
188
+ (typeof File !== 'undefined' && data instanceof File) ||
189
+ (typeof Buffer !== 'undefined' && data instanceof Buffer)));
176
190
  };
177
- function buildFormData(body) {
178
- var formData = getFormData();
179
- var _loop_1 = function (tuple) {
180
- if (Array.isArray(tuple[1])) {
181
- // refactor this
182
- tuple[1].forEach(function (val) { return val && formData.append(tuple[0] + '[]', "" + val); });
183
- }
184
- else if (isFileTuple(tuple)) {
185
- var name_1 = tuple[2];
186
- var file = transformFile(tuple[1]); // lgtm[js/superfluous-trailing-arguments]
187
- formData.append(tuple[0], file, name_1);
188
- }
189
- else if (tuple[1] != null) {
190
- formData.append(tuple[0], "" + tuple[1]);
191
+ /**
192
+ * Uuid type guard.
193
+ */
194
+ var isUuid = function (data) {
195
+ var UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
196
+ var regExp = new RegExp(UUID_REGEX);
197
+ return !isFileData(data) && regExp.test(data);
198
+ };
199
+ /**
200
+ * Url type guard.
201
+ *
202
+ * @param {NodeFile | BrowserFile | Url | Uuid} data
203
+ */
204
+ var isUrl = function (data) {
205
+ var URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
206
+ var regExp = new RegExp(URL_REGEX);
207
+ return !isFileData(data) && regExp.test(data);
208
+ };
209
+
210
+ var isSimpleValue = function (value) {
211
+ return (typeof value === 'string' ||
212
+ typeof value === 'number' ||
213
+ typeof value === 'undefined');
214
+ };
215
+ var isObjectValue = function (value) {
216
+ return !!value && typeof value === 'object' && !Array.isArray(value);
217
+ };
218
+ var isFileValue = function (value) {
219
+ return !!value &&
220
+ typeof value === 'object' &&
221
+ 'data' in value &&
222
+ isFileData(value.data);
223
+ };
224
+ function collectParams(params, inputKey, inputValue) {
225
+ if (isFileValue(inputValue)) {
226
+ var name_1 = inputValue.name;
227
+ var file = transformFile(inputValue.data); // lgtm [js/superfluous-trailing-arguments]
228
+ params.push(name_1 ? [inputKey, file, name_1] : [inputKey, file]);
229
+ }
230
+ else if (isObjectValue(inputValue)) {
231
+ for (var _i = 0, _a = Object.entries(inputValue); _i < _a.length; _i++) {
232
+ var _b = _a[_i], key = _b[0], value = _b[1];
233
+ if (typeof value !== 'undefined') {
234
+ params.push([inputKey + "[" + key + "]", String(value)]);
235
+ }
191
236
  }
192
- };
193
- for (var _i = 0, body_1 = body; _i < body_1.length; _i++) {
194
- var tuple = body_1[_i];
195
- _loop_1(tuple);
237
+ }
238
+ else if (isSimpleValue(inputValue) && inputValue) {
239
+ params.push([inputKey, inputValue.toString()]);
240
+ }
241
+ }
242
+ function getFormDataParams(options) {
243
+ var params = [];
244
+ for (var _i = 0, _a = Object.entries(options); _i < _a.length; _i++) {
245
+ var _b = _a[_i], key = _b[0], value = _b[1];
246
+ collectParams(params, key, value);
247
+ }
248
+ return params;
249
+ }
250
+ function buildFormData(options) {
251
+ var formData = getFormData();
252
+ var params = getFormDataParams(options);
253
+ for (var _i = 0, params_1 = params; _i < params_1.length; _i++) {
254
+ var param = params_1[_i];
255
+ formData.append.apply(formData, param);
196
256
  }
197
257
  return formData;
198
258
  }
@@ -200,13 +260,26 @@ function buildFormData(body) {
200
260
  var serializePair = function (key, value) {
201
261
  return typeof value !== 'undefined' ? key + "=" + encodeURIComponent(value) : null;
202
262
  };
263
+ // TODO: generalize value transforming logic and use it here and inside `buildFormData`
203
264
  var createQuery = function (query) {
204
265
  return Object.entries(query)
205
266
  .reduce(function (params, _a) {
206
267
  var key = _a[0], value = _a[1];
207
- return params.concat(Array.isArray(value)
208
- ? value.map(function (value) { return serializePair(key + "[]", value); })
209
- : serializePair(key, value));
268
+ var param;
269
+ if (typeof value === 'object' && !Array.isArray(value)) {
270
+ param = Object.entries(value)
271
+ .filter(function (entry) { return typeof entry[1] !== 'undefined'; })
272
+ .map(function (entry) {
273
+ return serializePair(key + "[" + entry[0] + "]", String(entry[1]));
274
+ });
275
+ }
276
+ else if (Array.isArray(value)) {
277
+ param = value.map(function (val) { return serializePair(key + "[]", val); });
278
+ }
279
+ else {
280
+ param = serializePair(key, value);
281
+ }
282
+ return params.concat(param);
210
283
  }, [])
211
284
  .filter(function (x) { return !!x; })
212
285
  .join('&');
@@ -242,7 +315,7 @@ var defaultSettings = {
242
315
  var defaultContentType = 'application/octet-stream';
243
316
  var defaultFilename = 'original';
244
317
 
245
- var version = '2.2.0';
318
+ var version = '3.1.0';
246
319
 
247
320
  /**
248
321
  * Returns User Agent based on version and settings.
@@ -353,12 +426,16 @@ function retryIfThrottled(fn, retryThrottledMaxTimes) {
353
426
  });
354
427
  }
355
428
 
429
+ function getStoreValue(store) {
430
+ return typeof store === 'undefined' ? 'auto' : store ? '1' : '0';
431
+ }
432
+
356
433
  /**
357
434
  * Performs file uploading request to Uploadcare Upload API.
358
435
  * Can be canceled and has progress.
359
436
  */
360
437
  function base(file, _a) {
361
- var publicKey = _a.publicKey, fileName = _a.fileName, _b = _a.baseURL, baseURL = _b === void 0 ? defaultSettings.baseURL : _b, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, _c = _a.source, source = _c === void 0 ? 'local' : _c, integration = _a.integration, userAgent = _a.userAgent, _d = _a.retryThrottledRequestMaxTimes, retryThrottledRequestMaxTimes = _d === void 0 ? defaultSettings.retryThrottledRequestMaxTimes : _d;
438
+ var publicKey = _a.publicKey, fileName = _a.fileName, _b = _a.baseURL, baseURL = _b === void 0 ? defaultSettings.baseURL : _b, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, _c = _a.source, source = _c === void 0 ? 'local' : _c, integration = _a.integration, userAgent = _a.userAgent, _d = _a.retryThrottledRequestMaxTimes, retryThrottledRequestMaxTimes = _d === void 0 ? defaultSettings.retryThrottledRequestMaxTimes : _d, metadata = _a.metadata;
362
439
  return retryIfThrottled(function () {
363
440
  var _a;
364
441
  return request({
@@ -369,17 +446,18 @@ function base(file, _a) {
369
446
  headers: {
370
447
  'X-UC-User-Agent': getUserAgent({ publicKey: publicKey, integration: integration, userAgent: userAgent })
371
448
  },
372
- data: buildFormData([
373
- ['file', file, (_a = fileName !== null && fileName !== void 0 ? fileName : file.name) !== null && _a !== void 0 ? _a : defaultFilename],
374
- ['UPLOADCARE_PUB_KEY', publicKey],
375
- [
376
- 'UPLOADCARE_STORE',
377
- typeof store === 'undefined' ? 'auto' : store ? 1 : 0
378
- ],
379
- ['signature', secureSignature],
380
- ['expire', secureExpire],
381
- ['source', source]
382
- ]),
449
+ data: buildFormData({
450
+ file: {
451
+ data: file,
452
+ name: (_a = fileName !== null && fileName !== void 0 ? fileName : file.name) !== null && _a !== void 0 ? _a : defaultFilename
453
+ },
454
+ UPLOADCARE_PUB_KEY: publicKey,
455
+ UPLOADCARE_STORE: getStoreValue(store),
456
+ signature: secureSignature,
457
+ expire: secureExpire,
458
+ source: source,
459
+ metadata: metadata
460
+ }),
383
461
  signal: signal,
384
462
  onProgress: onProgress
385
463
  }).then(function (_a) {
@@ -404,7 +482,7 @@ var TypeEnum;
404
482
  * Uploading files from URL.
405
483
  */
406
484
  function fromUrl(sourceUrl, _a) {
407
- var publicKey = _a.publicKey, _b = _a.baseURL, baseURL = _b === void 0 ? defaultSettings.baseURL : _b, store = _a.store, fileName = _a.fileName, checkForUrlDuplicates = _a.checkForUrlDuplicates, saveUrlForRecurrentUploads = _a.saveUrlForRecurrentUploads, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, _c = _a.source, source = _c === void 0 ? 'url' : _c, signal = _a.signal, integration = _a.integration, userAgent = _a.userAgent, _d = _a.retryThrottledRequestMaxTimes, retryThrottledRequestMaxTimes = _d === void 0 ? defaultSettings.retryThrottledRequestMaxTimes : _d;
485
+ var publicKey = _a.publicKey, _b = _a.baseURL, baseURL = _b === void 0 ? defaultSettings.baseURL : _b, store = _a.store, fileName = _a.fileName, checkForUrlDuplicates = _a.checkForUrlDuplicates, saveUrlForRecurrentUploads = _a.saveUrlForRecurrentUploads, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, _c = _a.source, source = _c === void 0 ? 'url' : _c, signal = _a.signal, integration = _a.integration, userAgent = _a.userAgent, _d = _a.retryThrottledRequestMaxTimes, retryThrottledRequestMaxTimes = _d === void 0 ? defaultSettings.retryThrottledRequestMaxTimes : _d, metadata = _a.metadata;
408
486
  return retryIfThrottled(function () {
409
487
  return request({
410
488
  method: 'POST',
@@ -415,13 +493,14 @@ function fromUrl(sourceUrl, _a) {
415
493
  jsonerrors: 1,
416
494
  pub_key: publicKey,
417
495
  source_url: sourceUrl,
418
- store: typeof store === 'undefined' ? 'auto' : store ? 1 : undefined,
496
+ store: getStoreValue(store),
419
497
  filename: fileName,
420
498
  check_URL_duplicates: checkForUrlDuplicates ? 1 : undefined,
421
499
  save_URL_duplicates: saveUrlForRecurrentUploads ? 1 : undefined,
422
500
  signature: secureSignature,
423
501
  expire: secureExpire,
424
- source: source
502
+ source: source,
503
+ metadata: metadata
425
504
  }),
426
505
  signal: signal
427
506
  }).then(function (_a) {
@@ -583,7 +662,7 @@ function info(uuid, _a) {
583
662
  * Start multipart uploading.
584
663
  */
585
664
  function multipartStart(size, _a) {
586
- var publicKey = _a.publicKey, contentType = _a.contentType, fileName = _a.fileName, _b = _a.multipartChunkSize, multipartChunkSize = _b === void 0 ? defaultSettings.multipartChunkSize : _b, _c = _a.baseURL, baseURL = _c === void 0 ? '' : _c, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, _d = _a.source, source = _d === void 0 ? 'local' : _d, integration = _a.integration, userAgent = _a.userAgent, _e = _a.retryThrottledRequestMaxTimes, retryThrottledRequestMaxTimes = _e === void 0 ? defaultSettings.retryThrottledRequestMaxTimes : _e;
665
+ var publicKey = _a.publicKey, contentType = _a.contentType, fileName = _a.fileName, _b = _a.multipartChunkSize, multipartChunkSize = _b === void 0 ? defaultSettings.multipartChunkSize : _b, _c = _a.baseURL, baseURL = _c === void 0 ? '' : _c, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, _d = _a.source, source = _d === void 0 ? 'local' : _d, integration = _a.integration, userAgent = _a.userAgent, _e = _a.retryThrottledRequestMaxTimes, retryThrottledRequestMaxTimes = _e === void 0 ? defaultSettings.retryThrottledRequestMaxTimes : _e, metadata = _a.metadata;
587
666
  return retryIfThrottled(function () {
588
667
  return request({
589
668
  method: 'POST',
@@ -591,17 +670,18 @@ function multipartStart(size, _a) {
591
670
  headers: {
592
671
  'X-UC-User-Agent': getUserAgent({ publicKey: publicKey, integration: integration, userAgent: userAgent })
593
672
  },
594
- data: buildFormData([
595
- ['filename', fileName !== null && fileName !== void 0 ? fileName : defaultFilename],
596
- ['size', size],
597
- ['content_type', contentType !== null && contentType !== void 0 ? contentType : defaultContentType],
598
- ['part_size', multipartChunkSize],
599
- ['UPLOADCARE_STORE', store ? '' : 'auto'],
600
- ['UPLOADCARE_PUB_KEY', publicKey],
601
- ['signature', secureSignature],
602
- ['expire', secureExpire],
603
- ['source', source]
604
- ]),
673
+ data: buildFormData({
674
+ filename: fileName !== null && fileName !== void 0 ? fileName : defaultFilename,
675
+ size: size,
676
+ content_type: contentType !== null && contentType !== void 0 ? contentType : defaultContentType,
677
+ part_size: multipartChunkSize,
678
+ UPLOADCARE_STORE: getStoreValue(store),
679
+ UPLOADCARE_PUB_KEY: publicKey,
680
+ signature: secureSignature,
681
+ expire: secureExpire,
682
+ source: source,
683
+ metadata: metadata
684
+ }),
605
685
  signal: signal
606
686
  }).then(function (_a) {
607
687
  var data = _a.data, headers = _a.headers, request = _a.request;
@@ -627,13 +707,17 @@ function multipartUpload(part, url, _a) {
627
707
  method: 'PUT',
628
708
  url: url,
629
709
  data: part,
710
+ // Upload request can't be non-computable because we always know exact size
630
711
  onProgress: onProgress,
631
712
  signal: signal
632
713
  })
633
714
  .then(function (result) {
634
715
  // hack for node ¯\_(ツ)_/¯
635
716
  if (onProgress)
636
- onProgress({ value: 1 });
717
+ onProgress({
718
+ isComputable: true,
719
+ value: 1
720
+ });
637
721
  return result;
638
722
  })
639
723
  .then(function (_a) {
@@ -654,11 +738,11 @@ function multipartComplete(uuid, _a) {
654
738
  headers: {
655
739
  'X-UC-User-Agent': getUserAgent({ publicKey: publicKey, integration: integration, userAgent: userAgent })
656
740
  },
657
- data: buildFormData([
658
- ['uuid', uuid],
659
- ['UPLOADCARE_PUB_KEY', publicKey],
660
- ['source', source]
661
- ]),
741
+ data: buildFormData({
742
+ uuid: uuid,
743
+ UPLOADCARE_PUB_KEY: publicKey,
744
+ source: source
745
+ }),
662
746
  signal: signal
663
747
  }).then(function (_a) {
664
748
  var data = _a.data, headers = _a.headers, request = _a.request;
@@ -687,6 +771,8 @@ var UploadcareFile = /** @class */ (function () {
687
771
  this.originalFilename = null;
688
772
  this.imageInfo = null;
689
773
  this.videoInfo = null;
774
+ this.contentInfo = null;
775
+ this.metadata = null;
690
776
  var uuid = fileInfo.uuid, s3Bucket = fileInfo.s3Bucket;
691
777
  var urlBase = s3Bucket
692
778
  ? "https://" + s3Bucket + ".s3.amazonaws.com/" + uuid + "/" + fileInfo.filename
@@ -706,6 +792,8 @@ var UploadcareFile = /** @class */ (function () {
706
792
  this.originalFilename = fileInfo.originalFilename;
707
793
  this.imageInfo = camelizeKeys(fileInfo.imageInfo);
708
794
  this.videoInfo = camelizeKeys(fileInfo.videoInfo);
795
+ this.contentInfo = camelizeKeys(fileInfo.contentInfo);
796
+ this.metadata = fileInfo.metadata || null;
709
797
  }
710
798
  return UploadcareFile;
711
799
  }());
@@ -756,7 +844,7 @@ function isReadyPoll(_a) {
756
844
  if (response.isReady) {
757
845
  return response;
758
846
  }
759
- onProgress && onProgress({ value: 1 });
847
+ onProgress && onProgress({ isComputable: true, value: 1 });
760
848
  return false;
761
849
  });
762
850
  },
@@ -765,7 +853,7 @@ function isReadyPoll(_a) {
765
853
  }
766
854
 
767
855
  var uploadFromObject = function (file, _a) {
768
- var publicKey = _a.publicKey, fileName = _a.fileName, baseURL = _a.baseURL, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, source = _a.source, integration = _a.integration, userAgent = _a.userAgent, retryThrottledRequestMaxTimes = _a.retryThrottledRequestMaxTimes, baseCDN = _a.baseCDN;
856
+ var publicKey = _a.publicKey, fileName = _a.fileName, baseURL = _a.baseURL, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, source = _a.source, integration = _a.integration, userAgent = _a.userAgent, retryThrottledRequestMaxTimes = _a.retryThrottledRequestMaxTimes, baseCDN = _a.baseCDN, metadata = _a.metadata;
769
857
  return base(file, {
770
858
  publicKey: publicKey,
771
859
  fileName: fileName,
@@ -778,7 +866,8 @@ var uploadFromObject = function (file, _a) {
778
866
  source: source,
779
867
  integration: integration,
780
868
  userAgent: userAgent,
781
- retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes
869
+ retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes,
870
+ metadata: metadata
782
871
  })
783
872
  .then(function (_a) {
784
873
  var file = _a.file;
@@ -1018,13 +1107,25 @@ function pollStrategy(_a) {
1018
1107
  return new UploadClientError("Token \"" + token + "\" was not found.");
1019
1108
  }
1020
1109
  case Status.Progress: {
1021
- if (onProgress)
1022
- onProgress({ value: response.done / response.total });
1110
+ if (onProgress) {
1111
+ if (response.total === 'unknown') {
1112
+ onProgress({ isComputable: false });
1113
+ }
1114
+ else {
1115
+ onProgress({
1116
+ isComputable: true,
1117
+ value: response.done / response.total
1118
+ });
1119
+ }
1120
+ }
1023
1121
  return false;
1024
1122
  }
1025
1123
  case Status.Success: {
1026
1124
  if (onProgress)
1027
- onProgress({ value: response.done / response.total });
1125
+ onProgress({
1126
+ isComputable: true,
1127
+ value: response.done / response.total
1128
+ });
1028
1129
  return response;
1029
1130
  }
1030
1131
  default: {
@@ -1053,14 +1154,25 @@ var pushStrategy = function (_a) {
1053
1154
  switch (result.status) {
1054
1155
  case Status.Progress: {
1055
1156
  if (onProgress) {
1056
- onProgress({ value: result.done / result.total });
1157
+ if (result.total === 'unknown') {
1158
+ onProgress({ isComputable: false });
1159
+ }
1160
+ else {
1161
+ onProgress({
1162
+ isComputable: true,
1163
+ value: result.done / result.total
1164
+ });
1165
+ }
1057
1166
  }
1058
1167
  break;
1059
1168
  }
1060
1169
  case Status.Success: {
1061
1170
  destroy();
1062
1171
  if (onProgress)
1063
- onProgress({ value: result.done / result.total });
1172
+ onProgress({
1173
+ isComputable: true,
1174
+ value: result.done / result.total
1175
+ });
1064
1176
  resolve(result);
1065
1177
  break;
1066
1178
  }
@@ -1073,7 +1185,7 @@ var pushStrategy = function (_a) {
1073
1185
  });
1074
1186
  };
1075
1187
  var uploadFromUrl = function (sourceUrl, _a) {
1076
- var publicKey = _a.publicKey, fileName = _a.fileName, baseURL = _a.baseURL, baseCDN = _a.baseCDN, checkForUrlDuplicates = _a.checkForUrlDuplicates, saveUrlForRecurrentUploads = _a.saveUrlForRecurrentUploads, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, source = _a.source, integration = _a.integration, userAgent = _a.userAgent, retryThrottledRequestMaxTimes = _a.retryThrottledRequestMaxTimes, _b = _a.pusherKey, pusherKey = _b === void 0 ? defaultSettings.pusherKey : _b;
1188
+ var publicKey = _a.publicKey, fileName = _a.fileName, baseURL = _a.baseURL, baseCDN = _a.baseCDN, checkForUrlDuplicates = _a.checkForUrlDuplicates, saveUrlForRecurrentUploads = _a.saveUrlForRecurrentUploads, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, source = _a.source, integration = _a.integration, userAgent = _a.userAgent, retryThrottledRequestMaxTimes = _a.retryThrottledRequestMaxTimes, _b = _a.pusherKey, pusherKey = _b === void 0 ? defaultSettings.pusherKey : _b, metadata = _a.metadata;
1077
1189
  return Promise.resolve(preconnect(pusherKey))
1078
1190
  .then(function () {
1079
1191
  return fromUrl(sourceUrl, {
@@ -1089,7 +1201,8 @@ var uploadFromUrl = function (sourceUrl, _a) {
1089
1201
  source: source,
1090
1202
  integration: integration,
1091
1203
  userAgent: userAgent,
1092
- retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes
1204
+ retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes,
1205
+ metadata: metadata
1093
1206
  });
1094
1207
  })
1095
1208
  .catch(function (error) {
@@ -1163,39 +1276,14 @@ var uploadFromUploaded = function (uuid, _a) {
1163
1276
  .then(function (result) {
1164
1277
  // hack for node ¯\_(ツ)_/¯
1165
1278
  if (onProgress)
1166
- onProgress({ value: 1 });
1279
+ onProgress({
1280
+ isComputable: true,
1281
+ value: 1
1282
+ });
1167
1283
  return result;
1168
1284
  });
1169
1285
  };
1170
1286
 
1171
- /**
1172
- * FileData type guard.
1173
- */
1174
- var isFileData = function (data) {
1175
- return (data !== undefined &&
1176
- ((typeof Blob !== 'undefined' && data instanceof Blob) ||
1177
- (typeof File !== 'undefined' && data instanceof File) ||
1178
- (typeof Buffer !== 'undefined' && data instanceof Buffer)));
1179
- };
1180
- /**
1181
- * Uuid type guard.
1182
- */
1183
- var isUuid = function (data) {
1184
- var UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
1185
- var regExp = new RegExp(UUID_REGEX);
1186
- return !isFileData(data) && regExp.test(data);
1187
- };
1188
- /**
1189
- * Url type guard.
1190
- *
1191
- * @param {NodeFile | BrowserFile | Url | Uuid} data
1192
- */
1193
- var isUrl = function (data) {
1194
- var URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
1195
- var regExp = new RegExp(URL_REGEX);
1196
- return !isFileData(data) && regExp.test(data);
1197
- };
1198
-
1199
1287
  /**
1200
1288
  * Get file size.
1201
1289
  */
@@ -1275,22 +1363,27 @@ var uploadPartWithRetry = function (chunk, url, _a) {
1275
1363
  });
1276
1364
  };
1277
1365
  var uploadMultipart = function (file, _a) {
1278
- var publicKey = _a.publicKey, fileName = _a.fileName, fileSize = _a.fileSize, baseURL = _a.baseURL, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, source = _a.source, integration = _a.integration, userAgent = _a.userAgent, retryThrottledRequestMaxTimes = _a.retryThrottledRequestMaxTimes, contentType = _a.contentType, _b = _a.multipartChunkSize, multipartChunkSize = _b === void 0 ? defaultSettings.multipartChunkSize : _b, _c = _a.maxConcurrentRequests, maxConcurrentRequests = _c === void 0 ? defaultSettings.maxConcurrentRequests : _c, _d = _a.multipartMaxAttempts, multipartMaxAttempts = _d === void 0 ? defaultSettings.multipartMaxAttempts : _d, baseCDN = _a.baseCDN;
1366
+ var publicKey = _a.publicKey, fileName = _a.fileName, fileSize = _a.fileSize, baseURL = _a.baseURL, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, source = _a.source, integration = _a.integration, userAgent = _a.userAgent, retryThrottledRequestMaxTimes = _a.retryThrottledRequestMaxTimes, contentType = _a.contentType, _b = _a.multipartChunkSize, multipartChunkSize = _b === void 0 ? defaultSettings.multipartChunkSize : _b, _c = _a.maxConcurrentRequests, maxConcurrentRequests = _c === void 0 ? defaultSettings.maxConcurrentRequests : _c, _d = _a.multipartMaxAttempts, multipartMaxAttempts = _d === void 0 ? defaultSettings.multipartMaxAttempts : _d, baseCDN = _a.baseCDN, metadata = _a.metadata;
1279
1367
  var size = fileSize || getFileSize(file);
1280
1368
  var progressValues;
1281
- var createProgressHandler = function (size, index) {
1369
+ var createProgressHandler = function (totalChunks, chunkIdx) {
1282
1370
  if (!onProgress)
1283
1371
  return;
1284
1372
  if (!progressValues) {
1285
- progressValues = Array(size).fill(0);
1373
+ progressValues = Array(totalChunks).fill(0);
1286
1374
  }
1287
1375
  var sum = function (values) {
1288
1376
  return values.reduce(function (sum, next) { return sum + next; }, 0);
1289
1377
  };
1290
- return function (_a) {
1291
- var value = _a.value;
1292
- progressValues[index] = value;
1293
- onProgress({ value: sum(progressValues) / size });
1378
+ return function (info) {
1379
+ if (!info.isComputable) {
1380
+ return;
1381
+ }
1382
+ progressValues[chunkIdx] = info.value;
1383
+ onProgress({
1384
+ isComputable: true,
1385
+ value: sum(progressValues) / totalChunks
1386
+ });
1294
1387
  };
1295
1388
  };
1296
1389
  return multipartStart(size, {
@@ -1305,7 +1398,8 @@ var uploadMultipart = function (file, _a) {
1305
1398
  source: source,
1306
1399
  integration: integration,
1307
1400
  userAgent: userAgent,
1308
- retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes
1401
+ retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes,
1402
+ metadata: metadata
1309
1403
  })
1310
1404
  .then(function (_a) {
1311
1405
  var uuid = _a.uuid, parts = _a.parts;
@@ -1359,10 +1453,10 @@ var uploadMultipart = function (file, _a) {
1359
1453
  * Uploads file from provided data.
1360
1454
  */
1361
1455
  function uploadFile(data, _a) {
1362
- var publicKey = _a.publicKey, fileName = _a.fileName, _b = _a.baseURL, baseURL = _b === void 0 ? defaultSettings.baseURL : _b, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, source = _a.source, integration = _a.integration, userAgent = _a.userAgent, retryThrottledRequestMaxTimes = _a.retryThrottledRequestMaxTimes, contentType = _a.contentType, multipartChunkSize = _a.multipartChunkSize, multipartMaxAttempts = _a.multipartMaxAttempts, maxConcurrentRequests = _a.maxConcurrentRequests, _c = _a.baseCDN, baseCDN = _c === void 0 ? defaultSettings.baseCDN : _c, checkForUrlDuplicates = _a.checkForUrlDuplicates, saveUrlForRecurrentUploads = _a.saveUrlForRecurrentUploads, pusherKey = _a.pusherKey;
1456
+ var publicKey = _a.publicKey, fileName = _a.fileName, _b = _a.baseURL, baseURL = _b === void 0 ? defaultSettings.baseURL : _b, secureSignature = _a.secureSignature, secureExpire = _a.secureExpire, store = _a.store, signal = _a.signal, onProgress = _a.onProgress, source = _a.source, integration = _a.integration, userAgent = _a.userAgent, retryThrottledRequestMaxTimes = _a.retryThrottledRequestMaxTimes, contentType = _a.contentType, multipartMinFileSize = _a.multipartMinFileSize, multipartChunkSize = _a.multipartChunkSize, multipartMaxAttempts = _a.multipartMaxAttempts, maxConcurrentRequests = _a.maxConcurrentRequests, _c = _a.baseCDN, baseCDN = _c === void 0 ? defaultSettings.baseCDN : _c, checkForUrlDuplicates = _a.checkForUrlDuplicates, saveUrlForRecurrentUploads = _a.saveUrlForRecurrentUploads, pusherKey = _a.pusherKey, metadata = _a.metadata;
1363
1457
  if (isFileData(data)) {
1364
1458
  var fileSize = getFileSize(data);
1365
- if (isMultipart(fileSize)) {
1459
+ if (isMultipart(fileSize, multipartMinFileSize)) {
1366
1460
  return uploadMultipart(data, {
1367
1461
  publicKey: publicKey,
1368
1462
  contentType: contentType,
@@ -1380,7 +1474,8 @@ function uploadFile(data, _a) {
1380
1474
  userAgent: userAgent,
1381
1475
  maxConcurrentRequests: maxConcurrentRequests,
1382
1476
  retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes,
1383
- baseCDN: baseCDN
1477
+ baseCDN: baseCDN,
1478
+ metadata: metadata
1384
1479
  });
1385
1480
  }
1386
1481
  return uploadFromObject(data, {
@@ -1396,7 +1491,8 @@ function uploadFile(data, _a) {
1396
1491
  integration: integration,
1397
1492
  userAgent: userAgent,
1398
1493
  retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes,
1399
- baseCDN: baseCDN
1494
+ baseCDN: baseCDN,
1495
+ metadata: metadata
1400
1496
  });
1401
1497
  }
1402
1498
  if (isUrl(data)) {
@@ -1416,7 +1512,8 @@ function uploadFile(data, _a) {
1416
1512
  integration: integration,
1417
1513
  userAgent: userAgent,
1418
1514
  retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes,
1419
- pusherKey: pusherKey
1515
+ pusherKey: pusherKey,
1516
+ metadata: metadata
1420
1517
  });
1421
1518
  }
1422
1519
  if (isUuid(data)) {
@@ -1495,6 +1592,7 @@ function uploadFileGroup(data, _a) {
1495
1592
  throw new TypeError("Group uploading from \"" + data + "\" is not supported");
1496
1593
  }
1497
1594
  var progressValues;
1595
+ var isStillComputable = true;
1498
1596
  var filesCount = data.length;
1499
1597
  var createProgressHandler = function (size, index) {
1500
1598
  if (!onProgress)
@@ -1505,10 +1603,14 @@ function uploadFileGroup(data, _a) {
1505
1603
  var normalize = function (values) {
1506
1604
  return values.reduce(function (sum, next) { return sum + next; }) / size;
1507
1605
  };
1508
- return function (_a) {
1509
- var value = _a.value;
1510
- progressValues[index] = value;
1511
- onProgress({ value: normalize(progressValues) });
1606
+ return function (info) {
1607
+ if (!info.isComputable || !isStillComputable) {
1608
+ isStillComputable = false;
1609
+ onProgress({ isComputable: false });
1610
+ return;
1611
+ }
1612
+ progressValues[index] = info.value;
1613
+ onProgress({ isComputable: true, value: normalize(progressValues) });
1512
1614
  };
1513
1615
  };
1514
1616
  return Promise.all(data.map(function (file, index) {
@@ -1549,7 +1651,12 @@ function uploadFileGroup(data, _a) {
1549
1651
  integration: integration,
1550
1652
  userAgent: userAgent,
1551
1653
  retryThrottledRequestMaxTimes: retryThrottledRequestMaxTimes
1552
- }).then(function (groupInfo) { return new UploadcareGroup(groupInfo, filesInGroup); });
1654
+ })
1655
+ .then(function (groupInfo) { return new UploadcareGroup(groupInfo, filesInGroup); })
1656
+ .then(function (group) {
1657
+ onProgress && onProgress({ isComputable: true, value: 1 });
1658
+ return group;
1659
+ });
1553
1660
  });
1554
1661
  }
1555
1662