Relay · Messages
傳送可安全重試的訊息
每次邏輯傳送都需要 client 產生的 nonce。重試結果不確定的 request 時,必須沿用原 nonce。Relay 透過 (channel_id, nonce) 回傳第一次寫入的結果,不建立第二則訊息。
傳送前提
你需要:
- 有效的 host-signed bearer token
- 與 token 屬於相同 tenant 的 channel
- Token 內的
user_id必須是 channel member - 這次邏輯傳送專用的新 nonce
Browser 或 Node.js runtime 可以使用 crypto.randomUUID() 產生 nonce。
第一次 request
NONCE="client-generated-uuid"
curl -i \
-X POST "https://relay.example.com/api/channels/$CHANNEL_ID/messages" \
-H "Authorization: Bearer $RELAY_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"body\":\"hello\",\"nonce\":\"$NONCE\",\"parent_message_id\":null,\"mentions\":[],\"attachment_ids\":[]}" 新 message 會回傳 201 Created:
{
"data": {
"id": "message-uuid",
"channel_id": "channel-uuid",
"sender_id": "user-uuid",
"body": "hello",
"nonce": "client-generated-uuid",
"seq": 41,
"parent_message_id": null,
"mentions": [],
"attachments": []
}
} Relay 在 database transaction 內分配 seq。排列 channel message 時,應使用 seq,不能使用 client timestamp。
結果不確定時重試
Timeout 或 client disconnected 不代表 write 一定失敗。使用相同的 channel 與 nonce 重送同一次邏輯傳送:
curl -i \
-X POST "https://relay.example.com/api/channels/$CHANNEL_ID/messages" \
-H "Authorization: Bearer $RELAY_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"body\":\"hello\",\"nonce\":\"$NONCE\",\"parent_message_id\":null,\"mentions\":[],\"attachment_ids\":[]}" 如果第一次 request 已經建立 message,retry 會回傳 200 OK 與原 message。它的 id 和 seq 不會改變,也不會產生第二則 message 或第二筆 post-commit handoff。
只有在 user 或 agent 確實要建立另一則邏輯訊息時,才產生新 nonce。Nonce 的 scope 是單一 channel,不是 global message ID。
失敗行為
| 條件 | 結果 |
|---|---|
| Token 缺少或無效 | 401,錯誤為 invalid_or_missing_token |
| User 不是 channel member | 403,錯誤為 forbidden |
| Channel 已關閉 | 422 validation response |
body 或 nonce 缺少或無效 | 422 validation response |
| Attachment 不存在、不屬於 sender,或尚未完成 upload | 整個 message transaction 失敗 |
成功回應的共同格式是 { "data": ... },失敗格式是 { "errors": [...] }。
Commit 之後
REST 與 WebSocket send 會呼叫同一個 Relay write action。因此,membership validation、nonce idempotency、sequence assignment、attachment binding 與 message serialization 遵循同一份契約。
Message transaction commit 後才會開始 delivery work。沿用相同 nonce 的 retry 只會回傳既有 message,不會建立另一筆 delivery intent。
Reconnect 後,使用最後保存的 sequence 補回後續 message:
GET /api/channels/{channel_id}/messages?after_seq=41&limit=100
Authorization: Bearer <jwt> Relay 依 seq 升冪回傳 channel history。這個 endpoint 的 limit 最大值為 100。
下一步:接收即時事件,並在重新連線後補齊訊息。