Skip to content
You are reading the HappyView v2 docs, which are no longer updated. Read the v3 docs.

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.

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.

-- 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
-- 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

Section titled “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.

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

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

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

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.