···18181919open Lwt.Syntax
2020open Jmap
2121-open Jmap_mail
2121+open Jmap.Mail
2222open Cmdliner
2323-module Mail = Jmap_mail.Types
2323+module Mail = Jmap.Proto.Types
24242525(** Prints the email details *)
2626let print_email ~show_labels (email : Mail.email) =
···4242 (* Format labels/keywords if requested *)
4343 let labels_str =
4444 if show_labels then
4545- let formatted = Jmap_mail.Types.format_email_keywords email.keywords in
4545+ let formatted = Jmap.Proto.Types.format_email_keywords email.keywords in
4646 if formatted <> "" then
4747 " [" ^ formatted ^ "]"
4848 else
···7373 Printf.printf "=====================\n";
74747575 (* Step 1: Get all mailboxes *)
7676- let* mailboxes_result = Jmap_mail.get_mailboxes conn ~account_id in
7676+ let* mailboxes_result = Jmap.Proto.get_mailboxes conn ~account_id in
7777 match mailboxes_result with
7878 | Error err ->
7979 Printf.printf "Error getting mailboxes: %s\n" (Api.string_of_error err);
···9090 Printf.printf "Using mailbox: %s\n" first_mailbox.Mail.name;
91919292 (* Step 3: Get emails from the selected mailbox *)
9393- let* emails_result = Jmap_mail.get_messages_in_mailbox
9393+ let* emails_result = Jmap.Proto.get_messages_in_mailbox
9494 conn
9595 ~account_id
9696 ~mailbox_id:first_mailbox.Mail.id
···108108 (List.length emails);
109109110110 (* Display some basic information about the emails *)
111111- List.iteri (fun i (email:Jmap_mail.Types.email) ->
111111+ List.iteri (fun i (email:Jmap.Proto.Types.email) ->
112112 let subject = Option.value ~default:"<no subject>" email.Mail.subject in
113113 Printf.printf " %d. %s\n" (i + 1) subject
114114 ) emails;
···159159 | Ok conn ->
160160 (* Get the primary account ID *)
161161 let primary_account_id =
162162- let mail_capability = Jmap_mail.Capability.to_string Jmap_mail.Capability.Mail in
162162+ let mail_capability = Jmap.Proto.Capability.to_string Jmap.Proto.Capability.Mail in
163163 match List.assoc_opt mail_capability conn.session.primary_accounts with
164164 | Some id -> id
165165 | None ->
···220220 if sender_filter <> "" then begin
221221 Printf.printf "Filtering by sender: %s\n" sender_filter;
222222 List.filter (fun email ->
223223- Jmap_mail.email_matches_sender email sender_filter
223223+ Jmap.Proto.email_matches_sender email sender_filter
224224 ) filtered_by_unread
225225 end else
226226 filtered_by_unread
+7-7
bin/fastmail_send.ml
···5252 (* Initialize JMAP connection *)
5353 let fastmail_uri = "https://api.fastmail.com/jmap/session" in
5454 Lwt_main.run begin
5555- let* conn_result = Jmap_mail.login_with_token ~uri:fastmail_uri ~api_token:token in
5555+ let* conn_result = Jmap.Proto.login_with_token ~uri:fastmail_uri ~api_token:token in
5656 match conn_result with
5757 | Error err ->
5858 let msg = Jmap.Api.string_of_error err in
···7878 | Some email -> Lwt.return_ok email
7979 | None ->
8080 (* Get first available identity *)
8181- let* identities_result = Jmap_mail.get_identities conn ~account_id in
8181+ let* identities_result = Jmap.Proto.get_identities conn ~account_id in
8282 match identities_result with
8383 | Ok [] ->
8484 log_error "No identities found for account";
···9999 (String.concat ", " to_addresses);
100100101101 let* submission_result =
102102- Jmap_mail.create_and_submit_email
102102+ Jmap.Proto.create_and_submit_email
103103 conn
104104 ~account_id
105105 ~from:from_email
···118118 log_success "Email sent successfully (Submission ID: %s)" submission_id;
119119 (* Wait briefly then check submission status *)
120120 let* () = Lwt_unix.sleep 1.0 in
121121- let* status_result = Jmap_mail.get_submission_status
121121+ let* status_result = Jmap.Proto.get_submission_status
122122 conn
123123 ~account_id
124124 ~submission_id
···126126127127 (match status_result with
128128 | Ok status ->
129129- let status_text = match status.Jmap_mail.Types.undo_status with
129129+ let status_text = match status.Jmap.Proto.Types.undo_status with
130130 | Some `pending -> "Pending"
131131 | Some `final -> "Final (delivered)"
132132 | Some `canceled -> "Canceled"
···134134 in
135135 log_info "Submission status: %s" status_text;
136136137137- (match status.Jmap_mail.Types.delivery_status with
137137+ (match status.Jmap.Proto.Types.delivery_status with
138138 | Some statuses ->
139139 List.iter (fun (email, status) ->
140140- let delivery = match status.Jmap_mail.Types.delivered with
140140+ let delivery = match status.Jmap.Proto.Types.delivered with
141141 | Some "yes" -> "Delivered"
142142 | Some "no" -> "Failed"
143143 | Some "queued" -> "Queued"
+48-48
bin/jmap.ml
···1717 if String.length s <= max_len then s
1818 else String.sub s 0 (max_len - 3) ^ "..."
19192020-let format_email_address (addr : Jmap_mail.Email_address.t) =
2020+let format_email_address (addr : Jmap.Proto.Email_address.t) =
2121 match addr.name with
2222 | Some name -> Printf.sprintf "%s <%s>" name addr.email
2323 | None -> addr.email
···5151 ) session.capabilities;
5252 Fmt.pr "@, %a@," Fmt.(styled `Bold string) "Accounts:";
5353 List.iter (fun (id, acct) ->
5454- let acct : Jmap_proto.Session.Account.t = acct in
5454+ let acct : Jmap.Proto.Session.Account.t = acct in
5555 Fmt.pr " %a: %s (personal=%b, read_only=%b)@,"
5656- Fmt.(styled `Cyan string) (Jmap_proto.Id.to_string id)
5656+ Fmt.(styled `Cyan string) (Jmap.Proto.Id.to_string id)
5757 acct.name acct.is_personal acct.is_read_only
5858 ) session.accounts;
5959 Fmt.pr "@, %a@," Fmt.(styled `Bold string) "Primary Accounts:";
6060 List.iter (fun (cap, id) ->
6161- Fmt.pr " %s: %s@," cap (Jmap_proto.Id.to_string id)
6161+ Fmt.pr " %s: %s@," cap (Jmap.Proto.Id.to_string id)
6262 ) session.primary_accounts;
6363 Fmt.pr "@]@."
6464 in
···7575 let client = Jmap_eio.Cli.create_client ~sw env cfg in
7676 let account_id = Jmap_eio.Cli.get_account_id cfg client in
77777878- Jmap_eio.Cli.debug cfg "Fetching mailboxes for account %s" (Jmap_proto.Id.to_string account_id);
7878+ Jmap_eio.Cli.debug cfg "Fetching mailboxes for account %s" (Jmap.Proto.Id.to_string account_id);
79798080 let req = Jmap_eio.Client.Build.(
8181 make_request
8282- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
8282+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
8383 [mailbox_get ~call_id:"m1" ~account_id ()]
8484 ) in
8585···9797 Fmt.(styled `Bold string) "Mailboxes"
9898 result.state;
9999 (* Sort by sort_order then name *)
100100- let sorted = List.sort (fun (a : Jmap_mail.Mailbox.t) (b : Jmap_mail.Mailbox.t) ->
100100+ let sorted = List.sort (fun (a : Jmap.Proto.Mailbox.t) (b : Jmap.Proto.Mailbox.t) ->
101101 let cmp = Int64.compare a.sort_order b.sort_order in
102102 if cmp <> 0 then cmp else String.compare a.name b.name
103103 ) result.list in
104104- List.iter (fun (mbox : Jmap_mail.Mailbox.t) ->
104104+ List.iter (fun (mbox : Jmap.Proto.Mailbox.t) ->
105105 let role_str = match mbox.role with
106106- | Some role -> Printf.sprintf " [%s]" (Jmap_mail.Mailbox.role_to_string role)
106106+ | Some role -> Printf.sprintf " [%s]" (Jmap.Proto.Mailbox.role_to_string role)
107107 | None -> ""
108108 in
109109 Fmt.pr " %a %s%a (%Ld total, %Ld unread)@,"
110110- Fmt.(styled `Cyan string) (Jmap_proto.Id.to_string mbox.id)
110110+ Fmt.(styled `Cyan string) (Jmap.Proto.Id.to_string mbox.id)
111111 mbox.name
112112 Fmt.(styled `Yellow string) role_str
113113 mbox.total_emails mbox.unread_emails
···140140 (* Build filter if mailbox specified *)
141141 let filter = match mailbox_id_str with
142142 | Some id_str ->
143143- let mailbox_id = Jmap_proto.Id.of_string_exn id_str in
144144- let cond : Jmap_mail.Email.Filter_condition.t = {
143143+ let mailbox_id = Jmap.Proto.Id.of_string_exn id_str in
144144+ let cond : Jmap.Proto.Email.Filter_condition.t = {
145145 in_mailbox = Some mailbox_id;
146146 in_mailbox_other_than = None;
147147 before = None; after = None;
···155155 cc = None; bcc = None; subject = None;
156156 body = None; header = None;
157157 } in
158158- Some (Jmap_proto.Filter.Condition cond)
158158+ Some (Jmap.Proto.Filter.Condition cond)
159159 | None -> None
160160 in
161161162162- let sort = [Jmap_proto.Filter.comparator ~is_ascending:false "receivedAt"] in
162162+ let sort = [Jmap.Proto.Filter.comparator ~is_ascending:false "receivedAt"] in
163163 let query_inv = Jmap_eio.Client.Build.email_query
164164 ~call_id:"q1"
165165 ~account_id
···171171172172 let req = Jmap_eio.Client.Build.(
173173 make_request
174174- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
174174+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
175175 [query_inv]
176176 ) in
177177···202202 in
203203 let req2 = Jmap_eio.Client.Build.(
204204 make_request
205205- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
205205+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
206206 [get_inv]
207207 ) in
208208···222222 (match query_result.total with
223223 | Some n -> Int64.to_string n
224224 | None -> "?");
225225- List.iter (fun (email : Jmap_mail.Email.t) ->
225225+ List.iter (fun (email : Jmap.Proto.Email.t) ->
226226 let from_str = match email.from with
227227 | Some addrs -> format_email_addresses addrs
228228 | None -> "(unknown)"
···231231 let flags = format_keywords email.keywords in
232232 let flag_str = if flags = "" then "" else " [" ^ flags ^ "]" in
233233 Fmt.pr " %a %s@,"
234234- Fmt.(styled `Cyan string) (Jmap_proto.Id.to_string email.id)
234234+ Fmt.(styled `Cyan string) (Jmap.Proto.Id.to_string email.id)
235235 (ptime_to_string email.received_at);
236236 Fmt.pr " From: %s@," (truncate_string 60 from_str);
237237 Fmt.pr " Subject: %a%s@,"
···267267 Jmap_eio.Cli.debug cfg "Searching for: %s" query;
268268269269 (* Build text filter *)
270270- let cond : Jmap_mail.Email.Filter_condition.t = {
270270+ let cond : Jmap.Proto.Email.Filter_condition.t = {
271271 in_mailbox = None; in_mailbox_other_than = None;
272272 before = None; after = None;
273273 min_size = None; max_size = None;
···281281 cc = None; bcc = None; subject = None;
282282 body = None; header = None;
283283 } in
284284- let filter = Jmap_proto.Filter.Condition cond in
284284+ let filter = Jmap.Proto.Filter.Condition cond in
285285286286- let sort = [Jmap_proto.Filter.comparator ~is_ascending:false "receivedAt"] in
286286+ let sort = [Jmap.Proto.Filter.comparator ~is_ascending:false "receivedAt"] in
287287 let query_inv = Jmap_eio.Client.Build.email_query
288288 ~call_id:"q1"
289289 ~account_id
···295295296296 let req = Jmap_eio.Client.Build.(
297297 make_request
298298- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
298298+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
299299 [query_inv]
300300 ) in
301301···325325 in
326326 let req2 = Jmap_eio.Client.Build.(
327327 make_request
328328- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
328328+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
329329 [get_inv]
330330 ) in
331331···343343 Fmt.(styled `Bold string) "Search results"
344344 query
345345 (List.length get_result.list);
346346- List.iter (fun (email : Jmap_mail.Email.t) ->
346346+ List.iter (fun (email : Jmap.Proto.Email.t) ->
347347 let from_str = match email.from with
348348 | Some addrs -> format_email_addresses addrs
349349 | None -> "(unknown)"
350350 in
351351 let subject = Option.value email.subject ~default:"(no subject)" in
352352 Fmt.pr " %a %s@,"
353353- Fmt.(styled `Cyan string) (Jmap_proto.Id.to_string email.id)
353353+ Fmt.(styled `Cyan string) (Jmap.Proto.Id.to_string email.id)
354354 (ptime_to_string email.received_at);
355355 Fmt.pr " From: %s@," (truncate_string 60 from_str);
356356 Fmt.pr " Subject: %a@,"
···387387 Jmap_eio.Cli.debug cfg "Fetching %d most recent emails" limit;
388388389389 (* Query for recent emails *)
390390- let sort = [Jmap_proto.Filter.comparator ~is_ascending:false "receivedAt"] in
390390+ let sort = [Jmap.Proto.Filter.comparator ~is_ascending:false "receivedAt"] in
391391 let query_inv = Jmap_eio.Client.Build.email_query
392392 ~call_id:"q1"
393393 ~account_id
···398398399399 let req = Jmap_eio.Client.Build.(
400400 make_request
401401- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
401401+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
402402 [query_inv]
403403 ) in
404404···432432 in
433433 let req2 = Jmap_eio.Client.Build.(
434434 make_request
435435- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
435435+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
436436 [get_inv]
437437 ) in
438438···453453 (* Output based on format *)
454454 match format with
455455 | `Compact ->
456456- List.iter (fun (email : Jmap_mail.Email.t) ->
456456+ List.iter (fun (email : Jmap.Proto.Email.t) ->
457457 let from_str = match email.from with
458458 | Some (addr :: _) ->
459459 Option.value addr.name ~default:addr.email
···462462 let subject = Option.value email.subject ~default:"(no subject)" in
463463 let flags = format_keywords email.keywords in
464464 Printf.printf "%s\t%s\t%s\t%s\t%s\n"
465465- (Jmap_proto.Id.to_string email.id)
465465+ (Jmap.Proto.Id.to_string email.id)
466466 (ptime_to_string email.received_at)
467467 (truncate_string 20 from_str)
468468 (truncate_string 50 subject)
···478478 Fmt.pr "%-12s %-19s %-20s %-40s %s@,"
479479 "ID" "Date" "From" "Subject" "Flags";
480480 Fmt.pr "%s@," (String.make 110 '-');
481481- List.iter (fun (email : Jmap_mail.Email.t) ->
481481+ List.iter (fun (email : Jmap.Proto.Email.t) ->
482482 let from_str = match email.from with
483483 | Some (addr :: _) ->
484484 Option.value addr.name ~default:addr.email
···487487 let subject = Option.value email.subject ~default:"(no subject)" in
488488 let flags = format_keywords email.keywords in
489489 let id_short =
490490- let id = Jmap_proto.Id.to_string email.id in
490490+ let id = Jmap.Proto.Id.to_string email.id in
491491 if String.length id > 12 then String.sub id 0 12 else id
492492 in
493493 Fmt.pr "%-12s %s %-20s %-40s %s@,"
···503503 Fmt.pr "@[<v>%a (%d emails)@,@,"
504504 Fmt.(styled `Bold string) "Recent Emails"
505505 (List.length get_result.list);
506506- List.iteri (fun i (email : Jmap_mail.Email.t) ->
506506+ List.iteri (fun i (email : Jmap.Proto.Email.t) ->
507507 let from_str = match email.from with
508508 | Some addrs -> format_email_addresses addrs
509509 | None -> "(unknown)"
···524524 Fmt.(styled `Bold string) "---"
525525 (i + 1) (List.length get_result.list);
526526 Fmt.pr "ID: %a@,"
527527- Fmt.(styled `Cyan string) (Jmap_proto.Id.to_string email.id);
528528- Fmt.pr "Thread: %s@," (Jmap_proto.Id.to_string email.thread_id);
527527+ Fmt.(styled `Cyan string) (Jmap.Proto.Id.to_string email.id);
528528+ Fmt.pr "Thread: %s@," (Jmap.Proto.Id.to_string email.thread_id);
529529 Fmt.pr "Date: %s@," (ptime_to_string email.received_at);
530530 Fmt.pr "From: %s@," from_str;
531531 if to_str <> "" then Fmt.pr "To: %s@," to_str;
···557557 let client = Jmap_eio.Cli.create_client ~sw env cfg in
558558 let account_id = Jmap_eio.Cli.get_account_id cfg client in
559559560560- let email_id = Jmap_proto.Id.of_string_exn email_id_str in
560560+ let email_id = Jmap.Proto.Id.of_string_exn email_id_str in
561561562562 (* First get the email to find its thread ID - include required properties *)
563563 let get_inv = Jmap_eio.Client.Build.email_get
···569569 in
570570 let req = Jmap_eio.Client.Build.(
571571 make_request
572572- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
572572+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
573573 [get_inv]
574574 ) in
575575···589589 exit 1
590590 | email :: _ ->
591591 let thread_id = email.thread_id in
592592- Jmap_eio.Cli.debug cfg "Thread ID: %s" (Jmap_proto.Id.to_string thread_id);
592592+ Jmap_eio.Cli.debug cfg "Thread ID: %s" (Jmap.Proto.Id.to_string thread_id);
593593594594 (* Get the thread *)
595595 let thread_inv = Jmap_eio.Client.Build.thread_get
···600600 in
601601 let req2 = Jmap_eio.Client.Build.(
602602 make_request
603603- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
603603+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
604604 [thread_inv]
605605 ) in
606606···622622 let email_ids = thread.email_ids in
623623 Fmt.pr "@[<v>%a %s (%d emails)@,@,"
624624 Fmt.(styled `Bold string) "Thread"
625625- (Jmap_proto.Id.to_string thread.id)
625625+ (Jmap.Proto.Id.to_string thread.id)
626626 (List.length email_ids);
627627628628 (* Fetch all emails in thread *)
···636636 in
637637 let req3 = Jmap_eio.Client.Build.(
638638 make_request
639639- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail]
639639+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail]
640640 [get_inv2]
641641 ) in
642642···650650 Fmt.epr "Parse error: %s@." (Jsont.Error.to_string e);
651651 exit 1
652652 | Ok emails_result ->
653653- List.iter (fun (email : Jmap_mail.Email.t) ->
653653+ List.iter (fun (email : Jmap.Proto.Email.t) ->
654654 let from_str = match email.from with
655655 | Some addrs -> format_email_addresses addrs
656656 | None -> "(unknown)"
657657 in
658658 let subject = Option.value email.subject ~default:"(no subject)" in
659659 Fmt.pr " %a %s@,"
660660- Fmt.(styled `Cyan string) (Jmap_proto.Id.to_string email.id)
660660+ Fmt.(styled `Cyan string) (Jmap.Proto.Id.to_string email.id)
661661 (ptime_to_string email.received_at);
662662 Fmt.pr " From: %s@," (truncate_string 60 from_str);
663663 Fmt.pr " Subject: %a@,@,"
···680680681681 let req = Jmap_eio.Client.Build.(
682682 make_request
683683- ~capabilities:[Jmap_proto.Capability.core; Jmap_proto.Capability.mail;
684684- Jmap_proto.Capability.submission]
683683+ ~capabilities:[Jmap.Proto.Capability.core; Jmap.Proto.Capability.mail;
684684+ Jmap.Proto.Capability.submission]
685685 [identity_get ~call_id:"i1" ~account_id ()]
686686 ) in
687687···691691 exit 1
692692 | Ok response ->
693693 match Jmap_eio.Client.Parse.parse_response ~call_id:"i1"
694694- (Jmap_eio.Client.Parse.get_response Jmap_mail.Identity.jsont)
694694+ (Jmap_eio.Client.Parse.get_response Jmap.Proto.Identity.jsont)
695695 response with
696696 | Error e ->
697697 Fmt.epr "Parse error: %s@." (Jsont.Error.to_string e);
···700700 Fmt.pr "@[<v>%a (state: %s)@,@,"
701701 Fmt.(styled `Bold string) "Identities"
702702 result.state;
703703- List.iter (fun (ident : Jmap_mail.Identity.t) ->
703703+ List.iter (fun (ident : Jmap.Proto.Identity.t) ->
704704 Fmt.pr " %a@,"
705705- Fmt.(styled `Cyan string) (Jmap_proto.Id.to_string ident.id);
705705+ Fmt.(styled `Cyan string) (Jmap.Proto.Id.to_string ident.id);
706706 Fmt.pr " Name: %s@," ident.name;
707707 Fmt.pr " Email: %a@,"
708708 Fmt.(styled `Green string) ident.email;
+8-8
bin/tutorial_examples.ml
···2233open Lwt.Syntax
44open Jmap
55-open Jmap_mail
55+open Jmap.Mail
6677(* Example: Authentication *)
88let auth_example () =
···1313 Printf.eprintf "Error: JMAP_API_TOKEN environment variable not set\n";
1414 Lwt.return_none
1515 | Some token ->
1616- let+ result = Jmap_mail.login_with_token
1616+ let+ result = Jmap.Proto.login_with_token
1717 ~uri:"https://api.fastmail.com/jmap/session"
1818 ~api_token:token
1919 in
···2323 | Ok conn ->
2424 (* Get the primary account ID *)
2525 let account_id =
2626- let mail_capability = Jmap_mail.Capability.to_string Jmap_mail.Capability.Mail in
2626+ let mail_capability = Jmap.Proto.Capability.to_string Jmap.Proto.Capability.Mail in
2727 match List.assoc_opt mail_capability conn.session.primary_accounts with
2828 | Some id -> id
2929 | None ->
···4545(* Example: Working with Mailboxes *)
4646let mailbox_example (conn, account_id) =
4747 (* Get all mailboxes *)
4848- let+ mailboxes_result = Jmap_mail.get_mailboxes conn ~account_id in
4848+ let+ mailboxes_result = Jmap.Proto.get_mailboxes conn ~account_id in
49495050 match mailboxes_result with
5151 | Ok mailboxes ->
···7878(* Example: Working with Emails *)
7979let email_example (conn, account_id, mailbox_id) =
8080 (* Get emails from mailbox *)
8181- let+ emails_result = Jmap_mail.get_messages_in_mailbox
8181+ let+ emails_result = Jmap.Proto.get_messages_in_mailbox
8282 conn
8383 ~account_id
8484 ~mailbox_id
···9191 Printf.printf "Found %d emails\n" (List.length emails);
92929393 (* Display emails *)
9494- List.iter (fun (email:Jmap_mail.Types.email) ->
9494+ List.iter (fun (email:Jmap.Proto.Types.email) ->
9595 (* Using explicit module path for Types to avoid ambiguity *)
9696- let module Mail = Jmap_mail.Types in
9696+ let module Mail = Jmap.Proto.Types in
97979898 (* Get sender info *)
9999 let from = match email.Mail.from with
···127127128128 match emails with
129129 | [] -> None
130130- | hd::_ -> Some (conn, account_id, hd.Jmap_mail.Types.id)
130130+ | hd::_ -> Some (conn, account_id, hd.Jmap.Proto.Types.id)
131131 end
132132 | Error e ->
133133 Printf.eprintf "Error getting emails: %s\n"
+2-2
eio/cli.ml
···197197198198let get_account_id cfg client =
199199 match cfg.account_id with
200200- | Some id -> Jmap_proto.Id.of_string_exn id
200200+ | Some id -> Jmap.Proto.Id.of_string_exn id
201201 | None ->
202202 let session = Client.session client in
203203- match Jmap_proto.Session.primary_account_for Jmap_proto.Capability.mail session with
203203+ match Jmap.Proto.Session.primary_account_for Jmap.Proto.Capability.mail session with
204204 | Some id -> id
205205 | None ->
206206 Fmt.epr "@[<v>%a No primary mail account found. Specify --account.@]@."
+1-1
eio/cli.mli
···8686(** [create_client ~sw env cfg] creates a JMAP client from the configuration.
8787 Exits with error message on connection failure. *)
88888989-val get_account_id : config -> Client.t -> Jmap_proto.Id.t
8989+val get_account_id : config -> Client.t -> Jmap.Proto.Id.t
9090(** [get_account_id cfg client] returns the account ID from config, or the
9191 primary mail account if not specified. Exits with error if no account found. *)
9292
+20-20
eio/client.ml
···5566type error =
77 | Http_error of int * string
88- | Jmap_error of Jmap_proto.Error.Request_error.t
88+ | Jmap_error of Jmap.Proto.Error.Request_error.t
99 | Json_error of Jsont.Error.t
1010 | Session_error of string
1111 | Connection_error of string
···1515 Format.fprintf fmt "HTTP error %d: %s" code msg
1616 | Jmap_error err ->
1717 Format.fprintf fmt "JMAP error: %s"
1818- (Jmap_proto.Error.Request_error.urn_to_string err.type_)
1818+ (Jmap.Proto.Error.Request_error.urn_to_string err.type_)
1919 | Json_error err ->
2020 Format.fprintf fmt "JSON error: %s" (Jsont.Error.to_string err)
2121 | Session_error msg ->
···2929exception Jmap_client_error of error
30303131type t = {
3232- mutable session : Jmap_proto.Session.t;
3232+ mutable session : Jmap.Proto.Session.t;
3333 requests : Requests.t;
3434 auth : Requests.Auth.t option;
3535 session_url : string;
3636}
37373838let session t = t.session
3939-let api_url t = Jmap_proto.Session.api_url t.session
4040-let upload_url t = Jmap_proto.Session.upload_url t.session
4141-let download_url t = Jmap_proto.Session.download_url t.session
3939+let api_url t = Jmap.Proto.Session.api_url t.session
4040+let upload_url t = Jmap.Proto.Session.upload_url t.session
4141+let download_url t = Jmap.Proto.Session.download_url t.session
42424343let create ?auth ~session requests =
4444- let session_url = Jmap_proto.Session.api_url session in
4444+ let session_url = Jmap.Proto.Session.api_url session in
4545 { session; requests; auth; session_url }
46464747let fetch_session ?auth requests url =
···119119120120let expand_upload_url t ~account_id =
121121 let template = upload_url t in
122122- let account_id_str = Jmap_proto.Id.to_string account_id in
122122+ let account_id_str = Jmap.Proto.Id.to_string account_id in
123123 (* Simple template expansion for {accountId} *)
124124 let re = Str.regexp "{accountId}" in
125125 Str.global_replace re account_id_str template
···154154155155let expand_download_url t ~account_id ~blob_id ?name ?accept () =
156156 let template = download_url t in
157157- let account_id_str = Jmap_proto.Id.to_string account_id in
158158- let blob_id_str = Jmap_proto.Id.to_string blob_id in
157157+ let account_id_str = Jmap.Proto.Id.to_string account_id in
158158+ let blob_id_str = Jmap.Proto.Id.to_string blob_id in
159159 let name_str = Option.value name ~default:"download" in
160160 let type_str = Option.value accept ~default:"application/octet-stream" in
161161 (* Simple template expansion *)
···190190191191(* Convenience builders *)
192192module Build = struct
193193- open Jmap_proto
193193+ open Jmap.Proto
194194195195 let json_of_id id =
196196 Jsont.String (Id.to_string id, Jsont.Meta.none)
···264264 let args = match filter with
265265 | None -> args
266266 | Some f ->
267267- ("filter", encode_to_json Jmap_mail.Mail_filter.mailbox_filter_jsont f) :: args
267267+ ("filter", encode_to_json Jmap.Proto.Mail_filter.mailbox_filter_jsont f) :: args
268268 in
269269 let args = match sort with
270270 | None -> args
···336336 let args = match filter with
337337 | None -> args
338338 | Some f ->
339339- ("filter", encode_to_json Jmap_mail.Mail_filter.email_filter_jsont f) :: args
339339+ ("filter", encode_to_json Jmap.Proto.Mail_filter.email_filter_jsont f) :: args
340340 in
341341 let args = match sort with
342342 | None -> args
···413413 let args = match filter with
414414 | None -> args
415415 | Some f ->
416416- ("filter", encode_to_json Jmap_mail.Mail_filter.submission_filter_jsont f) :: args
416416+ ("filter", encode_to_json Jmap.Proto.Mail_filter.submission_filter_jsont f) :: args
417417 in
418418 let args = match sort with
419419 | None -> args
···433433 let vacation_response_get ~call_id ~account_id () =
434434 let args = [
435435 ("accountId", json_of_id account_id);
436436- ("ids", json_of_id_list [Jmap_mail.Vacation.singleton_id]);
436436+ ("ids", json_of_id_list [Jmap.Proto.Vacation.singleton_id]);
437437 ] in
438438 make_invocation ~name:"VacationResponse/get" ~call_id args
439439···447447448448(* Response parsing helpers *)
449449module Parse = struct
450450- open Jmap_proto
450450+ open Jmap.Proto
451451452452 let decode_from_json jsont json =
453453 Jsont.Json.decode' jsont json
···484484 (* Mail-specific parsers *)
485485486486 let mailbox_get_response =
487487- get_response Jmap_mail.Mailbox.jsont
487487+ get_response Jmap.Proto.Mailbox.jsont
488488489489 let email_get_response =
490490- get_response Jmap_mail.Email.jsont
490490+ get_response Jmap.Proto.Email.jsont
491491492492 let thread_get_response =
493493- get_response Jmap_mail.Thread.jsont
493493+ get_response Jmap.Proto.Thread.jsont
494494495495 let identity_get_response =
496496- get_response Jmap_mail.Identity.jsont
496496+ get_response Jmap.Proto.Identity.jsont
497497498498 (* Convenience functions *)
499499
+78-78
eio/client.mli
···1616type error =
1717 | Http_error of int * string
1818 (** HTTP error with status code and message. *)
1919- | Jmap_error of Jmap_proto.Error.Request_error.t
1919+ | Jmap_error of Jmap.Proto.Error.Request_error.t
2020 (** JMAP protocol error at request level. *)
2121 | Json_error of Jsont.Error.t
2222 (** JSON encoding/decoding error. *)
···39394040val create :
4141 ?auth:Requests.Auth.t ->
4242- session:Jmap_proto.Session.t ->
4242+ session:Jmap.Proto.Session.t ->
4343 Requests.t ->
4444 t
4545(** [create ?auth ~session requests] creates a JMAP client from an existing
···75757676(** {1 Session Access} *)
77777878-val session : t -> Jmap_proto.Session.t
7878+val session : t -> Jmap.Proto.Session.t
7979(** [session client] returns the current JMAP session. *)
80808181val refresh_session : t -> (unit, error) result
···98989999val request :
100100 t ->
101101- Jmap_proto.Request.t ->
102102- (Jmap_proto.Response.t, error) result
101101+ Jmap.Proto.Request.t ->
102102+ (Jmap.Proto.Response.t, error) result
103103(** [request client req] executes a JMAP request and returns the response. *)
104104105105val request_exn :
106106 t ->
107107- Jmap_proto.Request.t ->
108108- Jmap_proto.Response.t
107107+ Jmap.Proto.Request.t ->
108108+ Jmap.Proto.Response.t
109109(** [request_exn client req] is like {!request} but raises on error. *)
110110111111(** {1 Blob Operations} *)
112112113113val upload :
114114 t ->
115115- account_id:Jmap_proto.Id.t ->
115115+ account_id:Jmap.Proto.Id.t ->
116116 content_type:string ->
117117 data:string ->
118118- (Jmap_proto.Blob.upload_response, error) result
118118+ (Jmap.Proto.Blob.upload_response, error) result
119119(** [upload client ~account_id ~content_type ~data] uploads a blob.
120120121121 @param account_id The account to upload to.
···124124125125val upload_exn :
126126 t ->
127127- account_id:Jmap_proto.Id.t ->
127127+ account_id:Jmap.Proto.Id.t ->
128128 content_type:string ->
129129 data:string ->
130130- Jmap_proto.Blob.upload_response
130130+ Jmap.Proto.Blob.upload_response
131131(** [upload_exn client ~account_id ~content_type ~data] is like {!upload}
132132 but raises on error. *)
133133134134val download :
135135 t ->
136136- account_id:Jmap_proto.Id.t ->
137137- blob_id:Jmap_proto.Id.t ->
136136+ account_id:Jmap.Proto.Id.t ->
137137+ blob_id:Jmap.Proto.Id.t ->
138138 ?name:string ->
139139 ?accept:string ->
140140 unit ->
···148148149149val download_exn :
150150 t ->
151151- account_id:Jmap_proto.Id.t ->
152152- blob_id:Jmap_proto.Id.t ->
151151+ account_id:Jmap.Proto.Id.t ->
152152+ blob_id:Jmap.Proto.Id.t ->
153153 ?name:string ->
154154 ?accept:string ->
155155 unit ->
···166166 val echo :
167167 call_id:string ->
168168 Jsont.json ->
169169- Jmap_proto.Invocation.t
169169+ Jmap.Proto.Invocation.t
170170 (** [echo ~call_id data] builds a Core/echo invocation. *)
171171172172 (** {2 Mailbox Methods} *)
173173174174 val mailbox_get :
175175 call_id:string ->
176176- account_id:Jmap_proto.Id.t ->
177177- ?ids:Jmap_proto.Id.t list ->
176176+ account_id:Jmap.Proto.Id.t ->
177177+ ?ids:Jmap.Proto.Id.t list ->
178178 ?properties:string list ->
179179 unit ->
180180- Jmap_proto.Invocation.t
180180+ Jmap.Proto.Invocation.t
181181 (** [mailbox_get ~call_id ~account_id ?ids ?properties ()] builds a
182182 Mailbox/get invocation. *)
183183184184 val mailbox_changes :
185185 call_id:string ->
186186- account_id:Jmap_proto.Id.t ->
186186+ account_id:Jmap.Proto.Id.t ->
187187 since_state:string ->
188188 ?max_changes:int64 ->
189189 unit ->
190190- Jmap_proto.Invocation.t
190190+ Jmap.Proto.Invocation.t
191191 (** [mailbox_changes ~call_id ~account_id ~since_state ?max_changes ()]
192192 builds a Mailbox/changes invocation. *)
193193194194 val mailbox_query :
195195 call_id:string ->
196196- account_id:Jmap_proto.Id.t ->
197197- ?filter:Jmap_mail.Mail_filter.mailbox_filter ->
198198- ?sort:Jmap_proto.Filter.comparator list ->
196196+ account_id:Jmap.Proto.Id.t ->
197197+ ?filter:Jmap.Proto.Mail_filter.mailbox_filter ->
198198+ ?sort:Jmap.Proto.Filter.comparator list ->
199199 ?position:int64 ->
200200 ?limit:int64 ->
201201 unit ->
202202- Jmap_proto.Invocation.t
202202+ Jmap.Proto.Invocation.t
203203 (** [mailbox_query ~call_id ~account_id ?filter ?sort ?position ?limit ()]
204204 builds a Mailbox/query invocation. *)
205205···207207208208 val email_get :
209209 call_id:string ->
210210- account_id:Jmap_proto.Id.t ->
211211- ?ids:Jmap_proto.Id.t list ->
210210+ account_id:Jmap.Proto.Id.t ->
211211+ ?ids:Jmap.Proto.Id.t list ->
212212 ?properties:string list ->
213213 ?body_properties:string list ->
214214 ?fetch_text_body_values:bool ->
···216216 ?fetch_all_body_values:bool ->
217217 ?max_body_value_bytes:int64 ->
218218 unit ->
219219- Jmap_proto.Invocation.t
219219+ Jmap.Proto.Invocation.t
220220 (** [email_get ~call_id ~account_id ?ids ?properties ...] builds an
221221 Email/get invocation. *)
222222223223 val email_changes :
224224 call_id:string ->
225225- account_id:Jmap_proto.Id.t ->
225225+ account_id:Jmap.Proto.Id.t ->
226226 since_state:string ->
227227 ?max_changes:int64 ->
228228 unit ->
229229- Jmap_proto.Invocation.t
229229+ Jmap.Proto.Invocation.t
230230 (** [email_changes ~call_id ~account_id ~since_state ?max_changes ()]
231231 builds an Email/changes invocation. *)
232232233233 val email_query :
234234 call_id:string ->
235235- account_id:Jmap_proto.Id.t ->
236236- ?filter:Jmap_mail.Mail_filter.email_filter ->
237237- ?sort:Jmap_proto.Filter.comparator list ->
235235+ account_id:Jmap.Proto.Id.t ->
236236+ ?filter:Jmap.Proto.Mail_filter.email_filter ->
237237+ ?sort:Jmap.Proto.Filter.comparator list ->
238238 ?position:int64 ->
239239 ?limit:int64 ->
240240 ?collapse_threads:bool ->
241241 unit ->
242242- Jmap_proto.Invocation.t
242242+ Jmap.Proto.Invocation.t
243243 (** [email_query ~call_id ~account_id ?filter ?sort ?position ?limit
244244 ?collapse_threads ()] builds an Email/query invocation. *)
245245···247247248248 val thread_get :
249249 call_id:string ->
250250- account_id:Jmap_proto.Id.t ->
251251- ?ids:Jmap_proto.Id.t list ->
250250+ account_id:Jmap.Proto.Id.t ->
251251+ ?ids:Jmap.Proto.Id.t list ->
252252 unit ->
253253- Jmap_proto.Invocation.t
253253+ Jmap.Proto.Invocation.t
254254 (** [thread_get ~call_id ~account_id ?ids ()] builds a Thread/get invocation. *)
255255256256 val thread_changes :
257257 call_id:string ->
258258- account_id:Jmap_proto.Id.t ->
258258+ account_id:Jmap.Proto.Id.t ->
259259 since_state:string ->
260260 ?max_changes:int64 ->
261261 unit ->
262262- Jmap_proto.Invocation.t
262262+ Jmap.Proto.Invocation.t
263263 (** [thread_changes ~call_id ~account_id ~since_state ?max_changes ()]
264264 builds a Thread/changes invocation. *)
265265···267267268268 val identity_get :
269269 call_id:string ->
270270- account_id:Jmap_proto.Id.t ->
271271- ?ids:Jmap_proto.Id.t list ->
270270+ account_id:Jmap.Proto.Id.t ->
271271+ ?ids:Jmap.Proto.Id.t list ->
272272 ?properties:string list ->
273273 unit ->
274274- Jmap_proto.Invocation.t
274274+ Jmap.Proto.Invocation.t
275275 (** [identity_get ~call_id ~account_id ?ids ?properties ()] builds an
276276 Identity/get invocation. *)
277277···279279280280 val email_submission_get :
281281 call_id:string ->
282282- account_id:Jmap_proto.Id.t ->
283283- ?ids:Jmap_proto.Id.t list ->
282282+ account_id:Jmap.Proto.Id.t ->
283283+ ?ids:Jmap.Proto.Id.t list ->
284284 ?properties:string list ->
285285 unit ->
286286- Jmap_proto.Invocation.t
286286+ Jmap.Proto.Invocation.t
287287 (** [email_submission_get ~call_id ~account_id ?ids ?properties ()]
288288 builds an EmailSubmission/get invocation. *)
289289290290 val email_submission_query :
291291 call_id:string ->
292292- account_id:Jmap_proto.Id.t ->
293293- ?filter:Jmap_mail.Mail_filter.submission_filter ->
294294- ?sort:Jmap_proto.Filter.comparator list ->
292292+ account_id:Jmap.Proto.Id.t ->
293293+ ?filter:Jmap.Proto.Mail_filter.submission_filter ->
294294+ ?sort:Jmap.Proto.Filter.comparator list ->
295295 ?position:int64 ->
296296 ?limit:int64 ->
297297 unit ->
298298- Jmap_proto.Invocation.t
298298+ Jmap.Proto.Invocation.t
299299 (** [email_submission_query ~call_id ~account_id ?filter ?sort ?position
300300 ?limit ()] builds an EmailSubmission/query invocation. *)
301301···303303304304 val vacation_response_get :
305305 call_id:string ->
306306- account_id:Jmap_proto.Id.t ->
306306+ account_id:Jmap.Proto.Id.t ->
307307 unit ->
308308- Jmap_proto.Invocation.t
308308+ Jmap.Proto.Invocation.t
309309 (** [vacation_response_get ~call_id ~account_id ()] builds a
310310 VacationResponse/get invocation. The singleton ID is automatically used. *)
311311312312 (** {2 Request Building} *)
313313314314 val make_request :
315315- ?created_ids:(Jmap_proto.Id.t * Jmap_proto.Id.t) list ->
315315+ ?created_ids:(Jmap.Proto.Id.t * Jmap.Proto.Id.t) list ->
316316 capabilities:string list ->
317317- Jmap_proto.Invocation.t list ->
318318- Jmap_proto.Request.t
317317+ Jmap.Proto.Invocation.t list ->
318318+ Jmap.Proto.Request.t
319319 (** [make_request ?created_ids ~capabilities invocations] builds a JMAP request.
320320321321 @param created_ids Optional client-created ID mappings.
···330330module Parse : sig
331331 val find_invocation :
332332 call_id:string ->
333333- Jmap_proto.Response.t ->
334334- Jmap_proto.Invocation.t option
333333+ Jmap.Proto.Response.t ->
334334+ Jmap.Proto.Invocation.t option
335335 (** [find_invocation ~call_id response] finds an invocation by call ID. *)
336336337337 val get_invocation_exn :
338338 call_id:string ->
339339- Jmap_proto.Response.t ->
340340- Jmap_proto.Invocation.t
339339+ Jmap.Proto.Response.t ->
340340+ Jmap.Proto.Invocation.t
341341 (** [get_invocation_exn ~call_id response] finds an invocation by call ID.
342342 @raise Failure if not found. *)
343343344344 val parse_invocation :
345345 'a Jsont.t ->
346346- Jmap_proto.Invocation.t ->
346346+ Jmap.Proto.Invocation.t ->
347347 ('a, Jsont.Error.t) result
348348 (** [parse_invocation jsont inv] decodes the invocation's arguments. *)
349349350350 val parse_response :
351351 call_id:string ->
352352 'a Jsont.t ->
353353- Jmap_proto.Response.t ->
353353+ Jmap.Proto.Response.t ->
354354 ('a, Jsont.Error.t) result
355355 (** [parse_response ~call_id jsont response] finds and parses an invocation. *)
356356357357 (** {2 Typed Response Codecs} *)
358358359359- val get_response : 'a Jsont.t -> 'a Jmap_proto.Method.get_response Jsont.t
359359+ val get_response : 'a Jsont.t -> 'a Jmap.Proto.Method.get_response Jsont.t
360360 (** [get_response obj_jsont] creates a Foo/get response codec. *)
361361362362- val query_response : Jmap_proto.Method.query_response Jsont.t
362362+ val query_response : Jmap.Proto.Method.query_response Jsont.t
363363 (** Codec for Foo/query responses. *)
364364365365- val changes_response : Jmap_proto.Method.changes_response Jsont.t
365365+ val changes_response : Jmap.Proto.Method.changes_response Jsont.t
366366 (** Codec for Foo/changes responses. *)
367367368368- val set_response : 'a Jsont.t -> 'a Jmap_proto.Method.set_response Jsont.t
368368+ val set_response : 'a Jsont.t -> 'a Jmap.Proto.Method.set_response Jsont.t
369369 (** [set_response obj_jsont] creates a Foo/set response codec. *)
370370371371 (** {2 Mail-specific Codecs} *)
372372373373- val mailbox_get_response : Jmap_mail.Mailbox.t Jmap_proto.Method.get_response Jsont.t
374374- val email_get_response : Jmap_mail.Email.t Jmap_proto.Method.get_response Jsont.t
375375- val thread_get_response : Jmap_mail.Thread.t Jmap_proto.Method.get_response Jsont.t
376376- val identity_get_response : Jmap_mail.Identity.t Jmap_proto.Method.get_response Jsont.t
373373+ val mailbox_get_response : Jmap.Proto.Mailbox.t Jmap.Proto.Method.get_response Jsont.t
374374+ val email_get_response : Jmap.Proto.Email.t Jmap.Proto.Method.get_response Jsont.t
375375+ val thread_get_response : Jmap.Proto.Thread.t Jmap.Proto.Method.get_response Jsont.t
376376+ val identity_get_response : Jmap.Proto.Identity.t Jmap.Proto.Method.get_response Jsont.t
377377378378 (** {2 Convenience Parsers} *)
379379380380 val parse_mailbox_get :
381381 call_id:string ->
382382- Jmap_proto.Response.t ->
383383- (Jmap_mail.Mailbox.t Jmap_proto.Method.get_response, Jsont.Error.t) result
382382+ Jmap.Proto.Response.t ->
383383+ (Jmap.Proto.Mailbox.t Jmap.Proto.Method.get_response, Jsont.Error.t) result
384384385385 val parse_email_get :
386386 call_id:string ->
387387- Jmap_proto.Response.t ->
388388- (Jmap_mail.Email.t Jmap_proto.Method.get_response, Jsont.Error.t) result
387387+ Jmap.Proto.Response.t ->
388388+ (Jmap.Proto.Email.t Jmap.Proto.Method.get_response, Jsont.Error.t) result
389389390390 val parse_email_query :
391391 call_id:string ->
392392- Jmap_proto.Response.t ->
393393- (Jmap_proto.Method.query_response, Jsont.Error.t) result
392392+ Jmap.Proto.Response.t ->
393393+ (Jmap.Proto.Method.query_response, Jsont.Error.t) result
394394395395 val parse_thread_get :
396396 call_id:string ->
397397- Jmap_proto.Response.t ->
398398- (Jmap_mail.Thread.t Jmap_proto.Method.get_response, Jsont.Error.t) result
397397+ Jmap.Proto.Response.t ->
398398+ (Jmap.Proto.Thread.t Jmap.Proto.Method.get_response, Jsont.Error.t) result
399399400400 val parse_changes :
401401 call_id:string ->
402402- Jmap_proto.Response.t ->
403403- (Jmap_proto.Method.changes_response, Jsont.Error.t) result
402402+ Jmap.Proto.Response.t ->
403403+ (Jmap.Proto.Method.changes_response, Jsont.Error.t) result
404404end
···34343535 (* Get session info *)
3636 let session = Jmap_eio.Client.session client in
3737- Printf.printf "API URL: %s\n" (Jmap_proto.Session.api_url session);
3737+ Printf.printf "API URL: %s\n" (Jmap.Proto.Session.api_url session);
38383939 (* Build and execute a request *)
4040 let account_id = (* get from session *) ... in
4141 let req = Jmap_eio.Client.Build.(
4242 make_request
4343- ~capabilities:[Jmap_proto.Capability.core_uri;
4444- Jmap_proto.Capability.mail_uri]
4343+ ~capabilities:[Jmap.Proto.Capability.core_uri;
4444+ Jmap.Proto.Capability.mail_uri]
4545 [mailbox_get ~call_id:"0" ~account_id ()]
4646 ) in
4747 let response = Jmap_eio.Client.request_exn client req in
···4949 (* Process response *)
5050 List.iter (fun inv ->
5151 Printf.printf "Method: %s, CallId: %s\n"
5252- (Jmap_proto.Invocation.name inv)
5353- (Jmap_proto.Invocation.method_call_id inv)
5454- ) (Jmap_proto.Response.method_responses response)
5252+ (Jmap.Proto.Invocation.name inv)
5353+ (Jmap.Proto.Invocation.method_call_id inv)
5454+ ) (Jmap.Proto.Response.method_responses response)
5555 ]}
56565757 {2 Capabilities}
···6363 - [urn:ietf:params:jmap:submission] - EmailSubmission
6464 - [urn:ietf:params:jmap:vacationresponse] - VacationResponse
65656666- These are available as constants in {!Jmap_proto.Capability}.
6666+ These are available as constants in {!Jmap.Proto.Capability}.
6767*)
68686969(** Low-level JSON codec for JMAP messages. *)
+493
lib/core/jmap.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Unified JMAP interface for OCaml
77+88+ This module provides a clean, ergonomic API for working with JMAP
99+ (RFC 8620/8621), combining the protocol and mail layers with abstract
1010+ types and polymorphic variants.
1111+1212+ {2 Quick Start}
1313+1414+ {[
1515+ open Jmap
1616+1717+ (* Keywords use polymorphic variants *)
1818+ let is_unread email =
1919+ not (List.mem `Seen (Email.keywords email))
2020+2121+ (* Mailbox roles are also polymorphic *)
2222+ let find_inbox mailboxes =
2323+ List.find_opt (fun m -> Mailbox.role m = Some `Inbox) mailboxes
2424+ ]}
2525+2626+ {2 Module Structure}
2727+2828+ - {!Proto} - Low-level protocol and mail types (RFC 8620/8621)
2929+ - {!Error}, {!Id}, {!Keyword}, {!Role}, {!Capability} - Core types
3030+ - {!Session}, {!Email}, {!Mailbox}, etc. - Abstract type accessors
3131+*)
3232+3333+(** {1 Protocol Layer Re-exports} *)
3434+3535+(** Low-level JMAP protocol types (RFC 8620/8621).
3636+3737+ These are the raw protocol and mail types. For most use cases, prefer the
3838+ higher-level types in this module. *)
3939+module Proto = Jmap_proto
4040+4141+(** {1 Core Types} *)
4242+4343+(** Unified error type for JMAP operations.
4444+4545+ All errors from JSON parsing, HTTP, session management, and JMAP method
4646+ calls are represented as polymorphic variants. *)
4747+module Error = Jmap_types.Error
4848+4949+(** JMAP identifier type.
5050+5151+ Identifiers are opaque strings assigned by the server. *)
5252+module Id = Jmap_types.Id
5353+5454+(** Email keyword type.
5555+5656+ Standard keywords are represented as polymorphic variants.
5757+ Custom keywords use [`Custom of string]. *)
5858+module Keyword = Jmap_types.Keyword
5959+6060+(** Mailbox role type.
6161+6262+ Standard roles are represented as polymorphic variants.
6363+ Custom roles use [`Custom of string]. *)
6464+module Role = Jmap_types.Role
6565+6666+(** JMAP capability type.
6767+6868+ Standard capabilities are represented as polymorphic variants.
6969+ Custom capabilities use [`Custom of string]. *)
7070+module Capability = Jmap_types.Capability
7171+7272+(** {1 Session Types} *)
7373+7474+(** JMAP session information.
7575+7676+ The session contains server capabilities, account information,
7777+ and API endpoint URLs. *)
7878+module Session = struct
7979+ (** Account information. *)
8080+ module Account = struct
8181+ type t = Jmap_types.account
8282+8383+ let name a = Proto.Session.Account.name a
8484+ let is_personal a = Proto.Session.Account.is_personal a
8585+ let is_read_only a = Proto.Session.Account.is_read_only a
8686+ end
8787+8888+ type t = Jmap_types.session
8989+9090+ let capabilities s = Proto.Session.capabilities s
9191+ let accounts s = Proto.Session.accounts s
9292+ let primary_accounts s = Proto.Session.primary_accounts s
9393+ let username s = Proto.Session.username s
9494+ let api_url s = Proto.Session.api_url s
9595+ let download_url s = Proto.Session.download_url s
9696+ let upload_url s = Proto.Session.upload_url s
9797+ let event_source_url s = Proto.Session.event_source_url s
9898+ let state s = Proto.Session.state s
9999+100100+ let get_account id s = Proto.Session.get_account id s
101101+ let primary_account_for cap s = Proto.Session.primary_account_for cap s
102102+ let has_capability uri s = Proto.Session.has_capability uri s
103103+end
104104+105105+(** {1 Mail Types} *)
106106+107107+(** Email address with optional display name. *)
108108+module Email_address = struct
109109+ type t = Jmap_types.email_address
110110+111111+ let name a = Proto.Email_address.name a
112112+ let email a = Proto.Email_address.email a
113113+114114+ let create ?name email =
115115+ Proto.Email_address.create ?name email
116116+end
117117+118118+(** Email mailbox. *)
119119+module Mailbox = struct
120120+ type t = Jmap_types.mailbox
121121+122122+ let id m = Proto.Mailbox.id m
123123+ let name m = Proto.Mailbox.name m
124124+ let parent_id m = Proto.Mailbox.parent_id m
125125+ let sort_order m = Proto.Mailbox.sort_order m
126126+ let total_emails m = Proto.Mailbox.total_emails m
127127+ let unread_emails m = Proto.Mailbox.unread_emails m
128128+ let total_threads m = Proto.Mailbox.total_threads m
129129+ let unread_threads m = Proto.Mailbox.unread_threads m
130130+ let is_subscribed m = Proto.Mailbox.is_subscribed m
131131+132132+ let role m =
133133+ let convert_role = function
134134+ | Proto.Mailbox.Inbox -> `Inbox
135135+ | Proto.Mailbox.Sent -> `Sent
136136+ | Proto.Mailbox.Drafts -> `Drafts
137137+ | Proto.Mailbox.Trash -> `Trash
138138+ | Proto.Mailbox.Junk -> `Junk
139139+ | Proto.Mailbox.Archive -> `Archive
140140+ | Proto.Mailbox.Flagged -> `Flagged
141141+ | Proto.Mailbox.Important -> `Important
142142+ | Proto.Mailbox.All -> `All
143143+ | Proto.Mailbox.Subscribed -> `Subscribed
144144+ | Proto.Mailbox.Other s -> `Custom s
145145+ in
146146+ Option.map convert_role (Proto.Mailbox.role m)
147147+148148+ (** Mailbox rights. *)
149149+ module Rights = struct
150150+ type t = Proto.Mailbox.Rights.t
151151+152152+ let may_read_items r = Proto.Mailbox.Rights.may_read_items r
153153+ let may_add_items r = Proto.Mailbox.Rights.may_add_items r
154154+ let may_remove_items r = Proto.Mailbox.Rights.may_remove_items r
155155+ let may_set_seen r = Proto.Mailbox.Rights.may_set_seen r
156156+ let may_set_keywords r = Proto.Mailbox.Rights.may_set_keywords r
157157+ let may_create_child r = Proto.Mailbox.Rights.may_create_child r
158158+ let may_rename r = Proto.Mailbox.Rights.may_rename r
159159+ let may_delete r = Proto.Mailbox.Rights.may_delete r
160160+ let may_submit r = Proto.Mailbox.Rights.may_submit r
161161+ end
162162+163163+ let my_rights m = Proto.Mailbox.my_rights m
164164+end
165165+166166+(** Email thread. *)
167167+module Thread = struct
168168+ type t = Jmap_types.thread
169169+170170+ let id t = Proto.Thread.id t
171171+ let email_ids t = Proto.Thread.email_ids t
172172+end
173173+174174+(** Email message. *)
175175+module Email = struct
176176+ (** Email body part. *)
177177+ module Body = struct
178178+ type part = Proto.Email_body.Part.t
179179+ type value = Proto.Email_body.Value.t
180180+181181+ let part_id p = Proto.Email_body.Part.part_id p
182182+ let blob_id p = Proto.Email_body.Part.blob_id p
183183+ let size p = Proto.Email_body.Part.size p
184184+ let name p = Proto.Email_body.Part.name p
185185+ let type_ p = Proto.Email_body.Part.type_ p
186186+ let charset p = Proto.Email_body.Part.charset p
187187+ let disposition p = Proto.Email_body.Part.disposition p
188188+ let cid p = Proto.Email_body.Part.cid p
189189+ let language p = Proto.Email_body.Part.language p
190190+ let location p = Proto.Email_body.Part.location p
191191+192192+ let value_text v = Proto.Email_body.Value.value v
193193+ let value_is_truncated v = Proto.Email_body.Value.is_truncated v
194194+ let value_is_encoding_problem v = Proto.Email_body.Value.is_encoding_problem v
195195+ end
196196+197197+ type t = Jmap_types.email
198198+199199+ let id e = Proto.Email.id e
200200+ let blob_id e = Proto.Email.blob_id e
201201+ let thread_id e = Proto.Email.thread_id e
202202+ let mailbox_ids e = Proto.Email.mailbox_ids e
203203+ let size e = Proto.Email.size e
204204+ let received_at e = Proto.Email.received_at e
205205+ let message_id e = Proto.Email.message_id e
206206+ let in_reply_to e = Proto.Email.in_reply_to e
207207+ let references e = Proto.Email.references e
208208+ let subject e = Proto.Email.subject e
209209+ let sent_at e = Proto.Email.sent_at e
210210+ let has_attachment e = Proto.Email.has_attachment e
211211+ let preview e = Proto.Email.preview e
212212+213213+ (** Get active keywords as polymorphic variants. *)
214214+ let keywords e =
215215+ let kw_map = Proto.Email.keywords e in
216216+ List.filter_map (fun (k, v) ->
217217+ if v then Some (Keyword.of_string k) else None
218218+ ) kw_map
219219+220220+ (** Check if email has a specific keyword. *)
221221+ let has_keyword kw e =
222222+ let kw_str = Keyword.to_string kw in
223223+ let kw_map = Proto.Email.keywords e in
224224+ List.exists (fun (k, v) -> k = kw_str && v) kw_map
225225+226226+ let from e = Proto.Email.from e
227227+ let to_ e = Proto.Email.to_ e
228228+ let cc e = Proto.Email.cc e
229229+ let bcc e = Proto.Email.bcc e
230230+ let reply_to e = Proto.Email.reply_to e
231231+ let sender e = Proto.Email.sender e
232232+233233+ let text_body e = Proto.Email.text_body e
234234+ let html_body e = Proto.Email.html_body e
235235+ let attachments e = Proto.Email.attachments e
236236+ let body_values e = Proto.Email.body_values e
237237+end
238238+239239+(** Email identity for sending. *)
240240+module Identity = struct
241241+ type t = Jmap_types.identity
242242+243243+ let id i = Proto.Identity.id i
244244+ let name i = Proto.Identity.name i
245245+ let email i = Proto.Identity.email i
246246+ let reply_to i = Proto.Identity.reply_to i
247247+ let bcc i = Proto.Identity.bcc i
248248+ let text_signature i = Proto.Identity.text_signature i
249249+ let html_signature i = Proto.Identity.html_signature i
250250+ let may_delete i = Proto.Identity.may_delete i
251251+end
252252+253253+(** Email submission for outgoing mail. *)
254254+module Submission = struct
255255+ type t = Jmap_types.submission
256256+257257+ let id s = Proto.Submission.id s
258258+ let identity_id s = Proto.Submission.identity_id s
259259+ let email_id s = Proto.Submission.email_id s
260260+ let thread_id s = Proto.Submission.thread_id s
261261+ let send_at s = Proto.Submission.send_at s
262262+ let undo_status s = Proto.Submission.undo_status s
263263+ let delivery_status s = Proto.Submission.delivery_status s
264264+ let dsn_blob_ids s = Proto.Submission.dsn_blob_ids s
265265+ let mdn_blob_ids s = Proto.Submission.mdn_blob_ids s
266266+end
267267+268268+(** Vacation auto-response. *)
269269+module Vacation = struct
270270+ type t = Jmap_types.vacation
271271+272272+ let id v = Proto.Vacation.id v
273273+ let is_enabled v = Proto.Vacation.is_enabled v
274274+ let from_date v = Proto.Vacation.from_date v
275275+ let to_date v = Proto.Vacation.to_date v
276276+ let subject v = Proto.Vacation.subject v
277277+ let text_body v = Proto.Vacation.text_body v
278278+ let html_body v = Proto.Vacation.html_body v
279279+end
280280+281281+(** Search snippet with highlighted matches. *)
282282+module Search_snippet = struct
283283+ type t = Jmap_types.search_snippet
284284+285285+ let email_id s = Proto.Search_snippet.email_id s
286286+ let subject s = Proto.Search_snippet.subject s
287287+ let preview s = Proto.Search_snippet.preview s
288288+end
289289+290290+(** {1 Filter Types} *)
291291+292292+(** Email filter conditions for queries. *)
293293+module Email_filter = struct
294294+ type condition = Proto.Email.Filter_condition.t
295295+296296+ (** Create an email filter condition.
297297+298298+ All parameters are optional. Omitted parameters are not included
299299+ in the filter. Use [make ()] for an empty filter. *)
300300+ let make
301301+ ?in_mailbox
302302+ ?in_mailbox_other_than
303303+ ?before
304304+ ?after
305305+ ?min_size
306306+ ?max_size
307307+ ?(all_in_thread_have_keyword : Keyword.t option)
308308+ ?(some_in_thread_have_keyword : Keyword.t option)
309309+ ?(none_in_thread_have_keyword : Keyword.t option)
310310+ ?(has_keyword : Keyword.t option)
311311+ ?(not_keyword : Keyword.t option)
312312+ ?has_attachment
313313+ ?text
314314+ ?from
315315+ ?to_
316316+ ?cc
317317+ ?bcc
318318+ ?subject
319319+ ?body
320320+ ?header
321321+ () : condition =
322322+ {
323323+ in_mailbox;
324324+ in_mailbox_other_than;
325325+ before;
326326+ after;
327327+ min_size;
328328+ max_size;
329329+ all_in_thread_have_keyword = Option.map Keyword.to_string all_in_thread_have_keyword;
330330+ some_in_thread_have_keyword = Option.map Keyword.to_string some_in_thread_have_keyword;
331331+ none_in_thread_have_keyword = Option.map Keyword.to_string none_in_thread_have_keyword;
332332+ has_keyword = Option.map Keyword.to_string has_keyword;
333333+ not_keyword = Option.map Keyword.to_string not_keyword;
334334+ has_attachment;
335335+ text;
336336+ from;
337337+ to_;
338338+ cc;
339339+ bcc;
340340+ subject;
341341+ body;
342342+ header;
343343+ }
344344+end
345345+346346+(** Mailbox filter conditions for queries. *)
347347+module Mailbox_filter = struct
348348+ type condition = Proto.Mailbox.Filter_condition.t
349349+350350+ let convert_role = function
351351+ | `Inbox -> Proto.Mailbox.Inbox
352352+ | `Sent -> Proto.Mailbox.Sent
353353+ | `Drafts -> Proto.Mailbox.Drafts
354354+ | `Trash -> Proto.Mailbox.Trash
355355+ | `Junk -> Proto.Mailbox.Junk
356356+ | `Archive -> Proto.Mailbox.Archive
357357+ | `Flagged -> Proto.Mailbox.Flagged
358358+ | `Important -> Proto.Mailbox.Important
359359+ | `All -> Proto.Mailbox.All
360360+ | `Subscribed -> Proto.Mailbox.Subscribed
361361+ | `Custom s -> Proto.Mailbox.Other s
362362+363363+ (** Create a mailbox filter condition.
364364+365365+ All parameters are optional.
366366+ For [role]: [Some (Some r)] filters by role [r], [Some None] filters for
367367+ mailboxes with no role, [None] doesn't filter by role. *)
368368+ let make
369369+ ?parent_id
370370+ ?name
371371+ ?role
372372+ ?has_any_role
373373+ ?is_subscribed
374374+ () : condition =
375375+ {
376376+ parent_id;
377377+ name;
378378+ role = Option.map (Option.map convert_role) role;
379379+ has_any_role;
380380+ is_subscribed;
381381+ }
382382+end
383383+384384+(** {1 Response Types} *)
385385+386386+(** Generic /get response wrapper. *)
387387+module Get_response = struct
388388+ type 'a t = 'a Proto.Method.get_response
389389+390390+ let account_id (r : 'a t) = r.Proto.Method.account_id
391391+ let state (r : 'a t) = r.Proto.Method.state
392392+ let list (r : 'a t) = r.Proto.Method.list
393393+ let not_found (r : 'a t) = r.Proto.Method.not_found
394394+end
395395+396396+(** Query response. *)
397397+module Query_response = struct
398398+ type t = Proto.Method.query_response
399399+400400+ let account_id (r : t) = r.Proto.Method.account_id
401401+ let query_state (r : t) = r.Proto.Method.query_state
402402+ let can_calculate_changes (r : t) = r.Proto.Method.can_calculate_changes
403403+ let position (r : t) = r.Proto.Method.position
404404+ let ids (r : t) = r.Proto.Method.ids
405405+ let total (r : t) = r.Proto.Method.total
406406+end
407407+408408+(** Changes response. *)
409409+module Changes_response = struct
410410+ type t = Proto.Method.changes_response
411411+412412+ let account_id (r : t) = r.Proto.Method.account_id
413413+ let old_state (r : t) = r.Proto.Method.old_state
414414+ let new_state (r : t) = r.Proto.Method.new_state
415415+ let has_more_changes (r : t) = r.Proto.Method.has_more_changes
416416+ let created (r : t) = r.Proto.Method.created
417417+ let updated (r : t) = r.Proto.Method.updated
418418+ let destroyed (r : t) = r.Proto.Method.destroyed
419419+end
420420+421421+(** {1 JSONABLE Interface} *)
422422+423423+(** Module type for types that can be serialized to/from JSON bytes. *)
424424+module type JSONABLE = sig
425425+ type t
426426+427427+ val of_string : string -> (t, Error.t) result
428428+ val to_string : t -> (string, Error.t) result
429429+end
430430+431431+(** {1 Private Interface} *)
432432+433433+(** Private module for internal use by Jmap_eio.
434434+435435+ This exposes the underlying Jsont codecs for serialization. *)
436436+module Private = struct
437437+ module Session = struct
438438+ let jsont = Proto.Session.jsont
439439+ end
440440+441441+ module Request = struct
442442+ let jsont = Proto.Request.jsont
443443+ end
444444+445445+ module Response = struct
446446+ let jsont = Proto.Response.jsont
447447+ end
448448+449449+ module Mailbox = struct
450450+ let jsont = Proto.Mailbox.jsont
451451+ end
452452+453453+ module Email = struct
454454+ let jsont = Proto.Email.jsont
455455+ end
456456+457457+ module Thread = struct
458458+ let jsont = Proto.Thread.jsont
459459+ end
460460+461461+ module Identity = struct
462462+ let jsont = Proto.Identity.jsont
463463+ end
464464+465465+ module Submission = struct
466466+ let jsont = Proto.Submission.jsont
467467+ end
468468+469469+ module Vacation = struct
470470+ let jsont = Proto.Vacation.jsont
471471+ end
472472+473473+ module Blob = struct
474474+ let upload_response_jsont = Proto.Blob.upload_response_jsont
475475+ end
476476+477477+ module Method = struct
478478+ let get_response_jsont = Proto.Method.get_response_jsont
479479+ let query_response_jsont = Proto.Method.query_response_jsont
480480+ let changes_response_jsont = Proto.Method.changes_response_jsont
481481+ let set_response_jsont = Proto.Method.set_response_jsont
482482+ end
483483+484484+ module Mail_filter = struct
485485+ let email_filter_jsont = Proto.Mail_filter.email_filter_jsont
486486+ let mailbox_filter_jsont = Proto.Mail_filter.mailbox_filter_jsont
487487+ let submission_filter_jsont = Proto.Mail_filter.submission_filter_jsont
488488+ end
489489+490490+ module Filter = struct
491491+ let comparator_jsont = Proto.Filter.comparator_jsont
492492+ end
493493+end
+518
lib/core/jmap.mli
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Unified JMAP interface for OCaml
77+88+ This module provides a clean, ergonomic API for working with JMAP
99+ (RFC 8620/8621), combining the protocol and mail layers with abstract
1010+ types and polymorphic variants.
1111+1212+ {2 Quick Start}
1313+1414+ {[
1515+ open Jmap
1616+1717+ (* Keywords use polymorphic variants *)
1818+ let is_unread email =
1919+ not (List.mem `Seen (Email.keywords email))
2020+2121+ (* Mailbox roles are also polymorphic *)
2222+ let find_inbox mailboxes =
2323+ List.find_opt (fun m -> Mailbox.role m = Some `Inbox) mailboxes
2424+ ]}
2525+2626+ {2 Module Structure}
2727+2828+ - {!Proto} - Low-level protocol and mail types (RFC 8620/8621)
2929+ - {!Error}, {!Id}, {!Keyword}, {!Role}, {!Capability} - Core types
3030+ - {!Session}, {!Email}, {!Mailbox}, etc. - Abstract type accessors
3131+*)
3232+3333+(** {1 Protocol Layer Re-exports} *)
3434+3535+(** Low-level JMAP protocol types (RFC 8620/8621).
3636+3737+ These are the raw protocol and mail types. For most use cases, prefer the
3838+ higher-level types in this module. *)
3939+module Proto = Jmap_proto
4040+4141+(** {1 Core Types} *)
4242+4343+(** Unified error type for JMAP operations. *)
4444+module Error : sig
4545+ (** Request-level error (RFC 7807 Problem Details). *)
4646+ type request = {
4747+ type_ : string;
4848+ status : int option;
4949+ title : string option;
5050+ detail : string option;
5151+ limit : string option;
5252+ }
5353+5454+ (** Method-level error. *)
5555+ type method_ = {
5656+ type_ : string;
5757+ description : string option;
5858+ }
5959+6060+ (** Set operation error for a specific object. *)
6161+ type set = {
6262+ type_ : string;
6363+ description : string option;
6464+ properties : string list option;
6565+ }
6666+6767+ (** Unified error type.
6868+6969+ All errors from JSON parsing, HTTP, session management, and JMAP method
7070+ calls are represented as polymorphic variants. *)
7171+ type t = [
7272+ | `Request of request
7373+ | `Method of method_
7474+ | `Set of string * set
7575+ | `Json of string
7676+ | `Http of int * string
7777+ | `Connection of string
7878+ | `Session of string
7979+ ]
8080+8181+ val pp : Format.formatter -> t -> unit
8282+ val to_string : t -> string
8383+end
8484+8585+(** JMAP identifier type. *)
8686+module Id : sig
8787+ type t
8888+8989+ val of_string : string -> (t, string) result
9090+ val of_string_exn : string -> t
9191+ val to_string : t -> string
9292+ val compare : t -> t -> int
9393+ val equal : t -> t -> bool
9494+ val pp : Format.formatter -> t -> unit
9595+end
9696+9797+(** Email keyword type.
9898+9999+ Standard keywords are represented as polymorphic variants.
100100+ Custom keywords use [`Custom of string]. *)
101101+module Keyword : sig
102102+ type t = [
103103+ | `Seen
104104+ | `Flagged
105105+ | `Answered
106106+ | `Draft
107107+ | `Forwarded
108108+ | `Phishing
109109+ | `Junk
110110+ | `NotJunk
111111+ | `Custom of string
112112+ ]
113113+114114+ val of_string : string -> t
115115+ val to_string : t -> string
116116+ val pp : Format.formatter -> t -> unit
117117+end
118118+119119+(** Mailbox role type.
120120+121121+ Standard roles are represented as polymorphic variants.
122122+ Custom roles use [`Custom of string]. *)
123123+module Role : sig
124124+ type t = [
125125+ | `Inbox
126126+ | `Sent
127127+ | `Drafts
128128+ | `Trash
129129+ | `Junk
130130+ | `Archive
131131+ | `Flagged
132132+ | `Important
133133+ | `All
134134+ | `Subscribed
135135+ | `Custom of string
136136+ ]
137137+138138+ val of_string : string -> t
139139+ val to_string : t -> string
140140+ val pp : Format.formatter -> t -> unit
141141+end
142142+143143+(** JMAP capability type.
144144+145145+ Standard capabilities are represented as polymorphic variants.
146146+ Custom capabilities use [`Custom of string]. *)
147147+module Capability : sig
148148+ type t = [
149149+ | `Core
150150+ | `Mail
151151+ | `Submission
152152+ | `VacationResponse
153153+ | `Custom of string
154154+ ]
155155+156156+ val core_uri : string
157157+ val mail_uri : string
158158+ val submission_uri : string
159159+ val vacation_uri : string
160160+161161+ val of_string : string -> t
162162+ val to_string : t -> string
163163+ val pp : Format.formatter -> t -> unit
164164+end
165165+166166+(** {1 Session Types} *)
167167+168168+(** JMAP session information. *)
169169+module Session : sig
170170+ (** Account information. *)
171171+ module Account : sig
172172+ type t
173173+174174+ val name : t -> string
175175+ val is_personal : t -> bool
176176+ val is_read_only : t -> bool
177177+ end
178178+179179+ type t
180180+181181+ val capabilities : t -> (string * Jsont.json) list
182182+ val accounts : t -> (Id.t * Account.t) list
183183+ val primary_accounts : t -> (string * Id.t) list
184184+ val username : t -> string
185185+ val api_url : t -> string
186186+ val download_url : t -> string
187187+ val upload_url : t -> string
188188+ val event_source_url : t -> string
189189+ val state : t -> string
190190+191191+ val get_account : Id.t -> t -> Account.t option
192192+ val primary_account_for : string -> t -> Id.t option
193193+ val has_capability : string -> t -> bool
194194+end
195195+196196+(** {1 Mail Types} *)
197197+198198+(** Email address with optional display name. *)
199199+module Email_address : sig
200200+ type t
201201+202202+ val name : t -> string option
203203+ val email : t -> string
204204+ val create : ?name:string -> string -> t
205205+end
206206+207207+(** Email mailbox. *)
208208+module Mailbox : sig
209209+ type t
210210+211211+ val id : t -> Id.t
212212+ val name : t -> string
213213+ val parent_id : t -> Id.t option
214214+ val sort_order : t -> int64
215215+ val total_emails : t -> int64
216216+ val unread_emails : t -> int64
217217+ val total_threads : t -> int64
218218+ val unread_threads : t -> int64
219219+ val is_subscribed : t -> bool
220220+ val role : t -> Role.t option
221221+222222+ (** Mailbox rights. *)
223223+ module Rights : sig
224224+ type t
225225+226226+ val may_read_items : t -> bool
227227+ val may_add_items : t -> bool
228228+ val may_remove_items : t -> bool
229229+ val may_set_seen : t -> bool
230230+ val may_set_keywords : t -> bool
231231+ val may_create_child : t -> bool
232232+ val may_rename : t -> bool
233233+ val may_delete : t -> bool
234234+ val may_submit : t -> bool
235235+ end
236236+237237+ val my_rights : t -> Rights.t
238238+end
239239+240240+(** Email thread. *)
241241+module Thread : sig
242242+ type t
243243+244244+ val id : t -> Id.t
245245+ val email_ids : t -> Id.t list
246246+end
247247+248248+(** Email message. *)
249249+module Email : sig
250250+ (** Email body part. *)
251251+ module Body : sig
252252+ type part
253253+ type value
254254+255255+ val part_id : part -> string option
256256+ val blob_id : part -> Id.t option
257257+ val size : part -> int64 option
258258+ val name : part -> string option
259259+ val type_ : part -> string
260260+ val charset : part -> string option
261261+ val disposition : part -> string option
262262+ val cid : part -> string option
263263+ val language : part -> string list option
264264+ val location : part -> string option
265265+266266+ val value_text : value -> string
267267+ val value_is_truncated : value -> bool
268268+ val value_is_encoding_problem : value -> bool
269269+ end
270270+271271+ type t
272272+273273+ val id : t -> Id.t
274274+ val blob_id : t -> Id.t
275275+ val thread_id : t -> Id.t
276276+ val mailbox_ids : t -> (Id.t * bool) list
277277+ val size : t -> int64
278278+ val received_at : t -> Ptime.t
279279+ val message_id : t -> string list option
280280+ val in_reply_to : t -> string list option
281281+ val references : t -> string list option
282282+ val subject : t -> string option
283283+ val sent_at : t -> Ptime.t option
284284+ val has_attachment : t -> bool
285285+ val preview : t -> string
286286+287287+ (** Get active keywords as polymorphic variants. *)
288288+ val keywords : t -> Keyword.t list
289289+290290+ (** Check if email has a specific keyword. *)
291291+ val has_keyword : Keyword.t -> t -> bool
292292+293293+ val from : t -> Email_address.t list option
294294+ val to_ : t -> Email_address.t list option
295295+ val cc : t -> Email_address.t list option
296296+ val bcc : t -> Email_address.t list option
297297+ val reply_to : t -> Email_address.t list option
298298+ val sender : t -> Email_address.t list option
299299+300300+ val text_body : t -> Body.part list option
301301+ val html_body : t -> Body.part list option
302302+ val attachments : t -> Body.part list option
303303+ val body_values : t -> (string * Body.value) list option
304304+end
305305+306306+(** Email identity for sending. *)
307307+module Identity : sig
308308+ type t
309309+310310+ val id : t -> Id.t
311311+ val name : t -> string
312312+ val email : t -> string
313313+ val reply_to : t -> Email_address.t list option
314314+ val bcc : t -> Email_address.t list option
315315+ val text_signature : t -> string
316316+ val html_signature : t -> string
317317+ val may_delete : t -> bool
318318+end
319319+320320+(** Email submission for outgoing mail. *)
321321+module Submission : sig
322322+ type t
323323+324324+ val id : t -> Id.t
325325+ val identity_id : t -> Id.t
326326+ val email_id : t -> Id.t
327327+ val thread_id : t -> Id.t
328328+ val send_at : t -> Ptime.t
329329+ val undo_status : t -> Proto.Submission.undo_status
330330+ val delivery_status : t -> (string * Proto.Submission.Delivery_status.t) list option
331331+ val dsn_blob_ids : t -> Id.t list
332332+ val mdn_blob_ids : t -> Id.t list
333333+end
334334+335335+(** Vacation auto-response. *)
336336+module Vacation : sig
337337+ type t
338338+339339+ val id : t -> Id.t
340340+ val is_enabled : t -> bool
341341+ val from_date : t -> Ptime.t option
342342+ val to_date : t -> Ptime.t option
343343+ val subject : t -> string option
344344+ val text_body : t -> string option
345345+ val html_body : t -> string option
346346+end
347347+348348+(** Search snippet with highlighted matches. *)
349349+module Search_snippet : sig
350350+ type t
351351+352352+ val email_id : t -> Id.t
353353+ val subject : t -> string option
354354+ val preview : t -> string option
355355+end
356356+357357+(** {1 Filter Types} *)
358358+359359+(** Email filter conditions for queries. *)
360360+module Email_filter : sig
361361+ type condition
362362+363363+ (** Create an email filter condition.
364364+365365+ All parameters are optional. Omitted parameters are not included
366366+ in the filter. Use [make ()] for an empty filter. *)
367367+ val make :
368368+ ?in_mailbox:Id.t ->
369369+ ?in_mailbox_other_than:Id.t list ->
370370+ ?before:Ptime.t ->
371371+ ?after:Ptime.t ->
372372+ ?min_size:int64 ->
373373+ ?max_size:int64 ->
374374+ ?all_in_thread_have_keyword:Keyword.t ->
375375+ ?some_in_thread_have_keyword:Keyword.t ->
376376+ ?none_in_thread_have_keyword:Keyword.t ->
377377+ ?has_keyword:Keyword.t ->
378378+ ?not_keyword:Keyword.t ->
379379+ ?has_attachment:bool ->
380380+ ?text:string ->
381381+ ?from:string ->
382382+ ?to_:string ->
383383+ ?cc:string ->
384384+ ?bcc:string ->
385385+ ?subject:string ->
386386+ ?body:string ->
387387+ ?header:(string * string option) ->
388388+ unit -> condition
389389+end
390390+391391+(** Mailbox filter conditions for queries. *)
392392+module Mailbox_filter : sig
393393+ type condition
394394+395395+ (** Create a mailbox filter condition.
396396+397397+ All parameters are optional.
398398+ For [role]: [Some (Some r)] filters by role [r], [Some None] filters for
399399+ mailboxes with no role, [None] doesn't filter by role. *)
400400+ val make :
401401+ ?parent_id:Id.t option ->
402402+ ?name:string ->
403403+ ?role:Role.t option ->
404404+ ?has_any_role:bool ->
405405+ ?is_subscribed:bool ->
406406+ unit -> condition
407407+end
408408+409409+(** {1 Response Types} *)
410410+411411+(** Generic /get response wrapper. *)
412412+module Get_response : sig
413413+ type 'a t
414414+415415+ val account_id : 'a t -> Id.t
416416+ val state : 'a t -> string
417417+ val list : 'a t -> 'a list
418418+ val not_found : 'a t -> Id.t list
419419+end
420420+421421+(** Query response. *)
422422+module Query_response : sig
423423+ type t
424424+425425+ val account_id : t -> Id.t
426426+ val query_state : t -> string
427427+ val can_calculate_changes : t -> bool
428428+ val position : t -> int64
429429+ val ids : t -> Id.t list
430430+ val total : t -> int64 option
431431+end
432432+433433+(** Changes response. *)
434434+module Changes_response : sig
435435+ type t
436436+437437+ val account_id : t -> Id.t
438438+ val old_state : t -> string
439439+ val new_state : t -> string
440440+ val has_more_changes : t -> bool
441441+ val created : t -> Id.t list
442442+ val updated : t -> Id.t list
443443+ val destroyed : t -> Id.t list
444444+end
445445+446446+(** {1 JSONABLE Interface} *)
447447+448448+(** Module type for types that can be serialized to/from JSON bytes. *)
449449+module type JSONABLE = sig
450450+ type t
451451+452452+ val of_string : string -> (t, Error.t) result
453453+ val to_string : t -> (string, Error.t) result
454454+end
455455+456456+(** {1 Private Interface} *)
457457+458458+(** Private module for internal use by Jmap_eio.
459459+460460+ This exposes the underlying Jsont codecs for serialization. *)
461461+module Private : sig
462462+ module Session : sig
463463+ val jsont : Proto.Session.t Jsont.t
464464+ end
465465+466466+ module Request : sig
467467+ val jsont : Proto.Request.t Jsont.t
468468+ end
469469+470470+ module Response : sig
471471+ val jsont : Proto.Response.t Jsont.t
472472+ end
473473+474474+ module Mailbox : sig
475475+ val jsont : Proto.Mailbox.t Jsont.t
476476+ end
477477+478478+ module Email : sig
479479+ val jsont : Proto.Email.t Jsont.t
480480+ end
481481+482482+ module Thread : sig
483483+ val jsont : Proto.Thread.t Jsont.t
484484+ end
485485+486486+ module Identity : sig
487487+ val jsont : Proto.Identity.t Jsont.t
488488+ end
489489+490490+ module Submission : sig
491491+ val jsont : Proto.Submission.t Jsont.t
492492+ end
493493+494494+ module Vacation : sig
495495+ val jsont : Proto.Vacation.t Jsont.t
496496+ end
497497+498498+ module Blob : sig
499499+ val upload_response_jsont : Proto.Blob.upload_response Jsont.t
500500+ end
501501+502502+ module Method : sig
503503+ val get_response_jsont : 'a Jsont.t -> 'a Proto.Method.get_response Jsont.t
504504+ val query_response_jsont : Proto.Method.query_response Jsont.t
505505+ val changes_response_jsont : Proto.Method.changes_response Jsont.t
506506+ val set_response_jsont : 'a Jsont.t -> 'a Proto.Method.set_response Jsont.t
507507+ end
508508+509509+ module Mail_filter : sig
510510+ val email_filter_jsont : Proto.Mail_filter.email_filter Jsont.t
511511+ val mailbox_filter_jsont : Proto.Mail_filter.mailbox_filter Jsont.t
512512+ val submission_filter_jsont : Proto.Mail_filter.submission_filter Jsont.t
513513+ end
514514+515515+ module Filter : sig
516516+ val comparator_jsont : Proto.Filter.comparator Jsont.t
517517+ end
518518+end
+231
lib/core/jmap_types.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Internal types for the unified Jmap interface *)
77+88+(** {1 Error Types} *)
99+1010+module Error = struct
1111+ (** Request-level error (RFC 7807 Problem Details) *)
1212+ type request = {
1313+ type_ : string;
1414+ status : int option;
1515+ title : string option;
1616+ detail : string option;
1717+ limit : string option;
1818+ }
1919+2020+ (** Method-level error *)
2121+ type method_ = {
2222+ type_ : string;
2323+ description : string option;
2424+ }
2525+2626+ (** Set operation error for a specific object *)
2727+ type set = {
2828+ type_ : string;
2929+ description : string option;
3030+ properties : string list option;
3131+ }
3232+3333+ (** Unified error type *)
3434+ type t = [
3535+ | `Request of request
3636+ | `Method of method_
3737+ | `Set of string * set
3838+ | `Json of string
3939+ | `Http of int * string
4040+ | `Connection of string
4141+ | `Session of string
4242+ ]
4343+4444+ let pp_request ppf (r : request) =
4545+ Format.fprintf ppf "Request error: %s" r.type_;
4646+ Option.iter (Format.fprintf ppf " (status %d)") r.status;
4747+ Option.iter (Format.fprintf ppf ": %s") r.detail
4848+4949+ let pp_method ppf (m : method_) =
5050+ Format.fprintf ppf "Method error: %s" m.type_;
5151+ Option.iter (Format.fprintf ppf ": %s") m.description
5252+5353+ let pp_set ppf (id, (s : set)) =
5454+ Format.fprintf ppf "Set error for %s: %s" id s.type_;
5555+ Option.iter (Format.fprintf ppf ": %s") s.description
5656+5757+ let pp ppf = function
5858+ | `Request r -> pp_request ppf r
5959+ | `Method m -> pp_method ppf m
6060+ | `Set (id, s) -> pp_set ppf (id, s)
6161+ | `Json msg -> Format.fprintf ppf "JSON error: %s" msg
6262+ | `Http (code, msg) -> Format.fprintf ppf "HTTP error %d: %s" code msg
6363+ | `Connection msg -> Format.fprintf ppf "Connection error: %s" msg
6464+ | `Session msg -> Format.fprintf ppf "Session error: %s" msg
6565+6666+ let to_string e = Format.asprintf "%a" pp e
6767+end
6868+6969+(** {1 Identifier Type} *)
7070+7171+module Id = struct
7272+ type t = Jmap_proto.Id.t
7373+7474+ let of_string s = Jmap_proto.Id.of_string s
7575+ let of_string_exn s = Jmap_proto.Id.of_string_exn s
7676+ let to_string = Jmap_proto.Id.to_string
7777+ let compare = Jmap_proto.Id.compare
7878+ let equal = Jmap_proto.Id.equal
7979+ let pp = Jmap_proto.Id.pp
8080+end
8181+8282+(** {1 Keyword Type} *)
8383+8484+module Keyword = struct
8585+ type t = [
8686+ | `Seen
8787+ | `Flagged
8888+ | `Answered
8989+ | `Draft
9090+ | `Forwarded
9191+ | `Phishing
9292+ | `Junk
9393+ | `NotJunk
9494+ | `Custom of string
9595+ ]
9696+9797+ let of_string = function
9898+ | "$seen" -> `Seen
9999+ | "$flagged" -> `Flagged
100100+ | "$answered" -> `Answered
101101+ | "$draft" -> `Draft
102102+ | "$forwarded" -> `Forwarded
103103+ | "$phishing" -> `Phishing
104104+ | "$junk" -> `Junk
105105+ | "$notjunk" -> `NotJunk
106106+ | s -> `Custom s
107107+108108+ let to_string = function
109109+ | `Seen -> "$seen"
110110+ | `Flagged -> "$flagged"
111111+ | `Answered -> "$answered"
112112+ | `Draft -> "$draft"
113113+ | `Forwarded -> "$forwarded"
114114+ | `Phishing -> "$phishing"
115115+ | `Junk -> "$junk"
116116+ | `NotJunk -> "$notjunk"
117117+ | `Custom s -> s
118118+119119+ let pp ppf k = Format.pp_print_string ppf (to_string k)
120120+end
121121+122122+(** {1 Mailbox Role Type} *)
123123+124124+module Role = struct
125125+ type t = [
126126+ | `Inbox
127127+ | `Sent
128128+ | `Drafts
129129+ | `Trash
130130+ | `Junk
131131+ | `Archive
132132+ | `Flagged
133133+ | `Important
134134+ | `All
135135+ | `Subscribed
136136+ | `Custom of string
137137+ ]
138138+139139+ let of_string = function
140140+ | "inbox" -> `Inbox
141141+ | "sent" -> `Sent
142142+ | "drafts" -> `Drafts
143143+ | "trash" -> `Trash
144144+ | "junk" -> `Junk
145145+ | "archive" -> `Archive
146146+ | "flagged" -> `Flagged
147147+ | "important" -> `Important
148148+ | "all" -> `All
149149+ | "subscribed" -> `Subscribed
150150+ | s -> `Custom s
151151+152152+ let to_string = function
153153+ | `Inbox -> "inbox"
154154+ | `Sent -> "sent"
155155+ | `Drafts -> "drafts"
156156+ | `Trash -> "trash"
157157+ | `Junk -> "junk"
158158+ | `Archive -> "archive"
159159+ | `Flagged -> "flagged"
160160+ | `Important -> "important"
161161+ | `All -> "all"
162162+ | `Subscribed -> "subscribed"
163163+ | `Custom s -> s
164164+165165+ let pp ppf r = Format.pp_print_string ppf (to_string r)
166166+end
167167+168168+(** {1 Capability Type} *)
169169+170170+module Capability = struct
171171+ type t = [
172172+ | `Core
173173+ | `Mail
174174+ | `Submission
175175+ | `VacationResponse
176176+ | `Custom of string
177177+ ]
178178+179179+ let core_uri = "urn:ietf:params:jmap:core"
180180+ let mail_uri = "urn:ietf:params:jmap:mail"
181181+ let submission_uri = "urn:ietf:params:jmap:submission"
182182+ let vacation_uri = "urn:ietf:params:jmap:vacationresponse"
183183+184184+ let of_string = function
185185+ | s when s = core_uri -> `Core
186186+ | s when s = mail_uri -> `Mail
187187+ | s when s = submission_uri -> `Submission
188188+ | s when s = vacation_uri -> `VacationResponse
189189+ | s -> `Custom s
190190+191191+ let to_string = function
192192+ | `Core -> core_uri
193193+ | `Mail -> mail_uri
194194+ | `Submission -> submission_uri
195195+ | `VacationResponse -> vacation_uri
196196+ | `Custom s -> s
197197+198198+ let pp ppf c = Format.pp_print_string ppf (to_string c)
199199+end
200200+201201+(** {1 Abstract Type Wrappers} *)
202202+203203+(** Wrapped session type *)
204204+type session = Jmap_proto.Session.t
205205+206206+(** Wrapped account type *)
207207+type account = Jmap_proto.Session.Account.t
208208+209209+(** Wrapped mailbox type *)
210210+type mailbox = Jmap_proto.Mailbox.t
211211+212212+(** Wrapped email type *)
213213+type email = Jmap_proto.Email.t
214214+215215+(** Wrapped thread type *)
216216+type thread = Jmap_proto.Thread.t
217217+218218+(** Wrapped identity type *)
219219+type identity = Jmap_proto.Identity.t
220220+221221+(** Wrapped email submission type *)
222222+type submission = Jmap_proto.Submission.t
223223+224224+(** Wrapped vacation response type *)
225225+type vacation = Jmap_proto.Vacation.t
226226+227227+(** Wrapped email address type *)
228228+type email_address = Jmap_proto.Email_address.t
229229+230230+(** Wrapped search snippet type *)
231231+type search_snippet = Jmap_proto.Search_snippet.t
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** JMAP filter and sort types as defined in RFC 8620 Section 5.5 *)
66+(** JMAP filter and sort types as defined in RFC 8620 Section 5.5
77+88+ @canonical Jmap.Proto.Filter *)
79810(** {1 Filter Operators} *)
911···66686769(** Added entry position in query change results. *)
6870type added_item = {
6969- id : Id.t;
7171+ id : Proto_id.t;
7072 index : int64;
7173}
7274
proto/id.ml
lib/proto/proto_id.ml
+3-1
proto/id.mli
lib/proto/proto_id.mli
···88 An Id is a string of 1-255 octets from the URL-safe base64 alphabet
99 (A-Za-z0-9_-), plus the ASCII alphanumeric characters.
10101111- See {{:https://datatracker.ietf.org/doc/html/rfc8620#section-1.2} RFC 8620 Section 1.2}. *)
1111+ See {{:https://datatracker.ietf.org/doc/html/rfc8620#section-1.2} RFC 8620 Section 1.2}.
1212+1313+ @canonical Jmap.Proto.Id *)
12141315type t
1416(** The type of JMAP identifiers. *)
proto/int53.ml
lib/proto/proto_int53.ml
+3-1
proto/int53.mli
lib/proto/proto_int53.mli
···99 IEEE 754 double-precision floating point format without loss of precision.
1010 The safe range is -2^53+1 to 2^53-1.
11111212- See {{:https://datatracker.ietf.org/doc/html/rfc8620#section-1.3} RFC 8620 Section 1.3}. *)
1212+ See {{:https://datatracker.ietf.org/doc/html/rfc8620#section-1.3} RFC 8620 Section 1.3}.
1313+1414+ @canonical Jmap.Proto.Int53 *)
13151416(** 53-bit signed integer.
1517
+4-4
proto/invocation.ml
lib/proto/proto_invocation.ml
···100100 Jsont.map ~kind ~dec ~enc Jsont.json
101101102102let make_get ~method_call_id ~method_name args =
103103- let arguments = encode_json_value Method_.get_args_jsont args in
103103+ let arguments = encode_json_value Proto_method.get_args_jsont args in
104104 { name = method_name; arguments; method_call_id }
105105106106let make_changes ~method_call_id ~method_name args =
107107- let arguments = encode_json_value Method_.changes_args_jsont args in
107107+ let arguments = encode_json_value Proto_method.changes_args_jsont args in
108108 { name = method_name; arguments; method_call_id }
109109110110let make_query (type f) ~method_call_id ~method_name
111111- ~(filter_cond_jsont : f Jsont.t) (args : f Method_.query_args) =
112112- let arguments = encode_json_value (Method_.query_args_jsont filter_cond_jsont) args in
111111+ ~(filter_cond_jsont : f Jsont.t) (args : f Proto_method.query_args) =
112112+ let arguments = encode_json_value (Proto_method.query_args_jsont filter_cond_jsont) args in
113113 { name = method_name; arguments; method_call_id }
···2525 let string_codec = of_string value_jsont in
2626 let dec pairs =
2727 List.map (fun (k, v) ->
2828- match Id.of_string k with
2828+ match Proto_id.of_string k with
2929 | Ok id -> (id, v)
3030 | Error msg -> Jsont.Error.msgf Jsont.Meta.none "%s: invalid key %s - %s" kind k msg
3131 ) pairs
3232 in
3333 let enc pairs =
3434- List.map (fun (id, v) -> (Id.to_string id, v)) pairs
3434+ List.map (fun (id, v) -> (Proto_id.to_string id, v)) pairs
3535 in
3636 Jsont.map ~kind ~dec ~enc string_codec
3737
+5-3
proto/json_map.mli
lib/proto/proto_json_map.mli
···66(** JSON object-as-map codec utilities.
7788 JMAP frequently uses JSON objects as maps with string or Id keys.
99- These codecs convert between JSON objects and OCaml association lists. *)
99+ These codecs convert between JSON objects and OCaml association lists.
1010+1111+ @canonical Jmap.Proto.Json_map *)
10121113val of_string : 'a Jsont.t -> (string * 'a) list Jsont.t
1214(** [of_string value_jsont] creates a codec for JSON objects
1315 used as string-keyed maps. Returns an association list. *)
14161515-val of_id : 'a Jsont.t -> (Id.t * 'a) list Jsont.t
1717+val of_id : 'a Jsont.t -> (Proto_id.t * 'a) list Jsont.t
1618(** [of_id value_jsont] creates a codec for JSON objects
1719 keyed by JMAP identifiers. *)
18201919-val id_to_bool : (Id.t * bool) list Jsont.t
2121+val id_to_bool : (Proto_id.t * bool) list Jsont.t
2022(** Codec for Id[Boolean] maps, common in JMAP (e.g., mailboxIds, keywords). *)
21232224val string_to_bool : (string * bool) list Jsont.t
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** Email address types as defined in RFC 8621 Section 4.1.2.3 *)
66+(** Email address types as defined in RFC 8621 Section 4.1.2.3
77+88+ @canonical Jmap.Proto.Email_address *)
79810(** {1 Email Address} *)
911
+5-5
proto/mail/email_body.ml
lib/mail/mail_body.ml
···3131module Part = struct
3232 type t = {
3333 part_id : string option;
3434- blob_id : Jmap_proto.Id.t option;
3434+ blob_id : Proto_id.t option;
3535 size : int64 option;
3636- headers : Email_header.t list option;
3636+ headers : Mail_header.t list option;
3737 name : string option;
3838 type_ : string;
3939 charset : string option;
···6666 in
6767 (* Many fields can be null per RFC 8621 Section 4.1.4 *)
6868 let nullable_string = Jsont.(option string) in
6969- let nullable_id = Jsont.(option Jmap_proto.Id.jsont) in
6969+ let nullable_id = Jsont.(option Proto_id.jsont) in
7070 lazy (
7171 Jsont.Object.map ~kind make
7272 |> Jsont.Object.mem "partId" nullable_string
7373 ~dec_absent:None ~enc_omit:Option.is_none ~enc:part_id
7474 |> Jsont.Object.mem "blobId" nullable_id
7575 ~dec_absent:None ~enc_omit:Option.is_none ~enc:blob_id
7676- |> Jsont.Object.opt_mem "size" Jmap_proto.Int53.Unsigned.jsont ~enc:size
7777- |> Jsont.Object.opt_mem "headers" (Jsont.list Email_header.jsont) ~enc:headers
7676+ |> Jsont.Object.opt_mem "size" Proto_int53.Unsigned.jsont ~enc:size
7777+ |> Jsont.Object.opt_mem "headers" (Jsont.list Mail_header.jsont) ~enc:headers
7878 |> Jsont.Object.mem "name" nullable_string
7979 ~dec_absent:None ~enc_omit:Option.is_none ~enc:name
8080 |> Jsont.Object.mem "type" Jsont.string ~enc:type_
+7-5
proto/mail/email_body.mli
lib/mail/mail_body.mli
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** Email body types as defined in RFC 8621 Section 4.1.4 *)
66+(** Email body types as defined in RFC 8621 Section 4.1.4
77+88+ @canonical Jmap.Proto.Email_body *)
79810(** {1 Body Value} *)
911···3234 type t = {
3335 part_id : string option;
3436 (** Identifier for this part, used to fetch content. *)
3535- blob_id : Jmap_proto.Id.t option;
3737+ blob_id : Proto_id.t option;
3638 (** Blob id if the part can be fetched as a blob. *)
3739 size : int64 option;
3840 (** Size in octets. *)
3939- headers : Email_header.t list option;
4141+ headers : Mail_header.t list option;
4042 (** Headers specific to this part. *)
4143 name : string option;
4244 (** Suggested filename from Content-Disposition. *)
···5759 }
58605961 val part_id : t -> string option
6060- val blob_id : t -> Jmap_proto.Id.t option
6262+ val blob_id : t -> Proto_id.t option
6163 val size : t -> int64 option
6262- val headers : t -> Email_header.t list option
6464+ val headers : t -> Mail_header.t list option
6365 val name : t -> string option
6466 val type_ : t -> string
6567 val charset : t -> string option
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** Email header types as defined in RFC 8621 Section 4.1.2 *)
66+(** Email header types as defined in RFC 8621 Section 4.1.2
77+88+ @canonical Jmap.Proto.Email_header *)
79810(** {1 Raw Headers} *)
911···3436val text_jsont : string Jsont.t
35373638(** The addresses form - list of email addresses. *)
3737-val addresses_jsont : Email_address.t list Jsont.t
3939+val addresses_jsont : Mail_address.t list Jsont.t
38403941(** The grouped addresses form - addresses with group info. *)
4040-val grouped_addresses_jsont : Email_address.Group.t list Jsont.t
4242+val grouped_addresses_jsont : Mail_address.Group.t list Jsont.t
41434244(** The message IDs form - list of message-id strings. *)
4345val message_ids_jsont : string list Jsont.t
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** Identity type as defined in RFC 8621 Section 6 *)
66+(** Identity type as defined in RFC 8621 Section 6
77+88+ @canonical Jmap.Proto.Identity *)
79810type t = {
99- id : Jmap_proto.Id.t;
1111+ id : Proto_id.t;
1012 (** Server-assigned identity id. *)
1113 name : string;
1214 (** Display name for sent emails. *)
1315 email : string;
1416 (** The email address to use. *)
1515- reply_to : Email_address.t list option;
1717+ reply_to : Mail_address.t list option;
1618 (** Default Reply-To addresses. *)
1717- bcc : Email_address.t list option;
1919+ bcc : Mail_address.t list option;
1820 (** Default BCC addresses. *)
1921 text_signature : string;
2022 (** Plain text signature. *)
···2426 (** Whether the user may delete this identity. *)
2527}
26282727-val id : t -> Jmap_proto.Id.t
2929+val id : t -> Proto_id.t
2830val name : t -> string
2931val email : t -> string
3030-val reply_to : t -> Email_address.t list option
3131-val bcc : t -> Email_address.t list option
3232+val reply_to : t -> Mail_address.t list option
3333+val bcc : t -> Mail_address.t list option
3234val text_signature : t -> string
3335val html_signature : t -> string
3436val may_delete : t -> bool
···9292 Jsont.string
93939494type t = {
9595- id : Jmap_proto.Id.t;
9595+ id : Proto_id.t;
9696 name : string;
9797- parent_id : Jmap_proto.Id.t option;
9797+ parent_id : Proto_id.t option;
9898 role : role option;
9999 sort_order : int64;
100100 total_emails : int64;
···125125let jsont =
126126 let kind = "Mailbox" in
127127 (* parentId and role can be null - RFC 8621 Section 2 *)
128128- let nullable_id = Jsont.(option Jmap_proto.Id.jsont) in
128128+ let nullable_id = Jsont.(option Proto_id.jsont) in
129129 let nullable_role = Jsont.(option role_jsont) in
130130 Jsont.Object.map ~kind make
131131- |> Jsont.Object.mem "id" Jmap_proto.Id.jsont ~enc:id
131131+ |> Jsont.Object.mem "id" Proto_id.jsont ~enc:id
132132 |> Jsont.Object.mem "name" Jsont.string ~enc:name
133133 |> Jsont.Object.mem "parentId" nullable_id
134134 ~dec_absent:None ~enc_omit:Option.is_none ~enc:parent_id
135135 |> Jsont.Object.mem "role" nullable_role
136136 ~dec_absent:None ~enc_omit:Option.is_none ~enc:role
137137- |> Jsont.Object.mem "sortOrder" Jmap_proto.Int53.Unsigned.jsont ~dec_absent:0L ~enc:sort_order
138138- |> Jsont.Object.mem "totalEmails" Jmap_proto.Int53.Unsigned.jsont ~enc:total_emails
139139- |> Jsont.Object.mem "unreadEmails" Jmap_proto.Int53.Unsigned.jsont ~enc:unread_emails
140140- |> Jsont.Object.mem "totalThreads" Jmap_proto.Int53.Unsigned.jsont ~enc:total_threads
141141- |> Jsont.Object.mem "unreadThreads" Jmap_proto.Int53.Unsigned.jsont ~enc:unread_threads
137137+ |> Jsont.Object.mem "sortOrder" Proto_int53.Unsigned.jsont ~dec_absent:0L ~enc:sort_order
138138+ |> Jsont.Object.mem "totalEmails" Proto_int53.Unsigned.jsont ~enc:total_emails
139139+ |> Jsont.Object.mem "unreadEmails" Proto_int53.Unsigned.jsont ~enc:unread_emails
140140+ |> Jsont.Object.mem "totalThreads" Proto_int53.Unsigned.jsont ~enc:total_threads
141141+ |> Jsont.Object.mem "unreadThreads" Proto_int53.Unsigned.jsont ~enc:unread_threads
142142 |> Jsont.Object.mem "myRights" Rights.jsont ~enc:my_rights
143143 |> Jsont.Object.mem "isSubscribed" Jsont.bool ~enc:is_subscribed
144144 |> Jsont.Object.finish
145145146146module Filter_condition = struct
147147 type t = {
148148- parent_id : Jmap_proto.Id.t option option;
148148+ parent_id : Proto_id.t option option;
149149 name : string option;
150150 role : role option option;
151151 has_any_role : bool option;
···162162 - None = field absent (don't filter)
163163 - Some None = field present with null (filter for no parent/role)
164164 - Some (Some x) = field present with value (filter for specific value) *)
165165- let nullable_id = Jsont.(option Jmap_proto.Id.jsont) in
165165+ let nullable_id = Jsont.(option Proto_id.jsont) in
166166 let nullable_role = Jsont.(option role_jsont) in
167167 Jsont.Object.map ~kind make
168168 |> Jsont.Object.opt_mem "parentId" nullable_id ~enc:(fun f -> f.parent_id)
+8-6
proto/mail/mailbox.mli
lib/mail/mail_mailbox.mli
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** Mailbox type as defined in RFC 8621 Section 2 *)
66+(** Mailbox type as defined in RFC 8621 Section 2
77+88+ @canonical Jmap.Proto.Mailbox *)
79810(** {1 Mailbox Rights} *)
911···5759(** {1 Mailbox} *)
58605961type t = {
6060- id : Jmap_proto.Id.t;
6262+ id : Proto_id.t;
6163 (** Server-assigned mailbox id. *)
6264 name : string;
6365 (** User-visible name (UTF-8). *)
6464- parent_id : Jmap_proto.Id.t option;
6666+ parent_id : Proto_id.t option;
6567 (** Id of parent mailbox, or [None] for root. *)
6668 role : role option;
6769 (** Standard role, if any. *)
···8183 (** Whether user is subscribed to this mailbox. *)
8284}
83858484-val id : t -> Jmap_proto.Id.t
8686+val id : t -> Proto_id.t
8587val name : t -> string
8686-val parent_id : t -> Jmap_proto.Id.t option
8888+val parent_id : t -> Proto_id.t option
8789val role : t -> role option
8890val sort_order : t -> int64
8991val total_emails : t -> int64
···100102(** Filter conditions for Mailbox/query. *)
101103module Filter_condition : sig
102104 type t = {
103103- parent_id : Jmap_proto.Id.t option option;
105105+ parent_id : Proto_id.t option option;
104106 (** Filter by parent. [Some None] = top-level only. *)
105107 name : string option;
106108 (** Filter by exact name match. *)
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** SearchSnippet type as defined in RFC 8621 Section 5 *)
66+(** SearchSnippet type as defined in RFC 8621 Section 5
77+88+ @canonical Jmap.Proto.Search_snippet *)
79810type t = {
99- email_id : Jmap_proto.Id.t;
1111+ email_id : Proto_id.t;
1012 (** The email this snippet is for. *)
1113 subject : string option;
1214 (** HTML snippet of matching subject text. *)
···1416 (** HTML snippet of matching body text. *)
1517}
16181717-val email_id : t -> Jmap_proto.Id.t
1919+val email_id : t -> Proto_id.t
1820val subject : t -> string option
1921val preview : t -> string option
2022
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** EmailSubmission type as defined in RFC 8621 Section 7 *)
66+(** EmailSubmission type as defined in RFC 8621 Section 7
77+88+ @canonical Jmap.Proto.Submission *)
79810(** {1 Address} *)
911···8183(** {1 EmailSubmission} *)
82848385type t = {
8484- id : Jmap_proto.Id.t;
8686+ id : Proto_id.t;
8587 (** Server-assigned submission id. *)
8686- identity_id : Jmap_proto.Id.t;
8888+ identity_id : Proto_id.t;
8789 (** The identity used to send. *)
8888- email_id : Jmap_proto.Id.t;
9090+ email_id : Proto_id.t;
8991 (** The email that was submitted. *)
9090- thread_id : Jmap_proto.Id.t;
9292+ thread_id : Proto_id.t;
9193 (** The thread of the submitted email. *)
9294 envelope : Envelope.t option;
9395 (** The envelope used, if different from email headers. *)
···9799 (** Whether sending can be undone. *)
98100 delivery_status : (string * Delivery_status.t) list option;
99101 (** Delivery status per recipient. *)
100100- dsn_blob_ids : Jmap_proto.Id.t list;
102102+ dsn_blob_ids : Proto_id.t list;
101103 (** Blob ids of received DSN messages. *)
102102- mdn_blob_ids : Jmap_proto.Id.t list;
104104+ mdn_blob_ids : Proto_id.t list;
103105 (** Blob ids of received MDN messages. *)
104106}
105107106106-val id : t -> Jmap_proto.Id.t
107107-val identity_id : t -> Jmap_proto.Id.t
108108-val email_id : t -> Jmap_proto.Id.t
109109-val thread_id : t -> Jmap_proto.Id.t
108108+val id : t -> Proto_id.t
109109+val identity_id : t -> Proto_id.t
110110+val email_id : t -> Proto_id.t
111111+val thread_id : t -> Proto_id.t
110112val envelope : t -> Envelope.t option
111113val send_at : t -> Ptime.t
112114val undo_status : t -> undo_status
113115val delivery_status : t -> (string * Delivery_status.t) list option
114114-val dsn_blob_ids : t -> Jmap_proto.Id.t list
115115-val mdn_blob_ids : t -> Jmap_proto.Id.t list
116116+val dsn_blob_ids : t -> Proto_id.t list
117117+val mdn_blob_ids : t -> Proto_id.t list
116118117119val jsont : t Jsont.t
118120···120122121123module Filter_condition : sig
122124 type t = {
123123- identity_ids : Jmap_proto.Id.t list option;
124124- email_ids : Jmap_proto.Id.t list option;
125125- thread_ids : Jmap_proto.Id.t list option;
125125+ identity_ids : Proto_id.t list option;
126126+ email_ids : Proto_id.t list option;
127127+ thread_ids : Proto_id.t list option;
126128 undo_status : undo_status option;
127129 before : Ptime.t option;
128130 after : Ptime.t option;
+4-4
proto/mail/thread.ml
lib/mail/mail_thread.ml
···44 ---------------------------------------------------------------------------*)
5566type t = {
77- id : Jmap_proto.Id.t;
88- email_ids : Jmap_proto.Id.t list;
77+ id : Proto_id.t;
88+ email_ids : Proto_id.t list;
99}
10101111let id t = t.id
···1616let jsont =
1717 let kind = "Thread" in
1818 Jsont.Object.map ~kind make
1919- |> Jsont.Object.mem "id" Jmap_proto.Id.jsont ~enc:id
2020- |> Jsont.Object.mem "emailIds" (Jsont.list Jmap_proto.Id.jsont) ~enc:email_ids
1919+ |> Jsont.Object.mem "id" Proto_id.jsont ~enc:id
2020+ |> Jsont.Object.mem "emailIds" (Jsont.list Proto_id.jsont) ~enc:email_ids
2121 |> Jsont.Object.finish
+7-5
proto/mail/thread.mli
lib/mail/mail_thread.mli
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** Thread type as defined in RFC 8621 Section 3 *)
66+(** Thread type as defined in RFC 8621 Section 3
77+88+ @canonical Jmap.Proto.Thread *)
79810type t = {
99- id : Jmap_proto.Id.t;
1111+ id : Proto_id.t;
1012 (** Server-assigned thread id. *)
1111- email_ids : Jmap_proto.Id.t list;
1313+ email_ids : Proto_id.t list;
1214 (** Ids of emails in this thread, in date order. *)
1315}
14161515-val id : t -> Jmap_proto.Id.t
1616-val email_ids : t -> Jmap_proto.Id.t list
1717+val id : t -> Proto_id.t
1818+val email_ids : t -> Proto_id.t list
17191820val jsont : t Jsont.t
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** VacationResponse type as defined in RFC 8621 Section 8 *)
66+(** VacationResponse type as defined in RFC 8621 Section 8
77+88+ @canonical Jmap.Proto.Vacation *)
79810type t = {
99- id : Jmap_proto.Id.t;
1111+ id : Proto_id.t;
1012 (** Always "singleton" - there is only one vacation response. *)
1113 is_enabled : bool;
1214 (** Whether the vacation response is active. *)
···2224 (** HTML body. *)
2325}
24262525-val id : t -> Jmap_proto.Id.t
2727+val id : t -> Proto_id.t
2628val is_enabled : t -> bool
2729val from_date : t -> Ptime.t option
2830val to_date : t -> Ptime.t option
···3335val jsont : t Jsont.t
34363537(** The singleton id for VacationResponse. *)
3636-val singleton_id : Jmap_proto.Id.t
3838+val singleton_id : Proto_id.t
-317
proto/method_.ml
···11-(*---------------------------------------------------------------------------
22- Copyright (c) 2025 Anil Madhavapeddy. All rights reserved.
33- SPDX-License-Identifier: ISC
44- ---------------------------------------------------------------------------*)
55-66-(* Foo/get *)
77-88-type get_args = {
99- account_id : Id.t;
1010- ids : Id.t list option;
1111- properties : string list option;
1212-}
1313-1414-let get_args ~account_id ?ids ?properties () =
1515- { account_id; ids; properties }
1616-1717-let get_args_make account_id ids properties =
1818- { account_id; ids; properties }
1919-2020-let get_args_jsont =
2121- let kind = "GetArgs" in
2222- Jsont.Object.map ~kind get_args_make
2323- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun a -> a.account_id)
2424- |> Jsont.Object.opt_mem "ids" (Jsont.list Id.jsont) ~enc:(fun a -> a.ids)
2525- |> Jsont.Object.opt_mem "properties" (Jsont.list Jsont.string) ~enc:(fun a -> a.properties)
2626- |> Jsont.Object.finish
2727-2828-type 'a get_response = {
2929- account_id : Id.t;
3030- state : string;
3131- list : 'a list;
3232- not_found : Id.t list;
3333-}
3434-3535-let get_response_jsont (type a) (obj_jsont : a Jsont.t) : a get_response Jsont.t =
3636- let kind = "GetResponse" in
3737- let make account_id state list not_found =
3838- { account_id; state; list; not_found }
3939- in
4040- Jsont.Object.map ~kind make
4141- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun r -> r.account_id)
4242- |> Jsont.Object.mem "state" Jsont.string ~enc:(fun r -> r.state)
4343- |> Jsont.Object.mem "list" (Jsont.list obj_jsont) ~enc:(fun r -> r.list)
4444- |> Jsont.Object.mem "notFound" (Jsont.list Id.jsont) ~enc:(fun r -> r.not_found)
4545- |> Jsont.Object.finish
4646-4747-(* Foo/changes *)
4848-4949-type changes_args = {
5050- account_id : Id.t;
5151- since_state : string;
5252- max_changes : int64 option;
5353-}
5454-5555-let changes_args ~account_id ~since_state ?max_changes () =
5656- { account_id; since_state; max_changes }
5757-5858-let changes_args_make account_id since_state max_changes =
5959- { account_id; since_state; max_changes }
6060-6161-let changes_args_jsont =
6262- let kind = "ChangesArgs" in
6363- Jsont.Object.map ~kind changes_args_make
6464- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun a -> a.account_id)
6565- |> Jsont.Object.mem "sinceState" Jsont.string ~enc:(fun a -> a.since_state)
6666- |> Jsont.Object.opt_mem "maxChanges" Int53.Unsigned.jsont ~enc:(fun a -> a.max_changes)
6767- |> Jsont.Object.finish
6868-6969-type changes_response = {
7070- account_id : Id.t;
7171- old_state : string;
7272- new_state : string;
7373- has_more_changes : bool;
7474- created : Id.t list;
7575- updated : Id.t list;
7676- destroyed : Id.t list;
7777-}
7878-7979-let changes_response_make account_id old_state new_state has_more_changes
8080- created updated destroyed =
8181- { account_id; old_state; new_state; has_more_changes; created; updated; destroyed }
8282-8383-let changes_response_jsont =
8484- let kind = "ChangesResponse" in
8585- Jsont.Object.map ~kind changes_response_make
8686- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun r -> r.account_id)
8787- |> Jsont.Object.mem "oldState" Jsont.string ~enc:(fun r -> r.old_state)
8888- |> Jsont.Object.mem "newState" Jsont.string ~enc:(fun r -> r.new_state)
8989- |> Jsont.Object.mem "hasMoreChanges" Jsont.bool ~enc:(fun r -> r.has_more_changes)
9090- |> Jsont.Object.mem "created" (Jsont.list Id.jsont) ~enc:(fun r -> r.created)
9191- |> Jsont.Object.mem "updated" (Jsont.list Id.jsont) ~enc:(fun r -> r.updated)
9292- |> Jsont.Object.mem "destroyed" (Jsont.list Id.jsont) ~enc:(fun r -> r.destroyed)
9393- |> Jsont.Object.finish
9494-9595-(* Foo/set *)
9696-9797-type 'a set_args = {
9898- account_id : Id.t;
9999- if_in_state : string option;
100100- create : (Id.t * 'a) list option;
101101- update : (Id.t * Jsont.json) list option;
102102- destroy : Id.t list option;
103103-}
104104-105105-let set_args ~account_id ?if_in_state ?create ?update ?destroy () =
106106- { account_id; if_in_state; create; update; destroy }
107107-108108-let set_args_jsont (type a) (obj_jsont : a Jsont.t) : a set_args Jsont.t =
109109- let kind = "SetArgs" in
110110- let make account_id if_in_state create update destroy =
111111- { account_id; if_in_state; create; update; destroy }
112112- in
113113- Jsont.Object.map ~kind make
114114- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun a -> a.account_id)
115115- |> Jsont.Object.opt_mem "ifInState" Jsont.string ~enc:(fun a -> a.if_in_state)
116116- |> Jsont.Object.opt_mem "create" (Json_map.of_id obj_jsont) ~enc:(fun a -> a.create)
117117- |> Jsont.Object.opt_mem "update" (Json_map.of_id Jsont.json) ~enc:(fun a -> a.update)
118118- |> Jsont.Object.opt_mem "destroy" (Jsont.list Id.jsont) ~enc:(fun a -> a.destroy)
119119- |> Jsont.Object.finish
120120-121121-type 'a set_response = {
122122- account_id : Id.t;
123123- old_state : string option;
124124- new_state : string;
125125- created : (Id.t * 'a) list option;
126126- updated : (Id.t * 'a option) list option;
127127- destroyed : Id.t list option;
128128- not_created : (Id.t * Error.set_error) list option;
129129- not_updated : (Id.t * Error.set_error) list option;
130130- not_destroyed : (Id.t * Error.set_error) list option;
131131-}
132132-133133-let set_response_jsont (type a) (obj_jsont : a Jsont.t) : a set_response Jsont.t =
134134- let kind = "SetResponse" in
135135- let make account_id old_state new_state created updated destroyed
136136- not_created not_updated not_destroyed =
137137- { account_id; old_state; new_state; created; updated; destroyed;
138138- not_created; not_updated; not_destroyed }
139139- in
140140- (* For updated values, the server may return null or an object - RFC 8620 Section 5.3 *)
141141- (* "Id[Foo|null]" means map values can be null, use Jsont.option to handle this *)
142142- let nullable_obj = Jsont.(option obj_jsont) in
143143- Jsont.Object.map ~kind make
144144- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun r -> r.account_id)
145145- |> Jsont.Object.opt_mem "oldState" Jsont.string ~enc:(fun r -> r.old_state)
146146- |> Jsont.Object.mem "newState" Jsont.string ~enc:(fun r -> r.new_state)
147147- |> Jsont.Object.opt_mem "created" (Json_map.of_id obj_jsont) ~enc:(fun r -> r.created)
148148- |> Jsont.Object.opt_mem "updated" (Json_map.of_id nullable_obj) ~enc:(fun r -> r.updated)
149149- |> Jsont.Object.opt_mem "destroyed" (Jsont.list Id.jsont) ~enc:(fun r -> r.destroyed)
150150- |> Jsont.Object.opt_mem "notCreated" (Json_map.of_id Error.set_error_jsont) ~enc:(fun r -> r.not_created)
151151- |> Jsont.Object.opt_mem "notUpdated" (Json_map.of_id Error.set_error_jsont) ~enc:(fun r -> r.not_updated)
152152- |> Jsont.Object.opt_mem "notDestroyed" (Json_map.of_id Error.set_error_jsont) ~enc:(fun r -> r.not_destroyed)
153153- |> Jsont.Object.finish
154154-155155-(* Foo/copy *)
156156-157157-type 'a copy_args = {
158158- from_account_id : Id.t;
159159- if_from_in_state : string option;
160160- account_id : Id.t;
161161- if_in_state : string option;
162162- create : (Id.t * 'a) list;
163163- on_success_destroy_original : bool;
164164- destroy_from_if_in_state : string option;
165165-}
166166-167167-let copy_args_jsont (type a) (obj_jsont : a Jsont.t) : a copy_args Jsont.t =
168168- let kind = "CopyArgs" in
169169- let make from_account_id if_from_in_state account_id if_in_state create
170170- on_success_destroy_original destroy_from_if_in_state =
171171- { from_account_id; if_from_in_state; account_id; if_in_state; create;
172172- on_success_destroy_original; destroy_from_if_in_state }
173173- in
174174- Jsont.Object.map ~kind make
175175- |> Jsont.Object.mem "fromAccountId" Id.jsont ~enc:(fun a -> a.from_account_id)
176176- |> Jsont.Object.opt_mem "ifFromInState" Jsont.string ~enc:(fun a -> a.if_from_in_state)
177177- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun a -> a.account_id)
178178- |> Jsont.Object.opt_mem "ifInState" Jsont.string ~enc:(fun a -> a.if_in_state)
179179- |> Jsont.Object.mem "create" (Json_map.of_id obj_jsont) ~enc:(fun a -> a.create)
180180- |> Jsont.Object.mem "onSuccessDestroyOriginal" Jsont.bool ~dec_absent:false
181181- ~enc:(fun a -> a.on_success_destroy_original)
182182- ~enc_omit:(fun b -> not b)
183183- |> Jsont.Object.opt_mem "destroyFromIfInState" Jsont.string ~enc:(fun a -> a.destroy_from_if_in_state)
184184- |> Jsont.Object.finish
185185-186186-type 'a copy_response = {
187187- from_account_id : Id.t;
188188- account_id : Id.t;
189189- old_state : string option;
190190- new_state : string;
191191- created : (Id.t * 'a) list option;
192192- not_created : (Id.t * Error.set_error) list option;
193193-}
194194-195195-let copy_response_jsont (type a) (obj_jsont : a Jsont.t) : a copy_response Jsont.t =
196196- let kind = "CopyResponse" in
197197- let make from_account_id account_id old_state new_state created not_created =
198198- { from_account_id; account_id; old_state; new_state; created; not_created }
199199- in
200200- Jsont.Object.map ~kind make
201201- |> Jsont.Object.mem "fromAccountId" Id.jsont ~enc:(fun r -> r.from_account_id)
202202- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun r -> r.account_id)
203203- |> Jsont.Object.opt_mem "oldState" Jsont.string ~enc:(fun r -> r.old_state)
204204- |> Jsont.Object.mem "newState" Jsont.string ~enc:(fun r -> r.new_state)
205205- |> Jsont.Object.opt_mem "created" (Json_map.of_id obj_jsont) ~enc:(fun r -> r.created)
206206- |> Jsont.Object.opt_mem "notCreated" (Json_map.of_id Error.set_error_jsont) ~enc:(fun r -> r.not_created)
207207- |> Jsont.Object.finish
208208-209209-(* Foo/query *)
210210-211211-type 'filter query_args = {
212212- account_id : Id.t;
213213- filter : 'filter Filter.filter option;
214214- sort : Filter.comparator list option;
215215- position : int64;
216216- anchor : Id.t option;
217217- anchor_offset : int64;
218218- limit : int64 option;
219219- calculate_total : bool;
220220-}
221221-222222-let query_args ~account_id ?filter ?sort ?(position = 0L) ?anchor
223223- ?(anchor_offset = 0L) ?limit ?(calculate_total = false) () =
224224- { account_id; filter; sort; position; anchor; anchor_offset; limit; calculate_total }
225225-226226-let query_args_jsont (type f) (filter_cond_jsont : f Jsont.t) : f query_args Jsont.t =
227227- let kind = "QueryArgs" in
228228- let make account_id filter sort position anchor anchor_offset limit calculate_total =
229229- { account_id; filter; sort; position; anchor; anchor_offset; limit; calculate_total }
230230- in
231231- Jsont.Object.map ~kind make
232232- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun a -> a.account_id)
233233- |> Jsont.Object.opt_mem "filter" (Filter.filter_jsont filter_cond_jsont) ~enc:(fun a -> a.filter)
234234- |> Jsont.Object.opt_mem "sort" (Jsont.list Filter.comparator_jsont) ~enc:(fun a -> a.sort)
235235- |> Jsont.Object.mem "position" Int53.Signed.jsont ~dec_absent:0L ~enc:(fun a -> a.position)
236236- ~enc_omit:(fun p -> p = 0L)
237237- |> Jsont.Object.opt_mem "anchor" Id.jsont ~enc:(fun a -> a.anchor)
238238- |> Jsont.Object.mem "anchorOffset" Int53.Signed.jsont ~dec_absent:0L ~enc:(fun a -> a.anchor_offset)
239239- ~enc_omit:(fun o -> o = 0L)
240240- |> Jsont.Object.opt_mem "limit" Int53.Unsigned.jsont ~enc:(fun a -> a.limit)
241241- |> Jsont.Object.mem "calculateTotal" Jsont.bool ~dec_absent:false ~enc:(fun a -> a.calculate_total)
242242- ~enc_omit:(fun b -> not b)
243243- |> Jsont.Object.finish
244244-245245-type query_response = {
246246- account_id : Id.t;
247247- query_state : string;
248248- can_calculate_changes : bool;
249249- position : int64;
250250- ids : Id.t list;
251251- total : int64 option;
252252-}
253253-254254-let query_response_make account_id query_state can_calculate_changes position ids total =
255255- { account_id; query_state; can_calculate_changes; position; ids; total }
256256-257257-let query_response_jsont =
258258- let kind = "QueryResponse" in
259259- Jsont.Object.map ~kind query_response_make
260260- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun r -> r.account_id)
261261- |> Jsont.Object.mem "queryState" Jsont.string ~enc:(fun r -> r.query_state)
262262- |> Jsont.Object.mem "canCalculateChanges" Jsont.bool ~enc:(fun r -> r.can_calculate_changes)
263263- |> Jsont.Object.mem "position" Int53.Unsigned.jsont ~enc:(fun r -> r.position)
264264- |> Jsont.Object.mem "ids" (Jsont.list Id.jsont) ~enc:(fun r -> r.ids)
265265- |> Jsont.Object.opt_mem "total" Int53.Unsigned.jsont ~enc:(fun r -> r.total)
266266- |> Jsont.Object.finish
267267-268268-(* Foo/queryChanges *)
269269-270270-type 'filter query_changes_args = {
271271- account_id : Id.t;
272272- filter : 'filter Filter.filter option;
273273- sort : Filter.comparator list option;
274274- since_query_state : string;
275275- max_changes : int64 option;
276276- up_to_id : Id.t option;
277277- calculate_total : bool;
278278-}
279279-280280-let query_changes_args_jsont (type f) (filter_cond_jsont : f Jsont.t) : f query_changes_args Jsont.t =
281281- let kind = "QueryChangesArgs" in
282282- let make account_id filter sort since_query_state max_changes up_to_id calculate_total =
283283- { account_id; filter; sort; since_query_state; max_changes; up_to_id; calculate_total }
284284- in
285285- Jsont.Object.map ~kind make
286286- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun a -> a.account_id)
287287- |> Jsont.Object.opt_mem "filter" (Filter.filter_jsont filter_cond_jsont) ~enc:(fun a -> a.filter)
288288- |> Jsont.Object.opt_mem "sort" (Jsont.list Filter.comparator_jsont) ~enc:(fun a -> a.sort)
289289- |> Jsont.Object.mem "sinceQueryState" Jsont.string ~enc:(fun a -> a.since_query_state)
290290- |> Jsont.Object.opt_mem "maxChanges" Int53.Unsigned.jsont ~enc:(fun a -> a.max_changes)
291291- |> Jsont.Object.opt_mem "upToId" Id.jsont ~enc:(fun a -> a.up_to_id)
292292- |> Jsont.Object.mem "calculateTotal" Jsont.bool ~dec_absent:false ~enc:(fun a -> a.calculate_total)
293293- ~enc_omit:(fun b -> not b)
294294- |> Jsont.Object.finish
295295-296296-type query_changes_response = {
297297- account_id : Id.t;
298298- old_query_state : string;
299299- new_query_state : string;
300300- total : int64 option;
301301- removed : Id.t list;
302302- added : Filter.added_item list;
303303-}
304304-305305-let query_changes_response_make account_id old_query_state new_query_state total removed added =
306306- { account_id; old_query_state; new_query_state; total; removed; added }
307307-308308-let query_changes_response_jsont =
309309- let kind = "QueryChangesResponse" in
310310- Jsont.Object.map ~kind query_changes_response_make
311311- |> Jsont.Object.mem "accountId" Id.jsont ~enc:(fun r -> r.account_id)
312312- |> Jsont.Object.mem "oldQueryState" Jsont.string ~enc:(fun r -> r.old_query_state)
313313- |> Jsont.Object.mem "newQueryState" Jsont.string ~enc:(fun r -> r.new_query_state)
314314- |> Jsont.Object.opt_mem "total" Int53.Unsigned.jsont ~enc:(fun r -> r.total)
315315- |> Jsont.Object.mem "removed" (Jsont.list Id.jsont) ~enc:(fun r -> r.removed)
316316- |> Jsont.Object.mem "added" (Jsont.list Filter.added_item_jsont) ~enc:(fun r -> r.added)
317317- |> Jsont.Object.finish
+54-52
proto/method_.mli
lib/proto/proto_method.mli
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** JMAP standard method types as defined in RFC 8620 Section 5 *)
66+(** JMAP standard method types as defined in RFC 8620 Section 5
77+88+ @canonical Jmap.Proto.Method *)
79810(** {1 Foo/get} *)
9111012(** Arguments for /get methods. *)
1113type get_args = {
1212- account_id : Id.t;
1414+ account_id : Proto_id.t;
1315 (** The account to fetch from. *)
1414- ids : Id.t list option;
1616+ ids : Proto_id.t list option;
1517 (** The ids to fetch. [None] means fetch all. *)
1618 properties : string list option;
1719 (** Properties to include. [None] means all. *)
1820}
19212022val get_args :
2121- account_id:Id.t ->
2222- ?ids:Id.t list ->
2323+ account_id:Proto_id.t ->
2424+ ?ids:Proto_id.t list ->
2325 ?properties:string list ->
2426 unit ->
2527 get_args
···28302931(** Response for /get methods. *)
3032type 'a get_response = {
3131- account_id : Id.t;
3333+ account_id : Proto_id.t;
3234 (** The account fetched from. *)
3335 state : string;
3436 (** Current state string. *)
3537 list : 'a list;
3638 (** The objects fetched. *)
3737- not_found : Id.t list;
3939+ not_found : Proto_id.t list;
3840 (** Ids that were not found. *)
3941}
4042···44464547(** Arguments for /changes methods. *)
4648type changes_args = {
4747- account_id : Id.t;
4949+ account_id : Proto_id.t;
4850 since_state : string;
4951 max_changes : int64 option;
5052}
51535254val changes_args :
5353- account_id:Id.t ->
5555+ account_id:Proto_id.t ->
5456 since_state:string ->
5557 ?max_changes:int64 ->
5658 unit ->
···60626163(** Response for /changes methods. *)
6264type changes_response = {
6363- account_id : Id.t;
6565+ account_id : Proto_id.t;
6466 old_state : string;
6567 new_state : string;
6668 has_more_changes : bool;
6767- created : Id.t list;
6868- updated : Id.t list;
6969- destroyed : Id.t list;
6969+ created : Proto_id.t list;
7070+ updated : Proto_id.t list;
7171+ destroyed : Proto_id.t list;
7072}
71737274val changes_response_jsont : changes_response Jsont.t
···77797880 The ['a] type parameter is the object type being created/updated. *)
7981type 'a set_args = {
8080- account_id : Id.t;
8282+ account_id : Proto_id.t;
8183 if_in_state : string option;
8284 (** If set, only apply if current state matches. *)
8383- create : (Id.t * 'a) list option;
8585+ create : (Proto_id.t * 'a) list option;
8486 (** Objects to create, keyed by temporary id. *)
8585- update : (Id.t * Jsont.json) list option;
8787+ update : (Proto_id.t * Jsont.json) list option;
8688 (** Objects to update. Value is a PatchObject. *)
8787- destroy : Id.t list option;
8989+ destroy : Proto_id.t list option;
8890 (** Ids to destroy. *)
8991}
90929193val set_args :
9292- account_id:Id.t ->
9494+ account_id:Proto_id.t ->
9395 ?if_in_state:string ->
9494- ?create:(Id.t * 'a) list ->
9595- ?update:(Id.t * Jsont.json) list ->
9696- ?destroy:Id.t list ->
9696+ ?create:(Proto_id.t * 'a) list ->
9797+ ?update:(Proto_id.t * Jsont.json) list ->
9898+ ?destroy:Proto_id.t list ->
9799 unit ->
98100 'a set_args
99101···101103102104(** Response for /set methods. *)
103105type 'a set_response = {
104104- account_id : Id.t;
106106+ account_id : Proto_id.t;
105107 old_state : string option;
106108 new_state : string;
107107- created : (Id.t * 'a) list option;
109109+ created : (Proto_id.t * 'a) list option;
108110 (** Successfully created objects, keyed by temporary id. *)
109109- updated : (Id.t * 'a option) list option;
111111+ updated : (Proto_id.t * 'a option) list option;
110112 (** Successfully updated objects. Value may include server-set properties. *)
111111- destroyed : Id.t list option;
113113+ destroyed : Proto_id.t list option;
112114 (** Successfully destroyed ids. *)
113113- not_created : (Id.t * Error.set_error) list option;
115115+ not_created : (Proto_id.t * Proto_error.set_error) list option;
114116 (** Failed creates. *)
115115- not_updated : (Id.t * Error.set_error) list option;
117117+ not_updated : (Proto_id.t * Proto_error.set_error) list option;
116118 (** Failed updates. *)
117117- not_destroyed : (Id.t * Error.set_error) list option;
119119+ not_destroyed : (Proto_id.t * Proto_error.set_error) list option;
118120 (** Failed destroys. *)
119121}
120122···124126125127(** Arguments for /copy methods. *)
126128type 'a copy_args = {
127127- from_account_id : Id.t;
129129+ from_account_id : Proto_id.t;
128130 if_from_in_state : string option;
129129- account_id : Id.t;
131131+ account_id : Proto_id.t;
130132 if_in_state : string option;
131131- create : (Id.t * 'a) list;
133133+ create : (Proto_id.t * 'a) list;
132134 on_success_destroy_original : bool;
133135 destroy_from_if_in_state : string option;
134136}
···137139138140(** Response for /copy methods. *)
139141type 'a copy_response = {
140140- from_account_id : Id.t;
141141- account_id : Id.t;
142142+ from_account_id : Proto_id.t;
143143+ account_id : Proto_id.t;
142144 old_state : string option;
143145 new_state : string;
144144- created : (Id.t * 'a) list option;
145145- not_created : (Id.t * Error.set_error) list option;
146146+ created : (Proto_id.t * 'a) list option;
147147+ not_created : (Proto_id.t * Proto_error.set_error) list option;
146148}
147149148150val copy_response_jsont : 'a Jsont.t -> 'a copy_response Jsont.t
···151153152154(** Arguments for /query methods. *)
153155type 'filter query_args = {
154154- account_id : Id.t;
155155- filter : 'filter Filter.filter option;
156156- sort : Filter.comparator list option;
156156+ account_id : Proto_id.t;
157157+ filter : 'filter Proto_filter.filter option;
158158+ sort : Proto_filter.comparator list option;
157159 position : int64;
158158- anchor : Id.t option;
160160+ anchor : Proto_id.t option;
159161 anchor_offset : int64;
160162 limit : int64 option;
161163 calculate_total : bool;
162164}
163165164166val query_args :
165165- account_id:Id.t ->
166166- ?filter:'filter Filter.filter ->
167167- ?sort:Filter.comparator list ->
167167+ account_id:Proto_id.t ->
168168+ ?filter:'filter Proto_filter.filter ->
169169+ ?sort:Proto_filter.comparator list ->
168170 ?position:int64 ->
169169- ?anchor:Id.t ->
171171+ ?anchor:Proto_id.t ->
170172 ?anchor_offset:int64 ->
171173 ?limit:int64 ->
172174 ?calculate_total:bool ->
···177179178180(** Response for /query methods. *)
179181type query_response = {
180180- account_id : Id.t;
182182+ account_id : Proto_id.t;
181183 query_state : string;
182184 can_calculate_changes : bool;
183185 position : int64;
184184- ids : Id.t list;
186186+ ids : Proto_id.t list;
185187 total : int64 option;
186188}
187189···191193192194(** Arguments for /queryChanges methods. *)
193195type 'filter query_changes_args = {
194194- account_id : Id.t;
195195- filter : 'filter Filter.filter option;
196196- sort : Filter.comparator list option;
196196+ account_id : Proto_id.t;
197197+ filter : 'filter Proto_filter.filter option;
198198+ sort : Proto_filter.comparator list option;
197199 since_query_state : string;
198200 max_changes : int64 option;
199199- up_to_id : Id.t option;
201201+ up_to_id : Proto_id.t option;
200202 calculate_total : bool;
201203}
202204···204206205207(** Response for /queryChanges methods. *)
206208type query_changes_response = {
207207- account_id : Id.t;
209209+ account_id : Proto_id.t;
208210 old_query_state : string;
209211 new_query_state : string;
210212 total : int64 option;
211211- removed : Id.t list;
212212- added : Filter.added_item list;
213213+ removed : Proto_id.t list;
214214+ added : Proto_filter.added_item list;
213215}
214216215217val query_changes_response_jsont : query_changes_response Jsont.t
+16-16
proto/push.ml
lib/proto/proto_push.ml
···11111212 type t = {
1313 type_ : string;
1414- changed : (Id.t * type_state list) list;
1414+ changed : (Proto_id.t * type_state list) list;
1515 }
16161717 (* The changed object is account_id -> { typeName: state } *)
1818 let changed_jsont =
1919 let kind = "Changed" in
2020 (* Inner is type -> state string map *)
2121- let type_states_jsont = Json_map.of_string Jsont.string in
2121+ let type_states_jsont = Proto_json_map.of_string Jsont.string in
2222 (* Convert list of (string * string) to type_state list *)
2323 let decode_type_states pairs =
2424 List.map (fun (type_name, state) -> { type_name; state }) pairs
···2626 let encode_type_states states =
2727 List.map (fun ts -> (ts.type_name, ts.state)) states
2828 in
2929- Json_map.of_id
2929+ Proto_json_map.of_id
3030 (Jsont.map ~kind ~dec:decode_type_states ~enc:encode_type_states type_states_jsont)
31313232 let make type_ changed = { type_; changed }
···5454 |> Jsont.Object.finish
55555656type t = {
5757- id : Id.t;
5757+ id : Proto_id.t;
5858 device_client_id : string;
5959 url : string;
6060 keys : push_keys option;
···7777let jsont =
7878 let kind = "PushSubscription" in
7979 Jsont.Object.map ~kind make
8080- |> Jsont.Object.mem "id" Id.jsont ~enc:id
8080+ |> Jsont.Object.mem "id" Proto_id.jsont ~enc:id
8181 |> Jsont.Object.mem "deviceClientId" Jsont.string ~enc:device_client_id
8282 |> Jsont.Object.mem "url" Jsont.string ~enc:url
8383 |> Jsont.Object.opt_mem "keys" push_keys_jsont ~enc:keys
8484 |> Jsont.Object.opt_mem "verificationCode" Jsont.string ~enc:verification_code
8585- |> Jsont.Object.opt_mem "expires" Date.Utc.jsont ~enc:expires
8585+ |> Jsont.Object.opt_mem "expires" Proto_date.Utc.jsont ~enc:expires
8686 |> Jsont.Object.opt_mem "types" (Jsont.list Jsont.string) ~enc:types
8787 |> Jsont.Object.finish
88888989-let get_args_jsont = Method_.get_args_jsont
9090-let get_response_jsont = Method_.get_response_jsont jsont
8989+let get_args_jsont = Proto_method.get_args_jsont
9090+let get_response_jsont = Proto_method.get_response_jsont jsont
91919292type create_args = {
9393 device_client_id : string;
···111111 |> Jsont.Object.finish
112112113113type set_args = {
114114- account_id : Id.t option;
114114+ account_id : Proto_id.t option;
115115 if_in_state : string option;
116116- create : (Id.t * create_args) list option;
117117- update : (Id.t * Jsont.json) list option;
118118- destroy : Id.t list option;
116116+ create : (Proto_id.t * create_args) list option;
117117+ update : (Proto_id.t * Jsont.json) list option;
118118+ destroy : Proto_id.t list option;
119119}
120120121121let set_args_make account_id if_in_state create update destroy =
···124124let set_args_jsont =
125125 let kind = "PushSubscription/set args" in
126126 Jsont.Object.map ~kind set_args_make
127127- |> Jsont.Object.opt_mem "accountId" Id.jsont ~enc:(fun a -> a.account_id)
127127+ |> Jsont.Object.opt_mem "accountId" Proto_id.jsont ~enc:(fun a -> a.account_id)
128128 |> Jsont.Object.opt_mem "ifInState" Jsont.string ~enc:(fun a -> a.if_in_state)
129129- |> Jsont.Object.opt_mem "create" (Json_map.of_id create_args_jsont) ~enc:(fun a -> a.create)
130130- |> Jsont.Object.opt_mem "update" (Json_map.of_id Jsont.json) ~enc:(fun a -> a.update)
131131- |> Jsont.Object.opt_mem "destroy" (Jsont.list Id.jsont) ~enc:(fun a -> a.destroy)
129129+ |> Jsont.Object.opt_mem "create" (Proto_json_map.of_id create_args_jsont) ~enc:(fun a -> a.create)
130130+ |> Jsont.Object.opt_mem "update" (Proto_json_map.of_id Jsont.json) ~enc:(fun a -> a.update)
131131+ |> Jsont.Object.opt_mem "destroy" (Jsont.list Proto_id.jsont) ~enc:(fun a -> a.destroy)
132132 |> Jsont.Object.finish
+12-10
proto/push.mli
lib/proto/proto_push.mli
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** JMAP push types as defined in RFC 8620 Section 7 *)
66+(** JMAP push types as defined in RFC 8620 Section 7
77+88+ @canonical Jmap.Proto.Push *)
79810(** {1 StateChange} *)
911···1921 type t = {
2022 type_ : string;
2123 (** Always "StateChange". *)
2222- changed : (Id.t * type_state list) list;
2424+ changed : (Proto_id.t * type_state list) list;
2325 (** Map of account id to list of type state changes. *)
2426 }
2527···40424143(** A push subscription object. *)
4244type t = {
4343- id : Id.t;
4545+ id : Proto_id.t;
4446 (** Server-assigned subscription id. *)
4547 device_client_id : string;
4648 (** Client-provided device identifier. *)
···5658 (** Data types to receive notifications for. [None] means all. *)
5759}
58605959-val id : t -> Id.t
6161+val id : t -> Proto_id.t
6062val device_client_id : t -> string
6163val url : t -> string
6264val keys : t -> push_keys option
···7072(** {1 PushSubscription Methods} *)
71737274(** Arguments for PushSubscription/get. *)
7373-val get_args_jsont : Method_.get_args Jsont.t
7575+val get_args_jsont : Proto_method.get_args Jsont.t
74767577(** Response for PushSubscription/get. *)
7676-val get_response_jsont : t Method_.get_response Jsont.t
7878+val get_response_jsont : t Proto_method.get_response Jsont.t
77797880(** Arguments for PushSubscription/set. *)
7981type set_args = {
8080- account_id : Id.t option;
8282+ account_id : Proto_id.t option;
8183 (** Not used for PushSubscription. *)
8284 if_in_state : string option;
8383- create : (Id.t * create_args) list option;
8484- update : (Id.t * Jsont.json) list option;
8585- destroy : Id.t list option;
8585+ create : (Proto_id.t * create_args) list option;
8686+ update : (Proto_id.t * Jsont.json) list option;
8787+ destroy : Proto_id.t list option;
8688}
87898890and create_args = {
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** JMAP request object as defined in RFC 8620 Section 3.3 *)
66+(** JMAP request object as defined in RFC 8620 Section 3.3
77+88+ @canonical Jmap.Proto.Request *)
79810type t = {
911 using : string list;
1012 (** Capability URIs required for this request. *)
1111- method_calls : Invocation.t list;
1313+ method_calls : Proto_invocation.t list;
1214 (** The method calls to execute. *)
1313- created_ids : (Id.t * Id.t) list option;
1515+ created_ids : (Proto_id.t * Proto_id.t) list option;
1416 (** Map of client-created temporary ids to server-assigned ids.
1517 Used for result references in batch operations. *)
1618}
17191820val create :
1921 using:string list ->
2020- method_calls:Invocation.t list ->
2121- ?created_ids:(Id.t * Id.t) list ->
2222+ method_calls:Proto_invocation.t list ->
2323+ ?created_ids:(Proto_id.t * Proto_id.t) list ->
2224 unit ->
2325 t
2426(** [create ~using ~method_calls ?created_ids ()] creates a JMAP request. *)
25272628val using : t -> string list
2727-val method_calls : t -> Invocation.t list
2828-val created_ids : t -> (Id.t * Id.t) list option
2929+val method_calls : t -> Proto_invocation.t list
3030+val created_ids : t -> (Proto_id.t * Proto_id.t) list option
29313032val jsont : t Jsont.t
3133(** JSON codec for JMAP requests. *)
···34363537val single :
3638 using:string list ->
3737- Invocation.t ->
3939+ Proto_invocation.t ->
3840 t
3941(** [single ~using invocation] creates a request with a single method call. *)
40424143val batch :
4244 using:string list ->
4343- Invocation.t list ->
4545+ Proto_invocation.t list ->
4446 t
4547(** [batch ~using invocations] creates a request with multiple method calls. *)
···33 SPDX-License-Identifier: ISC
44 ---------------------------------------------------------------------------*)
5566-(** JMAP session object as defined in RFC 8620 Section 2 *)
66+(** JMAP session object as defined in RFC 8620 Section 2
77+88+ @canonical Jmap.Proto.Session *)
79810(** {1 Account} *)
911···3436type t = {
3537 capabilities : (string * Jsont.json) list;
3638 (** Server capabilities. Keys are capability URIs. *)
3737- accounts : (Id.t * Account.t) list;
3939+ accounts : (Proto_id.t * Account.t) list;
3840 (** Available accounts keyed by account id. *)
3939- primary_accounts : (string * Id.t) list;
4141+ primary_accounts : (string * Proto_id.t) list;
4042 (** Map of capability URI to the primary account id for that capability. *)
4143 username : string;
4244 (** The username associated with the credentials. *)
···5355}
54565557val capabilities : t -> (string * Jsont.json) list
5656-val accounts : t -> (Id.t * Account.t) list
5757-val primary_accounts : t -> (string * Id.t) list
5858+val accounts : t -> (Proto_id.t * Account.t) list
5959+val primary_accounts : t -> (string * Proto_id.t) list
5860val username : t -> string
5961val api_url : t -> string
6062val download_url : t -> string
···67696870(** {1 Session Helpers} *)
69717070-val get_account : Id.t -> t -> Account.t option
7272+val get_account : Proto_id.t -> t -> Account.t option
7173(** [get_account id session] returns the account with the given id. *)
72747373-val primary_account_for : string -> t -> Id.t option
7575+val primary_account_for : string -> t -> Proto_id.t option
7476(** [primary_account_for capability session] returns the primary account
7577 for the given capability URI. *)
76787779val has_capability : string -> t -> bool
7880(** [has_capability uri session] returns [true] if the server supports the capability. *)
79818080-val get_core_capability : t -> Capability.Core.t option
8282+val get_core_capability : t -> Proto_capability.Core.t option
8183(** [get_core_capability session] returns the parsed core capability. *)
82848383-val get_mail_capability : t -> Capability.Mail.t option
8585+val get_mail_capability : t -> Proto_capability.Mail.t option
8486(** [get_mail_capability session] returns the parsed mail capability. *)
proto/unknown.ml
lib/proto/proto_unknown.ml
+3-1
proto/unknown.mli
lib/proto/proto_unknown.mli
···66(** Unknown field preservation for forward compatibility.
7788 All JMAP objects preserve unknown fields to support future spec versions
99- and custom extensions. *)
99+ and custom extensions.
1010+1111+ @canonical Jmap.Proto.Unknown *)
10121113type t = Jsont.json
1214(** Unknown or unrecognized JSON object members as a generic JSON value.