@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 +42 -6
- package/dist/index.browser.js +22 -24
- package/dist/index.d.ts +43 -45
- package/dist/index.node.js +22 -24
- package/dist/index.react-native.js +22 -25
- 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,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
|
-
|
|
438
|
+
contentType = file.type;
|
|
437
439
|
}
|
|
438
|
-
|
|
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
|
|
446
|
-
|
|
447
|
-
|
|
443
|
+
const getFileName = (file) => {
|
|
444
|
+
let filename = '';
|
|
445
|
+
if (isFile(file) && file.name) {
|
|
446
|
+
filename = file.name;
|
|
448
447
|
}
|
|
449
|
-
if (
|
|
450
|
-
|
|
448
|
+
else if (isBlob(file) || isBuffer(file)) {
|
|
449
|
+
filename = '';
|
|
451
450
|
}
|
|
452
|
-
if (isReactNativeAsset(file)) {
|
|
453
|
-
|
|
451
|
+
else if (isReactNativeAsset(file) && file.name) {
|
|
452
|
+
filename = file.name;
|
|
454
453
|
}
|
|
455
|
-
|
|
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 ||
|
|
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
|
|
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
|
|
1229
|
+
const blob = await getBlobFromReactNativeAsset(file);
|
|
1232
1230
|
return blob.size;
|
|
1233
1231
|
}
|
|
1234
|
-
throw new Error(`
|
|
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 {
|
|
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
|
|
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 ||
|
|
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
|
|
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,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
|
-
|
|
466
|
+
contentType = file.type;
|
|
465
467
|
}
|
|
466
|
-
|
|
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
|
|
474
|
-
|
|
475
|
-
|
|
471
|
+
const getFileName = (file) => {
|
|
472
|
+
let filename = '';
|
|
473
|
+
if (isFile(file) && file.name) {
|
|
474
|
+
filename = file.name;
|
|
476
475
|
}
|
|
477
|
-
if (
|
|
478
|
-
|
|
476
|
+
else if (isBlob(file) || isBuffer(file)) {
|
|
477
|
+
filename = '';
|
|
479
478
|
}
|
|
480
|
-
if (isReactNativeAsset(file)) {
|
|
481
|
-
|
|
479
|
+
else if (isReactNativeAsset(file) && file.name) {
|
|
480
|
+
filename = file.name;
|
|
482
481
|
}
|
|
483
|
-
|
|
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 ||
|
|
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
|
|
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
|
|
1255
|
+
const blob = await getBlobFromReactNativeAsset(file);
|
|
1258
1256
|
return blob.size;
|
|
1259
1257
|
}
|
|
1260
|
-
throw new Error(`
|
|
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 {
|
|
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
|
|
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 ||
|
|
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
|
|
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,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
|
-
|
|
446
|
+
contentType = file.type;
|
|
446
447
|
}
|
|
447
|
-
|
|
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
|
|
455
|
-
|
|
456
|
-
|
|
451
|
+
const getFileName = (file) => {
|
|
452
|
+
let filename = '';
|
|
453
|
+
if (isFile(file) && file.name) {
|
|
454
|
+
filename = file.name;
|
|
457
455
|
}
|
|
458
|
-
if (
|
|
459
|
-
|
|
456
|
+
else if (isBlob(file) || isBuffer(file)) {
|
|
457
|
+
filename = '';
|
|
460
458
|
}
|
|
461
|
-
if (isReactNativeAsset(file)) {
|
|
462
|
-
|
|
459
|
+
else if (isReactNativeAsset(file) && file.name) {
|
|
460
|
+
filename = file.name;
|
|
463
461
|
}
|
|
464
|
-
|
|
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 ||
|
|
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
|
|
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
|
|
1237
|
+
const blob = await getBlobFromReactNativeAsset(file);
|
|
1241
1238
|
return blob.size;
|
|
1242
1239
|
}
|
|
1243
|
-
throw new Error(`
|
|
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 {
|
|
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
|
|
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
|
|
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 ||
|
|
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
|
|
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": "
|
|
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",
|