UNPKG

@epic-web/cachified

Version:
206 lines (205 loc) 7.24 kB
import type { CreateReporter, Reporter } from './reporter'; import { StandardSchemaV1 } from './StandardSchemaV1'; export interface CacheMetadata { createdTime: number; ttl?: number | null; swr?: number | null; traceId?: any; /** @deprecated use swr instead */ readonly swv?: number | null; } export interface CacheEntry<Value = unknown> { metadata: CacheMetadata; value: Value; } export type Eventually<Value> = Value | null | undefined | Promise<Value | null | undefined>; export interface Cache<Value = any> { name?: string; get: (key: string) => Eventually<CacheEntry<Value>>; set: (key: string, value: CacheEntry<Value>) => unknown | Promise<unknown>; delete: (key: string) => unknown | Promise<unknown>; } export interface GetFreshValueContext { readonly metadata: CacheMetadata; readonly background: boolean; } export declare const HANDLE: unique symbol; export type GetFreshValue<Value> = { (context: GetFreshValueContext): Promise<Value> | Value; [HANDLE]?: () => void; }; export declare const MIGRATED: unique symbol; export type MigratedValue<Value> = { [MIGRATED]: boolean; value: Value; }; export type ValueCheckResultOk<Value> = true | undefined | null | void | MigratedValue<Value>; export type ValueCheckResultInvalid = false | string; export type ValueCheckResult<Value> = ValueCheckResultOk<Value> | ValueCheckResultInvalid; export type CheckValue<Value> = (value: unknown, migrate: (value: Value, updateCache?: boolean) => MigratedValue<Value>) => ValueCheckResult<Value> | Promise<ValueCheckResult<Value>>; /** * @deprecated use a library supporting Standard Schema * @see https://github.com/standard-schema/standard-schema?tab=readme-ov-file#what-schema-libraries-implement-the-spec * @todo remove in next major version */ export interface Schema<Value, InputValue> { _input: InputValue; parseAsync(value: unknown): Promise<Value>; } export interface CachifiedOptions<Value> { /** * Required * * The key this value is cached by * Must be unique for each value */ key: string; /** * Required * * Cache implementation to use * * Must conform with signature * - set(key: string, value: object): void | Promise<void> * - get(key: string): object | Promise<object> * - delete(key: string): void | Promise<void> */ cache: Cache; /** * Required * * Function that is called when no valid value is in cache for given key * Basically what we would do if we wouldn't use a cache * * Can be async and must return fresh value or throw * * receives context object as argument * - context.metadata.ttl?: number * - context.metadata.swr?: number * - context.metadata.createdTime: number * - context.background: boolean */ getFreshValue: GetFreshValue<Value>; /** * Time To Live; often also referred to as max age * * Amount of milliseconds the value should stay in cache * before we get a fresh one * * Setting any negative value will disable caching * Can be infinite * * Default: `Infinity` */ ttl?: number; /** * Amount of milliseconds that a value with exceeded ttl is still returned * while a fresh value is refreshed in the background * * Should be positive, can be infinite * * Default: `0` */ staleWhileRevalidate?: number; /** * Alias for staleWhileRevalidate */ swr?: number; /** * Validator that checks every cached and fresh value to ensure type safety * * Can be a standard schema validator or a custom validator function * @see https://github.com/standard-schema/standard-schema?tab=readme-ov-file#what-schema-libraries-implement-the-spec * * Value considered ok when: * - schema succeeds * - validator returns * - true * - migrate(newValue) * - undefined * - null * * Value considered bad when: * - schema throws * - validator: * - returns false * - returns reason as string * - throws * * A validator function receives two arguments: * 1. the value * 2. a migrate callback, see https://github.com/epicweb-dev/cachified#migrating-values * * Default: `undefined` - no validation */ checkValue?: CheckValue<Value> | StandardSchemaV1<unknown, Value> | Schema<Value, unknown>; /** * Set true to not even try reading the currently cached value * * Will write new value to cache even when cached value is * still valid. * * Default: `false` */ forceFresh?: boolean; /** * Whether or not to fall back to cache when getting a forced fresh value * fails * * Can also be a positive number as the maximum age in milliseconds that a * fallback value might have * * Default: `Infinity` */ fallbackToCache?: boolean | number; /** * Amount of time in milliseconds before revalidation of a stale * cache entry is started * * Must be positive and finite * * Default: `0` * @deprecated manually delay background refreshes in getFreshValue instead * @see https://github.com/epicweb-dev/cachified/issues/132 */ staleRefreshTimeout?: number; /** * @deprecated pass reporter as second argument to cachified */ reporter?: never; /** * Promises passed to `waitUntil` represent background tasks which must be * completed before the server can shutdown. e.g. swr cache revalidation * * Useful for serverless environments such as Cloudflare Workers. * * Default: `undefined` */ waitUntil?: (promise: Promise<unknown>) => void; /** * Trace ID for debugging, is stored along cache metadata and can be accessed * in `getFreshValue` and reporter */ traceId?: any; } export type CachifiedOptionsWithSchema<Value, InternalValue> = Omit<CachifiedOptions<Value>, 'checkValue' | 'getFreshValue'> & { checkValue: StandardSchemaV1<unknown, Value> | Schema<Value, InternalValue>; getFreshValue: GetFreshValue<InternalValue>; }; export interface Context<Value> extends Omit<Required<CachifiedOptions<Value>>, 'fallbackToCache' | 'reporter' | 'checkValue' | 'swr' | 'traceId'> { checkValue: CheckValue<Value>; report: Reporter<Value>; fallbackToCache: number; metadata: CacheMetadata; traceId?: any; } export declare function createContext<Value>({ fallbackToCache, checkValue, ...options }: CachifiedOptions<Value>, reporter?: CreateReporter<Value>): Context<Value>; export declare function staleWhileRevalidate(metadata: CacheMetadata): number | null; export declare function totalTtl(metadata?: CacheMetadata): number; export declare function createCacheMetaData({ ttl, swr, createdTime, traceId, }?: Partial<Omit<CacheMetadata, 'swv'>>): { traceId?: any; ttl: number | null; swr: number | null; createdTime: number; }; export declare function createCacheEntry<Value>(value: Value, metadata?: Partial<Omit<CacheMetadata, 'swv'>>): CacheEntry<Value>;