@uploadcare/upload-client 3.1.0 → 4.0.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 +5 -3
- package/dist/index.browser.js +1441 -1451
- package/dist/{index.js → index.node.js} +1468 -1463
- package/dist/index.react-native.js +1546 -0
- package/dist/types.d.ts +47 -37
- package/package.json +30 -37
- package/dist/index.browser.cjs +0 -1743
- package/dist/index.cjs +0 -1775
|
@@ -3,1555 +3,1560 @@ import https from 'https';
|
|
|
3
3
|
import { parse } from 'url';
|
|
4
4
|
import { Transform, Readable } from 'stream';
|
|
5
5
|
import NodeFormData from 'form-data';
|
|
6
|
-
import { AbortController } from 'abort-controller';
|
|
7
|
-
export { AbortController } from 'abort-controller';
|
|
8
6
|
import WebSocket from 'ws';
|
|
9
7
|
|
|
10
|
-
class UploadClientError extends Error {
|
|
11
|
-
constructor(message, code, request, response, headers) {
|
|
12
|
-
super();
|
|
13
|
-
this.name = 'UploadClientError';
|
|
14
|
-
this.message = message;
|
|
15
|
-
this.code = code;
|
|
16
|
-
this.request = request;
|
|
17
|
-
this.response = response;
|
|
18
|
-
this.headers = headers;
|
|
19
|
-
Object.setPrototypeOf(this, UploadClientError.prototype);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
const cancelError = (message = 'Request canceled') => {
|
|
23
|
-
const error = new UploadClientError(message);
|
|
24
|
-
error.isCancel = true;
|
|
25
|
-
return error;
|
|
8
|
+
class UploadClientError extends Error {
|
|
9
|
+
constructor(message, code, request, response, headers) {
|
|
10
|
+
super();
|
|
11
|
+
this.name = 'UploadClientError';
|
|
12
|
+
this.message = message;
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.request = request;
|
|
15
|
+
this.response = response;
|
|
16
|
+
this.headers = headers;
|
|
17
|
+
Object.setPrototypeOf(this, UploadClientError.prototype);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const cancelError = (message = 'Request canceled') => {
|
|
21
|
+
const error = new UploadClientError(message);
|
|
22
|
+
error.isCancel = true;
|
|
23
|
+
return error;
|
|
26
24
|
};
|
|
27
25
|
|
|
28
|
-
const onCancel = (signal, callback) => {
|
|
29
|
-
if (signal) {
|
|
30
|
-
if (signal.aborted) {
|
|
31
|
-
Promise.resolve().then(callback);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
signal.addEventListener('abort', () => callback(), { once: true });
|
|
35
|
-
}
|
|
36
|
-
}
|
|
26
|
+
const onCancel = (signal, callback) => {
|
|
27
|
+
if (signal) {
|
|
28
|
+
if (signal.aborted) {
|
|
29
|
+
Promise.resolve().then(callback);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
signal.addEventListener('abort', () => callback(), { once: true });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
37
35
|
};
|
|
38
36
|
|
|
39
|
-
// ProgressEmitter is a simple PassThrough-style transform stream which keeps
|
|
40
|
-
// track of the number of bytes which have been piped through it and will
|
|
41
|
-
// invoke the `onprogress` function whenever new number are available.
|
|
42
|
-
class ProgressEmitter extends Transform {
|
|
43
|
-
constructor(onProgress, size) {
|
|
44
|
-
super();
|
|
45
|
-
this._onprogress = onProgress;
|
|
46
|
-
this._position = 0;
|
|
47
|
-
this.size = size;
|
|
48
|
-
}
|
|
49
|
-
_transform(chunk, encoding, callback) {
|
|
50
|
-
this._position += chunk.length;
|
|
51
|
-
this._onprogress({
|
|
52
|
-
isComputable: true,
|
|
53
|
-
value: this._position / this.size
|
|
54
|
-
});
|
|
55
|
-
callback(null, chunk);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
const getLength = (formData) => new Promise((resolve, reject) => {
|
|
59
|
-
formData.getLength((error, length) => {
|
|
60
|
-
if (error)
|
|
61
|
-
reject(error);
|
|
62
|
-
else
|
|
63
|
-
resolve(length);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
function isFormData(formData) {
|
|
67
|
-
if (formData && formData.toString() === '[object FormData]') {
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
function isReadable(data, isFormData) {
|
|
73
|
-
if (data && (data instanceof Readable || isFormData)) {
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
const request = (params) => {
|
|
79
|
-
const { method = 'GET', url, data, headers = {}, signal, onProgress } = params;
|
|
80
|
-
return Promise.resolve()
|
|
81
|
-
.then(() => {
|
|
82
|
-
if (isFormData(data)) {
|
|
83
|
-
return getLength(data);
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
.then((length) => new Promise((resolve, reject) => {
|
|
90
|
-
const isFormData = !!length;
|
|
91
|
-
let aborted = false;
|
|
92
|
-
const options = parse(url);
|
|
93
|
-
options.method = method;
|
|
94
|
-
options.headers = isFormData
|
|
95
|
-
? Object.assign(data.getHeaders(), headers)
|
|
96
|
-
: headers;
|
|
97
|
-
if (isFormData || (data && data.length)) {
|
|
98
|
-
options.headers['Content-Length'] =
|
|
99
|
-
length || data.length;
|
|
100
|
-
}
|
|
101
|
-
const req = options.protocol !== 'https:'
|
|
102
|
-
? http.request(options)
|
|
103
|
-
: https.request(options);
|
|
104
|
-
onCancel(signal, () => {
|
|
105
|
-
aborted = true;
|
|
106
|
-
req.abort();
|
|
107
|
-
reject(cancelError());
|
|
108
|
-
});
|
|
109
|
-
req.on('response', (res) => {
|
|
110
|
-
if (aborted)
|
|
111
|
-
return;
|
|
112
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
|
-
const resChunks = [];
|
|
114
|
-
res.on('data', (data) => {
|
|
115
|
-
resChunks.push(data);
|
|
116
|
-
});
|
|
117
|
-
res.on('end', () => resolve({
|
|
118
|
-
data: Buffer.concat(resChunks).toString('utf8'),
|
|
119
|
-
status: res.statusCode,
|
|
120
|
-
headers: res.headers,
|
|
121
|
-
request: params
|
|
122
|
-
}));
|
|
123
|
-
});
|
|
124
|
-
req.on('error', (err) => {
|
|
125
|
-
if (aborted)
|
|
126
|
-
return;
|
|
127
|
-
reject(err);
|
|
128
|
-
});
|
|
129
|
-
if (isReadable(data, isFormData)) {
|
|
130
|
-
if (onProgress && length) {
|
|
131
|
-
data.pipe(new ProgressEmitter(onProgress, length)).pipe(req);
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
data.pipe(req);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
req.end(data);
|
|
139
|
-
}
|
|
140
|
-
}));
|
|
37
|
+
// ProgressEmitter is a simple PassThrough-style transform stream which keeps
|
|
38
|
+
// track of the number of bytes which have been piped through it and will
|
|
39
|
+
// invoke the `onprogress` function whenever new number are available.
|
|
40
|
+
class ProgressEmitter extends Transform {
|
|
41
|
+
constructor(onProgress, size) {
|
|
42
|
+
super();
|
|
43
|
+
this._onprogress = onProgress;
|
|
44
|
+
this._position = 0;
|
|
45
|
+
this.size = size;
|
|
46
|
+
}
|
|
47
|
+
_transform(chunk, encoding, callback) {
|
|
48
|
+
this._position += chunk.length;
|
|
49
|
+
this._onprogress({
|
|
50
|
+
isComputable: true,
|
|
51
|
+
value: this._position / this.size
|
|
52
|
+
});
|
|
53
|
+
callback(null, chunk);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const getLength = (formData) => new Promise((resolve, reject) => {
|
|
57
|
+
formData.getLength((error, length) => {
|
|
58
|
+
if (error)
|
|
59
|
+
reject(error);
|
|
60
|
+
else
|
|
61
|
+
resolve(length);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
function isFormData(formData) {
|
|
65
|
+
if (formData && formData.toString() === '[object FormData]') {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
function isReadable(data, isFormData) {
|
|
71
|
+
if (data && (data instanceof Readable || isFormData)) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const request = (params) => {
|
|
77
|
+
const { method = 'GET', url, data, headers = {}, signal, onProgress } = params;
|
|
78
|
+
return Promise.resolve()
|
|
79
|
+
.then(() => {
|
|
80
|
+
if (isFormData(data)) {
|
|
81
|
+
return getLength(data);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
.then((length) => new Promise((resolve, reject) => {
|
|
88
|
+
const isFormData = !!length;
|
|
89
|
+
let aborted = false;
|
|
90
|
+
const options = parse(url);
|
|
91
|
+
options.method = method;
|
|
92
|
+
options.headers = isFormData
|
|
93
|
+
? Object.assign(data.getHeaders(), headers)
|
|
94
|
+
: headers;
|
|
95
|
+
if (isFormData || (data && data.length)) {
|
|
96
|
+
options.headers['Content-Length'] =
|
|
97
|
+
length || data.length;
|
|
98
|
+
}
|
|
99
|
+
const req = options.protocol !== 'https:'
|
|
100
|
+
? http.request(options)
|
|
101
|
+
: https.request(options);
|
|
102
|
+
onCancel(signal, () => {
|
|
103
|
+
aborted = true;
|
|
104
|
+
req.abort();
|
|
105
|
+
reject(cancelError());
|
|
106
|
+
});
|
|
107
|
+
req.on('response', (res) => {
|
|
108
|
+
if (aborted)
|
|
109
|
+
return;
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
|
+
const resChunks = [];
|
|
112
|
+
res.on('data', (data) => {
|
|
113
|
+
resChunks.push(data);
|
|
114
|
+
});
|
|
115
|
+
res.on('end', () => resolve({
|
|
116
|
+
data: Buffer.concat(resChunks).toString('utf8'),
|
|
117
|
+
status: res.statusCode,
|
|
118
|
+
headers: res.headers,
|
|
119
|
+
request: params
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
req.on('error', (err) => {
|
|
123
|
+
if (aborted)
|
|
124
|
+
return;
|
|
125
|
+
reject(err);
|
|
126
|
+
});
|
|
127
|
+
if (isReadable(data, isFormData)) {
|
|
128
|
+
if (onProgress && length) {
|
|
129
|
+
data.pipe(new ProgressEmitter(onProgress, length)).pipe(req);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
data.pipe(req);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
req.end(data);
|
|
137
|
+
}
|
|
138
|
+
}));
|
|
141
139
|
};
|
|
142
140
|
|
|
143
|
-
function identity(obj) {
|
|
144
|
-
return obj;
|
|
141
|
+
function identity(obj) {
|
|
142
|
+
return obj;
|
|
145
143
|
}
|
|
146
144
|
|
|
147
|
-
|
|
145
|
+
// node form-data has another append signature
|
|
146
|
+
// see docs at https://www.npmjs.com/package/formdata-node
|
|
147
|
+
const getFileOptions = ({ name, contentType }) => [
|
|
148
|
+
Object.entries({
|
|
149
|
+
filename: name,
|
|
150
|
+
contentType
|
|
151
|
+
})
|
|
152
|
+
.filter(([, value]) => !!value)
|
|
153
|
+
.reduce((acc, [key, value]) => (Object.assign(Object.assign({}, acc), { [key]: value })), {})
|
|
154
|
+
].filter((value) => !!value);
|
|
155
|
+
const transformFile = identity;
|
|
148
156
|
var getFormData = () => new NodeFormData();
|
|
149
157
|
|
|
150
|
-
/**
|
|
151
|
-
* FileData type guard.
|
|
152
|
-
*/
|
|
153
|
-
const isFileData = (data) => {
|
|
154
|
-
return (data !== undefined &&
|
|
155
|
-
((typeof Blob !== 'undefined' && data instanceof Blob) ||
|
|
156
|
-
(typeof File !== 'undefined' && data instanceof File) ||
|
|
157
|
-
(typeof Buffer !== 'undefined' && data instanceof Buffer)));
|
|
158
|
-
};
|
|
159
|
-
/**
|
|
160
|
-
* Uuid type guard.
|
|
161
|
-
*/
|
|
162
|
-
const isUuid = (data) => {
|
|
163
|
-
const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
|
|
164
|
-
const regExp = new RegExp(UUID_REGEX);
|
|
165
|
-
return !isFileData(data) && regExp.test(data);
|
|
166
|
-
};
|
|
167
|
-
/**
|
|
168
|
-
* Url type guard.
|
|
169
|
-
*
|
|
170
|
-
* @param {NodeFile | BrowserFile | Url | Uuid} data
|
|
171
|
-
*/
|
|
172
|
-
const isUrl = (data) => {
|
|
173
|
-
const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
|
|
174
|
-
const regExp = new RegExp(URL_REGEX);
|
|
175
|
-
return !isFileData(data) && regExp.test(data);
|
|
158
|
+
/**
|
|
159
|
+
* FileData type guard.
|
|
160
|
+
*/
|
|
161
|
+
const isFileData = (data) => {
|
|
162
|
+
return (data !== undefined &&
|
|
163
|
+
((typeof Blob !== 'undefined' && data instanceof Blob) ||
|
|
164
|
+
(typeof File !== 'undefined' && data instanceof File) ||
|
|
165
|
+
(typeof Buffer !== 'undefined' && data instanceof Buffer)));
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Uuid type guard.
|
|
169
|
+
*/
|
|
170
|
+
const isUuid = (data) => {
|
|
171
|
+
const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
|
|
172
|
+
const regExp = new RegExp(UUID_REGEX);
|
|
173
|
+
return !isFileData(data) && regExp.test(data);
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Url type guard.
|
|
177
|
+
*
|
|
178
|
+
* @param {NodeFile | BrowserFile | Url | Uuid} data
|
|
179
|
+
*/
|
|
180
|
+
const isUrl = (data) => {
|
|
181
|
+
const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
|
|
182
|
+
const regExp = new RegExp(URL_REGEX);
|
|
183
|
+
return !isFileData(data) && regExp.test(data);
|
|
176
184
|
};
|
|
177
185
|
|
|
178
|
-
const isSimpleValue = (value) => {
|
|
179
|
-
return (typeof value === 'string' ||
|
|
180
|
-
typeof value === 'number' ||
|
|
181
|
-
typeof value === 'undefined');
|
|
182
|
-
};
|
|
183
|
-
const isObjectValue = (value) => {
|
|
184
|
-
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
185
|
-
};
|
|
186
|
-
const isFileValue = (value) => !!value &&
|
|
187
|
-
typeof value === 'object' &&
|
|
188
|
-
'data' in value &&
|
|
189
|
-
isFileData(value.data);
|
|
190
|
-
function collectParams(params, inputKey, inputValue) {
|
|
191
|
-
if (isFileValue(inputValue)) {
|
|
192
|
-
const name = inputValue
|
|
193
|
-
const file = transformFile(inputValue.data); // lgtm [js/superfluous-trailing-arguments]
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
186
|
+
const isSimpleValue = (value) => {
|
|
187
|
+
return (typeof value === 'string' ||
|
|
188
|
+
typeof value === 'number' ||
|
|
189
|
+
typeof value === 'undefined');
|
|
190
|
+
};
|
|
191
|
+
const isObjectValue = (value) => {
|
|
192
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
193
|
+
};
|
|
194
|
+
const isFileValue = (value) => !!value &&
|
|
195
|
+
typeof value === 'object' &&
|
|
196
|
+
'data' in value &&
|
|
197
|
+
isFileData(value.data);
|
|
198
|
+
function collectParams(params, inputKey, inputValue) {
|
|
199
|
+
if (isFileValue(inputValue)) {
|
|
200
|
+
const { name, contentType } = inputValue;
|
|
201
|
+
const file = transformFile(inputValue.data); // lgtm [js/superfluous-trailing-arguments]
|
|
202
|
+
const options = getFileOptions({ name, contentType });
|
|
203
|
+
params.push([inputKey, file, ...options]);
|
|
204
|
+
}
|
|
205
|
+
else if (isObjectValue(inputValue)) {
|
|
206
|
+
for (const [key, value] of Object.entries(inputValue)) {
|
|
207
|
+
if (typeof value !== 'undefined') {
|
|
208
|
+
params.push([`${inputKey}[${key}]`, String(value)]);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (isSimpleValue(inputValue) && inputValue) {
|
|
213
|
+
params.push([inputKey, inputValue.toString()]);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function getFormDataParams(options) {
|
|
217
|
+
const params = [];
|
|
218
|
+
for (const [key, value] of Object.entries(options)) {
|
|
219
|
+
collectParams(params, key, value);
|
|
220
|
+
}
|
|
221
|
+
return params;
|
|
222
|
+
}
|
|
223
|
+
function buildFormData(options) {
|
|
224
|
+
const formData = getFormData();
|
|
225
|
+
const paramsList = getFormDataParams(options);
|
|
226
|
+
for (const params of paramsList) {
|
|
227
|
+
const [key, value, ...options] = params;
|
|
228
|
+
// node form-data has another signature for append
|
|
229
|
+
formData.append(key, value, ...options);
|
|
230
|
+
}
|
|
231
|
+
return formData;
|
|
221
232
|
}
|
|
222
233
|
|
|
223
|
-
const serializePair = (key, value) => typeof value !== 'undefined' ? `${key}=${encodeURIComponent(value)}` : null;
|
|
224
|
-
// TODO: generalize value transforming logic and use it here and inside `buildFormData`
|
|
225
|
-
const createQuery = (query) => Object.entries(query)
|
|
226
|
-
.reduce((params, [key, value]) => {
|
|
227
|
-
let param;
|
|
228
|
-
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
229
|
-
param = Object.entries(value)
|
|
230
|
-
.filter((entry) => typeof entry[1] !== 'undefined')
|
|
231
|
-
.map((entry) => serializePair(`${key}[${entry[0]}]`, String(entry[1])));
|
|
232
|
-
}
|
|
233
|
-
else if (Array.isArray(value)) {
|
|
234
|
-
param = value.map((val) => serializePair(`${key}[]`, val));
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
param = serializePair(key, value);
|
|
238
|
-
}
|
|
239
|
-
return params.concat(param);
|
|
240
|
-
}, [])
|
|
241
|
-
.filter((x) => !!x)
|
|
242
|
-
.join('&');
|
|
243
|
-
const getUrl = (base, path, query) => [
|
|
244
|
-
base,
|
|
245
|
-
path,
|
|
246
|
-
query && Object.keys(query).length > 0 ? '?' : '',
|
|
247
|
-
query && createQuery(query)
|
|
248
|
-
]
|
|
249
|
-
.filter(Boolean)
|
|
234
|
+
const serializePair = (key, value) => typeof value !== 'undefined' ? `${key}=${encodeURIComponent(value)}` : null;
|
|
235
|
+
// TODO: generalize value transforming logic and use it here and inside `buildFormData`
|
|
236
|
+
const createQuery = (query) => Object.entries(query)
|
|
237
|
+
.reduce((params, [key, value]) => {
|
|
238
|
+
let param;
|
|
239
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
240
|
+
param = Object.entries(value)
|
|
241
|
+
.filter((entry) => typeof entry[1] !== 'undefined')
|
|
242
|
+
.map((entry) => serializePair(`${key}[${entry[0]}]`, String(entry[1])));
|
|
243
|
+
}
|
|
244
|
+
else if (Array.isArray(value)) {
|
|
245
|
+
param = value.map((val) => serializePair(`${key}[]`, val));
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
param = serializePair(key, value);
|
|
249
|
+
}
|
|
250
|
+
return params.concat(param);
|
|
251
|
+
}, [])
|
|
252
|
+
.filter((x) => !!x)
|
|
253
|
+
.join('&');
|
|
254
|
+
const getUrl = (base, path, query) => [
|
|
255
|
+
base,
|
|
256
|
+
path,
|
|
257
|
+
query && Object.keys(query).length > 0 ? '?' : '',
|
|
258
|
+
query && createQuery(query)
|
|
259
|
+
]
|
|
260
|
+
.filter(Boolean)
|
|
250
261
|
.join('');
|
|
251
262
|
|
|
252
|
-
/*
|
|
253
|
-
Settings for future support:
|
|
254
|
-
parallelDirectUploads: 10,
|
|
255
|
-
*/
|
|
256
|
-
const defaultSettings = {
|
|
257
|
-
baseCDN: 'https://ucarecdn.com',
|
|
258
|
-
baseURL: 'https://upload.uploadcare.com',
|
|
259
|
-
maxContentLength: 50 * 1024 * 1024,
|
|
260
|
-
retryThrottledRequestMaxTimes: 1,
|
|
261
|
-
multipartMinFileSize: 25 * 1024 * 1024,
|
|
262
|
-
multipartChunkSize: 5 * 1024 * 1024,
|
|
263
|
-
multipartMinLastPartSize: 1024 * 1024,
|
|
264
|
-
maxConcurrentRequests: 4,
|
|
265
|
-
multipartMaxAttempts: 3,
|
|
266
|
-
pollingTimeoutMilliseconds: 10000,
|
|
267
|
-
pusherKey: '79ae88bd931ea68464d9'
|
|
268
|
-
};
|
|
269
|
-
const defaultContentType = 'application/octet-stream';
|
|
263
|
+
/*
|
|
264
|
+
Settings for future support:
|
|
265
|
+
parallelDirectUploads: 10,
|
|
266
|
+
*/
|
|
267
|
+
const defaultSettings = {
|
|
268
|
+
baseCDN: 'https://ucarecdn.com',
|
|
269
|
+
baseURL: 'https://upload.uploadcare.com',
|
|
270
|
+
maxContentLength: 50 * 1024 * 1024,
|
|
271
|
+
retryThrottledRequestMaxTimes: 1,
|
|
272
|
+
multipartMinFileSize: 25 * 1024 * 1024,
|
|
273
|
+
multipartChunkSize: 5 * 1024 * 1024,
|
|
274
|
+
multipartMinLastPartSize: 1024 * 1024,
|
|
275
|
+
maxConcurrentRequests: 4,
|
|
276
|
+
multipartMaxAttempts: 3,
|
|
277
|
+
pollingTimeoutMilliseconds: 10000,
|
|
278
|
+
pusherKey: '79ae88bd931ea68464d9'
|
|
279
|
+
};
|
|
280
|
+
const defaultContentType = 'application/octet-stream';
|
|
270
281
|
const defaultFilename = 'original';
|
|
271
282
|
|
|
272
|
-
var version = '3.1.
|
|
283
|
+
var version = '3.1.1';
|
|
273
284
|
|
|
274
|
-
/**
|
|
275
|
-
* Returns User Agent based on version and settings.
|
|
276
|
-
*/
|
|
277
|
-
function getUserAgent({ userAgent, publicKey = '', integration = '' } = {}) {
|
|
278
|
-
const libraryName = 'UploadcareUploadClient';
|
|
279
|
-
const libraryVersion = version;
|
|
280
|
-
const languageName = 'JavaScript';
|
|
281
|
-
if (typeof userAgent === 'string') {
|
|
282
|
-
return userAgent;
|
|
283
|
-
}
|
|
284
|
-
if (typeof userAgent === 'function') {
|
|
285
|
-
return userAgent({
|
|
286
|
-
publicKey,
|
|
287
|
-
libraryName,
|
|
288
|
-
libraryVersion,
|
|
289
|
-
languageName,
|
|
290
|
-
integration
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
const mainInfo = [libraryName, libraryVersion, publicKey]
|
|
294
|
-
.filter(Boolean)
|
|
295
|
-
.join('/');
|
|
296
|
-
const additionInfo = [languageName, integration].filter(Boolean).join('; ');
|
|
297
|
-
return `${mainInfo} (${additionInfo})`;
|
|
285
|
+
/**
|
|
286
|
+
* Returns User Agent based on version and settings.
|
|
287
|
+
*/
|
|
288
|
+
function getUserAgent({ userAgent, publicKey = '', integration = '' } = {}) {
|
|
289
|
+
const libraryName = 'UploadcareUploadClient';
|
|
290
|
+
const libraryVersion = version;
|
|
291
|
+
const languageName = 'JavaScript';
|
|
292
|
+
if (typeof userAgent === 'string') {
|
|
293
|
+
return userAgent;
|
|
294
|
+
}
|
|
295
|
+
if (typeof userAgent === 'function') {
|
|
296
|
+
return userAgent({
|
|
297
|
+
publicKey,
|
|
298
|
+
libraryName,
|
|
299
|
+
libraryVersion,
|
|
300
|
+
languageName,
|
|
301
|
+
integration
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
const mainInfo = [libraryName, libraryVersion, publicKey]
|
|
305
|
+
.filter(Boolean)
|
|
306
|
+
.join('/');
|
|
307
|
+
const additionInfo = [languageName, integration].filter(Boolean).join('; ');
|
|
308
|
+
return `${mainInfo} (${additionInfo})`;
|
|
298
309
|
}
|
|
299
310
|
|
|
300
|
-
const SEPARATOR = /\W|_/g;
|
|
301
|
-
/**
|
|
302
|
-
* Transforms a string to camelCased.
|
|
303
|
-
*/
|
|
304
|
-
function camelize(text) {
|
|
305
|
-
return text
|
|
306
|
-
.split(SEPARATOR)
|
|
307
|
-
.map((word, index) => word.charAt(0)[index > 0 ? 'toUpperCase' : 'toLowerCase']() +
|
|
308
|
-
word.slice(1))
|
|
309
|
-
.join('');
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Transforms keys of an object to camelCased recursively.
|
|
313
|
-
*/
|
|
314
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
315
|
-
function camelizeKeys(source) {
|
|
316
|
-
if (!source || typeof source !== 'object') {
|
|
317
|
-
return source;
|
|
318
|
-
}
|
|
319
|
-
return Object.keys(source).reduce((accumulator, key) => {
|
|
320
|
-
accumulator[camelize(key)] =
|
|
321
|
-
typeof source[key] === 'object' ? camelizeKeys(source[key]) : source[key];
|
|
322
|
-
return accumulator;
|
|
323
|
-
}, {});
|
|
311
|
+
const SEPARATOR = /\W|_/g;
|
|
312
|
+
/**
|
|
313
|
+
* Transforms a string to camelCased.
|
|
314
|
+
*/
|
|
315
|
+
function camelize(text) {
|
|
316
|
+
return text
|
|
317
|
+
.split(SEPARATOR)
|
|
318
|
+
.map((word, index) => word.charAt(0)[index > 0 ? 'toUpperCase' : 'toLowerCase']() +
|
|
319
|
+
word.slice(1))
|
|
320
|
+
.join('');
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Transforms keys of an object to camelCased recursively.
|
|
324
|
+
*/
|
|
325
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
326
|
+
function camelizeKeys(source) {
|
|
327
|
+
if (!source || typeof source !== 'object') {
|
|
328
|
+
return source;
|
|
329
|
+
}
|
|
330
|
+
return Object.keys(source).reduce((accumulator, key) => {
|
|
331
|
+
accumulator[camelize(key)] =
|
|
332
|
+
typeof source[key] === 'object' ? camelizeKeys(source[key]) : source[key];
|
|
333
|
+
return accumulator;
|
|
334
|
+
}, {});
|
|
324
335
|
}
|
|
325
336
|
|
|
326
|
-
/**
|
|
327
|
-
* setTimeout as Promise.
|
|
328
|
-
*
|
|
329
|
-
* @param {number} ms Timeout in milliseconds.
|
|
330
|
-
*/
|
|
337
|
+
/**
|
|
338
|
+
* setTimeout as Promise.
|
|
339
|
+
*
|
|
340
|
+
* @param {number} ms Timeout in milliseconds.
|
|
341
|
+
*/
|
|
331
342
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
332
343
|
|
|
333
|
-
const defaultOptions = {
|
|
334
|
-
factor: 2,
|
|
335
|
-
time: 100
|
|
336
|
-
};
|
|
337
|
-
function retrier(fn, options = defaultOptions) {
|
|
338
|
-
let attempts = 0;
|
|
339
|
-
function runAttempt(fn) {
|
|
340
|
-
const defaultDelayTime = Math.round(options.time * Math.pow(options.factor, attempts));
|
|
341
|
-
const retry = (ms) => delay(ms !== null && ms !== void 0 ? ms : defaultDelayTime).then(() => {
|
|
342
|
-
attempts += 1;
|
|
343
|
-
return runAttempt(fn);
|
|
344
|
-
});
|
|
345
|
-
return fn({
|
|
346
|
-
attempt: attempts,
|
|
347
|
-
retry
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
return runAttempt(fn);
|
|
344
|
+
const defaultOptions = {
|
|
345
|
+
factor: 2,
|
|
346
|
+
time: 100
|
|
347
|
+
};
|
|
348
|
+
function retrier(fn, options = defaultOptions) {
|
|
349
|
+
let attempts = 0;
|
|
350
|
+
function runAttempt(fn) {
|
|
351
|
+
const defaultDelayTime = Math.round(options.time * Math.pow(options.factor, attempts));
|
|
352
|
+
const retry = (ms) => delay(ms !== null && ms !== void 0 ? ms : defaultDelayTime).then(() => {
|
|
353
|
+
attempts += 1;
|
|
354
|
+
return runAttempt(fn);
|
|
355
|
+
});
|
|
356
|
+
return fn({
|
|
357
|
+
attempt: attempts,
|
|
358
|
+
retry
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
return runAttempt(fn);
|
|
351
362
|
}
|
|
352
363
|
|
|
353
|
-
const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
|
|
354
|
-
const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
|
|
355
|
-
function getTimeoutFromThrottledRequest(error) {
|
|
356
|
-
const { headers } = error || {};
|
|
357
|
-
return ((headers &&
|
|
358
|
-
Number.parseInt(headers['x-throttle-wait-seconds']) * 1000) ||
|
|
359
|
-
DEFAULT_RETRY_AFTER_TIMEOUT);
|
|
360
|
-
}
|
|
361
|
-
function retryIfThrottled(fn, retryThrottledMaxTimes) {
|
|
362
|
-
return retrier(({ attempt, retry }) => fn().catch((error) => {
|
|
363
|
-
if ('response' in error &&
|
|
364
|
-
(error === null || error === void 0 ? void 0 : error.code) === REQUEST_WAS_THROTTLED_CODE &&
|
|
365
|
-
attempt < retryThrottledMaxTimes) {
|
|
366
|
-
return retry(getTimeoutFromThrottledRequest(error));
|
|
367
|
-
}
|
|
368
|
-
throw error;
|
|
369
|
-
}));
|
|
364
|
+
const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
|
|
365
|
+
const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
|
|
366
|
+
function getTimeoutFromThrottledRequest(error) {
|
|
367
|
+
const { headers } = error || {};
|
|
368
|
+
return ((headers &&
|
|
369
|
+
Number.parseInt(headers['x-throttle-wait-seconds']) * 1000) ||
|
|
370
|
+
DEFAULT_RETRY_AFTER_TIMEOUT);
|
|
371
|
+
}
|
|
372
|
+
function retryIfThrottled(fn, retryThrottledMaxTimes) {
|
|
373
|
+
return retrier(({ attempt, retry }) => fn().catch((error) => {
|
|
374
|
+
if ('response' in error &&
|
|
375
|
+
(error === null || error === void 0 ? void 0 : error.code) === REQUEST_WAS_THROTTLED_CODE &&
|
|
376
|
+
attempt < retryThrottledMaxTimes) {
|
|
377
|
+
return retry(getTimeoutFromThrottledRequest(error));
|
|
378
|
+
}
|
|
379
|
+
throw error;
|
|
380
|
+
}));
|
|
370
381
|
}
|
|
371
382
|
|
|
372
|
-
function getStoreValue(store) {
|
|
373
|
-
return typeof store === 'undefined' ? 'auto' : store ? '1' : '0';
|
|
383
|
+
function getStoreValue(store) {
|
|
384
|
+
return typeof store === 'undefined' ? 'auto' : store ? '1' : '0';
|
|
374
385
|
}
|
|
375
386
|
|
|
376
|
-
/**
|
|
377
|
-
* Performs file uploading request to Uploadcare Upload API.
|
|
378
|
-
* Can be canceled and has progress.
|
|
379
|
-
*/
|
|
380
|
-
function base(file, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
381
|
-
return retryIfThrottled(() => {
|
|
382
|
-
var _a;
|
|
383
|
-
return request({
|
|
384
|
-
method: 'POST',
|
|
385
|
-
url: getUrl(baseURL, '/base/', {
|
|
386
|
-
jsonerrors: 1
|
|
387
|
-
}),
|
|
388
|
-
headers: {
|
|
389
|
-
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
390
|
-
},
|
|
391
|
-
data: buildFormData({
|
|
392
|
-
file: {
|
|
393
|
-
data: file,
|
|
394
|
-
name: (_a = fileName !== null && fileName !== void 0 ? fileName : file.name) !== null && _a !== void 0 ? _a : defaultFilename
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
387
|
+
/**
|
|
388
|
+
* Performs file uploading request to Uploadcare Upload API.
|
|
389
|
+
* Can be canceled and has progress.
|
|
390
|
+
*/
|
|
391
|
+
function base(file, { publicKey, fileName, contentType, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
392
|
+
return retryIfThrottled(() => {
|
|
393
|
+
var _a;
|
|
394
|
+
return request({
|
|
395
|
+
method: 'POST',
|
|
396
|
+
url: getUrl(baseURL, '/base/', {
|
|
397
|
+
jsonerrors: 1
|
|
398
|
+
}),
|
|
399
|
+
headers: {
|
|
400
|
+
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
401
|
+
},
|
|
402
|
+
data: buildFormData({
|
|
403
|
+
file: {
|
|
404
|
+
data: file,
|
|
405
|
+
name: (_a = fileName !== null && fileName !== void 0 ? fileName : file.name) !== null && _a !== void 0 ? _a : defaultFilename,
|
|
406
|
+
contentType
|
|
407
|
+
},
|
|
408
|
+
UPLOADCARE_PUB_KEY: publicKey,
|
|
409
|
+
UPLOADCARE_STORE: getStoreValue(store),
|
|
410
|
+
signature: secureSignature,
|
|
411
|
+
expire: secureExpire,
|
|
412
|
+
source: source,
|
|
413
|
+
metadata
|
|
414
|
+
}),
|
|
415
|
+
signal,
|
|
416
|
+
onProgress
|
|
417
|
+
}).then(({ data, headers, request }) => {
|
|
418
|
+
const response = camelizeKeys(JSON.parse(data));
|
|
419
|
+
if ('error' in response) {
|
|
420
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
return response;
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
}, retryThrottledRequestMaxTimes);
|
|
415
427
|
}
|
|
416
428
|
|
|
417
|
-
var TypeEnum;
|
|
418
|
-
(function (TypeEnum) {
|
|
419
|
-
TypeEnum["Token"] = "token";
|
|
420
|
-
TypeEnum["FileInfo"] = "file_info";
|
|
421
|
-
})(TypeEnum || (TypeEnum = {}));
|
|
422
|
-
/**
|
|
423
|
-
* Uploading files from URL.
|
|
424
|
-
*/
|
|
425
|
-
function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
426
|
-
return retryIfThrottled(() => request({
|
|
427
|
-
method: 'POST',
|
|
428
|
-
headers: {
|
|
429
|
-
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
430
|
-
},
|
|
431
|
-
url: getUrl(baseURL, '/from_url/', {
|
|
432
|
-
jsonerrors: 1,
|
|
433
|
-
pub_key: publicKey,
|
|
434
|
-
source_url: sourceUrl,
|
|
435
|
-
store: getStoreValue(store),
|
|
436
|
-
filename: fileName,
|
|
437
|
-
check_URL_duplicates: checkForUrlDuplicates ? 1 : undefined,
|
|
438
|
-
save_URL_duplicates: saveUrlForRecurrentUploads ? 1 : undefined,
|
|
439
|
-
signature: secureSignature,
|
|
440
|
-
expire: secureExpire,
|
|
441
|
-
source: source,
|
|
442
|
-
metadata
|
|
443
|
-
}),
|
|
444
|
-
signal
|
|
445
|
-
}).then(({ data, headers, request }) => {
|
|
446
|
-
const response = camelizeKeys(JSON.parse(data));
|
|
447
|
-
if ('error' in response) {
|
|
448
|
-
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
449
|
-
}
|
|
450
|
-
else {
|
|
451
|
-
return response;
|
|
452
|
-
}
|
|
453
|
-
}), retryThrottledRequestMaxTimes);
|
|
429
|
+
var TypeEnum;
|
|
430
|
+
(function (TypeEnum) {
|
|
431
|
+
TypeEnum["Token"] = "token";
|
|
432
|
+
TypeEnum["FileInfo"] = "file_info";
|
|
433
|
+
})(TypeEnum || (TypeEnum = {}));
|
|
434
|
+
/**
|
|
435
|
+
* Uploading files from URL.
|
|
436
|
+
*/
|
|
437
|
+
function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
438
|
+
return retryIfThrottled(() => request({
|
|
439
|
+
method: 'POST',
|
|
440
|
+
headers: {
|
|
441
|
+
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
442
|
+
},
|
|
443
|
+
url: getUrl(baseURL, '/from_url/', {
|
|
444
|
+
jsonerrors: 1,
|
|
445
|
+
pub_key: publicKey,
|
|
446
|
+
source_url: sourceUrl,
|
|
447
|
+
store: getStoreValue(store),
|
|
448
|
+
filename: fileName,
|
|
449
|
+
check_URL_duplicates: checkForUrlDuplicates ? 1 : undefined,
|
|
450
|
+
save_URL_duplicates: saveUrlForRecurrentUploads ? 1 : undefined,
|
|
451
|
+
signature: secureSignature,
|
|
452
|
+
expire: secureExpire,
|
|
453
|
+
source: source,
|
|
454
|
+
metadata
|
|
455
|
+
}),
|
|
456
|
+
signal
|
|
457
|
+
}).then(({ data, headers, request }) => {
|
|
458
|
+
const response = camelizeKeys(JSON.parse(data));
|
|
459
|
+
if ('error' in response) {
|
|
460
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
return response;
|
|
464
|
+
}
|
|
465
|
+
}), retryThrottledRequestMaxTimes);
|
|
454
466
|
}
|
|
455
467
|
|
|
456
|
-
var Status;
|
|
457
|
-
(function (Status) {
|
|
458
|
-
Status["Unknown"] = "unknown";
|
|
459
|
-
Status["Waiting"] = "waiting";
|
|
460
|
-
Status["Progress"] = "progress";
|
|
461
|
-
Status["Error"] = "error";
|
|
462
|
-
Status["Success"] = "success";
|
|
463
|
-
})(Status || (Status = {}));
|
|
464
|
-
const isErrorResponse = (response) => {
|
|
465
|
-
return 'status' in response && response.status === Status.Error;
|
|
466
|
-
};
|
|
467
|
-
/**
|
|
468
|
-
* Checking upload status and working with file tokens.
|
|
469
|
-
*/
|
|
470
|
-
function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes } = {}) {
|
|
471
|
-
return retryIfThrottled(() => request({
|
|
472
|
-
method: 'GET',
|
|
473
|
-
headers: publicKey
|
|
474
|
-
? {
|
|
475
|
-
'X-UC-User-Agent': getUserAgent({
|
|
476
|
-
publicKey,
|
|
477
|
-
integration,
|
|
478
|
-
userAgent
|
|
479
|
-
})
|
|
480
|
-
}
|
|
481
|
-
: undefined,
|
|
482
|
-
url: getUrl(baseURL, '/from_url/status/', {
|
|
483
|
-
jsonerrors: 1,
|
|
484
|
-
token
|
|
485
|
-
}),
|
|
486
|
-
signal
|
|
487
|
-
}).then(({ data, headers, request }) => {
|
|
488
|
-
const response = camelizeKeys(JSON.parse(data));
|
|
489
|
-
if ('error' in response && !isErrorResponse(response)) {
|
|
490
|
-
throw new UploadClientError(response.error.content, undefined, request, response, headers);
|
|
491
|
-
}
|
|
492
|
-
else {
|
|
493
|
-
return response;
|
|
494
|
-
}
|
|
495
|
-
}), retryThrottledRequestMaxTimes);
|
|
468
|
+
var Status;
|
|
469
|
+
(function (Status) {
|
|
470
|
+
Status["Unknown"] = "unknown";
|
|
471
|
+
Status["Waiting"] = "waiting";
|
|
472
|
+
Status["Progress"] = "progress";
|
|
473
|
+
Status["Error"] = "error";
|
|
474
|
+
Status["Success"] = "success";
|
|
475
|
+
})(Status || (Status = {}));
|
|
476
|
+
const isErrorResponse = (response) => {
|
|
477
|
+
return 'status' in response && response.status === Status.Error;
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* Checking upload status and working with file tokens.
|
|
481
|
+
*/
|
|
482
|
+
function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes } = {}) {
|
|
483
|
+
return retryIfThrottled(() => request({
|
|
484
|
+
method: 'GET',
|
|
485
|
+
headers: publicKey
|
|
486
|
+
? {
|
|
487
|
+
'X-UC-User-Agent': getUserAgent({
|
|
488
|
+
publicKey,
|
|
489
|
+
integration,
|
|
490
|
+
userAgent
|
|
491
|
+
})
|
|
492
|
+
}
|
|
493
|
+
: undefined,
|
|
494
|
+
url: getUrl(baseURL, '/from_url/status/', {
|
|
495
|
+
jsonerrors: 1,
|
|
496
|
+
token
|
|
497
|
+
}),
|
|
498
|
+
signal
|
|
499
|
+
}).then(({ data, headers, request }) => {
|
|
500
|
+
const response = camelizeKeys(JSON.parse(data));
|
|
501
|
+
if ('error' in response && !isErrorResponse(response)) {
|
|
502
|
+
throw new UploadClientError(response.error.content, undefined, request, response, headers);
|
|
503
|
+
}
|
|
504
|
+
else {
|
|
505
|
+
return response;
|
|
506
|
+
}
|
|
507
|
+
}), retryThrottledRequestMaxTimes);
|
|
496
508
|
}
|
|
497
509
|
|
|
498
|
-
/**
|
|
499
|
-
* Create files group.
|
|
500
|
-
*/
|
|
501
|
-
function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallback, secureSignature, secureExpire, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
502
|
-
return retryIfThrottled(() => request({
|
|
503
|
-
method: 'POST',
|
|
504
|
-
headers: {
|
|
505
|
-
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
506
|
-
},
|
|
507
|
-
url: getUrl(baseURL, '/group/', {
|
|
508
|
-
jsonerrors: 1,
|
|
509
|
-
pub_key: publicKey,
|
|
510
|
-
files: uuids,
|
|
511
|
-
callback: jsonpCallback,
|
|
512
|
-
signature: secureSignature,
|
|
513
|
-
expire: secureExpire,
|
|
514
|
-
source
|
|
515
|
-
}),
|
|
516
|
-
signal
|
|
517
|
-
}).then(({ data, headers, request }) => {
|
|
518
|
-
const response = camelizeKeys(JSON.parse(data));
|
|
519
|
-
if ('error' in response) {
|
|
520
|
-
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
521
|
-
}
|
|
522
|
-
else {
|
|
523
|
-
return response;
|
|
524
|
-
}
|
|
525
|
-
}), retryThrottledRequestMaxTimes);
|
|
510
|
+
/**
|
|
511
|
+
* Create files group.
|
|
512
|
+
*/
|
|
513
|
+
function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallback, secureSignature, secureExpire, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
514
|
+
return retryIfThrottled(() => request({
|
|
515
|
+
method: 'POST',
|
|
516
|
+
headers: {
|
|
517
|
+
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
518
|
+
},
|
|
519
|
+
url: getUrl(baseURL, '/group/', {
|
|
520
|
+
jsonerrors: 1,
|
|
521
|
+
pub_key: publicKey,
|
|
522
|
+
files: uuids,
|
|
523
|
+
callback: jsonpCallback,
|
|
524
|
+
signature: secureSignature,
|
|
525
|
+
expire: secureExpire,
|
|
526
|
+
source
|
|
527
|
+
}),
|
|
528
|
+
signal
|
|
529
|
+
}).then(({ data, headers, request }) => {
|
|
530
|
+
const response = camelizeKeys(JSON.parse(data));
|
|
531
|
+
if ('error' in response) {
|
|
532
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
533
|
+
}
|
|
534
|
+
else {
|
|
535
|
+
return response;
|
|
536
|
+
}
|
|
537
|
+
}), retryThrottledRequestMaxTimes);
|
|
526
538
|
}
|
|
527
539
|
|
|
528
|
-
/**
|
|
529
|
-
* Get info about group.
|
|
530
|
-
*/
|
|
531
|
-
function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
532
|
-
return retryIfThrottled(() => request({
|
|
533
|
-
method: 'GET',
|
|
534
|
-
headers: {
|
|
535
|
-
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
536
|
-
},
|
|
537
|
-
url: getUrl(baseURL, '/group/info/', {
|
|
538
|
-
jsonerrors: 1,
|
|
539
|
-
pub_key: publicKey,
|
|
540
|
-
group_id: id,
|
|
541
|
-
source
|
|
542
|
-
}),
|
|
543
|
-
signal
|
|
544
|
-
}).then(({ data, headers, request }) => {
|
|
545
|
-
const response = camelizeKeys(JSON.parse(data));
|
|
546
|
-
if ('error' in response) {
|
|
547
|
-
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
548
|
-
}
|
|
549
|
-
else {
|
|
550
|
-
return response;
|
|
551
|
-
}
|
|
552
|
-
}), retryThrottledRequestMaxTimes);
|
|
540
|
+
/**
|
|
541
|
+
* Get info about group.
|
|
542
|
+
*/
|
|
543
|
+
function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
544
|
+
return retryIfThrottled(() => request({
|
|
545
|
+
method: 'GET',
|
|
546
|
+
headers: {
|
|
547
|
+
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
548
|
+
},
|
|
549
|
+
url: getUrl(baseURL, '/group/info/', {
|
|
550
|
+
jsonerrors: 1,
|
|
551
|
+
pub_key: publicKey,
|
|
552
|
+
group_id: id,
|
|
553
|
+
source
|
|
554
|
+
}),
|
|
555
|
+
signal
|
|
556
|
+
}).then(({ data, headers, request }) => {
|
|
557
|
+
const response = camelizeKeys(JSON.parse(data));
|
|
558
|
+
if ('error' in response) {
|
|
559
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
return response;
|
|
563
|
+
}
|
|
564
|
+
}), retryThrottledRequestMaxTimes);
|
|
553
565
|
}
|
|
554
566
|
|
|
555
|
-
/**
|
|
556
|
-
* Returns a JSON dictionary holding file info.
|
|
557
|
-
*/
|
|
558
|
-
function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
559
|
-
return retryIfThrottled(() => request({
|
|
560
|
-
method: 'GET',
|
|
561
|
-
headers: {
|
|
562
|
-
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
563
|
-
},
|
|
564
|
-
url: getUrl(baseURL, '/info/', {
|
|
565
|
-
jsonerrors: 1,
|
|
566
|
-
pub_key: publicKey,
|
|
567
|
-
file_id: uuid,
|
|
568
|
-
source
|
|
569
|
-
}),
|
|
570
|
-
signal
|
|
571
|
-
}).then(({ data, headers, request }) => {
|
|
572
|
-
const response = camelizeKeys(JSON.parse(data));
|
|
573
|
-
if ('error' in response) {
|
|
574
|
-
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
575
|
-
}
|
|
576
|
-
else {
|
|
577
|
-
return response;
|
|
578
|
-
}
|
|
579
|
-
}), retryThrottledRequestMaxTimes);
|
|
567
|
+
/**
|
|
568
|
+
* Returns a JSON dictionary holding file info.
|
|
569
|
+
*/
|
|
570
|
+
function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
571
|
+
return retryIfThrottled(() => request({
|
|
572
|
+
method: 'GET',
|
|
573
|
+
headers: {
|
|
574
|
+
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
575
|
+
},
|
|
576
|
+
url: getUrl(baseURL, '/info/', {
|
|
577
|
+
jsonerrors: 1,
|
|
578
|
+
pub_key: publicKey,
|
|
579
|
+
file_id: uuid,
|
|
580
|
+
source
|
|
581
|
+
}),
|
|
582
|
+
signal
|
|
583
|
+
}).then(({ data, headers, request }) => {
|
|
584
|
+
const response = camelizeKeys(JSON.parse(data));
|
|
585
|
+
if ('error' in response) {
|
|
586
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
return response;
|
|
590
|
+
}
|
|
591
|
+
}), retryThrottledRequestMaxTimes);
|
|
580
592
|
}
|
|
581
593
|
|
|
582
|
-
/**
|
|
583
|
-
* Start multipart uploading.
|
|
584
|
-
*/
|
|
585
|
-
function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
586
|
-
return retryIfThrottled(() => request({
|
|
587
|
-
method: 'POST',
|
|
588
|
-
url: getUrl(baseURL, '/multipart/start/', { jsonerrors: 1 }),
|
|
589
|
-
headers: {
|
|
590
|
-
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
591
|
-
},
|
|
592
|
-
data: buildFormData({
|
|
593
|
-
filename: fileName !== null && fileName !== void 0 ? fileName : defaultFilename,
|
|
594
|
-
size: size,
|
|
595
|
-
content_type: contentType !== null && contentType !== void 0 ? contentType : defaultContentType,
|
|
596
|
-
part_size: multipartChunkSize,
|
|
597
|
-
UPLOADCARE_STORE: getStoreValue(store),
|
|
598
|
-
UPLOADCARE_PUB_KEY: publicKey,
|
|
599
|
-
signature: secureSignature,
|
|
600
|
-
expire: secureExpire,
|
|
601
|
-
source: source,
|
|
602
|
-
metadata
|
|
603
|
-
}),
|
|
604
|
-
signal
|
|
605
|
-
}).then(({ data, headers, request }) => {
|
|
606
|
-
const response = camelizeKeys(JSON.parse(data));
|
|
607
|
-
if ('error' in response) {
|
|
608
|
-
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
609
|
-
}
|
|
610
|
-
else {
|
|
611
|
-
// convert to array
|
|
612
|
-
response.parts = Object.keys(response.parts).map((key) => response.parts[key]);
|
|
613
|
-
return response;
|
|
614
|
-
}
|
|
615
|
-
}), retryThrottledRequestMaxTimes);
|
|
594
|
+
/**
|
|
595
|
+
* Start multipart uploading.
|
|
596
|
+
*/
|
|
597
|
+
function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
|
|
598
|
+
return retryIfThrottled(() => request({
|
|
599
|
+
method: 'POST',
|
|
600
|
+
url: getUrl(baseURL, '/multipart/start/', { jsonerrors: 1 }),
|
|
601
|
+
headers: {
|
|
602
|
+
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
603
|
+
},
|
|
604
|
+
data: buildFormData({
|
|
605
|
+
filename: fileName !== null && fileName !== void 0 ? fileName : defaultFilename,
|
|
606
|
+
size: size,
|
|
607
|
+
content_type: contentType !== null && contentType !== void 0 ? contentType : defaultContentType,
|
|
608
|
+
part_size: multipartChunkSize,
|
|
609
|
+
UPLOADCARE_STORE: getStoreValue(store),
|
|
610
|
+
UPLOADCARE_PUB_KEY: publicKey,
|
|
611
|
+
signature: secureSignature,
|
|
612
|
+
expire: secureExpire,
|
|
613
|
+
source: source,
|
|
614
|
+
metadata
|
|
615
|
+
}),
|
|
616
|
+
signal
|
|
617
|
+
}).then(({ data, headers, request }) => {
|
|
618
|
+
const response = camelizeKeys(JSON.parse(data));
|
|
619
|
+
if ('error' in response) {
|
|
620
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
// convert to array
|
|
624
|
+
response.parts = Object.keys(response.parts).map((key) => response.parts[key]);
|
|
625
|
+
return response;
|
|
626
|
+
}
|
|
627
|
+
}), retryThrottledRequestMaxTimes);
|
|
616
628
|
}
|
|
617
629
|
|
|
618
|
-
/**
|
|
619
|
-
* Complete multipart uploading.
|
|
620
|
-
*/
|
|
621
|
-
function multipartUpload(part, url, { signal, onProgress }) {
|
|
622
|
-
return request({
|
|
623
|
-
method: 'PUT',
|
|
624
|
-
url,
|
|
625
|
-
data: part,
|
|
626
|
-
// Upload request can't be non-computable because we always know exact size
|
|
627
|
-
onProgress: onProgress,
|
|
628
|
-
signal
|
|
629
|
-
})
|
|
630
|
-
.then((result) => {
|
|
631
|
-
// hack for node ¯\_(ツ)_/¯
|
|
632
|
-
if (onProgress)
|
|
633
|
-
onProgress({
|
|
634
|
-
isComputable: true,
|
|
635
|
-
value: 1
|
|
636
|
-
});
|
|
637
|
-
return result;
|
|
638
|
-
})
|
|
639
|
-
.then(({ status }) => ({ code: status }));
|
|
630
|
+
/**
|
|
631
|
+
* Complete multipart uploading.
|
|
632
|
+
*/
|
|
633
|
+
function multipartUpload(part, url, { signal, onProgress }) {
|
|
634
|
+
return request({
|
|
635
|
+
method: 'PUT',
|
|
636
|
+
url,
|
|
637
|
+
data: part,
|
|
638
|
+
// Upload request can't be non-computable because we always know exact size
|
|
639
|
+
onProgress: onProgress,
|
|
640
|
+
signal
|
|
641
|
+
})
|
|
642
|
+
.then((result) => {
|
|
643
|
+
// hack for node ¯\_(ツ)_/¯
|
|
644
|
+
if (onProgress)
|
|
645
|
+
onProgress({
|
|
646
|
+
isComputable: true,
|
|
647
|
+
value: 1
|
|
648
|
+
});
|
|
649
|
+
return result;
|
|
650
|
+
})
|
|
651
|
+
.then(({ status }) => ({ code: status }));
|
|
640
652
|
}
|
|
641
653
|
|
|
642
|
-
/**
|
|
643
|
-
* Complete multipart uploading.
|
|
644
|
-
*/
|
|
645
|
-
function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL, source = 'local', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
646
|
-
return retryIfThrottled(() => request({
|
|
647
|
-
method: 'POST',
|
|
648
|
-
url: getUrl(baseURL, '/multipart/complete/', { jsonerrors: 1 }),
|
|
649
|
-
headers: {
|
|
650
|
-
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
651
|
-
},
|
|
652
|
-
data: buildFormData({
|
|
653
|
-
uuid: uuid,
|
|
654
|
-
UPLOADCARE_PUB_KEY: publicKey,
|
|
655
|
-
source: source
|
|
656
|
-
}),
|
|
657
|
-
signal
|
|
658
|
-
}).then(({ data, headers, request }) => {
|
|
659
|
-
const response = camelizeKeys(JSON.parse(data));
|
|
660
|
-
if ('error' in response) {
|
|
661
|
-
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
662
|
-
}
|
|
663
|
-
else {
|
|
664
|
-
return response;
|
|
665
|
-
}
|
|
666
|
-
}), retryThrottledRequestMaxTimes);
|
|
654
|
+
/**
|
|
655
|
+
* Complete multipart uploading.
|
|
656
|
+
*/
|
|
657
|
+
function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL, source = 'local', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
|
|
658
|
+
return retryIfThrottled(() => request({
|
|
659
|
+
method: 'POST',
|
|
660
|
+
url: getUrl(baseURL, '/multipart/complete/', { jsonerrors: 1 }),
|
|
661
|
+
headers: {
|
|
662
|
+
'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
|
|
663
|
+
},
|
|
664
|
+
data: buildFormData({
|
|
665
|
+
uuid: uuid,
|
|
666
|
+
UPLOADCARE_PUB_KEY: publicKey,
|
|
667
|
+
source: source
|
|
668
|
+
}),
|
|
669
|
+
signal
|
|
670
|
+
}).then(({ data, headers, request }) => {
|
|
671
|
+
const response = camelizeKeys(JSON.parse(data));
|
|
672
|
+
if ('error' in response) {
|
|
673
|
+
throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
return response;
|
|
677
|
+
}
|
|
678
|
+
}), retryThrottledRequestMaxTimes);
|
|
667
679
|
}
|
|
668
680
|
|
|
669
|
-
class UploadcareFile {
|
|
670
|
-
constructor(fileInfo, { baseCDN,
|
|
671
|
-
this.name = null;
|
|
672
|
-
this.size = null;
|
|
673
|
-
this.isStored = null;
|
|
674
|
-
this.isImage = null;
|
|
675
|
-
this.mimeType = null;
|
|
676
|
-
this.cdnUrl = null;
|
|
677
|
-
this.
|
|
678
|
-
this.
|
|
679
|
-
this.
|
|
680
|
-
this.
|
|
681
|
-
this.
|
|
682
|
-
this.
|
|
683
|
-
this.
|
|
684
|
-
const { uuid, s3Bucket } = fileInfo;
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
this.
|
|
692
|
-
this.
|
|
693
|
-
this.
|
|
694
|
-
this.
|
|
695
|
-
this.
|
|
696
|
-
this.
|
|
697
|
-
this.
|
|
698
|
-
this.
|
|
699
|
-
this.
|
|
700
|
-
this.
|
|
701
|
-
this.
|
|
702
|
-
this.
|
|
703
|
-
|
|
704
|
-
this.metadata = fileInfo.metadata || null;
|
|
705
|
-
}
|
|
681
|
+
class UploadcareFile {
|
|
682
|
+
constructor(fileInfo, { baseCDN, fileName }) {
|
|
683
|
+
this.name = null;
|
|
684
|
+
this.size = null;
|
|
685
|
+
this.isStored = null;
|
|
686
|
+
this.isImage = null;
|
|
687
|
+
this.mimeType = null;
|
|
688
|
+
this.cdnUrl = null;
|
|
689
|
+
this.s3Url = null;
|
|
690
|
+
this.originalFilename = null;
|
|
691
|
+
this.imageInfo = null;
|
|
692
|
+
this.videoInfo = null;
|
|
693
|
+
this.contentInfo = null;
|
|
694
|
+
this.metadata = null;
|
|
695
|
+
this.s3Bucket = null;
|
|
696
|
+
const { uuid, s3Bucket } = fileInfo;
|
|
697
|
+
const cdnUrl = `${baseCDN}/${uuid}/`;
|
|
698
|
+
const s3Url = s3Bucket
|
|
699
|
+
? `https://${s3Bucket}.s3.amazonaws.com/${uuid}/${fileInfo.filename}`
|
|
700
|
+
: null;
|
|
701
|
+
this.uuid = uuid;
|
|
702
|
+
this.name = fileName || fileInfo.filename;
|
|
703
|
+
this.size = fileInfo.size;
|
|
704
|
+
this.isStored = fileInfo.isStored;
|
|
705
|
+
this.isImage = fileInfo.isImage;
|
|
706
|
+
this.mimeType = fileInfo.mimeType;
|
|
707
|
+
this.cdnUrl = cdnUrl;
|
|
708
|
+
this.originalFilename = fileInfo.originalFilename;
|
|
709
|
+
this.imageInfo = camelizeKeys(fileInfo.imageInfo);
|
|
710
|
+
this.videoInfo = camelizeKeys(fileInfo.videoInfo);
|
|
711
|
+
this.contentInfo = camelizeKeys(fileInfo.contentInfo);
|
|
712
|
+
this.metadata = fileInfo.metadata || null;
|
|
713
|
+
this.s3Bucket = s3Bucket || null;
|
|
714
|
+
this.s3Url = s3Url;
|
|
715
|
+
}
|
|
706
716
|
}
|
|
707
717
|
|
|
708
|
-
const DEFAULT_INTERVAL = 500;
|
|
709
|
-
const poll = ({ check, interval = DEFAULT_INTERVAL, signal }) => new Promise((resolve, reject) => {
|
|
710
|
-
let timeoutId;
|
|
711
|
-
onCancel(signal, () => {
|
|
712
|
-
timeoutId && clearTimeout(timeoutId);
|
|
713
|
-
reject(cancelError('Poll cancelled'));
|
|
714
|
-
});
|
|
715
|
-
const tick = () => {
|
|
716
|
-
try {
|
|
717
|
-
Promise.resolve(check(signal))
|
|
718
|
-
.then((result) => {
|
|
719
|
-
if (result) {
|
|
720
|
-
resolve(result);
|
|
721
|
-
}
|
|
722
|
-
else {
|
|
723
|
-
timeoutId = setTimeout(tick, interval);
|
|
724
|
-
}
|
|
725
|
-
})
|
|
726
|
-
.catch((error) => reject(error));
|
|
727
|
-
}
|
|
728
|
-
catch (error) {
|
|
729
|
-
reject(error);
|
|
730
|
-
}
|
|
731
|
-
};
|
|
732
|
-
timeoutId = setTimeout(tick, 0);
|
|
718
|
+
const DEFAULT_INTERVAL = 500;
|
|
719
|
+
const poll = ({ check, interval = DEFAULT_INTERVAL, signal }) => new Promise((resolve, reject) => {
|
|
720
|
+
let timeoutId;
|
|
721
|
+
onCancel(signal, () => {
|
|
722
|
+
timeoutId && clearTimeout(timeoutId);
|
|
723
|
+
reject(cancelError('Poll cancelled'));
|
|
724
|
+
});
|
|
725
|
+
const tick = () => {
|
|
726
|
+
try {
|
|
727
|
+
Promise.resolve(check(signal))
|
|
728
|
+
.then((result) => {
|
|
729
|
+
if (result) {
|
|
730
|
+
resolve(result);
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
timeoutId = setTimeout(tick, interval);
|
|
734
|
+
}
|
|
735
|
+
})
|
|
736
|
+
.catch((error) => reject(error));
|
|
737
|
+
}
|
|
738
|
+
catch (error) {
|
|
739
|
+
reject(error);
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
timeoutId = setTimeout(tick, 0);
|
|
733
743
|
});
|
|
734
744
|
|
|
735
|
-
function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, signal, onProgress }) {
|
|
736
|
-
return poll({
|
|
737
|
-
check: (signal) => info(file, {
|
|
738
|
-
publicKey,
|
|
739
|
-
baseURL,
|
|
740
|
-
signal,
|
|
741
|
-
source,
|
|
742
|
-
integration,
|
|
743
|
-
userAgent,
|
|
744
|
-
retryThrottledRequestMaxTimes
|
|
745
|
-
}).then((response) => {
|
|
746
|
-
if (response.isReady) {
|
|
747
|
-
return response;
|
|
748
|
-
}
|
|
749
|
-
onProgress && onProgress({ isComputable: true, value: 1 });
|
|
750
|
-
return false;
|
|
751
|
-
}),
|
|
752
|
-
signal
|
|
753
|
-
});
|
|
745
|
+
function isReadyPoll({ file, publicKey, baseURL, source, integration, userAgent, retryThrottledRequestMaxTimes, signal, onProgress }) {
|
|
746
|
+
return poll({
|
|
747
|
+
check: (signal) => info(file, {
|
|
748
|
+
publicKey,
|
|
749
|
+
baseURL,
|
|
750
|
+
signal,
|
|
751
|
+
source,
|
|
752
|
+
integration,
|
|
753
|
+
userAgent,
|
|
754
|
+
retryThrottledRequestMaxTimes
|
|
755
|
+
}).then((response) => {
|
|
756
|
+
if (response.isReady) {
|
|
757
|
+
return response;
|
|
758
|
+
}
|
|
759
|
+
onProgress && onProgress({ isComputable: true, value: 1 });
|
|
760
|
+
return false;
|
|
761
|
+
}),
|
|
762
|
+
signal
|
|
763
|
+
});
|
|
754
764
|
}
|
|
755
765
|
|
|
756
|
-
const
|
|
757
|
-
return base(file, {
|
|
758
|
-
publicKey,
|
|
759
|
-
fileName,
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
766
|
+
const uploadDirect = (file, { publicKey, fileName, baseURL, secureSignature, secureExpire, store, contentType, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN, metadata }) => {
|
|
767
|
+
return base(file, {
|
|
768
|
+
publicKey,
|
|
769
|
+
fileName,
|
|
770
|
+
contentType,
|
|
771
|
+
baseURL,
|
|
772
|
+
secureSignature,
|
|
773
|
+
secureExpire,
|
|
774
|
+
store,
|
|
775
|
+
signal,
|
|
776
|
+
onProgress,
|
|
777
|
+
source,
|
|
778
|
+
integration,
|
|
779
|
+
userAgent,
|
|
780
|
+
retryThrottledRequestMaxTimes,
|
|
781
|
+
metadata
|
|
782
|
+
})
|
|
783
|
+
.then(({ file }) => {
|
|
784
|
+
return isReadyPoll({
|
|
785
|
+
file,
|
|
786
|
+
publicKey,
|
|
787
|
+
baseURL,
|
|
788
|
+
source,
|
|
789
|
+
integration,
|
|
790
|
+
userAgent,
|
|
791
|
+
retryThrottledRequestMaxTimes,
|
|
792
|
+
onProgress,
|
|
793
|
+
signal
|
|
794
|
+
});
|
|
795
|
+
})
|
|
796
|
+
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
|
|
786
797
|
};
|
|
787
798
|
|
|
788
|
-
const race = (fns, { signal } = {}) => {
|
|
789
|
-
let lastError = null;
|
|
790
|
-
let winnerIndex = null;
|
|
791
|
-
const controllers = fns.map(() => new AbortController());
|
|
792
|
-
const createStopRaceCallback = (i) => () => {
|
|
793
|
-
winnerIndex = i;
|
|
794
|
-
controllers.forEach((controller, index) => index !== i && controller.abort());
|
|
795
|
-
};
|
|
796
|
-
onCancel(signal, () => {
|
|
797
|
-
controllers.forEach((controller) => controller.abort());
|
|
798
|
-
});
|
|
799
|
-
return Promise.all(fns.map((fn, i) => {
|
|
800
|
-
const stopRace = createStopRaceCallback(i);
|
|
801
|
-
return Promise.resolve()
|
|
802
|
-
.then(() => fn({ stopRace, signal: controllers[i].signal }))
|
|
803
|
-
.then((result) => {
|
|
804
|
-
stopRace();
|
|
805
|
-
return result;
|
|
806
|
-
})
|
|
807
|
-
.catch((error) => {
|
|
808
|
-
lastError = error;
|
|
809
|
-
return null;
|
|
810
|
-
});
|
|
811
|
-
})).then((results) => {
|
|
812
|
-
if (winnerIndex === null) {
|
|
813
|
-
throw lastError;
|
|
814
|
-
}
|
|
815
|
-
else {
|
|
816
|
-
return results[winnerIndex];
|
|
817
|
-
}
|
|
818
|
-
});
|
|
799
|
+
const race = (fns, { signal } = {}) => {
|
|
800
|
+
let lastError = null;
|
|
801
|
+
let winnerIndex = null;
|
|
802
|
+
const controllers = fns.map(() => new AbortController());
|
|
803
|
+
const createStopRaceCallback = (i) => () => {
|
|
804
|
+
winnerIndex = i;
|
|
805
|
+
controllers.forEach((controller, index) => index !== i && controller.abort());
|
|
806
|
+
};
|
|
807
|
+
onCancel(signal, () => {
|
|
808
|
+
controllers.forEach((controller) => controller.abort());
|
|
809
|
+
});
|
|
810
|
+
return Promise.all(fns.map((fn, i) => {
|
|
811
|
+
const stopRace = createStopRaceCallback(i);
|
|
812
|
+
return Promise.resolve()
|
|
813
|
+
.then(() => fn({ stopRace, signal: controllers[i].signal }))
|
|
814
|
+
.then((result) => {
|
|
815
|
+
stopRace();
|
|
816
|
+
return result;
|
|
817
|
+
})
|
|
818
|
+
.catch((error) => {
|
|
819
|
+
lastError = error;
|
|
820
|
+
return null;
|
|
821
|
+
});
|
|
822
|
+
})).then((results) => {
|
|
823
|
+
if (winnerIndex === null) {
|
|
824
|
+
throw lastError;
|
|
825
|
+
}
|
|
826
|
+
else {
|
|
827
|
+
return results[winnerIndex];
|
|
828
|
+
}
|
|
829
|
+
});
|
|
819
830
|
};
|
|
820
831
|
|
|
821
|
-
class Events {
|
|
822
|
-
constructor() {
|
|
823
|
-
this.events = Object.create({});
|
|
824
|
-
}
|
|
825
|
-
emit(event, data) {
|
|
826
|
-
var _a;
|
|
827
|
-
(_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.forEach((fn) => fn(data));
|
|
828
|
-
}
|
|
829
|
-
on(event, callback) {
|
|
830
|
-
this.events[event] = this.events[event] || [];
|
|
831
|
-
this.events[event].push(callback);
|
|
832
|
-
}
|
|
833
|
-
off(event, callback) {
|
|
834
|
-
if (callback) {
|
|
835
|
-
this.events[event] = this.events[event].filter((fn) => fn !== callback);
|
|
836
|
-
}
|
|
837
|
-
else {
|
|
838
|
-
this.events[event] = [];
|
|
839
|
-
}
|
|
840
|
-
}
|
|
832
|
+
class Events {
|
|
833
|
+
constructor() {
|
|
834
|
+
this.events = Object.create({});
|
|
835
|
+
}
|
|
836
|
+
emit(event, data) {
|
|
837
|
+
var _a;
|
|
838
|
+
(_a = this.events[event]) === null || _a === void 0 ? void 0 : _a.forEach((fn) => fn(data));
|
|
839
|
+
}
|
|
840
|
+
on(event, callback) {
|
|
841
|
+
this.events[event] = this.events[event] || [];
|
|
842
|
+
this.events[event].push(callback);
|
|
843
|
+
}
|
|
844
|
+
off(event, callback) {
|
|
845
|
+
if (callback) {
|
|
846
|
+
this.events[event] = this.events[event].filter((fn) => fn !== callback);
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
this.events[event] = [];
|
|
850
|
+
}
|
|
851
|
+
}
|
|
841
852
|
}
|
|
842
853
|
|
|
843
|
-
const response = (type, data) => {
|
|
844
|
-
if (type === 'success') {
|
|
845
|
-
return Object.assign({ status: Status.Success }, data);
|
|
846
|
-
}
|
|
847
|
-
if (type === 'progress') {
|
|
848
|
-
return Object.assign({ status: Status.Progress }, data);
|
|
849
|
-
}
|
|
850
|
-
return Object.assign({ status: Status.Error }, data);
|
|
851
|
-
};
|
|
852
|
-
class Pusher {
|
|
853
|
-
constructor(pusherKey, disconnectTime = 30000) {
|
|
854
|
-
this.ws = undefined;
|
|
855
|
-
this.queue = [];
|
|
856
|
-
this.isConnected = false;
|
|
857
|
-
this.subscribers = 0;
|
|
858
|
-
this.emmitter = new Events();
|
|
859
|
-
this.disconnectTimeoutId = null;
|
|
860
|
-
this.key = pusherKey;
|
|
861
|
-
this.disconnectTime = disconnectTime;
|
|
862
|
-
}
|
|
863
|
-
connect() {
|
|
864
|
-
this.disconnectTimeoutId && clearTimeout(this.disconnectTimeoutId);
|
|
865
|
-
if (!this.isConnected && !this.ws) {
|
|
866
|
-
const pusherUrl = `wss://ws.pusherapp.com/app/${this.key}?protocol=5&client=js&version=1.12.2`;
|
|
867
|
-
this.ws = new WebSocket(pusherUrl);
|
|
868
|
-
this.ws.addEventListener('error', (error) => {
|
|
869
|
-
this.emmitter.emit('error', new Error(error.message));
|
|
870
|
-
});
|
|
871
|
-
this.emmitter.on('connected', () => {
|
|
872
|
-
this.isConnected = true;
|
|
873
|
-
this.queue.forEach((message) => this.send(message.event, message.data));
|
|
874
|
-
this.queue = [];
|
|
875
|
-
});
|
|
876
|
-
this.ws.addEventListener('message', (e) => {
|
|
877
|
-
const data = JSON.parse(e.data.toString());
|
|
878
|
-
switch (data.event) {
|
|
879
|
-
case 'pusher:connection_established': {
|
|
880
|
-
this.emmitter.emit('connected', undefined);
|
|
881
|
-
break;
|
|
882
|
-
}
|
|
883
|
-
case 'pusher:ping': {
|
|
884
|
-
this.send('pusher:pong', {});
|
|
885
|
-
break;
|
|
886
|
-
}
|
|
887
|
-
case 'progress':
|
|
888
|
-
case 'success':
|
|
889
|
-
case 'fail': {
|
|
890
|
-
this.emmitter.emit(data.channel, response(data.event, JSON.parse(data.data)));
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
});
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
disconnect() {
|
|
897
|
-
const actualDisconect = () => {
|
|
898
|
-
var _a;
|
|
899
|
-
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.close();
|
|
900
|
-
this.ws = undefined;
|
|
901
|
-
this.isConnected = false;
|
|
902
|
-
};
|
|
903
|
-
if (this.disconnectTime) {
|
|
904
|
-
this.disconnectTimeoutId = setTimeout(() => {
|
|
905
|
-
actualDisconect();
|
|
906
|
-
}, this.disconnectTime);
|
|
907
|
-
}
|
|
908
|
-
else {
|
|
909
|
-
actualDisconect();
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
send(event, data) {
|
|
913
|
-
var _a;
|
|
914
|
-
const str = JSON.stringify({ event, data });
|
|
915
|
-
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.send(str);
|
|
916
|
-
}
|
|
917
|
-
subscribe(token, handler) {
|
|
918
|
-
this.subscribers += 1;
|
|
919
|
-
this.connect();
|
|
920
|
-
const channel = `task-status-${token}`;
|
|
921
|
-
const message = {
|
|
922
|
-
event: 'pusher:subscribe',
|
|
923
|
-
data: { channel }
|
|
924
|
-
};
|
|
925
|
-
this.emmitter.on(channel, handler);
|
|
926
|
-
if (this.isConnected) {
|
|
927
|
-
this.send(message.event, message.data);
|
|
928
|
-
}
|
|
929
|
-
else {
|
|
930
|
-
this.queue.push(message);
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
unsubscribe(token) {
|
|
934
|
-
this.subscribers -= 1;
|
|
935
|
-
const channel = `task-status-${token}`;
|
|
936
|
-
const message = {
|
|
937
|
-
event: 'pusher:unsubscribe',
|
|
938
|
-
data: { channel }
|
|
939
|
-
};
|
|
940
|
-
this.emmitter.off(channel);
|
|
941
|
-
if (this.isConnected) {
|
|
942
|
-
this.send(message.event, message.data);
|
|
943
|
-
}
|
|
944
|
-
else {
|
|
945
|
-
this.queue = this.queue.filter((msg) => msg.data.channel !== channel);
|
|
946
|
-
}
|
|
947
|
-
if (this.subscribers === 0) {
|
|
948
|
-
this.disconnect();
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
onError(callback) {
|
|
952
|
-
this.emmitter.on('error', callback);
|
|
953
|
-
return () => this.emmitter.off('error', callback);
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
let pusher = null;
|
|
957
|
-
const getPusher = (key) => {
|
|
958
|
-
if (!pusher) {
|
|
959
|
-
// no timeout for nodeJS and 30000 ms for browser
|
|
960
|
-
const disconectTimeout = typeof window === 'undefined' ? 0 : 30000;
|
|
961
|
-
pusher = new Pusher(key, disconectTimeout);
|
|
962
|
-
}
|
|
963
|
-
return pusher;
|
|
964
|
-
};
|
|
965
|
-
const preconnect = (key) => {
|
|
966
|
-
getPusher(key).connect();
|
|
854
|
+
const response = (type, data) => {
|
|
855
|
+
if (type === 'success') {
|
|
856
|
+
return Object.assign({ status: Status.Success }, data);
|
|
857
|
+
}
|
|
858
|
+
if (type === 'progress') {
|
|
859
|
+
return Object.assign({ status: Status.Progress }, data);
|
|
860
|
+
}
|
|
861
|
+
return Object.assign({ status: Status.Error }, data);
|
|
862
|
+
};
|
|
863
|
+
class Pusher {
|
|
864
|
+
constructor(pusherKey, disconnectTime = 30000) {
|
|
865
|
+
this.ws = undefined;
|
|
866
|
+
this.queue = [];
|
|
867
|
+
this.isConnected = false;
|
|
868
|
+
this.subscribers = 0;
|
|
869
|
+
this.emmitter = new Events();
|
|
870
|
+
this.disconnectTimeoutId = null;
|
|
871
|
+
this.key = pusherKey;
|
|
872
|
+
this.disconnectTime = disconnectTime;
|
|
873
|
+
}
|
|
874
|
+
connect() {
|
|
875
|
+
this.disconnectTimeoutId && clearTimeout(this.disconnectTimeoutId);
|
|
876
|
+
if (!this.isConnected && !this.ws) {
|
|
877
|
+
const pusherUrl = `wss://ws.pusherapp.com/app/${this.key}?protocol=5&client=js&version=1.12.2`;
|
|
878
|
+
this.ws = new WebSocket(pusherUrl);
|
|
879
|
+
this.ws.addEventListener('error', (error) => {
|
|
880
|
+
this.emmitter.emit('error', new Error(error.message));
|
|
881
|
+
});
|
|
882
|
+
this.emmitter.on('connected', () => {
|
|
883
|
+
this.isConnected = true;
|
|
884
|
+
this.queue.forEach((message) => this.send(message.event, message.data));
|
|
885
|
+
this.queue = [];
|
|
886
|
+
});
|
|
887
|
+
this.ws.addEventListener('message', (e) => {
|
|
888
|
+
const data = JSON.parse(e.data.toString());
|
|
889
|
+
switch (data.event) {
|
|
890
|
+
case 'pusher:connection_established': {
|
|
891
|
+
this.emmitter.emit('connected', undefined);
|
|
892
|
+
break;
|
|
893
|
+
}
|
|
894
|
+
case 'pusher:ping': {
|
|
895
|
+
this.send('pusher:pong', {});
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
case 'progress':
|
|
899
|
+
case 'success':
|
|
900
|
+
case 'fail': {
|
|
901
|
+
this.emmitter.emit(data.channel, response(data.event, JSON.parse(data.data)));
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
disconnect() {
|
|
908
|
+
const actualDisconect = () => {
|
|
909
|
+
var _a;
|
|
910
|
+
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.close();
|
|
911
|
+
this.ws = undefined;
|
|
912
|
+
this.isConnected = false;
|
|
913
|
+
};
|
|
914
|
+
if (this.disconnectTime) {
|
|
915
|
+
this.disconnectTimeoutId = setTimeout(() => {
|
|
916
|
+
actualDisconect();
|
|
917
|
+
}, this.disconnectTime);
|
|
918
|
+
}
|
|
919
|
+
else {
|
|
920
|
+
actualDisconect();
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
send(event, data) {
|
|
924
|
+
var _a;
|
|
925
|
+
const str = JSON.stringify({ event, data });
|
|
926
|
+
(_a = this.ws) === null || _a === void 0 ? void 0 : _a.send(str);
|
|
927
|
+
}
|
|
928
|
+
subscribe(token, handler) {
|
|
929
|
+
this.subscribers += 1;
|
|
930
|
+
this.connect();
|
|
931
|
+
const channel = `task-status-${token}`;
|
|
932
|
+
const message = {
|
|
933
|
+
event: 'pusher:subscribe',
|
|
934
|
+
data: { channel }
|
|
935
|
+
};
|
|
936
|
+
this.emmitter.on(channel, handler);
|
|
937
|
+
if (this.isConnected) {
|
|
938
|
+
this.send(message.event, message.data);
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
this.queue.push(message);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
unsubscribe(token) {
|
|
945
|
+
this.subscribers -= 1;
|
|
946
|
+
const channel = `task-status-${token}`;
|
|
947
|
+
const message = {
|
|
948
|
+
event: 'pusher:unsubscribe',
|
|
949
|
+
data: { channel }
|
|
950
|
+
};
|
|
951
|
+
this.emmitter.off(channel);
|
|
952
|
+
if (this.isConnected) {
|
|
953
|
+
this.send(message.event, message.data);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
this.queue = this.queue.filter((msg) => msg.data.channel !== channel);
|
|
957
|
+
}
|
|
958
|
+
if (this.subscribers === 0) {
|
|
959
|
+
this.disconnect();
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
onError(callback) {
|
|
963
|
+
this.emmitter.on('error', callback);
|
|
964
|
+
return () => this.emmitter.off('error', callback);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
let pusher = null;
|
|
968
|
+
const getPusher = (key) => {
|
|
969
|
+
if (!pusher) {
|
|
970
|
+
// no timeout for nodeJS and 30000 ms for browser
|
|
971
|
+
const disconectTimeout = typeof window === 'undefined' ? 0 : 30000;
|
|
972
|
+
pusher = new Pusher(key, disconectTimeout);
|
|
973
|
+
}
|
|
974
|
+
return pusher;
|
|
975
|
+
};
|
|
976
|
+
const preconnect = (key) => {
|
|
977
|
+
getPusher(key).connect();
|
|
967
978
|
};
|
|
968
979
|
|
|
969
|
-
function pollStrategy({ token, publicKey, baseURL, integration, userAgent, retryThrottledRequestMaxTimes, onProgress, signal }) {
|
|
970
|
-
return poll({
|
|
971
|
-
check: (signal) => fromUrlStatus(token, {
|
|
972
|
-
publicKey,
|
|
973
|
-
baseURL,
|
|
974
|
-
integration,
|
|
975
|
-
userAgent,
|
|
976
|
-
retryThrottledRequestMaxTimes,
|
|
977
|
-
signal
|
|
978
|
-
}).then((response) => {
|
|
979
|
-
switch (response.status) {
|
|
980
|
-
case Status.Error: {
|
|
981
|
-
return new UploadClientError(response.error, response.errorCode);
|
|
982
|
-
}
|
|
983
|
-
case Status.Waiting: {
|
|
984
|
-
return false;
|
|
985
|
-
}
|
|
986
|
-
case Status.Unknown: {
|
|
987
|
-
return new UploadClientError(`Token "${token}" was not found.`);
|
|
988
|
-
}
|
|
989
|
-
case Status.Progress: {
|
|
990
|
-
if (onProgress) {
|
|
991
|
-
if (response.total === 'unknown') {
|
|
992
|
-
onProgress({ isComputable: false });
|
|
993
|
-
}
|
|
994
|
-
else {
|
|
995
|
-
onProgress({
|
|
996
|
-
isComputable: true,
|
|
997
|
-
value: response.done / response.total
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
return false;
|
|
1002
|
-
}
|
|
1003
|
-
case Status.Success: {
|
|
1004
|
-
if (onProgress)
|
|
1005
|
-
onProgress({
|
|
1006
|
-
isComputable: true,
|
|
1007
|
-
value: response.done / response.total
|
|
1008
|
-
});
|
|
1009
|
-
return response;
|
|
1010
|
-
}
|
|
1011
|
-
default: {
|
|
1012
|
-
throw new Error('Unknown status');
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
}),
|
|
1016
|
-
signal
|
|
1017
|
-
});
|
|
1018
|
-
}
|
|
1019
|
-
const pushStrategy = ({ token, pusherKey, signal, onProgress }) => new Promise((resolve, reject) => {
|
|
1020
|
-
const pusher = getPusher(pusherKey);
|
|
1021
|
-
const unsubErrorHandler = pusher.onError(reject);
|
|
1022
|
-
const destroy = () => {
|
|
1023
|
-
unsubErrorHandler();
|
|
1024
|
-
pusher.unsubscribe(token);
|
|
1025
|
-
};
|
|
1026
|
-
onCancel(signal, () => {
|
|
1027
|
-
destroy();
|
|
1028
|
-
reject(cancelError('pusher cancelled'));
|
|
1029
|
-
});
|
|
1030
|
-
pusher.subscribe(token, (result) => {
|
|
1031
|
-
switch (result.status) {
|
|
1032
|
-
case Status.Progress: {
|
|
1033
|
-
if (onProgress) {
|
|
1034
|
-
if (result.total === 'unknown') {
|
|
1035
|
-
onProgress({ isComputable: false });
|
|
1036
|
-
}
|
|
1037
|
-
else {
|
|
1038
|
-
onProgress({
|
|
1039
|
-
isComputable: true,
|
|
1040
|
-
value: result.done / result.total
|
|
1041
|
-
});
|
|
1042
|
-
}
|
|
1043
|
-
}
|
|
1044
|
-
break;
|
|
1045
|
-
}
|
|
1046
|
-
case Status.Success: {
|
|
1047
|
-
destroy();
|
|
1048
|
-
if (onProgress)
|
|
1049
|
-
onProgress({
|
|
1050
|
-
isComputable: true,
|
|
1051
|
-
value: result.done / result.total
|
|
1052
|
-
});
|
|
1053
|
-
resolve(result);
|
|
1054
|
-
break;
|
|
1055
|
-
}
|
|
1056
|
-
case Status.Error: {
|
|
1057
|
-
destroy();
|
|
1058
|
-
reject(new UploadClientError(result.msg, result.error_code));
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
|
-
});
|
|
1062
|
-
});
|
|
1063
|
-
const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, pusherKey = defaultSettings.pusherKey, metadata }) => Promise.resolve(preconnect(pusherKey))
|
|
1064
|
-
.then(() => fromUrl(sourceUrl, {
|
|
1065
|
-
publicKey,
|
|
1066
|
-
fileName,
|
|
1067
|
-
baseURL,
|
|
1068
|
-
checkForUrlDuplicates,
|
|
1069
|
-
saveUrlForRecurrentUploads,
|
|
1070
|
-
secureSignature,
|
|
1071
|
-
secureExpire,
|
|
1072
|
-
store,
|
|
1073
|
-
signal,
|
|
1074
|
-
source,
|
|
1075
|
-
integration,
|
|
1076
|
-
userAgent,
|
|
1077
|
-
retryThrottledRequestMaxTimes,
|
|
1078
|
-
metadata
|
|
1079
|
-
}))
|
|
1080
|
-
.catch((error) => {
|
|
1081
|
-
const pusher = getPusher(pusherKey);
|
|
1082
|
-
pusher === null || pusher === void 0 ? void 0 : pusher.disconnect();
|
|
1083
|
-
return Promise.reject(error);
|
|
1084
|
-
})
|
|
1085
|
-
.then((urlResponse) => {
|
|
1086
|
-
if (urlResponse.type === TypeEnum.FileInfo) {
|
|
1087
|
-
return urlResponse;
|
|
1088
|
-
}
|
|
1089
|
-
else {
|
|
1090
|
-
return race([
|
|
1091
|
-
({ signal }) => pollStrategy({
|
|
1092
|
-
token: urlResponse.token,
|
|
1093
|
-
publicKey,
|
|
1094
|
-
baseURL,
|
|
1095
|
-
integration,
|
|
1096
|
-
userAgent,
|
|
1097
|
-
retryThrottledRequestMaxTimes,
|
|
1098
|
-
onProgress,
|
|
1099
|
-
signal
|
|
1100
|
-
}),
|
|
1101
|
-
({ signal }) => pushStrategy({
|
|
1102
|
-
token: urlResponse.token,
|
|
1103
|
-
pusherKey,
|
|
1104
|
-
signal,
|
|
1105
|
-
onProgress
|
|
1106
|
-
})
|
|
1107
|
-
], { signal });
|
|
1108
|
-
}
|
|
1109
|
-
})
|
|
1110
|
-
.then((result) => {
|
|
1111
|
-
if (result instanceof UploadClientError)
|
|
1112
|
-
throw result;
|
|
1113
|
-
return result;
|
|
1114
|
-
})
|
|
1115
|
-
.then((result) => isReadyPoll({
|
|
1116
|
-
file: result.uuid,
|
|
1117
|
-
publicKey,
|
|
1118
|
-
baseURL,
|
|
1119
|
-
integration,
|
|
1120
|
-
userAgent,
|
|
1121
|
-
retryThrottledRequestMaxTimes,
|
|
1122
|
-
onProgress,
|
|
1123
|
-
signal
|
|
1124
|
-
}))
|
|
980
|
+
function pollStrategy({ token, publicKey, baseURL, integration, userAgent, retryThrottledRequestMaxTimes, onProgress, signal }) {
|
|
981
|
+
return poll({
|
|
982
|
+
check: (signal) => fromUrlStatus(token, {
|
|
983
|
+
publicKey,
|
|
984
|
+
baseURL,
|
|
985
|
+
integration,
|
|
986
|
+
userAgent,
|
|
987
|
+
retryThrottledRequestMaxTimes,
|
|
988
|
+
signal
|
|
989
|
+
}).then((response) => {
|
|
990
|
+
switch (response.status) {
|
|
991
|
+
case Status.Error: {
|
|
992
|
+
return new UploadClientError(response.error, response.errorCode);
|
|
993
|
+
}
|
|
994
|
+
case Status.Waiting: {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
case Status.Unknown: {
|
|
998
|
+
return new UploadClientError(`Token "${token}" was not found.`);
|
|
999
|
+
}
|
|
1000
|
+
case Status.Progress: {
|
|
1001
|
+
if (onProgress) {
|
|
1002
|
+
if (response.total === 'unknown') {
|
|
1003
|
+
onProgress({ isComputable: false });
|
|
1004
|
+
}
|
|
1005
|
+
else {
|
|
1006
|
+
onProgress({
|
|
1007
|
+
isComputable: true,
|
|
1008
|
+
value: response.done / response.total
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
return false;
|
|
1013
|
+
}
|
|
1014
|
+
case Status.Success: {
|
|
1015
|
+
if (onProgress)
|
|
1016
|
+
onProgress({
|
|
1017
|
+
isComputable: true,
|
|
1018
|
+
value: response.done / response.total
|
|
1019
|
+
});
|
|
1020
|
+
return response;
|
|
1021
|
+
}
|
|
1022
|
+
default: {
|
|
1023
|
+
throw new Error('Unknown status');
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}),
|
|
1027
|
+
signal
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
const pushStrategy = ({ token, pusherKey, signal, onProgress }) => new Promise((resolve, reject) => {
|
|
1031
|
+
const pusher = getPusher(pusherKey);
|
|
1032
|
+
const unsubErrorHandler = pusher.onError(reject);
|
|
1033
|
+
const destroy = () => {
|
|
1034
|
+
unsubErrorHandler();
|
|
1035
|
+
pusher.unsubscribe(token);
|
|
1036
|
+
};
|
|
1037
|
+
onCancel(signal, () => {
|
|
1038
|
+
destroy();
|
|
1039
|
+
reject(cancelError('pusher cancelled'));
|
|
1040
|
+
});
|
|
1041
|
+
pusher.subscribe(token, (result) => {
|
|
1042
|
+
switch (result.status) {
|
|
1043
|
+
case Status.Progress: {
|
|
1044
|
+
if (onProgress) {
|
|
1045
|
+
if (result.total === 'unknown') {
|
|
1046
|
+
onProgress({ isComputable: false });
|
|
1047
|
+
}
|
|
1048
|
+
else {
|
|
1049
|
+
onProgress({
|
|
1050
|
+
isComputable: true,
|
|
1051
|
+
value: result.done / result.total
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
break;
|
|
1056
|
+
}
|
|
1057
|
+
case Status.Success: {
|
|
1058
|
+
destroy();
|
|
1059
|
+
if (onProgress)
|
|
1060
|
+
onProgress({
|
|
1061
|
+
isComputable: true,
|
|
1062
|
+
value: result.done / result.total
|
|
1063
|
+
});
|
|
1064
|
+
resolve(result);
|
|
1065
|
+
break;
|
|
1066
|
+
}
|
|
1067
|
+
case Status.Error: {
|
|
1068
|
+
destroy();
|
|
1069
|
+
reject(new UploadClientError(result.msg, result.error_code));
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
});
|
|
1074
|
+
const uploadFromUrl = (sourceUrl, { publicKey, fileName, baseURL, baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, pusherKey = defaultSettings.pusherKey, metadata }) => Promise.resolve(preconnect(pusherKey))
|
|
1075
|
+
.then(() => fromUrl(sourceUrl, {
|
|
1076
|
+
publicKey,
|
|
1077
|
+
fileName,
|
|
1078
|
+
baseURL,
|
|
1079
|
+
checkForUrlDuplicates,
|
|
1080
|
+
saveUrlForRecurrentUploads,
|
|
1081
|
+
secureSignature,
|
|
1082
|
+
secureExpire,
|
|
1083
|
+
store,
|
|
1084
|
+
signal,
|
|
1085
|
+
source,
|
|
1086
|
+
integration,
|
|
1087
|
+
userAgent,
|
|
1088
|
+
retryThrottledRequestMaxTimes,
|
|
1089
|
+
metadata
|
|
1090
|
+
}))
|
|
1091
|
+
.catch((error) => {
|
|
1092
|
+
const pusher = getPusher(pusherKey);
|
|
1093
|
+
pusher === null || pusher === void 0 ? void 0 : pusher.disconnect();
|
|
1094
|
+
return Promise.reject(error);
|
|
1095
|
+
})
|
|
1096
|
+
.then((urlResponse) => {
|
|
1097
|
+
if (urlResponse.type === TypeEnum.FileInfo) {
|
|
1098
|
+
return urlResponse;
|
|
1099
|
+
}
|
|
1100
|
+
else {
|
|
1101
|
+
return race([
|
|
1102
|
+
({ signal }) => pollStrategy({
|
|
1103
|
+
token: urlResponse.token,
|
|
1104
|
+
publicKey,
|
|
1105
|
+
baseURL,
|
|
1106
|
+
integration,
|
|
1107
|
+
userAgent,
|
|
1108
|
+
retryThrottledRequestMaxTimes,
|
|
1109
|
+
onProgress,
|
|
1110
|
+
signal
|
|
1111
|
+
}),
|
|
1112
|
+
({ signal }) => pushStrategy({
|
|
1113
|
+
token: urlResponse.token,
|
|
1114
|
+
pusherKey,
|
|
1115
|
+
signal,
|
|
1116
|
+
onProgress
|
|
1117
|
+
})
|
|
1118
|
+
], { signal });
|
|
1119
|
+
}
|
|
1120
|
+
})
|
|
1121
|
+
.then((result) => {
|
|
1122
|
+
if (result instanceof UploadClientError)
|
|
1123
|
+
throw result;
|
|
1124
|
+
return result;
|
|
1125
|
+
})
|
|
1126
|
+
.then((result) => isReadyPoll({
|
|
1127
|
+
file: result.uuid,
|
|
1128
|
+
publicKey,
|
|
1129
|
+
baseURL,
|
|
1130
|
+
integration,
|
|
1131
|
+
userAgent,
|
|
1132
|
+
retryThrottledRequestMaxTimes,
|
|
1133
|
+
onProgress,
|
|
1134
|
+
signal
|
|
1135
|
+
}))
|
|
1125
1136
|
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
|
|
1126
1137
|
|
|
1127
|
-
const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN }) => {
|
|
1128
|
-
return info(uuid, {
|
|
1129
|
-
publicKey,
|
|
1130
|
-
baseURL,
|
|
1131
|
-
signal,
|
|
1132
|
-
source,
|
|
1133
|
-
integration,
|
|
1134
|
-
userAgent,
|
|
1135
|
-
retryThrottledRequestMaxTimes
|
|
1136
|
-
})
|
|
1137
|
-
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
|
|
1138
|
-
.then((result) => {
|
|
1139
|
-
// hack for node ¯\_(ツ)_/¯
|
|
1140
|
-
if (onProgress)
|
|
1141
|
-
onProgress({
|
|
1142
|
-
isComputable: true,
|
|
1143
|
-
value: 1
|
|
1144
|
-
});
|
|
1145
|
-
return result;
|
|
1146
|
-
});
|
|
1138
|
+
const uploadFromUploaded = (uuid, { publicKey, fileName, baseURL, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, baseCDN }) => {
|
|
1139
|
+
return info(uuid, {
|
|
1140
|
+
publicKey,
|
|
1141
|
+
baseURL,
|
|
1142
|
+
signal,
|
|
1143
|
+
source,
|
|
1144
|
+
integration,
|
|
1145
|
+
userAgent,
|
|
1146
|
+
retryThrottledRequestMaxTimes
|
|
1147
|
+
})
|
|
1148
|
+
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN, fileName }))
|
|
1149
|
+
.then((result) => {
|
|
1150
|
+
// hack for node ¯\_(ツ)_/¯
|
|
1151
|
+
if (onProgress)
|
|
1152
|
+
onProgress({
|
|
1153
|
+
isComputable: true,
|
|
1154
|
+
value: 1
|
|
1155
|
+
});
|
|
1156
|
+
return result;
|
|
1157
|
+
});
|
|
1147
1158
|
};
|
|
1148
1159
|
|
|
1149
|
-
/**
|
|
1150
|
-
* Get file size.
|
|
1151
|
-
*/
|
|
1152
|
-
const getFileSize = (file) => {
|
|
1153
|
-
return file.length || file.size;
|
|
1154
|
-
};
|
|
1155
|
-
/**
|
|
1156
|
-
* Check if FileData is multipart data.
|
|
1157
|
-
*/
|
|
1158
|
-
const isMultipart = (fileSize, multipartMinFileSize = defaultSettings.multipartMinFileSize) => {
|
|
1159
|
-
return fileSize >= multipartMinFileSize;
|
|
1160
|
+
/**
|
|
1161
|
+
* Get file size.
|
|
1162
|
+
*/
|
|
1163
|
+
const getFileSize = (file) => {
|
|
1164
|
+
return file.length || file.size;
|
|
1165
|
+
};
|
|
1166
|
+
/**
|
|
1167
|
+
* Check if FileData is multipart data.
|
|
1168
|
+
*/
|
|
1169
|
+
const isMultipart = (fileSize, multipartMinFileSize = defaultSettings.multipartMinFileSize) => {
|
|
1170
|
+
return fileSize >= multipartMinFileSize;
|
|
1160
1171
|
};
|
|
1161
1172
|
|
|
1162
|
-
const sliceChunk = (file, index, fileSize, chunkSize) => {
|
|
1163
|
-
const start = chunkSize * index;
|
|
1164
|
-
const end = Math.min(start + chunkSize, fileSize);
|
|
1165
|
-
return file.slice(start, end);
|
|
1173
|
+
const sliceChunk = (file, index, fileSize, chunkSize) => {
|
|
1174
|
+
const start = chunkSize * index;
|
|
1175
|
+
const end = Math.min(start + chunkSize, fileSize);
|
|
1176
|
+
return file.slice(start, end);
|
|
1166
1177
|
};
|
|
1167
1178
|
|
|
1168
|
-
function prepareChunks(file, fileSize, chunkSize) {
|
|
1169
|
-
return (index) => sliceChunk(file, index, fileSize, chunkSize);
|
|
1179
|
+
function prepareChunks(file, fileSize, chunkSize) {
|
|
1180
|
+
return (index) => sliceChunk(file, index, fileSize, chunkSize);
|
|
1170
1181
|
}
|
|
1171
1182
|
|
|
1172
|
-
const runWithConcurrency = (concurrency, tasks) => {
|
|
1173
|
-
return new Promise((resolve, reject) => {
|
|
1174
|
-
const results = [];
|
|
1175
|
-
let rejected = false;
|
|
1176
|
-
let settled = tasks.length;
|
|
1177
|
-
const forRun = [...tasks];
|
|
1178
|
-
const run = () => {
|
|
1179
|
-
const index = tasks.length - forRun.length;
|
|
1180
|
-
const next = forRun.shift();
|
|
1181
|
-
if (next) {
|
|
1182
|
-
next()
|
|
1183
|
-
.then((result) => {
|
|
1184
|
-
if (rejected)
|
|
1185
|
-
return;
|
|
1186
|
-
results[index] = result;
|
|
1187
|
-
settled -= 1;
|
|
1188
|
-
if (settled) {
|
|
1189
|
-
run();
|
|
1190
|
-
}
|
|
1191
|
-
else {
|
|
1192
|
-
resolve(results);
|
|
1193
|
-
}
|
|
1194
|
-
})
|
|
1195
|
-
.catch((error) => {
|
|
1196
|
-
rejected = true;
|
|
1197
|
-
reject(error);
|
|
1198
|
-
});
|
|
1199
|
-
}
|
|
1200
|
-
};
|
|
1201
|
-
for (let i = 0; i < concurrency; i++) {
|
|
1202
|
-
run();
|
|
1203
|
-
}
|
|
1204
|
-
});
|
|
1183
|
+
const runWithConcurrency = (concurrency, tasks) => {
|
|
1184
|
+
return new Promise((resolve, reject) => {
|
|
1185
|
+
const results = [];
|
|
1186
|
+
let rejected = false;
|
|
1187
|
+
let settled = tasks.length;
|
|
1188
|
+
const forRun = [...tasks];
|
|
1189
|
+
const run = () => {
|
|
1190
|
+
const index = tasks.length - forRun.length;
|
|
1191
|
+
const next = forRun.shift();
|
|
1192
|
+
if (next) {
|
|
1193
|
+
next()
|
|
1194
|
+
.then((result) => {
|
|
1195
|
+
if (rejected)
|
|
1196
|
+
return;
|
|
1197
|
+
results[index] = result;
|
|
1198
|
+
settled -= 1;
|
|
1199
|
+
if (settled) {
|
|
1200
|
+
run();
|
|
1201
|
+
}
|
|
1202
|
+
else {
|
|
1203
|
+
resolve(results);
|
|
1204
|
+
}
|
|
1205
|
+
})
|
|
1206
|
+
.catch((error) => {
|
|
1207
|
+
rejected = true;
|
|
1208
|
+
reject(error);
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
for (let i = 0; i < concurrency; i++) {
|
|
1213
|
+
run();
|
|
1214
|
+
}
|
|
1215
|
+
});
|
|
1205
1216
|
};
|
|
1206
1217
|
|
|
1207
|
-
const uploadPartWithRetry = (chunk, url, { publicKey, onProgress, signal, integration, multipartMaxAttempts }) => retrier(({ attempt, retry }) => multipartUpload(chunk, url, {
|
|
1208
|
-
publicKey,
|
|
1209
|
-
onProgress,
|
|
1210
|
-
signal,
|
|
1211
|
-
integration
|
|
1212
|
-
}).catch((error) => {
|
|
1213
|
-
if (attempt < multipartMaxAttempts) {
|
|
1214
|
-
return retry();
|
|
1215
|
-
}
|
|
1216
|
-
throw error;
|
|
1217
|
-
}));
|
|
1218
|
-
const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, maxConcurrentRequests = defaultSettings.maxConcurrentRequests, multipartMaxAttempts = defaultSettings.multipartMaxAttempts, baseCDN, metadata }) => {
|
|
1219
|
-
const size = fileSize || getFileSize(file);
|
|
1220
|
-
let progressValues;
|
|
1221
|
-
const createProgressHandler = (totalChunks, chunkIdx) => {
|
|
1222
|
-
if (!onProgress)
|
|
1223
|
-
return;
|
|
1224
|
-
if (!progressValues) {
|
|
1225
|
-
progressValues = Array(totalChunks).fill(0);
|
|
1226
|
-
}
|
|
1227
|
-
const sum = (values) => values.reduce((sum, next) => sum + next, 0);
|
|
1228
|
-
return (info) => {
|
|
1229
|
-
if (!info.isComputable) {
|
|
1230
|
-
return;
|
|
1231
|
-
}
|
|
1232
|
-
progressValues[chunkIdx] = info.value;
|
|
1233
|
-
onProgress({
|
|
1234
|
-
isComputable: true,
|
|
1235
|
-
value: sum(progressValues) / totalChunks
|
|
1236
|
-
});
|
|
1237
|
-
};
|
|
1238
|
-
};
|
|
1239
|
-
return multipartStart(size, {
|
|
1240
|
-
publicKey,
|
|
1241
|
-
contentType,
|
|
1242
|
-
fileName: fileName !== null && fileName !== void 0 ? fileName : file.name,
|
|
1243
|
-
baseURL,
|
|
1244
|
-
secureSignature,
|
|
1245
|
-
secureExpire,
|
|
1246
|
-
store,
|
|
1247
|
-
signal,
|
|
1248
|
-
source,
|
|
1249
|
-
integration,
|
|
1250
|
-
userAgent,
|
|
1251
|
-
retryThrottledRequestMaxTimes,
|
|
1252
|
-
metadata
|
|
1253
|
-
})
|
|
1254
|
-
.then(({ uuid, parts }) => {
|
|
1255
|
-
const getChunk = prepareChunks(file, size, multipartChunkSize);
|
|
1256
|
-
return Promise.all([
|
|
1257
|
-
uuid,
|
|
1258
|
-
runWithConcurrency(maxConcurrentRequests, parts.map((url, index) => () => uploadPartWithRetry(getChunk(index), url, {
|
|
1259
|
-
publicKey,
|
|
1260
|
-
onProgress: createProgressHandler(parts.length, index),
|
|
1261
|
-
signal,
|
|
1262
|
-
integration,
|
|
1263
|
-
multipartMaxAttempts
|
|
1264
|
-
})))
|
|
1265
|
-
]);
|
|
1266
|
-
})
|
|
1267
|
-
.then(([uuid]) => multipartComplete(uuid, {
|
|
1268
|
-
publicKey,
|
|
1269
|
-
baseURL,
|
|
1270
|
-
source,
|
|
1271
|
-
integration,
|
|
1272
|
-
userAgent,
|
|
1273
|
-
retryThrottledRequestMaxTimes
|
|
1274
|
-
}))
|
|
1275
|
-
.then((fileInfo) => {
|
|
1276
|
-
if (fileInfo.isReady) {
|
|
1277
|
-
return fileInfo;
|
|
1278
|
-
}
|
|
1279
|
-
else {
|
|
1280
|
-
return isReadyPoll({
|
|
1281
|
-
file: fileInfo.uuid,
|
|
1282
|
-
publicKey,
|
|
1283
|
-
baseURL,
|
|
1284
|
-
source,
|
|
1285
|
-
integration,
|
|
1286
|
-
userAgent,
|
|
1287
|
-
retryThrottledRequestMaxTimes,
|
|
1288
|
-
onProgress,
|
|
1289
|
-
signal
|
|
1290
|
-
});
|
|
1291
|
-
}
|
|
1292
|
-
})
|
|
1293
|
-
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
|
|
1218
|
+
const uploadPartWithRetry = (chunk, url, { publicKey, onProgress, signal, integration, multipartMaxAttempts }) => retrier(({ attempt, retry }) => multipartUpload(chunk, url, {
|
|
1219
|
+
publicKey,
|
|
1220
|
+
onProgress,
|
|
1221
|
+
signal,
|
|
1222
|
+
integration
|
|
1223
|
+
}).catch((error) => {
|
|
1224
|
+
if (attempt < multipartMaxAttempts) {
|
|
1225
|
+
return retry();
|
|
1226
|
+
}
|
|
1227
|
+
throw error;
|
|
1228
|
+
}));
|
|
1229
|
+
const uploadMultipart = (file, { publicKey, fileName, fileSize, baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, maxConcurrentRequests = defaultSettings.maxConcurrentRequests, multipartMaxAttempts = defaultSettings.multipartMaxAttempts, baseCDN, metadata }) => {
|
|
1230
|
+
const size = fileSize || getFileSize(file);
|
|
1231
|
+
let progressValues;
|
|
1232
|
+
const createProgressHandler = (totalChunks, chunkIdx) => {
|
|
1233
|
+
if (!onProgress)
|
|
1234
|
+
return;
|
|
1235
|
+
if (!progressValues) {
|
|
1236
|
+
progressValues = Array(totalChunks).fill(0);
|
|
1237
|
+
}
|
|
1238
|
+
const sum = (values) => values.reduce((sum, next) => sum + next, 0);
|
|
1239
|
+
return (info) => {
|
|
1240
|
+
if (!info.isComputable) {
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
progressValues[chunkIdx] = info.value;
|
|
1244
|
+
onProgress({
|
|
1245
|
+
isComputable: true,
|
|
1246
|
+
value: sum(progressValues) / totalChunks
|
|
1247
|
+
});
|
|
1248
|
+
};
|
|
1249
|
+
};
|
|
1250
|
+
return multipartStart(size, {
|
|
1251
|
+
publicKey,
|
|
1252
|
+
contentType,
|
|
1253
|
+
fileName: fileName !== null && fileName !== void 0 ? fileName : file.name,
|
|
1254
|
+
baseURL,
|
|
1255
|
+
secureSignature,
|
|
1256
|
+
secureExpire,
|
|
1257
|
+
store,
|
|
1258
|
+
signal,
|
|
1259
|
+
source,
|
|
1260
|
+
integration,
|
|
1261
|
+
userAgent,
|
|
1262
|
+
retryThrottledRequestMaxTimes,
|
|
1263
|
+
metadata
|
|
1264
|
+
})
|
|
1265
|
+
.then(({ uuid, parts }) => {
|
|
1266
|
+
const getChunk = prepareChunks(file, size, multipartChunkSize);
|
|
1267
|
+
return Promise.all([
|
|
1268
|
+
uuid,
|
|
1269
|
+
runWithConcurrency(maxConcurrentRequests, parts.map((url, index) => () => uploadPartWithRetry(getChunk(index), url, {
|
|
1270
|
+
publicKey,
|
|
1271
|
+
onProgress: createProgressHandler(parts.length, index),
|
|
1272
|
+
signal,
|
|
1273
|
+
integration,
|
|
1274
|
+
multipartMaxAttempts
|
|
1275
|
+
})))
|
|
1276
|
+
]);
|
|
1277
|
+
})
|
|
1278
|
+
.then(([uuid]) => multipartComplete(uuid, {
|
|
1279
|
+
publicKey,
|
|
1280
|
+
baseURL,
|
|
1281
|
+
source,
|
|
1282
|
+
integration,
|
|
1283
|
+
userAgent,
|
|
1284
|
+
retryThrottledRequestMaxTimes
|
|
1285
|
+
}))
|
|
1286
|
+
.then((fileInfo) => {
|
|
1287
|
+
if (fileInfo.isReady) {
|
|
1288
|
+
return fileInfo;
|
|
1289
|
+
}
|
|
1290
|
+
else {
|
|
1291
|
+
return isReadyPoll({
|
|
1292
|
+
file: fileInfo.uuid,
|
|
1293
|
+
publicKey,
|
|
1294
|
+
baseURL,
|
|
1295
|
+
source,
|
|
1296
|
+
integration,
|
|
1297
|
+
userAgent,
|
|
1298
|
+
retryThrottledRequestMaxTimes,
|
|
1299
|
+
onProgress,
|
|
1300
|
+
signal
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
})
|
|
1304
|
+
.then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
|
|
1294
1305
|
};
|
|
1295
1306
|
|
|
1296
|
-
/**
|
|
1297
|
-
* Uploads file from provided data.
|
|
1298
|
-
*/
|
|
1299
|
-
function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartMinFileSize, multipartChunkSize, multipartMaxAttempts, maxConcurrentRequests, baseCDN = defaultSettings.baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, pusherKey, metadata }) {
|
|
1300
|
-
if (isFileData(data)) {
|
|
1301
|
-
const fileSize = getFileSize(data);
|
|
1302
|
-
if (isMultipart(fileSize, multipartMinFileSize)) {
|
|
1303
|
-
return uploadMultipart(data, {
|
|
1304
|
-
publicKey,
|
|
1305
|
-
contentType,
|
|
1306
|
-
multipartChunkSize,
|
|
1307
|
-
multipartMaxAttempts,
|
|
1308
|
-
fileName,
|
|
1309
|
-
baseURL,
|
|
1310
|
-
secureSignature,
|
|
1311
|
-
secureExpire,
|
|
1312
|
-
store,
|
|
1313
|
-
signal,
|
|
1314
|
-
onProgress,
|
|
1315
|
-
source,
|
|
1316
|
-
integration,
|
|
1317
|
-
userAgent,
|
|
1318
|
-
maxConcurrentRequests,
|
|
1319
|
-
retryThrottledRequestMaxTimes,
|
|
1320
|
-
baseCDN,
|
|
1321
|
-
metadata
|
|
1322
|
-
});
|
|
1323
|
-
}
|
|
1324
|
-
return
|
|
1325
|
-
publicKey,
|
|
1326
|
-
fileName,
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1307
|
+
/**
|
|
1308
|
+
* Uploads file from provided data.
|
|
1309
|
+
*/
|
|
1310
|
+
function uploadFile(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartMinFileSize, multipartChunkSize, multipartMaxAttempts, maxConcurrentRequests, baseCDN = defaultSettings.baseCDN, checkForUrlDuplicates, saveUrlForRecurrentUploads, pusherKey, metadata }) {
|
|
1311
|
+
if (isFileData(data)) {
|
|
1312
|
+
const fileSize = getFileSize(data);
|
|
1313
|
+
if (isMultipart(fileSize, multipartMinFileSize)) {
|
|
1314
|
+
return uploadMultipart(data, {
|
|
1315
|
+
publicKey,
|
|
1316
|
+
contentType,
|
|
1317
|
+
multipartChunkSize,
|
|
1318
|
+
multipartMaxAttempts,
|
|
1319
|
+
fileName,
|
|
1320
|
+
baseURL,
|
|
1321
|
+
secureSignature,
|
|
1322
|
+
secureExpire,
|
|
1323
|
+
store,
|
|
1324
|
+
signal,
|
|
1325
|
+
onProgress,
|
|
1326
|
+
source,
|
|
1327
|
+
integration,
|
|
1328
|
+
userAgent,
|
|
1329
|
+
maxConcurrentRequests,
|
|
1330
|
+
retryThrottledRequestMaxTimes,
|
|
1331
|
+
baseCDN,
|
|
1332
|
+
metadata
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
return uploadDirect(data, {
|
|
1336
|
+
publicKey,
|
|
1337
|
+
fileName,
|
|
1338
|
+
contentType,
|
|
1339
|
+
baseURL,
|
|
1340
|
+
secureSignature,
|
|
1341
|
+
secureExpire,
|
|
1342
|
+
store,
|
|
1343
|
+
signal,
|
|
1344
|
+
onProgress,
|
|
1345
|
+
source,
|
|
1346
|
+
integration,
|
|
1347
|
+
userAgent,
|
|
1348
|
+
retryThrottledRequestMaxTimes,
|
|
1349
|
+
baseCDN,
|
|
1350
|
+
metadata
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
if (isUrl(data)) {
|
|
1354
|
+
return uploadFromUrl(data, {
|
|
1355
|
+
publicKey,
|
|
1356
|
+
fileName,
|
|
1357
|
+
baseURL,
|
|
1358
|
+
baseCDN,
|
|
1359
|
+
checkForUrlDuplicates,
|
|
1360
|
+
saveUrlForRecurrentUploads,
|
|
1361
|
+
secureSignature,
|
|
1362
|
+
secureExpire,
|
|
1363
|
+
store,
|
|
1364
|
+
signal,
|
|
1365
|
+
onProgress,
|
|
1366
|
+
source,
|
|
1367
|
+
integration,
|
|
1368
|
+
userAgent,
|
|
1369
|
+
retryThrottledRequestMaxTimes,
|
|
1370
|
+
pusherKey,
|
|
1371
|
+
metadata
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
if (isUuid(data)) {
|
|
1375
|
+
return uploadFromUploaded(data, {
|
|
1376
|
+
publicKey,
|
|
1377
|
+
fileName,
|
|
1378
|
+
baseURL,
|
|
1379
|
+
signal,
|
|
1380
|
+
onProgress,
|
|
1381
|
+
source,
|
|
1382
|
+
integration,
|
|
1383
|
+
userAgent,
|
|
1384
|
+
retryThrottledRequestMaxTimes,
|
|
1385
|
+
baseCDN
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
throw new TypeError(`File uploading from "${data}" is not supported`);
|
|
1377
1389
|
}
|
|
1378
1390
|
|
|
1379
|
-
class UploadcareGroup {
|
|
1380
|
-
constructor(groupInfo, files) {
|
|
1381
|
-
this.storedAt = null;
|
|
1382
|
-
this.uuid = groupInfo.id;
|
|
1383
|
-
this.filesCount = groupInfo.filesCount;
|
|
1384
|
-
this.totalSize = Object.values(groupInfo.files).reduce((acc, file) => acc + file.size, 0);
|
|
1385
|
-
this.isStored = !!groupInfo.datetimeStored;
|
|
1386
|
-
this.isImage = !!Object.values(groupInfo.files).filter((file) => file.isImage).length;
|
|
1387
|
-
this.cdnUrl = groupInfo.cdnUrl;
|
|
1388
|
-
this.files = files;
|
|
1389
|
-
this.createdAt = groupInfo.datetimeCreated;
|
|
1390
|
-
this.storedAt = groupInfo.datetimeStored;
|
|
1391
|
-
}
|
|
1391
|
+
class UploadcareGroup {
|
|
1392
|
+
constructor(groupInfo, files) {
|
|
1393
|
+
this.storedAt = null;
|
|
1394
|
+
this.uuid = groupInfo.id;
|
|
1395
|
+
this.filesCount = groupInfo.filesCount;
|
|
1396
|
+
this.totalSize = Object.values(groupInfo.files).reduce((acc, file) => acc + file.size, 0);
|
|
1397
|
+
this.isStored = !!groupInfo.datetimeStored;
|
|
1398
|
+
this.isImage = !!Object.values(groupInfo.files).filter((file) => file.isImage).length;
|
|
1399
|
+
this.cdnUrl = groupInfo.cdnUrl;
|
|
1400
|
+
this.files = files;
|
|
1401
|
+
this.createdAt = groupInfo.datetimeCreated;
|
|
1402
|
+
this.storedAt = groupInfo.datetimeStored;
|
|
1403
|
+
}
|
|
1392
1404
|
}
|
|
1393
1405
|
|
|
1394
|
-
/**
|
|
1395
|
-
* FileData type guard.
|
|
1396
|
-
*/
|
|
1397
|
-
const isFileDataArray = (data) => {
|
|
1398
|
-
for (const item of data) {
|
|
1399
|
-
if (!isFileData(item)) {
|
|
1400
|
-
return false;
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
return true;
|
|
1404
|
-
};
|
|
1405
|
-
/**
|
|
1406
|
-
* Uuid type guard.
|
|
1407
|
-
*/
|
|
1408
|
-
const isUuidArray = (data) => {
|
|
1409
|
-
for (const item of data) {
|
|
1410
|
-
if (!isUuid(item)) {
|
|
1411
|
-
return false;
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
return true;
|
|
1415
|
-
};
|
|
1416
|
-
/**
|
|
1417
|
-
* Url type guard.
|
|
1418
|
-
*/
|
|
1419
|
-
const isUrlArray = (data) => {
|
|
1420
|
-
for (const item of data) {
|
|
1421
|
-
if (!isUrl(item)) {
|
|
1422
|
-
return false;
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
return true;
|
|
1406
|
+
/**
|
|
1407
|
+
* FileData type guard.
|
|
1408
|
+
*/
|
|
1409
|
+
const isFileDataArray = (data) => {
|
|
1410
|
+
for (const item of data) {
|
|
1411
|
+
if (!isFileData(item)) {
|
|
1412
|
+
return false;
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
return true;
|
|
1416
|
+
};
|
|
1417
|
+
/**
|
|
1418
|
+
* Uuid type guard.
|
|
1419
|
+
*/
|
|
1420
|
+
const isUuidArray = (data) => {
|
|
1421
|
+
for (const item of data) {
|
|
1422
|
+
if (!isUuid(item)) {
|
|
1423
|
+
return false;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
return true;
|
|
1427
|
+
};
|
|
1428
|
+
/**
|
|
1429
|
+
* Url type guard.
|
|
1430
|
+
*/
|
|
1431
|
+
const isUrlArray = (data) => {
|
|
1432
|
+
for (const item of data) {
|
|
1433
|
+
if (!isUrl(item)) {
|
|
1434
|
+
return false;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
return true;
|
|
1426
1438
|
};
|
|
1427
1439
|
|
|
1428
|
-
function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, baseCDN = defaultSettings.baseCDN, jsonpCallback
|
|
1429
|
-
if (!isFileDataArray(data) && !isUrlArray(data) && !isUuidArray(data)) {
|
|
1430
|
-
throw new TypeError(`Group uploading from "${data}" is not supported`);
|
|
1431
|
-
}
|
|
1432
|
-
let progressValues;
|
|
1433
|
-
let isStillComputable = true;
|
|
1434
|
-
const filesCount = data.length;
|
|
1435
|
-
const createProgressHandler = (size, index) => {
|
|
1436
|
-
if (!onProgress)
|
|
1437
|
-
return;
|
|
1438
|
-
if (!progressValues) {
|
|
1439
|
-
progressValues = Array(size).fill(0);
|
|
1440
|
-
}
|
|
1441
|
-
const normalize = (values) => values.reduce((sum, next) => sum + next) / size;
|
|
1442
|
-
return (info) => {
|
|
1443
|
-
if (!info.isComputable || !isStillComputable) {
|
|
1444
|
-
isStillComputable = false;
|
|
1445
|
-
onProgress({ isComputable: false });
|
|
1446
|
-
return;
|
|
1447
|
-
}
|
|
1448
|
-
progressValues[index] = info.value;
|
|
1449
|
-
onProgress({ isComputable: true, value: normalize(progressValues) });
|
|
1450
|
-
};
|
|
1451
|
-
};
|
|
1452
|
-
return Promise.all(data.map((file, index) => uploadFile(file, {
|
|
1453
|
-
publicKey,
|
|
1454
|
-
fileName,
|
|
1455
|
-
baseURL,
|
|
1456
|
-
secureSignature,
|
|
1457
|
-
secureExpire,
|
|
1458
|
-
store,
|
|
1459
|
-
signal,
|
|
1460
|
-
onProgress: createProgressHandler(filesCount, index),
|
|
1461
|
-
source,
|
|
1462
|
-
integration,
|
|
1463
|
-
userAgent,
|
|
1464
|
-
retryThrottledRequestMaxTimes,
|
|
1465
|
-
contentType,
|
|
1466
|
-
multipartChunkSize,
|
|
1467
|
-
baseCDN
|
|
1468
|
-
}))).then((files) => {
|
|
1469
|
-
const uuids = files.map((file) => file.uuid);
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
})
|
|
1489
|
-
.then((groupInfo) => new UploadcareGroup(groupInfo, filesInGroup))
|
|
1490
|
-
.then((group) => {
|
|
1491
|
-
onProgress && onProgress({ isComputable: true, value: 1 });
|
|
1492
|
-
return group;
|
|
1493
|
-
});
|
|
1494
|
-
});
|
|
1440
|
+
function uploadFileGroup(data, { publicKey, fileName, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source, integration, userAgent, retryThrottledRequestMaxTimes, contentType, multipartChunkSize = defaultSettings.multipartChunkSize, baseCDN = defaultSettings.baseCDN, jsonpCallback }) {
|
|
1441
|
+
if (!isFileDataArray(data) && !isUrlArray(data) && !isUuidArray(data)) {
|
|
1442
|
+
throw new TypeError(`Group uploading from "${data}" is not supported`);
|
|
1443
|
+
}
|
|
1444
|
+
let progressValues;
|
|
1445
|
+
let isStillComputable = true;
|
|
1446
|
+
const filesCount = data.length;
|
|
1447
|
+
const createProgressHandler = (size, index) => {
|
|
1448
|
+
if (!onProgress)
|
|
1449
|
+
return;
|
|
1450
|
+
if (!progressValues) {
|
|
1451
|
+
progressValues = Array(size).fill(0);
|
|
1452
|
+
}
|
|
1453
|
+
const normalize = (values) => values.reduce((sum, next) => sum + next) / size;
|
|
1454
|
+
return (info) => {
|
|
1455
|
+
if (!info.isComputable || !isStillComputable) {
|
|
1456
|
+
isStillComputable = false;
|
|
1457
|
+
onProgress({ isComputable: false });
|
|
1458
|
+
return;
|
|
1459
|
+
}
|
|
1460
|
+
progressValues[index] = info.value;
|
|
1461
|
+
onProgress({ isComputable: true, value: normalize(progressValues) });
|
|
1462
|
+
};
|
|
1463
|
+
};
|
|
1464
|
+
return Promise.all(data.map((file, index) => uploadFile(file, {
|
|
1465
|
+
publicKey,
|
|
1466
|
+
fileName,
|
|
1467
|
+
baseURL,
|
|
1468
|
+
secureSignature,
|
|
1469
|
+
secureExpire,
|
|
1470
|
+
store,
|
|
1471
|
+
signal,
|
|
1472
|
+
onProgress: createProgressHandler(filesCount, index),
|
|
1473
|
+
source,
|
|
1474
|
+
integration,
|
|
1475
|
+
userAgent,
|
|
1476
|
+
retryThrottledRequestMaxTimes,
|
|
1477
|
+
contentType,
|
|
1478
|
+
multipartChunkSize,
|
|
1479
|
+
baseCDN
|
|
1480
|
+
}))).then((files) => {
|
|
1481
|
+
const uuids = files.map((file) => file.uuid);
|
|
1482
|
+
return group(uuids, {
|
|
1483
|
+
publicKey,
|
|
1484
|
+
baseURL,
|
|
1485
|
+
jsonpCallback,
|
|
1486
|
+
secureSignature,
|
|
1487
|
+
secureExpire,
|
|
1488
|
+
signal,
|
|
1489
|
+
source,
|
|
1490
|
+
integration,
|
|
1491
|
+
userAgent,
|
|
1492
|
+
retryThrottledRequestMaxTimes
|
|
1493
|
+
})
|
|
1494
|
+
.then((groupInfo) => new UploadcareGroup(groupInfo, files))
|
|
1495
|
+
.then((group) => {
|
|
1496
|
+
onProgress && onProgress({ isComputable: true, value: 1 });
|
|
1497
|
+
return group;
|
|
1498
|
+
});
|
|
1499
|
+
});
|
|
1495
1500
|
}
|
|
1496
1501
|
|
|
1497
|
-
/**
|
|
1498
|
-
* Populate options with settings.
|
|
1499
|
-
*/
|
|
1500
|
-
const populateOptionsWithSettings = (options, settings) => (Object.assign(Object.assign({}, settings), options));
|
|
1501
|
-
class UploadClient {
|
|
1502
|
-
constructor(settings) {
|
|
1503
|
-
this.settings = Object.assign({}, defaultSettings, settings);
|
|
1504
|
-
}
|
|
1505
|
-
updateSettings(newSettings) {
|
|
1506
|
-
this.settings = Object.assign(this.settings, newSettings);
|
|
1507
|
-
}
|
|
1508
|
-
getSettings() {
|
|
1509
|
-
return this.settings;
|
|
1510
|
-
}
|
|
1511
|
-
base(file, options) {
|
|
1512
|
-
const settings = this.getSettings();
|
|
1513
|
-
return base(file, populateOptionsWithSettings(options, settings));
|
|
1514
|
-
}
|
|
1515
|
-
info(uuid, options) {
|
|
1516
|
-
const settings = this.getSettings();
|
|
1517
|
-
return info(uuid, populateOptionsWithSettings(options, settings));
|
|
1518
|
-
}
|
|
1519
|
-
fromUrl(sourceUrl, options) {
|
|
1520
|
-
const settings = this.getSettings();
|
|
1521
|
-
return fromUrl(sourceUrl, populateOptionsWithSettings(options, settings));
|
|
1522
|
-
}
|
|
1523
|
-
fromUrlStatus(token, options) {
|
|
1524
|
-
const settings = this.getSettings();
|
|
1525
|
-
return fromUrlStatus(token, populateOptionsWithSettings(options, settings));
|
|
1526
|
-
}
|
|
1527
|
-
group(uuids, options) {
|
|
1528
|
-
const settings = this.getSettings();
|
|
1529
|
-
return group(uuids, populateOptionsWithSettings(options, settings));
|
|
1530
|
-
}
|
|
1531
|
-
groupInfo(id, options) {
|
|
1532
|
-
const settings = this.getSettings();
|
|
1533
|
-
return groupInfo(id, populateOptionsWithSettings(options, settings));
|
|
1534
|
-
}
|
|
1535
|
-
multipartStart(size, options) {
|
|
1536
|
-
const settings = this.getSettings();
|
|
1537
|
-
return multipartStart(size, populateOptionsWithSettings(options, settings));
|
|
1538
|
-
}
|
|
1539
|
-
multipartUpload(part, url, options) {
|
|
1540
|
-
const settings = this.getSettings();
|
|
1541
|
-
return multipartUpload(part, url, populateOptionsWithSettings(options, settings));
|
|
1542
|
-
}
|
|
1543
|
-
multipartComplete(uuid, options) {
|
|
1544
|
-
const settings = this.getSettings();
|
|
1545
|
-
return multipartComplete(uuid, populateOptionsWithSettings(options, settings));
|
|
1546
|
-
}
|
|
1547
|
-
uploadFile(data, options) {
|
|
1548
|
-
const settings = this.getSettings();
|
|
1549
|
-
return uploadFile(data, populateOptionsWithSettings(options, settings));
|
|
1550
|
-
}
|
|
1551
|
-
uploadFileGroup(data, options) {
|
|
1552
|
-
const settings = this.getSettings();
|
|
1553
|
-
return uploadFileGroup(data, populateOptionsWithSettings(options, settings));
|
|
1554
|
-
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Populate options with settings.
|
|
1504
|
+
*/
|
|
1505
|
+
const populateOptionsWithSettings = (options, settings) => (Object.assign(Object.assign({}, settings), options));
|
|
1506
|
+
class UploadClient {
|
|
1507
|
+
constructor(settings) {
|
|
1508
|
+
this.settings = Object.assign({}, defaultSettings, settings);
|
|
1509
|
+
}
|
|
1510
|
+
updateSettings(newSettings) {
|
|
1511
|
+
this.settings = Object.assign(this.settings, newSettings);
|
|
1512
|
+
}
|
|
1513
|
+
getSettings() {
|
|
1514
|
+
return this.settings;
|
|
1515
|
+
}
|
|
1516
|
+
base(file, options = {}) {
|
|
1517
|
+
const settings = this.getSettings();
|
|
1518
|
+
return base(file, populateOptionsWithSettings(options, settings));
|
|
1519
|
+
}
|
|
1520
|
+
info(uuid, options = {}) {
|
|
1521
|
+
const settings = this.getSettings();
|
|
1522
|
+
return info(uuid, populateOptionsWithSettings(options, settings));
|
|
1523
|
+
}
|
|
1524
|
+
fromUrl(sourceUrl, options = {}) {
|
|
1525
|
+
const settings = this.getSettings();
|
|
1526
|
+
return fromUrl(sourceUrl, populateOptionsWithSettings(options, settings));
|
|
1527
|
+
}
|
|
1528
|
+
fromUrlStatus(token, options = {}) {
|
|
1529
|
+
const settings = this.getSettings();
|
|
1530
|
+
return fromUrlStatus(token, populateOptionsWithSettings(options, settings));
|
|
1531
|
+
}
|
|
1532
|
+
group(uuids, options = {}) {
|
|
1533
|
+
const settings = this.getSettings();
|
|
1534
|
+
return group(uuids, populateOptionsWithSettings(options, settings));
|
|
1535
|
+
}
|
|
1536
|
+
groupInfo(id, options = {}) {
|
|
1537
|
+
const settings = this.getSettings();
|
|
1538
|
+
return groupInfo(id, populateOptionsWithSettings(options, settings));
|
|
1539
|
+
}
|
|
1540
|
+
multipartStart(size, options = {}) {
|
|
1541
|
+
const settings = this.getSettings();
|
|
1542
|
+
return multipartStart(size, populateOptionsWithSettings(options, settings));
|
|
1543
|
+
}
|
|
1544
|
+
multipartUpload(part, url, options = {}) {
|
|
1545
|
+
const settings = this.getSettings();
|
|
1546
|
+
return multipartUpload(part, url, populateOptionsWithSettings(options, settings));
|
|
1547
|
+
}
|
|
1548
|
+
multipartComplete(uuid, options = {}) {
|
|
1549
|
+
const settings = this.getSettings();
|
|
1550
|
+
return multipartComplete(uuid, populateOptionsWithSettings(options, settings));
|
|
1551
|
+
}
|
|
1552
|
+
uploadFile(data, options = {}) {
|
|
1553
|
+
const settings = this.getSettings();
|
|
1554
|
+
return uploadFile(data, populateOptionsWithSettings(options, settings));
|
|
1555
|
+
}
|
|
1556
|
+
uploadFileGroup(data, options = {}) {
|
|
1557
|
+
const settings = this.getSettings();
|
|
1558
|
+
return uploadFileGroup(data, populateOptionsWithSettings(options, settings));
|
|
1559
|
+
}
|
|
1555
1560
|
}
|
|
1556
1561
|
|
|
1557
|
-
export { UploadClient, UploadClientError, UploadcareFile, UploadcareGroup, base, fromUrl, fromUrlStatus, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload,
|
|
1562
|
+
export { UploadClient, UploadClientError, UploadcareFile, UploadcareGroup, base, fromUrl, fromUrlStatus, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadDirect, uploadFile, uploadFileGroup, uploadFromUploaded, uploadFromUrl, uploadMultipart };
|