this repo has no description
at main 851 lines 30 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6open Jmap_proto 7 8(* Phantom types for handle kinds *) 9type query 10type get 11type changes 12type set 13type query_changes 14type copy 15type import 16type parse 17 18(* Internal handle representation with GADT for response type *) 19type (_, _) handle = 20 | Query_handle : { 21 call_id : string; 22 method_name : string; 23 } -> (query, Method.query_response) handle 24 | Query_changes_handle : { 25 call_id : string; 26 method_name : string; 27 } -> (query_changes, Method.query_changes_response) handle 28 | Email_get_handle : { 29 call_id : string; 30 method_name : string; 31 } -> (get, Email.t Method.get_response) handle 32 | Thread_get_handle : { 33 call_id : string; 34 method_name : string; 35 } -> (get, Thread.t Method.get_response) handle 36 | Mailbox_get_handle : { 37 call_id : string; 38 method_name : string; 39 } -> (get, Mailbox.t Method.get_response) handle 40 | Identity_get_handle : { 41 call_id : string; 42 method_name : string; 43 } -> (get, Identity.t Method.get_response) handle 44 | Submission_get_handle : { 45 call_id : string; 46 method_name : string; 47 } -> (get, Submission.t Method.get_response) handle 48 | Search_snippet_get_handle : { 49 call_id : string; 50 method_name : string; 51 } -> (get, Search_snippet.t Method.get_response) handle 52 | Vacation_get_handle : { 53 call_id : string; 54 method_name : string; 55 } -> (get, Vacation.t Method.get_response) handle 56 | Changes_handle : { 57 call_id : string; 58 method_name : string; 59 } -> (changes, Method.changes_response) handle 60 | Email_set_handle : { 61 call_id : string; 62 method_name : string; 63 } -> (set, Email.t Method.set_response) handle 64 | Mailbox_set_handle : { 65 call_id : string; 66 method_name : string; 67 } -> (set, Mailbox.t Method.set_response) handle 68 | Identity_set_handle : { 69 call_id : string; 70 method_name : string; 71 } -> (set, Identity.t Method.set_response) handle 72 | Submission_set_handle : { 73 call_id : string; 74 method_name : string; 75 } -> (set, Submission.t Method.set_response) handle 76 | Vacation_set_handle : { 77 call_id : string; 78 method_name : string; 79 } -> (set, Vacation.t Method.set_response) handle 80 | Email_copy_handle : { 81 call_id : string; 82 method_name : string; 83 } -> (copy, Email.t Method.copy_response) handle 84 | Raw_handle : { 85 call_id : string; 86 method_name : string; 87 } -> (unit, Jsont.Json.t) handle 88 89let call_id : type k r. (k, r) handle -> string = function 90 | Query_handle h -> h.call_id 91 | Query_changes_handle h -> h.call_id 92 | Email_get_handle h -> h.call_id 93 | Thread_get_handle h -> h.call_id 94 | Mailbox_get_handle h -> h.call_id 95 | Identity_get_handle h -> h.call_id 96 | Submission_get_handle h -> h.call_id 97 | Search_snippet_get_handle h -> h.call_id 98 | Vacation_get_handle h -> h.call_id 99 | Changes_handle h -> h.call_id 100 | Email_set_handle h -> h.call_id 101 | Mailbox_set_handle h -> h.call_id 102 | Identity_set_handle h -> h.call_id 103 | Submission_set_handle h -> h.call_id 104 | Vacation_set_handle h -> h.call_id 105 | Email_copy_handle h -> h.call_id 106 | Raw_handle h -> h.call_id 107 108let method_name : type k r. (k, r) handle -> string = function 109 | Query_handle h -> h.method_name 110 | Query_changes_handle h -> h.method_name 111 | Email_get_handle h -> h.method_name 112 | Thread_get_handle h -> h.method_name 113 | Mailbox_get_handle h -> h.method_name 114 | Identity_get_handle h -> h.method_name 115 | Submission_get_handle h -> h.method_name 116 | Search_snippet_get_handle h -> h.method_name 117 | Vacation_get_handle h -> h.method_name 118 | Changes_handle h -> h.method_name 119 | Email_set_handle h -> h.method_name 120 | Mailbox_set_handle h -> h.method_name 121 | Identity_set_handle h -> h.method_name 122 | Submission_set_handle h -> h.method_name 123 | Vacation_set_handle h -> h.method_name 124 | Email_copy_handle h -> h.method_name 125 | Raw_handle h -> h.method_name 126 127(* Creation IDs *) 128type 'a create_id = string 129 130let created_id cid = Id.of_string_exn ("#" ^ cid) 131let created_id_of_string s = Id.of_string_exn ("#" ^ s) 132 133(* ID sources *) 134type id_source = 135 | Ids of Id.t list 136 | Ref of Invocation.result_reference 137 138let ids lst = Ids lst 139let id x = Ids [x] 140 141let make_ref ~call_id ~method_name ~path = 142 Ref (Invocation.result_reference_of_strings 143 ~result_of:call_id 144 ~name:method_name 145 ~path) 146 147let from_query : type r. (query, r) handle -> id_source = fun h -> 148 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/ids" 149 150let from_get_ids : type r. (get, r) handle -> id_source = fun h -> 151 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/list/*/id" 152 153let from_get_field : type r. (get, r) handle -> string -> id_source = fun h field -> 154 make_ref ~call_id:(call_id h) ~method_name:(method_name h) 155 ~path:(Printf.sprintf "/list/*/%s" field) 156 157let from_changes_created : type r. (changes, r) handle -> id_source = fun h -> 158 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/created" 159 160let from_changes_updated : type r. (changes, r) handle -> id_source = fun h -> 161 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/updated" 162 163let from_changes_destroyed : type r. (changes, r) handle -> id_source = fun h -> 164 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/destroyed" 165 166let from_set_created : type r. (set, r) handle -> id_source = fun h -> 167 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/created/*/id" 168 169let from_set_updated : type r. (set, r) handle -> id_source = fun h -> 170 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/updated" 171 172let from_query_changes_removed : type r. (query_changes, r) handle -> id_source = fun h -> 173 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/removed" 174 175let from_query_changes_added : type r. (query_changes, r) handle -> id_source = fun h -> 176 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/added/*/id" 177 178let from_copy_created : type r. (copy, r) handle -> id_source = fun h -> 179 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/created/*/id" 180 181let from_import_created : type r. (import, r) handle -> id_source = fun h -> 182 make_ref ~call_id:(call_id h) ~method_name:(method_name h) ~path:"/created/*/id" 183 184(* Chain state *) 185type state = { 186 mutable next_id : int; 187 mutable next_create_id : int; 188 mutable invocations : Invocation.t list; 189} 190 191(* Chain monad *) 192type 'a t = state -> 'a 193 194let return x _state = x 195 196let bind m f state = 197 let a = m state in 198 f a state 199 200let map f m state = 201 f (m state) 202 203let both a b state = 204 let x = a state in 205 let y = b state in 206 (x, y) 207 208let ( let* ) = bind 209let ( let+ ) m f = map f m 210let ( and* ) = both 211let ( and+ ) = both 212 213(* Building *) 214let fresh_call_id state = 215 let id = Printf.sprintf "c%d" state.next_id in 216 state.next_id <- state.next_id + 1; 217 id 218 219let fresh_create_id () state = 220 let id = Printf.sprintf "k%d" state.next_create_id in 221 state.next_create_id <- state.next_create_id + 1; 222 id 223 224let record_invocation inv state = 225 state.invocations <- inv :: state.invocations 226 227let build ~capabilities chain = 228 let state = { next_id = 0; next_create_id = 0; invocations = [] } in 229 let result = chain state in 230 let request = Request.create 231 ~using:capabilities 232 ~method_calls:(List.rev state.invocations) 233 () 234 in 235 (request, result) 236 237let build_request ~capabilities chain = 238 fst (build ~capabilities chain) 239 240(* JSON helpers - exported *) 241let json_null = Jsont.Null ((), Jsont.Meta.none) 242 243let json_bool b = Jsont.Bool (b, Jsont.Meta.none) 244 245let json_string s = Jsont.String (s, Jsont.Meta.none) 246 247let json_int n = Jsont.Number (Int64.to_float n, Jsont.Meta.none) 248 249let json_name s = (s, Jsont.Meta.none) 250 251let json_obj fields = 252 let fields' = List.map (fun (k, v) -> (json_name k, v)) fields in 253 Jsont.Object (fields', Jsont.Meta.none) 254 255let json_array items = Jsont.Array (items, Jsont.Meta.none) 256 257(* JSON helpers - internal *) 258let json_of_id id = 259 Jsont.String (Id.to_string id, Jsont.Meta.none) 260 261let json_of_id_list ids = 262 let items = List.map json_of_id ids in 263 Jsont.Array (items, Jsont.Meta.none) 264 265let json_of_string_list strs = 266 let items = List.map json_string strs in 267 Jsont.Array (items, Jsont.Meta.none) 268 269let json_map pairs = 270 let fields' = List.map (fun (k, v) -> (json_name k, v)) pairs in 271 Jsont.Object (fields', Jsont.Meta.none) 272 273let encode_to_json jsont value = 274 match Jsont.Json.encode' jsont value with 275 | Ok j -> j 276 | Error _ -> json_obj [] 277 278let encode_list_to_json jsont values = 279 match Jsont.Json.encode' (Jsont.list jsont) values with 280 | Ok j -> j 281 | Error _ -> Jsont.Array ([], Jsont.Meta.none) 282 283(* Add id_source to args *) 284let add_ids_arg args = function 285 | None -> args 286 | Some (Ids ids) -> 287 ("ids", json_of_id_list ids) :: args 288 | Some (Ref ref_) -> 289 let ref_json = encode_to_json Invocation.result_reference_jsont ref_ in 290 ("#ids", ref_json) :: args 291 292let add_destroy_arg args = function 293 | None -> args 294 | Some (Ids ids) -> 295 ("destroy", json_of_id_list ids) :: args 296 | Some (Ref ref_) -> 297 let ref_json = encode_to_json Invocation.result_reference_jsont ref_ in 298 ("#destroy", ref_json) :: args 299 300(* Query builder helper *) 301let build_query_args ~account_id ?filter ?filter_jsont ?sort ?position ?anchor 302 ?anchor_offset ?limit ?calculate_total () = 303 let args = [ ("accountId", json_of_id account_id) ] in 304 let args = match filter, filter_jsont with 305 | Some f, Some jsont -> ("filter", encode_to_json jsont f) :: args 306 | _ -> args 307 in 308 let args = match sort with 309 | None -> args 310 | Some comparators -> ("sort", encode_list_to_json Filter.comparator_jsont comparators) :: args 311 in 312 let args = match position with 313 | None -> args 314 | Some n -> ("position", json_int n) :: args 315 in 316 let args = match anchor with 317 | None -> args 318 | Some id -> ("anchor", json_of_id id) :: args 319 in 320 let args = match anchor_offset with 321 | None -> args 322 | Some n -> ("anchorOffset", json_int n) :: args 323 in 324 let args = match limit with 325 | None -> args 326 | Some n -> ("limit", json_int n) :: args 327 in 328 let args = match calculate_total with 329 | None -> args 330 | Some b -> ("calculateTotal", json_bool b) :: args 331 in 332 args 333 334(* Changes builder helper *) 335let build_changes_args ~account_id ~since_state ?max_changes () = 336 let args = [ 337 ("accountId", json_of_id account_id); 338 ("sinceState", json_string since_state); 339 ] in 340 let args = match max_changes with 341 | None -> args 342 | Some n -> ("maxChanges", json_int n) :: args 343 in 344 args 345 346(* QueryChanges builder helper *) 347let build_query_changes_args ~account_id ~since_query_state ?filter ?filter_jsont 348 ?sort ?max_changes ?up_to_id ?calculate_total () = 349 let args = [ 350 ("accountId", json_of_id account_id); 351 ("sinceQueryState", json_string since_query_state); 352 ] in 353 let args = match filter, filter_jsont with 354 | Some f, Some jsont -> ("filter", encode_to_json jsont f) :: args 355 | _ -> args 356 in 357 let args = match sort with 358 | None -> args 359 | Some comparators -> ("sort", encode_list_to_json Filter.comparator_jsont comparators) :: args 360 in 361 let args = match max_changes with 362 | None -> args 363 | Some n -> ("maxChanges", json_int n) :: args 364 in 365 let args = match up_to_id with 366 | None -> args 367 | Some id -> ("upToId", json_of_id id) :: args 368 in 369 let args = match calculate_total with 370 | None -> args 371 | Some b -> ("calculateTotal", json_bool b) :: args 372 in 373 args 374 375(* Set builder helper *) 376let build_set_args ~account_id ?if_in_state ?create ?update ?destroy () = 377 let args = [ ("accountId", json_of_id account_id) ] in 378 let args = match if_in_state with 379 | None -> args 380 | Some s -> ("ifInState", json_string s) :: args 381 in 382 let args = match create with 383 | None | Some [] -> args 384 | Some items -> 385 let create_map = json_map (List.map (fun (cid, obj) -> (cid, obj)) items) in 386 ("create", create_map) :: args 387 in 388 let args = match update with 389 | None | Some [] -> args 390 | Some items -> 391 let update_map = json_map (List.map (fun (id, patch) -> (Id.to_string id, patch)) items) in 392 ("update", update_map) :: args 393 in 394 let args = add_destroy_arg args destroy in 395 args 396 397(* Method builders *) 398 399let email_query ~account_id ?filter ?sort ?position ?anchor ?anchor_offset 400 ?limit ?calculate_total ?collapse_threads () state = 401 let call_id = fresh_call_id state in 402 let args = build_query_args ~account_id ?filter 403 ~filter_jsont:Mail_filter.email_filter_jsont 404 ?sort ?position ?anchor ?anchor_offset ?limit ?calculate_total () in 405 let args = match collapse_threads with 406 | None -> args 407 | Some b -> ("collapseThreads", json_bool b) :: args 408 in 409 let inv = Invocation.create 410 ~name:"Email/query" 411 ~arguments:(json_obj args) 412 ~method_call_id:call_id 413 in 414 record_invocation inv state; 415 Query_handle { call_id; method_name = "Email/query" } 416 417let email_get ~account_id ?ids ?properties ?body_properties 418 ?fetch_text_body_values ?fetch_html_body_values ?fetch_all_body_values 419 ?max_body_value_bytes () state = 420 let call_id = fresh_call_id state in 421 let args = [ ("accountId", json_of_id account_id) ] in 422 let args = add_ids_arg args ids in 423 let args = match properties with 424 | None -> args 425 | Some props -> ("properties", json_of_string_list props) :: args 426 in 427 let args = match body_properties with 428 | None -> args 429 | Some props -> ("bodyProperties", json_of_string_list props) :: args 430 in 431 let args = match fetch_text_body_values with 432 | None -> args 433 | Some b -> ("fetchTextBodyValues", json_bool b) :: args 434 in 435 let args = match fetch_html_body_values with 436 | None -> args 437 | Some b -> ("fetchHTMLBodyValues", json_bool b) :: args 438 in 439 let args = match fetch_all_body_values with 440 | None -> args 441 | Some b -> ("fetchAllBodyValues", json_bool b) :: args 442 in 443 let args = match max_body_value_bytes with 444 | None -> args 445 | Some n -> ("maxBodyValueBytes", json_int n) :: args 446 in 447 let inv = Invocation.create 448 ~name:"Email/get" 449 ~arguments:(json_obj args) 450 ~method_call_id:call_id 451 in 452 record_invocation inv state; 453 Email_get_handle { call_id; method_name = "Email/get" } 454 455let email_changes ~account_id ~since_state ?max_changes () state = 456 let call_id = fresh_call_id state in 457 let args = build_changes_args ~account_id ~since_state ?max_changes () in 458 let inv = Invocation.create 459 ~name:"Email/changes" 460 ~arguments:(json_obj args) 461 ~method_call_id:call_id 462 in 463 record_invocation inv state; 464 Changes_handle { call_id; method_name = "Email/changes" } 465 466let email_query_changes ~account_id ~since_query_state ?filter ?sort 467 ?max_changes ?up_to_id ?calculate_total () state = 468 let call_id = fresh_call_id state in 469 let args = build_query_changes_args ~account_id ~since_query_state 470 ?filter ~filter_jsont:Mail_filter.email_filter_jsont 471 ?sort ?max_changes ?up_to_id ?calculate_total () in 472 let inv = Invocation.create 473 ~name:"Email/queryChanges" 474 ~arguments:(json_obj args) 475 ~method_call_id:call_id 476 in 477 record_invocation inv state; 478 Query_changes_handle { call_id; method_name = "Email/queryChanges" } 479 480let email_set ~account_id ?if_in_state ?create ?update ?destroy () state = 481 let call_id = fresh_call_id state in 482 let args = build_set_args ~account_id ?if_in_state ?create ?update ?destroy () in 483 let inv = Invocation.create 484 ~name:"Email/set" 485 ~arguments:(json_obj args) 486 ~method_call_id:call_id 487 in 488 record_invocation inv state; 489 Email_set_handle { call_id; method_name = "Email/set" } 490 491let email_copy ~from_account_id ~account_id ?if_from_in_state ?if_in_state 492 ?create ?on_success_destroy_original ?destroy_from_if_in_state () state = 493 let call_id = fresh_call_id state in 494 let args = [ 495 ("fromAccountId", json_of_id from_account_id); 496 ("accountId", json_of_id account_id); 497 ] in 498 let args = match if_from_in_state with 499 | None -> args 500 | Some s -> ("ifFromInState", json_string s) :: args 501 in 502 let args = match if_in_state with 503 | None -> args 504 | Some s -> ("ifInState", json_string s) :: args 505 in 506 let args = match create with 507 | None | Some [] -> args 508 | Some items -> 509 let create_map = json_map (List.map (fun (id, obj) -> (Id.to_string id, obj)) items) in 510 ("create", create_map) :: args 511 in 512 let args = match on_success_destroy_original with 513 | None -> args 514 | Some b -> ("onSuccessDestroyOriginal", json_bool b) :: args 515 in 516 let args = match destroy_from_if_in_state with 517 | None -> args 518 | Some s -> ("destroyFromIfInState", json_string s) :: args 519 in 520 let inv = Invocation.create 521 ~name:"Email/copy" 522 ~arguments:(json_obj args) 523 ~method_call_id:call_id 524 in 525 record_invocation inv state; 526 Email_copy_handle { call_id; method_name = "Email/copy" } 527 528let thread_get ~account_id ?ids () state = 529 let call_id = fresh_call_id state in 530 let args = [ ("accountId", json_of_id account_id) ] in 531 let args = add_ids_arg args ids in 532 let inv = Invocation.create 533 ~name:"Thread/get" 534 ~arguments:(json_obj args) 535 ~method_call_id:call_id 536 in 537 record_invocation inv state; 538 Thread_get_handle { call_id; method_name = "Thread/get" } 539 540let thread_changes ~account_id ~since_state ?max_changes () state = 541 let call_id = fresh_call_id state in 542 let args = build_changes_args ~account_id ~since_state ?max_changes () in 543 let inv = Invocation.create 544 ~name:"Thread/changes" 545 ~arguments:(json_obj args) 546 ~method_call_id:call_id 547 in 548 record_invocation inv state; 549 Changes_handle { call_id; method_name = "Thread/changes" } 550 551let mailbox_query ~account_id ?filter ?sort ?position ?anchor ?anchor_offset 552 ?limit ?calculate_total () state = 553 let call_id = fresh_call_id state in 554 let args = build_query_args ~account_id ?filter 555 ~filter_jsont:Mail_filter.mailbox_filter_jsont 556 ?sort ?position ?anchor ?anchor_offset ?limit ?calculate_total () in 557 let inv = Invocation.create 558 ~name:"Mailbox/query" 559 ~arguments:(json_obj args) 560 ~method_call_id:call_id 561 in 562 record_invocation inv state; 563 Query_handle { call_id; method_name = "Mailbox/query" } 564 565let mailbox_get ~account_id ?ids ?properties () state = 566 let call_id = fresh_call_id state in 567 let args = [ ("accountId", json_of_id account_id) ] in 568 let args = add_ids_arg args ids in 569 let args = match properties with 570 | None -> args 571 | Some props -> ("properties", json_of_string_list props) :: args 572 in 573 let inv = Invocation.create 574 ~name:"Mailbox/get" 575 ~arguments:(json_obj args) 576 ~method_call_id:call_id 577 in 578 record_invocation inv state; 579 Mailbox_get_handle { call_id; method_name = "Mailbox/get" } 580 581let mailbox_changes ~account_id ~since_state ?max_changes () state = 582 let call_id = fresh_call_id state in 583 let args = build_changes_args ~account_id ~since_state ?max_changes () in 584 let inv = Invocation.create 585 ~name:"Mailbox/changes" 586 ~arguments:(json_obj args) 587 ~method_call_id:call_id 588 in 589 record_invocation inv state; 590 Changes_handle { call_id; method_name = "Mailbox/changes" } 591 592let mailbox_query_changes ~account_id ~since_query_state ?filter ?sort 593 ?max_changes ?up_to_id ?calculate_total () state = 594 let call_id = fresh_call_id state in 595 let args = build_query_changes_args ~account_id ~since_query_state 596 ?filter ~filter_jsont:Mail_filter.mailbox_filter_jsont 597 ?sort ?max_changes ?up_to_id ?calculate_total () in 598 let inv = Invocation.create 599 ~name:"Mailbox/queryChanges" 600 ~arguments:(json_obj args) 601 ~method_call_id:call_id 602 in 603 record_invocation inv state; 604 Query_changes_handle { call_id; method_name = "Mailbox/queryChanges" } 605 606let mailbox_set ~account_id ?if_in_state ?create ?update ?destroy 607 ?on_destroy_remove_emails () state = 608 let call_id = fresh_call_id state in 609 let args = build_set_args ~account_id ?if_in_state ?create ?update ?destroy () in 610 let args = match on_destroy_remove_emails with 611 | None -> args 612 | Some b -> ("onDestroyRemoveEmails", json_bool b) :: args 613 in 614 let inv = Invocation.create 615 ~name:"Mailbox/set" 616 ~arguments:(json_obj args) 617 ~method_call_id:call_id 618 in 619 record_invocation inv state; 620 Mailbox_set_handle { call_id; method_name = "Mailbox/set" } 621 622let identity_get ~account_id ?ids ?properties () state = 623 let call_id = fresh_call_id state in 624 let args = [ ("accountId", json_of_id account_id) ] in 625 let args = add_ids_arg args ids in 626 let args = match properties with 627 | None -> args 628 | Some props -> ("properties", json_of_string_list props) :: args 629 in 630 let inv = Invocation.create 631 ~name:"Identity/get" 632 ~arguments:(json_obj args) 633 ~method_call_id:call_id 634 in 635 record_invocation inv state; 636 Identity_get_handle { call_id; method_name = "Identity/get" } 637 638let identity_changes ~account_id ~since_state ?max_changes () state = 639 let call_id = fresh_call_id state in 640 let args = build_changes_args ~account_id ~since_state ?max_changes () in 641 let inv = Invocation.create 642 ~name:"Identity/changes" 643 ~arguments:(json_obj args) 644 ~method_call_id:call_id 645 in 646 record_invocation inv state; 647 Changes_handle { call_id; method_name = "Identity/changes" } 648 649let identity_set ~account_id ?if_in_state ?create ?update ?destroy () state = 650 let call_id = fresh_call_id state in 651 let args = build_set_args ~account_id ?if_in_state ?create ?update ?destroy () in 652 let inv = Invocation.create 653 ~name:"Identity/set" 654 ~arguments:(json_obj args) 655 ~method_call_id:call_id 656 in 657 record_invocation inv state; 658 Identity_set_handle { call_id; method_name = "Identity/set" } 659 660let email_submission_query ~account_id ?filter ?sort ?position ?anchor 661 ?anchor_offset ?limit ?calculate_total () state = 662 let call_id = fresh_call_id state in 663 let args = build_query_args ~account_id ?filter 664 ~filter_jsont:Mail_filter.submission_filter_jsont 665 ?sort ?position ?anchor ?anchor_offset ?limit ?calculate_total () in 666 let inv = Invocation.create 667 ~name:"EmailSubmission/query" 668 ~arguments:(json_obj args) 669 ~method_call_id:call_id 670 in 671 record_invocation inv state; 672 Query_handle { call_id; method_name = "EmailSubmission/query" } 673 674let email_submission_get ~account_id ?ids ?properties () state = 675 let call_id = fresh_call_id state in 676 let args = [ ("accountId", json_of_id account_id) ] in 677 let args = add_ids_arg args ids in 678 let args = match properties with 679 | None -> args 680 | Some props -> ("properties", json_of_string_list props) :: args 681 in 682 let inv = Invocation.create 683 ~name:"EmailSubmission/get" 684 ~arguments:(json_obj args) 685 ~method_call_id:call_id 686 in 687 record_invocation inv state; 688 Submission_get_handle { call_id; method_name = "EmailSubmission/get" } 689 690let email_submission_changes ~account_id ~since_state ?max_changes () state = 691 let call_id = fresh_call_id state in 692 let args = build_changes_args ~account_id ~since_state ?max_changes () in 693 let inv = Invocation.create 694 ~name:"EmailSubmission/changes" 695 ~arguments:(json_obj args) 696 ~method_call_id:call_id 697 in 698 record_invocation inv state; 699 Changes_handle { call_id; method_name = "EmailSubmission/changes" } 700 701let email_submission_query_changes ~account_id ~since_query_state ?filter ?sort 702 ?max_changes ?up_to_id ?calculate_total () state = 703 let call_id = fresh_call_id state in 704 let args = build_query_changes_args ~account_id ~since_query_state 705 ?filter ~filter_jsont:Mail_filter.submission_filter_jsont 706 ?sort ?max_changes ?up_to_id ?calculate_total () in 707 let inv = Invocation.create 708 ~name:"EmailSubmission/queryChanges" 709 ~arguments:(json_obj args) 710 ~method_call_id:call_id 711 in 712 record_invocation inv state; 713 Query_changes_handle { call_id; method_name = "EmailSubmission/queryChanges" } 714 715let email_submission_set ~account_id ?if_in_state ?create ?update ?destroy 716 ?on_success_update_email ?on_success_destroy_email () state = 717 let call_id = fresh_call_id state in 718 let args = build_set_args ~account_id ?if_in_state ?create ?update ?destroy () in 719 let args = match on_success_update_email with 720 | None | Some [] -> args 721 | Some items -> 722 let update_map = json_map items in 723 ("onSuccessUpdateEmail", update_map) :: args 724 in 725 let args = match on_success_destroy_email with 726 | None | Some [] -> args 727 | Some ids -> 728 ("onSuccessDestroyEmail", json_of_string_list ids) :: args 729 in 730 let inv = Invocation.create 731 ~name:"EmailSubmission/set" 732 ~arguments:(json_obj args) 733 ~method_call_id:call_id 734 in 735 record_invocation inv state; 736 Submission_set_handle { call_id; method_name = "EmailSubmission/set" } 737 738let search_snippet_get ~account_id ~filter ~email_ids () state = 739 let call_id = fresh_call_id state in 740 let args = [ ("accountId", json_of_id account_id) ] in 741 let args = ("filter", encode_to_json Mail_filter.email_filter_jsont filter) :: args in 742 let args = match email_ids with 743 | Ids ids -> ("emailIds", json_of_id_list ids) :: args 744 | Ref ref_ -> 745 let ref_json = encode_to_json Invocation.result_reference_jsont ref_ in 746 ("#emailIds", ref_json) :: args 747 in 748 let inv = Invocation.create 749 ~name:"SearchSnippet/get" 750 ~arguments:(json_obj args) 751 ~method_call_id:call_id 752 in 753 record_invocation inv state; 754 Search_snippet_get_handle { call_id; method_name = "SearchSnippet/get" } 755 756let vacation_response_get ~account_id ?properties () state = 757 let call_id = fresh_call_id state in 758 let args = [ ("accountId", json_of_id account_id) ] in 759 let args = match properties with 760 | None -> args 761 | Some props -> ("properties", json_of_string_list props) :: args 762 in 763 let inv = Invocation.create 764 ~name:"VacationResponse/get" 765 ~arguments:(json_obj args) 766 ~method_call_id:call_id 767 in 768 record_invocation inv state; 769 Vacation_get_handle { call_id; method_name = "VacationResponse/get" } 770 771let vacation_response_set ~account_id ?if_in_state ~update () state = 772 let call_id = fresh_call_id state in 773 let args = [ ("accountId", json_of_id account_id) ] in 774 let args = match if_in_state with 775 | None -> args 776 | Some s -> ("ifInState", json_string s) :: args 777 in 778 let args = ("update", json_map [("singleton", update)]) :: args in 779 let inv = Invocation.create 780 ~name:"VacationResponse/set" 781 ~arguments:(json_obj args) 782 ~method_call_id:call_id 783 in 784 record_invocation inv state; 785 Vacation_set_handle { call_id; method_name = "VacationResponse/set" } 786 787let raw_invocation ~name ~arguments state = 788 let call_id = fresh_call_id state in 789 let inv = Invocation.create 790 ~name 791 ~arguments 792 ~method_call_id:call_id 793 in 794 record_invocation inv state; 795 Raw_handle { call_id; method_name = name } 796 797(* Response parsing *) 798 799let find_invocation ~call_id response = 800 List.find_opt 801 (fun inv -> Invocation.method_call_id inv = call_id) 802 (Response.method_responses response) 803 804let parse : type k r. (k, r) handle -> Response.t -> (r, Jsont.Error.t) result = 805 fun handle response -> 806 let cid = call_id handle in 807 match find_invocation ~call_id:cid response with 808 | None -> 809 Error (Jsont.Error.msgf Jsont.Meta.none "No response found for call_id: %s" cid) 810 | Some inv -> 811 let args = Invocation.arguments inv in 812 match handle with 813 | Query_handle _ -> 814 Jsont.Json.decode' Method.query_response_jsont args 815 | Query_changes_handle _ -> 816 Jsont.Json.decode' Method.query_changes_response_jsont args 817 | Email_get_handle _ -> 818 Jsont.Json.decode' (Method.get_response_jsont Email.jsont) args 819 | Thread_get_handle _ -> 820 Jsont.Json.decode' (Method.get_response_jsont Thread.jsont) args 821 | Mailbox_get_handle _ -> 822 Jsont.Json.decode' (Method.get_response_jsont Mailbox.jsont) args 823 | Identity_get_handle _ -> 824 Jsont.Json.decode' (Method.get_response_jsont Identity.jsont) args 825 | Submission_get_handle _ -> 826 Jsont.Json.decode' (Method.get_response_jsont Submission.jsont) args 827 | Search_snippet_get_handle _ -> 828 Jsont.Json.decode' (Method.get_response_jsont Search_snippet.jsont) args 829 | Vacation_get_handle _ -> 830 Jsont.Json.decode' (Method.get_response_jsont Vacation.jsont) args 831 | Changes_handle _ -> 832 Jsont.Json.decode' Method.changes_response_jsont args 833 | Email_set_handle _ -> 834 Jsont.Json.decode' (Method.set_response_jsont Email.jsont) args 835 | Mailbox_set_handle _ -> 836 Jsont.Json.decode' (Method.set_response_jsont Mailbox.jsont) args 837 | Identity_set_handle _ -> 838 Jsont.Json.decode' (Method.set_response_jsont Identity.jsont) args 839 | Submission_set_handle _ -> 840 Jsont.Json.decode' (Method.set_response_jsont Submission.jsont) args 841 | Vacation_set_handle _ -> 842 Jsont.Json.decode' (Method.set_response_jsont Vacation.jsont) args 843 | Email_copy_handle _ -> 844 Jsont.Json.decode' (Method.copy_response_jsont Email.jsont) args 845 | Raw_handle _ -> 846 Ok args 847 848let parse_exn handle response = 849 match parse handle response with 850 | Ok r -> r 851 | Error e -> failwith (Jsont.Error.to_string e)