@uploadcare/upload-client 4.3.1 → 5.0.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
@@ -364,6 +364,19 @@ Sets the maximum number of attempts to retry throttled requests.
364
364
 
365
365
  Defaults to `1`.
366
366
 
367
+ #### `retryNetworkErrorMaxTimes: number`
368
+
369
+ Sets the maximum number of attempts to retry requests that failed with a network error.
370
+
371
+ Defaults to `3`.
372
+
373
+ The delay between attempts equals attempt number, i.e.
374
+
375
+ - first attempt - 1 second delay
376
+ - second attempt - 2 seconds delay
377
+ - third attempt - 3 seconds delay
378
+ - ...
379
+
367
380
  #### `multipartChunkSize: number`
368
381
 
369
382
  This option is only applicable when handling local files.
@@ -411,7 +424,7 @@ Metadata is additional, arbitrary data, associated with uploaded file.
411
424
 
412
425
  Non-string values will be converted to `string`. `undefined` values will be ignored.
413
426
 
414
- See [REST API reference][uc-docs-metadata] for details.
427
+ See [docs][uc-file-metadata] and [REST API][uc-docs-metadata] for details.
415
428
 
416
429
 
417
430
  ## Testing
@@ -476,3 +489,4 @@ request at [hello@uploadcare.com][uc-email-hello].
476
489
  [build-url]: https://github.com/uploadcare/uploadcare-js-api-clients/actions/workflows/checks.yml
477
490
  [uc-docs-upload-api]: https://uploadcare.com/docs/api_reference/upload/?utm_source=github&utm_campaign=uploadcare-js-api-clients
478
491
  [uc-docs-metadata]: https://uploadcare.com/api-refs/rest-api/v0.7.0/#tag/File-Metadata
492
+ [uc-file-metadata]: https://uploadcare.com/docs/file-metadata/
@@ -27,6 +27,107 @@ const onCancel = (signal, callback) => {
27
27
  }
28
28
  };
29
29
 
30
+ function isObject(o) {
31
+ return Object.prototype.toString.call(o) === '[object Object]';
32
+ }
33
+
34
+ const SEPARATOR = /\W|_/g;
35
+ function camelizeString(text) {
36
+ return text
37
+ .split(SEPARATOR)
38
+ .map((word, index) => word.charAt(0)[index > 0 ? 'toUpperCase' : 'toLowerCase']() +
39
+ word.slice(1))
40
+ .join('');
41
+ }
42
+ function camelizeArrayItems(array, { ignoreKeys } = { ignoreKeys: [] }) {
43
+ if (!Array.isArray(array)) {
44
+ return array;
45
+ }
46
+ return array.map((item) => camelizeKeys(item, { ignoreKeys }));
47
+ }
48
+ function camelizeKeys(source, { ignoreKeys } = { ignoreKeys: [] }) {
49
+ if (Array.isArray(source)) {
50
+ return camelizeArrayItems(source, { ignoreKeys });
51
+ }
52
+ if (!isObject(source)) {
53
+ return source;
54
+ }
55
+ const result = {};
56
+ for (const key of Object.keys(source)) {
57
+ let value = source[key];
58
+ if (ignoreKeys.includes(key)) {
59
+ result[key] = value;
60
+ continue;
61
+ }
62
+ if (isObject(value)) {
63
+ value = camelizeKeys(value, { ignoreKeys });
64
+ }
65
+ else if (Array.isArray(value)) {
66
+ value = camelizeArrayItems(value, { ignoreKeys });
67
+ }
68
+ result[camelizeString(key)] = value;
69
+ }
70
+ return result;
71
+ }
72
+
73
+ /**
74
+ * setTimeout as Promise.
75
+ *
76
+ * @param {number} ms Timeout in milliseconds.
77
+ */
78
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
79
+
80
+ function getUserAgent$1({ libraryName, libraryVersion, userAgent, publicKey = '', integration = '' }) {
81
+ const languageName = 'JavaScript';
82
+ if (typeof userAgent === 'string') {
83
+ return userAgent;
84
+ }
85
+ if (typeof userAgent === 'function') {
86
+ return userAgent({
87
+ publicKey,
88
+ libraryName,
89
+ libraryVersion,
90
+ languageName,
91
+ integration
92
+ });
93
+ }
94
+ const mainInfo = [libraryName, libraryVersion, publicKey]
95
+ .filter(Boolean)
96
+ .join('/');
97
+ const additionInfo = [languageName, integration].filter(Boolean).join('; ');
98
+ return `${mainInfo} (${additionInfo})`;
99
+ }
100
+
101
+ const defaultOptions = {
102
+ factor: 2,
103
+ time: 100
104
+ };
105
+ function retrier(fn, options = defaultOptions) {
106
+ let attempts = 0;
107
+ function runAttempt(fn) {
108
+ const defaultDelayTime = Math.round(options.time * options.factor ** attempts);
109
+ const retry = (ms) => delay(ms ?? defaultDelayTime).then(() => {
110
+ attempts += 1;
111
+ return runAttempt(fn);
112
+ });
113
+ return fn({
114
+ attempt: attempts,
115
+ retry
116
+ });
117
+ }
118
+ return runAttempt(fn);
119
+ }
120
+
121
+ class UploadcareNetworkError extends Error {
122
+ constructor(progressEvent) {
123
+ super();
124
+ this.name = 'UploadcareNetworkError';
125
+ this.message = 'Network error';
126
+ Object.setPrototypeOf(this, UploadcareNetworkError.prototype);
127
+ this.originalProgressEvent = progressEvent;
128
+ }
129
+ }
130
+
30
131
  const request = ({ method, url, data, headers = {}, signal, onProgress }) => new Promise((resolve, reject) => {
31
132
  const xhr = new XMLHttpRequest();
32
133
  const requestMethod = method?.toUpperCase() || 'GET';
@@ -92,11 +193,11 @@ const request = ({ method, url, data, headers = {}, signal, onProgress }) => new
92
193
  });
