This repository has no description
1import type { BobbinContext, XrpcRequestInit } from "./client";
2import { jsonGet } from "./_request";
3
4export interface MiniDoc {
5 did: string;
6 handle: string;
7 pds?: string;
8 avatar?: string;
9}
10
11export const resolveMiniDoc = (
12 ctx: BobbinContext,
13 identifier: string,
14 init?: XrpcRequestInit
15): Promise<MiniDoc> =>
16 jsonGet<MiniDoc>(ctx, "com.bad-example.identity.resolveMiniDoc", { identifier }, init);
17
18// did/handle cache with in-flight de-dupe.
19export class IdentityCache {
20 readonly #ctx: BobbinContext;
21 readonly #byDid = new Map<string, MiniDoc>();
22 readonly #byHandle = new Map<string, MiniDoc>();
23 readonly #inflight = new Map<string, Promise<MiniDoc>>();
24
25 constructor(ctx: BobbinContext) {
26 this.#ctx = ctx;
27 }
28
29 prime(doc: MiniDoc): void {
30 this.#byDid.set(doc.did, doc);
31 this.#byHandle.set(doc.handle, doc);
32 }
33
34 didFor(handle: string): string | undefined {
35 return this.#byHandle.get(handle)?.did;
36 }
37
38 handleFor(did: string): string | undefined {
39 return this.#byDid.get(did)?.handle;
40 }
41
42 resolve(identifier: string, init?: XrpcRequestInit): Promise<MiniDoc> {
43 const cached = identifier.startsWith("did:")
44 ? this.#byDid.get(identifier)
45 : this.#byHandle.get(identifier);
46 if (cached) return Promise.resolve(cached);
47
48 const existing = this.#inflight.get(identifier);
49 if (existing) return existing;
50
51 const pending = resolveMiniDoc(this.#ctx, identifier, init)
52 .then((doc) => {
53 this.prime(doc);
54 return doc;
55 })
56 .finally(() => this.#inflight.delete(identifier));
57 this.#inflight.set(identifier, pending);
58 return pending;
59 }
60}