@atlaskit/editor-synced-block-provider 8.1.10 → 8.3.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 (31) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/cjs/common/types.js +63 -2
  3. package/dist/cjs/hooks/useFetchSyncBlockData.js +49 -15
  4. package/dist/cjs/providers/block-service/blockServiceAPI.js +7 -4
  5. package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +42 -8
  6. package/dist/cjs/store-manager/syncBlockBatchFetcher.js +29 -1
  7. package/dist/cjs/store-manager/syncBlockProviderFactoryManager.js +4 -3
  8. package/dist/cjs/store-manager/syncBlockSubscriptionManager.js +11 -4
  9. package/dist/cjs/utils/errorHandling.js +152 -6
  10. package/dist/es2019/common/types.js +47 -1
  11. package/dist/es2019/hooks/useFetchSyncBlockData.js +38 -5
  12. package/dist/es2019/providers/block-service/blockServiceAPI.js +11 -3
  13. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +36 -7
  14. package/dist/es2019/store-manager/syncBlockBatchFetcher.js +28 -2
  15. package/dist/es2019/store-manager/syncBlockProviderFactoryManager.js +5 -4
  16. package/dist/es2019/store-manager/syncBlockSubscriptionManager.js +12 -5
  17. package/dist/es2019/utils/errorHandling.js +167 -22
  18. package/dist/esm/common/types.js +62 -1
  19. package/dist/esm/hooks/useFetchSyncBlockData.js +51 -17
  20. package/dist/esm/providers/block-service/blockServiceAPI.js +7 -4
  21. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +44 -10
  22. package/dist/esm/store-manager/syncBlockBatchFetcher.js +30 -2
  23. package/dist/esm/store-manager/syncBlockProviderFactoryManager.js +5 -4
  24. package/dist/esm/store-manager/syncBlockSubscriptionManager.js +12 -5
  25. package/dist/esm/utils/errorHandling.js +149 -5
  26. package/dist/types/common/types.d.ts +29 -0
  27. package/dist/types/providers/types.d.ts +8 -0
  28. package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +8 -0
  29. package/dist/types/store-manager/syncBlockBatchFetcher.d.ts +7 -0
  30. package/dist/types/utils/errorHandling.d.ts +94 -2
  31. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 8.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`426eef1e61679`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/426eef1e61679) -
8
+ Add failure `reason`, HTTP `statusCode` and `benign` attributes to synced block fetch/subscribe
9
+ operational error analytics, so fetch failures can be broken down by cause (benign source-gone /
10
+ permission-denied vs genuine system failures) instead of regex-matching free text. Gated behind
11
+ `platform_editor_blocks_patch_3`; gate-off behaviour is unchanged.
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+
17
+ ## 8.2.0
18
+
19
+ ### Minor Changes
20
+
21
+ - [`f13db8731461d`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/f13db8731461d) -
22
+ [EDITOR-7860] Gate synced block reference fetch and subscribe on data-provider readiness so
23
+ reference blocks no longer attempt to fetch before the (asynchronously wired) provider is ready.
24
+ This removes spurious "Data provider not set" fetch errors on Jira and keeps reference blocks
25
+ loading correctly once the provider resolves.
26
+
27
+ This also hardens the not-ready / torn-down window: a teardown-aware `hasDataProvider()` (also
28
+ checks `isDestroyed`), a tagged `ProviderNotReadyError` thrown at the fetch source, and catch-site
29
+ suppression in the hook, store manager and batch fetcher so an in-flight or queued fetch on an
30
+ orphaned manager re-queues for retry instead of emitting a false fetch error. All behaviour is
31
+ behind the `platform_editor_blocks_patch_3` feature gate.
32
+
3
33
  ## 8.1.10
4
34
 
5
35
  ### Patch Changes
@@ -1,9 +1,20 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
4
  Object.defineProperty(exports, "__esModule", {
4
5
  value: true
5
6
  });
