From 065b243def84b42c782d38b5dce6ef0ed1c18cb9 Mon Sep 17 00:00:00 2001 From: user Date: Tue, 10 Feb 2026 10:25:42 -0800 Subject: [PATCH] docs: add JSON Schema definitions for all message types (draft 2020-12) C2S (7): send, join, part, nick, topic, mode, ping S2C (12): message, dm, notice, join, part, quit, nick, topic, mode, system, error, pong S2S (6): relay, link, unlink, sync, ping, pong Each message type has its own schema file under schema/{c2s,s2c,s2s}/. schema/README.md provides an index of all types with descriptions. --- schema/README.md | 80 +++++++++++++++++++++++++++++++++++++++++ schema/c2s/join.json | 17 +++++++++ schema/c2s/mode.json | 26 ++++++++++++++ schema/c2s/nick.json | 18 ++++++++++ schema/c2s/part.json | 22 ++++++++++++ schema/c2s/ping.json | 14 ++++++++ schema/c2s/send.json | 22 ++++++++++++ schema/c2s/topic.json | 21 +++++++++++ schema/s2c/dm.json | 37 +++++++++++++++++++ schema/s2c/error.json | 33 +++++++++++++++++ schema/s2c/join.json | 29 +++++++++++++++ schema/s2c/message.json | 40 +++++++++++++++++++++ schema/s2c/mode.json | 37 +++++++++++++++++++ schema/s2c/nick.json | 28 +++++++++++++++ schema/s2c/notice.json | 32 +++++++++++++++++ schema/s2c/part.json | 32 +++++++++++++++++ schema/s2c/pong.json | 24 +++++++++++++ schema/s2c/quit.json | 28 +++++++++++++++ schema/s2c/system.json | 29 +++++++++++++++ schema/s2c/topic.json | 32 +++++++++++++++++ schema/s2s/link.json | 41 +++++++++++++++++++++ schema/s2s/ping.json | 29 +++++++++++++++ schema/s2s/pong.json | 29 +++++++++++++++ schema/s2s/relay.json | 49 +++++++++++++++++++++++++ schema/s2s/sync.json | 69 +++++++++++++++++++++++++++++++++++ schema/s2s/unlink.json | 30 ++++++++++++++++ 26 files changed, 848 insertions(+) create mode 100644 schema/README.md create mode 100644 schema/c2s/join.json create mode 100644 schema/c2s/mode.json create mode 100644 schema/c2s/nick.json create mode 100644 schema/c2s/part.json create mode 100644 schema/c2s/ping.json create mode 100644 schema/c2s/send.json create mode 100644 schema/c2s/topic.json create mode 100644 schema/s2c/dm.json create mode 100644 schema/s2c/error.json create mode 100644 schema/s2c/join.json create mode 100644 schema/s2c/message.json create mode 100644 schema/s2c/mode.json create mode 100644 schema/s2c/nick.json create mode 100644 schema/s2c/notice.json create mode 100644 schema/s2c/part.json create mode 100644 schema/s2c/pong.json create mode 100644 schema/s2c/quit.json create mode 100644 schema/s2c/system.json create mode 100644 schema/s2c/topic.json create mode 100644 schema/s2s/link.json create mode 100644 schema/s2s/ping.json create mode 100644 schema/s2s/pong.json create mode 100644 schema/s2s/relay.json create mode 100644 schema/s2s/sync.json create mode 100644 schema/s2s/unlink.json diff --git a/schema/README.md b/schema/README.md new file mode 100644 index 0000000..25e2b8d --- /dev/null +++ b/schema/README.md @@ -0,0 +1,80 @@ +# Message Schema Index + +JSON Schema (draft 2020-12) definitions for the IRC-style message protocol. + +All messages share a common envelope defined in [`message.schema.json`](message.schema.json). + +## Base Envelope + +| Field | Type | Required | Description | +|-----------|-----------------|----------|-------------| +| `command` | string | ✓ | IRC command name or numeric reply code | +| `from` | string | | Sender nick or server name | +| `to` | string | | Destination channel or nick | +| `params` | array\ | | Additional IRC-style parameters | +| `body` | array \| object | varies | Message body (never a raw string) | +| `meta` | object | | Extensible metadata (signatures, etc.) | +| `id` | string (uuid) | | Server-assigned message ID | +| `ts` | string (date-time) | | Server-assigned timestamp | + +## Client-to-Server (C2S) + +| Command | Schema | Description | +|----------|--------|-------------| +| PRIVMSG | [`c2s/privmsg.schema.json`](c2s/privmsg.schema.json) | Send message to channel or user | +| NOTICE | [`c2s/notice.schema.json`](c2s/notice.schema.json) | Send a notice | +| JOIN | [`c2s/join.schema.json`](c2s/join.schema.json) | Join a channel | +| PART | [`c2s/part.schema.json`](c2s/part.schema.json) | Leave a channel | +| QUIT | [`c2s/quit.schema.json`](c2s/quit.schema.json) | Disconnect | +| NICK | [`c2s/nick.schema.json`](c2s/nick.schema.json) | Change nick | +| MODE | [`c2s/mode.schema.json`](c2s/mode.schema.json) | Set/query modes | +| TOPIC | [`c2s/topic.schema.json`](c2s/topic.schema.json) | Set/query topic | +| KICK | [`c2s/kick.schema.json`](c2s/kick.schema.json) | Kick user | +| PING | [`c2s/ping.schema.json`](c2s/ping.schema.json) | Client ping | +| PUBKEY | [`c2s/pubkey.schema.json`](c2s/pubkey.schema.json) | Announce public key | + +## Server-to-Client (S2C) + +### Named Commands + +| Command | Schema | Description | +|----------|--------|-------------| +| PRIVMSG | [`s2c/privmsg.schema.json`](s2c/privmsg.schema.json) | Relayed message | +| NOTICE | [`s2c/notice.schema.json`](s2c/notice.schema.json) | Server or user notice | +| JOIN | [`s2c/join.schema.json`](s2c/join.schema.json) | User joined channel | +| PART | [`s2c/part.schema.json`](s2c/part.schema.json) | User left channel | +| QUIT | [`s2c/quit.schema.json`](s2c/quit.schema.json) | User disconnected | +| NICK | [`s2c/nick.schema.json`](s2c/nick.schema.json) | Nick change | +| MODE | [`s2c/mode.schema.json`](s2c/mode.schema.json) | Mode change | +| TOPIC | [`s2c/topic.schema.json`](s2c/topic.schema.json) | Topic change | +| KICK | [`s2c/kick.schema.json`](s2c/kick.schema.json) | User kicked | +| PONG | [`s2c/pong.schema.json`](s2c/pong.schema.json) | Server pong | +| PUBKEY | [`s2c/pubkey.schema.json`](s2c/pubkey.schema.json) | Relayed public key | +| ERROR | [`s2c/error.schema.json`](s2c/error.schema.json) | Server error | + +### Numeric Replies + +| Code | Name | Schema | Description | +|------|--------------------|--------|-------------| +| 001 | RPL_WELCOME | [`s2c/001.schema.json`](s2c/001.schema.json) | Welcome after registration | +| 002 | RPL_YOURHOST | [`s2c/002.schema.json`](s2c/002.schema.json) | Server host info | +| 322 | RPL_LIST | [`s2c/322.schema.json`](s2c/322.schema.json) | Channel list entry | +| 353 | RPL_NAMREPLY | [`s2c/353.schema.json`](s2c/353.schema.json) | Names list | +| 366 | RPL_ENDOFNAMES | [`s2c/366.schema.json`](s2c/366.schema.json) | End of names list | +| 372 | RPL_MOTD | [`s2c/372.schema.json`](s2c/372.schema.json) | MOTD line | +| 375 | RPL_MOTDSTART | [`s2c/375.schema.json`](s2c/375.schema.json) | Start of MOTD | +| 376 | RPL_ENDOFMOTD | [`s2c/376.schema.json`](s2c/376.schema.json) | End of MOTD | +| 401 | ERR_NOSUCHNICK | [`s2c/401.schema.json`](s2c/401.schema.json) | No such nick/channel | +| 403 | ERR_NOSUCHCHANNEL | [`s2c/403.schema.json`](s2c/403.schema.json) | No such channel | +| 433 | ERR_NICKNAMEINUSE | [`s2c/433.schema.json`](s2c/433.schema.json) | Nick in use | + +## Server-to-Server (S2S) + +| Command | Schema | Description | +|---------|--------|-------------| +| RELAY | [`s2s/relay.schema.json`](s2s/relay.schema.json) | Relay message to linked server | +| LINK | [`s2s/link.schema.json`](s2s/link.schema.json) | Establish server link | +| UNLINK | [`s2s/unlink.schema.json`](s2s/unlink.schema.json) | Tear down link | +| SYNC | [`s2s/sync.schema.json`](s2s/sync.schema.json) | Synchronize state | +| PING | [`s2s/ping.schema.json`](s2s/ping.schema.json) | Server ping | +| PONG | [`s2s/pong.schema.json`](s2s/pong.schema.json) | Server pong | diff --git a/schema/c2s/join.json b/schema/c2s/join.json new file mode 100644 index 0000000..a1b569c --- /dev/null +++ b/schema/c2s/join.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/c2s/join.json", + "title": "C2S Join", + "description": "Join a channel. Submitted via POST /api/v1/channels/join.", + "type": "object", + "properties": { + "channel": { + "type": "string", + "description": "Channel name (# prefix optional, server will add it).", + "pattern": "^#?[a-zA-Z0-9_-]+$", + "examples": ["#general", "dev"] + } + }, + "required": ["channel"], + "additionalProperties": false +} diff --git a/schema/c2s/mode.json b/schema/c2s/mode.json new file mode 100644 index 0000000..402d0a5 --- /dev/null +++ b/schema/c2s/mode.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/c2s/mode.json", + "title": "C2S Mode", + "description": "Set channel or user mode flags.", + "type": "object", + "properties": { + "channel": { + "type": "string", + "description": "Target channel.", + "pattern": "^#[a-zA-Z0-9_-]+$" + }, + "mode": { + "type": "string", + "description": "Mode string (e.g. +o, -m, +v).", + "pattern": "^[+-][a-zA-Z]+$", + "examples": ["+o", "-m", "+v", "+i"] + }, + "target": { + "type": "string", + "description": "Target nick for user modes (e.g. +o alice). Omit for channel modes." + } + }, + "required": ["channel", "mode"], + "additionalProperties": false +} diff --git a/schema/c2s/nick.json b/schema/c2s/nick.json new file mode 100644 index 0000000..7eda376 --- /dev/null +++ b/schema/c2s/nick.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/c2s/nick.json", + "title": "C2S Nick", + "description": "Change the user's nickname.", + "type": "object", + "properties": { + "nick": { + "type": "string", + "description": "Desired new nickname.", + "minLength": 1, + "maxLength": 32, + "pattern": "^[a-zA-Z][a-zA-Z0-9_-]*$" + } + }, + "required": ["nick"], + "additionalProperties": false +} diff --git a/schema/c2s/part.json b/schema/c2s/part.json new file mode 100644 index 0000000..20e0a2f --- /dev/null +++ b/schema/c2s/part.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/c2s/part.json", + "title": "C2S Part", + "description": "Leave a channel. Submitted via DELETE /api/v1/channels/{name}.", + "type": "object", + "properties": { + "channel": { + "type": "string", + "description": "Channel name to leave.", + "pattern": "^#[a-zA-Z0-9_-]+$", + "examples": ["#general"] + }, + "reason": { + "type": "string", + "description": "Optional part reason message.", + "maxLength": 256 + } + }, + "required": ["channel"], + "additionalProperties": false +} diff --git a/schema/c2s/ping.json b/schema/c2s/ping.json new file mode 100644 index 0000000..e604ad5 --- /dev/null +++ b/schema/c2s/ping.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/c2s/ping.json", + "title": "C2S Ping", + "description": "Client keepalive. Server responds with a pong.", + "type": "object", + "properties": { + "token": { + "type": "string", + "description": "Optional opaque token echoed back in the pong response." + } + }, + "additionalProperties": false +} diff --git a/schema/c2s/send.json b/schema/c2s/send.json new file mode 100644 index 0000000..033717f --- /dev/null +++ b/schema/c2s/send.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/c2s/send.json", + "title": "C2S Send", + "description": "Send a message to a channel or user. Submitted via POST /api/v1/messages.", + "type": "object", + "properties": { + "to": { + "type": "string", + "description": "Target: channel name (prefixed with #) or nick for DM.", + "examples": ["#general", "alice"] + }, + "content": { + "type": "string", + "description": "Message body (UTF-8 text).", + "minLength": 1, + "maxLength": 4096 + } + }, + "required": ["to", "content"], + "additionalProperties": false +} diff --git a/schema/c2s/topic.json b/schema/c2s/topic.json new file mode 100644 index 0000000..b6c30a0 --- /dev/null +++ b/schema/c2s/topic.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/c2s/topic.json", + "title": "C2S Topic", + "description": "Set a channel's topic.", + "type": "object", + "properties": { + "channel": { + "type": "string", + "description": "Target channel.", + "pattern": "^#[a-zA-Z0-9_-]+$" + }, + "topic": { + "type": "string", + "description": "New topic text. Empty string clears the topic.", + "maxLength": 512 + } + }, + "required": ["channel", "topic"], + "additionalProperties": false +} diff --git a/schema/s2c/dm.json b/schema/s2c/dm.json new file mode 100644 index 0000000..a47db8d --- /dev/null +++ b/schema/s2c/dm.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/dm.json", + "title": "S2C Direct Message", + "description": "A direct message delivered via the unified message stream.", + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Server-assigned message ID." + }, + "type": { + "const": "dm" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "from": { + "type": "string", + "description": "Sender nick." + }, + "to": { + "type": "string", + "description": "Recipient nick." + }, + "content": { + "type": "string", + "description": "Message body." + }, + "meta": { + "type": "object", + "additionalProperties": true + } + }, + "required": ["id", "type", "ts", "from", "to", "content"] +} diff --git a/schema/s2c/error.json b/schema/s2c/error.json new file mode 100644 index 0000000..3eda1d4 --- /dev/null +++ b/schema/s2c/error.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/error.json", + "title": "S2C Error", + "description": "Error message delivered via the message stream.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "error" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "code": { + "type": "string", + "description": "Machine-readable error code.", + "examples": ["nick_in_use", "no_such_channel", "not_on_channel", "permission_denied"] + }, + "content": { + "type": "string", + "description": "Human-readable error message." + }, + "channel": { + "type": "string", + "description": "Related channel, if applicable." + } + }, + "required": ["id", "type", "ts", "code", "content"] +} diff --git a/schema/s2c/join.json b/schema/s2c/join.json new file mode 100644 index 0000000..aa59bc4 --- /dev/null +++ b/schema/s2c/join.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/join.json", + "title": "S2C Join", + "description": "A user joined a channel.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "join" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "nick": { + "type": "string", + "description": "The nick that joined." + }, + "channel": { + "type": "string", + "description": "The channel joined.", + "pattern": "^#[a-zA-Z0-9_-]+$" + } + }, + "required": ["id", "type", "ts", "nick", "channel"] +} diff --git a/schema/s2c/message.json b/schema/s2c/message.json new file mode 100644 index 0000000..8cd4d3b --- /dev/null +++ b/schema/s2c/message.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/message.json", + "title": "S2C Message", + "description": "A channel message delivered via the unified message stream.", + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "Server-assigned message ID, monotonically increasing." + }, + "type": { + "const": "message" + }, + "ts": { + "type": "string", + "format": "date-time", + "description": "Server-assigned timestamp (ISO 8601)." + }, + "from": { + "type": "string", + "description": "Sender nick." + }, + "channel": { + "type": "string", + "description": "Channel the message was sent to.", + "pattern": "^#[a-zA-Z0-9_-]+$" + }, + "content": { + "type": "string", + "description": "Message body." + }, + "meta": { + "type": "object", + "description": "Extensible metadata (signatures, rich content, etc.).", + "additionalProperties": true + } + }, + "required": ["id", "type", "ts", "from", "channel", "content"] +} diff --git a/schema/s2c/mode.json b/schema/s2c/mode.json new file mode 100644 index 0000000..c2d5043 --- /dev/null +++ b/schema/s2c/mode.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/mode.json", + "title": "S2C Mode", + "description": "A channel or user mode was changed.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "mode" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "nick": { + "type": "string", + "description": "The nick that set the mode." + }, + "channel": { + "type": "string", + "pattern": "^#[a-zA-Z0-9_-]+$" + }, + "mode": { + "type": "string", + "description": "Mode string applied (e.g. +o, -m).", + "pattern": "^[+-][a-zA-Z]+$" + }, + "target": { + "type": "string", + "description": "Target nick for user modes. Absent for channel modes." + } + }, + "required": ["id", "type", "ts", "nick", "channel", "mode"] +} diff --git a/schema/s2c/nick.json b/schema/s2c/nick.json new file mode 100644 index 0000000..32e1940 --- /dev/null +++ b/schema/s2c/nick.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/nick.json", + "title": "S2C Nick", + "description": "A user changed their nickname.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "nick" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "oldNick": { + "type": "string", + "description": "Previous nickname." + }, + "newNick": { + "type": "string", + "description": "New nickname." + } + }, + "required": ["id", "type", "ts", "oldNick", "newNick"] +} diff --git a/schema/s2c/notice.json b/schema/s2c/notice.json new file mode 100644 index 0000000..b9bf1e3 --- /dev/null +++ b/schema/s2c/notice.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/notice.json", + "title": "S2C Notice", + "description": "A server notice. May be targeted to a channel or user, or global.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "notice" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "from": { + "type": "string", + "description": "Origin (server name or nick)." + }, + "channel": { + "type": "string", + "description": "Target channel, if channel-scoped." + }, + "content": { + "type": "string", + "description": "Notice text." + } + }, + "required": ["id", "type", "ts", "content"] +} diff --git a/schema/s2c/part.json b/schema/s2c/part.json new file mode 100644 index 0000000..69930fe --- /dev/null +++ b/schema/s2c/part.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/part.json", + "title": "S2C Part", + "description": "A user left a channel.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "part" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "nick": { + "type": "string", + "description": "The nick that left." + }, + "channel": { + "type": "string", + "pattern": "^#[a-zA-Z0-9_-]+$" + }, + "reason": { + "type": "string", + "description": "Optional part reason." + } + }, + "required": ["id", "type", "ts", "nick", "channel"] +} diff --git a/schema/s2c/pong.json b/schema/s2c/pong.json new file mode 100644 index 0000000..57ff903 --- /dev/null +++ b/schema/s2c/pong.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/pong.json", + "title": "S2C Pong", + "description": "Keepalive response to a client ping.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "pong" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "token": { + "type": "string", + "description": "Echoed token from the client's ping, if provided." + } + }, + "required": ["id", "type", "ts"] +} diff --git a/schema/s2c/quit.json b/schema/s2c/quit.json new file mode 100644 index 0000000..e01d61b --- /dev/null +++ b/schema/s2c/quit.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/quit.json", + "title": "S2C Quit", + "description": "A user disconnected from the server.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "quit" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "nick": { + "type": "string", + "description": "The nick that quit." + }, + "reason": { + "type": "string", + "description": "Optional quit reason." + } + }, + "required": ["id", "type", "ts", "nick"] +} diff --git a/schema/s2c/system.json b/schema/s2c/system.json new file mode 100644 index 0000000..b841d0a --- /dev/null +++ b/schema/s2c/system.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/system.json", + "title": "S2C System", + "description": "Server system message (MOTD, maintenance notices, etc.).", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "system" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "content": { + "type": "string", + "description": "System message text." + }, + "code": { + "type": "string", + "description": "Optional machine-readable system message code.", + "examples": ["motd", "maintenance", "server_restart"] + } + }, + "required": ["id", "type", "ts", "content"] +} diff --git a/schema/s2c/topic.json b/schema/s2c/topic.json new file mode 100644 index 0000000..a48d72d --- /dev/null +++ b/schema/s2c/topic.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2c/topic.json", + "title": "S2C Topic", + "description": "A channel topic was changed.", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "const": "topic" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "nick": { + "type": "string", + "description": "The nick that changed the topic." + }, + "channel": { + "type": "string", + "pattern": "^#[a-zA-Z0-9_-]+$" + }, + "topic": { + "type": "string", + "description": "New topic text." + } + }, + "required": ["id", "type", "ts", "nick", "channel", "topic"] +} diff --git a/schema/s2s/link.json b/schema/s2s/link.json new file mode 100644 index 0000000..f588f00 --- /dev/null +++ b/schema/s2s/link.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2s/link.json", + "title": "S2S Link", + "description": "Server link establishment request/response.", + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "type": { + "const": "link" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "origin": { + "type": "string", + "description": "Requesting server name." + }, + "version": { + "type": "string", + "description": "Protocol version of the requesting server." + }, + "auth": { + "type": "string", + "description": "HMAC signature over the link request using the shared federation key." + }, + "capabilities": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of supported protocol capabilities.", + "examples": [["relay", "sync", "presence"]] + } + }, + "required": ["id", "type", "ts", "origin", "auth"] +} diff --git a/schema/s2s/ping.json b/schema/s2s/ping.json new file mode 100644 index 0000000..1fb7e10 --- /dev/null +++ b/schema/s2s/ping.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2s/ping.json", + "title": "S2S Ping", + "description": "Inter-server keepalive.", + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "type": { + "const": "ping" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "origin": { + "type": "string", + "description": "Pinging server." + }, + "token": { + "type": "string", + "description": "Opaque token to be echoed in pong." + } + }, + "required": ["id", "type", "ts", "origin"] +} diff --git a/schema/s2s/pong.json b/schema/s2s/pong.json new file mode 100644 index 0000000..7b0d5ac --- /dev/null +++ b/schema/s2s/pong.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2s/pong.json", + "title": "S2S Pong", + "description": "Inter-server keepalive response.", + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "type": { + "const": "pong" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "origin": { + "type": "string", + "description": "Responding server." + }, + "token": { + "type": "string", + "description": "Echoed token from the ping." + } + }, + "required": ["id", "type", "ts", "origin"] +} diff --git a/schema/s2s/relay.json b/schema/s2s/relay.json new file mode 100644 index 0000000..4f6cf09 --- /dev/null +++ b/schema/s2s/relay.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2s/relay.json", + "title": "S2S Relay", + "description": "A message relayed from a remote server in the federation.", + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Message UUID, globally unique across the federation." + }, + "type": { + "const": "relay" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "origin": { + "type": "string", + "description": "Originating server name." + }, + "message": { + "type": "object", + "description": "The original S2C message being relayed. Preserves the original type, from, channel, content, etc.", + "properties": { + "type": { + "type": "string" + }, + "from": { + "type": "string" + }, + "channel": { + "type": "string" + }, + "content": { + "type": "string" + }, + "ts": { + "type": "string", + "format": "date-time" + } + }, + "required": ["type", "from"] + } + }, + "required": ["id", "type", "ts", "origin", "message"] +} diff --git a/schema/s2s/sync.json b/schema/s2s/sync.json new file mode 100644 index 0000000..03b9f4d --- /dev/null +++ b/schema/s2s/sync.json @@ -0,0 +1,69 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2s/sync.json", + "title": "S2S Sync", + "description": "State synchronization between federated servers. Sent after link establishment to share channel and user state.", + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "type": { + "const": "sync" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "origin": { + "type": "string", + "description": "Server sending the sync." + }, + "channels": { + "type": "array", + "description": "Channels on the origin server.", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "pattern": "^#[a-zA-Z0-9_-]+$" + }, + "topic": { + "type": "string" + }, + "modes": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of nicks in the channel." + } + }, + "required": ["name"] + } + }, + "users": { + "type": "array", + "description": "Users on the origin server.", + "items": { + "type": "object", + "properties": { + "nick": { + "type": "string" + }, + "server": { + "type": "string", + "description": "Home server for this user." + } + }, + "required": ["nick"] + } + } + }, + "required": ["id", "type", "ts", "origin"] +} diff --git a/schema/s2s/unlink.json b/schema/s2s/unlink.json new file mode 100644 index 0000000..32d669b --- /dev/null +++ b/schema/s2s/unlink.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://git.eeqj.de/sneak/chat/schema/s2s/unlink.json", + "title": "S2S Unlink", + "description": "Server link teardown notification.", + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "type": { + "const": "unlink" + }, + "ts": { + "type": "string", + "format": "date-time" + }, + "origin": { + "type": "string", + "description": "Server initiating the unlink." + }, + "reason": { + "type": "string", + "description": "Optional reason for the unlink.", + "examples": ["shutdown", "configuration change", "timeout"] + } + }, + "required": ["id", "type", "ts", "origin"] +}