Skip to content

Commit 149bf63

Browse files
committed
add websocket notes
1 parent c5ac2eb commit 149bf63

1 file changed

Lines changed: 78 additions & 0 deletions

File tree

src/content/docs/developers/chats.mdx

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ This document explains how Ecency's chat experience works and how other Hive app
1414
- **Hive identity**: Users authenticate with their Hive account (access/refresh tokens). The bootstrap API validates those tokens before issuing a Mattermost PAT so the chat identity is bound to the Hive username.
1515
- **Community mapping**: Hive communities map to public Mattermost channels named after the community id (e.g., `hive-123`). The bootstrap flow can auto-join users to channels for the communities they subscribe to.
1616

17+
### Realtime transport
18+
19+
- **Websocket proxy**: `/api/mattermost/websocket` is a passthrough to Mattermost's websocket upgraded connection. It upgrades on the edge runtime, forwards all frames bi-directionally, and injects the authentication challenge upstream using the `mm_pat` cookie created during bootstrap.
20+
- **Auth flow**: Clients do **not** need to send the PAT manually; the proxy pulls it from the cookie, opens the upstream websocket derived from `MATTERMOST_BASE_URL`, and immediately sends Mattermost's `authentication_challenge` action with the PAT.
21+
- **Error handling**: Missing cookies receive `401 Unauthorized`; invalid upgrades respond with `400`; upstream issues (e.g., Mattermost unreachable) respond with `502`.
22+
1723
## Using Ecency-hosted chat endpoints
1824

1925
Other Hive apps can call Ecency's `/api/mattermost/*` routes directly - **no Mattermost infrastructure required**. Key points:
@@ -32,6 +38,78 @@ Other Hive apps can call Ecency's `/api/mattermost/*` routes directly - **no Mat
3238
3. **Call chat endpoints with the cookie**: Subsequent requests to `https://ecency.com/api/mattermost/*` automatically include the PAT cookie when `credentials: "include"` is set, enabling channel lists, posting, reactions, searches, and direct messages.
3339
4. **Link back to your UI**: Use returned `channelId` or search endpoints to deep-link into chat surfaces within your app (e.g., from profiles or community pages).
3440

41+
### Realtime websocket usage
42+
43+
Use the websocket proxy to stream reactions, typing events, and post updates without exposing PATs to the browser:
44+
45+
```ts
46+
// Requires the mm_pat cookie set by the bootstrap call above; same-origin
47+
// requests automatically include it and allow the edge function to auth upstream.
48+
const socket = new WebSocket("wss://ecency.com/api/mattermost/websocket");
49+
50+
socket.addEventListener("open", () => {
51+
// Mattermost websocket protocol uses typed actions; you can immediately
52+
// subscribe to channels or send ping frames after connect.
53+
socket.send(JSON.stringify({ seq: 2, action: "ping" }));
54+
});
55+
56+
socket.addEventListener("message", (event) => {
57+
const data = JSON.parse(event.data as string);
58+
59+
if (data.event === "posted") {
60+
// Handle new post payloads and update your UI accordingly.
61+
}
62+
});
63+
64+
socket.addEventListener("close", () => {
65+
// Implement your own reconnection strategy as needed.
66+
});
67+
```
68+
69+
**Notes**:
70+
71+
- No token needs to be provided in the websocket URL or headers; the proxy pulls it from `mm_pat` and runs the `authentication_challenge` upstream for you.
72+
- If the PAT cookie is missing or expired, the request returns `401` before upgrading. Re-run the bootstrap route to refresh it.
73+
- The websocket endpoint is same-origin, so use `wss://<your-ecency-host>/api/mattermost/websocket` for staging or production as appropriate.
74+
75+
#### What websocket events look like
76+
77+
Mattermost emits typed events over the websocket. Each frame is a JSON object with an `event` name, a `data` payload, and per-event metadata (full schema in the [Mattermost websocket reference](https://developers.mattermost.com/api-documentation/#/#websocket-events)). Some of the most useful events for in-app chat surfaces:
78+
79+
- **`posted`**: A new post or reply was created. The payload includes the `post` object (stringified JSON), `channel_display_name`, and `team_id`. Parse the `post` field to get message text, attachments, and `root_id` (thread parent).
80+
- **`post_edited`**: A user updated an existing message. Merge the `post` JSON with your existing message state.
81+
- **`post_deleted`**: A message was deleted. The `data` includes `post` and `channel_display_name`; rely on `post.id` to remove it from the UI.
82+
- **`reaction_added` / `reaction_removed`**: Reaction toggles with `user_id`, `emoji_name`, `post_id`, and `channel_id`.
83+
- **`typing`**: Indicates a user is typing in a channel. Includes `user_id`, `channel_id`, and `parent_id` for thread typing.
84+
- **`user_updated`**: Profile or status changes that may affect avatars or presence indicators.
85+
- **`hello`**: Sent once after authentication; contains server connection info and session id. Useful to confirm the connection succeeded.
86+
87+
Example `posted` event payload structure (fields trimmed for brevity):
88+
89+
```json
90+
{
91+
"event": "posted",
92+
"seq": 4,
93+
"data": {
94+
"channel_display_name": "hive-123",
95+
"channel_type": "O",
96+
"post": "{\"id\":\"abc123\",\"channel_id\":\"...\",\"message\":\"hello world\",\"root_id\":\"\"}",
97+
"sender_name": "alice",
98+
"team_id": "team123"
99+
},
100+
"broadcast": {
101+
"channel_id": "CHANNEL_ID",
102+
"team_id": "team123"
103+
}
104+
}
105+
```
106+
107+
Notes when consuming events:
108+
109+
- `data.post` is a JSON string; parse it before use. The `message` and `root_id` fields are where you decide whether to update the main channel timeline or a thread.
110+
- `broadcast` hints which channel or team should receive the update; you can use it to filter events if you maintain multiple channel tabs.
111+
- Some events (e.g., `typing`) do not include a `post` body. Handle them separately from message mutations.
112+
35113
### How Ecency access tokens are issued
36114

37115
Ecency always mints the same JWT `accessToken`/`refreshToken` pair regardless of the login provider. Hivesigner users obtain them via the OAuth callback, while other methods (Keychain, HiveAuth, or manual posting-key sign-in) go through the Ecency auth API, which returns the tokens after verifying a signed login challenge tied to the Hive posting authority.

0 commit comments

Comments
 (0)