@atlaskit/editor-synced-block-provider 8.2.0 → 8.3.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 +22 -0
- package/dist/cjs/clients/block-service/ari.js +7 -3
- package/dist/cjs/clients/block-service/blockSubscription.js +4 -2
- package/dist/cjs/clients/confluence/ari.js +3 -1
- package/dist/cjs/clients/jira/ari.js +3 -1
- package/dist/cjs/hooks/useFetchSyncBlockData.js +1 -1
- package/dist/cjs/providers/block-service/blockServiceAPI.js +11 -6
- package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +9 -4
- package/dist/cjs/store-manager/syncBlockBatchFetcher.js +2 -1
- package/dist/cjs/store-manager/syncBlockProviderFactoryManager.js +4 -3
- package/dist/cjs/store-manager/syncBlockSubscriptionManager.js +11 -4
- package/dist/cjs/utils/errorHandling.js +152 -6
- package/dist/cjs/utils/utils.js +2 -1
- package/dist/es2019/clients/block-service/ari.js +7 -3
- package/dist/es2019/clients/block-service/blockSubscription.js +4 -2
- package/dist/es2019/clients/confluence/ari.js +3 -1
- package/dist/es2019/clients/jira/ari.js +3 -1
- package/dist/es2019/hooks/useFetchSyncBlockData.js +2 -2
- package/dist/es2019/providers/block-service/blockServiceAPI.js +15 -5
- package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +10 -5
- package/dist/es2019/store-manager/syncBlockBatchFetcher.js +3 -2
- package/dist/es2019/store-manager/syncBlockProviderFactoryManager.js +5 -4
- package/dist/es2019/store-manager/syncBlockSubscriptionManager.js +12 -5
- package/dist/es2019/utils/errorHandling.js +167 -22
- package/dist/es2019/utils/utils.js +2 -1
- package/dist/esm/clients/block-service/ari.js +7 -3
- package/dist/esm/clients/block-service/blockSubscription.js +4 -2
- package/dist/esm/clients/confluence/ari.js +3 -1
- package/dist/esm/clients/jira/ari.js +3 -1
- package/dist/esm/hooks/useFetchSyncBlockData.js +2 -2
- package/dist/esm/providers/block-service/blockServiceAPI.js +11 -6
- package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +10 -5
- package/dist/esm/store-manager/syncBlockBatchFetcher.js +3 -2
- package/dist/esm/store-manager/syncBlockProviderFactoryManager.js +5 -4
- package/dist/esm/store-manager/syncBlockSubscriptionManager.js +12 -5
- package/dist/esm/utils/errorHandling.js +149 -5
- package/dist/esm/utils/utils.js +2 -1
- package/dist/types/providers/types.d.ts +8 -0
- package/dist/types/utils/errorHandling.d.ts +94 -2
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
1
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
3
2
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
4
|
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
|
|
5
5
|
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
6
6
|
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; }
|
|
@@ -18,6 +18,8 @@ import { SyncBlockError } from '../../common/types';
|
|
|
18
18
|
import { stringifyError } from '../../utils/errorHandling';
|
|
19
19
|
import { createResourceIdForReference } from '../../utils/resourceId';
|
|
20
20
|
import { convertContentUpdatedAt } from '../../utils/utils';
|
|
21
|
+
var BLOCK_ARI_TO_RESOURCE_ID_REGEX = /^ari:cloud:blocks:.*:synced-block\/(.+)$/;
|
|
22
|
+
var EXTRACT_RESOURCE_ID_FROM_BLOCK_ARI_REGEX = /ari:cloud:blocks:[^:]+:synced-block\/(.+)$/;
|
|
21
23
|
var mapBlockError = function mapBlockError(error) {
|
|
22
24
|
switch (error.status) {
|
|
23
25
|
case 400:
|
|
@@ -84,7 +86,7 @@ export var blockAriToResourceId = function blockAriToResourceId(blockAri) {
|
|
|
84
86
|
// The regex captures the full path after synced-block/
|
|
85
87
|
// e.g. ari:cloud:blocks:DUMMY-a5a01d21-1cc3-4f29-9565-f2bb8cd969f5:synced-block/confluence-page/455232061495/e8cf64e3-1b6e-489b-ad86-8465b0905bb4
|
|
86
88
|
// should return confluence-page/455232061495/e8cf64e3-1b6e-489b-ad86-8465b0905bb4
|
|
87
|
-
var match = blockAri.match(
|
|
89
|
+
var match = blockAri.match(BLOCK_ARI_TO_RESOURCE_ID_REGEX);
|
|
88
90
|
return (match === null || match === void 0 ? void 0 : match[1]) || null;
|
|
89
91
|
};
|
|
90
92
|
|
|
@@ -193,7 +195,7 @@ export var fetchReferences = /*#__PURE__*/function () {
|
|
|
193
195
|
* Block ARI format: ari:cloud:blocks:<cloudId>:synced-block/<resourceId>
|
|
194
196
|
*/
|
|
195
197
|
export var extractResourceIdFromBlockAri = function extractResourceIdFromBlockAri(blockAri) {
|
|
196
|
-
var match = blockAri.match(
|
|
198
|
+
var match = blockAri.match(EXTRACT_RESOURCE_ID_FROM_BLOCK_ARI_REGEX);
|
|
197
199
|
return match === null || match === void 0 ? void 0 : match[1];
|
|
198
200
|
};
|
|
199
201
|
|
|
@@ -405,10 +407,12 @@ var _batchFetchData = /*#__PURE__*/function () {
|
|
|
405
407
|
case 21:
|
|
406
408
|
return _context2.abrupt("return", blockNodeIdentifiers.map(function (blockNodeIdentifier) {
|
|
407
409
|
return {
|
|
408
|
-
error: {
|
|
410
|
+
error: _objectSpread({
|
|
409
411
|
type: _t4 instanceof BlockError ? mapBlockError(_t4) : SyncBlockError.Errored,
|
|
410
412
|
reason: _t4.message
|
|
411
|
-
},
|
|
413
|
+
}, _t4 instanceof BlockError && {
|
|
414
|
+
statusCode: _t4.status
|
|
415
|
+
}),
|
|
412
416
|
resourceId: blockNodeIdentifier.resourceId
|
|
413
417
|
};
|
|
414
418
|
}));
|
|
@@ -661,7 +665,8 @@ var BlockServiceADFFetchProvider = /*#__PURE__*/function () {
|
|
|
661
665
|
return _context5.abrupt("return", {
|
|
662
666
|
error: {
|
|
663
667
|
type: mapBlockError(_t7),
|
|
664
|
-
reason: _t7.message
|
|
668
|
+
reason: _t7.message,
|
|
669
|
+
statusCode: _t7.status
|
|
665
670
|
},
|
|
666
671
|
resourceId: resourceId
|
|
667
672
|
});
|
|
@@ -13,7 +13,7 @@ import isEqual from 'lodash/isEqual';
|
|
|
13
13
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
14
14
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
15
15
|
import { isProviderNotReadyError, ProviderNotReadyError, SyncBlockError } from '../common/types';
|
|
16
|
-
import { buildErrorAttribution, cacheDeletionForcedPayload, fetchErrorPayload, fetchSuccessPayload, getSourceInfoErrorPayload, sourceInfoOrphanedPayload, updateReferenceErrorPayload } from '../utils/errorHandling';
|
|
16
|
+
import { buildErrorAttribution, buildFetchErrorAttribution, cacheDeletionForcedPayload, fetchErrorPayload, fetchSuccessPayload, getSourceInfoErrorPayload, sourceInfoOrphanedPayload, updateReferenceErrorPayload } from '../utils/errorHandling';
|
|
17
17
|
import { getFetchExperience, getFetchSourceInfoExperience, getSaveReferenceExperience } from '../utils/experienceTracking';
|
|
18
18
|
import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
|
|
19
19
|
import { createSyncBlockNode, getSourceProductFromResourceIdSafe, normalizeSyncBlockJSONContent } from '../utils/utils';
|
|
@@ -602,10 +602,12 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
602
602
|
data.forEach(function (syncBlockInstance) {
|
|
603
603
|
var _resolvedSyncBlockIns;
|
|
604
604
|
if (!syncBlockInstance.resourceId) {
|
|
605
|
-
var _syncBlockInstance$er, _syncBlockInstance$er2, _this5$fireAnalyticsE;
|
|
605
|
+
var _syncBlockInstance$er, _syncBlockInstance$er2, _this5$fireAnalyticsE, _syncBlockInstance$er3, _syncBlockInstance$er4, _syncBlockInstance$er5;
|
|
606
606
|
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';
|
|
607
607
|
// No resourceId means we cannot derive a sourceProduct here; intentionally omit.
|
|
608
|
-
|
|
608
|
+
// Classify on the structured `type` first, falling back to the free-text
|
|
609
|
+
// `reason`/payload (EDITOR-7862).
|
|
610
|
+
(_this5$fireAnalyticsE = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE === void 0 || _this5$fireAnalyticsE.call(_this5, fetchErrorPayload(payload, undefined, undefined, buildFetchErrorAttribution(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)));
|
|
609
611
|
return;
|
|
610
612
|
}
|
|
611
613
|
var existingSyncBlock = _this5.getFromCache(syncBlockInstance.resourceId);
|
|
@@ -639,7 +641,10 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
639
641
|
var isRetryingEntityNotFound = syncBlockInstance.error.type === SyncBlockError.EntityNotFound && ((_this5$entityNotFound = _this5.entityNotFoundRetryCount.get(syncBlockInstance.resourceId)) !== null && _this5$entityNotFound !== void 0 ? _this5$entityNotFound : 0) < ENTITY_NOT_FOUND_MAX_RETRIES && fg('platform_synced_block_patch_13');
|
|
640
642
|
if (!isRetryingEntityNotFound) {
|
|
641
643
|
var _this5$fireAnalyticsE2, _syncBlockInstance$da, _syncBlockInstance$da2;
|
|
642
|
-
|
|
644
|
+
// Classify on the structured `type` (a `SyncBlockError` enum value) first,
|
|
645
|
+
// falling back to the free-text `reason` so source-state/permission strings
|
|
646
|
+
// are still bucketed (EDITOR-7862). The emitted `error` attribute is unchanged.
|
|
647
|
+
(_this5$fireAnalyticsE2 = _this5.fireAnalyticsEvent) === null || _this5$fireAnalyticsE2 === void 0 || _this5$fireAnalyticsE2.call(_this5, 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 : getSourceProductFromResourceIdSafe(syncBlockInstance.resourceId), buildFetchErrorAttribution(fg('platform_editor_blocks_patch_3'), syncBlockInstance.error.type || syncBlockInstance.error.reason, syncBlockInstance.error.statusCode)));
|
|
643
648
|
}
|
|
644
649
|
if (syncBlockInstance.error.type === SyncBlockError.NotFound || syncBlockInstance.error.type === SyncBlockError.Forbidden) {
|
|
645
650
|
hasExpectedError = true;
|
|
@@ -963,7 +968,7 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
963
968
|
logException(error, {
|
|
964
969
|
location: 'editor-synced-block-provider/referenceSyncBlockStoreManager'
|
|
965
970
|
});
|
|
966
|
-
(_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 || _this$fireAnalyticsEv7.call(this, fetchErrorPayload(error.message));
|
|
971
|
+
(_this$fireAnalyticsEv7 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv7 === void 0 || _this$fireAnalyticsEv7.call(this, fetchErrorPayload(error.message, undefined, undefined, buildFetchErrorAttribution(fg('platform_editor_blocks_patch_3'), error.message)));
|
|
967
972
|
return function () {};
|
|
968
973
|
}
|
|
969
974
|
}
|
|
@@ -5,7 +5,7 @@ import rafSchedule from 'raf-schd';
|
|
|
5
5
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
6
6
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
7
|
import { isProviderNotReadyError } from '../common/types';
|
|
8
|
-
import { fetchErrorPayload } from '../utils/errorHandling';
|
|
8
|
+
import { buildFetchErrorAttribution, fetchErrorPayload } from '../utils/errorHandling';
|
|
9
9
|
import { createSyncBlockNode, getSourceProductFromResourceIdSafe } from '../utils/utils';
|
|
10
10
|
/**
|
|
11
11
|
* Handles debounced batch-fetching of sync block data via `raf-schd`.
|
|
@@ -68,9 +68,10 @@ export var SyncBlockBatchFetcher = /*#__PURE__*/function () {
|
|
|
68
68
|
logException(error, {
|
|
69
69
|
location: 'editor-synced-block-provider/syncBlockBatchFetcher/batchedFetchSyncBlocks'
|
|
70
70
|
});
|
|
71
|
+
var attribution = buildFetchErrorAttribution(fg('platform_editor_blocks_patch_3'), error.message);
|
|
71
72
|
resourceIds.forEach(function (resId) {
|
|
72
73
|
var _this$deps$getFireAna;
|
|
73
|
-
(_this$deps$getFireAna = _this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna(fetchErrorPayload(error.message, resId, getSourceProductFromResourceIdSafe(resId)));
|
|
74
|
+
(_this$deps$getFireAna = _this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna(fetchErrorPayload(error.message, resId, getSourceProductFromResourceIdSafe(resId), attribution));
|
|
74
75
|
});
|
|
75
76
|
}).finally(function () {
|
|
76
77
|
// If the fetcher was destroyed while the request was in flight,
|
|
@@ -3,7 +3,8 @@ import _createClass from "@babel/runtime/helpers/createClass";
|
|
|
3
3
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
4
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
5
5
|
import { ProviderFactory } from '@atlaskit/editor-common/provider-factory';
|
|
6
|
-
import {
|
|
6
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
|
+
import { buildFetchErrorAttribution, fetchErrorPayload } from '../utils/errorHandling';
|
|
7
8
|
import { parseResourceId } from '../utils/resourceId';
|
|
8
9
|
import { getSourceProductFromResourceIdSafe } from '../utils/utils';
|
|
9
10
|
/**
|
|
@@ -26,7 +27,7 @@ export var SyncBlockProviderFactoryManager = /*#__PURE__*/function () {
|
|
|
26
27
|
logException(error, {
|
|
27
28
|
location: 'editor-synced-block-provider/syncBlockProviderFactoryManager'
|
|
28
29
|
});
|
|
29
|
-
(_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna(fetchErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
|
|
30
|
+
(_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna(fetchErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId), buildFetchErrorAttribution(fg('platform_editor_blocks_patch_3'), error.message)));
|
|
30
31
|
return undefined;
|
|
31
32
|
}
|
|
32
33
|
var _dataProvider$getSync = dataProvider.getSyncedBlockRendererProviderOptions(),
|
|
@@ -59,7 +60,7 @@ export var SyncBlockProviderFactoryManager = /*#__PURE__*/function () {
|
|
|
59
60
|
logException(error, {
|
|
60
61
|
location: 'editor-synced-block-provider/syncBlockProviderFactoryManager'
|
|
61
62
|
});
|
|
62
|
-
(_this$deps$getFireAna2 = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna2 === void 0 || _this$deps$getFireAna2(fetchErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
|
|
63
|
+
(_this$deps$getFireAna2 = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna2 === void 0 || _this$deps$getFireAna2(fetchErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId), buildFetchErrorAttribution(fg('platform_editor_blocks_patch_3'), error.message)));
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
return providerFactory;
|
|
@@ -144,7 +145,7 @@ export var SyncBlockProviderFactoryManager = /*#__PURE__*/function () {
|
|
|
144
145
|
if (!syncBlock.data.sourceAri || !syncBlock.data.product) {
|
|
145
146
|
var _this$deps$getFireAna3, _syncBlock$data$produ;
|
|
146
147
|
(_this$deps$getFireAna3 = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna3 === void 0 || _this$deps$getFireAna3(fetchErrorPayload('Sync block source ari or product not found', resourceId, // Prefer cached product when available; fall back to parsing resourceId.
|
|
147
|
-
(_syncBlock$data$produ = syncBlock.data.product) !== null && _syncBlock$data$produ !== void 0 ? _syncBlock$data$produ : getSourceProductFromResourceIdSafe(resourceId)));
|
|
148
|
+
(_syncBlock$data$produ = syncBlock.data.product) !== null && _syncBlock$data$produ !== void 0 ? _syncBlock$data$produ : getSourceProductFromResourceIdSafe(resourceId), buildFetchErrorAttribution(fg('platform_editor_blocks_patch_3'), 'Sync block source ari or product not found')));
|
|
148
149
|
return;
|
|
149
150
|
}
|
|
150
151
|
var parentInfo = dataProvider.retrieveSyncBlockParentInfo(syncBlock.data.sourceAri, syncBlock.data.product);
|
|
@@ -8,7 +8,7 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
|
|
|
8
8
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
9
9
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
10
10
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
11
|
-
import { fetchErrorPayload, fetchSuccessPayload } from '../utils/errorHandling';
|
|
11
|
+
import { buildFetchErrorAttribution, fetchErrorPayload, fetchSuccessPayload } from '../utils/errorHandling';
|
|
12
12
|
import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
|
|
13
13
|
import { getSourceProductFromResourceIdSafe } from '../utils/utils';
|
|
14
14
|
/**
|
|
@@ -114,7 +114,7 @@ export var SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
|
114
114
|
logException(error, {
|
|
115
115
|
location: 'editor-synced-block-provider/syncBlockSubscriptionManager/notifySubscriptionChangeListeners'
|
|
116
116
|
});
|
|
117
|
-
(_this2$deps$getFireAn = _this2.deps.getFireAnalyticsEvent()) === null || _this2$deps$getFireAn === void 0 || _this2$deps$getFireAn(fetchErrorPayload(error.message));
|
|
117
|
+
(_this2$deps$getFireAn = _this2.deps.getFireAnalyticsEvent()) === null || _this2$deps$getFireAn === void 0 || _this2$deps$getFireAn(fetchErrorPayload(error.message, undefined, undefined, buildFetchErrorAttribution(fg('platform_editor_blocks_patch_3'), error.message)));
|
|
118
118
|
}
|
|
119
119
|
});
|
|
120
120
|
}
|
|
@@ -299,6 +299,9 @@ export var SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
|
299
299
|
// recovers on reconnect, so under the gate we don't fire a
|
|
300
300
|
// user-facing error here — it's only surfaced on exhaustion (see
|
|
301
301
|
// scheduleReconnection). Gate OFF keeps the legacy fire-on-drop.
|
|
302
|
+
// This branch only runs when the gate is OFF, so buildFetchErrorAttribution
|
|
303
|
+
// would return undefined; the structured attribution (EDITOR-7862) is therefore
|
|
304
|
+
// applied at the gate-ON exhaustion site in scheduleReconnection instead.
|
|
302
305
|
if (!fg('platform_editor_blocks_patch_3')) {
|
|
303
306
|
var _this5$deps$getFireAn;
|
|
304
307
|
(_this5$deps$getFireAn = _this5.deps.getFireAnalyticsEvent()) === null || _this5$deps$getFireAn === void 0 || _this5$deps$getFireAn(fetchErrorPayload(error.message, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
|
|
@@ -350,7 +353,7 @@ export var SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
|
350
353
|
logException(new Error(errorMessage), {
|
|
351
354
|
location: 'editor-synced-block-provider/syncBlockSubscriptionManager/max-retries-exhausted'
|
|
352
355
|
});
|
|
353
|
-
(_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna(fetchErrorPayload(errorMessage, resourceId, getSourceProductFromResourceIdSafe(resourceId)));
|
|
356
|
+
(_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna(fetchErrorPayload(errorMessage, resourceId, getSourceProductFromResourceIdSafe(resourceId), buildFetchErrorAttribution(fg('platform_editor_blocks_patch_3'), errorMessage)));
|
|
354
357
|
return;
|
|
355
358
|
}
|
|
356
359
|
var delay = this.getReconnectionDelay(attempts);
|
|
@@ -504,9 +507,13 @@ export var SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
|
504
507
|
});
|
|
505
508
|
this.deps.fetchSyncBlockSourceInfo(resolved.resourceId);
|
|
506
509
|
} else {
|
|
507
|
-
var _syncBlockInstance$er, _syncBlockInstance$er2, _this$deps$getFireAna2, _syncBlockInstance$da3, _syncBlockInstance$da4;
|
|
510
|
+
var _syncBlockInstance$er, _syncBlockInstance$er2, _this$deps$getFireAna2, _syncBlockInstance$da3, _syncBlockInstance$da4, _syncBlockInstance$er3, _syncBlockInstance$er4, _syncBlockInstance$er5;
|
|
508
511
|
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);
|
|
509
|
-
|
|
512
|
+
|
|
513
|
+
// Prefer the structured `type` (a `SyncBlockError` enum value) for classification
|
|
514
|
+
// and fall back to the free-text `reason` so source-state/permission strings are
|
|
515
|
+
// still bucketed (EDITOR-7862). The emitted free-text `error` attribute is unchanged.
|
|
516
|
+
(_this$deps$getFireAna2 = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna2 === void 0 || _this$deps$getFireAna2(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 : getSourceProductFromResourceIdSafe(syncBlockInstance.resourceId), buildFetchErrorAttribution(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)));
|
|
510
517
|
}
|
|
511
518
|
}
|
|
512
519
|
}]);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
1
2
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
3
|
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; }
|
|
3
4
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -60,19 +61,155 @@ export var buildErrorAttribution = function buildErrorAttribution(gateEnabled, e
|
|
|
60
61
|
});
|
|
61
62
|
};
|
|
62
63
|
|
|
64
|
+
/**
|
|
65
|
+
* The set of categorical failure reasons emitted on synced-block fetch/subscribe
|
|
66
|
+
* operational error events (EDITOR-7862). Extends the write-path
|
|
67
|
+
* {@link SyncBlockErrorReason} set with read-path-specific buckets so the analytics
|
|
68
|
+
* dashboard can break fetch failures down by cause instead of regex-matching the
|
|
69
|
+
* free-text `error` blob.
|
|
70
|
+
*
|
|
71
|
+
* The read path surfaces several causes the write-path `SyncBlockError` enum does not
|
|
72
|
+
* model (benign source-state transitions, permission denials, WebSocket lifecycle, and
|
|
73
|
+
* client-side readiness errors), so those are added here. Known `SyncBlockError` enum
|
|
74
|
+
* values (`not_found`, `forbidden`, ...) still pass through unchanged.
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Fetch reasons that represent benign (working-as-designed) outcomes rather than genuine
|
|
79
|
+
* system failures. The dashboard uses this to compute a "true error rate" by excluding
|
|
80
|
+
* benign reasons via the structured `reason` attribute instead of brittle free-text regex
|
|
81
|
+
* (EDITOR-7862).
|
|
82
|
+
*/
|
|
83
|
+
export var FETCH_BENIGN_REASONS = new Set(['source_deleted', 'source_unpublished', 'source_unsynced', 'source_not_found', 'permission_denied', 'unauthenticated',
|
|
84
|
+
// Mirror the benign write-path enum equivalents so already-classified errors are
|
|
85
|
+
// treated consistently.
|
|
86
|
+
'not_found', 'forbidden', 'unpublished'
|
|
87
|
+
// NOTE: `entity_not_found` and `offline` are intentionally NOT benign.
|
|
88
|
+
// - `entity_not_found` is retried up to ENTITY_NOT_FOUND_MAX_RETRIES (analytics are
|
|
89
|
+
// suppressed during retries); by the time the error event fires, retries are
|
|
90
|
+
// exhausted and it is a genuine failure.
|
|
91
|
+
// - `offline` is genuine client connectivity loss, not a working-as-designed outcome.
|
|
92
|
+
// Both still emit `reason` (so they can be inspected) but are counted as true errors.
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Ordered list of substring matchers mapping known free-text fetch/subscribe error
|
|
97
|
+
* strings to a categorical {@link SyncBlockFetchErrorReason}. Each entry is a list of
|
|
98
|
+
* lowercase needles; if ANY needle is found (case-insensitively) in the raw `error`
|
|
99
|
+
* string, the entry's reason is used. Order matters: more specific entries must precede
|
|
100
|
+
* more general ones.
|
|
101
|
+
*
|
|
102
|
+
* Plain `String.includes` substring matching is used deliberately instead of `RegExp`:
|
|
103
|
+
* it sidesteps the `require-unicode-regexp` lint rule AND the declaration build's lower
|
|
104
|
+
* compile target (which rejects the regex `u` flag with TS1501), while being faster and
|
|
105
|
+
* easier to read. Doing this classification in code (rather than in dashboard SQL) keeps
|
|
106
|
+
* the buckets versioned with the source strings that produce them (EDITOR-7862).
|
|
107
|
+
*/
|
|
108
|
+
var FETCH_REASON_MATCHERS = [
|
|
109
|
+
// Benign: source-state transitions (deletionReason values + free text).
|
|
110
|
+
[['source-document-deleted'], 'source_deleted'], [['source-block-deleted'], 'source_deleted'], [['source-block-unpublished'], 'source_unpublished'], [['source-block-unsynced'], 'source_unsynced'], [['does not exist'], 'source_not_found'], [['unpublished'], 'source_unpublished'],
|
|
111
|
+
// Working-as-designed permission outcomes.
|
|
112
|
+
[['unauthenticated'], 'unauthenticated'], [['not permitted to read synced block'], 'permission_denied'], [['bulk permission check failed'], 'permission_denied'], [['permission denied'], 'permission_denied'],
|
|
113
|
+
// Genuine system failures.
|
|
114
|
+
[['reconnection failed after'], 'websocket_exhausted'],
|
|
115
|
+
// `reconnect to the subscription` (not a bare `reconnect`) avoids false positives on
|
|
116
|
+
// unrelated DB/GraphQL "reconnect" messages while still matching the WS-drop string.
|
|
117
|
+
[['websocket', 'reconnect to the subscription', 'subscription terminated'], 'websocket_drop'], [['429', 'rate limit', 'rate-limit', 'ratelimit'], 'rate_limited'],
|
|
118
|
+
// `econnrefused`/`econnreset` (not a bare `econn`, which would also match `reconnect`).
|
|
119
|
+
[['network', 'failed to fetch', 'econnrefused', 'econnreset', 'timed out', 'timeout'], 'network'], [['data provider not set'], 'data_provider_not_ready']];
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Maps a fetch/subscribe `error` field — which may be a {@link SyncBlockError} enum
|
|
123
|
+
* value, a {@link DeletionReason} value, or an arbitrary free-text/JSON blob — to a
|
|
124
|
+
* stable categorical {@link SyncBlockFetchErrorReason} for analytics grouping.
|
|
125
|
+
*
|
|
126
|
+
* Resolution order:
|
|
127
|
+
* 1. Known `SyncBlockError` enum value → passed through (via {@link classifyErrorReason}).
|
|
128
|
+
* 2. Known free-text substring → mapped to a fetch-specific bucket.
|
|
129
|
+
* 3. Anything else (including opaque blobs like `errored`-only payloads or
|
|
130
|
+
* `ErrorEvent: "undefined"`) → `'unknown'`, so the dashboard never groups on free text.
|
|
131
|
+
*
|
|
132
|
+
* Note: the bare string `'errored'` IS a `SyncBlockError` enum value and therefore
|
|
133
|
+
* classifies as `'errored'` (not `'unknown'`); only genuinely unrecognised strings
|
|
134
|
+
* collapse to `'unknown'`.
|
|
135
|
+
*/
|
|
136
|
+
export var classifyFetchErrorReason = function classifyFetchErrorReason(error) {
|
|
137
|
+
var enumReason = classifyErrorReason(error);
|
|
138
|
+
if (enumReason !== 'unknown') {
|
|
139
|
+
return enumReason;
|
|
140
|
+
}
|
|
141
|
+
if (error) {
|
|
142
|
+
var haystack = error.toLowerCase();
|
|
143
|
+
for (var _i = 0, _FETCH_REASON_MATCHER = FETCH_REASON_MATCHERS; _i < _FETCH_REASON_MATCHER.length; _i++) {
|
|
144
|
+
var _FETCH_REASON_MATCHER2 = _slicedToArray(_FETCH_REASON_MATCHER[_i], 2),
|
|
145
|
+
needles = _FETCH_REASON_MATCHER2[0],
|
|
146
|
+
reason = _FETCH_REASON_MATCHER2[1];
|
|
147
|
+
if (needles.some(function (needle) {
|
|
148
|
+
return haystack.includes(needle);
|
|
149
|
+
})) {
|
|
150
|
+
return reason;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return 'unknown';
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Extra, optional analytics attributes describing WHY a fetch/subscribe synced-block
|
|
159
|
+
* action failed. Spread conditionally so we never emit `undefined` keys (EDITOR-7862).
|
|
160
|
+
*
|
|
161
|
+
* Adds `benign` on top of the shared {@link ErrorAttributionAttributes} so the dashboard
|
|
162
|
+
* can compute a true error rate (`genuine / total`) without any free-text regex.
|
|
163
|
+
*/
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Builds the {@link FetchErrorAttributionAttributes} for a failed fetch/subscribe
|
|
167
|
+
* synced-block operation from the raw `error` field and optional backend `statusCode`.
|
|
168
|
+
* Returns `undefined` when the `platform_editor_blocks_patch_3` gate is OFF, so the new
|
|
169
|
+
* `reason`/`statusCode`/`benign` attributes are only emitted once the gate is rolled out
|
|
170
|
+
* (EDITOR-7862). The existing free-text `error` attribute is always left unchanged.
|
|
171
|
+
*
|
|
172
|
+
* `gateEnabled` is injected by the caller (the store managers evaluate `fg(...)`) so this
|
|
173
|
+
* helper stays pure and trivially unit-testable for both gate states.
|
|
174
|
+
*/
|
|
175
|
+
export var buildFetchErrorAttribution = function buildFetchErrorAttribution(gateEnabled, error, statusCode) {
|
|
176
|
+
if (!gateEnabled) {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
var reason = classifyFetchErrorReason(error);
|
|
180
|
+
return _objectSpread({
|
|
181
|
+
reason: reason,
|
|
182
|
+
benign: FETCH_BENIGN_REASONS.has(reason)
|
|
183
|
+
}, statusCode !== undefined && {
|
|
184
|
+
statusCode: statusCode
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
|
|
63
188
|
// `sourceProduct` is threaded through every helper so analytics
|
|
64
189
|
// events can be attributed to the source product (`confluence-page` vs `jira-work-item`).
|
|
65
190
|
// All helpers accept it as an optional trailing argument; the spread-only-when-truthy
|
|
66
191
|
// pattern below ensures we never emit `sourceProduct: undefined` (which would dirty the
|
|
67
192
|
// event schema with empty keys).
|
|
68
193
|
|
|
69
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Shared operational ERROR payload builder for synced-block events.
|
|
196
|
+
*
|
|
197
|
+
* Overloaded so the emitted `reason` type stays accurate per path (raised in review on
|
|
198
|
+
* EDITOR-7862): fetch/subscribe callers pass a {@link FetchErrorAttributionAttributes}
|
|
199
|
+
* (discriminated by its required `benign` field) and get the wider
|
|
200
|
+
* {@link SyncBlockFetchErrorReason}; write-path callers pass an
|
|
201
|
+
* {@link ErrorAttributionAttributes} (or nothing) and keep the narrower
|
|
202
|
+
* {@link SyncBlockErrorReason}, so write-path payloads never claim to carry fetch-only
|
|
203
|
+
* buckets like `source_deleted` they never emit.
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
export function getErrorPayload(actionSubjectId, error, resourceId, sourceProduct, attribution) {
|
|
70
207
|
return {
|
|
71
208
|
action: ACTION.ERROR,
|
|
72
209
|
actionSubject: ACTION_SUBJECT.SYNCED_BLOCK,
|
|
73
210
|
actionSubjectId: actionSubjectId,
|
|
74
211
|
eventType: EVENT_TYPE.OPERATIONAL,
|
|
75
|
-
attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread({
|
|
212
|
+
attributes: _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({
|
|
76
213
|
error: error
|
|
77
214
|
}, resourceId && {
|
|
78
215
|
resourceId: resourceId
|
|
@@ -82,11 +219,18 @@ export var getErrorPayload = function getErrorPayload(actionSubjectId, error, re
|
|
|
82
219
|
reason: attribution.reason
|
|
83
220
|
}), (attribution === null || attribution === void 0 ? void 0 : attribution.statusCode) !== undefined && {
|
|
84
221
|
statusCode: attribution.statusCode
|
|
222
|
+
}), attribution && 'benign' in attribution && {
|
|
223
|
+
benign: attribution.benign
|
|
85
224
|
})
|
|
86
225
|
};
|
|
87
|
-
}
|
|
88
|
-
export var fetchErrorPayload = function fetchErrorPayload(error, resourceId, sourceProduct) {
|
|
89
|
-
return
|
|
226
|
+
}
|
|
227
|
+
export var fetchErrorPayload = function fetchErrorPayload(error, resourceId, sourceProduct, attribution) {
|
|
228
|
+
return (
|
|
229
|
+
// Branch on attribution presence so each call resolves to a concrete overload: with
|
|
230
|
+
// attribution it hits the fetch overload (wider `reason`); without it (gate OFF) it
|
|
231
|
+
// hits the no-attribution overload. Both produce a fetch event regardless.
|
|
232
|
+
attribution ? getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct, attribution) : getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct)
|
|
233
|
+
);
|
|
90
234
|
};
|
|
91
235
|
export var getSourceInfoErrorPayload = function getSourceInfoErrorPayload(error, resourceId, sourceProduct) {
|
|
92
236
|
return getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error, resourceId, sourceProduct);
|
package/dist/esm/utils/utils.js
CHANGED
|
@@ -3,6 +3,7 @@ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbol
|
|
|
3
3
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
4
|
/* eslint-disable require-unicode-regexp */
|
|
5
5
|
|
|
6
|
+
var GET_CONTENT_ID_AND_PRODUCT_REGEX = /^(confluence-page|jira-work-item)\/([^/]+)/;
|
|
6
7
|
var _normalizeSyncBlockJSONContentInternal = function normalizeSyncBlockJSONContentInternal(content, options) {
|
|
7
8
|
var normalizedContent;
|
|
8
9
|
content.forEach(function (contentNode, index) {
|
|
@@ -102,7 +103,7 @@ export var convertPMNodesToSyncBlockNodes = function convertPMNodesToSyncBlockNo
|
|
|
102
103
|
* Extracts the source page content id and source product
|
|
103
104
|
*/
|
|
104
105
|
export var getContentIdAndProductFromResourceId = function getContentIdAndProductFromResourceId(resourceId) {
|
|
105
|
-
var match = resourceId.match(
|
|
106
|
+
var match = resourceId.match(GET_CONTENT_ID_AND_PRODUCT_REGEX);
|
|
106
107
|
if (match !== null && match !== void 0 && match[2]) {
|
|
107
108
|
return {
|
|
108
109
|
sourceProduct: match[1],
|
|
@@ -7,6 +7,14 @@ import type { SyncBlockData, SyncBlockStatus, ResourceId, SyncBlockError, SyncBl
|
|
|
7
7
|
type SyncBlockErrorInfo = {
|
|
8
8
|
reason?: string;
|
|
9
9
|
sourceAri?: string;
|
|
10
|
+
/**
|
|
11
|
+
* HTTP status code from the backend (Block Service) when a fetch/subscribe failure
|
|
12
|
+
* originated from a `BlockError`. Surfaced so fetch failure analytics can break down
|
|
13
|
+
* read-path failures by status code (EDITOR-7862). Undefined for non-HTTP failures
|
|
14
|
+
* (e.g. JSON parse errors, missing-content NotFound, or backend error responses that
|
|
15
|
+
* only carry a string `code`).
|
|
16
|
+
*/
|
|
17
|
+
statusCode?: number;
|
|
10
18
|
type: SyncBlockError;
|
|
11
19
|
};
|
|
12
20
|
/**
|
|
@@ -38,14 +38,106 @@ export type ErrorAttributionAttributes = {
|
|
|
38
38
|
* helper stays pure and trivially unit-testable for both gate states.
|
|
39
39
|
*/
|
|
40
40
|
export declare const buildErrorAttribution: (gateEnabled: boolean, error?: string, statusCode?: number) => ErrorAttributionAttributes | undefined;
|
|
41
|
-
|
|
41
|
+
/**
|
|
42
|
+
* The set of categorical failure reasons emitted on synced-block fetch/subscribe
|
|
43
|
+
* operational error events (EDITOR-7862). Extends the write-path
|
|
44
|
+
* {@link SyncBlockErrorReason} set with read-path-specific buckets so the analytics
|
|
45
|
+
* dashboard can break fetch failures down by cause instead of regex-matching the
|
|
46
|
+
* free-text `error` blob.
|
|
47
|
+
*
|
|
48
|
+
* The read path surfaces several causes the write-path `SyncBlockError` enum does not
|
|
49
|
+
* model (benign source-state transitions, permission denials, WebSocket lifecycle, and
|
|
50
|
+
* client-side readiness errors), so those are added here. Known `SyncBlockError` enum
|
|
51
|
+
* values (`not_found`, `forbidden`, ...) still pass through unchanged.
|
|
52
|
+
*/
|
|
53
|
+
export type SyncBlockFetchErrorReason = SyncBlockErrorReason | 'source_deleted' | 'source_unpublished' | 'source_unsynced' | 'source_not_found' | 'permission_denied' | 'unauthenticated' | 'websocket_drop' | 'websocket_exhausted' | 'network' | 'data_provider_not_ready';
|
|
54
|
+
/**
|
|
55
|
+
* Fetch reasons that represent benign (working-as-designed) outcomes rather than genuine
|
|
56
|
+
* system failures. The dashboard uses this to compute a "true error rate" by excluding
|
|
57
|
+
* benign reasons via the structured `reason` attribute instead of brittle free-text regex
|
|
58
|
+
* (EDITOR-7862).
|
|
59
|
+
*/
|
|
60
|
+
export declare const FETCH_BENIGN_REASONS: ReadonlySet<SyncBlockFetchErrorReason>;
|
|
61
|
+
/**
|
|
62
|
+
* Maps a fetch/subscribe `error` field — which may be a {@link SyncBlockError} enum
|
|
63
|
+
* value, a {@link DeletionReason} value, or an arbitrary free-text/JSON blob — to a
|
|
64
|
+
* stable categorical {@link SyncBlockFetchErrorReason} for analytics grouping.
|
|
65
|
+
*
|
|
66
|
+
* Resolution order:
|
|
67
|
+
* 1. Known `SyncBlockError` enum value → passed through (via {@link classifyErrorReason}).
|
|
68
|
+
* 2. Known free-text substring → mapped to a fetch-specific bucket.
|
|
69
|
+
* 3. Anything else (including opaque blobs like `errored`-only payloads or
|
|
70
|
+
* `ErrorEvent: "undefined"`) → `'unknown'`, so the dashboard never groups on free text.
|
|
71
|
+
*
|
|
72
|
+
* Note: the bare string `'errored'` IS a `SyncBlockError` enum value and therefore
|
|
73
|
+
* classifies as `'errored'` (not `'unknown'`); only genuinely unrecognised strings
|
|
74
|
+
* collapse to `'unknown'`.
|
|
75
|
+
*/
|
|
76
|
+
export declare const classifyFetchErrorReason: (error?: string) => SyncBlockFetchErrorReason;
|
|
77
|
+
/**
|
|
78
|
+
* Extra, optional analytics attributes describing WHY a fetch/subscribe synced-block
|
|
79
|
+
* action failed. Spread conditionally so we never emit `undefined` keys (EDITOR-7862).
|
|
80
|
+
*
|
|
81
|
+
* Adds `benign` on top of the shared {@link ErrorAttributionAttributes} so the dashboard
|
|
82
|
+
* can compute a true error rate (`genuine / total`) without any free-text regex.
|
|
83
|
+
*/
|
|
84
|
+
export type FetchErrorAttributionAttributes = {
|
|
85
|
+
/**
|
|
86
|
+
* Categorical fetch failure cause for dashboard grouping. Declared standalone (not via
|
|
87
|
+
* `ErrorAttributionAttributes & ...`) because intersecting two `reason?` properties
|
|
88
|
+
* narrows the type to the write-path {@link SyncBlockErrorReason}; we need the wider
|
|
89
|
+
* {@link SyncBlockFetchErrorReason} here (EDITOR-7862).
|
|
90
|
+
*/
|
|
91
|
+
reason?: SyncBlockFetchErrorReason;
|
|
92
|
+
/** Backend HTTP status code when the failure came from a `BlockError`. */
|
|
93
|
+
statusCode?: number;
|
|
94
|
+
/**
|
|
95
|
+
* Whether the reason is a benign/working-as-designed outcome (not a true failure).
|
|
96
|
+
* Required (not optional) so this type structurally discriminates fetch attribution
|
|
97
|
+
* from the write-path {@link ErrorAttributionAttributes}; this lets {@link getErrorPayload}
|
|
98
|
+
* overload-resolve the correct (wider) `reason` type per path. `buildFetchErrorAttribution`
|
|
99
|
+
* always sets it, so requiring it costs nothing.
|
|
100
|
+
*/
|
|
101
|
+
benign: boolean;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Builds the {@link FetchErrorAttributionAttributes} for a failed fetch/subscribe
|
|
105
|
+
* synced-block operation from the raw `error` field and optional backend `statusCode`.
|
|
106
|
+
* Returns `undefined` when the `platform_editor_blocks_patch_3` gate is OFF, so the new
|
|
107
|
+
* `reason`/`statusCode`/`benign` attributes are only emitted once the gate is rolled out
|
|
108
|
+
* (EDITOR-7862). The existing free-text `error` attribute is always left unchanged.
|
|
109
|
+
*
|
|
110
|
+
* `gateEnabled` is injected by the caller (the store managers evaluate `fg(...)`) so this
|
|
111
|
+
* helper stays pure and trivially unit-testable for both gate states.
|
|
112
|
+
*/
|
|
113
|
+
export declare const buildFetchErrorAttribution: (gateEnabled: boolean, error?: string, statusCode?: number) => FetchErrorAttributionAttributes | undefined;
|
|
114
|
+
/**
|
|
115
|
+
* Shared operational ERROR payload builder for synced-block events.
|
|
116
|
+
*
|
|
117
|
+
* Overloaded so the emitted `reason` type stays accurate per path (raised in review on
|
|
118
|
+
* EDITOR-7862): fetch/subscribe callers pass a {@link FetchErrorAttributionAttributes}
|
|
119
|
+
* (discriminated by its required `benign` field) and get the wider
|
|
120
|
+
* {@link SyncBlockFetchErrorReason}; write-path callers pass an
|
|
121
|
+
* {@link ErrorAttributionAttributes} (or nothing) and keep the narrower
|
|
122
|
+
* {@link SyncBlockErrorReason}, so write-path payloads never claim to carry fetch-only
|
|
123
|
+
* buckets like `source_deleted` they never emit.
|
|
124
|
+
*/
|
|
125
|
+
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, {
|
|
126
|
+
error: string;
|
|
127
|
+
resourceId?: string;
|
|
128
|
+
sourceProduct?: string;
|
|
129
|
+
reason?: SyncBlockFetchErrorReason;
|
|
130
|
+
statusCode?: number;
|
|
131
|
+
benign?: boolean;
|
|
132
|
+
}>;
|
|
133
|
+
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, {
|
|
42
134
|
error: string;
|
|
43
135
|
resourceId?: string;
|
|
44
136
|
sourceProduct?: string;
|
|
45
137
|
reason?: SyncBlockErrorReason;
|
|
46
138
|
statusCode?: number;
|
|
47
139
|
}>;
|
|
48
|
-
export declare const fetchErrorPayload: (error: string, resourceId?: string, sourceProduct?: string) => RendererSyncBlockEventPayload;
|
|
140
|
+
export declare const fetchErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, attribution?: FetchErrorAttributionAttributes) => RendererSyncBlockEventPayload;
|
|
49
141
|
export declare const getSourceInfoErrorPayload: (error: string, resourceId?: string, sourceProduct?: string) => RendererSyncBlockEventPayload;
|
|
50
142
|
export declare const updateErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes) => SyncBlockEventPayload;
|
|
51
143
|
export declare const updateReferenceErrorPayload: (error: string, resourceId?: string, sourceProduct?: string, attribution?: ErrorAttributionAttributes) => RendererSyncBlockEventPayload;
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"@atlaskit/editor-prosemirror": "^8.0.0",
|
|
22
22
|
"@atlaskit/node-data-provider": "^13.0.0",
|
|
23
23
|
"@atlaskit/platform-feature-flags": "^2.0.0",
|
|
24
|
-
"@atlaskit/tmp-editor-statsig": "^114.
|
|
24
|
+
"@atlaskit/tmp-editor-statsig": "^114.5.0",
|
|
25
25
|
"@babel/runtime": "^7.0.0",
|
|
26
26
|
"@compiled/react": "^0.20.0",
|
|
27
27
|
"graphql-ws": "^5.14.2",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"uuid": "^3.1.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@atlaskit/editor-common": "^116.
|
|
33
|
+
"@atlaskit/editor-common": "^116.17.0",
|
|
34
34
|
"react": "^18.2.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
76
|
"name": "@atlaskit/editor-synced-block-provider",
|
|
77
|
-
"version": "8.
|
|
77
|
+
"version": "8.3.1",
|
|
78
78
|
"description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
|
|
79
79
|
"author": "Atlassian Pty Ltd",
|
|
80
80
|
"license": "Apache-2.0",
|