@atlaskit/editor-synced-block-provider 4.4.3 → 4.5.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 4.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 4.5.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`81ae8b16d6c35`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/81ae8b16d6c35) -
14
+ [ux] Allows reference sync blocks with media load it correctly in Confluence when source sync
15
+ block is in Jira.
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies
20
+
3
21
  ## 4.4.3
4
22
 
5
23
  ### Patch Changes
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.fetchJiraMediaToken = void 0;
8
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
11
+ var _monitoring = require("@atlaskit/editor-common/monitoring");
12
+ var _retry = require("../../utils/retry");
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
+ 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
+ var COMMON_HEADERS = {
16
+ 'Content-Type': 'application/json',
17
+ Accept: 'application/json'
18
+ };
19
+ var AGG_HEADERS = {
20
+ 'X-ExperimentalApi': 'confluence-agg-beta'
21
+ };
22
+ var GRAPHQL_ENDPOINT = '/gateway/api/graphql';
23
+ var JIRA_MEDIA_READ_TOKEN_MAX_TOKEN_LENGTH = 2048;
24
+ var GET_JIRA_MEDIA_READ_TOKEN_OPERATION_NAME = 'EDITOR_SYNCED_BLOCK_GET_JIRA_MEDIA_TOKEN';
25
+ var GET_JIRA_MEDIA_READ_TOKEN_QUERY = "query ".concat(GET_JIRA_MEDIA_READ_TOKEN_OPERATION_NAME, "($issueAri: ID!, $maxTokenLength: Int!) {\n jira {\n issueById(id: $issueAri) {\n mediaReadToken(maxTokenLength: $maxTokenLength) @optIn(to: \"JiraMediaReadTokenInIssue\") {\n clientId\n endpointUrl\n tokenLifespanInSeconds\n tokensWithFiles {\n edges {\n node {\n token\n }\n }\n }\n }\n }\n }\n}");
26
+ var getJiraMediaReadToken = /*#__PURE__*/function () {
27
+ var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(issueAri) {
28
+ var bodyData, response;
29
+ return _regenerator.default.wrap(function _callee$(_context) {
30
+ while (1) switch (_context.prev = _context.next) {
31
+ case 0:
32
+ bodyData = {
33
+ query: GET_JIRA_MEDIA_READ_TOKEN_QUERY,
34
+ operationName: GET_JIRA_MEDIA_READ_TOKEN_OPERATION_NAME,
35
+ variables: {
36
+ issueAri: issueAri,
37
+ maxTokenLength: JIRA_MEDIA_READ_TOKEN_MAX_TOKEN_LENGTH
38
+ }
39
+ };
40
+ _context.next = 3;
41
+ return (0, _retry.fetchWithRetry)(GRAPHQL_ENDPOINT, {
42
+ method: 'POST',
43
+ headers: _objectSpread(_objectSpread({}, COMMON_HEADERS), AGG_HEADERS),
44
+ body: JSON.stringify(bodyData)
45
+ });
46
+ case 3:
47
+ response = _context.sent;
48
+ if (response.ok) {
49
+ _context.next = 6;
50
+ break;
51
+ }
52
+ throw new Error("Failed to get Jira media read token: ".concat(response.statusText));
53
+ case 6:
54
+ _context.next = 8;
55
+ return response.json();
56
+ case 8:
57
+ return _context.abrupt("return", _context.sent);
58
+ case 9:
59
+ case "end":
60
+ return _context.stop();
61
+ }
62
+ }, _callee);
63
+ }));
64
+ return function getJiraMediaReadToken(_x) {
65
+ return _ref.apply(this, arguments);
66
+ };
67
+ }();
68
+
69
+ /**
70
+ * Fetches a media read token for a Jira issue, to allow media uploaded to Jira
71
+ * to be rendered in cross-product synced block references (e.g. in Confluence).
72
+ *
73
+ * @param issueAri - the Jira issue ARI (e.g. ari:cloud:jira:{cloudId}:issue/{issueId})
74
+ * @returns TokenData with token, config (clientId + fileStoreUrl), and optional collectionId
75
+ */
76
+ var fetchJiraMediaToken = exports.fetchJiraMediaToken = /*#__PURE__*/function () {
77
+ var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(issueAri) {
78
+ var _response$data, _mediaReadToken$token, _mediaReadToken$token2, response, mediaReadToken, clientId, endpointUrl, token, errorMsg;
79
+ return _regenerator.default.wrap(function _callee2$(_context2) {
80
+ while (1) switch (_context2.prev = _context2.next) {
81
+ case 0:
82
+ _context2.prev = 0;
83
+ _context2.next = 3;
84
+ return getJiraMediaReadToken(issueAri);
85
+ case 3:
86
+ response = _context2.sent;
87
+ mediaReadToken = (_response$data = response.data) === null || _response$data === void 0 || (_response$data = _response$data.jira) === null || _response$data === void 0 || (_response$data = _response$data.issueById) === null || _response$data === void 0 ? void 0 : _response$data.mediaReadToken;
88
+ clientId = mediaReadToken === null || mediaReadToken === void 0 ? void 0 : mediaReadToken.clientId;
89
+ endpointUrl = mediaReadToken === null || mediaReadToken === void 0 ? void 0 : mediaReadToken.endpointUrl; // Use the first available token from tokensWithFiles, or fall back to empty string.
90
+ // A generic read token (without specific file IDs) is sufficient for rendering.
91
+ token = (_mediaReadToken$token = mediaReadToken === null || mediaReadToken === void 0 || (_mediaReadToken$token2 = mediaReadToken.tokensWithFiles) === null || _mediaReadToken$token2 === void 0 || (_mediaReadToken$token2 = _mediaReadToken$token2.edges) === null || _mediaReadToken$token2 === void 0 || (_mediaReadToken$token2 = _mediaReadToken$token2[0]) === null || _mediaReadToken$token2 === void 0 || (_mediaReadToken$token2 = _mediaReadToken$token2.node) === null || _mediaReadToken$token2 === void 0 ? void 0 : _mediaReadToken$token2.token) !== null && _mediaReadToken$token !== void 0 ? _mediaReadToken$token : '';
92
+ if (!(!clientId || !endpointUrl)) {
93
+ _context2.next = 10;
94
+ break;
95
+ }
96
+ throw new Error('Missing clientId or endpointUrl');
97
+ case 10:
98
+ return _context2.abrupt("return", {
99
+ config: {
100
+ clientId: clientId,
101
+ fileStoreUrl: endpointUrl
102
+ },
103
+ token: token
104
+ });
105
+ case 13:
106
+ _context2.prev = 13;
107
+ _context2.t0 = _context2["catch"](0);
108
+ (0, _monitoring.logException)(_context2.t0, {
109
+ location: 'editor-synced-block-provider/fetchJiraMediaToken'
110
+ });
111
+ errorMsg = _context2.t0 instanceof Error ? _context2.t0.message : String(_context2.t0);
112
+ throw new Error("Failed to get Jira media read token: ".concat(errorMsg));
113
+ case 18:
114
+ case "end":
115
+ return _context2.stop();
116
+ }
117
+ }, _callee2, null, [[0, 13]]);
118
+ }));
119
+ return function fetchJiraMediaToken(_x2) {
120
+ return _ref2.apply(this, arguments);
121
+ };
122
+ }();
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.requiresCrossProductAuth = exports.fetchTokenForSourceProduct = void 0;
7
+ var _fetchMediaToken = require("./confluence/fetchMediaToken");
8
+ var _fetchMediaToken2 = require("./jira/fetchMediaToken");
9
+ var requiresCrossProductAuth = exports.requiresCrossProductAuth = function requiresCrossProductAuth(_ref) {
10
+ var hostProduct = _ref.hostProduct,
11
+ sourceProduct = _ref.sourceProduct;
12
+ return !!sourceProduct && sourceProduct !== hostProduct;
13
+ };
14
+ var fetchTokenForSourceProduct = exports.fetchTokenForSourceProduct = function fetchTokenForSourceProduct(_ref2) {
15
+ var contentId = _ref2.contentId,
16
+ sourceProduct = _ref2.sourceProduct;
17
+ switch (sourceProduct) {
18
+ case 'confluence-page':
19
+ return (0, _fetchMediaToken.fetchMediaToken)(contentId);
20
+ case 'jira-work-item':
21
+ return (0, _fetchMediaToken2.fetchJiraMediaToken)(contentId);
22
+ default:
23
+ throw new Error("Unsupported source product for token fetch: ".concat(sourceProduct));
24
+ }
25
+ };
@@ -313,13 +313,14 @@ var SyncedBlockProvider = exports.SyncedBlockProvider = /*#__PURE__*/function (_
313
313
  key: "fetchSyncBlockSourceInfo",
314
314
  value: (function () {
315
315
  var _fetchSyncBlockSourceInfo = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(localId, sourceAri, sourceProduct) {
316
- var _this$writeProvider, _this$writeProvider3;
316
+ var _this$writeProvider;
317
317
  var hasAccess,
318
318
  ari,
319
319
  product,
320
320
  _this$writeProvider2,
321
- _sourceInfo,
322
321
  sourceInfo,
322
+ _this$writeProvider3,
323
+ _sourceInfo,
323
324
  _args4 = arguments;
324
325
  return _regenerator.default.wrap(function _callee4$(_context4) {
325
326
  while (1) switch (_context4.prev = _context4.next) {
@@ -340,14 +341,14 @@ var SyncedBlockProvider = exports.SyncedBlockProvider = /*#__PURE__*/function (_
340
341
  _context4.next = 10;
341
342
  return (0, _sourceInfo2.fetchConfluencePageInfo)(ari, hasAccess, localId);
342
343
  case 10:
343
- _sourceInfo = _context4.sent;
344
- if (_sourceInfo) {
344
+ sourceInfo = _context4.sent;
345
+ if (sourceInfo) {
345
346
  _context4.next = 13;
346
347
  break;
347
348
  }
348
349
  return _context4.abrupt("return", Promise.resolve(undefined));
349
350
  case 13:
350
- return _context4.abrupt("return", _objectSpread(_objectSpread({}, _sourceInfo), {}, {
351
+ return _context4.abrupt("return", _objectSpread(_objectSpread({}, sourceInfo), {}, {
351
352
  onSameDocument: ((_this$writeProvider2 = this.writeProvider) === null || _this$writeProvider2 === void 0 ? void 0 : _this$writeProvider2.parentAri) === ari,
352
353
  productType: product
353
354
  }));
@@ -355,14 +356,14 @@ var SyncedBlockProvider = exports.SyncedBlockProvider = /*#__PURE__*/function (_
355
356
  _context4.next = 16;
356
357
  return (0, _sourceInfo3.fetchJiraWorkItemInfo)(ari, hasAccess);
357
358
  case 16:
358
- sourceInfo = _context4.sent;
359
- if (sourceInfo) {
359
+ _sourceInfo = _context4.sent;
360
+ if (_sourceInfo) {
360
361
  _context4.next = 19;
361
362
  break;
362
363
  }
363
364
  return _context4.abrupt("return", Promise.resolve(undefined));
364
365
  case 19:
365
- return _context4.abrupt("return", _objectSpread(_objectSpread({}, sourceInfo), {}, {
366
+ return _context4.abrupt("return", _objectSpread(_objectSpread({}, _sourceInfo), {}, {
366
367
  onSameDocument: ((_this$writeProvider3 = this.writeProvider) === null || _this$writeProvider3 === void 0 ? void 0 : _this$writeProvider3.parentAri) === ari,
367
368
  productType: product
368
369
  }));
@@ -432,7 +433,10 @@ var SyncedBlockProvider = exports.SyncedBlockProvider = /*#__PURE__*/function (_
432
433
  contentProduct: sourceProduct
433
434
  };
434
435
  case 'jira-work-item':
435
- throw new Error('Jira work item source product not supported');
436
+ return {
437
+ contentId: sourceAri,
438
+ contentProduct: sourceProduct
439
+ };
436
440
  default:
437
441
  throw new Error("".concat(sourceProduct, " source product not supported"));
438
442
  }
@@ -73,6 +73,7 @@ var SyncBlockProviderFactoryManager = exports.SyncBlockProviderFactoryManager =
73
73
  }, {
74
74
  key: "getSSRProviders",
75
75
  value: function getSSRProviders(resourceId) {
76
+ var _syncBlock$data;
76
77
  var dataProvider = this.deps.getDataProvider();
77
78
  if (!dataProvider) {
78
79
  return null;
@@ -88,6 +89,14 @@ var SyncBlockProviderFactoryManager = exports.SyncBlockProviderFactoryManager =
88
89
  }
89
90
  var contentId = parsedResourceId.contentId,
90
91
  contentProduct = parsedResourceId.product;
92
+ var syncBlock = this.deps.getFromCache(resourceId);
93
+ if (syncBlock !== null && syncBlock !== void 0 && (_syncBlock$data = syncBlock.data) !== null && _syncBlock$data !== void 0 && _syncBlock$data.sourceAri && syncBlock.data.product) {
94
+ var parentInfo = dataProvider.retrieveSyncBlockParentInfo(syncBlock.data.sourceAri, syncBlock.data.product);
95
+ if (parentInfo) {
96
+ contentId = parentInfo.contentId;
97
+ contentProduct = parentInfo.contentProduct;
98
+ }
99
+ }
91
100
  try {
92
101
  var mediaProvider = providerCreator.createSSRMediaProvider({
93
102
  contentId: contentId,
@@ -0,0 +1,89 @@
1
+ import { logException } from '@atlaskit/editor-common/monitoring';
2
+ import { fetchWithRetry } from '../../utils/retry';
3
+ const COMMON_HEADERS = {
4
+ 'Content-Type': 'application/json',
5
+ Accept: 'application/json'
6
+ };
7
+ const AGG_HEADERS = {
8
+ 'X-ExperimentalApi': 'confluence-agg-beta'
9
+ };
10
+ const GRAPHQL_ENDPOINT = '/gateway/api/graphql';
11
+ const JIRA_MEDIA_READ_TOKEN_MAX_TOKEN_LENGTH = 2048;
12
+ const GET_JIRA_MEDIA_READ_TOKEN_OPERATION_NAME = 'EDITOR_SYNCED_BLOCK_GET_JIRA_MEDIA_TOKEN';
13
+ const GET_JIRA_MEDIA_READ_TOKEN_QUERY = `query ${GET_JIRA_MEDIA_READ_TOKEN_OPERATION_NAME}($issueAri: ID!, $maxTokenLength: Int!) {
14
+ jira {
15
+ issueById(id: $issueAri) {
16
+ mediaReadToken(maxTokenLength: $maxTokenLength) @optIn(to: "JiraMediaReadTokenInIssue") {
17
+ clientId
18
+ endpointUrl
19
+ tokenLifespanInSeconds
20
+ tokensWithFiles {
21
+ edges {
22
+ node {
23
+ token
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
30
+ }`;
31
+ const getJiraMediaReadToken = async issueAri => {
32
+ const bodyData = {
33
+ query: GET_JIRA_MEDIA_READ_TOKEN_QUERY,
34
+ operationName: GET_JIRA_MEDIA_READ_TOKEN_OPERATION_NAME,
35
+ variables: {
36
+ issueAri,
37
+ maxTokenLength: JIRA_MEDIA_READ_TOKEN_MAX_TOKEN_LENGTH
38
+ }
39
+ };
40
+ const response = await fetchWithRetry(GRAPHQL_ENDPOINT, {
41
+ method: 'POST',
42
+ headers: {
43
+ ...COMMON_HEADERS,
44
+ ...AGG_HEADERS
45
+ },
46
+ body: JSON.stringify(bodyData)
47
+ });
48
+ if (!response.ok) {
49
+ throw new Error(`Failed to get Jira media read token: ${response.statusText}`);
50
+ }
51
+ return await response.json();
52
+ };
53
+
54
+ /**
55
+ * Fetches a media read token for a Jira issue, to allow media uploaded to Jira
56
+ * to be rendered in cross-product synced block references (e.g. in Confluence).
57
+ *
58
+ * @param issueAri - the Jira issue ARI (e.g. ari:cloud:jira:{cloudId}:issue/{issueId})
59
+ * @returns TokenData with token, config (clientId + fileStoreUrl), and optional collectionId
60
+ */
61
+ export const fetchJiraMediaToken = async issueAri => {
62
+ try {
63
+ var _response$data, _response$data$jira, _response$data$jira$i, _mediaReadToken$token, _mediaReadToken$token2, _mediaReadToken$token3, _mediaReadToken$token4, _mediaReadToken$token5;
64
+ const response = await getJiraMediaReadToken(issueAri);
65
+ const mediaReadToken = (_response$data = response.data) === null || _response$data === void 0 ? void 0 : (_response$data$jira = _response$data.jira) === null || _response$data$jira === void 0 ? void 0 : (_response$data$jira$i = _response$data$jira.issueById) === null || _response$data$jira$i === void 0 ? void 0 : _response$data$jira$i.mediaReadToken;
66
+ const clientId = mediaReadToken === null || mediaReadToken === void 0 ? void 0 : mediaReadToken.clientId;
67
+ const endpointUrl = mediaReadToken === null || mediaReadToken === void 0 ? void 0 : mediaReadToken.endpointUrl;
68
+
69
+ // Use the first available token from tokensWithFiles, or fall back to empty string.
70
+ // A generic read token (without specific file IDs) is sufficient for rendering.
71
+ const token = (_mediaReadToken$token = mediaReadToken === null || mediaReadToken === void 0 ? void 0 : (_mediaReadToken$token2 = mediaReadToken.tokensWithFiles) === null || _mediaReadToken$token2 === void 0 ? void 0 : (_mediaReadToken$token3 = _mediaReadToken$token2.edges) === null || _mediaReadToken$token3 === void 0 ? void 0 : (_mediaReadToken$token4 = _mediaReadToken$token3[0]) === null || _mediaReadToken$token4 === void 0 ? void 0 : (_mediaReadToken$token5 = _mediaReadToken$token4.node) === null || _mediaReadToken$token5 === void 0 ? void 0 : _mediaReadToken$token5.token) !== null && _mediaReadToken$token !== void 0 ? _mediaReadToken$token : '';
72
+ if (!clientId || !endpointUrl) {
73
+ throw new Error('Missing clientId or endpointUrl');
74
+ }
75
+ return {
76
+ config: {
77
+ clientId,
78
+ fileStoreUrl: endpointUrl
79
+ },
80
+ token
81
+ };
82
+ } catch (error) {
83
+ logException(error, {
84
+ location: 'editor-synced-block-provider/fetchJiraMediaToken'
85
+ });
86
+ const errorMsg = error instanceof Error ? error.message : String(error);
87
+ throw new Error(`Failed to get Jira media read token: ${errorMsg}`);
88
+ }
89
+ };
@@ -0,0 +1,21 @@
1
+ import { fetchMediaToken } from './confluence/fetchMediaToken';
2
+ import { fetchJiraMediaToken } from './jira/fetchMediaToken';
3
+ export const requiresCrossProductAuth = ({
4
+ hostProduct,
5
+ sourceProduct
6
+ }) => {
7
+ return !!sourceProduct && sourceProduct !== hostProduct;
8
+ };
9
+ export const fetchTokenForSourceProduct = ({
10
+ contentId,
11
+ sourceProduct
12
+ }) => {
13
+ switch (sourceProduct) {
14
+ case 'confluence-page':
15
+ return fetchMediaToken(contentId);
16
+ case 'jira-work-item':
17
+ return fetchJiraMediaToken(contentId);
18
+ default:
19
+ throw new Error(`Unsupported source product for token fetch: ${sourceProduct}`);
20
+ }
21
+ };
@@ -195,7 +195,7 @@ export class SyncedBlockProvider extends SyncBlockDataProviderInterface {
195
195
  * @returns The source info
196
196
  */
197
197
  async fetchSyncBlockSourceInfo(localId, sourceAri, sourceProduct, hasAccess = true) {
198
- var _this$writeProvider2, _this$writeProvider4;
198
+ var _this$writeProvider2;
199
199
  const ari = sourceAri !== null && sourceAri !== void 0 ? sourceAri : (_this$writeProvider2 = this.writeProvider) === null || _this$writeProvider2 === void 0 ? void 0 : _this$writeProvider2.parentAri;
200
200
  const product = sourceProduct !== null && sourceProduct !== void 0 ? sourceProduct : getProductFromSourceAri(ari);
201
201
  if (!ari || !product) {
@@ -216,15 +216,22 @@ export class SyncedBlockProvider extends SyncBlockDataProviderInterface {
216
216
  };
217
217
  }
218
218
  case 'jira-work-item':
219
- const sourceInfo = await fetchJiraWorkItemInfo(ari, hasAccess);
220
- if (!sourceInfo) {
221
- return Promise.resolve(undefined);
219
+ {
220
+ var _this$writeProvider4;
221
+ // Note: `subType`, archived URL handling, and `isUnpublished` are intentionally
222
+ // omitted here — Jira work items have no equivalent page subtype or archived state.
223
+ // The `localId` param is not forwarded because deep-linking to a specific block
224
+ // within a Jira issue description is working as intended without it.
225
+ const sourceInfo = await fetchJiraWorkItemInfo(ari, hasAccess);
226
+ if (!sourceInfo) {
227
+ return Promise.resolve(undefined);
228
+ }
229
+ return {
230
+ ...sourceInfo,
231
+ onSameDocument: ((_this$writeProvider4 = this.writeProvider) === null || _this$writeProvider4 === void 0 ? void 0 : _this$writeProvider4.parentAri) === ari,
232
+ productType: product
233
+ };
222
234
  }
223
- return {
224
- ...sourceInfo,
225
- onSameDocument: ((_this$writeProvider4 = this.writeProvider) === null || _this$writeProvider4 === void 0 ? void 0 : _this$writeProvider4.parentAri) === ari,
226
- productType: product
227
- };
228
235
  default:
229
236
  return Promise.reject(new Error(`${product} source product not supported`));
230
237
  }
@@ -274,7 +281,10 @@ export class SyncedBlockProvider extends SyncBlockDataProviderInterface {
274
281
  contentProduct: sourceProduct
275
282
  };
276
283
  case 'jira-work-item':
277
- throw new Error('Jira work item source product not supported');
284
+ return {
285
+ contentId: sourceAri,
286
+ contentProduct: sourceProduct
287
+ };
278
288
  default:
279
289
  throw new Error(`${sourceProduct} source product not supported`);
280
290
  }
@@ -60,6 +60,7 @@ export class SyncBlockProviderFactoryManager {
60
60
  return providerFactory;
61
61
  }
62
62
  getSSRProviders(resourceId) {
63
+ var _syncBlock$data;
63
64
  const dataProvider = this.deps.getDataProvider();
64
65
  if (!dataProvider) {
65
66
  return null;
@@ -74,10 +75,18 @@ export class SyncBlockProviderFactoryManager {
74
75
  if (!parsedResourceId) {
75
76
  return null;
76
77
  }
77
- const {
78
+ let {
78
79
  contentId,
79
80
  product: contentProduct
80
81
  } = parsedResourceId;
82
+ const syncBlock = this.deps.getFromCache(resourceId);
83
+ if (syncBlock !== null && syncBlock !== void 0 && (_syncBlock$data = syncBlock.data) !== null && _syncBlock$data !== void 0 && _syncBlock$data.sourceAri && syncBlock.data.product) {
84
+ const parentInfo = dataProvider.retrieveSyncBlockParentInfo(syncBlock.data.sourceAri, syncBlock.data.product);
85
+ if (parentInfo) {
86
+ contentId = parentInfo.contentId;
87
+ contentProduct = parentInfo.contentProduct;
88
+ }
89
+ }
81
90
  try {
82
91
  const mediaProvider = providerCreator.createSSRMediaProvider({
83
92
  contentId,
@@ -0,0 +1,115 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
3
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
4
+ 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; }
5
+ 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) { _defineProperty(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; }
6
+ import { logException } from '@atlaskit/editor-common/monitoring';
7
+ import { fetchWithRetry } from '../../utils/retry';
8
+ var COMMON_HEADERS = {
9
+ 'Content-Type': 'application/json',
10
+ Accept: 'application/json'
11
+ };
12
+ var AGG_HEADERS = {
13
+ 'X-ExperimentalApi': 'confluence-agg-beta'
14
+ };
15
+ var GRAPHQL_ENDPOINT = '/gateway/api/graphql';
16
+ var JIRA_MEDIA_READ_TOKEN_MAX_TOKEN_LENGTH = 2048;
17
+ var GET_JIRA_MEDIA_READ_TOKEN_OPERATION_NAME = 'EDITOR_SYNCED_BLOCK_GET_JIRA_MEDIA_TOKEN';
18
+ var GET_JIRA_MEDIA_READ_TOKEN_QUERY = "query ".concat(GET_JIRA_MEDIA_READ_TOKEN_OPERATION_NAME, "($issueAri: ID!, $maxTokenLength: Int!) {\n jira {\n issueById(id: $issueAri) {\n mediaReadToken(maxTokenLength: $maxTokenLength) @optIn(to: \"JiraMediaReadTokenInIssue\") {\n clientId\n endpointUrl\n tokenLifespanInSeconds\n tokensWithFiles {\n edges {\n node {\n token\n }\n }\n }\n }\n }\n }\n}");
19
+ var getJiraMediaReadToken = /*#__PURE__*/function () {
20
+ var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(issueAri) {
21
+ var bodyData, response;
22
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
23
+ while (1) switch (_context.prev = _context.next) {
24
+ case 0:
25
+ bodyData = {
26
+ query: GET_JIRA_MEDIA_READ_TOKEN_QUERY,
27
+ operationName: GET_JIRA_MEDIA_READ_TOKEN_OPERATION_NAME,
28
+ variables: {
29
+ issueAri: issueAri,
30
+ maxTokenLength: JIRA_MEDIA_READ_TOKEN_MAX_TOKEN_LENGTH
31
+ }
32
+ };
33
+ _context.next = 3;
34
+ return fetchWithRetry(GRAPHQL_ENDPOINT, {
35
+ method: 'POST',
36
+ headers: _objectSpread(_objectSpread({}, COMMON_HEADERS), AGG_HEADERS),
37
+ body: JSON.stringify(bodyData)
38
+ });
39
+ case 3:
40
+ response = _context.sent;
41
+ if (response.ok) {
42
+ _context.next = 6;
43
+ break;
44
+ }
45
+ throw new Error("Failed to get Jira media read token: ".concat(response.statusText));
46
+ case 6:
47
+ _context.next = 8;
48
+ return response.json();
49
+ case 8:
50
+ return _context.abrupt("return", _context.sent);
51
+ case 9:
52
+ case "end":
53
+ return _context.stop();
54
+ }
55
+ }, _callee);
56
+ }));
57
+ return function getJiraMediaReadToken(_x) {
58
+ return _ref.apply(this, arguments);
59
+ };
60
+ }();
61
+
62
+ /**
63
+ * Fetches a media read token for a Jira issue, to allow media uploaded to Jira
64
+ * to be rendered in cross-product synced block references (e.g. in Confluence).
65
+ *
66
+ * @param issueAri - the Jira issue ARI (e.g. ari:cloud:jira:{cloudId}:issue/{issueId})
67
+ * @returns TokenData with token, config (clientId + fileStoreUrl), and optional collectionId
68
+ */
69
+ export var fetchJiraMediaToken = /*#__PURE__*/function () {
70
+ var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(issueAri) {
71
+ var _response$data, _mediaReadToken$token, _mediaReadToken$token2, response, mediaReadToken, clientId, endpointUrl, token, errorMsg;
72
+ return _regeneratorRuntime.wrap(function _callee2$(_context2) {
73
+ while (1) switch (_context2.prev = _context2.next) {
74
+ case 0:
75
+ _context2.prev = 0;
76
+ _context2.next = 3;
77
+ return getJiraMediaReadToken(issueAri);
78
+ case 3:
79
+ response = _context2.sent;
80
+ mediaReadToken = (_response$data = response.data) === null || _response$data === void 0 || (_response$data = _response$data.jira) === null || _response$data === void 0 || (_response$data = _response$data.issueById) === null || _response$data === void 0 ? void 0 : _response$data.mediaReadToken;
81
+ clientId = mediaReadToken === null || mediaReadToken === void 0 ? void 0 : mediaReadToken.clientId;
82
+ endpointUrl = mediaReadToken === null || mediaReadToken === void 0 ? void 0 : mediaReadToken.endpointUrl; // Use the first available token from tokensWithFiles, or fall back to empty string.
83
+ // A generic read token (without specific file IDs) is sufficient for rendering.
84
+ token = (_mediaReadToken$token = mediaReadToken === null || mediaReadToken === void 0 || (_mediaReadToken$token2 = mediaReadToken.tokensWithFiles) === null || _mediaReadToken$token2 === void 0 || (_mediaReadToken$token2 = _mediaReadToken$token2.edges) === null || _mediaReadToken$token2 === void 0 || (_mediaReadToken$token2 = _mediaReadToken$token2[0]) === null || _mediaReadToken$token2 === void 0 || (_mediaReadToken$token2 = _mediaReadToken$token2.node) === null || _mediaReadToken$token2 === void 0 ? void 0 : _mediaReadToken$token2.token) !== null && _mediaReadToken$token !== void 0 ? _mediaReadToken$token : '';
85
+ if (!(!clientId || !endpointUrl)) {
86
+ _context2.next = 10;
87
+ break;
88
+ }
89
+ throw new Error('Missing clientId or endpointUrl');
90
+ case 10:
91
+ return _context2.abrupt("return", {
92
+ config: {
93
+ clientId: clientId,
94
+ fileStoreUrl: endpointUrl
95
+ },
96
+ token: token
97
+ });
98
+ case 13:
99
+ _context2.prev = 13;
100
+ _context2.t0 = _context2["catch"](0);
101
+ logException(_context2.t0, {
102
+ location: 'editor-synced-block-provider/fetchJiraMediaToken'
103
+ });
104
+ errorMsg = _context2.t0 instanceof Error ? _context2.t0.message : String(_context2.t0);
105
+ throw new Error("Failed to get Jira media read token: ".concat(errorMsg));
106
+ case 18:
107
+ case "end":
108
+ return _context2.stop();
109
+ }
110
+ }, _callee2, null, [[0, 13]]);
111
+ }));
112
+ return function fetchJiraMediaToken(_x2) {
113
+ return _ref2.apply(this, arguments);
114
+ };
115
+ }();
@@ -0,0 +1,19 @@
1
+ import { fetchMediaToken } from './confluence/fetchMediaToken';
2
+ import { fetchJiraMediaToken } from './jira/fetchMediaToken';
3
+ export var requiresCrossProductAuth = function requiresCrossProductAuth(_ref) {
4
+ var hostProduct = _ref.hostProduct,
5
+ sourceProduct = _ref.sourceProduct;
6
+ return !!sourceProduct && sourceProduct !== hostProduct;
7
+ };
8
+ export var fetchTokenForSourceProduct = function fetchTokenForSourceProduct(_ref2) {
9
+ var contentId = _ref2.contentId,
10
+ sourceProduct = _ref2.sourceProduct;
11
+ switch (sourceProduct) {
12
+ case 'confluence-page':
13
+ return fetchMediaToken(contentId);
14
+ case 'jira-work-item':
15
+ return fetchJiraMediaToken(contentId);
16
+ default:
17
+ throw new Error("Unsupported source product for token fetch: ".concat(sourceProduct));
18
+ }
19
+ };
@@ -306,13 +306,14 @@ export var SyncedBlockProvider = /*#__PURE__*/function (_SyncBlockDataProvide) {
306
306
  key: "fetchSyncBlockSourceInfo",
307
307
  value: (function () {
308
308
  var _fetchSyncBlockSourceInfo = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(localId, sourceAri, sourceProduct) {
309
- var _this$writeProvider, _this$writeProvider3;
309
+ var _this$writeProvider;
310
310
  var hasAccess,
311
311
  ari,
312
312
  product,
313
313
  _this$writeProvider2,
314
- _sourceInfo,
315
314
  sourceInfo,
315
+ _this$writeProvider3,
316
+ _sourceInfo,
316
317
  _args4 = arguments;
317
318
  return _regeneratorRuntime.wrap(function _callee4$(_context4) {
318
319
  while (1) switch (_context4.prev = _context4.next) {
@@ -333,14 +334,14 @@ export var SyncedBlockProvider = /*#__PURE__*/function (_SyncBlockDataProvide) {
333
334
  _context4.next = 10;
334
335
  return fetchConfluencePageInfo(ari, hasAccess, localId);
335
336
  case 10:
336
- _sourceInfo = _context4.sent;
337
- if (_sourceInfo) {
337
+ sourceInfo = _context4.sent;
338
+ if (sourceInfo) {
338
339
  _context4.next = 13;
339
340
  break;
340
341
  }
341
342
  return _context4.abrupt("return", Promise.resolve(undefined));
342
343
  case 13:
343
- return _context4.abrupt("return", _objectSpread(_objectSpread({}, _sourceInfo), {}, {
344
+ return _context4.abrupt("return", _objectSpread(_objectSpread({}, sourceInfo), {}, {
344
345
  onSameDocument: ((_this$writeProvider2 = this.writeProvider) === null || _this$writeProvider2 === void 0 ? void 0 : _this$writeProvider2.parentAri) === ari,
345
346
  productType: product
346
347
  }));
@@ -348,14 +349,14 @@ export var SyncedBlockProvider = /*#__PURE__*/function (_SyncBlockDataProvide) {
348
349
  _context4.next = 16;
349
350
  return fetchJiraWorkItemInfo(ari, hasAccess);
350
351
  case 16:
351
- sourceInfo = _context4.sent;
352
- if (sourceInfo) {
352
+ _sourceInfo = _context4.sent;
353
+ if (_sourceInfo) {
353
354
  _context4.next = 19;
354
355
  break;
355
356
  }
356
357
  return _context4.abrupt("return", Promise.resolve(undefined));
357
358
  case 19:
358
- return _context4.abrupt("return", _objectSpread(_objectSpread({}, sourceInfo), {}, {
359
+ return _context4.abrupt("return", _objectSpread(_objectSpread({}, _sourceInfo), {}, {
359
360
  onSameDocument: ((_this$writeProvider3 = this.writeProvider) === null || _this$writeProvider3 === void 0 ? void 0 : _this$writeProvider3.parentAri) === ari,
360
361
  productType: product
361
362
  }));
@@ -425,7 +426,10 @@ export var SyncedBlockProvider = /*#__PURE__*/function (_SyncBlockDataProvide) {
425
426
  contentProduct: sourceProduct
426
427
  };
427
428
  case 'jira-work-item':
428
- throw new Error('Jira work item source product not supported');
429
+ return {
430
+ contentId: sourceAri,
431
+ contentProduct: sourceProduct
432
+ };
429
433
  default:
430
434
  throw new Error("".concat(sourceProduct, " source product not supported"));
431
435
  }
@@ -66,6 +66,7 @@ export var SyncBlockProviderFactoryManager = /*#__PURE__*/function () {
66
66
  }, {
67
67
  key: "getSSRProviders",
68
68
  value: function getSSRProviders(resourceId) {
69
+ var _syncBlock$data;
69
70
  var dataProvider = this.deps.getDataProvider();
70
71
  if (!dataProvider) {
71
72
  return null;
@@ -81,6 +82,14 @@ export var SyncBlockProviderFactoryManager = /*#__PURE__*/function () {
81
82
  }
82
83
  var contentId = parsedResourceId.contentId,
83
84
  contentProduct = parsedResourceId.product;
85
+ var syncBlock = this.deps.getFromCache(resourceId);
86
+ if (syncBlock !== null && syncBlock !== void 0 && (_syncBlock$data = syncBlock.data) !== null && _syncBlock$data !== void 0 && _syncBlock$data.sourceAri && syncBlock.data.product) {
87
+ var parentInfo = dataProvider.retrieveSyncBlockParentInfo(syncBlock.data.sourceAri, syncBlock.data.product);
88
+ if (parentInfo) {
89
+ contentId = parentInfo.contentId;
90
+ contentProduct = parentInfo.contentProduct;
91
+ }
92
+ }
84
93
  try {
85
94
  var mediaProvider = providerCreator.createSSRMediaProvider({
86
95
  contentId: contentId,
@@ -0,0 +1,9 @@
1
+ import type { TokenData } from '../confluence/fetchMediaToken';
2
+ /**
3
+ * Fetches a media read token for a Jira issue, to allow media uploaded to Jira
4
+ * to be rendered in cross-product synced block references (e.g. in Confluence).
5
+ *
6
+ * @param issueAri - the Jira issue ARI (e.g. ari:cloud:jira:{cloudId}:issue/{issueId})
7
+ * @returns TokenData with token, config (clientId + fileStoreUrl), and optional collectionId
8
+ */
9
+ export declare const fetchJiraMediaToken: (issueAri: string) => Promise<TokenData>;
@@ -0,0 +1,10 @@
1
+ import type { SyncBlockProduct } from '../common/types';
2
+ import type { TokenData } from './confluence/fetchMediaToken';
3
+ export declare const requiresCrossProductAuth: ({ hostProduct, sourceProduct, }: {
4
+ hostProduct: SyncBlockProduct;
5
+ sourceProduct?: SyncBlockProduct;
6
+ }) => boolean;
7
+ export declare const fetchTokenForSourceProduct: ({ contentId, sourceProduct, }: {
8
+ contentId: string;
9
+ sourceProduct?: SyncBlockProduct;
10
+ }) => Promise<TokenData>;
@@ -0,0 +1,9 @@
1
+ import type { TokenData } from '../confluence/fetchMediaToken';
2
+ /**
3
+ * Fetches a media read token for a Jira issue, to allow media uploaded to Jira
4
+ * to be rendered in cross-product synced block references (e.g. in Confluence).
5
+ *
6
+ * @param issueAri - the Jira issue ARI (e.g. ari:cloud:jira:{cloudId}:issue/{issueId})
7
+ * @returns TokenData with token, config (clientId + fileStoreUrl), and optional collectionId
8
+ */
9
+ export declare const fetchJiraMediaToken: (issueAri: string) => Promise<TokenData>;
@@ -0,0 +1,10 @@
1
+ import type { SyncBlockProduct } from '../common/types';
2
+ import type { TokenData } from './confluence/fetchMediaToken';
3
+ export declare const requiresCrossProductAuth: ({ hostProduct, sourceProduct, }: {
4
+ hostProduct: SyncBlockProduct;
5
+ sourceProduct?: SyncBlockProduct;
6
+ }) => boolean;
7
+ export declare const fetchTokenForSourceProduct: ({ contentId, sourceProduct, }: {
8
+ contentId: string;
9
+ sourceProduct?: SyncBlockProduct;
10
+ }) => Promise<TokenData>;
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@atlaskit/editor-synced-block-provider/fetchJiraMediaToken",
3
+ "main": "../dist/cjs/clients/jira/fetchMediaToken.js",
4
+ "module": "../dist/esm/clients/jira/fetchMediaToken.js",
5
+ "module:es2019": "../dist/es2019/clients/jira/fetchMediaToken.js",
6
+ "sideEffects": [
7
+ "*.compiled.css"
8
+ ],
9
+ "types": "../dist/types/clients/jira/fetchMediaToken.d.ts",
10
+ "typesVersions": {
11
+ ">=4.5 <5.9": {
12
+ "*": [
13
+ "../dist/types-ts4.5/clients/jira/fetchMediaToken.d.ts"
14
+ ]
15
+ }
16
+ }
17
+ }
package/package.json CHANGED
@@ -29,7 +29,7 @@
29
29
  "@atlaskit/editor-prosemirror": "^7.3.0",
30
30
  "@atlaskit/node-data-provider": "^9.0.0",
31
31
  "@atlaskit/platform-feature-flags": "^1.1.0",
32
- "@atlaskit/tmp-editor-statsig": "^58.0.0",
32
+ "@atlaskit/tmp-editor-statsig": "^60.2.0",
33
33
  "@babel/runtime": "^7.0.0",
34
34
  "@compiled/react": "^0.20.0",
35
35
  "graphql-ws": "^5.14.2",
@@ -38,7 +38,7 @@
38
38
  "uuid": "^3.1.0"
39
39
  },
40
40
  "peerDependencies": {
41
- "@atlaskit/editor-common": "^112.19.0",
41
+ "@atlaskit/editor-common": "^112.20.0",
42
42
  "react": "^18.2.0"
43
43
  },
44
44
  "devDependencies": {
@@ -81,7 +81,7 @@
81
81
  }
82
82
  },
83
83
  "name": "@atlaskit/editor-synced-block-provider",
84
- "version": "4.4.3",
84
+ "version": "4.5.1",
85
85
  "description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
86
86
  "author": "Atlassian Pty Ltd",
87
87
  "license": "Apache-2.0",
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@atlaskit/editor-synced-block-provider/tokenRouting",
3
+ "main": "../dist/cjs/clients/tokenRouting.js",
4
+ "module": "../dist/esm/clients/tokenRouting.js",
5
+ "module:es2019": "../dist/es2019/clients/tokenRouting.js",
6
+ "sideEffects": [
7
+ "*.compiled.css"
8
+ ],
9
+ "types": "../dist/types/clients/tokenRouting.d.ts",
10
+ "typesVersions": {
11
+ ">=4.5 <5.9": {
12
+ "*": [
13
+ "../dist/types-ts4.5/clients/tokenRouting.d.ts"
14
+ ]
15
+ }
16
+ }
17
+ }