-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcache-handler.mjs
More file actions
77 lines (65 loc) · 2.17 KB
/
Copy pathcache-handler.mjs
File metadata and controls
77 lines (65 loc) · 2.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// ============================================================
// Vercel Remote Cache Handler — ISR + Data Cache
// ============================================================
// This file is referenced by next.config.ts via the
// `cacheHandler` option. It stores ISR-rendered pages and
// fetch() cache in Upstash Redis so they survive deployments
// and are shared across all Vercel regions.
//
// Falls back to the default in-memory cache when Redis is
// unavailable (local dev, build phase).
// ============================================================
import { Redis } from "@upstash/redis";
const redisUrl = process.env.UPSTASH_REDIS_REST_URL;
const redisToken = process.env.UPSTASH_REDIS_REST_TOKEN;
const hasRedis = !!(redisUrl && redisToken);
const redis = hasRedis
? new Redis({ url: redisUrl, token: redisToken })
: null;
const PREFIX = "suplecost:isr:";
export default class RemoteCache {
/** @type {Map<string, any>} */
_cache = new Map();
async get(key) {
// Try local (fast path) first
const local = this._cache.get(key);
if (local !== undefined) return local;
// Fall back to Redis
if (redis) {
try {
const val = await redis.get(`${PREFIX}${key}`);
if (val !== null && val !== undefined) {
// Warm local cache
this._cache.set(key, val);
return val;
}
} catch {
// Redis unavailable — fall back
}
}
return null;
}
async set(key, value, { ttl } = {}) {
// Always store locally
this._cache.set(key, value);
// Fire-and-forget to Redis
if (redis) {
const redisKey = `${PREFIX}${key}`;
if (ttl) {
redis.set(redisKey, value, { ex: ttl }).catch(() => {});
} else {
redis.set(redisKey, value).catch(() => {});
}
}
}
async revalidateTag(tag) {
// Tags are stored as keys under suplecost:isr:tag:{tag}
// Invalidation is handled by the app-level cache system.
// For ISR tag-based revalidation, clear the local cache
// and let the app's revalidation logic handle Redis.
this._cache.clear();
}
async resetRequestCache() {
// Called per-request — no-op for persistent cache
}
}