a tool for shared writing and social publishing
1import { IdResolver } from "@atproto/identity";
2import type { DidCache, CacheResult, DidDocument } from "@atproto/identity";
3import Client from "ioredis";
4// Create Redis client for DID caching
5let redisClient: Client | null = null;
6if (process.env.REDIS_URL) {
7 redisClient = new Client(process.env.REDIS_URL);
8}
9
10// Redis-based DID cache implementation
11class RedisDidCache implements DidCache {
12 private staleTTL: number;
13 private maxTTL: number;
14
15 constructor(
16 private client: Client,
17 staleTTL = 60 * 60, // 1 hour
18 maxTTL = 60 * 60 * 24, // 24 hours
19 ) {
20 this.staleTTL = staleTTL;
21 this.maxTTL = maxTTL;
22 }
23
24 async cacheDid(did: string, doc: DidDocument): Promise<void> {
25 const cacheVal = {
26 doc,
27 updatedAt: Date.now(),
28 };
29 await this.client.setex(
30 `did:${did}`,
31 this.maxTTL,
32 JSON.stringify(cacheVal),
33 );
34 }
35
36 async checkCache(did: string): Promise<CacheResult | null> {
37 const cached = await this.client.get(`did:${did}`);
38 if (!cached) return null;
39
40 const { doc, updatedAt } = JSON.parse(cached);
41 const now = Date.now();
42 const age = now - updatedAt;
43
44 return {
45 did,
46 doc,
47 updatedAt,
48 stale: age > this.staleTTL * 1000,
49 expired: age > this.maxTTL * 1000,
50 };
51 }
52
53 async refreshCache(
54 did: string,
55 getDoc: () => Promise<DidDocument | null>,
56 ): Promise<void> {
57 const doc = await getDoc();
58 if (doc) {
59 await this.cacheDid(did, doc);
60 }
61 }
62
63 async clearEntry(did: string): Promise<void> {
64 await this.client.del(`did:${did}`);
65 }
66
67 async clear(): Promise<void> {
68 const keys = await this.client.keys("did:*");
69 if (keys.length > 0) {
70 await this.client.del(...keys);
71 }
72 }
73}
74
75// Create IdResolver with Redis-based DID cache
76export const idResolver = new IdResolver({
77 didCache: redisClient ? new RedisDidCache(redisClient) : undefined,
78});