@uploadcare/upload-client 6.0.1-alpha.9 → 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 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,27 +433,32 @@ 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
+ if (contentType) {
441
+ return contentType;
440
442
  }
441
- console.warn(`Unknown filename: ${file}. Using default filename: ${defaultFilename}`);
442
- return defaultFilename;
443
+ console.warn(`Cannot determine content type. Using default content type: ${defaultContentType}`, file);
444
+ return defaultContentType;
443
445
  };
444
446
 
445
- const getFilename = (file) => {
446
- if (isBlob(file) || isBuffer(file)) {
447
- return defaultFilename;
447
+ const getFileName = (file) => {
448
+ let filename = '';
449
+ if (isFile(file) && file.name) {
450
+ filename = file.name;
448
451
  }
449
- if (isFile(file)) {
450
- return file.name || defaultFilename;
452
+ else if (isBlob(file) || isBuffer(file)) {
453
+ filename = '';
451
454
  }
452
- if (isReactNativeAsset(file)) {
453
- return file.name || defaultFilename;
455
+ else if (isReactNativeAsset(file) && file.name) {
456
+ filename = file.name;
457
+ }
458
+ if (filename) {
459
+ return filename;
454
460
  }
455
- console.warn(`Unknown file type: ${file}. Using default filename: ${defaultFilename}`);
461
+ console.warn(`Cannot determine filename. Using default filename: ${defaultFilename}`, file);
456
462
  return defaultFilename;
457
463
  };
458
464
 
@@ -476,7 +482,7 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
476
482
  data: buildFormData({
477
483
  file: {
478
484
  data: file,
479
- name: fileName || getFilename(file),
485
+ name: fileName || getFileName(file),
480
486
  contentType: contentType || getContentType(file)
481
487
  },
482
488
  UPLOADCARE_PUB_KEY: publicKey,
@@ -1211,7 +1217,7 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
1211
1217
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1212
1218
 
1213
1219
  const memo = new WeakMap();
1214
- const getReactNativeBlob = async (asset) => {
1220
+ const getBlobFromReactNativeAsset = async (asset) => {
1215
1221
  if (memo.has(asset)) {
1216
1222
  return memo.get(asset);
1217
1223
  }
@@ -1228,10 +1234,10 @@ const getFileSize = async (file) => {
1228
1234
  return file.size;
1229
1235
  }
1230
1236
  if (isReactNativeAsset(file)) {
1231
- const blob = await getReactNativeBlob(file);
1237
+ const blob = await getBlobFromReactNativeAsset(file);
1232
1238
  return blob.size;
1233
1239
  }
1234
- throw new Error(`Failed to get file size for file: ${file}`);
1240
+ throw new Error(`Unknown file type. Cannot determine file size.`);
1235
1241
  };
1236
1242
 
1237
1243
  /**
@@ -1252,7 +1258,7 @@ const isUuid = (data) => {
1252
1258
  /**
1253
1259
  * Url type guard.
1254
1260
  *
1255
- * @param {AnyFile | Url | Uuid} data
1261
+ * @param {SupportedFileInput | Url | Uuid} data
1256
1262
  */
1257
1263
  const isUrl = (data) => {
1258
1264
  const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
@@ -1314,7 +1320,7 @@ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, re
1314
1320
  retryNetworkErrorMaxTimes
1315
1321
  });
1316
1322
  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);
1323
+ const size = fileSize ?? (await getFileSize(file));
1318
1324
  let progressValues;
1319
1325
  const createProgressHandler = (totalChunks, chunkIdx) => {
1320
1326
  if (!onProgress)
@@ -1337,7 +1343,7 @@ const uploadMultipart = async (file, { publicKey, fileName, fileSize, baseURL, s
1337
1343
  return multipartStart(size, {
1338
1344
  publicKey,
1339
1345
  contentType: contentType || getContentType(file),
1340
- fileName: fileName || getFilename(file),
1346
+ fileName: fileName || getFileName(file),
1341
1347
  baseURL,
1342
1348
  secureSignature,
1343
1349
  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,27 +461,32 @@ 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
+ if (contentType) {
469
+ return contentType;
468
470
  }
469
- console.warn(`Unknown filename: ${file}. Using default filename: ${defaultFilename}`);
470
- return defaultFilename;
471
+ console.warn(`Cannot determine content type. Using default content type: ${defaultContentType}`, file);
472
+ return defaultContentType;
471
473
  };
472
474
 
473
- const getFilename = (file) => {
474
- if (isBlob(file) || isBuffer(file)) {
475
- return defaultFilename;
475
+ const getFileName = (file) => {
476
+ let filename = '';
477
+ if (isFile(file) && file.name) {
478
+ filename = file.name;
476
479
  }
477
- if (isFile(file)) {
478
- return file.name || defaultFilename;
480
+ else if (isBlob(file) || isBuffer(file)) {
481
+ filename = '';
479
482
  }
480
- if (isReactNativeAsset(file)) {
481
- return file.name || defaultFilename;
483
+ else if (isReactNativeAsset(file) && file.name) {
484
+ filename = file.name;
485
+ }
486
+ if (filename) {
487
+ return filename;
482
488
  }
483
- console.warn(`Unknown file type: ${file}. Using default filename: ${defaultFilename}`);
489
+ console.warn(`Cannot determine filename. Using default filename: ${defaultFilename}`, file);
484
490
  return defaultFilename;
485
491
  };
486
492
 
@@ -504,7 +510,7 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
504
510
  data: buildFormData({
505
511
  file: {
506
512
  data: file,
507
- name: fileName || getFilename(file),
513
+ name: fileName || getFileName(file),
508
514
  contentType: contentType || getContentType(file)
509
515
  },
510
516
  UPLOADCARE_PUB_KEY: publicKey,
@@ -1237,7 +1243,7 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
1237
1243
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1238
1244
 
1239
1245
  const memo = new WeakMap();
1240
- const getReactNativeBlob = async (asset) => {
1246
+ const getBlobFromReactNativeAsset = async (asset) => {
1241
1247
  if (memo.has(asset)) {
1242
1248
  return memo.get(asset);
1243
1249
  }
@@ -1254,10 +1260,10 @@ const getFileSize = async (file) => {
1254
1260
  return file.size;
1255
1261
  }
1256
1262
  if (isReactNativeAsset(file)) {
1257
- const blob = await getReactNativeBlob(file);
1263
+ const blob = await getBlobFromReactNativeAsset(file);
1258
1264
  return blob.size;
1259
1265
  }
1260
- throw new Error(`Failed to get file size for file: ${file}`);
1266
+ throw new Error(`Unknown file type. Cannot determine file size.`);
1261
1267
  };
1262
1268
 
1263
1269
  /**
@@ -1278,7 +1284,7 @@ const isUuid = (data) => {
1278
1284
  /**
1279
1285
  * Url type guard.
1280
1286
  *
1281
- * @param {AnyFile | Url | Uuid} data
1287
+ * @param {SupportedFileInput | Url | Uuid} data
1282
1288
  */
1283
1289
  const isUrl = (data) => {
1284
1290
  const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
@@ -1340,7 +1346,7 @@ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, re
1340
1346
  retryNetworkErrorMaxTimes
1341
1347
  });
1342
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 }) => {
1343
- const size = fileSize || await getFileSize(file);
1349
+ const size = fileSize ?? (await getFileSize(file));
1344
1350
  let progressValues;
1345
1351
  const createProgressHandler = (totalChunks, chunkIdx) => {
1346
1352
  if (!onProgress)
@@ -1363,7 +1369,7 @@ const uploadMultipart = async (file, { publicKey, fileName, fileSize, baseURL, s
1363
1369
  return multipartStart(size, {
1364
1370
  publicKey,
1365
1371
  contentType: contentType || getContentType(file),
1366
- fileName: fileName || getFilename(file),
1372
+ fileName: fileName || getFileName(file),
1367
1373
  baseURL,
1368
1374
  secureSignature,
1369
1375
  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,27 +441,32 @@ 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;
448
+ if (contentType) {
449
+ return contentType;
449
450
  }
450
- console.warn(`Unknown filename: ${file}. Using default filename: ${defaultFilename}`);
451
- return defaultFilename;
451
+ console.warn(`Cannot determine content type. Using default content type: ${defaultContentType}`, file);
452
+ return defaultContentType;
452
453
  };
453
454
 
454
- const getFilename = (file) => {
455
- if (isBlob(file) || isBuffer(file)) {
456
- return defaultFilename;
455
+ const getFileName = (file) => {
456
+ let filename = '';
457
+ if (isFile(file) && file.name) {
458
+ filename = file.name;
457
459
  }
458
- if (isFile(file)) {
459
- return file.name || defaultFilename;
460
+ else if (isBlob(file) || isBuffer(file)) {
461
+ filename = '';
460
462
  }
461
- if (isReactNativeAsset(file)) {
462
- return file.name || defaultFilename;
463
+ else if (isReactNativeAsset(file) && file.name) {
464
+ filename = file.name;
465
+ }
466
+ if (filename) {
467
+ return filename;
463
468
  }
464
- console.warn(`Unknown file type: ${file}. Using default filename: ${defaultFilename}`);
469
+ console.warn(`Cannot determine filename. Using default filename: ${defaultFilename}`, file);
465
470
  return defaultFilename;
466
471
  };
467
472
 
@@ -485,7 +490,7 @@ function base(file, { publicKey, fileName, contentType, baseURL = defaultSetting
485
490
  data: buildFormData({
486
491
  file: {
487
492
  data: file,
488
- name: fileName || getFilename(file),
493
+ name: fileName || getFileName(file),
489
494
  contentType: contentType || getContentType(file)
490
495
  },
491
496
  UPLOADCARE_PUB_KEY: publicKey,
@@ -1220,7 +1225,7 @@ const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, check
1220
1225
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1221
1226
 
1222
1227
  const memo = new WeakMap();
1223
- const getReactNativeBlob = async (asset) => {
1228
+ const getBlobFromReactNativeAsset = async (asset) => {
1224
1229
  if (memo.has(asset)) {
1225
1230
  return memo.get(asset);
1226
1231
  }
@@ -1237,10 +1242,10 @@ const getFileSize = async (file) => {
1237
1242
  return file.size;
1238
1243
  }
1239
1244
  if (isReactNativeAsset(file)) {
1240
- const blob = await getReactNativeBlob(file);
1245
+ const blob = await getBlobFromReactNativeAsset(file);
1241
1246
  return blob.size;
1242
1247
  }
1243
- throw new Error(`Failed to get file size for file: ${file}`);
1248
+ throw new Error(`Unknown file type. Cannot determine file size.`);
1244
1249
  };
1245
1250
 
1246
1251
  /**
@@ -1261,7 +1266,7 @@ const isUuid = (data) => {
1261
1266
  /**
1262
1267
  * Url type guard.
1263
1268
  *
1264
- * @param {AnyFile | Url | Uuid} data
1269
+ * @param {SupportedFileInput | Url | Uuid} data
1265
1270
  */
1266
1271
  const isUrl = (data) => {
1267
1272
  const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
@@ -1323,7 +1328,7 @@ const sliceChunk = (file, index, fileSize, chunkSize) => {
1323
1328
  const prepareChunks = async (file, fileSize, chunkSize) => {
1324
1329
  let blob;
1325
1330
  if (isReactNativeAsset(file)) {
1326
- blob = await getReactNativeBlob(file);
1331
+ blob = await getBlobFromReactNativeAsset(file);
1327
1332
  }
1328
1333
  else {
1329
1334
  blob = file;
@@ -1343,7 +1348,7 @@ const uploadPart = (chunk, url, { publicKey, onProgress, signal, integration, re
1343
1348
  retryNetworkErrorMaxTimes
1344
1349
  });
1345
1350
  const uploadMultipart = async (file, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, retryNetworkErrorMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, maxConcurrentRequests = defaultSettings.maxConcurrentRequests, baseCDN, metadata }) => {
1346
- const size = fileSize || await getFileSize(file);
1351
+ const size = fileSize ?? (await getFileSize(file));
1347
1352
  let progressValues;
1348
1353
  const createProgressHandler = (totalChunks, chunkIdx) => {
1349
1354
  if (!onProgress)
@@ -1366,7 +1371,7 @@ const uploadMultipart = async (file, { publicKey, fileName, fileSize, baseURL, s
1366
1371
  return multipartStart(size, {
1367
1372
  publicKey,
1368
1373
  contentType: contentType || getContentType(file),
1369
- fileName: fileName || getFilename(file),
1374
+ fileName: fileName || getFileName(file),
1370
1375
  baseURL,
1371
1376
  secureSignature,
1372
1377
  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.0",
4
4
  "description": "Library for work with Uploadcare Upload API",
5
5
  "type": "module",
6
6
  "module": "./dist/index.node.js",
@@ -71,8 +71,8 @@
71
71
  "@types/ws": "8.5.3",
72
72
  "data-uri-to-buffer": "3.0.1",
73
73
  "dataurl-to-blob": "0.0.1",
74
- "jest-environment-jsdom": "28.1.0",
75
- "jest-websocket-mock": "2.3.0",
74
+ "jest-environment-jsdom": "29.3.1",
75
+ "jest-websocket-mock": "2.4.0",
76
76
  "koa": "2.13.4",
77
77
  "koa-add-trailing-slashes": "2.0.1",
78
78
  "koa-body": "5.0.0",