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});