Scratch space for learning atproto app development
1import { IdResolver, DidDocument, CacheResult } from '@atproto/identity'
2import type { Database } from '#/db'
3
4const HOUR = 60e3 * 60
5const DAY = HOUR * 24
6
7export function createResolver(db: Database) {
8 const resolver = new IdResolver({
9 didCache: {
10 async cacheDid(did: string, doc: DidDocument): Promise<void> {
11 await db
12 .insertInto('did_cache')
13 .values({
14 did,
15 doc: JSON.stringify(doc),
16 updatedAt: new Date().toISOString(),
17 })
18 .onConflict((oc) =>
19 oc.column('did').doUpdateSet({
20 doc: JSON.stringify(doc),
21 updatedAt: new Date().toISOString(),
22 })
23 )
24 .execute()
25 },
26
27 async checkCache(did: string): Promise<CacheResult | null> {
28 const row = await db
29 .selectFrom('did_cache')
30 .selectAll()
31 .where('did', '=', did)
32 .executeTakeFirst()
33 if (!row) return null
34 const now = Date.now()
35 const updatedAt = +new Date(row.updatedAt)
36 return {
37 did,
38 doc: JSON.parse(row.doc),
39 updatedAt,
40 stale: now > updatedAt + HOUR,
41 expired: now > updatedAt + DAY,
42 }
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 clearEntry(did: string): Promise<void> {
56 await db.deleteFrom('did_cache').where('did', '=', did).execute()
57 },
58
59 async clear(): Promise<void> {
60 await db.deleteFrom('did_cache').execute()
61 },
62 },
63 })
64
65 return {
66 async resolveDidToHandle(did: string): Promise<string> {
67 const didDoc = await resolver.did.resolveAtprotoData(did)
68 const resolvedHandle = await resolver.handle.resolve(didDoc.handle)
69 if (resolvedHandle === did) {
70 return didDoc.handle
71 }
72 return did
73 },
74
75 async resolveDidsToHandles(
76 dids: string[]
77 ): Promise<Record<string, string>> {
78 const didHandleMap: Record<string, string> = {}
79 const resolves = await Promise.all(
80 dids.map((did) => this.resolveDidToHandle(did).catch((_) => did))
81 )
82 for (let i = 0; i < dids.length; i++) {
83 didHandleMap[dids[i]] = resolves[i]
84 }
85 return didHandleMap
86 },
87 }
88}