Utility Globals
Global functions available in queries, procedures, and index hooks. These don't belong to a specific API table — they're available at the top level of any Lua script.
now
local timestamp = now()
-- "2026-04-19T15:30:00Z"Returns the current UTC time as an ISO 8601 string. Use this for createdAt, updatedAt, and similar timestamp fields.
log
log("processing record: " .. uri)
log("count: " .. tostring(n))Writes a message to the server logs at debug level. Useful for debugging scripts during development. Log output appears in HappyView's stdout — check your platform's log viewer (Railway logs, docker logs, terminal output) to see it.
TID
local id = TID()
-- "3abc123def456"Generates a fresh atproto TID (Timestamp Identifier) — a 13-character, base32-sortable string derived from the current timestamp. TIDs are the standard record key format in atproto. Use this when creating records with a specific rkey:
local r = Record(collection, { text = "hello" })
r:set_rkey(TID())
r:save()TID.toISO8601
local iso = TID.toISO8601(tid)
-- "2026-04-19T15:30:00.123456Z"Converts a TID to an ISO 8601 timestamp string with microsecond precision. This is lossy — the 10-bit clock ID embedded in the TID is discarded.
TID.fromISO8601
local tid = TID.fromISO8601("2026-04-19T15:30:00Z")Creates a TID from an ISO 8601 timestamp string. Accepts timezone offsets and fractional seconds. The resulting TID uses a zero clock ID, so it won't match any specific generated TID but will sort correctly relative to TIDs from the same moment.
TID.toUnixMicroseconds
local us = TID.toUnixMicroseconds(tid)
-- 1745074200123456Extracts the microsecond timestamp from a TID (microseconds since the Unix epoch). Lossy — drops the clock ID.
TID.fromUnixMicroseconds
local tid = TID.fromUnixMicroseconds(1745074200123456)Creates a TID from a microsecond timestamp. Uses a zero clock ID.
TID.toNumber
local n = TID.toNumber(tid)
local same_tid = TID.fromNumber(n)
-- same_tid == tidDecodes a TID to its full numeric representation (timestamp + clock ID). This is the only lossless conversion — TID.fromNumber(TID.toNumber(tid)) always returns the original TID.
TID.fromNumber
local tid = TID.fromNumber(n)Encodes a number back into a TID. Inverse of TID.toNumber.
toarray
return { items = toarray(results) }Marks a Lua table so it serializes as a JSON array rather than a JSON object. This matters for empty tables — without toarray, an empty {} becomes a JSON object {} instead of an array [].
-- Without toarray:
return { items = {} }
-- → {"items": {}}
-- With toarray:
return { items = toarray({}) }
-- → {"items": []}You don't need toarray() on results from db.query, db.search, db.backlinks, or db.raw — those already return properly marked arrays. Use it when you build a table yourself with table.insert() or array-index assignment.