93
194
  }
94
195
  };
95
- xhr.onerror = () => {
196
+ xhr.onerror = (progressEvent) => {
96
197
  if (aborted)
97
198
  return;
98
199
  // only triggers if the request couldn't be made at all
99
- reject(new Error('Network error'));
200
+ reject(new UploadcareNetworkError(progressEvent));
100
201
  };
101
202
  if (onProgress && typeof onProgress === 'function') {
102
203
  xhr.upload.onprogress = (event) => {
@@ -243,109 +344,18 @@ const defaultSettings = {
243
344
  baseURL: 'https://upload.uploadcare.com',
244
345
  maxContentLength: 50 * 1024 * 1024,
245
346
  retryThrottledRequestMaxTimes: 1,
347
+ retryNetworkErrorMaxTimes: 3,
246
348
  multipartMinFileSize: 25 * 1024 * 1024,
247
349
  multipartChunkSize: 5 * 1024 * 1024,
248
350
  multipartMinLastPartSize: 1024 * 1024,
249
351
  maxConcurrentRequests: 4,
250
- multipartMaxAttempts: 3,
251
352
  pollingTimeoutMilliseconds: 10000,
252
353
  pusherKey: '79ae88bd931ea68464d9'
253
354
  };
254
355
  const defaultContentType = 'application/octet-stream';
255
356
  const defaultFilename = 'original';
256
357
 
257
- var version = '4.3.1';
258
-
259
- function isObject(o) {
260
- return Object.prototype.toString.call(o) === '[object Object]';
261
- }
262
-
263
- const SEPARATOR = /\W|_/g;
264
- function camelizeString(text) {
265
- return text
266
- .split(SEPARATOR)
267
- .map((word, index) => word.charAt(0)[index > 0 ? 'toUpperCase' : 'toLowerCase']() +
268
- word.slice(1))
269
- .join('');
270
- }
271
- function camelizeArrayItems(array, { ignoreKeys } = { ignoreKeys: [] }) {
272
- if (!Array.isArray(array)) {
273
- return array;
274
- }
275
- return array.map((item) => camelizeKeys(item, { ignoreKeys }));
276
- }
277
- function camelizeKeys(source, { ignoreKeys } = { ignoreKeys: [] }) {
278
- if (Array.isArray(source)) {
279
- return camelizeArrayItems(source, { ignoreKeys });
280
- }
281
- if (!isObject(source)) {
282
- return source;
283
- }
284
- const result = {};
285
- for (const key of Object.keys(source)) {
286
- let value = source[key];
287
- if (ignoreKeys.includes(key)) {
288
- result[key] = value;
289
- continue;
290
- }
291
- if (isObject(value)) {
292
- value = camelizeKeys(value, { ignoreKeys });
293
- }
294
- else if (Array.isArray(value)) {
295
- value = camelizeArrayItems(value, { ignoreKeys });
296
- }
297
- result[camelizeString(key)] = value;
298
- }
299
- return result;
300
- }
301
-
302
- /**
303
- * setTimeout as Promise.
304
- *
305
- * @param {number} ms Timeout in milliseconds.
306
- */
307
- const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
308
-
309
- function getUserAgent$1({ libraryName, libraryVersion, userAgent, publicKey = '', integration = '' }) {
310
- const languageName = 'JavaScript';
311
- if (typeof userAgent === 'string') {
312
- return userAgent;
313
- }
314
- if (typeof userAgent === 'function') {
315
- return userAgent({
316
- publicKey,
317
- libraryName,
318
- libraryVersion,
319
- languageName,
320
- integration
321
- });
322
- }
323
- const mainInfo = [libraryName, libraryVersion, publicKey]
324
- .filter(Boolean)
325
- .join('/');
326
- const additionInfo = [languageName, integration].filter(Boolean).join('; ');
327
- return `${mainInfo} (${additionInfo})`;
328
- }
329
-
330
- const defaultOptions = {
331
- factor: 2,
332
- time: 100
333
- };
334
- function retrier(fn, options = defaultOptions) {
335
- let attempts = 0;
336
- function runAttempt(fn) {
337
- const defaultDelayTime = Math.round(options.time * options.factor ** attempts);
338
- const retry = (ms) => delay(ms ?? defaultDelayTime).then(() => {
339
- attempts += 1;
340
- return runAttempt(fn);
341
- });
342
- return fn({
343
- attempt: attempts,
344
- retry
345
- });
346
- }
347
- return runAttempt(fn);
348
- }
358
+ var version = '5.0.0';
349
359
 
350
360
  const LIBRARY_NAME = 'UploadcareUploadClient';
351
361
  const LIBRARY_VERSION = version;
@@ -358,20 +368,26 @@ function getUserAgent(options) {
358
368
  }
359
369
 
360
370
  const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
361
- const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
371
+ const DEFAULT_THROTTLED_TIMEOUT = 15000;
372
+ const DEFAULT_NETWORK_ERROR_TIMEOUT = 1000;
362
373
  function getTimeoutFromThrottledRequest(error) {
363
374
  const { headers } = error || {};
364
375
  return ((headers &&
365
376
  Number.parseInt(headers['x-throttle-wait-seconds']) * 1000) ||
366
- DEFAULT_RETRY_AFTER_TIMEOUT);
377
+ DEFAULT_THROTTLED_TIMEOUT);
367
378
  }
368
- function retryIfThrottled(fn, retryThrottledMaxTimes) {
379
+ function retryIfFailed(fn, options) {
380
+ const { retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes } = options;
369
381
  return retrier(({ attempt, retry }) => fn().catch((error) => {
370
382
  if ('response' in error &&
371
383
  error?.code === REQUEST_WAS_THROTTLED_CODE &&
372
- attempt < retryThrottledMaxTimes) {
384
+ attempt < retryThrottledRequestMaxTimes) {
373
385
  return retry(getTimeoutFromThrottledRequest(error));
374
386
  }
387
+ if (error instanceof UploadcareNetworkError &&
388
+ attempt < retryNetworkErrorMaxTimes) {
389
+ return retry((attempt + 1) * DEFAULT_NETWORK_ERROR_TIMEOUT);
390
+ }
375
391
  throw error;
376
392
  }));
377
393
  }
@@ -384,8 +400,8 @@ function getStoreValue(store) {
384
400
  * Performs file uploading request to Uploadcare Upload API.
385
401
  * Can be canceled and has progress.
386
402
  */
387
- function base(file, { publicKey, fileName, contentType, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
388
- return retryIfThrottled(() => request({
403
+ function base(file, { publicKey, fileName, contentType, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes = defaultSettings.retryNetworkErrorMaxTimes, metadata }) {
404
+ return retryIfFailed(() => request({
389
405
  method: 'POST',
390
406
  url: getUrl(baseURL, '/base/', {
391
407
  jsonerrors: 1
@@ -416,7 +432,7 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
416
432
  else {
417
433
  return response;
418
434
  }
419
- }), retryThrottledRequestMaxTimes);
435
+ }), { retryNetworkErrorMaxTimes, retryThrottledRequestMaxTimes });
420
436
  }
421
437
 
422
438
  var TypeEnum;
@@ -427,8 +443,8 @@ var TypeEnum;
427
443
  /**
428
444
  * Uploading files from URL.
429
445
  */
430
- function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
431
- return retryIfThrottled(() => request({
446
+ function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes = defaultSettings.retryNetworkErrorMaxTimes, metadata }) {
447
+ return retryIfFailed(() => request({
432
448
  method: 'POST',
433
449
  headers: {
434
450
  'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
@@ -455,7 +471,7 @@ function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, stor
455
471
  else {
456
472
  return response;
457
473
  }
458
- }), retryThrottledRequestMaxTimes);
474
+ }), { retryNetworkErrorMaxTimes, retryThrottledRequestMaxTimes });
459
475
  }
460
476
 
461
477
  var Status;
@@ -472,8 +488,8 @@ const isErrorResponse = (response) => {
472
488
  /**
473
489
  * Checking upload status and working with file tokens.
474
490
  */
475
- function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes } = {}) {
476
- return retryIfThrottled(() => request({
491
+ function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes = defaultSettings.retryNetworkErrorMaxTimes } = {}) {
492
+ return retryIfFailed(() => request({
477
493
  method: 'GET',
478
494
  headers: publicKey
479
495
  ? {
@@ -497,14 +513,14 @@ function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, si
497
513
  else {
498
514
  return response;
499
515
  }
500
- }), retryThrottledRequestMaxTimes);
516
+ }), { retryNetworkErrorMaxTimes, retryThrottledRequestMaxTimes });
501
517
  }
502
518
 
503
519
  /**
504
520
  * Create files group.
505
521
  */
506
- function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallback, secureSignature, secureExpire, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
507
- return retryIfThrottled(() => request({
522
+ function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallback, secureSignature, secureExpire, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes = defaultSettings.retryNetworkErrorMaxTimes }) {
523
+ return retryIfFailed(() => request({
508
524
  method: 'POST',
509
525
  headers: {
510
526
  'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
@@ -527,14 +543,14 @@ function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallb
527
543
  else {
528
544
  return response;
529
545
  }
530
- }), retryThrottledRequestMaxTimes);
546
+ }), { retryNetworkErrorMaxTimes, retryThrottledRequestMaxTimes });
531
547
  }
532
548
 
533
549
  /**
534
550
  * Get info about group.
535
551
  */
536
- function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
537
- return retryIfThrottled(() => request({
552
+ function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes = defaultSettings.retryNetworkErrorMaxTimes }) {
553
+ return retryIfFailed(() => request({
538
554
  method: 'GET',
539
555
  headers: {
540
556
  'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
@@ -554,14 +570,14 @@ function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, s
554
570
  else {
555
571
  return response;
556
572
  }
557
- }), retryThrottledRequestMaxTimes);
573
+ }), { retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes });
558
574
  }
559
575
 
560
576
  /**
561
577
  * Returns a JSON dictionary holding file info.
562
578
  */
563
- function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
564
- return retryIfThrottled(() => request({
579
+ function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes = defaultSettings.retryNetworkErrorMaxTimes }) {
580
+ return retryIfFailed(() => request({
565
581
  method: 'GET',
566
582
  headers: {
567
583
  'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
@@ -581,14 +597,14 @@ function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, sour
581
597
  else {
582
598
  return response;
583
599
  }
584
- }), retryThrottledRequestMaxTimes);
600
+ }), { retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes });
585
601
  }
586
602
 
587
603
  /**
588
604
  * Start multipart uploading.
589
605
  */
590
- function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
591
- return retryIfThrottled(() => request({
606
+ function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes = defaultSettings.retryNetworkErrorMaxTimes, metadata }) {
607
+ return retryIfFailed(() => request({
592
608
  method: 'POST',
593
609
  url: getUrl(baseURL, '/multipart/start/', { jsonerrors: 1 }),
594
610
  headers: {
@@ -617,14 +633,14 @@ function multipartStart(size, { publicKey, contentType, fileName, multipartChunk
617
633
  response.parts = Object.keys(response.parts).map((key) => response.parts[key]);
618
634
  return response;
619
635
  }
620
- }), retryThrottledRequestMaxTimes);
636
+ }), { retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes });
621
637
  }
622
638
 
623
639
  /**
624
640
  * Complete multipart uploading.
625
641
  */
626
- function multipartUpload(part, url, { signal, onProgress }) {
627
- return request({
642
+ function multipartUpload(part, url, { signal, onProgress, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes = defaultSettings.retryNetworkErrorMaxTimes }) {
643
+ return retryIfFailed(() => request({
628
644
  method: 'PUT',
629
645
  url,
630
646
  data: part,
@@ -641,14 +657,17 @@ function multipartUpload(part, url, { signal, onProgress }) {
641
657
  });
642
658
  return result;
643
659
  })
644
- .then(({ status }) => ({ code: status }));
660
+ .then(({ status }) => ({ code: status })), {
661
+ retryThrottledRequestMaxTimes,
662
+ retryNetworkErrorMaxTimes
663
+ });
645
664
  }
646
665
 
647
666
  /**
648
667
  * Complete multipart uploading.
649
668
  */
650
- function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL, source = 'local', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
651
- return retryIfThrottled(() => request({
669
+ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL, source = 'local', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes = defaultSettings.retryNetworkErrorMaxTimes }) {
670
+ return retryIfFailed(() => request({
652
671
  method: 'POST',
653
672
  url: getUrl(baseURL, '/multipart/complete/', { jsonerrors: 1 }),
654
673
  headers: {
@@ -668,7 +687,7 @@ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL,
668
687
  else {
669
688
  return response;
670
689
  }
671
- }), retryThrottledRequestMaxTimes);
690
+ }), { retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes });
672
691
  }
673
692
 
674
693
  class UploadcareFile {
@@ -735,7 +754,7 @@ const poll = ({ check, interval = DEFAULT_INTERVAL, signal }) => new Promise((re
735
754
  timeoutId = setTimeout(tick, 0);
736
755
  });
737
756
 
738
- function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, signal, onProgress }) {
757
+ function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, signal, onProgress }) {
739
758
  return poll({
740
759
  check: (signal) => info(file, {
741
760
  publicKey,
@@ -744,7 +763,8 @@ function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent,
744
763
  source,
745
764
  integration,
746
765
  userAgent,
747
- retryThrottledRequestMaxTimes
766
+ retryThrottledRequestMaxTimes,
767
+ retryNetworkErrorMaxTimes
748
768
  }).then((response) => {
749
769
  if (response.isReady) {
750
770
  return response;
@@ -756,7 +776,7 @@ function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent,
756
776
  });
757
777
  }
758
778
 
759
- const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, contentType, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN, metadata }) => {
779
+ const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, contentType, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN, metadata }) => {
760
780
  return base(file, {
761
781
  publicKey,
762
782
  fileName,
@@ -771,6 +791,7 @@ const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, sec
771
791
  integration,
772
792
  userAgent,
773
793
  retryThrottledRequestMaxTimes,
794
+ retryNetworkErrorMaxTimes,
774
795
  metadata
775
796
  })
776
797
  .then(({ file }) => {
@@ -782,6 +803,7 @@ const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, sec
782
803
  integration,
783
804
  userAgent,
784
805
  retryThrottledRequestMaxTimes,
806
+ retryNetworkErrorMaxTimes,
785
807
  onProgress,
786
808
  signal
787
809
  });
@@ -969,7 +991,7 @@ const preconnect = (key) => {
969
991
  getPusher(key).connect();
970
992
  };
971
993
 
972
- function pollStrategy({ token, publicKey, baseURL, integration, userAgent, retryThrottledRequestMaxTimes, onProgress, signal }) {
994
+ function pollStrategy({ token, publicKey, baseURL, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, onProgress, signal }) {
973
995
  return poll({
974
996
  check: (signal) => fromUrlStatus(token, {
975
997
  publicKey,
@@ -977,6 +999,7 @@ function pollStrategy({ token, publicKey, baseURL, integration, userAgent, retry
977
999
  integration,
978
1000
  userAgent,
979
1001
  retryThrottledRequestMaxTimes,
1002
+ retryNetworkErrorMaxTimes,
980
1003
  signal
981
1004
  }).then((response) => {
982
1005
  switch (response.status) {
@@ -1127,7 +1150,7 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
1127
1150
  }))
1128
1151
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1129
1152
 
1130
- const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN }) => {
1153
+ const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN }) => {
1131
1154
  return info(uuid, {
1132
1155
  publicKey,
1133
1156
  baseURL,
@@ -1135,7 +1158,8 @@ const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProg
1135
1158
  source,
1136
1159
  integration,
1137
1160
  userAgent,
1138
- retryThrottledRequestMaxTimes
1161
+ retryThrottledRequestMaxTimes,
1162
+ retryNetworkErrorMaxTimes
1139
1163
  })
1140
1164
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
1141
1165
  .then((result) => {
@@ -1207,18 +1231,15 @@ const runWithConcurrency = (concurrency, tasks) => {
1207
1231
  });
1208
1232
  };
1209
1233
 
1210
- const uploadPartWithRetry = (chunk, url, { publicKey, onProgress, signal, integration, multipartMaxAttempts }) => retrier(({ attempt, retry }) => multipartUpload(chunk, url, {
1234
+ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes }) => multipartUpload(chunk, url, {
1211
1235
  publicKey,
1212
1236
  onProgress,
1213
1237
  signal,
1214
- integration
1215
- }).catch((error) => {
1216
- if (attempt < multipartMaxAttempts) {
1217
- return retry();
1218
- }
1219
- throw error;
1220
- }));
1221
- 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 }) => {
1238
+ integration,
1239
+ retryThrottledRequestMaxTimes,
1240
+ retryNetworkErrorMaxTimes
1241
+ });
1242
+ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, maxConcurrentRequests = defaultSettings.maxConcurrentRequests, baseCDN, metadata }) => {
1222
1243
  const size = fileSize || getFileSize(file);
1223
1244
  let progressValues;
1224
1245
  const createProgressHandler = (totalChunks, chunkIdx) => {
@@ -1252,18 +1273,20 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1252
1273
  integration,
1253
1274
  userAgent,
1254
1275
  retryThrottledRequestMaxTimes,
1276
+ retryNetworkErrorMaxTimes,
1255
1277
  metadata
1256
1278
  })
1257
1279
  .then(({ uuid, parts }) => {
1258
1280
  const getChunk = prepareChunks(file, size, multipartChunkSize);
1259
1281
  return Promise.all([
1260
1282
  uuid,
1261
- runWithConcurrency(maxConcurrentRequests, parts.map((url, index) => () => uploadPartWithRetry(getChunk(index), url, {
1283
+ runWithConcurrency(maxConcurrentRequests, parts.map((url, index) => () => uploadPart(getChunk(index), url, {
1262
1284
  publicKey,
1263
1285
  onProgress: createProgressHandler(parts.length, index),
1264
1286
  signal,
1265
1287
  integration,
1266
- multipartMaxAttempts
1288
+ retryThrottledRequestMaxTimes,
1289
+ retryNetworkErrorMaxTimes
1267
1290
  })))
1268
1291
  ]);
1269
1292
  })
@@ -1273,7 +1296,8 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1273
1296
  source,
1274
1297
  integration,
1275
1298
  userAgent,
1276
- retryThrottledRequestMaxTimes
1299
+ retryThrottledRequestMaxTimes,
1300
+ retryNetworkErrorMaxTimes
1277
1301
  }))
1278
1302
  .then((fileInfo) => {
1279
1303
  if (fileInfo.isReady) {
@@ -1288,6 +1312,7 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1288
1312
  integration,
1289
1313
  userAgent,
1290
1314
  retryThrottledRequestMaxTimes,
1315
+ retryNetworkErrorMaxTimes,
1291
1316
  onProgress,
1292
1317
  signal
1293
1318
  });
@@ -1299,7 +1324,7 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1299
1324
  /**
1300
1325
  * Uploads file from provided data.
1301
1326
  */
1302
- 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 }) {
1327
+ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartMinFileSize, multipartChunkSize, maxConcurrentRequests, baseCDN = defaultSettings.baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, pusherKey, metadata }) {
1303
1328
  if (isFileData(data)) {
1304
1329
  const fileSize = getFileSize(data);
1305
1330
  if (isMultipart(fileSize, multipartMinFileSize)) {
@@ -1307,7 +1332,6 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1307
1332
  publicKey,
1308
1333
  contentType,
1309
1334
  multipartChunkSize,
1310
- multipartMaxAttempts,
1311
1335
  fileName,
1312
1336
  baseURL,
1313
1337
  secureSignature,
@@ -1320,6 +1344,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1320
1344
  userAgent,
1321
1345
  maxConcurrentRequests,
1322
1346
  retryThrottledRequestMaxTimes,
1347
+ retryNetworkErrorMaxTimes,
1323
1348
  baseCDN,
1324
1349
  metadata
1325
1350
  });
@@ -1338,6 +1363,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1338
1363
  integration,
1339
1364
  userAgent,
1340
1365
  retryThrottledRequestMaxTimes,
1366
+ retryNetworkErrorMaxTimes,
1341
1367
  baseCDN,
1342
1368
  metadata
1343
1369
  });
