jsm-core
Version:
Core library for JSM project
733 lines (732 loc) • 35.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CacheManager = void 0;
const jsm_logger_1 = __importStar(require("jsm-logger"));
const jsm_utilities_1 = require("jsm-utilities");
const moment_1 = __importDefault(require("moment"));
const redis_1 = require("redis");
const typedi_1 = require("typedi");
const context_1 = require("../../../context");
const actions_cache_manager_1 = __importDefault(require("./managers/actions.cache-manager"));
const fcm_tokens_cache_manager_1 = __importDefault(require("./managers/fcm-tokens.cache-manager"));
const heavy_computing_cache_manager_1 = __importDefault(require("./managers/heavy-computing.cache-manager"));
const tasks_cache_manager_1 = __importDefault(require("./managers/tasks.cache-manager"));
let CacheManager = (() => {
let _classDecorators = [(0, typedi_1.Service)()];
let _classDescriptor;
let _classExtraInitializers = [];
let _classThis;
var CacheManager = _classThis = class {
// protected _sdk!: JsmCoreSdk;
constructor() {
this.logger = (0, jsm_logger_1.default)(jsm_logger_1.LoggerContext.MANAGER, `${this.constructor.name}`, {
logLevel: (0, context_1.getRegistry)().getConfig('cacheManager.debug', false) ? jsm_logger_1.LogSeverity.Debug : jsm_logger_1.LogSeverity.Warning
});
this.getClient();
}
getClient() {
return __awaiter(this, void 0, void 0, function* () {
if (this.client)
return this.client;
this.client = (0, redis_1.createClient)({
url: (0, context_1.getRegistry)().getConfig('cacheManager.redis.url'),
username: (0, context_1.getRegistry)().getConfig('cacheManager.redis.user') || undefined,
password: (0, context_1.getRegistry)().getConfig('cacheManager.redis.password') || undefined,
});
this.client.on("error", (err) => {
this.logger.error(this.getClient.name, "Redis Client Error", err);
});
yield this.client.connect();
// Check Redis role to detect read-only replicas
try {
const info = yield this.client.info('replication');
const roleMatch = info.match(/role:(\w+)/);
const role = roleMatch ? roleMatch[1] : 'unknown';
if (role === 'slave') {
this.logger.error(this.getClient.name, "Redis is configured as a read-only replica. Write operations will fail.", { role, url: (0, context_1.getRegistry)().getConfig('cacheManager.redis.url') });
}
else {
this.logger.info(this.getClient.name, `Redis role: ${role}`);
}
}
catch (infoError) {
this.logger.warning(this.getClient.name, "Could not check Redis role", infoError);
}
this.logger.success((0, context_1.getRegistry)().getConfig('cacheManager.redis.url') || "redis://localhost:6379", "Redis client connected successfully");
return this.client;
});
}
getClientStatus() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
try {
const client = yield this.getClient();
return {
status: client.isOpen ? 'connected' : 'disconnected',
db: {
dbSize: client.dbSize ? (yield client.dbSize()) : null,
name: (_a = client.options) === null || _a === void 0 ? void 0 : _a.database,
url: (_b = client.options) === null || _b === void 0 ? void 0 : _b.url,
},
redis: {
config: (0, context_1.getRegistry)().getConfig('cacheManager.redis'),
},
};
}
catch (error) {
this.logger.error(this.getClientStatus.name, error);
throw error;
}
});
}
/**
* Check if the entity is related to a company
* @param {string} entity - The entity name
* @returns {boolean} - True if the entity is related to a company, false otherwise
*/
_entityRelatedToCompany(entity) {
const notRelated = ["app"];
return !notRelated.includes(entity);
}
generateEntityKey(entity, company) {
if (this._entityRelatedToCompany(entity) && company)
return `${(0, context_1.getRegistry)().getConfig('cacheManager.keyPrefix') || "JSM_V1:"}${company}:${entity}`;
else
return `${(0, context_1.getRegistry)().getConfig('cacheManager.keyPrefix') || "JSM_V1:"}noCompany:${entity}`;
}
generateForeignKey(id, company) {
if (company)
return `${(0, context_1.getRegistry)().getConfig('cacheManager.keyPrefix') || "JSM_V1:FOREIGN:"}${company}:${id}`;
else
return `${(0, context_1.getRegistry)().getConfig('cacheManager.keyPrefix') || "JSM_V1:FOREIGN:"}noCompany:${id}`;
}
getCollectionEntries(key) {
return __awaiter(this, void 0, void 0, function* () {
try {
const client = yield this.getClient();
let entries = (yield client.hGetAll(key));
if (entries && Object.keys(entries).length) {
entries = Object.entries(entries).reduce((prev, [k, entry]) => {
return Object.assign(Object.assign({}, prev), { [k]: JSON.parse(entry) });
}, {});
}
return entries;
}
catch (error) {
this.logger.error(this.getCollectionEntries.name, error);
throw error;
}
});
}
setForeign(key, id, value, config) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
try {
const client = yield this.getClient();
// Check if Redis is writable before attempting write
try {
yield client.hSet(this.generateForeignKey(key, config.company || null), id.toString(), JSON.stringify({
last_updated: new Date(),
value,
}));
}
catch (writeError) {
if (((_a = writeError.message) === null || _a === void 0 ? void 0 : _a.includes('READONLY')) || ((_b = writeError.message) === null || _b === void 0 ? void 0 : _b.includes('read only replica'))) {
this.logger.error(this.setForeign.name, "Cannot write to Redis: Instance is read-only replica", {
key,
id,
redisUrl: (0, context_1.getRegistry)().getConfig('cacheManager.redis.url'),
error: writeError.message
});
// In read-only mode, we could either:
// 1. Throw an error (current behavior)
// 2. Silently fail and log warning
// 3. Store in local memory cache as fallback
throw new Error(`Redis write failed: Instance is read-only replica. Original error: ${writeError.message}`);
}
// Re-throw other errors
throw writeError;
}
}
catch (error) {
this.logger.error(this.setForeign.name, error);
throw error;
}
});
}
getForeign(key_1, id_1) {
return __awaiter(this, arguments, void 0, function* (key, id, config = {
expiration: 3600 * 24,
company: null,
}) {
try {
/**
* Apply defaults on config
*/
config = (0, jsm_utilities_1.defaults)(config, {
expiration: 3600 * 24,
company: null,
});
if (!id)
return null;
const client = yield this.getClient();
const obj = yield client.hGet(this.generateForeignKey(key, config.company), id.toString());
if (!obj) {
return null;
}
const parsed = JSON.parse(obj);
if (!this.isExpired(parsed.last_updated, config.expiration || 0)) {
return parsed.value;
}
else
this.logger.warn(this.get.name, key, "EXPIRED", id);
return null;
}
catch (error) {
this.logger.error(this.setForeign.name, error);
throw error;
}
});
}
unsetForeign(key, id, company) {
return __awaiter(this, void 0, void 0, function* () {
try {
const client = yield this.getClient();
yield client.hDel(this.generateForeignKey(key, company), id);
}
catch (error) {
this.logger.error(this.unsetForeign.name, error);
throw error;
}
});
}
/**
*
* @param {Date} date
* @param {number} expiration in seconds
*/
isExpired(last_updated, expiration) {
return !(0, moment_1.default)(last_updated).isAfter((0, moment_1.default)().subtract(expiration, "seconds"));
}
generateLogItemName(method) {
return `${this.constructor.name}:${method.name}`;
}
loadObjectByIdFormDB(sdkClient, id) {
return __awaiter(this, void 0, void 0, function* () {
try {
let data;
let result;
data = typeof sdkClient.getById === 'function' ? yield sdkClient.getById(id) : { data: undefined };
result = data === null || data === void 0 ? void 0 : data.data;
this.logger.trace.value(this.loadObjectByIdFormDB.name, sdkClient.prefix, id, `retrieved: ${!!result}`);
if (!result)
this.logger.trace.warn(this.loadObjectByIdFormDB.name, "OBJECT NOT FOUND ON DB", this.loadObjectByIdFormDB.name, `${(0, context_1.getRegistry)().getConfig('http.sdk.baseURL')}${sdkClient.prefix}`, id);
return result;
}
catch (error) {
this.logger.save.error({
name: this.generateLogItemName(this.loadObjectByIdFormDB),
payload: {
prefix: sdkClient.prefix,
id,
error: (0, jsm_utilities_1.errorToObject)(error),
},
});
return;
}
});
}
loadObjectListFromDB(sdkClient, query, company) {
return __awaiter(this, void 0, void 0, function* () {
try {
let data;
let result = [];
query = Object.assign(Object.assign({}, (query || {})), { filters: Object.assign({}, ((query === null || query === void 0 ? void 0 : query.filters) || {})) });
if (company)
query.filters.company = company;
data = typeof sdkClient.list === 'function' ? yield sdkClient.list(query) : { data: [] };
result = data === null || data === void 0 ? void 0 : data.data;
return result;
}
catch (error) {
this.logger.error(this.generateLogItemName(this.loadObjectListFromDB), {
prefix: sdkClient.prefix,
query,
error: (0, jsm_utilities_1.errorToObject)(error),
});
this.logger.save.error({
name: this.generateLogItemName(this.loadObjectListFromDB),
payload: {
prefix: sdkClient.prefix,
query,
error: (0, jsm_utilities_1.errorToObject)(error),
},
});
return [];
}
});
}
/* -------------------------------------------------------------------------- */
/* START COMMON METHODS */
/* -------------------------------------------------------------------------- */
set(entity_1, id_1, value_1) {
return __awaiter(this, arguments, void 0, function* (entity, id, value, company = null, config = {
customKey: null,
}) {
try {
/**
* Apply defaults on config
*/
config = (0, jsm_utilities_1.defaults)(config, {
customKey: null,
});
const customKey = config.customKey ? config.customKey : entity;
this.logger.trace.event('set value', entity, id);
const now = new Date();
const client = yield this.getClient();
yield client.hSet(this.generateEntityKey(customKey, company), id.toString(), JSON.stringify({
value,
last_updated: now,
}));
if (!company && value.company) {
yield this.set(entity, id, value, value.company);
}
}
catch (error) {
this.logger.save.error({
name: this.generateLogItemName(this.set),
payload: {
entity,
id,
value,
},
});
throw error;
}
});
}
/**
*
* @param entity string representing the entity name [camelCased] single
* @param id
* @param config
* @returns
*/
get(entity_1, id_1) {
return __awaiter(this, arguments, void 0, function* (entity, id, _config = {
expiration: 3600 * 24,
forceLoadFromDb: false,
company: null,
customKey: null,
}) {
try {
/**
* Apply defaults on config
*/
const config = (0, jsm_utilities_1.defaults)(_config, {
expiration: 3600 * 24,
forceLoadFromDb: false,
company: null,
customKey: null,
});
config.sdkClient = _config.sdkClient;
const customKey = config.customKey ? config.customKey : entity;
if (!id)
return;
const client = yield this.getClient();
const val = yield client.hGet(this.generateEntityKey(customKey, config.company), id.toString());
let oldDoc;
if (val) {
oldDoc = JSON.parse(val);
}
let result;
if (oldDoc) {
if (!this.isExpired(oldDoc.last_updated, config.expiration || 0)) {
result = oldDoc.value;
}
else
this.logger.warn("EXPIRED", entity, id);
}
else
this.logger.warn("NOT FOUND", entity, id);
if (!result)
this.logger.warn("NO RESULT FOUND", { entity, id, oldDoc });
if (config.forceLoadFromDb)
this.logger.warn("FORCE LOADING FROM DB", entity, id);
if (!result || config.forceLoadFromDb) {
if (config.sdkClient) {
const db_object = yield this.loadObjectByIdFormDB(config.sdkClient, id);
if (db_object) {
yield this.set(customKey, id, db_object, config.company);
}
else {
this.logger.error("Could not load item from DB", { entity, id });
}
return db_object;
}
else {
this.logger.warn("SDK CLIENT NOT PROVIDED", entity, id);
}
}
return result;
}
catch (error) {
this.logger.error('get', {
name: this.generateLogItemName(this.get),
payload: {
entity,
id,
error: (0, jsm_utilities_1.errorToObject)(error),
},
});
this.logger.save.error({
name: this.generateLogItemName(this.get),
payload: {
entity,
id,
error: (0, jsm_utilities_1.errorToObject)(error),
},
});
return;
}
});
}
getMany(entity_1, ids_1) {
return __awaiter(this, arguments, void 0, function* (entity, ids, _config = {
expiration: 3600 * 24,
forceLoadFromDb: true,
company: null,
}) {
/**
* Apply defaults on config
*/
const config = (0, jsm_utilities_1.defaults)(_config, {
expiration: 3600 * 24,
forceLoadFromDb: true,
company: null,
});
try {
if (!(ids === null || ids === void 0 ? void 0 : ids.length))
return [];
config.sdkClient = _config.sdkClient;
return ids.reduce((previousPromise, currentItem) => __awaiter(this, void 0, void 0, function* () {
const accumulator = yield previousPromise;
const result = yield this.get(entity, currentItem === null || currentItem === void 0 ? void 0 : currentItem.toString(), config);
return [...accumulator, result];
}), Promise.resolve([]));
}
catch (error) {
this.logger.save.error({
name: this.generateLogItemName(this.get),
payload: {
entity,
ids,
config,
error: (0, jsm_utilities_1.errorToObject)(error),
},
});
return [];
}
});
}
unset(entity_1, id_1) {
return __awaiter(this, arguments, void 0, function* (entity, id, company = null) {
try {
const client = yield this.getClient();
yield client.hDel(this.generateEntityKey(entity, company), id.toString());
}
catch (error) {
this.logger.save.error({
name: this.generateLogItemName(this.unset),
payload: {
entity,
id,
error: (0, jsm_utilities_1.errorToObject)(error),
},
});
throw error;
}
});
}
unsetAll(entity_1) {
return __awaiter(this, arguments, void 0, function* (entity, company = null) {
try {
const client = yield this.getClient();
yield client.del(this.generateEntityKey(entity, company));
const baseKey = this.generateEntityKey(entity, company);
// The line `await client.del(baseKey);` already deletes the primary hash key.
// Now, search for and delete other keys that use this baseKey as a prefix.
const subKeyPattern = `${baseKey}:*`;
// List keys matching the pattern
// Note: In Redis, the KEYS command can be blocking for large databases.
// For production environments with very large key sets, consider using SCAN.
// However, using client.keys for consistency with flushAll method if applicable.
const subKeys = yield client.keys(subKeyPattern);
if (subKeys && subKeys.length > 0) {
this.logger.info(this.unsetAll.name, `Found ${subKeys.length} prefixed sub-keys for base '${baseKey}' (pattern: '${subKeyPattern}'). Sub-keys: ${subKeys.join(', ')}`);
// Delete the found sub-keys
// client.del can accept an array of keys
yield client.del(subKeys);
this.logger.info(this.unsetAll.name, `Successfully deleted ${subKeys.length} prefixed sub-keys for base '${baseKey}'.`);
}
else {
this.logger.debug(this.unsetAll.name, `No prefixed sub-keys found for base '${baseKey}' with pattern '${subKeyPattern}'.`);
}
}
catch (error) {
this.logger.save.error({
name: this.generateLogItemName(this.unsetAll),
payload: {
entity,
error: (0, jsm_utilities_1.errorToObject)(error),
},
});
throw error;
}
});
}
list(entity_1) {
return __awaiter(this, arguments, void 0, function* (entity, config = {
query: {},
forceLoadFromDb: true,
filter: () => true,
company: null,
customKey: null,
}) {
var _a, _b;
try {
/**
* Apply defaults on config
*/
config = (0, jsm_utilities_1.defaults)(config, {
query: {},
forceLoadFromDb: true,
filter: () => true,
company: null,
customKey: null,
});
const customKey = config.customKey ? config.customKey : entity;
let result = [];
const client = yield this.getClient();
const key = this.generateEntityKey(customKey, config.company || ((_b = (_a = config.query) === null || _a === void 0 ? void 0 : _a.filters) === null || _b === void 0 ? void 0 : _b.company));
const valuesObject = yield client.hGetAll(key);
if (valuesObject) {
for (const [_, val] of Object.entries(valuesObject)) {
let oldDoc;
if (val) {
oldDoc = JSON.parse(val);
}
if (oldDoc) {
result.push(oldDoc.value);
}
}
}
result = config.filter ? result.filter(config.filter) : result;
if (!result.length && config.forceLoadFromDb && config.sdkClient) {
const loadedData = yield this.loadObjectListFromDB(config.sdkClient, config.query || {}, config.company || null);
for (const item of loadedData) {
yield this.set(entity, item["_id"], item, config.company);
}
return config.filter ? (loadedData || []).filter(config.filter) : loadedData;
}
else
return result;
}
catch (error) {
this.logger.error(error.message, error);
return [];
}
});
}
/**
* @description Retrieves a configuration value from the cache, returning a default value if not found or expired.
* @param {string} id - The identifier for the configuration value.
* @param {T} defaultValue - The default value to return if the configuration value is not found.
* @returns {Promise<T | D>} - A promise that resolves to the configuration value or the default value.
* @template T - The type of the configuration value.
* @template D - The type of the default value, which can be the same as T or undefined.
*/
getConfigValue(id, defaultValue) {
return __awaiter(this, void 0, void 0, function* () {
const client = yield this.getClient();
const val = yield client.hGet(this.generateForeignKey("configuration"), id);
const isConfigObject = (obj) => {
return obj && typeof obj === 'object' && 'value' in obj && 'updated_at' in obj;
};
if (val) {
const obj = JSON.parse(val);
if (!isConfigObject(obj)) {
this.logger.error(this.getConfigValue.name, "Invalid configuration object", id, obj);
return defaultValue;
}
if (obj.ttl && this.isExpired(obj.updated_at, obj.ttl)) {
this.logger.warn(this.getConfigValue.name, "EXPIRED", id);
return defaultValue;
}
return obj.value;
}
else
return defaultValue;
});
}
/**
* Sets a configuration value in the cache.
* @param {string} id - The identifier for the configuration value.
* @param {T} value - The value to set for the configuration.
* @param {number} [ttl] - Optional time-to-live in milliseconds.
*/
setConfigValue(id, value, ttl) {
return __awaiter(this, void 0, void 0, function* () {
const client = yield this.getClient();
yield client.hSet(this.generateForeignKey("configuration"), id, JSON.stringify({
value,
updated_at: new Date(),
ttl: ttl || null
}));
});
}
/* -------------------------------------------------------------------------- */
/* END COMMON METHODS */
/* -------------------------------------------------------------------------- */
get actions() {
return actions_cache_manager_1.default.getInstance(this);
}
get fcmTokens() {
return fcm_tokens_cache_manager_1.default.getInstance(this);
}
get heavyComputing() {
return heavy_computing_cache_manager_1.default.getInstance(this);
}
get tasks() {
return tasks_cache_manager_1.default.getInstance(this);
}
/* -------------------------------------------------------------------------- */
/* ENTITY MANAGERS */
/* -------------------------------------------------------------------------- */
// public get apiKeys() {
// return ApiKeysCacheManager.getInstance();
// }
// public get permissions() {
// return PermissionsCacheManager.getInstance();
// }
// public get permissionGroups() {
// return PermissionGroupsCacheManager.getInstance();
// }
// public get roles() {
// return RolesCacheManager.getInstance();
// }
// public get users() {
// return UsersCacheManager.getInstance();
// }
// public get apps() {
// return AppsCacheManager.getInstance();
// }
flushAll() {
return __awaiter(this, void 0, void 0, function* () {
const client = yield this.getClient();
const keys = yield client.sendCommand(["keys", "*"]);
keys.forEach((key) => {
if (key.startsWith(`${(0, context_1.getRegistry)().getConfig('cacheManager.keyPrefix') || "JSM_V1_"}`)) {
this.logger.info(this.flushAll.name, key);
client.del(key);
}
});
// client.multi().keys('*' as any).exec((err: any, keys: string[]) => {
// });
});
}
};
__setFunctionName(_classThis, "CacheManager");
(() => {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
CacheManager = _classThis = _classDescriptor.value;
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
__runInitializers(_classThis, _classExtraInitializers);
})();
return CacheManager = _classThis;
})();
exports.CacheManager = CacheManager;