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

pub type Lockfile {
  Lockfile(version: Int, entries: List(LockEntry))
}

Constructors

  • Lockfile(version: Int, entries: List(LockEntry))
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))

    read found 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 decode_lock(text: String) -> Result(Lockfile, PinError)
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.

Search Document