Skip to content

Commit 888ab20

Browse files
authored
Add structured thread lineage endpoint (#41)
1 parent 6ef5136 commit 888ab20

4 files changed

Lines changed: 412 additions & 3 deletions

File tree

‎README.md‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

713769
Uploads a file attachment for a draft message. Only the owner may upload, and the message must not have been sent.

‎cmd/fmsg-webapi/main.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ func main() {
194194
fmsg.POST("/:id/add-to", msgHandler.AddRecipients)
195195
fmsg.GET("/:id/data", msgHandler.DownloadData)
196196
fmsg.GET("/:id/thread", msgHandler.ThreadText)
197+
fmsg.GET("/:id/thread/messages", msgHandler.ThreadMessages)
197198

198199
fmsg.POST("/:id/attach", attHandler.Upload)
199200
fmsg.GET("/:id/attach/:filename", attHandler.Download)

0 commit comments

Comments
 (0)