@atlaskit/media-viewer 54.5.10 → 54.5.12

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atlaskit/media-viewer
2
2
 
3
+ ## 54.5.12
4
+
5
+ ### Patch Changes
6
+
7
+ - [`fc42b7257d341`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/fc42b7257d341) -
8
+ Attach native MediaError diagnostics to videoviewer-playback failures so the existing
9
+ error/errorDetail analytics fields report a real cause instead of unknown (observability-only, no
10
+ behaviour change).
11
+ - Updated dependencies
12
+
13
+ ## 54.5.11
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies
18
+
3
19
  ## 54.5.10
4
20
 
5
21
  ### Patch Changes
@@ -10,7 +10,7 @@ exports.packageVersion = exports.packageName = void 0;
10
10
  var _analytics = require("@atlaskit/media-common/analytics");
11
11
  var componentName = exports.component = exports.componentName = 'mediaViewer';
12
12
  var packageName = exports.packageName = "@atlaskit/media-viewer";
13
- var packageVersion = exports.packageVersion = "54.5.9";
13
+ var packageVersion = exports.packageVersion = "54.5.11";
14
14
  function getFileAttributes(fileState) {
15
15
  if (!fileState) {
16
16
  return {
@@ -13,7 +13,7 @@ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
13
13
  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; }
14
14
  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; }
15
15
  var packageName = "@atlaskit/media-viewer";
16
- var packageVersion = "54.5.9";
16
+ var packageVersion = "54.5.11";
17
17
  var ufoExperience;
18
18
  var getExperience = function getExperience() {
19
19
  if (!ufoExperience) {
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.MediaViewerError = exports.ArchiveViewerError = void 0;
8
8
  exports.buildImgErrorDiagnostics = buildImgErrorDiagnostics;
9
+ exports.buildVideoErrorDiagnostics = buildVideoErrorDiagnostics;
9
10
  exports.classifyFailedSrc = classifyFailedSrc;
10
11
  exports.getErrorDetail = getErrorDetail;
11
12
  exports.getPrimaryErrorReason = getPrimaryErrorReason;
@@ -155,4 +156,61 @@ function buildImgErrorDiagnostics(item, event) {
155
156
  return "".concat(key, "=").concat(value);
156
157
  }).join(', ');
157
158
  return new Error(detail);
159
+ }
160
+
161
+ /**
162
+ * Human-readable names for the four standard `MediaError.code` values, so the
163
+ * downstream analytics `error`/`errorDetail` report a meaningful cause instead of
164
+ * a bare numeric code.
165
+ *
166
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaError/code
167
+ */
168
+ var MEDIA_ERROR_CODE_NAMES = {
169
+ 1: 'MEDIA_ERR_ABORTED',
170
+ 2: 'MEDIA_ERR_NETWORK',
171
+ 3: 'MEDIA_ERR_DECODE',
172
+ 4: 'MEDIA_ERR_SRC_NOT_SUPPORTED'
173
+ };
174
+
175
+ /**
176
+ * Builds a descriptive `secondaryError` for a `<video>` onerror so the downstream
177
+ * `loadFailed` analytics event reports a meaningful `error`/`errorDetail` instead of
178
+ * the opaque `unknown`/`unknown`. The returned Error's `message` captures playback
179
+ * diagnostics as a comma-separated `key=value` string (undefined fields are omitted):
180
+ * - the native `MediaError.code` and its readable name (e.g. `MEDIA_ERR_DECODE`)
181
+ * - the native `MediaError.message` (browser-provided detail, often empty)
182
+ * - the file MIME type and whether it is natively browser-playable
183
+ * - the file size in bytes (helps distinguish large-file/streaming failures)
184
+ *
185
+ * @example
186
+ * // message:
187
+ * "mediaErrorCode=3, mediaErrorName=MEDIA_ERR_DECODE, mimeType=video/quicktime, isBrowserPlayable=false, fileSize=734003200"
188
+ */
189
+ function buildVideoErrorDiagnostics(item, mediaError) {
190
+ var mimeType = item && !(0, _mediaClient.isErrorFileState)(item) ? item.mimeType : undefined;
191
+ var isBrowserPlayable = mimeType ? (0, _isMimeTypeSupportedByBrowser.isVideoMimeTypeSupportedByBrowser)(mimeType) : undefined;
192
+ var fileSize = item && !(0, _mediaClient.isErrorFileState)(item) ? item.size : undefined;
193
+ var mediaErrorCode = mediaError === null || mediaError === void 0 ? void 0 : mediaError.code;
194
+ var mediaErrorName = mediaErrorCode !== undefined ? MEDIA_ERROR_CODE_NAMES[mediaErrorCode] : undefined;
195
+ // A native MediaError.message can be empty; only include it when present.
196
+ var mediaErrorMessage = (mediaError === null || mediaError === void 0 ? void 0 : mediaError.message) || undefined;
197
+ var diagnostics = {
198
+ mediaErrorCode: mediaErrorCode,
199
+ mediaErrorName: mediaErrorName,
200
+ mediaErrorMessage: mediaErrorMessage,
201
+ mimeType: mimeType,
202
+ isBrowserPlayable: isBrowserPlayable,
203
+ fileSize: fileSize
204
+ };
205
+ var detail = Object.entries(diagnostics).filter(function (_ref7) {
206
+ var _ref8 = (0, _slicedToArray2.default)(_ref7, 2),
207
+ value = _ref8[1];
208
+ return value !== undefined;
209
+ }).map(function (_ref9) {
210
+ var _ref0 = (0, _slicedToArray2.default)(_ref9, 2),
211
+ key = _ref0[0],
212
+ value = _ref0[1];
213
+ return "".concat(key, "=").concat(value);
214
+ }).join(', ');
215
+ return new Error(detail);
158
216
  }
@@ -201,7 +201,14 @@ var ArchiveViewerBase = exports.ArchiveViewerBase = /*#__PURE__*/function (_Base
201
201
  });
