Exosphere.Lexicon (Exosphere v0.6.0)

Copy Markdown View Source

Registering, type-checking, and publishing lexicons.

This module is the entry point for the lexicon workflow; the pieces live in their own modules:

  • Lexicon.Parser — lexicon JSON → normalized IR
  • Lexicon.Schema — the com.atproto.lexicon.schema record type
  • Lexicon.Validator — runtime validation of values against schemas
  • Lexicon.Registry — runtime NSID → lexicon registry
  • Lexicon.Resolver — fetching published lexicons from a PDS
  • Lexicon.Generator + mix exosphere.gen.lexicons — compile-time typed modules

The workflow

# 1. Define (or fetch) a lexicon document
{:ok, schema} = Exosphere.Lexicon.Schema.new(%{
  "lexicon" => 1,
  "id" => "com.example.post",
  "defs" => %{"main" => %{
    "type" => "record", "key" => "tid",
    "record" => %{"type" => "object",
      "required" => ["text"],
      "properties" => %{"text" => %{"type" => "string", "maxGraphemes" => 100}}}
  }}
})

# 2. Type-check records against it — now, and at runtime
:ok = Exosphere.Lexicon.register(schema)
:ok = Exosphere.Lexicon.validate("com.example.post", %{
  "$type" => "com.example.post", "text" => "hello"
})

# 3. Publish it to a PDS (record key = the NSID)
{:ok, %{uri: uri, cid: cid}} =
  Exosphere.Lexicon.publish(session, pds_url, did, schema)

Publishing and updating

publish/4 writes to com.atproto.lexicon.schema with the lexicon's NSID as the record key, so publishing an updated document for the same NSID overwrites the previous version.

Summary

Functions

Delete a published lexicon record by NSID.

Publish a lexicon to a PDS as a com.atproto.lexicon.schema record.

Register a lexicon (parsed, or a raw JSON document) in the runtime Lexicon.Registry. See Exosphere.Lexicon.Registry.register/1.

Type-check a value against a registered lexicon.

Type-check a value against a schema without registering it.

Functions

delete(session, nsid)

@spec delete(map(), String.t()) :: {:ok, map()} | {:error, term()}

Delete a published lexicon record by NSID.

Like publish/2, delete(session, nsid) reads the PDS URL and DID from the session.

delete(session, pds_url, did, nsid)

@spec delete(map(), String.t(), String.t(), String.t()) ::
  {:ok, map()} | {:error, term()}

publish(session, schema_or_doc)

@spec publish(map(), Exosphere.Lexicon.Schema.t() | map()) ::
  {:ok, %{uri: String.t(), cid: String.t()}} | {:error, term()}

Publish a lexicon to a PDS as a com.atproto.lexicon.schema record.

publish(session, schema) takes the PDS URL and DID from the session (session.pds / session.sub); publish(session, pds_url, did, schema) overrides them explicitly.

The record key is the lexicon's NSID, so the record lands at at://<did>/com.atproto.lexicon.schema/<nsid> and re-publishing an updated document updates it in place.

publish(session, pds_url, did, schema_or_doc)

@spec publish(map(), String.t(), String.t(), Exosphere.Lexicon.Schema.t() | map()) ::
  {:ok, %{uri: String.t(), cid: String.t()}} | {:error, term()}

register(lexicon)

Register a lexicon (parsed, or a raw JSON document) in the runtime Lexicon.Registry. See Exosphere.Lexicon.Registry.register/1.

register_all(lexicons)

Register many lexicons at once. See Exosphere.Lexicon.Registry.register_all/1.

validate(type, value, opts \\ [])

Type-check a value against a registered lexicon.

type is an NSID or NSID with fragment; value is the wire-format map. Options are forwarded to Validator.validate/4 (notably strict: true to reject unknown fields, open-union variants, and refs whose target lexicon is not registered). See Exosphere.Lexicon.Registry.validate/3.

validate_with(schema_or_parsed, value, def_name \\ "main", opts \\ [])

@spec validate_with(
  Exosphere.Lexicon.Schema.t() | Exosphere.Lexicon.Parser.lexicon(),
  term(),
  String.t(),
  [Exosphere.Lexicon.Validator.opt()]
) :: :ok | {:error, [{path :: String.t(), message :: String.t()}]}

Type-check a value against a schema without registering it.

Takes a %Lexicon.Schema{} (or its parsed IR) — for checking a fetched document without touching global registry state. Options are forwarded to Validator.validate/4.