@@ -1359,6 +1385,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1359
1385
  integration,
1360
1386
  userAgent,
1361
1387
  retryThrottledRequestMaxTimes,
1388
+ retryNetworkErrorMaxTimes,
1362
1389
  pusherKey,
1363
1390
  metadata
1364
1391
  });
@@ -1374,6 +1401,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1374
1401
  integration,
1375
1402
  userAgent,
1376
1403
  retryThrottledRequestMaxTimes,
1404
+ retryNetworkErrorMaxTimes,
1377
1405
  baseCDN
1378
1406
  });
1379
1407
  }
@@ -1429,7 +1457,7 @@ const isUrlArray = (data) => {
1429
1457
  return true;
1430
1458
  };
1431
1459
 
1432
- function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, baseCDN = defaultSettings.baseCDN, jsonpCallback }) {
1460
+ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, baseCDN = defaultSettings.baseCDN, jsonpCallback }) {
1433
1461
  if (!isFileDataArray(data) && !isUrlArray(data) && !isUuidArray(data)) {
1434
1462
  throw new TypeError(`Group uploading from "${data}" is not supported`);
1435
1463
  }
@@ -1466,6 +1494,7 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
1466
1494
  integration,
1467
1495
  userAgent,
1468
1496
  retryThrottledRequestMaxTimes,
1497
+ retryNetworkErrorMaxTimes,
1469
1498
  contentType,
1470
1499
  multipartChunkSize,
1471
1500
  baseCDN
@@ -1481,7 +1510,8 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
1481
1510
  source,
1482
1511
  integration,
1483
1512
  userAgent,
1484
- retryThrottledRequestMaxTimes
1513
+ retryThrottledRequestMaxTimes,
1514
+ retryNetworkErrorMaxTimes
1485
1515
  })
1486
1516
  .then((groupInfo) => new UploadcareGroup(groupInfo, files))
1487
1517
  .then((group) => {
@@ -1554,4 +1584,4 @@ class UploadClient {
1554
1584
  }
1555
1585
  }
1556
1586
 
1557
- export { UploadClient, UploadClientError, UploadcareFile, UploadcareGroup, base, fromUrl, fromUrlStatus, getUserAgent$1 as getUserAgent, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadDirect, uploadFile, uploadFileGroup, uploadFromUploaded, uploadFromUrl, uploadMultipart };
1587
+ export { UploadClient, UploadClientError, UploadcareFile, UploadcareGroup, UploadcareNetworkError, base, fromUrl, fromUrlStatus, getUserAgent$1 as getUserAgent, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadDirect, uploadFile, uploadFileGroup, uploadFromUploaded, uploadFromUrl, uploadMultipart };