You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

157 lines
4.3 KiB

import {
CACHE_DURATION_UNIT_DAY,
CACHE_DURATION_UNIT_HOUR,
CACHE_DURATION_UNIT_MINUTE,
CACHE_DURATION_UNIT_MS,
CACHE_DURATION_UNIT_SECOND,
CACHE_ERROR_MESSAGES,
CACHE_MS_DAY,
CACHE_MS_HOUR,
CACHE_MS_MINUTE,
CACHE_MS_SECOND,
CACHE_POLICY_CATALOG,
CACHE_POLICY_IMMUTABLE,
CACHE_POLICY_INTERACTIVE,
CACHE_POLICY_PRIVATE_SESSION,
CACHE_POLICY_REALTIME,
CACHE_READ_MODE_CACHE_FIRST,
CACHE_READ_MODE_MUST_REVALIDATE,
CACHE_READ_MODE_STALE_WHILE_REVALIDATE,
DEFAULT_CACHE_POLICY
} from './consts.ts';
import { CachePolicyError } from './errors.ts';
import type { CachePolicy, CacheReadMode, DurationInput, ResolvedCachePolicy } from './types.ts';
export function defaultCachePolicies(): Record<string, CachePolicy> {
return {
[CACHE_POLICY_REALTIME]: {
freshFor: 0,
staleFor: 0,
staleIfErrorFor: 0,
gcAfter: CACHE_MS_MINUTE,
mode: CACHE_READ_MODE_MUST_REVALIDATE,
persist: false
},
[CACHE_POLICY_INTERACTIVE]: {
freshFor: 30 * CACHE_MS_SECOND,
staleFor: 5 * CACHE_MS_MINUTE,
staleIfErrorFor: 30 * CACHE_MS_MINUTE,
gcAfter: 30 * CACHE_MS_MINUTE,
mode: CACHE_READ_MODE_STALE_WHILE_REVALIDATE,
persist: true
},
[CACHE_POLICY_CATALOG]: {
freshFor: 10 * CACHE_MS_MINUTE,
staleFor: CACHE_MS_DAY,
staleIfErrorFor: 7 * CACHE_MS_DAY,
gcAfter: 7 * CACHE_MS_DAY,
mode: CACHE_READ_MODE_STALE_WHILE_REVALIDATE,
persist: true
},
[CACHE_POLICY_PRIVATE_SESSION]: {
freshFor: 10 * CACHE_MS_SECOND,
staleFor: CACHE_MS_MINUTE,
staleIfErrorFor: 0,
gcAfter: 15 * CACHE_MS_MINUTE,
mode: CACHE_READ_MODE_MUST_REVALIDATE,
persist: false
},
[CACHE_POLICY_IMMUTABLE]: {
freshFor: Number.MAX_SAFE_INTEGER,
staleFor: Number.MAX_SAFE_INTEGER,
staleIfErrorFor: Number.MAX_SAFE_INTEGER,
gcAfter: Number.MAX_SAFE_INTEGER,
mode: CACHE_READ_MODE_CACHE_FIRST,
persist: true
}
};
}
export function resolvePolicy(input: {
policy?: string | CachePolicy;
policies?: Record<string, CachePolicy>;
defaultPolicy?: string | CachePolicy;
mode?: CacheReadMode;
persist?: boolean;
}): ResolvedCachePolicy {
const namedPolicies = {
...defaultCachePolicies(),
...(input.policies ?? {})
};
const selected = input.policy ?? input.defaultPolicy ?? DEFAULT_CACHE_POLICY;
let raw: CachePolicy;
let name: string | undefined;
if (typeof selected === 'string') {
name = selected;
const named = namedPolicies[selected];
if (!named) throw new CachePolicyError(CACHE_ERROR_MESSAGES.POLICY_UNKNOWN(selected));
raw = named;
} else {
raw = selected;
}
const merged: CachePolicy = {
...DEFAULT_CACHE_POLICY,
...raw,
mode: input.mode ?? raw.mode ?? DEFAULT_CACHE_POLICY.mode,
persist: input.persist ?? raw.persist ?? DEFAULT_CACHE_POLICY.persist
};
const freshForMs = durationToMs(merged.freshFor, 'freshFor');
const staleForMs = durationToMs(merged.staleFor ?? 0, 'staleFor');
const staleIfErrorForMs = durationToMs(merged.staleIfErrorFor ?? 0, 'staleIfErrorFor');
const gcAfterMs = durationToMs(
merged.gcAfter ?? Math.max(freshForMs + staleForMs, freshForMs + staleIfErrorForMs),
'gcAfter'
);
if (freshForMs < 0 || staleForMs < 0 || staleIfErrorForMs < 0 || gcAfterMs < 0) {
throw new CachePolicyError(CACHE_ERROR_MESSAGES.POLICY_DURATION_NEGATIVE);
}
return {
...(name ? { name } : {}),
freshForMs,
staleForMs,
staleIfErrorForMs,
gcAfterMs,
mode: merged.mode ?? CACHE_READ_MODE_STALE_WHILE_REVALIDATE,
persist: merged.persist ?? true
};
}
export function durationToMs(value: DurationInput, fieldName = 'duration'): number {
if (typeof value === 'number') {
if (!Number.isFinite(value)) {
throw new CachePolicyError(CACHE_ERROR_MESSAGES.POLICY_DURATION_NOT_FINITE(fieldName));
}
return value;
}
const match = /^(\d+(?:\.\d+)?)(ms|s|m|h|d)$/.exec(value);
if (!match) {
throw new CachePolicyError(CACHE_ERROR_MESSAGES.POLICY_DURATION_INVALID(fieldName));
}
const amount = Number(match[1]);
const unit = match[2];
switch (unit) {
case CACHE_DURATION_UNIT_MS:
return amount;
case CACHE_DURATION_UNIT_SECOND:
return amount * CACHE_MS_SECOND;
case CACHE_DURATION_UNIT_MINUTE:
return amount * CACHE_MS_MINUTE;
case CACHE_DURATION_UNIT_HOUR:
return amount * CACHE_MS_HOUR;
case CACHE_DURATION_UNIT_DAY:
return amount * CACHE_MS_DAY;
default:
throw new CachePolicyError(CACHE_ERROR_MESSAGES.POLICY_DURATION_UNIT_INVALID(fieldName));
}
}

Powered by TurnKey Linux.