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 foundInstance 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 type | Generated rkey |
|---|---|
tid | Sortable timestamp-based ID |
any | Same as tid |
literal:value | The literal value after the colon |
nsid | Error — use set_rkey() instead |
Instance fields
These fields are set automatically and are read-only (writes raise an error):
| Field | Type | Description |
|---|---|---|
_uri | string? | AT URI — set after save(), cleared after delete() |
_cid | string? | Content hash — set after save(), cleared after delete() |
_key_type | string? | Record key type from the lexicon definition |
_rkey | string? | Record key — set via set_rkey() or generate_rkey() |
_collection | string | Collection NSID (always set) |
_schema | table? | Schema definition from the lexicon (used for validation) |
_repo_override | string? | 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
propertiesare sent to the PDS
Save behavior
r:save() auto-detects create vs update:
- If
_uriis nil → callscreateRecordon the PDS - If
_uriis set → callsputRecordon the PDS
After a successful save, _uri and _cid are updated on the record instance.