@uploadcare/upload-client 2.0.0-alpha.7 → 2.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/dist/index.js CHANGED
@@ -1,17 +1,18 @@
1
- import { request as request$1 } from 'http';
2
- import { request as request$2 } from 'https';
1
+ import http from 'http';
2
+ import https from 'https';
3
3
  import { parse } from 'url';
4
4
  import { Transform, Readable } from 'stream';
5
5
  import NodeFormData from 'form-data';
6
6
  import { AbortController } from 'abort-controller';
7
7
  export { AbortController } from 'abort-controller';
8
- import * as WebSocket from 'ws';
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$1(options)
99
- : request$2(options);
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 (isTriple(tuple)) {
150
- formData.append(tuple[0], tuple[1], tuple[2]);
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,15 +200,32 @@ const defaultSettings = {
192
200
  const defaultContentType = 'application/octet-stream';
193
201
  const defaultFilename = 'original';
194
202
 
195
- var version = '1.1.2';
203
+ var version = '2.1.0';
196
204
 
197
205
  /**
198
206
  * Returns User Agent based on version and settings.
199
207
  */
200
- function getUserAgent({ publicKey = '', integration = '' } = {}) {
201
- const mainInfo = [version, publicKey].filter(Boolean).join('/');
202
- const additionInfo = ['JavaScript', integration].filter(Boolean).join('; ');
203
- return `UploadcareUploadClient/${mainInfo} (${additionInfo})`;
208
+ function getUserAgent({ userAgent, publicKey = '', integration = '' } = {}) {
209
+ const libraryName = 'UploadcareUploadClient';
210
+ const libraryVersion = version;
211
+ const languageName = 'JavaScript';
212
+ if (typeof userAgent === 'string') {
213
+ return userAgent;
214
+ }
215
+ if (typeof userAgent === 'function') {
216
+ return userAgent({
217
+ publicKey,
218
+ libraryName,
219
+ libraryVersion,
220
+ languageName,
221
+ integration
222
+ });
223
+ }
224
+ const mainInfo = [libraryName, libraryVersion, publicKey]
225
+ .filter(Boolean)
226
+ .join('/');
227
+ const additionInfo = [languageName, integration].filter(Boolean).join('; ');
228
+ return `${mainInfo} (${additionInfo})`;
204
229
  }
205
230
 
206
231
  const SEPARATOR = /\W|_/g;
@@ -234,7 +259,7 @@ function camelizeKeys(source) {
234
259
  *
235
260
  * @param {number} ms Timeout in milliseconds.
236
261
  */
237
- const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
262
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
238
263
 
239
264
  const defaultOptions = {
240
265
  factor: 2,
@@ -256,7 +281,7 @@ function retrier(fn, options = defaultOptions) {
256
281
  return runAttempt(fn);
257
282
  }
258
283
 
259
- const REQUEST_WAS_THROTTLED_CODE = 429;
284
+ const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
260
285
  const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
261
286
  function getTimeoutFromThrottledRequest(error) {
262
287
  const { headers } = error || {};
@@ -266,9 +291,8 @@ function getTimeoutFromThrottledRequest(error) {
266
291
  }
267
292
  function retryIfThrottled(fn, retryThrottledMaxTimes) {
268
293
  return retrier(({ attempt, retry }) => fn().catch((error) => {
269
- var _a;
270
294
  if ('response' in error &&
271
- ((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.statusCode) === REQUEST_WAS_THROTTLED_CODE &&
295
+ (error === null || error === void 0 ? void 0 : error.code) === REQUEST_WAS_THROTTLED_CODE &&
272
296
  attempt < retryThrottledMaxTimes) {
273
297
  return retry(getTimeoutFromThrottledRequest(error));
274
298
  }
@@ -280,7 +304,7 @@ function retryIfThrottled(fn, retryThrottledMaxTimes) {
280
304
  * Performs file uploading request to Uploadcare Upload API.
281
305
  * Can be canceled and has progress.
282
306
  */
283
- function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
307
+ function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
284
308
  return retryIfThrottled(() => {
285
309
  var _a;
286
310
  return request({
@@ -289,7 +313,7 @@ function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, se
289
313
  jsonerrors: 1
290
314
  }),
291
315
  headers: {
292
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
316
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
293
317
  },
294
318
  data: buildFormData([
295
319
  ['file', file, (_a = fileName !== null && fileName !== void 0 ? fileName : file.name) !== null && _a !== void 0 ? _a : defaultFilename],
@@ -307,7 +331,7 @@ function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, se
307
331
  }).then(({ data, headers, request }) => {
308
332
  const response = camelizeKeys(JSON.parse(data));
309
333
  if ('error' in response) {
310
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
334
+ throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
311
335
  }
312
336
  else {
313
337
  return response;
@@ -324,12 +348,11 @@ var TypeEnum;
324
348
  /**
325
349
  * Uploading files from URL.
326
350
  */
327
- /* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key", "source_url", "check_URL_duplicates", "save_URL_duplicates"]}] */
328
- function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
351
+ function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
329
352
  return retryIfThrottled(() => request({
330
353
  method: 'POST',
331
354
  headers: {
332
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
355
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
333
356
  },
334
357
  url: getUrl(baseURL, '/from_url/', {
335
358
  jsonerrors: 1,
@@ -347,7 +370,7 @@ function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, stor
347
370
  }).then(({ data, headers, request }) => {
348
371
  const response = camelizeKeys(JSON.parse(data));
349
372
  if ('error' in response) {
350
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
373
+ throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
351
374
  }
352
375
  else {
353
376
  return response;
@@ -369,11 +392,17 @@ const isErrorResponse = (response) => {
369
392
  /**
370
393
  * Checking upload status and working with file tokens.
371
394
  */
372
- function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, signal, integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes } = {}) {
395
+ function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes } = {}) {
373
396
  return retryIfThrottled(() => request({
374
397
  method: 'GET',
375
398
  headers: publicKey
376
- ? { 'X-UC-User-Agent': getUserAgent({ publicKey, integration }) }
399
+ ? {
400
+ 'X-UC-User-Agent': getUserAgent({
401
+ publicKey,
402
+ integration,
403
+ userAgent
404
+ })
405
+ }
377
406
  : undefined,
378
407
  url: getUrl(baseURL, '/from_url/status/', {
379
408
  jsonerrors: 1,
@@ -383,7 +412,7 @@ function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, si
383
412
  }).then(({ data, headers, request }) => {
384
413
  const response = camelizeKeys(JSON.parse(data));
385
414
  if ('error' in response && !isErrorResponse(response)) {
386
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
415
+ throw new UploadClientError(response.error.content, undefined, request, response, headers);
387
416
  }
388
417
  else {
389
418
  return response;
@@ -394,12 +423,11 @@ function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, si
394
423
  /**
395
424
  * Create files group.
396
425
  */
397
- /* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key"]}] */
398
- function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallback, secureSignature, secureExpire, signal, source, integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
426
+ function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallback, secureSignature, secureExpire, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
399
427
  return retryIfThrottled(() => request({
400
428
  method: 'POST',
401
429
  headers: {
402
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
430
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
403
431
  },
404
432
  url: getUrl(baseURL, '/group/', {
405
433
  jsonerrors: 1,
@@ -414,7 +442,7 @@ function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallb
414
442
  }).then(({ data, headers, request }) => {
415
443
  const response = camelizeKeys(JSON.parse(data));
416
444
  if ('error' in response) {
417
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
445
+ throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
418
446
  }
419
447
  else {
420
448
  return response;
@@ -425,12 +453,11 @@ function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallb
425
453
  /**
426
454
  * Get info about group.
427
455
  */
428
- /* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key", "group_id"]}] */
429
- function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
456
+ function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
430
457
  return retryIfThrottled(() => request({
431
458
  method: 'GET',
432
459
  headers: {
433
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
460
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
434
461
  },
435
462
  url: getUrl(baseURL, '/group/info/', {
436
463
  jsonerrors: 1,
@@ -442,7 +469,7 @@ function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, s
442
469
  }).then(({ data, headers, request }) => {
443
470
  const response = camelizeKeys(JSON.parse(data));
444
471
  if ('error' in response) {
445
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
472
+ throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
446
473
  }
447
474
  else {
448
475
  return response;
@@ -453,12 +480,11 @@ function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, s
453
480
  /**
454
481
  * Returns a JSON dictionary holding file info.
455
482
  */
456
- /* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key", "file_id"]}] */
457
- function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
483
+ function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
458
484
  return retryIfThrottled(() => request({
459
485
  method: 'GET',
460
486
  headers: {
461
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
487
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
462
488
  },
463
489
  url: getUrl(baseURL, '/info/', {
464
490
  jsonerrors: 1,
@@ -470,7 +496,7 @@ function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, sour
470
496
  }).then(({ data, headers, request }) => {
471
497
  const response = camelizeKeys(JSON.parse(data));
472
498
  if ('error' in response) {
473
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
499
+ throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
474
500
  }
475
501
  else {
476
502
  return response;
@@ -481,12 +507,12 @@ function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, sour
481
507
  /**
482
508
  * Start multipart uploading.
483
509
  */
484
- function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
510
+ function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
485
511
  return retryIfThrottled(() => request({
486
512
  method: 'POST',
487
513
  url: getUrl(baseURL, '/multipart/start/', { jsonerrors: 1 }),
488
514
  headers: {
489
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
515
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
490
516
  },
491
517
  data: buildFormData([
492
518
  ['filename', fileName !== null && fileName !== void 0 ? fileName : defaultFilename],
@@ -503,11 +529,11 @@ function multipartStart(size, { publicKey, contentType, fileName, multipartChunk
503
529
  }).then(({ data, headers, request }) => {
504
530
  const response = camelizeKeys(JSON.parse(data));
505
531
  if ('error' in response) {
506
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
532
+ throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
507
533
  }
508
534
  else {
509
535
  // convert to array
510
- response.parts = Object.keys(response.parts).map(key => response.parts[key]);
536
+ response.parts = Object.keys(response.parts).map((key) => response.parts[key]);
511
537
  return response;
512
538
  }
513
539
  }), retryThrottledRequestMaxTimes);
@@ -516,20 +542,15 @@ function multipartStart(size, { publicKey, contentType, fileName, multipartChunk
516
542
  /**
517
543
  * Complete multipart uploading.
518
544
  */
519
- function multipartUpload(part, url, { publicKey, signal, onProgress, integration }) {
545
+ function multipartUpload(part, url, { signal, onProgress }) {
520
546
  return request({
521
547
  method: 'PUT',
522
548
  url,
523
- headers: {
524
- 'X-UC-User-Agent': publicKey
525
- ? getUserAgent({ publicKey, integration })
526
- : undefined
527
- },
528
549
  data: part,
529
550
  onProgress,
530
551
  signal
531
552
  })
532
- .then(result => {
553
+ .then((result) => {
533
554
  // hack for node ¯\_(ツ)_/¯
534
555
  if (onProgress)
535
556
  onProgress({ value: 1 });
@@ -541,12 +562,12 @@ function multipartUpload(part, url, { publicKey, signal, onProgress, integration
541
562
  /**
542
563
  * Complete multipart uploading.
543
564
  */
544
- function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL, source = 'local', signal, integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
565
+ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL, source = 'local', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
545
566
  return retryIfThrottled(() => request({
546
567
  method: 'POST',
547
568
  url: getUrl(baseURL, '/multipart/complete/', { jsonerrors: 1 }),
548
569
  headers: {
549
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
570
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
550
571
  },
551
572
  data: buildFormData([
552
573
  ['uuid', uuid],
@@ -557,7 +578,7 @@ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL,
557
578
  }).then(({ data, headers, request }) => {
558
579
  const response = camelizeKeys(JSON.parse(data));
559
580
  if ('error' in response) {
560
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
581
+ throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
561
582
  }
562
583
  else {
563
584
  return response;
@@ -571,6 +592,7 @@ class UploadcareFile {
571
592
  this.size = null;
572
593
  this.isStored = null;
573
594
  this.isImage = null;
595
+ this.mimeType = null;
574
596
  this.cdnUrl = null;
575
597
  this.cdnUrlModifiers = null;
576
598
  this.originalUrl = null;
@@ -589,6 +611,7 @@ class UploadcareFile {
589
611
  this.size = fileInfo.size;
590
612
  this.isStored = fileInfo.isStored;
591
613
  this.isImage = fileInfo.isImage;
614
+ this.mimeType = fileInfo.mimeType;
592
615
  this.cdnUrl = cdnUrl;
593
616
  this.cdnUrlModifiers = cdnUrlModifiers;
594
617
  this.originalUrl = originalUrl;
@@ -608,7 +631,7 @@ const poll = ({ check, interval = DEFAULT_INTERVAL, signal }) => new Promise((re
608
631
  const tick = () => {
609
632
  try {
610
633
  Promise.resolve(check(signal))
611
- .then(result => {
634
+ .then((result) => {
612
635
  if (result) {
613
636
  resolve(result);
614
637
  }
@@ -616,7 +639,7 @@ const poll = ({ check, interval = DEFAULT_INTERVAL, signal }) => new Promise((re
616
639
  timeoutId = setTimeout(tick, interval);
617
640
  }
618
641
  })
619
- .catch(error => reject(error));
642
+ .catch((error) => reject(error));
620
643
  }
621
644
  catch (error) {
622
645
  reject(error);
@@ -625,16 +648,17 @@ const poll = ({ check, interval = DEFAULT_INTERVAL, signal }) => new Promise((re
625
648
  timeoutId = setTimeout(tick, 0);
626
649
  });
627
650
 
628
- function isReadyPoll({ file, publicKey, baseURL, source, integration, retryThrottledRequestMaxTimes, signal, onProgress }) {
651
+ function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, signal, onProgress }) {
629
652
  return poll({
630
- check: signal => info(file, {
653
+ check: (signal) => info(file, {
631
654
  publicKey,
632
655
  baseURL,
633
656
  signal,
634
657
  source,
635
658
  integration,
659
+ userAgent,
636
660
  retryThrottledRequestMaxTimes
637
- }).then(response => {
661
+ }).then((response) => {
638
662
  if (response.isReady) {
639
663
  return response;
640
664
  }
@@ -645,7 +669,7 @@ function isReadyPoll({ file, publicKey, baseURL, source, integration, retryThrot
645
669
  });
646
670
  }
647
671
 
648
- const uploadFromObject = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, retryThrottledRequestMaxTimes, baseCDN }) => {
672
+ const uploadFromObject = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN }) => {
649
673
  return base(file, {
650
674
  publicKey,
651
675
  fileName,
@@ -657,6 +681,7 @@ const uploadFromObject = (file, { publicKey, fileName, baseURL, secureSignature,
657
681
  onProgress,
658
682
  source,
659
683
  integration,
684
+ userAgent,
660
685
  retryThrottledRequestMaxTimes
661
686
  })
662
687
  .then(({ file }) => {
@@ -666,12 +691,13 @@ const uploadFromObject = (file, { publicKey, fileName, baseURL, secureSignature,
666
691
  baseURL,
667
692
  source,
668
693
  integration,
694
+ userAgent,
669
695
  retryThrottledRequestMaxTimes,
670
696
  onProgress,
671
697
  signal
672
698
  });
673
699
  })
674
- .then(fileInfo => new UploadcareFile(fileInfo, { baseCDN }));
700
+ .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
675
701
  };
676
702
 
677
703
  const race = (fns, { signal } = {}) => {
@@ -683,21 +709,21 @@ const race = (fns, { signal } = {}) => {
683
709
  controllers.forEach((controller, index) => index !== i && controller.abort());
684
710
  };
685
711
  onCancel(signal, () => {
686
- controllers.forEach(controller => controller.abort());
712
+ controllers.forEach((controller) => controller.abort());
687
713
  });
688
714
  return Promise.all(fns.map((fn, i) => {
689
715
  const stopRace = createStopRaceCallback(i);
690
716
  return Promise.resolve()
691
717
  .then(() => fn({ stopRace, signal: controllers[i].signal }))
692
- .then(result => {
718
+ .then((result) => {
693
719
  stopRace();
694
720
  return result;
695
721
  })
696
- .catch(error => {
722
+ .catch((error) => {
697
723
  lastError = error;
698
724
  return null;
699
725
  });
700
- })).then(results => {
726
+ })).then((results) => {
701
727
  if (winnerIndex === null) {
702
728
  throw lastError;
703
729
  }
@@ -713,7 +739,7 @@ class Events {
713
739
  }
714
740
  emit(event, data) {
715
741
  var _a;
716
- (_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));
717
743
  }
718
744
  on(event, callback) {
719
745
  this.events[event] = this.events[event] || [];
@@ -721,7 +747,7 @@ class Events {
721
747
  }
722
748
  off(event, callback) {
723
749
  if (callback) {
724
- this.events[event] = this.events[event].filter(fn => fn !== callback);
750
+ this.events[event] = this.events[event].filter((fn) => fn !== callback);
725
751
  }
726
752
  else {
727
753
  this.events[event] = [];
@@ -754,16 +780,16 @@ class Pusher {
754
780
  if (!this.isConnected && !this.ws) {
755
781
  const pusherUrl = `wss://ws.pusherapp.com/app/${this.key}?protocol=5&client=js&version=1.12.2`;
756
782
  this.ws = new WebSocket(pusherUrl);
757
- this.ws.addEventListener('error', error => {
783
+ this.ws.addEventListener('error', (error) => {
758
784
  this.emmitter.emit('error', new Error(error.message));
759
785
  });
760
786
  this.emmitter.on('connected', () => {
761
787
  this.isConnected = true;
762
- this.queue.forEach(message => this.send(message.event, message.data));
788
+ this.queue.forEach((message) => this.send(message.event, message.data));
763
789
  this.queue = [];
764
790
  });
765
- this.ws.addEventListener('message', e => {
766
- const data = JSON.parse(e.data);
791
+ this.ws.addEventListener('message', (e) => {
792
+ const data = JSON.parse(e.data.toString());
767
793
  switch (data.event) {
768
794
  case 'pusher:connection_established': {
769
795
  this.emmitter.emit('connected', undefined);
@@ -831,7 +857,7 @@ class Pusher {
831
857
  this.send(message.event, message.data);
832
858
  }
833
859
  else {
834
- this.queue = this.queue.filter(msg => msg.data.channel !== channel);
860
+ this.queue = this.queue.filter((msg) => msg.data.channel !== channel);
835
861
  }
836
862
  if (this.subscribers === 0) {
837
863
  this.disconnect();
@@ -855,18 +881,19 @@ const preconnect = (key) => {
855
881
  getPusher(key).connect();
856
882
  };
857
883
 
858
- function pollStrategy({ token, publicKey, baseURL, integration, retryThrottledRequestMaxTimes, onProgress, signal }) {
884
+ function pollStrategy({ token, publicKey, baseURL, integration, userAgent, retryThrottledRequestMaxTimes, onProgress, signal }) {
859
885
  return poll({
860
- check: signal => fromUrlStatus(token, {
886
+ check: (signal) => fromUrlStatus(token, {
861
887
  publicKey,
862
888
  baseURL,
863
889
  integration,
890
+ userAgent,
864
891
  retryThrottledRequestMaxTimes,
865
892
  signal
866
- }).then(response => {
893
+ }).then((response) => {
867
894
  switch (response.status) {
868
895
  case Status.Error: {
869
- return new UploadClientError(response.error);
896
+ return new UploadClientError(response.error, response.errorCode);
870
897
  }
871
898
  case Status.Waiting: {
872
899
  return false;
@@ -892,7 +919,7 @@ function pollStrategy({ token, publicKey, baseURL, integration, retryThrottledRe
892
919
  signal
893
920
  });
894
921
  }
895
- const pushStrategy = ({ token, pusherKey, signal, stopRace, onProgress }) => new Promise((resolve, reject) => {
922
+ const pushStrategy = ({ token, pusherKey, signal, onProgress }) => new Promise((resolve, reject) => {
896
923
  const pusher = getPusher(pusherKey);
897
924
  const unsubErrorHandler = pusher.onError(reject);
898
925
  const destroy = () => {
@@ -901,10 +928,9 @@ const pushStrategy = ({ token, pusherKey, signal, stopRace, onProgress }) => new
901
928
  };
902
929
  onCancel(signal, () => {
903
930
  destroy();
904
- reject(cancelError('pisher cancelled'));
931
+ reject(cancelError('pusher cancelled'));
905
932
  });
906
- pusher.subscribe(token, result => {
907
- stopRace();
933
+ pusher.subscribe(token, (result) => {
908
934
  switch (result.status) {
909
935
  case Status.Progress: {
910
936
  if (onProgress) {
@@ -921,12 +947,12 @@ const pushStrategy = ({ token, pusherKey, signal, stopRace, onProgress }) => new
921
947
  }
922
948
  case Status.Error: {
923
949
  destroy();
924
- reject(new UploadClientError(result.msg));
950
+ reject(new UploadClientError(result.msg, result.error_code));
925
951
  }
926
952
  }
927
953
  });
928
954
  });
929
- const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, store, signal, onProgress, source, integration, retryThrottledRequestMaxTimes, pusherKey = defaultSettings.pusherKey }) => Promise.resolve(preconnect(pusherKey))
955
+ 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))
930
956
  .then(() => fromUrl(sourceUrl, {
931
957
  publicKey,
932
958
  fileName,
@@ -939,9 +965,15 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
939
965
  signal,
940
966
  source,
941
967
  integration,
968
+ userAgent,
942
969
  retryThrottledRequestMaxTimes
943
970
  }))
944
- .then(urlResponse => {
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) => {
945
977
  if (urlResponse.type === TypeEnum.FileInfo) {
946
978
  return urlResponse;
947
979
  }
@@ -952,47 +984,49 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
952
984
  publicKey,
953
985
  baseURL,
954
986
  integration,
987
+ userAgent,
955
988
  retryThrottledRequestMaxTimes,
956
989
  onProgress,
957
990
  signal
958
991
  }),
959
- ({ stopRace, signal }) => pushStrategy({
992
+ ({ signal }) => pushStrategy({
960
993
  token: urlResponse.token,
961
994
  pusherKey,
962
- stopRace,
963
995
  signal,
964
996
  onProgress
965
997
  })
966
998
  ], { signal });
967
999
  }
968
1000
  })
969
- .then(result => {
1001
+ .then((result) => {
970
1002
  if (result instanceof UploadClientError)
971
1003
  throw result;
972
1004
  return result;
973
1005
  })
974
- .then(result => isReadyPoll({
1006
+ .then((result) => isReadyPoll({
975
1007
  file: result.uuid,
976
1008
  publicKey,
977
1009
  baseURL,
978
1010
  integration,
1011
+ userAgent,
979
1012
  retryThrottledRequestMaxTimes,
980
1013
  onProgress,
981
1014
  signal
982
1015
  }))
983
- .then(fileInfo => new UploadcareFile(fileInfo, { baseCDN }));
1016
+ .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
984
1017
 
985
- const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, retryThrottledRequestMaxTimes, baseCDN }) => {
1018
+ const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN }) => {
986
1019
  return info(uuid, {
987
1020
  publicKey,
988
1021
  baseURL,
989
1022
  signal,
990
1023
  source,
991
1024
  integration,
1025
+ userAgent,
992
1026
  retryThrottledRequestMaxTimes
993
1027
  })
994
- .then(fileInfo => new UploadcareFile(fileInfo, { baseCDN, fileName }))
995
- .then(result => {
1028
+ .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
1029
+ .then((result) => {
996
1030
  // hack for node ¯\_(ツ)_/¯
997
1031
  if (onProgress)
998
1032
  onProgress({ value: 1 });
@@ -1041,6 +1075,16 @@ const isMultipart = (fileSize, multipartMinFileSize = defaultSettings.multipartM
1041
1075
  return fileSize >= multipartMinFileSize;
1042
1076
  };
1043
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
+
1044
1088
  const runWithConcurrency = (concurrency, tasks) => {
1045
1089
  return new Promise((resolve, reject) => {
1046
1090
  const results = [];
@@ -1064,7 +1108,7 @@ const runWithConcurrency = (concurrency, tasks) => {
1064
1108
  resolve(results);
1065
1109
  }
1066
1110
  })
1067
- .catch(error => {
1111
+ .catch((error) => {
1068
1112
  rejected = true;
1069
1113
  reject(error);
1070
1114
  });
@@ -1076,23 +1120,18 @@ const runWithConcurrency = (concurrency, tasks) => {
1076
1120
  });
1077
1121
  };
1078
1122
 
1079
- const getChunk = (file, index, fileSize, chunkSize) => {
1080
- const start = chunkSize * index;
1081
- const end = Math.min(start + chunkSize, fileSize);
1082
- return file.slice(start, end);
1083
- };
1084
1123
  const uploadPartWithRetry = (chunk, url, { publicKey, onProgress, signal, integration, multipartMaxAttempts }) => retrier(({ attempt, retry }) => multipartUpload(chunk, url, {
1085
1124
  publicKey,
1086
1125
  onProgress,
1087
1126
  signal,
1088
1127
  integration
1089
- }).catch(error => {
1128
+ }).catch((error) => {
1090
1129
  if (attempt < multipartMaxAttempts) {
1091
1130
  return retry();
1092
1131
  }
1093
1132
  throw error;
1094
1133
  }));
1095
- const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, maxConcurrentRequests = defaultSettings.maxConcurrentRequests, multipartMaxAttempts = defaultSettings.multipartMaxAttempts, baseCDN }) => {
1134
+ 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 }) => {
1096
1135
  const size = fileSize || getFileSize(file);
1097
1136
  let progressValues;
1098
1137
  const createProgressHandler = (size, index) => {
@@ -1118,26 +1157,31 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1118
1157
  signal,
1119
1158
  source,
1120
1159
  integration,
1160
+ userAgent,
1121
1161
  retryThrottledRequestMaxTimes
1122
1162
  })
1123
- .then(({ uuid, parts }) => Promise.all([
1124
- uuid,
1125
- runWithConcurrency(maxConcurrentRequests, parts.map((url, index) => () => uploadPartWithRetry(getChunk(file, index, size, multipartChunkSize), url, {
1126
- publicKey,
1127
- onProgress: createProgressHandler(parts.length, index),
1128
- signal,
1129
- integration,
1130
- multipartMaxAttempts
1131
- })))
1132
- ]))
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
+ })
1133
1176
  .then(([uuid]) => multipartComplete(uuid, {
1134
1177
  publicKey,
1135
1178
  baseURL,
1136
1179
  source,
1137
1180
  integration,
1181
+ userAgent,
1138
1182
  retryThrottledRequestMaxTimes
1139
1183
  }))
1140
- .then(fileInfo => {
1184
+ .then((fileInfo) => {
1141
1185
  if (fileInfo.isReady) {
1142
1186
  return fileInfo;
1143
1187
  }
@@ -1148,19 +1192,20 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1148
1192
  baseURL,
1149
1193
  source,
1150
1194
  integration,
1195
+ userAgent,
1151
1196
  retryThrottledRequestMaxTimes,
1152
1197
  onProgress,
1153
1198
  signal
1154
1199
  });
1155
1200
  }
1156
1201
  })
1157
- .then(fileInfo => new UploadcareFile(fileInfo, { baseCDN }));
1202
+ .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1158
1203
  };
1159
1204
 
1160
1205
  /**
1161
1206
  * Uploads file from provided data.
1162
1207
  */
1163
- function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, baseCDN = defaultSettings.baseCDN }) {
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 }) {
1164
1209
  if (isFileData(data)) {
1165
1210
  const fileSize = getFileSize(data);
1166
1211
  if (isMultipart(fileSize)) {
@@ -1168,6 +1213,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1168
1213
  publicKey,
1169
1214
  contentType,
1170
1215
  multipartChunkSize,
1216
+ multipartMaxAttempts,
1171
1217
  fileName,
1172
1218
  baseURL,
1173
1219
  secureSignature,
@@ -1177,6 +1223,8 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1177
1223
  onProgress,
1178
1224
  source,
1179
1225
  integration,
1226
+ userAgent,
1227
+ maxConcurrentRequests,
1180
1228
  retryThrottledRequestMaxTimes,
1181
1229
  baseCDN
1182
1230
  });
@@ -1192,6 +1240,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1192
1240
  onProgress,
1193
1241
  source,
1194
1242
  integration,
1243
+ userAgent,
1195
1244
  retryThrottledRequestMaxTimes,
1196
1245
  baseCDN
1197
1246
  });
@@ -1201,6 +1250,9 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1201
1250
  publicKey,
1202
1251
  fileName,
1203
1252
  baseURL,
1253
+ baseCDN,
1254
+ checkForUrlDuplicates,
1255
+ saveUrlForRecurrentUploads,
1204
1256
  secureSignature,
1205
1257
  secureExpire,
1206
1258
  store,
@@ -1208,8 +1260,9 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1208
1260
  onProgress,
1209
1261
  source,
1210
1262
  integration,
1263
+ userAgent,
1211
1264
  retryThrottledRequestMaxTimes,
1212
- baseCDN
1265
+ pusherKey
1213
1266
  });
1214
1267
  }
1215
1268
  if (isUuid(data)) {
@@ -1221,6 +1274,7 @@ function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseU
1221
1274
  onProgress,
1222
1275
  source,
1223
1276
  integration,
1277
+ userAgent,
1224
1278
  retryThrottledRequestMaxTimes,
1225
1279
  baseCDN
1226
1280
  });
@@ -1235,8 +1289,7 @@ class UploadcareGroup {
1235
1289
  this.filesCount = groupInfo.filesCount;
1236
1290
  this.totalSize = Object.values(groupInfo.files).reduce((acc, file) => acc + file.size, 0);
1237
1291
  this.isStored = !!groupInfo.datetimeStored;
1238
- this.isImage = !!Object.values(groupInfo.files).filter(file => file.isImage)
1239
- .length;
1292
+ this.isImage = !!Object.values(groupInfo.files).filter((file) => file.isImage).length;
1240
1293
  this.cdnUrl = groupInfo.cdnUrl;
1241
1294
  this.files = files;
1242
1295
  this.createdAt = groupInfo.datetimeCreated;
@@ -1278,7 +1331,7 @@ const isUrlArray = (data) => {
1278
1331
  return true;
1279
1332
  };
1280
1333
 
1281
- function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, baseCDN = defaultSettings.baseCDN, jsonpCallback, defaultEffects }) {
1334
+ 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, defaultEffects }) {
1282
1335
  if (!isFileDataArray(data) && !isUrlArray(data) && !isUuidArray(data)) {
1283
1336
  throw new TypeError(`Group uploading from "${data}" is not supported`);
1284
1337
  }
@@ -1307,12 +1360,13 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
1307
1360
  onProgress: createProgressHandler(filesCount, index),
1308
1361
  source,
1309
1362
  integration,
1363
+ userAgent,
1310
1364
  retryThrottledRequestMaxTimes,
1311
1365
  contentType,
1312
1366
  multipartChunkSize,
1313
1367
  baseCDN
1314
- }))).then(files => {
1315
- const uuids = files.map(file => file.uuid);
1368
+ }))).then((files) => {
1369
+ const uuids = files.map((file) => file.uuid);
1316
1370
  const addDefaultEffects = (file) => {
1317
1371
  const cdnUrlModifiers = defaultEffects ? `-/${defaultEffects}` : null;
1318
1372
  const cdnUrl = `${file.urlBase}${cdnUrlModifiers || ''}`;
@@ -1329,8 +1383,9 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
1329
1383
  signal,
1330
1384
  source,
1331
1385
  integration,
1386
+ userAgent,
1332
1387
  retryThrottledRequestMaxTimes
1333
- }).then(groupInfo => new UploadcareGroup(groupInfo, filesInGroup));
1388
+ }).then((groupInfo) => new UploadcareGroup(groupInfo, filesInGroup));
1334
1389
  });
1335
1390
  }
1336
1391
 
@@ -1394,4 +1449,4 @@ class UploadClient {
1394
1449
  }
1395
1450
  }
1396
1451
 
1397
- export { UploadClient, base, fromUrl, fromUrlStatus, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadFile, uploadFileGroup };
1452
+ export { UploadClient, UploadcareFile, UploadcareGroup, base, fromUrl, fromUrlStatus, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadFromObject as uploadBase, uploadFile, uploadFileGroup, uploadFromUploaded, uploadFromUrl, uploadMultipart };