mastercache
Version:
Multi-tier cache module for Node.js. Redis, Upstash, CloudfareKV, File, in-memory and others drivers
1 lines • 16.9 kB
Source Map (JSON)
{"version":3,"sources":["../../../../src/cache/cache-entry/index.ts","../../../../../../node_modules/.pnpm/hexoid@2.0.0/node_modules/hexoid/dist/index.mjs","../../../../../../node_modules/.pnpm/@lukeed+ms@2.0.2/node_modules/@lukeed/ms/dist/index.mjs","../../../../src/helpers.ts","../../../../src/cache/cache-entry/cache-entry-options.ts","../../../../src/serializers/json.ts","../../../../src/cache/cache-entry/cache-entry.ts"],"sourcesContent":["export * from './cache-entry-options';\nexport * from './cache-entry';","for(var r=256,n=[];r--;)n[r]=(r+256).toString(16).substring(1);export 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++]}}","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?)?)?$/,\n\tSEC = 1e3,\n\tMIN = SEC * 60,\n\tHOUR = MIN * 60,\n\tDAY = HOUR * 24,\n\tYEAR = DAY * 365.25;\n\nexport function parse(val) {\n\tvar num, arr = val.toLowerCase().match(RGX);\n\tif (arr != null && (num = parseFloat(arr[1]))) {\n\t\tif (arr[3] != null) return num * SEC;\n\t\tif (arr[4] != null) return num * MIN;\n\t\tif (arr[5] != null) return num * HOUR;\n\t\tif (arr[6] != null) return num * DAY;\n\t\tif (arr[7] != null) return num * DAY * 7;\n\t\tif (arr[8] != null) return num * YEAR;\n\t\treturn num;\n\t}\n}\n\nfunction fmt(val, pfx, str, long) {\n\tvar num = (val | 0) === val ? val : ~~(val + 0.5);\n\treturn pfx + num + (long ? (' ' + str + (num != 1 ? 's' : '')) : str[0]);\n}\n\nexport function format(num, long) {\n\tvar pfx = num < 0 ? '-' : '', abs = num < 0 ? -num : num;\n\tif (abs < SEC) return num + (long ? ' ms' : 'ms');\n\tif (abs < MIN) return fmt(abs / SEC, pfx, 'second', long);\n\tif (abs < HOUR) return fmt(abs / MIN, pfx, 'minute', long);\n\tif (abs < DAY) return fmt(abs / HOUR, pfx, 'hour', long);\n\tif (abs < YEAR) return fmt(abs / DAY, pfx, 'day', long);\n\treturn fmt(abs / YEAR, pfx, 'year', long);\n}\n","import { parse } from '@lukeed/ms';\n\nimport type { Duration } from './types/main';\n\n/**\n * Resolve a TTL value to a number in milliseconds\n */\nexport function resolveTtl(ttl?: Duration, defaultTtl: Duration = 30_000) {\n if (typeof ttl === 'number') return ttl;\n\n /**\n * If the TTL is null, it means the value should never expire\n */\n if (ttl === null) {\n return undefined;\n }\n\n if (ttl === undefined) {\n if (typeof defaultTtl === 'number') return defaultTtl;\n if (typeof defaultTtl === 'string') return parse(defaultTtl);\n\n return undefined;\n }\n\n return parse(ttl);\n}\n\n/**\n * Useful for creating a return value that can be destructured\n * or iterated over.\n *\n * See : https://antfu.me/posts/destructuring-with-object-or-array\n */\nexport function createIsomorphicDestructurable<\n T extends Record<string, unknown>,\n A extends readonly any[],\n>(obj: T, arr: A): T & A {\n const clone = { ...obj };\n\n Object.defineProperty(clone, Symbol.iterator, {\n enumerable: false,\n value() {\n let index = 0;\n return {\n next: () => ({\n value: arr[index++],\n done: index > arr.length,\n }),\n };\n },\n });\n\n return clone as T & A;\n}\n","import { hexoid } from 'hexoid';\n\nimport { resolveTtl } from '../../helpers';\nimport type { Duration, RawCommonOptions } from '../../types/main';\n\nconst toId = hexoid(12);\n\nexport class CacheEntryOptions {\n /**\n * The options that were passed to the constructor\n */\n #options: RawCommonOptions;\n\n /**\n * Unique identifier that will be used when logging\n * debug information.\n */\n id: string;\n\n /**\n * Logical TTL is when the value is considered expired\n * but still can be in the cache ( Grace period )\n */\n logicalTtl?: number;\n\n /**\n * Physical TTL is the time when value will be automatically\n * removed from the cache. This is the Grace period\n * duration\n */\n physicalTtl?: number;\n\n /**\n * Early expiration TTL is when the value should be\n * refreshed in the background.\n */\n earlyExpireTtl?: number;\n\n /**\n * Timeouts for the cache operations\n */\n timeouts?: {\n soft?: number\n hard?: number\n };\n\n /**\n * Resolved grace period options\n */\n gracePeriod: { enabled: false } | { enabled: true; duration?: number; fallbackDuration?: number };\n\n /**\n * Max time to wait for the lock to be acquired\n */\n lockTimeout?: number;\n\n constructor(options: RawCommonOptions = {}, defaults: Partial<RawCommonOptions> = {}) {\n this.id = toId();\n\n const timeouts = { ...defaults.timeouts, ...options.timeouts };\n this.#options = {\n ...defaults,\n ...options,\n gracePeriod: { ...defaults.gracePeriod, ...options.gracePeriod } as any,\n timeouts: Object.keys(timeouts).length ? timeouts : undefined,\n };\n\n this.logicalTtl = this.#resolveLogicalTtl();\n this.physicalTtl = this.#resolvePhysicalTtl();\n this.earlyExpireTtl = this.#resolveEarlyExpireTtl();\n this.timeouts = this.#resolveTimeouts();\n this.gracePeriod = this.#resolveGracePeriod();\n this.lockTimeout = resolveTtl(this.#options.lockTimeout, null);\n }\n\n /**\n * Resolve the grace period options\n */\n #resolveGracePeriod() {\n if (!this.#options.gracePeriod || !this.#options.gracePeriod.enabled) {\n return { enabled: false };\n }\n\n return {\n enabled: true,\n duration: resolveTtl(this.#options.gracePeriod.duration),\n fallbackDuration: resolveTtl(this.#options.gracePeriod.fallbackDuration),\n };\n }\n\n /**\n * Resolve the timeouts to a duration in milliseconds\n */\n #resolveTimeouts() {\n const timeouts = this.#options.timeouts;\n if (!timeouts) return undefined;\n\n return {\n soft: resolveTtl(timeouts.soft, null),\n hard: resolveTtl(timeouts.hard, null),\n };\n }\n\n /**\n * Early expiration is received as a percentage of the\n * logical TTL. We need to convert it to a duration\n * in milliseconds.\n */\n #resolveEarlyExpireTtl() {\n const percentage = this.#options.earlyExpiration;\n\n /**\n * Ignore invalid values\n */\n if (!percentage || percentage <= 0 || percentage >= 1) {\n return undefined;\n }\n\n /**\n * If no logical ttl, that means value will never expire\n * So no early expiration\n */\n if (!this.logicalTtl) return undefined;\n\n return this.logicalTtl * percentage;\n }\n\n /**\n * Returns a new instance of `CacheItemOptions` with the same\n * options as the current instance, but with any provided\n * options overriding the current\n *\n * For performance reasons, if no options are provided, the\n * current instance is returned\n */\n cloneWith(options?: Partial<RawCommonOptions>) {\n return options ? new CacheEntryOptions(options, this.#options) : this;\n }\n\n /**\n * Resolve the logical TTL to a duration in milliseconds\n */\n #resolveLogicalTtl() {\n return resolveTtl(this.#options.ttl);\n }\n\n /**\n * Resolve the physical TTL to a duration in milliseconds\n *\n * If grace period is not enabled then the physical TTL\n * is the same as the logical TTL\n */\n #resolvePhysicalTtl() {\n return this.isGracePeriodEnabled\n ? resolveTtl(this.#options.gracePeriod!.duration)\n : this.logicalTtl;\n }\n\n get isGracePeriodEnabled() {\n return this.#options.gracePeriod?.enabled;\n }\n\n get suppressL2Errors() {\n return this.#options.suppressL2Errors;\n }\n\n /**\n * Set a new logical TTL\n */\n setLogicalTtl(ttl: Duration) {\n this.#options.ttl = ttl;\n\n this.logicalTtl = this.#resolveLogicalTtl();\n this.physicalTtl = this.#resolvePhysicalTtl();\n this.earlyExpireTtl = this.#resolveEarlyExpireTtl();\n\n return this;\n }\n\n /**\n * Compute the logical TTL timestamp from now\n */\n logicalTtlFromNow() {\n if (!this.logicalTtl) return undefined;\n return Date.now() + this.logicalTtl;\n }\n\n /**\n * Compute the physical TTL timestamp from now\n */\n physicalTtlFromNow() {\n if (!this.physicalTtl) return undefined;\n return Date.now() + this.physicalTtl;\n }\n\n /**\n * Compute the early expiration TTL timestamp from now\n */\n earlyExpireTtlFromNow() {\n if (!this.earlyExpireTtl) return undefined;\n return Date.now() + this.earlyExpireTtl!;\n }\n\n /**\n * Compute the lock timeout we should use for the\n * factory\n */\n factoryTimeout(hasFallbackValue: boolean) {\n if (!this.timeouts) return undefined;\n\n /**\n * If grace period is enabled, we should use the soft timeout.\n * Because if the soft timeout is reached, we will\n * return the stale value.\n */\n if (hasFallbackValue && this.isGracePeriodEnabled && this.timeouts.soft) {\n return this.timeouts.soft;\n }\n\n return this.timeouts.hard;\n }\n\n /**\n * Compute the maximum time we should wait for the\n * lock to be acquired\n */\n getApplicableLockTimeout(hasFallbackValue: boolean) {\n if (this.lockTimeout) {\n return this.lockTimeout;\n }\n\n /**\n * If we have a fallback value and grace period is enabled,\n * that means we should wait at most for the soft timeout\n * duration.\n */\n if (hasFallbackValue && this.isGracePeriodEnabled && this.timeouts?.soft) {\n return this.timeouts.soft;\n }\n }\n}\n","import type { CacheSerializer } from '../types/main';\n\n/**\n * Simple class to serialize and deserialize values using JSON\n */\nexport class JsonSerializer implements CacheSerializer {\n serialize(value: unknown) {\n return JSON.stringify(value);\n }\n\n deserialize(value: string) {\n return JSON.parse(value);\n }\n}\n","import { JsonSerializer } from '../../serializers/json';\n\n/**\n * Represents a cache entry stored inside a cache driver.\n */\nexport class CacheEntry {\n /**\n * The key of the cache item.\n */\n #key: string;\n\n /**\n * The value of the item.\n */\n #value: any;\n\n /**\n * The logical expiration is the time in miliseconds when the item\n * will be considered expired. But, if grace period is enabled,\n * the item will still be available for a while.\n */\n #logicalExpiration: number;\n\n #earlyExpiration: number;\n\n static #serializer = new JsonSerializer();\n\n constructor(key: string, item: Record<string, any>) {\n this.#key = key;\n this.#value = item.value;\n this.#logicalExpiration = item.logicalExpiration;\n this.#earlyExpiration = item.earlyExpiration;\n }\n\n getValue() {\n return this.#value;\n }\n\n getKey() {\n return this.#key;\n }\n\n getLogicalExpiration() {\n return this.#logicalExpiration;\n }\n\n getEarlyExpiration() {\n return this.#earlyExpiration;\n }\n\n isLogicallyExpired() {\n return Date.now() >= this.#logicalExpiration;\n }\n\n isEarlyExpired() {\n if (!this.#earlyExpiration) {\n return false;\n }\n\n if (this.isLogicallyExpired()) {\n return false;\n }\n\n return Date.now() >= this.#earlyExpiration;\n }\n\n static fromDriver(key: string, item: string) {\n return new CacheEntry(key, this.#serializer.deserialize(item));\n }\n\n applyFallbackDuration(duration: number) {\n this.#logicalExpiration += duration;\n this.#earlyExpiration = 0;\n return this;\n }\n\n expire() {\n this.#logicalExpiration = Date.now() - 100;\n this.#earlyExpiration = 0;\n return this;\n }\n\n serialize() {\n return CacheEntry.#serializer.serialize({\n value: this.#value,\n logicalExpiration: this.#logicalExpiration,\n earlyExpiration: this.#earlyExpiration,\n });\n }\n}\n"],"mappings":"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","names":[]}