202
202
  (0, _defineProperty2.default)(_this, "onViewerError", function (primaryErrorReason, selectedArchiveEntry) {
203
203
  return function (error) {
204
- return error && (0, _errors.isMediaViewerError)(error) ? _this.onError(new _errors.ArchiveViewerError(primaryErrorReason, error.secondaryError, selectedArchiveEntry)) : _this.onError(new _errors.ArchiveViewerError(primaryErrorReason, error, selectedArchiveEntry));
204
+ if (error instanceof Error && (0, _errors.isMediaViewerError)(error)) {
205
+ return _this.onError(new _errors.ArchiveViewerError(primaryErrorReason, error.secondaryError, selectedArchiveEntry));
206
+ }
207
+ // The video/audio CustomMediaPlayer surfaces a native `MediaError` (not a
208
+ // JS `Error`). Convert it into a descriptive diagnostics `Error` so the
209
+ // downstream analytics report a meaningful cause instead of `unknown`.
210
+ var secondaryError = error && !(error instanceof Error) ? (0, _errors.buildVideoErrorDiagnostics)(undefined, error) : error !== null && error !== void 0 ? error : undefined;
211
+ return _this.onError(new _errors.ArchiveViewerError(primaryErrorReason, secondaryError, selectedArchiveEntry));
205
212
  };
206
213
  });
207
214
  (0, _defineProperty2.default)(_this, "onSidebarLoaded", function () {
@@ -54,9 +54,18 @@ var VideoViewer = exports.VideoViewer = /*#__PURE__*/function (_BaseViewer) {
54
54
  _this.init();
55
55
  }
56
56
  });
