@uploadcare/upload-client 6.0.1-alpha.8 → 6.1.0-alpha.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.
@@ -157,6 +157,26 @@ const poll = ({ check, interval = DEFAULT_INTERVAL, timeout, signal }) => new Pr
157
157
  tickTimeoutId = setTimeout(tick, 0);
158
158
  });
159
159
 
160
+ /*
161
+ Settings for future support:
162
+ parallelDirectUploads: 10,
163
+ */
164
+ const defaultSettings = {
165
+ baseCDN: 'https://ucarecdn.com',
166
+ baseURL: 'https://upload.uploadcare.com',
167
+ maxContentLength: 50 * 1024 * 1024,
168
+ retryThrottledRequestMaxTimes: 1,
169
+ retryNetworkErrorMaxTimes: 3,
170
+ multipartMinFileSize: 25 * 1024 * 1024,
171
+ multipartChunkSize: 5 * 1024 * 1024,
172
+ multipartMinLastPartSize: 1024 * 1024,
173
+ maxConcurrentRequests: 4,
174
+ pollingTimeoutMilliseconds: 10000,
175
+ pusherKey: '79ae88bd931ea68464d9'
176
+ };
177
+ const defaultContentType = 'application/octet-stream';
178
+ const defaultFilename = 'original';
179
+
160
180
  const request = ({ method, url, data, headers = {}, signal, onProgress }) => new Promise((resolve, reject) => {
161
181
  const xhr = new XMLHttpRequest();
162
182
  const requestMethod = method?.toUpperCase() || 'GET';
@@ -168,14 +188,12 @@ const request = ({ method, url, data, headers = {}, signal, onProgress }) => new
168
188
  * and https://bugs.chromium.org/p/chromium/issues/detail?id=1346628
169
189
  */
170
190
  xhr.open(requestMethod, url, true);
171
- console.log(`xhr.open(${requestMethod}, ${url}, true)`);
172
191
  if (headers) {
173
192
  Object.entries(headers).forEach((entry) => {
174
193
  const [key, value] = entry;
175
194
  typeof value !== 'undefined' &&
176
195
  !Array.isArray(value) &&
177
196
  xhr.setRequestHeader(key, value);
178
- console.log(`xhr.setRequestHeader(${key}, ${value})`);
179
197
  });
180
198
  }
181
199
  xhr.responseType = 'text';
@@ -227,7 +245,6 @@ const request = ({ method, url, data, headers = {}, signal, onProgress }) => new
227
245
  xhr.onerror = (progressEvent) => {
228
246
  if (aborted)
229
247
  return;
230
- console.log('aboirt', xhr, progressEvent);
231
248
  // only triggers if the request couldn't be made at all
232
249
  reject(new UploadcareNetworkError(progressEvent));
233
250
  };
@@ -245,7 +262,6 @@ const request = ({ method, url, data, headers = {}, signal, onProgress }) => new
245
262
  };
246
263
  }
247
264
  if (data) {
248
- console.log(`xhr.send(${data})`);
249
265
  xhr.send(data);
250
266
  }
251
267
  else {
@@ -253,26 +269,28 @@ const request = ({ method, url, data, headers = {}, signal, onProgress }) => new
253
269
  }
254
270
  });
255
271
 
