My agentic slop goes here. Not intended for anyone else!
at main 23 kB view raw
1(** JMAP Thread types and operations. 2 3 This module implements the JMAP Thread data type as specified in RFC 8621 4 Section 3. Threads represent conversations - collections of related Email 5 objects that are grouped together based on standard email threading algorithms 6 (typically using Message-ID, References, and In-Reply-To headers). 7 8 Threads provide a way to organize emails into conversations, making it easier 9 for users to follow email discussions. Thread objects are server-computed and 10 contain the list of email IDs that belong to the conversation. 11 12 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3> RFC 8621, Section 3: Threads 13*) 14 15open Jmap.Methods 16 17(** Thread object representation. 18 19 A Thread object represents a single conversation thread containing one or more 20 related Email objects. Threads are immutable and server-computed based on 21 email headers and threading algorithms. 22 23 The Thread object contains minimal information - just the thread ID and the 24 list of email IDs that belong to the thread. Additional thread information 25 can be obtained by fetching the constituent Email objects. 26 27 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3> RFC 8621, Section 3 28*) 29module Thread : sig 30 (** Immutable thread object type *) 31 type t 32 33 (** Pretty printing interface *) 34 include Jmap_sigs.PRINTABLE with type t := t 35 36 (** JMAP object interface for property selection and object creation *) 37 include Jmap_sigs.JMAP_OBJECT with type t := t and type id_type := string 38 39 (** Get the server-assigned thread identifier. 40 @return Unique thread ID (Some for all persisted threads, None only for unsaved objects) *) 41 val id : t -> Jmap.Id.t option 42 43 (** Get the list of email IDs belonging to this thread. 44 @return List of email IDs in conversation order *) 45 val email_ids : t -> Jmap.Id.t list 46 47 (** Create a new Thread object. 48 @param Jmap.Id.t Server-assigned thread identifier 49 @param email_ids List of email IDs in the thread 50 @return New thread object *) 51 val v : id:Jmap.Id.t -> email_ids:Jmap.Id.t list -> t 52end 53 54 55(** {1 Thread Methods} 56 57 JMAP method argument and response types for Thread operations. 58 Thread objects support query, get, and changes methods but not 59 queryChanges or set (threads are server-computed). 60*) 61 62(** Arguments for Thread/query method. 63 64 Allows querying for Thread objects based on filter criteria. 65 Since Thread objects don't have many properties, filtering is typically 66 done based on the emails they contain rather than thread properties directly. 67 68 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3.1> RFC 8621, Section 3.1 69*) 70module Query_args : sig 71 (** Thread/query arguments *) 72 type t 73 74 (** JSON serialization interface *) 75 include Jmap_sigs.JSONABLE with type t := t 76 77 (** JMAP method arguments interface *) 78 include Jmap_sigs.METHOD_ARGS with type t := t and type account_id := string 79 80 (** Get the account ID for the operation. 81 @return Account identifier where threads will be queried *) 82 val account_id : t -> Jmap.Id.t 83 84 (** Validate query arguments according to JMAP method constraints. 85 @param t Query arguments to validate 86 @return Ok () if valid, Error with description if invalid *) 87 val validate : t -> (unit, string) result 88 89 (** Get the method name for these arguments. 90 @return The JMAP method name "Thread/query" *) 91 val method_name : unit -> string 92 93 (** Get the filter condition for thread selection. 94 @return Filter criteria, or None for no filtering *) 95 val filter : t -> Filter.t option 96 97 (** Get the sort criteria for result ordering. 98 @return List of sort comparators, or None for server default *) 99 val sort : t -> Comparator.t list option 100 101 (** Get the starting position for results. 102 @return Zero-based start position, or None for beginning *) 103 val position : t -> int option 104 105 (** Get the anchor thread ID for relative positioning. 106 @return Thread ID to anchor results from, or None *) 107 val anchor : t -> Jmap.Id.t option 108 109 (** Get the offset from the anchor position. 110 @return Number of positions to offset from anchor *) 111 val anchor_offset : t -> int option 112 113 (** Get the maximum number of results to return. 114 @return Result limit, or None for server default *) 115 val limit : t -> Jmap.UInt.t option 116 117 (** Check if total count should be calculated. 118 @return true to calculate total result count *) 119 val calculate_total : t -> bool option 120 121 (** Create Thread/query arguments. 122 @param account_id Account where threads will be queried 123 @param filter Optional filter criteria 124 @param sort Optional sort comparators 125 @param position Optional starting position 126 @param anchor Optional anchor thread ID 127 @param anchor_offset Optional offset from anchor 128 @param limit Optional result limit 129 @param calculate_total Optional flag to calculate totals 130 @return Thread/query arguments object *) 131 val v : 132 account_id:Jmap.Id.t -> 133 ?filter:Filter.t -> 134 ?sort:Comparator.t list -> 135 ?position:int -> 136 ?anchor:Jmap.Id.t -> 137 ?anchor_offset:int -> 138 ?limit:Jmap.UInt.t -> 139 ?calculate_total:bool -> 140 unit -> t 141 142 (** Convert arguments to JSON for JMAP protocol. 143 @param t Thread/query arguments 144 @return JSON representation *) 145 val to_json : t -> Yojson.Safe.t 146end 147 148(** Response for Thread/query method. 149 150 Contains the list of thread IDs matching the query criteria along with 151 metadata about the query results and pagination information. 152 153 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3.1> RFC 8621, Section 3.1 154*) 155module Query_response : sig 156 (** Thread/query response *) 157 type t 158 159 (** JSON serialization interface *) 160 include Jmap_sigs.JSONABLE with type t := t 161 162 (** JMAP method response interface *) 163 include Jmap_sigs.METHOD_RESPONSE with type t := t and type account_id := string and type state := string 164 165 (** Get the account ID from the response. 166 @return Account identifier where threads were queried *) 167 val account_id : t -> Jmap.Id.t 168 169 (** Get the query state string for change tracking. 170 @return State string for use in queryChanges *) 171 val query_state : t -> string 172 173 (** Get the state token for synchronization (alias for query_state). 174 @return State token for change tracking *) 175 val state : t -> string option 176 177 (** Check if this response indicates an error condition. 178 @return false (query responses are success responses) *) 179 val is_error : t -> bool 180 181 (** Check if query changes can be calculated. 182 @return true if queryChanges is supported for this query *) 183 val can_calculate_changes : t -> bool 184 185 (** Get the starting position of the results. 186 @return Zero-based position in the complete result set *) 187 val position : t -> int 188 189 (** Get the list of matching thread IDs. 190 @return Ordered list of thread IDs matching the query *) 191 val ids : t -> Jmap.Id.t list 192 193 (** Get the total number of matching threads. 194 @return Total result count if calculateTotal was requested *) 195 val total : t -> Jmap.UInt.t option 196 197 (** Get the limit that was applied to the results. 198 @return Number of results returned, or None if no limit *) 199 val limit : t -> Jmap.UInt.t option 200 201 (** Create Thread/query response. 202 @param account_id Account where threads were queried 203 @param query_state State string for change tracking 204 @param can_calculate_changes Whether queryChanges is supported 205 @param position Starting position of results 206 @param ids List of matching thread IDs 207 @param total Optional total result count 208 @param limit Optional result limit applied 209 @return Thread/query response object *) 210 val v : 211 account_id:Jmap.Id.t -> 212 query_state:string -> 213 can_calculate_changes:bool -> 214 position:int -> 215 ids:Jmap.Id.t list -> 216 ?total:Jmap.UInt.t -> 217 ?limit:Jmap.UInt.t -> 218 unit -> t 219end 220 221(** Arguments for Thread/get method. 222 223 Extends the standard JMAP get pattern for retrieving Thread objects. 224 Since Thread objects are simple, property filtering is rarely needed. 225 226 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3.1> RFC 8621, Section 3.1 227*) 228module Get_args : sig 229 (** Thread/get arguments *) 230 type t 231 232 (** JSON serialization interface *) 233 include Jmap_sigs.JSONABLE with type t := t 234 235 (** JMAP method arguments interface *) 236 include Jmap_sigs.METHOD_ARGS with type t := t and type account_id := string 237 238 (** Get the account ID for the operation. 239 @return Account identifier where threads will be retrieved *) 240 val account_id : t -> Jmap.Id.t 241 242 (** Validate get arguments according to JMAP method constraints. 243 @param t Get arguments to validate 244 @return Ok () if valid, Error with description if invalid *) 245 val validate : t -> (unit, string) result 246 247 (** Get the method name for these arguments. 248 @return The JMAP method name "Thread/get" *) 249 val method_name : unit -> string 250 251 (** Get the specific thread IDs to retrieve. 252 @return List of thread IDs, or None to retrieve all threads *) 253 val ids : t -> Jmap.Id.t list option 254 255 (** Get the properties to include in the response. 256 @return List of property names, or None for all properties *) 257 val properties : t -> string list option 258 259 (** Create Thread/get arguments. 260 @param account_id Account where threads are located 261 @param ids Optional list of specific thread IDs to retrieve 262 @param properties Optional list of properties to include 263 @return Thread/get arguments object *) 264 val v : 265 account_id:Jmap.Id.t -> 266 ?ids:Jmap.Id.t list -> 267 ?properties:string list -> 268 unit -> t 269 270 (** Convert arguments to JSON for JMAP protocol. 271 @param t Thread/get arguments 272 @return JSON representation *) 273 val to_json : t -> Yojson.Safe.t 274end 275 276(** Response for Thread/get method. 277 278 Contains the retrieved Thread objects along with standard JMAP response 279 metadata including state string for change tracking. 280 281 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3.1> RFC 8621, Section 3.1 282*) 283module Get_response : sig 284 (** Thread/get response *) 285 type t 286 287 (** JSON serialization interface *) 288 include Jmap_sigs.JSONABLE with type t := t 289 290 (** JMAP method response interface *) 291 include Jmap_sigs.METHOD_RESPONSE with type t := t and type account_id := string and type state := string 292 293 (** Get the account ID from the response. 294 @return Account identifier where threads were retrieved *) 295 val account_id : t -> Jmap.Id.t 296 297 (** Get the current state string for change tracking. 298 @return State string for use in Thread/changes *) 299 val state : t -> string 300 301 (** Check if this response indicates an error condition. 302 @return false (get responses are success responses) *) 303 val is_error : t -> bool 304 305 (** Get the list of retrieved Thread objects. 306 @return List of Thread objects that were found *) 307 val list : t -> Thread.t list 308 309 (** Get the list of thread IDs that were not found. 310 @return List of requested IDs that don't exist *) 311 val not_found : t -> Jmap.Id.t list 312 313 (** Create Thread/get response. 314 @param account_id Account where threads were retrieved 315 @param state Current state string 316 @param list Retrieved thread objects 317 @param not_found IDs that were not found 318 @return Thread/get response object *) 319 val v : 320 account_id:Jmap.Id.t -> 321 state:string -> 322 list:Thread.t list -> 323 not_found:Jmap.Id.t list -> 324 unit -> t 325end 326 327(** Arguments for Thread/changes method. 328 329 Used to retrieve changes to Thread objects since a previous state. 330 Thread changes occur when emails are added to or removed from threads, 331 or when threading algorithms recompute thread relationships. 332 333 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3.2> RFC 8621, Section 3.2 334*) 335module Changes_args : sig 336 (** Thread/changes arguments *) 337 type t 338 339 (** JSON serialization interface *) 340 include Jmap_sigs.JSONABLE with type t := t 341 342 (** JMAP method arguments interface *) 343 include Jmap_sigs.METHOD_ARGS with type t := t and type account_id := string 344 345 (** Get the account ID for the operation. 346 @return Account identifier where thread changes are tracked *) 347 val account_id : t -> Jmap.Id.t 348 349 (** Validate changes arguments according to JMAP method constraints. 350 @param t Changes arguments to validate 351 @return Ok () if valid, Error with description if invalid *) 352 val validate : t -> (unit, string) result 353 354 (** Get the method name for these arguments. 355 @return The JMAP method name "Thread/changes" *) 356 val method_name : unit -> string 357 358 (** Get the state string from which to calculate changes. 359 @return Previous state string from Thread/get or Thread/changes *) 360 val since_state : t -> string 361 362 (** Get the maximum number of changes to return. 363 @return Change limit, or None for server default *) 364 val max_changes : t -> Jmap.UInt.t option 365 366 (** Create Thread/changes arguments. 367 @param account_id Account where thread changes are tracked 368 @param since_state Previous state string to compare against 369 @param max_changes Optional limit on number of changes returned 370 @return Thread/changes arguments object *) 371 val v : 372 account_id:Jmap.Id.t -> 373 since_state:string -> 374 ?max_changes:Jmap.UInt.t -> 375 unit -> t 376end 377 378(** Response for Thread/changes method. 379 380 Contains lists of thread IDs that were created, updated, or destroyed 381 since the specified state, along with the new state string for tracking 382 future changes. 383 384 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3.2> RFC 8621, Section 3.2 385*) 386module Changes_response : sig 387 (** Thread/changes response *) 388 type t 389 390 (** JSON serialization interface *) 391 include Jmap_sigs.JSONABLE with type t := t 392 393 (** JMAP method response interface *) 394 include Jmap_sigs.METHOD_RESPONSE with type t := t and type account_id := string and type state := string 395 396 (** Get the account ID from the response. 397 @return Account identifier where changes occurred *) 398 val account_id : t -> Jmap.Id.t 399 400 (** Get the old state string that was compared against. 401 @return The since_state parameter from the request *) 402 val old_state : t -> string 403 404 (** Get the new current state string. 405 @return Updated state for use in future Thread/changes calls *) 406 val new_state : t -> string 407 408 (** Get the state token for synchronization (alias for new_state). 409 @return State token for change tracking *) 410 val state : t -> string option 411 412 (** Check if this response indicates an error condition. 413 @return false (changes responses are success responses) *) 414 val is_error : t -> bool 415 416 (** Check if more changes are available. 417 @return true if max_changes limit was reached and more changes exist *) 418 val has_more_changes : t -> bool 419 420 (** Get the list of newly created thread IDs. 421 @return Thread IDs that were created since the old state *) 422 val created : t -> Jmap.Id.t list 423 424 (** Get the list of updated thread IDs. 425 @return Thread IDs whose email lists changed since the old state *) 426 val updated : t -> Jmap.Id.t list 427 428 (** Get the list of destroyed thread IDs. 429 @return Thread IDs that were deleted since the old state *) 430 val destroyed : t -> Jmap.Id.t list 431 432 (** Create Thread/changes response. 433 @param account_id Account where changes occurred 434 @param old_state Previous state string 435 @param new_state Current state string 436 @param has_more_changes Whether more changes are available 437 @param created List of created thread IDs 438 @param updated List of updated thread IDs 439 @param destroyed List of destroyed thread IDs 440 @return Thread/changes response object *) 441 val v : 442 account_id:Jmap.Id.t -> 443 old_state:string -> 444 new_state:string -> 445 has_more_changes:bool -> 446 created:Jmap.Id.t list -> 447 updated:Jmap.Id.t list -> 448 destroyed:Jmap.Id.t list -> 449 unit -> t 450end 451 452(** {1 Helper Functions} 453 454 Utility functions for creating common thread-related filter conditions. 455 These are used with Email/query when searching for emails that belong 456 to specific types of threads, since Thread objects themselves don't 457 support query operations. 458*) 459 460(** Create a filter to find threads containing a specific email. 461 @param email_id The email ID to search for in threads 462 @return Filter condition for Email/query to find related emails *) 463val filter_has_email : Jmap.Id.t -> Filter.t 464 465(** Create a filter to find threads containing emails from a sender. 466 @param sender Email address or name to search for in From fields 467 @return Filter condition for finding threads with emails from the sender *) 468val filter_from : string -> Filter.t 469 470(** Create a filter to find threads containing emails to a recipient. 471 @param recipient Email address or name to search for in To/Cc fields 472 @return Filter condition for finding threads with emails to the recipient *) 473val filter_to : string -> Filter.t 474 475(** Create a filter to find threads containing emails with a subject. 476 @param subject Text to search for in email subjects 477 @return Filter condition for finding threads containing the subject text *) 478val filter_subject : string -> Filter.t 479 480(** Create a filter to find threads with emails received before a Date.t. 481 @param Date.t Cutoff Date.t for filtering 482 @return Filter condition for threads with emails before the Date.t *) 483val filter_before : Jmap.Date.t -> Filter.t 484 485(** Create a filter to find threads with emails received after a Date.t. 486 @param Date.t Start Date.t for filtering 487 @return Filter condition for threads with emails after the Date.t *) 488val filter_after : Jmap.Date.t -> Filter.t 489 490(** {1 Advanced Thread Management} *) 491 492(** Conversation reconstruction state for managing complex threading operations. 493 494 Provides stateful thread management including thread merging, splitting, 495 and recalculation using different threading algorithms. 496*) 497module ConversationState : sig 498 (** Opaque conversation state type *) 499 type t 500 501 (** Create new conversation state. 502 503 @param algorithm Threading algorithm to use (default: `HYBRID) 504 @param auto_merge Whether to automatically merge related threads 505 @param subject_threshold Similarity threshold for subject-based merging 506 @return New conversation state *) 507 val create : ?algorithm:[`RFC5256_REFERENCES | `RFC5256_ORDEREDSUBJECT | `HYBRID | `CONVERSATION] -> ?auto_merge:bool -> ?subject_threshold:float -> unit -> t 508 509 (** Add an email to conversation tracking. 510 511 @param t Conversation state 512 @param email_id Email ID to add to tracking 513 @return Updated conversation state *) 514 val add_email : t -> Jmap.Id.t -> t 515 516 (** Remove an email from conversation tracking. 517 518 @param t Conversation state 519 @param email_id ID of email to remove 520 @return Updated conversation state *) 521 val remove_email : t -> Jmap.Id.t -> t 522 523 (** Find which thread contains a specific email. 524 525 @param t Conversation state 526 @param email_id Email ID to search for 527 @return Thread ID if found *) 528 val find_containing_thread : t -> Jmap.Id.t -> Jmap.Id.t option 529 530 (** Get all emails in a specific thread. 531 532 @param t Conversation state 533 @param thread_id Thread ID 534 @return List of email IDs in the thread *) 535 val get_thread_emails : t -> Jmap.Id.t -> Jmap.Id.t list 536 537 (** Get all current thread groups. 538 539 @param t Conversation state 540 @return List of all thread groups *) 541 val get_all_threads : t -> (Jmap.Id.t * Jmap.Id.t list) list 542 543 (** Merge two threads into one conversation. 544 545 @param t Conversation state 546 @param thread1 First thread ID 547 @param thread2 Second thread ID 548 @return Updated conversation state *) 549 val merge_threads : t -> Jmap.Id.t -> Jmap.Id.t -> t 550 551 (** Split a thread at a specific email. 552 553 @param t Conversation state 554 @param thread_id Thread to split 555 @param split_email Email ID where to split 556 @return Updated conversation state *) 557 val split_thread : t -> Jmap.Id.t -> Jmap.Id.t -> t 558 559 (** Recalculate all thread relationships. 560 561 @param t Conversation state 562 @return Updated conversation state *) 563 val recalculate_threads : t -> t 564 565 (** Change threading algorithm and recalculate. 566 567 @param t Conversation state 568 @param algorithm New algorithm to use 569 @return Updated conversation state *) 570 val set_algorithm : t -> [`RFC5256_REFERENCES | `RFC5256_ORDEREDSUBJECT | `HYBRID | `CONVERSATION] -> t 571 572 (** Get conversation statistics. 573 574 @param t Conversation state 575 @return List of statistics about current threads *) 576 val get_stats : t -> [ 577 | `ThreadCount of int 578 | `AverageThreadSize of float 579 | `LargestThread of int 580 | `SingletonThreads of int 581 | `MultiEmailThreads of int 582 ] list 583end 584 585(** Normalize a subject line for threading comparison. 586 587 @param subject Subject line to normalize 588 @return Normalized subject string *) 589val normalize_thread_subject : string -> string 590 591(** {1 Property System} *) 592 593(** Thread object property identifiers for selective retrieval. 594 595 Property identifiers for Thread objects as specified in RFC 8621 Section 3. 596 These identifiers are used in Thread/get requests to specify which properties 597 should be returned, enabling efficient partial object retrieval. 598 599 @see <https://www.rfc-editor.org/rfc/rfc8621.html#section-3> RFC 8621, Section 3 600*) 601module Property : sig 602 (** Thread object property identifier type. 603 604 Polymorphic variant enumeration of all standard properties available 605 on Thread objects. Thread objects have a minimal set of properties 606 since they primarily serve as containers for email ID lists. 607 *) 608 type t = [ 609 | `Id (** Server-assigned unique identifier for the thread *) 610 | `EmailIds (** List of email IDs belonging to this thread *) 611 ] 612 613 (** Convert a property to its JMAP protocol string representation. 614 615 @param prop The property to convert 616 @return JMAP protocol string representation *) 617 val to_string : t -> string 618 619 (** Parse a JMAP protocol string into a property variant. 620 621 @param str The protocol string to parse 622 @return Some property if valid, None if unknown *) 623 val of_string : string -> t option 624 625 (** Get all standard thread properties. 626 627 @return Complete list of all defined thread properties *) 628 val all_properties : t list 629 630 (** Convert a list of properties to their string representations. 631 632 @param properties List of property variants 633 @return List of JMAP protocol strings *) 634 val to_string_list : t list -> string list 635 636 (** Parse a list of strings into property variants. 637 638 @param strings List of JMAP protocol strings 639 @return List of parsed property variants (invalid strings ignored) *) 640 val of_string_list : string list -> t list 641end