6
- exports.SyncBlockError = void 0;
7
+ exports.isProviderNotReadyError = exports.SyncBlockError = exports.ProviderNotReadyError = exports.PROVIDER_NOT_READY_MESSAGE = void 0;
8
+ var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
9
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
+ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
12
+ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
13
+ var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
14
+ var _wrapNativeSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/wrapNativeSuper"));
15
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
16
+ function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
17
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
7
18
  var SyncBlockError = exports.SyncBlockError = /*#__PURE__*/function (SyncBlockError) {
8
19
  SyncBlockError["Errored"] = "errored";
9
20
  SyncBlockError["NotFound"] = "not_found";
@@ -22,4 +33,54 @@ var SyncBlockError = exports.SyncBlockError = /*#__PURE__*/function (SyncBlockEr
22
33
  // block does not exist on this site (e.g. cross-site reference or hard deleted)
23
34
  SyncBlockError["EntityNotFound"] = "entity_not_found";
24
35
  return SyncBlockError;
25
- }({});
36
+ }({});
37
+ /**
38
+ * Helpers to distinguish "data provider not ready / torn down" from a genuine
39
+ * fetch/subscribe failure (EDITOR-7860). On Jira the provider is wired
40
+ * asynchronously and `destroy()` nulls it on orphaned managers, so queued/
41
+ * in-flight ops throw `Data provider not set` — previously mis-logged as a real
42
+ * error. These let throw and catch sites agree on one non-string-matched signal
43
+ * so the residual false errors are suppressed. Gated by
44
+ * `platform_editor_blocks_patch_3`.
45
+ *
46
+ * NB: these intentionally live here rather than in a dedicated module to avoid
47
+ * adding a downstream file to consuming Jira packages' Thunderstone complexity.
48
+ */
49
+
50
+ /** Legacy message — kept identical for gate-off and historical events. */
51
+ var PROVIDER_NOT_READY_MESSAGE = exports.PROVIDER_NOT_READY_MESSAGE = 'Data provider not set';
52
+
53
+ /**
54
+ * Thrown when a fetch/subscribe runs against a manager whose provider is not
55
+ * (yet) available or torn down. Keeps the legacy message + name so string
56
+ * matchers still work, while new code uses {@link isProviderNotReadyError}.
57
+ */
58
+ var ProviderNotReadyError = exports.ProviderNotReadyError = /*#__PURE__*/function (_Error) {
59
+ function ProviderNotReadyError() {
60
+ var _this;
61
+ var message = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : PROVIDER_NOT_READY_MESSAGE;
62
+ (0, _classCallCheck2.default)(this, ProviderNotReadyError);
63
+ _this = _callSuper(this, ProviderNotReadyError, [message]);
64
+ (0, _defineProperty2.default)(_this, "isProviderNotReadyError", true);
65
+ _this.name = 'ProviderNotReadyError';
66
+ // Restore prototype chain so instanceof works after transpilation.
67
+ Object.setPrototypeOf(_this, ProviderNotReadyError.prototype);
68
+ return _this;
69
+ }
70
+ (0, _inherits2.default)(ProviderNotReadyError, _Error);
71
+ return (0, _createClass2.default)(ProviderNotReadyError);
72
+ }( /*#__PURE__*/(0, _wrapNativeSuper2.default)(Error));
73
+ /**
74
+ * True when the value is a "provider not ready / torn down" condition, not a
75
+ * genuine failure. Recognises the tagged {@link ProviderNotReadyError} and the
76
+ * legacy message (for errors thrown before rollout).
77
+ */
78
+ var isProviderNotReadyError = exports.isProviderNotReadyError = function isProviderNotReadyError(error) {
79
+ if (error instanceof ProviderNotReadyError) {
80
+ return true;
81
+ }
82
+ if ((0, _typeof2.default)(error) === 'object' && error !== null && error.isProviderNotReadyError === true) {
83
+ return true;
84
+ }
85
+ return error instanceof Error && error.message === PROVIDER_NOT_READY_MESSAGE;
86
+ };
@@ -12,12 +12,14 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
12
12
  var _react = require("react");
13
13
  var _coreUtils = require("@atlaskit/editor-common/core-utils");
14
14
  var _monitoring = require("@atlaskit/editor-common/monitoring");
15
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
15
16
  var _types = require("../common/types");
16
17
  var _errorHandling = require("../utils/errorHandling");
17
18
  var _utils = require("../utils/utils");
