@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 +42 -6
- package/dist/index.browser.js +28 -22
- package/dist/index.d.ts +43 -45
- package/dist/index.node.js +28 -22
- package/dist/index.react-native.js +28 -23
- package/package.json +3 -3
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:
|
|
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:
|
|
162
|
+
data: Blob | File | Buffer | ReactNativeAsset | Url | Uuid,
|
|
162
163
|
options: FileFromOptions
|
|
163
164
|
): Promise<UploadcareFile>
|
|
164
165
|
|
|
165
166
|
uploadFileGroup(
|
|
166
|
-
data: (
|
|
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:
|
|
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
|
|
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
|
package/dist/index.browser.js
CHANGED
|
@@ -269,7 +269,8 @@ const request = ({ method, url, data, headers = {}, signal, onProgress }) => new
|
|
|
269
269
|
}
|
|
270
270
|
});
|
|
271
271
|
|
|
272
|
-
|
|
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);
|
|
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
|
-
|
|
438
|
+
contentType = file.type;
|
|
437
439
|
}
|
|
438
|
-
if (
|
|
439
|
-
return
|
|
440
|
+
if (contentType) {
|
|
441
|
+
return contentType;
|
|
440
442
|
}
|
|
441
|
-
console.warn(`
|
|
442
|
-
return
|
|
443
|
+
console.warn(`Cannot determine content type. Using default content type: ${defaultContentType}`, file);
|
|
444
|
+
return defaultContentType;
|
|
443
445
|
};
|
|
444
446
|
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
447
|
+
const getFileName = (file) => {
|
|
448
|
+
let filename = '';
|
|
449
|
+
if (isFile(file) && file.name) {
|
|
450
|
+
filename = file.name;
|
|
448
451
|
}
|
|
449
|
-
if (
|
|
450
|
-
|
|
452
|
+
else if (isBlob(file) || isBuffer(file)) {
|
|
453
|
+
filename = '';
|
|
451
454
|
}
|
|
452
|
-
if (isReactNativeAsset(file)) {
|
|
453
|
-
|
|
455
|
+
else if (isReactNativeAsset(file) && file.name) {
|
|
456
|
+
filename = file.name;
|
|
457
|
+
}
|
|
458
|
+
if (filename) {
|
|
459
|
+
return filename;
|
|
454
460
|
}
|
|
455
|
-
console.warn(`
|
|
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 ||
|
|
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
|
|
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
|
|
1237
|
+
const blob = await getBlobFromReactNativeAsset(file);
|
|
1232
1238
|
return blob.size;
|
|
1233
1239
|
}
|
|
1234
|
-
throw new Error(`
|
|
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 {
|
|
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
|
|
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 ||
|
|
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
|
|
108
|
-
export declare type
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
486
|
+
multipartUpload(part: Sliceable, url: MultipartPart, options?: Partial<MultipartUploadOptions>): Promise<MultipartUploadResponse>;
|
|
489
487
|
multipartComplete(uuid: Uuid, options?: Partial<MultipartCompleteOptions>): Promise<FileInfo>;
|
|
490
|
-
uploadFile(data:
|
|
491
|
-
uploadFileGroup(data:
|
|
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 |
|
|
498
|
+
data?: NodeFormData | FormData | SupportedFileInput;
|
|
501
499
|
headers?: Headers;
|
|
502
500
|
};
|
|
503
501
|
export declare type ErrorResponseInfo = {
|
package/dist/index.node.js
CHANGED
|
@@ -288,7 +288,8 @@ const request = (params) => {
|
|
|
288
288
|
}));
|
|
289
289
|
};
|
|
290
290
|
|
|
291
|
-
|
|
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);
|
|
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
|
-
|
|
466
|
+
contentType = file.type;
|
|
465
467
|
}
|
|
466
|
-
if (
|
|
467
|
-
return
|
|
468
|
+
if (contentType) {
|
|
469
|
+
return contentType;
|
|
468
470
|
}
|
|
469
|
-
console.warn(`
|
|
470
|
-
return
|
|
471
|
+
console.warn(`Cannot determine content type. Using default content type: ${defaultContentType}`, file);
|
|
472
|
+
return defaultContentType;
|
|
471
473
|
};
|
|
472
474
|
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
475
|
+
const getFileName = (file) => {
|
|
476
|
+
let filename = '';
|
|
477
|
+
if (isFile(file) && file.name) {
|
|
478
|
+
filename = file.name;
|
|
476
479
|
}
|
|
477
|
-
if (
|
|
478
|
-
|
|
480
|
+
else if (isBlob(file) || isBuffer(file)) {
|
|
481
|
+
filename = '';
|
|
479
482
|
}
|
|
480
|
-
if (isReactNativeAsset(file)) {
|
|
481
|
-
|
|
483
|
+
else if (isReactNativeAsset(file) && file.name) {
|
|
484
|
+
filename = file.name;
|
|
485
|
+
}
|
|
486
|
+
if (filename) {
|
|
487
|
+
return filename;
|
|
482
488
|
}
|
|
483
|
-
console.warn(`
|
|
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 ||
|
|
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
|
|
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
|
|
1263
|
+
const blob = await getBlobFromReactNativeAsset(file);
|
|
1258
1264
|
return blob.size;
|
|
1259
1265
|
}
|
|
1260
|
-
throw new Error(`
|
|
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 {
|
|
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
|
|
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 ||
|
|
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
|
|
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);
|
|
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
|
-
|
|
446
|
+
contentType = file.type;
|
|
446
447
|
}
|
|
447
|
-
if (
|
|
448
|
-
return
|
|
448
|
+
if (contentType) {
|
|
449
|
+
return contentType;
|
|
449
450
|
}
|
|
450
|
-
console.warn(`
|
|
451
|
-
return
|
|
451
|
+
console.warn(`Cannot determine content type. Using default content type: ${defaultContentType}`, file);
|
|
452
|
+
return defaultContentType;
|
|
452
453
|
};
|
|
453
454
|
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
455
|
+
const getFileName = (file) => {
|
|
456
|
+
let filename = '';
|
|
457
|
+
if (isFile(file) && file.name) {
|
|
458
|
+
filename = file.name;
|
|
457
459
|
}
|
|
458
|
-
if (
|
|
459
|
-
|
|
460
|
+
else if (isBlob(file) || isBuffer(file)) {
|
|
461
|
+
filename = '';
|
|
460
462
|
}
|
|
461
|
-
if (isReactNativeAsset(file)) {
|
|
462
|
-
|
|
463
|
+
else if (isReactNativeAsset(file) && file.name) {
|
|
464
|
+
filename = file.name;
|
|
465
|
+
}
|
|
466
|
+
if (filename) {
|
|
467
|
+
return filename;
|
|
463
468
|
}
|
|
464
|
-
console.warn(`
|
|
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 ||
|
|
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
|
|
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
|
|
1245
|
+
const blob = await getBlobFromReactNativeAsset(file);
|
|
1241
1246
|
return blob.size;
|
|
1242
1247
|
}
|
|
1243
|
-
throw new Error(`
|
|
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 {
|
|
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
|
|
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
|
|
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 ||
|
|
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
|
|
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": "
|
|
75
|
-
"jest-websocket-mock": "2.
|
|
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",
|