@atlaskit/editor-synced-block-provider 3.30.2 → 3.30.3

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/editor-synced-block-provider
2
2
 
3
+ ## 3.30.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`5ddfc9ed0352f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/5ddfc9ed0352f) -
8
+ Switched from browser session storage to in memory session storage
9
+ - Updated dependencies
10
+
3
11
  ## 3.30.2
4
12
 
5
13
  ### Patch Changes
package/dist/cjs/index.js CHANGED
@@ -21,6 +21,12 @@ Object.defineProperty(exports, "SyncBlockError", {
21
21
  return _types.SyncBlockError;
22
22
  }
23
23
  });
24
+ Object.defineProperty(exports, "SyncBlockInMemorySessionCache", {
25
+ enumerable: true,
26
+ get: function get() {
27
+ return _syncBlockInMemorySessionCache.SyncBlockInMemorySessionCache;
28
+ }
29
+ });
24
30
  Object.defineProperty(exports, "SyncBlockStoreManager", {
25
31
  enumerable: true,
26
32
  get: function get() {
@@ -189,6 +195,12 @@ Object.defineProperty(exports, "resolveSyncBlockInstance", {
189
195
  return _resolveSyncBlockInstance.resolveSyncBlockInstance;
190
196
  }
191
197
  });
198
+ Object.defineProperty(exports, "syncBlockInMemorySessionCache", {
199
+ enumerable: true,
200
+ get: function get() {
201
+ return _syncBlockInMemorySessionCache.syncBlockInMemorySessionCache;
202
+ }
203
+ });
192
204
  Object.defineProperty(exports, "useFetchSyncBlockData", {
193
205
  enumerable: true,
194
206
  get: function get() {
@@ -245,6 +257,7 @@ var _blockServiceAPI = require("./providers/block-service/blockServiceAPI");
245
257
  var _sourceInfo = require("./clients/confluence/sourceInfo");
246
258
  var _syncBlockProvider = require("./providers/syncBlockProvider");
247
259
  var _referenceSyncBlockStoreManager = require("./store-manager/referenceSyncBlockStoreManager");
260
+ var _syncBlockInMemorySessionCache = require("./store-manager/syncBlockInMemorySessionCache");
248
261
  var _syncBlockStoreManager = require("./store-manager/syncBlockStoreManager");
249
262
  var _resolveSyncBlockInstance = require("./utils/resolveSyncBlockInstance");
250
263
  var _resourceId = require("./utils/resourceId");
@@ -22,12 +22,13 @@ var _experienceTracking = require("../utils/experienceTracking");
22
22
  var _resolveSyncBlockInstance = require("../utils/resolveSyncBlockInstance");
23
23
  var _resourceId = require("../utils/resourceId");
24
24
  var _utils = require("../utils/utils");
25
+ var _syncBlockInMemorySessionCache = require("./syncBlockInMemorySessionCache");
25
26
  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; }
26
27
  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; }
27
28
  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; } } }; }
28
29
  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; } }
29
30
  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; }
30
- var SESSION_STORAGE_KEY_PREFIX = 'sync-block-data-';
31
+ var CACHE_KEY_PREFIX = 'sync-block-data-';
31
32
 
32
33
  // A store manager responsible for the lifecycle and state management of reference sync blocks in an editor instance.
33
34
  // Designed to manage local in-memory state and synchronize with an external data provider.
@@ -85,8 +86,8 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
85
86
  this.subscriptionChangeListeners = new Set();
86
87
  this.newlyAddedSyncBlocks = new Set();
87
88
 
