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