@atlaskit/media-client 15.1.1 → 17.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/constants/package.json +1 -0
- package/dist/cjs/client/file-fetcher/index.js +0 -2
- package/dist/cjs/client/media-store/index.js +63 -24
- package/dist/cjs/constants.js +11 -2
- package/dist/cjs/index.js +12 -6
- package/dist/cjs/models/media.js +10 -2
- package/dist/cjs/uploader/calculateChunkSize.js +45 -0
- package/dist/cjs/uploader/error.js +67 -0
- package/dist/cjs/{uploader.js → uploader/index.js} +43 -8
- package/dist/cjs/utils/request/errors.js +4 -0
- package/dist/cjs/utils/request/helpers.js +40 -34
- package/dist/cjs/version.json +1 -1
- package/dist/es2019/client/media-store/index.js +37 -9
- package/dist/es2019/constants.js +5 -1
- package/dist/es2019/index.js +2 -2
- package/dist/es2019/models/media.js +8 -1
- package/dist/es2019/uploader/calculateChunkSize.js +32 -0
- package/dist/es2019/uploader/error.js +30 -0
- package/dist/es2019/{uploader.js → uploader/index.js} +39 -8
- package/dist/es2019/utils/request/errors.js +4 -0
- package/dist/es2019/utils/request/helpers.js +22 -24
- package/dist/es2019/version.json +1 -1
- package/dist/esm/client/file-fetcher/index.js +0 -2
- package/dist/esm/client/media-store/index.js +57 -24
- package/dist/esm/constants.js +5 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/models/media.js +8 -1
- package/dist/esm/uploader/calculateChunkSize.js +32 -0
- package/dist/esm/uploader/error.js +51 -0
- package/dist/esm/{uploader.js → uploader/index.js} +39 -8
- package/dist/esm/utils/request/errors.js +4 -0
- package/dist/esm/utils/request/helpers.js +36 -31
- package/dist/esm/version.json +1 -1
- package/dist/types/client/media-store/index.d.ts +11 -2
- package/dist/types/constants.d.ts +3 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/models/errors/types.d.ts +1 -1
- package/dist/types/models/media.d.ts +5 -0
- package/dist/types/uploader/calculateChunkSize.d.ts +11 -0
- package/dist/types/uploader/error.d.ts +29 -0
- package/dist/types/{uploader.d.ts → uploader/index.d.ts} +1 -1
- package/dist/types/utils/request/errors.d.ts +2 -0
- package/dist/types/utils/request/helpers.d.ts +4 -4
- package/dist/types/utils/request/types.d.ts +2 -0
- package/package.json +7 -9
|
@@ -14,7 +14,7 @@ exports.createProcessFetchResponse = createProcessFetchResponse;
|
|
|
14
14
|
exports.createRequestErrorFromResponse = createRequestErrorFromResponse;
|
|
15
15
|
exports.createRequestErrorReason = createRequestErrorReason;
|
|
16
16
|
exports.createUrl = createUrl;
|
|
17
|
-
exports.
|
|
17
|
+
exports.extractMediaHeaders = extractMediaHeaders;
|
|
18
18
|
exports.fetchRetry = fetchRetry;
|
|
19
19
|
exports.isAbortedRequestError = isAbortedRequestError;
|
|
20
20
|
exports.isFetchNetworkError = isFetchNetworkError;
|
|
@@ -30,12 +30,14 @@ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"))
|
|
|
30
30
|
|
|
31
31
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
32
32
|
|
|
33
|
+
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
34
|
+
|
|
35
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
36
|
+
|
|
33
37
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
34
38
|
|
|
35
39
|
var _mediaCore = require("@atlaskit/media-core");
|
|
36
40
|
|
|
37
|
-
var _queryString = require("query-string");
|
|
38
|
-
|
|
39
41
|
var _authQueryParameters = require("../../models/auth-query-parameters");
|
|
40
42
|
|
|
41
43
|
var _errors = require("./errors");
|
|
@@ -69,21 +71,6 @@ function isRateLimitedError(error) {
|
|
|
69
71
|
return !!error && (0, _errors.isRequestError)(error) && error.attributes.statusCode === 429 || !!error && !!error.message && error.message.includes('429');
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
function extract(url) {
|
|
73
|
-
var index = url.indexOf('?');
|
|
74
|
-
|
|
75
|
-
if (index > 0) {
|
|
76
|
-
return {
|
|
77
|
-
baseUrl: url.substring(0, index),
|
|
78
|
-
queryParams: (0, _queryString.parse)(url.substring(index + 1, url.length))
|
|
79
|
-
};
|
|
80
|
-
} else {
|
|
81
|
-
return {
|
|
82
|
-
baseUrl: url
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
74
|
function mapAuthToRequestHeaders(auth) {
|
|
88
75
|
if ((0, _mediaCore.isClientBasedAuth)(auth)) {
|
|
89
76
|
return {
|
|
@@ -101,15 +88,24 @@ function mapAuthToRequestHeaders(auth) {
|
|
|
101
88
|
function createUrl(url, _ref) {
|
|
102
89
|
var params = _ref.params,
|
|
103
90
|
auth = _ref.auth;
|
|
91
|
+
var parsedUrl = new URL(url);
|
|
92
|
+
var authParams = auth && (0, _authQueryParameters.mapAuthToQueryParameters)(auth) || {};
|
|
93
|
+
|
|
94
|
+
var paramsToAppend = _objectSpread(_objectSpread({}, params), authParams);
|
|
104
95
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
96
|
+
Object.entries(paramsToAppend).filter(function (_ref2) {
|
|
97
|
+
var _ref3 = (0, _slicedToArray2.default)(_ref2, 2),
|
|
98
|
+
_ = _ref3[0],
|
|
99
|
+
value = _ref3[1];
|
|
108
100
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
101
|
+
return value != null;
|
|
102
|
+
}).forEach(function (pair) {
|
|
103
|
+
var _parsedUrl$searchPara;
|
|
104
|
+
|
|
105
|
+
(_parsedUrl$searchPara = parsedUrl.searchParams).append.apply(_parsedUrl$searchPara, (0, _toConsumableArray2.default)(pair));
|
|
106
|
+
});
|
|
107
|
+
parsedUrl.searchParams.sort();
|
|
108
|
+
return parsedUrl.toString();
|
|
113
109
|
}
|
|
114
110
|
|
|
115
111
|
function withAuth(auth) {
|
|
@@ -217,7 +213,7 @@ function mapResponseToVoid() {
|
|
|
217
213
|
|
|
218
214
|
function createMapResponseToJson(metadata) {
|
|
219
215
|
return /*#__PURE__*/function () {
|
|
220
|
-
var
|
|
216
|
+
var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(response) {
|
|
221
217
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
222
218
|
while (1) {
|
|
223
219
|
switch (_context.prev = _context.next) {
|
|
@@ -232,7 +228,7 @@ function createMapResponseToJson(metadata) {
|
|
|
232
228
|
case 6:
|
|
233
229
|
_context.prev = 6;
|
|
234
230
|
_context.t0 = _context["catch"](0);
|
|
235
|
-
throw new _errors.RequestError('serverInvalidBody', _objectSpread(_objectSpread({}, metadata), {}, {
|
|
231
|
+
throw new _errors.RequestError('serverInvalidBody', _objectSpread(_objectSpread(_objectSpread({}, metadata), extractMediaHeaders(response)), {}, {
|
|
236
232
|
statusCode: response.status
|
|
237
233
|
}), _context.t0);
|
|
238
234
|
|
|
@@ -245,14 +241,14 @@ function createMapResponseToJson(metadata) {
|
|
|
245
241
|
}));
|
|
246
242
|
|
|
247
243
|
return function (_x3) {
|
|
248
|
-
return
|
|
244
|
+
return _ref4.apply(this, arguments);
|
|
249
245
|
};
|
|
250
246
|
}();
|
|
251
247
|
}
|
|
252
248
|
|
|
253
249
|
function createMapResponseToBlob(metadata) {
|
|
254
250
|
return /*#__PURE__*/function () {
|
|
255
|
-
var
|
|
251
|
+
var _ref5 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(response) {
|
|
256
252
|
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
257
253
|
while (1) {
|
|
258
254
|
switch (_context2.prev = _context2.next) {
|
|
@@ -267,7 +263,7 @@ function createMapResponseToBlob(metadata) {
|
|
|
267
263
|
case 6:
|
|
268
264
|
_context2.prev = 6;
|
|
269
265
|
_context2.t0 = _context2["catch"](0);
|
|
270
|
-
throw new _errors.RequestError('serverInvalidBody', _objectSpread(_objectSpread({}, metadata), {}, {
|
|
266
|
+
throw new _errors.RequestError('serverInvalidBody', _objectSpread(_objectSpread(_objectSpread({}, metadata), extractMediaHeaders(response)), {}, {
|
|
271
267
|
statusCode: response.status
|
|
272
268
|
}), _context2.t0);
|
|
273
269
|
|
|
@@ -280,7 +276,7 @@ function createMapResponseToBlob(metadata) {
|
|
|
280
276
|
}));
|
|
281
277
|
|
|
282
278
|
return function (_x4) {
|
|
283
|
-
return
|
|
279
|
+
return _ref5.apply(this, arguments);
|
|
284
280
|
};
|
|
285
281
|
}();
|
|
286
282
|
}
|
|
@@ -329,7 +325,7 @@ function _fetchRetry() {
|
|
|
329
325
|
timeoutInMs = startTimeoutInMs;
|
|
330
326
|
|
|
331
327
|
waitAndBumpTimeout = /*#__PURE__*/function () {
|
|
332
|
-
var
|
|
328
|
+
var _ref6 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5() {
|
|
333
329
|
return _regenerator.default.wrap(function _callee5$(_context5) {
|
|
334
330
|
while (1) {
|
|
335
331
|
switch (_context5.prev = _context5.next) {
|
|
@@ -350,7 +346,7 @@ function _fetchRetry() {
|
|
|
350
346
|
}));
|
|
351
347
|
|
|
352
348
|
return function waitAndBumpTimeout() {
|
|
353
|
-
return
|
|
349
|
+
return _ref6.apply(this, arguments);
|
|
354
350
|
};
|
|
355
351
|
}();
|
|
356
352
|
|
|
@@ -453,7 +449,7 @@ function createRequestErrorReason(statusCode) {
|
|
|
453
449
|
function createRequestErrorFromResponse(metadata, response) {
|
|
454
450
|
var statusCode = response.status;
|
|
455
451
|
var reason = createRequestErrorReason(statusCode);
|
|
456
|
-
return new _errors.RequestError(reason, _objectSpread(_objectSpread({}, metadata), {}, {
|
|
452
|
+
return new _errors.RequestError(reason, _objectSpread(_objectSpread(_objectSpread({}, metadata), extractMediaHeaders(response)), {}, {
|
|
457
453
|
statusCode: statusCode
|
|
458
454
|
}));
|
|
459
455
|
}
|
|
@@ -467,4 +463,14 @@ function createProcessFetchResponse(metadata) {
|
|
|
467
463
|
var requestError = createRequestErrorFromResponse(metadata, response);
|
|
468
464
|
throw requestError;
|
|
469
465
|
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function extractMediaHeaders(response) {
|
|
469
|
+
var headers = response.headers;
|
|
470
|
+
var mediaRegion = headers.get('x-media-region') || 'unknown';
|
|
471
|
+
var mediaEnv = headers.get('x-media-env') || 'unknown';
|
|
472
|
+
return {
|
|
473
|
+
mediaRegion: mediaRegion,
|
|
474
|
+
mediaEnv: mediaEnv
|
|
475
|
+
};
|
|
470
476
|
}
|
package/dist/cjs/version.json
CHANGED
|
@@ -5,6 +5,8 @@ import { request } from '../../utils/request';
|
|
|
5
5
|
import { createUrl, createMapResponseToJson, createMapResponseToBlob } from '../../utils/request/helpers';
|
|
6
6
|
import { resolveAuth, resolveInitialAuth } from './resolveAuth';
|
|
7
7
|
export { MediaStoreError, isMediaStoreError } from './error';
|
|
8
|
+
const MEDIA_API_REGION = 'media-api-region';
|
|
9
|
+
const MEDIA_API_ENVIRONMENT = 'media-api-environment';
|
|
8
10
|
const defaultImageOptions = {
|
|
9
11
|
'max-age': FILE_CACHE_MAX_AGE,
|
|
10
12
|
allowAnimated: true,
|
|
@@ -120,12 +122,20 @@ export class MediaStore {
|
|
|
120
122
|
return this.request(`/upload`, options).then(createMapResponseToJson(metadata));
|
|
121
123
|
}
|
|
122
124
|
|
|
123
|
-
async uploadChunk(etag, blob,
|
|
125
|
+
async uploadChunk(etag, blob, {
|
|
126
|
+
collectionName,
|
|
127
|
+
uploadId,
|
|
128
|
+
partNumber
|
|
129
|
+
} = {}) {
|
|
124
130
|
const metadata = {
|
|
125
131
|
method: 'PUT',
|
|
126
132
|
endpoint: '/chunk/{etag}'
|
|
127
133
|
};
|
|
128
134
|
const options = { ...metadata,
|
|
135
|
+
params: {
|
|
136
|
+
uploadId,
|
|
137
|
+
partNumber
|
|
138
|
+
},
|
|
129
139
|
authContext: {
|
|
130
140
|
collectionName
|
|
131
141
|
},
|
|
@@ -134,12 +144,18 @@ export class MediaStore {
|
|
|
134
144
|
await this.request(`/chunk/${etag}`, options);
|
|
135
145
|
}
|
|
136
146
|
|
|
137
|
-
probeChunks(chunks,
|
|
147
|
+
probeChunks(chunks, {
|
|
148
|
+
collectionName,
|
|
149
|
+
uploadId
|
|
150
|
+
} = {}) {
|
|
138
151
|
const metadata = {
|
|
139
152
|
method: 'POST',
|
|
140
153
|
endpoint: '/chunk/probe'
|
|
141
154
|
};
|
|
142
155
|
const options = { ...metadata,
|
|
156
|
+
params: {
|
|
157
|
+
uploadId
|
|
158
|
+
},
|
|
143
159
|
authContext: {
|
|
144
160
|
collectionName
|
|
145
161
|
},
|
|
@@ -373,20 +389,32 @@ export class MediaStore {
|
|
|
373
389
|
body,
|
|
374
390
|
clientOptions
|
|
375
391
|
}, controller);
|
|
376
|
-
|
|
392
|
+
setKeyValueInSessionStorage(MEDIA_API_REGION, response.headers.get('x-media-region'));
|
|
393
|
+
setKeyValueInSessionStorage(MEDIA_API_ENVIRONMENT, response.headers.get('x-media-env'));
|
|
377
394
|
return response;
|
|
378
395
|
}
|
|
379
396
|
|
|
380
397
|
}
|
|
381
398
|
|
|
382
|
-
|
|
383
|
-
|
|
399
|
+
const getValueFromSessionStorage = key => {
|
|
400
|
+
return window && window.sessionStorage && window.sessionStorage.getItem(key) || undefined;
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
const setKeyValueInSessionStorage = (key, value) => {
|
|
404
|
+
if (!value || !(window && window.sessionStorage)) {
|
|
384
405
|
return;
|
|
385
406
|
}
|
|
386
407
|
|
|
387
|
-
const
|
|
408
|
+
const currentValue = window.sessionStorage.getItem(key);
|
|
388
409
|
|
|
389
|
-
if (
|
|
390
|
-
window.sessionStorage.setItem(
|
|
410
|
+
if (currentValue !== value) {
|
|
411
|
+
window.sessionStorage.setItem(key, value);
|
|
391
412
|
}
|
|
392
|
-
}
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
export const getMediaEnvironment = () => {
|
|
416
|
+
return getValueFromSessionStorage(MEDIA_API_ENVIRONMENT);
|
|
417
|
+
};
|
|
418
|
+
export const getMediaRegion = () => {
|
|
419
|
+
return getValueFromSessionStorage(MEDIA_API_REGION);
|
|
420
|
+
};
|
package/dist/es2019/constants.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { DATA_UNIT } from './models/media';
|
|
1
2
|
export const RECENTS_COLLECTION = 'recents';
|
|
2
3
|
export const FILE_CACHE_MAX_AGE = 60 * 60 * 24 * 30; // Retain for 30 days
|
|
3
4
|
|
|
4
|
-
export const MAX_RESOLUTION = 4096;
|
|
5
|
+
export const MAX_RESOLUTION = 4096;
|
|
6
|
+
export const CHUNK_SIZE = 4 * DATA_UNIT.MB;
|
|
7
|
+
export const PROCESSING_BATCH_SIZE = 1000;
|
|
8
|
+
export const MAX_UPLOAD_FILE_SIZE = 2 * DATA_UNIT.TB;
|
package/dist/es2019/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { MediaStore, MediaStoreError, isMediaStoreError } from './client/media-store';
|
|
1
|
+
export { MediaStore, MediaStoreError, isMediaStoreError, getMediaEnvironment, getMediaRegion } from './client/media-store';
|
|
2
2
|
export { UploadController } from './upload-controller';
|
|
3
3
|
export { isPreviewableType, isMediaCollectionItemFullDetails } from './models/media';
|
|
4
4
|
export { getArtifactUrl } from './models/artifacts';
|
|
5
5
|
export { isMediaClientError, getMediaClientErrorReason } from './models/errors';
|
|
6
6
|
export { isUploadingFileState, isProcessingFileState, isProcessedFileState, isErrorFileState, isPreviewableFileState, isFinalFileState, isImageRepresentationReady, mapMediaFileToFileState, mapMediaItemToFileState } from './models/file-state';
|
|
7
7
|
// TODO: remove access to media file stream cache https://product-fabric.atlassian.net/browse/MEX-1417
|
|
8
|
-
export {
|
|
8
|
+
export { StreamsCache } from './file-streams-cache';
|
|
9
9
|
export { uploadFile } from './uploader';
|
|
10
10
|
export { request, RequestError, isRequestError, isRateLimitedError } from './utils/request';
|
|
11
11
|
export { isAbortedRequestError, mapResponseToJson, mapResponseToBlob, mapResponseToVoid, createUrl } from './utils/request/helpers';
|
|
@@ -9,4 +9,11 @@ export const isPreviewableType = (type, featureFlags) => {
|
|
|
9
9
|
|
|
10
10
|
return defaultPreviewableTypes.indexOf(type) > -1;
|
|
11
11
|
};
|
|
12
|
-
export const isMediaCollectionItemFullDetails = mediaCollectionItem => !!mediaCollectionItem['mediaType'] && !!mediaCollectionItem['mimeType'] && !!mediaCollectionItem['processingStatus'];
|
|
12
|
+
export const isMediaCollectionItemFullDetails = mediaCollectionItem => !!mediaCollectionItem['mediaType'] && !!mediaCollectionItem['mimeType'] && !!mediaCollectionItem['processingStatus'];
|
|
13
|
+
export let DATA_UNIT;
|
|
14
|
+
|
|
15
|
+
(function (DATA_UNIT) {
|
|
16
|
+
DATA_UNIT[DATA_UNIT["MB"] = 1048576] = "MB";
|
|
17
|
+
DATA_UNIT[DATA_UNIT["GB"] = 1073741824] = "GB";
|
|
18
|
+
DATA_UNIT[DATA_UNIT["TB"] = 1099511627776] = "TB";
|
|
19
|
+
})(DATA_UNIT || (DATA_UNIT = {}));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DATA_UNIT } from '../models/media';
|
|
2
|
+
import { MAX_UPLOAD_FILE_SIZE } from '../constants';
|
|
3
|
+
export const fileSizeError = 'fileSizeExceedsLimit';
|
|
4
|
+
/**
|
|
5
|
+
* This is a helper to dynamically calculate the chunk size for a given file size.
|
|
6
|
+
*
|
|
7
|
+
* @param fileSize The size of a file to calculate the chunk size for.
|
|
8
|
+
* @returns A number of bytes per chunk or Throws an Error if the file size exceeds 2TB
|
|
9
|
+
*
|
|
10
|
+
* @see {@link https://product-fabric.atlassian.net/wiki/spaces/FIL/pages/3221881143/Rule+of+thumb+for+chunk+sizes#Given-the-following-conditions}
|
|
11
|
+
*
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export const calculateChunkSize = fileSize => {
|
|
15
|
+
if (fileSize > MAX_UPLOAD_FILE_SIZE) {
|
|
16
|
+
throw new Error(fileSizeError);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (fileSize <= 5 * DATA_UNIT.GB) {
|
|
20
|
+
return 5 * DATA_UNIT.MB;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (fileSize > 5 * DATA_UNIT.GB && fileSize <= 50 * DATA_UNIT.GB) {
|
|
24
|
+
return 50 * DATA_UNIT.MB;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (fileSize > 50 * DATA_UNIT.GB && fileSize <= 0.95 * DATA_UNIT.TB) {
|
|
28
|
+
return 100 * DATA_UNIT.MB;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return 210 * DATA_UNIT.MB;
|
|
32
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BaseMediaClientError } from '../models/errors';
|
|
2
|
+
export class UploaderError extends BaseMediaClientError {
|
|
3
|
+
constructor(reason, id, metadata) {
|
|
4
|
+
super(reason);
|
|
5
|
+
this.reason = reason;
|
|
6
|
+
this.id = id;
|
|
7
|
+
this.metadata = metadata;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
get attributes() {
|
|
11
|
+
const {
|
|
12
|
+
reason,
|
|
13
|
+
id,
|
|
14
|
+
metadata: {
|
|
15
|
+
collectionName,
|
|
16
|
+
occurrenceKey
|
|
17
|
+
} = {}
|
|
18
|
+
} = this;
|
|
19
|
+
return {
|
|
20
|
+
reason,
|
|
21
|
+
id,
|
|
22
|
+
collectionName,
|
|
23
|
+
occurrenceKey
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
export function isUploaderError(err) {
|
|
29
|
+
return err instanceof UploaderError;
|
|
30
|
+
}
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
import { chunkinator } from '@atlaskit/chunkinator';
|
|
2
2
|
import { from } from 'rxjs/observable/from';
|
|
3
3
|
import { concatMap } from 'rxjs/operators/concatMap';
|
|
4
|
-
import { createHasher } from '
|
|
4
|
+
import { createHasher } from '../utils/hashing/hasherCreator';
|
|
5
|
+
import { UploaderError } from './error';
|
|
6
|
+
import { CHUNK_SIZE, PROCESSING_BATCH_SIZE } from '../constants';
|
|
7
|
+
import { calculateChunkSize, fileSizeError } from './calculateChunkSize';
|
|
8
|
+
import { getMediaFeatureFlag } from '@atlaskit/media-common'; // TODO: Allow to pass multiple files
|
|
5
9
|
|
|
6
10
|
const hashingFunction = async blob => {
|
|
7
11
|
const hasher = await createHasher();
|
|
8
12
|
return hasher.hash(blob);
|
|
9
13
|
};
|
|
10
14
|
|
|
11
|
-
const createProbingFunction = (store,
|
|
12
|
-
const response = await store.probeChunks(hashedChunks(chunks),
|
|
15
|
+
const createProbingFunction = (store, collectionName) => async chunks => {
|
|
16
|
+
const response = await store.probeChunks(hashedChunks(chunks), {
|
|
17
|
+
collectionName
|
|
18
|
+
});
|
|
13
19
|
const results = response.data.results;
|
|
14
20
|
return Object.values(results).map(result => result.exists);
|
|
15
21
|
};
|
|
16
22
|
|
|
17
|
-
const createUploadingFunction = (store,
|
|
18
|
-
return chunk => store.uploadChunk(chunk.hash, chunk.blob,
|
|
23
|
+
const createUploadingFunction = (store, collectionName) => {
|
|
24
|
+
return chunk => store.uploadChunk(chunk.hash, chunk.blob, {
|
|
25
|
+
collectionName
|
|
26
|
+
});
|
|
19
27
|
};
|
|
20
28
|
|
|
21
29
|
const createProcessingFunction = (store, deferredUploadId, collection) => {
|
|
@@ -56,17 +64,40 @@ export const uploadFile = (file, store, uploadableFileUpfrontIds, callbacks) =>
|
|
|
56
64
|
collection
|
|
57
65
|
} = file;
|
|
58
66
|
const {
|
|
59
|
-
deferredUploadId
|
|
67
|
+
deferredUploadId,
|
|
68
|
+
id,
|
|
69
|
+
occurrenceKey
|
|
60
70
|
} = uploadableFileUpfrontIds;
|
|
71
|
+
let chunkSize = CHUNK_SIZE;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
if (content instanceof Blob && getMediaFeatureFlag('mediaUploadApiV2', store.featureFlags)) {
|
|
75
|
+
chunkSize = calculateChunkSize(content.size);
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
if (err instanceof Error && err.message === fileSizeError) {
|
|
79
|
+
callbacks === null || callbacks === void 0 ? void 0 : callbacks.onUploadFinish(new UploaderError(err.message, id, {
|
|
80
|
+
collectionName: collection,
|
|
81
|
+
occurrenceKey: occurrenceKey
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
cancel: () => {
|
|
87
|
+
callbacks === null || callbacks === void 0 ? void 0 : callbacks.onUploadFinish('canceled');
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
61
92
|
const chunkinatorObservable = chunkinator(content, {
|
|
62
93
|
hashingFunction,
|
|
63
94
|
hashingConcurrency: 5,
|
|
64
95
|
probingBatchSize: 100,
|
|
65
|
-
chunkSize
|
|
96
|
+
chunkSize,
|
|
66
97
|
uploadingConcurrency: 3,
|
|
67
98
|
uploadingFunction: createUploadingFunction(store, collection),
|
|
68
99
|
probingFunction: createProbingFunction(store, collection),
|
|
69
|
-
processingBatchSize:
|
|
100
|
+
processingBatchSize: PROCESSING_BATCH_SIZE,
|
|
70
101
|
processingFunction: createProcessingFunction(store, deferredUploadId, collection)
|
|
71
102
|
}, {
|
|
72
103
|
onProgress(progress) {
|
|
@@ -13,6 +13,8 @@ export class RequestError extends BaseMediaClientError {
|
|
|
13
13
|
metadata: {
|
|
14
14
|
method,
|
|
15
15
|
endpoint,
|
|
16
|
+
mediaRegion,
|
|
17
|
+
mediaEnv,
|
|
16
18
|
attempts,
|
|
17
19
|
clientExhaustedRetries,
|
|
18
20
|
statusCode
|
|
@@ -23,6 +25,8 @@ export class RequestError extends BaseMediaClientError {
|
|
|
23
25
|
reason,
|
|
24
26
|
method,
|
|
25
27
|
endpoint,
|
|
28
|
+
mediaRegion,
|
|
29
|
+
mediaEnv,
|
|
26
30
|
attempts,
|
|
27
31
|
clientExhaustedRetries,
|
|
28
32
|
statusCode,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { isClientBasedAuth } from '@atlaskit/media-core';
|
|
2
|
-
import { parse, stringify } from 'query-string';
|
|
3
2
|
import { mapAuthToQueryParameters } from '../../models/auth-query-parameters';
|
|
4
3
|
import { RequestError, isRequestError } from './errors';
|
|
5
4
|
export function clientTimeoutPromise(timeout) {
|
|
@@ -20,20 +19,6 @@ export function isFetchNetworkError(err) {
|
|
|
20
19
|
export function isRateLimitedError(error) {
|
|
21
20
|
return !!error && isRequestError(error) && error.attributes.statusCode === 429 || !!error && !!error.message && error.message.includes('429');
|
|
22
21
|
}
|
|
23
|
-
export function extract(url) {
|
|
24
|
-
const index = url.indexOf('?');
|
|
25
|
-
|
|
26
|
-
if (index > 0) {
|
|
27
|
-
return {
|
|
28
|
-
baseUrl: url.substring(0, index),
|
|
29
|
-
queryParams: parse(url.substring(index + 1, url.length))
|
|
30
|
-
};
|
|
31
|
-
} else {
|
|
32
|
-
return {
|
|
33
|
-
baseUrl: url
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
22
|
export function mapAuthToRequestHeaders(auth) {
|
|
38
23
|
if (isClientBasedAuth(auth)) {
|
|
39
24
|
return {
|
|
@@ -51,17 +36,16 @@ export function createUrl(url, {
|
|
|
51
36
|
params,
|
|
52
37
|
auth
|
|
53
38
|
}) {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
} = extract(url);
|
|
58
|
-
const authParams = auth && mapAuthToQueryParameters(auth);
|
|
59
|
-
const queryString = stringify({ ...queryParams,
|
|
60
|
-
...params,
|
|
39
|
+
const parsedUrl = new URL(url);
|
|
40
|
+
const authParams = auth && mapAuthToQueryParameters(auth) || {};
|
|
41
|
+
const paramsToAppend = { ...params,
|
|
61
42
|
...authParams
|
|
43
|
+
};
|
|
44
|
+
Object.entries(paramsToAppend).filter(([_, value]) => value != null).forEach(pair => {
|
|
45
|
+
parsedUrl.searchParams.append(...pair);
|
|
62
46
|
});
|
|
63
|
-
|
|
64
|
-
return
|
|
47
|
+
parsedUrl.searchParams.sort();
|
|
48
|
+
return parsedUrl.toString();
|
|
65
49
|
}
|
|
66
50
|
export function withAuth(auth) {
|
|
67
51
|
return headers => {
|
|
@@ -124,6 +108,7 @@ export function createMapResponseToJson(metadata) {
|
|
|
124
108
|
return await response.json();
|
|
125
109
|
} catch (err) {
|
|
126
110
|
throw new RequestError('serverInvalidBody', { ...metadata,
|
|
111
|
+
...extractMediaHeaders(response),
|
|
127
112
|
statusCode: response.status
|
|
128
113
|
}, err);
|
|
129
114
|
}
|
|
@@ -135,6 +120,7 @@ export function createMapResponseToBlob(metadata) {
|
|
|
135
120
|
return await response.blob();
|
|
136
121
|
} catch (err) {
|
|
137
122
|
throw new RequestError('serverInvalidBody', { ...metadata,
|
|
123
|
+
...extractMediaHeaders(response),
|
|
138
124
|
statusCode: response.status
|
|
139
125
|
}, err);
|
|
140
126
|
}
|
|
@@ -240,6 +226,7 @@ export function createRequestErrorFromResponse(metadata, response) {
|
|
|
240
226
|
} = response;
|
|
241
227
|
const reason = createRequestErrorReason(statusCode);
|
|
242
228
|
return new RequestError(reason, { ...metadata,
|
|
229
|
+
...extractMediaHeaders(response),
|
|
243
230
|
statusCode
|
|
244
231
|
});
|
|
245
232
|
}
|
|
@@ -252,4 +239,15 @@ export function createProcessFetchResponse(metadata) {
|
|
|
252
239
|
const requestError = createRequestErrorFromResponse(metadata, response);
|
|
253
240
|
throw requestError;
|
|
254
241
|
};
|
|
242
|
+
}
|
|
243
|
+
export function extractMediaHeaders(response) {
|
|
244
|
+
const {
|
|
245
|
+
headers
|
|
246
|
+
} = response;
|
|
247
|
+
const mediaRegion = headers.get('x-media-region') || 'unknown';
|
|
248
|
+
const mediaEnv = headers.get('x-media-env') || 'unknown';
|
|
249
|
+
return {
|
|
250
|
+
mediaRegion,
|
|
251
|
+
mediaEnv
|
|
252
|
+
};
|
|
255
253
|
}
|
package/dist/es2019/version.json
CHANGED
|
@@ -285,7 +285,6 @@ export var FileFetcherImpl = /*#__PURE__*/function () {
|
|
|
285
285
|
};
|
|
286
286
|
mediaType = getMediaTypeFromMimeType(type); // we emit a richer state after the blob is fetched
|
|
287
287
|
|
|
288
|
-
// we emit a richer state after the blob is fetched
|
|
289
288
|
subject.next({
|
|
290
289
|
status: 'processing',
|
|
291
290
|
name: name,
|
|
@@ -297,7 +296,6 @@ export var FileFetcherImpl = /*#__PURE__*/function () {
|
|
|
297
296
|
preview: preview
|
|
298
297
|
}); // we don't want to wait for the file to be upload
|
|
299
298
|
|
|
300
|
-
// we don't want to wait for the file to be upload
|
|
301
299
|
_this3.upload(file, undefined, uploadableFileUpfrontIds);
|
|
302
300
|
|
|
303
301
|
_context3.next = 12;
|