88
- // The provider might have SSR data cache already set, so we need to update the cache in session storage
89
- this.setSSRDataInSessionStorage((_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getNodeDataCacheKeys());
89
+ // The provider might have SSR data cache already set, so we need to update the cache in session memory storage
90
+ this.setSSRDataInSessionCache((_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getNodeDataCacheKeys());
90
91
  }
91
92
 
92
93
  /**
@@ -225,52 +226,32 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
225
226
  value: function getInitialSyncBlockData(resourceId) {
226
227
  var _this$dataProvider2;
227
228
  var syncBlockNode = (0, _utils.createSyncBlockNode)('', resourceId);
228
- var data = (_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;
229
- if (data) {
230
- return data;
229
+ 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;
230
+ if (providerData) {
231
+ return providerData;
231
232
  }
232
- if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_3')) {
233
- var sessionData = this.getSyncBlockDataFromSessionStorage(resourceId);
234
- if (sessionData) {
235
- return sessionData;
236
- }
237
- }
238
- return undefined;
233
+ return this.getFromSessionCache(resourceId);
239
234
  }
240
235
  }, {
241
- key: "updateCacheInSessionStorage",
242
- value: function updateCacheInSessionStorage(resourceId) {
243
- try {
244
- var latestData = this.getFromCache(resourceId);
245
- if (latestData) {
246
- sessionStorage.setItem("".concat(SESSION_STORAGE_KEY_PREFIX).concat(resourceId), JSON.stringify(latestData));
247
- }
248
- } catch (error) {
249
- (0, _monitoring.logException)(error, {
250
- location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/updateCacheInSessionStorage'
251
- });
236
+ key: "updateSessionCache",
237
+ value: function updateSessionCache(resourceId) {
238
+ var latestData = this.getFromCache(resourceId);
239
+ if (latestData) {
240
+ _syncBlockInMemorySessionCache.syncBlockInMemorySessionCache.setItem("".concat(CACHE_KEY_PREFIX).concat(resourceId), JSON.stringify(latestData));
252
241
  }
253
242
  }
254
243
  }, {
255
- key: "getSyncBlockDataFromSessionStorage",
256
- value: function getSyncBlockDataFromSessionStorage(resourceId) {
257
- var sessionData = null;
258
- try {
259
- sessionData = sessionStorage.getItem("".concat(SESSION_STORAGE_KEY_PREFIX).concat(resourceId));
260
- } catch (error) {
261
- (0, _monitoring.logException)(error, {
262
- location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getSyncBlockDataFromSessionStorage'
263
- });
264
- return undefined;
265
- }
266
- if (!sessionData) {
267
- return undefined;
268
- }
244
+ key: "getFromSessionCache",
245
+ value: function getFromSessionCache(resourceId) {
269
246
  try {
270
- return JSON.parse(sessionData);
247
+ var raw = _syncBlockInMemorySessionCache.syncBlockInMemorySessionCache.getItem("".concat(CACHE_KEY_PREFIX).concat(resourceId));
248
+ if (!raw) {
249
+ return undefined;
250
+ }
251
+ return JSON.parse(raw);
271
252
  } catch (error) {
272
253
  (0, _monitoring.logException)(error, {
273
- location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getSyncBlockDataFromSessionStorage'
254
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getFromSessionCache'
274
255
  });
275
256
  return undefined;
276
257
  }
@@ -846,7 +827,7 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
846
827
  });
847
828
  }
848
829
  if ((0, _platformFeatureFlags.fg)('platform_synced_block_patch_3')) {
849
- this.updateCacheInSessionStorage(resourceId);
830
+ this.updateSessionCache(resourceId);
850
831
  }
851
832
  }
852
833
  }
@@ -891,14 +872,14 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
891
872
  }
892
873
  }
893
874
  }, {
894
- key: "setSSRDataInSessionStorage",
895
- value: function setSSRDataInSessionStorage(resourceIds) {
875
+ key: "setSSRDataInSessionCache",
876
+ value: function setSSRDataInSessionCache(resourceIds) {
896
877
  var _this0 = this;
897
878
  if (!resourceIds || resourceIds.length === 0) {
898
879
  return;
899
880
  }
900
881
  resourceIds.forEach(function (resourceId) {
901
- _this0.updateCacheInSessionStorage(resourceId);
882
+ _this0.updateSessionCache(resourceId);
902
883
  });
903
884
  }
904
885
  }, {
@@ -929,8 +910,6 @@ var ReferenceSyncBlockStoreManager = exports.ReferenceSyncBlockStoreManager = /*
929
910
  this.notifySubscriptionChangeListeners();
930
911
  }
931
912
  var syncBlockNode = (0, _utils.createSyncBlockNode)(localId, resourceId);
932
-
933
- // call the callback immediately if we have cached data
934
913
  var cachedData = (_this$dataProvider7 = this.dataProvider) === null || _this$dataProvider7 === void 0 || (_this$dataProvider7 = _this$dataProvider7.getNodeDataFromCache(syncBlockNode)) === null || _this$dataProvider7 === void 0 ? void 0 : _this$dataProvider7.data;
935
914
  if (cachedData) {
936
915
  callback(cachedData);
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.syncBlockInMemorySessionCache = exports.SyncBlockInMemorySessionCache = 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
+ /**
12
+ * In-memory session cache for sync block data with size-based LRU eviction.
13
+ *
14
+ * Backed by a plain Map so that potentially private ADF content is never
15
+ * written to any browser-persistent storage (sessionStorage, localStorage,
16
+ * IndexedDB). The module-level singleton survives SPA transitions (no full
17
+ * page reload) and is naturally cleared on hard navigation or tab close.
18
+ *
19
+ * Uses JavaScript Map's insertion-order guarantee to implement LRU:
20
+ * on every read or write the accessed entry is moved to the end of the
21
+ * iteration order; when total cached size exceeds `maxSize`, the oldest
22
+ * (least-recently-used) entries are evicted first.
23
+ */
24
+ var SyncBlockInMemorySessionCache = exports.SyncBlockInMemorySessionCache = /*#__PURE__*/function () {
25
+ function SyncBlockInMemorySessionCache() {
26
+ var maxSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 5 * 1024 * 1024;
27
+ (0, _classCallCheck2.default)(this, SyncBlockInMemorySessionCache);
28
+ (0, _defineProperty2.default)(this, "store", new Map());
29
+ (0, _defineProperty2.default)(this, "currentSize", 0);
30
+ this.maxSize = maxSize;
31
+ }
32
+ return (0, _createClass2.default)(SyncBlockInMemorySessionCache, [{
33
+ key: "getItem",
34
+ value: function getItem(key) {
35
+ var value = this.store.get(key);
36
+ if (value === undefined) {
37
+ return null;
38
+ }
39
+ this.store.delete(key);
40
+ this.store.set(key, value);
41
+ return value;
42
+ }
43
+ }, {
44
+ key: "setItem",
45
+ value: function setItem(key, value) {
46
+ var existing = this.store.get(key);
47
+ if (existing !== undefined) {
48
+ this.currentSize -= existing.length;
49
+ this.store.delete(key);
50
+ }
51
+ this.store.set(key, value);
52
+ this.currentSize += value.length;
53
+ while (this.currentSize > this.maxSize && this.store.size > 1) {
54
+ var oldestKey = this.store.keys().next().value;
55
+ if (oldestKey !== undefined) {
56
+ var oldestValue = this.store.get(oldestKey);
57
+ if (oldestValue !== undefined) {
58
+ this.currentSize -= oldestValue.length;
59
+ }
60
+ this.store.delete(oldestKey);
61
+ }
62
+ }
63
+ }
64
+ }, {
65
+ key: "removeItem",
66
+ value: function removeItem(key) {
67
+ var value = this.store.get(key);
68
+ if (value !== undefined) {
69
+ this.currentSize -= value.length;
70
+ this.store.delete(key);
71
+ }
72
+ }
73
+ }]);
74
+ }();
75
+ var syncBlockInMemorySessionCache = exports.syncBlockInMemorySessionCache = new SyncBlockInMemorySessionCache();
@@ -21,6 +21,7 @@ export { fetchConfluencePageInfo } from './clients/confluence/sourceInfo';
21
21
  export { SyncedBlockProvider, useMemoizedSyncedBlockProvider } from './providers/syncBlockProvider';
22
22
  // store managers
23
23
  export { ReferenceSyncBlockStoreManager } from './store-manager/referenceSyncBlockStoreManager';
24
+ export { SyncBlockInMemorySessionCache, syncBlockInMemorySessionCache } from './store-manager/syncBlockInMemorySessionCache';
24
25
  export { SyncBlockStoreManager, useMemoizedSyncBlockStoreManager } from './store-manager/syncBlockStoreManager';
25
26
 
26
27
  // utils
@@ -10,7 +10,8 @@ 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
- const SESSION_STORAGE_KEY_PREFIX = 'sync-block-data-';
13
+ import { syncBlockInMemorySessionCache } from './syncBlockInMemorySessionCache';
14
+ const CACHE_KEY_PREFIX = 'sync-block-data-';
14
15
 
15
16
  // A store manager responsible for the lifecycle and state management of reference sync blocks in an editor instance.
16
17
  // Designed to manage local in-memory state and synchronize with an external data provider.
@@ -66,8 +67,8 @@ export class ReferenceSyncBlockStoreManager {
66
67
  this.subscriptionChangeListeners = new Set();
67
68
  this.newlyAddedSyncBlocks = new Set();
68
69
 
69
- // The provider might have SSR data cache already set, so we need to update the cache in session storage
70
- this.setSSRDataInSessionStorage((_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getNodeDataCacheKeys());
70
+ // The provider might have SSR data cache already set, so we need to update the cache in session memory storage
71
+ this.setSSRDataInSessionCache((_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getNodeDataCacheKeys());
71
72
  }
72
73
 
73
74
  /**
@@ -180,48 +181,28 @@ export class ReferenceSyncBlockStoreManager {
180
181
  getInitialSyncBlockData(resourceId) {
181
182
  var _this$dataProvider2, _this$dataProvider2$g;
182
183
  const syncBlockNode = createSyncBlockNode('', resourceId);
183
- const data = (_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;
184
- if (data) {
185
- return data;
184
+ 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;
185
+ if (providerData) {
186
+ return providerData;
186
187
  }
187
- if (fg('platform_synced_block_patch_3')) {
188
- const sessionData = this.getSyncBlockDataFromSessionStorage(resourceId);
189
- if (sessionData) {
190
- return sessionData;
191
- }
192
- }
193
- return undefined;
188
+ return this.getFromSessionCache(resourceId);
194
189
  }
195
- updateCacheInSessionStorage(resourceId) {
196
- try {
197
- const latestData = this.getFromCache(resourceId);
198
- if (latestData) {
199
- sessionStorage.setItem(`${SESSION_STORAGE_KEY_PREFIX}${resourceId}`, JSON.stringify(latestData));
200
- }
201
- } catch (error) {
202
- logException(error, {
203
- location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/updateCacheInSessionStorage'
204
- });
190
+ updateSessionCache(resourceId) {
191
+ const latestData = this.getFromCache(resourceId);
192
+ if (latestData) {
193
+ syncBlockInMemorySessionCache.setItem(`${CACHE_KEY_PREFIX}${resourceId}`, JSON.stringify(latestData));
205
194
  }
206
195
  }
207
- getSyncBlockDataFromSessionStorage(resourceId) {
208
- let sessionData = null;
209
- try {
210
- sessionData = sessionStorage.getItem(`${SESSION_STORAGE_KEY_PREFIX}${resourceId}`);
211
- } catch (error) {
212
- logException(error, {
213
- location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getSyncBlockDataFromSessionStorage'
214
- });
215
- return undefined;
216
- }
217
- if (!sessionData) {
218
- return undefined;
219
- }
196
+ getFromSessionCache(resourceId) {
220
197
  try {
221
- return JSON.parse(sessionData);
198
+ const raw = syncBlockInMemorySessionCache.getItem(`${CACHE_KEY_PREFIX}${resourceId}`);
199
+ if (!raw) {
200
+ return undefined;
201
+ }
202
+ return JSON.parse(raw);
222
203
  } catch (error) {
223
204
  logException(error, {
224
- location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getSyncBlockDataFromSessionStorage'
205
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getFromSessionCache'
225
206
  });
226
207
  return undefined;
227
208
  }
@@ -655,7 +636,7 @@ export class ReferenceSyncBlockStoreManager {
655
636
  });
656
637
  }
657
638
  if (fg('platform_synced_block_patch_3')) {
658
- this.updateCacheInSessionStorage(resourceId);
639
+ this.updateSessionCache(resourceId);
659
640
  }
660
641
  }
661
642
  }
@@ -691,12 +672,12 @@ export class ReferenceSyncBlockStoreManager {
691
672
  this.scheduledBatchFetch();
692
673
  }
693
674
  }
694
- setSSRDataInSessionStorage(resourceIds) {
675
+ setSSRDataInSessionCache(resourceIds) {
695
676
  if (!resourceIds || resourceIds.length === 0) {
696
677
  return;
697
678
  }
698
679
  resourceIds.forEach(resourceId => {
699
- this.updateCacheInSessionStorage(resourceId);
680
+ this.updateSessionCache(resourceId);
700
681
  });
701
682
  }
702
683
  subscribeToSyncBlock(resourceId, localId, callback) {
@@ -727,8 +708,6 @@ export class ReferenceSyncBlockStoreManager {
727
708
  this.notifySubscriptionChangeListeners();
728
709
  }
729
710
  const syncBlockNode = createSyncBlockNode(localId, resourceId);
730
-
731
- // call the callback immediately if we have cached data
732
711
  const cachedData = (_this$dataProvider7 = this.dataProvider) === null || _this$dataProvider7 === void 0 ? void 0 : (_this$dataProvider7$g = _this$dataProvider7.getNodeDataFromCache(syncBlockNode)) === null || _this$dataProvider7$g === void 0 ? void 0 : _this$dataProvider7$g.data;
733
712
  if (cachedData) {
734
713
  callback(cachedData);
@@ -0,0 +1,57 @@
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ /**
3
+ * In-memory session cache for sync block data with size-based LRU eviction.
4
+ *
5
+ * Backed by a plain Map so that potentially private ADF content is never
6
+ * written to any browser-persistent storage (sessionStorage, localStorage,
7
+ * IndexedDB). The module-level singleton survives SPA transitions (no full
8
+ * page reload) and is naturally cleared on hard navigation or tab close.
9
+ *
10
+ * Uses JavaScript Map's insertion-order guarantee to implement LRU:
11
+ * on every read or write the accessed entry is moved to the end of the
12
+ * iteration order; when total cached size exceeds `maxSize`, the oldest
13
+ * (least-recently-used) entries are evicted first.
14
+ */
15
+ export class SyncBlockInMemorySessionCache {
16
+ constructor(maxSize = 5 * 1024 * 1024) {
17
+ _defineProperty(this, "store", new Map());
18
+ _defineProperty(this, "currentSize", 0);
19
+ this.maxSize = maxSize;
20
+ }
21
+ getItem(key) {
22
+ const value = this.store.get(key);
23
+ if (value === undefined) {
24
+ return null;
25
+ }
26
+ this.store.delete(key);
27
+ this.store.set(key, value);
28
+ return value;
29
+ }
30
+ setItem(key, value) {
31
+ const existing = this.store.get(key);
32
+ if (existing !== undefined) {
33
+ this.currentSize -= existing.length;
34
+ this.store.delete(key);
35
+ }
36
+ this.store.set(key, value);
37
+ this.currentSize += value.length;
38
+ while (this.currentSize > this.maxSize && this.store.size > 1) {
39
+ const oldestKey = this.store.keys().next().value;
40
+ if (oldestKey !== undefined) {
41
+ const oldestValue = this.store.get(oldestKey);
42
+ if (oldestValue !== undefined) {
43
+ this.currentSize -= oldestValue.length;
44
+ }
45
+ this.store.delete(oldestKey);
46
+ }
47
+ }
48
+ }
49
+ removeItem(key) {
50
+ const value = this.store.get(key);
51
+ if (value !== undefined) {
52
+ this.currentSize -= value.length;
53
+ this.store.delete(key);
54
+ }
55
+ }
56
+ }
57
+ export const syncBlockInMemorySessionCache = new SyncBlockInMemorySessionCache();
package/dist/esm/index.js CHANGED
@@ -21,6 +21,7 @@ export { fetchConfluencePageInfo } from './clients/confluence/sourceInfo';
21
21
  export { SyncedBlockProvider, useMemoizedSyncedBlockProvider } from './providers/syncBlockProvider';
22
22
  // store managers
23
23
  export { ReferenceSyncBlockStoreManager } from './store-manager/referenceSyncBlockStoreManager';
24
+ export { SyncBlockInMemorySessionCache, syncBlockInMemorySessionCache } from './store-manager/syncBlockInMemorySessionCache';
24
25
  export { SyncBlockStoreManager, useMemoizedSyncBlockStoreManager } from './store-manager/syncBlockStoreManager';
25
26
 
26
27
  // utils
@@ -20,7 +20,8 @@ import { getFetchExperience, getFetchSourceInfoExperience, getSaveReferenceExper
20
20
  import { resolveSyncBlockInstance } from '../utils/resolveSyncBlockInstance';
21
21
  import { parseResourceId } from '../utils/resourceId';
22
22
  import { createSyncBlockNode } from '../utils/utils';
23
- var SESSION_STORAGE_KEY_PREFIX = 'sync-block-data-';
23
+ import { syncBlockInMemorySessionCache } from './syncBlockInMemorySessionCache';
24
+ var CACHE_KEY_PREFIX = 'sync-block-data-';
24
25
 
25
26
  // A store manager responsible for the lifecycle and state management of reference sync blocks in an editor instance.
26
27
  // Designed to manage local in-memory state and synchronize with an external data provider.
@@ -78,8 +79,8 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
78
79
  this.subscriptionChangeListeners = new Set();
79
80
  this.newlyAddedSyncBlocks = new Set();
80
81
 
81
- // The provider might have SSR data cache already set, so we need to update the cache in session storage
82
- this.setSSRDataInSessionStorage((_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getNodeDataCacheKeys());
82
+ // The provider might have SSR data cache already set, so we need to update the cache in session memory storage
83
+ this.setSSRDataInSessionCache((_this$dataProvider = this.dataProvider) === null || _this$dataProvider === void 0 ? void 0 : _this$dataProvider.getNodeDataCacheKeys());
83
84
  }
84
85
 
85
86
  /**
@@ -218,52 +219,32 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
218
219
  value: function getInitialSyncBlockData(resourceId) {
219
220
  var _this$dataProvider2;
220
221
  var syncBlockNode = createSyncBlockNode('', resourceId);
221
- var data = (_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;
222
- if (data) {
223
- return data;
222
+ 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;
223
+ if (providerData) {
224
+ return providerData;
224
225
  }
225
- if (fg('platform_synced_block_patch_3')) {
226
- var sessionData = this.getSyncBlockDataFromSessionStorage(resourceId);
227
- if (sessionData) {
228
- return sessionData;
229
- }
230
- }
231
- return undefined;
226
+ return this.getFromSessionCache(resourceId);
232
227
  }
233
228
  }, {
234
- key: "updateCacheInSessionStorage",
235
- value: function updateCacheInSessionStorage(resourceId) {
236
- try {
237
- var latestData = this.getFromCache(resourceId);
238
- if (latestData) {
239
- sessionStorage.setItem("".concat(SESSION_STORAGE_KEY_PREFIX).concat(resourceId), JSON.stringify(latestData));
240
- }
241
- } catch (error) {
242
- logException(error, {
243
- location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/updateCacheInSessionStorage'
244
- });
229
+ key: "updateSessionCache",
230
+ value: function updateSessionCache(resourceId) {
231
+ var latestData = this.getFromCache(resourceId);
232
+ if (latestData) {
233
+ syncBlockInMemorySessionCache.setItem("".concat(CACHE_KEY_PREFIX).concat(resourceId), JSON.stringify(latestData));
245
234
  }
246
235
  }
247
236
  }, {
248
- key: "getSyncBlockDataFromSessionStorage",
249
- value: function getSyncBlockDataFromSessionStorage(resourceId) {
250
- var sessionData = null;
251
- try {
252
- sessionData = sessionStorage.getItem("".concat(SESSION_STORAGE_KEY_PREFIX).concat(resourceId));
253
- } catch (error) {
254
- logException(error, {
255
- location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getSyncBlockDataFromSessionStorage'
256
- });
257
- return undefined;
258
- }
259
- if (!sessionData) {
260
- return undefined;
261
- }
237
+ key: "getFromSessionCache",
238
+ value: function getFromSessionCache(resourceId) {
262
239
  try {
263
- return JSON.parse(sessionData);
240
+ var raw = syncBlockInMemorySessionCache.getItem("".concat(CACHE_KEY_PREFIX).concat(resourceId));
241
+ if (!raw) {
242
+ return undefined;
243
+ }
244
+ return JSON.parse(raw);
264
245
  } catch (error) {
265
246
  logException(error, {
266
- location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getSyncBlockDataFromSessionStorage'
247
+ location: 'editor-synced-block-provider/referenceSyncBlockStoreManager/getFromSessionCache'
267
248
  });
268
249
  return undefined;
269
250
  }
@@ -839,7 +820,7 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
839
820
  });
840
821
  }
841
822
  if (fg('platform_synced_block_patch_3')) {
842
- this.updateCacheInSessionStorage(resourceId);
823
+ this.updateSessionCache(resourceId);
843
824
  }
844
825
  }
845
826
  }
@@ -884,14 +865,14 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
884
865
  }
885
866
  }
886
867
  }, {
887
- key: "setSSRDataInSessionStorage",
888
- value: function setSSRDataInSessionStorage(resourceIds) {
868
+ key: "setSSRDataInSessionCache",
869
+ value: function setSSRDataInSessionCache(resourceIds) {
889
870
  var _this0 = this;
890
871
  if (!resourceIds || resourceIds.length === 0) {
891
872
  return;
892
873
  }
893
874
  resourceIds.forEach(function (resourceId) {
894
- _this0.updateCacheInSessionStorage(resourceId);
875
+ _this0.updateSessionCache(resourceId);
895
876
  });
896
877
  }
897
878
  }, {
@@ -922,8 +903,6 @@ export var ReferenceSyncBlockStoreManager = /*#__PURE__*/function () {
922
903
  this.notifySubscriptionChangeListeners();
923
904
  }
924
905
  var syncBlockNode = createSyncBlockNode(localId, resourceId);
925
-
926
- // call the callback immediately if we have cached data
927
906
  var cachedData = (_this$dataProvider7 = this.dataProvider) === null || _this$dataProvider7 === void 0 || (_this$dataProvider7 = _this$dataProvider7.getNodeDataFromCache(syncBlockNode)) === null || _this$dataProvider7 === void 0 ? void 0 : _this$dataProvider7.data;
928
907
  if (cachedData) {
929
908
  callback(cachedData);
@@ -0,0 +1,68 @@
1
+ import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
2
+ import _createClass from "@babel/runtime/helpers/createClass";
3
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
+ /**
5
+ * In-memory session cache for sync block data with size-based LRU eviction.
6
+ *
7
+ * Backed by a plain Map so that potentially private ADF content is never
8
+ * written to any browser-persistent storage (sessionStorage, localStorage,
9
+ * IndexedDB). The module-level singleton survives SPA transitions (no full
10
+ * page reload) and is naturally cleared on hard navigation or tab close.
11
+ *
12
+ * Uses JavaScript Map's insertion-order guarantee to implement LRU:
13
+ * on every read or write the accessed entry is moved to the end of the
14
+ * iteration order; when total cached size exceeds `maxSize`, the oldest
15
+ * (least-recently-used) entries are evicted first.
16
+ */
17
+ export var SyncBlockInMemorySessionCache = /*#__PURE__*/function () {
18
+ function SyncBlockInMemorySessionCache() {
19
+ var maxSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 5 * 1024 * 1024;
20
+ _classCallCheck(this, SyncBlockInMemorySessionCache);
21
+ _defineProperty(this, "store", new Map());
22
+ _defineProperty(this, "currentSize", 0);
23
+ this.maxSize = maxSize;
24
+ }
25
+ return _createClass(SyncBlockInMemorySessionCache, [{
26
+ key: "getItem",
27
+ value: function getItem(key) {
28
+ var value = this.store.get(key);
29
+ if (value === undefined) {
30
+ return null;
31
+ }
32
+ this.store.delete(key);
33
+ this.store.set(key, value);
34
+ return value;
35
+ }
36
+ }, {
37
+ key: "setItem",
38
+ value: function setItem(key, value) {
39
+ var existing = this.store.get(key);
40
+ if (existing !== undefined) {
41
+ this.currentSize -= existing.length;
42
+ this.store.delete(key);
43
+ }
44
+ this.store.set(key, value);
45
+ this.currentSize += value.length;
46
+ while (this.currentSize > this.maxSize && this.store.size > 1) {
47
+ var oldestKey = this.store.keys().next().value;
48
+ if (oldestKey !== undefined) {
49
+ var oldestValue = this.store.get(oldestKey);
50
+ if (oldestValue !== undefined) {
51
+ this.currentSize -= oldestValue.length;
52
+ }
53
+ this.store.delete(oldestKey);
54
+ }
55
+ }
56
+ }
57
+ }, {
58
+ key: "removeItem",
59
+ value: function removeItem(key) {
60
+ var value = this.store.get(key);
61
+ if (value !== undefined) {
62
+ this.currentSize -= value.length;
63
+ this.store.delete(key);
64
+ }
65
+ }
66
+ }]);
67
+ }();
68
+ export var syncBlockInMemorySessionCache = new SyncBlockInMemorySessionCache();
@@ -15,6 +15,7 @@ export { fetchConfluencePageInfo } from './clients/confluence/sourceInfo';
15
15
  export { SyncedBlockProvider, useMemoizedSyncedBlockProvider } from './providers/syncBlockProvider';
16
16
  export type { ADFFetchProvider, ADFWriteProvider, BlockNodeIdentifiers, BlockSubscriptionErrorCallback, BlockUpdateCallback, SyncBlockDataProviderInterface, SyncBlockInstance, MediaEmojiProviderOptions, SyncedBlockRendererProviderOptions, SyncBlockRendererProviderCreator, SyncedBlockRendererDataProviders, Unsubscribe, UpdateReferenceSyncBlockResult, WriteSyncBlockResult, SyncBlockParentInfo, SyncBlockSourceInfo, } from './providers/types';
17
17
  export { ReferenceSyncBlockStoreManager } from './store-manager/referenceSyncBlockStoreManager';
18
+ export { SyncBlockInMemorySessionCache, syncBlockInMemorySessionCache, } from './store-manager/syncBlockInMemorySessionCache';
18
19
  export { SyncBlockStoreManager, useMemoizedSyncBlockStoreManager, } from './store-manager/syncBlockStoreManager';
19
20
  export { resolveSyncBlockInstance } from './utils/resolveSyncBlockInstance';
20
21
  export { parseResourceId, createResourceIdForReference } from './utils/resourceId';
@@ -73,8 +73,8 @@ export declare class ReferenceSyncBlockStoreManager {
73
73
  generateResourceIdForReference(sourceId: ResourceId): ResourceId;
74
74
  updateFireAnalyticsEvent(fireAnalyticsEvent?: (payload: RendererSyncBlockEventPayload) => void): void;
75
75
  getInitialSyncBlockData(resourceId: ResourceId): SyncBlockInstance | undefined;
76
- private updateCacheInSessionStorage;
77
- private getSyncBlockDataFromSessionStorage;
76
+ private updateSessionCache;
77
+ private getFromSessionCache;
78
78
  /**
79
79
  * Refreshes the subscriptions for all sync blocks.
80
80
  * This is a fallback polling mechanism when real-time subscriptions are not enabled.
@@ -125,7 +125,7 @@ export declare class ReferenceSyncBlockStoreManager {
125
125
  getFromCache(resourceId: ResourceId): SyncBlockInstance | undefined;
126
126
  private deleteFromCache;
127
127
  private debouncedBatchedFetchSyncBlocks;
128
- private setSSRDataInSessionStorage;
128
+ private setSSRDataInSessionCache;
129
129
  subscribeToSyncBlock(resourceId: string, localId: string, callback: SubscriptionCallback): () => void;
130
130
  subscribeToSourceTitle(node: PMNode, callback: TitleSubscriptionCallback): () => void;
131
131
  subscribe(node: PMNode, callback: SubscriptionCallback): () => void;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * In-memory session cache for sync block data with size-based LRU eviction.
3
+ *
4
+ * Backed by a plain Map so that potentially private ADF content is never
5
+ * written to any browser-persistent storage (sessionStorage, localStorage,
6
+ * IndexedDB). The module-level singleton survives SPA transitions (no full
7
+ * page reload) and is naturally cleared on hard navigation or tab close.
8
+ *
9
+ * Uses JavaScript Map's insertion-order guarantee to implement LRU:
10
+ * on every read or write the accessed entry is moved to the end of the
11
+ * iteration order; when total cached size exceeds `maxSize`, the oldest
12
+ * (least-recently-used) entries are evicted first.
13
+ */
14
+ export declare class SyncBlockInMemorySessionCache {
15
+ private store;
16
+ private currentSize;
17
+ private maxSize;
18
+ constructor(maxSize?: number);
19
+ getItem(key: string): string | null;
20
+ setItem(key: string, value: string): void;
21
+ removeItem(key: string): void;
22
+ }
23
+ export declare const syncBlockInMemorySessionCache: SyncBlockInMemorySessionCache;
@@ -1,3 +1,3 @@
1
- import type { SyncBlockProduct, SyncBlockStatus } from "../common/types";
1
+ import type { SyncBlockProduct, SyncBlockStatus } from '../common/types';
2
2
  export declare const normaliseSyncBlockProduct: (value: string | null | undefined) => SyncBlockProduct | undefined;
3
3
  export declare const normaliseSyncBlockStatus: (value: string | null | undefined) => SyncBlockStatus | undefined;
@@ -15,6 +15,7 @@ export { fetchConfluencePageInfo } from './clients/confluence/sourceInfo';
15
15
  export { SyncedBlockProvider, useMemoizedSyncedBlockProvider } from './providers/syncBlockProvider';
16
16
  export type { ADFFetchProvider, ADFWriteProvider, BlockNodeIdentifiers, BlockSubscriptionErrorCallback, BlockUpdateCallback, SyncBlockDataProviderInterface, SyncBlockInstance, MediaEmojiProviderOptions, SyncedBlockRendererProviderOptions, SyncBlockRendererProviderCreator, SyncedBlockRendererDataProviders, Unsubscribe, UpdateReferenceSyncBlockResult, WriteSyncBlockResult, SyncBlockParentInfo, SyncBlockSourceInfo, } from './providers/types';
17
17
  export { ReferenceSyncBlockStoreManager } from './store-manager/referenceSyncBlockStoreManager';
18
+ export { SyncBlockInMemorySessionCache, syncBlockInMemorySessionCache, } from './store-manager/syncBlockInMemorySessionCache';
18
19
  export { SyncBlockStoreManager, useMemoizedSyncBlockStoreManager, } from './store-manager/syncBlockStoreManager';
19
20
  export { resolveSyncBlockInstance } from './utils/resolveSyncBlockInstance';
20
21
  export { parseResourceId, createResourceIdForReference } from './utils/resourceId';
@@ -73,8 +73,8 @@ export declare class ReferenceSyncBlockStoreManager {
73
73
  generateResourceIdForReference(sourceId: ResourceId): ResourceId;
74
74
  updateFireAnalyticsEvent(fireAnalyticsEvent?: (payload: RendererSyncBlockEventPayload) => void): void;
75
75
  getInitialSyncBlockData(resourceId: ResourceId): SyncBlockInstance | undefined;
76
- private updateCacheInSessionStorage;
77
- private getSyncBlockDataFromSessionStorage;
76
+ private updateSessionCache;
77
+ private getFromSessionCache;
78
78
  /**
79
79
  * Refreshes the subscriptions for all sync blocks.
80
80
  * This is a fallback polling mechanism when real-time subscriptions are not enabled.
@@ -125,7 +125,7 @@ export declare class ReferenceSyncBlockStoreManager {
125
125
  getFromCache(resourceId: ResourceId): SyncBlockInstance | undefined;
126
126
  private deleteFromCache;
127
127
  private debouncedBatchedFetchSyncBlocks;
128
- private setSSRDataInSessionStorage;
128
+ private setSSRDataInSessionCache;
129
129
  subscribeToSyncBlock(resourceId: string, localId: string, callback: SubscriptionCallback): () => void;
130
130
  subscribeToSourceTitle(node: PMNode, callback: TitleSubscriptionCallback): () => void;
131
131
  subscribe(node: PMNode, callback: SubscriptionCallback): () => void;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * In-memory session cache for sync block data with size-based LRU eviction.
3
+ *
4
+ * Backed by a plain Map so that potentially private ADF content is never
5
+ * written to any browser-persistent storage (sessionStorage, localStorage,
6
+ * IndexedDB). The module-level singleton survives SPA transitions (no full
7
+ * page reload) and is naturally cleared on hard navigation or tab close.
8
+ *
9
+ * Uses JavaScript Map's insertion-order guarantee to implement LRU:
10
+ * on every read or write the accessed entry is moved to the end of the
11
+ * iteration order; when total cached size exceeds `maxSize`, the oldest
12
+ * (least-recently-used) entries are evicted first.
13
+ */
14
+ export declare class SyncBlockInMemorySessionCache {
15
+ private store;
16
+ private currentSize;
17
+ private maxSize;
18
+ constructor(maxSize?: number);
19
+ getItem(key: string): string | null;
20
+ setItem(key: string, value: string): void;
21
+ removeItem(key: string): void;
22
+ }
23
+ export declare const syncBlockInMemorySessionCache: SyncBlockInMemorySessionCache;
@@ -1,3 +1,3 @@
1
- import type { SyncBlockProduct, SyncBlockStatus } from "../common/types";
1
+ import type { SyncBlockProduct, SyncBlockStatus } from '../common/types';
2
2
  export declare const normaliseSyncBlockProduct: (value: string | null | undefined) => SyncBlockProduct | undefined;
3
3
  export declare const normaliseSyncBlockStatus: (value: string | null | undefined) => SyncBlockStatus | undefined;
package/package.json CHANGED
@@ -80,7 +80,7 @@
80
80
  }
81
81
  },
82
82
  "name": "@atlaskit/editor-synced-block-provider",
83
- "version": "3.30.2",
83
+ "version": "3.30.3",
84
84
  "description": "Synced Block Provider for @atlaskit/editor-plugin-synced-block",
85
85
  "author": "Atlassian Pty Ltd",
86
86
  "license": "Apache-2.0",