createCachedRecordResolver
@atiproto/record-resolver
Returns a RecordResolver that wraps createFetchRecordResolver with a SimpleStore cache. Cache key is the full at:// URI. Safe because proof records are content-addressed by their strongRef CID and never change in place.
Signature
function createCachedRecordResolver(options?: CachedRecordResolverOptions,): RecordResolver
| Option | Type | Default | Description |
|---|---|---|---|
| relay | string | "https://bsky.network" | Base URL for getRecord. |
| timeout | number | 3000 | Milliseconds before the fetch is aborted. |
| fetch | typeof fetch | globalThis.fetch | Override the global fetch. |
| cache | SimpleStore<string, RecordMap> | SimpleStoreMemory (24hr TTL) | Cache keyed by full at:// URI. |
Edge (Cloudflare Workers)
Pair with a tiered cache (in-memory L1 + Cache API L2) for cross-request persistence within a colo. Build the cache from the same primitives as @atiproto/edge-resolver-cache:
import { verify } from "@atiproto/atproto-attestation";import { createCachedRecordResolver } from "@atiproto/record-resolver";import { CacheApiStore, TieredStore } from "@atiproto/edge-resolver-cache";import { SimpleStoreMemory } from "@atproto-labs/simple-store-memory";const cache = new TieredStore(new SimpleStoreMemory({ ttl: 86_400_000, ttlAutopurge: true, max: 1000 }),new CacheApiStore({ prefix: "proof:", ttlSeconds: 7 * 86_400 }),);const recordResolver = createCachedRecordResolver({ cache });export default {async fetch(req: Request) {const result = await verify({record,repository,recordResolver,});return Response.json(result);},};
Why caching is safe
Each strongRef pins a specific proof record CID. If the proof's contents change, the strongRef stops resolving: there is no mutation in place. So a cache keyed by URI is safe for an unlimited duration. The 24-hour TTL on the in-memory default exists only to bound memory; for Workers backed by Cache API, much longer TTLs are reasonable.