@uploadcare/upload-client 2.0.0-alpha.6 → 2.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/dist/index.js CHANGED
@@ -1,37 +1,18 @@
1
- import { AbortController } from 'abort-controller';
2
- export { AbortController } from 'abort-controller';
3
- import { request as request$1 } from 'http';
4
- import { request as request$2 } from 'https';
1
+ import http from 'http';
2
+ import https from 'https';
5
3
  import { parse } from 'url';
6
4
  import { Transform, Readable } from 'stream';
7
- import * as NodeFormData from 'form-data';
8
- import * as WebSocket from 'ws';
9
-
10
- /*
11
- Settings for future support:
12
- parallelDirectUploads: 10,
13
- */
14
- const defaultSettings = {
15
- baseCDN: 'https://ucarecdn.com',
16
- baseURL: 'https://upload.uploadcare.com',
17
- maxContentLength: 50 * 1024 * 1024,
18
- retryThrottledRequestMaxTimes: 1,
19
- multipartMinFileSize: 25 * 1024 * 1024,
20
- multipartChunkSize: 5 * 1024 * 1024,
21
- multipartMinLastPartSize: 1024 * 1024,
22
- maxConcurrentRequests: 4,
23
- multipartMaxAttempts: 3,
24
- pollingTimeoutMilliseconds: 10000,
25
- pusherKey: '79ae88bd931ea68464d9'
26
- };
27
- const defaultContentType = 'application/octet-stream';
28
- const defaultFilename = 'original';
5
+ import NodeFormData from 'form-data';
6
+ import { AbortController } from 'abort-controller';
7
+ export { AbortController } from 'abort-controller';
8
+ import WebSocket from 'ws';
29
9
 