18
19
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
19
20
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
20
21
  var useFetchSyncBlockData = exports.useFetchSyncBlockData = function useFetchSyncBlockData(manager, resourceId, localId, fireAnalyticsEvent) {
22
+ var _manager$referenceMan2, _manager$referenceMan3, _manager$referenceMan4;
21
23
  // Initialize both states from a single cache lookup to avoid race conditions.
22
24
  // When a block is moved/remounted, the old component's cleanup may clear the cache
23
25
  // before or after the new component mounts. By doing a single lookup, we ensure
@@ -41,6 +43,14 @@ var useFetchSyncBlockData = exports.useFetchSyncBlockData = function useFetchSyn
41
43
  syncBlockInstance = _useState2$.syncBlockInstance,
42
44
  isLoading = _useState2$.isLoading,
43
45
  setFetchState = _useState2[1];
46
+
47
+ // On Jira the data provider is wired asynchronously, so the manager can be
48
+ // constructed with `dataProvider === undefined`. Fetching/subscribing in that
49
+ // window throws `Data provider not set`, logged as a false fetch error
50
+ // (EDITOR-7860). Gate on readiness; once the provider resolves a new manager
51
+ // instance is created so `referenceManager` changes identity and the effect
52
+ // below re-runs, subscribing exactly once.
53
+ var isDataProviderReady = (0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3') ? (_manager$referenceMan2 = (_manager$referenceMan3 = (_manager$referenceMan4 = manager.referenceManager).hasDataProvider) === null || _manager$referenceMan3 === void 0 ? void 0 : _manager$referenceMan3.call(_manager$referenceMan4)) !== null && _manager$referenceMan2 !== void 0 ? _manager$referenceMan2 : false : true;
44
54
  var reloadData = (0, _react.useCallback)( /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
45
55
  var syncBlockNode, _t;
46
56
  return _regenerator.default.wrap(function (_context) {
@@ -52,14 +62,20 @@ var useFetchSyncBlockData = exports.useFetchSyncBlockData = function useFetchSyn
52
62
  }
53
63
  return _context.abrupt("return");
54
64
  case 1:
55
- _context.prev = 1;
65
+ if (isDataProviderReady) {
66
+ _context.next = 2;
67
+ break;
68
+ }
69
+ return _context.abrupt("return");
70
+ case 2:
71
+ _context.prev = 2;
56
72
  syncBlockNode = resourceId && localId ? (0, _utils.createSyncBlockNode)(localId, resourceId) : null;
57
73
  if (syncBlockNode) {
58
- _context.next = 2;
74
+ _context.next = 3;
59
75
  break;
60
76
  }
61
77
  throw new Error('Failed to create sync block node from resourceid and localid');
62
- case 2:
78
+ case 3:
63
79
  setFetchState(function (prev) {
64
80
  return _objectSpread(_objectSpread({}, prev), {}, {
65
81
  isLoading: true
@@ -67,18 +83,29 @@ var useFetchSyncBlockData = exports.useFetchSyncBlockData = function useFetchSyn
67
83
  });
68
84
 
69
85
  // Fetch sync block data, the `subscribeToSyncBlock` will update the state once data is fetched
70
- _context.next = 3;
86
+ _context.next = 4;
71
87
  return manager.referenceManager.fetchSyncBlocksData([syncBlockNode]);
72
- case 3:
73
- _context.next = 5;
74
- break;
75
88
  case 4:
76
- _context.prev = 4;
77
- _t = _context["catch"](1);
89
+ _context.next = 7;
90
+ break;
91
+ case 5:
92
+ _context.prev = 5;
93
+ _t = _context["catch"](2);
94
+ if (!((0, _types.isProviderNotReadyError)(_t) && (0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'))) {
95
+ _context.next = 6;
96
+ break;
97
+ }
98
+ setFetchState(function (prev) {
99
+ return _objectSpread(_objectSpread({}, prev), {}, {
100
+ isLoading: true
101
+ });
102
+ });
103
+ return _context.abrupt("return");
104
+ case 6:
78
105
  (0, _monitoring.logException)(_t, {
79
106
  location: 'editor-synced-block-provider/useFetchSyncBlockData'
80
107
  });
81
- fireAnalyticsEvent === null || fireAnalyticsEvent === void 0 || fireAnalyticsEvent((0, _errorHandling.fetchErrorPayload)(_t.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
108
+ fireAnalyticsEvent === null || fireAnalyticsEvent === void 0 || fireAnalyticsEvent((0, _errorHandling.fetchErrorPayload)(_t.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), _t.message)));
82
109
 
83
110
  // Set error state if fetching fails
84
111
  setFetchState({
@@ -91,24 +118,31 @@ var useFetchSyncBlockData = exports.useFetchSyncBlockData = function useFetchSyn
91
118
  isLoading: false
92
119
  });
93
120
  return _context.abrupt("return");
94
- case 5:
121
+ case 7:
95
122
  setFetchState(function (prev) {
96
123
  return _objectSpread(_objectSpread({}, prev), {}, {
97
124
  isLoading: false
98
125
  });
99
126
  });
100
- case 6:
127
+ case 8:
101
128
  case "end":
102
129
  return _context.stop();
103
130
  }
104
- }, _callee, null, [[1, 4]]);
105
- })), [isLoading, localId, manager.referenceManager, resourceId, fireAnalyticsEvent]);
131
+ }, _callee, null, [[2, 5]]);
132
+ })), [isLoading, isDataProviderReady, localId, manager.referenceManager, resourceId, fireAnalyticsEvent]);
106
133
  (0, _react.useEffect)(function () {
107
134
  if ((0, _coreUtils.isSSR)()) {
108
135
  // in SSR, we don't need to subscribe to updates,
109
136
  // instead we rely on pre-fetched data ONLY, see initialization of syncBlockInstance above
110
137
  return;
111
138
  }
139
+
140
+ // Not ready: skip subscribe (it would trigger a batched fetch and a false
141
+ // error) and keep `isLoading: true`. `isDataProviderReady` is in the deps,
142
+ // so the effect re-runs and subscribes once the provider resolves.
143
+ if (!isDataProviderReady) {
144
+ return;
145
+ }
112
146
  var unsubscribe = manager.referenceManager.subscribeToSyncBlock(resourceId || '', localId || '', function (data) {
113
147
  setFetchState({
114
148
  syncBlockInstance: data,
@@ -118,7 +152,7 @@ var useFetchSyncBlockData = exports.useFetchSyncBlockData = function useFetchSyn
118
152
  return function () {
119
153
  unsubscribe();
120
154
  };
121
- }, [localId, manager.referenceManager, resourceId]);
155
+ }, [isDataProviderReady, localId, manager.referenceManager, resourceId]);
122
156
  var ssrProviders = (0, _react.useMemo)(function () {
123
157
  return resourceId ? manager.referenceManager.getSSRProviders(resourceId) : null;
124
158
  }, [resourceId, manager.referenceManager]);
@@ -7,9 +7,9 @@ Object.defineProperty(exports, "__esModule", {
7
7
  });
8
8
  exports.writeDataBatch = exports.useMemoizedBlockServiceFetchOnlyAPIProvider = exports.useMemoizedBlockServiceAPIProviders = exports.fetchReferences = exports.extractResourceIdFromBlockAri = exports.convertToSyncBlockData = exports.blockAriToResourceId = exports.batchFetchData = void 0;
9
9
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
10
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
10
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
12
11
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
12
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
13
13
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
14
14
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
15
15
  var _react = require("react");
@@ -413,10 +413,12 @@ var _batchFetchData = exports.batchFetchData = /*#__PURE__*/function () {
413
413
  case 21:
414
414
  return _context2.abrupt("return", blockNodeIdentifiers.map(function (blockNodeIdentifier) {
415
415
  return {
416
- error: {
416
+ error: _objectSpread({
417
417
  type: _t4 instanceof _blockService.BlockError ? mapBlockError(_t4) : _types.SyncBlockError.Errored,
418
418
  reason: _t4.message
419
- },
419
+ }, _t4 instanceof _blockService.BlockError && {
420
+ statusCode: _t4.status
421
+ }),
420
422
  resourceId: blockNodeIdentifier.resourceId
421
423
  };
422
424
  }));
@@ -668,7 +670,8 @@ var BlockServiceADFFetchProvider = /*#__PURE__*/function () {
668
670
  return _context5.abrupt("return", {
669
671
  error: {
670
672
  type: mapBlockError(_t7),
671
- reason: _t7.message
673
+ reason: _t7.message,
674
+ statusCode: _t7.status
672
675
  },
673
676
  resourceId: resourceId
674
677
  });
@@ -128,6 +128,10 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
128
128
  },
129
129
  getFireAnalyticsEvent: function getFireAnalyticsEvent() {
130
130
  return _this.fireAnalyticsEvent;
131
+ },
132
+ // EDITOR-7860: skip + re-queue fetches while not ready / torn down.
133
+ isProviderReady: function isProviderReady() {
134
+ return _this.hasDataProvider();
131
135
  }
132
136
  });
133
137
 
@@ -140,6 +144,19 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
140
144
  return node.type.name === 'syncBlock';
141
145
  }