256
- const isReactNativeUri = (uri) => {
257
- if (typeof uri !== 'string') {
258
- return false;
259
- }
260
- return uri.startsWith('file:') || uri.startsWith('content:');
272
+ const isBlob = (data) => {
273
+ return typeof Blob !== 'undefined' && data instanceof Blob;
261
274
  };
262
- const isReactNativeAsset = (asset) => {
263
- return (!!asset &&
264
- typeof asset === 'object' &&
265
- !Array.isArray(asset) &&
266
- 'uri' in asset &&
267
- typeof asset.uri === 'string' &&
268
- isReactNativeUri(asset.uri));
275
+ const isFile = (data) => {
276
+ return typeof File !== 'undefined' && data instanceof File;
277
+ };
278
+ const isBuffer = (data) => {
279
+ return typeof Buffer !== 'undefined' && data instanceof Buffer;
280
+ };
281
+ const isReactNativeAsset = (data) => {
282
+ return (!!data &&
283
+ typeof data === 'object' &&
284
+ !Array.isArray(data) &&
285
+ 'uri' in data &&
286
+ typeof data.uri === 'string');
287
+ };
288
+ const isFileData = (data) => {
289
+ return (isBlob(data) || isFile(data) || isBuffer(data) || isReactNativeAsset(data));
269
290
  };
270
291
 
271
- const getFileOptions = ({ name }) => name ? [name] : [];
292
+ const getFileOptions = () => [];
272
293
  const transformFile = (file, name, contentType) => {
273
- if (isReactNativeUri(file)) {
274
- return { uri: file, name, type: contentType };
275
- }
276
294
  if (isReactNativeAsset(file)) {
277
295
  return {
278
296
  uri: file.uri,
@@ -280,41 +298,14 @@ const transformFile = (file, name, contentType) => {
280
298
  type: file.type || contentType
281
299
  };
282
300
  }
283
- const uri = URL.createObjectURL(file);
284
- return { uri, name, type: contentType };
301
+ if (isBlob(file)) {
302
+ const uri = URL.createObjectURL(file);
303
+ return { uri, name: name, type: file.type || contentType };
304
+ }
305
+ throw new Error(`Unsupported file type.`);
285
306
  };
286
307
  var getFormData = () => new FormData();
287
308
 
288
- /**
289
- * FileData type guard.
290
- */
291
- const isFileData = (data) => {
292
- return (data !== undefined &&
293
- ((typeof Blob !== 'undefined' && data instanceof Blob) ||
294
- (typeof File !== 'undefined' && data instanceof File) ||
295
- (typeof Buffer !== 'undefined' && data instanceof Buffer) ||
296
- (typeof data === 'string' && isReactNativeUri(data)) ||
297
- (typeof data === 'object' && isReactNativeAsset(data))));
298
- };
299
- /**
300
- * Uuid type guard.
301
- */
302
- const isUuid = (data) => {
303
- const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
304
- const regExp = new RegExp(UUID_REGEX);
305
- return !isFileData(data) && regExp.test(data);
306
- };
307
- /**
308
- * Url type guard.
309
- *
310
- * @param {NodeFile | BrowserFile | Url | Uuid} data
311
- */
312
- const isUrl = (data) => {
313
- const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
314
- const regExp = new RegExp(URL_REGEX);
315
- return !isFileData(data) && regExp.test(data);
316
- };
317
-
318
309
  const isSimpleValue = (value) => {
319
310
  return (typeof value === 'string' ||
320
311
  typeof value === 'number' ||
@@ -330,8 +321,8 @@ const isFileValue = (value) => !!value &&
330
321
  function collectParams(params, inputKey, inputValue) {
331
322
  if (isFileValue(inputValue)) {
332
323
  const { name, contentType } = inputValue;
333
- const file = transformFile(inputValue.data, name, contentType); // lgtm [js/superfluous-trailing-arguments]
334
- const options = getFileOptions({ name, contentType });
324
+ const file = transformFile(inputValue.data, name, contentType);
325
+ const options = getFileOptions();
335
326
  params.push([inputKey, file, ...options]);
336
327
  }
337
328
  else if (isObjectValue(inputValue)) {
@@ -353,11 +344,9 @@ function getFormDataParams(options) {
353
344
  return params;
354
345
  }
355
346
  function buildFormData(options) {
356
- console.log('buildFormData', options);
357
347
  const formData = getFormData();
358
348
  const paramsList = getFormDataParams(options);
359
349
  for (const params of paramsList) {
360
- console.log('params', params);
361
350
  const [key, value, ...rest] = params;
362
351
  // node form-data has another signature for append
363
352
  formData.append(key, value, ...rest);
@@ -365,6 +354,19 @@ function buildFormData(options) {
365
354
  return formData;
366
355
  }
367
356
 
357
+ class UploadClientError extends Error {
358
+ constructor(message, code, request, response, headers) {
359
+ super();
360
+ this.name = 'UploadClientError';
361
+ this.message = message;
362
+ this.code = code;
363
+ this.request = request;
364
+ this.response = response;
365
+ this.headers = headers;
366
+ Object.setPrototypeOf(this, UploadClientError.prototype);
367
+ }
368
+ }
369
+
368
370
  const buildSearchParams = (query) => {
369
371
  const searchParams = new URLSearchParams();
370
372
  for (const [key, value] of Object.entries(query)) {
@@ -396,26 +398,6 @@ const getUrl = (base, path, query) => {
396
398
  return url.toString();
397
399
  };
398
400
 
399
- /*
400
- Settings for future support:
401
- parallelDirectUploads: 10,
402
- */
403
- const defaultSettings = {
404
- baseCDN: 'https://ucarecdn.com',
405
- baseURL: 'https://upload.uploadcare.com',
406
- maxContentLength: 50 * 1024 * 1024,
407
- retryThrottledRequestMaxTimes: 1,
408
- retryNetworkErrorMaxTimes: 3,
409
- multipartMinFileSize: 25 * 1024 * 1024,
410
- multipartChunkSize: 5 * 1024 * 1024,
411
- multipartMinLastPartSize: 1024 * 1024,
412
- maxConcurrentRequests: 4,
413
- pollingTimeoutMilliseconds: 10000,
414
- pusherKey: '79ae88bd931ea68464d9'
415
- };
416
- const defaultContentType = 'application/octet-stream';
417
- const defaultFilename = 'original';
418
-
419
401
  var version = '6.0.0';
420
402
 
421
403
  const LIBRARY_NAME = 'UploadcareUploadClient';
@@ -428,19 +410,6 @@ function getUserAgent(options) {
428
410
  });
429
411
  }
430
412
 
431
- class UploadClientError extends Error {
432
- constructor(message, code, request, response, headers) {
433
- super();
434
- this.name = 'UploadClientError';
435
- this.message = message;
436
- this.code = code;
437
- this.request = request;
438
- this.response = response;
439
- this.headers = headers;
440
- Object.setPrototypeOf(this, UploadClientError.prototype);
441
- }
442
- }
443
-
444
413
  const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
445
414
  const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
446
415
  const DEFAULT_NETWORK_ERROR_TIMEOUT = 1000;
@@ -471,6 +440,36 @@ function retryIfFailed(fn, options) {
471
440
  }));
472
441
  }
473
442
 
443
+ const getContentType = (file) => {
444
+ let contentType = '';
445
+ if (isBlob(file) || isFile(file) || isReactNativeAsset(file)) {
446
+ contentType = file.type;
447
+ }
448
+ if (contentType) {
449
+ return contentType;
450
+ }
451
+ console.warn(`Cannot determine content type. Using default content type: ${defaultContentType}`, file);
452
+ return defaultContentType;
453
+ };
454
+
455
+ const getFileName = (file) => {
456
+ let filename = '';
457
+ if (isFile(file) && file.name) {
458
+ filename = file.name;
459
+ }
460
+ else if (isBlob(file) || isBuffer(file)) {
461
+ filename = '';
462
+ }
463
+ else if (isReactNativeAsset(file) && file.name) {
464
+ filename = file.name;
465
+ }
466
+ if (filename) {
467
+ return filename;
468
+ }
469
+ console.warn(`Cannot determine filename. Using default filename: ${defaultFilename}`, file);
470
+ return defaultFilename;
471
+ };
472
+
474
473
  function getStoreValue(store) {
475
474
  return typeof store === 'undefined' ? 'auto' : store ? '1' : '0';
476
475
  }
@@ -486,13 +485,13 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
486
485
  jsonerrors: 1
487
486
  }),
488
487
  headers: {
489
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent }),
488
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
490
489
  },
491
490
  data: buildFormData({
492
491
  file: {
493
492
  data: file,
494
- name: fileName ?? file?.name ?? defaultFilename,
495
- contentType: contentType ?? file?.type ?? defaultContentType
493
+ name: fileName || getFileName(file),
494
+ contentType: contentType || getContentType(file)
496
495
  },
497
496
  UPLOADCARE_PUB_KEY: publicKey,
498
497
  UPLOADCARE_STORE: getStoreValue(store),
@@ -690,9 +689,9 @@ function multipartStart(size, { publicKey, contentType, fileName, multipartChunk
690
689
  'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
691
690
  },
692
691
  data: buildFormData({
693
- filename: fileName ?? defaultFilename,
692
+ filename: fileName || defaultFilename,
694
693
  size: size,
695
- content_type: contentType ?? defaultContentType,
694
+ content_type: contentType || defaultContentType,
696
695
  part_size: multipartChunkSize,
697
696
  UPLOADCARE_STORE: getStoreValue(store),
698
697
  UPLOADCARE_PUB_KEY: publicKey,
@@ -769,6 +768,28 @@ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL,
769
768
  }), { retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes });
770
769
  }
771
770
 
771
+ function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, signal, onProgress }) {
772
+ return poll({
773
+ check: (signal) => info(file, {
774
+ publicKey,
775
+ baseURL,
776
+ signal,
777
+ source,
778
+ integration,
779
+ userAgent,
780
+ retryThrottledRequestMaxTimes,
781
+ retryNetworkErrorMaxTimes
782
+ }).then((response) => {
783
+ if (response.isReady) {
784
+ return response;
785
+ }
786
+ onProgress && onProgress({ isComputable: true, value: 1 });
787
+ return false;
788
+ }),
789
+ signal
790
+ });
791
+ }
792
+
772
793
  class UploadcareFile {
773
794
  constructor(fileInfo, { baseCDN, fileName }) {
774
795
  this.name = null;
@@ -806,28 +827,6 @@ class UploadcareFile {
806
827
  }
807
828
  }
808
829
 
809
- function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, signal, onProgress }) {
810
- return poll({
811
- check: (signal) => info(file, {
812
- publicKey,
813
- baseURL,
814
- signal,
815
- source,
816
- integration,
817
- userAgent,
818
- retryThrottledRequestMaxTimes,
819
- retryNetworkErrorMaxTimes
820
- }).then((response) => {
821
- if (response.isReady) {
822
- return response;
823
- }
824
- onProgress && onProgress({ isComputable: true, value: 1 });
825
- return false;
826
- }),
827
- signal
828
- });
829
- }
830
-
831
830
  const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, contentType, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN, metadata }) => {
832
831
  return base(file, {
833
832
  publicKey,
@@ -863,6 +862,29 @@ const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, sec
863
862
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
864
863
  };
865
864
 
865
+ const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN }) => {
866
+ return info(uuid, {
867
+ publicKey,
868
+ baseURL,
869
+ signal,
870
+ source,
871
+ integration,
872
+ userAgent,
873
+ retryThrottledRequestMaxTimes,
874
+ retryNetworkErrorMaxTimes
875
+ })
876
+ .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
877
+ .then((result) => {
878
+ // hack for node ¯\_(ツ)_/¯
879
+ if (onProgress)
880
+ onProgress({
881
+ isComputable: true,
882
+ value: 1
883
+ });
884
+ return result;
885
+ });
886
+ };
887
+
866
888
  const race = (fns, { signal } = {}) => {
867
889
  let lastError = null;
868
890
  let winnerIndex = null;
@@ -1202,35 +1224,30 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
1202
1224
  }))
