@atlaskit/editor-card-provider 6.4.7 → 6.4.9
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 +15 -0
- package/dist/cjs/provider.js +1 -1
- package/dist/cjs/smart-card-local-cache-client.js +116 -67
- package/dist/es2019/provider.js +1 -1
- package/dist/es2019/smart-card-local-cache-client.js +60 -19
- package/dist/esm/provider.js +1 -1
- package/dist/esm/smart-card-local-cache-client.js +116 -67
- package/dist/types/smart-card-local-cache-client.d.ts +23 -2
- package/dist/types-ts4.5/smart-card-local-cache-client.d.ts +23 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @atlaskit/editor-card-provider
|
|
2
2
|
|
|
3
|
+
## 6.4.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`50a2e34ed2f69`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/50a2e34ed2f69) -
|
|
8
|
+
Optimize SmartCardLocalCacheClient: in-memory caching, async writes, singleton pattern, and write
|
|
9
|
+
batching.
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
|
|
12
|
+
## 6.4.8
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
|
|
3
18
|
## 6.4.7
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/dist/cjs/provider.js
CHANGED
|
@@ -141,7 +141,7 @@ var EditorCardProvider = exports.EditorCardProvider = /*#__PURE__*/function (_re
|
|
|
141
141
|
var _this;
|
|
142
142
|
(0, _classCallCheck2.default)(this, EditorCardProvider);
|
|
143
143
|
_this = _callSuper(this, EditorCardProvider);
|
|
144
|
-
(0, _defineProperty2.default)(_this, "smartCardLocalCacheClient",
|
|
144
|
+
(0, _defineProperty2.default)(_this, "smartCardLocalCacheClient", _smartCardLocalCacheClient.SmartCardLocalCacheClient.getInstance());
|
|
145
145
|
_this.name = 'editorCardProvider';
|
|
146
146
|
_this.baseUrl = baseUrlOverride || (0, _linkingCommon.getBaseUrl)(envKey);
|
|
147
147
|
_this.resolverUrl = (0, _linkingCommon.getResolverUrl)(envKey, baseUrlOverride);
|
|
@@ -5,82 +5,131 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.SmartCardLocalCacheClient = void 0;
|
|
8
|
-
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
9
8
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
10
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
11
|
var _storageClient = require("@atlaskit/frontend-utilities/storage-client");
|
|
12
12
|
var SMART_CARD_CACHE_CLIENT_KEY = 'smart-card-url-data';
|
|
13
13
|
var SMART_CARD_CACHE_KEY = 'response-cache';
|
|
14
14
|
var SMART_CARD_CACHE_DEFAULT_MAX_ITEMS = 100;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Singleton cache client for smart link responses. Uses sessionStorage for per-tab isolation (no cross-tab conflicts).
|
|
17
|
+
* If switching to localStorage for cross-tab sharing, add a 'storage' event listener in the constructor to sync
|
|
18
|
+
* memoryCache when other tabs modify the cache, preventing race conditions from concurrent writes.
|
|
19
|
+
*/
|
|
20
|
+
var SmartCardLocalCacheClient = exports.SmartCardLocalCacheClient = /*#__PURE__*/function () {
|
|
21
|
+
function SmartCardLocalCacheClient() {
|
|
22
|
+
var _this = this;
|
|
23
|
+
var maxItems = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SMART_CARD_CACHE_DEFAULT_MAX_ITEMS;
|
|
24
|
+
(0, _classCallCheck2.default)(this, SmartCardLocalCacheClient);
|
|
25
|
+
(0, _defineProperty2.default)(this, "storageClient", new _storageClient.StorageClient(SMART_CARD_CACHE_CLIENT_KEY, {
|
|
26
|
+
storageEngine: 'sessionStorage'
|
|
27
|
+
}));
|
|
28
|
+
(0, _defineProperty2.default)(this, "pendingWrite", false);
|
|
29
|
+
/**
|
|
30
|
+
* Retrieves the entire cache object from memory
|
|
31
|
+
* @returns The entire cache object
|
|
32
|
+
*/
|
|
33
|
+
(0, _defineProperty2.default)(this, "getCache", function () {
|
|
34
|
+
return _this.memoryCache;
|
|
29
35
|
});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Caches the SmartLinkResponse against the provided url in storage
|
|
38
|
+
* @param url The url (key) to store the response against
|
|
39
|
+
* @param response The SmartLinkResponse to be cached in storage
|
|
40
|
+
*/
|
|
41
|
+
(0, _defineProperty2.default)(this, "setItem", function (url, response) {
|
|
42
|
+
// Add or update the item in the cache with current timestamp
|
|
43
|
+
_this.memoryCache[url] = {
|
|
44
|
+
data: response,
|
|
45
|
+
timestamp: Date.now()
|
|
46
|
+
};
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
// Apply FIFO behavior if cache exceeds maxItems
|
|
49
|
+
var cacheKeys = Object.keys(_this.memoryCache);
|
|
50
|
+
if (cacheKeys.length > _this.maxItems) {
|
|
51
|
+
// Sort keys by timestamp (oldest first) and remove the oldest items
|
|
52
|
+
var sortedKeys = cacheKeys.sort(function (a, b) {
|
|
53
|
+
return _this.memoryCache[a].timestamp - _this.memoryCache[b].timestamp;
|
|
54
|
+
});
|
|
55
|
+
var itemsToRemove = cacheKeys.length - _this.maxItems;
|
|
56
|
+
var keysToRemove = sortedKeys.slice(0, itemsToRemove);
|
|
57
|
+
keysToRemove.forEach(function (key) {
|
|
58
|
+
delete _this.memoryCache[key];
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Write through to storage asynchronously (non-blocking)
|
|
63
|
+
// Debounced to batch multiple rapid calls into a single write
|
|
64
|
+
if (!_this.pendingWrite) {
|
|
65
|
+
_this.pendingWrite = true;
|
|
66
|
+
queueMicrotask(function () {
|
|
67
|
+
try {
|
|
68
|
+
_this.storageClient.setItemWithExpiry(SMART_CARD_CACHE_KEY, JSON.stringify(_this.memoryCache));
|
|
69
|
+
} catch (_) {
|
|
70
|
+
// Ignore storage write errors (e.g. quota exceeded) to prevent blocking future writes
|
|
71
|
+
// Cache will still function in-memory for the session, but won't persist
|
|
72
|
+
} finally {
|
|
73
|
+
_this.pendingWrite = false;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* Retrieves the cached SmartLinkResponse for the provided url from storage (if it exists)
|
|
80
|
+
* @param url The url (key) to retrieve the cached response for
|
|
81
|
+
* @returns The cached SmartLinkResponse if it exists, else undefined
|
|
82
|
+
*/
|
|
83
|
+
(0, _defineProperty2.default)(this, "getItem", function (url) {
|
|
84
|
+
var _this$memoryCache;
|
|
85
|
+
if (!url) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
var response = (_this$memoryCache = _this.memoryCache) === null || _this$memoryCache === void 0 || (_this$memoryCache = _this$memoryCache[url]) === null || _this$memoryCache === void 0 ? void 0 : _this$memoryCache.data;
|
|
89
|
+
return response;
|
|
90
|
+
});
|
|
91
|
+
/**
|
|
92
|
+
* Checks if a cached entry exists for the provided url in storage
|
|
93
|
+
* @param url The url (key) to check for existence in the cache
|
|
94
|
+
* @returns True if a cached entry exists, else false
|
|
95
|
+
*/
|
|
96
|
+
(0, _defineProperty2.default)(this, "isUrlInCache", function (url) {
|
|
97
|
+
return url in _this.memoryCache;
|
|
98
|
+
});
|
|
99
|
+
this.maxItems = maxItems;
|
|
100
|
+
// Load cache from storage into memory on instantiation
|
|
101
|
+
var stored = this.storageClient.getItem(SMART_CARD_CACHE_KEY, {
|
|
102
|
+
useExpiredItem: true
|
|
103
|
+
});
|
|
104
|
+
this.memoryCache = stored ? JSON.parse(stored) : {};
|
|
105
|
+
}
|
|
46
106
|
|
|
47
|
-
// Apply FIFO behavior if cache exceeds maxItems
|
|
48
|
-
var cacheKeys = Object.keys(newCache);
|
|
49
|
-
if (cacheKeys.length > _this.maxItems) {
|
|
50
|
-
// Sort keys by timestamp (oldest first) and remove the oldest items
|
|
51
|
-
var sortedKeys = cacheKeys.sort(function (a, b) {
|
|
52
|
-
return newCache[a].timestamp - newCache[b].timestamp;
|
|
53
|
-
});
|
|
54
|
-
var itemsToRemove = cacheKeys.length - _this.maxItems;
|
|
55
|
-
var keysToRemove = sortedKeys.slice(0, itemsToRemove);
|
|
56
|
-
keysToRemove.forEach(function (key) {
|
|
57
|
-
delete newCache[key];
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
_this.storageClient.setItemWithExpiry(SMART_CARD_CACHE_KEY, JSON.stringify(newCache));
|
|
61
|
-
});
|
|
62
107
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
108
|
+
* Gets the singleton instance of SmartCardLocalCacheClient.
|
|
109
|
+
* This ensures all callers share the same in-memory cache and prevents
|
|
110
|
+
* race conditions when multiple instances write to the same storage key.
|
|
111
|
+
* @param maxItems Maximum number of items to store in the cache (only used on first instantiation)
|
|
112
|
+
* @returns The singleton instance
|
|
66
113
|
*/
|
|
67
|
-
(0,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
114
|
+
return (0, _createClass2.default)(SmartCardLocalCacheClient, null, [{
|
|
115
|
+
key: "getInstance",
|
|
116
|
+
value: function getInstance() {
|
|
117
|
+
var maxItems = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SMART_CARD_CACHE_DEFAULT_MAX_ITEMS;
|
|
118
|
+
if (!SmartCardLocalCacheClient.instance) {
|
|
119
|
+
SmartCardLocalCacheClient.instance = new SmartCardLocalCacheClient(maxItems);
|
|
120
|
+
}
|
|
121
|
+
return SmartCardLocalCacheClient.instance;
|
|
71
122
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.maxItems = maxItems;
|
|
86
|
-
});
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Resets the singleton instance. Only intended for testing purposes.
|
|
126
|
+
* @internal
|
|
127
|
+
*/
|
|
128
|
+
}, {
|
|
129
|
+
key: "resetInstance",
|
|
130
|
+
value: function resetInstance() {
|
|
131
|
+
SmartCardLocalCacheClient.instance = null;
|
|
132
|
+
}
|
|
133
|
+
}]);
|
|
134
|
+
}();
|
|
135
|
+
(0, _defineProperty2.default)(SmartCardLocalCacheClient, "instance", null);
|
package/dist/es2019/provider.js
CHANGED
|
@@ -72,7 +72,7 @@ export const isJiraWorkItem = url => /\/browse\/((?:\w+)-(?:\d+))/i.test(url);
|
|
|
72
72
|
export class EditorCardProvider extends NodeDataProvider {
|
|
73
73
|
constructor(envKey, baseUrlOverride, product, onResolve, customCardClient) {
|
|
74
74
|
super();
|
|
75
|
-
_defineProperty(this, "smartCardLocalCacheClient",
|
|
75
|
+
_defineProperty(this, "smartCardLocalCacheClient", SmartCardLocalCacheClient.getInstance());
|
|
76
76
|
this.name = 'editorCardProvider';
|
|
77
77
|
this.baseUrl = baseUrlOverride || getBaseUrl(envKey);
|
|
78
78
|
this.resolverUrl = getResolverUrl(envKey, baseUrlOverride);
|
|
@@ -3,21 +3,23 @@ import { StorageClient } from '@atlaskit/frontend-utilities/storage-client';
|
|
|
3
3
|
const SMART_CARD_CACHE_CLIENT_KEY = 'smart-card-url-data';
|
|
4
4
|
const SMART_CARD_CACHE_KEY = 'response-cache';
|
|
5
5
|
const SMART_CARD_CACHE_DEFAULT_MAX_ITEMS = 100;
|
|
6
|
+
/**
|
|
7
|
+
* Singleton cache client for smart link responses. Uses sessionStorage for per-tab isolation (no cross-tab conflicts).
|
|
8
|
+
* If switching to localStorage for cross-tab sharing, add a 'storage' event listener in the constructor to sync
|
|
9
|
+
* memoryCache when other tabs modify the cache, preventing race conditions from concurrent writes.
|
|
10
|
+
*/
|
|
6
11
|
export class SmartCardLocalCacheClient {
|
|
7
12
|
constructor(maxItems = SMART_CARD_CACHE_DEFAULT_MAX_ITEMS) {
|
|
8
13
|
_defineProperty(this, "storageClient", new StorageClient(SMART_CARD_CACHE_CLIENT_KEY, {
|
|
9
14
|
storageEngine: 'sessionStorage'
|
|
10
15
|
}));
|
|
16
|
+
_defineProperty(this, "pendingWrite", false);
|
|
11
17
|
/**
|
|
12
|
-
* Retrieves the entire cache object from
|
|
18
|
+
* Retrieves the entire cache object from memory
|
|
13
19
|
* @returns The entire cache object
|
|
14
20
|
*/
|
|
15
21
|
_defineProperty(this, "getCache", () => {
|
|
16
|
-
|
|
17
|
-
useExpiredItem: true
|
|
18
|
-
});
|
|
19
|
-
const persistentCache = stored ? JSON.parse(stored) : {};
|
|
20
|
-
return persistentCache;
|
|
22
|
+
return this.memoryCache;
|
|
21
23
|
});
|
|
22
24
|
/**
|
|
23
25
|
* Caches the SmartLinkResponse against the provided url in storage
|
|
@@ -25,26 +27,39 @@ export class SmartCardLocalCacheClient {
|
|
|
25
27
|
* @param response The SmartLinkResponse to be cached in storage
|
|
26
28
|
*/
|
|
27
29
|
_defineProperty(this, "setItem", (url, response) => {
|
|
28
|
-
const newCache = this.getCache();
|
|
29
|
-
|
|
30
30
|
// Add or update the item in the cache with current timestamp
|
|
31
|
-
|
|
31
|
+
this.memoryCache[url] = {
|
|
32
32
|
data: response,
|
|
33
33
|
timestamp: Date.now()
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
// Apply FIFO behavior if cache exceeds maxItems
|
|
37
|
-
const cacheKeys = Object.keys(
|
|
37
|
+
const cacheKeys = Object.keys(this.memoryCache);
|
|
38
38
|
if (cacheKeys.length > this.maxItems) {
|
|
39
39
|
// Sort keys by timestamp (oldest first) and remove the oldest items
|
|
40
|
-
const sortedKeys = cacheKeys.sort((a, b) =>
|
|
40
|
+
const sortedKeys = cacheKeys.sort((a, b) => this.memoryCache[a].timestamp - this.memoryCache[b].timestamp);
|
|
41
41
|
const itemsToRemove = cacheKeys.length - this.maxItems;
|
|
42
42
|
const keysToRemove = sortedKeys.slice(0, itemsToRemove);
|
|
43
43
|
keysToRemove.forEach(key => {
|
|
44
|
-
delete
|
|
44
|
+
delete this.memoryCache[key];
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Write through to storage asynchronously (non-blocking)
|
|
49
|
+
// Debounced to batch multiple rapid calls into a single write
|
|
50
|
+
if (!this.pendingWrite) {
|
|
51
|
+
this.pendingWrite = true;
|
|
52
|
+
queueMicrotask(() => {
|
|
53
|
+
try {
|
|
54
|
+
this.storageClient.setItemWithExpiry(SMART_CARD_CACHE_KEY, JSON.stringify(this.memoryCache));
|
|
55
|
+
} catch (_) {
|
|
56
|
+
// Ignore storage write errors (e.g. quota exceeded) to prevent blocking future writes
|
|
57
|
+
// Cache will still function in-memory for the session, but won't persist
|
|
58
|
+
} finally {
|
|
59
|
+
this.pendingWrite = false;
|
|
60
|
+
}
|
|
45
61
|
});
|
|
46
62
|
}
|
|
47
|
-
this.storageClient.setItemWithExpiry(SMART_CARD_CACHE_KEY, JSON.stringify(newCache));
|
|
48
63
|
});
|
|
49
64
|
/**
|
|
50
65
|
* Retrieves the cached SmartLinkResponse for the provided url from storage (if it exists)
|
|
@@ -52,12 +67,11 @@ export class SmartCardLocalCacheClient {
|
|
|
52
67
|
* @returns The cached SmartLinkResponse if it exists, else undefined
|
|
53
68
|
*/
|
|
54
69
|
_defineProperty(this, "getItem", url => {
|
|
55
|
-
var
|
|
70
|
+
var _this$memoryCache, _this$memoryCache$url;
|
|
56
71
|
if (!url) {
|
|
57
72
|
return;
|
|
58
73
|
}
|
|
59
|
-
const
|
|
60
|
-
const response = persistentCache === null || persistentCache === void 0 ? void 0 : (_persistentCache$url = persistentCache[url]) === null || _persistentCache$url === void 0 ? void 0 : _persistentCache$url.data;
|
|
74
|
+
const response = (_this$memoryCache = this.memoryCache) === null || _this$memoryCache === void 0 ? void 0 : (_this$memoryCache$url = _this$memoryCache[url]) === null || _this$memoryCache$url === void 0 ? void 0 : _this$memoryCache$url.data;
|
|
61
75
|
return response;
|
|
62
76
|
});
|
|
63
77
|
/**
|
|
@@ -66,9 +80,36 @@ export class SmartCardLocalCacheClient {
|
|
|
66
80
|
* @returns True if a cached entry exists, else false
|
|
67
81
|
*/
|
|
68
82
|
_defineProperty(this, "isUrlInCache", url => {
|
|
69
|
-
|
|
70
|
-
return persistentCache ? url in persistentCache : false;
|
|
83
|
+
return url in this.memoryCache;
|
|
71
84
|
});
|
|
72
85
|
this.maxItems = maxItems;
|
|
86
|
+
// Load cache from storage into memory on instantiation
|
|
87
|
+
const stored = this.storageClient.getItem(SMART_CARD_CACHE_KEY, {
|
|
88
|
+
useExpiredItem: true
|
|
89
|
+
});
|
|
90
|
+
this.memoryCache = stored ? JSON.parse(stored) : {};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Gets the singleton instance of SmartCardLocalCacheClient.
|
|
95
|
+
* This ensures all callers share the same in-memory cache and prevents
|
|
96
|
+
* race conditions when multiple instances write to the same storage key.
|
|
97
|
+
* @param maxItems Maximum number of items to store in the cache (only used on first instantiation)
|
|
98
|
+
* @returns The singleton instance
|
|
99
|
+
*/
|
|
100
|
+
static getInstance(maxItems = SMART_CARD_CACHE_DEFAULT_MAX_ITEMS) {
|
|
101
|
+
if (!SmartCardLocalCacheClient.instance) {
|
|
102
|
+
SmartCardLocalCacheClient.instance = new SmartCardLocalCacheClient(maxItems);
|
|
103
|
+
}
|
|
104
|
+
return SmartCardLocalCacheClient.instance;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Resets the singleton instance. Only intended for testing purposes.
|
|
109
|
+
* @internal
|
|
110
|
+
*/
|
|
111
|
+
static resetInstance() {
|
|
112
|
+
SmartCardLocalCacheClient.instance = null;
|
|
73
113
|
}
|
|
74
|
-
}
|
|
114
|
+
}
|
|
115
|
+
_defineProperty(SmartCardLocalCacheClient, "instance", null);
|
package/dist/esm/provider.js
CHANGED
|
@@ -136,7 +136,7 @@ export var EditorCardProvider = /*#__PURE__*/function (_ref) {
|
|
|
136
136
|
var _this;
|
|
137
137
|
_classCallCheck(this, EditorCardProvider);
|
|
138
138
|
_this = _callSuper(this, EditorCardProvider);
|
|
139
|
-
_defineProperty(_this, "smartCardLocalCacheClient",
|
|
139
|
+
_defineProperty(_this, "smartCardLocalCacheClient", SmartCardLocalCacheClient.getInstance());
|
|
140
140
|
_this.name = 'editorCardProvider';
|
|
141
141
|
_this.baseUrl = baseUrlOverride || getBaseUrl(envKey);
|
|
142
142
|
_this.resolverUrl = getResolverUrl(envKey, baseUrlOverride);
|
|
@@ -1,79 +1,128 @@
|
|
|
1
|
-
import _createClass from "@babel/runtime/helpers/createClass";
|
|
2
1
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
|
+
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
3
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
4
|
import { StorageClient } from '@atlaskit/frontend-utilities/storage-client';
|
|
5
5
|
var SMART_CARD_CACHE_CLIENT_KEY = 'smart-card-url-data';
|
|
6
6
|
var SMART_CARD_CACHE_KEY = 'response-cache';
|
|
7
7
|
var SMART_CARD_CACHE_DEFAULT_MAX_ITEMS = 100;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Singleton cache client for smart link responses. Uses sessionStorage for per-tab isolation (no cross-tab conflicts).
|
|
10
|
+
* If switching to localStorage for cross-tab sharing, add a 'storage' event listener in the constructor to sync
|
|
11
|
+
* memoryCache when other tabs modify the cache, preventing race conditions from concurrent writes.
|
|
12
|
+
*/
|
|
13
|
+
export var SmartCardLocalCacheClient = /*#__PURE__*/function () {
|
|
14
|
+
function SmartCardLocalCacheClient() {
|
|
15
|
+
var _this = this;
|
|
16
|
+
var maxItems = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SMART_CARD_CACHE_DEFAULT_MAX_ITEMS;
|
|
17
|
+
_classCallCheck(this, SmartCardLocalCacheClient);
|
|
18
|
+
_defineProperty(this, "storageClient", new StorageClient(SMART_CARD_CACHE_CLIENT_KEY, {
|
|
19
|
+
storageEngine: 'sessionStorage'
|
|
20
|
+
}));
|
|
21
|
+
_defineProperty(this, "pendingWrite", false);
|
|
22
|
+
/**
|
|
23
|
+
* Retrieves the entire cache object from memory
|
|
24
|
+
* @returns The entire cache object
|
|
25
|
+
*/
|
|
26
|
+
_defineProperty(this, "getCache", function () {
|
|
27
|
+
return _this.memoryCache;
|
|
22
28
|
});
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Caches the SmartLinkResponse against the provided url in storage
|
|
31
|
+
* @param url The url (key) to store the response against
|
|
32
|
+
* @param response The SmartLinkResponse to be cached in storage
|
|
33
|
+
*/
|
|
34
|
+
_defineProperty(this, "setItem", function (url, response) {
|
|
35
|
+
// Add or update the item in the cache with current timestamp
|
|
36
|
+
_this.memoryCache[url] = {
|
|
37
|
+
data: response,
|
|
38
|
+
timestamp: Date.now()
|
|
39
|
+
};
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
// Apply FIFO behavior if cache exceeds maxItems
|
|
42
|
+
var cacheKeys = Object.keys(_this.memoryCache);
|
|
43
|
+
if (cacheKeys.length > _this.maxItems) {
|
|
44
|
+
// Sort keys by timestamp (oldest first) and remove the oldest items
|
|
45
|
+
var sortedKeys = cacheKeys.sort(function (a, b) {
|
|
46
|
+
return _this.memoryCache[a].timestamp - _this.memoryCache[b].timestamp;
|
|
47
|
+
});
|
|
48
|
+
var itemsToRemove = cacheKeys.length - _this.maxItems;
|
|
49
|
+
var keysToRemove = sortedKeys.slice(0, itemsToRemove);
|
|
50
|
+
keysToRemove.forEach(function (key) {
|
|
51
|
+
delete _this.memoryCache[key];
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Write through to storage asynchronously (non-blocking)
|
|
56
|
+
// Debounced to batch multiple rapid calls into a single write
|
|
57
|
+
if (!_this.pendingWrite) {
|
|
58
|
+
_this.pendingWrite = true;
|
|
59
|
+
queueMicrotask(function () {
|
|
60
|
+
try {
|
|
61
|
+
_this.storageClient.setItemWithExpiry(SMART_CARD_CACHE_KEY, JSON.stringify(_this.memoryCache));
|
|
62
|
+
} catch (_) {
|
|
63
|
+
// Ignore storage write errors (e.g. quota exceeded) to prevent blocking future writes
|
|
64
|
+
// Cache will still function in-memory for the session, but won't persist
|
|
65
|
+
} finally {
|
|
66
|
+
_this.pendingWrite = false;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
/**
|
|
72
|
+
* Retrieves the cached SmartLinkResponse for the provided url from storage (if it exists)
|
|
73
|
+
* @param url The url (key) to retrieve the cached response for
|
|
74
|
+
* @returns The cached SmartLinkResponse if it exists, else undefined
|
|
75
|
+
*/
|
|
76
|
+
_defineProperty(this, "getItem", function (url) {
|
|
77
|
+
var _this$memoryCache;
|
|
78
|
+
if (!url) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
var response = (_this$memoryCache = _this.memoryCache) === null || _this$memoryCache === void 0 || (_this$memoryCache = _this$memoryCache[url]) === null || _this$memoryCache === void 0 ? void 0 : _this$memoryCache.data;
|
|
82
|
+
return response;
|
|
83
|
+
});
|
|
84
|
+
/**
|
|
85
|
+
* Checks if a cached entry exists for the provided url in storage
|
|
86
|
+
* @param url The url (key) to check for existence in the cache
|
|
87
|
+
* @returns True if a cached entry exists, else false
|
|
88
|
+
*/
|
|
89
|
+
_defineProperty(this, "isUrlInCache", function (url) {
|
|
90
|
+
return url in _this.memoryCache;
|
|
91
|
+
});
|
|
92
|
+
this.maxItems = maxItems;
|
|
93
|
+
// Load cache from storage into memory on instantiation
|
|
94
|
+
var stored = this.storageClient.getItem(SMART_CARD_CACHE_KEY, {
|
|
95
|
+
useExpiredItem: true
|
|
96
|
+
});
|
|
97
|
+
this.memoryCache = stored ? JSON.parse(stored) : {};
|
|
98
|
+
}
|
|
39
99
|
|
|
40
|
-
// Apply FIFO behavior if cache exceeds maxItems
|
|
41
|
-
var cacheKeys = Object.keys(newCache);
|
|
42
|
-
if (cacheKeys.length > _this.maxItems) {
|
|
43
|
-
// Sort keys by timestamp (oldest first) and remove the oldest items
|
|
44
|
-
var sortedKeys = cacheKeys.sort(function (a, b) {
|
|
45
|
-
return newCache[a].timestamp - newCache[b].timestamp;
|
|
46
|
-
});
|
|
47
|
-
var itemsToRemove = cacheKeys.length - _this.maxItems;
|
|
48
|
-
var keysToRemove = sortedKeys.slice(0, itemsToRemove);
|
|
49
|
-
keysToRemove.forEach(function (key) {
|
|
50
|
-
delete newCache[key];
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
_this.storageClient.setItemWithExpiry(SMART_CARD_CACHE_KEY, JSON.stringify(newCache));
|
|
54
|
-
});
|
|
55
100
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
101
|
+
* Gets the singleton instance of SmartCardLocalCacheClient.
|
|
102
|
+
* This ensures all callers share the same in-memory cache and prevents
|
|
103
|
+
* race conditions when multiple instances write to the same storage key.
|
|
104
|
+
* @param maxItems Maximum number of items to store in the cache (only used on first instantiation)
|
|
105
|
+
* @returns The singleton instance
|
|
59
106
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
107
|
+
return _createClass(SmartCardLocalCacheClient, null, [{
|
|
108
|
+
key: "getInstance",
|
|
109
|
+
value: function getInstance() {
|
|
110
|
+
var maxItems = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : SMART_CARD_CACHE_DEFAULT_MAX_ITEMS;
|
|
111
|
+
if (!SmartCardLocalCacheClient.instance) {
|
|
112
|
+
SmartCardLocalCacheClient.instance = new SmartCardLocalCacheClient(maxItems);
|
|
113
|
+
}
|
|
114
|
+
return SmartCardLocalCacheClient.instance;
|
|
64
115
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this.maxItems = maxItems;
|
|
79
|
-
});
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Resets the singleton instance. Only intended for testing purposes.
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
}, {
|
|
122
|
+
key: "resetInstance",
|
|
123
|
+
value: function resetInstance() {
|
|
124
|
+
SmartCardLocalCacheClient.instance = null;
|
|
125
|
+
}
|
|
126
|
+
}]);
|
|
127
|
+
}();
|
|
128
|
+
_defineProperty(SmartCardLocalCacheClient, "instance", null);
|
|
@@ -3,12 +3,33 @@ type CacheEntry = {
|
|
|
3
3
|
data: SmartLinkResponse;
|
|
4
4
|
timestamp: number;
|
|
5
5
|
};
|
|
6
|
+
/**
|
|
7
|
+
* Singleton cache client for smart link responses. Uses sessionStorage for per-tab isolation (no cross-tab conflicts).
|
|
8
|
+
* If switching to localStorage for cross-tab sharing, add a 'storage' event listener in the constructor to sync
|
|
9
|
+
* memoryCache when other tabs modify the cache, preventing race conditions from concurrent writes.
|
|
10
|
+
*/
|
|
6
11
|
export declare class SmartCardLocalCacheClient {
|
|
12
|
+
private static instance;
|
|
7
13
|
private readonly storageClient;
|
|
8
14
|
private maxItems;
|
|
9
|
-
|
|
15
|
+
private memoryCache;
|
|
16
|
+
private pendingWrite;
|
|
17
|
+
private constructor();
|
|
10
18
|
/**
|
|
11
|
-
*
|
|
19
|
+
* Gets the singleton instance of SmartCardLocalCacheClient.
|
|
20
|
+
* This ensures all callers share the same in-memory cache and prevents
|
|
21
|
+
* race conditions when multiple instances write to the same storage key.
|
|
22
|
+
* @param maxItems Maximum number of items to store in the cache (only used on first instantiation)
|
|
23
|
+
* @returns The singleton instance
|
|
24
|
+
*/
|
|
25
|
+
static getInstance(maxItems?: number): SmartCardLocalCacheClient;
|
|
26
|
+
/**
|
|
27
|
+
* Resets the singleton instance. Only intended for testing purposes.
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
static resetInstance(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Retrieves the entire cache object from memory
|
|
12
33
|
* @returns The entire cache object
|
|
13
34
|
*/
|
|
14
35
|
getCache: () => Record<string, CacheEntry>;
|
|
@@ -3,12 +3,33 @@ type CacheEntry = {
|
|
|
3
3
|
data: SmartLinkResponse;
|
|
4
4
|
timestamp: number;
|
|
5
5
|
};
|
|
6
|
+
/**
|
|
7
|
+
* Singleton cache client for smart link responses. Uses sessionStorage for per-tab isolation (no cross-tab conflicts).
|
|
8
|
+
* If switching to localStorage for cross-tab sharing, add a 'storage' event listener in the constructor to sync
|
|
9
|
+
* memoryCache when other tabs modify the cache, preventing race conditions from concurrent writes.
|
|
10
|
+
*/
|
|
6
11
|
export declare class SmartCardLocalCacheClient {
|
|
12
|
+
private static instance;
|
|
7
13
|
private readonly storageClient;
|
|
8
14
|
private maxItems;
|
|
9
|
-
|
|
15
|
+
private memoryCache;
|
|
16
|
+
private pendingWrite;
|
|
17
|
+
private constructor();
|
|
10
18
|
/**
|
|
11
|
-
*
|
|
19
|
+
* Gets the singleton instance of SmartCardLocalCacheClient.
|
|
20
|
+
* This ensures all callers share the same in-memory cache and prevents
|
|
21
|
+
* race conditions when multiple instances write to the same storage key.
|
|
22
|
+
* @param maxItems Maximum number of items to store in the cache (only used on first instantiation)
|
|
23
|
+
* @returns The singleton instance
|
|
24
|
+
*/
|
|
25
|
+
static getInstance(maxItems?: number): SmartCardLocalCacheClient;
|
|
26
|
+
/**
|
|
27
|
+
* Resets the singleton instance. Only intended for testing purposes.
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
static resetInstance(): void;
|
|
31
|
+
/**
|
|
32
|
+
* Retrieves the entire cache object from memory
|
|
12
33
|
* @returns The entire cache object
|
|
13
34
|
*/
|
|
14
35
|
getCache: () => Record<string, CacheEntry>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-card-provider",
|
|
3
|
-
"version": "6.4.
|
|
3
|
+
"version": "6.4.9",
|
|
4
4
|
"description": "Contains the EditorCardProvider, for determining smart card behaviour in the editor.",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@atlaskit/linking-types": "^14.2.0",
|
|
40
40
|
"@atlaskit/node-data-provider": "^8.3.0",
|
|
41
41
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
42
|
-
"@atlaskit/tmp-editor-statsig": "^
|
|
42
|
+
"@atlaskit/tmp-editor-statsig": "^29.2.0",
|
|
43
43
|
"@babel/runtime": "^7.0.0",
|
|
44
44
|
"dataloader": "^2.1.0"
|
|
45
45
|
},
|