My agentic slop goes here. Not intended for anyone else!

more

Changed files
+163 -40
stack
+15
stack/jmap/jmap-core/jmap_standard_methods.ml
···
in
{ account_id; ids; properties }
+
(** Convert request to JSON *)
+
let request_to_json (req : 'a request) =
+
let fields = [
+
("accountId", Jmap_id.to_json req.account_id);
+
] in
+
let fields = match req.ids with
+
| Some ids -> ("ids", `A (List.map Jmap_id.to_json ids)) :: fields
+
| None -> fields
+
in
+
let fields = match req.properties with
+
| Some props -> ("properties", `A (List.map (fun s -> `String s) props)) :: fields
+
| None -> fields
+
in
+
`O fields
+
(** Parse response from JSON.
Test files: test/data/core/response_get.json *)
let response_of_json parse_obj json =
+3
stack/jmap/jmap-core/jmap_standard_methods.mli
···
(** Constructor for response *)
val response_v : account_id:Jmap_id.t -> state:string -> list:'a list -> not_found:Jmap_id.t list -> 'a response
+
(** Convert request to JSON *)
+
val request_to_json : 'a request -> Ezjsonm.value
+
(** Parse request from JSON *)
val request_of_json : (Ezjsonm.value -> 'a) -> Ezjsonm.value -> 'a request
+74
stack/jmap/jmap-mail/jmap_mailbox.ml
···
type request = t Jmap_core.Standard_methods.Get.request
type response = t Jmap_core.Standard_methods.Get.response
+
(** Constructor for request *)
+
let request_v = Jmap_core.Standard_methods.Get.v
+
+
(** Convert request to JSON *)
+
let request_to_json = Jmap_core.Standard_methods.Get.request_to_json
+
(** Parse get request from JSON *)
let request_of_json json =
Jmap_core.Standard_methods.Get.request_of_json Parser.of_json json
···
(* Constructor *)
let v ?parent_id ?name ?role ?has_any_role ?is_subscribed () =
{ parent_id; name; role; has_any_role; is_subscribed }
+
+
(* Convert to JSON *)
+
let to_json t =
+
let fields = [] in
+
let fields = match t.parent_id with
+
| Some id -> ("parentId", Jmap_core.Id.to_json id) :: fields
+
| None -> fields
+
in
+
let fields = match t.name with
+
| Some n -> ("name", `String n) :: fields
+
| None -> fields
+
in
+
let fields = match t.role with
+
| Some r -> ("role", `String r) :: fields
+
| None -> fields
+
in
+
let fields = match t.has_any_role with
+
| Some har -> ("hasAnyRole", `Bool har) :: fields
+
| None -> fields
+
in
+
let fields = match t.is_subscribed with
+
| Some is -> ("isSubscribed", `Bool is) :: fields
+
| None -> fields
+
in
+
`O fields
end
(** Standard /query method with Mailbox-specific extensions (RFC 8621 Section 2.5) *)
···
in
{ account_id; filter; sort; position; anchor; anchor_offset; limit;
calculate_total; sort_as_tree; filter_as_tree }
+
+
(** Convert query request to JSON *)
+
let request_to_json req =
+
let fields = [
+
("accountId", Jmap_core.Id.to_json req.account_id);
+
] in
+
let fields = match req.filter with
+
| Some f -> ("filter", Jmap_core.Filter.to_json Filter.to_json f) :: fields
+
| None -> fields
+
in
+
let fields = match req.sort with
+
| Some s -> ("sort", `A (List.map Jmap_core.Comparator.to_json s)) :: fields
+
| None -> fields
+
in
+
let fields = match req.position with
+
| Some p -> ("position", Jmap_core.Primitives.Int53.to_json p) :: fields
+
| None -> fields
+
in
+
let fields = match req.anchor with
+
| Some a -> ("anchor", Jmap_core.Id.to_json a) :: fields
+
| None -> fields
+
in
+
let fields = match req.anchor_offset with
+
| Some ao -> ("anchorOffset", Jmap_core.Primitives.Int53.to_json ao) :: fields
+
| None -> fields
+
in
+
let fields = match req.limit with
+
| Some l -> ("limit", Jmap_core.Primitives.UnsignedInt.to_json l) :: fields
+
| None -> fields
+
in
+
let fields = match req.calculate_total with
+
| Some ct -> ("calculateTotal", `Bool ct) :: fields
+
| None -> fields
+
in
+
let fields = match req.sort_as_tree with
+
| Some sat -> ("sortAsTree", `Bool sat) :: fields
+
| None -> fields
+
in
+
let fields = match req.filter_as_tree with
+
| Some fat -> ("filterAsTree", `Bool fat) :: fields
+
| None -> fields
+
in
+
`O fields
(** Parse query response from JSON.
Test files: test/data/mail/mailbox_query_response.json *)
+4
stack/jmap/jmap-mail/jmap_mailbox.mli
···
type request = t Standard_methods.Get.request
type response = t Standard_methods.Get.response
+
val request_v : account_id:Id.t -> ?ids:Id.t list -> ?properties:string list -> unit -> request
+
val request_to_json : request -> Ezjsonm.value
val request_of_json : Ezjsonm.value -> request
val response_of_json : Ezjsonm.value -> response
end
···
unit ->
t
+
val to_json : t -> Ezjsonm.value
val of_json : Ezjsonm.value -> t
end
···
unit ->
request
+
val request_to_json : request -> Ezjsonm.value
val request_of_json : Ezjsonm.value -> request
val response_of_json : Ezjsonm.value -> response
end
+2 -2
stack/jmap/lib/dune
···
(library
(name jmap)
(public_name jmap)
-
(libraries jmap-core jmap-mail jmap-client)
-
(modules jmap))
+
(libraries jmap-core jmap-mail jmap-client cmdliner)
+
(modules jmap jmap_cmd))
+5
stack/jmap/lib/jmap.ml
···
(** Complete jmap-mail library *)
module Mail = Jmap_mail
+
+
(** {1 CLI Utilities} *)
+
+
(** Common Cmdliner terms for CLI tools *)
+
module Cmd = Jmap_cmd
+5
stack/jmap/lib/jmap.mli
···
(** Complete jmap-mail library *)
module Mail = Jmap_mail
+
+
(** {1 CLI Utilities} *)
+
+
(** Common Cmdliner terms for CLI tools *)
+
module Cmd = Jmap_cmd
+1 -1
stack/jmap/test/dune
···
(executable
(name test_fastmail)
-
(libraries eio_main jmap-core jmap-mail jmap-client requests mirage-crypto-rng.unix)
+
(libraries eio_main jmap requests mirage-crypto-rng.unix)
(flags (:standard -w -21))
(modes exe))
+39 -36
stack/jmap/test/test_fastmail.ml
···
-
(** Simple JMAP client test against Fastmail API *)
+
(** Simple JMAP client test against Fastmail API
+
+
This test demonstrates the unified Jmap API for clean, ergonomic usage.
+
*)
let read_api_key () =
let locations = [
···
let api_key = read_api_key () in
Printf.printf "✓ API key loaded\n\n%!";
-
let conn = Jmap_connection.v
-
~auth:(Jmap_connection.Bearer api_key)
+
let conn = Jmap.Connection.v
+
~auth:(Jmap.Connection.Bearer api_key)
() in
let session_url = "https://api.fastmail.com/jmap/session" in
Printf.printf "Connecting to %s...\n%!" session_url;
-
let client = Jmap_client.create ~sw ~env ~conn ~session_url () in
+
let client = Jmap.Client.create ~sw ~env ~conn ~session_url () in
Printf.printf "Fetching JMAP session...\n%!";
-
let session = Jmap_client.fetch_session client in
+
let session = Jmap.Client.fetch_session client in
Printf.printf "✓ Session fetched\n";
-
Printf.printf " Username: %s\n" (Jmap_core.Session.username session);
-
Printf.printf " API URL: %s\n\n%!" (Jmap_core.Session.api_url session);
+
Printf.printf " Username: %s\n" (Jmap.Session.username session);
+
Printf.printf " API URL: %s\n\n%!" (Jmap.Session.api_url session);
(* Get primary mail account *)
-
let primary_accounts = Jmap_core.Session.primary_accounts session in
+
let primary_accounts = Jmap.Session.primary_accounts session in
let account_id = match List.assoc_opt "urn:ietf:params:jmap:mail" primary_accounts with
-
| Some id -> Jmap_core.Id.to_string id
+
| Some id -> Jmap.Id.to_string id
| None ->
Printf.eprintf "Error: No mail account found\n";
exit 1
in
Printf.printf " Account ID: %s\n\n%!" account_id;
-
(* Build a JMAP request using the typed library API *)
+
(* Build a JMAP request using the unified Jmap API *)
Printf.printf "Querying for 10 most recent emails...\n";
-
Printf.printf " API URL: %s\n%!" (Jmap_core.Session.api_url session);
+
Printf.printf " API URL: %s\n%!" (Jmap.Session.api_url session);
(* Build Email/query request using typed constructors *)
-
let query_request = Jmap_mail.Email.Query.request_v
-
~account_id:(Jmap_core.Id.of_string account_id)
-
~limit:(Jmap_core.Primitives.UnsignedInt.of_int 10)
-
~sort:[Jmap_core.Comparator.v ~property:"receivedAt" ~is_ascending:false ()]
+
let query_request = Jmap.Email.Query.request_v
+
~account_id:(Jmap.Id.of_string account_id)
+
~limit:(Jmap.Primitives.UnsignedInt.of_int 10)
+
~sort:[Jmap.Comparator.v ~property:"receivedAt" ~is_ascending:false ()]
~calculate_total:true
() in
(* Convert to JSON *)
-
let query_args = Jmap_mail.Email.Query.request_to_json query_request in
+
let query_args = Jmap.Email.Query.request_to_json query_request in
(* Create invocation using Echo witness *)
-
let query_invocation = Jmap_core.Invocation.Invocation {
+
let query_invocation = Jmap.Invocation.Invocation {
method_name = "Email/query";
arguments = query_args;
call_id = "q1";
-
witness = Jmap_core.Invocation.Echo;
+
witness = Jmap.Invocation.Echo;
} in
(* Build request using constructors *)
-
let req = Jmap_core.Request.make
-
~using:[Jmap_core.Capability.core; Jmap_core.Capability.mail]
-
[Jmap_core.Invocation.Packed query_invocation]
+
let req = Jmap.Request.make
+
~using:[Jmap.Capability.core; Jmap.Capability.mail]
+
[Jmap.Invocation.Packed query_invocation]
in
Printf.printf " Request built using typed Email.Query API\n%!";
Printf.printf " Making API call...\n%!";
(try
-
let query_resp = Jmap_client.call client req in
+
let query_resp = Jmap.Client.call client req in
Printf.printf "✓ Query successful!\n";
(* Extract email IDs from the query response *)
-
let method_responses = Jmap_core.Response.method_responses query_resp in
+
let method_responses = Jmap.Response.method_responses query_resp in
let email_ids = match method_responses with
| [packed_resp] ->
-
let response_json = Jmap_core.Invocation.response_to_json packed_resp in
+
let response_json = Jmap.Invocation.response_to_json packed_resp in
(match response_json with
| `O fields ->
(match List.assoc_opt "ids" fields with
| Some (`A ids) ->
List.map (fun id ->
match id with
-
| `String s -> Jmap_core.Id.of_string s
+
| `String s -> Jmap.Id.of_string s
| _ -> failwith "Expected string ID"
) ids
| _ -> failwith "No 'ids' field in query response")
···
if List.length email_ids > 0 then (
(* Fetch the actual emails with Email/get *)
-
let get_request = Jmap_mail.Email.Get.request_v
-
~account_id:(Jmap_core.Id.of_string account_id)
+
let get_request = Jmap.Email.Get.request_v
+
~account_id:(Jmap.Id.of_string account_id)
~ids:email_ids
~properties:["id"; "subject"; "from"; "receivedAt"]
() in
-
let get_args = Jmap_mail.Email.Get.request_to_json get_request in
+
let get_args = Jmap.Email.Get.request_to_json get_request in
-
let get_invocation = Jmap_core.Invocation.Invocation {
+
let get_invocation = Jmap.Invocation.Invocation {
method_name = "Email/get";
arguments = get_args;
call_id = "g1";
-
witness = Jmap_core.Invocation.Echo;
+
witness = Jmap.Invocation.Echo;
} in
-
let get_req = Jmap_core.Request.make
-
~using:[Jmap_core.Capability.core; Jmap_core.Capability.mail]
-
[Jmap_core.Invocation.Packed get_invocation]
+
let get_req = Jmap.Request.make
+
~using:[Jmap.Capability.core; Jmap.Capability.mail]
+
[Jmap.Invocation.Packed get_invocation]
in
-
let get_resp = Jmap_client.call client get_req in
+
let get_resp = Jmap.Client.call client get_req in
(* Parse and display emails *)
-
let get_method_responses = Jmap_core.Response.method_responses get_resp in
+
let get_method_responses = Jmap.Response.method_responses get_resp in
(match get_method_responses with
| [packed_resp] ->
-
let response_json = Jmap_core.Invocation.response_to_json packed_resp in
+
let response_json = Jmap.Invocation.response_to_json packed_resp in
(match response_json with
| `O fields ->
(match List.assoc_opt "list" fields with
+15 -1
stack/mltessera/test/dune
···
(executable
(public_name test_coordinates)
(name test_coordinates)
-
(libraries mltessera lonlat))
+
(libraries mltessera lonlat))
+
+
(executable
+
(public_name test_tile_download)
+
(name test_tile_download)
+
(libraries
+
mltessera
+
lonlat
+
toru
+
requests
+
eio
+
eio_main
+
logs
+
logs.fmt
+
digestif))