@atlaskit/media-file-preview 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/LICENSE.md +13 -0
  3. package/README.md +9 -0
  4. package/dist/cjs/analytics.js +50 -0
  5. package/dist/cjs/errors.js +143 -0
  6. package/dist/cjs/getPreview/cache.js +39 -0
  7. package/dist/cjs/getPreview/getPreview.js +119 -0
  8. package/dist/cjs/getPreview/helpers.js +167 -0
  9. package/dist/cjs/getPreview/index.js +56 -0
  10. package/dist/cjs/getPreview/objectURLCache.js +85 -0
  11. package/dist/cjs/getPreview/videoSnapshot.js +63 -0
  12. package/dist/cjs/globalScope/getSSRData.js +14 -0
  13. package/dist/cjs/globalScope/globalScope.js +66 -0
  14. package/dist/cjs/globalScope/index.js +37 -0
  15. package/dist/cjs/globalScope/printScript.js +32 -0
  16. package/dist/cjs/globalScope/types.js +5 -0
  17. package/dist/cjs/helpers.js +56 -0
  18. package/dist/cjs/index.js +12 -0
  19. package/dist/cjs/types.js +5 -0
  20. package/dist/cjs/useFilePreview.js +355 -0
  21. package/dist/es2019/analytics.js +44 -0
  22. package/dist/es2019/errors.js +90 -0
  23. package/dist/es2019/getPreview/cache.js +30 -0
  24. package/dist/es2019/getPreview/getPreview.js +75 -0
  25. package/dist/es2019/getPreview/helpers.js +77 -0
  26. package/dist/es2019/getPreview/index.js +3 -0
  27. package/dist/es2019/getPreview/objectURLCache.js +44 -0
  28. package/dist/es2019/getPreview/videoSnapshot.js +41 -0
  29. package/dist/es2019/globalScope/getSSRData.js +8 -0
  30. package/dist/es2019/globalScope/globalScope.js +48 -0
  31. package/dist/es2019/globalScope/index.js +2 -0
  32. package/dist/es2019/globalScope/printScript.js +16 -0
  33. package/dist/es2019/globalScope/types.js +1 -0
  34. package/dist/es2019/helpers.js +53 -0
  35. package/dist/es2019/index.js +1 -0
  36. package/dist/es2019/types.js +1 -0
  37. package/dist/es2019/useFilePreview.js +333 -0
  38. package/dist/esm/analytics.js +44 -0
  39. package/dist/esm/errors.js +133 -0
  40. package/dist/esm/getPreview/cache.js +32 -0
  41. package/dist/esm/getPreview/getPreview.js +112 -0
  42. package/dist/esm/getPreview/helpers.js +161 -0
  43. package/dist/esm/getPreview/index.js +3 -0
  44. package/dist/esm/getPreview/objectURLCache.js +78 -0
  45. package/dist/esm/getPreview/videoSnapshot.js +56 -0
  46. package/dist/esm/globalScope/getSSRData.js +8 -0
  47. package/dist/esm/globalScope/globalScope.js +56 -0
  48. package/dist/esm/globalScope/index.js +2 -0
  49. package/dist/esm/globalScope/printScript.js +25 -0
  50. package/dist/esm/globalScope/types.js +1 -0
  51. package/dist/esm/helpers.js +49 -0
  52. package/dist/esm/index.js +1 -0
  53. package/dist/esm/types.js +1 -0
  54. package/dist/esm/useFilePreview.js +348 -0
  55. package/dist/types/analytics.d.ts +28 -0
  56. package/dist/types/errors.d.ts +42 -0
  57. package/dist/types/getPreview/cache.d.ts +21 -0
  58. package/dist/types/getPreview/getPreview.d.ts +9 -0
  59. package/dist/types/getPreview/helpers.d.ts +10 -0
  60. package/dist/types/getPreview/index.d.ts +3 -0
  61. package/dist/types/getPreview/objectURLCache.d.ts +12 -0
  62. package/dist/types/getPreview/videoSnapshot.d.ts +1 -0
  63. package/dist/types/globalScope/getSSRData.d.ts +3 -0
  64. package/dist/types/globalScope/globalScope.d.ts +15 -0
  65. package/dist/types/globalScope/index.d.ts +4 -0
  66. package/dist/types/globalScope/printScript.d.ts +2 -0
  67. package/dist/types/globalScope/types.d.ts +8 -0
  68. package/dist/types/helpers.d.ts +10 -0
  69. package/dist/types/index.d.ts +2 -0
  70. package/dist/types/types.d.ts +12 -0
  71. package/dist/types/useFilePreview.d.ts +33 -0
  72. package/dist/types-ts4.5/analytics.d.ts +28 -0
  73. package/dist/types-ts4.5/errors.d.ts +42 -0
  74. package/dist/types-ts4.5/getPreview/cache.d.ts +21 -0
  75. package/dist/types-ts4.5/getPreview/getPreview.d.ts +9 -0
  76. package/dist/types-ts4.5/getPreview/helpers.d.ts +10 -0
  77. package/dist/types-ts4.5/getPreview/index.d.ts +3 -0
  78. package/dist/types-ts4.5/getPreview/objectURLCache.d.ts +12 -0
  79. package/dist/types-ts4.5/getPreview/videoSnapshot.d.ts +1 -0
  80. package/dist/types-ts4.5/globalScope/getSSRData.d.ts +3 -0
  81. package/dist/types-ts4.5/globalScope/globalScope.d.ts +15 -0
  82. package/dist/types-ts4.5/globalScope/index.d.ts +4 -0
  83. package/dist/types-ts4.5/globalScope/printScript.d.ts +2 -0
  84. package/dist/types-ts4.5/globalScope/types.d.ts +8 -0
  85. package/dist/types-ts4.5/helpers.d.ts +10 -0
  86. package/dist/types-ts4.5/index.d.ts +2 -0
  87. package/dist/types-ts4.5/types.d.ts +12 -0
  88. package/dist/types-ts4.5/useFilePreview.d.ts +33 -0
  89. package/package.json +98 -0
