@epic-web/cachified
Version:
neat wrapper for various caches
5 lines • 50.7 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../src/common.ts", "../src/reporter.ts", "../src/createBatch.ts", "../src/assertCacheEntry.ts", "../src/isExpired.ts", "../src/checkValue.ts", "../src/getCachedValue.ts", "../src/getFreshValue.ts", "../src/cachified.ts", "../src/softPurge.ts", "../src/configure.ts"],
"sourcesContent": ["import type { CreateReporter, Reporter } from './reporter';\nimport { StandardSchemaV1 } from './StandardSchemaV1';\n\nexport interface CacheMetadata {\n createdTime: number;\n ttl?: number | null;\n swr?: number | null;\n traceId?: any;\n /** @deprecated use swr instead */\n readonly swv?: number | null;\n}\n\nexport interface CacheEntry<Value = unknown> {\n metadata: CacheMetadata;\n value: Value;\n}\n\nexport type Eventually<Value> =\n | Value\n | null\n | undefined\n | Promise<Value | null | undefined>;\n\nexport interface Cache<Value = any> {\n name?: string;\n get: (key: string) => Eventually<CacheEntry<Value>>;\n set: (key: string, value: CacheEntry<Value>) => unknown | Promise<unknown>;\n delete: (key: string) => unknown | Promise<unknown>;\n}\n\nexport interface GetFreshValueContext {\n readonly metadata: CacheMetadata;\n readonly background: boolean;\n}\nexport const HANDLE = Symbol();\nexport type GetFreshValue<Value> = {\n (context: GetFreshValueContext): Promise<Value> | Value;\n [HANDLE]?: () => void;\n};\nexport const MIGRATED = Symbol();\nexport type MigratedValue<Value> = {\n [MIGRATED]: boolean;\n value: Value;\n};\n\nexport type ValueCheckResultOk<Value> =\n | true\n | undefined\n | null\n | void\n | MigratedValue<Value>;\nexport type ValueCheckResultInvalid = false | string;\nexport type ValueCheckResult<Value> =\n | ValueCheckResultOk<Value>\n | ValueCheckResultInvalid;\n\nexport type CheckValue<Value> = (\n value: unknown,\n migrate: (value: Value, updateCache?: boolean) => MigratedValue<Value>,\n) => ValueCheckResult<Value> | Promise<ValueCheckResult<Value>>;\n\n/**\n * @deprecated use a library supporting Standard Schema\n * @see https://github.com/standard-schema/standard-schema?tab=readme-ov-file#what-schema-libraries-implement-the-spec\n * @todo remove in next major version\n */\nexport interface Schema<Value, InputValue> {\n _input: InputValue;\n parseAsync(value: unknown): Promise<Value>;\n}\n\nexport interface CachifiedOptions<Value> {\n /**\n * Required\n *\n * The key this value is cached by\n * Must be unique for each value\n */\n key: string;\n /**\n * Required\n *\n * Cache implementation to use\n *\n * Must conform with signature\n * - set(key: string, value: object): void | Promise<void>\n * - get(key: string): object | Promise<object>\n * - delete(key: string): void | Promise<void>\n */\n cache: Cache;\n /**\n * Required\n *\n * Function that is called when no valid value is in cache for given key\n * Basically what we would do if we wouldn't use a cache\n *\n * Can be async and must return fresh value or throw\n *\n * receives context object as argument\n * - context.metadata.ttl?: number\n * - context.metadata.swr?: number\n * - context.metadata.createdTime: number\n * - context.background: boolean\n */\n getFreshValue: GetFreshValue<Value>;\n /**\n * Time To Live; often also referred to as max age\n *\n * Amount of milliseconds the value should stay in cache\n * before we get a fresh one\n *\n * Setting any negative value will disable caching\n * Can be infinite\n *\n * Default: `Infinity`\n */\n ttl?: number;\n /**\n * Amount of milliseconds that a value with exceeded ttl is still returned\n * while a fresh value is refreshed in the background\n *\n * Should be positive, can be infinite\n *\n * Default: `0`\n */\n staleWhileRevalidate?: number;\n /**\n * Alias for staleWhileRevalidate\n */\n swr?: number;\n /**\n * Validator that checks every cached and fresh value to ensure type safety\n *\n * Can be a standard schema validator or a custom validator function\n * @see https://github.com/standard-schema/standard-schema?tab=readme-ov-file#what-schema-libraries-implement-the-spec\n *\n * Value considered ok when:\n * - schema succeeds\n * - validator returns\n * - true\n * - migrate(newValue)\n * - undefined\n * - null\n *\n * Value considered bad when:\n * - schema throws\n * - validator:\n * - returns false\n * - returns reason as string\n * - throws\n *\n * A validator function receives two arguments:\n * 1. the value\n * 2. a migrate callback, see https://github.com/epicweb-dev/cachified#migrating-values\n *\n * Default: `undefined` - no validation\n */\n checkValue?:\n | CheckValue<Value>\n | StandardSchemaV1<unknown, Value>\n | Schema<Value, unknown>;\n /**\n * Set true to not even try reading the currently cached value\n *\n * Will write new value to cache even when cached value is\n * still valid.\n *\n * Default: `false`\n */\n forceFresh?: boolean;\n /**\n * Whether or not to fall back to cache when getting a forced fresh value\n * fails\n *\n * Can also be a positive number as the maximum age in milliseconds that a\n * fallback value might have\n *\n * Default: `Infinity`\n */\n fallbackToCache?: boolean | number;\n /**\n * Amount of time in milliseconds before revalidation of a stale\n * cache entry is started\n *\n * Must be positive and finite\n *\n * Default: `0`\n * @deprecated manually delay background refreshes in getFreshValue instead\n * @see https://github.com/epicweb-dev/cachified/issues/132\n */\n staleRefreshTimeout?: number;\n /**\n * @deprecated pass reporter as second argument to cachified\n */\n reporter?: never;\n /**\n * Promises passed to `waitUntil` represent background tasks which must be\n * completed before the server can shutdown. e.g. swr cache revalidation\n *\n * Useful for serverless environments such as Cloudflare Workers.\n *\n * Default: `undefined`\n */\n waitUntil?: (promise: Promise<unknown>) => void;\n /**\n * Trace ID for debugging, is stored along cache metadata and can be accessed\n * in `getFreshValue` and reporter\n */\n traceId?: any;\n}\n\n/* When using a schema validator, a strongly typed getFreshValue is not required\n and sometimes even sub-optimal */\nexport type CachifiedOptionsWithSchema<Value, InternalValue> = Omit<\n CachifiedOptions<Value>,\n 'checkValue' | 'getFreshValue'\n> & {\n checkValue: StandardSchemaV1<unknown, Value> | Schema<Value, InternalValue>;\n getFreshValue: GetFreshValue<InternalValue>;\n};\n\nexport interface Context<Value>\n extends Omit<\n Required<CachifiedOptions<Value>>,\n 'fallbackToCache' | 'reporter' | 'checkValue' | 'swr' | 'traceId'\n > {\n checkValue: CheckValue<Value>;\n report: Reporter<Value>;\n fallbackToCache: number;\n metadata: CacheMetadata;\n traceId?: any;\n}\n\nfunction validateWithSchema<Value>(\n checkValue: StandardSchemaV1<unknown, Value> | Schema<Value, unknown>,\n): CheckValue<Value> {\n return async (value, migrate) => {\n let validatedValue;\n\n /* Standard Schema validation\n https://github.com/standard-schema/standard-schema?tab=readme-ov-file#how-do-i-accept-standard-schemas-in-my-library */\n if ('~standard' in checkValue) {\n let result = checkValue['~standard'].validate(value);\n if (result instanceof Promise) result = await result;\n\n if (result.issues) {\n throw result.issues;\n }\n\n validatedValue = result.value;\n } else {\n /* Legacy Schema validation for zod only\n TODO: remove in next major version */\n validatedValue = await checkValue.parseAsync(value);\n }\n\n return migrate(validatedValue, false);\n };\n}\n\nexport function createContext<Value>(\n { fallbackToCache, checkValue, ...options }: CachifiedOptions<Value>,\n reporter?: CreateReporter<Value>,\n): Context<Value> {\n const ttl = options.ttl ?? Infinity;\n const staleWhileRevalidate = options.swr ?? options.staleWhileRevalidate ?? 0;\n const checkValueCompat: CheckValue<Value> =\n typeof checkValue === 'function'\n ? checkValue\n : typeof checkValue === 'object'\n ? validateWithSchema(checkValue)\n : () => true;\n\n const contextWithoutReport = {\n checkValue: checkValueCompat,\n ttl,\n staleWhileRevalidate,\n fallbackToCache:\n fallbackToCache === false\n ? 0\n : fallbackToCache === true || fallbackToCache === undefined\n ? Infinity\n : fallbackToCache,\n staleRefreshTimeout: 0,\n forceFresh: false,\n ...options,\n metadata: createCacheMetaData({\n ttl,\n swr: staleWhileRevalidate,\n traceId: options.traceId,\n }),\n waitUntil: options.waitUntil ?? (() => {}),\n };\n\n const report =\n reporter?.(contextWithoutReport) ||\n (() => {\n /* \u00AF\\_(\u30C4)_/\u00AF */\n });\n\n return {\n ...contextWithoutReport,\n report,\n };\n}\n\nexport function staleWhileRevalidate(metadata: CacheMetadata): number | null {\n return (\n (typeof metadata.swr === 'undefined' ? metadata.swv : metadata.swr) || null\n );\n}\n\nexport function totalTtl(metadata?: CacheMetadata): number {\n if (!metadata) {\n return 0;\n }\n if (metadata.ttl === null) {\n return Infinity;\n }\n return (metadata.ttl || 0) + (staleWhileRevalidate(metadata) || 0);\n}\n\nexport function createCacheMetaData({\n ttl = null,\n swr = 0,\n createdTime = Date.now(),\n traceId,\n}: Partial<Omit<CacheMetadata, 'swv'>> = {}) {\n return {\n ttl: ttl === Infinity ? null : ttl,\n swr: swr === Infinity ? null : swr,\n createdTime,\n ...(traceId ? { traceId } : {}),\n };\n}\n\nexport function createCacheEntry<Value>(\n value: Value,\n metadata?: Partial<Omit<CacheMetadata, 'swv'>>,\n): CacheEntry<Value> {\n return {\n value,\n metadata: createCacheMetaData(metadata),\n };\n}\n", "import { CacheMetadata, Context, staleWhileRevalidate } from './common';\n\nexport type GetFreshValueStartEvent = {\n name: 'getFreshValueStart';\n};\nexport type GetFreshValueHookPendingEvent = {\n name: 'getFreshValueHookPending';\n};\nexport type GetFreshValueSuccessEvent<Value> = {\n name: 'getFreshValueSuccess';\n value: Value;\n};\nexport type GetFreshValueErrorEvent = {\n name: 'getFreshValueError';\n error: unknown;\n};\nexport type GetFreshValueCacheFallbackEvent = {\n name: 'getFreshValueCacheFallback';\n value: unknown;\n};\n/** @deprecated this event will be removed in favour of `CheckFreshValueErrorObjEvent` */\nexport type CheckFreshValueErrorEvent<Value> = {\n name: 'checkFreshValueError';\n reason: string;\n};\nexport type CheckFreshValueErrorObjEvent = {\n name: 'checkFreshValueErrorObj';\n reason: unknown;\n};\nexport type WriteFreshValueSuccessEvent<Value> = {\n name: 'writeFreshValueSuccess';\n metadata: CacheMetadata;\n /**\n * Value might not actually be written to cache in case getting fresh\n * value took longer then ttl */\n written: boolean;\n migrated: boolean;\n};\nexport type WriteFreshValueErrorEvent = {\n name: 'writeFreshValueError';\n error: unknown;\n};\n\nexport type GetCachedValueStartEvent = {\n name: 'getCachedValueStart';\n};\nexport type GetCachedValueReadEvent = {\n name: 'getCachedValueRead';\n entry: unknown;\n};\nexport type GetCachedValueEmptyEvent = {\n name: 'getCachedValueEmpty';\n};\nexport type GetCachedValueOutdatedEvent = {\n name: 'getCachedValueOutdated';\n value: unknown;\n metadata: CacheMetadata;\n};\nexport type GetCachedValueSuccessEvent<Value> = {\n name: 'getCachedValueSuccess';\n value: Value;\n migrated: boolean;\n};\n/** @deprecated this event will be removed in favour of `CheckCachedValueErrorObjEvent` */\nexport type CheckCachedValueErrorEvent = {\n name: 'checkCachedValueError';\n reason: string;\n};\nexport type CheckCachedValueErrorObjEvent = {\n name: 'checkCachedValueErrorObj';\n reason: unknown;\n};\nexport type GetCachedValueErrorEvent = {\n name: 'getCachedValueError';\n error: unknown;\n};\n\nexport type RefreshValueStartEvent = {\n name: 'refreshValueStart';\n};\nexport type RefreshValueSuccessEvent<Value> = {\n name: 'refreshValueSuccess';\n value: Value;\n};\nexport type RefreshValueErrorEvent = {\n name: 'refreshValueError';\n error: unknown;\n};\nexport type DoneEvent<Value> = {\n name: 'done';\n value: Value;\n};\n\nexport type CacheEvent<Value> =\n | GetFreshValueStartEvent\n | GetFreshValueHookPendingEvent\n | GetFreshValueSuccessEvent<Value>\n | GetFreshValueErrorEvent\n | GetFreshValueCacheFallbackEvent\n | CheckFreshValueErrorEvent<Value>\n | CheckFreshValueErrorObjEvent\n | WriteFreshValueSuccessEvent<Value>\n | WriteFreshValueErrorEvent\n | GetCachedValueStartEvent\n | GetCachedValueReadEvent\n | GetCachedValueEmptyEvent\n | GetCachedValueOutdatedEvent\n | GetCachedValueSuccessEvent<Value>\n | CheckCachedValueErrorEvent\n | CheckCachedValueErrorObjEvent\n | GetCachedValueErrorEvent\n | RefreshValueStartEvent\n | RefreshValueSuccessEvent<Value>\n | RefreshValueErrorEvent\n | DoneEvent<Value>;\n\nexport type Reporter<Value> = (event: CacheEvent<Value>) => void;\n\nexport type CreateReporter<Value> = (\n context: Omit<Context<Value>, 'report'>,\n) => Reporter<Value>;\n\nconst defaultFormatDuration = (ms: number) => `${Math.round(ms)}ms`;\nfunction formatCacheTime(\n metadata: CacheMetadata,\n formatDuration: (duration: number) => string,\n) {\n const swr = staleWhileRevalidate(metadata);\n if (metadata.ttl == null || swr == null) {\n return `forever${\n metadata.ttl != null\n ? ` (revalidation after ${formatDuration(metadata.ttl)})`\n : ''\n }`;\n }\n\n return `${formatDuration(metadata.ttl)} + ${formatDuration(swr)} stale`;\n}\n\nexport type NoInfer<T> = [T][T extends any ? 0 : never];\ninterface ReporterOpts {\n formatDuration?: (ms: number) => string;\n logger?: Pick<typeof console, 'log' | 'warn' | 'error'>;\n performance?: Pick<typeof Date, 'now'>;\n}\nexport function verboseReporter<Value>({\n formatDuration = defaultFormatDuration,\n logger = console,\n performance = globalThis.performance || Date,\n}: ReporterOpts = {}): CreateReporter<Value> {\n return ({ key, fallbackToCache, forceFresh, metadata, cache }) => {\n const cacheName =\n cache.name ||\n cache\n .toString()\n .toString()\n .replace(/^\\[object (.*?)]$/, '$1');\n let cached: unknown;\n let freshValue: unknown;\n let getFreshValueStartTs: number;\n let refreshValueStartTS: number;\n\n return (event) => {\n switch (event.name) {\n case 'getCachedValueRead':\n cached = event.entry;\n break;\n case 'checkCachedValueError':\n logger.warn(\n `check failed for cached value of ${key}\\nReason: ${event.reason}.\\nDeleting the cache key and trying to get a fresh value.`,\n cached,\n );\n break;\n case 'getCachedValueError':\n logger.error(\n `error with cache at ${key}. Deleting the cache key and trying to get a fresh value.`,\n event.error,\n );\n break;\n case 'getFreshValueError':\n logger.error(\n `getting a fresh value for ${key} failed`,\n { fallbackToCache, forceFresh },\n event.error,\n );\n break;\n case 'getFreshValueStart':\n getFreshValueStartTs = performance.now();\n break;\n case 'writeFreshValueSuccess': {\n const totalTime = performance.now() - getFreshValueStartTs;\n if (event.written) {\n logger.log(\n `Updated the cache value for ${key}.`,\n `Getting a fresh value for this took ${formatDuration(\n totalTime,\n )}.`,\n `Caching for ${formatCacheTime(\n metadata,\n formatDuration,\n )} in ${cacheName}.`,\n );\n } else {\n logger.log(\n `Not updating the cache value for ${key}.`,\n `Getting a fresh value for this took ${formatDuration(\n totalTime,\n )}.`,\n `Thereby exceeding caching time of ${formatCacheTime(\n metadata,\n formatDuration,\n )}`,\n );\n }\n break;\n }\n case 'writeFreshValueError':\n logger.error(`error setting cache: ${key}`, event.error);\n break;\n case 'getFreshValueSuccess':\n freshValue = event.value;\n break;\n case 'checkFreshValueError':\n logger.error(\n `check failed for fresh value of ${key}\\nReason: ${event.reason}.`,\n freshValue,\n );\n break;\n case 'refreshValueStart':\n refreshValueStartTS = performance.now();\n break;\n case 'refreshValueSuccess':\n logger.log(\n `Background refresh for ${key} successful.`,\n `Getting a fresh value for this took ${formatDuration(\n performance.now() - refreshValueStartTS,\n )}.`,\n `Caching for ${formatCacheTime(\n metadata,\n formatDuration,\n )} in ${cacheName}.`,\n );\n break;\n case 'refreshValueError':\n logger.error(`Background refresh for ${key} failed.`, event.error);\n break;\n }\n };\n };\n}\n\nexport function mergeReporters<Value = unknown>(\n ...reporters: (CreateReporter<Value> | null | undefined)[]\n): CreateReporter<Value> {\n return (context) => {\n const reporter = reporters.map((r) => r?.(context));\n return (event) => {\n reporter.forEach((r) => r?.(event));\n };\n };\n}\n", "import type {\n CacheMetadata,\n GetFreshValue,\n GetFreshValueContext,\n} from './common';\nimport { HANDLE } from './common';\n\ntype OnValueCallback<Value> = (\n context: GetFreshValueContext & {\n value: Value;\n },\n) => void;\n\nexport type AddFn<Value, Param> = (\n param: Param,\n onValue?: OnValueCallback<Value>,\n) => GetFreshValue<Value>;\n\nexport type GetFreshValues<Value, Param> = (\n params: Param[],\n metadata: CacheMetadata[],\n) => Value[] | Promise<Value[]>;\n\nexport function createBatch<Value, Param>(\n getFreshValues: GetFreshValues<Value, Param>,\n autoSubmit: false,\n): {\n submit: () => Promise<void>;\n add: AddFn<Value, Param>;\n};\nexport function createBatch<Value, Param>(\n getFreshValues: GetFreshValues<Value, Param>,\n): {\n add: AddFn<Value, Param>;\n};\nexport function createBatch<Value, Param>(\n getFreshValues: GetFreshValues<Value, Param>,\n autoSubmit: boolean = true,\n): {\n submit?: () => Promise<void>;\n add: AddFn<Value, Param>;\n} {\n const requests: [\n param: Param,\n res: (value: Value) => void,\n rej: (reason: unknown) => void,\n metadata: CacheMetadata,\n ][] = [];\n\n let count = 0;\n let submitted = false;\n const submission = new Deferred<void>();\n\n const checkSubmission = () => {\n if (submitted) {\n throw new Error('Can not add to batch after submission');\n }\n };\n\n const submit = async () => {\n if (count !== 0) {\n autoSubmit = true;\n return submission.promise;\n }\n checkSubmission();\n submitted = true;\n\n if (requests.length === 0) {\n submission.resolve();\n return;\n }\n\n try {\n const results = await Promise.resolve(\n getFreshValues(\n requests.map(([param]) => param),\n requests.map((args) => args[3]),\n ),\n );\n if (results.length !== requests.length) {\n throw new Error(\n `Batch loader must return an array with the same length as the input array (expected ${requests.length}, got ${results.length})`,\n );\n }\n results.forEach((value, index) => requests[index][1](value));\n submission.resolve();\n } catch (err) {\n requests.forEach(([_, __, rej]) => rej(err));\n submission.resolve();\n }\n };\n\n const trySubmitting = () => {\n count--;\n if (autoSubmit === false) {\n return;\n }\n submit();\n };\n\n return {\n ...(autoSubmit === false ? { submit } : {}),\n add(param, onValue) {\n checkSubmission();\n count++;\n let handled = false;\n\n return Object.assign(\n (context: GetFreshValueContext) => {\n return new Promise<Value>((res, rej) => {\n requests.push([\n param,\n (value) => {\n onValue?.({ ...context, value });\n res(value);\n },\n rej,\n context.metadata,\n ]);\n if (!handled) {\n handled = true;\n trySubmitting();\n }\n });\n },\n {\n [HANDLE]: () => {\n if (!handled) {\n handled = true;\n trySubmitting();\n }\n },\n },\n );\n },\n };\n}\n\nexport class Deferred<Value> {\n readonly promise: Promise<Value>;\n // @ts-ignore\n readonly resolve: (value: Value | Promise<Value>) => void;\n // @ts-ignore\n readonly reject: (reason: unknown) => void;\n constructor() {\n this.promise = new Promise((res, rej) => {\n // @ts-ignore\n this.resolve = res;\n // @ts-ignore\n this.reject = rej;\n });\n }\n}\n", "import type { CacheMetadata } from './common';\n\nexport function logKey(key?: string) {\n return key ? `for ${key} ` : '';\n}\n\nexport function assertCacheEntry(\n entry: unknown,\n key?: string,\n): asserts entry is {\n metadata: CacheMetadata;\n value: unknown;\n} {\n if (!isRecord(entry)) {\n throw new Error(\n `Cache entry ${logKey(\n key,\n )}is not a cache entry object, it's a ${typeof entry}`,\n );\n }\n if (\n !isRecord(entry.metadata) ||\n typeof entry.metadata.createdTime !== 'number' ||\n (entry.metadata.ttl != null && typeof entry.metadata.ttl !== 'number') ||\n (entry.metadata.swr != null && typeof entry.metadata.swr !== 'number')\n ) {\n throw new Error(\n `Cache entry ${logKey(key)}does not have valid metadata property`,\n );\n }\n\n if (!('value' in entry)) {\n throw new Error(\n `Cache entry for ${logKey(key)}does not have a value property`,\n );\n }\n}\n\nfunction isRecord(entry: unknown): entry is Record<string, unknown> {\n return typeof entry === 'object' && entry !== null && !Array.isArray(entry);\n}\n", "import { CacheMetadata, staleWhileRevalidate } from './common';\n\n/**\n * Check wether a cache entry is expired.\n *\n * @returns\n * - `true` when the cache entry is expired\n * - `false` when it's still valid\n * - `\"stale\"` when it's within the stale period\n */\nexport function isExpired(metadata: CacheMetadata): boolean | 'stale' {\n /* No TTL means the cache is permanent / never expires */\n if (metadata.ttl === null) {\n return false;\n }\n\n const validUntil = metadata.createdTime + (metadata.ttl || 0);\n const staleUntil = validUntil + (staleWhileRevalidate(metadata) || 0);\n const now = Date.now();\n\n /* We're still within the ttl period */\n if (now <= validUntil) {\n return false;\n }\n /* We're within the stale period */\n if (now <= staleUntil) {\n return 'stale';\n }\n\n /* Expired */\n return true;\n}\n\n/**\n * @deprecated prefer using `isExpired` instead\n */\nexport function shouldRefresh(\n metadata: CacheMetadata,\n): 'now' | 'stale' | false {\n const expired = isExpired(metadata);\n\n if (expired === true) {\n return 'now';\n }\n\n return expired;\n}\n", "import type { Context } from './common';\nimport { MIGRATED } from './common';\n\nexport async function checkValue<Value>(\n context: Context<Value>,\n value: unknown,\n): Promise<\n | { success: true; value: Value; migrated: boolean }\n | { success: false; reason: unknown }\n> {\n try {\n const checkResponse = await context.checkValue(\n value,\n (value, updateCache = true) => ({\n [MIGRATED]: updateCache,\n value,\n }),\n );\n\n if (typeof checkResponse === 'string') {\n return { success: false, reason: checkResponse };\n }\n\n if (checkResponse == null || checkResponse === true) {\n return {\n success: true,\n value: value as Value,\n migrated: false,\n };\n }\n\n if (checkResponse && typeof checkResponse[MIGRATED] === 'boolean') {\n return {\n success: true,\n migrated: checkResponse[MIGRATED],\n value: checkResponse.value,\n };\n }\n\n return { success: false, reason: 'unknown' };\n } catch (err) {\n return {\n success: false,\n reason: err,\n };\n }\n}\n", "import { Context, CacheEntry, CachifiedOptions } from './common';\nimport { assertCacheEntry } from './assertCacheEntry';\nimport { HANDLE } from './common';\nimport { isExpired } from './isExpired';\nimport { cachified } from './cachified';\nimport { Reporter } from './reporter';\nimport { checkValue } from './checkValue';\n\nexport const CACHE_EMPTY = Symbol();\nexport async function getCacheEntry<Value>(\n { key, cache }: Pick<Context<Value>, 'key' | 'cache'>,\n report: Reporter<Value>,\n): Promise<CacheEntry<unknown> | typeof CACHE_EMPTY> {\n report({ name: 'getCachedValueStart' });\n const cached = await cache.get(key);\n report({ name: 'getCachedValueRead', entry: cached });\n if (cached) {\n assertCacheEntry(cached, key);\n return cached;\n }\n return CACHE_EMPTY;\n}\n\nexport async function getCachedValue<Value>(\n context: Context<Value>,\n report: Reporter<Value>,\n hasPendingValue: () => boolean,\n): Promise<Value | typeof CACHE_EMPTY> {\n const {\n key,\n cache,\n staleWhileRevalidate,\n staleRefreshTimeout,\n metadata,\n getFreshValue,\n } = context;\n\n try {\n const cached = await getCacheEntry(context, report);\n\n if (cached === CACHE_EMPTY) {\n report({ name: 'getCachedValueEmpty' });\n return CACHE_EMPTY;\n }\n\n const expired = isExpired(cached.metadata);\n const staleRefresh =\n expired === 'stale' ||\n (expired === true && staleWhileRevalidate === Infinity);\n\n if (expired === true) {\n report({ name: 'getCachedValueOutdated', ...cached });\n }\n\n if (staleRefresh) {\n const staleRefreshOptions: CachifiedOptions<Value> = {\n ...context,\n async getFreshValue({ metadata }) {\n /* TODO: When staleRefreshTimeout option is removed we should\n also remove this or set it to ~0-200ms depending on ttl values.\n The intention of the delay is to not take sync resources for\n background refreshing \u2013 still we need to queue the refresh\n directly so that the de-duplication works.\n See https://github.com/epicweb-dev/cachified/issues/132 */\n await sleep(staleRefreshTimeout);\n report({ name: 'refreshValueStart' });\n return getFreshValue({\n metadata,\n background: true,\n });\n },\n forceFresh: true,\n fallbackToCache: false,\n };\n\n // pass down batch handle when present\n // https://github.com/epicweb-dev/cachified/issues/144\n staleRefreshOptions.getFreshValue[HANDLE] = context.getFreshValue[HANDLE];\n\n // refresh cache in background so future requests are faster\n context.waitUntil(\n cachified(staleRefreshOptions)\n .then((value) => {\n report({ name: 'refreshValueSuccess', value });\n })\n .catch((error) => {\n report({ name: 'refreshValueError', error });\n }),\n );\n }\n\n if (!expired || staleRefresh) {\n const valueCheck = await checkValue(context, cached.value);\n if (valueCheck.success) {\n report({\n name: 'getCachedValueSuccess',\n value: valueCheck.value,\n migrated: valueCheck.migrated,\n });\n if (!staleRefresh) {\n // Notify batch that we handled this call using cached value\n getFreshValue[HANDLE]?.();\n }\n\n if (valueCheck.migrated) {\n context.waitUntil(\n Promise.resolve().then(async () => {\n try {\n await sleep(0); // align with original setTimeout behavior (allowing other microtasks/tasks to run)\n const cached = await context.cache.get(context.key);\n\n // Unless cached value was changed in the meantime or is about to\n // change\n if (\n cached &&\n cached.metadata.createdTime === metadata.createdTime &&\n !hasPendingValue()\n ) {\n // update with migrated value\n await context.cache.set(context.key, {\n ...cached,\n value: valueCheck.value,\n });\n }\n } catch (err) {\n /* \u00AF\\_(\u30C4)_/\u00AF */\n }\n }),\n );\n }\n\n return valueCheck.value;\n } else {\n report({ name: 'checkCachedValueErrorObj', reason: valueCheck.reason });\n report({\n name: 'checkCachedValueError',\n reason:\n valueCheck.reason instanceof Error\n ? valueCheck.reason.message\n : String(valueCheck.reason),\n });\n\n await cache.delete(key);\n }\n }\n } catch (error: unknown) {\n report({ name: 'getCachedValueError', error });\n\n await cache.delete(key);\n }\n\n return CACHE_EMPTY;\n}\n\nfunction sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n", "import { Context, CacheMetadata, createCacheEntry } from './common';\nimport { getCacheEntry, CACHE_EMPTY } from './getCachedValue';\nimport { isExpired } from './isExpired';\nimport { Reporter } from './reporter';\nimport { checkValue } from './checkValue';\n\nexport async function getFreshValue<Value>(\n context: Context<Value>,\n metadata: CacheMetadata,\n report: Reporter<Value>,\n): Promise<Value> {\n const { fallbackToCache, key, getFreshValue, forceFresh, cache } = context;\n\n let value: unknown;\n try {\n report({ name: 'getFreshValueStart' });\n const freshValue = await getFreshValue({\n metadata: context.metadata,\n background: false,\n });\n value = freshValue;\n report({ name: 'getFreshValueSuccess', value: freshValue });\n } catch (error) {\n report({ name: 'getFreshValueError', error });\n\n // in case a fresh value was forced (and errored) we might be able to\n // still get one from cache\n if (forceFresh && fallbackToCache > 0) {\n const entry = await getCacheEntry(context, report);\n if (\n entry === CACHE_EMPTY ||\n entry.metadata.createdTime + fallbackToCache < Date.now()\n ) {\n throw error;\n }\n value = entry.value;\n report({ name: 'getFreshValueCacheFallback', value });\n } else {\n // we are either not allowed to check the cache or already checked it\n // nothing we can do anymore\n throw error;\n }\n }\n\n const valueCheck = await checkValue(context, value);\n if (!valueCheck.success) {\n report({ name: 'checkFreshValueErrorObj', reason: valueCheck.reason });\n report({\n name: 'checkFreshValueError',\n reason:\n valueCheck.reason instanceof Error\n ? valueCheck.reason.message\n : String(valueCheck.reason),\n });\n\n throw new Error(`check failed for fresh value of ${key}`, {\n cause: valueCheck.reason,\n });\n }\n\n try {\n /* Only write to cache when the value has not already fully expired while getting it */\n const write = isExpired(metadata) !== true;\n if (write) {\n await cache.set(key, createCacheEntry(value, metadata));\n }\n report({\n name: 'writeFreshValueSuccess',\n metadata,\n migrated: valueCheck.migrated,\n written: write,\n });\n } catch (error: unknown) {\n report({ name: 'writeFreshValueError', error });\n }\n\n return valueCheck.value;\n}\n", "import {\n CachifiedOptions,\n CachifiedOptionsWithSchema,\n Cache,\n createContext,\n HANDLE,\n} from './common';\nimport { CACHE_EMPTY, getCachedValue } from './getCachedValue';\nimport { getFreshValue } from './getFreshValue';\nimport { CreateReporter } from './reporter';\nimport { isExpired } from './isExpired';\n\n// This is to prevent requesting multiple fresh values in parallel\n// while revalidating or getting first value\n// Keys are unique per cache but may be used by multiple caches\nconst pendingValuesByCache = new WeakMap<Cache, Map<string, any>>();\n\n/**\n * Get the internal pending values cache for a given cache\n */\nexport function getPendingValuesCache(cache: Cache) {\n if (!pendingValuesByCache.has(cache)) {\n pendingValuesByCache.set(cache, new Map());\n }\n return pendingValuesByCache.get(cache)!;\n}\n\nexport async function cachified<Value, InternalValue>(\n options: CachifiedOptionsWithSchema<Value, InternalValue>,\n reporter?: CreateReporter<Value>,\n): Promise<Value>;\nexport async function cachified<Value>(\n options: CachifiedOptions<Value>,\n reporter?: CreateReporter<Value>,\n): Promise<Value>;\nexport async function cachified<Value>(\n options: CachifiedOptions<Value>,\n reporter?: CreateReporter<Value>,\n): Promise<Value> {\n const context = createContext(options, reporter);\n const { key, cache, forceFresh, report, metadata } = context;\n const pendingValues = getPendingValuesCache(cache);\n\n const hasPendingValue = () => {\n return pendingValues.has(key);\n };\n const cachedValue = !forceFresh\n ? await getCachedValue(context, report, hasPendingValue)\n : CACHE_EMPTY;\n if (cachedValue !== CACHE_EMPTY) {\n report({ name: 'done', value: cachedValue });\n return cachedValue;\n }\n\n if (pendingValues.has(key)) {\n const { value: pendingRefreshValue, metadata } = pendingValues.get(key)!;\n\n if (!isExpired(metadata)) {\n /* Notify batch that we handled this call using pending value */\n context.getFreshValue[HANDLE]?.();\n report({ name: 'getFreshValueHookPending' });\n const value = await pendingRefreshValue;\n report({ name: 'done', value });\n return value;\n }\n }\n\n let resolveFromFuture: (value: Value) => void;\n const freshValue = Promise.race([\n // try to get a fresh value\n getFreshValue(context, metadata, report),\n // or when a future call is faster, we'll take it's value\n // this happens when getting value of first call takes longer then ttl + second response\n new Promise<Value>((r) => {\n resolveFromFuture = r;\n }),\n ]).finally(() => {\n pendingValues.delete(key);\n });\n\n // here we inform past calls that we got a response\n if (pendingValues.has(key)) {\n const { resolve } = pendingValues.get(key)!;\n freshValue.then((value) => resolve(value));\n }\n\n pendingValues.set(key, {\n metadata,\n value: freshValue,\n // here we receive a fresh value from a future call\n resolve: resolveFromFuture!,\n });\n\n const value = await freshValue;\n report({ name: 'done', value });\n return value;\n}\n", "import { Cache, createCacheEntry, staleWhileRevalidate } from './common';\nimport { CACHE_EMPTY, getCacheEntry } from './getCachedValue';\nimport { isExpired } from './isExpired';\n\ninterface SoftPurgeOpts {\n cache: Cache;\n key: string;\n /**\n * Force the entry to outdate after ms\n */\n staleWhileRevalidate?: number;\n /**\n * Force the entry to outdate after ms\n */\n swr?: number;\n}\n\nexport async function softPurge({\n cache,\n key,\n ...swrOverwrites\n}: SoftPurgeOpts) {\n const swrOverwrite = swrOverwrites.swr ?? swrOverwrites.staleWhileRevalidate;\n const entry = await getCacheEntry({ cache, key }, () => {});\n\n if (entry === CACHE_EMPTY || isExpired(entry.metadata)) {\n return;\n }\n\n const ttl = entry.metadata.ttl || Infinity;\n const swr = staleWhileRevalidate(entry.metadata) || 0;\n const lt = Date.now() - entry.metadata.createdTime;\n\n await cache.set(\n key,\n createCacheEntry(entry.value, {\n ttl: 0,\n swr: swrOverwrite === undefined ? ttl + swr : swrOverwrite + lt,\n createdTime: entry.metadata.createdTime,\n }),\n );\n}\n", "import { cachified } from './cachified';\nimport { CachifiedOptions, CachifiedOptionsWithSchema } from './common';\nimport { CreateReporter, mergeReporters } from './reporter';\n\ntype PartialOptions<\n Options extends CachifiedOptions<any>,\n OptionalKeys extends string | number | symbol,\n> = Omit<Options, OptionalKeys> &\n Partial<Pick<Options, Extract<OptionalKeys, keyof Options>>>;\n\n/**\n * create a pre-configured version of cachified\n */\nexport function configure<\n ConfigureValue extends unknown,\n Opts extends Partial<CachifiedOptions<ConfigureValue>>,\n>(defaultOptions: Opts, defaultReporter?: CreateReporter<ConfigureValue>) {\n function configuredCachified<Value, InternalValue>(\n options: PartialOptions<\n CachifiedOptionsWithSchema<Value, InternalValue>,\n keyof Opts\n >,\n reporter?: CreateReporter<Value>,\n ): Promise<Value>;\n async function configuredCachified<Value>(\n options: PartialOptions<CachifiedOptions<Value>, keyof Opts>,\n reporter?: CreateReporter<Value>,\n ): Promise<Value>;\n function configuredCachified<Value>(\n options: PartialOptions<CachifiedOptions<Value>, keyof Opts>,\n reporter?: CreateReporter<Value>,\n ) {\n return cachified(\n {\n ...defaultOptions,\n ...options,\n } as any as CachifiedOptions<Value>,\n mergeReporters(defaultReporter as any as CreateReporter<Value>, reporter),\n );\n }\n\n return configuredCachified;\n}\n"],
"mappings": "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