57
- (0, _defineProperty2.default)(_this, "onError", function () {
58
- var onError = _this.props.onError;
59
- onError && onError(new _errors.MediaViewerError('videoviewer-playback'));
57
+ (0, _defineProperty2.default)(_this, "onError", function (mediaError) {
58
+ var _this$props2 = _this.props,
59
+ onError = _this$props2.onError,
60
+ item = _this$props2.item;
61
+ var secondaryError;
62
+ try {
63
+ secondaryError = (0, _errors.buildVideoErrorDiagnostics)(item, mediaError);
64
+ } catch (_unused) {
65
+ // Diagnostics are best-effort: never let them mask the underlying playback failure.
66
+ secondaryError = undefined;
67
+ }
68
+ onError && onError(new _errors.MediaViewerError('videoviewer-playback', secondaryError));
60
69
  });
61
70
  return _this;
62
71
  }
@@ -71,11 +80,11 @@ var VideoViewer = exports.VideoViewer = /*#__PURE__*/function (_BaseViewer) {
71
80
  }, {
72
81
  key: "renderSuccessful",
73
82
  value: function renderSuccessful(content) {
74
- var _this$props2 = this.props,
75
- item = _this$props2.item,
76
- showControls = _this$props2.showControls,
77
- previewCount = _this$props2.previewCount,
78
- identifier = _this$props2.identifier;
83
+ var _this$props3 = this.props,
84
+ item = _this$props3.item,
85
+ showControls = _this$props3.showControls,
86
+ previewCount = _this$props3.previewCount,
87
+ identifier = _this$props3.identifier;
79
88
  var useCustomVideoPlayer = !(0, _isIE.isIE)();
80
89
  var isAutoPlay = previewCount === 0;
81
90
  var hdAvailable = isHDAvailable(item);
@@ -123,11 +132,11 @@ var VideoViewer = exports.VideoViewer = /*#__PURE__*/function (_BaseViewer) {
123
132
  key: "init",
124
133
  value: function () {
125
134
  var _init = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
126
- var _this$props3, mediaClient, item, collectionName, contentUrl, _t;
135
+ var _this$props4, mediaClient, item, collectionName, contentUrl, _t;
127
136
  return _regenerator.default.wrap(function (_context) {
128
137
  while (1) switch (_context.prev = _context.next) {
129
138
  case 0:
130
- _this$props3 = this.props, mediaClient = _this$props3.mediaClient, item = _this$props3.item, collectionName = _this$props3.collectionName;
139
+ _this$props4 = this.props, mediaClient = _this$props4.mediaClient, item = _this$props4.item, collectionName = _this$props4.collectionName;
131
140
  _context.prev = 1;
132
141
  if (!(item.status === 'processed')) {
133
142
  _context.next = 4;
@@ -1,7 +1,7 @@
1
1
  import { ANALYTICS_MEDIA_CHANNEL, sanitiseAnalyticsPayload } from '@atlaskit/media-common/analytics';
2
2
  const componentName = 'mediaViewer';
3
3
  const packageName = "@atlaskit/media-viewer";
4
- const packageVersion = "54.5.9";
4
+ const packageVersion = "54.5.11";
5
5
  export { packageName, packageVersion, componentName, componentName as component };
6
6
  export function getFileAttributes(fileState) {
7
7
  if (!fileState) {
@@ -3,7 +3,7 @@ import { getMediaEnvironment, getMediaRegion } from '@atlaskit/media-client';
3
3
  import { getFeatureFlagKeysAllProducts } from '@atlaskit/media-common';
4
4
  import { fg } from '@atlaskit/platform-feature-flags';
5
5
  const packageName = "@atlaskit/media-viewer";
6
- const packageVersion = "54.5.9";
6
+ const packageVersion = "54.5.11";
7
7
  let ufoExperience;
8
8
  const getExperience = () => {
9
9
  if (!ufoExperience) {
@@ -1,5 +1,5 @@
1
1
  import { isCommonMediaClientError, isErrorFileState } from '@atlaskit/media-client';
2
- import { isImageMimeTypeSupportedByBrowser } from '@atlaskit/media-common/isMimeTypeSupportedByBrowser';
2
+ import { isImageMimeTypeSupportedByBrowser, isVideoMimeTypeSupportedByBrowser } from '@atlaskit/media-common/isMimeTypeSupportedByBrowser';
3
3
  export class MediaViewerError extends Error {
4
4
  constructor(primaryReason, secondaryError) {
5
5
  super(primaryReason);
@@ -116,4 +116,52 @@ export function buildImgErrorDiagnostics(item, event) {
116
116
  };
117
117
  const detail = Object.entries(diagnostics).filter(([, value]) => value !== undefined).map(([key, value]) => `${key}=${value}`).join(', ');
118
118
  return new Error(detail);
119
+ }
120
+
121
+ /**
122
+ * Human-readable names for the four standard `MediaError.code` values, so the
123
+ * downstream analytics `error`/`errorDetail` report a meaningful cause instead of
124
+ * a bare numeric code.
125
+ *
126
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaError/code
127
+ */
128
+ const MEDIA_ERROR_CODE_NAMES = {
129
+ 1: 'MEDIA_ERR_ABORTED',
130
+ 2: 'MEDIA_ERR_NETWORK',
131
+ 3: 'MEDIA_ERR_DECODE',
132
+ 4: 'MEDIA_ERR_SRC_NOT_SUPPORTED'
133
+ };
134
+
135
+ /**
136
+ * Builds a descriptive `secondaryError` for a `<video>` onerror so the downstream
137
+ * `loadFailed` analytics event reports a meaningful `error`/`errorDetail` instead of
138
+ * the opaque `unknown`/`unknown`. The returned Error's `message` captures playback
139
+ * diagnostics as a comma-separated `key=value` string (undefined fields are omitted):
140
+ * - the native `MediaError.code` and its readable name (e.g. `MEDIA_ERR_DECODE`)
141
+ * - the native `MediaError.message` (browser-provided detail, often empty)
142
+ * - the file MIME type and whether it is natively browser-playable
143
+ * - the file size in bytes (helps distinguish large-file/streaming failures)
144
+ *
145
+ * @example
146
+ * // message:
147
+ * "mediaErrorCode=3, mediaErrorName=MEDIA_ERR_DECODE, mimeType=video/quicktime, isBrowserPlayable=false, fileSize=734003200"
148
+ */
149
+ export function buildVideoErrorDiagnostics(item, mediaError) {
150
+ const mimeType = item && !isErrorFileState(item) ? item.mimeType : undefined;
151
+ const isBrowserPlayable = mimeType ? isVideoMimeTypeSupportedByBrowser(mimeType) : undefined;
152
+ const fileSize = item && !isErrorFileState(item) ? item.size : undefined;
153
+ const mediaErrorCode = mediaError === null || mediaError === void 0 ? void 0 : mediaError.code;
154
+ const mediaErrorName = mediaErrorCode !== undefined ? MEDIA_ERROR_CODE_NAMES[mediaErrorCode] : undefined;
155
+ // A native MediaError.message can be empty; only include it when present.
156
+ const mediaErrorMessage = (mediaError === null || mediaError === void 0 ? void 0 : mediaError.message) || undefined;
157
+ const diagnostics = {
158
+ mediaErrorCode,
159
+ mediaErrorName,
160
+ mediaErrorMessage,
161
+ mimeType,
162
+ isBrowserPlayable,
163
+ fileSize
164
+ };
165
+ const detail = Object.entries(diagnostics).filter(([, value]) => value !== undefined).map(([key, value]) => `${key}=${value}`).join(', ');
166
+ return new Error(detail);
119
167
  }
@@ -21,7 +21,7 @@ import { Spinner } from '../../loading';
21
21
  import { ENCRYPTED_ENTRY_ERROR_MESSAGE } from './consts';
22
22
  import { withAnalyticsEvents } from '@atlaskit/analytics-next';
23
23
  import { fireAnalytics } from '../../analytics';
24
- import { ArchiveViewerError, isMediaViewerError } from '../../errors';
24
+ import { ArchiveViewerError, buildVideoErrorDiagnostics, isMediaViewerError } from '../../errors';
25
25
  import { createZipEntryLoadSucceededEvent } from '../../analytics/events/operational/zipEntryLoadSucceeded';
26
26
  import { createZipEntryLoadFailedEvent } from '../../analytics/events/operational/zipEntryLoadFailed';
27
27
  import { createPreviewUnsupportedEvent } from '../../analytics/events/operational/previewUnsupported';
@@ -129,7 +129,16 @@ export class ArchiveViewerBase extends BaseViewer {
129
129
  _defineProperty(this, "onViewerLoad", selectedArchiveEntry => () => {
130
130
  fireAnalytics(createZipEntryLoadSucceededEvent(this.props.item, selectedArchiveEntry), this.props.createAnalyticsEvent);
131
131
  });
132
- _defineProperty(this, "onViewerError", (primaryErrorReason, selectedArchiveEntry) => error => error && isMediaViewerError(error) ? this.onError(new ArchiveViewerError(primaryErrorReason, error.secondaryError, selectedArchiveEntry)) : this.onError(new ArchiveViewerError(primaryErrorReason, error, selectedArchiveEntry)));
132
+ _defineProperty(this, "onViewerError", (primaryErrorReason, selectedArchiveEntry) => error => {
133
+ if (error instanceof Error && isMediaViewerError(error)) {
134
+ return this.onError(new ArchiveViewerError(primaryErrorReason, error.secondaryError, selectedArchiveEntry));
135
+ }
136
+ // The video/audio CustomMediaPlayer surfaces a native `MediaError` (not a
137
+ // JS `Error`). Convert it into a descriptive diagnostics `Error` so the
138
+ // downstream analytics report a meaningful cause instead of `unknown`.
139
+ const secondaryError = error && !(error instanceof Error) ? buildVideoErrorDiagnostics(undefined, error) : error !== null && error !== void 0 ? error : undefined;
140
+ return this.onError(new ArchiveViewerError(primaryErrorReason, secondaryError, selectedArchiveEntry));
141
+ });
133
142
  _defineProperty(this, "onSidebarLoaded", () => {
134
143
  this.setState({
135
144
  content: Outcome.successful({
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { getArtifactUrl, globalMediaEventEmitter, isFileIdentifier } from '@atlaskit/media-client';
4
4
  import { CustomMediaPlayer, MediaPlayer } from '@atlaskit/media-ui';
5
5
  import { Outcome } from '../domain';
6
- import { MediaViewerError } from '../errors';
6
+ import { buildVideoErrorDiagnostics, MediaViewerError } from '../errors';
7
7
  import { Video, CustomVideoPlayerWrapper } from '../styleWrappers';
8
8
  import { isIE } from '../utils/isIE';
9
9
  import { BaseViewer } from './base-viewer';
@@ -34,11 +34,19 @@ export class VideoViewer extends BaseViewer {
34
34
  this.init();
35
35
  }
36
36
  });
37
- _defineProperty(this, "onError", () => {
37
+ _defineProperty(this, "onError", mediaError => {
38
38
  const {
39
- onError
39
+ onError,
40
+ item
40
41
  } = this.props;
41
- onError && onError(new MediaViewerError('videoviewer-playback'));
42
+ let secondaryError;
43
+ try {
44
+ secondaryError = buildVideoErrorDiagnostics(item, mediaError);
45
+ } catch {
46
+ // Diagnostics are best-effort: never let them mask the underlying playback failure.
47
+ secondaryError = undefined;
48
+ }
49
+ onError && onError(new MediaViewerError('videoviewer-playback', secondaryError));
42
50
  });
43
51
  }
44
52
  get initialState() {
@@ -1,7 +1,7 @@
1
1
  import { ANALYTICS_MEDIA_CHANNEL, sanitiseAnalyticsPayload } from '@atlaskit/media-common/analytics';
2
2
  var componentName = 'mediaViewer';
3
3
  var packageName = "@atlaskit/media-viewer";
4
- var packageVersion = "54.5.9";
4
+ var packageVersion = "54.5.11";
5
5
  export { packageName, packageVersion, componentName, componentName as component };
6
6
  export function getFileAttributes(fileState) {
7
7
  if (!fileState) {
@@ -6,7 +6,7 @@ import { getMediaEnvironment, getMediaRegion } from '@atlaskit/media-client';
6
6
  import { getFeatureFlagKeysAllProducts } from '@atlaskit/media-common';
7
7
  import { fg } from '@atlaskit/platform-feature-flags';
8
8
  var packageName = "@atlaskit/media-viewer";
9
- var packageVersion = "54.5.9";
9
+ var packageVersion = "54.5.11";
10
10
  var ufoExperience;
11
11
  var getExperience = function getExperience() {
12
12
  if (!ufoExperience) {
@@ -8,7 +8,7 @@ import _wrapNativeSuper from "@babel/runtime/helpers/wrapNativeSuper";
8
8
  function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
9
9
  function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
10
10
  import { isCommonMediaClientError, isErrorFileState } from '@atlaskit/media-client';
11
- import { isImageMimeTypeSupportedByBrowser } from '@atlaskit/media-common/isMimeTypeSupportedByBrowser';
11
+ import { isImageMimeTypeSupportedByBrowser, isVideoMimeTypeSupportedByBrowser } from '@atlaskit/media-common/isMimeTypeSupportedByBrowser';
12
12
  export var MediaViewerError = /*#__PURE__*/function (_Error) {
13
13
  function MediaViewerError(primaryReason, secondaryError) {
14
14
  var _this;
@@ -140,4 +140,61 @@ export function buildImgErrorDiagnostics(item, event) {
140
140
  return "".concat(key, "=").concat(value);
141
141
  }).join(', ');
142
142
  return new Error(detail);
143
+ }
144
+
145
+ /**
146
+ * Human-readable names for the four standard `MediaError.code` values, so the
147
+ * downstream analytics `error`/`errorDetail` report a meaningful cause instead of
148
+ * a bare numeric code.
149
+ *
150
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/MediaError/code
151
+ */
152
+ var MEDIA_ERROR_CODE_NAMES = {
153
+ 1: 'MEDIA_ERR_ABORTED',
154
+ 2: 'MEDIA_ERR_NETWORK',
155
+ 3: 'MEDIA_ERR_DECODE',
156
+ 4: 'MEDIA_ERR_SRC_NOT_SUPPORTED'
157
+ };
158
+
159
+ /**
160
+ * Builds a descriptive `secondaryError` for a `<video>` onerror so the downstream
161
+ * `loadFailed` analytics event reports a meaningful `error`/`errorDetail` instead of
162
+ * the opaque `unknown`/`unknown`. The returned Error's `message` captures playback
163
+ * diagnostics as a comma-separated `key=value` string (undefined fields are omitted):
164
+ * - the native `MediaError.code` and its readable name (e.g. `MEDIA_ERR_DECODE`)
165
+ * - the native `MediaError.message` (browser-provided detail, often empty)
166
+ * - the file MIME type and whether it is natively browser-playable
167
+ * - the file size in bytes (helps distinguish large-file/streaming failures)
168
+ *
169
+ * @example
170
+ * // message:
171
+ * "mediaErrorCode=3, mediaErrorName=MEDIA_ERR_DECODE, mimeType=video/quicktime, isBrowserPlayable=false, fileSize=734003200"
172
+ */
173
+ export function buildVideoErrorDiagnostics(item, mediaError) {
174
+ var mimeType = item && !isErrorFileState(item) ? item.mimeType : undefined;
175
+ var isBrowserPlayable = mimeType ? isVideoMimeTypeSupportedByBrowser(mimeType) : undefined;
176
+ var fileSize = item && !isErrorFileState(item) ? item.size : undefined;
177
+ var mediaErrorCode = mediaError === null || mediaError === void 0 ? void 0 : mediaError.code;
178
+ var mediaErrorName = mediaErrorCode !== undefined ? MEDIA_ERROR_CODE_NAMES[mediaErrorCode] : undefined;
179
+ // A native MediaError.message can be empty; only include it when present.
180
+ var mediaErrorMessage = (mediaError === null || mediaError === void 0 ? void 0 : mediaError.message) || undefined;
181
+ var diagnostics = {
182
+ mediaErrorCode: mediaErrorCode,
183
+ mediaErrorName: mediaErrorName,
184
+ mediaErrorMessage: mediaErrorMessage,
185
+ mimeType: mimeType,
186
+ isBrowserPlayable: isBrowserPlayable,
187
+ fileSize: fileSize
188
+ };
189
+ var detail = Object.entries(diagnostics).filter(function (_ref7) {
190
+ var _ref8 = _slicedToArray(_ref7, 2),
191
+ value = _ref8[1];
192
+ return value !== undefined;
193
+ }).map(function (_ref9) {
194
+ var _ref0 = _slicedToArray(_ref9, 2),
195
+ key = _ref0[0],
196
+ value = _ref0[1];
197
+ return "".concat(key, "=").concat(value);
198
+ }).join(', ');
199
+ return new Error(detail);
143
200
  }
@@ -32,7 +32,7 @@ import { Spinner } from '../../loading';
32
32
  import { ENCRYPTED_ENTRY_ERROR_MESSAGE } from './consts';
33
33
  import { withAnalyticsEvents } from '@atlaskit/analytics-next';
34
34
  import { fireAnalytics } from '../../analytics';
35
- import { ArchiveViewerError, isMediaViewerError } from '../../errors';
35
+ import { ArchiveViewerError, buildVideoErrorDiagnostics, isMediaViewerError } from '../../errors';
36
36
  import { createZipEntryLoadSucceededEvent } from '../../analytics/events/operational/zipEntryLoadSucceeded';
37
37
  import { createZipEntryLoadFailedEvent } from '../../analytics/events/operational/zipEntryLoadFailed';
38
38
  import { createPreviewUnsupportedEvent } from '../../analytics/events/operational/previewUnsupported';
@@ -195,7 +195,14 @@ export var ArchiveViewerBase = /*#__PURE__*/function (_BaseViewer) {
195
195
  });
196
196
  _defineProperty(_this, "onViewerError", function (primaryErrorReason, selectedArchiveEntry) {
197
197
  return function (error) {
198
- return error && isMediaViewerError(error) ? _this.onError(new ArchiveViewerError(primaryErrorReason, error.secondaryError, selectedArchiveEntry)) : _this.onError(new ArchiveViewerError(primaryErrorReason, error, selectedArchiveEntry));
198
+ if (error instanceof Error && isMediaViewerError(error)) {
199
+ return _this.onError(new ArchiveViewerError(primaryErrorReason, error.secondaryError, selectedArchiveEntry));
200
+ }
201
+ // The video/audio CustomMediaPlayer surfaces a native `MediaError` (not a
202
+ // JS `Error`). Convert it into a descriptive diagnostics `Error` so the
203
+ // downstream analytics report a meaningful cause instead of `unknown`.
204
+ var secondaryError = error && !(error instanceof Error) ? buildVideoErrorDiagnostics(undefined, error) : error !== null && error !== void 0 ? error : undefined;
205
+ return _this.onError(new ArchiveViewerError(primaryErrorReason, secondaryError, selectedArchiveEntry));
199
206
  };
200
207
  });
201
208
  _defineProperty(_this, "onSidebarLoaded", function () {
@@ -12,7 +12,7 @@ import React from 'react';
12
12
  import { getArtifactUrl, globalMediaEventEmitter, isFileIdentifier } from '@atlaskit/media-client';
13
13
  import { CustomMediaPlayer, MediaPlayer } from '@atlaskit/media-ui';
14
14
  import { Outcome } from '../domain';
15
- import { MediaViewerError } from '../errors';
15
+ import { buildVideoErrorDiagnostics, MediaViewerError } from '../errors';
16
16
  import { Video, CustomVideoPlayerWrapper } from '../styleWrappers';
17
17
  import { isIE } from '../utils/isIE';
18
18
  import { BaseViewer } from './base-viewer';
@@ -47,9 +47,18 @@ export var VideoViewer = /*#__PURE__*/function (_BaseViewer) {
47
47
  _this.init();
48
48
  }
49
49
  });
50
- _defineProperty(_this, "onError", function () {
51
- var onError = _this.props.onError;
52
- onError && onError(new MediaViewerError('videoviewer-playback'));
50
+ _defineProperty(_this, "onError", function (mediaError) {
51
+ var _this$props2 = _this.props,
52
+ onError = _this$props2.onError,
53
+ item = _this$props2.item;
54
+ var secondaryError;
55
+ try {
56
+ secondaryError = buildVideoErrorDiagnostics(item, mediaError);
57
+ } catch (_unused) {
58
+ // Diagnostics are best-effort: never let them mask the underlying playback failure.
59
+ secondaryError = undefined;
60
+ }
61
+ onError && onError(new MediaViewerError('videoviewer-playback', secondaryError));
53
62
  });
54
63
  return _this;
55
64
  }
@@ -64,11 +73,11 @@ export var VideoViewer = /*#__PURE__*/function (_BaseViewer) {
64
73
  }, {
65
74
  key: "renderSuccessful",
66
75
  value: function renderSuccessful(content) {
67
- var _this$props2 = this.props,
68
- item = _this$props2.item,
69
- showControls = _this$props2.showControls,
70
- previewCount = _this$props2.previewCount,
71
- identifier = _this$props2.identifier;
76
+ var _this$props3 = this.props,
77
+ item = _this$props3.item,
78
+ showControls = _this$props3.showControls,
79
+ previewCount = _this$props3.previewCount,
80
+ identifier = _this$props3.identifier;
72
81
  var useCustomVideoPlayer = !isIE();
73
82
  var isAutoPlay = previewCount === 0;
74
83
  var hdAvailable = isHDAvailable(item);
@@ -116,11 +125,11 @@ export var VideoViewer = /*#__PURE__*/function (_BaseViewer) {
116
125
  key: "init",
117
126
  value: function () {
118
127
  var _init = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
119
- var _this$props3, mediaClient, item, collectionName, contentUrl, _t;
128
+ var _this$props4, mediaClient, item, collectionName, contentUrl, _t;
120
129
  return _regeneratorRuntime.wrap(function (_context) {
121
130
  while (1) switch (_context.prev = _context.next) {
122
131
  case 0:
123
- _this$props3 = this.props, mediaClient = _this$props3.mediaClient, item = _this$props3.item, collectionName = _this$props3.collectionName;
132
+ _this$props4 = this.props, mediaClient = _this$props4.mediaClient, item = _this$props4.item, collectionName = _this$props4.collectionName;
124
133
  _context.prev = 1;
125
134
  if (!(item.status === 'processed')) {
126
135
  _context.next = 4;
@@ -42,4 +42,19 @@ export declare function classifyFailedSrc(currentSrc?: string): srcType;
42
42
  * "mimeType=image/png, isBrowserDecodable=true, naturalWidth=0, naturalHeight=0, failedSrcType=blob"
43
43
  */
44
44
  export declare function buildImgErrorDiagnostics(item: FileState | undefined, event?: SyntheticEvent<HTMLImageElement, Event>): Error;
45
+ /**
46
+ * Builds a descriptive `secondaryError` for a `<video>` onerror so the downstream
47
+ * `loadFailed` analytics event reports a meaningful `error`/`errorDetail` instead of
48
+ * the opaque `unknown`/`unknown`. The returned Error's `message` captures playback
49
+ * diagnostics as a comma-separated `key=value` string (undefined fields are omitted):
50
+ * - the native `MediaError.code` and its readable name (e.g. `MEDIA_ERR_DECODE`)
51
+ * - the native `MediaError.message` (browser-provided detail, often empty)
52
+ * - the file MIME type and whether it is natively browser-playable
53
+ * - the file size in bytes (helps distinguish large-file/streaming failures)
54
+ *
55
+ * @example
56
+ * // message:
57
+ * "mediaErrorCode=3, mediaErrorName=MEDIA_ERR_DECODE, mimeType=video/quicktime, isBrowserPlayable=false, fileSize=734003200"
58
+ */
59
+ export declare function buildVideoErrorDiagnostics(item: FileState | undefined, mediaError?: MediaError | null): Error;
45
60
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/media-viewer",
3
- "version": "54.5.10",
3
+ "version": "54.5.12",
4
4
  "description": "MediaViewer is Atlassian's powerful solution for viewing files on the web. It's both powerful and extendable yet easy-to-integrate",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -54,7 +54,7 @@
54
54
  "@atlaskit/spinner": "^20.1.0",
55
55
  "@atlaskit/textfield": "^9.1.0",
56
56
  "@atlaskit/theme": "^26.1.0",
57
- "@atlaskit/tmp-editor-statsig": "^126.2.0",
57
+ "@atlaskit/tmp-editor-statsig": "^127.1.0",
58
58
  "@atlaskit/tokens": "^16.0.0",
59
59
  "@atlaskit/tooltip": "^23.1.0",
60
60
  "@atlaskit/ufo": "^1.0.0",