@@ -0,0 +1,355 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.useFilePreview = void 0;
8
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
+ var _react = require("react");
11
+ var _mediaClient = require("@atlaskit/media-client");
12
+ var _mediaClientReact = require("@atlaskit/media-client-react");
13
+ var _mediaCommon = require("@atlaskit/media-common");
14
+ var _analytics = require("./analytics");
15
+ var _errors = require("./errors");
16
+ var _getPreview = require("./getPreview");
17
+ var _globalScope = require("./globalScope");
18
+ var _helpers = require("./helpers");
19
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
20
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
21
+ var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
22
+ var _ref$resizeMode = _ref.resizeMode,
23
+ resizeMode = _ref$resizeMode === void 0 ? 'crop' : _ref$resizeMode,
24
+ identifier = _ref.identifier,
25
+ ssr = _ref.ssr,
26
+ dimensions = _ref.dimensions,
27
+ traceContext = _ref.traceContext,
28
+ previewDidRender = _ref.previewDidRender,
29
+ skipRemote = _ref.skipRemote,
30
+ mediaBlobUrlAttrs = _ref.mediaBlobUrlAttrs;
31
+ var mediaClient = (0, _mediaClientReact.useMediaClient)();
32
+ var _useState = (0, _react.useState)('loading'),
33
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
34
+ status = _useState2[0],
35
+ setStatus = _useState2[1];
36
+ var _useState3 = (0, _react.useState)(),
37
+ _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
38
+ error = _useState4[0],
39
+ setError = _useState4[1];
40
+ var _useState5 = (0, _react.useState)(),
41
+ _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
42
+ nonCriticalError = _useState6[0],
43
+ setNonCriticalError = _useState6[1];
44
+ var _useState7 = (0, _react.useState)(false),
45
+ _useState8 = (0, _slicedToArray2.default)(_useState7, 2),
46
+ isBannedLocalPreview = _useState8[0],
47
+ setIsBannedLocalPreview = _useState8[1];
48
+ var wasResolvedUpfrontPreviewRef = (0, _react.useRef)(false);
49
+ var ssrReliabilityRef = (0, _react.useRef)(initialSsrReliability);
50
+ var requestDimensions = (0, _react.useMemo)(function () {
51
+ return dimensions ? (0, _helpers.createRequestDimensions)(dimensions) : undefined;
52
+ }, [dimensions]);
53
+ var requestDimensionsRef = (0, _helpers.useCurrentValueRef)(requestDimensions);
54
+ var imageURLParams = (0, _react.useMemo)(function () {
55
+ return _objectSpread(_objectSpread({
56
+ collection: identifier.collectionName,
57
+ mode: resizeMode === 'stretchy-fit' ? 'full-fit' : resizeMode
58
+ }, requestDimensions), {}, {
59
+ allowAnimated: true
60
+ });
61
+ }, [requestDimensions, identifier.collectionName, resizeMode]);
62
+ var previewInitializer = function previewInitializer() {
63
+ var fileImageMode = (0, _mediaClient.imageResizeModeToFileImageMode)(resizeMode);
64
+ var preview = _getPreview.mediaFilePreviewCache.get(identifier.id, fileImageMode);
65
+ if (preview) {
66
+ return preview;
67
+ }
68
+ if (ssr) {
69
+ var ssrData = (0, _globalScope.getSSRData)(identifier);
70
+ if (ssrData !== null && ssrData !== void 0 && ssrData.error) {
71
+ ssrReliabilityRef.current.server = _objectSpread({
72
+ status: 'fail'
73
+ }, ssrData.error);
74
+ }
75
+ if (!(ssrData !== null && ssrData !== void 0 && ssrData.dataURI)) {
76
+ try {
77
+ return (0, _getPreview.getSSRPreview)(ssr, mediaClient, identifier.id, imageURLParams, mediaBlobUrlAttrs);
78
+ } catch (e) {
79
+ ssrReliabilityRef.current[ssr] = _objectSpread({
80
+ status: 'fail'
81
+ }, (0, _analytics.extractErrorInfo)(e));
82
+ }
83
+ } else {
84
+ var _dimensions = ssrData.dimensions,
85
+ dataURI = ssrData.dataURI;
86
+ return {
87
+ dataURI: dataURI,
88
+ dimensions: _dimensions,
89
+ source: 'ssr-data'
90
+ };
91
+ }
92
+ }
93
+ };
94
+ var _useState9 = (0, _react.useState)(previewInitializer),
95
+ _useState10 = (0, _slicedToArray2.default)(_useState9, 2),
96
+ preview = _useState10[0],
97
+ setPreview = _useState10[1];
98
+ var _useFileState = (0, _mediaClientReact.useFileState)(identifier.id, {
99
+ skipRemote: skipRemote,
100
+ collectionName: identifier.collectionName,
101
+ occurrenceKey: identifier.occurrenceKey
102
+ }),
103
+ fileState = _useFileState.fileState;
104
+
105
+ //----------------------------------------------------------------
106
+ // Update status
107
+ //----------------------------------------------------------------
108
+
109
+ // TOOD: make a full hook reset (remount) on New identifier or client
110
+ (0, _react.useEffect)(function () {
111
+ setStatus('loading');
112
+ }, [identifier]);
113
+ var updateFileStateRef = (0, _helpers.useCurrentValueRef)(function () {
114
+ if (fileState) {
115
+ // do not update the status if the status is final
116
+ if (['complete', 'error', 'failed-processing'].includes(status)) {
117
+ return;
118
+ }
119
+ if (fileState.status !== 'error') {
120
+ var mediaType = 'mediaType' in fileState ? fileState.mediaType : undefined;
121
+ var isPreviewable = !!mediaType && ['audio', 'video', 'image', 'doc'].indexOf(mediaType) > -1;
122
+ var isPreviewableFileState = !!fileState.preview;
123
+ var _isSupportedLocalPreview = mediaType === 'image' || mediaType === 'video';
124
+ var hasLocalPreview = !isBannedLocalPreview && isPreviewableFileState && _isSupportedLocalPreview && !!fileState.mimeType && (0, _mediaCommon.isMimeTypeSupportedByBrowser)(fileState.mimeType);
125
+ var hasRemotePreview = (0, _mediaClient.isImageRepresentationReady)(fileState);
126
+ var hasPreview = hasLocalPreview || hasRemotePreview;
127
+ var newStatus;
128
+ switch (fileState.status) {
129
+ case 'uploading':
130
+ case 'failed-processing':
131
+ case 'processing':
132
+ newStatus = fileState.status;
133
+ break;
134
+ case 'processed':
135
+ if (!isPreviewable || !hasPreview) {
136
+ newStatus = 'complete';
137
+ break;
138
+ }
139
+ newStatus = 'loading-preview';
140
+ break;
141
+ default:
142
+ newStatus = 'loading';
143
+ }
144
+ setStatus(newStatus);
145
+ } else {
146
+ var e = new _mediaClientReact.MediaFileStateError(fileState.id, fileState.reason, fileState.message, fileState.details);
147
+ var errorReason = status === 'uploading' ? 'upload' : 'metadata-fetch';
148
+ setError(new _errors.MediaFilePreviewError(errorReason, e));
149
+ setStatus('error');
150
+ }
151
+ }
152
+ });
153
+ (0, _react.useEffect)(function () {
154
+ updateFileStateRef.current();
155
+ }, [fileState, updateFileStateRef]);
156
+ (0, _react.useEffect)(function () {
157
+ if (previewDidRender &&
158
+ // We should't complete if status is uploading
159
+ ['loading-preview', 'processing'].includes(status)) {
160
+ setStatus('complete');
161
+ // TODO MEX-788: add test for "do not remove the preview when unsubscribing".
162
+ setIsBannedLocalPreview(false); // CXP-2723 TODO: we might be able to remove this??
163
+ }
164
+ }, [previewDidRender, status]);
165
+
166
+ // CXP-2723 TODO: Create test cases for banning local preview after status is complete
167
+
168
+ //----------------------------------------------------------------
169
+ // Preview Fetch Helper
170
+ //----------------------------------------------------------------
171
+ var getAndCacheRemotePreviewRef = (0, _helpers.useCurrentValueRef)(function () {
172
+ return (0, _getPreview.getAndCacheRemotePreview)(mediaClient, identifier.id, requestDimensions || {}, imageURLParams, mediaBlobUrlAttrs, traceContext);
173
+ });
174
+
175
+ //----------------------------------------------------------------
176
+ // Cache SSR Preview
177
+ //----------------------------------------------------------------
178
+ (0, _react.useEffect)(function () {
179
+ if (!skipRemote && ssr && !!preview && (0, _getPreview.isSSRClientPreview)(preview)) {
180
+ // Since the SSR preview brings the token in the query params,
181
+ // We need to fetch the remote preview to be able to cache it,
182
+ getAndCacheRemotePreviewRef.current().catch(function () {
183
+ // No need to log this error.
184
+ // If preview fails, it will be refetched later
185
+ //TODO: test this catch
186
+ // https://product-fabric.atlassian.net/browse/MEX-1071
187
+ });
188
+ }
189
+ }, [getAndCacheRemotePreviewRef, preview, skipRemote, ssr]);
190
+
191
+ //----------------------------------------------------------------
192
+ // Refetch SRR Preview if dimensions from Server have changed and are bigger,
193
+ //----------------------------------------------------------------
194
+ (0, _react.useEffect)(function () {
195
+ // CXP-2813 TODO: This is called too many times if the refetch failed. Should be called only once
196
+ if (preview && !skipRemote && (0, _getPreview.isSSRDataPreview)(preview) && (0, _helpers.isBigger)(preview.dimensions, requestDimensions)) {
197
+ getAndCacheRemotePreviewRef.current().then(setPreview).catch(function (e) {
198
+ var wrappedError = (0, _errors.ensureMediaFilePreviewError)('remote-preview-fetch-ssr', e, true);
199
+ setNonCriticalError(wrappedError);
200
+ });
201
+ }
202
+ }, [getAndCacheRemotePreviewRef, preview, requestDimensions, skipRemote]);
203
+
204
+ //----------------------------------------------------------------
205
+ // Upfront Preview
206
+ //----------------------------------------------------------------
207
+ (0, _react.useEffect)(function () {
208
+ if (!preview && !wasResolvedUpfrontPreviewRef.current && !skipRemote) {
209
+ // We block any possible future call to this method regardless of the outcome (success or fail)
210
+ // If it fails, the normal preview fetch should occur after the file state is fetched anyways
211
+ wasResolvedUpfrontPreviewRef.current = true;
212
+ var fetchedDimensions = _objectSpread({}, requestDimensions);
213
+ getAndCacheRemotePreviewRef.current().then(function (newPreview) {
214
+ // If there are new and bigger dimensions in the props, and the upfront preview is still resolving,
215
+ // the fetched preview is no longer valid, and thus, we dismiss it
216
+ if (!(0, _helpers.isBigger)(fetchedDimensions, requestDimensionsRef.current)) {
217
+ setPreview(newPreview);
218
+ }
219
+ }).catch(function () {
220
+ // NO need to log error. If this call fails, a refetch will happen after
221
+ });
222
+ }
223
+ }, [getAndCacheRemotePreviewRef, preview, requestDimensions, requestDimensionsRef, skipRemote]);
224
+
225
+ //----------------------------------------------------------------
226
+ // Cache, Local & Remote Preview
227
+ //----------------------------------------------------------------
228
+
229
+ (0, _react.useEffect)(function () {
230
+ var cachedPreview = _getPreview.mediaFilePreviewCache.get(identifier.id, imageURLParams.mode);
231
+
232
+ // Cached Preview ----------------------------------------------------------------
233
+ if (!preview && cachedPreview && !(0, _helpers.isBigger)(cachedPreview === null || cachedPreview === void 0 ? void 0 : cachedPreview.dimensions, requestDimensions)) {
234
+ setPreview(cachedPreview);
235
+ }
236
+ // Local Preview ----------------------------------------------------------------
237
+ else if (!preview && !isBannedLocalPreview && !!fileState && 'preview' in fileState && !!fileState.preview && (0, _getPreview.isSupportedLocalPreview)(fileState.mediaType) && (0, _mediaCommon.isMimeTypeSupportedByBrowser)(fileState.mimeType)) {
238
+ // Local preview is available only if it's supported by browser and supported by Media Card (isSupportedLocalPreview)
239
+ // For example, SVGs are mime type NOT supported by browser but media type supported by Media Card (image)
240
+ // Then, local Preview NOT available
241
+
242
+ (0, _getPreview.getAndCacheLocalPreview)(identifier.id, fileState.preview, requestDimensions || {}, imageURLParams.mode, mediaBlobUrlAttrs).then(setPreview).catch(function (e) {
243
+ setIsBannedLocalPreview(true);
244
+ // CXP-2723 TODO: We might have to wrap this error in MediaCardError
245
+ setNonCriticalError(e);
246
+ });
247
+ }
248
+ // Remote Preview ----------------------------------------------------------------
249
+ else if ((!preview || (0, _helpers.isBigger)(preview.dimensions, requestDimensions)) && !skipRemote && wasResolvedUpfrontPreviewRef.current && !!fileState && (0, _mediaClient.isImageRepresentationReady)(fileState)) {
250
+ getAndCacheRemotePreviewRef.current().then(setPreview).catch(function (e) {
251
+ setStatus('error');
252
+ setError((0, _errors.ensureMediaFilePreviewError)('preview-fetch', e));
253
+ });
254
+ }
255
+ }, [fileState, getAndCacheRemotePreviewRef, identifier.id, imageURLParams.mode, isBannedLocalPreview, mediaBlobUrlAttrs, preview, requestDimensions, skipRemote]);
256
+
257
+ //----------------------------------------------------------------
258
+ // RETURN
259
+ //----------------------------------------------------------------
260
+
261
+ var onImageError = (0, _react.useCallback)(function (newPreview) {
262
+ if (newPreview) {
263
+ var failedSSRObject = _objectSpread({
264
+ status: 'fail'
265
+ }, (0, _analytics.extractErrorInfo)(new _errors.ImageLoadError(newPreview.source)));
266
+ if ((0, _getPreview.isSSRClientPreview)(newPreview)) {
267
+ ssrReliabilityRef.current.client = failedSSRObject;
268
+ }
269
+
270
+ /*
271
+ If the preview failed and it comes from server (global scope / ssrData), it means that we have reused it in client and the error counts for both: server & client.
272
+ */
273
+
274
+ if ((0, _getPreview.isSSRDataPreview)(newPreview)) {
275
+ ssrReliabilityRef.current.server = failedSSRObject;
276
+ ssrReliabilityRef.current.client = failedSSRObject;
277
+ }
278
+ }
279
+
280
+ // If the dataURI has been replaced, we can dismiss this error
281
+ if ((newPreview === null || newPreview === void 0 ? void 0 : newPreview.dataURI) !== (preview === null || preview === void 0 ? void 0 : preview.dataURI)) {
282
+ return;
283
+ }
284
+ var error = new _errors.ImageLoadError(newPreview === null || newPreview === void 0 ? void 0 : newPreview.source);
285
+ var isLocal = newPreview && (0, _getPreview.isLocalPreview)(newPreview);
286
+ var isSSR = newPreview && ((0, _getPreview.isSSRClientPreview)(newPreview) || (0, _getPreview.isSSRDataPreview)(newPreview));
287
+ if (isLocal || isSSR) {
288
+ if (isLocal) {
289
+ setIsBannedLocalPreview(true);
290
+ setNonCriticalError(error);
291
+ }
292
+ var fileImageMode = (0, _mediaClient.imageResizeModeToFileImageMode)(resizeMode);
293
+ _getPreview.mediaFilePreviewCache.remove(identifier.id, fileImageMode);
294
+ setPreview(undefined);
295
+ } else {
296
+ if (!['complete', 'error', 'failed-processing'].includes(status)) {
297
+ setStatus('error');
298
+ setError(error);
299
+ }
300
+ }
301
+ }, [identifier.id, preview === null || preview === void 0 ? void 0 : preview.dataURI, resizeMode, status]);
302
+ var onImageLoad = (0, _react.useCallback)(function (newPreview) {
303
+ if (newPreview) {
304
+ if ((0, _getPreview.isSSRClientPreview)(newPreview) && ssrReliabilityRef.current.client.status === 'unknown') {
305
+ ssrReliabilityRef.current.client = {
306
+ status: 'success'
307
+ };
308
+ }
309
+
310
+ /*
311
+ If the image loads successfully and it comes from server (global scope / ssrData), it means that we have reused it in client and the success counts for both: server & client.
312
+ */
313
+
314
+ if ((0, _getPreview.isSSRDataPreview)(newPreview) && ssrReliabilityRef.current.server.status === 'unknown') {
315
+ ssrReliabilityRef.current.server = {
316
+ status: 'success'
317
+ };
318
+ ssrReliabilityRef.current.client = {
319
+ status: 'success'
320
+ };
321
+ }
322
+ }
323
+
324
+ // If the dataURI has been replaced, we can dismiss this callback
325
+ if ((newPreview === null || newPreview === void 0 ? void 0 : newPreview.dataURI) !== (preview === null || preview === void 0 ? void 0 : preview.dataURI)) {
326
+ return;
327
+ }
328
+ }, [preview === null || preview === void 0 ? void 0 : preview.dataURI]);
329
+
330
+ // FOR SSR
331
+ var getScriptProps = function getScriptProps() {
332
+ var _ssrReliabilityRef$cu;
333
+ return (0, _globalScope.generateScriptProps)(identifier, preview === null || preview === void 0 ? void 0 : preview.dataURI, requestDimensions, ((_ssrReliabilityRef$cu = ssrReliabilityRef.current.server) === null || _ssrReliabilityRef$cu === void 0 ? void 0 : _ssrReliabilityRef$cu.status) === 'fail' ? ssrReliabilityRef.current.server : undefined);
334
+ };
335
+
336
+ // CXP-2723 TODO: should consider simplifying our analytics, and how
337
+ // we might get rid of ssrReliabiltyRef from our hook
338
+ return {
339
+ preview: preview,
340
+ error: error,
341
+ nonCriticalError: nonCriticalError,
342
+ ssrReliabilityRef: ssrReliabilityRef,
343
+ onImageError: onImageError,
344
+ onImageLoad: onImageLoad,
345
+ getScriptProps: getScriptProps
346
+ };
347
+ };
348
+ var initialSsrReliability = {
349
+ server: {
350
+ status: 'unknown'
351
+ },
352
+ client: {
353
+ status: 'unknown'
354
+ }
355
+ };
@@ -0,0 +1,44 @@
1
+ import { getMediaClientErrorReason, isRequestError } from '@atlaskit/media-client';
2
+ import { getFileStateErrorReason, isMediaFilePreviewError, isMediaFileStateError } from './errors';
3
+ export const getErrorTraceContext = error => {
4
+ if (isMediaFilePreviewError(error) && !!error.secondaryError) {
5
+ if (isRequestError(error.secondaryError)) {
6
+ var _error$secondaryError;
7
+ return (_error$secondaryError = error.secondaryError.metadata) === null || _error$secondaryError === void 0 ? void 0 : _error$secondaryError.traceContext;
8
+ } else if (isMediaFileStateError(error.secondaryError)) {
9
+ var _error$secondaryError2, _error$secondaryError3;
10
+ return (_error$secondaryError2 = error.secondaryError.details) === null || _error$secondaryError2 === void 0 ? void 0 : (_error$secondaryError3 = _error$secondaryError2.metadata) === null || _error$secondaryError3 === void 0 ? void 0 : _error$secondaryError3.traceContext;
11
+ }
12
+ }
13
+ };
14
+ export const getRenderErrorFailReason = error => {
15
+ if (isMediaFilePreviewError(error)) {
16
+ return error.primaryReason;
17
+ } else {
18
+ return 'nativeError';
19
+ }
20
+ };
21
+ export const getRenderErrorErrorReason = error => {
22
+ if (isMediaFilePreviewError(error) && error.secondaryError) {
23
+ const mediaClientReason = isMediaFileStateError(error.secondaryError) ? getFileStateErrorReason(error.secondaryError) : getMediaClientErrorReason(error.secondaryError);
24
+ if (mediaClientReason !== 'unknown') {
25
+ return mediaClientReason;
26
+ }
27
+ }
28
+ return 'nativeError';
29
+ };
30
+ export const getRenderErrorErrorDetail = error => {
31
+ if (isMediaFilePreviewError(error) && error.secondaryError) {
32
+ return error.secondaryError.message;
33
+ } else {
34
+ return error.message;
35
+ }
36
+ };
37
+ export const extractErrorInfo = (error, metadataTraceContext) => {
38
+ return {
39
+ failReason: getRenderErrorFailReason(error),
40
+ error: getRenderErrorErrorReason(error),
41
+ errorDetail: getRenderErrorErrorDetail(error),
42
+ metadataTraceContext: metadataTraceContext !== null && metadataTraceContext !== void 0 ? metadataTraceContext : getErrorTraceContext(error)
43
+ };
44
+ };
@@ -0,0 +1,90 @@
1
+ import { MediaFileStateError } from '@atlaskit/media-client-react';
2
+
3
+ /**
4
+ * Primary reason is logged through Data Portal.
5
+ * Make sure all the values are whitelisted in Measure -> Event Regitry -> "mediaCardRender failed" event
6
+ */
7
+
8
+ export class MediaFilePreviewError extends Error {
9
+ constructor(primaryReason, secondaryError) {
10
+ super(primaryReason);
11
+ // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget
12
+ this.primaryReason = primaryReason;
13
+ this.secondaryError = secondaryError;
14
+ Object.setPrototypeOf(this, new.target.prototype);
15
+
16
+ // https://v8.dev/docs/stack-trace-api
17
+ if ('captureStackTrace' in Error) {
18
+ Error.captureStackTrace(this, new.target);
19
+ }
20
+ }
21
+ }
22
+ export class LocalPreviewError extends MediaFilePreviewError {
23
+ constructor(primaryReason, secondaryError) {
24
+ super(primaryReason, secondaryError);
25
+ this.primaryReason = primaryReason;
26
+ this.secondaryError = secondaryError;
27
+ }
28
+ }
29
+ export class RemotePreviewError extends MediaFilePreviewError {
30
+ constructor(primaryReason, secondaryError) {
31
+ super(primaryReason, secondaryError);
32
+ this.primaryReason = primaryReason;
33
+ this.secondaryError = secondaryError;
34
+ }
35
+ }
36
+ export class SsrPreviewError extends MediaFilePreviewError {
37
+ constructor(primaryReason, secondaryError) {
38
+ super(primaryReason, secondaryError);
39
+ this.primaryReason = primaryReason;
40
+ this.secondaryError = secondaryError;
41
+ }
42
+ }
43
+ const getImageLoadPrimaryReason = source => {
44
+ switch (source) {
45
+ case 'cache-remote':
46
+ return 'cache-remote-uri';
47
+ case 'cache-local':
48
+ return 'cache-local-uri';
49
+ case 'external':
50
+ return 'external-uri';
51
+ case 'local':
52
+ return 'local-uri';
53
+ case 'remote':
54
+ return 'remote-uri';
55
+ // This fail reason will come from a bug, most likely.
56
+ default:
57
+ return `unknown-uri`;
58
+ }
59
+ };
60
+ export class ImageLoadError extends MediaFilePreviewError {
61
+ constructor(source) {
62
+ super(getImageLoadPrimaryReason(source));
63
+ }
64
+ }
65
+ export function isMediaFilePreviewError(err) {
66
+ return err instanceof MediaFilePreviewError;
67
+ }
68
+ export const isLocalPreviewError = err => err instanceof LocalPreviewError;
69
+ export const isRemotePreviewError = err => err instanceof RemotePreviewError;
70
+ export const isUnsupportedLocalPreviewError = err => isMediaFilePreviewError(err) && err.primaryReason === 'local-preview-unsupported';
71
+
72
+ // In a try/catch statement, the error caught is the type of unknown.
73
+ // We can use this helper to ensure that the error handled is the type of MediaFilePreviewError if unsure
74
+ // If updatePrimaryReason is true, if it's a MediaFilePreviewError already, it will update it's primary reason
75
+ export const ensureMediaFilePreviewError = (primaryReason, error, updatePrimaryReason) => {
76
+ if (isMediaFilePreviewError(error)) {
77
+ if (updatePrimaryReason && error.primaryReason !== primaryReason) {
78
+ return new MediaFilePreviewError(primaryReason, error.secondaryError);
79
+ }
80
+ return error;
81
+ }
82
+ return new MediaFilePreviewError(primaryReason, error);
83
+ };
84
+ export function isMediaFileStateError(err) {
85
+ return err instanceof MediaFileStateError;
86
+ }
87
+ export function getFileStateErrorReason(err) {
88
+ var _err$details$reason, _err$details;
89
+ return (_err$details$reason = (_err$details = err.details) === null || _err$details === void 0 ? void 0 : _err$details.reason) !== null && _err$details$reason !== void 0 ? _err$details$reason : 'unknown';
90
+ }
@@ -0,0 +1,30 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import { createObjectURLCache } from './objectURLCache';
3
+
4
+ // Dimensions are used to create a key.
5
+ // Cache is invalidated when different dimensions are provided.
6
+ export const getCacheKey = (id, mode) => {
7
+ const resizeMode = mode || 'crop';
8
+ return [id, resizeMode].join('-');
9
+ };
10
+ export class CardPreviewCacheImpl {
11
+ constructor(previewCache) {
12
+ _defineProperty(this, "get", (id, mode) => {
13
+ const cacheKey = getCacheKey(id, mode);
14
+ return this.previewCache.get(cacheKey);
15
+ });
16
+ _defineProperty(this, "set", (id, mode, cardPreview) => {
17
+ const cacheKey = getCacheKey(id, mode);
18
+ this.previewCache.set(cacheKey, cardPreview);
19
+ });
20
+ _defineProperty(this, "remove", (id, mode) => {
21
+ const cacheKey = getCacheKey(id, mode);
22
+ this.previewCache.remove(cacheKey);
23
+ });
24
+ _defineProperty(this, "clear", () => {
25
+ this.previewCache.clear();
26
+ });
27
+ this.previewCache = previewCache;
28
+ }
29
+ }
30
+ export const mediaFilePreviewCache = new CardPreviewCacheImpl(createObjectURLCache());
@@ -0,0 +1,75 @@
1
+ import { addFileAttrsToUrl } from '@atlaskit/media-client';
2
+ import { SsrPreviewError } from '../errors';
3
+ import { mediaFilePreviewCache } from './cache';
4
+ import { getLocalPreview, getRemotePreview } from './helpers';
5
+ const extendAndCachePreview = (id, mode, preview, mediaBlobUrlAttrs) => {
6
+ let source;
7
+ switch (preview.source) {
8
+ case 'local':
9
+ source = 'cache-local';
10
+ break;
11
+ case 'remote':
12
+ source = 'cache-remote';
13
+ break;
14
+ case 'ssr-server':
15
+ source = 'cache-ssr-server';
16
+ break;
17
+ case 'ssr-client':
18
+ source = 'cache-ssr-client';
19
+ break;
20
+ default:
21
+ source = preview.source;
22
+ }
23
+ // We want to embed some meta context into dataURI for Copy/Paste to work.
24
+ const dataURI = mediaBlobUrlAttrs ? addFileAttrsToUrl(preview.dataURI, mediaBlobUrlAttrs) : preview.dataURI;
25
+ // We store new cardPreview into cache
26
+ mediaFilePreviewCache.set(id, mode, {
27
+ ...preview,
28
+ source,
29
+ dataURI
30
+ });
31
+ return {
32
+ ...preview,
33
+ dataURI
34
+ };
35
+ };
36
+ export const getSSRPreview = (ssr, mediaClient, id, params, mediaBlobUrlAttrs) => {
37
+ let dataURI;
38
+ try {
39
+ const rawDataURI = mediaClient.getImageUrlSync(id, params);
40
+ // We want to embed some meta context into dataURI for Copy/Paste to work.
41
+ dataURI = mediaBlobUrlAttrs ? addFileAttrsToUrl(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
42
+ const source = ssr === 'client' ? 'ssr-client' : 'ssr-server';
43
+ return {
44
+ dataURI,
45
+ source,
46
+ orientation: 1
47
+ };
48
+ } catch (e) {
49
+ const reason = ssr === 'server' ? 'ssr-server-uri' : 'ssr-client-uri';
50
+ throw new SsrPreviewError(reason, e instanceof Error ? e : undefined);
51
+ }
52
+ };
53
+ export const isLocalPreview = preview => {
54
+ const localSources = ['local', 'cache-local'];
55
+ return localSources.includes(preview.source);
56
+ };
57
+ export const isSSRClientPreview = preview => {
58
+ const ssrClientSources = ['ssr-client', 'cache-ssr-client'];
59
+ return ssrClientSources.includes(preview.source);
60
+ };
61
+ export const isSSRDataPreview = preview => preview.source === 'ssr-data';
62
+ export const getAndCacheRemotePreview = async (mediaClient, id, dimensions, params, mediaBlobUrlAttrs, traceContext) => {
63
+ const remotePreview = await getRemotePreview(mediaClient, id, params, traceContext);
64
+ return extendAndCachePreview(id, params.mode, {
65
+ ...remotePreview,
66
+ dimensions
67
+ }, mediaBlobUrlAttrs);
68
+ };
69
+ export const getAndCacheLocalPreview = async (id, filePreview, dimensions, mode, mediaBlobUrlAttrs) => {
70
+ const localPreview = await getLocalPreview(filePreview);
71
+ return extendAndCachePreview(id, mode, {
72
+ ...localPreview,
73
+ dimensions
74
+ }, mediaBlobUrlAttrs);
75
+ };
@@ -0,0 +1,77 @@
1
+ import { getMediaTypeFromMimeType } from '@atlaskit/media-common';
2
+ import { getOrientation } from '@atlaskit/media-ui';
3
+ import { LocalPreviewError, RemotePreviewError } from '../errors';
4
+ import { takeSnapshot } from './videoSnapshot';
5
+
6
+ /**
7
+ * This method tells the support for the media
8
+ * types covered in getCardPreviewFromFilePreview
9
+ */
10
+ export const isSupportedLocalPreview = mediaType => mediaType === 'image' || mediaType === 'video';
11
+ const getImageLocalPreview = async value => {
12
+ try {
13
+ const orientation = await getOrientation(value);
14
+ const dataURI = URL.createObjectURL(value);
15
+ return {
16
+ dataURI,
17
+ orientation,
18
+ source: 'local'
19
+ };
20
+ } catch (e) {
21
+ throw new LocalPreviewError('local-preview-image', e instanceof Error ? e : undefined);
22
+ }
23
+ };
24
+ const getVideoLocalPreview = async value => {
25
+ try {
26
+ const dataURI = await takeSnapshot(value);
27
+ return {
28
+ dataURI,
29
+ orientation: 1,
30
+ source: 'local'
31
+ };
32
+ } catch (e) {
33
+ throw new LocalPreviewError('local-preview-video', e instanceof Error ? e : undefined);
34
+ }
35
+ };
36
+ export const getLocalPreview = async filePreview => {
37
+ let value;
38
+ try {
39
+ const resolvedFilePreview = await filePreview;
40
+ value = resolvedFilePreview.value;
41
+ } catch (e) {
42
+ throw new LocalPreviewError('local-preview-rejected', e instanceof Error ? e : undefined);
43
+ }
44
+ if (typeof value === 'string') {
45
+ return {
46
+ dataURI: value,
47
+ orientation: 1,
48
+ source: 'local'
49
+ };
50
+ } else if (value instanceof Blob) {
51
+ const {
52
+ type
53
+ } = value;
54
+ const mediaType = getMediaTypeFromMimeType(type);
55
+ switch (mediaType) {
56
+ case 'image':
57
+ return getImageLocalPreview(value);
58
+ case 'video':
59
+ return getVideoLocalPreview(value);
60
+ default:
61
+ throw new LocalPreviewError('local-preview-unsupported');
62
+ }
63
+ }
64
+ throw new LocalPreviewError('local-preview-unsupported');
65
+ };
66
+ export const getRemotePreview = async (mediaClient, id, params, traceContext) => {
67
+ try {
68
+ const blob = await mediaClient.getImage(id, params, undefined, undefined, traceContext);
69
+ return {
70
+ dataURI: URL.createObjectURL(blob),
71
+ orientation: 1,
72
+ source: 'remote'
73
+ };
74
+ } catch (e) {
75
+ throw new RemotePreviewError('remote-preview-fetch', e instanceof Error ? e : undefined);
76
+ }
77
+ };
@@ -0,0 +1,3 @@
1
+ export { mediaFilePreviewCache } from './cache';
2
+ export { getSSRPreview, isLocalPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview } from './getPreview';
3
+ export { isSupportedLocalPreview } from './helpers';