142
146
 
147
+ /**
148
+ * Whether the async data provider is wired and the manager is not torn down.
149
+ * Consumers gate fetch/subscribe on this to avoid a false `Data provider not
150
+ * set` fetch error (EDITOR-7860). The `isDestroyed` check covers managers
151
+ * orphaned mid-flight during an async provider swap, where `dataProvider`
152
+ * alone is insufficient.
153
+ */
154
+ }, {
155
+ key: "hasDataProvider",
156
+ value: function hasDataProvider() {
157
+ return !this.isDestroyed && !!this.dataProvider;
158
+ }
159
+
143
160
  /**
144
161
  * Enables or disables real-time GraphQL subscriptions for block updates.
145
162
  * When enabled, the store manager will subscribe to real-time updates
@@ -531,22 +548,28 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
531
548
  return _context2.abrupt("return");
532
549
  case 2:
533
550
  if (this.dataProvider) {
551
+ _context2.next = 4;
552
+ break;
553
+ }
554
+ if (!(0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3')) {
534
555
  _context2.next = 3;
535
556
  break;
536
557
  }
537
- throw new Error('Data provider not set');
558
+ throw new _types.ProviderNotReadyError();
538
559
  case 3:
560
+ throw new Error('Data provider not set');
561
+ case 4:
539
562
  nodesToFetch.forEach(function (node) {
540
563
  _this4.syncBlockFetchDataRequests.set(node.attrs.resourceId, true);
541
564
  });
542
565
  (_this$fetchExperience6 = this.fetchExperience) === null || _this$fetchExperience6 === void 0 || _this$fetchExperience6.start({});
543
- _context2.next = 4;
566
+ _context2.next = 5;
544
567
  return this.dataProvider.fetchNodesData(nodesToFetch).finally(function () {
545
568
  nodesToFetch.forEach(function (node) {
546
569
  _this4.syncBlockFetchDataRequests.delete(node.attrs.resourceId);
547
570
  });
548
571
  });
549
- case 4:
572
+ case 5:
550
573
  data = _context2.sent;
551
574
  _this$processFetchedD2 = this.processFetchedData(data), hasUnexpectedError = _this$processFetchedD2.hasUnexpectedError, hasExpectedError = _this$processFetchedD2.hasExpectedError;
552
575
  if (hasUnexpectedError) {
@@ -560,7 +583,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
560
583
  } else {
561
584
  (_this$fetchExperience9 = this.fetchExperience) === null || _this$fetchExperience9 === void 0 || _this$fetchExperience9.success();
562
585
  }
563
- case 5:
586
+ case 6:
564
587
  case "end":
565
588
  return _context2.stop();
566
589
  }
@@ -586,10 +609,12 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
586
609
  data.forEach(function (syncBlockInstance) {
587
610
  var _resolvedSyncBlockIns;
588
611
  if (!syncBlockInstance.resourceId) {
589
- var _syncBlockInstance$er, _syncBlockInstance$er2, _this5$fireAnalyticsE;
612
+ var _syncBlockInstance$er, _syncBlockInstance$er2, _this5$fireAnalyticsE, _syncBlockInstance$er3, _syncBlockInstance$er4, _syncBlockInstance$er5;
590
613
  var payload = ((_syncBlockInstance$er = syncBlockInstance.error) === null || _syncBlockInstance$er === void 0 ? void 0 : _syncBlockInstance$er.reason) || ((_syncBlockInstance$er2 = syncBlockInstance.error) === null || _syncBlockInstance$er2 === void 0 ? void 0 : _syncBlockInstance$er2.type) || 'Returned sync block instance does not have resource id';
591
614
  // No resourceId means we cannot derive a sourceProduct here; intentionally omit.
592
- (_this5$fireAnalyticsE = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE === void 0 || _this5$fireAnalyticsE.call(_this5, (0, _errorHandling.fetchErrorPayload)(payload));
615
+ // Classify on the structured `type` first, falling back to the free-text
616
+ // `reason`/payload (EDITOR-7862).
617
+ (_this5$fireAnalyticsE = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE === void 0 || _this5$fireAnalyticsE.call(_this5, (0, _errorHandling.fetchErrorPayload)(payload, undefined, undefined, (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), ((_syncBlockInstance$er3 = syncBlockInstance.error) === null || _syncBlockInstance$er3 === void 0 ? void 0 : _syncBlockInstance$er3.type) || ((_syncBlockInstance$er4 = syncBlockInstance.error) === null || _syncBlockInstance$er4 === void 0 ? void 0 : _syncBlockInstance$er4.reason) || payload, (_syncBlockInstance$er5 = syncBlockInstance.error) === null || _syncBlockInstance$er5 === void 0 ? void 0 : _syncBlockInstance$er5.statusCode)));
593
618
  return;
594
619
  }
595
620
  var existingSyncBlock = _this5.getFromCache(syncBlockInstance.resourceId);
@@ -623,7 +648,10 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
623
648
  var isRetryingEntityNotFound = syncBlockInstance.error.type === _types.SyncBlockError.EntityNotFound && ((_this5$entityNotFound = _this5.entityNotFoundRetryCount.get(syncBlockInstance.resourceId)) !== null && _this5$entityNotFound !== void 0 ? _this5$entityNotFound : 0) < ENTITY_NOT_FOUND_MAX_RETRIES && (0, _platformFeatureFlags.fg)('platform_synced_block_patch_13');
624
649
  if (!isRetryingEntityNotFound) {
625
650
  var _this5$fireAnalyticsE2, _syncBlockInstance$da, _syncBlockInstance$da2;
626
- (_this5$fireAnalyticsE2 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE2 === void 0 || _this5$fireAnalyticsE2.call(_this5, (0, _errorHandling.fetchErrorPayload)(syncBlockInstance.error.reason || syncBlockInstance.error.type, syncBlockInstance.resourceId, (_syncBlockInstance$da = (_syncBlockInstance$da2 = syncBlockInstance.data) === null || _syncBlockInstance$da2 === void 0 ? void 0 : _syncBlockInstance$da2.product) !== null && _syncBlockInstance$da !== void 0 ? _syncBlockInstance$da : (0, _utils.getSourceProductFromResourceIdSafe)(syncBlockInstance.resourceId)));
651
+ // Classify on the structured `type` (a `SyncBlockError` enum value) first,
652
+ // falling back to the free-text `reason` so source-state/permission strings
653
+ // are still bucketed (EDITOR-7862). The emitted `error` attribute is unchanged.
654
+ (_this5$fireAnalyticsE2 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE2 === void 0 || _this5$fireAnalyticsE2.call(_this5, (0, _errorHandling.fetchErrorPayload)(syncBlockInstance.error.reason || syncBlockInstance.error.type, syncBlockInstance.resourceId, (_syncBlockInstance$da = (_syncBlockInstance$da2 = syncBlockInstance.data) === null || _syncBlockInstance$da2 === void 0 ? void 0 : _syncBlockInstance$da2.product) !== null && _syncBlockInstance$da !== void 0 ? _syncBlockInstance$da : (0, _utils.getSourceProductFromResourceIdSafe)(syncBlockInstance.resourceId), (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), syncBlockInstance.error.type || syncBlockInstance.error.reason, syncBlockInstance.error.statusCode)));
627
655
  }
628
656
  if (syncBlockInstance.error.type === _types.SyncBlockError.NotFound || syncBlockInstance.error.type === _types.SyncBlockError.Forbidden) {
629
657
  hasExpectedError = true;
@@ -938,10 +966,16 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
938
966
  return this._subscriptionManager.subscribeToSyncBlock(resourceId, localId, callback);
939
967
  } catch (error) {
940
968
  var _this$fireAnalyticsEv7;
969
+ // EDITOR-7860: benign not-ready/torn-down case — suppress both the
970
+ // exception-tracker log and the analytics event (checked first so the
971
+ // benign case stays fully silent). Gate-off behaviour is unchanged.
972
+ if ((0, _types.isProviderNotReadyError)(error) && (0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3')) {
973
+ return function () {};
974
+ }
941
975
  (0, _monitoring.logException)(error, {
942
976
  location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
943
977
  });
944
- (_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 || _this$fireAnalyticsEv7.call(this, (0, _errorHandling.fetchErrorPayload)(error.message));
978
+ (_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 || _this$fireAnalyticsEv7.call(this, (0, _errorHandling.fetchErrorPayload)(error.message, undefined, undefined, (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), error.message)));
945
979
  return function () {};
946
980
  }
947
981
  }
@@ -10,6 +10,8 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/creat
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
11
  var _rafSchd = _interopRequireDefault(require("raf-schd"));
12
12
  var _monitoring = require("@atlaskit/editor-common/monitoring");
13
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
14
+ var _types = require("../common/types");
13
15
  var _errorHandling = require("../utils/errorHandling");
14
16
  var _utils = require("../utils/utils");
15
17
  /**
@@ -32,6 +34,17 @@ var SyncBlockBatchFetcher = exports.SyncBlockBatchFetcher = /*#__PURE__*/functio
32
34
  if (_this.pendingFetchRequests.size === 0) {
33
35
  return;
34
36
  }
37
+
38
+ // EDITOR-7860: not ready — skip and leave resourceIds queued for the
39
+ // next batch once the provider resolves. Gate-off is unchanged (the
40
+ // readiness check is nested under the gate so it is not consulted when
41
+ // the gate is off, and `fg()` stays a standalone condition so gate
42
+ // exposure is still tracked — satisfies @atlaskit/platform/no-preconditioning).
43
+ if ((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3')) {
44
+ if (_this.deps.isProviderReady && !_this.deps.isProviderReady()) {
45
+ return;
46
+ }
47
+ }
35
48
  var resourceIds = Array.from(_this.pendingFetchRequests);
36
49
  var syncBlockNodes = resourceIds.map(function (resId) {
37
50
  var subscriptions = _this.deps.getSubscriptions().get(resId) || {};
@@ -45,12 +58,27 @@ var SyncBlockBatchFetcher = exports.SyncBlockBatchFetcher = /*#__PURE__*/functio
45
58
  return _this.inFlightFetches.add(resId);
46
59
  });
47
60
  _this.deps.fetchSyncBlocksData(syncBlockNodes).catch(function (error) {
61
+ // EDITOR-7860: benign not-ready throw — re-queue for retry and emit
62
+ // nothing (no analytics, no exception-tracker noise). Checked before
63
+ // `logException` so the benign case stays silent. Re-schedule so the
64
+ // re-queued IDs are retried on the next frame even if no further
65
+ // `queueFetch()` arrives. Gate-off behaviour is unchanged.
66
+ if ((0, _types.isProviderNotReadyError)(error) && (0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3')) {
67
+ resourceIds.forEach(function (resId) {
68
+ return _this.pendingFetchRequests.add(resId);
69
+ });
70
+ if (!_this.isDestroyed) {
71
+ _this.scheduledBatchFetch();
72
+ }
73
+ return;
74
+ }
48
75
  (0, _monitoring.logException)(error, {
49
76
  location: 'editor-synced-block-provider/syncBlockBatchFetcher/batchedFetchSyncBlocks'
50
77
  });
78
+ var attribution = (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), error.message);
51
79
  resourceIds.forEach(function (resId) {
52
80
  var _this$deps$getFireAna;
53
- (_this$deps$getFireAna = _this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((0, _errorHandling.fetchErrorPayload)(error.message, resId, (0, _utils.getSourceProductFromResourceIdSafe)(resId)));
81
+ (_this$deps$getFireAna = _this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((0, _errorHandling.fetchErrorPayload)(error.message, resId, (0, _utils.getSourceProductFromResourceIdSafe)(resId), attribution));
54
82
  });
55
83
  }).finally(function () {
56
84
  // If the fetcher was destroyed while the request was in flight,
@@ -10,6 +10,7 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/creat
10
10
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
11
  var _monitoring = require("@atlaskit/editor-common/monitoring");
12
12
  var _providerFactory = require("@atlaskit/editor-common/provider-factory");
13
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
13
14
  var _errorHandling = require("../utils/errorHandling");
14
15
  var _resourceId = require("../utils/resourceId");
15
16
  var _utils = require("../utils/utils");
@@ -33,7 +34,7 @@ var SyncBlockProviderFactoryManager = exports.SyncBlockProviderFactoryManager =
33
34
  (0, _monitoring.logException)(error, {
34
35
  location: 'editor-synced-block-provider/syncBlockProviderFactoryManager'
35
36
  });
36
- (_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((0, _errorHandling.fetchErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
37
+ (_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((0, _errorHandling.fetchErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), error.message)));
37
38
  return undefined;
38
39
  }
39
40
  var _dataProvider$getSync = dataProvider.getSyncedBlockRendererProviderOptions(),
@@ -66,7 +67,7 @@ var SyncBlockProviderFactoryManager = exports.SyncBlockProviderFactoryManager =
66
67
  (0, _monitoring.logException)(error, {
67
68
  location: 'editor-synced-block-provider/syncBlockProviderFactoryManager'
68
69
  });
69
- (_this$deps$getFireAna2 = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna2 === void 0 || _this$deps$getFireAna2((0, _errorHandling.fetchErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
70
+ (_this$deps$getFireAna2 = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna2 === void 0 || _this$deps$getFireAna2((0, _errorHandling.fetchErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), error.message)));
70
71
  }
71
72
  }
72
73
  return providerFactory;
@@ -151,7 +152,7 @@ var SyncBlockProviderFactoryManager = exports.SyncBlockProviderFactoryManager =
151
152
  if (!syncBlock.data.sourceAri || !syncBlock.data.product) {
152
153
  var _this$deps$getFireAna3, _syncBlock$data$produ;
153
154
  (_this$deps$getFireAna3 = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna3 === void 0 || _this$deps$getFireAna3((0, _errorHandling.fetchErrorPayload)('Sync block source ari or product not found', resourceId, // Prefer cached product when available; fall back to parsing resourceId.
154
- (_syncBlock$data$produ = syncBlock.data.product) !== null && _syncBlock$data$produ !== void 0 ? _syncBlock$data$produ : (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
155
+ (_syncBlock$data$produ = syncBlock.data.product) !== null && _syncBlock$data$produ !== void 0 ? _syncBlock$data$produ : (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), 'Sync block source ari or product not found')));
155
156
  return;
156
157
  }
157
158
  var parentInfo = dataProvider.retrieveSyncBlockParentInfo(syncBlock.data.sourceAri, syncBlock.data.product);
@@ -120,7 +120,7 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
120
120
  (0, _monitoring.logException)(error, {
121
121
  location: 'editor-synced-block-provider/syncBlockSubscriptionManager/notifySubscriptionChangeListeners'
122
122
  });
123
- (_this2$deps$getFireAn = _this2.deps.getFireAnalyticsEvent()) === null || _this2$deps$getFireAn === void 0 || _this2$deps$getFireAn((0, _errorHandling.fetchErrorPayload)(error.message));
123
+ (_this2$deps$getFireAn = _this2.deps.getFireAnalyticsEvent()) === null || _this2$deps$getFireAn === void 0 || _this2$deps$getFireAn((0, _errorHandling.fetchErrorPayload)(error.message, undefined, undefined, (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), error.message)));
124
124
  }
125
125
  });
126
126
  }
@@ -305,6 +305,9 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
305
305
  // recovers on reconnect, so under the gate we don't fire a
306
306
  // user-facing error here — it's only surfaced on exhaustion (see
307
307
  // scheduleReconnection). Gate OFF keeps the legacy fire-on-drop.
308
+ // This branch only runs when the gate is OFF, so buildFetchErrorAttribution
309
+ // would return undefined; the structured attribution (EDITOR-7862) is therefore
310
+ // applied at the gate-ON exhaustion site in scheduleReconnection instead.
308
311
  if (!(0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3')) {
309
312
  var _this5$deps$getFireAn;
310
313
  (_this5$deps$getFireAn = _this5.deps.getFireAnalyticsEvent()) === null || _this5$deps$getFireAn === void 0 || _this5$deps$getFireAn((0, _errorHandling.fetchErrorPayload)(error.message, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
@@ -356,7 +359,7 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
356
359
  (0, _monitoring.logException)(new Error(errorMessage), {
357
360
  location: 'editor-synced-block-provider/syncBlockSubscriptionManager/max-retries-exhausted'
358
361
  });
359
- (_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((0, _errorHandling.fetchErrorPayload)(errorMessage, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
362
+ (_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((0, _errorHandling.fetchErrorPayload)(errorMessage, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId), (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), errorMessage)));
360
363
  return;
361
364
  }
362
365
  var delay = this.getReconnectionDelay(attempts);
@@ -510,9 +513,13 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
510
513
  });
511
514
  this.deps.fetchSyncBlockSourceInfo(resolved.resourceId);
512
515
  } else {
513
- var _syncBlockInstance$er, _syncBlockInstance$er2, _this$deps$getFireAna2, _syncBlockInstance$da3, _syncBlockInstance$da4;
516
+ var _syncBlockInstance$er, _syncBlockInstance$er2, _this$deps$getFireAna2, _syncBlockInstance$da3, _syncBlockInstance$da4, _syncBlockInstance$er3, _syncBlockInstance$er4, _syncBlockInstance$er5;
514
517
  var errorMessage = ((_syncBlockInstance$er = syncBlockInstance.error) === null || _syncBlockInstance$er === void 0 ? void 0 : _syncBlockInstance$er.reason) || ((_syncBlockInstance$er2 = syncBlockInstance.error) === null || _syncBlockInstance$er2 === void 0 ? void 0 : _syncBlockInstance$er2.type);
515
- (_this$deps$getFireAna2 = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna2 === void 0 || _this$deps$getFireAna2((0, _errorHandling.fetchErrorPayload)(errorMessage, syncBlockInstance.resourceId, (_syncBlockInstance$da3 = (_syncBlockInstance$da4 = syncBlockInstance.data) === null || _syncBlockInstance$da4 === void 0 ? void 0 : _syncBlockInstance$da4.product) !== null && _syncBlockInstance$da3 !== void 0 ? _syncBlockInstance$da3 : (0, _utils.getSourceProductFromResourceIdSafe)(syncBlockInstance.resourceId)));
518
+
519
+ // Prefer the structured `type` (a `SyncBlockError` enum value) for classification
520
+ // and fall back to the free-text `reason` so source-state/permission strings are
521
+ // still bucketed (EDITOR-7862). The emitted free-text `error` attribute is unchanged.
522
+ (_this$deps$getFireAna2 = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna2 === void 0 || _this$deps$getFireAna2((0, _errorHandling.fetchErrorPayload)(errorMessage, syncBlockInstance.resourceId, (_syncBlockInstance$da3 = (_syncBlockInstance$da4 = syncBlockInstance.data) === null || _syncBlockInstance$da4 === void 0 ? void 0 : _syncBlockInstance$da4.product) !== null && _syncBlockInstance$da3 !== void 0 ? _syncBlockInstance$da3 : (0, _utils.getSourceProductFromResourceIdSafe)(syncBlockInstance.resourceId), (0, _errorHandling.buildFetchErrorAttribution)((0, _platformFeatureFlags.fg)('platform_editor_blocks_patch_3'), ((_syncBlockInstance$er3 = syncBlockInstance.error) === null || _syncBlockInstance$er3 === void 0 ? void 0 : _syncBlockInstance$er3.type) || ((_syncBlockInstance$er4 = syncBlockInstance.error) === null || _syncBlockInstance$er4 === void 0 ? void 0 : _syncBlockInstance$er4.reason), (_syncBlockInstance$er5 = syncBlockInstance.error) === null || _syncBlockInstance$er5 === void 0 ? void 0 : _syncBlockInstance$er5.statusCode)));
516
523
  }
517
524
  }
518
525
  }]);