UNPKG

@modern-js/runtime-utils

Version:

A Progressive React Framework for modern web development.

1,033 lines (1,032 loc) • 30.1 kB
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 };