@atlaskit/media-file-preview 0.17.1 → 0.18.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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/media-file-preview
2
2
 
3
+ ## 0.18.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`a68f551856a81`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a68f551856a81) -
8
+ Add initialFileState param to useFilePreview to support SSR-seeded file state for immediate
9
+ preview rendering.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+
15
+ ## 0.17.2
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+
3
21
  ## 0.17.1
4
22
 
5
23
  ### Patch Changes
@@ -4,10 +4,10 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.isSSRPreview = exports.isSSRDataPreview = exports.isSSRClientPreview = exports.isRemotePreview = exports.isLocalPreview = exports.getSSRPreview = exports.getAndCacheRemotePreview = exports.getAndCacheLocalPreview = void 0;
7
+ exports.isSSRPreview = exports.isSSRDataPreview = exports.isSSRClientPreview = exports.isRemotePreview = exports.isLocalPreview = exports.getSSRPreview = exports.getAndCacheRemotePreview = exports.getAndCacheLocalPreview = exports.extractCdnSigningParams = void 0;
8
8
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
- var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
10
9
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
11
11
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
12
12
  var _mediaClient = require("@atlaskit/media-client");
13
13
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
@@ -39,9 +39,62 @@ var extendAndCachePreview = function extendAndCachePreview(id, mode, preview, me
39
39
  dataURI: dataURI
40
40
  });
41
41
  };
