this repo has no description

Add core JMAP type definitions based on RFC8620

Implements comprehensive OCaml type definitions for the JMAP protocol:
- Basic data types (id, int_t, unsigned_int, date, utc_date)
- Core objects (error, set_error, invocation, result_reference)
- Filter and sorting mechanisms
- Account and session management
- Push notification structures
- Request/response structures
- Standard method argument and response types

All types are documented with corresponding RFC section references.

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>

Changed files
+618 -1
lib
+4 -1
AGENT.md
···
Read your instructions from this file, and mark successfully completed instructions
with DONE so that you will know what to do next when reinvoked in the future.
-
1. Define core OCaml type definitions corresponding to the JMAP protocol
specification, in a new Jmap.Types module.
···
Read your instructions from this file, and mark successfully completed instructions
with DONE so that you will know what to do next when reinvoked in the future.
+
1. DONE Define core OCaml type definitions corresponding to the JMAP protocol
specification, in a new Jmap.Types module.
+
2. Add a `Jmap_api` module to make JMAP API requests over HTTP and parse the
+
responses into the `Jmap_types`. Use `Cohttp_lwt_unix` for the HTTP library.
+
3. Add an implementation of the Jmap_session handling.
+307
lib/jmap.ml
···
···
+
(**
+
* JMAP protocol implementation based on RFC8620
+
* https://datatracker.ietf.org/doc/html/rfc8620
+
*)
+
+
module Types = struct
+
(** Id string as per Section 1.2 *)
+
type id = string
+
+
(** Int bounded within the range -2^53+1 to 2^53-1 as per Section 1.3 *)
+
type int_t = int
+
+
(** UnsignedInt bounded within the range 0 to 2^53-1 as per Section 1.3 *)
+
type unsigned_int = int
+
+
(** Date string in RFC3339 format as per Section 1.4 *)
+
type date = string
+
+
(** UTCDate is a Date with 'Z' time zone as per Section 1.4 *)
+
type utc_date = string
+
+
(** Error object as per Section 3.6.2 *)
+
type error = {
+
type_: string;
+
description: string option;
+
}
+
+
(** Set error object as per Section 5.3 *)
+
type set_error = {
+
type_: string;
+
description: string option;
+
properties: string list option;
+
(* Additional properties for specific error types *)
+
existing_id: id option; (* For alreadyExists error *)
+
}
+
+
(** Invocation object as per Section 3.2 *)
+
type 'a invocation = {
+
name: string;
+
arguments: 'a;
+
method_call_id: string;
+
}
+
+
(** ResultReference object as per Section 3.7 *)
+
type result_reference = {
+
result_of: string;
+
name: string;
+
path: string;
+
}
+
+
(** FilterOperator, FilterCondition and Filter as per Section 5.5 *)
+
type filter_operator = {
+
operator: string; (* "AND", "OR", "NOT" *)
+
conditions: filter list;
+
}
+
and filter_condition = (string * Ezjsonm.value) list
+
and filter =
+
| Operator of filter_operator
+
| Condition of filter_condition
+
+
(** Comparator object for sorting as per Section 5.5 *)
+
type comparator = {
+
property: string;
+
is_ascending: bool option; (* Optional, defaults to true *)
+
collation: string option; (* Optional, server-dependent default *)
+
}
+
+
(** PatchObject as per Section 5.3 *)
+
type patch_object = (string * Ezjsonm.value) list
+
+
(** AddedItem structure as per Section 5.6 *)
+
type added_item = {
+
id: id;
+
index: unsigned_int;
+
}
+
+
(** Account object as per Section 1.6.2 *)
+
type account = {
+
name: string;
+
is_personal: bool;
+
is_read_only: bool;
+
account_capabilities: (string * Ezjsonm.value) list;
+
}
+
+
(** Core capability object as per Section 2 *)
+
type core_capability = {
+
max_size_upload: unsigned_int;
+
max_concurrent_upload: unsigned_int;
+
max_size_request: unsigned_int;
+
max_concurrent_requests: unsigned_int;
+
max_calls_in_request: unsigned_int;
+
max_objects_in_get: unsigned_int;
+
max_objects_in_set: unsigned_int;
+
collation_algorithms: string list;
+
}
+
+
(** PushSubscription keys object as per Section 7.2 *)
+
type push_keys = {
+
p256dh: string;
+
auth: string;
+
}
+
+
(** Session object as per Section 2 *)
+
type session = {
+
capabilities: (string * Ezjsonm.value) list;
+
accounts: (id * account) list;
+
primary_accounts: (string * id) list;
+
username: string;
+
api_url: string;
+
download_url: string;
+
upload_url: string;
+
event_source_url: string option;
+
state: string;
+
}
+
+
(** TypeState for state changes as per Section 7.1 *)
+
type type_state = (string * string) list
+
+
(** StateChange object as per Section 7.1 *)
+
type state_change = {
+
changed: (id * type_state) list;
+
}
+
+
(** PushVerification object as per Section 7.2.2 *)
+
type push_verification = {
+
push_subscription_id: id;
+
verification_code: string;
+
}
+
+
(** PushSubscription object as per Section 7.2 *)
+
type push_subscription = {
+
id: id;
+
device_client_id: string;
+
url: string;
+
keys: push_keys option;
+
verification_code: string option;
+
expires: utc_date option;
+
types: string list option;
+
}
+
+
(** Request object as per Section 3.3 *)
+
type request = {
+
using: string list;
+
method_calls: Ezjsonm.value invocation list;
+
created_ids: (id * id) list option;
+
}
+
+
(** Response object as per Section 3.4 *)
+
type response = {
+
method_responses: Ezjsonm.value invocation list;
+
created_ids: (id * id) list option;
+
session_state: string;
+
}
+
+
(** Standard method arguments and responses *)
+
+
(** Arguments for Foo/get method as per Section 5.1 *)
+
type 'a get_arguments = {
+
account_id: id;
+
ids: id list option;
+
properties: string list option;
+
}
+
+
(** Response for Foo/get method as per Section 5.1 *)
+
type 'a get_response = {
+
account_id: id;
+
state: string;
+
list: 'a list;
+
not_found: id list;
+
}
+
+
(** Arguments for Foo/changes method as per Section 5.2 *)
+
type changes_arguments = {
+
account_id: id;
+
since_state: string;
+
max_changes: unsigned_int option;
+
}
+
+
(** Response for Foo/changes method as per Section 5.2 *)
+
type changes_response = {
+
account_id: id;
+
old_state: string;
+
new_state: string;
+
has_more_changes: bool;
+
created: id list;
+
updated: id list;
+
destroyed: id list;
+
}
+
+
(** Arguments for Foo/set method as per Section 5.3 *)
+
type 'a set_arguments = {
+
account_id: id;
+
if_in_state: string option;
+
create: (id * 'a) list option;
+
update: (id * patch_object) list option;
+
destroy: id list option;
+
}
+
+
(** Response for Foo/set method as per Section 5.3 *)
+
type 'a set_response = {
+
account_id: id;
+
old_state: string option;
+
new_state: string;
+
created: (id * 'a) list option;
+
updated: (id * 'a option) list option;
+
destroyed: id list option;
+
not_created: (id * set_error) list option;
+
not_updated: (id * set_error) list option;
+
not_destroyed: (id * set_error) list option;
+
}
+
+
(** Arguments for Foo/copy method as per Section 5.4 *)
+
type 'a copy_arguments = {
+
from_account_id: id;
+
if_from_in_state: string option;
+
account_id: id;
+
if_in_state: string option;
+
create: (id * 'a) list;
+
on_success_destroy_original: bool option;
+
destroy_from_if_in_state: string option;
+
}
+
+
(** Response for Foo/copy method as per Section 5.4 *)
+
type 'a copy_response = {
+
from_account_id: id;
+
account_id: id;
+
old_state: string option;
+
new_state: string;
+
created: (id * 'a) list option;
+
not_created: (id * set_error) list option;
+
}
+
+
(** Arguments for Foo/query method as per Section 5.5 *)
+
type query_arguments = {
+
account_id: id;
+
filter: filter option;
+
sort: comparator list option;
+
position: int_t option;
+
anchor: id option;
+
anchor_offset: int_t option;
+
limit: unsigned_int option;
+
calculate_total: bool option;
+
}
+
+
(** Response for Foo/query method as per Section 5.5 *)
+
type query_response = {
+
account_id: id;
+
query_state: string;
+
can_calculate_changes: bool;
+
position: unsigned_int;
+
ids: id list;
+
total: unsigned_int option;
+
limit: unsigned_int option;
+
}
+
+
(** Arguments for Foo/queryChanges method as per Section 5.6 *)
+
type query_changes_arguments = {
+
account_id: id;
+
filter: filter option;
+
sort: comparator list option;
+
since_query_state: string;
+
max_changes: unsigned_int option;
+
up_to_id: id option;
+
calculate_total: bool option;
+
}
+
+
(** Response for Foo/queryChanges method as per Section 5.6 *)
+
type query_changes_response = {
+
account_id: id;
+
old_query_state: string;
+
new_query_state: string;
+
total: unsigned_int option;
+
removed: id list;
+
added: added_item list option;
+
}
+
+
(** Arguments for Blob/copy method as per Section 6.3 *)
+
type blob_copy_arguments = {
+
from_account_id: id;
+
account_id: id;
+
blob_ids: id list;
+
}
+
+
(** Response for Blob/copy method as per Section 6.3 *)
+
type blob_copy_response = {
+
from_account_id: id;
+
account_id: id;
+
copied: (id * id) list option;
+
not_copied: (id * set_error) list option;
+
}
+
+
(** Upload response as per Section 6.1 *)
+
type upload_response = {
+
account_id: id;
+
blob_id: id;
+
type_: string;
+
size: unsigned_int;
+
}
+
+
(** Problem details object as per RFC7807 and Section 3.6.1 *)
+
type problem_details = {
+
type_: string;
+
status: int option;
+
detail: string option;
+
limit: string option; (* For "limit" error *)
+
}
+
end
+307
lib/jmap.mli
···
···
+
(**
+
* JMAP protocol implementation based on RFC8620
+
* https://datatracker.ietf.org/doc/html/rfc8620
+
*)
+
+
module Types : sig
+
(** Id string as per Section 1.2 *)
+
type id = string
+
+
(** Int bounded within the range -2^53+1 to 2^53-1 as per Section 1.3 *)
+
type int_t = int
+
+
(** UnsignedInt bounded within the range 0 to 2^53-1 as per Section 1.3 *)
+
type unsigned_int = int
+
+
(** Date string in RFC3339 format as per Section 1.4 *)
+
type date = string
+
+
(** UTCDate is a Date with 'Z' time zone as per Section 1.4 *)
+
type utc_date = string
+
+
(** Error object as per Section 3.6.2 *)
+
type error = {
+
type_: string;
+
description: string option;
+
}
+
+
(** Set error object as per Section 5.3 *)
+
type set_error = {
+
type_: string;
+
description: string option;
+
properties: string list option;
+
(* Additional properties for specific error types *)
+
existing_id: id option; (* For alreadyExists error *)
+
}
+
+
(** Invocation object as per Section 3.2 *)
+
type 'a invocation = {
+
name: string;
+
arguments: 'a;
+
method_call_id: string;
+
}
+
+
(** ResultReference object as per Section 3.7 *)
+
type result_reference = {
+
result_of: string;
+
name: string;
+
path: string;
+
}
+
+
(** FilterOperator, FilterCondition and Filter as per Section 5.5 *)
+
type filter_operator = {
+
operator: string; (* "AND", "OR", "NOT" *)
+
conditions: filter list;
+
}
+
and filter_condition = (string * Ezjsonm.value) list
+
and filter =
+
| Operator of filter_operator
+
| Condition of filter_condition
+
+
(** Comparator object for sorting as per Section 5.5 *)
+
type comparator = {
+
property: string;
+
is_ascending: bool option; (* Optional, defaults to true *)
+
collation: string option; (* Optional, server-dependent default *)
+
}
+
+
(** PatchObject as per Section 5.3 *)
+
type patch_object = (string * Ezjsonm.value) list
+
+
(** AddedItem structure as per Section 5.6 *)
+
type added_item = {
+
id: id;
+
index: unsigned_int;
+
}
+
+
(** Account object as per Section 1.6.2 *)
+
type account = {
+
name: string;
+
is_personal: bool;
+
is_read_only: bool;
+
account_capabilities: (string * Ezjsonm.value) list;
+
}
+
+
(** Core capability object as per Section 2 *)
+
type core_capability = {
+
max_size_upload: unsigned_int;
+
max_concurrent_upload: unsigned_int;
+
max_size_request: unsigned_int;
+
max_concurrent_requests: unsigned_int;
+
max_calls_in_request: unsigned_int;
+
max_objects_in_get: unsigned_int;
+
max_objects_in_set: unsigned_int;
+
collation_algorithms: string list;
+
}
+
+
(** PushSubscription keys object as per Section 7.2 *)
+
type push_keys = {
+
p256dh: string;
+
auth: string;
+
}
+
+
(** Session object as per Section 2 *)
+
type session = {
+
capabilities: (string * Ezjsonm.value) list;
+
accounts: (id * account) list;
+
primary_accounts: (string * id) list;
+
username: string;
+
api_url: string;
+
download_url: string;
+
upload_url: string;
+
event_source_url: string option;
+
state: string;
+
}
+
+
(** TypeState for state changes as per Section 7.1 *)
+
type type_state = (string * string) list
+
+
(** StateChange object as per Section 7.1 *)
+
type state_change = {
+
changed: (id * type_state) list;
+
}
+
+
(** PushVerification object as per Section 7.2.2 *)
+
type push_verification = {
+
push_subscription_id: id;
+
verification_code: string;
+
}
+
+
(** PushSubscription object as per Section 7.2 *)
+
type push_subscription = {
+
id: id;
+
device_client_id: string;
+
url: string;
+
keys: push_keys option;
+
verification_code: string option;
+
expires: utc_date option;
+
types: string list option;
+
}
+
+
(** Request object as per Section 3.3 *)
+
type request = {
+
using: string list;
+
method_calls: Ezjsonm.value invocation list;
+
created_ids: (id * id) list option;
+
}
+
+
(** Response object as per Section 3.4 *)
+
type response = {
+
method_responses: Ezjsonm.value invocation list;
+
created_ids: (id * id) list option;
+
session_state: string;
+
}
+
+
(** Standard method arguments and responses *)
+
+
(** Arguments for Foo/get method as per Section 5.1 *)
+
type 'a get_arguments = {
+
account_id: id;
+
ids: id list option;
+
properties: string list option;
+
}
+
+
(** Response for Foo/get method as per Section 5.1 *)
+
type 'a get_response = {
+
account_id: id;
+
state: string;
+
list: 'a list;
+
not_found: id list;
+
}
+
+
(** Arguments for Foo/changes method as per Section 5.2 *)
+
type changes_arguments = {
+
account_id: id;
+
since_state: string;
+
max_changes: unsigned_int option;
+
}
+
+
(** Response for Foo/changes method as per Section 5.2 *)
+
type changes_response = {
+
account_id: id;
+
old_state: string;
+
new_state: string;
+
has_more_changes: bool;
+
created: id list;
+
updated: id list;
+
destroyed: id list;
+
}
+
+
(** Arguments for Foo/set method as per Section 5.3 *)
+
type 'a set_arguments = {
+
account_id: id;
+
if_in_state: string option;
+
create: (id * 'a) list option;
+
update: (id * patch_object) list option;
+
destroy: id list option;
+
}
+
+
(** Response for Foo/set method as per Section 5.3 *)
+
type 'a set_response = {
+
account_id: id;
+
old_state: string option;
+
new_state: string;
+
created: (id * 'a) list option;
+
updated: (id * 'a option) list option;
+
destroyed: id list option;
+
not_created: (id * set_error) list option;
+
not_updated: (id * set_error) list option;
+
not_destroyed: (id * set_error) list option;
+
}
+
+
(** Arguments for Foo/copy method as per Section 5.4 *)
+
type 'a copy_arguments = {
+
from_account_id: id;
+
if_from_in_state: string option;
+
account_id: id;
+
if_in_state: string option;
+
create: (id * 'a) list;
+
on_success_destroy_original: bool option;
+
destroy_from_if_in_state: string option;
+
}
+
+
(** Response for Foo/copy method as per Section 5.4 *)
+
type 'a copy_response = {
+
from_account_id: id;
+
account_id: id;
+
old_state: string option;
+
new_state: string;
+
created: (id * 'a) list option;
+
not_created: (id * set_error) list option;
+
}
+
+
(** Arguments for Foo/query method as per Section 5.5 *)
+
type query_arguments = {
+
account_id: id;
+
filter: filter option;
+
sort: comparator list option;
+
position: int_t option;
+
anchor: id option;
+
anchor_offset: int_t option;
+
limit: unsigned_int option;
+
calculate_total: bool option;
+
}
+
+
(** Response for Foo/query method as per Section 5.5 *)
+
type query_response = {
+
account_id: id;
+
query_state: string;
+
can_calculate_changes: bool;
+
position: unsigned_int;
+
ids: id list;
+
total: unsigned_int option;
+
limit: unsigned_int option;
+
}
+
+
(** Arguments for Foo/queryChanges method as per Section 5.6 *)
+
type query_changes_arguments = {
+
account_id: id;
+
filter: filter option;
+
sort: comparator list option;
+
since_query_state: string;
+
max_changes: unsigned_int option;
+
up_to_id: id option;
+
calculate_total: bool option;
+
}
+
+
(** Response for Foo/queryChanges method as per Section 5.6 *)
+
type query_changes_response = {
+
account_id: id;
+
old_query_state: string;
+
new_query_state: string;
+
total: unsigned_int option;
+
removed: id list;
+
added: added_item list option;
+
}
+
+
(** Arguments for Blob/copy method as per Section 6.3 *)
+
type blob_copy_arguments = {
+
from_account_id: id;
+
account_id: id;
+
blob_ids: id list;
+
}
+
+
(** Response for Blob/copy method as per Section 6.3 *)
+
type blob_copy_response = {
+
from_account_id: id;
+
account_id: id;
+
copied: (id * id) list option;
+
not_copied: (id * set_error) list option;
+
}
+
+
(** Upload response as per Section 6.1 *)
+
type upload_response = {
+
account_id: id;
+
blob_id: id;
+
type_: string;
+
size: unsigned_int;
+
}
+
+
(** Problem details object as per RFC7807 and Section 3.6.1 *)
+
type problem_details = {
+
type_: string;
+
status: int option;
+
detail: string option;
+
limit: string option; (* For "limit" error *)
+
}
+
end