@uploadcare/upload-client 6.0.1-alpha.8 → 6.0.1-alpha.9

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.d.ts CHANGED
@@ -70,6 +70,42 @@ export declare type ContentInfo = {
70
70
  image?: ImageInfo;
71
71
  video?: VideoInfo;
72
72
  };
73
+ export interface DefaultSettings {
74
+ baseCDN: string;
75
+ baseURL: string;
76
+ maxContentLength: number;
77
+ retryThrottledRequestMaxTimes: number;
78
+ retryNetworkErrorMaxTimes: number;
79
+ multipartMinFileSize: number;
80
+ multipartChunkSize: number;
81
+ multipartMinLastPartSize: number;
82
+ maxConcurrentRequests: number;
83
+ pollingTimeoutMilliseconds: number;
84
+ pusherKey: string;
85
+ }
86
+ export interface Settings extends Partial<DefaultSettings> {
87
+ publicKey: string;
88
+ fileName?: string;
89
+ contentType?: string;
90
+ store?: boolean;
91
+ secureSignature?: string;
92
+ secureExpire?: string;
93
+ integration?: string;
94
+ userAgent?: CustomUserAgent;
95
+ checkForUrlDuplicates?: boolean;
96
+ saveUrlForRecurrentUploads?: boolean;
97
+ source?: string;
98
+ jsonpCallback?: string;
99
+ }
100
+ export declare type BrowserFile = Blob | File;
101
+ export declare type NodeFile = Buffer;
102
+ export declare type ReactNativeAsset = {
103
+ type: string;
104
+ uri: string;
105
+ name?: string;
106
+ };
107
+ export declare type ReactNativeFile = ReactNativeAsset | Blob;
108
+ export declare type AnyFile = BrowserFile | NodeFile | ReactNativeFile;
73
109
  export declare type FileInfo = {
74
110
  size: number;
75
111
  done: number;
@@ -112,18 +148,6 @@ export declare type ProgressCallback<T = ComputableProgressInfo | UnknownProgres
112
148
  export declare type Metadata = {
113
149
  [key: string]: string;
114
150
  };
115
- export declare type Headers = {
116
- [key: string]: string | string[] | undefined;
117
- };
118
- export declare type ErrorRequestInfo = {
119
- method?: string;
120
- url: string;
121
- query?: string;
122
- data?: NodeFormData | FormData | BrowserFile | NodeFile;
123
- headers?: Headers;
124
- };
125
- export declare type BrowserFile = Blob | File;
126
- export declare type NodeFile = Buffer;
127
151
  export declare type BaseResponse = {
128
152
  file: Uuid;
129
153
  };
@@ -148,7 +172,7 @@ export declare type BaseOptions = {
148
172
  * Performs file uploading request to Uploadcare Upload API.
149
173
  * Can be canceled and has progress.
150
174
  */
151
- export function base(file: NodeFile | BrowserFile, { publicKey, fileName, contentType, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, metadata }: BaseOptions): Promise<BaseResponse>;
175
+ export function base(file: AnyFile, { publicKey, fileName, contentType, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, metadata }: BaseOptions): Promise<BaseResponse>;
152
176
  declare enum TypeEnum {
153
177
  Token = "token",
154
178
  FileInfo = "file_info"
@@ -309,7 +333,7 @@ export declare type MultipartUploadResponse = {
309
333
  /**
310
334
  * Complete multipart uploading.
311
335
  */
312
- export function multipartUpload(part: NodeFile | BrowserFile, url: MultipartPart, { signal, onProgress, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes }: MultipartUploadOptions): Promise<MultipartUploadResponse>;
336
+ export function multipartUpload(part: AnyFile, url: MultipartPart, { signal, onProgress, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes }: MultipartUploadOptions): Promise<MultipartUploadResponse>;
313
337
  export declare type MultipartCompleteOptions = {
314
338
  publicKey: string;
315
339
  baseURL?: string;
@@ -362,13 +386,7 @@ export declare type DirectOptions = {
362
386
  baseCDN?: string;
363
387
  metadata?: Metadata;
364
388
  };
365
- export declare const uploadDirect: (file: NodeFile | BrowserFile, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, contentType, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN, metadata }: DirectOptions) => Promise<UploadcareFile>;
366
- export declare type UploadFromUrlOptions = {
367
- baseCDN?: string;
368
- onProgress?: ProgressCallback;
369
- pusherKey?: string;
370
- } & FromUrlOptions;
371
- export declare const uploadFromUrl: (sourceUrl: string, { publicKey, fileName, baseURL, baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, pusherKey, metadata }: UploadFromUrlOptions) => Promise<UploadcareFile>;
389
+ export declare const uploadDirect: (file: AnyFile, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, contentType, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN, metadata }: DirectOptions) => Promise<UploadcareFile>;
372
390
  export declare type FromUploadedOptions = {
373
391
  publicKey: string;
374
392
  fileName?: string;
@@ -383,6 +401,12 @@ export declare type FromUploadedOptions = {
383
401
  baseCDN?: string;
384
402
  };
385
403
  export declare const uploadFromUploaded: (uuid: Uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN }: FromUploadedOptions) => Promise<UploadcareFile>;
404
+ export declare type UploadFromUrlOptions = {
405
+ baseCDN?: string;
406
+ onProgress?: ProgressCallback;
407
+ pusherKey?: string;
408
+ } & FromUrlOptions;
409
+ export declare const uploadFromUrl: (sourceUrl: string, { publicKey, fileName, baseURL, baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, pusherKey, metadata }: UploadFromUrlOptions) => Promise<UploadcareFile>;
386
410
  export declare type MultipartOptions = {
387
411
  publicKey: string;
388
412
  contentType?: string;
@@ -404,7 +428,7 @@ export declare type MultipartOptions = {
404
428
  baseCDN?: string;
405
429
  metadata?: Metadata;
406
430
  };
407
- export declare const uploadMultipart: (file: NodeFile | BrowserFile, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize, maxConcurrentRequests, baseCDN, metadata }: MultipartOptions) => Promise<UploadcareFile>;
431
+ export declare const uploadMultipart: (file: AnyFile, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize, maxConcurrentRequests, baseCDN, metadata }: MultipartOptions) => Promise<UploadcareFile>;
408
432
  export declare type FileFromOptions = {
409
433
  publicKey: string;
410
434
  fileName?: string;
@@ -432,7 +456,7 @@ export declare type FileFromOptions = {
432
456
  /**
433
457
  * Uploads file from provided data.
434
458
  */
435
- export declare function uploadFile(data: NodeFile | BrowserFile | Url | Uuid, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartMinFileSize, multipartChunkSize, maxConcurrentRequests, baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, pusherKey, metadata }: FileFromOptions): Promise<UploadcareFile>;
459
+ export declare function uploadFile(data: AnyFile | Url | Uuid, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartMinFileSize, multipartChunkSize, maxConcurrentRequests, baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, pusherKey, metadata }: FileFromOptions): Promise<UploadcareFile>;
436
460
  export declare class UploadcareGroup {
437
461
  readonly uuid: GroupId;
438
462
  readonly filesCount: string;
@@ -448,51 +472,34 @@ export declare class UploadcareGroup {
448
472
  export declare type GroupFromOptions = {
449
473
  jsonpCallback?: string;
450
474
  };
451
- export function uploadFileGroup(data: (NodeFile | BrowserFile)[] | Url[] | Uuid[], { publicKey, fileName, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize, baseCDN, jsonpCallback }: FileFromOptions & GroupFromOptions): Promise<UploadcareGroup>;
452
- export interface DefaultSettings {
453
- baseCDN: string;
454
- baseURL: string;
455
- maxContentLength: number;
456
- retryThrottledRequestMaxTimes: number;
457
- retryNetworkErrorMaxTimes: number;
458
- multipartMinFileSize: number;
459
- multipartChunkSize: number;
460
- multipartMinLastPartSize: number;
461
- maxConcurrentRequests: number;
462
- pollingTimeoutMilliseconds: number;
463
- pusherKey: string;
464
- }
465
- export interface Settings extends Partial<DefaultSettings> {
466
- publicKey: string;
467
- fileName?: string;
468
- contentType?: string;
469
- store?: boolean;
470
- secureSignature?: string;
471
- secureExpire?: string;
472
- integration?: string;
473
- userAgent?: CustomUserAgent;
474
- checkForUrlDuplicates?: boolean;
475
- saveUrlForRecurrentUploads?: boolean;
476
- source?: string;
477
- jsonpCallback?: string;
478
- }
475
+ export function uploadFileGroup(data: AnyFile[] | Url[] | Uuid[], { publicKey, fileName, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize, baseCDN, jsonpCallback }: FileFromOptions & GroupFromOptions): Promise<UploadcareGroup>;
479
476
  export declare class UploadClient {
480
477
  private settings;
481
478
  constructor(settings: Settings);
482
479
  updateSettings(newSettings: Settings): void;
483
480
  getSettings(): Settings;
484
- base(file: NodeFile | BrowserFile, options?: Partial<BaseOptions>): Promise<BaseResponse>;
481
+ base(file: AnyFile, options?: Partial<BaseOptions>): Promise<BaseResponse>;
485
482
  info(uuid: Uuid, options?: Partial<InfoOptions>): Promise<FileInfo>;
486
483
  fromUrl(sourceUrl: Url, options?: Partial<FromUrlOptions>): Promise<FromUrlResponse>;
487
484
  fromUrlStatus(token: Token, options?: Partial<FromUrlStatusOptions>): Promise<FromUrlStatusResponse>;
488
485
  group(uuids: Uuid[], options?: Partial<GroupOptions>): Promise<GroupInfo>;
489
486
  groupInfo(id: GroupId, options?: Partial<GroupInfoOptions>): Promise<GroupInfo>;
490
487
  multipartStart(size: number, options?: Partial<MultipartStartOptions>): Promise<MultipartStartResponse>;
491
- multipartUpload(part: Buffer | Blob, url: MultipartPart, options?: Partial<MultipartUploadOptions>): Promise<MultipartUploadResponse>;
488
+ multipartUpload(part: BrowserFile | NodeFile, url: MultipartPart, options?: Partial<MultipartUploadOptions>): Promise<MultipartUploadResponse>;
492
489
  multipartComplete(uuid: Uuid, options?: Partial<MultipartCompleteOptions>): Promise<FileInfo>;
493
- uploadFile(data: NodeFile | BrowserFile | Url | Uuid, options?: Partial<FileFromOptions>): Promise<UploadcareFile>;
494
- uploadFileGroup(data: (NodeFile | BrowserFile)[] | Url[] | Uuid[], options?: Partial<FileFromOptions & GroupFromOptions>): Promise<UploadcareGroup>;
490
+ uploadFile(data: AnyFile | Url | Uuid, options?: Partial<FileFromOptions>): Promise<UploadcareFile>;
491
+ uploadFileGroup(data: (AnyFile)[] | Url[] | Uuid[], options?: Partial<FileFromOptions & GroupFromOptions>): Promise<UploadcareGroup>;
495
492
  }
493
+ export declare type Headers = {
494
+ [key: string]: string | string[] | undefined;
495
+ };
496
+ export declare type ErrorRequestInfo = {
497
+ method?: string;
498
+ url: string;
499
+ query?: string;
500
+ data?: NodeFormData | FormData | AnyFile;
501
+ headers?: Headers;
502
+ };
496
503
  export declare type ErrorResponseInfo = {
497
504
  error?: {
498
505
  statusCode: number;
@@ -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.
@@ -285,49 +305,24 @@ const getFileOptions = ({ name, contentType }) => [
285
305
  const transformFile = identity;
286
306
  var getFormData = () => new NodeFormData();
287
307
 
288
- const isReactNativeUri = (uri) => {
289
- if (typeof uri !== 'string') {
290
- return false;
291
- }
292
- return uri.startsWith('file:') || uri.startsWith('content:');
308
+ const isBlob = (data) => {
309
+ return typeof Blob !== 'undefined' && data instanceof Blob;
293
310
  };
294
- const isReactNativeAsset = (asset) => {
295
- return (!!asset &&
296
- typeof asset === 'object' &&
297
- !Array.isArray(asset) &&
298
- 'uri' in asset &&
299
- typeof asset.uri === 'string' &&
300
- isReactNativeUri(asset.uri));
311
+ const isFile = (data) => {
312
+ return typeof File !== 'undefined' && data instanceof File;
301
313
  };
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))));
314
+ const isBuffer = (data) => {
315
+ return typeof Buffer !== 'undefined' && data instanceof Buffer;
313
316
  };
314
- /**
315
- * Uuid type guard.
316
- */
317
- const isUuid = (data) => {
318
- const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
319
- const regExp = new RegExp(UUID_REGEX);
320
- return !isFileData(data) && regExp.test(data);
317
+ const isReactNativeAsset = (data) => {
318
+ return (!!data &&
319
+ typeof data === 'object' &&
320
+ !Array.isArray(data) &&
321
+ 'uri' in data &&
322
+ typeof data.uri === 'string');
321
323
  };
322
- /**
323
- * Url type guard.
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);
324
+ const isFileData = (data) => {
325
+ return (isBlob(data) || isFile(data) || isBuffer(data) || isReactNativeAsset(data));
331
326
  };
332
327
 
333
328
  const isSimpleValue = (value) => {
@@ -368,11 +363,9 @@ function getFormDataParams(options) {
368
363
  return params;
369
364
  }
370
365
  function buildFormData(options) {
371
- console.log('buildFormData', options);
372
366
  const formData = getFormData();
373
367
  const paramsList = getFormDataParams(options);
374
368
  for (const params of paramsList) {
375
- console.log('params', params);
376
369
  const [key, value, ...rest] = params;
377
370
  // node form-data has another signature for append
378
371
  formData.append(key, value, ...rest);
@@ -380,6 +373,19 @@ function buildFormData(options) {
380
373
  return formData;
381
374
  }
382
375
 
376
+ class UploadClientError extends Error {
377
+ constructor(message, code, request, response, headers) {
378
+ super();
379
+ this.name = 'UploadClientError';
380
+ this.message = message;
381
+ this.code = code;
382
+ this.request = request;
383
+ this.response = response;
384
+ this.headers = headers;
385
+ Object.setPrototypeOf(this, UploadClientError.prototype);
386
+ }
387
+ }
388
+
383
389
  const buildSearchParams = (query) => {
384
390
  const searchParams = new URLSearchParams();
385
391
  for (const [key, value] of Object.entries(query)) {
@@ -411,26 +417,6 @@ const getUrl = (base, path, query) => {
411
417
  return url.toString();
412
418
  };
413
419
 
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
420
  var version = '6.0.0';
435
421
 
436
422
  const LIBRARY_NAME = 'UploadcareUploadClient';
@@ -443,19 +429,6 @@ function getUserAgent(options) {
443
429
  });
444
430
  }
445
431
 
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
432
  const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
460
433
  const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
461
434
  const DEFAULT_NETWORK_ERROR_TIMEOUT = 1000;
@@ -486,6 +459,31 @@ function retryIfFailed(fn, options) {
486
459
  }));
487
460
  }
488
461
 
462
+ const getContentType = (file) => {
463
+ if (isBlob(file) || isFile(file) || isReactNativeAsset(file)) {
464
+ return file.type || defaultContentType;
465
+ }
466
+ if (isBuffer(file)) {
467
+ return defaultFilename;
468
+ }
469
+ console.warn(`Unknown filename: ${file}. Using default filename: ${defaultFilename}`);
470
+ return defaultFilename;
471
+ };
472
+
473
+ const getFilename = (file) => {
474
+ if (isBlob(file) || isBuffer(file)) {
475
+ return defaultFilename;
476
+ }
477
+ if (isFile(file)) {
478
+ return file.name || defaultFilename;
479
+ }
480
+ if (isReactNativeAsset(file)) {
481
+ return file.name || defaultFilename;
482
+ }
483
+ console.warn(`Unknown file type: ${file}. Using default filename: ${defaultFilename}`);
484
+ return defaultFilename;
485
+ };
486
+
489
487
  function getStoreValue(store) {
490
488
  return typeof store === 'undefined' ? 'auto' : store ? '1' : '0';
491
489
  }
@@ -501,13 +499,13 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
501
499
  jsonerrors: 1
502
500
  }),
503
501
  headers: {
504
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent }),
502
+ 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
505
503
  },
506
504
  data: buildFormData({
507
505
  file: {
508
506
  data: file,
509
- name: fileName ?? file?.name ?? defaultFilename,
510
- contentType: contentType ?? file?.type ?? defaultContentType
507
+ name: fileName || getFilename(file),
508
+ contentType: contentType || getContentType(file)
511
509
  },
512
510
  UPLOADCARE_PUB_KEY: publicKey,
513
511
  UPLOADCARE_STORE: getStoreValue(store),
@@ -705,9 +703,9 @@ function multipartStart(size, { publicKey, contentType, fileName, multipartChunk
705
703
  'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
706
704
  },
707
705
  data: buildFormData({
708
- filename: fileName ?? defaultFilename,
706
+ filename: fileName || defaultFilename,
709
707
  size: size,
710
- content_type: contentType ?? defaultContentType,
708
+ content_type: contentType || defaultContentType,
711
709
  part_size: multipartChunkSize,
712
710
  UPLOADCARE_STORE: getStoreValue(store),
713
711
  UPLOADCARE_PUB_KEY: publicKey,
@@ -784,6 +782,28 @@ function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL,
784
782
  }), { retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes });
785
783
  }
786
784
 
785
+ function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, signal, onProgress }) {
786
+ return poll({
787
+ check: (signal) => info(file, {
788
+ publicKey,
789
+ baseURL,
790
+ signal,
791
+ source,
792
+ integration,
793
+ userAgent,
794
+ retryThrottledRequestMaxTimes,
795
+ retryNetworkErrorMaxTimes
796
+ }).then((response) => {
797
+ if (response.isReady) {
798
+ return response;
799
+ }
800
+ onProgress && onProgress({ isComputable: true, value: 1 });
801
+ return false;
802
+ }),
803
+ signal
804
+ });
805
+ }
806
+
787
807
  class UploadcareFile {
788
808
  constructor(fileInfo, { baseCDN, fileName }) {
789
809
  this.name = null;
@@ -821,28 +841,6 @@ class UploadcareFile {
821
841
  }
822
842
  }
823
843
 
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
844
  const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, contentType, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN, metadata }) => {
847
845
  return base(file, {
848
846
  publicKey,
@@ -878,6 +876,29 @@ const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, sec
878
876
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
879
877
  };
880
878
 
879
+ const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN }) => {
880
+ return info(uuid, {
881
+ publicKey,
882
+ baseURL,
883
+ signal,
884
+ source,
885
+ integration,
886
+ userAgent,
887
+ retryThrottledRequestMaxTimes,
888
+ retryNetworkErrorMaxTimes
889
+ })
890
+ .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
891
+ .then((result) => {
892
+ // hack for node ¯\_(ツ)_/¯
893
+ if (onProgress)
894
+ onProgress({
895
+ isComputable: true,
896
+ value: 1
897
+ });
898
+ return result;
899
+ });
900
+ };
901
+
881
902
  const race = (fns, { signal } = {}) => {
882
903
  let lastError = null;
883
904
  let winnerIndex = null;
@@ -1215,35 +1236,30 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
1215
1236
  }))
1216
1237
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1217
1238
 
1218
- const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN }) => {
1219
- return info(uuid, {
1220
- publicKey,
1221
- baseURL,
1222
- signal,
1223
- source,
1224
- integration,
1225
- userAgent,
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
- });
1239
+ const memo = new WeakMap();
1240
+ const getReactNativeBlob = async (asset) => {
1241
+ if (memo.has(asset)) {
1242
+ return memo.get(asset);
1243
+ }
1244
+ const blob = await fetch(asset.uri).then((res) => res.blob());
1245
+ memo.set(asset, blob);
1246
+ return blob;
1239
1247
  };
1240
1248
 
1241
- /**
1242
- * Get file size.
1243
- */
1244
- const getFileSize = (file) => {
1245
- return file.length || file.size;
1249
+ const getFileSize = async (file) => {
1250
+ if (isBuffer(file)) {
1251
+ return file.length;
1252
+ }
1253
+ if (isFile(file) || isBlob(file)) {
1254
+ return file.size;
1255
+ }
1256
+ if (isReactNativeAsset(file)) {
1257
+ const blob = await getReactNativeBlob(file);
1258
+ return blob.size;
1259
+ }
1260
+ throw new Error(`Failed to get file size for file: ${file}`);
1246
1261
  };
1262
+
1247
1263
  /**
1248
1264
  * Check if FileData is multipart data.
1249
1265
  */
@@ -1251,15 +1267,24 @@ const isMultipart = (fileSize, multipartMinFileSize = defaultSettings.multipartM
1251
1267
  return fileSize >= multipartMinFileSize;
1252
1268
  };
1253
1269
 
1254
- const sliceChunk = (file, index, fileSize, chunkSize) => {
1255
- const start = chunkSize * index;
1256
- const end = Math.min(start + chunkSize, fileSize);
1257
- return file.slice(start, end);
1270
+ /**
1271
+ * Uuid type guard.
1272
+ */
1273
+ const isUuid = (data) => {
1274
+ const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
1275
+ const regExp = new RegExp(UUID_REGEX);
1276
+ return !isFileData(data) && regExp.test(data);
1277
+ };
1278
+ /**
1279
+ * Url type guard.
1280
+ *
1281
+ * @param {AnyFile | Url | Uuid} data
1282
+ */
1283
+ const isUrl = (data) => {
1284
+ const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
1285
+ const regExp = new RegExp(URL_REGEX);
1286
+ return !isFileData(data) && regExp.test(data);
1258
1287
  };
1259
-
1260
- function prepareChunks(file, fileSize, chunkSize) {
1261
- return (index) => sliceChunk(file, index, fileSize, chunkSize);
1262
- }
1263
1288
 
1264
1289
  const runWithConcurrency = (concurrency, tasks) => {
1265
1290
  return new Promise((resolve, reject) => {
@@ -1296,6 +1321,16 @@ const runWithConcurrency = (concurrency, tasks) => {
1296
1321
  });
1297
1322
  };
1298
1323
 
1324
+ const sliceChunk = (file, index, fileSize, chunkSize) => {
1325
+ const start = chunkSize * index;
1326
+ const end = Math.min(start + chunkSize, fileSize);
1327
+ return file.slice(start, end);
1328
+ };
1329
+
1330
+ const prepareChunks = async (file, fileSize, chunkSize) => {
1331
+ return (index) => sliceChunk(file, index, fileSize, chunkSize);
1332
+ };
1333
+
1299
1334
  const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes }) => multipartUpload(chunk, url, {
1300
1335
  publicKey,
1301
1336
  onProgress,
@@ -1304,8 +1339,8 @@ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, re
1304
1339
  retryThrottledRequestMaxTimes,
1305
1340
  retryNetworkErrorMaxTimes
1306
1341
  });
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);
1342
+ 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 }) => {
1343
+ const size = fileSize || await getFileSize(file);
1309
1344
  let progressValues;
1310
1345
  const createProgressHandler = (totalChunks, chunkIdx) => {
1311
1346
  if (!onProgress)
@@ -1327,8 +1362,8 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1327
1362
  };
1328
1363
  return multipartStart(size, {
1329
1364
  publicKey,
1330
- contentType,
1331
- fileName: fileName ?? file.name,
1365
+ contentType: contentType || getContentType(file),
1366
+ fileName: fileName || getFilename(file),
1332
1367
  baseURL,
1333
1368
  secureSignature,
1334
1369
  secureExpire,
@@ -1341,8 +1376,8 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1341
1376
  retryNetworkErrorMaxTimes,
1342
1377
  metadata
1343
1378
  })
1344
- .then(({ uuid, parts }) => {
1345
- const getChunk = prepareChunks(file, size, multipartChunkSize);
1379
+ .then(async ({ uuid, parts }) => {
1380
+ const getChunk = await prepareChunks(file, size, multipartChunkSize);
1346
1381
  return Promise.all([
1347
1382
  uuid,
1348
1383
  runWithConcurrency(maxConcurrentRequests, parts.map((url, index) => () => uploadPart(getChunk(index), url, {
@@ -1389,14 +1424,15 @@ const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureS
1389
1424
  /**
1390
1425
  * Uploads file from provided data.
1391
1426
  */
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 }) {
1427
+ 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
1428
  if (isFileData(data)) {
1394
- const fileSize = getFileSize(data);
1429
+ const fileSize = await getFileSize(data);
1395
1430
  if (isMultipart(fileSize, multipartMinFileSize)) {
1396
1431
  return uploadMultipart(data, {
1397
1432
  publicKey,
1398
1433
  contentType,
1399
1434
  multipartChunkSize,
1435
+ fileSize,
1400
1436
  fileName,
1401
1437
  baseURL,
1402
1438
  secureSignature,