@atlaskit/editor-synced-block-provider 10.0.4 → 10.0.5
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 +9 -0
- package/dist/cjs/common/types.js +1 -1
- package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +4 -8
- package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +5 -5
- package/dist/cjs/store-manager/syncBlockSubscriptionManager.js +9 -33
- package/dist/cjs/utils/errorHandling.js +3 -3
- package/dist/es2019/common/types.js +1 -1
- package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +4 -6
- package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +5 -5
- package/dist/es2019/store-manager/syncBlockSubscriptionManager.js +9 -24
- package/dist/es2019/utils/errorHandling.js +3 -3
- package/dist/esm/common/types.js +1 -1
- package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +4 -8
- package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +5 -5
- package/dist/esm/store-manager/syncBlockSubscriptionManager.js +9 -33
- package/dist/esm/utils/errorHandling.js +3 -3
- package/dist/types/common/types.d.ts +1 -1
- package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +4 -4
- package/dist/types/store-manager/syncBlockSubscriptionManager.d.ts +2 -4
- package/dist/types/utils/errorHandling.d.ts +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @atlaskit/editor-synced-block-provider
|
|
2
2
|
|
|
3
|
+
## 10.0.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`1f0dab65b6efd`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/1f0dab65b6efd) -
|
|
8
|
+
Remove unreachable cut-handling branch and duplicated synced block node view setup left over from
|
|
9
|
+
feature gate cleanup
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
|
|
3
12
|
## 10.0.4
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/dist/cjs/common/types.js
CHANGED
|
@@ -60,7 +60,7 @@ var SyncBlockError = exports.SyncBlockError = /*#__PURE__*/function (SyncBlockEr
|
|
|
60
60
|
* adding a downstream file to consuming Jira packages' Thunderstone complexity.
|
|
61
61
|
*/
|
|
62
62
|
|
|
63
|
-
/** Legacy message — kept identical for
|
|
63
|
+
/** Legacy message — kept identical for historical events. */
|
|
64
64
|
var PROVIDER_NOT_READY_MESSAGE = exports.PROVIDER_NOT_READY_MESSAGE = 'Data provider not set';
|
|
65
65
|
|
|
66
66
|
/**
|
|
@@ -61,8 +61,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
|
|
|
61
61
|
// Track retry attempts for EntityNotFound errors (block may be in the process of being created)
|
|
62
62
|
(0, _defineProperty2.default)(this, "entityNotFoundRetryCount", new Map());
|
|
63
63
|
(0, _defineProperty2.default)(this, "entityNotFoundRetryTimers", new Map());
|
|
64
|
-
// Pending cache deletion timers keyed by resourceId
|
|
65
|
-
// Cancelled when a subscriber re-attaches.
|
|
64
|
+
// Pending cache deletion timers keyed by resourceId. Cancelled when a subscriber re-attaches.
|
|
66
65
|
(0, _defineProperty2.default)(this, "pendingCacheDeletions", new Map());
|
|
67
66
|
// Reschedule counter per resource — reset on actual deletion or re-subscribe.
|
|
68
67
|
(0, _defineProperty2.default)(this, "cacheDeletionRescheduleCounts", new Map());
|
|
@@ -83,9 +82,6 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
|
|
|
83
82
|
updateCache: function updateCache(inst) {
|
|
84
83
|
return _this.updateCache(inst);
|
|
85
84
|
},
|
|
86
|
-
deleteFromCache: function deleteFromCache(rid) {
|
|
87
|
-
return _this.deleteFromCache(rid);
|
|
88
|
-
},
|
|
89
85
|
debouncedBatchedFetchSyncBlocks: function debouncedBatchedFetchSyncBlocks(rid) {
|
|
90
86
|
return _this.debouncedBatchedFetchSyncBlocks(rid);
|
|
91
87
|
},
|
|
@@ -821,7 +817,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
|
|
|
821
817
|
value: function onCacheDeletionTimerFire(resourceId) {
|
|
822
818
|
var _this$cacheDeletionRe;
|
|
823
819
|
if (this.canDeleteCache(resourceId)) {
|
|
824
|
-
// `deleteFromCache` resets the reschedule counter
|
|
820
|
+
// `deleteFromCache` resets the reschedule counter.
|
|
825
821
|
this.deleteFromCache(resourceId);
|
|
826
822
|
return;
|
|
827
823
|
}
|
|
@@ -841,7 +837,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
|
|
|
841
837
|
(0, _monitoring.logException)(new Error("Cache deletion forced after ".concat(currentCount, " reschedules \u2014 stuck in-flight guard")), {
|
|
842
838
|
location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/cache-deletion-forced'
|
|
843
839
|
});
|
|
844
|
-
// `deleteFromCache` resets the reschedule counter
|
|
840
|
+
// `deleteFromCache` resets the reschedule counter.
|
|
845
841
|
this.deleteFromCache(resourceId);
|
|
846
842
|
// If subscribers still exist, kick off a fresh fetch so they get
|
|
847
843
|
// fresh data on the next batch tick instead of holding stale data
|
|
@@ -1137,7 +1133,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
|
|
|
1137
1133
|
});
|
|
1138
1134
|
// No `resourceId` available in this catch — sourceProduct is intentionally omitted.
|
|
1139
1135
|
// No structured SyncBlockError/status here, so the attribution `reason` falls back
|
|
1140
|
-
// to `unknown
|
|
1136
|
+
// to `unknown`.
|
|
1141
1137
|
(_this$fireAnalyticsEv9 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv9 === void 0 || _this$fireAnalyticsEv9.call(this, (0, _errorHandling.updateReferenceErrorPayload)(_t3.message, undefined, undefined, (0, _errorHandling.buildErrorAttribution)()));
|
|
1142
1138
|
case 17:
|
|
1143
1139
|
_context4.prev = 17;
|
|
@@ -631,10 +631,10 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
631
631
|
}
|
|
632
632
|
|
|
633
633
|
/**
|
|
634
|
-
* Emit the `syncedBlockDelete` success event.
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
634
|
+
* Emit the `syncedBlockDelete` success event. Attaches `deletionReason`,
|
|
635
|
+
* `mechanism` and `blockInstanceId`, and suppresses repeat emissions within
|
|
636
|
+
* {@link DELETE_DEDUPE_WINDOW_MS}. Must run while the cache entry still exists
|
|
637
|
+
* so `blockInstanceId` is available.
|
|
638
638
|
*/
|
|
639
639
|
}, {
|
|
640
640
|
key: "emitDeleteSuccess",
|
|
@@ -723,7 +723,7 @@ var SourceSyncBlockStoreManager = exports.SourceSyncBlockStoreManager = /*#__PUR
|
|
|
723
723
|
_context2.prev = 4;
|
|
724
724
|
_t2 = _context2["catch"](0);
|
|
725
725
|
// Thrown (non-result) failure — no structured SyncBlockError/status is available,
|
|
726
|
-
// so the attribution `reason` falls back to `unknown
|
|
726
|
+
// so the attribution `reason` falls back to `unknown`.
|
|
727
727
|
attribution = (0, _errorHandling.buildErrorAttribution)();
|
|
728
728
|
syncBlockIds.forEach(function (Ids) {
|
|
729
729
|
var _this5$fireAnalyticsE2;
|
|
@@ -34,11 +34,6 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
34
34
|
(0, _defineProperty2.default)(this, "graphqlSubscriptions", new Map());
|
|
35
35
|
(0, _defineProperty2.default)(this, "subscriptionChangeListeners", new Set());
|
|
36
36
|
(0, _defineProperty2.default)(this, "useRealTimeSubscriptions", false);
|
|
37
|
-
// Track pending cache deletions to handle block moves (unmount/remount)
|
|
38
|
-
// When a block is moved, the old component unmounts before the new one mounts,
|
|
39
|
-
// causing the cache to be deleted prematurely. We delay deletion to allow
|
|
40
|
-
// the new component to subscribe and cancel the pending deletion.
|
|
41
|
-
(0, _defineProperty2.default)(this, "pendingCacheDeletions", new Map());
|
|
42
37
|
// backoff cap
|
|
43
38
|
(0, _defineProperty2.default)(this, "retryAttempts", new Map());
|
|
44
39
|
(0, _defineProperty2.default)(this, "pendingRetries", new Map());
|
|
@@ -76,11 +71,10 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
76
71
|
return SyncBlockSubscriptionManager.MAX_RETRY_ATTEMPTS_HARDENED;
|
|
77
72
|
}
|
|
78
73
|
|
|
79
|
-
// Backoff delay for the given attempt
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
// jitter
|
|
83
|
-
// reconnects while guaranteeing a non-zero delay (full jitter could hit 0).
|
|
74
|
+
// Backoff delay for the given attempt (EDITOR-7861): exponential capped at
|
|
75
|
+
// MAX_RETRY_DELAY_MS with equal jitter (capped/2 + random*capped/2) —
|
|
76
|
+
// de-synchronises simultaneous reconnects while guaranteeing a non-zero delay
|
|
77
|
+
// (full jitter could hit 0).
|
|
84
78
|
}, {
|
|
85
79
|
key: "getReconnectionDelay",
|
|
86
80
|
value: function getReconnectionDelay(attempts) {
|
|
@@ -288,13 +282,10 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
288
282
|
(0, _monitoring.logException)(error, {
|
|
289
283
|
location: 'editor-synced-block-provider/syncBlockSubscriptionManager/graphql-subscription'
|
|
290
284
|
});
|
|
291
|
-
// EDITOR-7861: a single socket drop is usually transient and
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
// This branch only runs when the gate is OFF, so buildFetchErrorAttribution
|
|
296
|
-
// would return undefined; the structured attribution (EDITOR-7862) is therefore
|
|
297
|
-
// applied at the gate-ON exhaustion site in scheduleReconnection instead.
|
|
285
|
+
// EDITOR-7861: a single socket drop is usually transient and recovers
|
|
286
|
+
// on reconnect, so we don't fire a user-facing error here — it's only
|
|
287
|
+
// surfaced on exhaustion, where the structured attribution
|
|
288
|
+
// (EDITOR-7862) is applied too. See scheduleReconnection.
|
|
298
289
|
_this6.handleSubscriptionTerminated(resourceId);
|
|
299
290
|
}, function () {
|
|
300
291
|
_this6.handleSubscriptionTerminated(resourceId);
|
|
@@ -337,7 +328,7 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
337
328
|
if (attempts >= maxAttempts) {
|
|
338
329
|
var _this$deps$getFireAna2;
|
|
339
330
|
// Exhausted all attempts — the only place a WS drop surfaces as a
|
|
340
|
-
// fetch error
|
|
331
|
+
// fetch error (EDITOR-7861).
|
|
341
332
|
var errorMessage = "Subscription reconnection failed after ".concat(attempts, " attempts");
|
|
342
333
|
|
|
343
334
|
// Tab hidden at exhaustion: don't surface a terminal failure (user isn't
|
|
@@ -574,21 +565,6 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
574
565
|
this.titleSubscriptions.clear();
|
|
575
566
|
this.subscriptionChangeListeners.clear();
|
|
576
567
|
this.useRealTimeSubscriptions = false;
|
|
577
|
-
|
|
578
|
-
// Clear any pending cache deletions
|
|
579
|
-
var _iterator5 = _createForOfIteratorHelper(this.pendingCacheDeletions.values()),
|
|
580
|
-
_step5;
|
|
581
|
-
try {
|
|
582
|
-
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
583
|
-
var timeout = _step5.value;
|
|
584
|
-
clearTimeout(timeout);
|
|
585
|
-
}
|
|
586
|
-
} catch (err) {
|
|
587
|
-
_iterator5.e(err);
|
|
588
|
-
} finally {
|
|
589
|
-
_iterator5.f();
|
|
590
|
-
}
|
|
591
|
-
this.pendingCacheDeletions.clear();
|
|
592
568
|
}
|
|
593
569
|
}, {
|
|
594
570
|
key: "shouldUseRealTime",
|
|
@@ -247,8 +247,8 @@ function getErrorPayload(actionSubjectId, error, resourceId, sourceProduct, attr
|
|
|
247
247
|
var fetchErrorPayload = exports.fetchErrorPayload = function fetchErrorPayload(error, resourceId, sourceProduct, attribution) {
|
|
248
248
|
return (
|
|
249
249
|
// Branch on attribution presence so each call resolves to a concrete overload: with
|
|
250
|
-
// attribution it hits the fetch overload (wider `reason`); without it
|
|
251
|
-
//
|
|
250
|
+
// attribution it hits the fetch overload (wider `reason`); without it, the
|
|
251
|
+
// no-attribution overload. Both produce a fetch event regardless.
|
|
252
252
|
attribution ? getErrorPayload(_analytics.ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct, attribution) : getErrorPayload(_analytics.ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct)
|
|
253
253
|
);
|
|
254
254
|
};
|
|
@@ -347,7 +347,7 @@ var createSuccessPayload = exports.createSuccessPayload = function createSuccess
|
|
|
347
347
|
|
|
348
348
|
/**
|
|
349
349
|
* Optional enrichment for the `syncedBlockCreate` success event. All fields
|
|
350
|
-
* optional so
|
|
350
|
+
* optional so legacy payloads are unchanged. `inputMethod`: creating
|
|
351
351
|
* surface (enum, PII-safe). `createdEmpty`: true from an empty selection, false
|
|
352
352
|
* when content was converted.
|
|
353
353
|
*/
|
|
@@ -46,7 +46,7 @@ export let SyncBlockError = /*#__PURE__*/function (SyncBlockError) {
|
|
|
46
46
|
* adding a downstream file to consuming Jira packages' Thunderstone complexity.
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
|
-
/** Legacy message — kept identical for
|
|
49
|
+
/** Legacy message — kept identical for historical events. */
|
|
50
50
|
export const PROVIDER_NOT_READY_MESSAGE = 'Data provider not set';
|
|
51
51
|
|
|
52
52
|
/**
|
|
@@ -42,8 +42,7 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
42
42
|
// Track retry attempts for EntityNotFound errors (block may be in the process of being created)
|
|
43
43
|
_defineProperty(this, "entityNotFoundRetryCount", new Map());
|
|
44
44
|
_defineProperty(this, "entityNotFoundRetryTimers", new Map());
|
|
45
|
-
// Pending cache deletion timers keyed by resourceId
|
|
46
|
-
// Cancelled when a subscriber re-attaches.
|
|
45
|
+
// Pending cache deletion timers keyed by resourceId. Cancelled when a subscriber re-attaches.
|
|
47
46
|
_defineProperty(this, "pendingCacheDeletions", new Map());
|
|
48
47
|
// Reschedule counter per resource — reset on actual deletion or re-subscribe.
|
|
49
48
|
_defineProperty(this, "cacheDeletionRescheduleCounts", new Map());
|
|
@@ -58,7 +57,6 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
58
57
|
getDataProvider: () => this.dataProvider,
|
|
59
58
|
getFromCache: rid => this.getFromCache(rid),
|
|
60
59
|
updateCache: inst => this.updateCache(inst),
|
|
61
|
-
deleteFromCache: rid => this.deleteFromCache(rid),
|
|
62
60
|
debouncedBatchedFetchSyncBlocks: rid => this.debouncedBatchedFetchSyncBlocks(rid),
|
|
63
61
|
fetchSyncBlockSourceInfo: rid => this.fetchSyncBlockSourceInfo(rid),
|
|
64
62
|
getFireAnalyticsEvent: () => this.fireAnalyticsEvent,
|
|
@@ -673,7 +671,7 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
673
671
|
onCacheDeletionTimerFire(resourceId) {
|
|
674
672
|
var _this$cacheDeletionRe;
|
|
675
673
|
if (this.canDeleteCache(resourceId)) {
|
|
676
|
-
// `deleteFromCache` resets the reschedule counter
|
|
674
|
+
// `deleteFromCache` resets the reschedule counter.
|
|
677
675
|
this.deleteFromCache(resourceId);
|
|
678
676
|
return;
|
|
679
677
|
}
|
|
@@ -693,7 +691,7 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
693
691
|
logException(new Error(`Cache deletion forced after ${currentCount} reschedules — stuck in-flight guard`), {
|
|
694
692
|
location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/cache-deletion-forced'
|
|
695
693
|
});
|
|
696
|
-
// `deleteFromCache` resets the reschedule counter
|
|
694
|
+
// `deleteFromCache` resets the reschedule counter.
|
|
697
695
|
this.deleteFromCache(resourceId);
|
|
698
696
|
// If subscribers still exist, kick off a fresh fetch so they get
|
|
699
697
|
// fresh data on the next batch tick instead of holding stale data
|
|
@@ -918,7 +916,7 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
918
916
|
});
|
|
919
917
|
// No `resourceId` available in this catch — sourceProduct is intentionally omitted.
|
|
920
918
|
// No structured SyncBlockError/status here, so the attribution `reason` falls back
|
|
921
|
-
// to `unknown
|
|
919
|
+
// to `unknown`.
|
|
922
920
|
(_this$fireAnalyticsEv13 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv13 === void 0 ? void 0 : _this$fireAnalyticsEv13.call(this, updateReferenceErrorPayload(error.message, undefined, undefined, buildErrorAttribution()));
|
|
923
921
|
} finally {
|
|
924
922
|
if (!success) {
|
|
@@ -529,10 +529,10 @@ export class SourceSyncBlockStoreManager {
|
|
|
529
529
|
}
|
|
530
530
|
|
|
531
531
|
/**
|
|
532
|
-
* Emit the `syncedBlockDelete` success event.
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
532
|
+
* Emit the `syncedBlockDelete` success event. Attaches `deletionReason`,
|
|
533
|
+
* `mechanism` and `blockInstanceId`, and suppresses repeat emissions within
|
|
534
|
+
* {@link DELETE_DEDUPE_WINDOW_MS}. Must run while the cache entry still exists
|
|
535
|
+
* so `blockInstanceId` is available.
|
|
536
536
|
*/
|
|
537
537
|
emitDeleteSuccess(resourceId, reason, mechanism) {
|
|
538
538
|
var _this$syncBlockCache$3, _this$fireAnalyticsEv11;
|
|
@@ -598,7 +598,7 @@ export class SourceSyncBlockStoreManager {
|
|
|
598
598
|
return isDeleteSuccessful;
|
|
599
599
|
} catch (error) {
|
|
600
600
|
// Thrown (non-result) failure — no structured SyncBlockError/status is available,
|
|
601
|
-
// so the attribution `reason` falls back to `unknown
|
|
601
|
+
// so the attribution `reason` falls back to `unknown`.
|
|
602
602
|
const attribution = buildErrorAttribution();
|
|
603
603
|
syncBlockIds.forEach(Ids => {
|
|
604
604
|
var _this$fireAnalyticsEv13;
|
|
@@ -19,11 +19,10 @@ export class SyncBlockSubscriptionManager {
|
|
|
19
19
|
return SyncBlockSubscriptionManager.MAX_RETRY_ATTEMPTS_HARDENED;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
// Backoff delay for the given attempt
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
// jitter
|
|
26
|
-
// reconnects while guaranteeing a non-zero delay (full jitter could hit 0).
|
|
22
|
+
// Backoff delay for the given attempt (EDITOR-7861): exponential capped at
|
|
23
|
+
// MAX_RETRY_DELAY_MS with equal jitter (capped/2 + random*capped/2) —
|
|
24
|
+
// de-synchronises simultaneous reconnects while guaranteeing a non-zero delay
|
|
25
|
+
// (full jitter could hit 0).
|
|
27
26
|
getReconnectionDelay(attempts) {
|
|
28
27
|
const exponential = SyncBlockSubscriptionManager.INITIAL_RETRY_DELAY_MS * Math.pow(SyncBlockSubscriptionManager.RETRY_BACKOFF_MULTIPLIER, attempts);
|
|
29
28
|
const half = Math.min(exponential, SyncBlockSubscriptionManager.MAX_RETRY_DELAY_MS) / 2;
|
|
@@ -35,11 +34,6 @@ export class SyncBlockSubscriptionManager {
|
|
|
35
34
|
_defineProperty(this, "graphqlSubscriptions", new Map());
|
|
36
35
|
_defineProperty(this, "subscriptionChangeListeners", new Set());
|
|
37
36
|
_defineProperty(this, "useRealTimeSubscriptions", false);
|
|
38
|
-
// Track pending cache deletions to handle block moves (unmount/remount)
|
|
39
|
-
// When a block is moved, the old component unmounts before the new one mounts,
|
|
40
|
-
// causing the cache to be deleted prematurely. We delay deletion to allow
|
|
41
|
-
// the new component to subscribe and cancel the pending deletion.
|
|
42
|
-
_defineProperty(this, "pendingCacheDeletions", new Map());
|
|
43
37
|
// backoff cap
|
|
44
38
|
_defineProperty(this, "retryAttempts", new Map());
|
|
45
39
|
_defineProperty(this, "pendingRetries", new Map());
|
|
@@ -244,13 +238,10 @@ export class SyncBlockSubscriptionManager {
|
|
|
244
238
|
logException(error, {
|
|
245
239
|
location: 'editor-synced-block-provider/syncBlockSubscriptionManager/graphql-subscription'
|
|
246
240
|
});
|
|
247
|
-
// EDITOR-7861: a single socket drop is usually transient and
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
// This branch only runs when the gate is OFF, so buildFetchErrorAttribution
|
|
252
|
-
// would return undefined; the structured attribution (EDITOR-7862) is therefore
|
|
253
|
-
// applied at the gate-ON exhaustion site in scheduleReconnection instead.
|
|
241
|
+
// EDITOR-7861: a single socket drop is usually transient and recovers
|
|
242
|
+
// on reconnect, so we don't fire a user-facing error here — it's only
|
|
243
|
+
// surfaced on exhaustion, where the structured attribution
|
|
244
|
+
// (EDITOR-7862) is applied too. See scheduleReconnection.
|
|
254
245
|
this.handleSubscriptionTerminated(resourceId);
|
|
255
246
|
}, () => {
|
|
256
247
|
this.handleSubscriptionTerminated(resourceId);
|
|
@@ -288,7 +279,7 @@ export class SyncBlockSubscriptionManager {
|
|
|
288
279
|
if (attempts >= maxAttempts) {
|
|
289
280
|
var _this$deps$getFireAna3;
|
|
290
281
|
// Exhausted all attempts — the only place a WS drop surfaces as a
|
|
291
|
-
// fetch error
|
|
282
|
+
// fetch error (EDITOR-7861).
|
|
292
283
|
const errorMessage = `Subscription reconnection failed after ${attempts} attempts`;
|
|
293
284
|
|
|
294
285
|
// Tab hidden at exhaustion: don't surface a terminal failure (user isn't
|
|
@@ -463,12 +454,6 @@ export class SyncBlockSubscriptionManager {
|
|
|
463
454
|
this.titleSubscriptions.clear();
|
|
464
455
|
this.subscriptionChangeListeners.clear();
|
|
465
456
|
this.useRealTimeSubscriptions = false;
|
|
466
|
-
|
|
467
|
-
// Clear any pending cache deletions
|
|
468
|
-
for (const timeout of this.pendingCacheDeletions.values()) {
|
|
469
|
-
clearTimeout(timeout);
|
|
470
|
-
}
|
|
471
|
-
this.pendingCacheDeletions.clear();
|
|
472
457
|
}
|
|
473
458
|
shouldUseRealTime() {
|
|
474
459
|
return this.useRealTimeSubscriptions;
|
|
@@ -246,8 +246,8 @@ export function getErrorPayload(actionSubjectId, error, resourceId, sourceProduc
|
|
|
246
246
|
}
|
|
247
247
|
export const fetchErrorPayload = (error, resourceId, sourceProduct, attribution) =>
|
|
248
248
|
// Branch on attribution presence so each call resolves to a concrete overload: with
|
|
249
|
-
// attribution it hits the fetch overload (wider `reason`); without it
|
|
250
|
-
//
|
|
249
|
+
// attribution it hits the fetch overload (wider `reason`); without it, the
|
|
250
|
+
// no-attribution overload. Both produce a fetch event regardless.
|
|
251
251
|
attribution ? getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct, attribution) : getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct);
|
|
252
252
|
export const getSourceInfoErrorPayload = (error, resourceId, sourceProduct) => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_GET_SOURCE_INFO, error, resourceId, sourceProduct);
|
|
253
253
|
export const updateErrorPayload = (error, resourceId, sourceProduct, attribution) => getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_UPDATE, error, resourceId, sourceProduct, attribution);
|
|
@@ -333,7 +333,7 @@ export const createSuccessPayload = (resourceId, sourceProduct) => {
|
|
|
333
333
|
|
|
334
334
|
/**
|
|
335
335
|
* Optional enrichment for the `syncedBlockCreate` success event. All fields
|
|
336
|
-
* optional so
|
|
336
|
+
* optional so legacy payloads are unchanged. `inputMethod`: creating
|
|
337
337
|
* surface (enum, PII-safe). `createdEmpty`: true from an empty selection, false
|
|
338
338
|
* when content was converted.
|
|
339
339
|
*/
|
package/dist/esm/common/types.js
CHANGED
|
@@ -55,7 +55,7 @@ export var SyncBlockError = /*#__PURE__*/function (SyncBlockError) {
|
|
|
55
55
|
* adding a downstream file to consuming Jira packages' Thunderstone complexity.
|
|
56
56
|
*/
|
|
57
57
|
|
|
58
|
-
/** Legacy message — kept identical for
|
|
58
|
+
/** Legacy message — kept identical for historical events. */
|
|
59
59
|
export var PROVIDER_NOT_READY_MESSAGE = 'Data provider not set';
|
|
60
60
|
|
|
61
61
|
/**
|
|
@@ -54,8 +54,7 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
54
54
|
// Track retry attempts for EntityNotFound errors (block may be in the process of being created)
|
|
55
55
|
_defineProperty(this, "entityNotFoundRetryCount", new Map());
|
|
56
56
|
_defineProperty(this, "entityNotFoundRetryTimers", new Map());
|
|
57
|
-
// Pending cache deletion timers keyed by resourceId
|
|
58
|
-
// Cancelled when a subscriber re-attaches.
|
|
57
|
+
// Pending cache deletion timers keyed by resourceId. Cancelled when a subscriber re-attaches.
|
|
59
58
|
_defineProperty(this, "pendingCacheDeletions", new Map());
|
|
60
59
|
// Reschedule counter per resource — reset on actual deletion or re-subscribe.
|
|
61
60
|
_defineProperty(this, "cacheDeletionRescheduleCounts", new Map());
|
|
@@ -76,9 +75,6 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
76
75
|
updateCache: function updateCache(inst) {
|
|
77
76
|
return _this.updateCache(inst);
|
|
78
77
|
},
|
|
79
|
-
deleteFromCache: function deleteFromCache(rid) {
|
|
80
|
-
return _this.deleteFromCache(rid);
|
|
81
|
-
},
|
|
82
78
|
debouncedBatchedFetchSyncBlocks: function debouncedBatchedFetchSyncBlocks(rid) {
|
|
83
79
|
return _this.debouncedBatchedFetchSyncBlocks(rid);
|
|
84
80
|
},
|
|
@@ -814,7 +810,7 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
814
810
|
value: function onCacheDeletionTimerFire(resourceId) {
|
|
815
811
|
var _this$cacheDeletionRe;
|
|
816
812
|
if (this.canDeleteCache(resourceId)) {
|
|
817
|
-
// `deleteFromCache` resets the reschedule counter
|
|
813
|
+
// `deleteFromCache` resets the reschedule counter.
|
|
818
814
|
this.deleteFromCache(resourceId);
|
|
819
815
|
return;
|
|
820
816
|
}
|
|
@@ -834,7 +830,7 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
834
830
|
logException(new Error("Cache deletion forced after ".concat(currentCount, " reschedules \u2014 stuck in-flight guard")), {
|
|
835
831
|
location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/cache-deletion-forced'
|
|
836
832
|
});
|
|
837
|
-
// `deleteFromCache` resets the reschedule counter
|
|
833
|
+
// `deleteFromCache` resets the reschedule counter.
|
|
838
834
|
this.deleteFromCache(resourceId);
|
|
839
835
|
// If subscribers still exist, kick off a fresh fetch so they get
|
|
840
836
|
// fresh data on the next batch tick instead of holding stale data
|
|
@@ -1130,7 +1126,7 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
1130
1126
|
});
|
|
1131
1127
|
// No `resourceId` available in this catch — sourceProduct is intentionally omitted.
|
|
1132
1128
|
// No structured SyncBlockError/status here, so the attribution `reason` falls back
|
|
1133
|
-
// to `unknown
|
|
1129
|
+
// to `unknown`.
|
|
1134
1130
|
(_this$fireAnalyticsEv9 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv9 === void 0 || _this$fireAnalyticsEv9.call(this, updateReferenceErrorPayload(_t3.message, undefined, undefined, buildErrorAttribution()));
|
|
1135
1131
|
case 17:
|
|
1136
1132
|
_context4.prev = 17;
|
|
@@ -624,10 +624,10 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
624
624
|
}
|
|
625
625
|
|
|
626
626
|
/**
|
|
627
|
-
* Emit the `syncedBlockDelete` success event.
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
627
|
+
* Emit the `syncedBlockDelete` success event. Attaches `deletionReason`,
|
|
628
|
+
* `mechanism` and `blockInstanceId`, and suppresses repeat emissions within
|
|
629
|
+
* {@link DELETE_DEDUPE_WINDOW_MS}. Must run while the cache entry still exists
|
|
630
|
+
* so `blockInstanceId` is available.
|
|
631
631
|
*/
|
|
632
632
|
}, {
|
|
633
633
|
key: "emitDeleteSuccess",
|
|
@@ -716,7 +716,7 @@ export var SourceSyncBlockStoreManager = /*#__PURE__*/function () {
|
|
|
716
716
|
_context2.prev = 4;
|
|
717
717
|
_t2 = _context2["catch"](0);
|
|
718
718
|
// Thrown (non-result) failure — no structured SyncBlockError/status is available,
|
|
719
|
-
// so the attribution `reason` falls back to `unknown
|
|
719
|
+
// so the attribution `reason` falls back to `unknown`.
|
|
720
720
|
attribution = buildErrorAttribution();
|
|
721
721
|
syncBlockIds.forEach(function (Ids) {
|
|
722
722
|
var _this5$fireAnalyticsE2;
|
|
@@ -28,11 +28,6 @@ export var SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
|
28
28
|
_defineProperty(this, "graphqlSubscriptions", new Map());
|
|
29
29
|
_defineProperty(this, "subscriptionChangeListeners", new Set());
|
|
30
30
|
_defineProperty(this, "useRealTimeSubscriptions", false);
|
|
31
|
-
// Track pending cache deletions to handle block moves (unmount/remount)
|
|
32
|
-
// When a block is moved, the old component unmounts before the new one mounts,
|
|
33
|
-
// causing the cache to be deleted prematurely. We delay deletion to allow
|
|
34
|
-
// the new component to subscribe and cancel the pending deletion.
|
|
35
|
-
_defineProperty(this, "pendingCacheDeletions", new Map());
|
|
36
31
|
// backoff cap
|
|
37
32
|
_defineProperty(this, "retryAttempts", new Map());
|
|
38
33
|
_defineProperty(this, "pendingRetries", new Map());
|
|
@@ -70,11 +65,10 @@ export var SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
|
70
65
|
return SyncBlockSubscriptionManager.MAX_RETRY_ATTEMPTS_HARDENED;
|
|
71
66
|
}
|
|
72
67
|
|
|
73
|
-
// Backoff delay for the given attempt
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
// jitter
|
|
77
|
-
// reconnects while guaranteeing a non-zero delay (full jitter could hit 0).
|
|
68
|
+
// Backoff delay for the given attempt (EDITOR-7861): exponential capped at
|
|
69
|
+
// MAX_RETRY_DELAY_MS with equal jitter (capped/2 + random*capped/2) —
|
|
70
|
+
// de-synchronises simultaneous reconnects while guaranteeing a non-zero delay
|
|
71
|
+
// (full jitter could hit 0).
|
|
78
72
|
}, {
|
|
79
73
|
key: "getReconnectionDelay",
|
|
80
74
|
value: function getReconnectionDelay(attempts) {
|
|
@@ -282,13 +276,10 @@ export var SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
|
282
276
|
logException(error, {
|
|
283
277
|
location: 'editor-synced-block-provider/syncBlockSubscriptionManager/graphql-subscription'
|
|
284
278
|
});
|
|
285
|
-
// EDITOR-7861: a single socket drop is usually transient and
|
|
286
|
-
//
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
// This branch only runs when the gate is OFF, so buildFetchErrorAttribution
|
|
290
|
-
// would return undefined; the structured attribution (EDITOR-7862) is therefore
|
|
291
|
-
// applied at the gate-ON exhaustion site in scheduleReconnection instead.
|
|
279
|
+
// EDITOR-7861: a single socket drop is usually transient and recovers
|
|
280
|
+
// on reconnect, so we don't fire a user-facing error here — it's only
|
|
281
|
+
// surfaced on exhaustion, where the structured attribution
|
|
282
|
+
// (EDITOR-7862) is applied too. See scheduleReconnection.
|
|
292
283
|
_this6.handleSubscriptionTerminated(resourceId);
|
|
293
284
|
}, function () {
|
|
294
285
|
_this6.handleSubscriptionTerminated(resourceId);
|
|
@@ -331,7 +322,7 @@ export var SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
|
331
322
|
if (attempts >= maxAttempts) {
|
|
332
323
|
var _this$deps$getFireAna2;
|
|
333
324
|
// Exhausted all attempts — the only place a WS drop surfaces as a
|
|
334
|
-
// fetch error
|
|
325
|
+
// fetch error (EDITOR-7861).
|
|
335
326
|
var errorMessage = "Subscription reconnection failed after ".concat(attempts, " attempts");
|
|
336
327
|
|
|
337
328
|
// Tab hidden at exhaustion: don't surface a terminal failure (user isn't
|
|
@@ -568,21 +559,6 @@ export var SyncBlockSubscriptionManager = /*#__PURE__*/function () {
|
|
|
568
559
|
this.titleSubscriptions.clear();
|
|
569
560
|
this.subscriptionChangeListeners.clear();
|
|
570
561
|
this.useRealTimeSubscriptions = false;
|
|
571
|
-
|
|
572
|
-
// Clear any pending cache deletions
|
|
573
|
-
var _iterator5 = _createForOfIteratorHelper(this.pendingCacheDeletions.values()),
|
|
574
|
-
_step5;
|
|
575
|
-
try {
|
|
576
|
-
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
577
|
-
var timeout = _step5.value;
|
|
578
|
-
clearTimeout(timeout);
|
|
579
|
-
}
|
|
580
|
-
} catch (err) {
|
|
581
|
-
_iterator5.e(err);
|
|
582
|
-
} finally {
|
|
583
|
-
_iterator5.f();
|
|
584
|
-
}
|
|
585
|
-
this.pendingCacheDeletions.clear();
|
|
586
562
|
}
|
|
587
563
|
}, {
|
|
588
564
|
key: "shouldUseRealTime",
|
|
@@ -238,8 +238,8 @@ export function getErrorPayload(actionSubjectId, error, resourceId, sourceProduc
|
|
|
238
238
|
export var fetchErrorPayload = function fetchErrorPayload(error, resourceId, sourceProduct, attribution) {
|
|
239
239
|
return (
|
|
240
240
|
// Branch on attribution presence so each call resolves to a concrete overload: with
|
|
241
|
-
// attribution it hits the fetch overload (wider `reason`); without it
|
|
242
|
-
//
|
|
241
|
+
// attribution it hits the fetch overload (wider `reason`); without it, the
|
|
242
|
+
// no-attribution overload. Both produce a fetch event regardless.
|
|
243
243
|
attribution ? getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct, attribution) : getErrorPayload(ACTION_SUBJECT_ID.SYNCED_BLOCK_FETCH, error, resourceId, sourceProduct)
|
|
244
244
|
);
|
|
245
245
|
};
|
|
@@ -338,7 +338,7 @@ export var createSuccessPayload = function createSuccessPayload(resourceId, sour
|
|
|
338
338
|
|
|
339
339
|
/**
|
|
340
340
|
* Optional enrichment for the `syncedBlockCreate` success event. All fields
|
|
341
|
-
* optional so
|
|
341
|
+
* optional so legacy payloads are unchanged. `inputMethod`: creating
|
|
342
342
|
* surface (enum, PII-safe). `createdEmpty`: true from an empty selection, false
|
|
343
343
|
* when content was converted.
|
|
344
344
|
*/
|
|
@@ -106,7 +106,7 @@ export type SyncBlockPrefetchData = {
|
|
|
106
106
|
* NB: these intentionally live here rather than in a dedicated module to avoid
|
|
107
107
|
* adding a downstream file to consuming Jira packages' Thunderstone complexity.
|
|
108
108
|
*/
|
|
109
|
-
/** Legacy message — kept identical for
|
|
109
|
+
/** Legacy message — kept identical for historical events. */
|
|
110
110
|
export declare const PROVIDER_NOT_READY_MESSAGE = "Data provider not set";
|
|
111
111
|
/**
|
|
112
112
|
* Thrown when a fetch/subscribe runs against a manager whose provider is not
|
|
@@ -141,10 +141,10 @@ export declare class SourceSyncBlockStoreManager {
|
|
|
141
141
|
*/
|
|
142
142
|
private pruneRecentDeleteEmissions;
|
|
143
143
|
/**
|
|
144
|
-
* Emit the `syncedBlockDelete` success event.
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
144
|
+
* Emit the `syncedBlockDelete` success event. Attaches `deletionReason`,
|
|
145
|
+
* `mechanism` and `blockInstanceId`, and suppresses repeat emissions within
|
|
146
|
+
* {@link DELETE_DEDUPE_WINDOW_MS}. Must run while the cache entry still exists
|
|
147
|
+
* so `blockInstanceId` is available.
|
|
148
148
|
*/
|
|
149
149
|
private emitDeleteSuccess;
|
|
150
150
|
private delete;
|
|
@@ -3,16 +3,15 @@ import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
|
3
3
|
import type { ResourceId, BlockInstanceId } from '../common/types';
|
|
4
4
|
import type { SyncBlockInstance, SubscriptionCallback, SyncBlockDataProviderInterface, SyncBlockSourceInfo, TitleSubscriptionCallback } from '../providers/types';
|
|
5
5
|
export interface SyncBlockSubscriptionManagerDeps {
|
|
6
|
-
/** Cancels any pending cache deletion timer for `resourceId
|
|
6
|
+
/** Cancels any pending cache deletion timer for `resourceId`. */
|
|
7
7
|
cancelPendingCacheDeletion: (resourceId: ResourceId) => void;
|
|
8
8
|
debouncedBatchedFetchSyncBlocks: (resourceId: string) => void;
|
|
9
|
-
deleteFromCache: (resourceId: ResourceId) => void;
|
|
10
9
|
fetchSyncBlockSourceInfo: (resourceId: ResourceId) => Promise<SyncBlockSourceInfo | undefined>;
|
|
11
10
|
getDataProvider: () => SyncBlockDataProviderInterface | undefined;
|
|
12
11
|
getFireAnalyticsEvent: () => ((payload: RendererSyncBlockEventPayload) => void) | undefined;
|
|
13
12
|
getFromCache: (resourceId: ResourceId) => SyncBlockInstance | undefined;
|
|
14
13
|
markCacheDirty: () => void;
|
|
15
|
-
/** Schedules guarded cache deletion for `resourceId` after a grace period
|
|
14
|
+
/** Schedules guarded cache deletion for `resourceId` after a grace period. */
|
|
16
15
|
scheduleCacheDeletion: (resourceId: ResourceId) => void;
|
|
17
16
|
updateCache: (syncBlockInstance: SyncBlockInstance) => void;
|
|
18
17
|
}
|
|
@@ -29,7 +28,6 @@ export declare class SyncBlockSubscriptionManager {
|
|
|
29
28
|
private graphqlSubscriptions;
|
|
30
29
|
private subscriptionChangeListeners;
|
|
31
30
|
private useRealTimeSubscriptions;
|
|
32
|
-
private pendingCacheDeletions;
|
|
33
31
|
private static readonly INITIAL_RETRY_DELAY_MS;
|
|
34
32
|
private static readonly RETRY_BACKOFF_MULTIPLIER;
|
|
35
33
|
private static readonly MAX_RETRY_ATTEMPTS_HARDENED;
|
|
@@ -174,7 +174,7 @@ export declare const fetchSuccessPayload: (resourceId: string, blockInstanceId?:
|
|
|
174
174
|
export declare const createSuccessPayload: (resourceId: string, sourceProduct?: string) => SyncBlockEventPayload;
|
|
175
175
|
/**
|
|
176
176
|
* Optional enrichment for the `syncedBlockCreate` success event. All fields
|
|
177
|
-
* optional so
|
|
177
|
+
* optional so legacy payloads are unchanged. `inputMethod`: creating
|
|
178
178
|
* surface (enum, PII-safe). `createdEmpty`: true from an empty selection, false
|
|
179
179
|
* when content was converted.
|
|
180
180
|
*/
|
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@atlaskit/editor-prosemirror": "^8.0.0",
|
|
23
23
|
"@atlaskit/node-data-provider": "^15.0.0",
|
|
24
24
|
"@atlaskit/platform-feature-flags": "^2.1.0",
|
|
25
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
25
|
+
"@atlaskit/tmp-editor-statsig": "^146.0.0",
|
|
26
26
|
"@babel/runtime": "^7.0.0",
|
|
27
27
|
"@compiled/react": "^1.0.0",
|
|
28
28
|
"bind-event-listener": "^3.0.0",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"uuid": "^3.1.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@atlaskit/editor-common": "^118.
|
|
35
|
+
"@atlaskit/editor-common": "^118.4.0",
|
|
36
36
|
"react": "^18.2.0 || ^19.2.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
78
|
"name": "@atlaskit/editor-synced-block-provider",
|
|
79
|
-
"version": "10.0.
|
|
79
|
+
"version": "10.0.5",
|
|
80
80
|
"description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
|
|
81
81
|
"author": "Atlassian Pty Ltd",
|
|
82
82
|
"license": "Apache-2.0",
|