@uploadcare/upload-client 3.1.2-alpha.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.
@@ -3,1567 +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
- const getFileOptions = ({ name, contentType }) => [
148
- {
149
- filename: name,
150
- contentType
151
- }
152
- ];
153
- const transformFile = identity;
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;
154
156
  var getFormData = () => new NodeFormData();
155
157
 
156
- /**
157
- * FileData type guard.
158
- */
159
- const isFileData = (data) => {
160
- return (data !== undefined &&
161
- ((typeof Blob !== 'undefined' && data instanceof Blob) ||
162
- (typeof File !== 'undefined' && data instanceof File) ||
163
- (typeof Buffer !== 'undefined' && data instanceof Buffer)));
164
- };
165
- /**
166
- * Uuid type guard.
167
- */
168
- const isUuid = (data) => {
169
- const UUID_REGEX = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
170
- const regExp = new RegExp(UUID_REGEX);
171
- return !isFileData(data) && regExp.test(data);
172
- };
173
- /**
174
- * Url type guard.
175
- *
176
- * @param {NodeFile | BrowserFile | Url | Uuid} data
177
- */
178
- const isUrl = (data) => {
179
- const URL_REGEX = '^(?:\\w+:)?\\/\\/([^\\s\\.]+\\.\\S{2}|localhost[\\:?\\d]*)\\S*$';
180
- const regExp = new RegExp(URL_REGEX);
181
- 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);
182
184
  };
183
185
 
184
- const isSimpleValue = (value) => {
185
- return (typeof value === 'string' ||
186
- typeof value === 'number' ||
187
- typeof value === 'undefined');
188
- };
189
- const isObjectValue = (value) => {
190
- return !!value && typeof value === 'object' && !Array.isArray(value);
191
- };
192
- const isFileValue = (value) => !!value &&
193
- typeof value === 'object' &&
194
- 'data' in value &&
195
- isFileData(value.data);
196
- function collectParams(params, inputKey, inputValue) {
197
- if (isFileValue(inputValue)) {
198
- const { name, contentType } = inputValue;
199
- const file = transformFile(inputValue.data); // lgtm [js/superfluous-trailing-arguments]
200
- const options = getFileOptions({ name, contentType });
201
- params.push([inputKey, file, ...options]);
202
- }
203
- else if (isObjectValue(inputValue)) {
204
- for (const [key, value] of Object.entries(inputValue)) {
205
- if (typeof value !== 'undefined') {
206
- params.push([`${inputKey}[${key}]`, String(value)]);
207
- }
208
- }
209
- }
210
- else if (isSimpleValue(inputValue) && inputValue) {
211
- params.push([inputKey, inputValue.toString()]);
212
- }
213
- }
214
- function getFormDataParams(options) {
215
- const params = [];
216
- for (const [key, value] of Object.entries(options)) {
217
- collectParams(params, key, value);
218
- }
219
- return params;
220
- }
221
- function buildFormData(options) {
222
- const formData = getFormData();
223
- const paramsList = getFormDataParams(options);
224
- for (const params of paramsList) {
225
- const [key, value, ...options] = params;
226
- // node form-data has another signature for append
227
- formData.append(key, value, ...options);
228
- }
229
- return formData;
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;
230
232
  }
231
233
 
232
- const serializePair = (key, value) => typeof value !== 'undefined' ? `${key}=${encodeURIComponent(value)}` : null;
233
- // TODO: generalize value transforming logic and use it here and inside `buildFormData`
234
- const createQuery = (query) => Object.entries(query)
235
- .reduce((params, [key, value]) => {
236
- let param;
237
- if (typeof value === 'object' && !Array.isArray(value)) {
238
- param = Object.entries(value)
239
- .filter((entry) => typeof entry[1] !== 'undefined')
240
- .map((entry) => serializePair(`${key}[${entry[0]}]`, String(entry[1])));
241
- }
242
- else if (Array.isArray(value)) {
243
- param = value.map((val) => serializePair(`${key}[]`, val));
244
- }
245
- else {
246
- param = serializePair(key, value);
247
- }
248
- return params.concat(param);
249
- }, [])
250
- .filter((x) => !!x)
251
- .join('&');
252
- const getUrl = (base, path, query) => [
253
- base,
254
- path,
255
- query && Object.keys(query).length > 0 ? '?' : '',
256
- query && createQuery(query)
257
- ]
258
- .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)
259
261
  .join('');
