import type { BobbinContext, XrpcRequestInit } from "./client"; import { jsonGet } from "./_request"; export interface MiniDoc { did: string; handle: string; pds?: string; avatar?: string; } export const resolveMiniDoc = ( ctx: BobbinContext, identifier: string, init?: XrpcRequestInit ): Promise => jsonGet(ctx, "com.bad-example.identity.resolveMiniDoc", { identifier }, init); // did/handle cache with in-flight de-dupe. export class IdentityCache { readonly #ctx: BobbinContext; readonly #byDid = new Map(); readonly #byHandle = new Map(); readonly #inflight = new Map>(); constructor(ctx: BobbinContext) { this.#ctx = ctx; } prime(doc: MiniDoc): void { this.#byDid.set(doc.did, doc); this.#byHandle.set(doc.handle, doc); } didFor(handle: string): string | undefined { return this.#byHandle.get(handle)?.did; } handleFor(did: string): string | undefined { return this.#byDid.get(did)?.handle; } resolve(identifier: string, init?: XrpcRequestInit): Promise { const cached = identifier.startsWith("did:") ? this.#byDid.get(identifier) : this.#byHandle.get(identifier); if (cached) return Promise.resolve(cached); const existing = this.#inflight.get(identifier); if (existing) return existing; const pending = resolveMiniDoc(this.#ctx, identifier, init) .then((doc) => { this.prime(doc); return doc; }) .finally(() => this.#inflight.delete(identifier)); this.#inflight.set(identifier, pending); return pending; } }