Scratch space for learning atproto app development

Properly resolve identities in staging

+5 -14
src/context.ts
···
import { pino } from 'pino'
import { createOAuthClient } from '#/auth/client'
-
import { Database } from '#/db'
-
import { createDb } from '#/db'
-
import {
-
BidirectionalResolver,
-
createBidirectionalResolver,
-
createIdResolver,
-
} from '#/id-resolver'
+
import { createDb, Database } from '#/db'
import { createIngester } from '#/ingester'
/**
···
ingester: Firehose
logger: pino.Logger
oauthClient: NodeOAuthClient
-
resolver: BidirectionalResolver
+
identityResolver: NodeOAuthClient['identityResolver']
}
export async function createAppContext(): Promise<AppContext> {
-
const logger = pino({ name: 'server start' })
-
const db = await createDb()
const oauthClient = await createOAuthClient(db)
-
const baseIdResolver = createIdResolver()
-
const ingester = createIngester(db, baseIdResolver)
-
const resolver = createBidirectionalResolver(baseIdResolver)
+
const ingester = createIngester(db)
+
const logger = pino({ name: 'server' })
return {
db,
ingester,
logger,
oauthClient,
-
resolver,
+
identityResolver: oauthClient.identityResolver,
}
}
-41
src/id-resolver.ts
···
-
import { IdResolver, MemoryCache } from '@atproto/identity'
-
-
const HOUR = 60e3 * 60
-
const DAY = HOUR * 24
-
-
export function createIdResolver() {
-
return new IdResolver({
-
didCache: new MemoryCache(HOUR, DAY),
-
})
-
}
-
-
export interface BidirectionalResolver {
-
resolveDidToHandle(did: string): Promise<string>
-
resolveDidsToHandles(dids: string[]): Promise<Record<string, string>>
-
}
-
-
export function createBidirectionalResolver(resolver: IdResolver) {
-
return {
-
async resolveDidToHandle(did: string): Promise<string> {
-
const didDoc = await resolver.did.resolveAtprotoData(did)
-
const resolvedHandle = await resolver.handle.resolve(didDoc.handle)
-
if (resolvedHandle === did) {
-
return didDoc.handle
-
}
-
return did
-
},
-
-
async resolveDidsToHandles(
-
dids: string[]
-
): Promise<Record<string, string>> {
-
const didHandleMap: Record<string, string> = {}
-
const resolves = await Promise.all(
-
dids.map((did) => this.resolveDidToHandle(did).catch((_) => did))
-
)
-
for (let i = 0; i < dids.length; i++) {
-
didHandleMap[dids[i]] = resolves[i]
-
}
-
return didHandleMap
-
},
-
}
-
}
+11 -6
src/ingester.ts
···
-
import pino from 'pino'
-
import { IdResolver } from '@atproto/identity'
-
import { Event, Firehose } from '@atproto/sync'
import type { Database } from '#/db'
import * as Status from '#/lexicon/types/xyz/statusphere/status'
+
import { IdResolver, MemoryCache } from '@atproto/identity'
+
import { Event, Firehose } from '@atproto/sync'
+
import pino from 'pino'
-
export function createIngester(db: Database, idResolver: IdResolver) {
+
const HOUR = 60e3 * 60
+
const DAY = HOUR * 24
+
+
export function createIngester(db: Database) {
const logger = pino({ name: 'firehose ingestion' })
return new Firehose({
-
idResolver,
+
idResolver: new IdResolver({
+
didCache: new MemoryCache(HOUR, DAY),
+
}),
handleEvent: async (evt: Event) => {
// Watch for write events
if (evt.event === 'create' || evt.event === 'update') {
···
oc.column('uri').doUpdateSet({
status: record.status,
indexedAt: now.toISOString(),
-
})
+
}),
)
.execute()
}
+14 -4
src/routes.ts
···
.executeTakeFirst()
: undefined
-
// Map user DIDs to their domain-name handles
-
const didHandleMap = await ctx.resolver.resolveDidsToHandles(
-
statuses.map((s) => s.authorDid),
-
)
+
// Map (unique) user DIDs to their domain-name handles
+
const uniqueDids = [...new Set(statuses.map((s) => s.authorDid))]
+
+
const didHandleMap: Record<string, string | undefined> =
+
Object.fromEntries(
+
await Promise.all(
+
uniqueDids.map((did) =>
+
ctx.identityResolver.resolve(did).then(
+
(r) => [did, r.handle],
+
() => [did, undefined],
+
),
+
),
+
),
+
)
if (!agent) {
// Serve the logged-out view