mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2025-10-05 19:42:39 +02:00
Add basically API documentation
This commit is contained in:
parent
ab16134a8e
commit
d021497e52
149 changed files with 7811 additions and 39 deletions
53
docs/api/README.md
Normal file
53
docs/api/README.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
# TimeLimit Server API documentation
|
||||
|
||||
The client communicates with the server using HTTP(S) requests
|
||||
and a socket.io websocket connection.
|
||||
|
||||
All requests bodies (if any) and responses are encoded as JSON
|
||||
if not said otherwise.
|
||||
|
||||
## /admin
|
||||
|
||||
This endpoint is for the server administrator.
|
||||
Its interface is described at [admin.md](./admin.md).
|
||||
|
||||
## /auth
|
||||
|
||||
This endpoint is used for the user authentication.
|
||||
Its interface is described at [auth.md](./auth.md).
|
||||
|
||||
## /child
|
||||
|
||||
This endpoint is used for by devices which are used by a child.
|
||||
Its interface is described at [child.md](./child.md).
|
||||
|
||||
## /parent
|
||||
|
||||
This endpoint is used by devices which are used by a parent.
|
||||
Its interface is described at [parent.md](./parent.md).
|
||||
|
||||
## /purchase
|
||||
|
||||
This endpoint is used for handling purchases from the client.
|
||||
Its interface is described at [purchase.md](./purchase.md).
|
||||
|
||||
## /sync
|
||||
|
||||
This endpoint is used by clients for syncing.
|
||||
Its interface is described at [sync.md](./sync.md).
|
||||
|
||||
## GET /time
|
||||
|
||||
This endpoint returns the current time of the server
|
||||
as a Unix timestamp in milliseconds. This does not need
|
||||
any authentication.
|
||||
|
||||
The response is a object with the property ``ms`` whose
|
||||
value is the timestamp as number.
|
||||
|
||||
Example response: ``{"ms":1578311020747}``
|
||||
|
||||
## Websocket
|
||||
|
||||
The websocket is used for real time notifications from the server
|
||||
to the client. The protocol is described at [websocket.md](./websocket.md).
|
88
docs/api/admin.md
Normal file
88
docs/api/admin.md
Normal file
|
@ -0,0 +1,88 @@
|
|||
# /admin
|
||||
|
||||
This endpoint is for the server admin.
|
||||
|
||||
Due to that, it requires authentication using the HTTP basic authentication.
|
||||
The username can be anything, the password must be the configured admin token.
|
||||
|
||||
Additionally, this endpoint allows cross origin requests.
|
||||
|
||||
## GET /admin/status
|
||||
|
||||
Use this to get the server status.
|
||||
|
||||
## Response
|
||||
|
||||
This returns a JSON object with ``websocketClients`` (of the type number,
|
||||
the number of clients connected using the websocket) and the map ``counters``
|
||||
which maps values to numbers. You should not make any assumptions about the counter names
|
||||
and their availability.
|
||||
|
||||
### example response
|
||||
|
||||
```
|
||||
{
|
||||
"websocketClients": 3,
|
||||
"counters": {
|
||||
"testCounter": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## POST /admin/reset-counters
|
||||
|
||||
Use this to reset the counters included in the server status.
|
||||
|
||||
Although this uses POST, it does not take any request body
|
||||
|
||||
Response: ``{"ok": true}``
|
||||
|
||||
## GET /admin/status-message
|
||||
|
||||
Use this to get the current status message.
|
||||
|
||||
This returns a object with the key ``statusMessage`` whose value
|
||||
of the type string is the current status message.
|
||||
|
||||
Example response: ``{"statusMessage":""}``
|
||||
|
||||
### see
|
||||
|
||||
- [status message concept](../concept/status-message.md)
|
||||
|
||||
## POST /admin/status-message
|
||||
|
||||
Use this to set the status message.
|
||||
|
||||
Request body: object with ``message`` (string)
|
||||
|
||||
Response: ``{"ok": true}``
|
||||
|
||||
### see
|
||||
|
||||
- [status message concept](../concept/status-message.md)
|
||||
|
||||
## POST /admin/unlock-premium
|
||||
|
||||
Use this to unlock all features for one user for a specified duration.
|
||||
|
||||
### request
|
||||
|
||||
request properties: ``mail`` and ``duration``
|
||||
|
||||
- ``duration`` must be ``year`` or ``month``
|
||||
- ``mail`` must be a mail address of any user assigned to the family for which the features should be unlocked
|
||||
|
||||
### response
|
||||
|
||||
If everything worked:
|
||||
|
||||
``{"ok": true}``
|
||||
|
||||
If the duration was invalid or no mail address was specified: HTTP status code 400 Bad Request
|
||||
|
||||
If there was nothing found for the mail address: HTTP status code 409 Conflict
|
||||
|
||||
### see
|
||||
|
||||
- [premium concept](../concept/premium.md)
|
86
docs/api/auth.md
Normal file
86
docs/api/auth.md
Normal file
|
@ -0,0 +1,86 @@
|
|||
# /auth
|
||||
|
||||
This endpoint is for the user authentication.
|
||||
|
||||
For this, mail addresses are used. The user starts
|
||||
a authentication flow by sending the mail address.
|
||||
Then the caller gets a mail login token and a
|
||||
code is sent to the specified mail address.
|
||||
After this, the caller can send the mail login token
|
||||
and the code received by mail to get a mail auth token which can be
|
||||
used at other APIs for creating a family, signing in into an existing family or
|
||||
recovering a password.
|
||||
|
||||
## POST /auth/send-mail-login-code-v2
|
||||
|
||||
Use this to start authenticating.
|
||||
|
||||
### Request
|
||||
|
||||
see [this JSON schema](../schema/sendmaillogincoderequest.md)
|
||||
|
||||
#### example request
|
||||
|
||||
```
|
||||
{
|
||||
"mail": "test@timelimit.io",
|
||||
"locale": "de"
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
If the request body is malformed or the mail address is invalid: HTTP status code 400 Bad Request
|
||||
|
||||
If the rate limit was exceeded: HTTP status code 429 Too Many Requests
|
||||
|
||||
If a whitelist was configured and the mail address is not within it: ``{"mailAddressNotWhitelisted": true}``
|
||||
|
||||
If a blacklist was configured and the mail server is within it: ``{"mailServerBlacklisted": true}``
|
||||
|
||||
On success: a object with a ``mailLoginToken`` of the type string
|
||||
|
||||
#### example response
|
||||
|
||||
```
|
||||
{
|
||||
"mailLoginToken": "dhdgfssgsdgd"
|
||||
}
|
||||
```
|
||||
|
||||
#### see
|
||||
|
||||
- [mail black and whitelist concept](../concept/mail-blackwhitelist.md)
|
||||
|
||||
## POST /auth/sign-in-by-mail-code
|
||||
|
||||
Use this to finish authenticating.
|
||||
|
||||
### Request
|
||||
|
||||
see [this JSON schema](../api/signinbymailcoderequest.md)
|
||||
|
||||
#### example request
|
||||
|
||||
```
|
||||
{
|
||||
"receivedCode": "ein test login",
|
||||
"mailLoginToken": "dhdgfssgsdgd"
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
If the request body is malformed: HTTP status code 400 Bad Request
|
||||
|
||||
If there were to many wrong attempts: HTTP status code 410 Gone
|
||||
|
||||
If the mail login token is unknown: HTTP status code 410 Gone
|
||||
|
||||
If the received code is wrong and it can be tried again: HTTP status code 403 Forbidden
|
||||
|
||||
On success: A object with a ``mailAuthToken`` of the type string
|
||||
|
||||
#### example response
|
||||
|
||||
``{"mailAuthToken": "wthdktjdejd"}``
|
79
docs/api/child.md
Normal file
79
docs/api/child.md
Normal file
|
@ -0,0 +1,79 @@
|
|||
# /child
|
||||
|
||||
This endpoint is used for by devices which are used by a child.
|
||||
|
||||
## POST /child/add-device
|
||||
|
||||
Use this during the setup to add a device to an existing family using an add device code.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/registerchilddevicerequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad request
|
||||
|
||||
On a invalid add device token: HTTP status code 401 Unauthorized
|
||||
|
||||
On success: a JSON object with the properties ``deviceAuthToken`` and ``ownDeviceId``,
|
||||
both of the type string
|
||||
|
||||
## POST /child/update-primary-device
|
||||
|
||||
Use this to (un)set the calling device as primary device.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/updateprimarydevicerequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad request
|
||||
|
||||
On a invalid auth token: HTTP status code 401 Unauthorized
|
||||
|
||||
If the transmitted ``currentUserId`` is empty or does not match the current user of the device:
|
||||
HTTP status code 409 Conflict
|
||||
|
||||
If the transmitted ``currentUserId`` does not match a valid user: HTTP status code 409 Conflict
|
||||
|
||||
If trying to unset the device as primary device and the device is not the current device of the user:
|
||||
HTTP status code 409 Conflict
|
||||
|
||||
Otherwise: a JSON object with the property ``status`` (string)
|
||||
|
||||
``status`` can have the following values:
|
||||
|
||||
- ``assigned to other device`` (if the user is assigned to an other device)
|
||||
- ``requires full version``
|
||||
- ``success``
|
||||
|
||||
### see
|
||||
|
||||
- [primary device concept](../concept/primary-device.md)
|
||||
|
||||
## POST /child/logout-at-primary-device
|
||||
|
||||
Use this to request unsetting the current primary device of the user
|
||||
which is currently assigned to the calling device. This triggers a websocket
|
||||
message to the current primary device of the user.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/requestwithauthtoken.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad request
|
||||
|
||||
On a invalid auth token: HTTP status code 401 Unauthorized
|
||||
|
||||
If there is no user assigned to the calling device or
|
||||
if there is no existing current primary device: HTTP status code 409 Conflict
|
||||
|
||||
On success: ``{"ok": true}``
|
||||
|
||||
### see
|
||||
|
||||
- [primary device concept](../concept/primary-device.md)
|
167
docs/api/parent.md
Normal file
167
docs/api/parent.md
Normal file
|
@ -0,0 +1,167 @@
|
|||
# /parent
|
||||
|
||||
This endpoint is used by devices which are used by a parent.
|
||||
|
||||
## see
|
||||
|
||||
- [auth API](./auth.md) for obtaining mail auth tokens which are needed at some APIs here
|
||||
|
||||
## POST /parent/get-status-by-mail-address
|
||||
|
||||
Use this to check the status of a mail auth token and the linked mail address.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/mailauthtokenrequestbody.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad Request
|
||||
|
||||
If the mail auth token is invalid/ expired: HTTP status code 401 Unauthorized
|
||||
|
||||
On success: a object with the properties ``status`` (string), ``mail`` (string) and
|
||||
``canCreateFamily`` (boolean)
|
||||
|
||||
- ``status`` is ``with family`` or ``without family``
|
||||
- ``mail`` is the mail address for which the auth token was created
|
||||
- ``canCreateFamily`` is false if the sign up of new families was disabled and otherwise true
|
||||
|
||||
## POST /parent/create-family
|
||||
|
||||
Use this to register a new family.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/createfamilybymailtokenrequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad Request
|
||||
|
||||
If the mail auth token is invalid/ expired: HTTP status code 401 Unauthorized
|
||||
|
||||
If there is already a user with the mail address of the mail auth token: HTTP status code 409 Conflict
|
||||
|
||||
On success: object with ``deviceAuthToken`` (string) and ``ownDeviceId`` (string)
|
||||
|
||||
## POST /parent/sign-in-into-family
|
||||
|
||||
Use this to sign in into an existing family using a mail auth token.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/signintofamilyrequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad Request
|
||||
|
||||
If there is no user with the mail address of the mail auth token: HTTP status code 409 Conflict
|
||||
|
||||
On success: object with ``deviceAuthToken`` (string) and ``ownDeviceId`` (string)
|
||||
|
||||
## POST /parent/can-recover-password
|
||||
|
||||
Use this to check if the parent password can be recovered. This checks that the
|
||||
mail auth token matches the mail address of the parent user.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](/schema/canrecoverpasswordrequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad Request
|
||||
|
||||
If the mail auth token is invalid/ expired: HTTP status code 401 Unauthorized
|
||||
|
||||
On success: object with the property ``canRecover`` (boolean)
|
||||
|
||||
## POST /parent/recover-parent-password
|
||||
|
||||
Use this to set the password for a user without knowing the old password.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/recoverparentpasswordrequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad Request
|
||||
|
||||
If the mail auth token is invalid/ expired: HTTP status code 401 Unauthorized
|
||||
|
||||
On success: ``{"ok": true}``
|
||||
|
||||
## POST /parent/create-add-device-token
|
||||
|
||||
Use this to create a token which can be used by ``/child/add-device``.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/createregisterdevicetokenrequest.md)
|
||||
|
||||
in case of a device used by a parent with disabled password checks, use ``device`` as ``secondPasswordHash``
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad Request
|
||||
|
||||
If the device auth token is invalid: HTTP status code 401 Unauthorized
|
||||
|
||||
If the ``secondPasswordHash`` is invalid: HTTP status code 401 Unauthorized
|
||||
|
||||
On success: object with ``token`` and ``deviceId``
|
||||
|
||||
``token`` is the add device token
|
||||
|
||||
``deviceId`` is the device id which the new device will get if it uses the token
|
||||
|
||||
## POST /parent/link-mail-address
|
||||
|
||||
Use this to link a mail address to an existing parent user.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/linkparentmailaddressrequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad Request
|
||||
|
||||
If the device auth token is invalid: HTTP status code 401 Unauthorized
|
||||
|
||||
If the mail auth token is invalid/ expired: HTTP status code 401 Unauthorized
|
||||
|
||||
If there is already a user with the mail address of the mail auth token: HTTP status code 409 Conflict
|
||||
|
||||
If there is no user with the specified ``parentId`` (user id): HTTP status code 409 Conflict
|
||||
|
||||
If there is already a mail address for the user: HTTP status code 409 Conflict
|
||||
|
||||
If the ``parentPasswordSecondHash`` is invalid: HTTP status code 409 Conflict
|
||||
|
||||
On success: ``{"ok": true}``
|
||||
|
||||
## POST /parent/remove-device
|
||||
|
||||
Use this to remove a device from a family.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/removedevicerequest.md)
|
||||
|
||||
in case of a device used by a parent with disabled password checks, use ``device`` as ``secondPasswordHash``
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad Request
|
||||
|
||||
If the device auth token is invalid: HTTP status code 401 Unauthorized
|
||||
|
||||
If there is no device with the specified ``deviceId``: HTTP status code 409 Conflict
|
||||
|
||||
If the ``secondPasswordHash`` is invalid: HTTP status code 401 Unauthorized
|
||||
|
||||
On success: ``{"ok": true}``
|
53
docs/api/purchase.md
Normal file
53
docs/api/purchase.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
# /purchase
|
||||
|
||||
This endpoint is used for handling purchases from the client.
|
||||
It currently only supports purchases using Google Play in app purchases.
|
||||
|
||||
## see
|
||||
|
||||
- [premium concept](../concept/premium.md)
|
||||
|
||||
## POST /purchase/can-do-purchase
|
||||
|
||||
Use this before a purchase to check if a purchase is possible.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/candopurchaserequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad request
|
||||
|
||||
On a invalid auth token: HTTP status code 401 Unauthorized
|
||||
|
||||
On success: a JSON object with the property ``canDoPurchase`` of the type string
|
||||
|
||||
possible values of ``canDoPurchase``:
|
||||
|
||||
- ``yes``
|
||||
- ``no due to old purchase``
|
||||
- ``no because not supported by the server``
|
||||
|
||||
## POST /purchase/finish-purchase-by-google-play
|
||||
|
||||
Use this to report a purchase to the server/ unlock all features after a purchase
|
||||
using Google Play.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/finishpurchasebygoogleplayrequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad request
|
||||
|
||||
On a invalid auth token: HTTP status code 401 Unauthorized
|
||||
|
||||
On a invalid purchase: HTTP status code 409 Conflict
|
||||
|
||||
On success: ``{"ok": true}``
|
||||
|
||||
### error handling
|
||||
|
||||
- if the purchase was already added (for the same or an other family), then this request is ignored and success is returned
|
117
docs/api/sync.md
Normal file
117
docs/api/sync.md
Normal file
|
@ -0,0 +1,117 @@
|
|||
# /sync
|
||||
|
||||
This endpoint is used by clients for syncing.
|
||||
|
||||
## the sync process
|
||||
|
||||
- the client pushes all actions (eventually in chunks)
|
||||
- all actions are numbered so that the server can ignore it if the client sends an action multiple times (e.g. due to connectivity issues)
|
||||
- in case something goes wrong, the server asks the client to do a full query when pulling the status the next time
|
||||
- the client pulls the status
|
||||
- the client sends a summary of the current status
|
||||
- the server does not send the data which the client already knows
|
||||
- in case the client is unauthorized, then the client checks against /sync/is-device-removed
|
||||
- if it tells the client that it was really removed, then the client resets itself
|
||||
|
||||
## possible sync triggers
|
||||
|
||||
- periodically/ by the time (e.g. every hour, not all 10 seconds)
|
||||
- the [websocket](./websocket.md) for syncing as soon as something was changed by an other client
|
||||
- changes/ actions at the client itself
|
||||
|
||||
## POST /sync/push-actions
|
||||
|
||||
Use this to sync actions to the server.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/clientpushchangesrequest.md)
|
||||
|
||||
the encoded actions are stringified JSON objects of one of this schemes:
|
||||
- [serialized app logic action](../schema/serializedapplogicaction.md)
|
||||
- [serialized parent action](../schema/serializedparentaction.md)
|
||||
- [serialized child action](../schema/serializedchildaction.md)
|
||||
|
||||
The request must not contain more than 50 actions. The request may contain less than 50
|
||||
actions.
|
||||
|
||||
The sequence numbers must be a increasing sequence per device.
|
||||
|
||||
#### integrity
|
||||
|
||||
The integrity field of a action may have got one of the following values:
|
||||
|
||||
- an empty string when no user authentication is required/ for app logic actions (e.g. incrementing the used time)
|
||||
- the string ``device`` in case of parent actions if a parent is assigned to the device and asking for the password was disabled
|
||||
- ``sha512(sequence number as string with the base 10 + the device id as string + the hash of the user password using the second salt as string + the encoded action as string)`` for parent and child actions
|
||||
|
||||
In case of a invalid integrity value, the action is ignored and the client is told to do a full sync
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad request
|
||||
|
||||
On a invalid auth token: HTTP status code 401 Unauthorized
|
||||
|
||||
On success: JSON object with the property ``shouldDoFullSync`` - example: ``{"shouldDoFullSync": false}``
|
||||
|
||||
### error handling
|
||||
|
||||
If a action has got a invalid ``integrity`` or ``encodedAction``, then only this action
|
||||
is ignored and ``shouldDoFullSync`` will be true.
|
||||
|
||||
## POST /sync/pull-status
|
||||
|
||||
Use this to pull the current status from the server.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/clientpullchangesrequest.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: HTTP status code 400 Bad request
|
||||
|
||||
On a invalid auth token: HTTP status code 401 Unauthorized
|
||||
|
||||
On success: see [this JSON schema](../schema/serverdatastatus.md)
|
||||
|
||||
## POST /sync/report-removed
|
||||
|
||||
Use this to report that TimeLimit is/ was reset.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/requestwithauthtoken.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: http status code 400 Bad request
|
||||
|
||||
On a invalid/ unknown auth token: http status code 500 Internal Server Error
|
||||
|
||||
On success: ``{"ok": true}``
|
||||
|
||||
### error handling
|
||||
|
||||
If a removed device reports that it is removed, then it is ignored and handled
|
||||
as success.
|
||||
|
||||
## POST /sync/is-device-removed
|
||||
|
||||
Use this to check if the device was removed.
|
||||
|
||||
Background: This checks if the auth token is in a list of known old auth tokens.
|
||||
This ensures that an empty database at the server does not trigger the client reset feature.
|
||||
|
||||
### request
|
||||
|
||||
see [this JSON schema](../schema/requestwithauthtoken.md)
|
||||
|
||||
### response
|
||||
|
||||
On a invalid request body: http status code 400 bad request
|
||||
|
||||
object with the property ``isDeviceRemoved`` of the type boolean
|
||||
|
||||
example response: ``{"isDeviceRemoved": false}``
|
36
docs/api/websocket.md
Normal file
36
docs/api/websocket.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Websocket
|
||||
|
||||
The websocket is used for real time notifications from the server
|
||||
to the client. For this, socket.io is used which internally
|
||||
uses the ``/socket.io`` endpoint. It is highly recommend to only
|
||||
use the websocket transport and to not use the polling transport.
|
||||
|
||||
Upon connecting, the client should emit ``devicelogin`` with one or two parameters.
|
||||
The first parameter must be the device auth token and the second one can be an ack
|
||||
function. After handling the connection, the server calls the ack function.
|
||||
|
||||
Clients should only do one ``devicelogin`` per connection. Doing it multiple
|
||||
times per connection can result in missing events. Invalid auth tokens are ignored/
|
||||
do not receive notifications.
|
||||
|
||||
## events from the server
|
||||
|
||||
### should sync
|
||||
|
||||
The server can emit ``should sync`` with one parameter of the type object.
|
||||
This object has the boolean property ``isImportant``.
|
||||
|
||||
The client should sync after receiving this. If it is not important, then the client
|
||||
can wait until to user opens the UI the next time.
|
||||
|
||||
### sign out
|
||||
|
||||
The server can emit ``sign out`` without any parameters. This tells the device
|
||||
if it is the primary device for a user that it should leave that role if possible.
|
||||
|
||||
see the [primary device concept](../concept/primary-device.md)
|
||||
|
||||
### connected devices
|
||||
|
||||
The server can emit ``connected devices`` with one parameter of the type array of string.
|
||||
This array contains the device ids of the devices which should be shown as connected.
|
Loading…
Add table
Add a link
Reference in a new issue