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
JavaScript
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