Libraries
A library is a plugin a script loads with require. Each has a namespace under happyview., declares the capabilities it needs, and documents its own surface in its README. HappyView ships none of them: every library is installed from the plugins repository through Integrations > Plugins or the admin API, and a script that requires one that is not installed fails to load.
require | Capabilities | Purpose | Surface |
|---|---|---|---|
happyview.db | records:read | Read indexed records: a chainable query per collection, one record by URI, substring search, and the backend name | README |
happyview.sql | database:read, database:write | Raw SQL, and a chainable builder over the operator’s own tables | README |
happyview.backlinks | records:read | Records whose strong refs point at a given AT URI | README |
happyview.record | caller:write, records:read, records:write | Record writes as the calling user, blob uploads, direct local-index writes, and lexicon validation | README |
happyview.xrpc | caller:read, caller:call | XRPC queries and procedures as the calling user | README |
happyview.atproto | atproto:read, attest:sign | Service resolution, blob download, label lookup, and attestation signing and verification | README |
happyview.spaces | spaces:read, spaces:write | Permissioned spaces: records, membership and invites | README |
happyview.linked_repos | linked_repos:use | Record writes, blob uploads and XRPC calls through repos an admin has linked | README |
happyview.jobs | jobs:create, jobs:read, jobs:read_any | Enqueue background jobs, and read them back (reading needs happyview-jobs 1.1.0 or later) | README |
happyview.http | network:request:unrestricted | Outbound HTTP: get, post, put, patch, delete, head | README |
happyview.blobs | blobs:read, blobs:write | Store and read byte content, addressed by the CID of its contents | README |
happyview.account | caller:email | The calling user’s email address, as their PDS reports it | README |
The capability column is what an operator grants when installing the library, and it bounds what any script can do through it: happyview.sql with database:write can run any statement, happyview.xrpc with caller:call can invoke any procedure as the user. Install only what your scripts use.
Conventions every library follows
Section titled “Conventions every library follows”Envelopes. Every read of an indexed record answers an envelope rather than the bare body:
{ uri, did, collection, rkey, cid, indexed_at, record }record is the stored body verbatim. cid is nil for a row written only with save_local, and indexed_at is nil until the network has echoed the record; a write through happyview.record is in the index at once, with the PDS’s cid. A page is { records, cursor }, where cursor is an opaque string present only when more records exist.
Chains. A constructor such as db.records(collection) or backlinks.to(uri) returns an object whose lazy steps (where, sort, limit, cursor, did, collection) each return the same object, so they chain, and whose immediate calls (run, count, first) make the library call. A lazy step given nil is skipped, so :limit(input.limit) reads as no limit when the input has none. An object holds nothing between calls, so a library cannot keep a transaction open, and a script cannot hand a library a function.
Acting as the caller. A library acts as ctx.caller_did, and a call that needs the caller’s PDS session succeeds only when ctx.has_pds_auth is true. happyview.linked_repos is the exception: it acts as the linked repo, from any script kind, and the grant’s scopes bound it instead.
Errors. A library failure raises a Lua error prefixed with the library and function, happyview-db.get: …, carrying the error code the README lists (BAD_INPUT, NO_SESSION, PDS_ERROR, …). Catch one with pcall when the failure is expected.
Protected tables. happyview.sql runs against the same database as the index, so raw and from are refused on HappyView’s internal happyview_* tables other than the public AppView data. The allowlist is in Developing Plugins. To read one collection quickly, use the view described in Reading one collection.
Record views on a raw read route. When an instance’s record storage offers a raw read route, raw reads of happyview_records and happyview_record_refs, and from on either view, run on that route in its own SQL dialect, which db.backend() doesn’t report. A query that reads those views together with other tables is refused, and a routed read fails with STORAGE_UNAVAILABLE while the storage is down. Raw SQL on the record views has the details.
Next steps
Section titled “Next steps”- Script Contract:
handle(input, ctx)and therequireorder - Built-in Modules: the
internal.*modules the runtime provides itself - Developing Plugins: how a library is built and how
requirerenders its surface

