This commit was merged in pull request #8.
This commit is contained in:
97
schema/README.md
Normal file
97
schema/README.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Message Schemas
|
||||
|
||||
JSON Schema definitions (draft 2020-12) for the chat protocol. Messages use
|
||||
**IRC command names and numeric reply codes** (RFC 1459/2812) encoded as JSON
|
||||
over HTTP.
|
||||
|
||||
## Envelope
|
||||
|
||||
Every message is a JSON object with a `command` field. The format maps directly
|
||||
to IRC wire format:
|
||||
|
||||
```
|
||||
IRC: :nick PRIVMSG #channel :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"]}
|
||||
|
||||
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` | 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
|
||||
|
||||
IRC commands used for client↔server and server↔server communication.
|
||||
|
||||
| Command | File | RFC | Description |
|
||||
|-----------|---------------------------|-----------|--------------------------------|
|
||||
| `PRIVMSG` | `commands/PRIVMSG.json` | 1459 §4.4.1 | Message to channel or user |
|
||||
| `NOTICE` | `commands/NOTICE.json` | 1459 §4.4.2 | Notice (no auto-reply) |
|
||||
| `JOIN` | `commands/JOIN.json` | 1459 §4.2.1 | Join a channel |
|
||||
| `PART` | `commands/PART.json` | 1459 §4.2.2 | Leave a channel |
|
||||
| `QUIT` | `commands/QUIT.json` | 1459 §4.1.6 | User disconnected |
|
||||
| `NICK` | `commands/NICK.json` | 1459 §4.1.2 | Change nickname |
|
||||
| `TOPIC` | `commands/TOPIC.json` | 1459 §4.2.4 | Get/set channel topic |
|
||||
| `MODE` | `commands/MODE.json` | 1459 §4.2.3 | Set channel/user modes |
|
||||
| `KICK` | `commands/KICK.json` | 1459 §4.2.8 | Kick user from channel |
|
||||
| `PING` | `commands/PING.json` | 1459 §4.6.2 | Keepalive |
|
||||
| `PONG` | `commands/PONG.json` | 1459 §4.6.3 | Keepalive response |
|
||||
| `PUBKEY` | `commands/PUBKEY.json` | (extension) | Announce/relay signing key |
|
||||
|
||||
## Numeric Replies
|
||||
|
||||
Three-digit codes for server responses, per IRC convention.
|
||||
|
||||
### Success / Informational (0xx–3xx)
|
||||
|
||||
| Code | Name | File | Description |
|
||||
|-------|-------------------|-----------------------|--------------------------------|
|
||||
| `001` | RPL_WELCOME | `numerics/001.json` | Welcome after session creation |
|
||||
| `002` | RPL_YOURHOST | `numerics/002.json` | Server host info |
|
||||
| `003` | RPL_CREATED | `numerics/003.json` | Server creation date |
|
||||
| `004` | RPL_MYINFO | `numerics/004.json` | Server info and modes |
|
||||
| `322` | RPL_LIST | `numerics/322.json` | Channel list entry |
|
||||
| `323` | RPL_LISTEND | `numerics/323.json` | End of channel list |
|
||||
| `332` | RPL_TOPIC | `numerics/332.json` | Channel topic |
|
||||
| `353` | RPL_NAMREPLY | `numerics/353.json` | Channel member list |
|
||||
| `366` | RPL_ENDOFNAMES | `numerics/366.json` | End of NAMES list |
|
||||
| `372` | RPL_MOTD | `numerics/372.json` | MOTD line |
|
||||
| `375` | RPL_MOTDSTART | `numerics/375.json` | Start of MOTD |
|
||||
| `376` | RPL_ENDOFMOTD | `numerics/376.json` | End of MOTD |
|
||||
|
||||
### Errors (4xx)
|
||||
|
||||
| Code | Name | File | Description |
|
||||
|-------|----------------------|-----------------------|--------------------------------|
|
||||
| `401` | ERR_NOSUCHNICK | `numerics/401.json` | No such nick/channel |
|
||||
| `403` | ERR_NOSUCHCHANNEL | `numerics/403.json` | No such channel |
|
||||
| `433` | ERR_NICKNAMEINUSE | `numerics/433.json` | Nickname already in use |
|
||||
| `442` | ERR_NOTONCHANNEL | `numerics/442.json` | Not on that channel |
|
||||
| `482` | ERR_CHANOPRIVSNEEDED | `numerics/482.json` | Not channel operator |
|
||||
|
||||
## Federation (S2S)
|
||||
|
||||
Server-to-server messages use the same command format. Federated servers relay
|
||||
messages with an additional `origin` field in `meta` to track the source server.
|
||||
The PING/PONG commands serve as inter-server keepalives. State sync after link
|
||||
establishment uses a burst of JOIN, NICK, TOPIC, and MODE commands.
|
||||
16
schema/commands/JOIN.json
Normal file
16
schema/commands/JOIN.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/JOIN.json",
|
||||
"title": "JOIN",
|
||||
"description": "Join a channel. C2S: request to join. S2C: notification that a user joined. RFC 1459 §4.2.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": { "const": "JOIN" },
|
||||
"from": { "type": "string", "description": "Nick that joined (S2C)." },
|
||||
"to": { "type": "string", "description": "Channel name.", "pattern": "^#[a-zA-Z0-9_-]+$" }
|
||||
},
|
||||
"required": ["command", "to"],
|
||||
"examples": [
|
||||
{ "command": "JOIN", "from": "alice", "to": "#general" }
|
||||
]
|
||||
}
|
||||
29
schema/commands/KICK.json
Normal file
29
schema/commands/KICK.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/KICK.json",
|
||||
"title": "KICK",
|
||||
"description": "Kick a user from a channel. RFC 1459 §4.2.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_-]+$" },
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Kicked nick. e.g. [\"alice\"].",
|
||||
"minItems": 1,
|
||||
"maxItems": 1
|
||||
},
|
||||
"body": {
|
||||
"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"] }
|
||||
]
|
||||
}
|
||||
29
schema/commands/MODE.json
Normal file
29
schema/commands/MODE.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/MODE.json",
|
||||
"title": "MODE",
|
||||
"description": "Set or query channel/user modes. RFC 1459 §4.2.3.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": { "const": "MODE" },
|
||||
"from": {
|
||||
"type": "string",
|
||||
"description": "Nick that set the mode (S2C only)."
|
||||
},
|
||||
"to": {
|
||||
"type": "string",
|
||||
"description": "Channel name.",
|
||||
"pattern": "^#[a-zA-Z0-9_-]+$"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Mode string and optional target nick. e.g. [\"+o\", \"alice\"].",
|
||||
"examples": [["+o", "alice"], ["-m"], ["+v", "bob"]]
|
||||
}
|
||||
},
|
||||
"required": ["command", "to", "params"],
|
||||
"examples": [
|
||||
{ "command": "MODE", "from": "op1", "to": "#general", "params": ["+o", "alice"] }
|
||||
]
|
||||
}
|
||||
22
schema/commands/NICK.json
Normal file
22
schema/commands/NICK.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/NICK.json",
|
||||
"title": "NICK",
|
||||
"description": "Change nickname. C2S: request new nick. S2C: notification of nick change. RFC 1459 §4.1.2.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": { "const": "NICK" },
|
||||
"from": { "type": "string", "description": "Old nick (S2C)." },
|
||||
"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"] }
|
||||
]
|
||||
}
|
||||
21
schema/commands/NOTICE.json
Normal file
21
schema/commands/NOTICE.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/NOTICE.json",
|
||||
"title": "NOTICE",
|
||||
"description": "Send a notice. Like PRIVMSG but must not trigger automatic replies. RFC 1459 §4.4.2.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": { "const": "NOTICE" },
|
||||
"from": { "type": "string" },
|
||||
"to": { "type": "string", "description": "Target: #channel, nick, or * (global)." },
|
||||
"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"] }
|
||||
]
|
||||
}
|
||||
22
schema/commands/PART.json
Normal file
22
schema/commands/PART.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/PART.json",
|
||||
"title": "PART",
|
||||
"description": "Leave a channel. C2S: request to leave. S2C: notification that a user left. RFC 1459 §4.2.2.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": { "const": "PART" },
|
||||
"from": { "type": "string", "description": "Nick that left (S2C)." },
|
||||
"to": { "type": "string", "description": "Channel name.", "pattern": "^#[a-zA-Z0-9_-]+$" },
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Optional part reason.",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": ["command", "to"],
|
||||
"examples": [
|
||||
{ "command": "PART", "from": "alice", "to": "#general", "body": ["later"] }
|
||||
]
|
||||
}
|
||||
20
schema/commands/PING.json
Normal file
20
schema/commands/PING.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/PING.json",
|
||||
"title": "PING",
|
||||
"description": "Keepalive. C2S or S2S. Server responds with PONG. RFC 1459 §4.6.2.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": { "const": "PING" },
|
||||
"body": {
|
||||
"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"] }
|
||||
]
|
||||
}
|
||||
21
schema/commands/PONG.json
Normal file
21
schema/commands/PONG.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/PONG.json",
|
||||
"title": "PONG",
|
||||
"description": "Keepalive response. S2C or S2S. RFC 1459 §4.6.3.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": { "const": "PONG" },
|
||||
"from": { "type": "string", "description": "Responding server name." },
|
||||
"body": {
|
||||
"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"] }
|
||||
]
|
||||
}
|
||||
24
schema/commands/PRIVMSG.json
Normal file
24
schema/commands/PRIVMSG.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/PRIVMSG.json",
|
||||
"title": "PRIVMSG",
|
||||
"description": "Send a message to a channel or user. C2S: client sends to server. S2C: server relays to recipients. RFC 1459 §4.4.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"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": "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": "#general", "body": ["line one", "line two"] },
|
||||
{ "command": "PRIVMSG", "from": "bob", "to": "alice", "body": ["hey"], "meta": { "sig": "base64...", "alg": "ed25519" } }
|
||||
]
|
||||
}
|
||||
37
schema/commands/PUBKEY.json
Normal file
37
schema/commands/PUBKEY.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/PUBKEY.json",
|
||||
"title": "PUBKEY",
|
||||
"description": "Announce or relay a user's public signing key. C2S: client announces key to channel or server. S2C: server relays to channel members. Protocol extension (not in RFC 1459). Body is a structured object (not an array) containing the key material.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": { "const": "PUBKEY" },
|
||||
"from": { "type": "string", "description": "Nick announcing the key (set by server on relay)." },
|
||||
"to": {
|
||||
"type": "string",
|
||||
"description": "Target: #channel to announce to channel members, or omit for server-wide announcement."
|
||||
},
|
||||
"body": {
|
||||
"type": "object",
|
||||
"description": "Key material.",
|
||||
"properties": {
|
||||
"alg": {
|
||||
"type": "string",
|
||||
"description": "Key algorithm.",
|
||||
"enum": ["ed25519"]
|
||||
},
|
||||
"key": {
|
||||
"type": "string",
|
||||
"description": "Base64-encoded public key."
|
||||
}
|
||||
},
|
||||
"required": ["alg", "key"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["command", "body"],
|
||||
"examples": [
|
||||
{ "command": "PUBKEY", "from": "alice", "body": { "alg": "ed25519", "key": "base64-encoded-pubkey" } },
|
||||
{ "command": "PUBKEY", "from": "alice", "to": "#general", "body": { "alg": "ed25519", "key": "base64-encoded-pubkey" } }
|
||||
]
|
||||
}
|
||||
21
schema/commands/QUIT.json
Normal file
21
schema/commands/QUIT.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/QUIT.json",
|
||||
"title": "QUIT",
|
||||
"description": "User disconnected. S2C only. RFC 1459 §4.1.6.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": { "const": "QUIT" },
|
||||
"from": { "type": "string", "description": "Nick that quit." },
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Optional quit reason.",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": ["command", "from"],
|
||||
"examples": [
|
||||
{ "command": "QUIT", "from": "alice", "body": ["Connection reset"] }
|
||||
]
|
||||
}
|
||||
22
schema/commands/TOPIC.json
Normal file
22
schema/commands/TOPIC.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/commands/TOPIC.json",
|
||||
"title": "TOPIC",
|
||||
"description": "Get or set channel topic. C2S: set topic (body present) or query (body absent). S2C: topic change notification. RFC 1459 §4.2.4.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"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": "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"] }
|
||||
]
|
||||
}
|
||||
72
schema/message.json
Normal file
72
schema/message.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/message.json",
|
||||
"title": "IRC Message Envelope",
|
||||
"description": "Base envelope for all messages. Mirrors IRC wire format (RFC 1459/2812) encoded as JSON over HTTP. The 'command' field carries either an IRC command name (PRIVMSG, JOIN, etc.) or a three-digit numeric reply code (001, 353, 433, etc.).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "Server-assigned message UUID. Present on all server-originated messages."
|
||||
},
|
||||
"command": {
|
||||
"type": "string",
|
||||
"description": "IRC command name (PRIVMSG, JOIN, NICK, etc.) or three-digit numeric reply code (001, 353, 433, etc.).",
|
||||
"examples": ["PRIVMSG", "JOIN", "001", "353", "433"]
|
||||
},
|
||||
"from": {
|
||||
"type": "string",
|
||||
"description": "Source — nick for user messages, server name for server messages. Equivalent to IRC prefix."
|
||||
},
|
||||
"to": {
|
||||
"type": "string",
|
||||
"description": "Target — channel (#name) or nick. Equivalent to first IRC parameter for most commands."
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Additional parameters (used primarily by numeric replies). Equivalent to IRC middle parameters."
|
||||
},
|
||||
"body": {
|
||||
"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",
|
||||
"format": "date-time",
|
||||
"description": "Server-assigned timestamp (ISO 8601). Not present in original IRC; added for HTTP transport."
|
||||
},
|
||||
"meta": {
|
||||
"type": "object",
|
||||
"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
|
||||
}
|
||||
},
|
||||
"required": ["command"]
|
||||
}
|
||||
37
schema/numerics/001.json
Normal file
37
schema/numerics/001.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"$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 \u00a75.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "001"
|
||||
},
|
||||
"to": {
|
||||
"type": "string",
|
||||
"description": "Target nick."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Welcome text lines."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"body"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "001",
|
||||
"to": "alice",
|
||||
"body": [
|
||||
"Welcome to the network, alice"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
36
schema/numerics/002.json
Normal file
36
schema/numerics/002.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"$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 \u00a75.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "002"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Host info lines."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"body"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "002",
|
||||
"to": "alice",
|
||||
"body": [
|
||||
"Your host is chat.example.com, running version 0.1.0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
36
schema/numerics/003.json
Normal file
36
schema/numerics/003.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/numerics/003.json",
|
||||
"title": "003 RPL_CREATED",
|
||||
"description": "Server creation date. RFC 2812 \u00a75.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "003"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Text lines."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"body"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "003",
|
||||
"to": "alice",
|
||||
"body": [
|
||||
"This server was created 2026-02-01"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
39
schema/numerics/004.json
Normal file
39
schema/numerics/004.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/numerics/004.json",
|
||||
"title": "004 RPL_MYINFO",
|
||||
"description": "Server info (name, version, available modes). RFC 2812 \u00a75.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "004"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[server_name, version, user_modes, channel_modes]."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "004",
|
||||
"to": "alice",
|
||||
"params": [
|
||||
"chat.example.com",
|
||||
"0.1.0",
|
||||
"o",
|
||||
"imnst+ov"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
47
schema/numerics/322.json
Normal file
47
schema/numerics/322.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/numerics/322.json",
|
||||
"title": "322 RPL_LIST",
|
||||
"description": "Channel list entry. One per channel in response to LIST. RFC 1459 \u00a76.2.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "322"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[channel, visible_count]."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Channel topic."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "322",
|
||||
"to": "alice",
|
||||
"params": [
|
||||
"#general",
|
||||
"12"
|
||||
],
|
||||
"body": [
|
||||
"General discussion"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
27
schema/numerics/323.json
Normal file
27
schema/numerics/323.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"$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 \u00a76.2.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "323"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "End of /LIST",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to"
|
||||
]
|
||||
}
|
||||
47
schema/numerics/332.json
Normal file
47
schema/numerics/332.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/numerics/332.json",
|
||||
"title": "332 RPL_TOPIC",
|
||||
"description": "Channel topic (sent on JOIN or TOPIC query). RFC 1459 \u00a76.2.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "332"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[channel]."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Topic text."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params",
|
||||
"body"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "332",
|
||||
"to": "alice",
|
||||
"params": [
|
||||
"#general"
|
||||
],
|
||||
"body": [
|
||||
"Welcome to the chat"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
48
schema/numerics/353.json
Normal file
48
schema/numerics/353.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/numerics/353.json",
|
||||
"title": "353 RPL_NAMREPLY",
|
||||
"description": "Channel member list. Sent on JOIN or NAMES query. RFC 1459 \u00a76.2.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "353"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[channel_type, channel]. channel_type: = (public), * (private), @ (secret)."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Space-separated list of nicks. Prefixed with @ for ops, + for voiced."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params",
|
||||
"body"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "353",
|
||||
"to": "alice",
|
||||
"params": [
|
||||
"=",
|
||||
"#general"
|
||||
],
|
||||
"body": [
|
||||
"@op1 alice bob +voiced1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
35
schema/numerics/366.json
Normal file
35
schema/numerics/366.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$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 \u00a76.2.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "366"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[channel]."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "End of /NAMES list",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params"
|
||||
]
|
||||
}
|
||||
36
schema/numerics/372.json
Normal file
36
schema/numerics/372.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/numerics/372.json",
|
||||
"title": "372 RPL_MOTD",
|
||||
"description": "MOTD line. One message per line of the MOTD. RFC 2812 \u00a75.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "372"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "MOTD line text (prefixed with '- ')."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"body"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "372",
|
||||
"to": "alice",
|
||||
"body": [
|
||||
"- Welcome to our server!"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
26
schema/numerics/375.json
Normal file
26
schema/numerics/375.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.eeqj.de/sneak/chat/schema/numerics/375.json",
|
||||
"title": "375 RPL_MOTDSTART",
|
||||
"description": "Start of MOTD. RFC 2812 \u00a75.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "375"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Text lines."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to"
|
||||
]
|
||||
}
|
||||
27
schema/numerics/376.json
Normal file
27
schema/numerics/376.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"$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 \u00a75.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "376"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "End of /MOTD command",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to"
|
||||
]
|
||||
}
|
||||
47
schema/numerics/401.json
Normal file
47
schema/numerics/401.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$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 \u00a76.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "401"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[target_nick]."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "No such nick/channel",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "401",
|
||||
"to": "alice",
|
||||
"params": [
|
||||
"bob"
|
||||
],
|
||||
"body": [
|
||||
"No such nick/channel"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
47
schema/numerics/403.json
Normal file
47
schema/numerics/403.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$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 \u00a76.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "403"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[channel_name]."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "No such channel",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "403",
|
||||
"to": "alice",
|
||||
"params": [
|
||||
"#nonexistent"
|
||||
],
|
||||
"body": [
|
||||
"No such channel"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
47
schema/numerics/433.json
Normal file
47
schema/numerics/433.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$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 \u00a76.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "433"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[requested_nick]."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Nickname is already in use",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"command": "433",
|
||||
"to": "*",
|
||||
"params": [
|
||||
"alice"
|
||||
],
|
||||
"body": [
|
||||
"Nickname is already in use"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
35
schema/numerics/442.json
Normal file
35
schema/numerics/442.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$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 \u00a76.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "442"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[channel]."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "You're not on that channel",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params"
|
||||
]
|
||||
}
|
||||
35
schema/numerics/482.json
Normal file
35
schema/numerics/482.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$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 \u00a76.1.",
|
||||
"$ref": "../message.json",
|
||||
"properties": {
|
||||
"command": {
|
||||
"const": "482"
|
||||
},
|
||||
"to": {
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "[channel]."
|
||||
},
|
||||
"body": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "You're not channel operator",
|
||||
"maxItems": 1
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"command",
|
||||
"to",
|
||||
"params"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user