this repo has no description
1(**
2 * JMAP protocol implementation based on RFC8620
3 * https://datatracker.ietf.org/doc/html/rfc8620
4 *)
5
6(** {1 Types} *)
7
8module Types : sig
9 (** Id string as per Section 1.2 *)
10 type id = string
11
12 (** Int bounded within the range -2^53+1 to 2^53-1 as per Section 1.3 *)
13 type int_t = int
14
15 (** UnsignedInt bounded within the range 0 to 2^53-1 as per Section 1.3 *)
16 type unsigned_int = int
17
18 (** Date string in RFC3339 format as per Section 1.4 *)
19 type date = string
20
21 (** UTCDate is a Date with 'Z' time zone as per Section 1.4 *)
22 type utc_date = string
23
24 (** Error object as per Section 3.6.2 *)
25 type error = {
26 type_: string;
27 description: string option;
28 }
29
30 (** Set error object as per Section 5.3 *)
31 type set_error = {
32 type_: string;
33 description: string option;
34 properties: string list option;
35 (* Additional properties for specific error types *)
36 existing_id: id option; (* For alreadyExists error *)
37 }
38
39 (** Invocation object as per Section 3.2 *)
40 type 'a invocation = {
41 name: string;
42 arguments: 'a;
43 method_call_id: string;
44 }
45
46 (** ResultReference object as per Section 3.7 *)
47 type result_reference = {
48 result_of: string;
49 name: string;
50 path: string;
51 }
52
53 (** FilterOperator, FilterCondition and Filter as per Section 5.5 *)
54 type filter_operator = {
55 operator: string; (* "AND", "OR", "NOT" *)
56 conditions: filter list;
57 }
58 and filter_condition = (string * Ezjsonm.value) list
59 and filter =
60 | Operator of filter_operator
61 | Condition of filter_condition
62
63 (** Comparator object for sorting as per Section 5.5 *)
64 type comparator = {
65 property: string;
66 is_ascending: bool option; (* Optional, defaults to true *)
67 collation: string option; (* Optional, server-dependent default *)
68 }
69
70 (** PatchObject as per Section 5.3 *)
71 type patch_object = (string * Ezjsonm.value) list
72
73 (** AddedItem structure as per Section 5.6 *)
74 type added_item = {
75 id: id;
76 index: unsigned_int;
77 }
78
79 (** Account object as per Section 1.6.2 *)
80 type account = {
81 name: string;
82 is_personal: bool;
83 is_read_only: bool;
84 account_capabilities: (string * Ezjsonm.value) list;
85 }
86
87 (** Core capability object as per Section 2 *)
88 type core_capability = {
89 max_size_upload: unsigned_int;
90 max_concurrent_upload: unsigned_int;
91 max_size_request: unsigned_int;
92 max_concurrent_requests: unsigned_int;
93 max_calls_in_request: unsigned_int;
94 max_objects_in_get: unsigned_int;
95 max_objects_in_set: unsigned_int;
96 collation_algorithms: string list;
97 }
98
99 (** PushSubscription keys object as per Section 7.2 *)
100 type push_keys = {
101 p256dh: string;
102 auth: string;
103 }
104
105 (** Session object as per Section 2 *)
106 type session = {
107 capabilities: (string * Ezjsonm.value) list;
108 accounts: (id * account) list;
109 primary_accounts: (string * id) list;
110 username: string;
111 api_url: string;
112 download_url: string;
113 upload_url: string;
114 event_source_url: string option;
115 state: string;
116 }
117
118 (** TypeState for state changes as per Section 7.1 *)
119 type type_state = (string * string) list
120
121 (** StateChange object as per Section 7.1 *)
122 type state_change = {
123 changed: (id * type_state) list;
124 }
125
126 (** PushVerification object as per Section 7.2.2 *)
127 type push_verification = {
128 push_subscription_id: id;
129 verification_code: string;
130 }
131
132 (** PushSubscription object as per Section 7.2 *)
133 type push_subscription = {
134 id: id;
135 device_client_id: string;
136 url: string;
137 keys: push_keys option;
138 verification_code: string option;
139 expires: utc_date option;
140 types: string list option;
141 }
142
143 (** Request object as per Section 3.3 *)
144 type request = {
145 using: string list;
146 method_calls: Ezjsonm.value invocation list;
147 created_ids: (id * id) list option;
148 }
149
150 (** Response object as per Section 3.4 *)
151 type response = {
152 method_responses: Ezjsonm.value invocation list;
153 created_ids: (id * id) list option;
154 session_state: string;
155 }
156
157 (** Standard method arguments and responses *)
158
159 (** Arguments for Foo/get method as per Section 5.1 *)
160 type 'a get_arguments = {
161 account_id: id;
162 ids: id list option;
163 properties: string list option;
164 }
165
166 (** Response for Foo/get method as per Section 5.1 *)
167 type 'a get_response = {
168 account_id: id;
169 state: string;
170 list: 'a list;
171 not_found: id list;
172 }
173
174 (** Arguments for Foo/changes method as per Section 5.2 *)
175 type changes_arguments = {
176 account_id: id;
177 since_state: string;
178 max_changes: unsigned_int option;
179 }
180
181 (** Response for Foo/changes method as per Section 5.2 *)
182 type changes_response = {
183 account_id: id;
184 old_state: string;
185 new_state: string;
186 has_more_changes: bool;
187 created: id list;
188 updated: id list;
189 destroyed: id list;
190 }
191
192 (** Arguments for Foo/set method as per Section 5.3 *)
193 type 'a set_arguments = {
194 account_id: id;
195 if_in_state: string option;
196 create: (id * 'a) list option;
197 update: (id * patch_object) list option;
198 destroy: id list option;
199 }
200
201 (** Response for Foo/set method as per Section 5.3 *)
202 type 'a set_response = {
203 account_id: id;
204 old_state: string option;
205 new_state: string;
206 created: (id * 'a) list option;
207 updated: (id * 'a option) list option;
208 destroyed: id list option;
209 not_created: (id * set_error) list option;
210 not_updated: (id * set_error) list option;
211 not_destroyed: (id * set_error) list option;
212 }
213
214 (** Arguments for Foo/copy method as per Section 5.4 *)
215 type 'a copy_arguments = {
216 from_account_id: id;
217 if_from_in_state: string option;
218 account_id: id;
219 if_in_state: string option;
220 create: (id * 'a) list;
221 on_success_destroy_original: bool option;
222 destroy_from_if_in_state: string option;
223 }
224
225 (** Response for Foo/copy method as per Section 5.4 *)
226 type 'a copy_response = {
227 from_account_id: id;
228 account_id: id;
229 old_state: string option;
230 new_state: string;
231 created: (id * 'a) list option;
232 not_created: (id * set_error) list option;
233 }
234
235 (** Arguments for Foo/query method as per Section 5.5 *)
236 type query_arguments = {
237 account_id: id;
238 filter: filter option;
239 sort: comparator list option;
240 position: int_t option;
241 anchor: id option;
242 anchor_offset: int_t option;
243 limit: unsigned_int option;
244 calculate_total: bool option;
245 }
246
247 (** Response for Foo/query method as per Section 5.5 *)
248 type query_response = {
249 account_id: id;
250 query_state: string;
251 can_calculate_changes: bool;
252 position: unsigned_int;
253 ids: id list;
254 total: unsigned_int option;
255 limit: unsigned_int option;
256 }
257
258 (** Arguments for Foo/queryChanges method as per Section 5.6 *)
259 type query_changes_arguments = {
260 account_id: id;
261 filter: filter option;
262 sort: comparator list option;
263 since_query_state: string;
264 max_changes: unsigned_int option;
265 up_to_id: id option;
266 calculate_total: bool option;
267 }
268
269 (** Response for Foo/queryChanges method as per Section 5.6 *)
270 type query_changes_response = {
271 account_id: id;
272 old_query_state: string;
273 new_query_state: string;
274 total: unsigned_int option;
275 removed: id list;
276 added: added_item list option;
277 }
278
279 (** Arguments for Blob/copy method as per Section 6.3 *)
280 type blob_copy_arguments = {
281 from_account_id: id;
282 account_id: id;
283 blob_ids: id list;
284 }
285
286 (** Response for Blob/copy method as per Section 6.3 *)
287 type blob_copy_response = {
288 from_account_id: id;
289 account_id: id;
290 copied: (id * id) list option;
291 not_copied: (id * set_error) list option;
292 }
293
294 (** Upload response as per Section 6.1 *)
295 type upload_response = {
296 account_id: id;
297 blob_id: id;
298 type_: string;
299 size: unsigned_int;
300 }
301
302 (** Problem details object as per RFC7807 and Section 3.6.1 *)
303 type problem_details = {
304 type_: string;
305 status: int option;
306 detail: string option;
307 limit: string option; (* For "limit" error *)
308 }
309end
310
311(** {1 API Client} *)
312
313(** Module for making JMAP API requests over HTTP.
314 Provides functionality to interact with JMAP servers according to RFC8620. *)
315module Api : sig
316 (** Error that may occur during API requests *)
317 type error =
318 | Connection_error of string
319 | HTTP_error of int * string
320 | Parse_error of string
321 | Authentication_error
322
323 (** Result type for API operations *)
324 type 'a result = ('a, error) Stdlib.result
325
326 (** Configuration for a JMAP API client *)
327 type config = {
328 api_uri: Uri.t;
329 username: string;
330 authentication_token: string;
331 }
332
333 (** Make a raw JMAP API request *)
334 val make_request :
335 config ->
336 Types.request ->
337 Types.response result Lwt.t
338
339 (** Fetch a Session object from a JMAP server.
340 Can authenticate with either username/password or API token. *)
341 val get_session :
342 Uri.t ->
343 ?username:string ->
344 ?authentication_token:string ->
345 ?api_token:string ->
346 unit ->
347 Types.session result Lwt.t
348
349 (** Upload a binary blob to the server *)
350 val upload_blob :
351 config ->
352 account_id:Types.id ->
353 content_type:string ->
354 string ->
355 Types.upload_response result Lwt.t
356
357 (** Download a binary blob from the server *)
358 val download_blob :
359 config ->
360 account_id:Types.id ->
361 blob_id:Types.id ->
362 ?type_:string ->
363 ?name:string ->
364 unit ->
365 string result Lwt.t
366end