My agentic slop goes here. Not intended for anyone else!
1(** JMAP Response Object
2
3 A Response object is returned from the JMAP API endpoint in response to a Request.
4 It contains method responses and the current session state.
5
6 Reference: RFC 8620 Section 3.4
7 Test files:
8 - test/data/core/response_echo.json
9 - test/data/core/response_get.json
10 - All response_*.json files
11*)
12
13(** Main response type *)
14type t = {
15 method_responses : Jmap_invocation.response_list;
16 created_ids : (Jmap_id.t * Jmap_id.t) list option;
17 session_state : string;
18}
19
20(** Accessors *)
21let method_responses t = t.method_responses
22let created_ids t = t.created_ids
23let session_state t = t.session_state
24
25(** Create a response *)
26let make ?(created_ids=None) ~method_responses ~session_state () =
27 { method_responses; created_ids; session_state }
28
29(** Parser submodule *)
30module Parser = struct
31 (** Parse response from JSON value.
32 Test files: test/data/core/response_*.json *)
33 let of_json json =
34 match json with
35 | `O fields ->
36 let get_field name =
37 match List.assoc_opt name fields with
38 | Some v -> v
39 | None -> raise (Jmap_error.Parse_error (Printf.sprintf "Missing field: %s" name))
40 in
41
42 (* Parse methodResponses - similar to parsing request methodCalls *)
43 let method_responses =
44 match get_field "methodResponses" with
45 | `A responses ->
46 List.map (fun resp_json ->
47 (* Each response is ["method", {...}, "callId"] *)
48 (* For now, just parse as generic invocations *)
49 match resp_json with
50 | `A [(`String method_name); response; (`String call_id)] ->
51 (* Parse as response invocation, storing raw JSON *)
52 Jmap_invocation.PackedResponse (Jmap_invocation.ResponseInvocation {
53 method_name;
54 response;
55 call_id;
56 witness = Jmap_invocation.Echo;
57 })
58 | _ -> raise (Jmap_error.Parse_error "Invalid method response format")
59 ) responses
60 | _ -> raise (Jmap_error.Parse_error "methodResponses must be an array")
61 in
62
63 (* Parse createdIds (optional) *)
64 let created_ids =
65 match List.assoc_opt "createdIds" fields with
66 | Some (`O ids) ->
67 Some (List.map (fun (k, v) ->
68 match v with
69 | `String id -> (Jmap_id.of_string k, Jmap_id.of_string id)
70 | _ -> raise (Jmap_error.Parse_error "createdIds values must be strings")
71 ) ids)
72 | Some _ -> raise (Jmap_error.Parse_error "createdIds must be an object")
73 | None -> None
74 in
75
76 (* Parse sessionState *)
77 let session_state =
78 match get_field "sessionState" with
79 | `String s -> s
80 | _ -> raise (Jmap_error.Parse_error "sessionState must be a string")
81 in
82
83 { method_responses; created_ids; session_state }
84 | _ -> raise (Jmap_error.Parse_error "Response must be a JSON object")
85
86 (** Parse response from JSON string *)
87 let of_string s =
88 try
89 of_json (Ezjsonm.from_string s)
90 with
91 | Ezjsonm.Parse_error (_, msg) ->
92 raise (Jmap_error.Parse_error ("Invalid JSON: " ^ msg))
93
94 (** Parse response from input channel *)
95 let of_channel ic =
96 try
97 of_json (Ezjsonm.from_channel ic)
98 with
99 | Ezjsonm.Parse_error (_, msg) ->
100 raise (Jmap_error.Parse_error ("Invalid JSON: " ^ msg))
101end
102
103(** Serialization *)
104let to_json _t =
105 (* TODO: Implement JSON serialization *)
106 raise (Jmap_error.Parse_error "Response.to_json not yet implemented")