A lexicon-driven AppView for ATProto.
0

Configure Feed

Select the types of activity you want to include in your feed.

happyview / migrations / postgres / 20260501000000_scripts_by_trigger.sql
2.9 kB 59 lines
1-- Trigger-keyed scripts subsystem. 2-- 3-- Each row's `id` IS the trigger string the dispatcher resolves on: 4-- record.index:<nsid> — wildcard for any record event 5-- record.create:<nsid> — specifically a create event (cascades to wildcard) 6-- record.update:<nsid> — specifically an update event 7-- record.delete:<nsid> — specifically a delete event 8-- xrpc.query:<nsid> — XRPC query handler 9-- xrpc.procedure:<nsid> — XRPC procedure handler 10-- labeler.apply:<nsid> — label arrives whose subject is at://<did>/<nsid>/<rkey> 11-- labeler.apply:_actor — label arrives whose subject is a bare DID 12-- 13-- Cascade rule (record events ONLY): the dispatcher tries 14-- `record.<action>:<nsid>` first, falls back to `record.index:<nsid>` if no 15-- specific row exists. No cascade for XRPC or labeler triggers — those 16-- resolve directly. Operators express per-action surgical control by 17-- creating action-specific rows; the wildcard `record.index:<nsid>` covers 18-- "one body for everything" with branching on `event.action`. 19CREATE TABLE scripts ( 20 id TEXT PRIMARY KEY, 21 body TEXT NOT NULL, 22 description TEXT, 23 script_type TEXT NOT NULL DEFAULT 'lua', 24 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), 25 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() 26); 27 28-- Permanently-failed runs from the firehose-driven runners (record / label 29-- events). XRPC scripts fail-closed and never land here. 30CREATE TABLE dead_letter_scripts ( 31 id BIGSERIAL PRIMARY KEY, 32 script_ref TEXT NOT NULL, -- = the trigger id whose script failed 33 host_kind TEXT NOT NULL, -- 'record' | 'label' 34 host_id TEXT NOT NULL, -- e.g. '<nsid>:<action>' for record, '<labeler-did>' for label 35 payload JSONB NOT NULL, -- event payload for re-run 36 error TEXT NOT NULL, 37 attempts INT NOT NULL DEFAULT 0, 38 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), 39 resolved_at TIMESTAMPTZ 40); 41 42CREATE INDEX idx_dead_letter_scripts_host 43 ON dead_letter_scripts (host_kind, host_id, created_at DESC); 44CREATE INDEX idx_dead_letter_scripts_resolved_at 45 ON dead_letter_scripts (resolved_at); 46 47-- Permissions: management for users who can manage lexicons; read for those who can read. 48-- granted_at lost its DEFAULT in 20260318 (type change to TEXT), so we must supply it. 49INSERT INTO user_permissions (user_id, permission, granted_at) 50SELECT user_id, 'scripts:manage', granted_at 51 FROM user_permissions 52 WHERE permission = 'lexicons:create' 53ON CONFLICT (user_id, permission) DO NOTHING; 54 55INSERT INTO user_permissions (user_id, permission, granted_at) 56SELECT user_id, 'scripts:read', granted_at 57 FROM user_permissions 58 WHERE permission = 'lexicons:read' 59ON CONFLICT (user_id, permission) DO NOTHING;