30
10
  class UploadClientError extends Error {
31
- constructor(message, request, response, headers) {
11
+ constructor(message, code, request, response, headers) {
32
12
  super();
33
13
  this.name = 'UploadClientError';
34
14
  this.message = message;
15
+ this.code = code;
35
16
  this.request = request;
36
17
  this.response = response;
37
18
  this.headers = headers;
@@ -102,7 +83,7 @@ const request = (params) => {
102
83
  return undefined;
103
84
  }
104
85
  })
105
- .then(length => new Promise((resolve, reject) => {
86
+ .then((length) => new Promise((resolve, reject) => {
106
87
  const isFormData = !!length;
107
88
  let aborted = false;
108
89
  const options = parse(url);
@@ -115,19 +96,19 @@ const request = (params) => {
115
96
  length || data.length;
116
97
  }
117
98
  const req = options.protocol !== 'https:'
118
- ? request$1(options)
119
- : request$2(options);
99
+ ? http.request(options)
100
+ : https.request(options);
120
101
  onCancel(signal, () => {
121
102
  aborted = true;
122
103
  req.abort();
123
104
  reject(cancelError());
124
105
  });
125
- req.on('response', res => {
106
+ req.on('response', (res) => {
126
107
  if (aborted)
127
108
  return;
128
109
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
129
110
  const resChunks = [];
130
- res.on('data', data => {
111
+ res.on('data', (data) => {
131
112
  resChunks.push(data);
132
113
  });
133
114
  res.on('end', () => resolve({
@@ -137,7 +118,7 @@ const request = (params) => {
137
118
  request: params
138
119
  }));
139
120
  });
140
- req.on('error', err => {
121
+ req.on('error', (err) => {
141
122
  if (aborted)
142
123
  return;
143
124
  reject(err);
@@ -156,18 +137,25 @@ const request = (params) => {
156
137
  }));
157
138
  };
158
139
 
140
+ function identity(obj) {
141
+ return obj;
142
+ }
143
+
144
+ const transformFile = identity;
159
145
  var getFormData = () => new NodeFormData();
160
146
 
147
+ const isFileTuple = (tuple) => tuple[0] === 'file';
161
148
  function buildFormData(body) {
162
149
  const formData = getFormData();
163
- const isTriple = (tuple) => tuple[0] === 'file';
164
150
  for (const tuple of body) {
165
151
  if (Array.isArray(tuple[1])) {
166
152
  // refactor this
167
- tuple[1].forEach(val => val && formData.append(tuple[0] + '[]', `${val}`));
153
+ tuple[1].forEach((val) => val && formData.append(tuple[0] + '[]', `${val}`));
168
154
  }
169
- else if (isTriple(tuple)) {
170
- 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);
171
159
  }
172
160
  else if (tuple[1] != null) {
173
161
  formData.append(tuple[0], `${tuple[1]}`);
@@ -179,9 +167,9 @@ function buildFormData(body) {
179
167
  const serializePair = (key, value) => typeof value !== 'undefined' ? `${key}=${encodeURIComponent(value)}` : null;
180
168
  const createQuery = (query) => Object.entries(query)
181
169
  .reduce((params, [key, value]) => params.concat(Array.isArray(value)
182
- ? value.map(value => serializePair(`${key}[]`, value))
170
+ ? value.map((value) => serializePair(`${key}[]`, value))
183
171
  : serializePair(key, value)), [])
184
- .filter(x => !!x)
172
+ .filter((x) => !!x)
185
173
  .join('&');
186
174
  const getUrl = (base, path, query) => [
187
175
  base,
@@ -192,15 +180,52 @@ const getUrl = (base, path, query) => [
192
180
  .filter(Boolean)
193
181
  .join('');
194
182
 
195
- var version = '2.0.0-alpha.6';
183
+ /*
184
+ Settings for future support:
185
+ parallelDirectUploads: 10,
186
+ */
187
+ const defaultSettings = {
188
+ baseCDN: 'https://ucarecdn.com',
189
+ baseURL: 'https://upload.uploadcare.com',
190
+ maxContentLength: 50 * 1024 * 1024,
191
+ retryThrottledRequestMaxTimes: 1,
192
+ multipartMinFileSize: 25 * 1024 * 1024,
193
+ multipartChunkSize: 5 * 1024 * 1024,
194
+ multipartMinLastPartSize: 1024 * 1024,
195
+ maxConcurrentRequests: 4,
196
+ multipartMaxAttempts: 3,
197
+ pollingTimeoutMilliseconds: 10000,
198
+ pusherKey: '79ae88bd931ea68464d9'
199
+ };
200
+ const defaultContentType = 'application/octet-stream';
201
+ const defaultFilename = 'original';
202
+
203
+ var version = '2.0.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;
@@ -316,34 +340,6 @@ function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, se
316
340
  }, retryThrottledRequestMaxTimes);
317
341
  }
318
342
 
319
- /**
320
- * Returns a JSON dictionary holding file info.
321
- */
322
- /* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key", "file_id"]}] */
323
- function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
324
- return retryIfThrottled(() => request({
325
- method: 'GET',
326
- headers: {
327
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
328
- },
329
- url: getUrl(baseURL, '/info/', {
330
- jsonerrors: 1,
331
- pub_key: publicKey,
332
- file_id: uuid,
333
- source
334
- }),
335
- signal
336
- }).then(({ data, headers, request }) => {
337
- const response = camelizeKeys(JSON.parse(data));
338
- if ('error' in response) {
339
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
340
- }
341
- else {
342
- return response;
343
- }
344
- }), retryThrottledRequestMaxTimes);
345
- }
346
-
347
343
  var TypeEnum;
348
344
  (function (TypeEnum) {
349
345
  TypeEnum["Token"] = "token";
@@ -352,12 +348,11 @@ var TypeEnum;
352
348
  /**
353
349
  * Uploading files from URL.
354
350
  */
355
- /* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key", "source_url", "check_URL_duplicates", "save_URL_duplicates"]}] */
356
- 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 }) {
357
352
  return retryIfThrottled(() => request({
358
353
  method: 'POST',
359
354
  headers: {
360
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
355
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
361
356
  },
362
357
  url: getUrl(baseURL, '/from_url/', {
363
358
  jsonerrors: 1,
@@ -375,7 +370,7 @@ function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, stor
375
370
  }).then(({ data, headers, request }) => {
376
371
  const response = camelizeKeys(JSON.parse(data));
377
372
  if ('error' in response) {
378
- 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);
379
374
  }
380
375
  else {
381
376
  return response;
@@ -397,11 +392,17 @@ const isErrorResponse = (response) => {
397
392
  /**
398
393
  * Checking upload status and working with file tokens.
399
394
  */
400
- 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 } = {}) {
401
396
  return retryIfThrottled(() => request({
402
397
  method: 'GET',
403
398
  headers: publicKey
404
- ? { 'X-UC-User-Agent': getUserAgent({ publicKey, integration }) }
399
+ ? {
400
+ 'X-UC-User-Agent': getUserAgent({
401
+ publicKey,
402
+ integration,
403
+ userAgent
404
+ })
405
+ }
405
406
  : undefined,
406
407
  url: getUrl(baseURL, '/from_url/status/', {
407
408
  jsonerrors: 1,
@@ -411,7 +412,7 @@ function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, si
411
412
  }).then(({ data, headers, request }) => {
412
413
  const response = camelizeKeys(JSON.parse(data));
413
414
  if ('error' in response && !isErrorResponse(response)) {
414
- throw new UploadClientError(`[${response.error.statusCode}] ${response.error.content}`, request, response.error, headers);
415
+ throw new UploadClientError(response.error.content, undefined, request, response, headers);
415
416
  }
416
417
  else {
417
418
  return response;
@@ -422,12 +423,11 @@ function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, si
422
423
  /**
423
424
  * Create files group.
424
425
  */
425
- /* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key"]}] */
426
- 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 }) {
427
427
  return retryIfThrottled(() => request({
428
428
  method: 'POST',
429
429
  headers: {
430
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
430
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
431
431
  },
432
432
  url: getUrl(baseURL, '/group/', {
433
433
  jsonerrors: 1,
@@ -442,7 +442,7 @@ function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallb
442
442
  }).then(({ data, headers, request }) => {
443
443
  const response = camelizeKeys(JSON.parse(data));
444
444
  if ('error' in response) {
445
- 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);
446
446
  }
447
447
  else {
448
448
  return response;
@@ -453,12 +453,11 @@ function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallb
453
453
  /**
454
454
  * Get info about group.
455
455
  */
456
- /* eslint @typescript-eslint/camelcase: [2, {allow: ["pub_key", "group_id"]}] */
457
- 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 }) {
458
457
  return retryIfThrottled(() => request({
459
458
  method: 'GET',
460
459
  headers: {
461
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
460
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
462
461
  },
463
462
  url: getUrl(baseURL, '/group/info/', {
464
463
  jsonerrors: 1,
@@ -470,7 +469,7 @@ function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, s
470
469
  }).then(({ data, headers, request }) => {
471
470
  const response = camelizeKeys(JSON.parse(data));
472
471
  if ('error' in response) {
473
- 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);
474
473
  }
475
474
  else {
476
475
  return response;
@@ -479,62 +478,62 @@ function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, s
479
478
  }
480
479
 
481
480
  /**
482
- * Start multipart uploading.
481
+ * Returns a JSON dictionary holding file info.
483
482
  */
484
- function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
483
+ function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
485
484
  return retryIfThrottled(() => request({
486
- method: 'POST',
487
- url: getUrl(baseURL, '/multipart/start/', { jsonerrors: 1 }),
485
+ method: 'GET',
488
486
  headers: {
489
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
487
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
490
488
  },
491
- data: buildFormData([
492
- ['filename', fileName !== null && fileName !== void 0 ? fileName : defaultFilename],
493
- ['size', size],
494
- ['content_type', contentType !== null && contentType !== void 0 ? contentType : defaultContentType],
495
- ['part_size', multipartChunkSize],
496
- ['UPLOADCARE_STORE', store ? '' : 'auto'],
497
- ['UPLOADCARE_PUB_KEY', publicKey],
498
- ['signature', secureSignature],
499
- ['expire', secureExpire],
500
- ['source', source]
501
- ]),
489
+ url: getUrl(baseURL, '/info/', {
490
+ jsonerrors: 1,
491
+ pub_key: publicKey,
492
+ file_id: uuid,
493
+ source
494
+ }),
502
495
  signal
503
496
  }).then(({ data, headers, request }) => {
504
497
  const response = camelizeKeys(JSON.parse(data));
505
498
  if ('error' in response) {
506
- 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);
507
500
  }
508
501
  else {
509
- // convert to array
510
- response.parts = Object.keys(response.parts).map(key => response.parts[key]);
511
502
  return response;
512
503
  }
513
504
  }), retryThrottledRequestMaxTimes);
514
505
  }
515
506
 
516
507
  /**
517
- * Complete multipart uploading.
508
+ * Start multipart uploading.
518
509
  */
519
- function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL, source = 'local', signal, 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 }) {
520
511
  return retryIfThrottled(() => request({
521
512
  method: 'POST',
522
- url: getUrl(baseURL, '/multipart/complete/', { jsonerrors: 1 }),
513
+ url: getUrl(baseURL, '/multipart/start/', { jsonerrors: 1 }),
523
514
  headers: {
524
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration })
515
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
525
516
  },
526
517
  data: buildFormData([
527
- ['uuid', uuid],
518
+ ['filename', fileName !== null && fileName !== void 0 ? fileName : defaultFilename],
519
+ ['size', size],
520
+ ['content_type', contentType !== null && contentType !== void 0 ? contentType : defaultContentType],
521
+ ['part_size', multipartChunkSize],
522
+ ['UPLOADCARE_STORE', store ? '' : 'auto'],
528
523
  ['UPLOADCARE_PUB_KEY', publicKey],
524
+ ['signature', secureSignature],
525
+ ['expire', secureExpire],
529
526
  ['source', source]
530
527
  ]),
531
528
  signal
532
529
  }).then(({ data, headers, request }) => {
533
530
  const response = camelizeKeys(JSON.parse(data));
534
531
  if ('error' in response) {
535
- 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);
536
533
  }
537
534
  else {
535
+ // convert to array
536
+ response.parts = Object.keys(response.parts).map((key) => response.parts[key]);
538
537
  return response;
539
538
  }
540
539
  }), retryThrottledRequestMaxTimes);
@@ -543,20 +542,15 @@ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL,
543
542
  /**
544
543
  * Complete multipart uploading.
545
544
  */
546
- function multipartUpload(part, url, { publicKey, signal, onProgress, integration }) {
545
+ function multipartUpload(part, url, { signal, onProgress }) {
547
546
  return request({
548
547
  method: 'PUT',
549
548
  url,
550
- headers: {
551
- 'X-UC-User-Agent': publicKey
552
- ? getUserAgent({ publicKey, integration })
553
- : undefined
554
- },
555
549
  data: part,
556
550
  onProgress,
557
551
  signal
558
552
  })
559
- .then(result => {
553
+ .then((result) => {
560
554
  // hack for node ¯\_(ツ)_/¯
561
555
  if (onProgress)
562
556
  onProgress({ value: 1 });
@@ -565,12 +559,40 @@ function multipartUpload(part, url, { publicKey, signal, onProgress, integration
565
559
  .then(({ status }) => ({ code: status }));
566
560
  }
567
561
 
562
+ /**
563
+ * Complete multipart uploading.
564
+ */
565
+ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL, source = 'local', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
566
+ return retryIfThrottled(() => request({
567
+ method: 'POST',
568
+ url: getUrl(baseURL, '/multipart/complete/', { jsonerrors: 1 }),
569
+ headers: {
570
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
571
+ },
572
+ data: buildFormData([
573
+ ['uuid', uuid],
574
+ ['UPLOADCARE_PUB_KEY', publicKey],
575
+ ['source', source]
576
+ ]),
577
+ signal
578
+ }).then(({ data, headers, request }) => {
579
+ const response = camelizeKeys(JSON.parse(data));
580
+ if ('error' in response) {
581
+ throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
582
+ }
583
+ else {
584
+ return response;
585
+ }
586
+ }), retryThrottledRequestMaxTimes);
587
+ }
588
+
568
589
  class UploadcareFile {
569
590
  constructor(fileInfo, { baseCDN, defaultEffects, fileName }) {
570
591
  this.name = null;
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, base, fromUrl, fromUrlStatus, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadFromObject as uploadBase, uploadFile, uploadFileGroup, uploadFromUploaded, uploadFromUrl, uploadMultipart };