260
262
 
261
- /*
262
- Settings for future support:
263
- parallelDirectUploads: 10,
264
- */
265
- const defaultSettings = {
266
- baseCDN: 'https://ucarecdn.com',
267
- baseURL: 'https://upload.uploadcare.com',
268
- maxContentLength: 50 * 1024 * 1024,
269
- retryThrottledRequestMaxTimes: 1,
270
- multipartMinFileSize: 25 * 1024 * 1024,
271
- multipartChunkSize: 5 * 1024 * 1024,
272
- multipartMinLastPartSize: 1024 * 1024,
273
- maxConcurrentRequests: 4,
274
- multipartMaxAttempts: 3,
275
- pollingTimeoutMilliseconds: 10000,
276
- pusherKey: '79ae88bd931ea68464d9'
277
- };
278
- 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';
279
281
  const defaultFilename = 'original';
280
282
 
281
283
  var version = '3.1.1';
282
284
 
283
- /**
284
- * Returns User Agent based on version and settings.
285
- */
286
- function getUserAgent({ userAgent, publicKey = '', integration = '' } = {}) {
287
- const libraryName = 'UploadcareUploadClient';
288
- const libraryVersion = version;
289
- const languageName = 'JavaScript';
290
- if (typeof userAgent === 'string') {
291
- return userAgent;
292
- }
293
- if (typeof userAgent === 'function') {
294
- return userAgent({
295
- publicKey,
296
- libraryName,
297
- libraryVersion,
298
- languageName,
299
- integration
300
- });
301
- }
302
- const mainInfo = [libraryName, libraryVersion, publicKey]
303
- .filter(Boolean)
304
- .join('/');
305
- const additionInfo = [languageName, integration].filter(Boolean).join('; ');
306
- 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})`;
307
309
  }
308
310
 
309
- const SEPARATOR = /\W|_/g;
310
- /**
311
- * Transforms a string to camelCased.
312
- */
313
- function camelize(text) {
314
- return text
315
- .split(SEPARATOR)
316
- .map((word, index) => word.charAt(0)[index > 0 ? 'toUpperCase' : 'toLowerCase']() +
317
- word.slice(1))
318
- .join('');
319
- }
320
- /**
321
- * Transforms keys of an object to camelCased recursively.
322
- */
323
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
324
- function camelizeKeys(source) {
325
- if (!source || typeof source !== 'object') {
326
- return source;
327
- }
328
- return Object.keys(source).reduce((accumulator, key) => {
329
- accumulator[camelize(key)] =
330
- typeof source[key] === 'object' ? camelizeKeys(source[key]) : source[key];
331
- return accumulator;
332
- }, {});
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
+ }, {});
333
335
  }
334
336
 
335
- /**
336
- * setTimeout as Promise.
337
- *
338
- * @param {number} ms Timeout in milliseconds.
339
- */
337
+ /**
338
+ * setTimeout as Promise.
339
+ *
340
+ * @param {number} ms Timeout in milliseconds.
341
+ */
340
342
  const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
341
343
 
342
- const defaultOptions = {
343
- factor: 2,
344
- time: 100
345
- };
346
- function retrier(fn, options = defaultOptions) {
347
- let attempts = 0;
348
- function runAttempt(fn) {
349
- const defaultDelayTime = Math.round(options.time * Math.pow(options.factor, attempts));
350
- const retry = (ms) => delay(ms !== null && ms !== void 0 ? ms : defaultDelayTime).then(() => {
351
- attempts += 1;
352
- return runAttempt(fn);
353
- });
354
- return fn({
355
- attempt: attempts,
356
- retry
357
- });
358
- }
359
- 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);
360
362
  }
361
363
 
362
- const REQUEST_WAS_THROTTLED_CODE = 'RequestThrottledError';
363
- const DEFAULT_RETRY_AFTER_TIMEOUT = 15000;
364
- function getTimeoutFromThrottledRequest(error) {
365
- const { headers } = error || {};
366
- return ((headers &&
367
- Number.parseInt(headers['x-throttle-wait-seconds']) * 1000) ||
368
- DEFAULT_RETRY_AFTER_TIMEOUT);
369
- }
370
- function retryIfThrottled(fn, retryThrottledMaxTimes) {
371
- return retrier(({ attempt, retry }) => fn().catch((error) => {
372
- if ('response' in error &&
373
- (error === null || error === void 0 ? void 0 : error.code) === REQUEST_WAS_THROTTLED_CODE &&
374
- attempt < retryThrottledMaxTimes) {
375
- return retry(getTimeoutFromThrottledRequest(error));
376
- }
377
- throw error;
378
- }));
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
+ }));
379
381
  }
380
382
 
381
- function getStoreValue(store) {
382
- return typeof store === 'undefined' ? 'auto' : store ? '1' : '0';
383
+ function getStoreValue(store) {
384
+ return typeof store === 'undefined' ? 'auto' : store ? '1' : '0';
383
385
  }
384
386
 
385
- /**
386
- * Performs file uploading request to Uploadcare Upload API.
387
- * Can be canceled and has progress.
388
- */
389
- function base(file, { publicKey, fileName, contentType, baseURL = defaultSettings.baseURL, secureSignature, secureExpire, store, signal, onProgress, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
390
- return retryIfThrottled(() => {
391
- var _a;
392
- return request({
393
- method: 'POST',
394
- url: getUrl(baseURL, '/base/', {
395
- jsonerrors: 1
396
- }),
397
- headers: {
398
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
399
- },
400
- data: buildFormData({
401
- file: {
402
- data: file,
403
- name: (_a = fileName !== null && fileName !== void 0 ? fileName : file.name) !== null && _a !== void 0 ? _a : defaultFilename,
404
- contentType
405
- },
406
- UPLOADCARE_PUB_KEY: publicKey,
407
- UPLOADCARE_STORE: getStoreValue(store),
408
- signature: secureSignature,
409
- expire: secureExpire,
410
- source: source,
411
- metadata
412
- }),
413
- signal,
414
- onProgress
415
- }).then(({ data, headers, request }) => {
416
- const response = camelizeKeys(JSON.parse(data));
417
- if ('error' in response) {
418
- throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
419
- }
420
- else {
421
- return response;
422
- }
423
- });
424
- }, retryThrottledRequestMaxTimes);
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);
425
427
  }
426
428
 
427
- var TypeEnum;
428
- (function (TypeEnum) {
429
- TypeEnum["Token"] = "token";
430
- TypeEnum["FileInfo"] = "file_info";
431
- })(TypeEnum || (TypeEnum = {}));
432
- /**
433
- * Uploading files from URL.
434
- */
435
- function fromUrl(sourceUrl, { publicKey, baseURL = defaultSettings.baseURL, store, fileName, checkForUrlDuplicates, saveUrlForRecurrentUploads, secureSignature, secureExpire, source = 'url', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
436
- return retryIfThrottled(() => request({
437
- method: 'POST',
438
- headers: {
439
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
440
- },
441
- url: getUrl(baseURL, '/from_url/', {
442
- jsonerrors: 1,
443
- pub_key: publicKey,
444
- source_url: sourceUrl,
445
- store: getStoreValue(store),
446
- filename: fileName,
447
- check_URL_duplicates: checkForUrlDuplicates ? 1 : undefined,
448
- save_URL_duplicates: saveUrlForRecurrentUploads ? 1 : undefined,
449
- signature: secureSignature,
450
- expire: secureExpire,
451
- source: source,
452
- metadata
453
- }),
454
- signal
455
- }).then(({ data, headers, request }) => {
456
- const response = camelizeKeys(JSON.parse(data));
457
- if ('error' in response) {
458
- throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
459
- }
460
- else {
461
- return response;
462
- }
463
- }), 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);
464
466
  }
465
467
 
466
- var Status;
467
- (function (Status) {
468
- Status["Unknown"] = "unknown";
469
- Status["Waiting"] = "waiting";
470
- Status["Progress"] = "progress";
471
- Status["Error"] = "error";
472
- Status["Success"] = "success";
473
- })(Status || (Status = {}));
474
- const isErrorResponse = (response) => {
475
- return 'status' in response && response.status === Status.Error;
476
- };
477
- /**
478
- * Checking upload status and working with file tokens.
479
- */
480
- function fromUrlStatus(token, { publicKey, baseURL = defaultSettings.baseURL, signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes } = {}) {
481
- return retryIfThrottled(() => request({
482
- method: 'GET',
483
- headers: publicKey
484
- ? {
485
- 'X-UC-User-Agent': getUserAgent({
486
- publicKey,
487
- integration,
488
- userAgent
489
- })
490
- }
491
- : undefined,
492
- url: getUrl(baseURL, '/from_url/status/', {
493
- jsonerrors: 1,
494
- token
495
- }),
496
- signal
497
- }).then(({ data, headers, request }) => {
498
- const response = camelizeKeys(JSON.parse(data));
499
- if ('error' in response && !isErrorResponse(response)) {
500
- throw new UploadClientError(response.error.content, undefined, request, response, headers);
501
- }
502
- else {
503
- return response;
504
- }
505
- }), 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);
506
508
  }
507
509
 
508
- /**
509
- * Create files group.
510
- */
511
- function group(uuids, { publicKey, baseURL = defaultSettings.baseURL, jsonpCallback, secureSignature, secureExpire, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
512
- return retryIfThrottled(() => request({
513
- method: 'POST',
514
- headers: {
515
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
516
- },
517
- url: getUrl(baseURL, '/group/', {
518
- jsonerrors: 1,
519
- pub_key: publicKey,
520
- files: uuids,
521
- callback: jsonpCallback,
522
- signature: secureSignature,
523
- expire: secureExpire,
524
- source
525
- }),
526
- signal
527
- }).then(({ data, headers, request }) => {
528
- const response = camelizeKeys(JSON.parse(data));
529
- if ('error' in response) {
530
- throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
531
- }
532
- else {
533
- return response;
534
- }
535
- }), 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);
536
538
  }
537
539
 
538
- /**
539
- * Get info about group.
540
- */
541
- function groupInfo(id, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
542
- return retryIfThrottled(() => request({
543
- method: 'GET',
544
- headers: {
545
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
546
- },
547
- url: getUrl(baseURL, '/group/info/', {
548
- jsonerrors: 1,
549
- pub_key: publicKey,
550
- group_id: id,
551
- source
552
- }),
553
- signal
554
- }).then(({ data, headers, request }) => {
555
- const response = camelizeKeys(JSON.parse(data));
556
- if ('error' in response) {
557
- throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
558
- }
559
- else {
560
- return response;
561
- }
562
- }), 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);
563
565
  }
564
566
 
565
- /**
566
- * Returns a JSON dictionary holding file info.
567
- */
568
- function info(uuid, { publicKey, baseURL = defaultSettings.baseURL, signal, source, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
569
- return retryIfThrottled(() => request({
570
- method: 'GET',
571
- headers: {
572
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
573
- },
574
- url: getUrl(baseURL, '/info/', {
575
- jsonerrors: 1,
576
- pub_key: publicKey,
577
- file_id: uuid,
578
- source
579
- }),
580
- signal
581
- }).then(({ data, headers, request }) => {
582
- const response = camelizeKeys(JSON.parse(data));
583
- if ('error' in response) {
584
- throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
585
- }
586
- else {
587
- return response;
588
- }
589
- }), 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);
590
592
  }
591
593
 
592
- /**
593
- * Start multipart uploading.
594
- */
595
- function multipartStart(size, { publicKey, contentType, fileName, multipartChunkSize = defaultSettings.multipartChunkSize, baseURL = '', secureSignature, secureExpire, store, signal, source = 'local', integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes, metadata }) {
596
- return retryIfThrottled(() => request({
597
- method: 'POST',
598
- url: getUrl(baseURL, '/multipart/start/', { jsonerrors: 1 }),
599
- headers: {
600
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
601
- },
602
- data: buildFormData({
603
- filename: fileName !== null && fileName !== void 0 ? fileName : defaultFilename,
604
- size: size,
605
- content_type: contentType !== null && contentType !== void 0 ? contentType : defaultContentType,
606
- part_size: multipartChunkSize,
607
- UPLOADCARE_STORE: getStoreValue(store),
608
- UPLOADCARE_PUB_KEY: publicKey,
609
- signature: secureSignature,
610
- expire: secureExpire,
611
- source: source,
612
- metadata
613
- }),
614
- signal
615
- }).then(({ data, headers, request }) => {
616
- const response = camelizeKeys(JSON.parse(data));
617
- if ('error' in response) {
618
- throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
619
- }
620
- else {
621
- // convert to array
622
- response.parts = Object.keys(response.parts).map((key) => response.parts[key]);
623
- return response;
624
- }
625
- }), 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);
626
628
  }
627
629
 
628
- /**
629
- * Complete multipart uploading.
630
- */
631
- function multipartUpload(part, url, { signal, onProgress }) {
632
- return request({
633
- method: 'PUT',
634
- url,
635
- data: part,
636
- // Upload request can't be non-computable because we always know exact size
637
- onProgress: onProgress,
638
- signal
639
- })
640
- .then((result) => {
641
- // hack for node ¯\_(ツ)_/¯
642
- if (onProgress)
643
- onProgress({
644
- isComputable: true,
645
- value: 1
646
- });
647
- return result;
648
- })
649
- .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 }));
650
652
  }
651
653
 
652
- /**
653
- * Complete multipart uploading.
654
- */
655
- function multipartComplete(uuid, { publicKey, baseURL = defaultSettings.baseURL, source = 'local', signal, integration, userAgent, retryThrottledRequestMaxTimes = defaultSettings.retryThrottledRequestMaxTimes }) {
656
- return retryIfThrottled(() => request({
657
- method: 'POST',
658
- url: getUrl(baseURL, '/multipart/complete/', { jsonerrors: 1 }),
659
- headers: {
660
- 'X-UC-User-Agent': getUserAgent({ publicKey, integration, userAgent })
661
- },
662
- data: buildFormData({
663
- uuid: uuid,
664
- UPLOADCARE_PUB_KEY: publicKey,
665
- source: source
666
- }),
667
- signal
668
- }).then(({ data, headers, request }) => {
669
- const response = camelizeKeys(JSON.parse(data));
670
- if ('error' in response) {
671
- throw new UploadClientError(response.error.content, response.error.errorCode, request, response, headers);
672
- }
673
- else {
674
- return response;
675
- }
676
- }), 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);
677
679
  }
678
680
 
679
- class UploadcareFile {
680
- constructor(fileInfo, { baseCDN, defaultEffects, fileName }) {
681
- this.name = null;
682
- this.size = null;
683
- this.isStored = null;
684
- this.isImage = null;
685
- this.mimeType = null;
686
- this.cdnUrl = null;
687
- this.cdnUrlModifiers = null;
688
- this.originalUrl = null;
689
- this.originalFilename = null;
690
- this.imageInfo = null;
691
- this.videoInfo = null;
692
- this.contentInfo = null;
693
- this.metadata = null;
694
- const { uuid, s3Bucket } = fileInfo;
695
- const urlBase = s3Bucket
696
- ? `https://${s3Bucket}.s3.amazonaws.com/${uuid}/${fileInfo.filename}`
697
- : `${baseCDN}/${uuid}/`;
698
- const cdnUrlModifiers = defaultEffects ? `-/${defaultEffects}` : null;
699
- const cdnUrl = `${urlBase}${cdnUrlModifiers || ''}`;
700
- const originalUrl = uuid ? urlBase : 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.cdnUrlModifiers = cdnUrlModifiers;
709
- this.originalUrl = originalUrl;
710
- this.originalFilename = fileInfo.originalFilename;
711
- this.imageInfo = camelizeKeys(fileInfo.imageInfo);
712
- this.videoInfo = camelizeKeys(fileInfo.videoInfo);
713
- this.contentInfo = camelizeKeys(fileInfo.contentInfo);
714
- this.metadata = fileInfo.metadata || null;
715
- }
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
+ }
716
716
  }
