@atlaskit/editor-synced-block-provider 23.0.5 → 23.1.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.
Files changed (30) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cjs/clients/jira/ari.js +2 -2
  3. package/dist/cjs/common/types.js +1 -0
  4. package/dist/cjs/providers/syncBlockProvider.js +6 -0
  5. package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +32 -13
  6. package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +15 -7
  7. package/dist/cjs/utils/errorHandling.js +16 -10
  8. package/dist/cjs/utils/fieldAwareLocations.js +26 -1
  9. package/dist/es2019/clients/jira/ari.js +1 -1
  10. package/dist/es2019/common/types.js +2 -0
  11. package/dist/es2019/providers/syncBlockProvider.js +4 -0
  12. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +33 -15
  13. package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +15 -9
  14. package/dist/es2019/utils/errorHandling.js +14 -5
  15. package/dist/es2019/utils/fieldAwareLocations.js +27 -2
  16. package/dist/esm/clients/jira/ari.js +1 -1
  17. package/dist/esm/common/types.js +2 -0
  18. package/dist/esm/providers/syncBlockProvider.js +6 -0
  19. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +32 -13
  20. package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +15 -7
  21. package/dist/esm/utils/errorHandling.js +16 -10
  22. package/dist/esm/utils/fieldAwareLocations.js +26 -1
  23. package/dist/types/clients/jira/ari.d.ts +1 -0
  24. package/dist/types/common/types.d.ts +2 -0
  25. package/dist/types/providers/syncBlockProvider.d.ts +1 -0
  26. package/dist/types/providers/types.d.ts +4 -0
  27. package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +1 -0
  28. package/dist/types/utils/errorHandling.d.ts +9 -7
  29. package/dist/types/utils/fieldAwareLocations.d.ts +9 -1
  30. package/package.json +6 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 23.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`bf97ae26b480d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/bf97ae26b480d) -
8
+ Add a `sourceLocation` analytics attribute (`description` | `custom-field`) to synced block create
9
+ and get-source-info events for Jira sources, behind the `platform_editor_blocks_patch_13` feature
10
+ gate and the `editor_synced_blocks_jira_custom_rich_text` experiment. With the gate off, events
11
+ are unchanged. Add an optional `getParentAri()` method to the synced block data provider.
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+
3
17
  ## 23.0.5
4
18
 
5
19
  ### Patch Changes
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.parseJiraFieldLocation = exports.getJiraWorkItemIdFromAri = exports.getJiraWorkItemAri = exports.getJiraIssueAriFromSourceAri = void 0;
6
+ exports.parseJiraFieldLocation = exports.getJiraWorkItemIdFromAri = exports.getJiraWorkItemAri = exports.getJiraIssueAriFromSourceAri = exports.JIRA_DESCRIPTION_FIELD_ID = void 0;
7
7
  /* eslint-disable require-unicode-regexp */
8
8
 
9
9
  var JIRA_WORK_ITEM_ARI_REGEX = /ari:cloud:jira:([^:]+):issue\/(\d+)/;
@@ -69,7 +69,7 @@ var getJiraIssueAriFromSourceAri = exports.getJiraIssueAriFromSourceAri = functi
69
69
  }
70
70
  return ari;
71
71
  };
72
- var JIRA_DESCRIPTION_FIELD_ID = 'description';
72
+ var JIRA_DESCRIPTION_FIELD_ID = exports.JIRA_DESCRIPTION_FIELD_ID = 'description';
73
73
 
74
74
  /**
75
75
  * One synced block location on a Jira work item, parsed once from its document ARI.
@@ -20,6 +20,7 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
20
20
  * `same-document` is the host document itself, the same page or the same work item field.
21
21
  * `same-parent-document` is another field of the host work item.
22
22
  */
23
+ /** Which Jira work item field holds a source block. */
23
24
  var SyncBlockError = exports.SyncBlockError = /*#__PURE__*/function (SyncBlockError) {
24
25
  SyncBlockError["Errored"] = "errored";
25
26
  SyncBlockError["NotFound"] = "not_found";
@@ -388,6 +388,12 @@ var SyncedBlockProvider = exports.SyncedBlockProvider = /*#__PURE__*/function (_
388
388
  }
389
389
  return fetchSyncBlockSourceInfo;
390
390
  }())
391
+ }, {
392
+ key: "getParentAri",
393
+ value: function getParentAri() {
394
+ var _this$writeProvider5;
395
+ return (_this$writeProvider5 = this.writeProvider) === null || _this$writeProvider5 === void 0 ? void 0 : _this$writeProvider5.parentAri;
396
+ }
391
397
  }, {
392
398
  key: "generateResourceId",
393
399
  value: function generateResourceId() {
@@ -18,6 +18,7 @@ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-ex
18
18
  var _types = require("../common/types");
19
19
  var _errorHandling = require("../utils/errorHandling");
20
20
  var _experienceTracking = require("../utils/experienceTracking");
21
+ var _fieldAwareLocations = require("../utils/fieldAwareLocations");
21
22
  var _resolveSyncBlockInstance = require("../utils/resolveSyncBlockInstance");
22
23
  var _resourceId = require("../utils/resourceId");
23
24
  var _utils = require("../utils/utils");
@@ -440,15 +441,26 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
440
441
  (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 || _this$fireAnalyticsEv3.call(this, (0, _errorHandling.getSourceInfoErrorPayload)('SourceAri, product or blockInstanceId missing', resourceId, sourceProduct));
441
442
  return Promise.resolve(undefined);
442
443
  }
444
+ var sourceLocation = (0, _fieldAwareLocations.getSourceLocation)(sourceAri);
445
+ // Undefined with `platform_editor_blocks_patch_13` off, so experience calls below keep
446
+ // exactly their previous arguments (no `metadata` key, `success()` without arguments).
447
+ var experienceMetadata = sourceLocation && {
448
+ sourceLocation: sourceLocation
449
+ };
450
+ var withExperienceMetadata = function withExperienceMetadata(options) {
451
+ return experienceMetadata ? _objectSpread(_objectSpread({}, options), {}, {
452
+ metadata: experienceMetadata
453
+ }) : options;
454
+ };
443
455
  (_this$fetchSourceInfo = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo === void 0 || _this$fetchSourceInfo.start({});
444
456
  var sourceInfoPromise = this.dataProvider.fetchSyncBlockSourceInfo(blockInstanceId, sourceAri, product, true // hasAccess
445
457
  ).then(function (sourceInfo) {
446
458
  if (!sourceInfo) {
447
459
  var _this2$fetchSourceInf, _this2$fireAnalyticsE;
448
- (_this2$fetchSourceInf = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf === void 0 || _this2$fetchSourceInf.failure({
460
+ (_this2$fetchSourceInf = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf === void 0 || _this2$fetchSourceInf.failure(withExperienceMetadata({
449
461
  reason: 'No source info returned'
450
- });
451
- (_this2$fireAnalyticsE = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE === void 0 || _this2$fireAnalyticsE.call(_this2, (0, _errorHandling.getSourceInfoErrorPayload)('No source info returned', resourceId, sourceProduct));
462
+ }));
463
+ (_this2$fireAnalyticsE = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE === void 0 || _this2$fireAnalyticsE.call(_this2, (0, _errorHandling.getSourceInfoErrorPayload)('No source info returned', resourceId, sourceProduct, sourceLocation));
452
464
  return undefined;
453
465
  }
454
466
  _this2.updateCacheWithSourceInfo(resourceId, sourceInfo);
@@ -456,22 +468,29 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
456
468
  _this2._subscriptionManager.updateSourceTitleSubscriptions(resourceId, sourceInfo.title);
457
469
  }
458
470
  if (sourceInfo.title && sourceInfo.url) {
459
- var _this2$fetchSourceInf2;
460
- (_this2$fetchSourceInf2 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf2 === void 0 || _this2$fetchSourceInf2.success();
471
+ if (experienceMetadata) {
472
+ var _this2$fetchSourceInf2;
473
+ (_this2$fetchSourceInf2 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf2 === void 0 || _this2$fetchSourceInf2.success({
474
+ metadata: experienceMetadata
475
+ });
476
+ } else {
477
+ var _this2$fetchSourceInf3;
478
+ (_this2$fetchSourceInf3 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf3 === void 0 || _this2$fetchSourceInf3.success();
479
+ }
461
480
  } else {
462
- var _this2$fetchSourceInf3, _this2$fireAnalyticsE2;
463
- (_this2$fetchSourceInf3 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf3 === void 0 || _this2$fetchSourceInf3.failure({
481
+ var _this2$fetchSourceInf4, _this2$fireAnalyticsE2;
482
+ (_this2$fetchSourceInf4 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf4 === void 0 || _this2$fetchSourceInf4.failure(withExperienceMetadata({
464
483
  reason: 'Missing title or url'
465
- });
466
- (_this2$fireAnalyticsE2 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE2 === void 0 || _this2$fireAnalyticsE2.call(_this2, (0, _errorHandling.getSourceInfoErrorPayload)('Missing title or url', resourceId, sourceProduct));
484
+ }));
485
+ (_this2$fireAnalyticsE2 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE2 === void 0 || _this2$fireAnalyticsE2.call(_this2, (0, _errorHandling.getSourceInfoErrorPayload)('Missing title or url', resourceId, sourceProduct, sourceLocation));
467
486
  }
468
487
  return sourceInfo;
469
488
  }).catch(function (error) {
470
- var _this2$fetchSourceInf4, _this2$fireAnalyticsE3;
471
- (_this2$fetchSourceInf4 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf4 === void 0 || _this2$fetchSourceInf4.failure({
489
+ var _this2$fetchSourceInf5, _this2$fireAnalyticsE3;
490
+ (_this2$fetchSourceInf5 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf5 === void 0 || _this2$fetchSourceInf5.failure(withExperienceMetadata({
472
491
  reason: error.message
473
- });
474
- (_this2$fireAnalyticsE3 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE3 === void 0 || _this2$fireAnalyticsE3.call(_this2, (0, _errorHandling.getSourceInfoErrorPayload)(error.message, resourceId, sourceProduct));
492
+ }));
493
+ (_this2$fireAnalyticsE3 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE3 === void 0 || _this2$fireAnalyticsE3.call(_this2, (0, _errorHandling.getSourceInfoErrorPayload)(error.message, resourceId, sourceProduct, sourceLocation));
475
494
  return undefined;
476
495
  }).finally(function () {
477
496
  _this2.syncBlockSourceInfoRequests.delete(resourceId);
@@ -18,6 +18,7 @@ var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-ex
18
18
  var _types = require("../common/types");
19
19
  var _errorHandling = require("../utils/errorHandling");
20
20
  var _experienceTracking = require("../utils/experienceTracking");
21
+ var _fieldAwareLocations = require("../utils/fieldAwareLocations");
21
22
  var _utils = require("../utils/utils");
22
23
  var _excluded = ["contentFragment", "isDirty"];
23
24
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
@@ -494,16 +495,17 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
494
495
  }
495
496
  } else {
496
497
  var _this$fireAnalyticsEv3;
497
- (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 || _this$fireAnalyticsEv3.call(this, (0, _errorHandling.createErrorPayload)('creation complete callback missing', resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
498
+ (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 || _this$fireAnalyticsEv3.call(this, (0, _errorHandling.createErrorPayload)('creation complete callback missing', resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), undefined, this.getSourceLocation()));
498
499
  }
499
500
  if (success) {
500
501
  var _this$dataProvider$ge, _this$dataProvider, _this$fireAnalyticsEv4, _this$fireAnalyticsEv5, _this$syncBlockCache$2;
501
502
  var sourceProduct = (0, _utils.getSourceProductFromResourceIdSafe)(resourceId);
503
+ var sourceLocation = this.getSourceLocation();
502
504
  var documentInsertedResourceId = (_this$dataProvider$ge = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.generateResourceIdForReference(resourceId)) !== null && _this$dataProvider$ge !== void 0 ? _this$dataProvider$ge : resourceId;
503
- (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 || _this$fireAnalyticsEv4.call(this, (0, _errorHandling.createSuccessPayload)(documentInsertedResourceId || '', sourceProduct));
505
+ (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 || _this$fireAnalyticsEv4.call(this, (0, _errorHandling.createSuccessPayload)(documentInsertedResourceId || '', sourceProduct, sourceLocation));
504
506
  // Operational create-success event with the join key + creation-type
505
507
  // signals (inputMethod / createdEmpty / nodeTypes) captured at the command layer.
506
- (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 || _this$fireAnalyticsEv5.call(this, (0, _errorHandling.createSuccessOperationalPayload)(resourceId || '', (_this$syncBlockCache$2 = this.syncBlockCache.get(resourceId)) === null || _this$syncBlockCache$2 === void 0 ? void 0 : _this$syncBlockCache$2.blockInstanceId, sourceProduct, this.creationEnrichment.get(resourceId)));
508
+ (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 || _this$fireAnalyticsEv5.call(this, (0, _errorHandling.createSuccessOperationalPayload)(resourceId || '', (_this$syncBlockCache$2 = this.syncBlockCache.get(resourceId)) === null || _this$syncBlockCache$2 === void 0 ? void 0 : _this$syncBlockCache$2.blockInstanceId, sourceProduct, this.creationEnrichment.get(resourceId), sourceLocation));
507
509
  } else {
508
510
  var _this$fireAnalyticsEv6;
509
511
  // Delete the node from cache if fail to create so it's not flushed to BE
@@ -513,7 +515,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
513
515
  // Creation failed, so there is no block to add content to — drop the
514
516
  // first-content tracking entry so a later unrelated edit cannot fire it.
515
517
  this.awaitingFirstContent.delete(resourceId || '');
516
- (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 || _this$fireAnalyticsEv6.call(this, (0, _errorHandling.createErrorPayload)('Fail to create bodied sync block', resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
518
+ (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 || _this$fireAnalyticsEv6.call(this, (0, _errorHandling.createErrorPayload)('Fail to create bodied sync block', resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), undefined, this.getSourceLocation()));
517
519
  }
518
520
  // Enrichment is single-use — drop it once the create has resolved either way.
519
521
  this.creationEnrichment.delete(resourceId || '');
@@ -635,7 +637,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
635
637
  (_this5$createExperien2 = _this5.createExperience) === null || _this5$createExperien2 === void 0 || _this5$createExperien2.failure({
636
638
  reason: result.error || 'Failed to create bodied sync block'
637
639
  });
638
- (_this5$fireAnalyticsE = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE === void 0 || _this5$fireAnalyticsE.call(_this5, (0, _errorHandling.createErrorPayload)(result.error || 'Failed to create bodied sync block', resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), (0, _errorHandling.buildErrorAttribution)(result.error, result.statusCode)));
640
+ (_this5$fireAnalyticsE = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE === void 0 || _this5$fireAnalyticsE.call(_this5, (0, _errorHandling.createErrorPayload)(result.error || 'Failed to create bodied sync block', resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), (0, _errorHandling.buildErrorAttribution)(result.error, result.statusCode), _this5.getSourceLocation()));
639
641
  }
640
642
  }).catch(function (error) {
641
643
  var _this5$createExperien3, _this5$fireAnalyticsE2;
@@ -646,7 +648,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
646
648
  (_this5$createExperien3 = _this5.createExperience) === null || _this5$createExperien3 === void 0 || _this5$createExperien3.failure({
647
649
  reason: error.message
648
650
  });
649
- (_this5$fireAnalyticsE2 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE2 === void 0 || _this5$fireAnalyticsE2.call(_this5, (0, _errorHandling.createErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
651
+ (_this5$fireAnalyticsE2 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE2 === void 0 || _this5$fireAnalyticsE2.call(_this5, (0, _errorHandling.createErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), undefined, _this5.getSourceLocation()));
650
652
  }).finally(function () {
651
653
  _this5.pendingCreationPromises.delete(resourceId);
652
654
  });
@@ -660,9 +662,15 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
660
662
  (0, _error.logException)(error, {
661
663
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
662
664
  });
663
- (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 || _this$fireAnalyticsEv8.call(this, (0, _errorHandling.createErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
665
+ (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 || _this$fireAnalyticsEv8.call(this, (0, _errorHandling.createErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), undefined, this.getSourceLocation()));
664
666
  }
665
667
  }
668
+ }, {
669
+ key: "getSourceLocation",
670
+ value: function getSourceLocation() {
671
+ var _this$dataProvider2, _this$dataProvider2$g;
672
+ return (0, _fieldAwareLocations.getSourceLocation)((_this$dataProvider2 = this.dataProvider) === null || _this$dataProvider2 === void 0 || (_this$dataProvider2$g = _this$dataProvider2.getParentAri) === null || _this$dataProvider2$g === void 0 ? void 0 : _this$dataProvider2$g.call(_this$dataProvider2));
673
+ }
666
674
  }, {
667
675
  key: "pruneRecentDeleteEmissions",
668
676
  value:
@@ -221,18 +221,20 @@ var buildFetchErrorAttribution = exports.buildFetchErrorAttribution = function b
221
221
  * buckets like `source_deleted` they never emit.
222
222
  */
223
223
 
224
- function getErrorPayload(actionSubjectId, error, resourceId, sourceProduct, attribution) {
224
+ function getErrorPayload(actionSubjectId, error, resourceId, sourceProduct, attribution, sourceLocation) {
225
225
  return {
226
226
  action: _enums.ACTION.ERROR,
227
227
  actionSubject: _enums.ACTION_SUBJECT.SYNCED_BLOCK,
228
228
  actionSubjectId: actionSubjectId,
229
229
  eventType: _enums.EVENT_TYPE.OPERATIONAL,
230
- attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
230
+ attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
231
231
  error: error
232
232
  }, resourceId && {
233
233
  resourceId: resourceId
234
234
  }), sourceProduct && {
235
235
  sourceProduct: sourceProduct
236
+ }), sourceLocation && {
237
+ sourceLocation: sourceLocation
236
238
  }), (attribution === null || attribution === void 0 ? void 0 : attribution.reason) && {
237
239
  reason: attribution.reason
238
240
  }), (attribution === null || attribution === void 0 ? void 0 : attribution.statusCode) !== undefined && {
@@ -252,8 +254,8 @@ var fetchErrorPayload = exports.fetchErrorPayload = function fetchErrorPayload(e
252
254
  attribution ? getErrorPayload(_enums.ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct, attribution) : getErrorPayload(_enums.ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct)
253
255
  );
254
256
  };
255
- var getSourceInfoErrorPayload = exports.getSourceInfoErrorPayload = function getSourceInfoErrorPayload(error, resourceId, sourceProduct) {
256
- return getErrorPayload(_enums.ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error, resourceId, sourceProduct);
257
+ var getSourceInfoErrorPayload = exports.getSourceInfoErrorPayload = function getSourceInfoErrorPayload(error, resourceId, sourceProduct, sourceLocation) {
258
+ return getErrorPayload(_enums.ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error, resourceId, sourceProduct, undefined, sourceLocation);
257
259
  };
258
260
  var updateErrorPayload = exports.updateErrorPayload = function updateErrorPayload(error, resourceId, sourceProduct, attribution) {
259
261
  return getErrorPayload(_enums.ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE, error, resourceId, sourceProduct, attribution);
@@ -261,8 +263,8 @@ var updateErrorPayload = exports.updateErrorPayload = function updateErrorPayloa
261
263
  var updateReferenceErrorPayload = exports.updateReferenceErrorPayload = function updateReferenceErrorPayload(error, resourceId, sourceProduct, attribution) {
262
264
  return getErrorPayload(_enums.ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_UPDATE, error, resourceId, sourceProduct, attribution);
263
265
  };
264
- var createErrorPayload = exports.createErrorPayload = function createErrorPayload(error, resourceId, sourceProduct, attribution) {
265
- return getErrorPayload(_enums.ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error, resourceId, sourceProduct, attribution);
266
+ var createErrorPayload = exports.createErrorPayload = function createErrorPayload(error, resourceId, sourceProduct, attribution, sourceLocation) {
267
+ return getErrorPayload(_enums.ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error, resourceId, sourceProduct, attribution, sourceLocation);
266
268
  };
267
269
  var deleteErrorPayload = exports.deleteErrorPayload = function deleteErrorPayload(error, resourceId, sourceProduct, attribution) {
268
270
  return getErrorPayload(_enums.ACTION_SUBJECT_ID.SYNCED_BLOCK_DELETE, error, resourceId, sourceProduct, attribution);
@@ -331,16 +333,18 @@ var fetchSuccessPayload = exports.fetchSuccessPayload = function fetchSuccessPay
331
333
  })
332
334
  };
333
335
  };
334
- var createSuccessPayload = exports.createSuccessPayload = function createSuccessPayload(resourceId, sourceProduct) {
336
+ var createSuccessPayload = exports.createSuccessPayload = function createSuccessPayload(resourceId, sourceProduct, sourceLocation) {
335
337
  return {
336
338
  action: _enums.ACTION.INSERTED,
337
339
  actionSubject: _enums.ACTION_SUBJECT.DOCUMENT,
338
340
  actionSubjectId: _enums.ACTION_SUBJECT_ID.BODIED_SYNCED_BLOCK,
339
341
  eventType: _enums.EVENT_TYPE.TRACK,
340
- attributes: _objectSpread({
342
+ attributes: _objectSpread(_objectSpread({
341
343
  resourceId: resourceId
342
344
  }, sourceProduct && {
343
345
  sourceProduct: sourceProduct
346
+ }), sourceLocation && {
347
+ sourceLocation: sourceLocation
344
348
  })
345
349
  };
346
350
  };
@@ -357,14 +361,14 @@ var createSuccessPayload = exports.createSuccessPayload = function createSuccess
357
361
  * Operational `syncedBlockCreate` success event with the `blockInstanceId` join key and,
358
362
  * when available, the `inputMethod`, `createdEmpty`, and `nodeTypes` creation signals.
359
363
  */
360
- var createSuccessOperationalPayload = exports.createSuccessOperationalPayload = function createSuccessOperationalPayload(resourceId, blockInstanceId, sourceProduct, enrichment) {
364
+ var createSuccessOperationalPayload = exports.createSuccessOperationalPayload = function createSuccessOperationalPayload(resourceId, blockInstanceId, sourceProduct, enrichment, sourceLocation) {
361
365
  var _enrichment$nodeTypes;
362
366
  return {
363
367
  action: _enums.ACTION.INSERTED,
364
368
  actionSubject: _enums.ACTION_SUBJECT.SYNCED_BLOCK,
365
369
  actionSubjectId: _enums.ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
366
370
  eventType: _enums.EVENT_TYPE.OPERATIONAL,
367
- attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
371
+ attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
368
372
  resourceId: resourceId
369
373
  }, blockInstanceId && {
370
374
  blockInstanceId: blockInstanceId
@@ -376,6 +380,8 @@ var createSuccessOperationalPayload = exports.createSuccessOperationalPayload =
376
380
  createdEmpty: enrichment.createdEmpty
377
381
  }), (enrichment === null || enrichment === void 0 || (_enrichment$nodeTypes = enrichment.nodeTypes) === null || _enrichment$nodeTypes === void 0 ? void 0 : _enrichment$nodeTypes.length) && {
378
382
  nodeTypes: enrichment.nodeTypes
383
+ }), sourceLocation && {
384
+ sourceLocation: sourceLocation
379
385
  })
380
386
  };
381
387
  };
@@ -3,9 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.isFieldAwareJiraLocation = exports.getFieldAwareLocationScope = void 0;
6
+ exports.isFieldAwareJiraLocation = exports.getSourceLocation = exports.getFieldAwareLocationScope = void 0;
7
7
  var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
8
+ var _fg = require("@atlaskit/platform-feature-flags/fg");
8
9
  var _ari = require("../clients/block-service/ari");
10
+ var _ari2 = require("../clients/jira/ari");
9
11
  /**
10
12
  * The product check runs first so a Confluence-only document never reads the experiment.
11
13
  */
@@ -27,4 +29,27 @@ var getFieldAwareLocationScope = exports.getFieldAwareLocationScope = function g
27
29
  hostAri: hostAri
28
30
  })
29
31
  } : undefined;
32
+ };
33
+
34
+ /**
35
+ * Analytics `sourceLocation` for a source ARI: `undefined` for non-Jira sources and for the
36
+ * control cohort, so events outside the experiment keep their current shape.
37
+ *
38
+ * The `platform_editor_blocks_patch_13` gate runs first: with it off this returns `undefined`
39
+ * without the product check or the experiment read, so no new exposure is logged.
40
+ */
41
+ var getSourceLocation = exports.getSourceLocation = function getSourceLocation(sourceAri) {
42
+ if (!(0, _fg.fg)('platform_editor_blocks_patch_13')) {
43
+ return undefined;
44
+ }
45
+ if (!sourceAri || !isFieldAwareJiraLocation((0, _ari.getProductFromSourceAri)(sourceAri))) {
46
+ return undefined;
47
+ }
48
+ var location = (0, _ari2.parseJiraFieldLocation)({
49
+ ari: sourceAri
50
+ });
51
+ if (!location) {
52
+ return undefined;
53
+ }
54
+ return location.fieldId === _ari2.JIRA_DESCRIPTION_FIELD_ID ? 'description' : 'custom-field';
30
55
  };
@@ -66,7 +66,7 @@ export const getJiraIssueAriFromSourceAri = ({
66
66
  }
67
67
  return ari;
68
68
  };
69
- const JIRA_DESCRIPTION_FIELD_ID = 'description';
69
+ export const JIRA_DESCRIPTION_FIELD_ID = 'description';
70
70
 
71
71
  /**
72
72
  * One synced block location on a Jira work item, parsed once from its document ARI.
@@ -5,6 +5,8 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
5
5
  * `same-parent-document` is another field of the host work item.
6
6
  */
7
7
 
8
+ /** Which Jira work item field holds a source block. */
9
+
8
10
  export let SyncBlockError = /*#__PURE__*/function (SyncBlockError) {
9
11
  SyncBlockError["Errored"] = "errored";
10
12
  SyncBlockError["NotFound"] = "not_found";
@@ -244,6 +244,10 @@ export class SyncedBlockProvider extends SyncBlockDataProviderInterface {
244
244
  return Promise.reject(new Error(`${product} source product not supported`));
245
245
  }
246
246
  }
247
+ getParentAri() {
248
+ var _this$writeProvider6;
249
+ return (_this$writeProvider6 = this.writeProvider) === null || _this$writeProvider6 === void 0 ? void 0 : _this$writeProvider6.parentAri;
250
+ }
247
251
  generateResourceId() {
248
252
  const localId = crypto.randomUUID();
249
253
  const resourceId = crypto.randomUUID();
@@ -5,6 +5,7 @@ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-e
5
5
  import { isProviderNotReadyError, ProviderNotReadyError, SyncBlockError } from '../common/types';
6
6
  import { buildErrorAttribution, buildFetchErrorAttribution, cacheDeletionForcedPayload, fetchErrorPayload, fetchSuccessPayload, getSourceInfoErrorPayload, sourceInfoOrphanedPayload, updateReferenceErrorPayload } from '../utils/errorHandling';
7
7
  import { getFetchExperience, getFetchSourceInfoExperience, getSaveReferenceExperience } from '../utils/experienceTracking';
8
+ import { getSourceLocation } from '../utils/fieldAwareLocations';
8
9
  import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
9
10
  import { parseResourceId } from '../utils/resourceId';
10
11
  import { createSyncBlockNode, getSourceProductFromResourceIdSafe, normalizeSyncBlockJSONContent } from '../utils/utils';
@@ -348,15 +349,25 @@ export class ReferenceSyncBlockStoreManager {
348
349
  (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 ? void 0 : _this$fireAnalyticsEv3.call(this, getSourceInfoErrorPayload('SourceAri, product or blockInstanceId missing', resourceId, sourceProduct));
349
350
  return Promise.resolve(undefined);
350
351
  }
352
+ const sourceLocation = getSourceLocation(sourceAri);
353
+ // Undefined with `platform_editor_blocks_patch_13` off, so experience calls below keep
354
+ // exactly their previous arguments (no `metadata` key, `success()` without arguments).
355
+ const experienceMetadata = sourceLocation && {
356
+ sourceLocation
357
+ };
358
+ const withExperienceMetadata = options => experienceMetadata ? {
359
+ ...options,
360
+ metadata: experienceMetadata
361
+ } : options;
351
362
  (_this$fetchSourceInfo = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo === void 0 ? void 0 : _this$fetchSourceInfo.start({});
352
363
  const sourceInfoPromise = this.dataProvider.fetchSyncBlockSourceInfo(blockInstanceId, sourceAri, product, true // hasAccess
353
364
  ).then(sourceInfo => {
354
365
  if (!sourceInfo) {
355
366
  var _this$fetchSourceInfo2, _this$fireAnalyticsEv4;
356
- (_this$fetchSourceInfo2 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo2 === void 0 ? void 0 : _this$fetchSourceInfo2.failure({
367
+ (_this$fetchSourceInfo2 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo2 === void 0 ? void 0 : _this$fetchSourceInfo2.failure(withExperienceMetadata({
357
368
  reason: 'No source info returned'
358
- });
359
- (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 ? void 0 : _this$fireAnalyticsEv4.call(this, getSourceInfoErrorPayload('No source info returned', resourceId, sourceProduct));
369
+ }));
370
+ (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 ? void 0 : _this$fireAnalyticsEv4.call(this, getSourceInfoErrorPayload('No source info returned', resourceId, sourceProduct, sourceLocation));
360
371
  return undefined;
361
372
  }
362
373
  this.updateCacheWithSourceInfo(resourceId, sourceInfo);
@@ -364,22 +375,29 @@ export class ReferenceSyncBlockStoreManager {
364
375
  this._subscriptionManager.updateSourceTitleSubscriptions(resourceId, sourceInfo.title);
365
376
  }
366
377
  if (sourceInfo.title && sourceInfo.url) {
367
- var _this$fetchSourceInfo3;
368
- (_this$fetchSourceInfo3 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo3 === void 0 ? void 0 : _this$fetchSourceInfo3.success();
378
+ if (experienceMetadata) {
379
+ var _this$fetchSourceInfo3;
380
+ (_this$fetchSourceInfo3 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo3 === void 0 ? void 0 : _this$fetchSourceInfo3.success({
381
+ metadata: experienceMetadata
382
+ });
383
+ } else {
384
+ var _this$fetchSourceInfo4;
385
+ (_this$fetchSourceInfo4 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo4 === void 0 ? void 0 : _this$fetchSourceInfo4.success();
386
+ }
369
387
  } else {
370
- var _this$fetchSourceInfo4, _this$fireAnalyticsEv5;
371
- (_this$fetchSourceInfo4 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo4 === void 0 ? void 0 : _this$fetchSourceInfo4.failure({
388
+ var _this$fetchSourceInfo5, _this$fireAnalyticsEv5;
389
+ (_this$fetchSourceInfo5 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo5 === void 0 ? void 0 : _this$fetchSourceInfo5.failure(withExperienceMetadata({
372
390
  reason: 'Missing title or url'
373
- });
374
- (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 ? void 0 : _this$fireAnalyticsEv5.call(this, getSourceInfoErrorPayload('Missing title or url', resourceId, sourceProduct));
391
+ }));
392
+ (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 ? void 0 : _this$fireAnalyticsEv5.call(this, getSourceInfoErrorPayload('Missing title or url', resourceId, sourceProduct, sourceLocation));
375
393
  }
376
394
  return sourceInfo;
377
395
  }).catch(error => {
378
- var _this$fetchSourceInfo5, _this$fireAnalyticsEv6;
379
- (_this$fetchSourceInfo5 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo5 === void 0 ? void 0 : _this$fetchSourceInfo5.failure({
396
+ var _this$fetchSourceInfo6, _this$fireAnalyticsEv6;
397
+ (_this$fetchSourceInfo6 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo6 === void 0 ? void 0 : _this$fetchSourceInfo6.failure(withExperienceMetadata({
380
398
  reason: error.message
381
- });
382
- (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 ? void 0 : _this$fireAnalyticsEv6.call(this, getSourceInfoErrorPayload(error.message, resourceId, sourceProduct));
399
+ }));
400
+ (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 ? void 0 : _this$fireAnalyticsEv6.call(this, getSourceInfoErrorPayload(error.message, resourceId, sourceProduct, sourceLocation));
383
401
  return undefined;
384
402
  }).finally(() => {
385
403
  this.syncBlockSourceInfoRequests.delete(resourceId);
@@ -1036,7 +1054,7 @@ export class ReferenceSyncBlockStoreManager {
1036
1054
  return success;
1037
1055
  }
1038
1056
  destroy() {
1039
- var _this$dataProvider7, _this$saveExperience5, _this$fetchExperience0, _this$fetchSourceInfo6;
1057
+ var _this$dataProvider7, _this$saveExperience5, _this$fetchExperience0, _this$fetchSourceInfo7;
1040
1058
  // Mark destroyed first so in-flight timer callbacks can early-return.
1041
1059
  this.isDestroyed = true;
1042
1060
 
@@ -1068,7 +1086,7 @@ export class ReferenceSyncBlockStoreManager {
1068
1086
  (_this$fetchExperience0 = this.fetchExperience) === null || _this$fetchExperience0 === void 0 ? void 0 : _this$fetchExperience0.abort({
1069
1087
  reason: 'editorDestroyed'
1070
1088
  });
1071
- (_this$fetchSourceInfo6 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo6 === void 0 ? void 0 : _this$fetchSourceInfo6.abort({
1089
+ (_this$fetchSourceInfo7 = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo7 === void 0 ? void 0 : _this$fetchSourceInfo7.abort({
1072
1090
  reason: 'editorDestroyed'
1073
1091
  });
1074
1092
  this.fireAnalyticsEvent = undefined;
@@ -4,6 +4,7 @@ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-e
4
4
  import { SyncBlockError } from '../common/types';
5
5
  import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, createSuccessOperationalPayload, addContentSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload, buildErrorAttribution } from '../utils/errorHandling';
6
6
  import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
7
+ import { getSourceLocation } from '../utils/fieldAwareLocations';
7
8
  import { convertSyncBlockPMNodeToSyncBlockData, getSourceProductFromResourceIdSafe } from '../utils/utils';
8
9
  /** Maximum time (ms) flush() will wait for in-flight block creations before proceeding. */
9
10
  const FLUSH_CREATION_AWAIT_TIMEOUT_MS = 1000;
@@ -406,16 +407,17 @@ export class SourceSyncBlockStoreManager {
406
407
  }
407
408
  } else {
408
409
  var _this$fireAnalyticsEv5;
409
- (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 ? void 0 : _this$fireAnalyticsEv5.call(this, createErrorPayload('creation complete callback missing', resourceId, getSourceProductFromResourceIdSafe(resourceId)));
410
+ (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 ? void 0 : _this$fireAnalyticsEv5.call(this, createErrorPayload('creation complete callback missing', resourceId, getSourceProductFromResourceIdSafe(resourceId), undefined, this.getSourceLocation()));
410
411
  }
411
412
  if (success) {
412
413
  var _this$dataProvider$ge, _this$dataProvider, _this$fireAnalyticsEv6, _this$fireAnalyticsEv7, _this$syncBlockCache$2;
413
414
  const sourceProduct = getSourceProductFromResourceIdSafe(resourceId);
415
+ const sourceLocation = this.getSourceLocation();
414
416
  const documentInsertedResourceId = (_this$dataProvider$ge = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.generateResourceIdForReference(resourceId)) !== null && _this$dataProvider$ge !== void 0 ? _this$dataProvider$ge : resourceId;
415
- (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 ? void 0 : _this$fireAnalyticsEv6.call(this, createSuccessPayload(documentInsertedResourceId || '', sourceProduct));
417
+ (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 ? void 0 : _this$fireAnalyticsEv6.call(this, createSuccessPayload(documentInsertedResourceId || '', sourceProduct, sourceLocation));
416
418
  // Operational create-success event with the join key + creation-type
417
419
  // signals (inputMethod / createdEmpty / nodeTypes) captured at the command layer.
418
- (_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 ? void 0 : _this$fireAnalyticsEv7.call(this, createSuccessOperationalPayload(resourceId || '', (_this$syncBlockCache$2 = this.syncBlockCache.get(resourceId)) === null || _this$syncBlockCache$2 === void 0 ? void 0 : _this$syncBlockCache$2.blockInstanceId, sourceProduct, this.creationEnrichment.get(resourceId)));
420
+ (_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 ? void 0 : _this$fireAnalyticsEv7.call(this, createSuccessOperationalPayload(resourceId || '', (_this$syncBlockCache$2 = this.syncBlockCache.get(resourceId)) === null || _this$syncBlockCache$2 === void 0 ? void 0 : _this$syncBlockCache$2.blockInstanceId, sourceProduct, this.creationEnrichment.get(resourceId), sourceLocation));
419
421
  } else {
420
422
  var _this$fireAnalyticsEv8;
421
423
  // Delete the node from cache if fail to create so it's not flushed to BE
@@ -425,7 +427,7 @@ export class SourceSyncBlockStoreManager {
425
427
  // Creation failed, so there is no block to add content to — drop the
426
428
  // first-content tracking entry so a later unrelated edit cannot fire it.
427
429
  this.awaitingFirstContent.delete(resourceId || '');
428
- (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 ? void 0 : _this$fireAnalyticsEv8.call(this, createErrorPayload('Fail to create bodied sync block', resourceId, getSourceProductFromResourceIdSafe(resourceId)));
430
+ (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 ? void 0 : _this$fireAnalyticsEv8.call(this, createErrorPayload('Fail to create bodied sync block', resourceId, getSourceProductFromResourceIdSafe(resourceId), undefined, this.getSourceLocation()));
429
431
  }
430
432
  // Enrichment is single-use — drop it once the create has resolved either way.
431
433
  this.creationEnrichment.delete(resourceId || '');
@@ -538,7 +540,7 @@ export class SourceSyncBlockStoreManager {
538
540
  (_this$createExperienc3 = this.createExperience) === null || _this$createExperienc3 === void 0 ? void 0 : _this$createExperienc3.failure({
539
541
  reason: result.error || 'Failed to create bodied sync block'
540
542
  });
541
- (_this$fireAnalyticsEv0 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv0 === void 0 ? void 0 : _this$fireAnalyticsEv0.call(this, createErrorPayload(result.error || 'Failed to create bodied sync block', resourceId, getSourceProductFromResourceIdSafe(resourceId), buildErrorAttribution(result.error, result.statusCode)));
543
+ (_this$fireAnalyticsEv0 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv0 === void 0 ? void 0 : _this$fireAnalyticsEv0.call(this, createErrorPayload(result.error || 'Failed to create bodied sync block', resourceId, getSourceProductFromResourceIdSafe(resourceId), buildErrorAttribution(result.error, result.statusCode), this.getSourceLocation()));
542
544
  }
543
545
  }).catch(error => {
544
546
  var _this$createExperienc4, _this$fireAnalyticsEv1;
@@ -549,7 +551,7 @@ export class SourceSyncBlockStoreManager {
549
551
  (_this$createExperienc4 = this.createExperience) === null || _this$createExperienc4 === void 0 ? void 0 : _this$createExperienc4.failure({
550
552
  reason: error.message
551
553
  });
552
- (_this$fireAnalyticsEv1 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv1 === void 0 ? void 0 : _this$fireAnalyticsEv1.call(this, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
554
+ (_this$fireAnalyticsEv1 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv1 === void 0 ? void 0 : _this$fireAnalyticsEv1.call(this, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId), undefined, this.getSourceLocation()));
553
555
  }).finally(() => {
554
556
  this.pendingCreationPromises.delete(resourceId);
555
557
  });
@@ -563,9 +565,13 @@ export class SourceSyncBlockStoreManager {
563
565
  logException(error, {
564
566
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
565
567
  });
566
- (_this$fireAnalyticsEv10 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv10 === void 0 ? void 0 : _this$fireAnalyticsEv10.call(this, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
568
+ (_this$fireAnalyticsEv10 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv10 === void 0 ? void 0 : _this$fireAnalyticsEv10.call(this, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId), undefined, this.getSourceLocation()));
567
569
  }
568
570
  }
571
+ getSourceLocation() {
572
+ var _this$dataProvider2, _this$dataProvider2$g;
573
+ return getSourceLocation((_this$dataProvider2 = this.dataProvider) === null || _this$dataProvider2 === void 0 ? void 0 : (_this$dataProvider2$g = _this$dataProvider2.getParentAri) === null || _this$dataProvider2$g === void 0 ? void 0 : _this$dataProvider2$g.call(_this$dataProvider2));
574
+ }
569
575
  /**
570
576
  * Drop dedupe entries older than {@link DELETE_DEDUPE_WINDOW_MS} so
571
577
  * `recentDeleteEmissions` stays bounded by the number of recent deletes.
@@ -709,8 +715,8 @@ export class SourceSyncBlockStoreManager {
709
715
  // so we can update the correct cache entries.
710
716
  const sourceToReferenceMap = new Map();
711
717
  const syncBlockNodes = Array.from(this.syncBlockCache.entries()).map(([resourceId, data]) => {
712
- var _this$dataProvider$ge2, _this$dataProvider2;
713
- const referenceResourceId = (_this$dataProvider$ge2 = (_this$dataProvider2 = this.dataProvider) === null || _this$dataProvider2 === void 0 ? void 0 : _this$dataProvider2.generateResourceIdForReference(resourceId)) !== null && _this$dataProvider$ge2 !== void 0 ? _this$dataProvider$ge2 : resourceId;
718
+ var _this$dataProvider$ge2, _this$dataProvider3;
719
+ const referenceResourceId = (_this$dataProvider$ge2 = (_this$dataProvider3 = this.dataProvider) === null || _this$dataProvider3 === void 0 ? void 0 : _this$dataProvider3.generateResourceIdForReference(resourceId)) !== null && _this$dataProvider$ge2 !== void 0 ? _this$dataProvider$ge2 : resourceId;
714
720
  sourceToReferenceMap.set(referenceResourceId, resourceId);
715
721
  return {
716
722
  type: 'bodiedSyncBlock',
@@ -209,7 +209,7 @@ export const buildFetchErrorAttribution = (error, statusCode, deferred) => {
209
209
  * buckets like `source_deleted` they never emit.
210
210
  */
211
211
 
212
- export function getErrorPayload(actionSubjectId, error, resourceId, sourceProduct, attribution) {
212
+ export function getErrorPayload(actionSubjectId, error, resourceId, sourceProduct, attribution, sourceLocation) {
213
213
  return {
214
214
  action: ACTION.ERROR,
215
215
  actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
@@ -223,6 +223,9 @@ export function getErrorPayload(actionSubjectId, error, resourceId, sourceProduc
223
223
  ...(sourceProduct && {
224
224
  sourceProduct
225
225
  }),
226
+ ...(sourceLocation && {
227
+ sourceLocation
228
+ }),
226
229
  ...((attribution === null || attribution === void 0 ? void 0 : attribution.reason) && {
227
230
  reason: attribution.reason
228
231
  }),
@@ -249,10 +252,10 @@ export const fetchErrorPayload = (error, resourceId, sourceProduct, attribution)
249
252
  // attribution it hits the fetch overload (wider `reason`); without it, the
250
253
  // no-attribution overload. Both produce a fetch event regardless.
251
254
  attribution ? getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct, attribution) : getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct);
252
- export const getSourceInfoErrorPayload = (error, resourceId, sourceProduct) => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error, resourceId, sourceProduct);
255
+ export const getSourceInfoErrorPayload = (error, resourceId, sourceProduct, sourceLocation) => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error, resourceId, sourceProduct, undefined, sourceLocation);
253
256
  export const updateErrorPayload = (error, resourceId, sourceProduct, attribution) => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE, error, resourceId, sourceProduct, attribution);
254
257
  export const updateReferenceErrorPayload = (error, resourceId, sourceProduct, attribution) => getErrorPayload(ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_UPDATE, error, resourceId, sourceProduct, attribution);
255
- export const createErrorPayload = (error, resourceId, sourceProduct, attribution) => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error, resourceId, sourceProduct, attribution);
258
+ export const createErrorPayload = (error, resourceId, sourceProduct, attribution, sourceLocation) => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error, resourceId, sourceProduct, attribution, sourceLocation);
256
259
  export const deleteErrorPayload = (error, resourceId, sourceProduct, attribution) => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_DELETE, error, resourceId, sourceProduct, attribution);
257
260
  export const updateCacheErrorPayload = (error, resourceId, sourceProduct) => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE_CACHE, error, resourceId, sourceProduct);
258
261
  /**
@@ -316,7 +319,7 @@ export const fetchSuccessPayload = (resourceId, blockInstanceId, sourceProduct)
316
319
  })
317
320
  }
318
321
  });
319
- export const createSuccessPayload = (resourceId, sourceProduct) => {
322
+ export const createSuccessPayload = (resourceId, sourceProduct, sourceLocation) => {
320
323
  return {
321
324
  action: ACTION.INSERTED,
322
325
  actionSubject: ACTION_SUBJECT.DOCUMENT,
@@ -326,6 +329,9 @@ export const createSuccessPayload = (resourceId, sourceProduct) => {
326
329
  resourceId,
327
330
  ...(sourceProduct && {
328
331
  sourceProduct
332
+ }),
333
+ ...(sourceLocation && {
334
+ sourceLocation
329
335
  })
330
336
  }
331
337
  };
@@ -343,7 +349,7 @@ export const createSuccessPayload = (resourceId, sourceProduct) => {
343
349
  * Operational `syncedBlockCreate` success event with the `blockInstanceId` join key and,
344
350
  * when available, the `inputMethod`, `createdEmpty`, and `nodeTypes` creation signals.
345
351
  */
346
- export const createSuccessOperationalPayload = (resourceId, blockInstanceId, sourceProduct, enrichment) => {
352
+ export const createSuccessOperationalPayload = (resourceId, blockInstanceId, sourceProduct, enrichment, sourceLocation) => {
347
353
  var _enrichment$nodeTypes;
348
354
  return {
349
355
  action: ACTION.INSERTED,
@@ -366,6 +372,9 @@ export const createSuccessOperationalPayload = (resourceId, blockInstanceId, sou
366
372
  }),
367
373
  ...((enrichment === null || enrichment === void 0 ? void 0 : (_enrichment$nodeTypes = enrichment.nodeTypes) === null || _enrichment$nodeTypes === void 0 ? void 0 : _enrichment$nodeTypes.length) && {
368
374
  nodeTypes: enrichment.nodeTypes
375
+ }),
376
+ ...(sourceLocation && {
377
+ sourceLocation
369
378
  })
370
379
  }
371
380
  };
@@ -1,5 +1,7 @@
1
1
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
2
- import { getLocationScope } from '../clients/block-service/ari';
2
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
3
+ import { getLocationScope, getProductFromSourceAri } from '../clients/block-service/ari';
4
+ import { JIRA_DESCRIPTION_FIELD_ID, parseJiraFieldLocation } from '../clients/jira/ari';
3
5
  /**
4
6
  * The product check runs first so a Confluence-only document never reads the experiment.
5
7
  */
@@ -18,4 +20,27 @@ export const getFieldAwareLocationScope = ({
18
20
  documentAri,
19
21
  hostAri
20
22
  })
21
- } : undefined;
23
+ } : undefined;
24
+
25
+ /**
26
+ * Analytics `sourceLocation` for a source ARI: `undefined` for non-Jira sources and for the
27
+ * control cohort, so events outside the experiment keep their current shape.
28
+ *
29
+ * The `platform_editor_blocks_patch_13` gate runs first: with it off this returns `undefined`
30
+ * without the product check or the experiment read, so no new exposure is logged.
31
+ */
32
+ export const getSourceLocation = sourceAri => {
33
+ if (!fg('platform_editor_blocks_patch_13')) {
34
+ return undefined;
35
+ }
36
+ if (!sourceAri || !isFieldAwareJiraLocation(getProductFromSourceAri(sourceAri))) {
37
+ return undefined;
38
+ }
39
+ const location = parseJiraFieldLocation({
40
+ ari: sourceAri
41
+ });
42
+ if (!location) {
43
+ return undefined;
44
+ }
45
+ return location.fieldId === JIRA_DESCRIPTION_FIELD_ID ? 'description' : 'custom-field';
46
+ };
@@ -63,7 +63,7 @@ export var getJiraIssueAriFromSourceAri = function getJiraIssueAriFromSourceAri(
63
63
  }
64
64
  return ari;
65
65
  };
66
- var JIRA_DESCRIPTION_FIELD_ID = 'description';
66
+ export var JIRA_DESCRIPTION_FIELD_ID = 'description';
67
67
 
68
68
  /**
69
69
  * One synced block location on a Jira work item, parsed once from its document ARI.
@@ -14,6 +14,8 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
14
14
  * `same-parent-document` is another field of the host work item.
15
15
  */
16
16
 
17
+ /** Which Jira work item field holds a source block. */
18
+
17
19
  export var SyncBlockError = /*#__PURE__*/function (SyncBlockError) {
18
20
  SyncBlockError["Errored"] = "errored";
19
21
  SyncBlockError["NotFound"] = "not_found";
@@ -381,6 +381,12 @@ export var SyncedBlockProvider = /*#__PURE__*/function (_SyncBlockDataProvide) {
381
381
  }
382
382
  return fetchSyncBlockSourceInfo;
383
383
  }())
384
+ }, {
385
+ key: "getParentAri",
386
+ value: function getParentAri() {
387
+ var _this$writeProvider5;
388
+ return (_this$writeProvider5 = this.writeProvider) === null || _this$writeProvider5 === void 0 ? void 0 : _this$writeProvider5.parentAri;
389
+ }
384
390
  }, {
385
391
  key: "generateResourceId",
386
392
  value: function generateResourceId() {
@@ -16,6 +16,7 @@ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-e
16
16
  import { isProviderNotReadyError, ProviderNotReadyError, SyncBlockError } from '../common/types';
17
17
  import { buildErrorAttribution, buildFetchErrorAttribution, cacheDeletionForcedPayload, fetchErrorPayload, fetchSuccessPayload, getSourceInfoErrorPayload, sourceInfoOrphanedPayload, updateReferenceErrorPayload } from '../utils/errorHandling';
18
18
  import { getFetchExperience, getFetchSourceInfoExperience, getSaveReferenceExperience } from '../utils/experienceTracking';
19
+ import { getSourceLocation } from '../utils/fieldAwareLocations';
19
20
  import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
20
21
  import { parseResourceId } from '../utils/resourceId';
21
22
  import { createSyncBlockNode, getSourceProductFromResourceIdSafe, normalizeSyncBlockJSONContent } from '../utils/utils';
@@ -433,15 +434,26 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
433
434
  (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 || _this$fireAnalyticsEv3.call(this, getSourceInfoErrorPayload('SourceAri, product or blockInstanceId missing', resourceId, sourceProduct));
434
435
  return Promise.resolve(undefined);
435
436
  }
437
+ var sourceLocation = getSourceLocation(sourceAri);
438
+ // Undefined with `platform_editor_blocks_patch_13` off, so experience calls below keep
439
+ // exactly their previous arguments (no `metadata` key, `success()` without arguments).
440
+ var experienceMetadata = sourceLocation && {
441
+ sourceLocation: sourceLocation
442
+ };
443
+ var withExperienceMetadata = function withExperienceMetadata(options) {
444
+ return experienceMetadata ? _objectSpread(_objectSpread({}, options), {}, {
445
+ metadata: experienceMetadata
446
+ }) : options;
447
+ };
436
448
  (_this$fetchSourceInfo = this.fetchSourceInfoExperience) === null || _this$fetchSourceInfo === void 0 || _this$fetchSourceInfo.start({});
437
449
  var sourceInfoPromise = this.dataProvider.fetchSyncBlockSourceInfo(blockInstanceId, sourceAri, product, true // hasAccess
438
450
  ).then(function (sourceInfo) {
439
451
  if (!sourceInfo) {
440
452
  var _this2$fetchSourceInf, _this2$fireAnalyticsE;
441
- (_this2$fetchSourceInf = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf === void 0 || _this2$fetchSourceInf.failure({
453
+ (_this2$fetchSourceInf = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf === void 0 || _this2$fetchSourceInf.failure(withExperienceMetadata({
442
454
  reason: 'No source info returned'
443
- });
444
- (_this2$fireAnalyticsE = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE === void 0 || _this2$fireAnalyticsE.call(_this2, getSourceInfoErrorPayload('No source info returned', resourceId, sourceProduct));
455
+ }));
456
+ (_this2$fireAnalyticsE = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE === void 0 || _this2$fireAnalyticsE.call(_this2, getSourceInfoErrorPayload('No source info returned', resourceId, sourceProduct, sourceLocation));
445
457
  return undefined;
446
458
  }
447
459
  _this2.updateCacheWithSourceInfo(resourceId, sourceInfo);
@@ -449,22 +461,29 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
449
461
  _this2._subscriptionManager.updateSourceTitleSubscriptions(resourceId, sourceInfo.title);
450
462
  }
451
463
  if (sourceInfo.title && sourceInfo.url) {
452
- var _this2$fetchSourceInf2;
453
- (_this2$fetchSourceInf2 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf2 === void 0 || _this2$fetchSourceInf2.success();
464
+ if (experienceMetadata) {
465
+ var _this2$fetchSourceInf2;
466
+ (_this2$fetchSourceInf2 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf2 === void 0 || _this2$fetchSourceInf2.success({
467
+ metadata: experienceMetadata
468
+ });
469
+ } else {
470
+ var _this2$fetchSourceInf3;
471
+ (_this2$fetchSourceInf3 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf3 === void 0 || _this2$fetchSourceInf3.success();
472
+ }
454
473
  } else {
455
- var _this2$fetchSourceInf3, _this2$fireAnalyticsE2;
456
- (_this2$fetchSourceInf3 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf3 === void 0 || _this2$fetchSourceInf3.failure({
474
+ var _this2$fetchSourceInf4, _this2$fireAnalyticsE2;
475
+ (_this2$fetchSourceInf4 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf4 === void 0 || _this2$fetchSourceInf4.failure(withExperienceMetadata({
457
476
  reason: 'Missing title or url'
458
- });
459
- (_this2$fireAnalyticsE2 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE2 === void 0 || _this2$fireAnalyticsE2.call(_this2, getSourceInfoErrorPayload('Missing title or url', resourceId, sourceProduct));
477
+ }));
478
+ (_this2$fireAnalyticsE2 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE2 === void 0 || _this2$fireAnalyticsE2.call(_this2, getSourceInfoErrorPayload('Missing title or url', resourceId, sourceProduct, sourceLocation));
460
479
  }
461
480
  return sourceInfo;
462
481
  }).catch(function (error) {
463
- var _this2$fetchSourceInf4, _this2$fireAnalyticsE3;
464
- (_this2$fetchSourceInf4 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf4 === void 0 || _this2$fetchSourceInf4.failure({
482
+ var _this2$fetchSourceInf5, _this2$fireAnalyticsE3;
483
+ (_this2$fetchSourceInf5 = _this2.fetchSourceInfoExperience) === null || _this2$fetchSourceInf5 === void 0 || _this2$fetchSourceInf5.failure(withExperienceMetadata({
465
484
  reason: error.message
466
- });
467
- (_this2$fireAnalyticsE3 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE3 === void 0 || _this2$fireAnalyticsE3.call(_this2, getSourceInfoErrorPayload(error.message, resourceId, sourceProduct));
485
+ }));
486
+ (_this2$fireAnalyticsE3 = _this2.fireAnalyticsEvent) === null || _this2$fireAnalyticsE3 === void 0 || _this2$fireAnalyticsE3.call(_this2, getSourceInfoErrorPayload(error.message, resourceId, sourceProduct, sourceLocation));
468
487
  return undefined;
469
488
  }).finally(function () {
470
489
  _this2.syncBlockSourceInfoRequests.delete(resourceId);
@@ -17,6 +17,7 @@ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-e
17
17
  import { SyncBlockError } from '../common/types';
18
18
  import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, createSuccessOperationalPayload, addContentSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload, buildErrorAttribution } from '../utils/errorHandling';
19
19
  import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
20
+ import { getSourceLocation as _getSourceLocation } from '../utils/fieldAwareLocations';
20
21
  import { convertSyncBlockPMNodeToSyncBlockData, getSourceProductFromResourceIdSafe } from '../utils/utils';
21
22
  /** Maximum time (ms) flush() will wait for in-flight block creations before proceeding. */
22
23
  var FLUSH_CREATION_AWAIT_TIMEOUT_MS = 1000;
@@ -487,16 +488,17 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
487
488
  }
488
489
  } else {
489
490
  var _this$fireAnalyticsEv3;
490
- (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 || _this$fireAnalyticsEv3.call(this, createErrorPayload('creation complete callback missing', resourceId, getSourceProductFromResourceIdSafe(resourceId)));
491
+ (_this$fireAnalyticsEv3 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv3 === void 0 || _this$fireAnalyticsEv3.call(this, createErrorPayload('creation complete callback missing', resourceId, getSourceProductFromResourceIdSafe(resourceId), undefined, this.getSourceLocation()));
491
492
  }
492
493
  if (success) {
493
494
  var _this$dataProvider$ge, _this$dataProvider, _this$fireAnalyticsEv4, _this$fireAnalyticsEv5, _this$syncBlockCache$2;
494
495
  var sourceProduct = getSourceProductFromResourceIdSafe(resourceId);
496
+ var sourceLocation = this.getSourceLocation();
495
497
  var documentInsertedResourceId = (_this$dataProvider$ge = (_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.generateResourceIdForReference(resourceId)) !== null && _this$dataProvider$ge !== void 0 ? _this$dataProvider$ge : resourceId;
496
- (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 || _this$fireAnalyticsEv4.call(this, createSuccessPayload(documentInsertedResourceId || '', sourceProduct));
498
+ (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 || _this$fireAnalyticsEv4.call(this, createSuccessPayload(documentInsertedResourceId || '', sourceProduct, sourceLocation));
497
499
  // Operational create-success event with the join key + creation-type
498
500
  // signals (inputMethod / createdEmpty / nodeTypes) captured at the command layer.
499
- (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 || _this$fireAnalyticsEv5.call(this, createSuccessOperationalPayload(resourceId || '', (_this$syncBlockCache$2 = this.syncBlockCache.get(resourceId)) === null || _this$syncBlockCache$2 === void 0 ? void 0 : _this$syncBlockCache$2.blockInstanceId, sourceProduct, this.creationEnrichment.get(resourceId)));
501
+ (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 || _this$fireAnalyticsEv5.call(this, createSuccessOperationalPayload(resourceId || '', (_this$syncBlockCache$2 = this.syncBlockCache.get(resourceId)) === null || _this$syncBlockCache$2 === void 0 ? void 0 : _this$syncBlockCache$2.blockInstanceId, sourceProduct, this.creationEnrichment.get(resourceId), sourceLocation));
500
502
  } else {
501
503
  var _this$fireAnalyticsEv6;
502
504
  // Delete the node from cache if fail to create so it's not flushed to BE
@@ -506,7 +508,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
506
508
  // Creation failed, so there is no block to add content to — drop the
507
509
  // first-content tracking entry so a later unrelated edit cannot fire it.
508
510
  this.awaitingFirstContent.delete(resourceId || '');
509
- (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 || _this$fireAnalyticsEv6.call(this, createErrorPayload('Fail to create bodied sync block', resourceId, getSourceProductFromResourceIdSafe(resourceId)));
511
+ (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 || _this$fireAnalyticsEv6.call(this, createErrorPayload('Fail to create bodied sync block', resourceId, getSourceProductFromResourceIdSafe(resourceId), undefined, this.getSourceLocation()));
510
512
  }
511
513
  // Enrichment is single-use — drop it once the create has resolved either way.
512
514
  this.creationEnrichment.delete(resourceId || '');
@@ -628,7 +630,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
628
630
  (_this5$createExperien2 = _this5.createExperience) === null || _this5$createExperien2 === void 0 || _this5$createExperien2.failure({
629
631
  reason: result.error || 'Failed to create bodied sync block'
630
632
  });
631
- (_this5$fireAnalyticsE = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE === void 0 || _this5$fireAnalyticsE.call(_this5, createErrorPayload(result.error || 'Failed to create bodied sync block', resourceId, getSourceProductFromResourceIdSafe(resourceId), buildErrorAttribution(result.error, result.statusCode)));
633
+ (_this5$fireAnalyticsE = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE === void 0 || _this5$fireAnalyticsE.call(_this5, createErrorPayload(result.error || 'Failed to create bodied sync block', resourceId, getSourceProductFromResourceIdSafe(resourceId), buildErrorAttribution(result.error, result.statusCode), _this5.getSourceLocation()));
632
634
  }
633
635
  }).catch(function (error) {
634
636
  var _this5$createExperien3, _this5$fireAnalyticsE2;
@@ -639,7 +641,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
639
641
  (_this5$createExperien3 = _this5.createExperience) === null || _this5$createExperien3 === void 0 || _this5$createExperien3.failure({
640
642
  reason: error.message
641
643
  });
642
- (_this5$fireAnalyticsE2 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE2 === void 0 || _this5$fireAnalyticsE2.call(_this5, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
644
+ (_this5$fireAnalyticsE2 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE2 === void 0 || _this5$fireAnalyticsE2.call(_this5, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId), undefined, _this5.getSourceLocation()));
643
645
  }).finally(function () {
644
646
  _this5.pendingCreationPromises.delete(resourceId);
645
647
  });
@@ -653,9 +655,15 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
653
655
  logException(error, {
654
656
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
655
657
  });
656
- (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 || _this$fireAnalyticsEv8.call(this, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
658
+ (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 || _this$fireAnalyticsEv8.call(this, createErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId), undefined, this.getSourceLocation()));
657
659
  }
658
660
  }
661
+ }, {
662
+ key: "getSourceLocation",
663
+ value: function getSourceLocation() {
664
+ var _this$dataProvider2, _this$dataProvider2$g;
665
+ return _getSourceLocation((_this$dataProvider2 = this.dataProvider) === null || _this$dataProvider2 === void 0 || (_this$dataProvider2$g = _this$dataProvider2.getParentAri) === null || _this$dataProvider2$g === void 0 ? void 0 : _this$dataProvider2$g.call(_this$dataProvider2));
666
+ }
659
667
  }, {
660
668
  key: "pruneRecentDeleteEmissions",
661
669
  value:
@@ -212,18 +212,20 @@ export var buildFetchErrorAttribution = function buildFetchErrorAttribution(erro
212
212
  * buckets like `source_deleted` they never emit.
213
213
  */
214
214
 
215
- export function getErrorPayload(actionSubjectId, error, resourceId, sourceProduct, attribution) {
215
+ export function getErrorPayload(actionSubjectId, error, resourceId, sourceProduct, attribution, sourceLocation) {
216
216
  return {
217
217
  action: ACTION.ERROR,
218
218
  actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
219
219
  actionSubjectId: actionSubjectId,
220
220
  eventType: EVENT_TYPE.OPERATIONAL,
221
- attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
221
+ attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
222
222
  error: error
223
223
  }, resourceId && {
224
224
  resourceId: resourceId
225
225
  }), sourceProduct && {
226
226
  sourceProduct: sourceProduct
227
+ }), sourceLocation && {
228
+ sourceLocation: sourceLocation
227
229
  }), (attribution === null || attribution === void 0 ? void 0 : attribution.reason) && {
228
230
  reason: attribution.reason
229
231
  }), (attribution === null || attribution === void 0 ? void 0 : attribution.statusCode) !== undefined && {
@@ -243,8 +245,8 @@ export var fetchErrorPayload = function fetchErrorPayload(error, resourceId, sou
243
245
  attribution ? getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct, attribution) : getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct)
244
246
  );
245
247
  };
246
- export var getSourceInfoErrorPayload = function getSourceInfoErrorPayload(error, resourceId, sourceProduct) {
247
- return getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error, resourceId, sourceProduct);
248
+ export var getSourceInfoErrorPayload = function getSourceInfoErrorPayload(error, resourceId, sourceProduct, sourceLocation) {
249
+ return getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error, resourceId, sourceProduct, undefined, sourceLocation);
248
250
  };
249
251
  export var updateErrorPayload = function updateErrorPayload(error, resourceId, sourceProduct, attribution) {
250
252
  return getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE, error, resourceId, sourceProduct, attribution);
@@ -252,8 +254,8 @@ export var updateErrorPayload = function updateErrorPayload(error, resourceId, s
252
254
  export var updateReferenceErrorPayload = function updateReferenceErrorPayload(error, resourceId, sourceProduct, attribution) {
253
255
  return getErrorPayload(ACTION_SUBJECT_ID.REFERENCE_SYNCED_BLOCK_UPDATE, error, resourceId, sourceProduct, attribution);
254
256
  };
255
- export var createErrorPayload = function createErrorPayload(error, resourceId, sourceProduct, attribution) {
256
- return getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error, resourceId, sourceProduct, attribution);
257
+ export var createErrorPayload = function createErrorPayload(error, resourceId, sourceProduct, attribution, sourceLocation) {
258
+ return getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE, error, resourceId, sourceProduct, attribution, sourceLocation);
257
259
  };
258
260
  export var deleteErrorPayload = function deleteErrorPayload(error, resourceId, sourceProduct, attribution) {
259
261
  return getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_DELETE, error, resourceId, sourceProduct, attribution);
@@ -322,16 +324,18 @@ export var fetchSuccessPayload = function fetchSuccessPayload(resourceId, blockI
322
324
  })
323
325
  };
324
326
  };
325
- export var createSuccessPayload = function createSuccessPayload(resourceId, sourceProduct) {
327
+ export var createSuccessPayload = function createSuccessPayload(resourceId, sourceProduct, sourceLocation) {
326
328
  return {
327
329
  action: ACTION.INSERTED,
328
330
  actionSubject: ACTION_SUBJECT.DOCUMENT,
329
331
  actionSubjectId: ACTION_SUBJECT_ID.BODIED_SYNCED_BLOCK,
330
332
  eventType: EVENT_TYPE.TRACK,
331
- attributes: _objectSpread({
333
+ attributes: _objectSpread(_objectSpread({
332
334
  resourceId: resourceId
333
335
  }, sourceProduct && {
334
336
  sourceProduct: sourceProduct
337
+ }), sourceLocation && {
338
+ sourceLocation: sourceLocation
335
339
  })
336
340
  };
337
341
  };
@@ -348,14 +352,14 @@ export var createSuccessPayload = function createSuccessPayload(resourceId, sour
348
352
  * Operational `syncedBlockCreate` success event with the `blockInstanceId` join key and,
349
353
  * when available, the `inputMethod`, `createdEmpty`, and `nodeTypes` creation signals.
350
354
  */
351
- export var createSuccessOperationalPayload = function createSuccessOperationalPayload(resourceId, blockInstanceId, sourceProduct, enrichment) {
355
+ export var createSuccessOperationalPayload = function createSuccessOperationalPayload(resourceId, blockInstanceId, sourceProduct, enrichment, sourceLocation) {
352
356
  var _enrichment$nodeTypes;
353
357
  return {
354
358
  action: ACTION.INSERTED,
355
359
  actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
356
360
  actionSubjectId: ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
357
361
  eventType: EVENT_TYPE.OPERATIONAL,
358
- attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
362
+ attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
359
363
  resourceId: resourceId
360
364
  }, blockInstanceId && {
361
365
  blockInstanceId: blockInstanceId
@@ -367,6 +371,8 @@ export var createSuccessOperationalPayload = function createSuccessOperationalPa
367
371
  createdEmpty: enrichment.createdEmpty
368
372
  }), (enrichment === null || enrichment === void 0 || (_enrichment$nodeTypes = enrichment.nodeTypes) === null || _enrichment$nodeTypes === void 0 ? void 0 : _enrichment$nodeTypes.length) && {
369
373
  nodeTypes: enrichment.nodeTypes
374
+ }), sourceLocation && {
375
+ sourceLocation: sourceLocation
370
376
  })
371
377
  };
372
378
  };
@@ -1,5 +1,7 @@
1
1
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
2
- import { getLocationScope } from '../clients/block-service/ari';
2
+ import { fg } from '@atlaskit/platform-feature-flags/fg';
3
+ import { getLocationScope, getProductFromSourceAri } from '../clients/block-service/ari';
4
+ import { JIRA_DESCRIPTION_FIELD_ID, parseJiraFieldLocation } from '../clients/jira/ari';
3
5
  /**
4
6
  * The product check runs first so a Confluence-only document never reads the experiment.
5
7
  */
@@ -21,4 +23,27 @@ export var getFieldAwareLocationScope = function getFieldAwareLocationScope(_ref
21
23
  hostAri: hostAri
22
24
  })
23
25
  } : undefined;
26
+ };
27
+
28
+ /**
29
+ * Analytics `sourceLocation` for a source ARI: `undefined` for non-Jira sources and for the
30
+ * control cohort, so events outside the experiment keep their current shape.
31
+ *
32
+ * The `platform_editor_blocks_patch_13` gate runs first: with it off this returns `undefined`
33
+ * without the product check or the experiment read, so no new exposure is logged.
34
+ */
35
+ export var getSourceLocation = function getSourceLocation(sourceAri) {
36
+ if (!fg('platform_editor_blocks_patch_13')) {
37
+ return undefined;
38
+ }
39
+ if (!sourceAri || !isFieldAwareJiraLocation(getProductFromSourceAri(sourceAri))) {
40
+ return undefined;
41
+ }
42
+ var location = parseJiraFieldLocation({
43
+ ari: sourceAri
44
+ });
45
+ if (!location) {
46
+ return undefined;
47
+ }
48
+ return location.fieldId === JIRA_DESCRIPTION_FIELD_ID ? 'description' : 'custom-field';
24
49
  };
@@ -26,6 +26,7 @@ export declare const getJiraWorkItemIdFromAri: ({ ari }: {
26
26
  export declare const getJiraIssueAriFromSourceAri: ({ ari }: {
27
27
  ari: string;
28
28
  }) => string;
29
+ export declare const JIRA_DESCRIPTION_FIELD_ID = "description";
29
30
  /**
30
31
  * One synced block location on a Jira work item, parsed once from its document ARI.
31
32
  * Two locations name the same field when both members match, whichever of the two ARI
@@ -12,6 +12,8 @@ export type SyncBlockStatus = 'active' | 'deleted' | 'unpublished';
12
12
  * `same-parent-document` is another field of the host work item.
13
13
  */
14
14
  export type SyncBlockLocationScope = 'same-document' | 'same-parent-document' | 'elsewhere';
15
+ /** Which Jira work item field holds a source block. */
16
+ export type SyncBlockSourceLocation = 'description' | 'custom-field';
15
17
  export type SyncBlockAttrs = {
16
18
  localId: BlockInstanceId;
17
19
  resourceId: ResourceId;
@@ -69,6 +69,7 @@ export declare class SyncedBlockProvider extends SyncBlockDataProviderInterface
69
69
  * @returns The source info
70
70
  */
71
71
  fetchSyncBlockSourceInfo(localId?: BlockInstanceId, sourceAri?: string, sourceProduct?: SyncBlockProduct, hasAccess?: boolean): Promise<SyncBlockSourceInfo | undefined>;
72
+ getParentAri(): string | undefined;
72
73
  generateResourceId(): {
73
74
  localId: BlockInstanceId;
74
75
  resourceId: ResourceId;
@@ -205,6 +205,10 @@ export declare abstract class SyncBlockDataProviderInterface extends NodeDataPro
205
205
  abstract fetchSyncBlockSourceInfo(localId?: BlockInstanceId, sourceAri?: string, sourceProduct?: SyncBlockProduct, hasAccess?: boolean): Promise<SyncBlockSourceInfo | undefined>;
206
206
  abstract setProviderOptions(providerOptions: SyncedBlockRendererProviderOptions): void;
207
207
  abstract getSyncedBlockRendererProviderOptions(): SyncedBlockRendererProviderOptions;
208
+ /**
209
+ * ARI of the document that new source blocks are created in, when a write provider is set.
210
+ */
211
+ getParentAri?(): string | undefined;
208
212
  abstract retrieveSyncBlockParentInfo(sourceAri: string, sourceProduct: SyncBlockProduct): SyncBlockParentInfo | undefined;
209
213
  /**
210
214
  * Generates a resource ID for source synced block.
@@ -144,6 +144,7 @@ export declare class SourceSyncBlockStoreManager {
144
144
  * first-content-added event.
145
145
  */
146
146
  createBodiedSyncBlockNode(attrs: SyncBlockAttrs, node: PMNode, onCompletion: OnCompletion, enrichment?: CreateSuccessEnrichment): void;
147
+ private getSourceLocation;
147
148
  private setPendingDeletion;
148
149
  /**
149
150
  * Drop dedupe entries older than {@link DELETE_DEDUPE_WINDOW_MS} so
@@ -3,7 +3,7 @@ import type { INPUT_METHOD } from '@atlaskit/editor-common/analytics/types/enums
3
3
  import type { RendererSyncBlockEventPayload, SyncBlockEventPayload } from '@atlaskit/editor-common/analytics/types/sync-block-events';
4
4
  import type { OperationalAEP } from '@atlaskit/editor-common/analytics/types/utils';
5
5
  import { SyncBlockError } from '../common/types';
6
- import type { DeletionMechanism, DeletionReason } from '../common/types';
6
+ import type { DeletionMechanism, DeletionReason, SyncBlockSourceLocation } from '../common/types';
7
7
  export declare const stringifyError: (error: unknown) => string | undefined;
8
8
  /**
9
9
  * PII-safe extraction of `message`/`name` from an unknown caught error, used to
@@ -134,27 +134,29 @@ export declare const buildFetchErrorAttribution: (error?: string, statusCode?: n
134
134
  * {@link SyncBlockErrorReason}, so write-path payloads never claim to carry fetch-only
135
135
  * buckets like `source_deleted` they never emit.
136
136
  */
137
- export declare function getErrorPayload<T extends ACTION_SUBJECT_ID>(actionSubjectId: T, error: string, resourceId: string | undefined, sourceProduct: string | undefined, attribution: FetchErrorAttributionAttributes): OperationalAEP<ACTION.ERROR, ACTION_SUBJECT.SYNCED_BLOCK, T, {
137
+ export declare function getErrorPayload<T extends ACTION_SUBJECT_ID>(actionSubjectId: T, error: string, resourceId: string | undefined, sourceProduct: string | undefined, attribution: FetchErrorAttributionAttributes, sourceLocation?: SyncBlockSourceLocation): OperationalAEP<ACTION.ERROR, ACTION_SUBJECT.SYNCED_BLOCK, T, {
138
138
  error: string;
139
139
  resourceId?: string;
140
140
  sourceProduct?: string;
141
+ sourceLocation?: SyncBlockSourceLocation;
141
142
  reason?: SyncBlockFetchErrorReason;
142
143
  statusCode?: number;
143
144
  benign?: boolean;
144
145
  deferred?: boolean;
145
146
  }>;
146
- export declare function getErrorPayload<T extends ACTION_SUBJECT_ID>(actionSubjectId: T, error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes): OperationalAEP<ACTION.ERROR, ACTION_SUBJECT.SYNCED_BLOCK, T, {
147
+ export declare function getErrorPayload<T extends ACTION_SUBJECT_ID>(actionSubjectId: T, error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes, sourceLocation?: SyncBlockSourceLocation): OperationalAEP<ACTION.ERROR, ACTION_SUBJECT.SYNCED_BLOCK, T, {
147
148
  error: string;
148
149
  resourceId?: string;
149
150
  sourceProduct?: string;
151
+ sourceLocation?: SyncBlockSourceLocation;
150
152
  reason?: SyncBlockErrorReason;
151
153
  statusCode?: number;
152
154
  }>;
153
155
  export declare const fetchErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, attribution?: FetchErrorAttributionAttributes) => RendererSyncBlockEventPayload;
154
- export declare const getSourceInfoErrorPayload: (error: string, resourceId?: string, sourceProduct?: string) => RendererSyncBlockEventPayload;
156
+ export declare const getSourceInfoErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, sourceLocation?: SyncBlockSourceLocation) => RendererSyncBlockEventPayload;
155
157
  export declare const updateErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes) => SyncBlockEventPayload;
156
158
  export declare const updateReferenceErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes) => RendererSyncBlockEventPayload;
157
- export declare const createErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes) => SyncBlockEventPayload;
159
+ export declare const createErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes, sourceLocation?: SyncBlockSourceLocation) => SyncBlockEventPayload;
158
160
  export declare const deleteErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes) => SyncBlockEventPayload;
159
161
  export declare const updateCacheErrorPayload: (error: string, resourceId?: string, sourceProduct?: string) => SyncBlockEventPayload;
160
162
  /**
@@ -173,7 +175,7 @@ export declare const sourceInfoOrphanedPayload: (resourceId?: string, sourceProd
173
175
  export declare const cacheDeletionForcedPayload: (rescheduleCount: number, resourceId?: string, sourceProduct?: string) => RendererSyncBlockEventPayload;
174
176
  export declare const fetchReferencesErrorPayload: (error: string, resourceId?: string, sourceProduct?: string) => SyncBlockEventPayload;
175
177
  export declare const fetchSuccessPayload: (resourceId: string, blockInstanceId?: string, sourceProduct?: string) => RendererSyncBlockEventPayload;
176
- export declare const createSuccessPayload: (resourceId: string, sourceProduct?: string) => SyncBlockEventPayload;
178
+ export declare const createSuccessPayload: (resourceId: string, sourceProduct?: string, sourceLocation?: SyncBlockSourceLocation) => SyncBlockEventPayload;
177
179
  /**
178
180
  * Optional enrichment for the `syncedBlockCreate` success event. All fields
179
181
  * optional so legacy payloads are unchanged. `inputMethod`: creating
@@ -190,7 +192,7 @@ export type CreateSuccessEnrichment = {
190
192
  * Operational `syncedBlockCreate` success event with the `blockInstanceId` join key and,
191
193
  * when available, the `inputMethod`, `createdEmpty`, and `nodeTypes` creation signals.
192
194
  */
193
- export declare const createSuccessOperationalPayload: (resourceId: string, blockInstanceId?: string, sourceProduct?: string, enrichment?: CreateSuccessEnrichment) => SyncBlockEventPayload;
195
+ export declare const createSuccessOperationalPayload: (resourceId: string, blockInstanceId?: string, sourceProduct?: string, enrichment?: CreateSuccessEnrichment, sourceLocation?: SyncBlockSourceLocation) => SyncBlockEventPayload;
194
196
  /**
195
197
  * Operational first-content-added event. Fired once when a block created empty first
196
198
  * gains user content. Join keys only (`resourceId` + `blockInstanceId`), no user
@@ -1,4 +1,4 @@
1
- import type { SyncBlockLocationScope, SyncBlockProduct } from '../common/types';
1
+ import type { SyncBlockLocationScope, SyncBlockProduct, SyncBlockSourceLocation } from '../common/types';
2
2
  /**
3
3
  * The product check runs first so a Confluence-only document never reads the experiment.
4
4
  */
@@ -14,3 +14,11 @@ export declare const getFieldAwareLocationScope: ({ documentAri, hostAri, produc
14
14
  }) => {
15
15
  locationScope: SyncBlockLocationScope;
16
16
  } | undefined;
17
+ /**
18
+ * Analytics `sourceLocation` for a source ARI: `undefined` for non-Jira sources and for the
19
+ * control cohort, so events outside the experiment keep their current shape.
20
+ *
21
+ * The `platform_editor_blocks_patch_13` gate runs first: with it off this returns `undefined`
22
+ * without the product check or the experiment read, so no new exposure is logged.
23
+ */
24
+ export declare const getSourceLocation: (sourceAri: string | undefined) => SyncBlockSourceLocation | undefined;
package/package.json CHANGED
@@ -42,11 +42,16 @@
42
42
  "react-dom": "^19.2.0"
43
43
  },
44
44
  "name": "@atlaskit/editor-synced-block-provider",
45
- "version": "23.0.5",
45
+ "version": "23.1.0",
46
46
  "description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
47
47
  "author": "Atlassian Pty Ltd",
48
48
  "license": "Apache-2.0",
49
49
  "publishConfig": {
50
50
  "registry": "https://registry.npmjs.org/"
51
+ },
52
+ "platform-feature-flags": {
53
+ "platform_editor_blocks_patch_13": {
54
+ "type": "boolean"
55
+ }
51
56
  }
52
57
  }