openapi: 3.1.0 info: title: Blah Chatserver Proto version: 0.0.1 paths: /ws: get: summary: WebSocket endpoint description: | Once connection, client must send a JSON text message of type `WithSig` for authentication. If server does not close it immediately, it means success. Then server will send JSON text messages on events that user are interested in (eg. chat from joined rooms). The message has type `Outgoing` in `blahd/src/ws.rs`. /room: get: summary: List rooms parameters: - name: filter in: query required: true schema: enum: - public - joined - unseen description: | Must be one of following values: - "public": list all public rooms on the server. - "joined": list rooms the user have joined. Requires `Authorization`. - "unseen": list rooms the user have joined and have unseen messages. Requires `Authorization`. - name: top in: query schema: type: string description: The maximum number of items returned in each page. This is only an advice and server can clamp it to a smaller value. - name: skipToken in: query schema: type: string description: The page token returned from a previous list response to fetch the next page. NB. Other parameters (eg. `joined` and `page_len`) should be included (as the same value) for each page fetch. - name: Authorization in: header description: Optional proof of membership for private rooms. schema: $ref: '#/components/schemas/WithSig-Auth' responses: 200: description: Filtered and paged rooms. content: application/json: schema: $ref: '#/components/schemas/RoomList' 401: description: Missing or invalid Authorization header. content: application/json: schema: $ref: '#/components/schemas/ApiError' /room/create: post: summary: Create room requestBody: content: application/json: schema: $ref: '#/components/schemas/WithSig-CreateRoom' responses: 200: description: Room created. content: application/json: schema: type: string description: Newly created room `rid`. 403: description: The user does not have permission to create room. content: application/json: schema: $ref: '#/components/schemas/ApiError' /room/{rid}: get: summary: Get room metadata parameters: - name: Authorization in: header description: Optional proof of membership for private rooms. schema: $ref: '#/components/schemas/WithSig-Auth' responses: 200: description: The metadata of the specified room. content: application/json: schema: $ref: '#/components/schemas/RoomMetadata' 404: description: | Room does not exist or the user does not have permission to get metadata of it. content: application/json: schema: $ref: '#/components/schemas/ApiError' /room/{rid}/admin: post: summary: Room management requestBody: content: application/json: schema: $ref: '#/components/schemas/WithSig-RoomAdmin' responses: 204: description: Operation completed. 409: description: Operation is already done, eg. joining an already joined room. content: application/json: schema: $ref: '#/components/schemas/ApiError' 404: description: | Room does not exist or the user does not have permission for management. content: application/json: schema: $ref: '#/components/schemas/ApiError' /room/{rid}/feed.json: get: summary: Get JSON feed of room description: | Get room {rid}'s content in JSON feed v1.1 format. The room must be public. For human and feed reader consumption only. responses: 200: description: The JSON feed. content: text/feed+json: schema: $ref: 'https://www.jsonfeed.org/version/1.1/' 404: description: Room does not exist or is private. content: application/json: schema: $ref: '#/components/schemas/ApiError' /room/{rid}/item: get: summary: List items in room description: | Return items in reversed time order, up to `skipToken` items in a single response, from room {rid}. The last (oldest) chat `cid` will be returned as `skipToken` in response, which can be used as query parameter for the next GET, to repeatedly fetch more history. parameters: - name: Authorization in: header description: Optional proof of membership for private rooms. schema: $ref: '#/components/schemas/WithSig-Auth' - name: top in: query schema: type: integer description: | The maximum number of items to return. This is an advice and may be further clamped by the server. It must not be zero. - name: skipToken in: query schema: type: string description: | Return items after (older than) an existing `cid`. Useful for pagination. responses: 200: content: application/json: schema: $ref: '#/components/schemas/RoomItems' 404: description: | Room does not exist or the user does not have permission to read it. content: application/json: schema: $ref: '#/components/schemas/ApiError' post: summary: Post item in room requestBody: content: application/json: schema: $ref: '#/components/schemas/WithSig-Chat' responses: 200: content: application/json: schema: type: string description: Newly created item `cid`. # FIXME: Distinguish this from 404? 403: description: | The user does not have permission to post in this room, or the room does not exist. content: application/json: schema: $ref: '#/components/schemas/ApiError' /room/{rid}/item/{cid}/seen: post: summary: Mark item seen description: | Mark item {cid} in room {rid} seen by the current user. Server may enforce that last seen item does not go backward. Marking an older item seen or sending the same request multiple times can be a no-op. parameters: - name: Authorization in: header required: true description: Proof of membership for private rooms. schema: $ref: '#/components/schemas/WithSig-Auth' responses: 204: description: Operation completed. 404: description: | Room does not exist or the user is not in the room. content: application/json: schema: $ref: '#/components/schemas/ApiError' # Ideally we should generate these from src, but we need to # WAIT: https://github.com/juhaku/utoipa/pull/1034 components: schemas: ApiError: type: object properties: error: type: object properties: code: type: string description: A machine-readable error code string. example: invalid_signature message: type: string description: A human-readable error message. example: signature verification failed RoomList: type: object required: - rooms properties: rooms: type: array items: $ref: '#/components/schemas/RoomMetadataForList' next_token: type: string description: An opaque token to fetch the next page. RoomMetadataForList: type: object required: ['rid', 'title', 'attrs'] properties: rid: type: string title: type: string attrs: description: Room attributes bitset, see `RoomAttrs`. type: integer format: int64 last_chat: $ref: '#/components/schemas/WithItemId-WithSig-Chat' last_seen_cid: description: The `cid` of the last chat being marked as seen. type: string unseen_cnt: description: | The number of unseen messages. Only available for GET `/room?filter=unseen`. type: integer format: uint64 RoomMetadata: type: object required: ['rid', 'title', 'attrs'] properties: rid: type: string title: type: string attrs: type: integer format: int64 RoomItems: type: object required: - items properties: items: description: Room items in reversed server-received time order. type: array items: $ref: '#/components/schemas/WithItemId-WithSig-Chat' skip_token: description: The token for fetching the next page. type: string RichText: type: array items: anyOf: - type: string description: Unstyled text piece. - type: array items: false prefixItems: - type: string description: The text piece to apply styles on. - type: object properties: b: type: boolean description: Bold. m: type: boolean description: Monospace. i: type: boolean description: Italic. s: type: boolean description: Strikethrough. u: type: boolean description: Underline. hashtag: type: boolean description: Hashtag. link: type: string description: Link target. WithSig-Auth: type: object properties: sig: type: string signee: type: object properties: nonce: type: integer format: uint32 payload: type: object properties: typ: type: string const: 'auth' WithSig-RoomAdmin: type: object properties: sig: type: string signee: type: object properties: nonce: type: integer format: uint32 payload: oneOf: - description: Add member to the room. type: object properties: typ: type: string const: 'add_member' room: type: string permission: type: integer format: uint64 user: type: string - description: Remove member from the room. type: object properties: typ: type: string const: 'remove_member' room: type: string user: type: string example: sig: 99a77e836538268839ed3419c649eefb043cb51d448f641cc2a1c523811aab4aacd09f92e7c0688ffd659bfc6acb764fea79979a491e132bf6a56dd23adc1d09 signee: nonce: 670593955 payload: permission: 1 room: 7ed9e067-ec37-4054-9fc2-b1bd890929bd typ: add_member user: 83ce46ced47ec0391c64846cbb6c507250ead4985b6a044d68751edc46015dd7 timestamp: 1724966284 user: 83ce46ced47ec0391c64846cbb6c507250ead4985b6a044d68751edc46015dd7 WithSig-Chat: type: object properties: sig: type: string signee: type: object properties: nonce: type: integer format: uint32 payload: type: object properties: typ: type: string const: 'chat' room: type: string rich_text: $ref: '$/components/schemas/RichText' example: sig: 99a77e836538268839ed3419c649eefb043cb51d448f641cc2a1c523811aab4aacd09f92e7c0688ffd659bfc6acb764fea79979a491e132bf6a56dd23adc1d09 signee: nonce: 670593955 payload: typ: chat room: 7ed9e067-ec37-4054-9fc2-b1bd890929bd rich_text: ["before ",["bold ",{"b":true}],["italic bold ",{"b":true,"i":true}],"end"] timestamp: 1724966284 user: 83ce46ced47ec0391c64846cbb6c507250ead4985b6a044d68751edc46015dd7 WithItemId-WithSig-Chat: allOf: - $ref: '#/components/schemas/WithSig-Chat' - type: object properties: cid: type: string description: An opaque server-specific item identifier. WithSig-CreateRoom: type: object properties: sig: type: string signee: type: object properties: nonce: type: integer format: uint32 payload: type: object properties: typ: type: string const: 'create_room' title: type: string members: type: array items: type: object properties: user: type: string permission: type: integer format: int64 example: sig: 99a77e836538268839ed3419c649eefb043cb51d448f641cc2a1c523811aab4aacd09f92e7c0688ffd659bfc6acb764fea79979a491e132bf6a56dd23adc1d09 signee: nonce: 670593955 payload: typ: create_room attrs: 1 # PUBLIC_READABLE title: 'hello room' members: - user: 83ce46ced47ec0391c64846cbb6c507250ead4985b6a044d68751edc46015dd7 permission: -1 timestamp: 1724966284 user: 83ce46ced47ec0391c64846cbb6c507250ead4985b6a044d68751edc46015dd7