diff --git a/README.md b/README.md index 638213e..a72ee37 100644 --- a/README.md +++ b/README.md @@ -158,86 +158,109 @@ Every message is a JSON object with these fields: | `from` | string | | Sender nick or server name | | `to` | string | | Destination: `#channel` or nick | | `params` | array\ | | Additional IRC-style parameters | -| `body` | array \| object | | Structured body (never a raw string) | -| `meta` | object | | Extensible metadata (signatures, etc.) | -| `id` | string (uuid) | | Server-assigned message ID | +| `body` | array \| object | | Structured body (never a raw string — see below) | +| `id` | string (uuid) | | Server-assigned message UUID | | `ts` | string | | Server-assigned ISO 8601 timestamp | +| `meta` | object | | Extensible metadata (signatures, hashes, etc.) | -**Important:** Message bodies MUST be objects or arrays, never raw strings. -This enables: -- Multiline messages (array of lines) -- Deterministic canonicalization for hashing/signing (RFC 8785 JCS) -- Structured data where needed (e.g. PUBKEY) +**Important:** Message bodies are **structured objects or arrays**, never raw +strings. This is a deliberate departure from IRC wire format that enables: + +- **Multiline messages** — body is a list of lines, no escape sequences +- **Deterministic canonicalization** — for hashing and signing (see below) +- **Structured data** — commands like PUBKEY carry key material as objects + +For text messages, `body` is an array of strings (one per line): + +```json +{"command": "PRIVMSG", "from": "nick", "to": "#channel", "body": ["hello world"]} +{"command": "PRIVMSG", "from": "nick", "to": "#channel", "body": ["line one", "line two"]} +``` + +For numeric replies with text trailing parameters: + +```json +{"command": "001", "to": "nick", "body": ["Welcome to the network, nick"]} +{"command": "353", "to": "nick", "params": ["=", "#channel"], "body": ["@op1 alice bob"]} +``` + +For structured data (keys, etc.), `body` is an object: + +```json +{"command": "PUBKEY", "from": "nick", "body": {"alg": "ed25519", "key": "base64..."}} +``` #### IRC Command Mapping -**Client-to-Server (C2S):** +**Commands (C2S and S2C):** -| Command | Description | -|----------|-------------| -| PRIVMSG | Send message to channel or user | -| NOTICE | Send notice (no auto-reply expected) | -| JOIN | Join a channel (creates it if nonexistent) | -| PART | Leave a channel | -| QUIT | Disconnect from server | -| NICK | Change nickname | -| MODE | Set/query channel or user modes | -| TOPIC | Set/query channel topic | -| KICK | Kick a user from a channel | -| PING | Client keepalive | -| PUBKEY | Announce public signing key | +| Command | RFC | Description | +|-----------|--------------|--------------------------------------| +| `PRIVMSG` | 1459 §4.4.1 | Message to channel or user | +| `NOTICE` | 1459 §4.4.2 | Notice (must not trigger auto-reply) | +| `JOIN` | 1459 §4.2.1 | Join a channel | +| `PART` | 1459 §4.2.2 | Leave a channel | +| `QUIT` | 1459 §4.1.6 | Disconnect from server | +| `NICK` | 1459 §4.1.2 | Change nickname | +| `MODE` | 1459 §4.2.3 | Set/query channel or user modes | +| `TOPIC` | 1459 §4.2.4 | Set/query channel topic | +| `KICK` | 1459 §4.2.8 | Kick user from channel | +| `PING` | 1459 §4.6.2 | Keepalive | +| `PONG` | 1459 §4.6.3 | Keepalive response | +| `PUBKEY` | (extension) | Announce/relay signing public key | -**Server-to-Client (S2C):** - -All C2S commands may be echoed back as S2C (relayed to other users), plus: - -| Command | Description | -|----------|-------------| -| PONG | Server keepalive response | -| PUBKEY | Relayed public key from another user | -| ERROR | Server error message | +All C2S commands may be relayed S2C to other users (e.g. JOIN, PART, PRIVMSG). **Numeric Reply Codes (S2C):** -| Code | Name | Description | -|------|-------------------|-------------| -| 001 | RPL_WELCOME | Welcome after session creation | -| 002 | RPL_YOURHOST | Server host information | -| 322 | RPL_LIST | Channel list entry | -| 353 | RPL_NAMREPLY | Names list for a channel | -| 366 | RPL_ENDOFNAMES | End of names list | -| 372 | RPL_MOTD | Message of the day line | -| 375 | RPL_MOTDSTART | Start of MOTD | -| 376 | RPL_ENDOFMOTD | End of MOTD | -| 401 | ERR_NOSUCHNICK | No such nick or channel | -| 403 | ERR_NOSUCHCHANNEL | No such channel | -| 433 | ERR_NICKNAMEINUSE | Nickname already in use | +| Code | Name | Description | +|------|----------------------|-------------| +| 001 | RPL_WELCOME | Welcome after session creation | +| 002 | RPL_YOURHOST | Server host information | +| 003 | RPL_CREATED | Server creation date | +| 004 | RPL_MYINFO | Server info and modes | +| 322 | RPL_LIST | Channel list entry | +| 323 | RPL_LISTEND | End of channel list | +| 332 | RPL_TOPIC | Channel topic | +| 353 | RPL_NAMREPLY | Channel member list | +| 366 | RPL_ENDOFNAMES | End of NAMES list | +| 372 | RPL_MOTD | MOTD line | +| 375 | RPL_MOTDSTART | Start of MOTD | +| 376 | RPL_ENDOFMOTD | End of MOTD | +| 401 | ERR_NOSUCHNICK | No such nick/channel | +| 403 | ERR_NOSUCHCHANNEL | No such channel | +| 433 | ERR_NICKNAMEINUSE | Nickname already in use | +| 442 | ERR_NOTONCHANNEL | Not on that channel | +| 482 | ERR_CHANOPRIVSNEEDED | Not channel operator | -**Server-to-Server (S2S):** +**Server-to-Server (Federation):** -| Command | Description | -|---------|-------------| -| RELAY | Relay message to linked server | -| LINK | Establish server link | -| UNLINK | Tear down server link | -| SYNC | Synchronize state between servers | -| PING | Server-to-server keepalive | -| PONG | Server-to-server keepalive response | +Federated servers use the same IRC commands. After link establishment, servers +exchange a burst of JOIN, NICK, TOPIC, and MODE commands to sync state. +PING/PONG serve as inter-server keepalives. #### Message Examples ```json -{"command": "PRIVMSG", "from": "alice", "to": "#general", "body": ["hello world"], "meta": {"sig": "base64...", "alg": "ed25519"}} +{"command": "PRIVMSG", "from": "alice", "to": "#general", "body": ["hello world"]} -{"command": "PRIVMSG", "from": "alice", "to": "#general", "body": ["line one", "line two"]} +{"command": "PRIVMSG", "from": "alice", "to": "#general", "body": ["line one", "line two"], "meta": {"sig": "base64...", "alg": "ed25519"}} + +{"command": "PRIVMSG", "from": "alice", "to": "bob", "body": ["hey, DM"]} + +{"command": "JOIN", "from": "bob", "to": "#general"} + +{"command": "PART", "from": "bob", "to": "#general", "body": ["later"]} + +{"command": "NICK", "from": "oldnick", "body": ["newnick"]} {"command": "001", "to": "alice", "body": ["Welcome to the network, alice"]} -{"command": "353", "to": "alice", "params": ["=", "#general"], "body": ["alice", "bob", "@charlie"]} +{"command": "353", "to": "alice", "params": ["=", "#general"], "body": ["@op1 alice bob +voiced1"]} -{"command": "JOIN", "from": "bob", "to": "#general", "body": []} +{"command": "433", "to": "*", "params": ["alice"], "body": ["Nickname is already in use"]} -{"command": "ERROR", "body": ["Closing link: connection timeout"]} +{"command": "PUBKEY", "from": "alice", "body": {"alg": "ed25519", "key": "base64..."}} ``` #### JSON Schemas diff --git a/schema/README.md b/schema/README.md index 529c331..65fc6c3 100644 --- a/schema/README.md +++ b/schema/README.md @@ -11,24 +11,33 @@ to IRC wire format: ``` IRC: :nick PRIVMSG #channel :hello world -JSON: {"command": "PRIVMSG", "from": "nick", "to": "#channel", "body": "hello world"} +JSON: {"command": "PRIVMSG", "from": "nick", "to": "#channel", "body": ["hello world"]} IRC: :server 353 nick = #channel :user1 @op1 +voice1 -JSON: {"command": "353", "to": "nick", "params": ["=", "#channel"], "body": "user1 @op1 +voice1"} +JSON: {"command": "353", "to": "nick", "params": ["=", "#channel"], "body": ["user1 @op1 +voice1"]} + +Multiline: {"command": "PRIVMSG", "to": "#ch", "body": ["line 1", "line 2"]} +Structured: {"command": "PUBKEY", "body": {"alg": "ed25519", "key": "base64..."}} ``` Common fields (see `message.json` for full schema): -| Field | Type | Description | -|-----------|----------|-------------------------------------------------------| -| `id` | integer | Server-assigned ID (monotonically increasing) | -| `command` | string | IRC command or 3-digit numeric code | -| `from` | string | Source nick or server name (IRC prefix) | -| `to` | string | Target: #channel or nick | -| `params` | string[] | Middle parameters (mainly for numerics) | -| `body` | string | Trailing parameter (message text) | -| `ts` | string | ISO 8601 timestamp (server-assigned, not in raw IRC) | -| `meta` | object | Extensible metadata (not in raw IRC) | +| Field | Type | Description | +|-----------|----------------|------------------------------------------------------| +| `id` | string (uuid) | Server-assigned message UUID | +| `command` | string | IRC command or 3-digit numeric code | +| `from` | string | Source nick or server name (IRC prefix) | +| `to` | string | Target: #channel or nick | +| `params` | string[] | Middle parameters (mainly for numerics) | +| `body` | array \| object | Structured body — never a raw string (see below) | +| `ts` | string | ISO 8601 timestamp (server-assigned, not in raw IRC) | +| `meta` | object | Extensible metadata (signatures, hashes, etc.) | + +**Structured bodies:** `body` is always an array of strings (for text) or an +object (for structured data like PUBKEY). Never a raw string. This enables: +- Multiline messages without escape sequences +- Deterministic canonicalization via RFC 8785 JCS for signing +- Structured data where needed ## Commands diff --git a/schema/commands/KICK.json b/schema/commands/KICK.json index 8380f31..25af8a8 100644 --- a/schema/commands/KICK.json +++ b/schema/commands/KICK.json @@ -6,15 +6,8 @@ "$ref": "../message.json", "properties": { "command": { "const": "KICK" }, - "from": { - "type": "string", - "description": "Nick that performed the kick." - }, - "to": { - "type": "string", - "description": "Channel name.", - "pattern": "^#[a-zA-Z0-9_-]+$" - }, + "from": { "type": "string", "description": "Nick that performed the kick." }, + "to": { "type": "string", "description": "Channel name.", "pattern": "^#[a-zA-Z0-9_-]+$" }, "params": { "type": "array", "items": { "type": "string" }, @@ -23,12 +16,14 @@ "maxItems": 1 }, "body": { - "type": "string", - "description": "Optional kick reason." + "type": "array", + "items": { "type": "string" }, + "description": "Optional kick reason.", + "maxItems": 1 } }, "required": ["command", "to", "params"], "examples": [ - { "command": "KICK", "from": "op1", "to": "#general", "params": ["troll"], "body": "Behave" } + { "command": "KICK", "from": "op1", "to": "#general", "params": ["troll"], "body": ["Behave"] } ] } diff --git a/schema/commands/NICK.json b/schema/commands/NICK.json index 49cf83f..e6e9bef 100644 --- a/schema/commands/NICK.json +++ b/schema/commands/NICK.json @@ -7,10 +7,16 @@ "properties": { "command": { "const": "NICK" }, "from": { "type": "string", "description": "Old nick (S2C)." }, - "body": { "type": "string", "description": "New nick.", "minLength": 1, "maxLength": 32, "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$" } + "body": { + "type": "array", + "items": { "type": "string" }, + "description": "New nick (single-element array).", + "minItems": 1, + "maxItems": 1 + } }, "required": ["command", "body"], "examples": [ - { "command": "NICK", "from": "oldnick", "body": "newnick" } + { "command": "NICK", "from": "oldnick", "body": ["newnick"] } ] } diff --git a/schema/commands/NOTICE.json b/schema/commands/NOTICE.json index 1ee166d..092e825 100644 --- a/schema/commands/NOTICE.json +++ b/schema/commands/NOTICE.json @@ -8,10 +8,14 @@ "command": { "const": "NOTICE" }, "from": { "type": "string" }, "to": { "type": "string", "description": "Target: #channel, nick, or * (global)." }, - "body": { "type": "string", "description": "Notice text." } + "body": { + "type": "array", + "items": { "type": "string" }, + "description": "Notice text lines." + } }, "required": ["command", "to", "body"], "examples": [ - { "command": "NOTICE", "from": "server.example.com", "to": "*", "body": "Server restarting in 5 minutes" } + { "command": "NOTICE", "from": "server.example.com", "to": "*", "body": ["Server restarting in 5 minutes"] } ] } diff --git a/schema/commands/PART.json b/schema/commands/PART.json index d82eb94..a2bd9ca 100644 --- a/schema/commands/PART.json +++ b/schema/commands/PART.json @@ -8,10 +8,15 @@ "command": { "const": "PART" }, "from": { "type": "string", "description": "Nick that left (S2C)." }, "to": { "type": "string", "description": "Channel name.", "pattern": "^#[a-zA-Z0-9_-]+$" }, - "body": { "type": "string", "description": "Optional part reason." } + "body": { + "type": "array", + "items": { "type": "string" }, + "description": "Optional part reason.", + "maxItems": 1 + } }, "required": ["command", "to"], "examples": [ - { "command": "PART", "from": "alice", "to": "#general", "body": "later" } + { "command": "PART", "from": "alice", "to": "#general", "body": ["later"] } ] } diff --git a/schema/commands/PING.json b/schema/commands/PING.json index 4bb4493..b911dc8 100644 --- a/schema/commands/PING.json +++ b/schema/commands/PING.json @@ -7,12 +7,14 @@ "properties": { "command": { "const": "PING" }, "body": { - "type": "string", - "description": "Opaque token to be echoed in PONG." + "type": "array", + "items": { "type": "string" }, + "description": "Opaque token to be echoed in PONG (single-element array).", + "maxItems": 1 } }, "required": ["command"], "examples": [ - { "command": "PING", "body": "1707580000" } + { "command": "PING", "body": ["1707580000"] } ] } diff --git a/schema/commands/PONG.json b/schema/commands/PONG.json index 400fc0c..6e04620 100644 --- a/schema/commands/PONG.json +++ b/schema/commands/PONG.json @@ -6,17 +6,16 @@ "$ref": "../message.json", "properties": { "command": { "const": "PONG" }, - "from": { - "type": "string", - "description": "Responding server name." - }, + "from": { "type": "string", "description": "Responding server name." }, "body": { - "type": "string", - "description": "Echoed token from PING." + "type": "array", + "items": { "type": "string" }, + "description": "Echoed token from PING (single-element array).", + "maxItems": 1 } }, "required": ["command"], "examples": [ - { "command": "PONG", "from": "server.example.com", "body": "1707580000" } + { "command": "PONG", "from": "server.example.com", "body": ["1707580000"] } ] } diff --git a/schema/commands/PRIVMSG.json b/schema/commands/PRIVMSG.json index 877e004..9204705 100644 --- a/schema/commands/PRIVMSG.json +++ b/schema/commands/PRIVMSG.json @@ -8,11 +8,17 @@ "command": { "const": "PRIVMSG" }, "from": { "type": "string", "description": "Sender nick (set by server on relay)." }, "to": { "type": "string", "description": "Target: #channel or nick.", "examples": ["#general", "alice"] }, - "body": { "type": "string", "description": "Message text.", "minLength": 1 } + "body": { + "type": "array", + "items": { "type": "string" }, + "description": "Message lines. One string per line.", + "minItems": 1 + } }, "required": ["command", "to", "body"], "examples": [ - { "command": "PRIVMSG", "from": "bob", "to": "#general", "body": "hello world" }, - { "command": "PRIVMSG", "from": "bob", "to": "alice", "body": "hey" } + { "command": "PRIVMSG", "from": "bob", "to": "#general", "body": ["hello world"] }, + { "command": "PRIVMSG", "from": "bob", "to": "#general", "body": ["line one", "line two"] }, + { "command": "PRIVMSG", "from": "bob", "to": "alice", "body": ["hey"], "meta": { "sig": "base64...", "alg": "ed25519" } } ] } diff --git a/schema/commands/QUIT.json b/schema/commands/QUIT.json index 9b66f20..cfb3a45 100644 --- a/schema/commands/QUIT.json +++ b/schema/commands/QUIT.json @@ -7,10 +7,15 @@ "properties": { "command": { "const": "QUIT" }, "from": { "type": "string", "description": "Nick that quit." }, - "body": { "type": "string", "description": "Optional quit reason." } + "body": { + "type": "array", + "items": { "type": "string" }, + "description": "Optional quit reason.", + "maxItems": 1 + } }, "required": ["command", "from"], "examples": [ - { "command": "QUIT", "from": "alice", "body": "Connection reset" } + { "command": "QUIT", "from": "alice", "body": ["Connection reset"] } ] } diff --git a/schema/commands/TOPIC.json b/schema/commands/TOPIC.json index 6ab998c..8ba1365 100644 --- a/schema/commands/TOPIC.json +++ b/schema/commands/TOPIC.json @@ -8,10 +8,15 @@ "command": { "const": "TOPIC" }, "from": { "type": "string", "description": "Nick that changed the topic (S2C)." }, "to": { "type": "string", "description": "Channel name.", "pattern": "^#[a-zA-Z0-9_-]+$" }, - "body": { "type": "string", "description": "New topic text. Empty string clears the topic.", "maxLength": 512 } + "body": { + "type": "array", + "items": { "type": "string" }, + "description": "New topic text (single-element array). Empty array clears the topic.", + "maxItems": 1 + } }, "required": ["command", "to"], "examples": [ - { "command": "TOPIC", "from": "alice", "to": "#general", "body": "Welcome to the chat" } + { "command": "TOPIC", "from": "alice", "to": "#general", "body": ["Welcome to the chat"] } ] } diff --git a/schema/message.json b/schema/message.json index 286d0ea..875a492 100644 --- a/schema/message.json +++ b/schema/message.json @@ -6,8 +6,9 @@ "type": "object", "properties": { "id": { - "type": "integer", - "description": "Server-assigned message ID, monotonically increasing. Present on all server-originated messages." + "type": "string", + "format": "uuid", + "description": "Server-assigned message UUID. Present on all server-originated messages." }, "command": { "type": "string", @@ -28,8 +29,19 @@ "description": "Additional parameters (used primarily by numeric replies). Equivalent to IRC middle parameters." }, "body": { - "type": "string", - "description": "Message body / trailing parameter. Equivalent to IRC trailing parameter (after the colon)." + "oneOf": [ + { + "type": "array", + "items": { "type": "string" }, + "description": "Array of strings (one per line for text messages)." + }, + { + "type": "object", + "description": "Structured data (e.g. PUBKEY key material).", + "additionalProperties": true + } + ], + "description": "Message body. MUST be an array or object, never a raw string. Arrays represent lines of text; objects carry structured data. This enables deterministic canonicalization (RFC 8785 JCS) for signing." }, "ts": { "type": "string", @@ -38,7 +50,21 @@ }, "meta": { "type": "object", - "description": "Extensible metadata (signatures, rich content hints, etc.). Not present in original IRC.", + "description": "Extensible metadata. Used for signatures (meta.sig, meta.alg), hashes (meta.hash), and client extensions.", + "properties": { + "sig": { + "type": "string", + "description": "Base64-encoded cryptographic signature over the canonical message form." + }, + "alg": { + "type": "string", + "description": "Signature algorithm (e.g. 'ed25519')." + }, + "hash": { + "type": "string", + "description": "Hash of the canonical message form (e.g. 'sha256:base64...')." + } + }, "additionalProperties": true } }, diff --git a/schema/numerics/001.json b/schema/numerics/001.json index 499d686..feb2ba0 100644 --- a/schema/numerics/001.json +++ b/schema/numerics/001.json @@ -2,19 +2,36 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/001.json", "title": "001 RPL_WELCOME", - "description": "Welcome message sent after successful session creation. RFC 2812 §5.1.", + "description": "Welcome message sent after successful session creation. RFC 2812 \u00a75.1.", "$ref": "../message.json", "properties": { - "command": { "const": "001" }, - "to": { "type": "string", "description": "Target nick." }, + "command": { + "const": "001" + }, + "to": { + "type": "string", + "description": "Target nick." + }, "body": { "type": "array", - "items": { "type": "string" }, + "items": { + "type": "string" + }, "description": "Welcome text lines." } }, - "required": ["command", "to", "body"], + "required": [ + "command", + "to", + "body" + ], "examples": [ - { "command": "001", "to": "alice", "body": ["Welcome to the network, alice"] } + { + "command": "001", + "to": "alice", + "body": [ + "Welcome to the network, alice" + ] + } ] } diff --git a/schema/numerics/002.json b/schema/numerics/002.json index 22166a9..13fc73c 100644 --- a/schema/numerics/002.json +++ b/schema/numerics/002.json @@ -2,19 +2,35 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/002.json", "title": "002 RPL_YOURHOST", - "description": "Server host info sent after session creation. RFC 2812 §5.1.", + "description": "Server host info sent after session creation. RFC 2812 \u00a75.1.", "$ref": "../message.json", "properties": { - "command": { "const": "002" }, - "to": { "type": "string" }, + "command": { + "const": "002" + }, + "to": { + "type": "string" + }, "body": { "type": "array", - "items": { "type": "string" }, + "items": { + "type": "string" + }, "description": "Host info lines." } }, - "required": ["command", "to", "body"], + "required": [ + "command", + "to", + "body" + ], "examples": [ - { "command": "002", "to": "alice", "body": ["Your host is chat.example.com, running version 0.1.0"] } + { + "command": "002", + "to": "alice", + "body": [ + "Your host is chat.example.com, running version 0.1.0" + ] + } ] } diff --git a/schema/numerics/323.json b/schema/numerics/323.json index 92734b8..310a061 100644 --- a/schema/numerics/323.json +++ b/schema/numerics/323.json @@ -2,12 +2,26 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/323.json", "title": "323 RPL_LISTEND", - "description": "End of channel list. RFC 1459 §6.2.", + "description": "End of channel list. RFC 1459 \u00a76.2.", "$ref": "../message.json", "properties": { - "command": { "const": "323" }, - "to": { "type": "string" }, - "body": { "const": "End of /LIST" } + "command": { + "const": "323" + }, + "to": { + "type": "string" + }, + "body": { + "type": "array", + "items": { + "type": "string" + }, + "description": "End of /LIST", + "maxItems": 1 + } }, - "required": ["command", "to"] + "required": [ + "command", + "to" + ] } diff --git a/schema/numerics/366.json b/schema/numerics/366.json index a4309c7..2b5d17a 100644 --- a/schema/numerics/366.json +++ b/schema/numerics/366.json @@ -2,17 +2,34 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/366.json", "title": "366 RPL_ENDOFNAMES", - "description": "End of NAMES list. RFC 1459 §6.2.", + "description": "End of NAMES list. RFC 1459 \u00a76.2.", "$ref": "../message.json", "properties": { - "command": { "const": "366" }, - "to": { "type": "string" }, + "command": { + "const": "366" + }, + "to": { + "type": "string" + }, "params": { "type": "array", - "items": { "type": "string" }, + "items": { + "type": "string" + }, "description": "[channel]." }, - "body": { "const": "End of /NAMES list" } + "body": { + "type": "array", + "items": { + "type": "string" + }, + "description": "End of /NAMES list", + "maxItems": 1 + } }, - "required": ["command", "to", "params"] + "required": [ + "command", + "to", + "params" + ] } diff --git a/schema/numerics/376.json b/schema/numerics/376.json index 7a2ca35..5082517 100644 --- a/schema/numerics/376.json +++ b/schema/numerics/376.json @@ -2,12 +2,26 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/376.json", "title": "376 RPL_ENDOFMOTD", - "description": "End of MOTD. RFC 2812 §5.1.", + "description": "End of MOTD. RFC 2812 \u00a75.1.", "$ref": "../message.json", "properties": { - "command": { "const": "376" }, - "to": { "type": "string" }, - "body": { "const": "End of /MOTD command" } + "command": { + "const": "376" + }, + "to": { + "type": "string" + }, + "body": { + "type": "array", + "items": { + "type": "string" + }, + "description": "End of /MOTD command", + "maxItems": 1 + } }, - "required": ["command", "to"] + "required": [ + "command", + "to" + ] } diff --git a/schema/numerics/401.json b/schema/numerics/401.json index be77370..3213156 100644 --- a/schema/numerics/401.json +++ b/schema/numerics/401.json @@ -2,20 +2,46 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/401.json", "title": "401 ERR_NOSUCHNICK", - "description": "No such nick/channel. RFC 1459 §6.1.", + "description": "No such nick/channel. RFC 1459 \u00a76.1.", "$ref": "../message.json", "properties": { - "command": { "const": "401" }, - "to": { "type": "string" }, + "command": { + "const": "401" + }, + "to": { + "type": "string" + }, "params": { "type": "array", - "items": { "type": "string" }, + "items": { + "type": "string" + }, "description": "[target_nick]." }, - "body": { "const": "No such nick/channel" } + "body": { + "type": "array", + "items": { + "type": "string" + }, + "description": "No such nick/channel", + "maxItems": 1 + } }, - "required": ["command", "to", "params"], + "required": [ + "command", + "to", + "params" + ], "examples": [ - { "command": "401", "to": "alice", "params": ["bob"], "body": "No such nick/channel" } + { + "command": "401", + "to": "alice", + "params": [ + "bob" + ], + "body": [ + "No such nick/channel" + ] + } ] } diff --git a/schema/numerics/403.json b/schema/numerics/403.json index f3bd5c2..bf06774 100644 --- a/schema/numerics/403.json +++ b/schema/numerics/403.json @@ -2,20 +2,46 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/403.json", "title": "403 ERR_NOSUCHCHANNEL", - "description": "No such channel. RFC 1459 §6.1.", + "description": "No such channel. RFC 1459 \u00a76.1.", "$ref": "../message.json", "properties": { - "command": { "const": "403" }, - "to": { "type": "string" }, + "command": { + "const": "403" + }, + "to": { + "type": "string" + }, "params": { "type": "array", - "items": { "type": "string" }, + "items": { + "type": "string" + }, "description": "[channel_name]." }, - "body": { "const": "No such channel" } + "body": { + "type": "array", + "items": { + "type": "string" + }, + "description": "No such channel", + "maxItems": 1 + } }, - "required": ["command", "to", "params"], + "required": [ + "command", + "to", + "params" + ], "examples": [ - { "command": "403", "to": "alice", "params": ["#nonexistent"], "body": "No such channel" } + { + "command": "403", + "to": "alice", + "params": [ + "#nonexistent" + ], + "body": [ + "No such channel" + ] + } ] } diff --git a/schema/numerics/433.json b/schema/numerics/433.json index 6d910af..1f4930e 100644 --- a/schema/numerics/433.json +++ b/schema/numerics/433.json @@ -2,20 +2,46 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/433.json", "title": "433 ERR_NICKNAMEINUSE", - "description": "Nickname is already in use. RFC 1459 §6.1.", + "description": "Nickname is already in use. RFC 1459 \u00a76.1.", "$ref": "../message.json", "properties": { - "command": { "const": "433" }, - "to": { "type": "string" }, + "command": { + "const": "433" + }, + "to": { + "type": "string" + }, "params": { "type": "array", - "items": { "type": "string" }, + "items": { + "type": "string" + }, "description": "[requested_nick]." }, - "body": { "const": "Nickname is already in use" } + "body": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Nickname is already in use", + "maxItems": 1 + } }, - "required": ["command", "to", "params"], + "required": [ + "command", + "to", + "params" + ], "examples": [ - { "command": "433", "to": "*", "params": ["alice"], "body": "Nickname is already in use" } + { + "command": "433", + "to": "*", + "params": [ + "alice" + ], + "body": [ + "Nickname is already in use" + ] + } ] } diff --git a/schema/numerics/442.json b/schema/numerics/442.json index 9fe8db0..a36518b 100644 --- a/schema/numerics/442.json +++ b/schema/numerics/442.json @@ -2,17 +2,34 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/442.json", "title": "442 ERR_NOTONCHANNEL", - "description": "You're not on that channel. RFC 1459 §6.1.", + "description": "You're not on that channel. RFC 1459 \u00a76.1.", "$ref": "../message.json", "properties": { - "command": { "const": "442" }, - "to": { "type": "string" }, + "command": { + "const": "442" + }, + "to": { + "type": "string" + }, "params": { "type": "array", - "items": { "type": "string" }, + "items": { + "type": "string" + }, "description": "[channel]." }, - "body": { "const": "You're not on that channel" } + "body": { + "type": "array", + "items": { + "type": "string" + }, + "description": "You're not on that channel", + "maxItems": 1 + } }, - "required": ["command", "to", "params"] + "required": [ + "command", + "to", + "params" + ] } diff --git a/schema/numerics/482.json b/schema/numerics/482.json index 1f0ad75..fb03924 100644 --- a/schema/numerics/482.json +++ b/schema/numerics/482.json @@ -2,17 +2,34 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://git.eeqj.de/sneak/chat/schema/numerics/482.json", "title": "482 ERR_CHANOPRIVSNEEDED", - "description": "You're not channel operator. RFC 1459 §6.1.", + "description": "You're not channel operator. RFC 1459 \u00a76.1.", "$ref": "../message.json", "properties": { - "command": { "const": "482" }, - "to": { "type": "string" }, + "command": { + "const": "482" + }, + "to": { + "type": "string" + }, "params": { "type": "array", - "items": { "type": "string" }, + "items": { + "type": "string" + }, "description": "[channel]." }, - "body": { "const": "You're not channel operator" } + "body": { + "type": "array", + "items": { + "type": "string" + }, + "description": "You're not channel operator", + "maxItems": 1 + } }, - "required": ["command", "to", "params"] + "required": [ + "command", + "to", + "params" + ] }