@atlaskit/editor-synced-block-provider 8.4.4 → 8.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,28 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 8.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 8.5.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`ecafba7c81b7d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ecafba7c81b7d) -
14
+ Enrich synced block deletion analytics so source-block deletions can be explained rather than just
15
+ counted. The source `syncedBlockDelete` operational event now carries `deletionReason` and a
16
+ `mechanism` dimension (undo/redo/deleteButton/keyboardDelete/selectionReplaced/other), and
17
+ repeated emissions for the same removal are de-duplicated. A real operational `syncedBlockCreate`
18
+ success event is now emitted, and the source bare-uuid join key is added to the copy event so
19
+ create/copy/delete can be correlated. All new attributes and events are gated behind
20
+ `platform_editor_blocks_patch_4`; gate-off behaviour is unchanged.
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies
25
+
3
26
  ## 8.4.4
4
27
 
5
28
  ### Patch Changes
@@ -34,6 +34,20 @@ var SyncBlockError = exports.SyncBlockError = /*#__PURE__*/function (SyncBlockEr
34
34
  SyncBlockError["EntityNotFound"] = "entity_not_found";
35
35
  return SyncBlockError;
36
36
  }({});
37
+ /**
38
+ * How a source bodiedSyncBlock removal was performed, derived from the
39
+ * originating transaction. Distinct from {@link DeletionReason} (the outcome):
40
+ * `mechanism` tells deliberate deletes apart from undos and accidental overwrites.
41
+ *
42
+ * Values name the user action that produced the removal:
43
+ * - `undo` / `redo` — removal came from a history undo/redo.
44
+ * - `deleteButton` — the explicit "Delete" control in the synced-block toolbar.
45
+ * - `keyboardDelete` — Backspace/Delete key on a caret or range selection.
46
+ * - `selectionReplaced` — the block was selected and replaced by typing or
47
+ * pasting over it (the accidental-overwrite path).
48
+ * - `other` — any non-direct removal (unsync, conversion, code-dispatched, or a
49
+ * structural wrap/lift/unwrap edit).
50
+ */
37
51
  /**
38
52
  * Helpers to distinguish "data provider not ready / torn down" from a genuine
39
53
  * fetch/subscribe failure (EDITOR-7860). On Jira the provider is wired
@@ -25,6 +25,14 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
25
25
  /** Maximum time (ms) flush() will wait for in-flight block creations before proceeding. */
26
26
  var FLUSH_CREATION_AWAIT_TIMEOUT_MS = 1000;
27
27
 
28
+ /**
29
+ * Window (ms) within which a repeated `syncedBlockDelete` emission for the same
30
+ * resourceId is suppressed. The same logical removal can re-fire across
31
+ * rebased/remote/redo transactions; a short window collapses those bursts to one
32
+ * event while still allowing a genuine delete→recreate→delete later.
33
+ */
34
+ var DELETE_DEDUPE_WINDOW_MS = 5000;
35
+
28
36
  // A store manager responsible for the lifecycle and state management of source sync blocks in an editor instance.
29
37
  // Designed to manage local in-memory state and synchronize with an external data provider.
30
38
  // Supports create, flush, and delete operations for source sync blocks.
@@ -51,6 +59,12 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
51
59
  * multiple blocks are created concurrently. See EDITOR-7112.
52
60
  */
53
61
  (0, _defineProperty2.default)(this, "creationsTimedOutDuringFlush", new Set());
62
+ /**
63
+ * resourceId -> timestamp (ms) of the last `syncedBlockDelete` emission, used
64
+ * to suppress duplicates within {@link DELETE_DEDUPE_WINDOW_MS}. Only consulted
65
+ * behind `platform_editor_blocks_patch_4`.
66
+ */
67
+ (0, _defineProperty2.default)(this, "recentDeleteEmissions", new Map());
54
68
  (0, _defineProperty2.default)(this, "setPendingDeletion", function (Ids, value) {
55
69
  if (_this.viewMode === 'view') {
56
70
  return;
@@ -395,12 +409,18 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
395
409
  }
396
410
  if (success) {
397
411
  var _this$fireAnalyticsEv4;
398
- (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 || _this$fireAnalyticsEv4.call(this, (0, _errorHandling.createSuccessPayload)(resourceId || '', (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
412
+ var sourceProduct = (0, _utils.getSourceProductFromResourceIdSafe)(resourceId);
413
+ (_this$fireAnalyticsEv4 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv4 === void 0 || _this$fireAnalyticsEv4.call(this, (0, _errorHandling.createSuccessPayload)(resourceId || '', sourceProduct));
414
+ // Operational create-success event with the join key.
415
+ if ((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_4')) {
416
+ var _this$fireAnalyticsEv5, _this$syncBlockCache$;
417
+ (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 || _this$fireAnalyticsEv5.call(this, (0, _errorHandling.createSuccessPayloadNew)(resourceId || '', (_this$syncBlockCache$ = this.syncBlockCache.get(resourceId)) === null || _this$syncBlockCache$ === void 0 ? void 0 : _this$syncBlockCache$.blockInstanceId, sourceProduct));
418
+ }
399
419
  } else {
400
- var _this$fireAnalyticsEv5;
420
+ var _this$fireAnalyticsEv6;
401
421
  // Delete the node from cache if fail to create so it's not flushed to BE
402
422
  this.syncBlockCache.delete(resourceId || '');
403
- (_this$fireAnalyticsEv5 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv5 === void 0 || _this$fireAnalyticsEv5.call(this, (0, _errorHandling.createErrorPayload)('Fail to create bodied sync block', resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
423
+ (_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)));
404
424
  }
405
425
  }
406
426
  }, {
@@ -500,20 +520,76 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
500
520
  });
501
521
  this.pendingCreationPromises.set(resourceId, creationPromise);
502
522
  } catch (error) {
503
- var _this$fireAnalyticsEv6;
523
+ var _this$fireAnalyticsEv7;
504
524
  if (this.isPendingCreation(resourceId)) {
505
525
  this.commitPendingCreation(false, resourceId);
506
526
  }
507
527
  (0, _monitoring.logException)(error, {
508
528
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
509
529
  });
510
- (_this$fireAnalyticsEv6 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv6 === void 0 || _this$fireAnalyticsEv6.call(this, (0, _errorHandling.createErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
530
+ (_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 || _this$fireAnalyticsEv7.call(this, (0, _errorHandling.createErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
511
531
  }
512
532
  }
533
+ }, {
534
+ key: "pruneRecentDeleteEmissions",
535
+ value:
536
+ /**
537
+ * Drop dedupe entries older than {@link DELETE_DEDUPE_WINDOW_MS} so
538
+ * `recentDeleteEmissions` stays bounded by the number of recent deletes.
539
+ */
540
+ function pruneRecentDeleteEmissions(now) {
541
+ var _iterator2 = _createForOfIteratorHelper(this.recentDeleteEmissions),
542
+ _step2;
543
+ try {
544
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
545
+ var _step2$value = (0, _slicedToArray2.default)(_step2.value, 2),
546
+ resourceId = _step2$value[0],
547
+ emittedAt = _step2$value[1];
548
+ if (now - emittedAt >= DELETE_DEDUPE_WINDOW_MS) {
549
+ this.recentDeleteEmissions.delete(resourceId);
550
+ }
551
+ }
552
+ } catch (err) {
553
+ _iterator2.e(err);
554
+ } finally {
555
+ _iterator2.f();
556
+ }
557
+ }
558
+
559
+ /**
560
+ * Emit the `syncedBlockDelete` success event. Gate off: legacy payload. Gate
561
+ * on: attaches `deletionReason`, `mechanism` and `blockInstanceId`, and
562
+ * suppresses repeat emissions within {@link DELETE_DEDUPE_WINDOW_MS}. Must run
563
+ * while the cache entry still exists so `blockInstanceId` is available.
564
+ */
565
+ }, {
566
+ key: "emitDeleteSuccess",
567
+ value: function emitDeleteSuccess(resourceId, reason, mechanism) {
568
+ var _this$syncBlockCache$2, _this$fireAnalyticsEv9;
569
+ var sourceProduct = (0, _utils.getSourceProductFromResourceIdSafe)(resourceId);
570
+ if (!(0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_4')) {
571
+ var _this$fireAnalyticsEv8;
572
+ (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 || _this$fireAnalyticsEv8.call(this, (0, _errorHandling.deleteSuccessPayload)(resourceId, sourceProduct));
573
+ return;
574
+ }
575
+ var now = Date.now();
576
+ var lastEmittedAt = this.recentDeleteEmissions.get(resourceId);
577
+ if (lastEmittedAt !== undefined && now - lastEmittedAt < DELETE_DEDUPE_WINDOW_MS) {
578
+ return; // duplicate emission for the same logical removal
579
+ }
580
+ this.pruneRecentDeleteEmissions(now);
581
+ this.recentDeleteEmissions.set(resourceId, now);
582
+ var enrichment = {
583
+ blockInstanceId: (_this$syncBlockCache$2 = this.syncBlockCache.get(resourceId)) === null || _this$syncBlockCache$2 === void 0 ? void 0 : _this$syncBlockCache$2.blockInstanceId,
584
+ deletionReason: reason,
585
+ mechanism: mechanism
586
+ };
587
+ (_this$fireAnalyticsEv9 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv9 === void 0 || _this$fireAnalyticsEv9.call(this, (0, _errorHandling.deleteSuccessPayload)(resourceId, sourceProduct, enrichment));
588
+ }
513
589
  }, {
514
590
  key: "delete",
515
591
  value: function () {
516
- var _delete2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(syncBlockIds, onDelete, onDeleteCompleted, reason) {
592
+ var _delete2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(syncBlockIds, onDelete, onDeleteCompleted, reason, mechanism) {
517
593
  var _this5 = this;
518
594
  var _this$deleteExperienc, results, callback, isDeleteSuccessful, _this$deleteExperienc2, _this$deleteExperienc3, attributionEnabled, attribution, _t2;
519
595
  return _regenerator.default.wrap(function (_context2) {
@@ -548,15 +624,16 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
548
624
  onDeleteCompleted(isDeleteSuccessful);
549
625
  if (isDeleteSuccessful) {
550
626
  onDelete();
627
+ // Emit before the cache entry is deleted below, so blockInstanceId
628
+ // is still available to emitDeleteSuccess.
629
+ results.forEach(function (result) {
630
+ _this5.emitDeleteSuccess(result.resourceId, reason, mechanism);
631
+ });
551
632
  callback = function callback(Ids) {
552
633
  return _this5.syncBlockCache.delete(Ids.resourceId);
553
634
  };
554
635
  this.clearPendingDeletion();
555
636
  (_this$deleteExperienc2 = this.deleteExperience) === null || _this$deleteExperienc2 === void 0 || _this$deleteExperienc2.success();
556
- results.forEach(function (result) {
557
- var _this5$fireAnalyticsE;
558
- (_this5$fireAnalyticsE = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE === void 0 || _this5$fireAnalyticsE.call(_this5, (0, _errorHandling.deleteSuccessPayload)(result.resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(result.resourceId)));
559
- });
560
637
  } else {
561
638
  callback = function callback(Ids) {
562
639
  _this5.setPendingDeletion(Ids, false);
@@ -565,11 +642,10 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
565
642
  attributionEnabled = (0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3');
566
643
  results.forEach(function (result) {
567
644
  if (result.success) {
568
- var _this5$fireAnalyticsE2;
569
- (_this5$fireAnalyticsE2 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE2 === void 0 || _this5$fireAnalyticsE2.call(_this5, (0, _errorHandling.deleteSuccessPayload)(result.resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(result.resourceId)));
645
+ _this5.emitDeleteSuccess(result.resourceId, reason, mechanism);
570
646
  } else {
571
- var _this5$fireAnalyticsE3;
572
- (_this5$fireAnalyticsE3 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE3 === void 0 || _this5$fireAnalyticsE3.call(_this5, (0, _errorHandling.deleteErrorPayload)(result.error || 'Failed to delete synced block', result.resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(result.resourceId), (0, _errorHandling.buildErrorAttribution)(attributionEnabled, result.error, result.statusCode)));
647
+ var _this5$fireAnalyticsE;
648
+ (_this5$fireAnalyticsE = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE === void 0 || _this5$fireAnalyticsE.call(_this5, (0, _errorHandling.deleteErrorPayload)(result.error || 'Failed to delete synced block', result.resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(result.resourceId), (0, _errorHandling.buildErrorAttribution)(attributionEnabled, result.error, result.statusCode)));
573
649
  }
574
650
  });
575
651
  }
@@ -582,9 +658,9 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
582
658
  // so the attribution `reason` falls back to `unknown` when the gate is on.
583
659
  attribution = (0, _errorHandling.buildErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'));
584
660
  syncBlockIds.forEach(function (Ids) {
585
- var _this5$fireAnalyticsE4;
661
+ var _this5$fireAnalyticsE2;
586
662
  _this5.setPendingDeletion(Ids, false);
587
- (_this5$fireAnalyticsE4 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE4 === void 0 || _this5$fireAnalyticsE4.call(_this5, (0, _errorHandling.deleteErrorPayload)(_t2.message, Ids.resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(Ids.resourceId), attribution));
663
+ (_this5$fireAnalyticsE2 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE2 === void 0 || _this5$fireAnalyticsE2.call(_this5, (0, _errorHandling.deleteErrorPayload)(_t2.message, Ids.resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(Ids.resourceId), attribution));
588
664
  });
589
665
  (0, _monitoring.logException)(_t2, {
590
666
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
@@ -597,7 +673,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
597
673
  }
598
674
  }, _callee2, this, [[0, 4]]);
599
675
  }));
600
- function _delete(_x, _x2, _x3, _x4) {
676
+ function _delete(_x, _x2, _x3, _x4, _x5) {
601
677
  return _delete2.apply(this, arguments);
602
678
  }
603
679
  return _delete;
@@ -611,7 +687,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
611
687
  key: "retryDeletion",
612
688
  value: function () {
613
689
  var _retryDeletion = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
614
- var _this$deletionRetryIn, syncBlockIds, onDelete, onDeleteCompleted, deletionReason;
690
+ var _this$deletionRetryIn, syncBlockIds, onDelete, onDeleteCompleted, deletionReason, mechanism;
615
691
  return _regenerator.default.wrap(function (_context3) {
616
692
  while (1) switch (_context3.prev = _context3.next) {
617
693
  case 0:
@@ -627,13 +703,13 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
627
703
  }
628
704
  return _context3.abrupt("return", Promise.resolve());
629
705
  case 2:
630
- _this$deletionRetryIn = this.deletionRetryInfo, syncBlockIds = _this$deletionRetryIn.syncBlockIds, onDelete = _this$deletionRetryIn.onDelete, onDeleteCompleted = _this$deletionRetryIn.onDeleteCompleted, deletionReason = _this$deletionRetryIn.deletionReason;
706
+ _this$deletionRetryIn = this.deletionRetryInfo, syncBlockIds = _this$deletionRetryIn.syncBlockIds, onDelete = _this$deletionRetryIn.onDelete, onDeleteCompleted = _this$deletionRetryIn.onDeleteCompleted, deletionReason = _this$deletionRetryIn.deletionReason, mechanism = _this$deletionRetryIn.mechanism;
631
707
  if (!this.confirmationCallback) {
632
708
  _context3.next = 3;
633
709
  break;
634
710
  }
635
711
  _context3.next = 3;
636
- return this.delete(syncBlockIds, onDelete, onDeleteCompleted, deletionReason);
712
+ return this.delete(syncBlockIds, onDelete, onDeleteCompleted, deletionReason, mechanism);
637
713
  case 3:
638
714
  case "end":
639
715
  return _context3.stop();
@@ -663,7 +739,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
663
739
  value: (function () {
664
740
  var _fetchAndCacheStatuses = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4() {
665
741
  var _this6 = this;
666
- var sourceToReferenceMap, syncBlockNodes, results, _iterator2, _step2, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached, _t3;
742
+ var sourceToReferenceMap, syncBlockNodes, results, _iterator3, _step3, _sourceToReferenceMap, _result$data, result, sourceResourceId, cached, _t3;
667
743
  return _regenerator.default.wrap(function (_context4) {
668
744
  while (1) switch (_context4.prev = _context4.next) {
669
745
  case 0:
@@ -699,10 +775,10 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
699
775
  return this.dataProvider.fetchNodesData(syncBlockNodes);
700
776
  case 3:
701
777
  results = _context4.sent;
702
- _iterator2 = _createForOfIteratorHelper(results);
778
+ _iterator3 = _createForOfIteratorHelper(results);
703
779
  try {
704
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
705
- result = _step2.value;
780
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
781
+ result = _step3.value;
706
782
  // Map the reference resourceId back to the source resourceId
707
783
  sourceResourceId = (_sourceToReferenceMap = sourceToReferenceMap.get(result.resourceId)) !== null && _sourceToReferenceMap !== void 0 ? _sourceToReferenceMap : result.resourceId;
708
784
  cached = this.syncBlockCache.get(sourceResourceId);
@@ -711,9 +787,9 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
711
787
  }
712
788
  }
713
789
  } catch (err) {
714
- _iterator2.e(err);
790
+ _iterator3.e(err);
715
791
  } finally {
716
- _iterator2.f();
792
+ _iterator3.f();
717
793
  }
718
794
  _context4.next = 5;
719
795
  break;
@@ -763,7 +839,9 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
763
839
  // onDelete: no-op, document is being discarded
764
840
  function () {},
765
841
  // onDeleteCompleted: no-op
766
- 'source-block-unpublished');
842
+ 'source-block-unpublished',
843
+ // Cancel/discard cleanup is code-initiated, not a direct user edit.
844
+ 'other');
767
845
  }
768
846
 
769
847
  /**
@@ -777,7 +855,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
777
855
  }, {
778
856
  key: "deleteSyncBlocksWithConfirmation",
779
857
  value: (function () {
780
- var _deleteSyncBlocksWithConfirmation = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5(syncBlockIds, deletionReason, onDelete, onDeleteCompleted, destroyCallback) {
858
+ var _deleteSyncBlocksWithConfirmation = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5(syncBlockIds, deletionReason, onDelete, onDeleteCompleted, destroyCallback, mechanism) {
781
859
  var confirmed, isDeleteSuccessful;
782
860
  return _regenerator.default.wrap(function (_context5) {
783
861
  while (1) switch (_context5.prev = _context5.next) {
@@ -801,7 +879,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
801
879
  break;
802
880
  }
803
881
  _context5.next = 3;
804
- return this.delete(syncBlockIds, onDelete, onDeleteCompleted, deletionReason);
882
+ return this.delete(syncBlockIds, onDelete, onDeleteCompleted, deletionReason, mechanism);
805
883
  case 3:
806
884
  isDeleteSuccessful = _context5.sent;
807
885
  if (!isDeleteSuccessful) {
@@ -811,7 +889,8 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
811
889
  onDelete: onDelete,
812
890
  onDeleteCompleted: onDeleteCompleted,
813
891
  destroyCallback: destroyCallback,
814
- deletionReason: deletionReason
892
+ deletionReason: deletionReason,
893
+ mechanism: mechanism
815
894
  };
816
895
  } else {
817
896
  destroyCallback();
@@ -826,7 +905,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
826
905
  }
827
906
  }, _callee5, this);
828
907
  }));
829
- function deleteSyncBlocksWithConfirmation(_x5, _x6, _x7, _x8, _x9) {
908
+ function deleteSyncBlocksWithConfirmation(_x6, _x7, _x8, _x9, _x0, _x1) {
830
909
  return _deleteSyncBlocksWithConfirmation.apply(this, arguments);
831
910
  }
832
911
  return deleteSyncBlocksWithConfirmation;
@@ -854,11 +933,11 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
854
933
  return sourceInfo;
855
934
  });
856
935
  } catch (error) {
857
- var _this$fireAnalyticsEv7;
936
+ var _this$fireAnalyticsEv0;
858
937
  (0, _monitoring.logException)(error, {
859
938
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
860
939
  });
861
- (_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 || _this$fireAnalyticsEv7.call(this, (0, _errorHandling.getSourceInfoErrorPayload)(error.message));
940
+ (_this$fireAnalyticsEv0 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv0 === void 0 || _this$fireAnalyticsEv0.call(this, (0, _errorHandling.getSourceInfoErrorPayload)(error.message));
862
941
  return Promise.resolve(undefined);
863
942
  }
864
943
  }
@@ -871,11 +950,11 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
871
950
  }
872
951
  return this.dataProvider.fetchReferences(resourceId, true);
873
952
  } catch (error) {
874
- var _this$fireAnalyticsEv8;
953
+ var _this$fireAnalyticsEv1;
875
954
  (0, _monitoring.logException)(error, {
876
955
  location: 'editor-synced-block-provider/sourceSyncBlockStoreManager'
877
956
  });
878
- (_this$fireAnalyticsEv8 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv8 === void 0 || _this$fireAnalyticsEv8.call(this, (0, _errorHandling.fetchReferencesErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
957
+ (_this$fireAnalyticsEv1 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv1 === void 0 || _this$fireAnalyticsEv1.call(this, (0, _errorHandling.fetchReferencesErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
879
958
  return Promise.resolve({
880
959
  error: _types.SyncBlockError.Errored
881
960
  });
@@ -892,6 +971,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
892
971
  this.postCreationFlushCallback = undefined;
893
972
  this.pendingCreationPromises.clear();
894
973
  this.creationsTimedOutDuringFlush.clear();
974
+ this.recentDeleteEmissions.clear();
895
975
  this.dataProvider = undefined;
896
976
  (_this$saveExperience4 = this.saveExperience) === null || _this$saveExperience4 === void 0 || _this$saveExperience4.abort({
897
977
  reason: 'editorDestroyed'
@@ -334,15 +334,25 @@ var createSuccessPayload = exports.createSuccessPayload = function createSuccess
334
334
  })
335
335
  };
336
336
  };
337
- var createSuccessPayloadNew = exports.createSuccessPayloadNew = function createSuccessPayloadNew(resourceId) {
337
+
338
+ /**
339
+ * Operational `syncedBlockCreate` success event (previously only error rows
340
+ * existed, so dashboards had no create denominator). Fired behind
341
+ * `platform_editor_blocks_patch_4` with the `blockInstanceId` join key.
342
+ */
343
+ var createSuccessPayloadNew = exports.createSuccessPayloadNew = function createSuccessPayloadNew(resourceId, blockInstanceId, sourceProduct) {
338
344
  return {
339
345
  action: _analytics.ACTION.INSERTED,
340
346
  actionSubject: _analytics.ACTION_SUBJECT.SYNCED_BLOCK,
341
347
  actionSubjectId: _analytics.ACTION_SUBJECT_ID.SYNCED_BLOCK_CREATE,
342
348
  eventType: _analytics.EVENT_TYPE.OPERATIONAL,
343
- attributes: {
349
+ attributes: _objectSpread(_objectSpread({
344
350
  resourceId: resourceId
345
- }
351
+ }, blockInstanceId && {
352
+ blockInstanceId: blockInstanceId
353
+ }), sourceProduct && {
354
+ sourceProduct: sourceProduct
355
+ })
346
356
  };
347
357
  };
348
358
  var updateSuccessPayload = exports.updateSuccessPayload = function updateSuccessPayload(resourceId, hasReference, sourceProduct) {
@@ -360,16 +370,29 @@ var updateSuccessPayload = exports.updateSuccessPayload = function updateSuccess
360
370
  })
361
371
  };
362
372
  };
363
- var deleteSuccessPayload = exports.deleteSuccessPayload = function deleteSuccessPayload(resourceId, sourceProduct) {
373
+
374
+ /**
375
+ * Optional enrichment for the `syncedBlockDelete` success event behind
376
+ * `platform_editor_blocks_patch_4`. All fields optional so the gate-off payload
377
+ * is unchanged; `blockInstanceId` is the bare-uuid join key.
378
+ */
379
+
380
+ var deleteSuccessPayload = exports.deleteSuccessPayload = function deleteSuccessPayload(resourceId, sourceProduct, enrichment) {
364
381
  return {
365
382
  action: _analytics.ACTION.DELETED,
366
383
  actionSubject: _analytics.ACTION_SUBJECT.SYNCED_BLOCK,
367
384
  actionSubjectId: _analytics.ACTION_SUBJECT_ID.SYNCED_BLOCK_DELETE,
368
385
  eventType: _analytics.EVENT_TYPE.OPERATIONAL,
369
- attributes: _objectSpread({
386
+ attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread({
370
387
  resourceId: resourceId
371
388
  }, sourceProduct && {
372
389
  sourceProduct: sourceProduct
390
+ }), (enrichment === null || enrichment === void 0 ? void 0 : enrichment.blockInstanceId) && {
391
+ blockInstanceId: enrichment.blockInstanceId
392
+ }), (enrichment === null || enrichment === void 0 ? void 0 : enrichment.deletionReason) && {
393
+ deletionReason: enrichment.deletionReason
394
+ }), (enrichment === null || enrichment === void 0 ? void 0 : enrichment.mechanism) && {
395
+ mechanism: enrichment.mechanism
373
396
  })
374
397
  };
375
398
  };
@@ -18,6 +18,22 @@ export let SyncBlockError = /*#__PURE__*/function (SyncBlockError) {
18
18
  SyncBlockError["EntityNotFound"] = "entity_not_found";
19
19
  return SyncBlockError;
20
20
  }({});
21
+
22
+ /**
23
+ * How a source bodiedSyncBlock removal was performed, derived from the
24
+ * originating transaction. Distinct from {@link DeletionReason} (the outcome):
25
+ * `mechanism` tells deliberate deletes apart from undos and accidental overwrites.
26
+ *
27
+ * Values name the user action that produced the removal:
28
+ * - `undo` / `redo` — removal came from a history undo/redo.
29
+ * - `deleteButton` — the explicit "Delete" control in the synced-block toolbar.
30
+ * - `keyboardDelete` — Backspace/Delete key on a caret or range selection.
31
+ * - `selectionReplaced` — the block was selected and replaced by typing or
32
+ * pasting over it (the accidental-overwrite path).
33
+ * - `other` — any non-direct removal (unsync, conversion, code-dispatched, or a
34
+ * structural wrap/lift/unwrap edit).
35
+ */
36
+
21
37
  /**
22
38
  * Helpers to distinguish "data provider not ready / torn down" from a genuine
23
39
  * fetch/subscribe failure (EDITOR-7860). On Jira the provider is wired