@myronsi/messenger-api 2.1.0-alpha.14 → 2.1.0-alpha.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/openapi.yaml +572 -3
- package/dist/schema.d.ts +920 -19
- package/dist/ws-docs.json +65 -1
- package/dist/ws-events.d.ts +136 -3
- package/dist/ws-events.schema.json +532 -2
- package/package.json +1 -1
package/dist/ws-docs.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"markdown": "# WebSocket protocol (API contract v2)\r\n\r\nThe JSON Schemas in `websocket/client/` (client → server) and `websocket/server/` (server → client) are the source of truth. Every event has an example in `websocket/examples/`, validated against its schema by `npm run check`. TypeScript types are generated into `dist/ws-events.d.ts` (`ClientEvent`, `ServerEvent`).\r\n\r\n## Connecting\r\n\r\n1. `POST /api/v2/ws/ticket` (authenticated) returns `{ \"ticket\": \"…\", \"expires_in\": 30 }`. The ticket is single-use and short-lived, so no access token ends up in a URL or a log.\r\n2. Open **one connection per browser tab**: `wss://<host>/api/v2/ws?ticket=<ticket>&api_version=<contract version>`. The connection carries the events of all chats of the user. `api_version` is optional and takes the place of the `X-Client-Api-Version` header, which browsers cannot send on a WebSocket.\r\n3. The first server event is `hello` with `api_version` and `min_client_api_version`. A client that reconnects after a deploy compares them with the contract version it was built for and shows an upgrade notice instead of failing at random.\r\n4. When the ticket is invalid or expired the server closes the connection with code `4401`. A client whose `api_version` is no longer served is closed with `4426` after `hello`.\r\n\r\n## Close codes\r\n\r\n| Code | Meaning | Client |\r\n| --- | --- | --- |\r\n| `1012` | `reconnect`: the server is restarting, or it lost its pub/sub connection and events may be missing | reconnect with backoff, then load what was missed (`after` cursor) |\r\n| `1013` | the client did not keep up with its events, or sent more than 64 events that are not handled yet | reconnect, then catch up |\r\n| `4401` | invalid ticket, or the session ended (logout, revoked, password changed) | get a new ticket; if that fails, sign in again |\r\n| `4426` | the client's contract version is no longer served | show the upgrade notice |\r\n| `4429` | the user opened more than 10 connections on this server; the oldest one is closed | do not reconnect this tab automatically |\r\n\r\n## Envelope\r\n\r\nServer → client:\r\n\r\n```json\r\n{ \"type\": \"message\", \"event_id\": \"7217400317439950849\", \"chat_id\": \"42\", \"data\": { \"message\": { \"…\": \"…\" } } }\r\n```\r\n\r\nClient → server:\r\n\r\n```json\r\n{ \"type\": \"message\", \"client_temp_id\": \"c-1\", \"chat_id\": \"42\", \"data\": { \"type\": \"text\", \"content\": \"Hello!\" } }\r\n```\r\n\r\n- All IDs are strings (Snowflake IDs do not fit into a JavaScript number).\r\n- `event_id` is unique and increases per server; it is only for deduplication and logs.\r\n- `chat_id` is always `null` in `hello`, `presence` and `approval_request_created`, which do not belong to a chat. `ack` and `error` repeat the `chat_id` of the client event they answer, and it is `null` for connection-level errors.\r\n- Unknown event `type`s must be ignored by clients, so new event types are not a breaking change.\r\n- A user who is removed from a chat (or whose chat is deleted) receives `chat_deleted` and no further events of that chat.\r\n\r\n## Acknowledgements\r\n\r\nEvery client event except `typing` (which is not acknowledged and carries no `client_temp_id`) has a `client_temp_id` (1–64 characters, unique per client). The server answers with exactly one of:\r\n\r\n- `ack` — `client_temp_id`, and for `message` the stored `message_id` and `created_at`. Sending the same `client_temp_id` again returns the same `ack` (idempotent), which makes retries after a reconnect safe.\r\n- `error` — `client_temp_id` and `data.code`/`data.message`. `code` is one of the stable codes of `ErrorCode` in `openapi.yaml` (the same codes as the REST `application/problem+json` errors).\r\n\r\nThe sender also receives the broadcast `message` event with the stored message (its `client_temp_id` is included, so the client can replace its pending copy).\r\n\r\n## Client → server events\r\n\r\n| Type | Purpose |\r\n| --- | --- |\r\n| `message` | Send a message (`type` `text`, `file` or `voice`; files are referenced by `attachment_id`, never by URL) |\r\n| `resend` | Deliver a stored but undelivered message again |\r\n| `edit` | Edit your own text message |\r\n| `delete` | Delete a message for yourself (`scope: me`) or everyone |\r\n| `read` | Mark messages as read up to `message_id` |\r\n| `reaction_add`, `reaction_remove` | Add or remove a reaction |\r\n| `typing` | Typing indicator (not acknowledged) |\r\n\r\n## Server → client events\r\n\r\n| Type | Meaning |\r\n| --- | --- |\r\n| `hello` | First event: `api_version`, `min_client_api_version`, `user_id` |\r\n| `ack`, `error` | Result of a client event, references `client_temp_id` |\r\n| `message`, `edit`, `delete` | Message created, edited or deleted |\r\n| `reaction_add`, `reaction_remove` | Reactions changed |\r\n| `read` | A user read up to `message_id` |\r\n| `typing` | A user is typing |\r\n| `chat_created`, `chat_deleted`, `chat_list_update` | Chat list changes |\r\n| `group_created`, `group_updated` | Group changes (members, roles, name, avatar) |\r\n| `approval_request_created` | New request in the inbox |\r\n| `presence` | A user came online or went offline |\r\n\r\n## Compatibility\r\n\r\nAdding an event type or an optional field is a MINOR change; removing or renaming an event or field, or making a field required, is MAJOR (see `docs/api-compatibility.md`). Clients must ignore unknown events and unknown fields.\r\n",
|
|
2
|
+
"markdown": "# WebSocket protocol (API contract v2)\r\n\r\nThe JSON Schemas in `websocket/client/` (client → server) and `websocket/server/` (server → client) are the source of truth. Every event has an example in `websocket/examples/`, validated against its schema by `npm run check`. TypeScript types are generated into `dist/ws-events.d.ts` (`ClientEvent`, `ServerEvent`).\r\n\r\n## Connecting\r\n\r\n1. `POST /api/v2/ws/ticket` (authenticated) returns `{ \"ticket\": \"…\", \"expires_in\": 30 }`. The ticket is single-use and short-lived, so no access token ends up in a URL or a log.\r\n2. Open **one connection per browser tab**: `wss://<host>/api/v2/ws?ticket=<ticket>&api_version=<contract version>`. The connection carries the events of all chats of the user. `api_version` is optional and takes the place of the `X-Client-Api-Version` header, which browsers cannot send on a WebSocket.\r\n3. The first server event is `hello` with `api_version` and `min_client_api_version`. A client that reconnects after a deploy compares them with the contract version it was built for and shows an upgrade notice instead of failing at random.\r\n4. When the ticket is invalid or expired the server closes the connection with code `4401`. A client whose `api_version` is no longer served is closed with `4426` after `hello`.\r\n\r\n## Close codes\r\n\r\n| Code | Meaning | Client |\r\n| --- | --- | --- |\r\n| `1012` | `reconnect`: the server is restarting, or it lost its pub/sub connection and events may be missing | reconnect with backoff, then load what was missed (`after` cursor) |\r\n| `1013` | the client did not keep up with its events, or sent more than 64 events that are not handled yet | reconnect, then catch up |\r\n| `4401` | invalid ticket, or the session ended (logout, revoked, password changed) | get a new ticket; if that fails, sign in again |\r\n| `4426` | the client's contract version is no longer served | show the upgrade notice |\r\n| `4429` | the user opened more than 10 connections on this server; the oldest one is closed | do not reconnect this tab automatically |\r\n\r\n## Envelope\r\n\r\nServer → client:\r\n\r\n```json\r\n{ \"type\": \"message\", \"event_id\": \"7217400317439950849\", \"chat_id\": \"42\", \"data\": { \"message\": { \"…\": \"…\" } } }\r\n```\r\n\r\nClient → server:\r\n\r\n```json\r\n{ \"type\": \"message\", \"client_temp_id\": \"c-1\", \"chat_id\": \"42\", \"data\": { \"type\": \"text\", \"content\": \"Hello!\" } }\r\n```\r\n\r\n- All IDs are strings (Snowflake IDs do not fit into a JavaScript number).\r\n- `event_id` is unique and increases per server; it is only for deduplication and logs.\r\n- `chat_id` is always `null` in `hello`, `presence` and `approval_request_created`, which do not belong to a chat. `ack` and `error` repeat the `chat_id` of the client event they answer, and it is `null` for connection-level errors.\r\n- Unknown event `type`s must be ignored by clients, so new event types are not a breaking change.\r\n- A user who is removed from a chat (or whose chat is deleted) receives `chat_deleted` and no further events of that chat.\r\n\r\n## Acknowledgements\r\n\r\nEvery client event except `typing` (which is not acknowledged and carries no `client_temp_id`) has a `client_temp_id` (1–64 characters, unique per client). The server answers with exactly one of:\r\n\r\n- `ack` — `client_temp_id`, and for `message` the stored `message_id` and `created_at`. Sending the same `client_temp_id` again returns the same `ack` (idempotent), which makes retries after a reconnect safe.\r\n- `error` — `client_temp_id` and `data.code`/`data.message`. `code` is one of the stable codes of `ErrorCode` in `openapi.yaml` (the same codes as the REST `application/problem+json` errors).\r\n\r\nThe sender also receives the broadcast `message` event with the stored message (its `client_temp_id` is included, so the client can replace its pending copy).\r\n\r\n## Client → server events\r\n\r\n| Type | Purpose |\r\n| --- | --- |\r\n| `message` | Send a message (`type` `text`, `file` or `voice`; files are referenced by `attachment_id`, never by URL) |\r\n| `resend` | Deliver a stored but undelivered message again |\r\n| `edit` | Edit your own text message |\r\n| `delete` | Delete a message for yourself (`scope: me`) or everyone |\r\n| `read` | Mark messages as read up to `message_id` |\r\n| `reaction_add`, `reaction_remove` | Add or remove a reaction |\r\n| `typing` | Typing indicator (not acknowledged) |\r\n\r\n## Server → client events\r\n\r\n| Type | Meaning |\r\n| --- | --- |\r\n| `hello` | First event: `api_version`, `min_client_api_version`, `user_id` |\r\n| `ack`, `error` | Result of a client event, references `client_temp_id` |\r\n| `message`, `edit`, `delete` | Message created, edited or deleted |\r\n| `reaction_add`, `reaction_remove` | Reactions changed |\r\n| `read` | A user read up to `message_id` |\r\n| `typing` | A user is typing |\r\n| `chat_created`, `chat_deleted`, `chat_list_update` | Chat list changes |\r\n| `group_created`, `group_updated` | Group changes (members, roles, name, avatar) |\r\n| `approval_request_created` | New request in the inbox |\r\n| `presence` | A user came online or went offline |\n| `call_updated` | A call of the chat changed (state, participants, epoch); carries the whole call, keep the highest `version` |\n| `call_keys` | Sealed call sender keys for this session only (`docs/calls-e2ee.md`) |\r\n\r\n## Compatibility\r\n\r\nAdding an event type or an optional field is a MINOR change; removing or renaming an event or field, or making a field required, is MAJOR (see `docs/api-compatibility.md`). Clients must ignore unknown events and unknown fields.\r\n",
|
|
3
3
|
"examples": {
|
|
4
4
|
"client/delete.json": {
|
|
5
5
|
"type": "delete",
|
|
@@ -104,6 +104,70 @@
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
|
+
"server/call_keys.json": {
|
|
108
|
+
"type": "call_keys",
|
|
109
|
+
"event_id": "7217400317439950111",
|
|
110
|
+
"chat_id": "77",
|
|
111
|
+
"data": {
|
|
112
|
+
"call_id": "7217400317439950100",
|
|
113
|
+
"epoch": 2,
|
|
114
|
+
"items": [
|
|
115
|
+
{
|
|
116
|
+
"epoch": 2,
|
|
117
|
+
"sender_user_id": "1002",
|
|
118
|
+
"sender_session_id": "9c1d2e3f-4a5b-4c6d-8e7f-001122334455",
|
|
119
|
+
"recipient_session_id": "5b0e8f0a-3f1c-4a52-9a8e-0d6e1c3f9b21",
|
|
120
|
+
"enc": "BJCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC",
|
|
121
|
+
"ciphertext": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"server/call_updated.json": {
|
|
127
|
+
"type": "call_updated",
|
|
128
|
+
"event_id": "7217400317439950110",
|
|
129
|
+
"chat_id": "77",
|
|
130
|
+
"data": {
|
|
131
|
+
"call": {
|
|
132
|
+
"id": "7217400317439950100",
|
|
133
|
+
"chat_id": "77",
|
|
134
|
+
"kind": "group",
|
|
135
|
+
"state": "active",
|
|
136
|
+
"end_reason": null,
|
|
137
|
+
"initiator_id": "1001",
|
|
138
|
+
"created_at": "2026-11-07T12:00:00Z",
|
|
139
|
+
"started_at": "2026-11-07T12:00:05Z",
|
|
140
|
+
"ended_at": null,
|
|
141
|
+
"ring_expires_at": "2026-11-07T12:00:30Z",
|
|
142
|
+
"epoch": 2,
|
|
143
|
+
"version": 4,
|
|
144
|
+
"max_participants": 10,
|
|
145
|
+
"participants": [
|
|
146
|
+
{
|
|
147
|
+
"user_id": "1001",
|
|
148
|
+
"state": "joined",
|
|
149
|
+
"session_id": "5b0e8f0a-3f1c-4a52-9a8e-0d6e1c3f9b21",
|
|
150
|
+
"identity_key": "BAt2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
151
|
+
"joined_at": "2026-11-07T12:00:01Z"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"user_id": "1002",
|
|
155
|
+
"state": "joined",
|
|
156
|
+
"session_id": "9c1d2e3f-4a5b-4c6d-8e7f-001122334455",
|
|
157
|
+
"identity_key": "BHk9BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
|
|
158
|
+
"joined_at": "2026-11-07T12:00:05Z"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"user_id": "1003",
|
|
162
|
+
"state": "ringing",
|
|
163
|
+
"session_id": null,
|
|
164
|
+
"identity_key": null,
|
|
165
|
+
"joined_at": null
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
107
171
|
"server/chat_created.json": {
|
|
108
172
|
"type": "chat_created",
|
|
109
173
|
"event_id": "7217400317439950009",
|
package/dist/ws-events.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Generated from api/openapi.yaml 2.1.0-alpha.
|
|
1
|
+
/* Generated from api/openapi.yaml 2.1.0-alpha.15. Do not edit. */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Any WebSocket event, in either direction.
|
|
@@ -34,6 +34,8 @@ export type AttachmentRef = string;
|
|
|
34
34
|
export type ServerEvent =
|
|
35
35
|
| ServerAckEvent
|
|
36
36
|
| ServerApprovalRequestCreatedEvent
|
|
37
|
+
| ServerCallKeysEvent
|
|
38
|
+
| ServerCallUpdatedEvent
|
|
37
39
|
| ServerChatCreatedEvent
|
|
38
40
|
| ServerChatDeletedEvent
|
|
39
41
|
| ServerChatListUpdateEvent
|
|
@@ -56,10 +58,31 @@ export type Timestamp = string;
|
|
|
56
58
|
export type ApprovalRequestType = "direct_message" | "group_invite";
|
|
57
59
|
export type ApprovalRequestStatus = "pending" | "approved" | "rejected";
|
|
58
60
|
export type Username = string;
|
|
61
|
+
/**
|
|
62
|
+
* `ringing` until someone answers, `active` while people are in it, `ended` afterwards.
|
|
63
|
+
*/
|
|
64
|
+
export type CallState = "ringing" | "active" | "ended";
|
|
65
|
+
/**
|
|
66
|
+
* Why the call ended: `completed` (people talked), `missed` (nobody answered in time), `declined` (the peer of a
|
|
67
|
+
* direct call declined), `cancelled` (the caller hung up before an answer), `failed` (the media service lost
|
|
68
|
+
* the call).
|
|
69
|
+
*
|
|
70
|
+
*/
|
|
71
|
+
export type CallEndReason = "completed" | "missed" | "declined" | "cancelled" | "failed";
|
|
72
|
+
/**
|
|
73
|
+
* `left` and `declined` can become `joined` again in a group call.
|
|
74
|
+
*/
|
|
75
|
+
export type CallParticipantState = "ringing" | "joined" | "declined" | "missed" | "left";
|
|
76
|
+
/**
|
|
77
|
+
* P-256 public key as an uncompressed point (65 bytes, first byte `0x04`), base64url without padding.
|
|
78
|
+
*
|
|
79
|
+
*/
|
|
80
|
+
export type CallIdentityKey = string;
|
|
59
81
|
export type ChatType = "direct" | "group";
|
|
60
82
|
export type MessageType = "text" | "file" | "voice" | "system";
|
|
61
83
|
export type AttachmentKind = "image" | "audio" | "voice" | "video" | "file";
|
|
62
|
-
export type SystemEventKind =
|
|
84
|
+
export type SystemEventKind =
|
|
85
|
+
"group_created" | "member_added" | "member_joined" | "member_removed" | "member_left" | "call";
|
|
63
86
|
/**
|
|
64
87
|
* A moderator may delete other members' messages; owners and admins also manage the group.
|
|
65
88
|
*/
|
|
@@ -88,6 +111,13 @@ export type ErrorCode =
|
|
|
88
111
|
| "invalid_client_version"
|
|
89
112
|
| "blocked_by_user"
|
|
90
113
|
| "approval_required"
|
|
114
|
+
| "calls_unavailable"
|
|
115
|
+
| "calls_not_allowed"
|
|
116
|
+
| "call_identity_required"
|
|
117
|
+
| "call_full"
|
|
118
|
+
| "call_ended"
|
|
119
|
+
| "already_in_call"
|
|
120
|
+
| "stale_epoch"
|
|
91
121
|
| "internal_error";
|
|
92
122
|
|
|
93
123
|
/**
|
|
@@ -267,6 +297,95 @@ export interface User {
|
|
|
267
297
|
last_seen: Timestamp | null;
|
|
268
298
|
is_deleted: boolean;
|
|
269
299
|
}
|
|
300
|
+
/**
|
|
301
|
+
* Sealed sender keys for this session (see docs/calls-e2ee.md). Sent only to the recipient session.
|
|
302
|
+
*/
|
|
303
|
+
export interface ServerCallKeysEvent {
|
|
304
|
+
type: "call_keys";
|
|
305
|
+
event_id: Id;
|
|
306
|
+
chat_id: Id;
|
|
307
|
+
data: CallKeyEnvelopeList;
|
|
308
|
+
}
|
|
309
|
+
export interface CallKeyEnvelopeList {
|
|
310
|
+
call_id: Id;
|
|
311
|
+
epoch: number;
|
|
312
|
+
items: CallKeyEnvelope[];
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* An HPKE Auth-mode envelope carrying one sender key (see `docs/calls-e2ee.md`).
|
|
316
|
+
*/
|
|
317
|
+
export interface CallKeyEnvelope {
|
|
318
|
+
epoch: number;
|
|
319
|
+
sender_user_id: Id;
|
|
320
|
+
sender_session_id: string;
|
|
321
|
+
recipient_session_id: string;
|
|
322
|
+
/**
|
|
323
|
+
* HPKE encapsulated key, base64url without padding.
|
|
324
|
+
*/
|
|
325
|
+
enc: string;
|
|
326
|
+
/**
|
|
327
|
+
* Sealed sender key, base64url without padding.
|
|
328
|
+
*/
|
|
329
|
+
ciphertext: string;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* A call of the chat started, rang, changed participants or epoch, or ended. Carries the whole call; keep the one with the highest `version`. Sent to every member of the chat.
|
|
333
|
+
*/
|
|
334
|
+
export interface ServerCallUpdatedEvent {
|
|
335
|
+
type: "call_updated";
|
|
336
|
+
event_id: Id;
|
|
337
|
+
chat_id: Id;
|
|
338
|
+
data: {
|
|
339
|
+
call: Call;
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
export interface Call {
|
|
343
|
+
id: Id;
|
|
344
|
+
chat_id: Id;
|
|
345
|
+
kind: "direct" | "group";
|
|
346
|
+
state: CallState;
|
|
347
|
+
end_reason: CallEndReason | null;
|
|
348
|
+
initiator_id: Id;
|
|
349
|
+
created_at: Timestamp;
|
|
350
|
+
/**
|
|
351
|
+
* First answer; `null` while nobody answered.
|
|
352
|
+
*/
|
|
353
|
+
started_at: Timestamp | null;
|
|
354
|
+
ended_at: Timestamp | null;
|
|
355
|
+
/**
|
|
356
|
+
* When ringing invitations of this call turn into `missed`.
|
|
357
|
+
*/
|
|
358
|
+
ring_expires_at: string;
|
|
359
|
+
/**
|
|
360
|
+
* Key epoch; increases whenever the set of joined sessions or their identity keys change.
|
|
361
|
+
*/
|
|
362
|
+
epoch: number;
|
|
363
|
+
/**
|
|
364
|
+
* Increases with every change of the call; ignore events with a lower version than one already seen.
|
|
365
|
+
*/
|
|
366
|
+
version: number;
|
|
367
|
+
max_participants: number;
|
|
368
|
+
/**
|
|
369
|
+
* Everyone invited or joined, the initiator first.
|
|
370
|
+
*/
|
|
371
|
+
participants: CallParticipant[];
|
|
372
|
+
}
|
|
373
|
+
export interface CallParticipant {
|
|
374
|
+
user_id: Id;
|
|
375
|
+
state: CallParticipantState;
|
|
376
|
+
/**
|
|
377
|
+
* The session that joined; `null` unless `state` is `joined`.
|
|
378
|
+
*/
|
|
379
|
+
session_id: string | null;
|
|
380
|
+
/**
|
|
381
|
+
* Call identity of the joined session; `null` unless `state` is `joined`.
|
|
382
|
+
*/
|
|
383
|
+
identity_key: CallIdentityKey | null;
|
|
384
|
+
/**
|
|
385
|
+
* When the participant last joined; `null` if never.
|
|
386
|
+
*/
|
|
387
|
+
joined_at: Timestamp | null;
|
|
388
|
+
}
|
|
270
389
|
/**
|
|
271
390
|
* A chat was created with you.
|
|
272
391
|
*/
|
|
@@ -382,7 +501,8 @@ export interface ReadReceipt {
|
|
|
382
501
|
/**
|
|
383
502
|
* What a `system` message records; set on system messages only, whose `content` is then `null`. The names
|
|
384
503
|
* are the display names at the time of the event. `target` fields are set for `member_added` and
|
|
385
|
-
* `member_removed`.
|
|
504
|
+
* `member_removed`. `call` is set for `call` messages: one per call, posted when the call ends, `actor` is the
|
|
505
|
+
* initiator.
|
|
386
506
|
*
|
|
387
507
|
*/
|
|
388
508
|
export interface SystemEvent {
|
|
@@ -391,6 +511,19 @@ export interface SystemEvent {
|
|
|
391
511
|
actor_name: string;
|
|
392
512
|
target_id?: Id;
|
|
393
513
|
target_name?: string;
|
|
514
|
+
call?: CallSummary;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* The call a `call` system message records.
|
|
518
|
+
*/
|
|
519
|
+
export interface CallSummary {
|
|
520
|
+
call_id: Id;
|
|
521
|
+
kind: "direct" | "group";
|
|
522
|
+
outcome: CallEndReason;
|
|
523
|
+
/**
|
|
524
|
+
* From the first answer to the end; `null` if nobody answered.
|
|
525
|
+
*/
|
|
526
|
+
duration_seconds: number | null;
|
|
394
527
|
}
|
|
395
528
|
/**
|
|
396
529
|
* A chat was deleted, or you were removed from it.
|