@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.
Files changed (36) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cjs/clients/block-service/blockSubscription.js +2 -2
  3. package/dist/cjs/providers/block-service/blockServiceAPI.js +2 -2
  4. package/dist/cjs/providers/syncBlockProvider.js +2 -2
  5. package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +26 -7
  6. package/dist/cjs/store-manager/syncBlockSubscriptionManager.js +148 -25
  7. package/dist/cjs/utils/utils.js +49 -4
  8. package/dist/es2019/clients/block-service/blockSubscription.js +2 -2
  9. package/dist/es2019/providers/block-service/blockServiceAPI.js +2 -2
  10. package/dist/es2019/providers/syncBlockProvider.js +2 -2
  11. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +27 -8
  12. package/dist/es2019/store-manager/syncBlockSubscriptionManager.js +109 -6
  13. package/dist/es2019/utils/utils.js +43 -1
  14. package/dist/esm/clients/block-service/blockSubscription.js +2 -2
  15. package/dist/esm/providers/block-service/blockServiceAPI.js +2 -2
  16. package/dist/esm/providers/syncBlockProvider.js +2 -2
  17. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +28 -9
  18. package/dist/esm/store-manager/syncBlockSubscriptionManager.js +148 -25
  19. package/dist/esm/utils/utils.js +48 -1
  20. package/dist/types/clients/block-service/blockSubscription.d.ts +2 -1
  21. package/dist/types/entry-points/providers-types.d.ts +1 -1
  22. package/dist/types/providers/block-service/blockServiceAPI.d.ts +1 -1
  23. package/dist/types/providers/syncBlockProvider.d.ts +1 -1
  24. package/dist/types/providers/types.d.ts +4 -2
  25. package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +1 -0
  26. package/dist/types/store-manager/syncBlockSubscriptionManager.d.ts +23 -0
  27. package/dist/types/utils/utils.d.ts +2 -1
  28. package/dist/types-ts4.5/clients/block-service/blockSubscription.d.ts +2 -1
  29. package/dist/types-ts4.5/entry-points/providers-types.d.ts +1 -1
  30. package/dist/types-ts4.5/providers/block-service/blockServiceAPI.d.ts +1 -1
  31. package/dist/types-ts4.5/providers/syncBlockProvider.d.ts +1 -1
  32. package/dist/types-ts4.5/providers/types.d.ts +4 -2
  33. package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +1 -0
  34. package/dist/types-ts4.5/store-manager/syncBlockSubscriptionManager.d.ts +23 -0
  35. package/dist/types-ts4.5/utils/utils.d.ts +2 -1
  36. 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
- // Subscription completed
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 resourceId = syncBlock.resourceId;
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, syncBlock), {
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, syncBlock);
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$data;
707
+ var _syncBlock$data2;
689
708
  var syncBlock = this.getFromCache(resourceId);
690
709
  if (!syncBlock) {
691
710
  return undefined;
692
711
  }
693
- return (_syncBlock$data = syncBlock.data) === null || _syncBlock$data === void 0 ? void 0 : _syncBlock$data.sourceURL;
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 _iterator = _createForOfIteratorHelper(this.subscriptions.keys()),
279
- _step;
390
+ var _iterator2 = _createForOfIteratorHelper(this.subscriptions.keys()),
391
+ _step2;
280
392
  try {
281
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
282
- var resourceId = _step.value;
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
- _iterator.e(err);
398
+ _iterator2.e(err);
287
399
  } finally {
288
- _iterator.f();
400
+ _iterator2.f();
289
401
  }
290
402
  }
291
403
  }, {
292
404
  key: "cleanupAll",
293
405
  value: function cleanupAll() {
294
- var _iterator2 = _createForOfIteratorHelper(this.graphqlSubscriptions.values()),
295
- _step2;
406
+ var _iterator3 = _createForOfIteratorHelper(this.graphqlSubscriptions.values()),
407
+ _step3;
296
408
  try {
297
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
298
- var unsubscribe = _step2.value;
409
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
410
+ var unsubscribe = _step3.value;
299
411
  unsubscribe();
300
412
  }
301
413
  } catch (err) {
302
- _iterator2.e(err);
414
+ _iterator3.e(err);
303
415
  } finally {
304
- _iterator2.f();
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 _iterator3 = _createForOfIteratorHelper(this.pendingCacheDeletions.values()),
319
- _step3;
433
+ var _iterator4 = _createForOfIteratorHelper(this.pendingCacheDeletions.values()),
434
+ _step4;
320
435
  try {
321
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
322
- var timeout = _step3.value;
436
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
437
+ var timeout = _step4.value;
323
438
  clearTimeout(timeout);
324
439
  }
325
440
  } catch (err) {
326
- _iterator3.e(err);
441
+ _iterator4.e(err);
327
442
  } finally {
328
- _iterator3.f();
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 _this6 = this;
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 _this6$deps$getFireAn, _syncBlockInstance$da, _syncBlockInstance$da2;
352
- (_this6$deps$getFireAn = _this6.deps.getFireAnalyticsEvent()) === null || _this6$deps$getFireAn === void 0 || _this6$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)));
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$getFireAna, _syncBlockInstance$da3, _syncBlockInstance$da4;
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$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((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)));
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);
@@ -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
- /* eslint-disable require-unicode-regexp */
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: node.content.toJSON(),
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
- // Subscription completed
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
- } = syncBlock;
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]: syncBlock
498
+ [resourceId]: sanitizedSyncBlock
480
499
  }, {
481
500
  strategy: 'merge',
482
501
  source: 'network'
483
502
  });
484
- this._subscriptionManager.notifySubscriptionCallbacks(resourceId, syncBlock);
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$data;
564
+ var _syncBlock$data2;
546
565
  const syncBlock = this.getFromCache(resourceId);
547
566
  if (!syncBlock) {
548
567
  return undefined;
549
568
  }
550
- return (_syncBlock$data = syncBlock.data) === null || _syncBlock$data === void 0 ? void 0 : _syncBlock$data.sourceURL;
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);