@atlaskit/editor-synced-block-provider 6.6.5 → 6.6.7
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 +17 -0
- package/dist/cjs/clients/block-service/blockSubscription.js +2 -2
- package/dist/cjs/providers/block-service/blockServiceAPI.js +2 -2
- package/dist/cjs/providers/syncBlockProvider.js +2 -2
- package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +26 -7
- package/dist/cjs/store-manager/syncBlockSubscriptionManager.js +148 -25
- package/dist/cjs/utils/utils.js +49 -4
- package/dist/es2019/clients/block-service/blockSubscription.js +2 -2
- package/dist/es2019/providers/block-service/blockServiceAPI.js +2 -2
- package/dist/es2019/providers/syncBlockProvider.js +2 -2
- package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +27 -8
- package/dist/es2019/store-manager/syncBlockSubscriptionManager.js +109 -6
- package/dist/es2019/utils/utils.js +43 -1
- package/dist/esm/clients/block-service/blockSubscription.js +2 -2
- package/dist/esm/providers/block-service/blockServiceAPI.js +2 -2
- package/dist/esm/providers/syncBlockProvider.js +2 -2
- package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +28 -9
- package/dist/esm/store-manager/syncBlockSubscriptionManager.js +148 -25
- package/dist/esm/utils/utils.js +48 -1
- package/dist/types/clients/block-service/blockSubscription.d.ts +2 -1
- package/dist/types/entry-points/providers-types.d.ts +1 -1
- package/dist/types/providers/block-service/blockServiceAPI.d.ts +1 -1
- package/dist/types/providers/syncBlockProvider.d.ts +1 -1
- package/dist/types/providers/types.d.ts +4 -2
- package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +1 -0
- package/dist/types/store-manager/syncBlockSubscriptionManager.d.ts +23 -0
- package/dist/types/utils/utils.d.ts +2 -1
- package/dist/types-ts4.5/clients/block-service/blockSubscription.d.ts +2 -1
- package/dist/types-ts4.5/entry-points/providers-types.d.ts +1 -1
- package/dist/types-ts4.5/providers/block-service/blockServiceAPI.d.ts +1 -1
- package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +1 -1
- package/dist/types-ts4.5/providers/types.d.ts +4 -2
- package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +1 -0
- package/dist/types-ts4.5/store-manager/syncBlockSubscriptionManager.d.ts +23 -0
- package/dist/types-ts4.5/utils/utils.d.ts +2 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @atlaskit/editor-synced-block-provider
|
|
2
2
|
|
|
3
|
+
## 6.6.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`bfba4158ff047`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/bfba4158ff047) -
|
|
8
|
+
Fix subscription reconnection for synced blocks when WebSocket or Relay subscriptions complete or
|
|
9
|
+
error silently
|
|
10
|
+
|
|
11
|
+
## 6.6.6
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [`33333417b0969`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/33333417b0969) -
|
|
16
|
+
Strip inline comment annotation marks from synced block content before syncing references behind
|
|
17
|
+
platform_synced_block_patch_12.
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
|
|
3
20
|
## 6.6.5
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -174,7 +174,7 @@ var parseSubscriptionPayload = function parseSubscriptionPayload(payload) {
|
|
|
174
174
|
* @param onError - Optional callback function invoked on subscription errors
|
|
175
175
|
* @returns Unsubscribe function to close the subscription
|
|
176
176
|
*/
|
|
177
|
-
var subscribeToBlockUpdates = exports.subscribeToBlockUpdates = function subscribeToBlockUpdates(blockAri, onData, onError) {
|
|
177
|
+
var subscribeToBlockUpdates = exports.subscribeToBlockUpdates = function subscribeToBlockUpdates(blockAri, onData, onError, onComplete) {
|
|
178
178
|
var client = getBlockServiceClient();
|
|
179
179
|
if (!client) {
|
|
180
180
|
// Return a no-op unsubscribe if client is not available (e.g., SSR)
|
|
@@ -210,7 +210,7 @@ var subscribeToBlockUpdates = exports.subscribeToBlockUpdates = function subscri
|
|
|
210
210
|
onError === null || onError === void 0 || onError(new Error(extractGraphQLWSErrorMessage(error)));
|
|
211
211
|
}),
|
|
212
212
|
complete: function complete() {
|
|
213
|
-
|
|
213
|
+
onComplete === null || onComplete === void 0 || onComplete();
|
|
214
214
|
}
|
|
215
215
|
});
|
|
216
216
|
return unsubscribe;
|
|
@@ -793,7 +793,7 @@ var BlockServiceADFFetchProvider = /*#__PURE__*/function () {
|
|
|
793
793
|
)
|
|
794
794
|
}, {
|
|
795
795
|
key: "subscribeToBlockUpdates",
|
|
796
|
-
value: function subscribeToBlockUpdates(resourceId, onUpdate, onError) {
|
|
796
|
+
value: function subscribeToBlockUpdates(resourceId, onUpdate, onError, onComplete) {
|
|
797
797
|
var blockAri = (0, _ari.generateBlockAriFromReference)({
|
|
798
798
|
cloudId: this.cloudId,
|
|
799
799
|
resourceId: resourceId
|
|
@@ -829,7 +829,7 @@ var BlockServiceADFFetchProvider = /*#__PURE__*/function () {
|
|
|
829
829
|
resourceId: parsedData.resourceId
|
|
830
830
|
};
|
|
831
831
|
onUpdate(syncBlockInstance);
|
|
832
|
-
}, onError);
|
|
832
|
+
}, onError, onComplete);
|
|
833
833
|
}).catch(function (err) {
|
|
834
834
|
if (cancelled) {
|
|
835
835
|
return;
|
|
@@ -469,9 +469,9 @@ var SyncedBlockProvider = exports.SyncedBlockProvider = /*#__PURE__*/function (_
|
|
|
469
469
|
*/
|
|
470
470
|
}, {
|
|
471
471
|
key: "subscribeToBlockUpdates",
|
|
472
|
-
value: function subscribeToBlockUpdates(resourceId, onUpdate, onError) {
|
|
472
|
+
value: function subscribeToBlockUpdates(resourceId, onUpdate, onError, onComplete) {
|
|
473
473
|
if (this.fetchProvider.subscribeToBlockUpdates) {
|
|
474
|
-
return this.fetchProvider.subscribeToBlockUpdates(resourceId, onUpdate, onError);
|
|
474
|
+
return this.fetchProvider.subscribeToBlockUpdates(resourceId, onUpdate, onError, onComplete);
|
|
475
475
|
}
|
|
476
476
|
return undefined;
|
|
477
477
|
}
|
|
@@ -13,6 +13,7 @@ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/creat
|
|
|
13
13
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
14
14
|
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
|
|
15
15
|
var _monitoring = require("@atlaskit/editor-common/monitoring");
|
|
16
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
16
17
|
var _types = require("../common/types");
|
|
17
18
|
var _errorHandling = require("../utils/errorHandling");
|
|
18
19
|
var _experienceTracking = require("../utils/experienceTracking");
|
|
@@ -210,10 +211,27 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
|
|
|
210
211
|
var syncBlockNode = (0, _utils.createSyncBlockNode)('', resourceId);
|
|
211
212
|
var providerData = (_this$dataProvider2 = this.dataProvider) === null || _this$dataProvider2 === void 0 || (_this$dataProvider2 = _this$dataProvider2.getNodeDataFromCache(syncBlockNode)) === null || _this$dataProvider2 === void 0 ? void 0 : _this$dataProvider2.data;
|
|
212
213
|
if (providerData) {
|
|
213
|
-
return providerData;
|
|
214
|
+
return this.stripAnnotationMarksFromReferenceData(providerData);
|
|
214
215
|
}
|
|
215
216
|
return this.getFromSessionCache(resourceId);
|
|
216
217
|
}
|
|
218
|
+
}, {
|
|
219
|
+
key: "stripAnnotationMarksFromReferenceData",
|
|
220
|
+
value: function stripAnnotationMarksFromReferenceData(syncBlock) {
|
|
221
|
+
var _syncBlock$data;
|
|
222
|
+
if (!(0, _platformFeatureFlags.fg)('platform_synced_block_patch_12') || !((_syncBlock$data = syncBlock.data) !== null && _syncBlock$data !== void 0 && _syncBlock$data.content)) {
|
|
223
|
+
return syncBlock;
|
|
224
|
+
}
|
|
225
|
+
var content = (0, _utils.stripAnnotationMarksFromJSONContent)(syncBlock.data.content);
|
|
226
|
+
if (content === syncBlock.data.content) {
|
|
227
|
+
return syncBlock;
|
|
228
|
+
}
|
|
229
|
+
return _objectSpread(_objectSpread({}, syncBlock), {}, {
|
|
230
|
+
data: _objectSpread(_objectSpread({}, syncBlock.data), {}, {
|
|
231
|
+
content: content
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
}
|
|
217
235
|
}, {
|
|
218
236
|
key: "updateSessionCache",
|
|
219
237
|
value: function updateSessionCache(resourceId) {
|
|
@@ -230,7 +248,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
|
|
|
230
248
|
if (!raw) {
|
|
231
249
|
return undefined;
|
|
232
250
|
}
|
|
233
|
-
return JSON.parse(raw);
|
|
251
|
+
return this.stripAnnotationMarksFromReferenceData(JSON.parse(raw));
|
|
234
252
|
} catch (error) {
|
|
235
253
|
(0, _monitoring.logException)(error, {
|
|
236
254
|
location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getFromSessionCache'
|
|
@@ -601,14 +619,15 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
|
|
|
601
619
|
}, {
|
|
602
620
|
key: "updateCache",
|
|
603
621
|
value: function updateCache(syncBlock) {
|
|
604
|
-
var
|
|
622
|
+
var sanitizedSyncBlock = this.stripAnnotationMarksFromReferenceData(syncBlock);
|
|
623
|
+
var resourceId = sanitizedSyncBlock.resourceId;
|
|
605
624
|
if (resourceId) {
|
|
606
625
|
var _this$dataProvider3;
|
|
607
|
-
(_this$dataProvider3 = this.dataProvider) === null || _this$dataProvider3 === void 0 || _this$dataProvider3.updateCache((0, _defineProperty2.default)({}, resourceId,
|
|
626
|
+
(_this$dataProvider3 = this.dataProvider) === null || _this$dataProvider3 === void 0 || _this$dataProvider3.updateCache((0, _defineProperty2.default)({}, resourceId, sanitizedSyncBlock), {
|
|
608
627
|
strategy: 'merge',
|
|
609
628
|
source: 'network'
|
|
610
629
|
});
|
|
611
|
-
this._subscriptionManager.notifySubscriptionCallbacks(resourceId,
|
|
630
|
+
this._subscriptionManager.notifySubscriptionCallbacks(resourceId, sanitizedSyncBlock);
|
|
612
631
|
this.updateSessionCache(resourceId);
|
|
613
632
|
}
|
|
614
633
|
}
|
|
@@ -685,12 +704,12 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
|
|
|
685
704
|
}, {
|
|
686
705
|
key: "getSyncBlockURL",
|
|
687
706
|
value: function getSyncBlockURL(resourceId) {
|
|
688
|
-
var _syncBlock$
|
|
707
|
+
var _syncBlock$data2;
|
|
689
708
|
var syncBlock = this.getFromCache(resourceId);
|
|
690
709
|
if (!syncBlock) {
|
|
691
710
|
return undefined;
|
|
692
711
|
}
|
|
693
|
-
return (_syncBlock$
|
|
712
|
+
return (_syncBlock$data2 = syncBlock.data) === null || _syncBlock$data2 === void 0 ? void 0 : _syncBlock$data2.sourceURL;
|
|
694
713
|
}
|
|
695
714
|
}, {
|
|
696
715
|
key: "getProviderFactory",
|
|
@@ -9,6 +9,7 @@ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/cl
|
|
|
9
9
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
11
|
var _monitoring = require("@atlaskit/editor-common/monitoring");
|
|
12
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
12
13
|
var _errorHandling = require("../utils/errorHandling");
|
|
13
14
|
var _resolveSyncBlockInstance = require("../utils/resolveSyncBlockInstance");
|
|
14
15
|
var _utils = require("../utils/utils");
|
|
@@ -36,6 +37,8 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
36
37
|
// causing the cache to be deleted prematurely. We delay deletion to allow
|
|
37
38
|
// the new component to subscribe and cancel the pending deletion.
|
|
38
39
|
(0, _defineProperty2.default)(this, "pendingCacheDeletions", new Map());
|
|
40
|
+
(0, _defineProperty2.default)(this, "retryAttempts", new Map());
|
|
41
|
+
(0, _defineProperty2.default)(this, "pendingRetries", new Map());
|
|
39
42
|
this.deps = deps;
|
|
40
43
|
}
|
|
41
44
|
|
|
@@ -250,6 +253,7 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
250
253
|
if (!(dataProvider !== null && dataProvider !== void 0 && dataProvider.subscribeToBlockUpdates)) {
|
|
251
254
|
return;
|
|
252
255
|
}
|
|
256
|
+
var reconnectEnabled = (0, _platformFeatureFlags.fg)('platform_synced_block_patch_12');
|
|
253
257
|
var unsubscribe = dataProvider.subscribeToBlockUpdates(resourceId, function (syncBlockInstance) {
|
|
254
258
|
_this5.handleGraphQLUpdate(syncBlockInstance);
|
|
255
259
|
}, function (error) {
|
|
@@ -258,11 +262,115 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
258
262
|
location: 'editor-synced-block-provider/syncBlockSubscriptionManager/graphql-subscription'
|
|
259
263
|
});
|
|
260
264
|
(_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)));
|
|
261
|
-
|
|
265
|
+
if (reconnectEnabled) {
|
|
266
|
+
_this5.handleSubscriptionTerminated(resourceId);
|
|
267
|
+
}
|
|
268
|
+
}, reconnectEnabled ? function () {
|
|
269
|
+
_this5.handleSubscriptionTerminated(resourceId);
|
|
270
|
+
} : undefined);
|
|
262
271
|
if (unsubscribe) {
|
|
263
272
|
this.graphqlSubscriptions.set(resourceId, unsubscribe);
|
|
264
273
|
}
|
|
265
274
|
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Handles subscription termination (complete or error) by cleaning up the
|
|
278
|
+
* stale entry and scheduling a reconnection with exponential backoff.
|
|
279
|
+
*/
|
|
280
|
+
}, {
|
|
281
|
+
key: "handleSubscriptionTerminated",
|
|
282
|
+
value: function handleSubscriptionTerminated(resourceId) {
|
|
283
|
+
// Remove the stale subscription entry so setupSubscription won't early-return
|
|
284
|
+
this.graphqlSubscriptions.delete(resourceId);
|
|
285
|
+
|
|
286
|
+
// Guard against duplicate calls (graphql-ws can fire both error and complete)
|
|
287
|
+
if (this.pendingRetries.has(resourceId)) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Only reconnect if there are still active subscribers for this resource
|
|
292
|
+
if (this.subscriptions.has(resourceId) && this.shouldUseRealTime()) {
|
|
293
|
+
this.scheduleReconnection(resourceId);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Schedules a reconnection attempt with exponential backoff.
|
|
299
|
+
* Delay = INITIAL_RETRY_DELAY_MS * (RETRY_BACKOFF_MULTIPLIER ^ attempts)
|
|
300
|
+
* e.g. 1s, 2s, 4s, 8s, 16s
|
|
301
|
+
*/
|
|
302
|
+
}, {
|
|
303
|
+
key: "scheduleReconnection",
|
|
304
|
+
value: function scheduleReconnection(resourceId) {
|
|
305
|
+
var _this$retryAttempts$g,
|
|
306
|
+
_this6 = this;
|
|
307
|
+
var attempts = (_this$retryAttempts$g = this.retryAttempts.get(resourceId)) !== null && _this$retryAttempts$g !== void 0 ? _this$retryAttempts$g : 0;
|
|
308
|
+
if (attempts >= SyncBlockSubscriptionManager.MAX_RETRY_ATTEMPTS) {
|
|
309
|
+
var _this$deps$getFireAna;
|
|
310
|
+
var errorMessage = "Subscription reconnection failed after ".concat(attempts, " attempts");
|
|
311
|
+
(0, _monitoring.logException)(new Error(errorMessage), {
|
|
312
|
+
location: 'editor-synced-block-provider/syncBlockSubscriptionManager/max-retries-exhausted'
|
|
313
|
+
});
|
|
314
|
+
(_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((0, _errorHandling.fetchErrorPayload)(errorMessage, resourceId, (0, _utils.getSourceProductFromResourceIdSafe)(resourceId)));
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
var delay = SyncBlockSubscriptionManager.INITIAL_RETRY_DELAY_MS * Math.pow(SyncBlockSubscriptionManager.RETRY_BACKOFF_MULTIPLIER, attempts);
|
|
318
|
+
var timer = setTimeout(function () {
|
|
319
|
+
_this6.pendingRetries.delete(resourceId);
|
|
320
|
+
|
|
321
|
+
// Only re-subscribe if still relevant
|
|
322
|
+
if (_this6.subscriptions.has(resourceId) && _this6.shouldUseRealTime()) {
|
|
323
|
+
_this6.setupSubscription(resourceId);
|
|
324
|
+
|
|
325
|
+
// Only increment if the subscription was actually established
|
|
326
|
+
// (setupSubscription may be a no-op if another code path already re-established it)
|
|
327
|
+
if (_this6.graphqlSubscriptions.has(resourceId)) {
|
|
328
|
+
_this6.retryAttempts.set(resourceId, attempts + 1);
|
|
329
|
+
}
|
|
330
|
+
} else {
|
|
331
|
+
// Conditions no longer met — clean up stale retry state
|
|
332
|
+
_this6.retryAttempts.delete(resourceId);
|
|
333
|
+
}
|
|
334
|
+
}, delay);
|
|
335
|
+
this.pendingRetries.set(resourceId, timer);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Resets the retry counter for a resource. Called when a successful
|
|
340
|
+
* update is received, indicating the subscription is healthy.
|
|
341
|
+
*/
|
|
342
|
+
}, {
|
|
343
|
+
key: "resetRetryCount",
|
|
344
|
+
value: function resetRetryCount(resourceId) {
|
|
345
|
+
this.retryAttempts.delete(resourceId);
|
|
346
|
+
}
|
|
347
|
+
}, {
|
|
348
|
+
key: "cancelPendingRetry",
|
|
349
|
+
value: function cancelPendingRetry(resourceId) {
|
|
350
|
+
var timer = this.pendingRetries.get(resourceId);
|
|
351
|
+
if (timer) {
|
|
352
|
+
clearTimeout(timer);
|
|
353
|
+
this.pendingRetries.delete(resourceId);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}, {
|
|
357
|
+
key: "cancelAllPendingRetries",
|
|
358
|
+
value: function cancelAllPendingRetries() {
|
|
359
|
+
var _iterator = _createForOfIteratorHelper(this.pendingRetries.values()),
|
|
360
|
+
_step;
|
|
361
|
+
try {
|
|
362
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
363
|
+
var timer = _step.value;
|
|
364
|
+
clearTimeout(timer);
|
|
365
|
+
}
|
|
366
|
+
} catch (err) {
|
|
367
|
+
_iterator.e(err);
|
|
368
|
+
} finally {
|
|
369
|
+
_iterator.f();
|
|
370
|
+
}
|
|
371
|
+
this.pendingRetries.clear();
|
|
372
|
+
this.retryAttempts.clear();
|
|
373
|
+
}
|
|
266
374
|
}, {
|
|
267
375
|
key: "cleanupSubscription",
|
|
268
376
|
value: function cleanupSubscription(resourceId) {
|
|
@@ -271,39 +379,46 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
271
379
|
unsubscribe();
|
|
272
380
|
this.graphqlSubscriptions.delete(resourceId);
|
|
273
381
|
}
|
|
382
|
+
if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_12')) {
|
|
383
|
+
this.cancelPendingRetry(resourceId);
|
|
384
|
+
this.retryAttempts.delete(resourceId);
|
|
385
|
+
}
|
|
274
386
|
}
|
|
275
387
|
}, {
|
|
276
388
|
key: "setupSubscriptionsForAllBlocks",
|
|
277
389
|
value: function setupSubscriptionsForAllBlocks() {
|
|
278
|
-
var
|
|
279
|
-
|
|
390
|
+
var _iterator2 = _createForOfIteratorHelper(this.subscriptions.keys()),
|
|
391
|
+
_step2;
|
|
280
392
|
try {
|
|
281
|
-
for (
|
|
282
|
-
var resourceId =
|
|
393
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
394
|
+
var resourceId = _step2.value;
|
|
283
395
|
this.setupSubscription(resourceId);
|
|
284
396
|
}
|
|
285
397
|
} catch (err) {
|
|
286
|
-
|
|
398
|
+
_iterator2.e(err);
|
|
287
399
|
} finally {
|
|
288
|
-
|
|
400
|
+
_iterator2.f();
|
|
289
401
|
}
|
|
290
402
|
}
|
|
291
403
|
}, {
|
|
292
404
|
key: "cleanupAll",
|
|
293
405
|
value: function cleanupAll() {
|
|
294
|
-
var
|
|
295
|
-
|
|
406
|
+
var _iterator3 = _createForOfIteratorHelper(this.graphqlSubscriptions.values()),
|
|
407
|
+
_step3;
|
|
296
408
|
try {
|
|
297
|
-
for (
|
|
298
|
-
var unsubscribe =
|
|
409
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
410
|
+
var unsubscribe = _step3.value;
|
|
299
411
|
unsubscribe();
|
|
300
412
|
}
|
|
301
413
|
} catch (err) {
|
|
302
|
-
|
|
414
|
+
_iterator3.e(err);
|
|
303
415
|
} finally {
|
|
304
|
-
|
|
416
|
+
_iterator3.f();
|
|
305
417
|
}
|
|
306
418
|
this.graphqlSubscriptions.clear();
|
|
419
|
+
if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_12')) {
|
|
420
|
+
this.cancelAllPendingRetries();
|
|
421
|
+
}
|
|
307
422
|
}
|
|
308
423
|
}, {
|
|
309
424
|
key: "destroy",
|
|
@@ -315,17 +430,17 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
315
430
|
this.useRealTimeSubscriptions = false;
|
|
316
431
|
|
|
317
432
|
// Clear any pending cache deletions
|
|
318
|
-
var
|
|
319
|
-
|
|
433
|
+
var _iterator4 = _createForOfIteratorHelper(this.pendingCacheDeletions.values()),
|
|
434
|
+
_step4;
|
|
320
435
|
try {
|
|
321
|
-
for (
|
|
322
|
-
var timeout =
|
|
436
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
437
|
+
var timeout = _step4.value;
|
|
323
438
|
clearTimeout(timeout);
|
|
324
439
|
}
|
|
325
440
|
} catch (err) {
|
|
326
|
-
|
|
441
|
+
_iterator4.e(err);
|
|
327
442
|
} finally {
|
|
328
|
-
|
|
443
|
+
_iterator4.f();
|
|
329
444
|
}
|
|
330
445
|
this.pendingCacheDeletions.clear();
|
|
331
446
|
}
|
|
@@ -337,7 +452,7 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
337
452
|
}, {
|
|
338
453
|
key: "handleGraphQLUpdate",
|
|
339
454
|
value: function handleGraphQLUpdate(syncBlockInstance) {
|
|
340
|
-
var
|
|
455
|
+
var _this7 = this;
|
|
341
456
|
if (!syncBlockInstance.resourceId) {
|
|
342
457
|
return;
|
|
343
458
|
}
|
|
@@ -345,18 +460,26 @@ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__P
|
|
|
345
460
|
var resolved = existing ? (0, _resolveSyncBlockInstance.resolveSyncBlockInstance)(existing, syncBlockInstance) : syncBlockInstance;
|
|
346
461
|
this.deps.updateCache(resolved);
|
|
347
462
|
if (!syncBlockInstance.error) {
|
|
463
|
+
// Successful data delivery means the subscription is healthy — reset retry counter
|
|
464
|
+
if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_12')) {
|
|
465
|
+
this.resetRetryCount(syncBlockInstance.resourceId);
|
|
466
|
+
}
|
|
348
467
|
var callbacks = this.subscriptions.get(syncBlockInstance.resourceId);
|
|
349
468
|
var localIds = callbacks ? Object.keys(callbacks) : [];
|
|
350
469
|
localIds.forEach(function (localId) {
|
|
351
|
-
var
|
|
352
|
-
(
|
|
470
|
+
var _this7$deps$getFireAn, _syncBlockInstance$da, _syncBlockInstance$da2;
|
|
471
|
+
(_this7$deps$getFireAn = _this7.deps.getFireAnalyticsEvent()) === null || _this7$deps$getFireAn === void 0 || _this7$deps$getFireAn((0, _errorHandling.fetchSuccessPayload)(syncBlockInstance.resourceId, localId, (_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)));
|
|
353
472
|
});
|
|
354
473
|
this.deps.fetchSyncBlockSourceInfo(resolved.resourceId);
|
|
355
474
|
} else {
|
|
356
|
-
var _syncBlockInstance$er, _syncBlockInstance$er2, _this$deps$
|
|
475
|
+
var _syncBlockInstance$er, _syncBlockInstance$er2, _this$deps$getFireAna2, _syncBlockInstance$da3, _syncBlockInstance$da4;
|
|
357
476
|
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);
|
|
358
|
-
(_this$deps$
|
|
477
|
+
(_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)));
|
|
359
478
|
}
|
|
360
479
|
}
|
|
361
480
|
}]);
|
|
362
|
-
}();
|
|
481
|
+
}();
|
|
482
|
+
// Reconnection with exponential backoff
|
|
483
|
+
(0, _defineProperty2.default)(SyncBlockSubscriptionManager, "INITIAL_RETRY_DELAY_MS", 1000);
|
|
484
|
+
(0, _defineProperty2.default)(SyncBlockSubscriptionManager, "RETRY_BACKOFF_MULTIPLIER", 2);
|
|
485
|
+
(0, _defineProperty2.default)(SyncBlockSubscriptionManager, "MAX_RETRY_ATTEMPTS", 5);
|
package/dist/cjs/utils/utils.js
CHANGED
|
@@ -1,15 +1,60 @@
|
|
|
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.getSourceProductFromResourceIdSafe = exports.getContentIdAndProductFromResourceId = exports.createSyncBlockNode = exports.convertSyncBlockPMNodeToSyncBlockData = exports.convertSyncBlockJSONNodeToSyncBlockNode = exports.convertPMNodesToSyncBlockNodes = exports.convertPMNodeToSyncBlockNode = exports.convertContentUpdatedAt = void 0;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
exports.stripAnnotationMarksFromJSONContent = exports.getSourceProductFromResourceIdSafe = exports.getContentIdAndProductFromResourceId = exports.createSyncBlockNode = exports.convertSyncBlockPMNodeToSyncBlockData = exports.convertSyncBlockJSONNodeToSyncBlockNode = exports.convertPMNodesToSyncBlockNodes = exports.convertPMNodeToSyncBlockNode = exports.convertContentUpdatedAt = void 0;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
10
|
+
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; }
|
|
11
|
+
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; } /* eslint-disable require-unicode-regexp */
|
|
12
|
+
var _stripAnnotationMarksFromJSONContent = exports.stripAnnotationMarksFromJSONContent = function stripAnnotationMarksFromJSONContent(content) {
|
|
13
|
+
var strippedContent;
|
|
14
|
+
content.forEach(function (contentNode, index) {
|
|
15
|
+
var _contentNode$marks;
|
|
16
|
+
if (!contentNode) {
|
|
17
|
+
var _strippedContent;
|
|
18
|
+
(_strippedContent = strippedContent) === null || _strippedContent === void 0 || _strippedContent.push(contentNode);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
var hasAnnotationMark = (_contentNode$marks = contentNode.marks) === null || _contentNode$marks === void 0 ? void 0 : _contentNode$marks.some(function (mark) {
|
|
22
|
+
return mark.type === 'annotation';
|
|
23
|
+
});
|
|
24
|
+
var childContent = contentNode.content ? _stripAnnotationMarksFromJSONContent(contentNode.content) : undefined;
|
|
25
|
+
var hasContentChanged = childContent !== undefined && childContent !== contentNode.content;
|
|
26
|
+
if (!hasAnnotationMark && !hasContentChanged) {
|
|
27
|
+
var _strippedContent2;
|
|
28
|
+
(_strippedContent2 = strippedContent) === null || _strippedContent2 === void 0 || _strippedContent2.push(contentNode);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (!strippedContent) {
|
|
32
|
+
strippedContent = content.slice(0, index);
|
|
33
|
+
}
|
|
34
|
+
var strippedNode = _objectSpread({}, contentNode);
|
|
35
|
+
if (hasAnnotationMark) {
|
|
36
|
+
var _contentNode$marks2;
|
|
37
|
+
var marks = (_contentNode$marks2 = contentNode.marks) === null || _contentNode$marks2 === void 0 ? void 0 : _contentNode$marks2.filter(function (mark) {
|
|
38
|
+
return mark.type !== 'annotation';
|
|
39
|
+
});
|
|
40
|
+
if (marks && marks.length > 0) {
|
|
41
|
+
strippedNode.marks = marks;
|
|
42
|
+
} else {
|
|
43
|
+
delete strippedNode.marks;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (hasContentChanged && childContent) {
|
|
47
|
+
strippedNode.content = childContent;
|
|
48
|
+
}
|
|
49
|
+
strippedContent.push(strippedNode);
|
|
50
|
+
});
|
|
51
|
+
return strippedContent !== null && strippedContent !== void 0 ? strippedContent : content;
|
|
52
|
+
};
|
|
9
53
|
var convertSyncBlockPMNodeToSyncBlockData = exports.convertSyncBlockPMNodeToSyncBlockData = function convertSyncBlockPMNodeToSyncBlockData(node) {
|
|
54
|
+
var content = node.content.toJSON();
|
|
10
55
|
return {
|
|
11
56
|
blockInstanceId: node.attrs.localId,
|
|
12
|
-
content:
|
|
57
|
+
content: (0, _platformFeatureFlags.fg)('platform_synced_block_patch_12') ? _stripAnnotationMarksFromJSONContent(content) : content,
|
|
13
58
|
resourceId: node.attrs.resourceId
|
|
14
59
|
};
|
|
15
60
|
};
|
|
@@ -181,7 +181,7 @@ const parseSubscriptionPayload = payload => {
|
|
|
181
181
|
* @param onError - Optional callback function invoked on subscription errors
|
|
182
182
|
* @returns Unsubscribe function to close the subscription
|
|
183
183
|
*/
|
|
184
|
-
export const subscribeToBlockUpdates = (blockAri, onData, onError) => {
|
|
184
|
+
export const subscribeToBlockUpdates = (blockAri, onData, onError, onComplete) => {
|
|
185
185
|
const client = getBlockServiceClient();
|
|
186
186
|
if (!client) {
|
|
187
187
|
// Return a no-op unsubscribe if client is not available (e.g., SSR)
|
|
@@ -209,7 +209,7 @@ export const subscribeToBlockUpdates = (blockAri, onData, onError) => {
|
|
|
209
209
|
onError === null || onError === void 0 ? void 0 : onError(new Error(extractGraphQLWSErrorMessage(error)));
|
|
210
210
|
},
|
|
211
211
|
complete: () => {
|
|
212
|
-
|
|
212
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
213
213
|
}
|
|
214
214
|
});
|
|
215
215
|
return unsubscribe;
|
|
@@ -533,7 +533,7 @@ class BlockServiceADFFetchProvider {
|
|
|
533
533
|
* @param onError - Optional callback function invoked on subscription errors
|
|
534
534
|
* @returns Unsubscribe function to stop receiving updates
|
|
535
535
|
*/
|
|
536
|
-
subscribeToBlockUpdates(resourceId, onUpdate, onError) {
|
|
536
|
+
subscribeToBlockUpdates(resourceId, onUpdate, onError, onComplete) {
|
|
537
537
|
const blockAri = generateBlockAriFromReference({
|
|
538
538
|
cloudId: this.cloudId,
|
|
539
539
|
resourceId
|
|
@@ -568,7 +568,7 @@ class BlockServiceADFFetchProvider {
|
|
|
568
568
|
resourceId: parsedData.resourceId
|
|
569
569
|
};
|
|
570
570
|
onUpdate(syncBlockInstance);
|
|
571
|
-
}, onError);
|
|
571
|
+
}, onError, onComplete);
|
|
572
572
|
}).catch(err => {
|
|
573
573
|
if (cancelled) {
|
|
574
574
|
return;
|
|
@@ -313,9 +313,9 @@ export class SyncedBlockProvider extends SyncBlockDataProviderInterface {
|
|
|
313
313
|
* @param onError - Optional callback function invoked on subscription errors
|
|
314
314
|
* @returns Unsubscribe function to stop receiving updates, or undefined if not supported
|
|
315
315
|
*/
|
|
316
|
-
subscribeToBlockUpdates(resourceId, onUpdate, onError) {
|
|
316
|
+
subscribeToBlockUpdates(resourceId, onUpdate, onError, onComplete) {
|
|
317
317
|
if (this.fetchProvider.subscribeToBlockUpdates) {
|
|
318
|
-
return this.fetchProvider.subscribeToBlockUpdates(resourceId, onUpdate, onError);
|
|
318
|
+
return this.fetchProvider.subscribeToBlockUpdates(resourceId, onUpdate, onError, onComplete);
|
|
319
319
|
}
|
|
320
320
|
return undefined;
|
|
321
321
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import isEqual from 'lodash/isEqual';
|
|
3
3
|
import { logException } from '@atlaskit/editor-common/monitoring';
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
4
5
|
import { SyncBlockError } from '../common/types';
|
|
5
6
|
import { fetchErrorPayload, fetchSuccessPayload, getSourceInfoErrorPayload, updateReferenceErrorPayload } from '../utils/errorHandling';
|
|
6
7
|
import { getFetchExperience, getFetchSourceInfoExperience, getSaveReferenceExperience } from '../utils/experienceTracking';
|
|
7
8
|
import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
|
|
8
|
-
import { createSyncBlockNode, getSourceProductFromResourceIdSafe } from '../utils/utils';
|
|
9
|
+
import { createSyncBlockNode, getSourceProductFromResourceIdSafe, stripAnnotationMarksFromJSONContent } from '../utils/utils';
|
|
9
10
|
import { SyncBlockBatchFetcher } from './syncBlockBatchFetcher';
|
|
10
11
|
import { syncBlockInMemorySessionCache } from './syncBlockInMemorySessionCache';
|
|
11
12
|
import { SyncBlockProviderFactoryManager } from './syncBlockProviderFactoryManager';
|
|
@@ -141,10 +142,27 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
141
142
|
const syncBlockNode = createSyncBlockNode('', resourceId);
|
|
142
143
|
const providerData = (_this$dataProvider2 = this.dataProvider) === null || _this$dataProvider2 === void 0 ? void 0 : (_this$dataProvider2$g = _this$dataProvider2.getNodeDataFromCache(syncBlockNode)) === null || _this$dataProvider2$g === void 0 ? void 0 : _this$dataProvider2$g.data;
|
|
143
144
|
if (providerData) {
|
|
144
|
-
return providerData;
|
|
145
|
+
return this.stripAnnotationMarksFromReferenceData(providerData);
|
|
145
146
|
}
|
|
146
147
|
return this.getFromSessionCache(resourceId);
|
|
147
148
|
}
|
|
149
|
+
stripAnnotationMarksFromReferenceData(syncBlock) {
|
|
150
|
+
var _syncBlock$data;
|
|
151
|
+
if (!fg('platform_synced_block_patch_12') || !((_syncBlock$data = syncBlock.data) !== null && _syncBlock$data !== void 0 && _syncBlock$data.content)) {
|
|
152
|
+
return syncBlock;
|
|
153
|
+
}
|
|
154
|
+
const content = stripAnnotationMarksFromJSONContent(syncBlock.data.content);
|
|
155
|
+
if (content === syncBlock.data.content) {
|
|
156
|
+
return syncBlock;
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
...syncBlock,
|
|
160
|
+
data: {
|
|
161
|
+
...syncBlock.data,
|
|
162
|
+
content
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
148
166
|
updateSessionCache(resourceId) {
|
|
149
167
|
const latestData = this.getFromCache(resourceId);
|
|
150
168
|
if (latestData) {
|
|
@@ -157,7 +175,7 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
157
175
|
if (!raw) {
|
|
158
176
|
return undefined;
|
|
159
177
|
}
|
|
160
|
-
return JSON.parse(raw);
|
|
178
|
+
return this.stripAnnotationMarksFromReferenceData(JSON.parse(raw));
|
|
161
179
|
} catch (error) {
|
|
162
180
|
logException(error, {
|
|
163
181
|
location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getFromSessionCache'
|
|
@@ -470,18 +488,19 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
470
488
|
}
|
|
471
489
|
}
|
|
472
490
|
updateCache(syncBlock) {
|
|
491
|
+
const sanitizedSyncBlock = this.stripAnnotationMarksFromReferenceData(syncBlock);
|
|
473
492
|
const {
|
|
474
493
|
resourceId
|
|
475
|
-
} =
|
|
494
|
+
} = sanitizedSyncBlock;
|
|
476
495
|
if (resourceId) {
|
|
477
496
|
var _this$dataProvider3;
|
|
478
497
|
(_this$dataProvider3 = this.dataProvider) === null || _this$dataProvider3 === void 0 ? void 0 : _this$dataProvider3.updateCache({
|
|
479
|
-
[resourceId]:
|
|
498
|
+
[resourceId]: sanitizedSyncBlock
|
|
480
499
|
}, {
|
|
481
500
|
strategy: 'merge',
|
|
482
501
|
source: 'network'
|
|
483
502
|
});
|
|
484
|
-
this._subscriptionManager.notifySubscriptionCallbacks(resourceId,
|
|
503
|
+
this._subscriptionManager.notifySubscriptionCallbacks(resourceId, sanitizedSyncBlock);
|
|
485
504
|
this.updateSessionCache(resourceId);
|
|
486
505
|
}
|
|
487
506
|
}
|
|
@@ -542,12 +561,12 @@ export class ReferenceSyncBlockStoreManager {
|
|
|
542
561
|
* @returns
|
|
543
562
|
*/
|
|
544
563
|
getSyncBlockURL(resourceId) {
|
|
545
|
-
var _syncBlock$
|
|
564
|
+
var _syncBlock$data2;
|
|
546
565
|
const syncBlock = this.getFromCache(resourceId);
|
|
547
566
|
if (!syncBlock) {
|
|
548
567
|
return undefined;
|
|
549
568
|
}
|
|
550
|
-
return (_syncBlock$
|
|
569
|
+
return (_syncBlock$data2 = syncBlock.data) === null || _syncBlock$data2 === void 0 ? void 0 : _syncBlock$data2.sourceURL;
|
|
551
570
|
}
|
|
552
571
|
getProviderFactory(resourceId) {
|
|
553
572
|
return this._providerFactoryManager.getProviderFactory(resourceId);
|