717
717
 
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);
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);
743
743
  });
744
744
 
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
- });
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
+ });
764
764
  }
765
765
 
766
- const uploadFromObject = (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 }));
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 }));
797
797
  };
798
798
 
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
- });
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
+ });
830
830
  };
831
831
 
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
- }
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
+ }
852
852
  }
853
853
 
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();
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();
978
978
  };
979
979
 
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
- }))
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
+ }))
1136
1136
  .then((fileInfo) => new UploadcareFile(fileInfo, { baseCDN }));
1137
1137
 
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
- });
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
+ });
1158
1158
  };
1159
1159
 
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
+ /**
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;
1171
1171
  };
1172
1172
 
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);
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);
1177
1177
  };
1178
1178
 
1179
- function prepareChunks(file, fileSize, chunkSize) {
1180
- return (index) => sliceChunk(file, index, fileSize, chunkSize);
1179
+ function prepareChunks(file, fileSize, chunkSize) {
1180
+ return (index) => sliceChunk(file, index, fileSize, chunkSize);
1181
1181
  }
1182
1182
 
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
- });
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
+ });
1216
1216
  };
1217
1217
 
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 }));
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 }));
1305
1305
  };
1306
1306
 
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 uploadFromObject(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`);
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`);
1389
1389
  }
1390
1390
 
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
- }
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
+ }
1404
1404
  }
1405
1405
 
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;
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;
1438
1438
  };
1439
1439
 
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, defaultEffects }) {
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
- const addDefaultEffects = (file) => {
1483
- const cdnUrlModifiers = defaultEffects ? `-/${defaultEffects}` : null;
1484
- const cdnUrl = `${file.urlBase}${cdnUrlModifiers || ''}`;
1485
- return Object.assign(Object.assign({}, file), { cdnUrlModifiers,
1486
- cdnUrl });
1487
- };
1488
- const filesInGroup = defaultEffects ? files.map(addDefaultEffects) : files;
1489
- return group(uuids, {
1490
- publicKey,
1491
- baseURL,
1492
- jsonpCallback,
1493
- secureSignature,
1494
- secureExpire,
1495
- signal,
1496
- source,
1497
- integration,
1498
- userAgent,
1499
- retryThrottledRequestMaxTimes
1500
- })
1501
- .then((groupInfo) => new UploadcareGroup(groupInfo, filesInGroup))
1502
- .then((group) => {
1503
- onProgress && onProgress({ isComputable: true, value: 1 });
1504
- return group;
1505
- });
1506
- });
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
+ });
1507
1500
  }
1508
1501
 
1509
- /**
1510
- * Populate options with settings.
1511
- */
1512
- const populateOptionsWithSettings = (options, settings) => (Object.assign(Object.assign({}, settings), options));
1513
- class UploadClient {
1514
- constructor(settings) {
1515
- this.settings = Object.assign({}, defaultSettings, settings);
1516
- }
1517
- updateSettings(newSettings) {
1518
- this.settings = Object.assign(this.settings, newSettings);
1519
- }
1520
- getSettings() {
1521
- return this.settings;
1522
- }
1523
- base(file, options) {
1524
- const settings = this.getSettings();
1525
- return base(file, populateOptionsWithSettings(options, settings));
1526
- }
1527
- info(uuid, options) {
1528
- const settings = this.getSettings();
1529
- return info(uuid, populateOptionsWithSettings(options, settings));
1530
- }
1531
- fromUrl(sourceUrl, options) {
1532
- const settings = this.getSettings();
1533
- return fromUrl(sourceUrl, populateOptionsWithSettings(options, settings));
1534
- }
1535
- fromUrlStatus(token, options) {
1536
- const settings = this.getSettings();
1537
- return fromUrlStatus(token, populateOptionsWithSettings(options, settings));
1538
- }
1539
- group(uuids, options) {
1540
- const settings = this.getSettings();
1541
- return group(uuids, populateOptionsWithSettings(options, settings));
1542
- }
1543
- groupInfo(id, options) {
1544
- const settings = this.getSettings();
1545
- return groupInfo(id, populateOptionsWithSettings(options, settings));
1546
- }
1547
- multipartStart(size, options) {
1548
- const settings = this.getSettings();
1549
- return multipartStart(size, populateOptionsWithSettings(options, settings));
1550
- }
1551
- multipartUpload(part, url, options) {
1552
- const settings = this.getSettings();
1553
- return multipartUpload(part, url, populateOptionsWithSettings(options, settings));
1554
- }
1555
- multipartComplete(uuid, options) {
1556
- const settings = this.getSettings();
1557
- return multipartComplete(uuid, populateOptionsWithSettings(options, settings));
1558
- }
1559
- uploadFile(data, options) {
1560
- const settings = this.getSettings();
1561
- return uploadFile(data, populateOptionsWithSettings(options, settings));
1562
- }
1563
- uploadFileGroup(data, options) {
1564
- const settings = this.getSettings();
1565
- return uploadFileGroup(data, populateOptionsWithSettings(options, settings));
1566
- }
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
+ }
1567
1560
  }
1568
1561
 
1569
- export { UploadClient, UploadClientError, UploadcareFile, UploadcareGroup, base, fromUrl, fromUrlStatus, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadFromObject as uploadBase, uploadFile, uploadFileGroup, uploadFromUploaded, uploadFromUrl, uploadMultipart };
1562
+ export { UploadClient, UploadClientError, UploadcareFile, UploadcareGroup, base, fromUrl, fromUrlStatus, group, groupInfo, info, multipartComplete, multipartStart, multipartUpload, uploadDirect, uploadFile, uploadFileGroup, uploadFromUploaded, uploadFromUrl, uploadMultipart };