@modern-js/runtime-utils
Version:
A Progressive React Framework for modern web development.
1,033 lines (1,032 loc) • 30.1 kB
JavaScript
import { _ as _async_to_generator } from "@swc/helpers/_/_async_to_generator";
import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
import { _ as _instanceof } from "@swc/helpers/_/_instanceof";
import { _ as _object_spread } from "@swc/helpers/_/_object_spread";
import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
import { _ as _to_consumable_array } from "@swc/helpers/_/_to_consumable_array";
import { _ as _type_of } from "@swc/helpers/_/_type_of";
import { _ as _ts_generator } from "@swc/helpers/_/_ts_generator";
import { LRUCache } from "lru-cache";
import { getAsyncLocalStorage } from "./async_storage";
var CacheSize = {
KB: 1024,
MB: 1024 * 1024,
GB: 1024 * 1024 * 1024
};
var CacheTime = {
SECOND: 1e3,
MINUTE: 60 * 1e3,
HOUR: 60 * 60 * 1e3,
DAY: 24 * 60 * 60 * 1e3,
WEEK: 7 * 24 * 60 * 60 * 1e3,
MONTH: 30 * 24 * 60 * 60 * 1e3
};
function estimateObjectSize(data) {
var type = typeof data === "undefined" ? "undefined" : _type_of(data);
if (type === "number")
return 8;
if (type === "boolean")
return 4;
if (type === "string")
return Math.max(data.length * 2, 1);
if (data === null || data === void 0)
return 1;
if (ArrayBuffer.isView(data)) {
return Math.max(data.byteLength, 1);
}
if (Array.isArray(data)) {
return Math.max(data.reduce(function(acc, item) {
return acc + estimateObjectSize(item);
}, 0), 1);
}
if (_instanceof(data, Map) || _instanceof(data, Set)) {
return 1024;
}
if (_instanceof(data, Date)) {
return 8;
}
if (type === "object") {
return Math.max(Object.entries(data).reduce(function(acc, param) {
var _param = _sliced_to_array(param, 2), key = _param[0], value = _param[1];
return acc + key.length * 2 + estimateObjectSize(value);
}, 0), 1);
}
return 1;
}
var MemoryContainer = /* @__PURE__ */ function() {
"use strict";
function MemoryContainer2(options) {
_class_call_check(this, MemoryContainer2);
var _options_maxSize;
this.lru = new LRUCache({
maxSize: (_options_maxSize = options === null || options === void 0 ? void 0 : options.maxSize) !== null && _options_maxSize !== void 0 ? _options_maxSize : CacheSize.GB,
sizeCalculation: estimateObjectSize,
updateAgeOnGet: true,
updateAgeOnHas: true
});
}
var _proto = MemoryContainer2.prototype;
_proto.get = function get(key) {
var _this = this;
return _async_to_generator(function() {
return _ts_generator(this, function(_state) {
return [
2,
_this.lru.get(key)
];
});
})();
};
_proto.set = function set(key, value, options) {
var _this = this;
return _async_to_generator(function() {
return _ts_generator(this, function(_state) {
if (options === null || options === void 0 ? void 0 : options.ttl) {
_this.lru.set(key, value, {
ttl: options.ttl * 1e3
});
} else {
_this.lru.set(key, value);
}
return [
2
];
});
})();
};
_proto.has = function has(key) {
var _this = this;
return _async_to_generator(function() {
return _ts_generator(this, function(_state) {
return [
2,
_this.lru.has(key)
];
});
})();
};
_proto.delete = function _delete(key) {
var _this = this;
return _async_to_generator(function() {
return _ts_generator(this, function(_state) {
return [
2,
_this.lru.delete(key)
];
});
})();
};
_proto.clear = function clear() {
var _this = this;
return _async_to_generator(function() {
return _ts_generator(this, function(_state) {
_this.lru.clear();
return [
2
];
});
})();
};
return MemoryContainer2;
}();
var isServer = typeof window === "undefined";
var requestCacheMap = /* @__PURE__ */ new WeakMap();
var TAG_PREFIX = "tag:";
var CACHE_PREFIX = "modernjs_cache:";
var ongoingRevalidations = /* @__PURE__ */ new Map();
var storage;
var cacheConfig = {
maxSize: CacheSize.GB
};
function getStorage() {
if (storage) {
return storage;
}
if (cacheConfig.container) {
storage = cacheConfig.container;
} else {
storage = new MemoryContainer({
maxSize: cacheConfig.maxSize
});
}
return storage;
}
function configureCache(config) {
cacheConfig = _object_spread({}, cacheConfig, config);
storage = void 0;
}
function generateKey(args) {
return JSON.stringify(args, function(_, value) {
if (value && (typeof value === "undefined" ? "undefined" : _type_of(value)) === "object" && !Array.isArray(value)) {
return Object.keys(value).sort().reduce(function(result, key) {
result[key] = value[key];
return result;
}, {});
}
return value;
});
}
function generateStableFunctionId(fn) {
var fnString = fn.toString();
var hash = 0;
for (var i = 0; i < fnString.length; i++) {
var char = fnString.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash = hash & hash;
}
return "fn_".concat(fn.name || "anonymous", "_").concat(Math.abs(hash).toString(36));
}
function cache(fn, options) {
return /* @__PURE__ */ _async_to_generator(function() {
var _len, args, _key, _storage_useContext, storage2, request, shouldDisableCaching, requestCache, fnCache, key, promise, data, error, tag, _options_maxAge, maxAge, _options_revalidate, revalidate, customKey, onCache, getKey, unstable_shouldCache, missReason, currentStorage, now, tags, genKey, finalKey, functionId, storageKey, shouldDisableCaching1, _asyncStorage_useContext, asyncStorage, request1, cached, cacheItem, age, revalidationPromise, data1, shouldCache, error1, data2, onCache1;
var _arguments = arguments;
return _ts_generator(this, function(_state) {
switch (_state.label) {
case 0:
for (_len = _arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = _arguments[_key];
}
if (!(isServer && typeof options === "undefined"))
return [
3,
7
];
storage2 = getAsyncLocalStorage();
request = storage2 === null || storage2 === void 0 ? void 0 : (_storage_useContext = storage2.useContext()) === null || _storage_useContext === void 0 ? void 0 : _storage_useContext.request;
if (!request)
return [
3,
6
];
shouldDisableCaching = false;
if (!cacheConfig.unstable_shouldDisable)
return [
3,
2
];
return [
4,
cacheConfig.unstable_shouldDisable({
request
})
];
case 1:
shouldDisableCaching = _state.sent();
_state.label = 2;
case 2:
if (shouldDisableCaching) {
return [
2,
fn.apply(void 0, _to_consumable_array(args))
];
}
requestCache = requestCacheMap.get(request);
if (!requestCache) {
requestCache = /* @__PURE__ */ new Map();
requestCacheMap.set(request, requestCache);
}
fnCache = requestCache.get(fn);
if (!fnCache) {
fnCache = /* @__PURE__ */ new Map();
requestCache.set(fn, fnCache);
}
key = generateKey(args);
if (fnCache.has(key)) {
return [
2,
fnCache.get(key)
];
}
promise = fn.apply(void 0, _to_consumable_array(args));
fnCache.set(key, promise);
_state.label = 3;
case 3:
_state.trys.push([
3,
5,
,
6
]);
return [
4,
promise
];
case 4:
data = _state.sent();
return [
2,
data
];
case 5:
error = _state.sent();
fnCache.delete(key);
throw error;
case 6:
return [
3,
23
];
case 7:
if (!(typeof options !== "undefined"))
return [
3,
22
];
_state.label = 8;
case 8:
_state.trys.push([
8,
19,
,
21
]);
tag = options.tag, _options_maxAge = options.maxAge, maxAge = _options_maxAge === void 0 ? CacheTime.MINUTE * 5 : _options_maxAge, _options_revalidate = options.revalidate, revalidate = _options_revalidate === void 0 ? 0 : _options_revalidate, customKey = options.customKey, onCache = options.onCache, getKey = options.getKey, unstable_shouldCache = options.unstable_shouldCache;
currentStorage = getStorage();
now = Date.now();
tags = tag ? Array.isArray(tag) ? tag : [
tag
] : [];
genKey = getKey ? getKey.apply(void 0, _to_consumable_array(args)) : generateKey(args);
if (customKey) {
finalKey = customKey({
params: args,
fn,
generatedKey: genKey
});
} else {
functionId = generateStableFunctionId(fn);
finalKey = "".concat(functionId, ":").concat(genKey);
}
storageKey = "".concat(CACHE_PREFIX).concat(finalKey);
shouldDisableCaching1 = false;
if (!(isServer && cacheConfig.unstable_shouldDisable))
return [
3,
10
];
asyncStorage = getAsyncLocalStorage();
request1 = asyncStorage === null || asyncStorage === void 0 ? void 0 : (_asyncStorage_useContext = asyncStorage.useContext()) === null || _asyncStorage_useContext === void 0 ? void 0 : _asyncStorage_useContext.request;
if (!request1)
return [
3,
10
];
return [
4,
cacheConfig.unstable_shouldDisable({
request: request1
})
];
case 9:
shouldDisableCaching1 = _state.sent();
_state.label = 10;
case 10:
if (!!shouldDisableCaching1)
return [
3,
12
];
return [
4,
currentStorage.get(storageKey)
];
case 11:
cached = _state.sent();
if (cached) {
try {
cacheItem = cached;
age = now - cacheItem.timestamp;
if (age < maxAge) {
onCache === null || onCache === void 0 ? void 0 : onCache({
status: "hit",
key: finalKey,
params: args,
result: cacheItem.data
});
return [
2,
cacheItem.data
];
}
if (revalidate > 0 && age < maxAge + revalidate) {
onCache === null || onCache === void 0 ? void 0 : onCache({
status: "stale",
key: finalKey,
params: args,
result: cacheItem.data
});
if (!ongoingRevalidations.has(storageKey)) {
revalidationPromise = _async_to_generator(function() {
var newData, shouldCache2, error2, _asyncStorage_useContext_monitors, _asyncStorage_useContext2, asyncStorage2;
return _ts_generator(this, function(_state2) {
switch (_state2.label) {
case 0:
_state2.trys.push([
0,
6,
7,
8
]);
return [
4,
fn.apply(void 0, _to_consumable_array(args))
];
case 1:
newData = _state2.sent();
shouldCache2 = true;
if (!unstable_shouldCache)
return [
3,
3
];
return [
4,
unstable_shouldCache({
params: args,
result: newData
})
];
case 2:
shouldCache2 = _state2.sent();
_state2.label = 3;
case 3:
if (!shouldCache2)
return [
3,
5
];
return [
4,
setCacheItem(currentStorage, storageKey, newData, tags, maxAge, revalidate)
];
case 4:
_state2.sent();
_state2.label = 5;
case 5:
return [
3,
8
];
case 6:
error2 = _state2.sent();
if (isServer) {
;
asyncStorage2 = getAsyncLocalStorage();
asyncStorage2 === null || asyncStorage2 === void 0 ? void 0 : (_asyncStorage_useContext2 = asyncStorage2.useContext()) === null || _asyncStorage_useContext2 === void 0 ? void 0 : (_asyncStorage_useContext_monitors = _asyncStorage_useContext2.monitors) === null || _asyncStorage_useContext_monitors === void 0 ? void 0 : _asyncStorage_useContext_monitors.error(error2.message);
} else {
console.error("Background revalidation failed:", error2);
}
return [
3,
8
];
case 7:
ongoingRevalidations.delete(storageKey);
return [
7
];
case 8:
return [
2
];
}
});
})();
ongoingRevalidations.set(storageKey, revalidationPromise);
}
return [
2,
cacheItem.data
];
}
missReason = 3;
} catch (error2) {
console.warn("Failed to parse cached data:", error2);
missReason = 4;
}
} else {
missReason = 2;
}
return [
3,
13
];
case 12:
missReason = 1;
_state.label = 13;
case 13:
return [
4,
fn.apply(void 0, _to_consumable_array(args))
];
case 14:
data1 = _state.sent();
if (!!shouldDisableCaching1)
return [
3,
18
];
shouldCache = true;
if (!unstable_shouldCache)
return [
3,
16
];
return [
4,
unstable_shouldCache({
params: args,
result: data1
})
];
case 15:
shouldCache = _state.sent();
_state.label = 16;
case 16:
if (!shouldCache)
return [
3,
18
];
return [
4,
setCacheItem(currentStorage, storageKey, data1, tags, maxAge, revalidate)
];
case 17:
_state.sent();
_state.label = 18;
case 18:
onCache === null || onCache === void 0 ? void 0 : onCache({
status: "miss",
key: finalKey,
params: args,
result: data1,
reason: missReason
});
return [
2,
data1
];
case 19:
error1 = _state.sent();
console.warn("Cache operation failed, falling back to direct execution:", error1);
return [
4,
fn.apply(void 0, _to_consumable_array(args))
];
case 20:
data2 = _state.sent();
onCache1 = options.onCache;
try {
onCache1 === null || onCache1 === void 0 ? void 0 : onCache1({
status: "miss",
key: "cache_failed",
params: args,
result: data2,
reason: 5
});
} catch (callbackError) {
console.warn("Failed to call onCache callback:", callbackError);
}
return [
2,
data2
];
case 21:
return [
3,
23
];
case 22:
console.warn("The cache function will not work because it runs on the browser and there are no options are provided.");
return [
2,
fn.apply(void 0, _to_consumable_array(args))
];
case 23:
return [
2
];
}
});
});
}
function setCacheItem(storage2, storageKey, data, tags, maxAge, revalidate) {
return _setCacheItem.apply(this, arguments);
}
function _setCacheItem() {
_setCacheItem = _async_to_generator(function(storage2, storageKey, data, tags, maxAge, revalidate) {
var newItem, ttl;
return _ts_generator(this, function(_state) {
switch (_state.label) {
case 0:
newItem = {
data,
timestamp: Date.now(),
tags: tags.length > 0 ? tags : void 0
};
ttl = (maxAge + revalidate) / 1e3;
return [
4,
storage2.set(storageKey, newItem, {
ttl: ttl > 0 ? ttl : void 0
})
];
case 1:
_state.sent();
return [
4,
updateTagRelationships(storage2, storageKey, tags)
];
case 2:
_state.sent();
return [
2
];
}
});
});
return _setCacheItem.apply(this, arguments);
}
function updateTagRelationships(storage2, storageKey, tags) {
return _updateTagRelationships.apply(this, arguments);
}
function _updateTagRelationships() {
_updateTagRelationships = _async_to_generator(function(storage2, storageKey, tags) {
var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, tag, tagStoreKey, keyList, keyArray, err;
return _ts_generator(this, function(_state) {
switch (_state.label) {
case 0:
_iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
_state.label = 1;
case 1:
_state.trys.push([
1,
7,
8,
9
]);
_iterator = tags[Symbol.iterator]();
_state.label = 2;
case 2:
if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done))
return [
3,
6
];
tag = _step.value;
tagStoreKey = "".concat(TAG_PREFIX).concat(tag);
return [
4,
storage2.get(tagStoreKey)
];
case 3:
keyList = _state.sent();
keyArray = keyList || [];
if (!keyArray.includes(storageKey)) {
keyArray.push(storageKey);
}
return [
4,
storage2.set(tagStoreKey, keyArray)
];
case 4:
_state.sent();
_state.label = 5;
case 5:
_iteratorNormalCompletion = true;
return [
3,
2
];
case 6:
return [
3,
9
];
case 7:
err = _state.sent();
_didIteratorError = true;
_iteratorError = err;
return [
3,
9
];
case 8:
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
return [
7
];
case 9:
return [
2
];
}
});
});
return _updateTagRelationships.apply(this, arguments);
}
function removeKeyFromTags(storage2, storageKey, tags) {
return _removeKeyFromTags.apply(this, arguments);
}
function _removeKeyFromTags() {
_removeKeyFromTags = _async_to_generator(function(storage2, storageKey, tags) {
var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, tag, tagStoreKey, keyList, keyArray, updatedKeyList, error, err;
return _ts_generator(this, function(_state) {
switch (_state.label) {
case 0:
_iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
_state.label = 1;
case 1:
_state.trys.push([
1,
12,
13,
14
]);
_iterator = tags[Symbol.iterator]();
_state.label = 2;
case 2:
if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done))
return [
3,
11
];
tag = _step.value;
tagStoreKey = "".concat(TAG_PREFIX).concat(tag);
return [
4,
storage2.get(tagStoreKey)
];
case 3:
keyList = _state.sent();
if (!keyList)
return [
3,
10
];
_state.label = 4;
case 4:
_state.trys.push([
4,
9,
,
10
]);
keyArray = Array.isArray(keyList) ? keyList : [];
updatedKeyList = keyArray.filter(function(key) {
return key !== storageKey;
});
if (!(updatedKeyList.length > 0))
return [
3,
6
];
return [
4,
storage2.set(tagStoreKey, updatedKeyList)
];
case 5:
_state.sent();
return [
3,
8
];
case 6:
return [
4,
storage2.delete(tagStoreKey)
];
case 7:
_state.sent();
_state.label = 8;
case 8:
return [
3,
10
];
case 9:
error = _state.sent();
console.warn("Failed to process tag key list for tag ".concat(tag, ":"), error);
return [
3,
10
];
case 10:
_iteratorNormalCompletion = true;
return [
3,
2
];
case 11:
return [
3,
14
];
case 12:
err = _state.sent();
_didIteratorError = true;
_iteratorError = err;
return [
3,
14
];
case 13:
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
return [
7
];
case 14:
return [
2
];
}
});
});
return _removeKeyFromTags.apply(this, arguments);
}
function withRequestCache(handler) {
if (!isServer) {
return handler;
}
return function() {
var _ref = _async_to_generator(function(req) {
var _len, args, _key, storage2;
var _arguments = arguments;
return _ts_generator(this, function(_state) {
for (_len = _arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = _arguments[_key];
}
storage2 = getAsyncLocalStorage();
return [
2,
storage2.run({
request: req
}, function() {
return handler.apply(void 0, [
req
].concat(_to_consumable_array(args)));
})
];
});
});
return function(req) {
return _ref.apply(this, arguments);
};
}();
}
function revalidateTag(tag) {
return _revalidateTag.apply(this, arguments);
}
function _revalidateTag() {
_revalidateTag = _async_to_generator(function(tag) {
var currentStorage, tagStoreKey, keyList, keyArray, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, cacheKey, cached, cacheItem, otherTags, error, err, error1;
return _ts_generator(this, function(_state) {
switch (_state.label) {
case 0:
currentStorage = getStorage();
tagStoreKey = "".concat(TAG_PREFIX).concat(tag);
return [
4,
currentStorage.get(tagStoreKey)
];
case 1:
keyList = _state.sent();
if (!keyList)
return [
3,
19
];
_state.label = 2;
case 2:
_state.trys.push([
2,
18,
,
19
]);
keyArray = Array.isArray(keyList) ? keyList : [];
_iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = void 0;
_state.label = 3;
case 3:
_state.trys.push([
3,
14,
15,
16
]);
_iterator = keyArray[Symbol.iterator]();
_state.label = 4;
case 4:
if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done))
return [
3,
13
];
cacheKey = _step.value;
return [
4,
currentStorage.get(cacheKey)
];
case 5:
cached = _state.sent();
if (!cached)
return [
3,
10
];
_state.label = 6;
case 6:
_state.trys.push([
6,
9,
,
10
]);
cacheItem = cached;
if (!cacheItem.tags)
return [
3,
8
];
otherTags = cacheItem.tags.filter(function(t) {
return t !== tag;
});
return [
4,
removeKeyFromTags(currentStorage, cacheKey, otherTags)
];
case 7:
_state.sent();
_state.label = 8;
case 8:
return [
3,
10
];
case 9:
error = _state.sent();
console.warn("Failed to parse cached data while revalidating:", error);
return [
3,
10
];
case 10:
return [
4,
currentStorage.delete(cacheKey)
];
case 11:
_state.sent();
_state.label = 12;
case 12:
_iteratorNormalCompletion = true;
return [
3,
4
];
case 13:
return [
3,
16
];
case 14:
err = _state.sent();
_didIteratorError = true;
_iteratorError = err;
return [
3,
16
];
case 15:
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
return [
7
];
case 16:
return [
4,
currentStorage.delete(tagStoreKey)
];
case 17:
_state.sent();
return [
3,
19
];
case 18:
error1 = _state.sent();
console.warn("Failed to process tag key list:", error1);
return [
3,
19
];
case 19:
return [
2
];
}
});
});
return _revalidateTag.apply(this, arguments);
}
function clearStore() {
return _clearStore.apply(this, arguments);
}
function _clearStore() {
_clearStore = _async_to_generator(function() {
var currentStorage;
return _ts_generator(this, function(_state) {
switch (_state.label) {
case 0:
currentStorage = getStorage();
return [
4,
currentStorage.clear()
];
case 1:
_state.sent();
storage = void 0;
ongoingRevalidations.clear();
return [
2
];
}
});
});
return _clearStore.apply(this, arguments);
}
export {
CacheSize,
CacheTime,
cache,
clearStore,
configureCache,
generateKey,
revalidateTag,
withRequestCache
};