Lua API

Record API

The Record API is available in procedure, query, and record/label scripts. In procedure scripts the full API is available — writes are proxied to the caller's PDS and indexed locally. In query and record/label scripts it runs in no-auth mode: Record.load, r:save_local(), r:delete_local(), and Record.delete_local() work, but PDS-touching methods (r:save(), r:delete()) raise an error.

Constructor

local r = Record("xyz.statusphere.status", { status = "\ud83d\ude0a", createdAt = now() })

Creates a new record instance for the given collection. The optional second argument sets initial field values. The record's _key_type is automatically set from the lexicon's key definition. Default values from the schema are populated for any missing fields.

Static methods

-- Save multiple records in parallel
Record.save_all({ record1, record2, record3 })

-- Load a record from the local database by AT URI
local r = Record.load("at://did:plc:abc/xyz.statusphere.status/abc123")
-- Returns nil if not found

-- Load multiple records in parallel
local records = Record.load_all({ uri1, uri2 })
-- Returns nil entries for URIs not found

-- Delete a record from the local database only (no PDS call)
local ok = Record.delete_local("at://did:plc:abc/xyz.statusphere.status/abc123")
-- Returns true if deleted, false if not found

Instance methods

-- Save (creates or updates depending on whether _uri is set)
r:save()

-- Delete from PDS and local database
r:delete()

-- Save directly to the local database (no PDS call)
r:save_local()

-- Delete from the local database only (no PDS call)
r:delete_local()

-- Set the repo DID (for no-auth contexts like record/label scripts)
r:set_repo("did:plc:abc")

-- Set the record key type (tid, any, nsid, or literal:*)
r:set_key_type("tid")

-- Set a specific record key
r:set_rkey("my-key")

-- Auto-generate a record key based on _key_type
local key = r:generate_rkey()

set_repo only targets repos you can write to

r:save() acts as the caller. Under DPoP it uses the session belonging to the target DID; under a cookie session it presents the caller's own token. Neither can write to another account's repo, so set_repo() accepts only the caller's own DID, or the delegated account's DID when the script is acting under a delegation. Anything else raises before the write is attempted:

cannot write to repo did:plc:xyz: a Record write acts as the caller
(did:plc:abc), so it can only target the caller's own repo.

To write to an account this instance doesn't act as, an admin links that repo and the script uses linked_repos instead:

local repo = linked_repos.get("did:plc:xyz")
repo:create_record{ collection = "com.example.note", record = { text = "hi" } }

set_repo() remains the right tool for save_local(), which never touches a PDS and needs a DID to build the URI for a brand-new local row.

save_local and network provenance

cid and indexed_at describe the record as it exists on the network, so save_local() never writes them.

On an existing record — the redaction flow this method exists for — both are left exactly as they were. The CID still describes what the PDS holds, since editing the local copy doesn't change the repo's copy, and it's what _cid feeds into strongRefs. indexed_at still records when the firehose delivered it.

On a record that has never existed on a PDS, there is nothing to describe: cid is empty and indexed_at is NULL. A row with indexed_at IS NULL is precisely "written locally, not yet echoed back" — use COALESCE(indexed_at, created_at) when you need a timestamp regardless.

Key type behavior for generate_rkey():

Key typeGenerated rkey
tidSortable timestamp-based ID
anySame as tid
literal:valueThe literal value after the colon
nsidError — use set_rkey() instead

Instance fields

These fields are set automatically and are read-only (writes raise an error):

FieldTypeDescription
_uristring?AT URI — set after save(), cleared after delete()
_cidstring?Content hash — set after save(), cleared after delete()
_key_typestring?Record key type from the lexicon definition
_rkeystring?Record key — set via set_rkey() or generate_rkey()
_collectionstringCollection NSID (always set)
_schematable?Schema definition from the lexicon (used for validation)
_repo_overridestring?DID set by set_repo(), used in no-auth contexts to target a repo

Schema validation

When a record has a schema (loaded from the lexicon):

  • On save: required fields are checked, and missing required fields raise an error
  • On construction: default values from schema properties are auto-populated
  • On save: only fields defined in the schema's properties are sent to the PDS

Save behavior

r:save() auto-detects create vs update:

  • If _uri is nil → calls createRecord on the PDS
  • If _uri is set → calls putRecord on the PDS

After a successful save, _uri and _cid are updated on the record instance.