Follow felis-web-gateway#3: felis-json v1 envelope, input shape, list rows #8

Closed
opened 2026-09-22 13:47:31 +09:00 by natsukium · 0 comments
Owner

felis-web-gateway#3 followed felis core to 6da5620d and the WebSocket contract the browser half decodes changed shape. This component is still pinned at felis 32775067 and reads the pre-felis-json envelope, so the two halves do not talk until it follows. docs/broker.md and README.md in felis-web-gateway carry the current contract; the authoritative payload schema is felis crates/felis-grid/schemas/felis-json-v1.schema.json.

What changes

  1. Frame envelope. Was {"kind":"Grid"|"Image"|"Control","msg":…}. Now felis's own, verbatim: {"felis_json":1,"kind":"grid"|"image"|"conn"|"session","msg":…}. Refuse an unknown felis_json before reading msg; ignore unknown keys inside v1. The old Control bucket splits into conn and session (both still non-renderable).
  2. Broker stream frames. sid sits beside felis's keys: {"sid":2,"felis_json":1,"kind":"grid","msg":…}.
  3. msg payloads are the v1 DTOs, not derived serde of the Rust enums: family enums internally tagged {"type":"…"} in snake_case; RowJson is {row, cells} with cells tagged {"encoding":"rle", graphemes, attr_runs, sized_cells, soft_wrap_continued}; GraphemeJson tagged {"type":…}; session ids are 32-digit lowercase hex. theme_color is {"channel":…,"action":{"action":"set","rgb":{r,g,b}}} or {"action":"reset"}; conn welcome carries identity (typed) where it carried build_id.
  4. Browser → gateway input. Was {"KeyBytes":[…]}. Now the v1 Input payload alone (no envelope): {"type":"key_bytes","bytes":[…]}, {"type":"resize","dims":{rows,cols,pixel_w,pixel_h}}, {"type":"next_grid_frame"}, … On the broker still {"sid":2,"input":{…}}. Malformed input is dropped without a reply; a request whose re can be read always gets it.
  5. list rows. Now SessionInfoJson + host: session → id, rows/cols → dims.{rows,cols,pixel_w,pixel_h}, plus attachments and sequence (the daemon's creation order; sort tabs on it). last_notification is {notification:{title,body,urgency}, age_seconds}.
  6. {"ev":"notify"}. notification is {title, body, urgency} with lowercase urgency.
  7. {"ev":"closed"} now also fires with "reason":"undecodable daemon frame" when the gateway cannot encode a frame of a consumed family; offer re-attach.
  8. Prefixes. attach, destroy, tag accept 1–32 hex digits; the daemon resolves them; ambiguity is an error.

Unchanged: attach header and attach/create ok shape, control verb request shapes, subprotocol and token negotiation, keepalive.

Available, not required: {"type":"key",…} (InputMsg::Key) lets the browser send logical keys and have the daemon encode them against the keyboard modes it owns, instead of encoding bytes in JS.

Also: felis-fcast#2 moved .fcast to envelope v3 (frames carry the same felis-json v1 msg; header has felis_json instead of proto_major/proto_minor/encoding), so the replay fixtures here are pre-v3.

felis-web-gateway#3 followed felis core to `6da5620d` and the WebSocket contract the browser half decodes changed shape. This component is still pinned at felis `32775067` and reads the pre-`felis-json` envelope, so the two halves do not talk until it follows. `docs/broker.md` and `README.md` in felis-web-gateway carry the current contract; the authoritative payload schema is felis `crates/felis-grid/schemas/felis-json-v1.schema.json`. ## What changes 1. **Frame envelope.** Was `{"kind":"Grid"|"Image"|"Control","msg":…}`. Now felis's own, verbatim: `{"felis_json":1,"kind":"grid"|"image"|"conn"|"session","msg":…}`. Refuse an unknown `felis_json` before reading `msg`; ignore unknown keys inside v1. The old `Control` bucket splits into `conn` and `session` (both still non-renderable). 2. **Broker stream frames.** `sid` sits beside felis's keys: `{"sid":2,"felis_json":1,"kind":"grid","msg":…}`. 3. **`msg` payloads** are the v1 DTOs, not derived serde of the Rust enums: family enums internally tagged `{"type":"…"}` in `snake_case`; `RowJson` is `{row, cells}` with `cells` tagged `{"encoding":"rle", graphemes, attr_runs, sized_cells, soft_wrap_continued}`; `GraphemeJson` tagged `{"type":…}`; session ids are 32-digit lowercase hex. `theme_color` is `{"channel":…,"action":{"action":"set","rgb":{r,g,b}}}` or `{"action":"reset"}`; `conn` `welcome` carries `identity` (typed) where it carried `build_id`. 4. **Browser → gateway input.** Was `{"KeyBytes":[…]}`. Now the v1 `Input` payload alone (no envelope): `{"type":"key_bytes","bytes":[…]}`, `{"type":"resize","dims":{rows,cols,pixel_w,pixel_h}}`, `{"type":"next_grid_frame"}`, … On the broker still `{"sid":2,"input":{…}}`. Malformed input is dropped without a reply; a request whose `re` can be read always gets it. 5. **`list` rows.** Now `SessionInfoJson` + `host`: `session` → `id`, `rows`/`cols` → `dims.{rows,cols,pixel_w,pixel_h}`, plus `attachments` and `sequence` (the daemon's creation order; sort tabs on it). `last_notification` is `{notification:{title,body,urgency}, age_seconds}`. 6. **`{"ev":"notify"}`.** `notification` is `{title, body, urgency}` with lowercase urgency. 7. **`{"ev":"closed"}`** now also fires with `"reason":"undecodable daemon frame"` when the gateway cannot encode a frame of a consumed family; offer re-attach. 8. **Prefixes.** `attach`, `destroy`, `tag` accept 1–32 hex digits; the daemon resolves them; ambiguity is an error. Unchanged: attach header and `attach`/`create` `ok` shape, control verb request shapes, subprotocol and token negotiation, keepalive. Available, not required: `{"type":"key",…}` (`InputMsg::Key`) lets the browser send logical keys and have the daemon encode them against the keyboard modes it owns, instead of encoding bytes in JS. Also: felis-fcast#2 moved `.fcast` to envelope v3 (frames carry the same felis-json v1 `msg`; header has `felis_json` instead of `proto_major`/`proto_minor`/`encoding`), so the replay fixtures here are pre-v3.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
natsukium/felis-web-component#8
No description provided.