@atlaskit/media-file-preview 0.16.3 → 0.16.4
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 +8 -0
- package/dist/cjs/getPreview/cache.js +8 -0
- package/dist/cjs/getPreview/objectURLCache.js +73 -20
- package/dist/cjs/useFilePreview.js +12 -0
- package/dist/es2019/getPreview/cache.js +8 -0
- package/dist/es2019/getPreview/objectURLCache.js +60 -14
- package/dist/es2019/useFilePreview.js +12 -0
- package/dist/esm/getPreview/cache.js +8 -0
- package/dist/esm/getPreview/objectURLCache.js +73 -20
- package/dist/esm/useFilePreview.js +12 -0
- package/dist/types/getPreview/cache.d.ts +4 -0
- package/dist/types/getPreview/objectURLCache.d.ts +9 -0
- package/dist/types-ts4.5/getPreview/cache.d.ts +4 -0
- package/dist/types-ts4.5/getPreview/objectURLCache.d.ts +9 -0
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @atlaskit/media-file-preview
|
|
2
2
|
|
|
3
|
+
## 0.16.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`be94d5f05b8ae`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/be94d5f05b8ae) -
|
|
8
|
+
Fix media image blob cache to only evict blobs when they are no longer referenced
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
|
|
3
11
|
## 0.16.3
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -34,6 +34,14 @@ var CardPreviewCacheImpl = exports.CardPreviewCacheImpl = /*#__PURE__*/(0, _crea
|
|
|
34
34
|
(0, _defineProperty2.default)(this, "clear", function () {
|
|
35
35
|
_this.previewCache.clear();
|
|
36
36
|
});
|
|
37
|
+
(0, _defineProperty2.default)(this, "acquire", function (id, mode) {
|
|
38
|
+
var cacheKey = getCacheKey(id, mode);
|
|
39
|
+
_this.previewCache.acquire(cacheKey);
|
|
40
|
+
});
|
|
41
|
+
(0, _defineProperty2.default)(this, "release", function (id, mode) {
|
|
42
|
+
var cacheKey = getCacheKey(id, mode);
|
|
43
|
+
_this.previewCache.release(cacheKey);
|
|
44
|
+
});
|
|
37
45
|
this.previewCache = previewCache;
|
|
38
46
|
});
|
|
39
47
|
var mediaFilePreviewCache = exports.mediaFilePreviewCache = new CardPreviewCacheImpl((0, _objectURLCache.createObjectURLCache)());
|
|
@@ -5,52 +5,103 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.createObjectURLCache = exports.PREVIEW_CACHE_LRU_SIZE = exports.ObjectURLCache = void 0;
|
|
8
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
8
9
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
10
|
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
11
|
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
|
|
11
12
|
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
|
|
12
13
|
var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get"));
|
|
13
14
|
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
|
|
14
|
-
var _eventemitter = require("eventemitter2");
|
|
15
15
|
var _lru_map = require("lru_map");
|
|
16
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
16
17
|
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
|
|
17
18
|
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
|
|
18
19
|
function _superPropGet(t, o, e, r) { var p = (0, _get2.default)((0, _getPrototypeOf2.default)(1 & r ? t.prototype : t), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; }
|
|
19
20
|
var PREVIEW_CACHE_LRU_SIZE = exports.PREVIEW_CACHE_LRU_SIZE = 50;
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* LRU cache that checks whether the oldest entry should be evicted
|
|
23
|
+
* this means that the cache can grow past the softLimit if `shouldEvict` returns false.
|
|
24
|
+
*
|
|
25
|
+
* When `platform_media_safe_blob_url_eviction` is ON the oldest
|
|
26
|
+
* entry is kept if `shouldEvict` returns false.
|
|
27
|
+
* When the flag is OFF the oldest entry is always evicted.
|
|
28
|
+
*/
|
|
29
|
+
var EvictionLRUCache = /*#__PURE__*/function (_LRUMap) {
|
|
30
|
+
function EvictionLRUCache(softLimit, options) {
|
|
22
31
|
var _this;
|
|
23
|
-
(0, _classCallCheck2.default)(this,
|
|
24
|
-
_this = _callSuper(this,
|
|
25
|
-
_this.
|
|
32
|
+
(0, _classCallCheck2.default)(this, EvictionLRUCache);
|
|
33
|
+
_this = _callSuper(this, EvictionLRUCache, [softLimit]);
|
|
34
|
+
_this.shouldEvict = options === null || options === void 0 ? void 0 : options.shouldEvict;
|
|
35
|
+
_this.onEvict = options === null || options === void 0 ? void 0 : options.onEvict;
|
|
26
36
|
return _this;
|
|
27
37
|
}
|
|
28
|
-
(0, _inherits2.default)(
|
|
29
|
-
return (0, _createClass2.default)(
|
|
38
|
+
(0, _inherits2.default)(EvictionLRUCache, _LRUMap);
|
|
39
|
+
return (0, _createClass2.default)(EvictionLRUCache, [{
|
|
30
40
|
key: "shift",
|
|
31
41
|
value: function shift() {
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
if ((0, _platformFeatureFlags.fg)('platform_media_safe_blob_url_eviction')) {
|
|
43
|
+
var oldest = this.oldest;
|
|
44
|
+
if (oldest && this.shouldEvict && !this.shouldEvict([oldest.key, oldest.value])) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
var entry = _superPropGet(EvictionLRUCache, "shift", this, 3)([]);
|
|
49
|
+
if (entry && this.onEvict) {
|
|
50
|
+
this.onEvict(entry);
|
|
51
|
+
}
|
|
34
52
|
return entry;
|
|
35
53
|
}
|
|
36
|
-
}, {
|
|
37
|
-
key: "on",
|
|
38
|
-
value: function on(event, callback) {
|
|
39
|
-
this.eventEmitter.on(event, callback);
|
|
40
|
-
}
|
|
41
54
|
}]);
|
|
42
55
|
}(_lru_map.LRUMap);
|
|
43
56
|
var ObjectURLCache = exports.ObjectURLCache = /*#__PURE__*/function () {
|
|
44
57
|
function ObjectURLCache(size) {
|
|
58
|
+
var _this2 = this;
|
|
45
59
|
(0, _classCallCheck2.default)(this, ObjectURLCache);
|
|
46
|
-
this
|
|
47
|
-
this.cache
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
(0, _defineProperty2.default)(this, "activeRefs", new Map());
|
|
61
|
+
this.cache = new EvictionLRUCache(size, {
|
|
62
|
+
shouldEvict: function shouldEvict(entry) {
|
|
63
|
+
return !_this2.isInUse(entry[0]);
|
|
64
|
+
},
|
|
65
|
+
onEvict: function onEvict(entry) {
|
|
66
|
+
if (entry[1].dataURI) {
|
|
67
|
+
var dataURI = (0, _platformFeatureFlags.fg)('platform_media_safe_blob_url_eviction') ? entry[1].dataURI.split('#')[0] : entry[1].dataURI;
|
|
68
|
+
if (dataURI) {
|
|
69
|
+
URL.revokeObjectURL(dataURI);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
50
72
|
}
|
|
51
73
|
});
|
|
52
74
|
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Marks a cache key as actively in use by a consumer.
|
|
78
|
+
* Multiple consumers can acquire the same key; eviction is
|
|
79
|
+
* blocked until all consumers have released it.
|
|
80
|
+
*/
|
|
53
81
|
return (0, _createClass2.default)(ObjectURLCache, [{
|
|
82
|
+
key: "acquire",
|
|
83
|
+
value: function acquire(key) {
|
|
84
|
+
var _this$activeRefs$get;
|
|
85
|
+
this.activeRefs.set(key, ((_this$activeRefs$get = this.activeRefs.get(key)) !== null && _this$activeRefs$get !== void 0 ? _this$activeRefs$get : 0) + 1);
|
|
86
|
+
}
|
|
87
|
+
}, {
|
|
88
|
+
key: "release",
|
|
89
|
+
value: function release(key) {
|
|
90
|
+
var _this$activeRefs$get2;
|
|
91
|
+
var count = (_this$activeRefs$get2 = this.activeRefs.get(key)) !== null && _this$activeRefs$get2 !== void 0 ? _this$activeRefs$get2 : 0;
|
|
92
|
+
if (count <= 1) {
|
|
93
|
+
this.activeRefs.delete(key);
|
|
94
|
+
} else {
|
|
95
|
+
this.activeRefs.set(key, count - 1);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}, {
|
|
99
|
+
key: "isInUse",
|
|
100
|
+
value: function isInUse(key) {
|
|
101
|
+
var _this$activeRefs$get3;
|
|
102
|
+
return ((_this$activeRefs$get3 = this.activeRefs.get(key)) !== null && _this$activeRefs$get3 !== void 0 ? _this$activeRefs$get3 : 0) > 0;
|
|
103
|
+
}
|
|
104
|
+
}, {
|
|
54
105
|
key: "has",
|
|
55
106
|
value: function has(key) {
|
|
56
107
|
return !!this.cache.find(key);
|
|
@@ -69,7 +120,9 @@ var ObjectURLCache = exports.ObjectURLCache = /*#__PURE__*/function () {
|
|
|
69
120
|
key: "remove",
|
|
70
121
|
value: function remove(key) {
|
|
71
122
|
var removed = this.cache.delete(key);
|
|
72
|
-
|
|
123
|
+
this.activeRefs.delete(key);
|
|
124
|
+
var dataURI = (0, _platformFeatureFlags.fg)('platform_media_safe_blob_url_eviction') ? removed === null || removed === void 0 ? void 0 : removed.dataURI.split('#')[0] : removed === null || removed === void 0 ? void 0 : removed.dataURI;
|
|
125
|
+
dataURI && URL.revokeObjectURL(dataURI);
|
|
73
126
|
}
|
|
74
127
|
}, {
|
|
75
128
|
key: "clear",
|
|
@@ -300,6 +300,18 @@ var useFilePreview = exports.useFilePreview = function useFilePreview(_ref) {
|
|
|
300
300
|
}
|
|
301
301
|
}, [error, nonCriticalError, getAndCacheRemotePreviewRef, identifier.id, identifier.collectionName, resizeMode, isBannedLocalPreview, mediaBlobUrlAttrsRef, mediaClient, preview, requestDimensions, skipRemote, isBackendPreviewReady, localBinary, mediaType, mimeType, upfrontPreviewStatus, dimensions]);
|
|
302
302
|
|
|
303
|
+
//----------------------------------------------------------------
|
|
304
|
+
// Cache ref tracking — prevent blob URL eviction while mounted
|
|
305
|
+
//----------------------------------------------------------------
|
|
306
|
+
(0, _react.useEffect)(function () {
|
|
307
|
+
if (preview) {
|
|
308
|
+
_getPreview.mediaFilePreviewCache.acquire(identifier.id, resizeMode);
|
|
309
|
+
return function () {
|
|
310
|
+
_getPreview.mediaFilePreviewCache.release(identifier.id, resizeMode);
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
}, [preview, identifier.id, resizeMode]);
|
|
314
|
+
|
|
303
315
|
//----------------------------------------------------------------
|
|
304
316
|
// RETURN
|
|
305
317
|
//----------------------------------------------------------------
|
|
@@ -25,6 +25,14 @@ export class CardPreviewCacheImpl {
|
|
|
25
25
|
_defineProperty(this, "clear", () => {
|
|
26
26
|
this.previewCache.clear();
|
|
27
27
|
});
|
|
28
|
+
_defineProperty(this, "acquire", (id, mode) => {
|
|
29
|
+
const cacheKey = getCacheKey(id, mode);
|
|
30
|
+
this.previewCache.acquire(cacheKey);
|
|
31
|
+
});
|
|
32
|
+
_defineProperty(this, "release", (id, mode) => {
|
|
33
|
+
const cacheKey = getCacheKey(id, mode);
|
|
34
|
+
this.previewCache.release(cacheKey);
|
|
35
|
+
});
|
|
28
36
|
this.previewCache = previewCache;
|
|
29
37
|
}
|
|
30
38
|
}
|
|
@@ -1,29 +1,73 @@
|
|
|
1
|
-
import
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import { LRUMap } from 'lru_map';
|
|
3
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
3
4
|
export const PREVIEW_CACHE_LRU_SIZE = 50;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* LRU cache that checks whether the oldest entry should be evicted
|
|
7
|
+
* this means that the cache can grow past the softLimit if `shouldEvict` returns false.
|
|
8
|
+
*
|
|
9
|
+
* When `platform_media_safe_blob_url_eviction` is ON the oldest
|
|
10
|
+
* entry is kept if `shouldEvict` returns false.
|
|
11
|
+
* When the flag is OFF the oldest entry is always evicted.
|
|
12
|
+
*/
|
|
13
|
+
class EvictionLRUCache extends LRUMap {
|
|
14
|
+
constructor(softLimit, options) {
|
|
15
|
+
super(softLimit);
|
|
16
|
+
this.shouldEvict = options === null || options === void 0 ? void 0 : options.shouldEvict;
|
|
17
|
+
this.onEvict = options === null || options === void 0 ? void 0 : options.onEvict;
|
|
8
18
|
}
|
|
9
19
|
shift() {
|
|
20
|
+
if (fg('platform_media_safe_blob_url_eviction')) {
|
|
21
|
+
const oldest = this.oldest;
|
|
22
|
+
if (oldest && this.shouldEvict && !this.shouldEvict([oldest.key, oldest.value])) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
10
26
|
const entry = super.shift();
|
|
11
|
-
this.
|
|
27
|
+
if (entry && this.onEvict) {
|
|
28
|
+
this.onEvict(entry);
|
|
29
|
+
}
|
|
12
30
|
return entry;
|
|
13
31
|
}
|
|
14
|
-
on(event, callback) {
|
|
15
|
-
this.eventEmitter.on(event, callback);
|
|
16
|
-
}
|
|
17
32
|
}
|
|
18
33
|
export class ObjectURLCache {
|
|
19
34
|
constructor(size) {
|
|
20
|
-
this
|
|
21
|
-
this.cache
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
_defineProperty(this, "activeRefs", new Map());
|
|
36
|
+
this.cache = new EvictionLRUCache(size, {
|
|
37
|
+
shouldEvict: entry => !this.isInUse(entry[0]),
|
|
38
|
+
onEvict: entry => {
|
|
39
|
+
if (entry[1].dataURI) {
|
|
40
|
+
const dataURI = fg('platform_media_safe_blob_url_eviction') ? entry[1].dataURI.split('#')[0] : entry[1].dataURI;
|
|
41
|
+
if (dataURI) {
|
|
42
|
+
URL.revokeObjectURL(dataURI);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
24
45
|
}
|
|
25
46
|
});
|
|
26
47
|
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Marks a cache key as actively in use by a consumer.
|
|
51
|
+
* Multiple consumers can acquire the same key; eviction is
|
|
52
|
+
* blocked until all consumers have released it.
|
|
53
|
+
*/
|
|
54
|
+
acquire(key) {
|
|
55
|
+
var _this$activeRefs$get;
|
|
56
|
+
this.activeRefs.set(key, ((_this$activeRefs$get = this.activeRefs.get(key)) !== null && _this$activeRefs$get !== void 0 ? _this$activeRefs$get : 0) + 1);
|
|
57
|
+
}
|
|
58
|
+
release(key) {
|
|
59
|
+
var _this$activeRefs$get2;
|
|
60
|
+
const count = (_this$activeRefs$get2 = this.activeRefs.get(key)) !== null && _this$activeRefs$get2 !== void 0 ? _this$activeRefs$get2 : 0;
|
|
61
|
+
if (count <= 1) {
|
|
62
|
+
this.activeRefs.delete(key);
|
|
63
|
+
} else {
|
|
64
|
+
this.activeRefs.set(key, count - 1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
isInUse(key) {
|
|
68
|
+
var _this$activeRefs$get3;
|
|
69
|
+
return ((_this$activeRefs$get3 = this.activeRefs.get(key)) !== null && _this$activeRefs$get3 !== void 0 ? _this$activeRefs$get3 : 0) > 0;
|
|
70
|
+
}
|
|
27
71
|
has(key) {
|
|
28
72
|
return !!this.cache.find(key);
|
|
29
73
|
}
|
|
@@ -35,7 +79,9 @@ export class ObjectURLCache {
|
|
|
35
79
|
}
|
|
36
80
|
remove(key) {
|
|
37
81
|
const removed = this.cache.delete(key);
|
|
38
|
-
|
|
82
|
+
this.activeRefs.delete(key);
|
|
83
|
+
const dataURI = fg('platform_media_safe_blob_url_eviction') ? removed === null || removed === void 0 ? void 0 : removed.dataURI.split('#')[0] : removed === null || removed === void 0 ? void 0 : removed.dataURI;
|
|
84
|
+
dataURI && URL.revokeObjectURL(dataURI);
|
|
39
85
|
}
|
|
40
86
|
clear() {
|
|
41
87
|
this.cache.clear();
|
|
@@ -275,6 +275,18 @@ export const useFilePreview = ({
|
|
|
275
275
|
}
|
|
276
276
|
}, [error, nonCriticalError, getAndCacheRemotePreviewRef, identifier.id, identifier.collectionName, resizeMode, isBannedLocalPreview, mediaBlobUrlAttrsRef, mediaClient, preview, requestDimensions, skipRemote, isBackendPreviewReady, localBinary, mediaType, mimeType, upfrontPreviewStatus, dimensions]);
|
|
277
277
|
|
|
278
|
+
//----------------------------------------------------------------
|
|
279
|
+
// Cache ref tracking — prevent blob URL eviction while mounted
|
|
280
|
+
//----------------------------------------------------------------
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
if (preview) {
|
|
283
|
+
mediaFilePreviewCache.acquire(identifier.id, resizeMode);
|
|
284
|
+
return () => {
|
|
285
|
+
mediaFilePreviewCache.release(identifier.id, resizeMode);
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}, [preview, identifier.id, resizeMode]);
|
|
289
|
+
|
|
278
290
|
//----------------------------------------------------------------
|
|
279
291
|
// RETURN
|
|
280
292
|
//----------------------------------------------------------------
|
|
@@ -28,6 +28,14 @@ export var CardPreviewCacheImpl = /*#__PURE__*/_createClass(function CardPreview
|
|
|
28
28
|
_defineProperty(this, "clear", function () {
|
|
29
29
|
_this.previewCache.clear();
|
|
30
30
|
});
|
|
31
|
+
_defineProperty(this, "acquire", function (id, mode) {
|
|
32
|
+
var cacheKey = getCacheKey(id, mode);
|
|
33
|
+
_this.previewCache.acquire(cacheKey);
|
|
34
|
+
});
|
|
35
|
+
_defineProperty(this, "release", function (id, mode) {
|
|
36
|
+
var cacheKey = getCacheKey(id, mode);
|
|
37
|
+
_this.previewCache.release(cacheKey);
|
|
38
|
+
});
|
|
31
39
|
this.previewCache = previewCache;
|
|
32
40
|
});
|
|
33
41
|
export var mediaFilePreviewCache = new CardPreviewCacheImpl(createObjectURLCache());
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
1
2
|
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
|
|
2
3
|
import _createClass from "@babel/runtime/helpers/createClass";
|
|
3
4
|
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
|
|
@@ -7,43 +8,93 @@ import _inherits from "@babel/runtime/helpers/inherits";
|
|
|
7
8
|
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
|
|
8
9
|
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
|
|
9
10
|
function _superPropGet(t, o, e, r) { var p = _get(_getPrototypeOf(1 & r ? t.prototype : t), o, e); return 2 & r && "function" == typeof p ? function (t) { return p.apply(e, t); } : p; }
|
|
10
|
-
import { EventEmitter2 } from 'eventemitter2';
|
|
11
11
|
import { LRUMap } from 'lru_map';
|
|
12
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
12
13
|
export var PREVIEW_CACHE_LRU_SIZE = 50;
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* LRU cache that checks whether the oldest entry should be evicted
|
|
16
|
+
* this means that the cache can grow past the softLimit if `shouldEvict` returns false.
|
|
17
|
+
*
|
|
18
|
+
* When `platform_media_safe_blob_url_eviction` is ON the oldest
|
|
19
|
+
* entry is kept if `shouldEvict` returns false.
|
|
20
|
+
* When the flag is OFF the oldest entry is always evicted.
|
|
21
|
+
*/
|
|
22
|
+
var EvictionLRUCache = /*#__PURE__*/function (_LRUMap) {
|
|
23
|
+
function EvictionLRUCache(softLimit, options) {
|
|
15
24
|
var _this;
|
|
16
|
-
_classCallCheck(this,
|
|
17
|
-
_this = _callSuper(this,
|
|
18
|
-
_this.
|
|
25
|
+
_classCallCheck(this, EvictionLRUCache);
|
|
26
|
+
_this = _callSuper(this, EvictionLRUCache, [softLimit]);
|
|
27
|
+
_this.shouldEvict = options === null || options === void 0 ? void 0 : options.shouldEvict;
|
|
28
|
+
_this.onEvict = options === null || options === void 0 ? void 0 : options.onEvict;
|
|
19
29
|
return _this;
|
|
20
30
|
}
|
|
21
|
-
_inherits(
|
|
22
|
-
return _createClass(
|
|
31
|
+
_inherits(EvictionLRUCache, _LRUMap);
|
|
32
|
+
return _createClass(EvictionLRUCache, [{
|
|
23
33
|
key: "shift",
|
|
24
34
|
value: function shift() {
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
if (fg('platform_media_safe_blob_url_eviction')) {
|
|
36
|
+
var oldest = this.oldest;
|
|
37
|
+
if (oldest && this.shouldEvict && !this.shouldEvict([oldest.key, oldest.value])) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
var entry = _superPropGet(EvictionLRUCache, "shift", this, 3)([]);
|
|
42
|
+
if (entry && this.onEvict) {
|
|
43
|
+
this.onEvict(entry);
|
|
44
|
+
}
|
|
27
45
|
return entry;
|
|
28
46
|
}
|
|
29
|
-
}, {
|
|
30
|
-
key: "on",
|
|
31
|
-
value: function on(event, callback) {
|
|
32
|
-
this.eventEmitter.on(event, callback);
|
|
33
|
-
}
|
|
34
47
|
}]);
|
|
35
48
|
}(LRUMap);
|
|
36
49
|
export var ObjectURLCache = /*#__PURE__*/function () {
|
|
37
50
|
function ObjectURLCache(size) {
|
|
51
|
+
var _this2 = this;
|
|
38
52
|
_classCallCheck(this, ObjectURLCache);
|
|
39
|
-
this
|
|
40
|
-
this.cache
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
_defineProperty(this, "activeRefs", new Map());
|
|
54
|
+
this.cache = new EvictionLRUCache(size, {
|
|
55
|
+
shouldEvict: function shouldEvict(entry) {
|
|
56
|
+
return !_this2.isInUse(entry[0]);
|
|
57
|
+
},
|
|
58
|
+
onEvict: function onEvict(entry) {
|
|
59
|
+
if (entry[1].dataURI) {
|
|
60
|
+
var dataURI = fg('platform_media_safe_blob_url_eviction') ? entry[1].dataURI.split('#')[0] : entry[1].dataURI;
|
|
61
|
+
if (dataURI) {
|
|
62
|
+
URL.revokeObjectURL(dataURI);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
43
65
|
}
|
|
44
66
|
});
|
|
45
67
|
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Marks a cache key as actively in use by a consumer.
|
|
71
|
+
* Multiple consumers can acquire the same key; eviction is
|
|
72
|
+
* blocked until all consumers have released it.
|
|
73
|
+
*/
|
|
46
74
|
return _createClass(ObjectURLCache, [{
|
|
75
|
+
key: "acquire",
|
|
76
|
+
value: function acquire(key) {
|
|
77
|
+
var _this$activeRefs$get;
|
|
78
|
+
this.activeRefs.set(key, ((_this$activeRefs$get = this.activeRefs.get(key)) !== null && _this$activeRefs$get !== void 0 ? _this$activeRefs$get : 0) + 1);
|
|
79
|
+
}
|
|
80
|
+
}, {
|
|
81
|
+
key: "release",
|
|
82
|
+
value: function release(key) {
|
|
83
|
+
var _this$activeRefs$get2;
|
|
84
|
+
var count = (_this$activeRefs$get2 = this.activeRefs.get(key)) !== null && _this$activeRefs$get2 !== void 0 ? _this$activeRefs$get2 : 0;
|
|
85
|
+
if (count <= 1) {
|
|
86
|
+
this.activeRefs.delete(key);
|
|
87
|
+
} else {
|
|
88
|
+
this.activeRefs.set(key, count - 1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}, {
|
|
92
|
+
key: "isInUse",
|
|
93
|
+
value: function isInUse(key) {
|
|
94
|
+
var _this$activeRefs$get3;
|
|
95
|
+
return ((_this$activeRefs$get3 = this.activeRefs.get(key)) !== null && _this$activeRefs$get3 !== void 0 ? _this$activeRefs$get3 : 0) > 0;
|
|
96
|
+
}
|
|
97
|
+
}, {
|
|
47
98
|
key: "has",
|
|
48
99
|
value: function has(key) {
|
|
49
100
|
return !!this.cache.find(key);
|
|
@@ -62,7 +113,9 @@ export var ObjectURLCache = /*#__PURE__*/function () {
|
|
|
62
113
|
key: "remove",
|
|
63
114
|
value: function remove(key) {
|
|
64
115
|
var removed = this.cache.delete(key);
|
|
65
|
-
|
|
116
|
+
this.activeRefs.delete(key);
|
|
117
|
+
var dataURI = fg('platform_media_safe_blob_url_eviction') ? removed === null || removed === void 0 ? void 0 : removed.dataURI.split('#')[0] : removed === null || removed === void 0 ? void 0 : removed.dataURI;
|
|
118
|
+
dataURI && URL.revokeObjectURL(dataURI);
|
|
66
119
|
}
|
|
67
120
|
}, {
|
|
68
121
|
key: "clear",
|
|
@@ -293,6 +293,18 @@ export var useFilePreview = function useFilePreview(_ref) {
|
|
|
293
293
|
}
|
|
294
294
|
}, [error, nonCriticalError, getAndCacheRemotePreviewRef, identifier.id, identifier.collectionName, resizeMode, isBannedLocalPreview, mediaBlobUrlAttrsRef, mediaClient, preview, requestDimensions, skipRemote, isBackendPreviewReady, localBinary, mediaType, mimeType, upfrontPreviewStatus, dimensions]);
|
|
295
295
|
|
|
296
|
+
//----------------------------------------------------------------
|
|
297
|
+
// Cache ref tracking — prevent blob URL eviction while mounted
|
|
298
|
+
//----------------------------------------------------------------
|
|
299
|
+
useEffect(function () {
|
|
300
|
+
if (preview) {
|
|
301
|
+
mediaFilePreviewCache.acquire(identifier.id, resizeMode);
|
|
302
|
+
return function () {
|
|
303
|
+
mediaFilePreviewCache.release(identifier.id, resizeMode);
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
}, [preview, identifier.id, resizeMode]);
|
|
307
|
+
|
|
296
308
|
//----------------------------------------------------------------
|
|
297
309
|
// RETURN
|
|
298
310
|
//----------------------------------------------------------------
|
|
@@ -8,6 +8,8 @@ export interface MediaFilePreviewCache {
|
|
|
8
8
|
set(id: string, mode: Mode, cardPreview: MediaFilePreview): void;
|
|
9
9
|
remove(id: string, mode: Mode): void;
|
|
10
10
|
clear(): void;
|
|
11
|
+
acquire(id: string, mode: Mode): void;
|
|
12
|
+
release(id: string, mode: Mode): void;
|
|
11
13
|
}
|
|
12
14
|
export declare class CardPreviewCacheImpl implements MediaFilePreviewCache {
|
|
13
15
|
private previewCache;
|
|
@@ -16,6 +18,8 @@ export declare class CardPreviewCacheImpl implements MediaFilePreviewCache {
|
|
|
16
18
|
set: (id: string, mode: Mode, cardPreview: MediaFilePreview) => void;
|
|
17
19
|
remove: (id: string, mode: Mode) => void;
|
|
18
20
|
clear: () => void;
|
|
21
|
+
acquire: (id: string, mode: Mode) => void;
|
|
22
|
+
release: (id: string, mode: Mode) => void;
|
|
19
23
|
}
|
|
20
24
|
export declare const mediaFilePreviewCache: CardPreviewCacheImpl;
|
|
21
25
|
export {};
|
|
@@ -2,7 +2,16 @@ import { type MediaFilePreview } from '../types';
|
|
|
2
2
|
export declare const PREVIEW_CACHE_LRU_SIZE = 50;
|
|
3
3
|
export declare class ObjectURLCache {
|
|
4
4
|
private readonly cache;
|
|
5
|
+
private readonly activeRefs;
|
|
5
6
|
constructor(size: number);
|
|
7
|
+
/**
|
|
8
|
+
* Marks a cache key as actively in use by a consumer.
|
|
9
|
+
* Multiple consumers can acquire the same key; eviction is
|
|
10
|
+
* blocked until all consumers have released it.
|
|
11
|
+
*/
|
|
12
|
+
acquire(key: string): void;
|
|
13
|
+
release(key: string): void;
|
|
14
|
+
private isInUse;
|
|
6
15
|
has(key: string): boolean;
|
|
7
16
|
get(key: string): MediaFilePreview | undefined;
|
|
8
17
|
set(key: string, value: MediaFilePreview): void;
|
|
@@ -8,6 +8,8 @@ export interface MediaFilePreviewCache {
|
|
|
8
8
|
set(id: string, mode: Mode, cardPreview: MediaFilePreview): void;
|
|
9
9
|
remove(id: string, mode: Mode): void;
|
|
10
10
|
clear(): void;
|
|
11
|
+
acquire(id: string, mode: Mode): void;
|
|
12
|
+
release(id: string, mode: Mode): void;
|
|
11
13
|
}
|
|
12
14
|
export declare class CardPreviewCacheImpl implements MediaFilePreviewCache {
|
|
13
15
|
private previewCache;
|
|
@@ -16,6 +18,8 @@ export declare class CardPreviewCacheImpl implements MediaFilePreviewCache {
|
|
|
16
18
|
set: (id: string, mode: Mode, cardPreview: MediaFilePreview) => void;
|
|
17
19
|
remove: (id: string, mode: Mode) => void;
|
|
18
20
|
clear: () => void;
|
|
21
|
+
acquire: (id: string, mode: Mode) => void;
|
|
22
|
+
release: (id: string, mode: Mode) => void;
|
|
19
23
|
}
|
|
20
24
|
export declare const mediaFilePreviewCache: CardPreviewCacheImpl;
|
|
21
25
|
export {};
|
|
@@ -2,7 +2,16 @@ import { type MediaFilePreview } from '../types';
|
|
|
2
2
|
export declare const PREVIEW_CACHE_LRU_SIZE = 50;
|
|
3
3
|
export declare class ObjectURLCache {
|
|
4
4
|
private readonly cache;
|
|
5
|
+
private readonly activeRefs;
|
|
5
6
|
constructor(size: number);
|
|
7
|
+
/**
|
|
8
|
+
* Marks a cache key as actively in use by a consumer.
|
|
9
|
+
* Multiple consumers can acquire the same key; eviction is
|
|
10
|
+
* blocked until all consumers have released it.
|
|
11
|
+
*/
|
|
12
|
+
acquire(key: string): void;
|
|
13
|
+
release(key: string): void;
|
|
14
|
+
private isInUse;
|
|
6
15
|
has(key: string): boolean;
|
|
7
16
|
get(key: string): MediaFilePreview | undefined;
|
|
8
17
|
set(key: string, value: MediaFilePreview): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/media-file-preview",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.4",
|
|
4
4
|
"description": "A React Hook to fetch and render file previews. It's overloaded with fancy features like SSR, lazy loading, memory cache and local preview.",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -37,7 +37,6 @@
|
|
|
37
37
|
"@atlaskit/platform-feature-flags": "^1.1.0",
|
|
38
38
|
"@atlaskit/react-ufo": "^5.4.0",
|
|
39
39
|
"@babel/runtime": "^7.0.0",
|
|
40
|
-
"eventemitter2": "^4.1.0",
|
|
41
40
|
"lru_map": "^0.4.1"
|
|
42
41
|
},
|
|
43
42
|
"peerDependencies": {
|
|
@@ -104,6 +103,9 @@
|
|
|
104
103
|
},
|
|
105
104
|
"platform_media_cross_client_copy_with_auth": {
|
|
106
105
|
"type": "boolean"
|
|
106
|
+
},
|
|
107
|
+
"platform_media_safe_blob_url_eviction": {
|
|
108
|
+
"type": "boolean"
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
}
|