UNPKG

mastercache

Version:

Multi-tier cache module for Node.js. Redis, Upstash, CloudfareKV, File, in-memory and others drivers

342 lines (335 loc) 9.63 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/cache/cache-entry/index.ts var cache_entry_exports = {}; __export(cache_entry_exports, { CacheEntry: () => CacheEntry, CacheEntryOptions: () => CacheEntryOptions }); module.exports = __toCommonJS(cache_entry_exports); // ../../node_modules/.pnpm/hexoid@2.0.0/node_modules/hexoid/dist/index.mjs for (r = 256, n = []; r--; ) n[r] = (r + 256).toString(16).substring(1); var r; var n; function hexoid(r) { r = r || 16; var t = "", o = 0; return function() { if (!t || 256 === o) { for (t = "", o = (1 + r) / 2 | 0; o--; ) t += n[256 * Math.random() | 0]; t = t.substring(o = 0, r - 2); } return t + n[o++]; }; } // ../../node_modules/.pnpm/@lukeed+ms@2.0.2/node_modules/@lukeed/ms/dist/index.mjs var RGX = /^(-?(?:\d+)?\.?\d+) *(m(?:illiseconds?|s(?:ecs?)?))?(s(?:ec(?:onds?|s)?)?)?(m(?:in(?:utes?|s)?)?)?(h(?:ours?|rs?)?)?(d(?:ays?)?)?(w(?:eeks?|ks?)?)?(y(?:ears?|rs?)?)?$/; var SEC = 1e3; var MIN = SEC * 60; var HOUR = MIN * 60; var DAY = HOUR * 24; var YEAR = DAY * 365.25; function parse(val) { var num, arr = val.toLowerCase().match(RGX); if (arr != null && (num = parseFloat(arr[1]))) { if (arr[3] != null) return num * SEC; if (arr[4] != null) return num * MIN; if (arr[5] != null) return num * HOUR; if (arr[6] != null) return num * DAY; if (arr[7] != null) return num * DAY * 7; if (arr[8] != null) return num * YEAR; return num; } } // src/helpers.ts function resolveTtl(ttl, defaultTtl = 3e4) { if (typeof ttl === "number") return ttl; if (ttl === null) { return void 0; } if (ttl === void 0) { if (typeof defaultTtl === "number") return defaultTtl; if (typeof defaultTtl === "string") return parse(defaultTtl); return void 0; } return parse(ttl); } // src/cache/cache-entry/cache-entry-options.ts var toId = hexoid(12); var CacheEntryOptions = class _CacheEntryOptions { /** * The options that were passed to the constructor */ #options; /** * Unique identifier that will be used when logging * debug information. */ id; /** * Logical TTL is when the value is considered expired * but still can be in the cache ( Grace period ) */ logicalTtl; /** * Physical TTL is the time when value will be automatically * removed from the cache. This is the Grace period * duration */ physicalTtl; /** * Early expiration TTL is when the value should be * refreshed in the background. */ earlyExpireTtl; /** * Timeouts for the cache operations */ timeouts; /** * Resolved grace period options */ gracePeriod; /** * Max time to wait for the lock to be acquired */ lockTimeout; constructor(options = {}, defaults = {}) { this.id = toId(); const timeouts = { ...defaults.timeouts, ...options.timeouts }; this.#options = { ...defaults, ...options, gracePeriod: { ...defaults.gracePeriod, ...options.gracePeriod }, timeouts: Object.keys(timeouts).length ? timeouts : void 0 }; this.logicalTtl = this.#resolveLogicalTtl(); this.physicalTtl = this.#resolvePhysicalTtl(); this.earlyExpireTtl = this.#resolveEarlyExpireTtl(); this.timeouts = this.#resolveTimeouts(); this.gracePeriod = this.#resolveGracePeriod(); this.lockTimeout = resolveTtl(this.#options.lockTimeout, null); } /** * Resolve the grace period options */ #resolveGracePeriod() { if (!this.#options.gracePeriod || !this.#options.gracePeriod.enabled) { return { enabled: false }; } return { enabled: true, duration: resolveTtl(this.#options.gracePeriod.duration), fallbackDuration: resolveTtl(this.#options.gracePeriod.fallbackDuration) }; } /** * Resolve the timeouts to a duration in milliseconds */ #resolveTimeouts() { const timeouts = this.#options.timeouts; if (!timeouts) return void 0; return { soft: resolveTtl(timeouts.soft, null), hard: resolveTtl(timeouts.hard, null) }; } /** * Early expiration is received as a percentage of the * logical TTL. We need to convert it to a duration * in milliseconds. */ #resolveEarlyExpireTtl() { const percentage = this.#options.earlyExpiration; if (!percentage || percentage <= 0 || percentage >= 1) { return void 0; } if (!this.logicalTtl) return void 0; return this.logicalTtl * percentage; } /** * Returns a new instance of `CacheItemOptions` with the same * options as the current instance, but with any provided * options overriding the current * * For performance reasons, if no options are provided, the * current instance is returned */ cloneWith(options) { return options ? new _CacheEntryOptions(options, this.#options) : this; } /** * Resolve the logical TTL to a duration in milliseconds */ #resolveLogicalTtl() { return resolveTtl(this.#options.ttl); } /** * Resolve the physical TTL to a duration in milliseconds * * If grace period is not enabled then the physical TTL * is the same as the logical TTL */ #resolvePhysicalTtl() { return this.isGracePeriodEnabled ? resolveTtl(this.#options.gracePeriod.duration) : this.logicalTtl; } get isGracePeriodEnabled() { return this.#options.gracePeriod?.enabled; } get suppressL2Errors() { return this.#options.suppressL2Errors; } /** * Set a new logical TTL */ setLogicalTtl(ttl) { this.#options.ttl = ttl; this.logicalTtl = this.#resolveLogicalTtl(); this.physicalTtl = this.#resolvePhysicalTtl(); this.earlyExpireTtl = this.#resolveEarlyExpireTtl(); return this; } /** * Compute the logical TTL timestamp from now */ logicalTtlFromNow() { if (!this.logicalTtl) return void 0; return Date.now() + this.logicalTtl; } /** * Compute the physical TTL timestamp from now */ physicalTtlFromNow() { if (!this.physicalTtl) return void 0; return Date.now() + this.physicalTtl; } /** * Compute the early expiration TTL timestamp from now */ earlyExpireTtlFromNow() { if (!this.earlyExpireTtl) return void 0; return Date.now() + this.earlyExpireTtl; } /** * Compute the lock timeout we should use for the * factory */ factoryTimeout(hasFallbackValue) { if (!this.timeouts) return void 0; if (hasFallbackValue && this.isGracePeriodEnabled && this.timeouts.soft) { return this.timeouts.soft; } return this.timeouts.hard; } /** * Compute the maximum time we should wait for the * lock to be acquired */ getApplicableLockTimeout(hasFallbackValue) { if (this.lockTimeout) { return this.lockTimeout; } if (hasFallbackValue && this.isGracePeriodEnabled && this.timeouts?.soft) { return this.timeouts.soft; } } }; // src/serializers/json.ts var JsonSerializer = class { serialize(value) { return JSON.stringify(value); } deserialize(value) { return JSON.parse(value); } }; // src/cache/cache-entry/cache-entry.ts var CacheEntry = class _CacheEntry { /** * The key of the cache item. */ #key; /** * The value of the item. */ #value; /** * The logical expiration is the time in miliseconds when the item * will be considered expired. But, if grace period is enabled, * the item will still be available for a while. */ #logicalExpiration; #earlyExpiration; static #serializer = new JsonSerializer(); constructor(key, item) { this.#key = key; this.#value = item.value; this.#logicalExpiration = item.logicalExpiration; this.#earlyExpiration = item.earlyExpiration; } getValue() { return this.#value; } getKey() { return this.#key; } getLogicalExpiration() { return this.#logicalExpiration; } getEarlyExpiration() { return this.#earlyExpiration; } isLogicallyExpired() { return Date.now() >= this.#logicalExpiration; } isEarlyExpired() { if (!this.#earlyExpiration) { return false; } if (this.isLogicallyExpired()) { return false; } return Date.now() >= this.#earlyExpiration; } static fromDriver(key, item) { return new _CacheEntry(key, this.#serializer.deserialize(item)); } applyFallbackDuration(duration) { this.#logicalExpiration += duration; this.#earlyExpiration = 0; return this; } expire() { this.#logicalExpiration = Date.now() - 100; this.#earlyExpiration = 0; return this; } serialize() { return _CacheEntry.#serializer.serialize({ value: this.#value, logicalExpiration: this.#logicalExpiration, earlyExpiration: this.#earlyExpiration }); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { CacheEntry, CacheEntryOptions }); //# sourceMappingURL=index.cjs.map