atproto_lexicon/pin
The pinned lexicon cache: resolved schema JSONs on disk plus a
lexicons.lock.json recording per-NSID provenance (who published it,
at what content hash, when, from which source spec).
LocalGlob specs are never pinned here: they already name files on
disk, so there’s nothing this cache adds for them. Only the
network-resolved tier (NsidExact, NsidWildcard, AtUri) goes
through pinning. read is strictly offline; refresh is the only
operation that touches the network, via the same injected Send as
atproto_lexicon/source.
All paths are caller-supplied (a cache directory, a lockfile path): this module hardcodes no location.
Types
pub type LockEntry {
LockEntry(nsid: String, provenance: Provenance)
}
Constructors
-
LockEntry(nsid: String, provenance: Provenance)
pub type PinError {
MissingLexicons(nsids: List(String))
ResolveFailed(spec: String, error: source.ResolveError)
LockDecodeFailed(reason: String)
SchemaDecodeFailed(nsid: String, path: String, reason: String)
FilesystemFailed(path: String, reason: String)
}
Constructors
-
MissingLexicons(nsids: List(String))readfound no pinned schema for these NSIDs; never partial (all missing ones are collected before failing). -
ResolveFailed(spec: String, error: source.ResolveError) -
LockDecodeFailed(reason: String) -
SchemaDecodeFailed(nsid: String, path: String, reason: String) -
FilesystemFailed(path: String, reason: String)
pub type Provenance {
Provenance(
did: String,
cid: String,
fetched_at: String,
source: String,
)
}
Constructors
-
Provenance( did: String, cid: String, fetched_at: String, source: String, )
pub type RefreshSummary {
RefreshSummary(
added: List(String),
updated: List(String),
unchanged: List(String),
removed: List(String),
)
}
Constructors
-
RefreshSummary( added: List(String), updated: List(String), unchanged: List(String), removed: List(String), )
Values
pub fn encode_lock(lock: Lockfile) -> String
pub fn new_lockfile() -> Lockfile
pub fn nsid_to_path(cache_dir: String, nsid: String) -> String
com.atproto.repo.getRecord -> <cache_dir>/com/atproto/repo/getRecord.json,
mirroring the fixture-corpus layout this package’s own tests already use.
pub fn read(
cache_dir: String,
lock_path: String,
specs: List(source.Spec),
) -> Result(
#(List(#(String, ast.LexiconDoc)), Lockfile),
PinError,
)
Load pinned schemas for the given specs, entirely offline. NsidWildcard
specs are satisfied from whatever the lockfile already recorded under
that prefix (offline can’t discover new NSIDs); LocalGlob specs are
skipped, since they aren’t this cache’s concern.
pub fn read_lock(lock_path: String) -> Result(Lockfile, PinError)
A missing lockfile is not an error: it just means nothing is pinned yet,
which read then reports precisely via MissingLexicons.
pub fn refresh(
send: fn(request.Request(BitArray)) -> Result(
response.Response(BitArray),
String,
),
cache_dir: String,
lock_path: String,
specs: List(source.Spec),
network: source.NetworkConfig,
fetched_at: String,
) -> Result(RefreshSummary, PinError)
Resolve every network-tier spec via source.resolve, diff the result
against the current lockfile, write the schema files and lockfile, and
report what changed. fetched_at is caller-supplied (an ISO 8601
timestamp, typically) so this module never reaches for a clock itself.