@uploadcare/upload-client 6.0.1-alpha.9 → 6.1.0-alpha.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 CHANGED
@@ -23,6 +23,7 @@ Node.js and browser.
23
23
  - [High-Level API](#high-level-api)
24
24
  - [Low-Level API](#low-level-api)
25
25
  - [Settings](#settings)
26
+ - [React Native](#react-native)
26
27
  - [Testing](#testing)
27
28
  - [Security issues](#security-issues)
28
29
  - [Feedback](#feedback)
@@ -124,7 +125,7 @@ interface UploadClient {
124
125
  getSettings(): Settings
125
126
 
126
127
  base(
127
- file: NodeFile | BrowserFile,
128
+ file: Blob | File | Buffer | ReactNativeAsset,
128
129
  options: BaseOptions
129
130
  ): Promise<BaseResponse>
130
131
 
@@ -158,12 +159,12 @@ interface UploadClient {
158
159
  ): Promise<FileInfo>
159
160
 
160
161
  uploadFile(
161
- data: NodeFile | BrowserFile | Url | Uuid,
162
+ data: Blob | File | Buffer | ReactNativeAsset | Url | Uuid,
162
163
  options: FileFromOptions
163
164
  ): Promise<UploadcareFile>
164
165
 
165
166
  uploadFileGroup(
166
- data: (NodeFile | BrowserFile)[] | Url[] | Uuid[],
167
+ data: (Blob | File | Buffer | ReactNativeAsset)[] | Url[] | Uuid[],
167
168
  options: FileFromOptions & GroupFromOptions
168
169
  ): Promise<UploadcareGroup>
169
170
  }
@@ -208,7 +209,7 @@ List of all available API methods:
208
209
 
209
210
  ```typescript
210
211
  base(
211
- file: NodeFile | BrowserFile,
212
+ file: Blob | File | Buffer | ReactNativeAsset,
212
213
  options: BaseOptions
213
214
  ): Promise<BaseResponse>
214
215
  ```
@@ -245,7 +246,7 @@ multipartStart(
245
246
 
246
247
  ```typescript
247
248
  multipartUpload(
248
- part: Buffer | Blob,
249
+ part: Buffer | Blob | File,
249
250
  url: MultipartPart,
250
251
  options: MultipartUploadOptions
251
252
  ): Promise<MultipartUploadResponse>
@@ -288,6 +289,7 @@ Defaults to `https://upload.uploadcare.com`
288
289
  #### `fileName: string`
289
290
 
290
291
  You can specify an original filename.
292
+ It could useful when file input does not contain filename.
291
293
 
292
294
  Defaults to `original`.
293
295
 
@@ -408,7 +410,7 @@ Defaults to `4`.
408
410
 
409
411
  ### `contentType: string`
410
412
 
411
- This setting is needed for correct multipart uploads.
413
+ This option is useful when file input does not contain content type.
412
414
 
413
415
  Defaults to `application/octet-stream`.
414
416
 
@@ -426,6 +428,37 @@ Non-string values will be converted to `string`. `undefined` values will be igno
426
428
 
427
429
  See [docs][uc-file-metadata] and [REST API][uc-docs-metadata] for details.
428
430
 
431
+ ## React Native
432
+
433
+ To be able to use `@uploadcare/upload-client` with React Native, you need to
434
+ install [react-native-url-polyfill][react-native-url-polyfill].
435
+
436
+ To prevent [`Error: Cannot create URL for blob`][react-native-url-polyfill-issue]
437
+ errors you need to configure your Android app schema to accept blobs -
438
+ have a look at this pull request for an example: [5985d7e][react-native-url-polyfill-example].
439
+
440
+ You can use `ReactNativeAsset` as an input to the `@uploadcare/upload-client` like this:
441
+
442
+ ```ts
443
+ type ReactNativeAsset = {
444
+ uri: string
445
+ type: string
446
+ name?: string
447
+ }
448
+ ```
449
+
450
+ ```ts
451
+ const asset = { uri: 'URI_TO_FILE', name: 'file.txt', type: 'text/plain' }
452
+ uploadFile(asset, { publicKey: 'YOUR_PUBLIC_KEY' })
453
+ ```
454
+
455
+ Or `Blob` like this:
456
+
457
+ ```ts
458
+ const uri = 'URI_TO_FILE'
459
+ const blob = await fetch(uri).then((res) => res.blob())
460
+ uploadFile(blob, { publicKey: 'YOUR_PUBLIC_KEY' })
461
+ ```
429
462
 
430
463
  ## Testing
431
464
 
@@ -490,3 +523,6 @@ request at [hello@uploadcare.com][uc-email-hello].
490
523
  [uc-docs-upload-api]: https://uploadcare.com/docs/api_reference/upload/?utm_source=github&utm_campaign=uploadcare-js-api-clients
491
524
  [uc-docs-metadata]: https://uploadcare.com/api-refs/rest-api/v0.7.0/#tag/File-Metadata
492
525
  [uc-file-metadata]: https://uploadcare.com/docs/file-metadata/
526
+ [react-native-url-polyfill]: https://github.com/charpeni/react-native-url-polyfill
527
+ [react-native-url-polyfill-issue]: https://github.com/charpeni/react-native-url-polyfill/issues/284
528
+ [react-native-url-polyfill-example]: https://github.com/charpeni/react-native-url-polyfill/commit/5985d7efc07b496b829883540d09c6f0be384387
@@ -269,7 +269,8 @@ const request = ({ method, url, data, headers = {}, signal, onProgress }) => new
269
269
  }
270
270
  });
271
271
 
272
- function identity(obj) {
272
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
273
+ function identity(obj, ..._args) {
273
274
  return obj;
274
275
  }
275
276
 
@@ -312,7 +313,7 @@ const isFileValue = (value) => !!value &&
312
313
  function collectParams(params, inputKey, inputValue) {
313
314
  if (isFileValue(inputValue)) {
314
315
  const { name, contentType } = inputValue;
315
- const file = transformFile(inputValue.data); // lgtm [js/superfluous-trailing-arguments]
316
+ const file = transformFile(inputValue.data, name, contentType);
316
317
  const options = getFileOptions({ name, contentType });
317
318
  params.push([inputKey, file, ...options]);
318
319
  }
@@ -432,28 +433,25 @@ function retryIfFailed(fn, options) {
432
433
  }
433
434
 
434
435
  const getContentType = (file) => {
436
+ let contentType = '';
435
437
  if (isBlob(file) || isFile(file) || isReactNativeAsset(file)) {
436
- return file.type || defaultContentType;
438
+ contentType = file.type;
437
439
  }
438
- if (isBuffer(file)) {
439
- return defaultFilename;
440
- }
441
- console.warn(`Unknown filename: ${file}. Using default filename: ${defaultFilename}`);
442
- return defaultFilename;
440
+ return contentType || defaultContentType;
443
441
  };
444
442
 
445
- const getFilename = (file) => {
446
- if (isBlob(file) || isBuffer(file)) {
447
- return defaultFilename;
443
+ const getFileName = (file) => {
444
+ let filename = '';
445
+ if (isFile(file) && file.name) {
446
+ filename = file.name;
448
447
  }
449
- if (isFile(file)) {
450
- return file.name || defaultFilename;
448
+ else if (isBlob(file) || isBuffer(file)) {
449
+ filename = '';
451
450
  }
452
- if (isReactNativeAsset(file)) {
453
- return file.name || defaultFilename;
451
+ else if (isReactNativeAsset(file) && file.name) {
452
+ filename = file.name;
454
453
  }
455
- console.warn(`Unknown file type: ${file}. Using default filename: ${defaultFilename}`);
456
- return defaultFilename;
454
+ return filename || defaultFilename;
457
455
  };
458
456
 
459
457
  function getStoreValue(store) {
@@ -476,7 +474,7 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
476
474
  data: buildFormData({
477
475
  file: {
478
476
  data: file,
479
- name: fileName || getFilename(file),
477
+ name: fileName || getFileName(file),
480
478
  contentType: contentType || getContentType(file)
481
479
  },
482
480
  UPLOADCARE_PUB_KEY: publicKey,
@@ -1211,7 +1209,7 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
1211
1209
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1212
1210
 
1213
1211
  const memo = new WeakMap();
1214
- const getReactNativeBlob = async (asset) => {
1212
+ const getBlobFromReactNativeAsset = async (asset) => {
1215
1213
  if (memo.has(asset)) {
1216
1214
  return memo.get(asset);
1217
1215
  }
@@ -1228,10 +1226,10 @@ const getFileSize = async (file) => {
1228
1226
  return file.size;
1229
1227
  }
1230
1228
  if (isReactNativeAsset(file)) {
1231
- const blob = await getReactNativeBlob(file);
1229
+ const blob = await getBlobFromReactNativeAsset(file);
1232
1230
  return blob.size;
1233
1231
  }
1234
- throw new Error(`Failed to get file size for file: ${file}`);
1232
+ throw new Error(`Unknown file type. Cannot determine file size.`);
1235
1233
  };
1236
1234
 
1237
1235
  /**
@@ -1252,7 +1250,7 @@ const isUuid = (data) => {
1252
1250
  /**
1253
1251
  * Url type guard.
1254
1252
  *
1255
- * @param {AnyFile | Url | Uuid} data
1253
+ * @param {SupportedFileInput | Url | Uuid} data
1256
1254
  */
1257
1255
  const isUrl = (data) => {
1258
1256
  const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
@@ -1314,7 +1312,7 @@ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, re
1314
1312
  retryNetworkErrorMaxTimes
1315
1313
  });
1316
1314
  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 }) => {
1317
- const size = fileSize || await getFileSize(file);
1315
+ const size = fileSize ?? (await getFileSize(file));
1318
1316
  let progressValues;
1319
1317
  const createProgressHandler = (totalChunks, chunkIdx) => {
1320
1318
  if (!onProgress)
@@ -1337,7 +1335,7 @@ const uploadMultipart = async (file, { publicKey, fileName, fileSize, baseURL, s
1337
1335
  return multipartStart(size, {
1338
1336
  publicKey,
1339
1337
  contentType: contentType || getContentType(file),
1340
- fileName: fileName || getFilename(file),
1338
+ fileName: fileName || getFileName(file),
1341
1339
  baseURL,
1342
1340
  secureSignature,
1343
1341
  secureExpire,
package/dist/index.d.ts CHANGED
@@ -70,6 +70,7 @@ export declare type ContentInfo = {
70
70
  image?: ImageInfo;
71
71
  video?: VideoInfo;
72
72
  };
73
+ export declare type Metadata = Record<string, string>;
73
74
  export interface DefaultSettings {
74
75
  baseCDN: string;
75
76
  baseURL: string;
@@ -104,8 +105,8 @@ export declare type ReactNativeAsset = {
104
105
  uri: string;
105
106
  name?: string;
106
107
  };
107
- export declare type ReactNativeFile = ReactNativeAsset | Blob;
108
- export declare type AnyFile = BrowserFile | NodeFile | ReactNativeFile;
108
+ export declare type SupportedFileInput = BrowserFile | NodeFile | ReactNativeAsset;
109
+ export declare type Sliceable = BrowserFile | NodeFile;
109
110
  export declare type FileInfo = {
110
111
  size: number;
111
112
  done: number;
@@ -145,9 +146,6 @@ export declare type UnknownProgressInfo = {
145
146
  isComputable: false;
146
147
  };
147
148
  export declare type ProgressCallback<T = ComputableProgressInfo | UnknownProgressInfo> = (arg: T) => void;
148
- export declare type Metadata = {
149
- [key: string]: string;
150
- };
151
149
  export declare type BaseResponse = {
152
150
  file: Uuid;
153
151
  };
@@ -172,8 +170,8 @@ export declare type BaseOptions = {
172
170
  * Performs file uploading request to Uploadcare Upload API.
173
171
  * Can be canceled and has progress.
174
172
  */
175
- export function base(file: AnyFile, { publicKey, fileName, contentType, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, metadata }: BaseOptions): Promise<BaseResponse>;
176
- declare enum TypeEnum {
173
+ export function base(file: SupportedFileInput, { publicKey, fileName, contentType, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, metadata }: BaseOptions): Promise<BaseResponse>;
174
+ export declare enum TypeEnum {
177
175
  Token = "token",
178
176
  FileInfo = "file_info"
179
177
  }
@@ -207,7 +205,7 @@ export declare type FromUrlOptions = {
207
205
  * Uploading files from URL.
208
206
  */
209
207
  export function fromUrl(sourceUrl: Url, { publicKey, baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source, signal, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, metadata }: FromUrlOptions): Promise<FromUrlSuccessResponse>;
210
- declare enum Status {
208
+ export declare enum Status {
211
209
  Unknown = "unknown",
212
210
  Waiting = "waiting",
213
211
  Progress = "progress",
@@ -333,7 +331,7 @@ export declare type MultipartUploadResponse = {
333
331
  /**
334
332
  * Complete multipart uploading.
335
333
  */
336
- export function multipartUpload(part: AnyFile, url: MultipartPart, { signal, onProgress, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes }: MultipartUploadOptions): Promise<MultipartUploadResponse>;
334
+ export function multipartUpload(part: SupportedFileInput, url: MultipartPart, { signal, onProgress, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes }: MultipartUploadOptions): Promise<MultipartUploadResponse>;
337
335
  export declare type MultipartCompleteOptions = {
338
336
  publicKey: string;
339
337
  baseURL?: string;
@@ -368,6 +366,34 @@ export declare class UploadcareFile {
368
366
  fileName?: string;
369
367
  });
370
368
  }
369
+ export declare type FileFromOptions = {
370
+ publicKey: string;
371
+ fileName?: string;
372
+ baseURL?: string;
373
+ secureSignature?: string;
374
+ secureExpire?: string;
375
+ store?: boolean;
376
+ signal?: AbortSignal;
377
+ onProgress?: ProgressCallback;
378
+ source?: string;
379
+ integration?: string;
380
+ userAgent?: CustomUserAgent;
381
+ retryThrottledRequestMaxTimes?: number;
382
+ retryNetworkErrorMaxTimes?: number;
383
+ contentType?: string;
384
+ multipartMinFileSize?: number;
385
+ multipartChunkSize?: number;
386
+ maxConcurrentRequests?: number;
387
+ baseCDN?: string;
388
+ checkForUrlDuplicates?: boolean;
389
+ saveUrlForRecurrentUploads?: boolean;
390
+ pusherKey?: string;
391
+ metadata?: Metadata;
392
+ };
393
+ /**
394
+ * Uploads file from provided data.
395
+ */
396
+ export declare function uploadFile(data: SupportedFileInput | 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>;
371
397
  export declare type DirectOptions = {
372
398
  publicKey: string;
373
399
  fileName?: string;
@@ -386,7 +412,7 @@ export declare type DirectOptions = {
386
412
  baseCDN?: string;
387
413
  metadata?: Metadata;
388
414
  };
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>;
415
+ export declare const uploadDirect: (file: SupportedFileInput, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, contentType, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, baseCDN, metadata }: DirectOptions) => Promise<UploadcareFile>;
390
416
  export declare type FromUploadedOptions = {
391
417
  publicKey: string;
392
418
  fileName?: string;
@@ -428,35 +454,7 @@ export declare type MultipartOptions = {
428
454
  baseCDN?: string;
429
455
  metadata?: Metadata;
430
456
  };
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>;
432
- export declare type FileFromOptions = {
433
- publicKey: string;
434
- fileName?: string;
435
- baseURL?: string;
436
- secureSignature?: string;
437
- secureExpire?: string;
438
- store?: boolean;
439
- signal?: AbortSignal;
440
- onProgress?: ProgressCallback;
441
- source?: string;
442
- integration?: string;
443
- userAgent?: CustomUserAgent;
444
- retryThrottledRequestMaxTimes?: number;
445
- retryNetworkErrorMaxTimes?: number;
446
- contentType?: string;
447
- multipartMinFileSize?: number;
448
- multipartChunkSize?: number;
449
- maxConcurrentRequests?: number;
450
- baseCDN?: string;
451
- checkForUrlDuplicates?: boolean;
452
- saveUrlForRecurrentUploads?: boolean;
453
- pusherKey?: string;
454
- metadata?: Metadata;
455
- };
456
- /**
457
- * Uploads file from provided data.
458
- */
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>;
457
+ export declare const uploadMultipart: (file: SupportedFileInput, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize, maxConcurrentRequests, baseCDN, metadata }: MultipartOptions) => Promise<UploadcareFile>;
460
458
  export declare class UploadcareGroup {
461
459
  readonly uuid: GroupId;
462
460
  readonly filesCount: string;
@@ -472,23 +470,23 @@ export declare class UploadcareGroup {
472
470
  export declare type GroupFromOptions = {
473
471
  jsonpCallback?: string;
474
472
  };
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>;
473
+ export declare function uploadFileGroup(data: SupportedFileInput[] | Url[] | Uuid[], { publicKey, fileName, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize, baseCDN, jsonpCallback }: FileFromOptions & GroupFromOptions): Promise<UploadcareGroup>;
476
474
  export declare class UploadClient {
477
475
  private settings;
478
476
  constructor(settings: Settings);
479
477
  updateSettings(newSettings: Settings): void;
480
478
  getSettings(): Settings;
481
- base(file: AnyFile, options?: Partial<BaseOptions>): Promise<BaseResponse>;
479
+ base(file: SupportedFileInput, options?: Partial<BaseOptions>): Promise<BaseResponse>;
482
480
  info(uuid: Uuid, options?: Partial<InfoOptions>): Promise<FileInfo>;
483
481
  fromUrl(sourceUrl: Url, options?: Partial<FromUrlOptions>): Promise<FromUrlResponse>;
484
482
  fromUrlStatus(token: Token, options?: Partial<FromUrlStatusOptions>): Promise<FromUrlStatusResponse>;
485
483
  group(uuids: Uuid[], options?: Partial<GroupOptions>): Promise<GroupInfo>;
486
484
  groupInfo(id: GroupId, options?: Partial<GroupInfoOptions>): Promise<GroupInfo>;
487
485
  multipartStart(size: number, options?: Partial<MultipartStartOptions>): Promise<MultipartStartResponse>;
488
- multipartUpload(part: BrowserFile | NodeFile, url: MultipartPart, options?: Partial<MultipartUploadOptions>): Promise<MultipartUploadResponse>;
486
+ multipartUpload(part: Sliceable, url: MultipartPart, options?: Partial<MultipartUploadOptions>): Promise<MultipartUploadResponse>;
489
487
  multipartComplete(uuid: Uuid, options?: Partial<MultipartCompleteOptions>): Promise<FileInfo>;
490
- uploadFile(data: AnyFile | Url | Uuid, options?: Partial<FileFromOptions>): Promise<UploadcareFile>;
491
- uploadFileGroup(data: (AnyFile)[] | Url[] | Uuid[], options?: Partial<FileFromOptions & GroupFromOptions>): Promise<UploadcareGroup>;
488
+ uploadFile(data: SupportedFileInput | Url | Uuid, options?: Partial<FileFromOptions>): Promise<UploadcareFile>;
489
+ uploadFileGroup(data: SupportedFileInput[] | Url[] | Uuid[], options?: Partial<FileFromOptions & GroupFromOptions>): Promise<UploadcareGroup>;
492
490
  }
493
491
  export declare type Headers = {
494
492
  [key: string]: string | string[] | undefined;
@@ -497,7 +495,7 @@ export declare type ErrorRequestInfo = {
497
495
  method?: string;
498
496
  url: string;
499
497
  query?: string;
500
- data?: NodeFormData | FormData | AnyFile;
498
+ data?: NodeFormData | FormData | SupportedFileInput;
501
499
  headers?: Headers;
502
500
  };
503
501
  export declare type ErrorResponseInfo = {
@@ -288,7 +288,8 @@ const request = (params) => {
288
288
  }));
289
289
  };
290
290
 
291
- function identity(obj) {
291
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
292
+ function identity(obj, ..._args) {
292
293
  return obj;
293
294
  }
294
295
 
@@ -340,7 +341,7 @@ const isFileValue = (value) => !!value &&
340
341
  function collectParams(params, inputKey, inputValue) {
341
342
  if (isFileValue(inputValue)) {
342
343
  const { name, contentType } = inputValue;
343
- const file = transformFile(inputValue.data); // lgtm [js/superfluous-trailing-arguments]
344
+ const file = transformFile(inputValue.data, name, contentType);
344
345
  const options = getFileOptions({ name, contentType });
345
346
  params.push([inputKey, file, ...options]);
346
347
  }
@@ -460,28 +461,25 @@ function retryIfFailed(fn, options) {
460
461
  }
461
462
 
462
463
  const getContentType = (file) => {
464
+ let contentType = '';
463
465
  if (isBlob(file) || isFile(file) || isReactNativeAsset(file)) {
464
- return file.type || defaultContentType;
466
+ contentType = file.type;
465
467
  }
466
- if (isBuffer(file)) {
467
- return defaultFilename;
468
- }
469
- console.warn(`Unknown filename: ${file}. Using default filename: ${defaultFilename}`);
470
- return defaultFilename;
468
+ return contentType || defaultContentType;
471
469
  };
472
470
 
473
- const getFilename = (file) => {
474
- if (isBlob(file) || isBuffer(file)) {
475
- return defaultFilename;
471
+ const getFileName = (file) => {
472
+ let filename = '';
473
+ if (isFile(file) && file.name) {
474
+ filename = file.name;
476
475
  }
477
- if (isFile(file)) {
478
- return file.name || defaultFilename;
476
+ else if (isBlob(file) || isBuffer(file)) {
477
+ filename = '';
479
478
  }
480
- if (isReactNativeAsset(file)) {
481
- return file.name || defaultFilename;
479
+ else if (isReactNativeAsset(file) && file.name) {
480
+ filename = file.name;
482
481
  }
483
- console.warn(`Unknown file type: ${file}. Using default filename: ${defaultFilename}`);
484
- return defaultFilename;
482
+ return filename || defaultFilename;
485
483
  };
486
484
 
487
485
  function getStoreValue(store) {
@@ -504,7 +502,7 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
504
502
  data: buildFormData({
505
503
  file: {
506
504
  data: file,
507
- name: fileName || getFilename(file),
505
+ name: fileName || getFileName(file),
508
506
  contentType: contentType || getContentType(file)
509
507
  },
510
508
  UPLOADCARE_PUB_KEY: publicKey,
@@ -1237,7 +1235,7 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
1237
1235
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1238
1236
 
1239
1237
  const memo = new WeakMap();
1240
- const getReactNativeBlob = async (asset) => {
1238
+ const getBlobFromReactNativeAsset = async (asset) => {
1241
1239
  if (memo.has(asset)) {
1242
1240
  return memo.get(asset);
1243
1241
  }
@@ -1254,10 +1252,10 @@ const getFileSize = async (file) => {
1254
1252
  return file.size;
1255
1253
  }
1256
1254
  if (isReactNativeAsset(file)) {
1257
- const blob = await getReactNativeBlob(file);
1255
+ const blob = await getBlobFromReactNativeAsset(file);
1258
1256
  return blob.size;
1259
1257
  }
1260
- throw new Error(`Failed to get file size for file: ${file}`);
1258
+ throw new Error(`Unknown file type. Cannot determine file size.`);
1261
1259
  };
1262
1260
 
1263
1261
  /**
@@ -1278,7 +1276,7 @@ const isUuid = (data) => {
1278
1276
  /**
1279
1277
  * Url type guard.
1280
1278
  *
1281
- * @param {AnyFile | Url | Uuid} data
1279
+ * @param {SupportedFileInput | Url | Uuid} data
1282
1280
  */
1283
1281
  const isUrl = (data) => {
1284
1282
  const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
@@ -1340,7 +1338,7 @@ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, re
1340
1338
  retryNetworkErrorMaxTimes
1341
1339
  });
1342
1340
  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);
1341
+ const size = fileSize ?? (await getFileSize(file));
1344
1342
  let progressValues;
1345
1343
  const createProgressHandler = (totalChunks, chunkIdx) => {
1346
1344
  if (!onProgress)
@@ -1363,7 +1361,7 @@ const uploadMultipart = async (file, { publicKey, fileName, fileSize, baseURL, s
1363
1361
  return multipartStart(size, {
1364
1362
  publicKey,
1365
1363
  contentType: contentType || getContentType(file),
1366
- fileName: fileName || getFilename(file),
1364
+ fileName: fileName || getFileName(file),
1367
1365
  baseURL,
1368
1366
  secureSignature,
1369
1367
  secureExpire,
@@ -302,7 +302,7 @@ const transformFile = (file, name, contentType) => {
302
302
  const uri = URL.createObjectURL(file);
303
303
  return { uri, name: name, type: file.type || contentType };
304
304
  }
305
- throw new Error(`Unsupported file type: ${file}`);
305
+ throw new Error(`Unsupported file type.`);
306
306
  };
307
307
  var getFormData = () => new FormData();
308
308
 
@@ -321,7 +321,7 @@ const isFileValue = (value) => !!value &&
321
321
  function collectParams(params, inputKey, inputValue) {
322
322
  if (isFileValue(inputValue)) {
323
323
  const { name, contentType } = inputValue;
324
- const file = transformFile(inputValue.data, name, contentType); // lgtm [js/superfluous-trailing-arguments]
324
+ const file = transformFile(inputValue.data, name, contentType);
325
325
  const options = getFileOptions();
326
326
  params.push([inputKey, file, ...options]);
327
327
  }
@@ -441,28 +441,25 @@ function retryIfFailed(fn, options) {
441
441
  }
442
442
 
443
443
  const getContentType = (file) => {
444
+ let contentType = '';
444
445
  if (isBlob(file) || isFile(file) || isReactNativeAsset(file)) {
445
- return file.type || defaultContentType;
446
+ contentType = file.type;
446
447
  }
447
- if (isBuffer(file)) {
448
- return defaultFilename;
449
- }
450
- console.warn(`Unknown filename: ${file}. Using default filename: ${defaultFilename}`);
451
- return defaultFilename;
448
+ return contentType || defaultContentType;
452
449
  };
453
450
 
454
- const getFilename = (file) => {
455
- if (isBlob(file) || isBuffer(file)) {
456
- return defaultFilename;
451
+ const getFileName = (file) => {
452
+ let filename = '';
453
+ if (isFile(file) && file.name) {
454
+ filename = file.name;
457
455
  }
458
- if (isFile(file)) {
459
- return file.name || defaultFilename;
456
+ else if (isBlob(file) || isBuffer(file)) {
457
+ filename = '';
460
458
  }
461
- if (isReactNativeAsset(file)) {
462
- return file.name || defaultFilename;
459
+ else if (isReactNativeAsset(file) && file.name) {
460
+ filename = file.name;
463
461
  }
464
- console.warn(`Unknown file type: ${file}. Using default filename: ${defaultFilename}`);
465
- return defaultFilename;
462
+ return filename || defaultFilename;
466
463
  };
467
464
 
468
465
  function getStoreValue(store) {
@@ -485,7 +482,7 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
485
482
  data: buildFormData({
486
483
  file: {
487
484
  data: file,
488
- name: fileName || getFilename(file),
485
+ name: fileName || getFileName(file),
489
486
  contentType: contentType || getContentType(file)
490
487
  },
491
488
  UPLOADCARE_PUB_KEY: publicKey,
@@ -1220,7 +1217,7 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
1220
1217
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1221
1218
 
1222
1219
  const memo = new WeakMap();
1223
- const getReactNativeBlob = async (asset) => {
1220
+ const getBlobFromReactNativeAsset = async (asset) => {
1224
1221
  if (memo.has(asset)) {
1225
1222
  return memo.get(asset);
1226
1223
  }
@@ -1237,10 +1234,10 @@ const getFileSize = async (file) => {
1237
1234
  return file.size;
1238
1235
  }
1239
1236
  if (isReactNativeAsset(file)) {
1240
- const blob = await getReactNativeBlob(file);
1237
+ const blob = await getBlobFromReactNativeAsset(file);
1241
1238
  return blob.size;
1242
1239
  }
1243
- throw new Error(`Failed to get file size for file: ${file}`);
1240
+ throw new Error(`Unknown file type. Cannot determine file size.`);
1244
1241
  };
1245
1242
 
1246
1243
  /**
@@ -1261,7 +1258,7 @@ const isUuid = (data) => {
1261
1258
  /**
1262
1259
  * Url type guard.
1263
1260
  *
1264
- * @param {AnyFile | Url | Uuid} data
1261
+ * @param {SupportedFileInput | Url | Uuid} data
1265
1262
  */
1266
1263
  const isUrl = (data) => {
1267
1264
  const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
@@ -1323,7 +1320,7 @@ const sliceChunk = (file, index, fileSize, chunkSize) => {
1323
1320
  const prepareChunks = async (file, fileSize, chunkSize) => {
1324
1321
  let blob;
1325
1322
  if (isReactNativeAsset(file)) {
1326
- blob = await getReactNativeBlob(file);
1323
+ blob = await getBlobFromReactNativeAsset(file);
1327
1324
  }
1328
1325
  else {
1329
1326
  blob = file;
@@ -1343,7 +1340,7 @@ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, re
1343
1340
  retryNetworkErrorMaxTimes
1344
1341
  });
1345
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 }) => {
1346
- const size = fileSize || await getFileSize(file);
1343
+ const size = fileSize ?? (await getFileSize(file));
1347
1344
  let progressValues;
1348
1345
  const createProgressHandler = (totalChunks, chunkIdx) => {
1349
1346
  if (!onProgress)
@@ -1366,7 +1363,7 @@ const uploadMultipart = async (file, { publicKey, fileName, fileSize, baseURL, s
1366
1363
  return multipartStart(size, {
1367
1364
  publicKey,
1368
1365
  contentType: contentType || getContentType(file),
1369
- fileName: fileName || getFilename(file),
1366
+ fileName: fileName || getFileName(file),
1370
1367
  baseURL,
1371
1368
  secureSignature,
1372
1369
  secureExpire,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uploadcare/upload-client",
3
- "version": "6.0.1-alpha.9",
3
+ "version": "6.1.0-alpha.1",
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",