- Cache read-heavy public API routes via redisCache (leaderboard, values, shop, articles, photos, guilds, teams, staff, users, home, radio, badges) - Add single-flight and bounded-memory cache layer with unit tests - Parallelize independent DB queries on search, rares, shop, staff, polls and profile pages - Push radio points leaderboard aggregation to SQL with a LIMIT - Split studio-client and import-furni-client into focused modules - Clean up next.config.ts
37 lines
961 B
TypeScript
37 lines
961 B
TypeScript
import "server-only";
|
|
|
|
import { cached } from "@/lib/cache";
|
|
|
|
/**
|
|
* Cache the result of a fetch function, memory-first with a Redis fallback
|
|
* (see `cached()`). TTL is given in seconds.
|
|
*/
|
|
export async function redisCache<T>(
|
|
key: string,
|
|
ttlSeconds: number,
|
|
fetch: () => Promise<T>,
|
|
): Promise<T> {
|
|
return cached(key, ttlSeconds * 1000, fetch);
|
|
}
|
|
|
|
/**
|
|
* Build a namespaced cache key for API routes.
|
|
*/
|
|
export function apiCacheKey(path: string): string {
|
|
return `api:${path}`;
|
|
}
|
|
|
|
/**
|
|
* Deep-convert a payload to a JSON-cache-safe form: BigInt → string (matching
|
|
* the apiJson() wire format) and Date → ISO string, since JSON.stringify throws
|
|
* on BigInt. Use for payloads cached through redisCache() that are serialised
|
|
* straight to a response and never consumed by page logic.
|
|
*/
|
|
export function cacheSafe<T>(value: T): T {
|
|
return JSON.parse(
|
|
JSON.stringify(value, (_k, v) =>
|
|
typeof v === "bigint" ? v.toString() : v,
|
|
),
|
|
) as T;
|
|
}
|