forked from
rocksky.app/rocksky
A decentralized music tracking and discovery platform built on AT Protocol 馃幍
1import {
2 type CacheResult,
3 type DidCache,
4 type DidDocument,
5} from "@atproto/identity";
6import type { Storage } from "unstorage";
7
8const HOUR = 60e3 * 60;
9const DAY = HOUR * 24;
10
11type CacheVal = {
12 doc: DidDocument;
13 updatedAt: number;
14};
15
16/**
17 * An unstorage based DidCache with staleness and max TTL
18 */
19export class StorageCache implements DidCache {
20 public staleTTL: number;
21 public maxTTL: number;
22 public cache: Storage<CacheVal>;
23 private prefix: string;
24 constructor({
25 store,
26 prefix,
27 staleTTL,
28 maxTTL,
29 }: {
30 store: Storage;
31 prefix: string;
32 staleTTL?: number;
33 maxTTL?: number;
34 }) {
35 this.cache = store as Storage<CacheVal>;
36 this.prefix = prefix;
37 this.staleTTL = staleTTL ?? HOUR;
38 this.maxTTL = maxTTL ?? DAY;
39 }
40
41 async cacheDid(did: string, doc: DidDocument): Promise<void> {
42 await this.cache.set(this.prefix + did, { doc, updatedAt: Date.now() });
43 }
44
45 async refreshCache(
46 did: string,
47 getDoc: () => Promise<DidDocument | null>
48 ): Promise<void> {
49 const doc = await getDoc();
50 if (doc) {
51 await this.cacheDid(did, doc);
52 }
53 }
54
55 async checkCache(did: string): Promise<CacheResult | null> {
56 const val = await this.cache.get<CacheVal>(this.prefix + did);
57 if (!val) return null;
58 const now = Date.now();
59 const expired = now > val.updatedAt + this.maxTTL;
60 const stale = now > val.updatedAt + this.staleTTL;
61 return {
62 ...val,
63 did,
64 stale,
65 expired,
66 };
67 }
68
69 async clearEntry(did: string): Promise<void> {
70 await this.cache.remove(this.prefix + did);
71 }
72
73 async clear(): Promise<void> {
74 await this.cache.clear(this.prefix);
75 }
76}