You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: PROTOCOL.md
+44-1Lines changed: 44 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -400,19 +400,62 @@ Clients **MUST** use the `Stream-Next-Offset` value returned in responses for su
400
400
401
401
## 7. Content Types
402
402
403
-
The protocol supports arbitrary MIME content types. The system operates at the byte level, leaving message framing and interpretation to clients.
403
+
The protocol supports arbitrary MIME content types. Most content types operate at the byte level, leaving message framing and interpretation to clients. The `application/json` content type has special semantics defined below.
404
404
405
405
**Restriction:**
406
406
407
407
- SSE mode (Section 5.7) **REQUIRES**`content-type: text/*` or `application/json`
408
408
409
409
Clients **MAY** use any content type for their streams, including:
410
410
411
+
-`application/json` for JSON mode with message boundary preservation
411
412
-`application/ndjson` for newline-delimited JSON
412
413
-`application/x-protobuf` for Protocol Buffer messages
413
414
-`text/plain` for plain text
414
415
- Custom types for application-specific formats
415
416
417
+
### 7.1. JSON Mode
418
+
419
+
Streams created with `Content-Type: application/json` have special semantics for message boundaries and batch operations.
420
+
421
+
#### Message Boundaries
422
+
423
+
For `application/json` streams, servers **MUST** preserve message boundaries. Each POST request stores messages as a distinct unit, and GET responses **MUST** return data as a JSON array containing all messages from the requested offset range.
424
+
425
+
#### Array Flattening for Batch Operations
426
+
427
+
When a POST request body contains a JSON array, servers **MUST** flatten exactly one level of the array, treating each element as a separate message. This enables clients to batch multiple messages in a single HTTP request while preserving individual message semantics.
428
+
429
+
**Examples (direct POST to server):**
430
+
431
+
- POST body `{"event": "created"}` stores one message: `{"event": "created"}`
432
+
- POST body `[{"event": "a"}, {"event": "b"}]` stores two messages: `{"event": "a"}`, `{"event": "b"}`
433
+
- POST body `[[1,2], [3,4]]` stores two messages: `[1,2]`, `[3,4]`
434
+
- POST body `[[[1,2,3]]]` stores one message: `[[1,2,3]]`
435
+
436
+
**Note:** Client libraries **MAY** automatically wrap individual values in arrays for batching. For example, a client calling `append({"x": 1})` might send POST body `[{"x": 1}]` to the server, which flattens it to store one message: `{"x": 1}`.
437
+
438
+
#### Empty Arrays
439
+
440
+
Servers **MUST** reject POST requests containing empty JSON arrays (`[]`) with `400 Bad Request`. Empty arrays represent no-op operations with no semantic meaning.
441
+
442
+
#### JSON Validation
443
+
444
+
Servers **MUST** validate that appended data is valid JSON. If validation fails, servers **MUST** return `400 Bad Request` with an appropriate error message.
445
+
446
+
#### Response Format
447
+
448
+
GET responses for `application/json` streams **MUST** return `Content-Type: application/json` with a body containing a JSON array of all messages in the requested range:
449
+
450
+
```http
451
+
HTTP/1.1 200 OK
452
+
Content-Type: application/json
453
+
454
+
[{"event":"created"},{"event":"updated"}]
455
+
```
456
+
457
+
If no messages exist in the range, servers **MUST** return an empty JSON array `[]`.
0 commit comments