@@ -277,6 +277,8 @@ the application.
277277| ` POST ` | ` /fmsg/:id/read ` | Mark a message as read |
278278| ` POST ` | ` /fmsg/:id/add-to ` | Add recipients |
279279| ` GET ` | ` /fmsg/:id/data ` | Download message data |
280+ | ` GET ` | ` /fmsg/:id/thread ` | Render direct ancestry as plain text |
281+ | ` GET ` | ` /fmsg/:id/thread/messages ` | Load direct ancestry as structured JSON |
280282| ` POST ` | ` /fmsg/:id/attach ` | Upload an attachment |
281283| ` GET ` | ` /fmsg/:id/attach/:filename ` | Download an attachment |
282284| ` DELETE ` | ` /fmsg/:id/attach/:filename ` | Delete an attachment |
@@ -708,6 +710,60 @@ what came before); non-text bodies appear as a `[non-text message: <type>,
708710| ` 404 ` | Message not found |
709711| ` 403 ` | Authenticated user is not a participant of the requested message |
710712
713+ ### GET ` /fmsg/:id/thread/messages `
714+
715+ Returns the requested message and its direct ` pid ` ancestors as structured
716+ JSON, ordered from the root to the requested message. Sibling branches are not
717+ included. Valid UTF-8 ` text/* ` , ` application/json ` , and ` application/*+json `
718+ bodies are included inline. Binary bodies and attachments are represented by
719+ authenticated download paths so clients can fetch them concurrently.
720+
721+ Each visible message includes its normal protocol metadata, a body descriptor,
722+ attachment descriptors, and the canonical message SHA-256 when available.
723+ Because that digest covers the complete message including attachment data,
724+ clients may use the supplied per-part ` cache_key ` values for content-addressed
725+ caching. Locally delivered messages without a persisted canonical digest are
726+ returned with ` cacheable: false ` .
727+
728+ The authenticated identity must be a participant of the requested message.
729+ Ancestors it cannot read appear only as ` {"id": ..., "visible": false} ` and
730+ make the top-level ` complete ` field false. The walk is capped at 100 messages
731+ and textual bodies are capped at 32 MiB in aggregate; neither limit is silently
732+ truncated.
733+
734+ ** Response:** ` 200 OK ` , ` application/json ` :
735+
736+ ``` json
737+ {
738+ "root_id" : 41 ,
739+ "trigger_id" : 43 ,
740+ "complete" : true ,
741+ "messages" : [
742+ {
743+ "id" : 41 ,
744+ "visible" : true ,
745+ "pid" : null ,
746+ "from" : " @alice@example.com" ,
747+ "to" : [" @agent@example.net" ],
748+ "type" : " text/plain" ,
749+ "size" : 5 ,
750+ "message_sha256" : " 0123456789abcdef" ,
751+ "body" : {"type" : " text/plain" , "size" : 5 , "text" : " hello" , "cache_key" : " sha256:0123456789abcdef:body" , "cacheable" : true },
752+ "attachments" : []
753+ }
754+ ]
755+ }
756+ ```
757+
758+ ** Errors:**
759+
760+ | Status | Condition |
761+ | ------ | --------- |
762+ | ` 403 ` | Authenticated user is not a participant of the requested message |
763+ | ` 404 ` | Requested message does not exist |
764+ | ` 413 ` | Aggregate inline text exceeds 32 MiB (` thread_too_large ` ) |
765+ | ` 422 ` | Direct ancestry exceeds 100 messages (` thread_too_deep ` ) |
766+
711767### POST ` /fmsg/:id/attach `
712768
713769Uploads a file attachment for a draft message. Only the owner may upload, and the message must not have been sent.
0 commit comments