diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/api/authentication.md | 97 | ||||
| -rw-r--r-- | docs/api/boot.md | 108 | ||||
| -rw-r--r-- | docs/api/channels-messages.md | 52 | ||||
| -rw-r--r-- | docs/api/events.md | 145 | ||||
| -rw-r--r-- | docs/api/initial-setup.md | 38 | ||||
| -rw-r--r-- | docs/api/invitations.md | 102 |
6 files changed, 281 insertions, 261 deletions
diff --git a/docs/api/authentication.md b/docs/api/authentication.md index 93a8e52..7b5ebd7 100644 --- a/docs/api/authentication.md +++ b/docs/api/authentication.md @@ -11,43 +11,45 @@ stateDiagram-v2 Authenticated --> Unauthenticated : Token expired ``` -Authentication associates each authenticated request with a login. +Authentication associates each authenticated request with a user. -To create logins, see [initial setup](./initial-setup.md) and [invitations](./invitations.md). +To create users, see [initial setup](./initial-setup.md) and [invitations](./invitations.md). ## Names <!-- This prose is duplicated in channels-messages.md. If you change it here, consider changing it there, too. --> -The service handles login names using two separate forms. +The service handles user names using two separate forms. -The first form is as given in the request used to create the login. This form of the login name is used throughout the API, and the service will preserve the name as entered (other than applying normalization), so that users' preferences around capitalization and accent marks are preserved. +The first form is as given in the request used to create the user. This form of the use name is used throughout the API, and the service will preserve the name as entered (other than applying normalization), so that users' preferences around capitalization and accent marks are preserved. -The second form is a "canonical" form, used internally by the service to control uniqueness and match names to logins. The canonical form is both case-folded and normalized. +The second form is a "canonical" form, used internally by the service to control uniqueness and match names to users. The canonical form is both case-folded and normalized. The canonical form is not available to API clients, but its use has practical consequences: -* Names that differ only by case or only by code point sequence are treated as the same name. If the name is in use, changing the capitalization or changing the sequence of combining marks will not allow the creation of a second "identical" login. -* The login API accepts any name that canonicalizes to the form stored in the database, making login names effectively case-insensitive. - +* Names that differ only by case or only by code point sequence are treated as the same name. If the name is in use, changing the capitalization or changing the sequence of combining marks will not allow the creation of a second "identical" user. +* The login API accepts any name that canonicalizes to the form stored in the database, making user names effectively case-insensitive and composition-insensitive. ## Identity tokens -A login is primarily authenticated using its username and password. However, passwords are a sensitive, long-lived credential, and are also operationally expensive to verify; for routine access, requests are authenticated using an identity token, instead. +A user is primarily authenticated using its username and password. However, passwords are a sensitive, long-lived credential, and are also operationally expensive to verify; for routine access, requests are authenticated using an identity token, instead. -Tokens are issued by logging into the service, using the `/api/auth/login` endpoint. The `/api/auth/logout` endpoint immediately invalidates the token used to make a request to it. Tokens are also invalidated after seven days of inactivity. +Tokens are issued by logging into the service, using the `/api/auth/login` endpoint. The +`/api/auth/logout` endpoint immediately invalidates the token used to make a request to it. Tokens are also invalidated after seven days of inactivity. -To authenticate a request, include `cookie: identity=TOKEN SECRET` header in the request. For browser-based clients, this may happen automatically. +To authenticate a request, include +`cookie: identity=TOKEN SECRET` header in the request. For browser-based clients, this may happen automatically. ## Authentication failures -Unless the endpoint's documentation says otherwise, all endpoints require authentication. Making a request to any endpoint that requires authentication, either without a token, or with a token that is not valid or that has expired, causes the service to return a `401 Unauthorized` response, instead of the responses documented for the endpoint the request was intended for. The API will not take action on requests that fail authentication in this way. +Unless the endpoint's documentation says otherwise, all endpoints require authentication. Making a request to any endpoint that requires authentication, either without a token, or with a token that is not valid or that has expired, causes the service to return a +`401 Unauthorized` response, instead of the responses documented for the endpoint the request was intended for. The API will not take action on requests that fail authentication in this way. ## `POST /api/auth/login` -Authenticates the user using their login name and password. The login must exist before calling this endpoint. +Authenticates the user using their name and password. The user must exist before calling this endpoint. **This endpoint does not require an `identity` cookie.** @@ -55,50 +57,53 @@ Authenticates the user using their login name and password. The login must exist ```json { - "name": "example username", - "password": "the plaintext password", + "name": "example username", + "password": "the plaintext password" } ``` The request must have the following fields: -| Field | Type | Description | -|:-----------|:-------|:--| -| `name` | string | The login's name. | +| Field | Type | Description | +|:-----------|:-------|:-------------------------------------| +| `name` | string | The login's name. | | `password` | string | The login's password, in plain text. | ### Success <!-- This prose is duplicated by 03-initial-setup.md and in 04-invitations.md, with small changes for context. If you edit it here, edit it there, too. --> -This endpoint will respond with a status of `200 Okay` when successful. The body of the response will be a JSON object describing the authenticated login: +This endpoint will respond with a status of +`200 Okay` when successful. The body of the response will be a JSON object describing the authenticated user: ```json { - "id": "Labcd1234", - "name": "Andrea" + "id": "Uabcd1234", + "name": "Andrea" } ``` The response will include the following fields: -| Field | Type | Description | -|:------------|:-------|:--| -| `id` | string | The authenticated login's ID. | -| `name` | string | The authenticated login's name. | +| Field | Type | Description | +|:-------|:-------|:-------------------------------| +| `id` | string | The authenticated user's ID. | +| `name` | string | The authenticated user's name. | -The response will include a `Set-Cookie` header for the `identity` cookie, providing the client with a newly-minted identity token associated with the login identified in the request. This token's value must be kept confidential. +The response will include a `Set-Cookie` header for the +`identity` cookie, providing the client with a newly-minted identity token associated with the user identified in the request. This token's value must be kept confidential. The cookie will expire if it is not used regularly. ### Authentication failure -This endpoint will respond with a status of `401 Unauthorized` if the login name and password do not correspond to an existing login. +This endpoint will respond with a status of +`401 Unauthorized` if the login name and password do not correspond to an existing user. ## `POST /api/auth/logout` -Invalidates the identity token used to make the request, logging the user out. +Invalidates the identity token used to make the request, logging the caller out. ### Request @@ -112,51 +117,55 @@ The request must be an empty JSON object. This endpoint will respond with a status of `204 No Content` when successful. -The response will include a `Set-Cookie` header that clears the `identity` cookie. Regardless of whether the client clears the cookie, the service also invalidates the token. +The response will include a `Set-Cookie` header that clears the +`identity` cookie. Regardless of whether the client clears the cookie, the service also invalidates the token. ## `POST /api/password` -Changes the current login's password, and invalidate all outstanding identity tokens. +Changes the current user's password, and invalidates all outstanding identity tokens. ### Request ```json { - "password": "my-old-password", - "to": "my-new-password" + "password": "my-old-password", + "to": "my-new-password" } ``` The request must have the following fields: -| Field | Type | Description | -|:-----------|:-------|:--| +| Field | Type | Description | +|:-----------|:-------|:-----------------------------------------------| | `password` | string | The login's _current_ password, in plain text. | -| `to` | string | The login's _new_ password, in plain text. | +| `to` | string | The login's _new_ password, in plain text. | ### Success -This endpoint will respond with a status of `200 Okay` when successful. The body of the response will be a JSON object describing the authenticated login: +This endpoint will respond with a status of +`200 Okay` when successful. The body of the response will be a JSON object describing the authenticated user: ```json { - "id": "Labcd1234", - "name": "Andrea" + "id": "Uabcd1234", + "name": "Andrea" } ``` The response will include the following fields: -| Field | Type | Description | -|:------------|:-------|:--| -| `id` | string | The authenticated login's ID. | -| `name` | string | The authenticated login's name. | +| Field | Type | Description | +|:-------|:-------|:-------------------------------| +| `id` | string | The authenticated user's ID. | +| `name` | string | The authenticated user's name. | -The response will include a `Set-Cookie` header for the `identity` cookie, providing the client with a newly-minted identity token associated with the login identified in the request. This token's value must be kept confidential. All previously-created identity cookies will cease to be valid. +The response will include a `Set-Cookie` header for the +`identity` cookie, providing the client with a newly-minted identity token associated with the login identified in the request. This token's value must be kept confidential. All previously-created identity cookies will cease to be valid. The cookie will expire if it is not used regularly. ### Authentication failure -This endpoint will respond with a status of `400 Bad Request` if the `password` does not match the login's current password. +This endpoint will respond with a status of `400 Bad Request` if the +`password` does not match the login's current password. diff --git a/docs/api/boot.md b/docs/api/boot.md index 88f2d5b..0c2dc08 100644 --- a/docs/api/boot.md +++ b/docs/api/boot.md @@ -18,14 +18,12 @@ sequenceDiagram API <<->>- Andrea: Disconnect ``` - Client initialization serves three purposes: -* It confirms that the client's [identity token](./authentication.md) is valid, and tells the client what login that token is associated with. +* It confirms that the client's [identity token](./authentication.md) is valid, and tells the client what user that token is associated with. * It provides an initial snapshot of the state of the service. * It provides a resume point for the [event stream](./events.md), which allows clients to consume events starting from the moment the snapshot was created. - ## `GET /api/boot` Returns the information needed to initialize a client. @@ -34,77 +32,77 @@ This method is also the recommended way to validate the client's identity token, ### Success -This endpoint will respond with a status of `200 Okay` when successful. The body of the response will be a JSON object containing the initial state for the client: +This endpoint will respond with a status of +`200 Okay` when successful. The body of the response will be a JSON object containing the initial state for the client: ```json { - "login": { - "name": "example username", - "id": "L1234abcd", - }, - "resume_point": 1312, - "logins": [ - { - "id": "L1234abcd", - "name": "example username" - } - ], - "channels": [ - { - "name": "nonsense and such", - "id": "C1234abcd", - } - ], - "messages": [ - { - "at": "2024-09-27T23:19:10.208147Z", - "channel": "C1234abcd", - "sender": "L1234abcd", - "id": "M1312acab", - "body": "beep" - } - ] + "user": { + "name": "example username", + "id": "U1234abcd" + }, + "resume_point": 1312, + "users": [ + { + "id": "U1234abcd", + "name": "example username" + } + ], + "channels": [ + { + "name": "nonsense and such", + "id": "C1234abcd" + } + ], + "messages": [ + { + "at": "2024-09-27T23:19:10.208147Z", + "channel": "C1234abcd", + "sender": "U1234abcd", + "id": "M1312acab", + "body": "beep" + } + ] } ``` The response will include the following fields: -| Field | Type | Description | -|:---------------|:----------------|:--| -| `login` | object | The details of the caller's identity. | +| Field | Type | Description | +|:---------------|:----------------|:-------------------------------------------------------------------------------------------------------------------------| +| `user` | object | The details of the caller's identity. | | `resume_point` | integer | A resume point for [events](./events.md), such that the event stream will begin immediately after the included snapshot. | -| `logins` | array of object | A snapshot of the logins present in the service. | -| `channels` | array of object | A snapshot of the channels present in the service. | -| `messages` | array of object | A snapshot of the messages present in the service. | +| `users` | array of object | A snapshot of the users present in the service. | +| `channels` | array of object | A snapshot of the channels present in the service. | +| `messages` | array of object | A snapshot of the messages present in the service. | -The `login` object will include the following fields: +The `user` object will include the following fields: -| Field | Type | Description | -|:-------|:-------|:--| +| Field | Type | Description | +|:-------|:-------|:-----------------------------------------| | `name` | string | The name of the caller's login identity. | -| `id` | string | The ID of the caller's login identity. | - +| `id` | string | The ID of the caller's login identity. | -Each element of the `logins` array describes a distinct login, and will include the following fields: +Each element of the `users` array describes a distinct user, and will include the following fields: -| Field | Type | Description | -|:-------|:-------|:--| -| `name` | string | The name for the login. | -| `id` | string | A unique identifier for the login. This can be used to associate the login with other events, or to make API calls targeting the login. | +| Field | Type | Description | +|:-------|:-------|:-------------------------------------------------------------------------------------------------------------------------------------| +| `name` | string | The name for the user. | +| `id` | string | A unique identifier for the user. This can be used to associate the user with other events, or to make API calls targeting the user. | Each element of the `channels` array describes a distinct channel, and will include the following fields: -| Field | Type | Description | -|:-------|:-------|:--| -| `name` | string | The name for the channel. | +| Field | Type | Description | +|:-------|:-------|:----------------------------------------------------------------------------------------------------------------------------------------------| +| `name` | string | The name for the channel. | | `id` | string | A unique identifier for the channel. This can be used to associate the channel with other events, or to make API calls targeting the channel. | Each element of the `messages` array describes a distinct message, and will include the following fields: -| Field | Type | Description | -|:----------|:----------|:--| -| `at` | timestamp | The moment the message was sent. | -| `channel` | string | The ID of the channel the message was sent to. | -| `sender` | string | The ID of the login that sent the message. | +| Field | Type | Description | +|:----------|:----------|:----------------------------------------------------------------------------------------------------------------------------------------------| +| `at` | timestamp | The moment the message was sent. | +| `channel` | string | The ID of the channel the message was sent to. | +| `sender` | string | The ID of the user that sent the message. | | `id` | string | A unique identifier for the message. This can be used to associate the message with other events, or to make API calls targeting the message. | -| `body` | string | The text of the message. | +| `body` | string | The text of the message. | diff --git a/docs/api/channels-messages.md b/docs/api/channels-messages.md index a3c90be..c5b90ab 100644 --- a/docs/api/channels-messages.md +++ b/docs/api/channels-messages.md @@ -31,25 +31,17 @@ Every channel has a unique name, chosen when the channel is created. <!-- This prose is duplicated in authentication.md. If you change it here, consider changing it there, too. --> The service handles channel names using two separate forms. -The first form is as given in the request used to create the channel. This form of the channel name is used throughout -the API, and the service will preserve the name as entered (other than applying normalization), so that users' -preferences around capitalization and accent marks are preserved. +The first form is as given in the request used to create the channel. This form of the channel name is used throughout the API, and the service will preserve the name as entered (other than applying normalization), so that users' preferences around capitalization and accent marks are preserved. -The second form is a "canonical" form, used internally by the service to control uniqueness and match names to channels. -The canonical form is both case-folded and normalized. +The second form is a "canonical" form, used internally by the service to control uniqueness and match names to channels. The canonical form is both case-folded and normalized. -The canonical form is not available to API clients, but its use has practical consequences. Names that differ only by -case or only by code point sequence are treated as the same name. If the name is in use, changing the capitalization or -changing the sequence of combining marks will not allow the creation of a second "identical" channel. +The canonical form is not available to API clients, but its use has practical consequences. Names that differ only by case or only by code point sequence are treated as the same name. If the name is in use, changing the capitalization or changing the sequence of combining marks will not allow the creation of a second "identical" channel. ## Expiry and purging -Both channels and messages expire after a time. Messages expire 90 days after being sent. Channels expire 90 days after -the last message sent to them, or after creation if no messages are sent in that time. +Both channels and messages expire after a time. Messages expire 90 days after being sent. Channels expire 90 days after the last message sent to them, or after creation if no messages are sent in that time. -Deleted channels and messages, including those that have expired, are temporarily retained by the service, to allow -clients that are not connected to receive the corresponding deletion [events](./events.md). To limit storage growth, -deleted channels and messages are purged from the service seven days after they were deleted. +Deleted channels and messages, including those that have expired, are temporarily retained by the service, to allow clients that are not connected to receive the corresponding deletion [events](./events.md). To limit storage growth, deleted channels and messages are purged from the service seven days after they were deleted. ## `POST /api/channels` @@ -79,8 +71,8 @@ The proposed `name` must be valid. The precise definition of valid is still up i ### Success -This endpoint will respond with a status of `202 Accepted` when successful. The body of the response will be a JSON -object describing the new channel: +This endpoint will respond with a status of +`202 Accepted` when successful. The body of the response will be a JSON object describing the new channel: ```json { @@ -96,9 +88,7 @@ The response will have the following fields: | `id` | string | A unique identifier for the channel. This can be used to associate the channel with events, or to make API calls targeting the channel. | | `name` | string | The channel's name. | -The returned name may not be identical to the name requested, as the name will be converted -to [normalization form C](http://www.unicode.org/reports/tr15/) automatically. The returned name will include this -normalization; the service will use the normalized name elsewhere, and does not store the originally requested name. +The returned name may not be identical to the name requested, as the name will be converted to [normalization form C](http://www.unicode.org/reports/tr15/) automatically. The returned name will include this normalization; the service will use the normalized name elsewhere, and does not store the originally requested name. When completed, the service will emit a [channel created](events.md#channel-created) event with the channel's ID. @@ -136,14 +126,14 @@ The request must have the following fields: ### Success -This endpoint will respond with a status of `202 Accepted` when successful. The body of the response will be a JSON -object describing the newly-sent message: +This endpoint will respond with a status of +`202 Accepted` when successful. The body of the response will be a JSON object describing the newly-sent message: ```json { "at": "2024-10-19T04:37:09.467325Z", "channel": "Cfqdn1234", - "sender": "Labcd1234", + "sender": "Uabcd1234", "id": "Mgh98yp75", "body": "an elaborate example message" } @@ -155,13 +145,11 @@ The response will have the following fields: |:----------|:----------|:----------------------------------------------------------------------------------------------------------------------------------------| | `at` | timestamp | The moment the message was sent. | | `channel` | string | The ID of the channel the message was sent to. | -| `sender` | string | The ID of the login that sent the message. | +| `sender` | string | The ID of the user that sent the message. | | `id` | string | A unique identifier for the message. This can be used to associate the message with events, or to make API calls targeting the message. | | `body` | string | The message's body. | -The returned message body may not be identical to the body as sent, as the body will be converted -to [normalization form C](http://www.unicode.org/reports/tr15/) automatically. The returned body will include this -normalization; the service will use the normalized body elsewhere, and does not store the originally submitted body. +The returned message body may not be identical to the body as sent, as the body will be converted to [normalization form C](http://www.unicode.org/reports/tr15/) automatically. The returned body will include this normalization; the service will use the normalized body elsewhere, and does not store the originally submitted body. When completed, the service will emit a [message sent](events.md#message-sent) event with the message's ID. @@ -173,8 +161,7 @@ This endpoint will respond with a status of `404 Not Found` if the channel ID is Deletes a channel. -Deleting a channel prevents it from receiving any further messages. The channel must be empty; to delete a channel with -messages in it, delete the messages first (or wait for them to expire). +Deleting a channel prevents it from receiving any further messages. The channel must be empty; to delete a channel with messages in it, delete the messages first (or wait for them to expire). This endpoint requires the following path parameter: @@ -184,8 +171,8 @@ This endpoint requires the following path parameter: ### Success -This endpoint will respond with a status of `202 Accepted` when successful. The body of the response will be a JSON -object describing the deleted channel: +This endpoint will respond with a status of +`202 Accepted` when successful. The body of the response will be a JSON object describing the deleted channel: ```json { @@ -199,8 +186,7 @@ The response will have the following fields: |:------|:-------|:------------------| | `id` | string | The channel's ID. | -When completed, the service will emit a [message deleted](events.md#message-deleted) event for each message in the -channel, followed by a [channel deleted](events.md#channel-deleted) event with the channel's ID. +When completed, the service will emit a [message deleted](events.md#message-deleted) event for each message in the channel, followed by a [channel deleted](events.md#channel-deleted) event with the channel's ID. ### Channel not empty @@ -222,8 +208,8 @@ This endpoint requires the following path parameter: ### Success -This endpoint will respond with a status of `202 Accepted` when successful. The body of the response will be a JSON -object describing the deleted message: +This endpoint will respond with a status of +`202 Accepted` when successful. The body of the response will be a JSON object describing the deleted message: ```json { diff --git a/docs/api/events.md b/docs/api/events.md index b23469c..3347a26 100644 --- a/docs/api/events.md +++ b/docs/api/events.md @@ -28,12 +28,14 @@ sequenceDiagram end ``` -The core of the service is to facilitate conversations between logins. Conversational activity is delivered to clients using _events_. Each event notifies interested clients of activity sent to the service through its API. +The core of the service is to facilitate conversations between users. Conversational activity is delivered to clients using +_events_. Each event notifies interested clients of activity sent to the service through its API. ## Asynchronous completion -A number of endpoints return `202 Accepted` responses. The actions performed by those endpoints will be completed before events are delivered. To await the completion of an operation which returns this response, clients must monitor the event stream for the corresponding event. +A number of endpoints return +`202 Accepted` responses. The actions performed by those endpoints will be completed before events are delivered. To await the completion of an operation which returns this response, clients must monitor the event stream for the corresponding event. ## `GET /api/events` @@ -46,11 +48,14 @@ This endpoint is designed for use with the [EventSource] DOM API, and supports s ### Query parameters -This endpoint requires a `resume_point` (integer) query parameter. The event stream will collect events published after that point in time. The value must be obtained by calling the [`GET /api/boot`](./boot.md) method. +This endpoint requires a +`resume_point` (integer) query parameter. The event stream will collect events published after that point in time. The value must be obtained by calling the [ +`GET /api/boot`](./boot.md) method. ### Request headers -This endpoint accepts an optional `last-event-id` (string) header. If present, the value must be the value of the `id` field of the last message processed by the client. The returned event stream will begin with the following message. If absent, the returned event stream will begin from the start of the event collection. +This endpoint accepts an optional `last-event-id` (string) header. If present, the value must be the value of the +`id` field of the last message processed by the client. The returned event stream will begin with the following message. If absent, the returned event stream will begin from the start of the event collection. This header is set automatically by `EventSource` when reconnecting to an event stream. @@ -67,7 +72,7 @@ data: "type": "message", data: "event": "sent", data: "at": "2024-09-27T23:19:10.208147Z", data: "channel": "C9876cyyz", -data: "sender": "L1234abcd", +data: "sender": "U1234abcd", data: "id": "M1312acab", data: "body": "beep" data: } @@ -75,46 +80,47 @@ data: } The service will keep the connection open, and will deliver events as they occur. -The service may terminate the connection at any time. Clients should reconnect and resume the stream, using the `last-event-id` header to resume from the last message received. The `id` of each event is an ephemeral ID, useful only for this purpose. +The service may terminate the connection at any time. Clients should reconnect and resume the stream, using the +`last-event-id` header to resume from the last message received. The +`id` of each event is an ephemeral ID, useful only for this purpose. Each event's `data` consists of a JSON object describing one event. Every event includes the following fields: -| Field | Type | Description | -|:--------|:-------|:--| -| `type` | string | The type of entity the event describes. Will be one of the types listed in the next section. | +| Field | Type | Description | +|:--------|:-------|:-------------------------------------------------------------------------------------------------------------| +| `type` | string | The type of entity the event describes. Will be one of the types listed in the next section. | | `event` | string | The specific kind of event. Will be one of the events listed with the associated `type` in the next section. | The remaining fields depend on the `type` and `event` field. -## Login events +## User events -The following events describe changes to logins. +The following events describe changes to users. -These events have the `type` field set to `"login"`. +These events have the `type` field set to `"user"`. -### Login created +### User created ```json { - "type": "login", - "event": "created", - "at": "2024-09-27T23:17:10.208147Z", - "id": "L1234abcd", - "name": "example username" + "type": "user", + "event": "created", + "at": "2024-09-27T23:17:10.208147Z", + "id": "U1234abcd", + "name": "example username" } ``` -Sent whenever a new login is created. +Sent whenever a new user is created. These events have the `event` field set to `"created"`. They include the following additional fields: -| Field | Type | Description | -|:-------|:----------|:--| -| `at` | timestamp | The moment the login was created. | -| `id` | string | A unique identifier for the newly-created login. This can be used to associate the login with other events, or to make API calls targeting the login. | -| `name` | string | The login's name. | - +| Field | Type | Description | +|:-------|:----------|:---------------------------------------------------------------------------------------------------------------------------------------------------| +| `at` | timestamp | The moment the user was created. | +| `id` | string | A unique identifier for the newly-created user. This can be used to associate the user with other events, or to make API calls targeting the user. | +| `name` | string | The user's name. | ## Channel events @@ -126,11 +132,11 @@ These events have the `type` field set to `"channel"`. ```json { - "type": "channel", - "event": "created", - "at": "2024-09-27T23:18:10.208147Z", - "id": "C9876cyyz", - "name": "example channel 2" + "type": "channel", + "event": "created", + "at": "2024-09-27T23:18:10.208147Z", + "id": "C9876cyyz", + "name": "example channel 2" } ``` @@ -138,14 +144,18 @@ Sent whenever a new channel is created. These events have the `event` field set to `"created"`. They include the following additional fields: -| Field | Type | Description | -|:-------------|:--------------------|:--| -| `at` | timestamp | The moment the channel was created. | +| Field | Type | Description | +|:-------------|:--------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `at` | timestamp | The moment the channel was created. | | `id` | string | A unique identifier for the newly-created channel. This can be used to associate the channel with other events, or to make API calls targeting the channel. | -| `name` | string | The channel's name. | -| `deleted_at` | timestamp, optional | If set, the moment the channel was deleted. | +| `name` | string | The channel's name. | +| `deleted_at` | timestamp, optional | If set, the moment the channel was deleted. | -When a channel is deleted or expires, the `"created"` event is replaced with a tombstone `"created"` event, so that the original channel cannot be trivially recovered from the event stream. Tombstone events have a `deleted_at` field, and a `name` of `""`. Tombstone events for channels use an empty string as the name, and not `null` or with the `name` field removed entirely, to simplify client development. While clients _should_ treat deleted channels specially, for example by rendering them as "channel deleted" markers, they don't have to be - they make sense if interpreted as channels with empty names, too. +When a channel is deleted or expires, the `"created"` event is replaced with a tombstone +`"created"` event, so that the original channel cannot be trivially recovered from the event stream. Tombstone events have a +`deleted_at` field, and a `name` of `""`. Tombstone events for channels use an empty string as the name, and not +`null` or with the `name` field removed entirely, to simplify client development. While clients +_should_ treat deleted channels specially, for example by rendering them as "channel deleted" markers, they don't have to be - they make sense if interpreted as channels with empty names, too. Once a deleted channel is [purged](./channels-messages.md#expiry-and-purging), these tombstone events are removed from the event stream. @@ -153,10 +163,10 @@ Once a deleted channel is [purged](./channels-messages.md#expiry-and-purging), t ```json { - "type": "channel", - "event": "deleted", - "at": "2024-09-28T03:40:25.384318Z", - "id": "C9876cyyz" + "type": "channel", + "event": "deleted", + "at": "2024-09-28T03:40:25.384318Z", + "id": "C9876cyyz" } ``` @@ -164,11 +174,10 @@ Sent whenever a channel is deleted or expires. These events have the `event` field set to `"deleted"`. They include the following additional fields: -| Field | Type | Description | -|:------|:----------|:--| +| Field | Type | Description | +|:------|:----------|:------------------------------------| | `at` | timestamp | The moment the channel was deleted. | -| `id` | string | The deleted channel's ID. | - +| `id` | string | The deleted channel's ID. | ## Message events @@ -180,13 +189,13 @@ These events have the `type` field set to `"message"`. ```json { - "type": "message", - "event": "sent", - "at": "2024-09-27T23:19:10.208147Z", - "channel": "C9876cyyz", - "sender": "L1234abcd", - "id": "M1312acab", - "body": "an effusive blob of prose, condensed down to a single string" + "type": "message", + "event": "sent", + "at": "2024-09-27T23:19:10.208147Z", + "channel": "C9876cyyz", + "sender": "U1234abcd", + "id": "M1312acab", + "body": "an effusive blob of prose, condensed down to a single string" } ``` @@ -194,16 +203,20 @@ Sent whenever a message is sent by a client. These events have the `event` field set to `"sent"`. They include the following additional fields: -| Field | Type | Description | -|:-------------|:--------------------|:--| -| `at` | timestamp | The moment the message was sent. | -| `channel` | string | The ID of the channel the message was sent to. | -| `sender` | string | The ID of the login that sent the message. | +| Field | Type | Description | +|:-------------|:--------------------|:----------------------------------------------------------------------------------------------------------------------------------------------| +| `at` | timestamp | The moment the message was sent. | +| `channel` | string | The ID of the channel the message was sent to. | +| `sender` | string | The ID of the user that sent the message. | | `id` | string | A unique identifier for the message. This can be used to associate the message with other events, or to make API calls targeting the message. | -| `body` | string | The text of the message. | -| `deleted_at` | timestamp, optional | If set, the moment the message was deleted. | +| `body` | string | The text of the message. | +| `deleted_at` | timestamp, optional | If set, the moment the message was deleted. | -When a message is deleted or expires, the `"sent"` event is replaced with a tombstone `"sent"` event, so that the original message cannot be trivially recovered from the event stream. Tombstone events have a `deleted_at` field, and a `body` of `""`. Tombstone events for messages use an empty string as the `body`, and not `null` or with the `body` field removed entirely, to simplify client development. While clients _should_ treat deleted messages specially, for example by rendering them as "message deleted" markers, they don't have to be - they make sense if interpreted as messages with empty bodies, too. +When a message is deleted or expires, the `"sent"` event is replaced with a tombstone +`"sent"` event, so that the original message cannot be trivially recovered from the event stream. Tombstone events have a +`deleted_at` field, and a `body` of `""`. Tombstone events for messages use an empty string as the `body`, and not +`null` or with the `body` field removed entirely, to simplify client development. While clients +_should_ treat deleted messages specially, for example by rendering them as "message deleted" markers, they don't have to be - they make sense if interpreted as messages with empty bodies, too. Once a deleted message is [purged](./channels-messages.md#expiry-and-purging), these tombstone events are removed from the event stream. @@ -211,10 +224,10 @@ Once a deleted message is [purged](./channels-messages.md#expiry-and-purging), t ```json { - "type": "message", - "event": "deleted", - "at": "2024-09-28T02:44:27.077355Z", - "id": "M1312acab" + "type": "message", + "event": "deleted", + "at": "2024-09-28T02:44:27.077355Z", + "id": "M1312acab" } ``` @@ -222,7 +235,7 @@ Sent whenever a message is deleted or expires. These events have the `event` field set to `"deleted"`. They include the following additional fields: -| Field | Type | Description | -|:------|:----------|:--| +| Field | Type | Description | +|:------|:----------|:------------------------------------| | `at` | timestamp | The moment the message was deleted. | -| `id` | string | The deleted message's ID. | +| `id` | string | The deleted message's ID. | diff --git a/docs/api/initial-setup.md b/docs/api/initial-setup.md index c2bdaec..0179397 100644 --- a/docs/api/initial-setup.md +++ b/docs/api/initial-setup.md @@ -18,7 +18,8 @@ New instances of this service require an initial setup step before they can full ## Requests before setup completed -Before the service is set up, all API endpoints, other than those specifically documented as exceptions, will return a status of `503 Service Unavailable` to all requests. +Before the service is set up, all API endpoints, other than those specifically documented as exceptions, will return a status of +`503 Service Unavailable` to all requests. Initial setup can be completed only once. @@ -27,9 +28,9 @@ Initial setup can be completed only once. Initial setup performs the following tasks: -* Create the first login for the service. +* Create the first user for the service. - This is the only login that does not require an [invitation](./invitations.md). + This is the only user that does not require an [invitation](./invitations.md). **This endpoint does not require an `identity` cookie.** @@ -39,16 +40,16 @@ Initial setup performs the following tasks: ```json { - "name": "example username", - "password": "the plaintext password", + "name": "example username", + "password": "the plaintext password" } ``` The request must have the following fields: -| Field | Type | Description | -|:-----------|:-------|:--| -| `name` | string | The initial login's name. | +| Field | Type | Description | +|:-----------|:-------|:---------------------------------------------| +| `name` | string | The initial login's name. | | `password` | string | The initial login's password, in plain text. | <!-- Reproduced in invitations.md. Edit in both places. --> @@ -65,27 +66,29 @@ The proposed `name` must be valid. The precise definition of valid is still up i <!-- This prose is duplicated from authentication.md, with small changes for context. If you edit it here, edit it there, too. --> -This endpoint will respond with a status of `200 Okay` when successful. The body of the response will be a JSON object describing the newly-created login: +This endpoint will respond with a status of +`200 Okay` when successful. The body of the response will be a JSON object describing the newly-created user: ```json { - "id": "Labcd1234", - "name": "Andrea" + "id": "Uabcd1234", + "name": "Andrea" } ``` The response will include the following fields: -| Field | Type | Description | -|:------------|:-------|:--| -| `id` | string | A unique identifier for the newly-created login. This can be used to associate the login with other events, or to make API calls targeting the login. | -| `name` | string | The login's name. | +| Field | Type | Description | +|:-------|:-------|:---------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | string | A unique identifier for the newly-created user. This can be used to associate the user with other events, or to make API calls targeting the user. | +| `name` | string | The user's name. | The returned name may not be identical to the name requested, as the name will be converted to [normalization form C](http://www.unicode.org/reports/tr15/) automatically. The returned name will include this normalization; the service will use the normalized name elsewhere, and does not store the originally requested name. The provided password will also be converted to normalization form C. However, the normalized password is not returned to the client. -The response will include a `Set-Cookie` header for the `identity` cookie, providing the client with a newly-minted identity token associated with the initial login created for this request. See the [authentication](./authentication) section for details on how this cookie may be used. +The response will include a `Set-Cookie` header for the +`identity` cookie, providing the client with a newly-minted identity token associated with the initial user created for this request. See the [authentication](./authentication) section for details on how this cookie may be used. The cookie will expire if it is not used regularly. @@ -95,5 +98,6 @@ This endpoint will respond with a status of `400 Bad Request` if the proposed `n ### Setup previously completed -Once completed, this operation cannot be performed a second time. Subsequent requests to this endpoint will respond with a status of `409 Conflict`. +Once completed, this operation cannot be performed a second time. Subsequent requests to this endpoint will respond with a status of +`409 Conflict`. diff --git a/docs/api/invitations.md b/docs/api/invitations.md index 1839ef5..0be2c2e 100644 --- a/docs/api/invitations.md +++ b/docs/api/invitations.md @@ -21,9 +21,9 @@ sequenceDiagram API -->>- Blake : Success ``` -Other than the login created during [initial setup](./initial-setup.md), new logins can only be created by using invitations. +Other than the user created during [initial setup](./initial-setup.md), new users can only be created by using invitations. -Any login can create invitations. Each invitation can be accepted at most once. An invitation which is not accepted within 24 hours expires. +Any user can create invitations. Each invitation can be accepted at most once. An invitation which is not accepted within 24 hours expires. ## `POST /api/invite` @@ -40,25 +40,27 @@ The request must be an empty JSON object. ### Success -This endpoint will respond with a status of `200 Okay` when successful. The body of the response will be a JSON object describing the new invitation: +This endpoint will respond with a status of +`200 Okay` when successful. The body of the response will be a JSON object describing the new invitation: ```json { - "id": "I3884", - "issuer": "Labcd1234", - "issued_at": "2024-10-12T01:43:12.001853Z" + "id": "I3884", + "issuer": "Uabcd1234", + "issued_at": "2024-10-12T01:43:12.001853Z" } ``` The response will include the following fields: -| Field | Type | Description | -|:------------|:-------|:--| +| Field | Type | Description | +|:------------|:-------|:------------------------------------------------------------------------------| | `id` | string | A unique identifier for the invitation. This ID must be given to the invitee. | -| `issuer` | string | The login ID of the invitation's issuer. | -| `issued_at` | string | The timestamp from which the invitation will expire. | +| `issuer` | string | The user ID of the invitation's issuer. | +| `issued_at` | string | The timestamp from which the invitation will expire. | -Clients and their operators are responsible for delivering the invitation to the invitee. Clients are strongly recommended to construct a URL for the invitation so that the invitee can take action on it easily. The included client supports URLs of the format `https://example.net/invite/:id` (with the `:id` placeholder substituted with the invitation's ID). +Clients and their operators are responsible for delivering the invitation to the invitee. Clients are strongly recommended to construct a URL for the invitation so that the invitee can take action on it easily. The included client supports URLs of the format +`https://example.net/invite/:id` (with the `:id` placeholder substituted with the invitation's ID). ## `GET /api/invite/:id` @@ -67,50 +69,53 @@ Returns information about an outstanding invitation. This endpoint requires the following path parameter: -| Parameter | Type | Description | -|:----------|:-------|:--| -| `id` | string | An invitation ID, as returned from a previous request to `POST /api/invite`. | +| Parameter | Type | Description | +|:----------|:-------|:-----------------------------------------------------------------------------| +| `id` | string | An invitation ID, as returned from a previous request to `POST /api/invite`. | **This endpoint does not require an `identity` cookie.** ### On success -This endpoint will respond with a status of `200 Okay` when successful. The body of the response will be a JSON object describing the invitation: +This endpoint will respond with a status of +`200 Okay` when successful. The body of the response will be a JSON object describing the invitation: ```json { - "issuer": { - "id": "Labcd1234", - "name": "i send you invites" - }, - "issued_at": "2024-10-12T01:43:12.001853Z" + "issuer": { + "id": "Uabcd1234", + "name": "i send you invites" + }, + "issued_at": "2024-10-12T01:43:12.001853Z" } ``` The response will include the following fields: -| Field | Type | Description | -|:------------|:-------|:--| -| `id` | string | The ID of the invitation. | -| `issuer` | string | The login name of the invitation's issuer. | +| Field | Type | Description | +|:------------|:-------|:-----------------------------------------------------| +| `id` | string | The ID of the invitation. | +| `issuer` | string | The name of the invitation's issuer. | | `issued_at` | string | The timestamp from which the invitation will expire. | -Clients should present the `issuer` to the user when presenting an invitation, so as to personalize the invitation and help them understand their connection with the service. +Clients should present the +`issuer` to the user when presenting an invitation, so as to personalize the invitation and help them understand their connection with the service. ### Invitation not found -This endpoint will respond with a status of `404 Not Found` when the invitation ID either does not exist, or has already been accepted. +This endpoint will respond with a status of +`404 Not Found` when the invitation ID either does not exist, or has already been accepted. ## `POST /api/invite/:id` -Accepts an invitation and creates a new login. +Accepts an invitation and creates a new user. This endpoint requires the following path parameter: -| Parameter | Type | Description | -|:----------|:-------|:--| -| `id` | string | An invitation ID, as returned from a previous request to `POST /api/invite`. | +| Parameter | Type | Description | +|:----------|:-------|:-----------------------------------------------------------------------------| +| `id` | string | An invitation ID, as returned from a previous request to `POST /api/invite`. | **This endpoint does not require an `identity` cookie.** @@ -118,17 +123,17 @@ This endpoint requires the following path parameter: ```json { - "name": "example login", - "password": "correct-horse-battery-staple" + "name": "example user", + "password": "correct-horse-battery-staple" } ``` The request must have the following fields: -| Field | Type | Description | -|:-----------|:-------|:--| -| `name` | string | The new login's name. | -| `password` | string | The new login's password, in plain text. | +| Field | Type | Description | +|:-----------|:-------|:----------------------------------------| +| `name` | string | The new user's name. | +| `password` | string | The new user's password, in plain text. | <!-- Reproduced in initial-setup.md. Edit in both places. --> The proposed `name` must be valid. The precise definition of valid is still up in the air, but, at minimum: @@ -143,40 +148,45 @@ The proposed `name` must be valid. The precise definition of valid is still up i <!-- This prose is duplicated from authentication.md, with small changes for context. If you edit it here, edit it there, too. --> -This endpoint will respond with a status of `200 Okay` when successful. The body of the response will be a JSON object describing the newly-created login: +This endpoint will respond with a status of +`200 Okay` when successful. The body of the response will be a JSON object describing the newly-created user: ```json { - "id": "Labcd1234", - "name": "Andrea" + "id": "Uabcd1234", + "name": "Andrea" } ``` The response will include the following fields: -| Field | Type | Description | -|:------------|:-------|:--| -| `id` | string | A unique identifier for the newly-created login. This can be used to associate the login with other events, or to make API calls targeting the login. | -| `name` | string | The login's name. | +| Field | Type | Description | +|:-------|:-------|:---------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | string | A unique identifier for the newly-created user. This can be used to associate the user with other events, or to make API calls targeting the user. | +| `name` | string | The user's name. | The returned name may not be identical to the name requested, as the name will be converted to [normalization form C](http://www.unicode.org/reports/tr15/) automatically. The returned name will include this normalization; the service will use the normalized name elsewhere, and does not store the originally requested name. The provided password will also be converted to normalization form C. However, the normalized password is not returned to the client. -The response will include a `Set-Cookie` header for the `identity` cookie, providing the client with a newly-minted identity token associated with the login created for this request. See the [authentication](./authentication.md) section for details on how this cookie may be used. +The response will include a `Set-Cookie` header for the +`identity` cookie, providing the client with a newly-minted identity token associated with the login created for this request. See the [authentication](./authentication.md) section for details on how this cookie may be used. The cookie will expire if it is not used regularly. ### Invitation not found -This endpoint will respond with a status of `404 Not Found` when the invitation ID either does not exist, or has already been accepted. +This endpoint will respond with a status of +`404 Not Found` when the invitation ID either does not exist, or has already been accepted. ### Name not valid This endpoint will respond with a status of `400 Bad Request` if the proposed `name` is not valid. +The invitation can be accepted with a different name. + ### Name in use -This endpoint will respond with a status of `409 Conflict` if the requested login name has already been taken. +This endpoint will respond with a status of `409 Conflict` if the requested `name` has already been taken. The invitation can be accepted with a different name. |
