My agentic slop goes here. Not intended for anyone else!
1(** JMAP Primitive Data Types 2 3 This module defines the primitive data types used in JMAP: 4 - Int (signed 53-bit integer) 5 - UnsignedInt (unsigned integer 0 to 2^53-1) 6 - Date (RFC 3339 date-time) 7 - UTCDate (RFC 3339 date-time with Z timezone) 8 9 Reference: RFC 8620 Section 1.3 10*) 11 12(** Signed 53-bit integer (-2^53 + 1 to 2^53 - 1) 13 JavaScript's safe integer range *) 14module Int53 = struct 15 type t = int 16 17 let min_value = -9007199254740991 (* -(2^53 - 1) *) 18 let max_value = 9007199254740991 (* 2^53 - 1 *) 19 20 let of_int i = 21 if i < min_value || i > max_value then 22 raise (Invalid_argument "Int53 out of range") 23 else 24 i 25 26 let to_int t = t 27 28 (** Parse from JSON. 29 Test files: test/data/core/request_query.json (position, anchorOffset) *) 30 let of_json = function 31 | `Float f -> 32 let i = int_of_float f in 33 if Float.is_integer f then 34 of_int i 35 else 36 raise (Jmap_error.Parse_error "Int53 must be an integer") 37 | _ -> raise (Jmap_error.Parse_error "Int53 must be a JSON number") 38 39 let to_json t = `Float (float_of_int t) 40end 41 42(** Unsigned integer (0 to 2^53 - 1) *) 43module UnsignedInt = struct 44 type t = int 45 46 let min_value = 0 47 let max_value = 9007199254740991 (* 2^53 - 1 *) 48 49 let of_int i = 50 if i < min_value || i > max_value then 51 raise (Invalid_argument "UnsignedInt out of range") 52 else 53 i 54 55 let to_int t = t 56 57 (** Parse from JSON. 58 Test files: 59 - test/data/mail/mailbox_get_response.json (totalEmails, unreadEmails, etc.) 60 - test/data/core/request_query.json (limit) 61 *) 62 let of_json = function 63 | `Float f -> 64 let i = int_of_float f in 65 if Float.is_integer f && i >= 0 then 66 of_int i 67 else 68 raise (Jmap_error.Parse_error "UnsignedInt must be a non-negative integer") 69 | _ -> raise (Jmap_error.Parse_error "UnsignedInt must be a JSON number") 70 71 let to_json t = `Float (float_of_int t) 72end 73 74(** RFC 3339 date-time (with or without timezone) 75 Examples: "2014-10-30T14:12:00+08:00", "2014-10-30T06:12:00Z" 76*) 77module Date = struct 78 type t = string 79 80 (** Basic validation of RFC 3339 format *) 81 let validate s = 82 (* Simple check: contains 'T' and has reasonable length *) 83 String.contains s 'T' && String.length s >= 19 84 85 let of_string s = 86 if validate s then s 87 else raise (Invalid_argument "Invalid RFC 3339 date-time format") 88 89 let to_string t = t 90 91 (** Parse from JSON. 92 Test files: test/data/mail/email_get_response.json (sentAt field) *) 93 let of_json = function 94 | `String s -> of_string s 95 | _ -> raise (Jmap_error.Parse_error "Date must be a JSON string") 96 97 let to_json t = `String t 98end 99 100(** RFC 3339 date-time with Z timezone (UTC) 101 Example: "2014-10-30T06:12:00Z" 102 103 MUST have "Z" suffix to indicate UTC. 104*) 105module UTCDate = struct 106 type t = string 107 108 (** Validate that string is RFC 3339 with Z suffix *) 109 let validate s = 110 String.contains s 'T' && 111 String.length s >= 20 && 112 s.[String.length s - 1] = 'Z' 113 114 let of_string s = 115 if validate s then s 116 else raise (Invalid_argument "Invalid RFC 3339 UTCDate format (must end with Z)") 117 118 let to_string t = t 119 120 (** Parse from JSON. 121 Test files: 122 - test/data/mail/email_get_response.json (receivedAt field) 123 - test/data/mail/email_submission_get_response.json (sendAt field) 124 *) 125 let of_json = function 126 | `String s -> of_string s 127 | _ -> raise (Jmap_error.Parse_error "UTCDate must be a JSON string") 128 129 let to_json t = `String t 130 131 (** Get current UTC time as UTCDate *) 132 let now () = 133 let open Unix in 134 let tm = gmtime (time ()) in 135 Printf.sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ" 136 (tm.tm_year + 1900) 137 (tm.tm_mon + 1) 138 tm.tm_mday 139 tm.tm_hour 140 tm.tm_min 141 tm.tm_sec 142end