42
- var getDataUri = function getDataUri(mediaClient, id, params, mediaBlobUrlAttrs) {
42
+
43
+ /**
44
+ * Allowlist of CDN signing query-param names that we propagate from a
45
+ * pre-signed `previewCdnUrl` onto the URL produced by `getImageUrlSync`.
46
+ * These are the standard CloudFront signed-URL params; if the upstream
47
+ * adds a new one, this list needs updating.
48
+ */
49
+ var SIGNING_PARAM_NAMES = ['token', 'Policy', 'Key-Pair-Id', 'Signature', 'Expires'];
50
+
51
+ /**
52
+ * Pull the CDN-signing query params (token / Policy / Key-Pair-Id / Signature
53
+ * / Expires) out of a pre-signed CDN URL so they can be overlaid on a URL
54
+ * built independently by `getImageUrlSync` (which constructs path, image
55
+ * params, pathBased routing, wmv, etc.). Image-shape params from the cdn URL
56
+ * itself (width/height/mode/...) are intentionally NOT extracted — those come
57
+ * from `imageURLParams` via `getImageUrlSync`.
58
+ *
59
+ * Returns `{}` on parse failure so we degrade rather than throw.
60
+ */
61
+ var extractCdnSigningParams = exports.extractCdnSigningParams = function extractCdnSigningParams(cdnUrl) {
62
+ try {
63
+ var url = new URL(cdnUrl);
64
+ var out = {};
65
+ for (var _i = 0, _SIGNING_PARAM_NAMES = SIGNING_PARAM_NAMES; _i < _SIGNING_PARAM_NAMES.length; _i++) {
66
+ var name = _SIGNING_PARAM_NAMES[_i];
67
+ var value = url.searchParams.get(name);
68
+ if (value !== null) {
69
+ out[name] = value;
70
+ }
71
+ }
72
+ return out;
73
+ } catch (_unused) {
74
+ return {};
75
+ }
76
+ };
77
+ var applyCdnSigningParams = function applyCdnSigningParams(url, cdnSigningParams) {
78
+ if (!cdnSigningParams || Object.keys(cdnSigningParams).length === 0) {
79
+ return url;
80
+ }
81
+ try {
82
+ var parsed = new URL(url);
83
+ Object.entries(cdnSigningParams).forEach(function (_ref) {
84
+ var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
85
+ key = _ref2[0],
86
+ value = _ref2[1];
87
+ parsed.searchParams.set(key, value);
88
+ });
89
+ return parsed.toString();
90
+ } catch (_unused2) {
91
+ return url;
92
+ }
93
+ };
94
+ var getDataUri = function getDataUri(mediaClient, id, params, mediaBlobUrlAttrs, cdnSigningParams) {
43
95
  var rawDataURI = mediaClient.getImageUrlSync(id, params);
44
- return mediaBlobUrlAttrs ? (0, _mediaClient.addFileAttrsToUrl)(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
96
+ var signedDataURI = applyCdnSigningParams(rawDataURI, cdnSigningParams);
97
+ return mediaBlobUrlAttrs ? (0, _mediaClient.addFileAttrsToUrl)(signedDataURI, mediaBlobUrlAttrs) : signedDataURI;
45
98
  };
46
99
 
47
100
  /**
@@ -66,18 +119,18 @@ var mergeClientIdIntoAttrs = function mergeClientIdIntoAttrs(clientId, id, media
66
119
  collection: collectionName
67
120
  };
68
121
  };
69
- var getSSRPreview = exports.getSSRPreview = function getSSRPreview(ssr, mediaClient, id, params, mediaBlobUrlAttrs) {
122
+ var getSSRPreview = exports.getSSRPreview = function getSSRPreview(ssr, mediaClient, id, params, mediaBlobUrlAttrs, cdnSigningParams) {
70
123
  try {
71
124
  // Synchronously extract clientId from initialAuth and merge into blob URL attrs
72
125
  var clientId = (0, _platformFeatureFlags.fg)('platform_media_cross_client_copy_with_auth') ? mediaClient.getClientIdSync() : undefined;
73
126
  var attrsWithClientId = mergeClientIdIntoAttrs(clientId, id, mediaBlobUrlAttrs, params.collection);
74
- var dataURI = getDataUri(mediaClient, id, params, attrsWithClientId);
127
+ var dataURI = getDataUri(mediaClient, id, params, attrsWithClientId, cdnSigningParams);
75
128
  var srcSet = "".concat(dataURI, " 1x");
76
129
  if (params.width) {
77
130
  var doubleDataURI = getDataUri(mediaClient, id, _objectSpread(_objectSpread({}, params), {}, {
78
131
  width: params.width * 2,
79
132
  height: params.height && params.height * 2
80
- }), attrsWithClientId);
133
+ }), attrsWithClientId, cdnSigningParams);
81
134
  // We want to embed some meta context into dataURI for Copy/Paste to work.
82
135
  srcSet += ", ".concat(doubleDataURI, " 2x");
83
136
  }
@@ -117,54 +170,54 @@ var isSSRPreview = exports.isSSRPreview = function isSSRPreview(preview) {
117
170
  * with it for cross-client copy support.
118
171
  */
119
172
  var enrichAttrsWithClientId = /*#__PURE__*/function () {
120
- var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(mediaClient, id, mediaBlobUrlAttrs, collectionName) {
121
- var clientId;
122
- return _regenerator.default.wrap(function _callee$(_context) {
173
+ var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(mediaClient, id, mediaBlobUrlAttrs, collectionName) {
174
+ var clientId, _t;
175
+ return _regenerator.default.wrap(function (_context) {
123
176
  while (1) switch (_context.prev = _context.next) {
124
177
  case 0:
125
178
  if ((0, _platformFeatureFlags.fg)('platform_media_cross_client_copy_with_auth')) {
126
- _context.next = 2;
179
+ _context.next = 1;
127
180
  break;
128
181
  }
129
182
  return _context.abrupt("return", mediaBlobUrlAttrs);
130
- case 2:
183
+ case 1:
131
184
  // Try sync first, then async fallback
132
185
  clientId = mediaClient.getClientIdSync();
133
186
  if (clientId) {
134
- _context.next = 12;
187
+ _context.next = 5;
135
188
  break;
136
189
  }
137
- _context.prev = 4;
138
- _context.next = 7;
190
+ _context.prev = 2;
191
+ _context.next = 3;
139
192
  return mediaClient.getClientId(collectionName);
140
- case 7:
193
+ case 3:
141
194
  clientId = _context.sent;
142
- _context.next = 12;
195
+ _context.next = 5;
143
196
  break;
144
- case 10:
145
- _context.prev = 10;
146
- _context.t0 = _context["catch"](4);
147
- case 12:
197
+ case 4:
198
+ _context.prev = 4;
199
+ _t = _context["catch"](2);
200
+ case 5:
148
201
  return _context.abrupt("return", mergeClientIdIntoAttrs(clientId, id, mediaBlobUrlAttrs, collectionName));
149
- case 13:
202
+ case 6:
150
203
  case "end":
151
204
  return _context.stop();
152
205
  }
153
- }, _callee, null, [[4, 10]]);
206
+ }, _callee, null, [[2, 4]]);
154
207
  }));
155
208
  return function enrichAttrsWithClientId(_x, _x2, _x3, _x4) {
156
- return _ref.apply(this, arguments);
209
+ return _ref3.apply(this, arguments);
157
210
  };
158
211
  }();
159
212
  var getAndCacheRemotePreview = exports.getAndCacheRemotePreview = /*#__PURE__*/function () {
160
- var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(mediaClient, id, dimensions, params, mediaBlobUrlAttrs, traceContext) {
213
+ var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(mediaClient, id, dimensions, params, mediaBlobUrlAttrs, traceContext) {
161
214
  var _yield$Promise$all, _yield$Promise$all2, remotePreview, enrichedAttrs;
162
- return _regenerator.default.wrap(function _callee2$(_context2) {
215
+ return _regenerator.default.wrap(function (_context2) {
163
216
  while (1) switch (_context2.prev = _context2.next) {
164
217
  case 0:
165
- _context2.next = 2;
218
+ _context2.next = 1;
166
219
  return Promise.all([(0, _helpers.getRemotePreview)(mediaClient, id, params, traceContext), enrichAttrsWithClientId(mediaClient, id, mediaBlobUrlAttrs, params.collection)]);
167
- case 2:
220
+ case 1:
168
221
  _yield$Promise$all = _context2.sent;
169
222
  _yield$Promise$all2 = (0, _slicedToArray2.default)(_yield$Promise$all, 2);
170
223
  remotePreview = _yield$Promise$all2[0];
@@ -172,25 +225,25 @@ var getAndCacheRemotePreview = exports.getAndCacheRemotePreview = /*#__PURE__*/f
172
225
  return _context2.abrupt("return", extendAndCachePreview(id, params.mode, _objectSpread(_objectSpread({}, remotePreview), {}, {
173
226
  dimensions: dimensions
174
227
  }), enrichedAttrs));
175
- case 7:
228
+ case 2:
176
229
  case "end":
177
230
  return _context2.stop();
178
231
  }
179
232
  }, _callee2);
180
233
  }));
181
234
  return function getAndCacheRemotePreview(_x5, _x6, _x7, _x8, _x9, _x0) {
182
- return _ref2.apply(this, arguments);
235
+ return _ref4.apply(this, arguments);
183
236
  };
184
237
  }();
185
238
  var getAndCacheLocalPreview = exports.getAndCacheLocalPreview = /*#__PURE__*/function () {
186
- var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(mediaClient, id, filePreview, dimensions, mode, mediaBlobUrlAttrs, collectionName) {
239
+ var _ref5 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(mediaClient, id, filePreview, dimensions, mode, mediaBlobUrlAttrs, collectionName) {
187
240
  var _yield$Promise$all3, _yield$Promise$all4, localPreview, enrichedAttrs;
188
- return _regenerator.default.wrap(function _callee3$(_context3) {
241
+ return _regenerator.default.wrap(function (_context3) {
189
242
  while (1) switch (_context3.prev = _context3.next) {
190
243
  case 0:
191
- _context3.next = 2;
244
+ _context3.next = 1;
192
245
  return Promise.all([(0, _helpers.getLocalPreview)(filePreview), enrichAttrsWithClientId(mediaClient, id, mediaBlobUrlAttrs, collectionName)]);
193
- case 2:
246
+ case 1:
194
247
  _yield$Promise$all3 = _context3.sent;
195
248
  _yield$Promise$all4 = (0, _slicedToArray2.default)(_yield$Promise$all3, 2);
196
249
  localPreview = _yield$Promise$all4[0];
@@ -198,13 +251,13 @@ var getAndCacheLocalPreview = exports.getAndCacheLocalPreview = /*#__PURE__*/fun
198
251
  return _context3.abrupt("return", extendAndCachePreview(id, mode, _objectSpread(_objectSpread({}, localPreview), {}, {
199
252
  dimensions: dimensions
200
253
  }), enrichedAttrs));
201
- case 7:
254
+ case 2:
202
255
  case "end":
203
256
  return _context3.stop();
204
257
  }
205
258
  }, _callee3);
206
259
  }));
207
260
  return function getAndCacheLocalPreview(_x1, _x10, _x11, _x12, _x13, _x14, _x15) {
208
- return _ref3.apply(this, arguments);
261
+ return _ref5.apply(this, arguments);
209
262
  };
210
263
  }();
@@ -20,14 +20,14 @@ var isSupportedLocalPreview = exports.isSupportedLocalPreview = function isSuppo
20
20
  };
21
21
  var getImageLocalPreview = /*#__PURE__*/function () {
22
22
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(value) {
23
- var orientation, dataURI;
24
- return _regenerator.default.wrap(function _callee$(_context) {
23
+ var orientation, dataURI, _t;
24
+ return _regenerator.default.wrap(function (_context) {
25
25
  while (1) switch (_context.prev = _context.next) {
26
26
  case 0:
27
27
  _context.prev = 0;
28
- _context.next = 3;
28
+ _context.next = 1;
29
29
  return (0, _mediaUi.getOrientation)(value);
30
- case 3:
30
+ case 1:
31
31
  orientation = _context.sent;
32
32
  dataURI = URL.createObjectURL(value);
33
33
  return _context.abrupt("return", {
@@ -35,15 +35,15 @@ var getImageLocalPreview = /*#__PURE__*/function () {
35
35
  orientation: orientation,
36
36
  source: 'local'
37
37
  });
38
- case 8:
39
- _context.prev = 8;
40
- _context.t0 = _context["catch"](0);
41
- throw new _errors.LocalPreviewError('local-preview-image', _context.t0 instanceof Error ? _context.t0 : undefined);
42
- case 11:
38
+ case 2:
39
+ _context.prev = 2;
40
+ _t = _context["catch"](0);
41
+ throw new _errors.LocalPreviewError('local-preview-image', _t instanceof Error ? _t : undefined);
42
+ case 3:
43
43
  case "end":
44
44
  return _context.stop();
45
45
  }
46
- }, _callee, null, [[0, 8]]);
46
+ }, _callee, null, [[0, 2]]);
47
47
  }));
48
48
  return function getImageLocalPreview(_x) {
49
49
  return _ref.apply(this, arguments);
@@ -51,29 +51,29 @@ var getImageLocalPreview = /*#__PURE__*/function () {
51
51
  }();
52
52
  var getVideoLocalPreview = /*#__PURE__*/function () {
53
53
  var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(value) {
54
- var dataURI;
55
- return _regenerator.default.wrap(function _callee2$(_context2) {
54
+ var dataURI, _t2;
55
+ return _regenerator.default.wrap(function (_context2) {
56
56
  while (1) switch (_context2.prev = _context2.next) {
57
57
  case 0:
58
58
  _context2.prev = 0;
59
- _context2.next = 3;
59
+ _context2.next = 1;
60
60
  return (0, _videoSnapshot.takeSnapshot)(value);
61
- case 3:
61
+ case 1:
62
62
  dataURI = _context2.sent;
63
63
  return _context2.abrupt("return", {
64
64
  dataURI: dataURI,
65
65
  orientation: 1,
66
66
  source: 'local'
67
67
  });
68
- case 7:
69
- _context2.prev = 7;
70
- _context2.t0 = _context2["catch"](0);
71
- throw new _errors.LocalPreviewError('local-preview-video', _context2.t0 instanceof Error ? _context2.t0 : undefined);
72
- case 10:
68
+ case 2:
69
+ _context2.prev = 2;
70
+ _t2 = _context2["catch"](0);
71
+ throw new _errors.LocalPreviewError('local-preview-video', _t2 instanceof Error ? _t2 : undefined);
72
+ case 3:
73
73
  case "end":
74
74
  return _context2.stop();
75
75
  }
76
- }, _callee2, null, [[0, 7]]);
76
+ }, _callee2, null, [[0, 2]]);
77
77
  }));
78
78
  return function getVideoLocalPreview(_x2) {
79
79
  return _ref2.apply(this, arguments);
@@ -81,25 +81,25 @@ var getVideoLocalPreview = /*#__PURE__*/function () {
81
81
  }();
82
82
  var getLocalPreview = exports.getLocalPreview = /*#__PURE__*/function () {
83
83
  var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(filePreview) {
84
- var value, resolvedFilePreview, _value, type, mediaType;
85
- return _regenerator.default.wrap(function _callee3$(_context3) {
84
+ var value, resolvedFilePreview, _value, type, mediaType, _t3, _t4;
85
+ return _regenerator.default.wrap(function (_context3) {
86
86
  while (1) switch (_context3.prev = _context3.next) {
87
87
  case 0:
88
88
  _context3.prev = 0;
89
- _context3.next = 3;
89
+ _context3.next = 1;
90
90
  return filePreview;
91
- case 3:
91
+ case 1:
92
92
  resolvedFilePreview = _context3.sent;
93
93
  value = resolvedFilePreview.value;
94
- _context3.next = 10;
94
+ _context3.next = 3;
95
95
  break;
96
- case 7:
97
- _context3.prev = 7;
98
- _context3.t0 = _context3["catch"](0);
99
- throw new _errors.LocalPreviewError('local-preview-rejected', _context3.t0 instanceof Error ? _context3.t0 : undefined);
100
- case 10:
96
+ case 2:
97
+ _context3.prev = 2;
98
+ _t3 = _context3["catch"](0);
99
+ throw new _errors.LocalPreviewError('local-preview-rejected', _t3 instanceof Error ? _t3 : undefined);
100
+ case 3:
101
101
  if (!(typeof value === 'string')) {
102
- _context3.next = 14;
102
+ _context3.next = 4;
103
103
  break;
104
104
  }
105
105
  return _context3.abrupt("return", {
@@ -107,29 +107,29 @@ var getLocalPreview = exports.getLocalPreview = /*#__PURE__*/function () {
107
107
  orientation: 1,
108
108
  source: 'local'
109
109
  });
110
- case 14:
110
+ case 4:
111
111
  if (!(value instanceof Blob)) {
112
- _context3.next = 23;
112
+ _context3.next = 8;
113
113
  break;
114
114
  }
115
115
  _value = value, type = _value.type;
116
116
  mediaType = (0, _mediaCommon.getMediaTypeFromMimeType)(type);
117
- _context3.t1 = mediaType;
118
- _context3.next = _context3.t1 === 'image' ? 20 : _context3.t1 === 'video' ? 21 : 22;
117
+ _t4 = mediaType;
118
+ _context3.next = _t4 === 'image' ? 5 : _t4 === 'video' ? 6 : 7;
119
119
  break;
120
- case 20:
120
+ case 5:
121
121
  return _context3.abrupt("return", getImageLocalPreview(value));
122
- case 21:
122
+ case 6:
123
123
  return _context3.abrupt("return", getVideoLocalPreview(value));
124
- case 22:
124
+ case 7:
125
125
  throw new _errors.LocalPreviewError('local-preview-unsupported');
126
- case 23:
126
+ case 8:
127
127
  throw new _errors.LocalPreviewError('local-preview-unsupported');
128
- case 24:
128
+ case 9:
129
129
  case "end":
130
130
  return _context3.stop();
131
131
  }
132
- }, _callee3, null, [[0, 7]]);
132
+ }, _callee3, null, [[0, 2]]);
133
133
  }));
134
134
  return function getLocalPreview(_x3) {
135
135
  return _ref3.apply(this, arguments);
@@ -137,29 +137,29 @@ var getLocalPreview = exports.getLocalPreview = /*#__PURE__*/function () {
137
137
  }();
138
138
  var getRemotePreview = exports.getRemotePreview = /*#__PURE__*/function () {
139
139
  var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(mediaClient, id, params, traceContext) {
140
- var blob;
141
- return _regenerator.default.wrap(function _callee4$(_context4) {
140
+ var blob, _t5;
141
+ return _regenerator.default.wrap(function (_context4) {
142
142
  while (1) switch (_context4.prev = _context4.next) {
143
143
  case 0:
144
144
  _context4.prev = 0;
145
- _context4.next = 3;
145
+ _context4.next = 1;
146
146
  return mediaClient.getImage(id, params, undefined, undefined, traceContext);
147
- case 3:
147
+ case 1:
148
148
  blob = _context4.sent;
149
149
  return _context4.abrupt("return", {
150
150
  dataURI: URL.createObjectURL(blob),
151
151
  orientation: 1,
152
152
  source: 'remote'
153
153
  });
154
- case 7:
155
- _context4.prev = 7;
156
- _context4.t0 = _context4["catch"](0);
157
- throw new _errors.RemotePreviewError('remote-preview-fetch', _context4.t0 instanceof Error ? _context4.t0 : undefined);
158
- case 10:
154
+ case 2:
155
+ _context4.prev = 2;
156
+ _t5 = _context4["catch"](0);
157
+ throw new _errors.RemotePreviewError('remote-preview-fetch', _t5 instanceof Error ? _t5 : undefined);
158
+ case 3:
159
159
  case "end":
160
160
  return _context4.stop();
161
161
  }
162
- }, _callee4, null, [[0, 7]]);
162
+ }, _callee4, null, [[0, 2]]);
163
163
  }));
164
164
  return function getRemotePreview(_x4, _x5, _x6, _x7) {
165
165
  return _ref4.apply(this, arguments);
@@ -3,6 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ Object.defineProperty(exports, "extractCdnSigningParams", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _getPreview.extractCdnSigningParams;
10
+ }
11
+ });
6
12
  Object.defineProperty(exports, "getAndCacheLocalPreview", {
7
13
  enumerable: true,
8
14
  get: function get() {
@@ -9,7 +9,7 @@ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"))
9
9
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
10
  var takeSnapshot = exports.takeSnapshot = /*#__PURE__*/function () {
11
11
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(blob) {
12
- return _regenerator.default.wrap(function _callee$(_context) {
12
+ return _regenerator.default.wrap(function (_context) {
13
13
  while (1) switch (_context.prev = _context.next) {
14
14
  case 0:
15
15
  return _context.abrupt("return", new Promise(function (resolve, reject) {
@@ -45,7 +45,8 @@ var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
45
45
  allowAnimated = _ref$allowAnimated === void 0 ? true : _ref$allowAnimated,
46
46
  upscale = _ref.upscale,
47
47
  maxAge = _ref.maxAge,
48
- source = _ref.source;
48
+ source = _ref.source,
49
+ initialFileState = _ref.initialFileState;
49
50
  var mediaClient = (0, _mediaClientReact.useMediaClient)();
50
51
  var _useState = (0, _react.useState)('loading'),
51
52
  _useState2 = (0, _slicedToArray2.default)(_useState, 2),
@@ -122,7 +123,15 @@ var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
122
123
  // where no SSR occurred, so we should skip SSR preview generation entirely.
123
124
  if (ssr === 'server' || ssrData) {
124
125
  try {
125
- return (0, _getPreview.getSSRPreview)(ssr, mediaClient, identifier.id, imageURLParams, mediaBlobUrlAttrs);
126
+ // When the relay/SSR-seed path provided a pre-signed CDN URL,
127
+ // overlay its CDN-signing query params on the URL produced by
128
+ // getImageUrlSync. This makes the SSR-rendered HTML use the
129
+ // cdn-signed URL directly (no auth-token -> cdn-signed swap on
130
+ // hydration) and the 'ssr-data' rehydration path inherits it
131
+ // automatically via globalScope.
132
+ var seededCdnUrl = initialFileState && initialFileState.status !== 'error' ? initialFileState.previewCdnUrl : undefined;
133
+ var cdnSigningParams = seededCdnUrl && (0, _platformFeatureFlags.fg)('platform_media_ssr_data_seed') ? (0, _getPreview.extractCdnSigningParams)(seededCdnUrl) : undefined;
134
+ return (0, _getPreview.getSSRPreview)(ssr, mediaClient, identifier.id, imageURLParams, mediaBlobUrlAttrs, cdnSigningParams);
126
135
  } catch (e) {
127
136
  ssrReliabilityRef.current = _objectSpread(_objectSpread({}, ssrReliabilityRef.current), {}, (0, _defineProperty2.default)({}, ssr, _objectSpread({
128
137
  status: 'fail'
@@ -154,6 +163,7 @@ var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
154
163
  //----------------------------------------------------------------
155
164
 
156
165
  var _useFileState = (0, _mediaClientReact.useFileState)(identifier.id, {
166
+ initialFileState: initialFileState,
157
167
  skipRemote: skipRemote,
158
168
  collectionName: identifier.collectionName,
159
169
  occurrenceKey: identifier.occurrenceKey
@@ -28,9 +28,58 @@ const extendAndCachePreview = (id, mode, preview, mediaBlobUrlAttrs) => {
28
28
  dataURI
29
29
  };
30
30
  };
31
- const getDataUri = (mediaClient, id, params, mediaBlobUrlAttrs) => {
31
+
32
+ /**
33
+ * Allowlist of CDN signing query-param names that we propagate from a
34
+ * pre-signed `previewCdnUrl` onto the URL produced by `getImageUrlSync`.
35
+ * These are the standard CloudFront signed-URL params; if the upstream
36
+ * adds a new one, this list needs updating.
37
+ */
38
+ const SIGNING_PARAM_NAMES = ['token', 'Policy', 'Key-Pair-Id', 'Signature', 'Expires'];
39
+
40
+ /**
41
+ * Pull the CDN-signing query params (token / Policy / Key-Pair-Id / Signature
42
+ * / Expires) out of a pre-signed CDN URL so they can be overlaid on a URL
43
+ * built independently by `getImageUrlSync` (which constructs path, image
44
+ * params, pathBased routing, wmv, etc.). Image-shape params from the cdn URL
45
+ * itself (width/height/mode/...) are intentionally NOT extracted — those come
46
+ * from `imageURLParams` via `getImageUrlSync`.
47
+ *
48
+ * Returns `{}` on parse failure so we degrade rather than throw.
49
+ */
50
+ export const extractCdnSigningParams = cdnUrl => {
51
+ try {
52
+ const url = new URL(cdnUrl);
53
+ const out = {};
54
+ for (const name of SIGNING_PARAM_NAMES) {
55
+ const value = url.searchParams.get(name);
56
+ if (value !== null) {
57
+ out[name] = value;
58
+ }
59
+ }
60
+ return out;
61
+ } catch {
62
+ return {};
63
+ }
64
+ };
65
+ const applyCdnSigningParams = (url, cdnSigningParams) => {
66
+ if (!cdnSigningParams || Object.keys(cdnSigningParams).length === 0) {
67
+ return url;
68
+ }
69
+ try {
70
+ const parsed = new URL(url);
71
+ Object.entries(cdnSigningParams).forEach(([key, value]) => {
72
+ parsed.searchParams.set(key, value);
73
+ });
74
+ return parsed.toString();
75
+ } catch {
76
+ return url;
77
+ }
78
+ };
79
+ const getDataUri = (mediaClient, id, params, mediaBlobUrlAttrs, cdnSigningParams) => {
32
80
  const rawDataURI = mediaClient.getImageUrlSync(id, params);
33
- return mediaBlobUrlAttrs ? addFileAttrsToUrl(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
81
+ const signedDataURI = applyCdnSigningParams(rawDataURI, cdnSigningParams);
82
+ return mediaBlobUrlAttrs ? addFileAttrsToUrl(signedDataURI, mediaBlobUrlAttrs) : signedDataURI;
34
83
  };
35
84
 
36
85
  /**
@@ -56,19 +105,19 @@ const mergeClientIdIntoAttrs = (clientId, id, mediaBlobUrlAttrs, collectionName)
56
105
  collection: collectionName
57
106
  };
58
107
  };
59
- export const getSSRPreview = (ssr, mediaClient, id, params, mediaBlobUrlAttrs) => {
108
+ export const getSSRPreview = (ssr, mediaClient, id, params, mediaBlobUrlAttrs, cdnSigningParams) => {
60
109
  try {
61
110
  // Synchronously extract clientId from initialAuth and merge into blob URL attrs
62
111
  const clientId = fg('platform_media_cross_client_copy_with_auth') ? mediaClient.getClientIdSync() : undefined;
63
112
  const attrsWithClientId = mergeClientIdIntoAttrs(clientId, id, mediaBlobUrlAttrs, params.collection);
64
- const dataURI = getDataUri(mediaClient, id, params, attrsWithClientId);
113
+ const dataURI = getDataUri(mediaClient, id, params, attrsWithClientId, cdnSigningParams);
65
114
  let srcSet = `${dataURI} 1x`;
66
115
  if (params.width) {
67
116
  const doubleDataURI = getDataUri(mediaClient, id, {
68
117
  ...params,
69
118
  width: params.width * 2,
70
119
  height: params.height && params.height * 2
71
- }, attrsWithClientId);
120
+ }, attrsWithClientId, cdnSigningParams);
72
121
  // We want to embed some meta context into dataURI for Copy/Paste to work.
73
122
  srcSet += `, ${doubleDataURI} 2x`;
74
123
  }
@@ -1,3 +1,3 @@
1
1
  export { mediaFilePreviewCache } from './cache';
2
- export { getSSRPreview, isLocalPreview, isRemotePreview, isSSRPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview } from './getPreview';
2
+ export { getSSRPreview, isLocalPreview, isRemotePreview, isSSRPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview, extractCdnSigningParams } from './getPreview';
3
3
  export { isSupportedLocalPreview } from './helpers';
@@ -6,7 +6,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
6
6
  import { useInteractionContext } from '@atlaskit/react-ufo/interaction-context';
7
7
  import { createFailedSSRObject, extractErrorInfo } from './analytics';
8
8
  import { ensureMediaFilePreviewError, ImageLoadError, MediaFilePreviewError } from './errors';
9
- import { getAndCacheLocalPreview, getAndCacheRemotePreview, getSSRPreview, isLocalPreview, isRemotePreview, isSSRClientPreview, isSSRDataPreview, isSSRPreview, isSupportedLocalPreview, mediaFilePreviewCache } from './getPreview';
9
+ import { extractCdnSigningParams, getAndCacheLocalPreview, getAndCacheRemotePreview, getSSRPreview, isLocalPreview, isRemotePreview, isSSRClientPreview, isSSRDataPreview, isSSRPreview, isSupportedLocalPreview, mediaFilePreviewCache } from './getPreview';
10
10
  import { generateScriptProps, getSSRData } from './globalScope';
11
11
  import { createRequestDimensions, isBigger, isWider, useCurrentValueRef } from './helpers';
12
12
  // invisible gif for SSR preview to show the underlying spinner until the src is replaced by
@@ -32,7 +32,8 @@ export const useFilePreview = ({
32
32
  allowAnimated = true,
33
33
  upscale,
34
34
  maxAge,
35
- source
35
+ source,
36
+ initialFileState
36
37
  }) => {
37
38
  const mediaClient = useMediaClient();
38
39
  const [status, setStatus] = useState('loading');
@@ -93,7 +94,15 @@ export const useFilePreview = ({
93
94
  // where no SSR occurred, so we should skip SSR preview generation entirely.
94
95
  if (ssr === 'server' || ssrData) {
95
96
  try {
96
- return getSSRPreview(ssr, mediaClient, identifier.id, imageURLParams, mediaBlobUrlAttrs);
97
+ // When the relay/SSR-seed path provided a pre-signed CDN URL,
98
+ // overlay its CDN-signing query params on the URL produced by
99
+ // getImageUrlSync. This makes the SSR-rendered HTML use the
100
+ // cdn-signed URL directly (no auth-token -> cdn-signed swap on
101
+ // hydration) and the 'ssr-data' rehydration path inherits it
102
+ // automatically via globalScope.
103
+ const seededCdnUrl = initialFileState && initialFileState.status !== 'error' ? initialFileState.previewCdnUrl : undefined;
104
+ const cdnSigningParams = seededCdnUrl && fg('platform_media_ssr_data_seed') ? extractCdnSigningParams(seededCdnUrl) : undefined;
105
+ return getSSRPreview(ssr, mediaClient, identifier.id, imageURLParams, mediaBlobUrlAttrs, cdnSigningParams);
97
106
  } catch (e) {
98
107
  ssrReliabilityRef.current = {
99
108
  ...ssrReliabilityRef.current,
@@ -130,6 +139,7 @@ export const useFilePreview = ({
130
139
  const {
131
140
  fileState
132
141
  } = useFileState(identifier.id, {
142
+ initialFileState,
133
143
  skipRemote,
134
144
  collectionName: identifier.collectionName,
135
145
  occurrenceKey: identifier.occurrenceKey
@@ -1,5 +1,5 @@
1
- import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
1
  import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
4
  import _regeneratorRuntime from "@babel/runtime/regenerator";
5
5
  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; }
@@ -32,9 +32,62 @@ var extendAndCachePreview = function extendAndCachePreview(id, mode, preview, me
32
32
  dataURI: dataURI
33
33
  });
34
34
  };
35
- var getDataUri = function getDataUri(mediaClient, id, params, mediaBlobUrlAttrs) {
35
+
36
+ /**
37
+ * Allowlist of CDN signing query-param names that we propagate from a
38
+ * pre-signed `previewCdnUrl` onto the URL produced by `getImageUrlSync`.
39
+ * These are the standard CloudFront signed-URL params; if the upstream
40
+ * adds a new one, this list needs updating.
41
+ */
42
+ var SIGNING_PARAM_NAMES = ['token', 'Policy', 'Key-Pair-Id', 'Signature', 'Expires'];
43
+
44
+ /**
45
+ * Pull the CDN-signing query params (token / Policy / Key-Pair-Id / Signature
46
+ * / Expires) out of a pre-signed CDN URL so they can be overlaid on a URL
47
+ * built independently by `getImageUrlSync` (which constructs path, image
48
+ * params, pathBased routing, wmv, etc.). Image-shape params from the cdn URL
49
+ * itself (width/height/mode/...) are intentionally NOT extracted — those come
50
+ * from `imageURLParams` via `getImageUrlSync`.
51
+ *
52
+ * Returns `{}` on parse failure so we degrade rather than throw.
53
+ */
54
+ export var extractCdnSigningParams = function extractCdnSigningParams(cdnUrl) {
55
+ try {
56
+ var url = new URL(cdnUrl);
57
+ var out = {};
58
+ for (var _i = 0, _SIGNING_PARAM_NAMES = SIGNING_PARAM_NAMES; _i < _SIGNING_PARAM_NAMES.length; _i++) {
59
+ var name = _SIGNING_PARAM_NAMES[_i];
60
+ var value = url.searchParams.get(name);
61
+ if (value !== null) {
62
+ out[name] = value;
63
+ }
64
+ }
65
+ return out;
66
+ } catch (_unused) {
67
+ return {};
68
+ }
69
+ };
70
+ var applyCdnSigningParams = function applyCdnSigningParams(url, cdnSigningParams) {
71
+ if (!cdnSigningParams || Object.keys(cdnSigningParams).length === 0) {
72
+ return url;
73
+ }
74
+ try {
75
+ var parsed = new URL(url);
76
+ Object.entries(cdnSigningParams).forEach(function (_ref) {
77
+ var _ref2 = _slicedToArray(_ref, 2),
78
+ key = _ref2[0],
79
+ value = _ref2[1];
80
+ parsed.searchParams.set(key, value);
81
+ });
82
+ return parsed.toString();
83
+ } catch (_unused2) {
84
+ return url;
85
+ }
86
+ };
87
+ var getDataUri = function getDataUri(mediaClient, id, params, mediaBlobUrlAttrs, cdnSigningParams) {
36
88
  var rawDataURI = mediaClient.getImageUrlSync(id, params);
37
- return mediaBlobUrlAttrs ? addFileAttrsToUrl(rawDataURI, mediaBlobUrlAttrs) : rawDataURI;
89
+ var signedDataURI = applyCdnSigningParams(rawDataURI, cdnSigningParams);
90
+ return mediaBlobUrlAttrs ? addFileAttrsToUrl(signedDataURI, mediaBlobUrlAttrs) : signedDataURI;
38
91
  };
39
92
 
40
93
  /**
@@ -59,18 +112,18 @@ var mergeClientIdIntoAttrs = function mergeClientIdIntoAttrs(clientId, id, media
59
112
  collection: collectionName
60
113
  };
61
114
  };
62
- export var getSSRPreview = function getSSRPreview(ssr, mediaClient, id, params, mediaBlobUrlAttrs) {
115
+ export var getSSRPreview = function getSSRPreview(ssr, mediaClient, id, params, mediaBlobUrlAttrs, cdnSigningParams) {
63
116
  try {
64
117
  // Synchronously extract clientId from initialAuth and merge into blob URL attrs
65
118
  var clientId = fg('platform_media_cross_client_copy_with_auth') ? mediaClient.getClientIdSync() : undefined;
66
119
  var attrsWithClientId = mergeClientIdIntoAttrs(clientId, id, mediaBlobUrlAttrs, params.collection);
67
- var dataURI = getDataUri(mediaClient, id, params, attrsWithClientId);
120
+ var dataURI = getDataUri(mediaClient, id, params, attrsWithClientId, cdnSigningParams);
68
121
  var srcSet = "".concat(dataURI, " 1x");
69
122
  if (params.width) {
70
123
  var doubleDataURI = getDataUri(mediaClient, id, _objectSpread(_objectSpread({}, params), {}, {
71
124
  width: params.width * 2,
72
125
  height: params.height && params.height * 2
73
- }), attrsWithClientId);
126
+ }), attrsWithClientId, cdnSigningParams);
74
127
  // We want to embed some meta context into dataURI for Copy/Paste to work.
75
128
  srcSet += ", ".concat(doubleDataURI, " 2x");
76
129
  }
@@ -110,54 +163,54 @@ export var isSSRPreview = function isSSRPreview(preview) {
110
163
  * with it for cross-client copy support.
111
164
  */
112
165
  var enrichAttrsWithClientId = /*#__PURE__*/function () {
113
- var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(mediaClient, id, mediaBlobUrlAttrs, collectionName) {
114
- var clientId;
115
- return _regeneratorRuntime.wrap(function _callee$(_context) {
166
+ var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(mediaClient, id, mediaBlobUrlAttrs, collectionName) {
167
+ var clientId, _t;
168
+ return _regeneratorRuntime.wrap(function (_context) {
116
169
  while (1) switch (_context.prev = _context.next) {
117
170
  case 0:
118
171
  if (fg('platform_media_cross_client_copy_with_auth')) {
119
- _context.next = 2;
172
+ _context.next = 1;
120
173
  break;
121
174
  }
122
175
  return _context.abrupt("return", mediaBlobUrlAttrs);
123
- case 2:
176
+ case 1:
124
177
  // Try sync first, then async fallback
125
178
  clientId = mediaClient.getClientIdSync();
126
179
  if (clientId) {
127
- _context.next = 12;
180
+ _context.next = 5;
128
181
  break;
129
182
  }
130
- _context.prev = 4;
131
- _context.next = 7;
183
+ _context.prev = 2;
184
+ _context.next = 3;
132
185
  return mediaClient.getClientId(collectionName);
133
- case 7:
186
+ case 3:
134
187
  clientId = _context.sent;
135
- _context.next = 12;
188
+ _context.next = 5;
136
189
  break;
137
- case 10:
138
- _context.prev = 10;
139
- _context.t0 = _context["catch"](4);
140
- case 12:
190
+ case 4:
191
+ _context.prev = 4;
192
+ _t = _context["catch"](2);
193
+ case 5:
141
194
  return _context.abrupt("return", mergeClientIdIntoAttrs(clientId, id, mediaBlobUrlAttrs, collectionName));
142
- case 13:
195
+ case 6:
143
196
  case "end":
144
197
  return _context.stop();
145
198
  }
146
- }, _callee, null, [[4, 10]]);
199
+ }, _callee, null, [[2, 4]]);
147
200
  }));
148
201
  return function enrichAttrsWithClientId(_x, _x2, _x3, _x4) {
149
- return _ref.apply(this, arguments);
202
+ return _ref3.apply(this, arguments);
150
203
  };
151
204
  }();
152
205
  export var getAndCacheRemotePreview = /*#__PURE__*/function () {
153
- var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(mediaClient, id, dimensions, params, mediaBlobUrlAttrs, traceContext) {
206
+ var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(mediaClient, id, dimensions, params, mediaBlobUrlAttrs, traceContext) {
154
207
  var _yield$Promise$all, _yield$Promise$all2, remotePreview, enrichedAttrs;
155
- return _regeneratorRuntime.wrap(function _callee2$(_context2) {
208
+ return _regeneratorRuntime.wrap(function (_context2) {
156
209
  while (1) switch (_context2.prev = _context2.next) {
157
210
  case 0:
158
- _context2.next = 2;
211
+ _context2.next = 1;
159
212
  return Promise.all([getRemotePreview(mediaClient, id, params, traceContext), enrichAttrsWithClientId(mediaClient, id, mediaBlobUrlAttrs, params.collection)]);
160
- case 2:
213
+ case 1:
161
214
  _yield$Promise$all = _context2.sent;
162
215
  _yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 2);
163
216
  remotePreview = _yield$Promise$all2[0];
@@ -165,25 +218,25 @@ export var getAndCacheRemotePreview = /*#__PURE__*/function () {
165
218
  return _context2.abrupt("return", extendAndCachePreview(id, params.mode, _objectSpread(_objectSpread({}, remotePreview), {}, {
166
219
  dimensions: dimensions
167
220
  }), enrichedAttrs));
168
- case 7:
221
+ case 2:
169
222
  case "end":
170
223
  return _context2.stop();
171
224
  }
172
225
  }, _callee2);
173
226
  }));
174
227
  return function getAndCacheRemotePreview(_x5, _x6, _x7, _x8, _x9, _x0) {
175
- return _ref2.apply(this, arguments);
228
+ return _ref4.apply(this, arguments);
176
229
  };
177
230
  }();
178
231
  export var getAndCacheLocalPreview = /*#__PURE__*/function () {
179
- var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(mediaClient, id, filePreview, dimensions, mode, mediaBlobUrlAttrs, collectionName) {
232
+ var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(mediaClient, id, filePreview, dimensions, mode, mediaBlobUrlAttrs, collectionName) {
180
233
  var _yield$Promise$all3, _yield$Promise$all4, localPreview, enrichedAttrs;
181
- return _regeneratorRuntime.wrap(function _callee3$(_context3) {
234
+ return _regeneratorRuntime.wrap(function (_context3) {
182
235
  while (1) switch (_context3.prev = _context3.next) {
183
236
  case 0:
184
- _context3.next = 2;
237
+ _context3.next = 1;
185
238
  return Promise.all([getLocalPreview(filePreview), enrichAttrsWithClientId(mediaClient, id, mediaBlobUrlAttrs, collectionName)]);
186
- case 2:
239
+ case 1:
187
240
  _yield$Promise$all3 = _context3.sent;
188
241
  _yield$Promise$all4 = _slicedToArray(_yield$Promise$all3, 2);
189
242
  localPreview = _yield$Promise$all4[0];
@@ -191,13 +244,13 @@ export var getAndCacheLocalPreview = /*#__PURE__*/function () {
191
244
  return _context3.abrupt("return", extendAndCachePreview(id, mode, _objectSpread(_objectSpread({}, localPreview), {}, {
192
245
  dimensions: dimensions
193
246
  }), enrichedAttrs));
194
- case 7:
247
+ case 2:
195
248
  case "end":
196
249
  return _context3.stop();
197
250
  }
198
251
  }, _callee3);
199
252
  }));
200
253
  return function getAndCacheLocalPreview(_x1, _x10, _x11, _x12, _x13, _x14, _x15) {
201
- return _ref3.apply(this, arguments);
254
+ return _ref5.apply(this, arguments);
202
255
  };
203
256
  }();
@@ -14,14 +14,14 @@ export var isSupportedLocalPreview = function isSupportedLocalPreview(mediaType)
14
14
  };
15
15
  var getImageLocalPreview = /*#__PURE__*/function () {
16
16
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(value) {
17
- var orientation, dataURI;
18
- return _regeneratorRuntime.wrap(function _callee$(_context) {
17
+ var orientation, dataURI, _t;
18
+ return _regeneratorRuntime.wrap(function (_context) {
19
19
  while (1) switch (_context.prev = _context.next) {
20
20
  case 0:
21
21
  _context.prev = 0;
22
- _context.next = 3;
22
+ _context.next = 1;
23
23
  return getOrientation(value);
24
- case 3:
24
+ case 1:
25
25
  orientation = _context.sent;
26
26
  dataURI = URL.createObjectURL(value);
27
27
  return _context.abrupt("return", {
@@ -29,15 +29,15 @@ var getImageLocalPreview = /*#__PURE__*/function () {
29
29
  orientation: orientation,
30
30
  source: 'local'
31
31
  });
32
- case 8:
33
- _context.prev = 8;
34
- _context.t0 = _context["catch"](0);
35
- throw new LocalPreviewError('local-preview-image', _context.t0 instanceof Error ? _context.t0 : undefined);
36
- case 11:
32
+ case 2:
33
+ _context.prev = 2;
34
+ _t = _context["catch"](0);
35
+ throw new LocalPreviewError('local-preview-image', _t instanceof Error ? _t : undefined);
36
+ case 3:
37
37
  case "end":
38
38
  return _context.stop();
39
39
  }
40
- }, _callee, null, [[0, 8]]);
40
+ }, _callee, null, [[0, 2]]);
41
41
  }));
42
42
  return function getImageLocalPreview(_x) {
43
43
  return _ref.apply(this, arguments);
@@ -45,29 +45,29 @@ var getImageLocalPreview = /*#__PURE__*/function () {
45
45
  }();
46
46
  var getVideoLocalPreview = /*#__PURE__*/function () {
47
47
  var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(value) {
48
- var dataURI;
49
- return _regeneratorRuntime.wrap(function _callee2$(_context2) {
48
+ var dataURI, _t2;
49
+ return _regeneratorRuntime.wrap(function (_context2) {
50
50
  while (1) switch (_context2.prev = _context2.next) {
51
51
  case 0:
52
52
  _context2.prev = 0;
53
- _context2.next = 3;
53
+ _context2.next = 1;
54
54
  return takeSnapshot(value);
55
- case 3:
55
+ case 1:
56
56
  dataURI = _context2.sent;
57
57
  return _context2.abrupt("return", {
58
58
  dataURI: dataURI,
59
59
  orientation: 1,
60
60
  source: 'local'
61
61
  });
62
- case 7:
63
- _context2.prev = 7;
64
- _context2.t0 = _context2["catch"](0);
65
- throw new LocalPreviewError('local-preview-video', _context2.t0 instanceof Error ? _context2.t0 : undefined);
66
- case 10:
62
+ case 2:
63
+ _context2.prev = 2;
64
+ _t2 = _context2["catch"](0);
65
+ throw new LocalPreviewError('local-preview-video', _t2 instanceof Error ? _t2 : undefined);
66
+ case 3:
67
67
  case "end":
68
68
  return _context2.stop();
69
69
  }
70
- }, _callee2, null, [[0, 7]]);
70
+ }, _callee2, null, [[0, 2]]);
71
71
  }));
72
72
  return function getVideoLocalPreview(_x2) {
73
73
  return _ref2.apply(this, arguments);
@@ -75,25 +75,25 @@ var getVideoLocalPreview = /*#__PURE__*/function () {
75
75
  }();
76
76
  export var getLocalPreview = /*#__PURE__*/function () {
77
77
  var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(filePreview) {
78
- var value, resolvedFilePreview, _value, type, mediaType;
79
- return _regeneratorRuntime.wrap(function _callee3$(_context3) {
78
+ var value, resolvedFilePreview, _value, type, mediaType, _t3, _t4;
79
+ return _regeneratorRuntime.wrap(function (_context3) {
80
80
  while (1) switch (_context3.prev = _context3.next) {
81
81
  case 0:
82
82
  _context3.prev = 0;
83
- _context3.next = 3;
83
+ _context3.next = 1;
84
84
  return filePreview;
85
- case 3:
85
+ case 1:
86
86
  resolvedFilePreview = _context3.sent;
87
87
  value = resolvedFilePreview.value;
88
- _context3.next = 10;
88
+ _context3.next = 3;
89
89
  break;
90
- case 7:
91
- _context3.prev = 7;
92
- _context3.t0 = _context3["catch"](0);
93
- throw new LocalPreviewError('local-preview-rejected', _context3.t0 instanceof Error ? _context3.t0 : undefined);
94
- case 10:
90
+ case 2:
91
+ _context3.prev = 2;
92
+ _t3 = _context3["catch"](0);
93
+ throw new LocalPreviewError('local-preview-rejected', _t3 instanceof Error ? _t3 : undefined);
94
+ case 3:
95
95
  if (!(typeof value === 'string')) {
96
- _context3.next = 14;
96
+ _context3.next = 4;
97
97
  break;
98
98
  }
99
99
  return _context3.abrupt("return", {
@@ -101,29 +101,29 @@ export var getLocalPreview = /*#__PURE__*/function () {
101
101
  orientation: 1,
102
102
  source: 'local'
103
103
  });
104
- case 14:
104
+ case 4:
105
105
  if (!(value instanceof Blob)) {
106
- _context3.next = 23;
106
+ _context3.next = 8;
107
107
  break;
108
108
  }
109
109
  _value = value, type = _value.type;
110
110
  mediaType = getMediaTypeFromMimeType(type);
111
- _context3.t1 = mediaType;
112
- _context3.next = _context3.t1 === 'image' ? 20 : _context3.t1 === 'video' ? 21 : 22;
111
+ _t4 = mediaType;
112
+ _context3.next = _t4 === 'image' ? 5 : _t4 === 'video' ? 6 : 7;
113
113
  break;
114
- case 20:
114
+ case 5:
115
115
  return _context3.abrupt("return", getImageLocalPreview(value));
116
- case 21:
116
+ case 6:
117
117
  return _context3.abrupt("return", getVideoLocalPreview(value));
118
- case 22:
118
+ case 7:
119
119
  throw new LocalPreviewError('local-preview-unsupported');
120
- case 23:
120
+ case 8:
121
121
  throw new LocalPreviewError('local-preview-unsupported');
122
- case 24:
122
+ case 9:
123
123
  case "end":
124
124
  return _context3.stop();
125
125
  }
126
- }, _callee3, null, [[0, 7]]);
126
+ }, _callee3, null, [[0, 2]]);
127
127
  }));
128
128
  return function getLocalPreview(_x3) {
129
129
  return _ref3.apply(this, arguments);
@@ -131,29 +131,29 @@ export var getLocalPreview = /*#__PURE__*/function () {
131
131
  }();
132
132
  export var getRemotePreview = /*#__PURE__*/function () {
133
133
  var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(mediaClient, id, params, traceContext) {
134
- var blob;
135
- return _regeneratorRuntime.wrap(function _callee4$(_context4) {
134
+ var blob, _t5;
135
+ return _regeneratorRuntime.wrap(function (_context4) {
136
136
  while (1) switch (_context4.prev = _context4.next) {
137
137
  case 0:
138
138
  _context4.prev = 0;
139
- _context4.next = 3;
139
+ _context4.next = 1;
140
140
  return mediaClient.getImage(id, params, undefined, undefined, traceContext);
141
- case 3:
141
+ case 1:
142
142
  blob = _context4.sent;
143
143
  return _context4.abrupt("return", {
144
144
  dataURI: URL.createObjectURL(blob),
145
145
  orientation: 1,
146
146
  source: 'remote'
147
147
  });
148
- case 7:
149
- _context4.prev = 7;
150
- _context4.t0 = _context4["catch"](0);
151
- throw new RemotePreviewError('remote-preview-fetch', _context4.t0 instanceof Error ? _context4.t0 : undefined);
152
- case 10:
148
+ case 2:
149
+ _context4.prev = 2;
150
+ _t5 = _context4["catch"](0);
151
+ throw new RemotePreviewError('remote-preview-fetch', _t5 instanceof Error ? _t5 : undefined);
152
+ case 3:
153
153
  case "end":
154
154
  return _context4.stop();
155
155
  }
156
- }, _callee4, null, [[0, 7]]);
156
+ }, _callee4, null, [[0, 2]]);
157
157
  }));
158
158
  return function getRemotePreview(_x4, _x5, _x6, _x7) {
159
159
  return _ref4.apply(this, arguments);
@@ -1,3 +1,3 @@
1
1
  export { mediaFilePreviewCache } from './cache';
2
- export { getSSRPreview, isLocalPreview, isRemotePreview, isSSRPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview } from './getPreview';
2
+ export { getSSRPreview, isLocalPreview, isRemotePreview, isSSRPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview, extractCdnSigningParams } from './getPreview';
3
3
  export { isSupportedLocalPreview } from './helpers';
@@ -2,7 +2,7 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
3
  export var takeSnapshot = /*#__PURE__*/function () {
4
4
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(blob) {
5
- return _regeneratorRuntime.wrap(function _callee$(_context) {
5
+ return _regeneratorRuntime.wrap(function (_context) {
6
6
  while (1) switch (_context.prev = _context.next) {
7
7
  case 0:
8
8
  return _context.abrupt("return", new Promise(function (resolve, reject) {
@@ -10,7 +10,7 @@ import { fg } from '@atlaskit/platform-feature-flags';
10
10
  import { useInteractionContext } from '@atlaskit/react-ufo/interaction-context';
11
11
  import { createFailedSSRObject, extractErrorInfo } from './analytics';
12
12
  import { ensureMediaFilePreviewError, ImageLoadError, MediaFilePreviewError } from './errors';
13
- import { getAndCacheLocalPreview, getAndCacheRemotePreview, getSSRPreview, isLocalPreview, isRemotePreview, isSSRClientPreview, isSSRDataPreview, isSSRPreview, isSupportedLocalPreview, mediaFilePreviewCache } from './getPreview';
13
+ import { extractCdnSigningParams, getAndCacheLocalPreview, getAndCacheRemotePreview, getSSRPreview, isLocalPreview, isRemotePreview, isSSRClientPreview, isSSRDataPreview, isSSRPreview, isSupportedLocalPreview, mediaFilePreviewCache } from './getPreview';
14
14
  import { generateScriptProps, getSSRData } from './globalScope';
15
15
  import { createRequestDimensions, isBigger, isWider, useCurrentValueRef } from './helpers';
16
16
  // invisible gif for SSR preview to show the underlying spinner until the src is replaced by
@@ -38,7 +38,8 @@ export var useFilePreview = function useFilePreview(_ref) {
38
38
  allowAnimated = _ref$allowAnimated === void 0 ? true : _ref$allowAnimated,
39
39
  upscale = _ref.upscale,
40
40
  maxAge = _ref.maxAge,
41
- source = _ref.source;
41
+ source = _ref.source,
42
+ initialFileState = _ref.initialFileState;
42
43
  var mediaClient = useMediaClient();
43
44
  var _useState = useState('loading'),
44
45
  _useState2 = _slicedToArray(_useState, 2),
@@ -115,7 +116,15 @@ export var useFilePreview = function useFilePreview(_ref) {
115
116
  // where no SSR occurred, so we should skip SSR preview generation entirely.
116
117
  if (ssr === 'server' || ssrData) {
117
118
  try {
118
- return getSSRPreview(ssr, mediaClient, identifier.id, imageURLParams, mediaBlobUrlAttrs);
119
+ // When the relay/SSR-seed path provided a pre-signed CDN URL,
120
+ // overlay its CDN-signing query params on the URL produced by
121
+ // getImageUrlSync. This makes the SSR-rendered HTML use the
122
+ // cdn-signed URL directly (no auth-token -> cdn-signed swap on
123
+ // hydration) and the 'ssr-data' rehydration path inherits it
124
+ // automatically via globalScope.
125
+ var seededCdnUrl = initialFileState && initialFileState.status !== 'error' ? initialFileState.previewCdnUrl : undefined;
126
+ var cdnSigningParams = seededCdnUrl && fg('platform_media_ssr_data_seed') ? extractCdnSigningParams(seededCdnUrl) : undefined;
127
+ return getSSRPreview(ssr, mediaClient, identifier.id, imageURLParams, mediaBlobUrlAttrs, cdnSigningParams);
119
128
  } catch (e) {
120
129
  ssrReliabilityRef.current = _objectSpread(_objectSpread({}, ssrReliabilityRef.current), {}, _defineProperty({}, ssr, _objectSpread({
121
130
  status: 'fail'
@@ -147,6 +156,7 @@ export var useFilePreview = function useFilePreview(_ref) {
147
156
  //----------------------------------------------------------------
148
157
 
149
158
  var _useFileState = useFileState(identifier.id, {
159
+ initialFileState: initialFileState,
150
160
  skipRemote: skipRemote,
151
161
  collectionName: identifier.collectionName,
152
162
  occurrenceKey: identifier.occurrenceKey
@@ -1,7 +1,18 @@
1
1
  import { type FilePreview, type MediaBlobUrlAttrs, type MediaClient, type MediaStoreGetFileImageParams } from '@atlaskit/media-client';
2
2
  import { type MediaTraceContext, type SSR } from '@atlaskit/media-common';
3
3
  import { type MediaFilePreview, type MediaFilePreviewDimensions } from '../types';
4
- export declare const getSSRPreview: (ssr: SSR, mediaClient: MediaClient, id: string, params: MediaStoreGetFileImageParams, mediaBlobUrlAttrs?: MediaBlobUrlAttrs) => MediaFilePreview;
4
+ /**
5
+ * Pull the CDN-signing query params (token / Policy / Key-Pair-Id / Signature
6
+ * / Expires) out of a pre-signed CDN URL so they can be overlaid on a URL
7
+ * built independently by `getImageUrlSync` (which constructs path, image
8
+ * params, pathBased routing, wmv, etc.). Image-shape params from the cdn URL
9
+ * itself (width/height/mode/...) are intentionally NOT extracted — those come
10
+ * from `imageURLParams` via `getImageUrlSync`.
11
+ *
12
+ * Returns `{}` on parse failure so we degrade rather than throw.
13
+ */
14
+ export declare const extractCdnSigningParams: (cdnUrl: string) => Record<string, string>;
15
+ export declare const getSSRPreview: (ssr: SSR, mediaClient: MediaClient, id: string, params: MediaStoreGetFileImageParams, mediaBlobUrlAttrs?: MediaBlobUrlAttrs, cdnSigningParams?: Record<string, string>) => MediaFilePreview;
5
16
  export declare const isLocalPreview: (preview: MediaFilePreview) => boolean;
6
17
  export declare const isRemotePreview: (preview: MediaFilePreview) => boolean;
7
18
  export declare const isSSRClientPreview: (preview: MediaFilePreview) => boolean;
@@ -1,3 +1,3 @@
1
1
  export { mediaFilePreviewCache } from './cache';
2
- export { getSSRPreview, isLocalPreview, isRemotePreview, isSSRPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview, } from './getPreview';
2
+ export { getSSRPreview, isLocalPreview, isRemotePreview, isSSRPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview, extractCdnSigningParams, } from './getPreview';
3
3
  export { isSupportedLocalPreview } from './helpers';
@@ -1,5 +1,5 @@
1
1
  import { type DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES, type ScriptHTMLAttributes } from 'react';
2
- import { type FileIdentifier, type MediaBlobUrlAttrs, type MediaStoreGetFileImageParams } from '@atlaskit/media-client';
2
+ import { type FileIdentifier, type FileState, type MediaBlobUrlAttrs, type MediaStoreGetFileImageParams } from '@atlaskit/media-client';
3
3
  import { type MediaTraceContext, type SSR } from '@atlaskit/media-common';
4
4
  import { type SSRStatus } from './analytics';
5
5
  import { MediaFilePreviewError } from './errors';
@@ -30,8 +30,10 @@ export interface UseFilePreviewParams {
30
30
  readonly maxAge?: number;
31
31
  /** Defines the source component */
32
32
  readonly source?: string;
33
+ /** Initial file state to be used for the preview. */
34
+ readonly initialFileState?: FileState;
33
35
  }
34
- export declare const useFilePreview: ({ resizeMode, identifier, ssr, dimensions, useSrcSet, traceContext, skipRemote, mediaBlobUrlAttrs, allowAnimated, upscale, maxAge, source, }: UseFilePreviewParams) => {
36
+ export declare const useFilePreview: ({ resizeMode, identifier, ssr, dimensions, useSrcSet, traceContext, skipRemote, mediaBlobUrlAttrs, allowAnimated, upscale, maxAge, source, initialFileState, }: UseFilePreviewParams) => {
35
37
  preview: MediaFilePreview | undefined;
36
38
  status: MediaFilePreviewStatus;
37
39
  error: MediaFilePreviewError | undefined;
@@ -1,7 +1,18 @@
1
1
  import { type FilePreview, type MediaBlobUrlAttrs, type MediaClient, type MediaStoreGetFileImageParams } from '@atlaskit/media-client';
2
2
  import { type MediaTraceContext, type SSR } from '@atlaskit/media-common';
3
3
  import { type MediaFilePreview, type MediaFilePreviewDimensions } from '../types';
4
- export declare const getSSRPreview: (ssr: SSR, mediaClient: MediaClient, id: string, params: MediaStoreGetFileImageParams, mediaBlobUrlAttrs?: MediaBlobUrlAttrs) => MediaFilePreview;
4
+ /**
5
+ * Pull the CDN-signing query params (token / Policy / Key-Pair-Id / Signature
6
+ * / Expires) out of a pre-signed CDN URL so they can be overlaid on a URL
7
+ * built independently by `getImageUrlSync` (which constructs path, image
8
+ * params, pathBased routing, wmv, etc.). Image-shape params from the cdn URL
9
+ * itself (width/height/mode/...) are intentionally NOT extracted — those come
10
+ * from `imageURLParams` via `getImageUrlSync`.
11
+ *
12
+ * Returns `{}` on parse failure so we degrade rather than throw.
13
+ */
14
+ export declare const extractCdnSigningParams: (cdnUrl: string) => Record<string, string>;
15
+ export declare const getSSRPreview: (ssr: SSR, mediaClient: MediaClient, id: string, params: MediaStoreGetFileImageParams, mediaBlobUrlAttrs?: MediaBlobUrlAttrs, cdnSigningParams?: Record<string, string>) => MediaFilePreview;
5
16
  export declare const isLocalPreview: (preview: MediaFilePreview) => boolean;
6
17
  export declare const isRemotePreview: (preview: MediaFilePreview) => boolean;
7
18
  export declare const isSSRClientPreview: (preview: MediaFilePreview) => boolean;
@@ -1,3 +1,3 @@
1
1
  export { mediaFilePreviewCache } from './cache';
2
- export { getSSRPreview, isLocalPreview, isRemotePreview, isSSRPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview, } from './getPreview';
2
+ export { getSSRPreview, isLocalPreview, isRemotePreview, isSSRPreview, isSSRClientPreview, isSSRDataPreview, getAndCacheRemotePreview, getAndCacheLocalPreview, extractCdnSigningParams, } from './getPreview';
3
3
  export { isSupportedLocalPreview } from './helpers';
@@ -1,5 +1,5 @@
1
1
  import { type DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES, type ScriptHTMLAttributes } from 'react';
2
- import { type FileIdentifier, type MediaBlobUrlAttrs, type MediaStoreGetFileImageParams } from '@atlaskit/media-client';
2
+ import { type FileIdentifier, type FileState, type MediaBlobUrlAttrs, type MediaStoreGetFileImageParams } from '@atlaskit/media-client';
3
3
  import { type MediaTraceContext, type SSR } from '@atlaskit/media-common';
4
4
  import { type SSRStatus } from './analytics';
5
5
  import { MediaFilePreviewError } from './errors';
@@ -30,8 +30,10 @@ export interface UseFilePreviewParams {
30
30
  readonly maxAge?: number;
31
31
  /** Defines the source component */
32
32
  readonly source?: string;
33
+ /** Initial file state to be used for the preview. */
34
+ readonly initialFileState?: FileState;
33
35
  }
34
- export declare const useFilePreview: ({ resizeMode, identifier, ssr, dimensions, useSrcSet, traceContext, skipRemote, mediaBlobUrlAttrs, allowAnimated, upscale, maxAge, source, }: UseFilePreviewParams) => {
36
+ export declare const useFilePreview: ({ resizeMode, identifier, ssr, dimensions, useSrcSet, traceContext, skipRemote, mediaBlobUrlAttrs, allowAnimated, upscale, maxAge, source, initialFileState, }: UseFilePreviewParams) => {
35
37
  preview: MediaFilePreview | undefined;
36
38
  status: MediaFilePreviewStatus;
37
39
  error: MediaFilePreviewError | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/media-file-preview",
3
- "version": "0.17.1",
3
+ "version": "0.18.0",
4
4
  "description": "A React Hook to fetch and render file previews. It's overloaded with fancy features like SSR, lazy loading, memory cache and local preview.",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -37,12 +37,12 @@
37
37
  "sideEffects": false,
38
38
  "atlaskit:src": "src/index.ts",
39
39
  "dependencies": {
40
- "@atlaskit/media-client": "^36.2.0",
41
- "@atlaskit/media-client-react": "^5.1.0",
40
+ "@atlaskit/media-client": "^36.3.0",
41
+ "@atlaskit/media-client-react": "^5.2.0",
42
42
  "@atlaskit/media-common": "^13.3.0",
43
- "@atlaskit/media-ui": "^29.2.0",
43
+ "@atlaskit/media-ui": "^29.3.0",
44
44
  "@atlaskit/platform-feature-flags": "^1.1.0",
45
- "@atlaskit/react-ufo": "^5.19.0",
45
+ "@atlaskit/react-ufo": "^6.5.0",
46
46
  "@babel/runtime": "^7.0.0",
47
47
  "lru_map": "^0.4.1"
48
48
  },
@@ -53,14 +53,16 @@
53
53
  "devDependencies": {
54
54
  "@af/integration-testing": "workspace:^",
55
55
  "@af/visual-regression": "workspace:^",
56
- "@atlaskit/media-state": "^2.1.0",
56
+ "@atlaskit/media-state": "^2.2.0",
57
57
  "@atlaskit/media-test-data": "^3.3.0",
58
- "@atlaskit/section-message": "^8.12.0",
58
+ "@atlaskit/section-message": "^8.13.0",
59
59
  "@atlaskit/ssr": "workspace:^",
60
60
  "@atlassian/a11y-jest-testing": "^0.11.0",
61
61
  "@atlassian/feature-flags-test-utils": "^1.1.0",
62
62
  "@atlassian/react-compiler-gating": "workspace:^",
63
+ "@atlassian/testing-library": "^0.6.0",
63
64
  "@testing-library/react": "^16.3.0",
65
+ "react": "^18.2.0",
64
66
  "react-dom": "^18.2.0",
65
67
  "wait-for-expect": "^1.2.0"
66
68
  },
@@ -114,6 +116,9 @@
114
116
  },
115
117
  "platform_media_safe_blob_url_eviction": {
116
118
  "type": "boolean"
119
+ },
120
+ "platform_media_ssr_data_seed": {
121
+ "type": "boolean"
117
122
  }
118
123
  }
119
124
  }