@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.
- package/README.md +42 -6
- package/dist/index.browser.js +187 -149
- package/dist/index.d.ts +90 -85
- package/dist/index.node.js +188 -146
- package/dist/index.react-native.js +212 -168
- package/package.json +3 -3
package/dist/index.node.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import http from 'http';
|
|
2
2
|
import https from 'https';
|
|
3
|
-
import { parse } from 'url';
|
|
4
3
|
import { Transform, Readable } from 'stream';
|
|
4
|
+
import { parse } from 'url';
|
|
5
5
|
import NodeFormData from 'form-data';
|
|
6
6
|
import WebSocket from 'ws';
|
|
7
7
|
|
|
@@ -164,6 +164,26 @@ const poll = ({ check, interval = DEFAULT_INTERVAL, timeout, signal }) => new Pr
|
|
|
164
164
|
tickTimeoutId = setTimeout(tick, 0);
|
|
165
165
|
});
|
|
166
166
|
|
|
167
|
+
/*
|
|
168
|
+
Settings for future support:
|
|
169
|
+
parallelDirectUploads: 10,
|
|
170
|
+
*/
|
|
171
|
+
const defaultSettings = {
|
|
172
|
+
baseCDN: 'https://ucarecdn.com',
|
|
173
|
+
baseURL: 'https://upload.uploadcare.com',
|
|
174
|
+
maxContentLength: 50 * 1024 * 1024,
|
|
175
|
+
retryThrottledRequestMaxTimes: 1,
|
|
176
|
+
retryNetworkErrorMaxTimes: 3,
|
|
177
|
+
multipartMinFileSize: 25 * 1024 * 1024,
|
|
178
|
+
multipartChunkSize: 5 * 1024 * 1024,
|
|
179
|
+
multipartMinLastPartSize: 1024 * 1024,
|
|
180
|
+
maxConcurrentRequests: 4,
|
|
181
|
+
pollingTimeoutMilliseconds: 10000,
|
|
182
|
+
pusherKey: '79ae88bd931ea68464d9'
|
|
183
|
+
};
|
|
184
|
+
const defaultContentType = 'application/octet-stream';
|
|
185
|
+
const defaultFilename = 'original';
|
|
186
|
+
|
|
167
187
|
// ProgressEmitter is a simple PassThrough-style transform stream which keeps
|
|
168
188
|
// track of the number of bytes which have been piped through it and will
|
|
169
189
|
// invoke the `onprogress` function whenever new number are available.
|
|
@@ -268,7 +288,8 @@ const request = (params) => {
|
|
|
268
288
|
}));
|
|
269
289
|
};
|
|
270
290
|
|
|
271
|
-
|
|
291
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
292
|
+
function identity(obj, ..._args) {
|
|
272
293
|
return obj;
|
|
273
294
|
}
|
|
274
295
|
|
|
@@ -285,49 +306,24 @@ const getFileOptions = ({ name, contentType }) => [
|
|
|
285
306
|
const transformFile = identity;
|
|
286
307
|
var getFormData = () => new NodeFormData();
|
|
287
308
|
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
return uri.startsWith('file:') || uri.startsWith('content:');
|
|
309
|
+
const isBlob = (data) => {
|
|
310
|
+
return typeof Blob !== 'undefined' && data instanceof Blob;
|
|
293
311
|
};
|
|
294
|
-
const
|
|
295
|
-
return
|
|
296
|
-
typeof asset === 'object' &&
|
|
297
|
-
!Array.isArray(asset) &&
|
|
298
|
-
'uri' in asset &&
|
|
299
|
-
typeof asset.uri === 'string' &&
|
|
300
|
-
isReactNativeUri(asset.uri));
|
|
312
|
+
const isFile = (data) => {
|
|
313
|
+
return typeof File !== 'undefined' && data instanceof File;
|
|
301
314
|
};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
* FileData type guard.
|
|
305
|
-
*/
|
|
306
|
-
const isFileData = (data) => {
|
|
307
|
-
return (data !== undefined &&
|
|
308
|
-
((typeof Blob !== 'undefined' && data instanceof Blob) ||
|
|
309
|
-
(typeof File !== 'undefined' && data instanceof File) ||
|
|
310
|
-
(typeof Buffer !== 'undefined' && data instanceof Buffer) ||
|
|
311
|
-
(typeof data === 'string' && isReactNativeUri(data)) ||
|
|
312
|
-
(typeof data === 'object' && isReactNativeAsset(data))));
|
|
315
|
+
const isBuffer = (data) => {
|
|
316
|
+
return typeof Buffer !== 'undefined' && data instanceof Buffer;
|
|
313
317
|
};
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
return !isFileData(data) && regExp.test(data);
|
|
318
|
+
const isReactNativeAsset = (data) => {
|
|
319
|
+
return (!!data &&
|
|
320
|
+
typeof data === 'object' &&
|
|
321
|
+
!Array.isArray(data) &&
|
|
322
|
+
'uri' in data &&
|
|
323
|
+
typeof data.uri === 'string');
|
|
321
324
|
};
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
*
|
|
325
|
-
* @param {NodeFile | BrowserFile | Url | Uuid} data
|
|
326
|
-
*/
|
|
327
|
-
const isUrl = (data) => {
|
|
328
|
-
const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
|
|
329
|
-
const regExp = new RegExp(URL_REGEX);
|
|
330
|
-
return !isFileData(data) && regExp.test(data);
|
|
325
|
+
const isFileData = (data) => {
|
|
326
|
+
return (isBlob(data) || isFile(data) || isBuffer(data) || isReactNativeAsset(data));
|
|
331
327
|
};
|
|
332
328
|
|
|
333
329
|
const isSimpleValue = (value) => {
|
|
@@ -345,7 +341,7 @@ const isFileValue = (value) => !!value &&
|
|
|
345
341
|
function collectParams(params, inputKey, inputValue) {
|
|
346
342
|
if (isFileValue(inputValue)) {
|
|
347
343
|
const { name, contentType } = inputValue;
|
|
348
|
-
const file = transformFile(inputValue.data);
|
|
344
|
+
const file = transformFile(inputValue.data, name, contentType);
|
|
349
345
|
const options = getFileOptions({ name, contentType });
|
|
350
346
|
params.push([inputKey, file, ...options]);
|
|
351
347
|
}
|
|
@@ -368,11 +364,9 @@ function getFormDataParams(options) {
|
|
|
368
364
|
return params;
|
|
369
365
|
}
|
|
370
366
|
function buildFormData(options) {
|
|
371
|
-
console.log('buildFormData', options);
|
|
372
367
|
const formData = getFormData();
|
|
373
368
|
const paramsList = getFormDataParams(options);
|
|
374
369
|
for (const params of paramsList) {
|
|
375
|
-
console.log('params', params);
|
|
376
370
|
const [key, value, ...rest] = params;
|
|
377
371
|
// node form-data has another signature for append
|
|
378
372
|
formData.append(key, value, ...rest);
|
|
@@ -380,6 +374,19 @@ function buildFormData(options) {
|
|
|
380
374
|
return formData;
|
|
381
375
|
}
|
|
382
376
|
|
|
377
|
+
class UploadClientError extends Error {
|
|
378
|
+
constructor(message, code, request, response, headers) {
|
|
379
|
+
super();
|
|
380
|
+
this.name = 'UploadClientError';
|
|
381
|
+
this.message = message;
|
|
382
|
+
this.code = code;
|
|
383
|
+
this.request = request;
|
|
384
|
+
this.response = response;
|
|
385
|
+
this.headers = headers;
|
|
386
|
+
Object.setPrototypeOf(this, UploadClientError.prototype);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
383
390
|
const buildSearchParams = (query) => {
|
|
384
391
|
const searchParams = new URLSearchParams();
|
|
385
392
|
for (const [key, value] of Object.entries(query)) {
|
|
@@ -411,26 +418,6 @@ const getUrl = (base, path, query) => {
|
|
|
411
418
|
return url.toString();
|
|
412
419
|
};
|
|
413
420
|
|
|
414
|
-
/*
|
|
415
|
-
Settings for future support:
|
|
416
|
-
parallelDirectUploads: 10,
|
|
417
|
-
*/
|
|
418
|
-
const defaultSettings = {
|
|
419
|
-
baseCDN: 'https://ucarecdn.com',
|
|
420
|
-
baseURL: 'https://upload.uploadcare.com',
|
|
421
|
-
maxContentLength: 50 * 1024 * 1024,
|
|
422
|
-
retryThrottledRequestMaxTimes: 1,
|
|
423
|
-
retryNetworkErrorMaxTimes: 3,
|
|
424
|
-
multipartMinFileSize: 25 * 1024 * 1024,
|
|
425
|
-
multipartChunkSize: 5 * 1024 * 1024,
|
|
426
|
-
multipartMinLastPartSize: 1024 * 1024,
|
|
427
|
-
maxConcurrentRequests: 4,
|
|
428
|
-
pollingTimeoutMilliseconds: 10000,
|
|
429
|
-
pusherKey: '79ae88bd931ea68464d9'
|
|
430
|
-
};
|
|
431
|
-
const defaultContentType = 'application/octet-stream';
|
|
432
|
-
const defaultFilename = 'original';
|
|
433
|
-
|
|
434
421
|
var version = '6.0.0';
|
|
435
422
|
|
|
436
423
|
const LIBRARY_NAME = 'UploadcareUploadClient';
|
|
@@ -443,19 +430,6 @@ function getUserAgent(options) {
|
|
|
443
430
|
});
|
|
444
431
|
}
|
|
445
432
|
|
|
446
|
-
class UploadClientError extends Error {
|
|
447
|
-
constructor(message, code, request, response, headers) {
|
|
448
|
-
super();
|
|
449
|
-
this.name = 'UploadClientError';
|
|
450
|
-
this.message = message;
|
|
451
|
-
this.code = code;
|
|
452
|
-
this.request = request;
|
|
453
|
-
this.response = response;
|
|
454
|
-
this.headers = headers;
|
|
455
|
-
Object.setPrototypeOf(this, UploadClientError.prototype);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
433
|
const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
|
|
460
434
|
const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
|
|
461
435
|
const DEFAULT_NETWORK_ERROR_TIMEOUT = 1000;
|
|
@@ -486,6 +460,36 @@ function retryIfFailed(fn, options) {
|
|
|
486
460
|
}));
|
|
487
461
|
}
|
|
488
462
|
|
|
463
|
+
const getContentType = (file) => {
|
|
464
|
+
let contentType = '';
|
|
465
|
+
if (isBlob(file) || isFile(file) || isReactNativeAsset(file)) {
|
|
466
|
+
contentType = file.type;
|
|
467
|
+
}
|
|
468
|
+
if (contentType) {
|
|
469
|
+
return contentType;
|
|
470
|
+
}
|
|
471
|
+
console.warn(`Cannot determine content type. Using default content type: ${defaultContentType}`, file);
|
|
472
|
+
return defaultContentType;
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
const getFileName = (file) => {
|
|
476
|
+
let filename = '';
|
|
477
|
+
if (isFile(file) && file.name) {
|
|
478
|
+
filename = file.name;
|
|
479
|
+
}
|
|
480
|
+
else if (isBlob(file) || isBuffer(file)) {
|
|
481
|
+
filename = '';
|
|
482
|
+
}
|
|
483
|
+
else if (isReactNativeAsset(file) && file.name) {
|
|
484
|
+
filename = file.name;
|
|
485
|
+
}
|
|
486
|
+
if (filename) {
|
|
487
|
+
return filename;
|
|
488
|
+
}
|
|
489
|
+
console.warn(`Cannot determine filename. Using default filename: ${defaultFilename}`, file);
|
|
490
|
+
return defaultFilename;
|
|
491
|
+
};
|
|
492
|
+
|
|
489
493
|
function getStoreValue(store) {
|
|
490
494
|
return typeof store === 'undefined' ? 'auto' : store ? '1' : '0';
|
|
491
495
|
}
|
|
@@ -501,13 +505,13 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
|
|
|
501
505
|
jsonerrors: 1
|
|
502
506
|
}),
|
|
503
507
|
headers: {
|
|
504
|
-
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
508
|
+
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
505
509
|
},
|
|
506
510
|
data: buildFormData({
|
|
507
511
|
file: {
|
|
508
512
|
data: file,
|
|
509
|
-
name: fileName
|
|
510
|
-
contentType: contentType
|
|
513
|
+
name: fileName || getFileName(file),
|
|
514
|
+
contentType: contentType || getContentType(file)
|
|
511
515
|
},
|
|
512
516
|
UPLOADCARE_PUB_KEY: publicKey,
|
|
513
517
|
UPLOADCARE_STORE: getStoreValue(store),
|
|
@@ -705,9 +709,9 @@ function multipartStart(size, { publicKey, contentType, fileName, multipartChunk
|
|
|
705
709
|
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
706
710
|
},
|
|
707
711
|
data: buildFormData({
|
|
708
|
-
filename: fileName
|
|
712
|
+
filename: fileName || defaultFilename,
|
|
709
713
|
size: size,
|
|
710
|
-
content_type: contentType
|
|
714
|
+
content_type: contentType || defaultContentType,
|
|
711
715
|
part_size: multipartChunkSize,
|
|
712
716
|
UPLOADCARE_STORE: getStoreValue(store),
|
|
713
717
|
UPLOADCARE_PUB_KEY: publicKey,
|
|
@@ -784,6 +788,28 @@ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL,
|
|
|
784
788
|
}), { retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes });
|
|
785
789
|
}
|
|
786
790
|
|
|
791
|
+
function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, signal, onProgress }) {
|
|
792
|
+
return poll({
|
|
793
|
+
check: (signal) => info(file, {
|
|
794
|
+
publicKey,
|
|
795
|
+
baseURL,
|
|
796
|
+
signal,
|
|
797
|
+
source,
|
|
798
|
+
integration,
|
|
799
|
+
userAgent,
|
|
800
|
+
retryThrottledRequestMaxTimes,
|
|
801
|
+
retryNetworkErrorMaxTimes
|
|
802
|
+
}).then((response) => {
|
|
803
|
+
if (response.isReady) {
|
|
804
|
+
return response;
|
|
805
|
+
}
|
|
806
|
+
onProgress && onProgress({ isComputable: true, value: 1 });
|
|
807
|
+
return false;
|
|
808
|
+
}),
|
|
809
|
+
signal
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
|
|
787
813
|
class UploadcareFile {
|
|
788
814
|
constructor(fileInfo, { baseCDN, fileName }) {
|
|
789
815
|
this.name = null;
|
|
@@ -821,28 +847,6 @@ class UploadcareFile {
|
|
|
821
847
|
}
|
|
822
848
|
}
|
|
823
849
|
|
|
824
|
-
function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, signal, onProgress }) {
|
|
825
|
-
return poll({
|
|
826
|
-
check: (signal) => info(file, {
|
|
827
|
-
publicKey,
|
|
828
|
-
baseURL,
|
|
829
|
-
signal,
|
|
830
|
-
source,
|
|
831
|
-
integration,
|
|
832
|
-
userAgent,
|
|
833
|
-
retryThrottledRequestMaxTimes,
|
|
834
|
-
retryNetworkErrorMaxTimes
|
|
835
|
-
}).then((response) => {
|
|
836
|
-
if (response.isReady) {
|
|
837
|
-
return response;
|
|
838
|
-
}
|
|
839
|
-
onProgress && onProgress({ isComputable: true, value: 1 });
|
|
840
|
-
return false;
|
|
841
|
-
}),
|
|
842
|
-
signal
|
|
843
|
-
});
|
|
844
|
-
}
|
|
845
|
-
|
|
846
850
|
const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, contentType, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN, metadata }) => {
|
|
847
851
|
return base(file, {
|
|
848
852
|
publicKey,
|
|
@@ -878,6 +882,29 @@ const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, sec
|
|
|
878
882
|
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
|
|
879
883
|
};
|
|
880
884
|
|
|
885
|
+
const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN }) => {
|
|
886
|
+
return info(uuid, {
|
|
887
|
+
publicKey,
|
|
888
|
+
baseURL,
|
|
889
|
+
signal,
|
|
890
|
+
source,
|
|
891
|
+
integration,
|
|
892
|
+
userAgent,
|
|
893
|
+
retryThrottledRequestMaxTimes,
|
|
894
|
+
retryNetworkErrorMaxTimes
|
|
895
|
+
})
|
|
896
|
+
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
|
|
897
|
+
.then((result) => {
|
|
898
|
+
// hack for node ¯\_(ツ)_/¯
|
|
899
|
+
if (onProgress)
|
|
900
|
+
onProgress({
|
|
901
|
+
isComputable: true,
|
|
902
|
+
value: 1
|
|
903
|
+
});
|
|
904
|
+
return result;
|
|
905
|
+
});
|
|
906
|
+
};
|
|
907
|
+
|
|
881
908
|
const race = (fns, { signal } = {}) => {
|
|
882
909
|
let lastError = null;
|
|
883
910
|
let winnerIndex = null;
|
|
@@ -1215,35 +1242,30 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
|
|
|
1215
1242
|
}))
|
|
1216
1243
|
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
|
|
1217
1244
|
|
|
1218
|
-
const
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
retryThrottledRequestMaxTimes,
|
|
1227
|
-
retryNetworkErrorMaxTimes
|
|
1228
|
-
})
|
|
1229
|
-
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
|
|
1230
|
-
.then((result) => {
|
|
1231
|
-
// hack for node ¯\_(ツ)_/¯
|
|
1232
|
-
if (onProgress)
|
|
1233
|
-
onProgress({
|
|
1234
|
-
isComputable: true,
|
|
1235
|
-
value: 1
|
|
1236
|
-
});
|
|
1237
|
-
return result;
|
|
1238
|
-
});
|
|
1245
|
+
const memo = new WeakMap();
|
|
1246
|
+
const getBlobFromReactNativeAsset = async (asset) => {
|
|
1247
|
+
if (memo.has(asset)) {
|
|
1248
|
+
return memo.get(asset);
|
|
1249
|
+
}
|
|
1250
|
+
const blob = await fetch(asset.uri).then((res) => res.blob());
|
|
1251
|
+
memo.set(asset, blob);
|
|
1252
|
+
return blob;
|
|
1239
1253
|
};
|
|
1240
1254
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1255
|
+
const getFileSize = async (file) => {
|
|
1256
|
+
if (isBuffer(file)) {
|
|
1257
|
+
return file.length;
|
|
1258
|
+
}
|
|
1259
|
+
if (isFile(file) || isBlob(file)) {
|
|
1260
|
+
return file.size;
|
|
1261
|
+
}
|
|
1262
|
+
if (isReactNativeAsset(file)) {
|
|
1263
|
+
const blob = await getBlobFromReactNativeAsset(file);
|
|
1264
|
+
return blob.size;
|
|
1265
|
+
}
|
|
1266
|
+
throw new Error(`Unknown file type. Cannot determine file size.`);
|
|
1246
1267
|
};
|
|
1268
|
+
|
|
1247
1269
|
/**
|
|
1248
1270
|
* Check if FileData is multipart data.
|
|
1249
1271
|
*/
|
|
@@ -1251,15 +1273,24 @@ const isMultipart = (fileSize, multipartMinFileSize = defaultSettings.multipartM
|
|
|
1251
1273
|
return fileSize >= multipartMinFileSize;
|
|
1252
1274
|
};
|
|
1253
1275
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1276
|
+
/**
|
|
1277
|
+
* Uuid type guard.
|
|
1278
|
+
*/
|
|
1279
|
+
const isUuid = (data) => {
|
|
1280
|
+
const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
|
|
1281
|
+
const regExp = new RegExp(UUID_REGEX);
|
|
1282
|
+
return !isFileData(data) && regExp.test(data);
|
|
1283
|
+
};
|
|
1284
|
+
/**
|
|
1285
|
+
* Url type guard.
|
|
1286
|
+
*
|
|
1287
|
+
* @param {SupportedFileInput | Url | Uuid} data
|
|
1288
|
+
*/
|
|
1289
|
+
const isUrl = (data) => {
|
|
1290
|
+
const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
|
|
1291
|
+
const regExp = new RegExp(URL_REGEX);
|
|
1292
|
+
return !isFileData(data) && regExp.test(data);
|
|
1258
1293
|
};
|
|
1259
|
-
|
|
1260
|
-
function prepareChunks(file, fileSize, chunkSize) {
|
|
1261
|
-
return (index) => sliceChunk(file, index, fileSize, chunkSize);
|
|
1262
|
-
}
|
|
1263
1294
|
|
|
1264
1295
|
const runWithConcurrency = (concurrency, tasks) => {
|
|
1265
1296
|
return new Promise((resolve, reject) => {
|
|
@@ -1296,6 +1327,16 @@ const runWithConcurrency = (concurrency, tasks) => {
|
|
|
1296
1327
|
});
|
|
1297
1328
|
};
|
|
1298
1329
|
|
|
1330
|
+
const sliceChunk = (file, index, fileSize, chunkSize) => {
|
|
1331
|
+
const start = chunkSize * index;
|
|
1332
|
+
const end = Math.min(start + chunkSize, fileSize);
|
|
1333
|
+
return file.slice(start, end);
|
|
1334
|
+
};
|
|
1335
|
+
|
|
1336
|
+
const prepareChunks = async (file, fileSize, chunkSize) => {
|
|
1337
|
+
return (index) => sliceChunk(file, index, fileSize, chunkSize);
|
|
1338
|
+
};
|
|
1339
|
+
|
|
1299
1340
|
const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes }) => multipartUpload(chunk, url, {
|
|
1300
1341
|
publicKey,
|
|
1301
1342
|
onProgress,
|
|
@@ -1304,8 +1345,8 @@ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, re
|
|
|
1304
1345
|
retryThrottledRequestMaxTimes,
|
|
1305
1346
|
retryNetworkErrorMaxTimes
|
|
1306
1347
|
});
|
|
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
|
|
1348
|
+
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 }) => {
|
|
1349
|
+
const size = fileSize ?? (await getFileSize(file));
|
|
1309
1350
|
let progressValues;
|
|
1310
1351
|
const createProgressHandler = (totalChunks, chunkIdx) => {
|
|
1311
1352
|
if (!onProgress)
|
|
@@ -1327,8 +1368,8 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
|
|
|
1327
1368
|
};
|
|
1328
1369
|
return multipartStart(size, {
|
|
1329
1370
|
publicKey,
|
|
1330
|
-
contentType,
|
|
1331
|
-
fileName: fileName
|
|
1371
|
+
contentType: contentType || getContentType(file),
|
|
1372
|
+
fileName: fileName || getFileName(file),
|
|
1332
1373
|
baseURL,
|
|
1333
1374
|
secureSignature,
|
|
1334
1375
|
secureExpire,
|
|
@@ -1341,8 +1382,8 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
|
|
|
1341
1382
|
retryNetworkErrorMaxTimes,
|
|
1342
1383
|
metadata
|
|
1343
1384
|
})
|
|
1344
|
-
.then(({ uuid, parts }) => {
|
|
1345
|
-
const getChunk = prepareChunks(file, size, multipartChunkSize);
|
|
1385
|
+
.then(async ({ uuid, parts }) => {
|
|
1386
|
+
const getChunk = await prepareChunks(file, size, multipartChunkSize);
|
|
1346
1387
|
return Promise.all([
|
|
1347
1388
|
uuid,
|
|
1348
1389
|
runWithConcurrency(maxConcurrentRequests, parts.map((url, index) => () => uploadPart(getChunk(index), url, {
|
|
@@ -1389,14 +1430,15 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
|
|
|
1389
1430
|
/**
|
|
1390
1431
|
* Uploads file from provided data.
|
|
1391
1432
|
*/
|
|
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 }) {
|
|
1433
|
+
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
1434
|
if (isFileData(data)) {
|
|
1394
|
-
const fileSize = getFileSize(data);
|
|
1435
|
+
const fileSize = await getFileSize(data);
|
|
1395
1436
|
if (isMultipart(fileSize, multipartMinFileSize)) {
|
|
1396
1437
|
return uploadMultipart(data, {
|
|
1397
1438
|
publicKey,
|
|
1398
1439
|
contentType,
|
|
1399
1440
|
multipartChunkSize,
|
|
1441
|
+
fileSize,
|
|
1400
1442
|
fileName,
|
|
1401
1443
|
baseURL,
|
|
1402
1444
|
secureSignature,
|