@uploadcare/upload-client 4.0.1 → 4.2.1
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 +13 -11
- package/dist/index.browser.js +140 -119
- package/dist/index.node.js +140 -119
- package/dist/index.react-native.js +141 -120
- package/dist/types.d.ts +45 -46
- package/package.json +27 -45
package/dist/index.node.js
CHANGED
|
@@ -150,7 +150,7 @@ const getFileOptions = ({ name, contentType }) => [
|
|
|
150
150
|
contentType
|
|
151
151
|
})
|
|
152
152
|
.filter(([, value]) => !!value)
|
|
153
|
-
.reduce((acc, [key, value]) => (
|
|
153
|
+
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
|
|
154
154
|
].filter((value) => !!value);
|
|
155
155
|
const transformFile = identity;
|
|
156
156
|
var getFormData = () => new NodeFormData();
|
|
@@ -231,34 +231,36 @@ function buildFormData(options) {
|
|
|
231
231
|
return formData;
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
234
|
+
const buildSearchParams = (query) => {
|
|
235
|
+
const searchParams = new URLSearchParams();
|
|
236
|
+
for (const [key, value] of Object.entries(query)) {
|
|
237
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
238
|
+
Object.entries(value)
|
|
239
|
+
.filter((entry) => entry[1] ?? false)
|
|
240
|
+
.forEach((entry) => searchParams.set(`${key}[${entry[0]}]`, String(entry[1])));
|
|
241
|
+
}
|
|
242
|
+
else if (Array.isArray(value)) {
|
|
243
|
+
value.forEach((val) => {
|
|
244
|
+
searchParams.append(`${key}[]`, val);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
else if (typeof value === 'string' && value) {
|
|
248
|
+
searchParams.set(key, value);
|
|
249
|
+
}
|
|
250
|
+
else if (typeof value === 'number') {
|
|
251
|
+
searchParams.set(key, value.toString());
|
|
252
|
+
}
|
|
246
253
|
}
|
|
247
|
-
|
|
248
|
-
|
|
254
|
+
return searchParams.toString();
|
|
255
|
+
};
|
|
256
|
+
const getUrl = (base, path, query) => {
|
|
257
|
+
const url = new URL(base);
|
|
258
|
+
url.pathname = path;
|
|
259
|
+
if (query) {
|
|
260
|
+
url.search = buildSearchParams(query);
|
|
249
261
|
}
|
|
250
|
-
return
|
|
251
|
-
}
|
|
252
|
-
.filter((x) => !!x)
|
|
253
|
-
.join('&');
|
|
254
|
-
const getUrl = (base, path, query) => [
|
|
255
|
-
base,
|
|
256
|
-
path,
|
|
257
|
-
query && Object.keys(query).length > 0 ? '?' : '',
|
|
258
|
-
query && createQuery(query)
|
|
259
|
-
]
|
|
260
|
-
.filter(Boolean)
|
|
261
|
-
.join('');
|
|
262
|
+
return url.toString();
|
|
263
|
+
};
|
|
262
264
|
|
|
263
265
|
/*
|
|
264
266
|
Settings for future support:
|
|
@@ -280,14 +282,59 @@ const defaultSettings = {
|
|
|
280
282
|
const defaultContentType = 'application/octet-stream';
|
|
281
283
|
const defaultFilename = 'original';
|
|
282
284
|
|
|
283
|
-
var version = '4.
|
|
285
|
+
var version = '4.2.1';
|
|
286
|
+
|
|
287
|
+
function isObject(o) {
|
|
288
|
+
return Object.prototype.toString.call(o) === '[object Object]';
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const SEPARATOR = /\W|_/g;
|
|
292
|
+
function camelizeString(text) {
|
|
293
|
+
return text
|
|
294
|
+
.split(SEPARATOR)
|
|
295
|
+
.map((word, index) => word.charAt(0)[index > 0 ? 'toUpperCase' : 'toLowerCase']() +
|
|
296
|
+
word.slice(1))
|
|
297
|
+
.join('');
|
|
298
|
+
}
|
|
299
|
+
function camelizeArrayItems(array, { ignoreKeys } = { ignoreKeys: [] }) {
|
|
300
|
+
if (!Array.isArray(array)) {
|
|
301
|
+
return array;
|
|
302
|
+
}
|
|
303
|
+
return array.map((item) => camelizeKeys(item, { ignoreKeys }));
|
|
304
|
+
}
|
|
305
|
+
function camelizeKeys(source, { ignoreKeys } = { ignoreKeys: [] }) {
|
|
306
|
+
if (Array.isArray(source)) {
|
|
307
|
+
return camelizeArrayItems(source, { ignoreKeys });
|
|
308
|
+
}
|
|
309
|
+
if (!isObject(source)) {
|
|
310
|
+
return source;
|
|
311
|
+
}
|
|
312
|
+
const result = {};
|
|
313
|
+
for (const key of Object.keys(source)) {
|
|
314
|
+
let value = source[key];
|
|
315
|
+
if (ignoreKeys.includes(key)) {
|
|
316
|
+
result[key] = value;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (isObject(value)) {
|
|
320
|
+
value = camelizeKeys(value, { ignoreKeys });
|
|
321
|
+
}
|
|
322
|
+
else if (Array.isArray(value)) {
|
|
323
|
+
value = camelizeArrayItems(value, { ignoreKeys });
|
|
324
|
+
}
|
|
325
|
+
result[camelizeString(key)] = value;
|
|
326
|
+
}
|
|
327
|
+
return result;
|
|
328
|
+
}
|
|
284
329
|
|
|
285
330
|
/**
|
|
286
|
-
*
|
|
331
|
+
* setTimeout as Promise.
|
|
332
|
+
*
|
|
333
|
+
* @param {number} ms Timeout in milliseconds.
|
|
287
334
|
*/
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
335
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
336
|
+
|
|
337
|
+
function getUserAgent$1({ libraryName, libraryVersion, userAgent, publicKey = '', integration = '' }) {
|
|
291
338
|
const languageName = 'JavaScript';
|
|
292
339
|
if (typeof userAgent === 'string') {
|
|
293
340
|
return userAgent;
|
|
@@ -308,39 +355,6 @@ function getUserAgent({ userAgent, publicKey = '', integration = '' } = {}) {
|
|
|
308
355
|
return `${mainInfo} (${additionInfo})`;
|
|
309
356
|
}
|
|
310
357
|
|
|
311
|
-
const SEPARATOR = /\W|_/g;
|
|
312
|
-
/**
|
|
313
|
-
* Transforms a string to camelCased.
|
|
314
|
-
*/
|
|
315
|
-
function camelize(text) {
|
|
316
|
-
return text
|
|
317
|
-
.split(SEPARATOR)
|
|
318
|
-
.map((word, index) => word.charAt(0)[index > 0 ? 'toUpperCase' : 'toLowerCase']() +
|
|
319
|
-
word.slice(1))
|
|
320
|
-
.join('');
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Transforms keys of an object to camelCased recursively.
|
|
324
|
-
*/
|
|
325
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
326
|
-
function camelizeKeys(source) {
|
|
327
|
-
if (!source || typeof source !== 'object') {
|
|
328
|
-
return source;
|
|
329
|
-
}
|
|
330
|
-
return Object.keys(source).reduce((accumulator, key) => {
|
|
331
|
-
accumulator[camelize(key)] =
|
|
332
|
-
typeof source[key] === 'object' ? camelizeKeys(source[key]) : source[key];
|
|
333
|
-
return accumulator;
|
|
334
|
-
}, {});
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* setTimeout as Promise.
|
|
339
|
-
*
|
|
340
|
-
* @param {number} ms Timeout in milliseconds.
|
|
341
|
-
*/
|
|
342
|
-
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
343
|
-
|
|
344
358
|
const defaultOptions = {
|
|
345
359
|
factor: 2,
|
|
346
360
|
time: 100
|
|
@@ -348,8 +362,8 @@ const defaultOptions = {
|
|
|
348
362
|
function retrier(fn, options = defaultOptions) {
|
|
349
363
|
let attempts = 0;
|
|
350
364
|
function runAttempt(fn) {
|
|
351
|
-
const defaultDelayTime = Math.round(options.time *
|
|
352
|
-
const retry = (ms) => delay(ms
|
|
365
|
+
const defaultDelayTime = Math.round(options.time * options.factor ** attempts);
|
|
366
|
+
const retry = (ms) => delay(ms ?? defaultDelayTime).then(() => {
|
|
353
367
|
attempts += 1;
|
|
354
368
|
return runAttempt(fn);
|
|
355
369
|
});
|
|
@@ -361,6 +375,16 @@ function retrier(fn, options = defaultOptions) {
|
|
|
361
375
|
return runAttempt(fn);
|
|
362
376
|
}
|
|
363
377
|
|
|
378
|
+
const LIBRARY_NAME = 'UploadcareUploadClient';
|
|
379
|
+
const LIBRARY_VERSION = version;
|
|
380
|
+
function getUserAgent(options) {
|
|
381
|
+
return getUserAgent$1({
|
|
382
|
+
libraryName: LIBRARY_NAME,
|
|
383
|
+
libraryVersion: LIBRARY_VERSION,
|
|
384
|
+
...options
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
364
388
|
const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
|
|
365
389
|
const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
|
|
366
390
|
function getTimeoutFromThrottledRequest(error) {
|
|
@@ -372,7 +396,7 @@ function getTimeoutFromThrottledRequest(error) {
|
|
|
372
396
|
function retryIfThrottled(fn, retryThrottledMaxTimes) {
|
|
373
397
|
return retrier(({ attempt, retry }) => fn().catch((error) => {
|
|
374
398
|
if ('response' in error &&
|
|
375
|
-
|
|
399
|
+
error?.code === REQUEST_WAS_THROTTLED_CODE &&
|
|
376
400
|
attempt < retryThrottledMaxTimes) {
|
|
377
401
|
return retry(getTimeoutFromThrottledRequest(error));
|
|
378
402
|
}
|
|
@@ -389,41 +413,38 @@ function getStoreValue(store) {
|
|
|
389
413
|
* Can be canceled and has progress.
|
|
390
414
|
*/
|
|
391
415
|
function base(file, { publicKey, fileName, contentType, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
392
|
-
return retryIfThrottled(() => {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
})
|
|
399
|
-
|
|
400
|
-
|
|
416
|
+
return retryIfThrottled(() => request({
|
|
417
|
+
method: 'POST',
|
|
418
|
+
url: getUrl(baseURL, '/base/', {
|
|
419
|
+
jsonerrors: 1
|
|
420
|
+
}),
|
|
421
|
+
headers: {
|
|
422
|
+
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
423
|
+
},
|
|
424
|
+
data: buildFormData({
|
|
425
|
+
file: {
|
|
426
|
+
data: file,
|
|
427
|
+
name: fileName ?? file.name ?? defaultFilename,
|
|
428
|
+
contentType
|
|
401
429
|
},
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
421
|
-
}
|
|
422
|
-
else {
|
|
423
|
-
return response;
|
|
424
|
-
}
|
|
425
|
-
});
|
|
426
|
-
}, retryThrottledRequestMaxTimes);
|
|
430
|
+
UPLOADCARE_PUB_KEY: publicKey,
|
|
431
|
+
UPLOADCARE_STORE: getStoreValue(store),
|
|
432
|
+
signature: secureSignature,
|
|
433
|
+
expire: secureExpire,
|
|
434
|
+
source: source,
|
|
435
|
+
metadata
|
|
436
|
+
}),
|
|
437
|
+
signal,
|
|
438
|
+
onProgress
|
|
439
|
+
}).then(({ data, headers, request }) => {
|
|
440
|
+
const response = camelizeKeys(JSON.parse(data));
|
|
441
|
+
if ('error' in response) {
|
|
442
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
return response;
|
|
446
|
+
}
|
|
447
|
+
}), retryThrottledRequestMaxTimes);
|
|
427
448
|
}
|
|
428
449
|
|
|
429
450
|
var TypeEnum;
|
|
@@ -602,9 +623,9 @@ function multipartStart(size, { publicKey, contentType, fileName, multipartChunk
|
|
|
602
623
|
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
603
624
|
},
|
|
604
625
|
data: buildFormData({
|
|
605
|
-
filename: fileName
|
|
626
|
+
filename: fileName ?? defaultFilename,
|
|
606
627
|
size: size,
|
|
607
|
-
content_type: contentType
|
|
628
|
+
content_type: contentType ?? defaultContentType,
|
|
608
629
|
part_size: multipartChunkSize,
|
|
609
630
|
UPLOADCARE_STORE: getStoreValue(store),
|
|
610
631
|
UPLOADCARE_PUB_KEY: publicKey,
|
|
@@ -706,9 +727,9 @@ class UploadcareFile {
|
|
|
706
727
|
this.mimeType = fileInfo.mimeType;
|
|
707
728
|
this.cdnUrl = cdnUrl;
|
|
708
729
|
this.originalFilename = fileInfo.originalFilename;
|
|
709
|
-
this.imageInfo =
|
|
710
|
-
this.videoInfo =
|
|
711
|
-
this.contentInfo =
|
|
730
|
+
this.imageInfo = fileInfo.imageInfo;
|
|
731
|
+
this.videoInfo = fileInfo.videoInfo;
|
|
732
|
+
this.contentInfo = fileInfo.contentInfo;
|
|
712
733
|
this.metadata = fileInfo.metadata || null;
|
|
713
734
|
this.s3Bucket = s3Bucket || null;
|
|
714
735
|
this.s3Url = s3Url;
|
|
@@ -834,8 +855,7 @@ class Events {
|
|
|
834
855
|
this.events = Object.create({});
|
|
835
856
|
}
|
|
836
857
|
emit(event, data) {
|
|
837
|
-
|
|
838
|
-
(_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.forEach((fn) => fn(data));
|
|
858
|
+
this.events[event]?.forEach((fn) => fn(data));
|
|
839
859
|
}
|
|
840
860
|
on(event, callback) {
|
|
841
861
|
this.events[event] = this.events[event] || [];
|
|
@@ -853,12 +873,12 @@ class Events {
|
|
|
853
873
|
|
|
854
874
|
const response = (type, data) => {
|
|
855
875
|
if (type === 'success') {
|
|
856
|
-
return
|
|
876
|
+
return { status: Status.Success, ...data };
|
|
857
877
|
}
|
|
858
878
|
if (type === 'progress') {
|
|
859
|
-
return
|
|
879
|
+
return { status: Status.Progress, ...data };
|
|
860
880
|
}
|
|
861
|
-
return
|
|
881
|
+
return { status: Status.Error, ...data };
|
|
862
882
|
};
|
|
863
883
|
class Pusher {
|
|
864
884
|
constructor(pusherKey, disconnectTime = 30000) {
|
|
@@ -906,8 +926,7 @@ class Pusher {
|
|
|
906
926
|
}
|
|
907
927
|
disconnect() {
|
|
908
928
|
const actualDisconect = () => {
|
|
909
|
-
|
|
910
|
-
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.close();
|
|
929
|
+
this.ws?.close();
|
|
911
930
|
this.ws = undefined;
|
|
912
931
|
this.isConnected = false;
|
|
913
932
|
};
|
|
@@ -921,9 +940,8 @@ class Pusher {
|
|
|
921
940
|
}
|
|
922
941
|
}
|
|
923
942
|
send(event, data) {
|
|
924
|
-
var _a;
|
|
925
943
|
const str = JSON.stringify({ event, data });
|
|
926
|
-
|
|
944
|
+
this.ws?.send(str);
|
|
927
945
|
}
|
|
928
946
|
subscribe(token, handler) {
|
|
929
947
|
this.subscribers += 1;
|
|
@@ -1090,7 +1108,7 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
|
|
|
1090
1108
|
}))
|
|
1091
1109
|
.catch((error) => {
|
|
1092
1110
|
const pusher = getPusher(pusherKey);
|
|
1093
|
-
pusher
|
|
1111
|
+
pusher?.disconnect();
|
|
1094
1112
|
return Promise.reject(error);
|
|
1095
1113
|
})
|
|
1096
1114
|
.then((urlResponse) => {
|
|
@@ -1250,7 +1268,7 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
|
|
|
1250
1268
|
return multipartStart(size, {
|
|
1251
1269
|
publicKey,
|
|
1252
1270
|
contentType,
|
|
1253
|
-
fileName: fileName
|
|
1271
|
+
fileName: fileName ?? file.name,
|
|
1254
1272
|
baseURL,
|
|
1255
1273
|
secureSignature,
|
|
1256
1274
|
secureExpire,
|
|
@@ -1502,7 +1520,10 @@ function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.
|
|
|
1502
1520
|
/**
|
|
1503
1521
|
* Populate options with settings.
|
|
1504
1522
|
*/
|
|
1505
|
-
const populateOptionsWithSettings = (options, settings) => (
|
|
1523
|
+
const populateOptionsWithSettings = (options, settings) => ({
|
|
1524
|
+
...settings,
|
|
1525
|
+
...options
|
|
1526
|
+
});
|
|
1506
1527
|
class UploadClient {
|
|
1507
1528
|
constructor(settings) {
|
|
1508
1529
|
this.settings = Object.assign({}, defaultSettings, settings);
|