-
Notifications
You must be signed in to change notification settings - Fork 118
Expand file tree
/
Copy pathr2-incremental-cache.ts
More file actions
80 lines (65 loc) · 2.53 KB
/
r2-incremental-cache.ts
File metadata and controls
80 lines (65 loc) · 2.53 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
78
79
80
import { debug, error } from "@opennextjs/aws/adapters/logger.js";
import type { CacheValue, IncrementalCache, WithLastModified } from "@opennextjs/aws/types/overrides.js";
import { IgnorableError } from "@opennextjs/aws/utils/error.js";
import { getCloudflareContext } from "./cloudflare-context.js";
/**
* An instance of the Incremental Cache that uses an R2 bucket (`NEXT_CACHE_R2_BUCKET`) as it's
* underlying data store.
*
* The directory that the cache entries are stored in can be confused with the `NEXT_CACHE_R2_PREFIX`
* environment variable, and defaults to `incremental-cache`.
*
* The cache uses an instance of the Cache API (`incremental-cache`) to store a local version of the
* R2 cache entry to enable fast retrieval, with the cache being updated from R2 in the background.
*/
class R2IncrementalCache implements IncrementalCache {
readonly name = "r2-incremental-cache";
async get<IsFetch extends boolean = false>(
key: string,
isFetch?: IsFetch
): Promise<WithLastModified<CacheValue<IsFetch>> | null> {
const r2 = getCloudflareContext().env.NEXT_CACHE_R2_BUCKET;
if (!r2) throw new IgnorableError("No R2 bucket");
debug(`Get ${key}`);
try {
const r2Object = await r2.get(this.getR2Key(key, isFetch));
if (!r2Object) return null;
return {
value: await r2Object.json(),
lastModified: r2Object.uploaded.getTime(),
};
} catch (e) {
error("Failed to get from cache", e);
return null;
}
}
async set<IsFetch extends boolean = false>(
key: string,
value: CacheValue<IsFetch>,
isFetch?: IsFetch
): Promise<void> {
const r2 = getCloudflareContext().env.NEXT_CACHE_R2_BUCKET;
if (!r2) throw new IgnorableError("No R2 bucket");
debug(`Set ${key}`);
try {
await r2.put(this.getR2Key(key, isFetch), JSON.stringify(value));
} catch (e) {
error("Failed to set to cache", e);
}
}
async delete(key: string): Promise<void> {
const r2 = getCloudflareContext().env.NEXT_CACHE_R2_BUCKET;
if (!r2) throw new IgnorableError("No R2 bucket");
debug(`Delete ${key}`);
try {
await r2.delete(this.getR2Key(key));
} catch (e) {
error("Failed to delete from cache", e);
}
}
protected getR2Key(key: string, isFetch?: boolean): string {
const directory = getCloudflareContext().env.NEXT_CACHE_R2_PREFIX ?? "incremental-cache";
return `${directory}/${process.env.NEXT_BUILD_ID ?? "no-build-id"}/${key}.${isFetch ? "fetch" : "cache"}`;
}
}
export default new R2IncrementalCache();