@atlaskit/editor-synced-block-provider 3.31.0 → 3.31.2

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 (32) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cjs/store-manager/referenceSyncBlockStoreManager.js +117 -9
  3. package/dist/cjs/store-manager/sourceSyncBlockStoreManager.js +16 -0
  4. package/dist/cjs/store-manager/syncBlockBatchFetcher.js +76 -0
  5. package/dist/cjs/store-manager/syncBlockInMemorySessionCache.js +26 -0
  6. package/dist/cjs/store-manager/syncBlockProviderFactoryManager.js +175 -0
  7. package/dist/cjs/store-manager/syncBlockSubscriptionManager.js +198 -0
  8. package/dist/es2019/store-manager/referenceSyncBlockStoreManager.js +93 -9
  9. package/dist/es2019/store-manager/sourceSyncBlockStoreManager.js +12 -0
  10. package/dist/es2019/store-manager/syncBlockBatchFetcher.js +56 -0
  11. package/dist/es2019/store-manager/syncBlockInMemorySessionCache.js +24 -0
  12. package/dist/es2019/store-manager/syncBlockProviderFactoryManager.js +158 -0
  13. package/dist/es2019/store-manager/syncBlockSubscriptionManager.js +136 -0
  14. package/dist/esm/store-manager/referenceSyncBlockStoreManager.js +117 -9
  15. package/dist/esm/store-manager/sourceSyncBlockStoreManager.js +16 -0
  16. package/dist/esm/store-manager/syncBlockBatchFetcher.js +69 -0
  17. package/dist/esm/store-manager/syncBlockInMemorySessionCache.js +26 -0
  18. package/dist/esm/store-manager/syncBlockProviderFactoryManager.js +168 -0
  19. package/dist/esm/store-manager/syncBlockSubscriptionManager.js +191 -0
  20. package/dist/types/store-manager/referenceSyncBlockStoreManager.d.ts +3 -0
  21. package/dist/types/store-manager/sourceSyncBlockStoreManager.d.ts +2 -0
  22. package/dist/types/store-manager/syncBlockBatchFetcher.d.ts +25 -0
  23. package/dist/types/store-manager/syncBlockInMemorySessionCache.d.ts +18 -0
  24. package/dist/types/store-manager/syncBlockProviderFactoryManager.d.ts +25 -0
  25. package/dist/types/store-manager/syncBlockSubscriptionManager.d.ts +38 -0
  26. package/dist/types-ts4.5/store-manager/referenceSyncBlockStoreManager.d.ts +3 -0
  27. package/dist/types-ts4.5/store-manager/sourceSyncBlockStoreManager.d.ts +2 -0
  28. package/dist/types-ts4.5/store-manager/syncBlockBatchFetcher.d.ts +25 -0
  29. package/dist/types-ts4.5/store-manager/syncBlockInMemorySessionCache.d.ts +18 -0
  30. package/dist/types-ts4.5/store-manager/syncBlockProviderFactoryManager.d.ts +25 -0
  31. package/dist/types-ts4.5/store-manager/syncBlockSubscriptionManager.d.ts +38 -0
  32. package/package.json +5 -2
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.SyncBlockSubscriptionManager = void 0;
8
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
9
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
10
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
11
+ var _monitoring = require("@atlaskit/editor-common/monitoring");
12
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
13
+ var _errorHandling = require("../utils/errorHandling");
14
+ var _resolveSyncBlockInstance = require("../utils/resolveSyncBlockInstance");
15
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
16
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
17
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
18
+ /**
19
+ * Manages the lifecycle of GraphQL WebSocket subscriptions for sync block
20
+ * real-time updates, and provides a listener API so React components can
21
+ * react when the set of subscribed resource IDs changes.
22
+ */
23
+ var SyncBlockSubscriptionManager = exports.SyncBlockSubscriptionManager = /*#__PURE__*/function () {
24
+ function SyncBlockSubscriptionManager(deps) {
25
+ (0, _classCallCheck2.default)(this, SyncBlockSubscriptionManager);
26
+ (0, _defineProperty2.default)(this, "graphqlSubscriptions", new Map());
27
+ (0, _defineProperty2.default)(this, "subscriptionChangeListeners", new Set());
28
+ (0, _defineProperty2.default)(this, "useRealTimeSubscriptions", false);
29
+ this.deps = deps;
30
+ }
31
+ return (0, _createClass2.default)(SyncBlockSubscriptionManager, [{
32
+ key: "setRealTimeSubscriptionsEnabled",
33
+ value: function setRealTimeSubscriptionsEnabled(enabled) {
34
+ if (this.useRealTimeSubscriptions === enabled) {
35
+ return;
36
+ }
37
+ this.useRealTimeSubscriptions = enabled;
38
+ if (enabled) {
39
+ this.setupSubscriptionsForAllBlocks();
40
+ } else {
41
+ this.cleanupAll();
42
+ }
43
+ }
44
+ }, {
45
+ key: "isRealTimeSubscriptionsEnabled",
46
+ value: function isRealTimeSubscriptionsEnabled() {
47
+ return this.useRealTimeSubscriptions;
48
+ }
49
+ }, {
50
+ key: "getSubscribedResourceIds",
51
+ value: function getSubscribedResourceIds() {
52
+ return Array.from(this.deps.getSubscriptions().keys());
53
+ }
54
+ }, {
55
+ key: "onSubscriptionsChanged",
56
+ value: function onSubscriptionsChanged(listener) {
57
+ var _this = this;
58
+ this.subscriptionChangeListeners.add(listener);
59
+ return function () {
60
+ _this.subscriptionChangeListeners.delete(listener);
61
+ };
62
+ }
63
+ }, {
64
+ key: "notifySubscriptionChangeListeners",
65
+ value: function notifySubscriptionChangeListeners() {
66
+ var _this2 = this;
67
+ this.subscriptionChangeListeners.forEach(function (listener) {
68
+ try {
69
+ listener();
70
+ } catch (error) {
71
+ var _this2$deps$getFireAn;
72
+ (0, _monitoring.logException)(error, {
73
+ location: 'editor-synced-block-provider/syncBlockSubscriptionManager/notifySubscriptionChangeListeners'
74
+ });
75
+ (_this2$deps$getFireAn = _this2.deps.getFireAnalyticsEvent()) === null || _this2$deps$getFireAn === void 0 || _this2$deps$getFireAn((0, _errorHandling.fetchErrorPayload)(error.message));
76
+ }
77
+ });
78
+ }
79
+ }, {
80
+ key: "handleSubscriptionUpdate",
81
+ value: function handleSubscriptionUpdate(syncBlockInstance) {
82
+ if (!syncBlockInstance.resourceId) {
83
+ return;
84
+ }
85
+ var existing = this.deps.getFromCache(syncBlockInstance.resourceId);
86
+ var resolved = existing ? (0, _resolveSyncBlockInstance.resolveSyncBlockInstance)(existing, syncBlockInstance) : syncBlockInstance;
87
+ this.deps.updateCache(resolved);
88
+ if (!syncBlockInstance.error) {
89
+ this.deps.fetchSyncBlockSourceInfo(resolved.resourceId);
90
+ }
91
+ }
92
+ }, {
93
+ key: "setupSubscription",
94
+ value: function setupSubscription(resourceId) {
95
+ var _this3 = this;
96
+ if (this.graphqlSubscriptions.has(resourceId)) {
97
+ return;
98
+ }
99
+ var dataProvider = this.deps.getDataProvider();
100
+ if (!(dataProvider !== null && dataProvider !== void 0 && dataProvider.subscribeToBlockUpdates)) {
101
+ return;
102
+ }
103
+ var unsubscribe = dataProvider.subscribeToBlockUpdates(resourceId, function (syncBlockInstance) {
104
+ _this3.handleGraphQLUpdate(syncBlockInstance);
105
+ }, function (error) {
106
+ var _this3$deps$getFireAn;
107
+ (0, _monitoring.logException)(error, {
108
+ location: 'editor-synced-block-provider/syncBlockSubscriptionManager/graphql-subscription'
109
+ });
110
+ (_this3$deps$getFireAn = _this3.deps.getFireAnalyticsEvent()) === null || _this3$deps$getFireAn === void 0 || _this3$deps$getFireAn((0, _errorHandling.fetchErrorPayload)(error.message));
111
+ });
112
+ if (unsubscribe) {
113
+ this.graphqlSubscriptions.set(resourceId, unsubscribe);
114
+ }
115
+ }
116
+ }, {
117
+ key: "cleanupSubscription",
118
+ value: function cleanupSubscription(resourceId) {
119
+ var unsubscribe = this.graphqlSubscriptions.get(resourceId);
120
+ if (unsubscribe) {
121
+ unsubscribe();
122
+ this.graphqlSubscriptions.delete(resourceId);
123
+ }
124
+ }
125
+ }, {
126
+ key: "setupSubscriptionsForAllBlocks",
127
+ value: function setupSubscriptionsForAllBlocks() {
128
+ var _iterator = _createForOfIteratorHelper(this.deps.getSubscriptions().keys()),
129
+ _step;
130
+ try {
131
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
132
+ var resourceId = _step.value;
133
+ this.setupSubscription(resourceId);
134
+ }
135
+ } catch (err) {
136
+ _iterator.e(err);
137
+ } finally {
138
+ _iterator.f();
139
+ }
140
+ }
141
+ }, {
142
+ key: "cleanupAll",
143
+ value: function cleanupAll() {
144
+ var _iterator2 = _createForOfIteratorHelper(this.graphqlSubscriptions.values()),
145
+ _step2;
146
+ try {
147
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
148
+ var unsubscribe = _step2.value;
149
+ unsubscribe();
150
+ }
151
+ } catch (err) {
152
+ _iterator2.e(err);
153
+ } finally {
154
+ _iterator2.f();
155
+ }
156
+ this.graphqlSubscriptions.clear();
157
+ }
158
+ }, {
159
+ key: "destroy",
160
+ value: function destroy() {
161
+ this.cleanupAll();
162
+ this.subscriptionChangeListeners.clear();
163
+ this.useRealTimeSubscriptions = false;
164
+ }
165
+ }, {
166
+ key: "shouldUseRealTime",
167
+ value: function shouldUseRealTime() {
168
+ return this.useRealTimeSubscriptions;
169
+ }
170
+ }, {
171
+ key: "handleGraphQLUpdate",
172
+ value: function handleGraphQLUpdate(syncBlockInstance) {
173
+ var _this4 = this;
174
+ if (!syncBlockInstance.resourceId) {
175
+ if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_5')) {
176
+ return;
177
+ }
178
+ throw new Error('Sync block instance provided to graphql subscription update missing resource id');
179
+ }
180
+ var existing = this.deps.getFromCache(syncBlockInstance.resourceId);
181
+ var resolved = existing ? (0, _resolveSyncBlockInstance.resolveSyncBlockInstance)(existing, syncBlockInstance) : syncBlockInstance;
182
+ this.deps.updateCache(resolved);
183
+ if (!syncBlockInstance.error) {
184
+ var callbacks = this.deps.getSubscriptions().get(syncBlockInstance.resourceId);
185
+ var localIds = callbacks ? Object.keys(callbacks) : [];
186
+ localIds.forEach(function (localId) {
187
+ var _this4$deps$getFireAn, _syncBlockInstance$da;
188
+ (_this4$deps$getFireAn = _this4.deps.getFireAnalyticsEvent()) === null || _this4$deps$getFireAn === void 0 || _this4$deps$getFireAn((0, _errorHandling.fetchSuccessPayload)(syncBlockInstance.resourceId, localId, (_syncBlockInstance$da = syncBlockInstance.data) === null || _syncBlockInstance$da === void 0 ? void 0 : _syncBlockInstance$da.product));
189
+ });
190
+ this.deps.fetchSyncBlockSourceInfo(resolved.resourceId);
191
+ } else {
192
+ var _syncBlockInstance$er, _syncBlockInstance$er2, _syncBlockInstance$er3, _this$deps$getFireAna;
193
+ var errorMessage = (0, _platformFeatureFlags.fg)('platform_synced_block_patch_3') ? ((_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) : (_syncBlockInstance$er3 = syncBlockInstance.error) === null || _syncBlockInstance$er3 === void 0 ? void 0 : _syncBlockInstance$er3.type;
194
+ (_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 || _this$deps$getFireAna((0, _errorHandling.fetchErrorPayload)(errorMessage, syncBlockInstance.resourceId));
195
+ }
196
+ }
197
+ }]);
198
+ }();
@@ -10,7 +10,10 @@ import { getFetchExperience, getFetchSourceInfoExperience, getSaveReferenceExper
10
10
  import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
11
11
  import { parseResourceId } from '../utils/resourceId';
12
12
  import { createSyncBlockNode } from '../utils/utils';
13
+ import { SyncBlockBatchFetcher } from './syncBlockBatchFetcher';
13
14
  import { syncBlockInMemorySessionCache } from './syncBlockInMemorySessionCache';
15
+ import { SyncBlockProviderFactoryManager } from './syncBlockProviderFactoryManager';
16
+ import { SyncBlockSubscriptionManager } from './syncBlockSubscriptionManager';
14
17
  const CACHE_KEY_PREFIX = 'sync-block-data-';
15
18
 
16
19
  // A store manager responsible for the lifecycle and state management of reference sync blocks in an editor instance.
@@ -66,6 +69,26 @@ export class ReferenceSyncBlockStoreManager {
66
69
  this.graphqlSubscriptions = new Map();
67
70
  this.subscriptionChangeListeners = new Set();
68
71
  this.newlyAddedSyncBlocks = new Set();
72
+ if (fg('platform_synced_block_patch_5')) {
73
+ this._subscriptionManager = new SyncBlockSubscriptionManager({
74
+ getDataProvider: () => this.dataProvider,
75
+ getSubscriptions: () => this.subscriptions,
76
+ getFromCache: rid => this.getFromCache(rid),
77
+ updateCache: inst => this.updateCache(inst),
78
+ fetchSyncBlockSourceInfo: rid => this.fetchSyncBlockSourceInfo(rid),
79
+ getFireAnalyticsEvent: () => this.fireAnalyticsEvent
80
+ });
81
+ this._providerFactoryManager = new SyncBlockProviderFactoryManager({
82
+ getDataProvider: () => this.dataProvider,
83
+ getFromCache: rid => this.getFromCache(rid),
84
+ getFireAnalyticsEvent: () => this.fireAnalyticsEvent
85
+ });
86
+ this._batchFetcher = new SyncBlockBatchFetcher({
87
+ getSubscriptions: () => this.subscriptions,
88
+ fetchSyncBlocksData: nodes => this.fetchSyncBlocksData(nodes),
89
+ getFireAnalyticsEvent: () => this.fireAnalyticsEvent
90
+ });
91
+ }
69
92
 
70
93
  // The provider might have SSR data cache already set, so we need to update the cache in session memory storage
71
94
  this.setSSRDataInSessionCache((_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getNodeDataCacheKeys());
@@ -78,6 +101,10 @@ export class ReferenceSyncBlockStoreManager {
78
101
  * @param enabled - Whether to enable real-time subscriptions
79
102
  */
80
103
  setRealTimeSubscriptionsEnabled(enabled) {
104
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
105
+ this._subscriptionManager.setRealTimeSubscriptionsEnabled(enabled);
106
+ return;
107
+ }
81
108
  if (this.useRealTimeSubscriptions === enabled) {
82
109
  return;
83
110
  }
@@ -95,6 +122,9 @@ export class ReferenceSyncBlockStoreManager {
95
122
  * Checks if real-time subscriptions are currently enabled.
96
123
  */
97
124
  isRealTimeSubscriptionsEnabled() {
125
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
126
+ return this._subscriptionManager.isRealTimeSubscriptionsEnabled();
127
+ }
98
128
  return this.useRealTimeSubscriptions;
99
129
  }
100
130
 
@@ -103,6 +133,9 @@ export class ReferenceSyncBlockStoreManager {
103
133
  * Used by React components to render subscription components.
104
134
  */
105
135
  getSubscribedResourceIds() {
136
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
137
+ return this._subscriptionManager.getSubscribedResourceIds();
138
+ }
106
139
  return Array.from(this.subscriptions.keys());
107
140
  }
108
141
 
@@ -112,6 +145,9 @@ export class ReferenceSyncBlockStoreManager {
112
145
  * @returns Unsubscribe function to remove the listener
113
146
  */
114
147
  onSubscriptionsChanged(listener) {
148
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
149
+ return this._subscriptionManager.onSubscriptionsChanged(listener);
150
+ }
115
151
  this.subscriptionChangeListeners.add(listener);
116
152
  return () => {
117
153
  this.subscriptionChangeListeners.delete(listener);
@@ -122,6 +158,10 @@ export class ReferenceSyncBlockStoreManager {
122
158
  * Notifies all subscription change listeners.
123
159
  */
124
160
  notifySubscriptionChangeListeners() {
161
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
162
+ this._subscriptionManager.notifySubscriptionChangeListeners();
163
+ return;
164
+ }
125
165
  this.subscriptionChangeListeners.forEach(listener => {
126
166
  try {
127
167
  listener();
@@ -141,6 +181,10 @@ export class ReferenceSyncBlockStoreManager {
141
181
  * @param syncBlockInstance - The updated sync block instance
142
182
  */
143
183
  handleSubscriptionUpdate(syncBlockInstance) {
184
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
185
+ this._subscriptionManager.handleSubscriptionUpdate(syncBlockInstance);
186
+ return;
187
+ }
144
188
  if (!syncBlockInstance.resourceId) {
145
189
  return;
146
190
  }
@@ -249,6 +293,11 @@ export class ReferenceSyncBlockStoreManager {
249
293
  */
250
294
  setupGraphQLSubscription(resourceId) {
251
295
  var _this$dataProvider3;
296
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
297
+ this._subscriptionManager.setupSubscription(resourceId);
298
+ return;
299
+ }
300
+
252
301
  // Don't set up duplicate subscriptions
253
302
  if (this.graphqlSubscriptions.has(resourceId)) {
254
303
  return;
@@ -305,6 +354,10 @@ export class ReferenceSyncBlockStoreManager {
305
354
  * @param resourceId - The resource ID of the block to unsubscribe from
306
355
  */
307
356
  cleanupGraphQLSubscription(resourceId) {
357
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
358
+ this._subscriptionManager.cleanupSubscription(resourceId);
359
+ return;
360
+ }
308
361
  const unsubscribe = this.graphqlSubscriptions.get(resourceId);
309
362
  if (unsubscribe) {
310
363
  unsubscribe();
@@ -316,6 +369,10 @@ export class ReferenceSyncBlockStoreManager {
316
369
  * Sets up GraphQL subscriptions for all currently subscribed blocks.
317
370
  */
318
371
  setupGraphQLSubscriptionsForAllBlocks() {
372
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
373
+ this._subscriptionManager.setupSubscriptionsForAllBlocks();
374
+ return;
375
+ }
319
376
  for (const resourceId of this.subscriptions.keys()) {
320
377
  this.setupGraphQLSubscription(resourceId);
321
378
  }
@@ -325,6 +382,10 @@ export class ReferenceSyncBlockStoreManager {
325
382
  * Cleans up all GraphQL subscriptions.
326
383
  */
327
384
  cleanupAllGraphQLSubscriptions() {
385
+ if (this._subscriptionManager && fg('platform_synced_block_patch_5')) {
386
+ this._subscriptionManager.cleanupAll();
387
+ return;
388
+ }
328
389
  for (const unsubscribe of this.graphqlSubscriptions.values()) {
329
390
  unsubscribe();
330
391
  }
@@ -591,14 +652,13 @@ export class ReferenceSyncBlockStoreManager {
591
652
  hasUnexpectedError = true;
592
653
  }
593
654
  return;
594
- } else {
595
- const callbacks = this.subscriptions.get(syncBlockInstance.resourceId);
596
- const localIds = callbacks ? Object.keys(callbacks) : [];
597
- localIds.forEach(localId => {
598
- var _this$fireAnalyticsEv14, _syncBlockInstance$da2;
599
- (_this$fireAnalyticsEv14 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv14 === void 0 ? void 0 : _this$fireAnalyticsEv14.call(this, fetchSuccessPayload(syncBlockInstance.resourceId, localId, (_syncBlockInstance$da2 = syncBlockInstance.data) === null || _syncBlockInstance$da2 === void 0 ? void 0 : _syncBlockInstance$da2.product));
600
- });
601
655
  }
656
+ const callbacks = this.subscriptions.get(syncBlockInstance.resourceId);
657
+ const localIds = callbacks ? Object.keys(callbacks) : [];
658
+ localIds.forEach(localId => {
659
+ var _this$fireAnalyticsEv14, _syncBlockInstance$da2;
660
+ (_this$fireAnalyticsEv14 = this.fireAnalyticsEvent) === null || _this$fireAnalyticsEv14 === void 0 ? void 0 : _this$fireAnalyticsEv14.call(this, fetchSuccessPayload(syncBlockInstance.resourceId, localId, (_syncBlockInstance$da2 = syncBlockInstance.data) === null || _syncBlockInstance$da2 === void 0 ? void 0 : _syncBlockInstance$da2.product));
661
+ });
602
662
  this.fetchSyncBlockSourceInfo(resolvedSyncBlockInstance.resourceId);
603
663
  });
604
664
  return {
@@ -659,9 +719,17 @@ export class ReferenceSyncBlockStoreManager {
659
719
  deleteFromCache(resourceId) {
660
720
  var _this$dataProvider6;
661
721
  (_this$dataProvider6 = this.dataProvider) === null || _this$dataProvider6 === void 0 ? void 0 : _this$dataProvider6.removeFromCache([resourceId]);
662
- this.providerFactories.delete(resourceId);
722
+ if (this._providerFactoryManager && fg('platform_synced_block_patch_5')) {
723
+ this._providerFactoryManager.deleteFactory(resourceId);
724
+ } else {
725
+ this.providerFactories.delete(resourceId);
726
+ }
663
727
  }
664
728
  debouncedBatchedFetchSyncBlocks(resourceId) {
729
+ if (this._batchFetcher && fg('platform_synced_block_patch_5')) {
730
+ this._batchFetcher.queueFetch(resourceId);
731
+ return;
732
+ }
665
733
  // Only add to pending requests if there are active subscriptions for this resource
666
734
  if (this.subscriptions.has(resourceId) && Object.keys(this.subscriptions.get(resourceId) || {}).length > 0) {
667
735
  this.pendingFetchRequests.add(resourceId);
@@ -714,7 +782,8 @@ export class ReferenceSyncBlockStoreManager {
714
782
  }
715
783
 
716
784
  // Set up GraphQL subscription if real-time subscriptions are enabled
717
- if (this.useRealTimeSubscriptions) {
785
+ const useRealTime = this._subscriptionManager && fg('platform_synced_block_patch_5') ? this._subscriptionManager.shouldUseRealTime() : this.useRealTimeSubscriptions;
786
+ if (useRealTime) {
718
787
  this.setupGraphQLSubscription(resourceId);
719
788
  }
720
789
  return () => {
@@ -825,6 +894,9 @@ export class ReferenceSyncBlockStoreManager {
825
894
  return (_syncBlock$data = syncBlock.data) === null || _syncBlock$data === void 0 ? void 0 : _syncBlock$data.sourceURL;
826
895
  }
827
896
  getProviderFactory(resourceId) {
897
+ if (this._providerFactoryManager && fg('platform_synced_block_patch_5')) {
898
+ return this._providerFactoryManager.getProviderFactory(resourceId);
899
+ }
828
900
  if (!this.dataProvider) {
829
901
  var _this$fireAnalyticsEv16;
830
902
  const error = new Error('Data provider not set');
@@ -871,6 +943,9 @@ export class ReferenceSyncBlockStoreManager {
871
943
  return providerFactory;
872
944
  }
873
945
  getSSRProviders(resourceId) {
946
+ if (this._providerFactoryManager && fg('platform_synced_block_patch_5')) {
947
+ return this._providerFactoryManager.getSSRProviders(resourceId);
948
+ }
874
949
  if (!this.dataProvider) {
875
950
  return null;
876
951
  }
@@ -1077,6 +1152,12 @@ export class ReferenceSyncBlockStoreManager {
1077
1152
  clearTimeout(this.queuedFlushTimeout);
1078
1153
  this.queuedFlushTimeout = undefined;
1079
1154
  }
1155
+ if (fg('platform_synced_block_patch_5')) {
1156
+ var _this$_subscriptionMa, _this$_providerFactor, _this$_batchFetcher;
1157
+ (_this$_subscriptionMa = this._subscriptionManager) === null || _this$_subscriptionMa === void 0 ? void 0 : _this$_subscriptionMa.destroy();
1158
+ (_this$_providerFactor = this._providerFactoryManager) === null || _this$_providerFactor === void 0 ? void 0 : _this$_providerFactor.destroy();
1159
+ (_this$_batchFetcher = this._batchFetcher) === null || _this$_batchFetcher === void 0 ? void 0 : _this$_batchFetcher.destroy();
1160
+ }
1080
1161
 
1081
1162
  // Clean up all GraphQL subscriptions first
1082
1163
  this.cleanupAllGraphQLSubscriptions();
@@ -1105,5 +1186,8 @@ export class ReferenceSyncBlockStoreManager {
1105
1186
  reason: 'editorDestroyed'
1106
1187
  });
1107
1188
  this.fireAnalyticsEvent = undefined;
1189
+ if (fg('platform_synced_block_patch_5')) {
1190
+ syncBlockInMemorySessionCache.clear();
1191
+ }
1108
1192
  }
1109
1193
  }
@@ -1,5 +1,7 @@
1
1
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import isEqual from 'lodash/isEqual';
2
3
  import { logException } from '@atlaskit/editor-common/monitoring';
4
+ import { fg } from '@atlaskit/platform-feature-flags';
3
5
  import { SyncBlockError } from '../common/types';
4
6
  import { updateErrorPayload, createErrorPayload, deleteErrorPayload, updateCacheErrorPayload, getSourceInfoErrorPayload, updateSuccessPayload, createSuccessPayload, deleteSuccessPayload, fetchReferencesErrorPayload } from '../utils/errorHandling';
5
7
  import { getCreateSourceExperience, getDeleteSourceExperience, getSaveSourceExperience, getFetchSourceInfoExperience } from '../utils/experienceTracking';
@@ -11,6 +13,7 @@ import { convertSyncBlockPMNodeToSyncBlockData } from '../utils/utils';
11
13
  // Ensures consistency between local and remote state, and can be used in both editor and renderer contexts.
12
14
  export class SourceSyncBlockStoreManager {
13
15
  constructor(dataProvider) {
16
+ _defineProperty(this, "hasReceivedContentChange", false);
14
17
  _defineProperty(this, "setPendingDeletion", (Ids, value) => {
15
18
  const syncBlock = this.syncBlockCache.get(Ids.resourceId);
16
19
  if (syncBlock) {
@@ -49,6 +52,12 @@ export class SourceSyncBlockStoreManager {
49
52
  throw new Error('Local ID or resource ID is not set');
50
53
  }
51
54
  const syncBlockData = convertSyncBlockPMNodeToSyncBlockData(syncBlockNode);
55
+ if (fg('platform_synced_block_patch_5')) {
56
+ const cachedBlock = this.syncBlockCache.get(resourceId);
57
+ if (cachedBlock && !isEqual(syncBlockData.content, cachedBlock.content)) {
58
+ this.hasReceivedContentChange = true;
59
+ }
60
+ }
52
61
  this.syncBlockCache.set(resourceId, {
53
62
  ...syncBlockData,
54
63
  isDirty: true
@@ -146,6 +155,9 @@ export class SourceSyncBlockStoreManager {
146
155
  return false;
147
156
  }
148
157
  }
158
+ hasUnsavedChanges() {
159
+ return this.hasReceivedContentChange && Array.from(this.syncBlockCache.values()).some(syncBlockData => syncBlockData.isDirty);
160
+ }
149
161
  isPendingCreation(resourceId) {
150
162
  return this.creationCompletionCallbacks.has(resourceId);
151
163
  }
@@ -0,0 +1,56 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ import rafSchedule from 'raf-schd';
3
+ import { logException } from '@atlaskit/editor-common/monitoring';
4
+ import { fetchErrorPayload } from '../utils/errorHandling';
5
+ import { createSyncBlockNode } from '../utils/utils';
6
+ /**
7
+ * Handles debounced batch-fetching of sync block data via `raf-schd`.
8
+ * Accumulates resource IDs and flushes them in a single fetch per
9
+ * animation frame.
10
+ */
11
+ export class SyncBlockBatchFetcher {
12
+ constructor(deps) {
13
+ _defineProperty(this, "pendingFetchRequests", new Set());
14
+ this.deps = deps;
15
+ this.scheduledBatchFetch = rafSchedule(() => {
16
+ if (this.pendingFetchRequests.size === 0) {
17
+ return;
18
+ }
19
+ const resourceIds = Array.from(this.pendingFetchRequests);
20
+ const syncBlockNodes = resourceIds.map(resId => {
21
+ const subscriptions = this.deps.getSubscriptions().get(resId) || {};
22
+ const firstLocalId = Object.keys(subscriptions)[0] || '';
23
+ return createSyncBlockNode(firstLocalId, resId);
24
+ });
25
+ this.pendingFetchRequests.clear();
26
+ this.deps.fetchSyncBlocksData(syncBlockNodes).catch(error => {
27
+ logException(error, {
28
+ location: 'editor-synced-block-provider/syncBlockBatchFetcher/batchedFetchSyncBlocks'
29
+ });
30
+ resourceIds.forEach(resId => {
31
+ var _this$deps$getFireAna;
32
+ (_this$deps$getFireAna = this.deps.getFireAnalyticsEvent()) === null || _this$deps$getFireAna === void 0 ? void 0 : _this$deps$getFireAna(fetchErrorPayload(error.message, resId));
33
+ });
34
+ });
35
+ });
36
+ }
37
+ queueFetch(resourceId) {
38
+ const subscriptions = this.deps.getSubscriptions();
39
+ if (subscriptions.has(resourceId) && Object.keys(subscriptions.get(resourceId) || {}).length > 0) {
40
+ this.pendingFetchRequests.add(resourceId);
41
+ this.scheduledBatchFetch();
42
+ } else {
43
+ this.pendingFetchRequests.delete(resourceId);
44
+ }
45
+ }
46
+ cancel() {
47
+ this.scheduledBatchFetch.cancel();
48
+ }
49
+ clearPending() {
50
+ this.pendingFetchRequests.clear();
51
+ }
52
+ destroy() {
53
+ this.cancel();
54
+ this.clearPending();
55
+ }
56
+ }
@@ -13,11 +13,26 @@ import _defineProperty from "@babel/runtime/helpers/defineProperty";
13
13
  * (least-recently-used) entries are evicted first.
14
14
  */
15
15
  export class SyncBlockInMemorySessionCache {
16
+ /**
17
+ * Maximum total size of all cached values, measured in **UTF-16 code
18
+ * units** (i.e. `String.prototype.length`), not bytes. For ASCII-only
19
+ * content the two are equivalent; for content with characters outside
20
+ * the BMP each surrogate pair counts as 2.
21
+ */
22
+
16
23
  constructor(maxSize = 5 * 1024 * 1024) {
17
24
  _defineProperty(this, "store", new Map());
18
25
  _defineProperty(this, "currentSize", 0);
19
26
  this.maxSize = maxSize;
20
27
  }
28
+
29
+ /**
30
+ * Retrieves a cached value by key.
31
+ *
32
+ * **Side-effect:** promotes the entry to the most-recently-used
33
+ * position by re-inserting it at the end of the underlying Map's
34
+ * iteration order.
35
+ */
21
36
  getItem(key) {
22
37
  const value = this.store.get(key);
23
38
  if (value === undefined) {
@@ -53,5 +68,14 @@ export class SyncBlockInMemorySessionCache {
53
68
  this.store.delete(key);
54
69
  }
55
70
  }
71
+
72
+ /**
73
+ * Removes all entries from the cache and resets the tracked size to zero.
74
+ * Useful for cleaning up the singleton on SPA navigation boundaries.
75
+ */
76
+ clear() {
77
+ this.store.clear();
78
+ this.currentSize = 0;
79
+ }
56
80
  }
57
81
  export const syncBlockInMemorySessionCache = new SyncBlockInMemorySessionCache();