1203
1225
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1204
1226
 
1205
- const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN }) => {
1206
- return info(uuid, {
1207
- publicKey,
1208
- baseURL,
1209
- signal,
1210
- source,
1211
- integration,
1212
- userAgent,
1213
- retryThrottledRequestMaxTimes,
1214
- retryNetworkErrorMaxTimes
1215
- })
1216
- .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
1217
- .then((result) => {
1218
- // hack for node ¯\_(ツ)_/¯
1219
- if (onProgress)
1220
- onProgress({
1221
- isComputable: true,
1222
- value: 1
1223
- });
1224
- return result;
1225
- });
1227
+ const memo = new WeakMap();
1228
+ const getBlobFromReactNativeAsset = async (asset) => {
1229
+ if (memo.has(asset)) {
1230
+ return memo.get(asset);
1231
+ }
1232
+ const blob = await fetch(asset.uri).then((res) => res.blob());
1233
+ memo.set(asset, blob);
1234
+ return blob;
1226
1235
  };
1227
1236
 
1228
- /**
1229
- * Get file size.
1230
- */
1231
- const getFileSize = (file) => {
1232
- return file.length || file.size;
1237
+ const getFileSize = async (file) => {
1238
+ if (isBuffer(file)) {
1239
+ return file.length;
1240
+ }
1241
+ if (isFile(file) || isBlob(file)) {
1242
+ return file.size;
1243
+ }
1244
+ if (isReactNativeAsset(file)) {
1245
+ const blob = await getBlobFromReactNativeAsset(file);
1246
+ return blob.size;
1247
+ }
1248
+ throw new Error(`Unknown file type. Cannot determine file size.`);
1233
1249
  };
1250
+
1234
1251
  /**
1235
1252
  * Check if FileData is multipart data.
1236
1253
  */
@@ -1238,28 +1255,24 @@ const isMultipart = (fileSize, multipartMinFileSize = defaultSettings.multipartM
1238
1255
  return fileSize >= multipartMinFileSize;
1239
1256
  };
1240
1257
 
1241
- const sliceChunk = (file, index, fileSize, chunkSize) => {
1242
- const start = chunkSize * index;
1243
- const end = Math.min(start + chunkSize, fileSize);
1244
- return file.slice(start, end);
1258
+ /**
1259
+ * Uuid type guard.
1260
+ */
1261
+ const isUuid = (data) => {
1262
+ const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
1263
+ const regExp = new RegExp(UUID_REGEX);
1264
+ return !isFileData(data) && regExp.test(data);
1245
1265
  };
1246
-
1247
1266
  /**
1248
- * React-native hack for blob slicing
1249
- *
1250
- * We need to store references to sliced blobs to prevent source blob from
1251
- * being deallocated until uploading complete. Access to deallocated blob
1252
- * causes app crash.
1267
+ * Url type guard.
1253
1268
  *
1254
- * See https://github.com/uploadcare/uploadcare-js-api-clients/issues/306
1255
- * and https://github.com/facebook/react-native/issues/27543
1269
+ * @param {SupportedFileInput | Url | Uuid} data
1256
1270
  */
1257
- function prepareChunks(file, fileSize, chunkSize) {
1258
- return (index) => {
1259
- const chunk = sliceChunk(file, index, fileSize, chunkSize);
1260
- return chunk;
1261
- };
1262
- }
1271
+ const isUrl = (data) => {
1272
+ const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
1273
+ const regExp = new RegExp(URL_REGEX);
1274
+ return !isFileData(data) && regExp.test(data);
1275
+ };
1263
1276
 
1264
1277
  const runWithConcurrency = (concurrency, tasks) => {
1265
1278
  return new Promise((resolve, reject) => {
@@ -1296,6 +1309,36 @@ const runWithConcurrency = (concurrency, tasks) => {
1296
1309
  });
1297
1310
  };
1298
1311
 
1312
+ const sliceChunk = (file, index, fileSize, chunkSize) => {
1313
+ const start = chunkSize * index;
1314
+ const end = Math.min(start + chunkSize, fileSize);
1315
+ return file.slice(start, end);
1316
+ };
1317
+
1318
+ /**
1319
+ * React-native hack for blob slicing
1320
+ *
1321
+ * We need to store references to sliced blobs to prevent source blob from
1322
+ * being deallocated until uploading complete. Access to deallocated blob
1323
+ * causes app crash.
1324
+ *
1325
+ * See https://github.com/uploadcare/uploadcare-js-api-clients/issues/306
1326
+ * and https://github.com/facebook/react-native/issues/27543
1327
+ */
1328
+ const prepareChunks = async (file, fileSize, chunkSize) => {
1329
+ let blob;
1330
+ if (isReactNativeAsset(file)) {
1331
+ blob = await getBlobFromReactNativeAsset(file);
1332
+ }
1333
+ else {
1334
+ blob = file;
1335
+ }
1336
+ return (index) => {
1337
+ const chunk = sliceChunk(blob, index, fileSize, chunkSize);
1338
+ return chunk;
1339
+ };
1340
+ };
1341
+
1299
1342
  const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes }) => multipartUpload(chunk, url, {
1300
1343
  publicKey,
1301
1344
  onProgress,
@@ -1304,8 +1347,8 @@ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, re
1304
1347
  retryThrottledRequestMaxTimes,
1305
1348
  retryNetworkErrorMaxTimes
1306
1349
  });
1307
- 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 }) => {
1308
- const size = fileSize || getFileSize(file);
1350
+ const uploadMultipart = async (file, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, maxConcurrentRequests = defaultSettings.maxConcurrentRequests, baseCDN, metadata }) => {
1351
+ const size = fileSize ?? (await getFileSize(file));
1309
1352
  let progressValues;
1310
1353
  const createProgressHandler = (totalChunks, chunkIdx) => {
1311
1354
  if (!onProgress)
@@ -1327,8 +1370,8 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1327
1370
  };
1328
1371
  return multipartStart(size, {
1329
1372
  publicKey,
1330
- contentType,
1331
- fileName: fileName ?? file.name,
1373
+ contentType: contentType || getContentType(file),
1374
+ fileName: fileName || getFileName(file),
1332
1375
  baseURL,
1333
1376
  secureSignature,
1334
1377
  secureExpire,
@@ -1341,8 +1384,8 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1341
1384
  retryNetworkErrorMaxTimes,
1342
1385
  metadata
1343
1386
  })
1344
- .then(({ uuid, parts }) => {
1345
- const getChunk = prepareChunks(file, size, multipartChunkSize);
1387
+ .then(async ({ uuid, parts }) => {
1388
+ const getChunk = await prepareChunks(file, size, multipartChunkSize);
1346
1389
  return Promise.all([
1347
1390
  uuid,
1348
1391
  runWithConcurrency(maxConcurrentRequests, parts.map((url, index) => () => uploadPart(getChunk(index), url, {
@@ -1389,14 +1432,15 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1389
1432
  /**
1390
1433
  * Uploads file from provided data.
1391
1434
  */
1392
- 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 }) {
1435
+ async 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 }) {
1393
1436
  if (isFileData(data)) {
1394
- const fileSize = getFileSize(data);
1437
+ const fileSize = await getFileSize(data);
1395
1438
  if (isMultipart(fileSize, multipartMinFileSize)) {
1396
1439
  return uploadMultipart(data, {
1397
1440
  publicKey,
1398
1441
  contentType,
1399
1442
  multipartChunkSize,
1443
+ fileSize,
1400
1444
  fileName,
1401
1445
  baseURL,
1402
1446
  secureSignature,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uploadcare/upload-client",
3
- "version": "6.0.1-alpha.8",
3
+ "version": "6.1.0-alpha.0",
4
4
  "description": "Library for work with Uploadcare Upload API",
5
5
  "type": "module",
6
6
  "module": "./dist/index.node.js",
@@ -71,8 +71,8 @@
71
71
  "@types/ws": "8.5.3",
72
72
  "data-uri-to-buffer": "3.0.1",
73
73
  "dataurl-to-blob": "0.0.1",
74
- "jest-environment-jsdom": "28.1.0",
75
- "jest-websocket-mock": "2.3.0",
74
+ "jest-environment-jsdom": "29.3.1",
75
+ "jest-websocket-mock": "2.4.0",
76
76
  "koa": "2.13.4",
77
77
  "koa-add-trailing-slashes": "2.0.1",
78
78
  "koa-body": "5.0.0",