jsm-core
Version:
Core library for JSM project
215 lines (214 loc) • 9.58 kB
JavaScript
;
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 __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 });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ttlCache = exports.TTLCache = void 0;
const typedi_1 = require("typedi");
/**
* A simple Time-To-Live (TTL) cache implementation.
* This cache stores key-value pairs with an expiration time.
* Once the expiration time is reached, the key-value pair is automatically removed.
*
* @example
* const cache = new TTLCache();
* cache.set('key1', 'value1', 5000); // Stores 'value1' with a TTL of 5 seconds
* console.log(cache.get('key1')); // Retrieves 'value1'
* setTimeout(() => console.log(cache.get('key1')), 6000); // After 6 seconds, returns null
*/
let TTLCache = (() => {
let _classDecorators = [(0, typedi_1.Service)()];
let _classDescriptor;
let _classExtraInitializers = [];
let _classThis;
var TTLCache = _classThis = class {
/**
* Creates an instance of TTLCache.
* @param {number} [defaultTtl=60000] - The default Time-To-Live (TTL) for cache entries in milliseconds.
*/
constructor(defaultTtl = 60 * 1000) {
this.cache = new Map();
this.defaultTtl = defaultTtl;
// Automatically clean up expired entries every minute
// This is a simple cleanup mechanism that checks all keys every minute
// and removes those that are expired.
// Note: This is not the most efficient way to handle TTL, but it is simple
// and works for many use cases. For high-performance applications, consider
// using a more sophisticated approach like a priority queue or a dedicated
// background worker to handle expirations.
setInterval(() => {
for (const key of this.getKeys()) {
this.get(key);
}
}, 60 * 1000); // Every minute
}
/**
* Stores a key-value pair in the cache with an optional TTL.
* @template T
* @param {string} key - The key to store the value under.
* @param {T} value - The value to store.
* @param {number} [ttl=this.defaultTtl] - The Time-To-Live (TTL) for the cache entry in milliseconds.
*/
set(key, value, ttl = this.defaultTtl) {
const expiry = Date.now() + ttl;
this.cache.set(key, { value, expiry });
}
/**
* Retrieves a value from the cache by its key.
* @template T
* @param {string} key - The key of the value to retrieve.
* @param {T | null} [defaultValue=null] - The default value to return if the key is not found or expired.
* @returns {T | null} - The cached value or the default value if the key is not found or expired.
*/
get(key, defaultValue = null) {
const cached = this.cache.get(key);
if (!cached || Date.now() > cached.expiry) {
this.cache.delete(key);
return defaultValue;
}
return cached.value;
}
/**
* Checks if a key exists in the cache and is not expired.
* @param {string} key - The key to check.
* @returns {boolean} - True if the key exists and is not expired, false otherwise.
*/
has(key) {
const cached = this.cache.get(key);
if (!cached || Date.now() > cached.expiry) {
this.cache.delete(key);
return false;
}
return true;
}
/**
* Deletes a key-value pair from the cache.
* @param {string} key - The key to delete.
*/
delete(key) {
this.cache.delete(key);
}
/**
* Clears all key-value pairs from the cache.
*/
clear() {
this.cache.clear();
}
/**
* Retrieves all keys currently stored in the cache.
* @returns {string[]} - An array of keys that are not expired.
*/
getKeys() {
return Array.from(this.cache.keys()).filter((key) => this.has(key));
}
/**
* Retrieves all values currently stored in the cache.
* @returns {any[]} - An array of values that are not expired.
*/
getValues() {
return Array.from(this.cache.values())
.filter((cached) => Date.now() <= cached.expiry)
.map((cached) => cached.value);
}
/**
* Retrieves the number of active (non-expired) entries in the cache.
* @returns {number} - The number of active entries.
*/
getSize() {
return this.getKeys().length;
}
/**
* Retrieves the default TTL for cache entries.
* @returns {number} - The default TTL in milliseconds.
*/
getDefaultTtl() {
return this.defaultTtl;
}
/**
* Updates the default TTL for cache entries.
* @param {number} ttl - The new default TTL in milliseconds.
* @throws {Error} - Throws an error if the TTL is not a positive number.
*/
setDefaultTtl(ttl) {
if (ttl <= 0) {
throw new Error("TTL must be a positive number");
}
this.defaultTtl = ttl;
}
/**
* Converts the cache to a JSON object.
* @returns {Record<string, any>} - A JSON object representation of the cache.
*/
toJSON() {
const json = {};
this.cache.forEach((cached, key) => {
if (Date.now() <= cached.expiry) {
json[key] = cached.value;
}
});
return json;
}
/**
* Populates the cache from a JSON object.
* @param {Record<string, any>} json - The JSON object to populate the cache from.
* @param {number} [ttl=this.defaultTtl] - The TTL to apply to all entries.
*/
fromJSON(json, ttl = this.defaultTtl) {
this.clear();
Object.entries(json).forEach(([key, value]) => {
this.set(key, value, ttl);
});
}
};
__setFunctionName(_classThis, "TTLCache");
(() => {
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);
TTLCache = _classThis = _classDescriptor.value;
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
__runInitializers(_classThis, _classExtraInitializers);
})();
return TTLCache = _classThis;
})();
exports.TTLCache = TTLCache;
// Set the defaultTtl argument for the TTLCache class
typedi_1.Container.set({
id: TTLCache,
factory: () => new TTLCache(120 * 1000), // Set defaultTtl to 120 seconds
});
exports.ttlCache = typedi_1.Container.get(TTLCache);